All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/21] RISC-V Kendryte K210 support improvements
@ 2020-12-02  3:24 ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

This series of patches improves support for boards based on the Kendryte
K210 RISC-V dual core SoC. Minimal support for this SoC is already
included in the kernel. These patches complete it, enabling support for
most peripherals present on the SoC as well as introducing device trees
for the various K210 boards available on the market today from SiPeed
and Kendryte.

Pathes 1 to 4 are various fixes for riscv arch code and riscv
dependent devices. Of note here is patch 3 which fix system calls
execution in the no MMU case, and patch 4 which simplifies DTB builtin
handling.

Patch 5 fixes naming of directories and configuration options to use the
K210 SoC vendor name (Canaan) instead of its branding name (Kendryte).

The following patches 6 to 10 document device tree bindings for the SoC
drivers. The implementation of these drivers is provided in patches 11,
12 and 13, respectively implementing the SoC clock driver, SOC pin
function control and reset controller.

Patches 14 to 19 update the existing K210 device tree and add new
device tree files for several K210 based boards: MAIX Bit, MAIXDUINO,
MAIX Dock and MAIX Go boards from SiPeed and the KD233 development
board from Canaan.

Finally the last two patches updates the k210 nommu defconfig to include
the newly implemented drivers and provide a new default configuration
file enabling SD card support.

A lot of the work on the device tree and on the K210 drivers come from
the work by Sean Anderson for the U-Boot project support of the K210
SoC. Sean also helped with debugging many aspects of this series.

A tree with all patches applied is available here:
https://github.com/damien-lemoal/linux, k210-sysctl-v17 branch.
A demonstration of this series used on a SiPeed MAIX Dock
board together with an I2C servo controller can be seen here:
https://damien-lemoal.github.io/linux-robot-arm/#example

This tree was used to build userspace busybox environment image that is
then copied onto an SD card formatted with ext2:
https://github.com/damien-lemoal/buildroot
Of note is that running this userspace environment requires a revert of
commit 2217b982624680d19a80ebb4600d05c8586c4f96 introduced during the
5.9 development cycle. Without this revert, execution of the init
process fails. A problem with the riscv port of elf2flt is suspected but
not confirmed. I am now starting to investigate this problem.

Reviews and comments are as always much welcome.

Changes from V3:
* Add one entry per driver in MAINTAINERS file

Changes from V2:
* Add MAINTAINERS file entry for the SoC support, listing myself as
  maintainer.
* Removed use of postcore_initcall() for declaring the drivers, using
  the regular builtin_platform_driver() instead.
* Fixed fpio pinctrl driver bindings documentation as commented by
  Geert: removed input-schmitt and added input-schmitt-disable, fixed
  typo and added input-disable and output-disable.
* Fixed device tree to have cs-gpios active low, as per the default, as
  active high necessity was an artifact of the gpio level double
  inversion bug fixed recently.
* Removed CONFIG_VT from defconfigs to reduce the kernel image size as
  suggested by Geert.

Changes from v1:
* Improved DT bindings documentation
* SPI and GPIO patches removed from this series (and being processed
  directly through the relevant subsystems directly)
* Improved device trees
* Various cleanup and improvments of the drivers

Damien Le Moal (21):
  riscv: Fix kernel time_init()
  riscv: Fix sifive serial driver
  riscv: Enable interrupts during syscalls with M-Mode
  riscv: Fix builtin DTB handling
  riscv: Use vendor name for K210 SoC support
  dt-bindings: Add Canaan vendor prefix
  dt-binding: clock: Document canaan,k210-clk bindings
  dt-bindings: reset: Document canaan,k210-rst bindings
  dt-bindings: pinctrl: Document canaan,k210-fpioa bindings
  dt-binding: mfd: Document canaan,k210-sysctl bindings
  riscv: Add Canaan Kendryte K210 clock driver
  riscv: Add Canaan Kendryte K210 FPIOA driver
  riscv: Add Canaan Kendryte K210 reset controller
  riscv: Update Canaan Kendryte K210 device tree
  riscv: Add SiPeed MAIX BiT board device tree
  riscv: Add SiPeed MAIX DOCK board device tree
  riscv: Add SiPeed MAIX GO board device tree
  riscv: Add SiPeed MAIXDUINO board device tree
  riscv: Add Kendryte KD233 board device tree
  riscv: Update Canaan Kendryte K210 defconfig
  riscv: Add Canaan Kendryte K210 SD card defconfig

 .../bindings/clock/canaan,k210-clk.yaml       |  55 +
 .../bindings/mfd/canaan,k210-sysctl.yaml      | 116 +++
 .../bindings/pinctrl/canaan,k210-fpioa.yaml   | 171 +++
 .../bindings/reset/canaan,k210-rst.yaml       |  40 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |  31 +
 arch/riscv/Kconfig.socs                       |  38 +-
 arch/riscv/Makefile                           |   2 +-
 arch/riscv/boot/dts/Makefile                  |   2 +-
 arch/riscv/boot/dts/canaan/Makefile           |   5 +
 arch/riscv/boot/dts/canaan/k210.dtsi          | 625 +++++++++++
 arch/riscv/boot/dts/canaan/k210_generic.dts   |  46 +
 arch/riscv/boot/dts/canaan/k210_kd233.dts     | 178 ++++
 arch/riscv/boot/dts/canaan/k210_maix_bit.dts  | 227 ++++
 arch/riscv/boot/dts/canaan/k210_maix_dock.dts | 229 ++++
 arch/riscv/boot/dts/canaan/k210_maix_go.dts   | 237 +++++
 arch/riscv/boot/dts/canaan/k210_maixduino.dts | 201 ++++
 arch/riscv/boot/dts/kendryte/Makefile         |   4 -
 arch/riscv/boot/dts/kendryte/k210.dts         |  23 -
 arch/riscv/boot/dts/kendryte/k210.dtsi        | 125 ---
 arch/riscv/configs/nommu_k210_defconfig       |  39 +-
 .../riscv/configs/nommu_k210_sdcard_defconfig |  93 ++
 arch/riscv/include/asm/soc.h                  |  38 -
 arch/riscv/kernel/entry.S                     |   9 +
 arch/riscv/kernel/soc.c                       |  27 -
 arch/riscv/kernel/time.c                      |   3 +
 arch/riscv/mm/init.c                          |   6 +-
 drivers/clk/Kconfig                           |   9 +
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-k210.c                        | 959 +++++++++++++++++
 drivers/pinctrl/Kconfig                       |  13 +
 drivers/pinctrl/Makefile                      |   1 +
 drivers/pinctrl/pinctrl-k210.c                | 984 ++++++++++++++++++
 drivers/reset/Kconfig                         |   9 +
 drivers/reset/Makefile                        |   1 +
 drivers/reset/reset-k210.c                    | 141 +++
 drivers/soc/Kconfig                           |   2 +-
 drivers/soc/Makefile                          |   2 +-
 drivers/soc/canaan/Kconfig                    |   9 +
 drivers/soc/canaan/Makefile                   |   3 +
 drivers/soc/canaan/k210-sysctl.c              |  79 ++
 drivers/soc/kendryte/Kconfig                  |  14 -
 drivers/soc/kendryte/Makefile                 |   3 -
 drivers/soc/kendryte/k210-sysctl.c            | 260 -----
 drivers/tty/serial/sifive.c                   |   1 +
 include/dt-bindings/clock/k210-clk.h          |  61 +-
 include/dt-bindings/pinctrl/k210-fpioa.h      | 276 +++++
 include/dt-bindings/reset/k210-rst.h          |  42 +
 include/soc/canaan/k210-sysctl.h              |  43 +
 49 files changed, 4954 insertions(+), 531 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
 create mode 100644 Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
 create mode 100644 arch/riscv/boot/dts/canaan/Makefile
 create mode 100644 arch/riscv/boot/dts/canaan/k210.dtsi
 create mode 100644 arch/riscv/boot/dts/canaan/k210_generic.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_kd233.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_bit.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_dock.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_go.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maixduino.dts
 delete mode 100644 arch/riscv/boot/dts/kendryte/Makefile
 delete mode 100644 arch/riscv/boot/dts/kendryte/k210.dts
 delete mode 100644 arch/riscv/boot/dts/kendryte/k210.dtsi
 create mode 100644 arch/riscv/configs/nommu_k210_sdcard_defconfig
 create mode 100644 drivers/clk/clk-k210.c
 create mode 100644 drivers/pinctrl/pinctrl-k210.c
 create mode 100644 drivers/reset/reset-k210.c
 create mode 100644 drivers/soc/canaan/Kconfig
 create mode 100644 drivers/soc/canaan/Makefile
 create mode 100644 drivers/soc/canaan/k210-sysctl.c
 delete mode 100644 drivers/soc/kendryte/Kconfig
 delete mode 100644 drivers/soc/kendryte/Makefile
 delete mode 100644 drivers/soc/kendryte/k210-sysctl.c
 create mode 100644 include/dt-bindings/pinctrl/k210-fpioa.h
 create mode 100644 include/dt-bindings/reset/k210-rst.h
 create mode 100644 include/soc/canaan/k210-sysctl.h

-- 
2.28.0


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

* [PATCH v4 00/21] RISC-V Kendryte K210 support improvements
@ 2020-12-02  3:24 ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

This series of patches improves support for boards based on the Kendryte
K210 RISC-V dual core SoC. Minimal support for this SoC is already
included in the kernel. These patches complete it, enabling support for
most peripherals present on the SoC as well as introducing device trees
for the various K210 boards available on the market today from SiPeed
and Kendryte.

Pathes 1 to 4 are various fixes for riscv arch code and riscv
dependent devices. Of note here is patch 3 which fix system calls
execution in the no MMU case, and patch 4 which simplifies DTB builtin
handling.

Patch 5 fixes naming of directories and configuration options to use the
K210 SoC vendor name (Canaan) instead of its branding name (Kendryte).

The following patches 6 to 10 document device tree bindings for the SoC
drivers. The implementation of these drivers is provided in patches 11,
12 and 13, respectively implementing the SoC clock driver, SOC pin
function control and reset controller.

Patches 14 to 19 update the existing K210 device tree and add new
device tree files for several K210 based boards: MAIX Bit, MAIXDUINO,
MAIX Dock and MAIX Go boards from SiPeed and the KD233 development
board from Canaan.

Finally the last two patches updates the k210 nommu defconfig to include
the newly implemented drivers and provide a new default configuration
file enabling SD card support.

A lot of the work on the device tree and on the K210 drivers come from
the work by Sean Anderson for the U-Boot project support of the K210
SoC. Sean also helped with debugging many aspects of this series.

A tree with all patches applied is available here:
https://github.com/damien-lemoal/linux, k210-sysctl-v17 branch.
A demonstration of this series used on a SiPeed MAIX Dock
board together with an I2C servo controller can be seen here:
https://damien-lemoal.github.io/linux-robot-arm/#example

This tree was used to build userspace busybox environment image that is
then copied onto an SD card formatted with ext2:
https://github.com/damien-lemoal/buildroot
Of note is that running this userspace environment requires a revert of
commit 2217b982624680d19a80ebb4600d05c8586c4f96 introduced during the
5.9 development cycle. Without this revert, execution of the init
process fails. A problem with the riscv port of elf2flt is suspected but
not confirmed. I am now starting to investigate this problem.

Reviews and comments are as always much welcome.

Changes from V3:
* Add one entry per driver in MAINTAINERS file

Changes from V2:
* Add MAINTAINERS file entry for the SoC support, listing myself as
  maintainer.
* Removed use of postcore_initcall() for declaring the drivers, using
  the regular builtin_platform_driver() instead.
* Fixed fpio pinctrl driver bindings documentation as commented by
  Geert: removed input-schmitt and added input-schmitt-disable, fixed
  typo and added input-disable and output-disable.
* Fixed device tree to have cs-gpios active low, as per the default, as
  active high necessity was an artifact of the gpio level double
  inversion bug fixed recently.
* Removed CONFIG_VT from defconfigs to reduce the kernel image size as
  suggested by Geert.

Changes from v1:
* Improved DT bindings documentation
* SPI and GPIO patches removed from this series (and being processed
  directly through the relevant subsystems directly)
* Improved device trees
* Various cleanup and improvments of the drivers

Damien Le Moal (21):
  riscv: Fix kernel time_init()
  riscv: Fix sifive serial driver
  riscv: Enable interrupts during syscalls with M-Mode
  riscv: Fix builtin DTB handling
  riscv: Use vendor name for K210 SoC support
  dt-bindings: Add Canaan vendor prefix
  dt-binding: clock: Document canaan,k210-clk bindings
  dt-bindings: reset: Document canaan,k210-rst bindings
  dt-bindings: pinctrl: Document canaan,k210-fpioa bindings
  dt-binding: mfd: Document canaan,k210-sysctl bindings
  riscv: Add Canaan Kendryte K210 clock driver
  riscv: Add Canaan Kendryte K210 FPIOA driver
  riscv: Add Canaan Kendryte K210 reset controller
  riscv: Update Canaan Kendryte K210 device tree
  riscv: Add SiPeed MAIX BiT board device tree
  riscv: Add SiPeed MAIX DOCK board device tree
  riscv: Add SiPeed MAIX GO board device tree
  riscv: Add SiPeed MAIXDUINO board device tree
  riscv: Add Kendryte KD233 board device tree
  riscv: Update Canaan Kendryte K210 defconfig
  riscv: Add Canaan Kendryte K210 SD card defconfig

 .../bindings/clock/canaan,k210-clk.yaml       |  55 +
 .../bindings/mfd/canaan,k210-sysctl.yaml      | 116 +++
 .../bindings/pinctrl/canaan,k210-fpioa.yaml   | 171 +++
 .../bindings/reset/canaan,k210-rst.yaml       |  40 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |  31 +
 arch/riscv/Kconfig.socs                       |  38 +-
 arch/riscv/Makefile                           |   2 +-
 arch/riscv/boot/dts/Makefile                  |   2 +-
 arch/riscv/boot/dts/canaan/Makefile           |   5 +
 arch/riscv/boot/dts/canaan/k210.dtsi          | 625 +++++++++++
 arch/riscv/boot/dts/canaan/k210_generic.dts   |  46 +
 arch/riscv/boot/dts/canaan/k210_kd233.dts     | 178 ++++
 arch/riscv/boot/dts/canaan/k210_maix_bit.dts  | 227 ++++
 arch/riscv/boot/dts/canaan/k210_maix_dock.dts | 229 ++++
 arch/riscv/boot/dts/canaan/k210_maix_go.dts   | 237 +++++
 arch/riscv/boot/dts/canaan/k210_maixduino.dts | 201 ++++
 arch/riscv/boot/dts/kendryte/Makefile         |   4 -
 arch/riscv/boot/dts/kendryte/k210.dts         |  23 -
 arch/riscv/boot/dts/kendryte/k210.dtsi        | 125 ---
 arch/riscv/configs/nommu_k210_defconfig       |  39 +-
 .../riscv/configs/nommu_k210_sdcard_defconfig |  93 ++
 arch/riscv/include/asm/soc.h                  |  38 -
 arch/riscv/kernel/entry.S                     |   9 +
 arch/riscv/kernel/soc.c                       |  27 -
 arch/riscv/kernel/time.c                      |   3 +
 arch/riscv/mm/init.c                          |   6 +-
 drivers/clk/Kconfig                           |   9 +
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-k210.c                        | 959 +++++++++++++++++
 drivers/pinctrl/Kconfig                       |  13 +
 drivers/pinctrl/Makefile                      |   1 +
 drivers/pinctrl/pinctrl-k210.c                | 984 ++++++++++++++++++
 drivers/reset/Kconfig                         |   9 +
 drivers/reset/Makefile                        |   1 +
 drivers/reset/reset-k210.c                    | 141 +++
 drivers/soc/Kconfig                           |   2 +-
 drivers/soc/Makefile                          |   2 +-
 drivers/soc/canaan/Kconfig                    |   9 +
 drivers/soc/canaan/Makefile                   |   3 +
 drivers/soc/canaan/k210-sysctl.c              |  79 ++
 drivers/soc/kendryte/Kconfig                  |  14 -
 drivers/soc/kendryte/Makefile                 |   3 -
 drivers/soc/kendryte/k210-sysctl.c            | 260 -----
 drivers/tty/serial/sifive.c                   |   1 +
 include/dt-bindings/clock/k210-clk.h          |  61 +-
 include/dt-bindings/pinctrl/k210-fpioa.h      | 276 +++++
 include/dt-bindings/reset/k210-rst.h          |  42 +
 include/soc/canaan/k210-sysctl.h              |  43 +
 49 files changed, 4954 insertions(+), 531 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
 create mode 100644 Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
 create mode 100644 arch/riscv/boot/dts/canaan/Makefile
 create mode 100644 arch/riscv/boot/dts/canaan/k210.dtsi
 create mode 100644 arch/riscv/boot/dts/canaan/k210_generic.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_kd233.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_bit.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_dock.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_go.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maixduino.dts
 delete mode 100644 arch/riscv/boot/dts/kendryte/Makefile
 delete mode 100644 arch/riscv/boot/dts/kendryte/k210.dts
 delete mode 100644 arch/riscv/boot/dts/kendryte/k210.dtsi
 create mode 100644 arch/riscv/configs/nommu_k210_sdcard_defconfig
 create mode 100644 drivers/clk/clk-k210.c
 create mode 100644 drivers/pinctrl/pinctrl-k210.c
 create mode 100644 drivers/reset/reset-k210.c
 create mode 100644 drivers/soc/canaan/Kconfig
 create mode 100644 drivers/soc/canaan/Makefile
 create mode 100644 drivers/soc/canaan/k210-sysctl.c
 delete mode 100644 drivers/soc/kendryte/Kconfig
 delete mode 100644 drivers/soc/kendryte/Makefile
 delete mode 100644 drivers/soc/kendryte/k210-sysctl.c
 create mode 100644 include/dt-bindings/pinctrl/k210-fpioa.h
 create mode 100644 include/dt-bindings/reset/k210-rst.h
 create mode 100644 include/soc/canaan/k210-sysctl.h

-- 
2.28.0


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

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

* [PATCH v4 01/21] riscv: Fix kernel time_init()
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

If of_clk_init() is not called in time_init(), clock providers defined
in the system device tree are not initialized, resulting in failures for
other devices to initialize due to missing clocks.
Similarly to other architectures and to the default kernel time_init()
implementation, call of_clk_init() before executing timer_probe() in
time_init().

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/kernel/time.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c
index 4d3a1048ad8b..8a5cf99c0776 100644
--- a/arch/riscv/kernel/time.c
+++ b/arch/riscv/kernel/time.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2017 SiFive
  */
 
+#include <linux/of_clk.h>
 #include <linux/clocksource.h>
 #include <linux/delay.h>
 #include <asm/sbi.h>
@@ -24,6 +25,8 @@ void __init time_init(void)
 	riscv_timebase = prop;
 
 	lpj_fine = riscv_timebase / HZ;
+
+	of_clk_init(NULL);
 	timer_probe();
 }
 
-- 
2.28.0


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

* [PATCH v4 01/21] riscv: Fix kernel time_init()
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

If of_clk_init() is not called in time_init(), clock providers defined
in the system device tree are not initialized, resulting in failures for
other devices to initialize due to missing clocks.
Similarly to other architectures and to the default kernel time_init()
implementation, call of_clk_init() before executing timer_probe() in
time_init().

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/kernel/time.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c
index 4d3a1048ad8b..8a5cf99c0776 100644
--- a/arch/riscv/kernel/time.c
+++ b/arch/riscv/kernel/time.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2017 SiFive
  */
 
+#include <linux/of_clk.h>
 #include <linux/clocksource.h>
 #include <linux/delay.h>
 #include <asm/sbi.h>
@@ -24,6 +25,8 @@ void __init time_init(void)
 	riscv_timebase = prop;
 
 	lpj_fine = riscv_timebase / HZ;
+
+	of_clk_init(NULL);
 	timer_probe();
 }
 
-- 
2.28.0


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

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

* [PATCH v4 02/21] riscv: Fix sifive serial driver
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Setup the port uartclk in sifive_serial_probe() so that the base baud
rate is correctly printed during device probe instead of always showing
"0".  I.e. the probe message is changed from

38000000.serial: ttySIF0 at MMIO 0x38000000 (irq = 1,
base_baud = 0) is a SiFive UART v0

to the correct:

38000000.serial: ttySIF0 at MMIO 0x38000000 (irq = 1,
base_baud = 115200) is a SiFive UART v0

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 drivers/tty/serial/sifive.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 13eadcb8aec4..214bf3086c68 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -999,6 +999,7 @@ static int sifive_serial_probe(struct platform_device *pdev)
 	/* Set up clock divider */
 	ssp->clkin_rate = clk_get_rate(ssp->clk);
 	ssp->baud_rate = SIFIVE_DEFAULT_BAUD_RATE;
+	ssp->port.uartclk = ssp->baud_rate * 16;
 	__ssp_update_div(ssp);
 
 	platform_set_drvdata(pdev, ssp);
-- 
2.28.0


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

* [PATCH v4 02/21] riscv: Fix sifive serial driver
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Setup the port uartclk in sifive_serial_probe() so that the base baud
rate is correctly printed during device probe instead of always showing
"0".  I.e. the probe message is changed from

38000000.serial: ttySIF0 at MMIO 0x38000000 (irq = 1,
base_baud = 0) is a SiFive UART v0

to the correct:

38000000.serial: ttySIF0 at MMIO 0x38000000 (irq = 1,
base_baud = 115200) is a SiFive UART v0

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 drivers/tty/serial/sifive.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 13eadcb8aec4..214bf3086c68 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -999,6 +999,7 @@ static int sifive_serial_probe(struct platform_device *pdev)
 	/* Set up clock divider */
 	ssp->clkin_rate = clk_get_rate(ssp->clk);
 	ssp->baud_rate = SIFIVE_DEFAULT_BAUD_RATE;
+	ssp->port.uartclk = ssp->baud_rate * 16;
 	__ssp_update_div(ssp);
 
 	platform_set_drvdata(pdev, ssp);
-- 
2.28.0


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

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

* [PATCH v4 03/21] riscv: Enable interrupts during syscalls with M-Mode
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

When running is M-Mode (no MMU config), MPIE does not get set. This
results in all syscalls being executed with interrupts disabled as
handle_exception never sets SR_IE as it always sees SR_PIE being
cleared. Fix this by always force enabling interrupts in
handle_syscall when CONFIG_RISCV_M_MODE is enabled.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/kernel/entry.S | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 524d918f3601..080eb8d78589 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -155,6 +155,15 @@ skip_context_tracking:
 	tail do_trap_unknown
 
 handle_syscall:
+#ifdef CONFIG_RISCV_M_MODE
+	/*
+	 * When running is M-Mode (no MMU config), MPIE does not get set.
+	 * As a result, we need to force enable interrupts here because
+	 * handle_exception did not do set SR_IE as it always sees SR_PIE
+	 * being cleared.
+	 */
+	csrs CSR_STATUS, SR_IE
+#endif
 #if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING)
 	/* Recover a0 - a7 for system calls */
 	REG_L a0, PT_A0(sp)
-- 
2.28.0


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

* [PATCH v4 03/21] riscv: Enable interrupts during syscalls with M-Mode
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

When running is M-Mode (no MMU config), MPIE does not get set. This
results in all syscalls being executed with interrupts disabled as
handle_exception never sets SR_IE as it always sees SR_PIE being
cleared. Fix this by always force enabling interrupts in
handle_syscall when CONFIG_RISCV_M_MODE is enabled.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/kernel/entry.S | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 524d918f3601..080eb8d78589 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -155,6 +155,15 @@ skip_context_tracking:
 	tail do_trap_unknown
 
 handle_syscall:
+#ifdef CONFIG_RISCV_M_MODE
+	/*
+	 * When running is M-Mode (no MMU config), MPIE does not get set.
+	 * As a result, we need to force enable interrupts here because
+	 * handle_exception did not do set SR_IE as it always sees SR_PIE
+	 * being cleared.
+	 */
+	csrs CSR_STATUS, SR_IE
+#endif
 #if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING)
 	/* Recover a0 - a7 for system calls */
 	REG_L a0, PT_A0(sp)
-- 
2.28.0


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

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

* [PATCH v4 04/21] riscv: Fix builtin DTB handling
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

All SiPeed K210 MAIX boards have the exact same vendor, arch and
implementation IDs, preventing differentiation to select the correct
device tree to use through the SOC_BUILTIN_DTB_DECLARE() macro. This
result in this macro to be useless and mandates changing the code of
the sysctl driver to change the builtin device tree suitable for the
target board.

Fix this problem by removing the SOC_BUILTIN_DTB_DECLARE() macro since
it is used only for the K210 support. The code searching the builtin
DTBs using the vendor, arch an implementation IDs is also removed.
Support for builtin DTB falls back to the simpler and more traditional
handling of builtin DTB using the CONFIG_BUILTIN_DTB option, similarly
to other architectures.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/Kconfig.socs               | 19 ++++++++++----
 arch/riscv/boot/dts/kendryte/Makefile |  5 ++--
 arch/riscv/include/asm/soc.h          | 38 ---------------------------
 arch/riscv/kernel/soc.c               | 27 -------------------
 arch/riscv/mm/init.c                  |  6 +----
 drivers/soc/kendryte/k210-sysctl.c    | 12 ---------
 6 files changed, 18 insertions(+), 89 deletions(-)

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 8a55f6156661..0bc3e28581f2 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -32,9 +32,7 @@ config SOC_KENDRYTE
 	help
 	  This enables support for Kendryte K210 SoC platform hardware.
 
-config SOC_KENDRYTE_K210_DTB
-	def_bool y
-	depends on SOC_KENDRYTE_K210_DTB_BUILTIN
+if SOC_KENDRYTE
 
 config SOC_KENDRYTE_K210_DTB_BUILTIN
 	bool "Builtin device tree for the Kendryte K210"
@@ -42,10 +40,21 @@ config SOC_KENDRYTE_K210_DTB_BUILTIN
 	default y
 	select OF
 	select BUILTIN_DTB
-	select SOC_KENDRYTE_K210_DTB
 	help
-	  Builds a device tree for the Kendryte K210 into the Linux image.
+	  Build a device tree for the Kendryte K210 into the Linux image.
 	  This option should be selected if no bootloader is being used.
 	  If unsure, say Y.
 
+config SOC_KENDRYTE_K210_DTB_SOURCE
+	string "Source file for the Kendryte K210 builtin DTB"
+	depends on SOC_KENDRYTE
+	depends on SOC_KENDRYTE_K210_DTB_BUILTIN
+	default "k210"
+	help
+	  Base name (without suffix, relative to arch/riscv/boot/dts/kendryte)
+	  for the DTS file that will be used to produce the DTB linked into the
+	  kernel.
+
+endif
+
 endmenu
diff --git a/arch/riscv/boot/dts/kendryte/Makefile b/arch/riscv/boot/dts/kendryte/Makefile
index 1a88e616f18e..83636693166d 100644
--- a/arch/riscv/boot/dts/kendryte/Makefile
+++ b/arch/riscv/boot/dts/kendryte/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-dtb-$(CONFIG_SOC_KENDRYTE_K210_DTB) += k210.dtb
-
+ifneq ($(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE),"")
+dtb-y += $(strip $(shell echo $(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE))).dtb
 obj-$(CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
+endif
diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h
index 6c8363b1f327..f494066051a2 100644
--- a/arch/riscv/include/asm/soc.h
+++ b/arch/riscv/include/asm/soc.h
@@ -21,42 +21,4 @@ void soc_early_init(void);
 extern unsigned long __soc_early_init_table_start;
 extern unsigned long __soc_early_init_table_end;
 
-/*
- * Allows Linux to provide a device tree, which is necessary for SOCs that
- * don't provide a useful one on their own.
- */
-struct soc_builtin_dtb {
-	unsigned long vendor_id;
-	unsigned long arch_id;
-	unsigned long imp_id;
-	void *(*dtb_func)(void);
-};
-
-/*
- * The argument name must specify a valid DTS file name without the dts
- * extension.
- */
-#define SOC_BUILTIN_DTB_DECLARE(name, vendor, arch, impl)		\
-	extern void *__dtb_##name##_begin;				\
-									\
-	static __init __used						\
-	void *__soc_builtin_dtb_f__##name(void)				\
-	{								\
-		return (void *)&__dtb_##name##_begin;			\
-	}								\
-									\
-	static const struct soc_builtin_dtb __soc_builtin_dtb__##name	\
-		__used __section("__soc_builtin_dtb_table") =		\
-	{								\
-		.vendor_id = vendor,					\
-		.arch_id   = arch,					\
-		.imp_id    = impl,					\
-		.dtb_func  = __soc_builtin_dtb_f__##name,		\
-	}
-
-extern unsigned long __soc_builtin_dtb_table_start;
-extern unsigned long __soc_builtin_dtb_table_end;
-
-void *soc_lookup_builtin_dtb(void);
-
 #endif
diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c
index c7b0a73e382e..a0516172a33c 100644
--- a/arch/riscv/kernel/soc.c
+++ b/arch/riscv/kernel/soc.c
@@ -26,30 +26,3 @@ void __init soc_early_init(void)
 		}
 	}
 }
-
-static bool soc_builtin_dtb_match(unsigned long vendor_id,
-				unsigned long arch_id, unsigned long imp_id,
-				const struct soc_builtin_dtb *entry)
-{
-	return entry->vendor_id == vendor_id &&
-	       entry->arch_id == arch_id &&
-	       entry->imp_id == imp_id;
-}
-
-void * __init soc_lookup_builtin_dtb(void)
-{
-	unsigned long vendor_id, arch_id, imp_id;
-	const struct soc_builtin_dtb *s;
-
-	__asm__ ("csrr %0, mvendorid" : "=r"(vendor_id));
-	__asm__ ("csrr %0, marchid" : "=r"(arch_id));
-	__asm__ ("csrr %0, mimpid" : "=r"(imp_id));
-
-	for (s = (void *)&__soc_builtin_dtb_table_start;
-	     (void *)s < (void *)&__soc_builtin_dtb_table_end; s++) {
-		if (soc_builtin_dtb_match(vendor_id, arch_id, imp_id, s))
-			return s->dtb_func();
-	}
-
-	return NULL;
-}
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 8e577f14f120..c32ff32cf9ab 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -601,11 +601,7 @@ static void __init setup_vm_final(void)
 asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 {
 #ifdef CONFIG_BUILTIN_DTB
-	dtb_early_va = soc_lookup_builtin_dtb();
-	if (!dtb_early_va) {
-		/* Fallback to first available DTS */
-		dtb_early_va = (void *) __dtb_start;
-	}
+	dtb_early_va = (void *) __dtb_start;
 #else
 	dtb_early_va = (void *)dtb_pa;
 #endif
diff --git a/drivers/soc/kendryte/k210-sysctl.c b/drivers/soc/kendryte/k210-sysctl.c
index 707019223dd8..4608fbca20e1 100644
--- a/drivers/soc/kendryte/k210-sysctl.c
+++ b/drivers/soc/kendryte/k210-sysctl.c
@@ -246,15 +246,3 @@ static void __init k210_soc_early_init(const void *fdt)
 	iounmap(regs);
 }
 SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init);
-
-#ifdef CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN
-/*
- * Generic entry for the default k210.dtb embedded DTB for boards with:
- *   - Vendor ID: 0x4B5
- *   - Arch ID: 0xE59889E6A5A04149 (= "Canaan AI" in UTF-8 encoded Chinese)
- *   - Impl ID:	0x4D41495832303030 (= "MAIX2000")
- * These values are reported by the SiPEED MAXDUINO, SiPEED MAIX GO and
- * SiPEED Dan dock boards.
- */
-SOC_BUILTIN_DTB_DECLARE(k210, 0x4B5, 0xE59889E6A5A04149, 0x4D41495832303030);
-#endif
-- 
2.28.0


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

* [PATCH v4 04/21] riscv: Fix builtin DTB handling
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

All SiPeed K210 MAIX boards have the exact same vendor, arch and
implementation IDs, preventing differentiation to select the correct
device tree to use through the SOC_BUILTIN_DTB_DECLARE() macro. This
result in this macro to be useless and mandates changing the code of
the sysctl driver to change the builtin device tree suitable for the
target board.

Fix this problem by removing the SOC_BUILTIN_DTB_DECLARE() macro since
it is used only for the K210 support. The code searching the builtin
DTBs using the vendor, arch an implementation IDs is also removed.
Support for builtin DTB falls back to the simpler and more traditional
handling of builtin DTB using the CONFIG_BUILTIN_DTB option, similarly
to other architectures.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/Kconfig.socs               | 19 ++++++++++----
 arch/riscv/boot/dts/kendryte/Makefile |  5 ++--
 arch/riscv/include/asm/soc.h          | 38 ---------------------------
 arch/riscv/kernel/soc.c               | 27 -------------------
 arch/riscv/mm/init.c                  |  6 +----
 drivers/soc/kendryte/k210-sysctl.c    | 12 ---------
 6 files changed, 18 insertions(+), 89 deletions(-)

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 8a55f6156661..0bc3e28581f2 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -32,9 +32,7 @@ config SOC_KENDRYTE
 	help
 	  This enables support for Kendryte K210 SoC platform hardware.
 
-config SOC_KENDRYTE_K210_DTB
-	def_bool y
-	depends on SOC_KENDRYTE_K210_DTB_BUILTIN
+if SOC_KENDRYTE
 
 config SOC_KENDRYTE_K210_DTB_BUILTIN
 	bool "Builtin device tree for the Kendryte K210"
@@ -42,10 +40,21 @@ config SOC_KENDRYTE_K210_DTB_BUILTIN
 	default y
 	select OF
 	select BUILTIN_DTB
-	select SOC_KENDRYTE_K210_DTB
 	help
-	  Builds a device tree for the Kendryte K210 into the Linux image.
+	  Build a device tree for the Kendryte K210 into the Linux image.
 	  This option should be selected if no bootloader is being used.
 	  If unsure, say Y.
 
+config SOC_KENDRYTE_K210_DTB_SOURCE
+	string "Source file for the Kendryte K210 builtin DTB"
+	depends on SOC_KENDRYTE
+	depends on SOC_KENDRYTE_K210_DTB_BUILTIN
+	default "k210"
+	help
+	  Base name (without suffix, relative to arch/riscv/boot/dts/kendryte)
+	  for the DTS file that will be used to produce the DTB linked into the
+	  kernel.
+
+endif
+
 endmenu
diff --git a/arch/riscv/boot/dts/kendryte/Makefile b/arch/riscv/boot/dts/kendryte/Makefile
index 1a88e616f18e..83636693166d 100644
--- a/arch/riscv/boot/dts/kendryte/Makefile
+++ b/arch/riscv/boot/dts/kendryte/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-dtb-$(CONFIG_SOC_KENDRYTE_K210_DTB) += k210.dtb
-
+ifneq ($(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE),"")
+dtb-y += $(strip $(shell echo $(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE))).dtb
 obj-$(CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
+endif
diff --git a/arch/riscv/include/asm/soc.h b/arch/riscv/include/asm/soc.h
index 6c8363b1f327..f494066051a2 100644
--- a/arch/riscv/include/asm/soc.h
+++ b/arch/riscv/include/asm/soc.h
@@ -21,42 +21,4 @@ void soc_early_init(void);
 extern unsigned long __soc_early_init_table_start;
 extern unsigned long __soc_early_init_table_end;
 
-/*
- * Allows Linux to provide a device tree, which is necessary for SOCs that
- * don't provide a useful one on their own.
- */
-struct soc_builtin_dtb {
-	unsigned long vendor_id;
-	unsigned long arch_id;
-	unsigned long imp_id;
-	void *(*dtb_func)(void);
-};
-
-/*
- * The argument name must specify a valid DTS file name without the dts
- * extension.
- */
-#define SOC_BUILTIN_DTB_DECLARE(name, vendor, arch, impl)		\
-	extern void *__dtb_##name##_begin;				\
-									\
-	static __init __used						\
-	void *__soc_builtin_dtb_f__##name(void)				\
-	{								\
-		return (void *)&__dtb_##name##_begin;			\
-	}								\
-									\
-	static const struct soc_builtin_dtb __soc_builtin_dtb__##name	\
-		__used __section("__soc_builtin_dtb_table") =		\
-	{								\
-		.vendor_id = vendor,					\
-		.arch_id   = arch,					\
-		.imp_id    = impl,					\
-		.dtb_func  = __soc_builtin_dtb_f__##name,		\
-	}
-
-extern unsigned long __soc_builtin_dtb_table_start;
-extern unsigned long __soc_builtin_dtb_table_end;
-
-void *soc_lookup_builtin_dtb(void);
-
 #endif
diff --git a/arch/riscv/kernel/soc.c b/arch/riscv/kernel/soc.c
index c7b0a73e382e..a0516172a33c 100644
--- a/arch/riscv/kernel/soc.c
+++ b/arch/riscv/kernel/soc.c
@@ -26,30 +26,3 @@ void __init soc_early_init(void)
 		}
 	}
 }
-
-static bool soc_builtin_dtb_match(unsigned long vendor_id,
-				unsigned long arch_id, unsigned long imp_id,
-				const struct soc_builtin_dtb *entry)
-{
-	return entry->vendor_id == vendor_id &&
-	       entry->arch_id == arch_id &&
-	       entry->imp_id == imp_id;
-}
-
-void * __init soc_lookup_builtin_dtb(void)
-{
-	unsigned long vendor_id, arch_id, imp_id;
-	const struct soc_builtin_dtb *s;
-
-	__asm__ ("csrr %0, mvendorid" : "=r"(vendor_id));
-	__asm__ ("csrr %0, marchid" : "=r"(arch_id));
-	__asm__ ("csrr %0, mimpid" : "=r"(imp_id));
-
-	for (s = (void *)&__soc_builtin_dtb_table_start;
-	     (void *)s < (void *)&__soc_builtin_dtb_table_end; s++) {
-		if (soc_builtin_dtb_match(vendor_id, arch_id, imp_id, s))
-			return s->dtb_func();
-	}
-
-	return NULL;
-}
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 8e577f14f120..c32ff32cf9ab 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -601,11 +601,7 @@ static void __init setup_vm_final(void)
 asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 {
 #ifdef CONFIG_BUILTIN_DTB
-	dtb_early_va = soc_lookup_builtin_dtb();
-	if (!dtb_early_va) {
-		/* Fallback to first available DTS */
-		dtb_early_va = (void *) __dtb_start;
-	}
+	dtb_early_va = (void *) __dtb_start;
 #else
 	dtb_early_va = (void *)dtb_pa;
 #endif
diff --git a/drivers/soc/kendryte/k210-sysctl.c b/drivers/soc/kendryte/k210-sysctl.c
index 707019223dd8..4608fbca20e1 100644
--- a/drivers/soc/kendryte/k210-sysctl.c
+++ b/drivers/soc/kendryte/k210-sysctl.c
@@ -246,15 +246,3 @@ static void __init k210_soc_early_init(const void *fdt)
 	iounmap(regs);
 }
 SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init);
-
-#ifdef CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN
-/*
- * Generic entry for the default k210.dtb embedded DTB for boards with:
- *   - Vendor ID: 0x4B5
- *   - Arch ID: 0xE59889E6A5A04149 (= "Canaan AI" in UTF-8 encoded Chinese)
- *   - Impl ID:	0x4D41495832303030 (= "MAIX2000")
- * These values are reported by the SiPEED MAXDUINO, SiPEED MAIX GO and
- * SiPEED Dan dock boards.
- */
-SOC_BUILTIN_DTB_DECLARE(k210, 0x4B5, 0xE59889E6A5A04149, 0x4D41495832303030);
-#endif
-- 
2.28.0


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

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

* [PATCH v4 05/21] riscv: Use vendor name for K210 SoC support
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Rename configuration options and directories related to the Kendryte
K210 SoC to use the SoC vendor name (canaan) instead of the "kendryte"
branding name.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/Kconfig.socs                       | 24 +++++++++----------
 arch/riscv/Makefile                           |  2 +-
 arch/riscv/boot/dts/Makefile                  |  2 +-
 arch/riscv/boot/dts/canaan/Makefile           |  5 ++++
 .../boot/dts/{kendryte => canaan}/k210.dts    |  0
 .../boot/dts/{kendryte => canaan}/k210.dtsi   |  0
 arch/riscv/boot/dts/kendryte/Makefile         |  5 ----
 arch/riscv/configs/nommu_k210_defconfig       |  2 +-
 drivers/soc/Kconfig                           |  2 +-
 drivers/soc/Makefile                          |  2 +-
 drivers/soc/{kendryte => canaan}/Kconfig      |  4 ++--
 drivers/soc/{kendryte => canaan}/Makefile     |  0
 .../soc/{kendryte => canaan}/k210-sysctl.c    |  0
 13 files changed, 24 insertions(+), 24 deletions(-)
 create mode 100644 arch/riscv/boot/dts/canaan/Makefile
 rename arch/riscv/boot/dts/{kendryte => canaan}/k210.dts (100%)
 rename arch/riscv/boot/dts/{kendryte => canaan}/k210.dtsi (100%)
 delete mode 100644 arch/riscv/boot/dts/kendryte/Makefile
 rename drivers/soc/{kendryte => canaan}/Kconfig (79%)
 rename drivers/soc/{kendryte => canaan}/Makefile (100%)
 rename drivers/soc/{kendryte => canaan}/k210-sysctl.c (100%)

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 0bc3e28581f2..88ac0d1a5da4 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -22,21 +22,21 @@ config SOC_VIRT
 	help
 	  This enables support for QEMU Virt Machine.
 
-config SOC_KENDRYTE
-	bool "Kendryte K210 SoC"
+config SOC_CANAAN
+	bool "Canaan Kendryte K210 SoC"
 	depends on !MMU
 	select CLINT_TIMER if RISCV_M_MODE
 	select SERIAL_SIFIVE if TTY
 	select SERIAL_SIFIVE_CONSOLE if TTY
 	select SIFIVE_PLIC
 	help
-	  This enables support for Kendryte K210 SoC platform hardware.
+	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
-if SOC_KENDRYTE
+if SOC_CANAAN
 
-config SOC_KENDRYTE_K210_DTB_BUILTIN
-	bool "Builtin device tree for the Kendryte K210"
-	depends on SOC_KENDRYTE
+config SOC_CANAAN_K210_DTB_BUILTIN
+	bool "Builtin device tree for the Canaan Kendryte K210"
+	depends on SOC_CANAAN
 	default y
 	select OF
 	select BUILTIN_DTB
@@ -45,13 +45,13 @@ config SOC_KENDRYTE_K210_DTB_BUILTIN
 	  This option should be selected if no bootloader is being used.
 	  If unsure, say Y.
 
-config SOC_KENDRYTE_K210_DTB_SOURCE
-	string "Source file for the Kendryte K210 builtin DTB"
-	depends on SOC_KENDRYTE
-	depends on SOC_KENDRYTE_K210_DTB_BUILTIN
+config SOC_CANAAN_K210_DTB_SOURCE
+	string "Source file for the Canaan Kendryte K210 builtin DTB"
+	depends on SOC_CANAAN
+	depends on SOC_CANAAN_K210_DTB_BUILTIN
 	default "k210"
 	help
-	  Base name (without suffix, relative to arch/riscv/boot/dts/kendryte)
+	  Base name (without suffix, relative to arch/riscv/boot/dts/canaan)
 	  for the DTS file that will be used to produce the DTB linked into the
 	  kernel.
 
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 0289a97325d1..cd08dc40e8d8 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -83,7 +83,7 @@ PHONY += vdso_install
 vdso_install:
 	$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
 
-ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_KENDRYTE),yy)
+ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_CANAAN),yy)
 KBUILD_IMAGE := $(boot)/loader.bin
 else
 KBUILD_IMAGE := $(boot)/Image.gz
diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile
index ca1f8cbd78c0..7b164f287a74 100644
--- a/arch/riscv/boot/dts/Makefile
+++ b/arch/riscv/boot/dts/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 subdir-y += sifive
-subdir-y += kendryte
+subdir-y += canaan
 
 obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
diff --git a/arch/riscv/boot/dts/canaan/Makefile b/arch/riscv/boot/dts/canaan/Makefile
new file mode 100644
index 000000000000..9ee7156c0c31
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+ifneq ($(CONFIG_SOC_CANAAN_K210_DTB_SOURCE),"")
+dtb-y += $(strip $(shell echo $(CONFIG_SOC_CANAAN_K210_DTB_SOURCE))).dtb
+obj-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
+endif
diff --git a/arch/riscv/boot/dts/kendryte/k210.dts b/arch/riscv/boot/dts/canaan/k210.dts
similarity index 100%
rename from arch/riscv/boot/dts/kendryte/k210.dts
rename to arch/riscv/boot/dts/canaan/k210.dts
diff --git a/arch/riscv/boot/dts/kendryte/k210.dtsi b/arch/riscv/boot/dts/canaan/k210.dtsi
similarity index 100%
rename from arch/riscv/boot/dts/kendryte/k210.dtsi
rename to arch/riscv/boot/dts/canaan/k210.dtsi
diff --git a/arch/riscv/boot/dts/kendryte/Makefile b/arch/riscv/boot/dts/kendryte/Makefile
deleted file mode 100644
index 83636693166d..000000000000
--- a/arch/riscv/boot/dts/kendryte/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-ifneq ($(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE),"")
-dtb-y += $(strip $(shell echo $(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE))).dtb
-obj-$(CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
-endif
diff --git a/arch/riscv/configs/nommu_k210_defconfig b/arch/riscv/configs/nommu_k210_defconfig
index cd1df62b13c7..368a28cf1467 100644
--- a/arch/riscv/configs/nommu_k210_defconfig
+++ b/arch/riscv/configs/nommu_k210_defconfig
@@ -27,7 +27,7 @@ CONFIG_EMBEDDED=y
 CONFIG_SLOB=y
 # CONFIG_SLAB_MERGE_DEFAULT is not set
 # CONFIG_MMU is not set
-CONFIG_SOC_KENDRYTE=y
+CONFIG_SOC_CANAAN=y
 CONFIG_MAXPHYSMEM_2GB=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 425ab6f7e375..f43886fec32b 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -6,6 +6,7 @@ source "drivers/soc/amlogic/Kconfig"
 source "drivers/soc/aspeed/Kconfig"
 source "drivers/soc/atmel/Kconfig"
 source "drivers/soc/bcm/Kconfig"
+source "drivers/soc/canaan/Kconfig"
 source "drivers/soc/fsl/Kconfig"
 source "drivers/soc/imx/Kconfig"
 source "drivers/soc/ixp4xx/Kconfig"
@@ -22,6 +23,5 @@ source "drivers/soc/ux500/Kconfig"
 source "drivers/soc/versatile/Kconfig"
 source "drivers/soc/xilinx/Kconfig"
 source "drivers/soc/zte/Kconfig"
-source "drivers/soc/kendryte/Kconfig"
 
 endmenu
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 36452bed86ef..dec90fca120b 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -28,4 +28,4 @@ obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_PLAT_VERSATILE)	+= versatile/
 obj-y				+= xilinx/
 obj-$(CONFIG_ARCH_ZX)		+= zte/
-obj-$(CONFIG_SOC_KENDRYTE)	+= kendryte/
+obj-$(CONFIG_SOC_CANAAN)	+= canaan/
diff --git a/drivers/soc/kendryte/Kconfig b/drivers/soc/canaan/Kconfig
similarity index 79%
rename from drivers/soc/kendryte/Kconfig
rename to drivers/soc/canaan/Kconfig
index 49785b1b0217..5232d13f07e5 100644
--- a/drivers/soc/kendryte/Kconfig
+++ b/drivers/soc/canaan/Kconfig
@@ -1,9 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
 
-if SOC_KENDRYTE
+if SOC_CANAAN
 
 config K210_SYSCTL
-	bool "Kendryte K210 system controller"
+	bool "Canaan Kendryte K210 SoC system controller"
 	default y
 	depends on RISCV
 	help
diff --git a/drivers/soc/kendryte/Makefile b/drivers/soc/canaan/Makefile
similarity index 100%
rename from drivers/soc/kendryte/Makefile
rename to drivers/soc/canaan/Makefile
diff --git a/drivers/soc/kendryte/k210-sysctl.c b/drivers/soc/canaan/k210-sysctl.c
similarity index 100%
rename from drivers/soc/kendryte/k210-sysctl.c
rename to drivers/soc/canaan/k210-sysctl.c
-- 
2.28.0


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

* [PATCH v4 05/21] riscv: Use vendor name for K210 SoC support
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Rename configuration options and directories related to the Kendryte
K210 SoC to use the SoC vendor name (canaan) instead of the "kendryte"
branding name.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/Kconfig.socs                       | 24 +++++++++----------
 arch/riscv/Makefile                           |  2 +-
 arch/riscv/boot/dts/Makefile                  |  2 +-
 arch/riscv/boot/dts/canaan/Makefile           |  5 ++++
 .../boot/dts/{kendryte => canaan}/k210.dts    |  0
 .../boot/dts/{kendryte => canaan}/k210.dtsi   |  0
 arch/riscv/boot/dts/kendryte/Makefile         |  5 ----
 arch/riscv/configs/nommu_k210_defconfig       |  2 +-
 drivers/soc/Kconfig                           |  2 +-
 drivers/soc/Makefile                          |  2 +-
 drivers/soc/{kendryte => canaan}/Kconfig      |  4 ++--
 drivers/soc/{kendryte => canaan}/Makefile     |  0
 .../soc/{kendryte => canaan}/k210-sysctl.c    |  0
 13 files changed, 24 insertions(+), 24 deletions(-)
 create mode 100644 arch/riscv/boot/dts/canaan/Makefile
 rename arch/riscv/boot/dts/{kendryte => canaan}/k210.dts (100%)
 rename arch/riscv/boot/dts/{kendryte => canaan}/k210.dtsi (100%)
 delete mode 100644 arch/riscv/boot/dts/kendryte/Makefile
 rename drivers/soc/{kendryte => canaan}/Kconfig (79%)
 rename drivers/soc/{kendryte => canaan}/Makefile (100%)
 rename drivers/soc/{kendryte => canaan}/k210-sysctl.c (100%)

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 0bc3e28581f2..88ac0d1a5da4 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -22,21 +22,21 @@ config SOC_VIRT
 	help
 	  This enables support for QEMU Virt Machine.
 
-config SOC_KENDRYTE
-	bool "Kendryte K210 SoC"
+config SOC_CANAAN
+	bool "Canaan Kendryte K210 SoC"
 	depends on !MMU
 	select CLINT_TIMER if RISCV_M_MODE
 	select SERIAL_SIFIVE if TTY
 	select SERIAL_SIFIVE_CONSOLE if TTY
 	select SIFIVE_PLIC
 	help
-	  This enables support for Kendryte K210 SoC platform hardware.
+	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
-if SOC_KENDRYTE
+if SOC_CANAAN
 
-config SOC_KENDRYTE_K210_DTB_BUILTIN
-	bool "Builtin device tree for the Kendryte K210"
-	depends on SOC_KENDRYTE
+config SOC_CANAAN_K210_DTB_BUILTIN
+	bool "Builtin device tree for the Canaan Kendryte K210"
+	depends on SOC_CANAAN
 	default y
 	select OF
 	select BUILTIN_DTB
@@ -45,13 +45,13 @@ config SOC_KENDRYTE_K210_DTB_BUILTIN
 	  This option should be selected if no bootloader is being used.
 	  If unsure, say Y.
 
-config SOC_KENDRYTE_K210_DTB_SOURCE
-	string "Source file for the Kendryte K210 builtin DTB"
-	depends on SOC_KENDRYTE
-	depends on SOC_KENDRYTE_K210_DTB_BUILTIN
+config SOC_CANAAN_K210_DTB_SOURCE
+	string "Source file for the Canaan Kendryte K210 builtin DTB"
+	depends on SOC_CANAAN
+	depends on SOC_CANAAN_K210_DTB_BUILTIN
 	default "k210"
 	help
-	  Base name (without suffix, relative to arch/riscv/boot/dts/kendryte)
+	  Base name (without suffix, relative to arch/riscv/boot/dts/canaan)
 	  for the DTS file that will be used to produce the DTB linked into the
 	  kernel.
 
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 0289a97325d1..cd08dc40e8d8 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -83,7 +83,7 @@ PHONY += vdso_install
 vdso_install:
 	$(Q)$(MAKE) $(build)=arch/riscv/kernel/vdso $@
 
-ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_KENDRYTE),yy)
+ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_SOC_CANAAN),yy)
 KBUILD_IMAGE := $(boot)/loader.bin
 else
 KBUILD_IMAGE := $(boot)/Image.gz
diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile
index ca1f8cbd78c0..7b164f287a74 100644
--- a/arch/riscv/boot/dts/Makefile
+++ b/arch/riscv/boot/dts/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 subdir-y += sifive
-subdir-y += kendryte
+subdir-y += canaan
 
 obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
diff --git a/arch/riscv/boot/dts/canaan/Makefile b/arch/riscv/boot/dts/canaan/Makefile
new file mode 100644
index 000000000000..9ee7156c0c31
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+ifneq ($(CONFIG_SOC_CANAAN_K210_DTB_SOURCE),"")
+dtb-y += $(strip $(shell echo $(CONFIG_SOC_CANAAN_K210_DTB_SOURCE))).dtb
+obj-$(CONFIG_SOC_CANAAN_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
+endif
diff --git a/arch/riscv/boot/dts/kendryte/k210.dts b/arch/riscv/boot/dts/canaan/k210.dts
similarity index 100%
rename from arch/riscv/boot/dts/kendryte/k210.dts
rename to arch/riscv/boot/dts/canaan/k210.dts
diff --git a/arch/riscv/boot/dts/kendryte/k210.dtsi b/arch/riscv/boot/dts/canaan/k210.dtsi
similarity index 100%
rename from arch/riscv/boot/dts/kendryte/k210.dtsi
rename to arch/riscv/boot/dts/canaan/k210.dtsi
diff --git a/arch/riscv/boot/dts/kendryte/Makefile b/arch/riscv/boot/dts/kendryte/Makefile
deleted file mode 100644
index 83636693166d..000000000000
--- a/arch/riscv/boot/dts/kendryte/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-ifneq ($(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE),"")
-dtb-y += $(strip $(shell echo $(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE))).dtb
-obj-$(CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
-endif
diff --git a/arch/riscv/configs/nommu_k210_defconfig b/arch/riscv/configs/nommu_k210_defconfig
index cd1df62b13c7..368a28cf1467 100644
--- a/arch/riscv/configs/nommu_k210_defconfig
+++ b/arch/riscv/configs/nommu_k210_defconfig
@@ -27,7 +27,7 @@ CONFIG_EMBEDDED=y
 CONFIG_SLOB=y
 # CONFIG_SLAB_MERGE_DEFAULT is not set
 # CONFIG_MMU is not set
-CONFIG_SOC_KENDRYTE=y
+CONFIG_SOC_CANAAN=y
 CONFIG_MAXPHYSMEM_2GB=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 425ab6f7e375..f43886fec32b 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -6,6 +6,7 @@ source "drivers/soc/amlogic/Kconfig"
 source "drivers/soc/aspeed/Kconfig"
 source "drivers/soc/atmel/Kconfig"
 source "drivers/soc/bcm/Kconfig"
+source "drivers/soc/canaan/Kconfig"
 source "drivers/soc/fsl/Kconfig"
 source "drivers/soc/imx/Kconfig"
 source "drivers/soc/ixp4xx/Kconfig"
@@ -22,6 +23,5 @@ source "drivers/soc/ux500/Kconfig"
 source "drivers/soc/versatile/Kconfig"
 source "drivers/soc/xilinx/Kconfig"
 source "drivers/soc/zte/Kconfig"
-source "drivers/soc/kendryte/Kconfig"
 
 endmenu
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 36452bed86ef..dec90fca120b 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -28,4 +28,4 @@ obj-$(CONFIG_ARCH_U8500)	+= ux500/
 obj-$(CONFIG_PLAT_VERSATILE)	+= versatile/
 obj-y				+= xilinx/
 obj-$(CONFIG_ARCH_ZX)		+= zte/
-obj-$(CONFIG_SOC_KENDRYTE)	+= kendryte/
+obj-$(CONFIG_SOC_CANAAN)	+= canaan/
diff --git a/drivers/soc/kendryte/Kconfig b/drivers/soc/canaan/Kconfig
similarity index 79%
rename from drivers/soc/kendryte/Kconfig
rename to drivers/soc/canaan/Kconfig
index 49785b1b0217..5232d13f07e5 100644
--- a/drivers/soc/kendryte/Kconfig
+++ b/drivers/soc/canaan/Kconfig
@@ -1,9 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
 
-if SOC_KENDRYTE
+if SOC_CANAAN
 
 config K210_SYSCTL
-	bool "Kendryte K210 system controller"
+	bool "Canaan Kendryte K210 SoC system controller"
 	default y
 	depends on RISCV
 	help
diff --git a/drivers/soc/kendryte/Makefile b/drivers/soc/canaan/Makefile
similarity index 100%
rename from drivers/soc/kendryte/Makefile
rename to drivers/soc/canaan/Makefile
diff --git a/drivers/soc/kendryte/k210-sysctl.c b/drivers/soc/canaan/k210-sysctl.c
similarity index 100%
rename from drivers/soc/kendryte/k210-sysctl.c
rename to drivers/soc/canaan/k210-sysctl.c
-- 
2.28.0


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

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

* [PATCH v4 06/21] dt-bindings: Add Canaan vendor prefix
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Update Documentation/devicetree/bindings/vendor-prefixes.yaml to
include "canaan" as a vendor prefix for "Canaan Inc.". Canaan is the
vendor of the Kendryte K210 RISC-V SoC.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 2735be1a8470..a07231aaf3e7 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -179,6 +179,8 @@ patternProperties:
     description: CALAO Systems SAS
   "^calxeda,.*":
     description: Calxeda
+  "^canaan,.*":
+    description: Canaan, Inc.
   "^caninos,.*":
     description: Caninos Loucos Program
   "^capella,.*":
-- 
2.28.0


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

* [PATCH v4 06/21] dt-bindings: Add Canaan vendor prefix
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Update Documentation/devicetree/bindings/vendor-prefixes.yaml to
include "canaan" as a vendor prefix for "Canaan Inc.". Canaan is the
vendor of the Kendryte K210 RISC-V SoC.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 2735be1a8470..a07231aaf3e7 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -179,6 +179,8 @@ patternProperties:
     description: CALAO Systems SAS
   "^calxeda,.*":
     description: Calxeda
+  "^canaan,.*":
+    description: Canaan, Inc.
   "^caninos,.*":
     description: Caninos Loucos Program
   "^capella,.*":
-- 
2.28.0


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

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

* [PATCH v4 07/21] dt-binding: clock: Document canaan,k210-clk bindings
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Document the device tree bindings of the Canaan Kendryte K210 SoC clock
driver in Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml.
The header file include/dt-bindings/clock/k210-clk.h is modified to
include the complete list of IDs for all clocks of the SoC.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../bindings/clock/canaan,k210-clk.yaml       | 55 +++++++++++++++++
 include/dt-bindings/clock/k210-clk.h          | 61 +++++++++++++++----
 2 files changed, 105 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml

diff --git a/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
new file mode 100644
index 000000000000..3547916a2421
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/canaan,k210-clk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K210 Clock Device Tree Bindings
+
+maintainers:
+  - Damien Le Moal <damien.lemoal@wdc.com>
+
+description: |
+  Canaan Kendryte K210 SoC clocks driver bindings. The clock
+  controller node must be defined as a child node of the K210
+  system controller node.
+
+  See also:
+  - dt-bindings/clock/k210-clk.h
+
+properties:
+  compatible:
+    const: canaan,k210-clk
+
+  clocks:
+    maxItems: 1
+    description:
+      System fixed rate oscillator clock.
+
+  '#clock-cells':
+    const: 1
+
+required:
+  - compatible
+  - '#clock-cells'
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/k210-clk.h>
+    clocks {
+      in0: oscillator {
+        compatible = "fixed-clock";
+        #clock-cells = <0>;
+        clock-frequency = <26000000>;
+      };
+    };
+
+    /* ... */
+    sysclk: clock-controller {
+      #clock-cells = <1>;
+      compatible = "canaan,k210-clk";
+      clocks = <&in0>;
+    };
diff --git a/include/dt-bindings/clock/k210-clk.h b/include/dt-bindings/clock/k210-clk.h
index 5a2fd64d1a49..8d7ab2f0737c 100644
--- a/include/dt-bindings/clock/k210-clk.h
+++ b/include/dt-bindings/clock/k210-clk.h
@@ -3,18 +3,57 @@
  * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
  */
-#ifndef K210_CLK_H
-#define K210_CLK_H
+#ifndef CLOCK_K210_CLK_H
+#define CLOCK_K210_CLK_H
 
 /*
- * Arbitrary identifiers for clocks.
- * The structure is: in0 -> pll0 -> aclk -> cpu
- *
- * Since we use the hardware defaults for now, set all these to the same clock.
+ * Kendryte K210 SoC clock identifiers (arbitrary values).
  */
-#define K210_CLK_PLL0   0
-#define K210_CLK_PLL1   0
-#define K210_CLK_ACLK   0
-#define K210_CLK_CPU    0
+#define K210_CLK_IN0	0
+#define K210_CLK_PLL0	1
+#define K210_CLK_PLL1	2
+#define K210_CLK_PLL2	3
+#define K210_CLK_ACLK	4
+#define K210_CLK_CPU	5
+#define K210_CLK_CLINT	6
+#define K210_CLK_DMA	7
+#define K210_CLK_FFT	8
+#define K210_CLK_SRAM0	9
+#define K210_CLK_SRAM1	10
+#define K210_CLK_ROM	11
+#define K210_CLK_DVP	12
+#define K210_CLK_APB0	13
+#define K210_CLK_APB1	14
+#define K210_CLK_APB2	15
+#define K210_CLK_AI	16
+#define K210_CLK_I2S0	17
+#define K210_CLK_I2S1	18
+#define K210_CLK_I2S2	19
+#define K210_CLK_I2S0_M	20
+#define K210_CLK_I2S1_M	21
+#define K210_CLK_I2S2_M	22
+#define K210_CLK_WDT0	23
+#define K210_CLK_WDT1	24
+#define K210_CLK_SPI0	25
+#define K210_CLK_SPI1	26
+#define K210_CLK_SPI2	27
+#define K210_CLK_I2C0	28
+#define K210_CLK_I2C1	29
+#define K210_CLK_I2C2	30
+#define K210_CLK_SPI3	31
+#define K210_CLK_TIMER0	32
+#define K210_CLK_TIMER1	33
+#define K210_CLK_TIMER2	34
+#define K210_CLK_GPIO	35
+#define K210_CLK_UART1	36
+#define K210_CLK_UART2	37
+#define K210_CLK_UART3	38
+#define K210_CLK_FPIOA	39
+#define K210_CLK_SHA	40
+#define K210_CLK_AES	41
+#define K210_CLK_OTP	42
+#define K210_CLK_RTC	43
 
-#endif /* K210_CLK_H */
+#define K210_NUM_CLKS	44
+
+#endif /* CLOCK_K210_CLK_H */
-- 
2.28.0


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

* [PATCH v4 07/21] dt-binding: clock: Document canaan, k210-clk bindings
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Document the device tree bindings of the Canaan Kendryte K210 SoC clock
driver in Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml.
The header file include/dt-bindings/clock/k210-clk.h is modified to
include the complete list of IDs for all clocks of the SoC.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../bindings/clock/canaan,k210-clk.yaml       | 55 +++++++++++++++++
 include/dt-bindings/clock/k210-clk.h          | 61 +++++++++++++++----
 2 files changed, 105 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml

diff --git a/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
new file mode 100644
index 000000000000..3547916a2421
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/canaan,k210-clk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K210 Clock Device Tree Bindings
+
+maintainers:
+  - Damien Le Moal <damien.lemoal@wdc.com>
+
+description: |
+  Canaan Kendryte K210 SoC clocks driver bindings. The clock
+  controller node must be defined as a child node of the K210
+  system controller node.
+
+  See also:
+  - dt-bindings/clock/k210-clk.h
+
+properties:
+  compatible:
+    const: canaan,k210-clk
+
+  clocks:
+    maxItems: 1
+    description:
+      System fixed rate oscillator clock.
+
+  '#clock-cells':
+    const: 1
+
+required:
+  - compatible
+  - '#clock-cells'
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/k210-clk.h>
+    clocks {
+      in0: oscillator {
+        compatible = "fixed-clock";
+        #clock-cells = <0>;
+        clock-frequency = <26000000>;
+      };
+    };
+
+    /* ... */
+    sysclk: clock-controller {
+      #clock-cells = <1>;
+      compatible = "canaan,k210-clk";
+      clocks = <&in0>;
+    };
diff --git a/include/dt-bindings/clock/k210-clk.h b/include/dt-bindings/clock/k210-clk.h
index 5a2fd64d1a49..8d7ab2f0737c 100644
--- a/include/dt-bindings/clock/k210-clk.h
+++ b/include/dt-bindings/clock/k210-clk.h
@@ -3,18 +3,57 @@
  * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
  */
-#ifndef K210_CLK_H
-#define K210_CLK_H
+#ifndef CLOCK_K210_CLK_H
+#define CLOCK_K210_CLK_H
 
 /*
- * Arbitrary identifiers for clocks.
- * The structure is: in0 -> pll0 -> aclk -> cpu
- *
- * Since we use the hardware defaults for now, set all these to the same clock.
+ * Kendryte K210 SoC clock identifiers (arbitrary values).
  */
-#define K210_CLK_PLL0   0
-#define K210_CLK_PLL1   0
-#define K210_CLK_ACLK   0
-#define K210_CLK_CPU    0
+#define K210_CLK_IN0	0
+#define K210_CLK_PLL0	1
+#define K210_CLK_PLL1	2
+#define K210_CLK_PLL2	3
+#define K210_CLK_ACLK	4
+#define K210_CLK_CPU	5
+#define K210_CLK_CLINT	6
+#define K210_CLK_DMA	7
+#define K210_CLK_FFT	8
+#define K210_CLK_SRAM0	9
+#define K210_CLK_SRAM1	10
+#define K210_CLK_ROM	11
+#define K210_CLK_DVP	12
+#define K210_CLK_APB0	13
+#define K210_CLK_APB1	14
+#define K210_CLK_APB2	15
+#define K210_CLK_AI	16
+#define K210_CLK_I2S0	17
+#define K210_CLK_I2S1	18
+#define K210_CLK_I2S2	19
+#define K210_CLK_I2S0_M	20
+#define K210_CLK_I2S1_M	21
+#define K210_CLK_I2S2_M	22
+#define K210_CLK_WDT0	23
+#define K210_CLK_WDT1	24
+#define K210_CLK_SPI0	25
+#define K210_CLK_SPI1	26
+#define K210_CLK_SPI2	27
+#define K210_CLK_I2C0	28
+#define K210_CLK_I2C1	29
+#define K210_CLK_I2C2	30
+#define K210_CLK_SPI3	31
+#define K210_CLK_TIMER0	32
+#define K210_CLK_TIMER1	33
+#define K210_CLK_TIMER2	34
+#define K210_CLK_GPIO	35
+#define K210_CLK_UART1	36
+#define K210_CLK_UART2	37
+#define K210_CLK_UART3	38
+#define K210_CLK_FPIOA	39
+#define K210_CLK_SHA	40
+#define K210_CLK_AES	41
+#define K210_CLK_OTP	42
+#define K210_CLK_RTC	43
 
-#endif /* K210_CLK_H */
+#define K210_NUM_CLKS	44
+
+#endif /* CLOCK_K210_CLK_H */
-- 
2.28.0


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

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

* [PATCH v4 08/21] dt-bindings: reset: Document canaan,k210-rst bindings
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Document the device tree bindings for the Canaan Kendryte K210 SoC
reset controller driver in
Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml. The header
file include/dt-bindings/reset/k210-rst.h is added to define all
possible reset lines of the SoC.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../bindings/reset/canaan,k210-rst.yaml       | 40 ++++++++++++++++++
 include/dt-bindings/reset/k210-rst.h          | 42 +++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
 create mode 100644 include/dt-bindings/reset/k210-rst.h

diff --git a/Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml b/Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
new file mode 100644
index 000000000000..53e4ede9c0bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reset/canaan,k210-rst.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K210 Reset Controller Device Tree Bindings
+
+maintainers:
+  - Damien Le Moal <damien.lemoal@wdc.com>
+
+description: |
+  Canaan Kendryte K210 reset controller driver which supports the SoC
+  system controller supplied reset registers for the various peripherals
+  of the SoC. The K210 reset controller node must be defined as a child
+  node of the K210 system controller node.
+
+  See also:
+  - dt-bindings/reset/k210-rst.h
+
+properties:
+  compatible:
+    const: canaan,k210-rst
+
+  '#reset-cells':
+    const: 1
+
+required:
+  - '#reset-cells'
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/reset/k210-rst.h>
+    sysrst: reset-controller {
+      compatible = "canaan,k210-rst";
+      #reset-cells = <1>;
+    };
diff --git a/include/dt-bindings/reset/k210-rst.h b/include/dt-bindings/reset/k210-rst.h
new file mode 100644
index 000000000000..883c1aed50e8
--- /dev/null
+++ b/include/dt-bindings/reset/k210-rst.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#ifndef RESET_K210_SYSCTL_H
+#define RESET_K210_SYSCTL_H
+
+/*
+ * Kendryte K210 SoC system controller K210_SYSCTL_SOFT_RESET register bits.
+ * Taken from Kendryte SDK (kendryte-standalone-sdk).
+ */
+#define K210_RST_ROM	0
+#define K210_RST_DMA	1
+#define K210_RST_AI	2
+#define K210_RST_DVP	3
+#define K210_RST_FFT	4
+#define K210_RST_GPIO	5
+#define K210_RST_SPI0	6
+#define K210_RST_SPI1	7
+#define K210_RST_SPI2	8
+#define K210_RST_SPI3	9
+#define K210_RST_I2S0	10
+#define K210_RST_I2S1	11
+#define K210_RST_I2S2	12
+#define K210_RST_I2C0	13
+#define K210_RST_I2C1	14
+#define K210_RST_I2C2	15
+#define K210_RST_UART1	16
+#define K210_RST_UART2	17
+#define K210_RST_UART3	18
+#define K210_RST_AES	19
+#define K210_RST_FPIOA	20
+#define K210_RST_TIMER0	21
+#define K210_RST_TIMER1	22
+#define K210_RST_TIMER2	23
+#define K210_RST_WDT0	24
+#define K210_RST_WDT1	25
+#define K210_RST_SHA	26
+#define K210_RST_RTC	29
+
+#endif /* RESET_K210_SYSCTL_H */
-- 
2.28.0


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

* [PATCH v4 08/21] dt-bindings: reset: Document canaan, k210-rst bindings
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Document the device tree bindings for the Canaan Kendryte K210 SoC
reset controller driver in
Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml. The header
file include/dt-bindings/reset/k210-rst.h is added to define all
possible reset lines of the SoC.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../bindings/reset/canaan,k210-rst.yaml       | 40 ++++++++++++++++++
 include/dt-bindings/reset/k210-rst.h          | 42 +++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
 create mode 100644 include/dt-bindings/reset/k210-rst.h

diff --git a/Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml b/Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
new file mode 100644
index 000000000000..53e4ede9c0bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reset/canaan,k210-rst.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K210 Reset Controller Device Tree Bindings
+
+maintainers:
+  - Damien Le Moal <damien.lemoal@wdc.com>
+
+description: |
+  Canaan Kendryte K210 reset controller driver which supports the SoC
+  system controller supplied reset registers for the various peripherals
+  of the SoC. The K210 reset controller node must be defined as a child
+  node of the K210 system controller node.
+
+  See also:
+  - dt-bindings/reset/k210-rst.h
+
+properties:
+  compatible:
+    const: canaan,k210-rst
+
+  '#reset-cells':
+    const: 1
+
+required:
+  - '#reset-cells'
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/reset/k210-rst.h>
+    sysrst: reset-controller {
+      compatible = "canaan,k210-rst";
+      #reset-cells = <1>;
+    };
diff --git a/include/dt-bindings/reset/k210-rst.h b/include/dt-bindings/reset/k210-rst.h
new file mode 100644
index 000000000000..883c1aed50e8
--- /dev/null
+++ b/include/dt-bindings/reset/k210-rst.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#ifndef RESET_K210_SYSCTL_H
+#define RESET_K210_SYSCTL_H
+
+/*
+ * Kendryte K210 SoC system controller K210_SYSCTL_SOFT_RESET register bits.
+ * Taken from Kendryte SDK (kendryte-standalone-sdk).
+ */
+#define K210_RST_ROM	0
+#define K210_RST_DMA	1
+#define K210_RST_AI	2
+#define K210_RST_DVP	3
+#define K210_RST_FFT	4
+#define K210_RST_GPIO	5
+#define K210_RST_SPI0	6
+#define K210_RST_SPI1	7
+#define K210_RST_SPI2	8
+#define K210_RST_SPI3	9
+#define K210_RST_I2S0	10
+#define K210_RST_I2S1	11
+#define K210_RST_I2S2	12
+#define K210_RST_I2C0	13
+#define K210_RST_I2C1	14
+#define K210_RST_I2C2	15
+#define K210_RST_UART1	16
+#define K210_RST_UART2	17
+#define K210_RST_UART3	18
+#define K210_RST_AES	19
+#define K210_RST_FPIOA	20
+#define K210_RST_TIMER0	21
+#define K210_RST_TIMER1	22
+#define K210_RST_TIMER2	23
+#define K210_RST_WDT0	24
+#define K210_RST_WDT1	25
+#define K210_RST_SHA	26
+#define K210_RST_RTC	29
+
+#endif /* RESET_K210_SYSCTL_H */
-- 
2.28.0


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

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

* [PATCH v4 09/21] dt-bindings: pinctrl: Document canaan,k210-fpioa bindings
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Document the device tree bindings for the Canaan Kendryte K210 SoC
Fully Programmable IO Array (FPIOA) pinctrl driver in
Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml. The
new header file include/dt-bindings/pinctrl/k210-fpioa.h is added to
define all 256 possible pin functions of the SoC IO pins, as well as
macros simplifying the definition of pin functions in a device tree.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../bindings/pinctrl/canaan,k210-fpioa.yaml   | 171 +++++++++++
 include/dt-bindings/pinctrl/k210-fpioa.h      | 276 ++++++++++++++++++
 2 files changed, 447 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
 create mode 100644 include/dt-bindings/pinctrl/k210-fpioa.h

diff --git a/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml b/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
new file mode 100644
index 000000000000..30b850c3bf2b
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
@@ -0,0 +1,171 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/canaan,k210-fpioa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K210 FPIOA Device Tree Bindings
+
+maintainers:
+  - Damien Le Moal <damien.lemoal@wdc.com>
+
+description:
+  The Canaan Kendryte K210 SoC Fully Programmable IO Array (FPIOA)
+  controller allows assiging any of 256 possible functions to any of
+  48 IO pins of the SoC. Pin function configuration is performed on
+  a per-pin basis.
+
+properties:
+  compatible:
+    const: canaan,k210-fpioa
+
+  reg:
+    maxItems: 1
+    description:
+      Address and length of the register set for the FPIOA controller.
+
+  clocks:
+    items:
+      - description: Controller reference clock source
+      - description: APB interface clock source
+
+  clock-names:
+    items:
+      - const: ref
+      - const: pclk
+
+  resets:
+    maxItems: 1
+
+  canaan,k210-sysctl-power:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: |
+      phandle of the K210 system controller node and offset of its
+      power domain control register.
+
+patternProperties:
+  '-pinmux$':
+    type: object
+    $ref: /schemas/pinctrl/pinmux-node.yaml
+    description:
+      FPIOA client devices use sub-nodes to define the desired pin
+      configuration. Client device sub-nodes use the pinux property
+      below.
+
+    properties:
+      pinmux:
+        description:
+          List of IO pins alternate functions. The values for each IO
+          pin is a combination of an IO pin number (0 to 47) with the
+          desired function for the IO pin. Functions are defined as
+          macros in include/dt-bindings/pinctrl/k210-fpioa.h.
+          The K210_FPIOA(IO pin, function) macro is provided to
+          facilitate the combination of IO pin numbers and functions.
+
+    required:
+      - pinmux
+
+    additionalProperties: false
+
+  '-pins$':
+    type: object
+    $ref: /schemas/pinctrl/pincfg-node.yaml
+    description:
+      FPIOA client devices use sub-nodes to define the desired
+      configuration of pins. Client device sub-nodes use the
+      properties below.
+
+    properties:
+      pins:
+        description:
+          List of IO pins affected by the properties specified in this
+          subnode. IO pins are identified using the pin names "IO_xx".
+          Pin configuration nodes can also define the power domain to
+          be used for the SoC pin groups A0 (IO pins 0-5),
+          A1 (IO pins 6-11), A2 (IO pins 12-17), B0 (IO pins 18-23),
+          B1 (IO pins 24-29), B2 (IO pins 30-35), B3 (IO pins 30-35),
+          C0 (IO pins 36-41) and C1 (IO pins 42-47) using the
+          power-source property.
+        items:
+          anyOf:
+            - pattern: "^(IO_([0-9]*))|(A[0-2])|(B[3-5])|(C[6-7])$"
+            - enum: [ IO_0, IO_1, IO_2, IO_3, IO_4, IO_5, IO_6, IO_7,
+                      IO_8, IO_9, IO_10, IO_11, IO_12, IO_13, IO_14,
+                      IO_15, IO_16, IO_17, IO_18, IO_19, IO_20, IO_21,
+                      IO_22, IO_23, IO_24, IO_25, IO_26, IO_27, IO_28,
+                      IO_29, IO_30, IO_31, IO_32, IO_33, IO_34, IO_35,
+                      IO_36, IO_37, IO_38, IO_39, IO_40, IO_41, IO_42,
+                      IO_43, IO_44, IO_45, IO_46, IO_47,
+                      A0, A1, A2, B3, B4, B5, C6, C7 ]
+      bias-disable: true
+
+      bias-pull-down: true
+
+      bias-pull-up: true
+
+      drive-strength: true
+
+      drive-strength-microamp: true
+
+      input-enable: true
+
+      input-disable: true
+
+      input-schmitt-enable: true
+
+      input-schmitt-disable: true
+
+      intput-polarity-invert:
+        description:
+          Enable or disable pin input polarity inversion.
+
+      output-enable: true
+
+      output-disable: true
+
+      output-high: true
+
+      output-low: true
+
+      output-polarity-invert:
+        description:
+          Enable or disable pin output polarity inversion.
+
+      slew-rate: true
+
+      power-source: true
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - canaan,k210-sysctl-power
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/pinctrl/k210-fpioa.h>
+    #include <dt-bindings/clock/k210-clk.h>
+    #include <dt-bindings/reset/k210-rst.h>
+
+    fpioa: pinmux@502B0000 {
+      compatible = "canaan,k210-fpioa";
+      reg = <0x502B0000 0x100>;
+      clocks = <&sysclk K210_CLK_FPIOA>,
+               <&sysclk K210_CLK_APB0>;
+      clock-names = "ref", "pclk";
+      resets = <&sysrst K210_RST_FPIOA>;
+      canaan,k210-sysctl-power = <&sysctl 108>;
+      pinctrl-0 = <&jtag_pinctrl>;
+      pinctrl-names = "default";
+
+      jtag_pinctrl: jtag-pinmux {
+        pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+                 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+                 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+                 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+      };
+    };
diff --git a/include/dt-bindings/pinctrl/k210-fpioa.h b/include/dt-bindings/pinctrl/k210-fpioa.h
new file mode 100644
index 000000000000..314285eab3a1
--- /dev/null
+++ b/include/dt-bindings/pinctrl/k210-fpioa.h
@@ -0,0 +1,276 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#ifndef PINCTRL_K210_FPIOA_H
+#define PINCTRL_K210_FPIOA_H
+
+/*
+ * Full list of FPIOA functions from
+ * kendryte-standalone-sdk/lib/drivers/include/fpioa.h
+ */
+#define K210_PCF_MASK		GENMASK(7, 0)
+#define K210_PCF_JTAG_TCLK	0   /* JTAG Test Clock */
+#define K210_PCF_JTAG_TDI	1   /* JTAG Test Data In */
+#define K210_PCF_JTAG_TMS	2   /* JTAG Test Mode Select */
+#define K210_PCF_JTAG_TDO	3   /* JTAG Test Data Out */
+#define K210_PCF_SPI0_D0	4   /* SPI0 Data 0 */
+#define K210_PCF_SPI0_D1	5   /* SPI0 Data 1 */
+#define K210_PCF_SPI0_D2	6   /* SPI0 Data 2 */
+#define K210_PCF_SPI0_D3	7   /* SPI0 Data 3 */
+#define K210_PCF_SPI0_D4	8   /* SPI0 Data 4 */
+#define K210_PCF_SPI0_D5	9   /* SPI0 Data 5 */
+#define K210_PCF_SPI0_D6	10  /* SPI0 Data 6 */
+#define K210_PCF_SPI0_D7	11  /* SPI0 Data 7 */
+#define K210_PCF_SPI0_SS0	12  /* SPI0 Chip Select 0 */
+#define K210_PCF_SPI0_SS1	13  /* SPI0 Chip Select 1 */
+#define K210_PCF_SPI0_SS2	14  /* SPI0 Chip Select 2 */
+#define K210_PCF_SPI0_SS3	15  /* SPI0 Chip Select 3 */
+#define K210_PCF_SPI0_ARB	16  /* SPI0 Arbitration */
+#define K210_PCF_SPI0_SCLK	17  /* SPI0 Serial Clock */
+#define K210_PCF_UARTHS_RX	18  /* UART High speed Receiver */
+#define K210_PCF_UARTHS_TX	19  /* UART High speed Transmitter */
+#define K210_PCF_RESV6		20  /* Reserved function */
+#define K210_PCF_RESV7		21  /* Reserved function */
+#define K210_PCF_CLK_SPI1	22  /* Clock SPI1 */
+#define K210_PCF_CLK_I2C1	23  /* Clock I2C1 */
+#define K210_PCF_GPIOHS0	24  /* GPIO High speed 0 */
+#define K210_PCF_GPIOHS1	25  /* GPIO High speed 1 */
+#define K210_PCF_GPIOHS2	26  /* GPIO High speed 2 */
+#define K210_PCF_GPIOHS3	27  /* GPIO High speed 3 */
+#define K210_PCF_GPIOHS4	28  /* GPIO High speed 4 */
+#define K210_PCF_GPIOHS5	29  /* GPIO High speed 5 */
+#define K210_PCF_GPIOHS6	30  /* GPIO High speed 6 */
+#define K210_PCF_GPIOHS7	31  /* GPIO High speed 7 */
+#define K210_PCF_GPIOHS8	32  /* GPIO High speed 8 */
+#define K210_PCF_GPIOHS9	33  /* GPIO High speed 9 */
+#define K210_PCF_GPIOHS10	34  /* GPIO High speed 10 */
+#define K210_PCF_GPIOHS11	35  /* GPIO High speed 11 */
+#define K210_PCF_GPIOHS12	36  /* GPIO High speed 12 */
+#define K210_PCF_GPIOHS13	37  /* GPIO High speed 13 */
+#define K210_PCF_GPIOHS14	38  /* GPIO High speed 14 */
+#define K210_PCF_GPIOHS15	39  /* GPIO High speed 15 */
+#define K210_PCF_GPIOHS16	40  /* GPIO High speed 16 */
+#define K210_PCF_GPIOHS17	41  /* GPIO High speed 17 */
+#define K210_PCF_GPIOHS18	42  /* GPIO High speed 18 */
+#define K210_PCF_GPIOHS19	43  /* GPIO High speed 19 */
+#define K210_PCF_GPIOHS20	44  /* GPIO High speed 20 */
+#define K210_PCF_GPIOHS21	45  /* GPIO High speed 21 */
+#define K210_PCF_GPIOHS22	46  /* GPIO High speed 22 */
+#define K210_PCF_GPIOHS23	47  /* GPIO High speed 23 */
+#define K210_PCF_GPIOHS24	48  /* GPIO High speed 24 */
+#define K210_PCF_GPIOHS25	49  /* GPIO High speed 25 */
+#define K210_PCF_GPIOHS26	50  /* GPIO High speed 26 */
+#define K210_PCF_GPIOHS27	51  /* GPIO High speed 27 */
+#define K210_PCF_GPIOHS28	52  /* GPIO High speed 28 */
+#define K210_PCF_GPIOHS29	53  /* GPIO High speed 29 */
+#define K210_PCF_GPIOHS30	54  /* GPIO High speed 30 */
+#define K210_PCF_GPIOHS31	55  /* GPIO High speed 31 */
+#define K210_PCF_GPIO0		56  /* GPIO pin 0 */
+#define K210_PCF_GPIO1		57  /* GPIO pin 1 */
+#define K210_PCF_GPIO2		58  /* GPIO pin 2 */
+#define K210_PCF_GPIO3		59  /* GPIO pin 3 */
+#define K210_PCF_GPIO4		60  /* GPIO pin 4 */
+#define K210_PCF_GPIO5		61  /* GPIO pin 5 */
+#define K210_PCF_GPIO6		62  /* GPIO pin 6 */
+#define K210_PCF_GPIO7		63  /* GPIO pin 7 */
+#define K210_PCF_UART1_RX	64  /* UART1 Receiver */
+#define K210_PCF_UART1_TX	65  /* UART1 Transmitter */
+#define K210_PCF_UART2_RX	66  /* UART2 Receiver */
+#define K210_PCF_UART2_TX	67  /* UART2 Transmitter */
+#define K210_PCF_UART3_RX	68  /* UART3 Receiver */
+#define K210_PCF_UART3_TX	69  /* UART3 Transmitter */
+#define K210_PCF_SPI1_D0	70  /* SPI1 Data 0 */
+#define K210_PCF_SPI1_D1	71  /* SPI1 Data 1 */
+#define K210_PCF_SPI1_D2	72  /* SPI1 Data 2 */
+#define K210_PCF_SPI1_D3	73  /* SPI1 Data 3 */
+#define K210_PCF_SPI1_D4	74  /* SPI1 Data 4 */
+#define K210_PCF_SPI1_D5	75  /* SPI1 Data 5 */
+#define K210_PCF_SPI1_D6	76  /* SPI1 Data 6 */
+#define K210_PCF_SPI1_D7	77  /* SPI1 Data 7 */
+#define K210_PCF_SPI1_SS0	78  /* SPI1 Chip Select 0 */
+#define K210_PCF_SPI1_SS1	79  /* SPI1 Chip Select 1 */
+#define K210_PCF_SPI1_SS2	80  /* SPI1 Chip Select 2 */
+#define K210_PCF_SPI1_SS3	81  /* SPI1 Chip Select 3 */
+#define K210_PCF_SPI1_ARB	82  /* SPI1 Arbitration */
+#define K210_PCF_SPI1_SCLK	83  /* SPI1 Serial Clock */
+#define K210_PCF_SPI2_D0	84  /* SPI2 Data 0 */
+#define K210_PCF_SPI2_SS	85  /* SPI2 Select */
+#define K210_PCF_SPI2_SCLK	86  /* SPI2 Serial Clock */
+#define K210_PCF_I2S0_MCLK	87  /* I2S0 Master Clock */
+#define K210_PCF_I2S0_SCLK	88  /* I2S0 Serial Clock(BCLK) */
+#define K210_PCF_I2S0_WS	89  /* I2S0 Word Select(LRCLK) */
+#define K210_PCF_I2S0_IN_D0	90  /* I2S0 Serial Data Input 0 */
+#define K210_PCF_I2S0_IN_D1	91  /* I2S0 Serial Data Input 1 */
+#define K210_PCF_I2S0_IN_D2	92  /* I2S0 Serial Data Input 2 */
+#define K210_PCF_I2S0_IN_D3	93  /* I2S0 Serial Data Input 3 */
+#define K210_PCF_I2S0_OUT_D0	94  /* I2S0 Serial Data Output 0 */
+#define K210_PCF_I2S0_OUT_D1	95  /* I2S0 Serial Data Output 1 */
+#define K210_PCF_I2S0_OUT_D2	96  /* I2S0 Serial Data Output 2 */
+#define K210_PCF_I2S0_OUT_D3	97  /* I2S0 Serial Data Output 3 */
+#define K210_PCF_I2S1_MCLK	98  /* I2S1 Master Clock */
+#define K210_PCF_I2S1_SCLK	99  /* I2S1 Serial Clock(BCLK) */
+#define K210_PCF_I2S1_WS	100 /* I2S1 Word Select(LRCLK) */
+#define K210_PCF_I2S1_IN_D0	101 /* I2S1 Serial Data Input 0 */
+#define K210_PCF_I2S1_IN_D1	102 /* I2S1 Serial Data Input 1 */
+#define K210_PCF_I2S1_IN_D2	103 /* I2S1 Serial Data Input 2 */
+#define K210_PCF_I2S1_IN_D3	104 /* I2S1 Serial Data Input 3 */
+#define K210_PCF_I2S1_OUT_D0	105 /* I2S1 Serial Data Output 0 */
+#define K210_PCF_I2S1_OUT_D1	106 /* I2S1 Serial Data Output 1 */
+#define K210_PCF_I2S1_OUT_D2	107 /* I2S1 Serial Data Output 2 */
+#define K210_PCF_I2S1_OUT_D3	108 /* I2S1 Serial Data Output 3 */
+#define K210_PCF_I2S2_MCLK	109 /* I2S2 Master Clock */
+#define K210_PCF_I2S2_SCLK	110 /* I2S2 Serial Clock(BCLK) */
+#define K210_PCF_I2S2_WS	111 /* I2S2 Word Select(LRCLK) */
+#define K210_PCF_I2S2_IN_D0	112 /* I2S2 Serial Data Input 0 */
+#define K210_PCF_I2S2_IN_D1	113 /* I2S2 Serial Data Input 1 */
+#define K210_PCF_I2S2_IN_D2	114 /* I2S2 Serial Data Input 2 */
+#define K210_PCF_I2S2_IN_D3	115 /* I2S2 Serial Data Input 3 */
+#define K210_PCF_I2S2_OUT_D0	116 /* I2S2 Serial Data Output 0 */
+#define K210_PCF_I2S2_OUT_D1	117 /* I2S2 Serial Data Output 1 */
+#define K210_PCF_I2S2_OUT_D2	118 /* I2S2 Serial Data Output 2 */
+#define K210_PCF_I2S2_OUT_D3	119 /* I2S2 Serial Data Output 3 */
+#define K210_PCF_RESV0		120 /* Reserved function */
+#define K210_PCF_RESV1		121 /* Reserved function */
+#define K210_PCF_RESV2		122 /* Reserved function */
+#define K210_PCF_RESV3		123 /* Reserved function */
+#define K210_PCF_RESV4		124 /* Reserved function */
+#define K210_PCF_RESV5		125 /* Reserved function */
+#define K210_PCF_I2C0_SCLK	126 /* I2C0 Serial Clock */
+#define K210_PCF_I2C0_SDA	127 /* I2C0 Serial Data */
+#define K210_PCF_I2C1_SCLK	128 /* I2C1 Serial Clock */
+#define K210_PCF_I2C1_SDA	129 /* I2C1 Serial Data */
+#define K210_PCF_I2C2_SCLK	130 /* I2C2 Serial Clock */
+#define K210_PCF_I2C2_SDA	131 /* I2C2 Serial Data */
+#define K210_PCF_DVP_XCLK	132 /* DVP System Clock */
+#define K210_PCF_DVP_RST	133 /* DVP System Reset */
+#define K210_PCF_DVP_PWDN	134 /* DVP Power Down Mode */
+#define K210_PCF_DVP_VSYNC	135 /* DVP Vertical Sync */
+#define K210_PCF_DVP_HSYNC	136 /* DVP Horizontal Sync */
+#define K210_PCF_DVP_PCLK	137 /* Pixel Clock */
+#define K210_PCF_DVP_D0		138 /* Data Bit 0 */
+#define K210_PCF_DVP_D1		139 /* Data Bit 1 */
+#define K210_PCF_DVP_D2		140 /* Data Bit 2 */
+#define K210_PCF_DVP_D3		141 /* Data Bit 3 */
+#define K210_PCF_DVP_D4		142 /* Data Bit 4 */
+#define K210_PCF_DVP_D5		143 /* Data Bit 5 */
+#define K210_PCF_DVP_D6		144 /* Data Bit 6 */
+#define K210_PCF_DVP_D7		145 /* Data Bit 7 */
+#define K210_PCF_SCCB_SCLK	146 /* Serial Camera Control Bus Clock */
+#define K210_PCF_SCCB_SDA	147 /* Serial Camera Control Bus Data */
+#define K210_PCF_UART1_CTS	148 /* UART1 Clear To Send */
+#define K210_PCF_UART1_DSR	149 /* UART1 Data Set Ready */
+#define K210_PCF_UART1_DCD	150 /* UART1 Data Carrier Detect */
+#define K210_PCF_UART1_RI	151 /* UART1 Ring Indicator */
+#define K210_PCF_UART1_SIR_IN	152 /* UART1 Serial Infrared Input */
+#define K210_PCF_UART1_DTR	153 /* UART1 Data Terminal Ready */
+#define K210_PCF_UART1_RTS	154 /* UART1 Request To Send */
+#define K210_PCF_UART1_OUT2	155 /* UART1 User-designated Output 2 */
+#define K210_PCF_UART1_OUT1	156 /* UART1 User-designated Output 1 */
+#define K210_PCF_UART1_SIR_OUT	157 /* UART1 Serial Infrared Output */
+#define K210_PCF_UART1_BAUD	158 /* UART1 Transmit Clock Output */
+#define K210_PCF_UART1_RE	159 /* UART1 Receiver Output Enable */
+#define K210_PCF_UART1_DE	160 /* UART1 Driver Output Enable */
+#define K210_PCF_UART1_RS485_EN	161 /* UART1 RS485 Enable */
+#define K210_PCF_UART2_CTS	162 /* UART2 Clear To Send */
+#define K210_PCF_UART2_DSR	163 /* UART2 Data Set Ready */
+#define K210_PCF_UART2_DCD	164 /* UART2 Data Carrier Detect */
+#define K210_PCF_UART2_RI	165 /* UART2 Ring Indicator */
+#define K210_PCF_UART2_SIR_IN	166 /* UART2 Serial Infrared Input */
+#define K210_PCF_UART2_DTR	167 /* UART2 Data Terminal Ready */
+#define K210_PCF_UART2_RTS	168 /* UART2 Request To Send */
+#define K210_PCF_UART2_OUT2	169 /* UART2 User-designated Output 2 */
+#define K210_PCF_UART2_OUT1	170 /* UART2 User-designated Output 1 */
+#define K210_PCF_UART2_SIR_OUT	171 /* UART2 Serial Infrared Output */
+#define K210_PCF_UART2_BAUD	172 /* UART2 Transmit Clock Output */
+#define K210_PCF_UART2_RE	173 /* UART2 Receiver Output Enable */
+#define K210_PCF_UART2_DE	174 /* UART2 Driver Output Enable */
+#define K210_PCF_UART2_RS485_EN	175 /* UART2 RS485 Enable */
+#define K210_PCF_UART3_CTS	176 /* UART3 Clear To Send */
+#define K210_PCF_UART3_DSR	177 /* UART3 Data Set Ready */
+#define K210_PCF_UART3_DCD	178 /* UART3 Data Carrier Detect */
+#define K210_PCF_UART3_RI	179 /* UART3 Ring Indicator */
+#define K210_PCF_UART3_SIR_IN	180 /* UART3 Serial Infrared Input */
+#define K210_PCF_UART3_DTR	181 /* UART3 Data Terminal Ready */
+#define K210_PCF_UART3_RTS	182 /* UART3 Request To Send */
+#define K210_PCF_UART3_OUT2	183 /* UART3 User-designated Output 2 */
+#define K210_PCF_UART3_OUT1	184 /* UART3 User-designated Output 1 */
+#define K210_PCF_UART3_SIR_OUT	185 /* UART3 Serial Infrared Output */
+#define K210_PCF_UART3_BAUD	186 /* UART3 Transmit Clock Output */
+#define K210_PCF_UART3_RE	187 /* UART3 Receiver Output Enable */
+#define K210_PCF_UART3_DE	188 /* UART3 Driver Output Enable */
+#define K210_PCF_UART3_RS485_EN	189 /* UART3 RS485 Enable */
+#define K210_PCF_TIMER0_TOGGLE1	190 /* TIMER0 Toggle Output 1 */
+#define K210_PCF_TIMER0_TOGGLE2	191 /* TIMER0 Toggle Output 2 */
+#define K210_PCF_TIMER0_TOGGLE3	192 /* TIMER0 Toggle Output 3 */
+#define K210_PCF_TIMER0_TOGGLE4	193 /* TIMER0 Toggle Output 4 */
+#define K210_PCF_TIMER1_TOGGLE1	194 /* TIMER1 Toggle Output 1 */
+#define K210_PCF_TIMER1_TOGGLE2	195 /* TIMER1 Toggle Output 2 */
+#define K210_PCF_TIMER1_TOGGLE3	196 /* TIMER1 Toggle Output 3 */
+#define K210_PCF_TIMER1_TOGGLE4	197 /* TIMER1 Toggle Output 4 */
+#define K210_PCF_TIMER2_TOGGLE1	198 /* TIMER2 Toggle Output 1 */
+#define K210_PCF_TIMER2_TOGGLE2	199 /* TIMER2 Toggle Output 2 */
+#define K210_PCF_TIMER2_TOGGLE3	200 /* TIMER2 Toggle Output 3 */
+#define K210_PCF_TIMER2_TOGGLE4	201 /* TIMER2 Toggle Output 4 */
+#define K210_PCF_CLK_SPI2	202 /* Clock SPI2 */
+#define K210_PCF_CLK_I2C2	203 /* Clock I2C2 */
+#define K210_PCF_INTERNAL0	204 /* Internal function signal 0 */
+#define K210_PCF_INTERNAL1	205 /* Internal function signal 1 */
+#define K210_PCF_INTERNAL2	206 /* Internal function signal 2 */
+#define K210_PCF_INTERNAL3	207 /* Internal function signal 3 */
+#define K210_PCF_INTERNAL4	208 /* Internal function signal 4 */
+#define K210_PCF_INTERNAL5	209 /* Internal function signal 5 */
+#define K210_PCF_INTERNAL6	210 /* Internal function signal 6 */
+#define K210_PCF_INTERNAL7	211 /* Internal function signal 7 */
+#define K210_PCF_INTERNAL8	212 /* Internal function signal 8 */
+#define K210_PCF_INTERNAL9	213 /* Internal function signal 9 */
+#define K210_PCF_INTERNAL10	214 /* Internal function signal 10 */
+#define K210_PCF_INTERNAL11	215 /* Internal function signal 11 */
+#define K210_PCF_INTERNAL12	216 /* Internal function signal 12 */
+#define K210_PCF_INTERNAL13	217 /* Internal function signal 13 */
+#define K210_PCF_INTERNAL14	218 /* Internal function signal 14 */
+#define K210_PCF_INTERNAL15	219 /* Internal function signal 15 */
+#define K210_PCF_INTERNAL16	220 /* Internal function signal 16 */
+#define K210_PCF_INTERNAL17	221 /* Internal function signal 17 */
+#define K210_PCF_CONSTANT	222 /* Constant function */
+#define K210_PCF_INTERNAL18	223 /* Internal function signal 18 */
+#define K210_PCF_DEBUG0		224 /* Debug function 0 */
+#define K210_PCF_DEBUG1		225 /* Debug function 1 */
+#define K210_PCF_DEBUG2		226 /* Debug function 2 */
+#define K210_PCF_DEBUG3		227 /* Debug function 3 */
+#define K210_PCF_DEBUG4		228 /* Debug function 4 */
+#define K210_PCF_DEBUG5		229 /* Debug function 5 */
+#define K210_PCF_DEBUG6		230 /* Debug function 6 */
+#define K210_PCF_DEBUG7		231 /* Debug function 7 */
+#define K210_PCF_DEBUG8		232 /* Debug function 8 */
+#define K210_PCF_DEBUG9		233 /* Debug function 9 */
+#define K210_PCF_DEBUG10	234 /* Debug function 10 */
+#define K210_PCF_DEBUG11	235 /* Debug function 11 */
+#define K210_PCF_DEBUG12	236 /* Debug function 12 */
+#define K210_PCF_DEBUG13	237 /* Debug function 13 */
+#define K210_PCF_DEBUG14	238 /* Debug function 14 */
+#define K210_PCF_DEBUG15	239 /* Debug function 15 */
+#define K210_PCF_DEBUG16	240 /* Debug function 16 */
+#define K210_PCF_DEBUG17	241 /* Debug function 17 */
+#define K210_PCF_DEBUG18	242 /* Debug function 18 */
+#define K210_PCF_DEBUG19	243 /* Debug function 19 */
+#define K210_PCF_DEBUG20	244 /* Debug function 20 */
+#define K210_PCF_DEBUG21	245 /* Debug function 21 */
+#define K210_PCF_DEBUG22	246 /* Debug function 22 */
+#define K210_PCF_DEBUG23	247 /* Debug function 23 */
+#define K210_PCF_DEBUG24	248 /* Debug function 24 */
+#define K210_PCF_DEBUG25	249 /* Debug function 25 */
+#define K210_PCF_DEBUG26	250 /* Debug function 26 */
+#define K210_PCF_DEBUG27	251 /* Debug function 27 */
+#define K210_PCF_DEBUG28	252 /* Debug function 28 */
+#define K210_PCF_DEBUG29	253 /* Debug function 29 */
+#define K210_PCF_DEBUG30	254 /* Debug function 30 */
+#define K210_PCF_DEBUG31	255 /* Debug function 31 */
+
+#define K210_FPIOA(pin, func)		(((pin) << 16) | (func))
+
+#define K210_PC_POWER_3V3	0
+#define K210_PC_POWER_1V8	1
+
+#endif /* PINCTRL_K210_FPIOA_H */
-- 
2.28.0


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

* [PATCH v4 09/21] dt-bindings: pinctrl: Document canaan, k210-fpioa bindings
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Document the device tree bindings for the Canaan Kendryte K210 SoC
Fully Programmable IO Array (FPIOA) pinctrl driver in
Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml. The
new header file include/dt-bindings/pinctrl/k210-fpioa.h is added to
define all 256 possible pin functions of the SoC IO pins, as well as
macros simplifying the definition of pin functions in a device tree.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../bindings/pinctrl/canaan,k210-fpioa.yaml   | 171 +++++++++++
 include/dt-bindings/pinctrl/k210-fpioa.h      | 276 ++++++++++++++++++
 2 files changed, 447 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
 create mode 100644 include/dt-bindings/pinctrl/k210-fpioa.h

diff --git a/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml b/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
new file mode 100644
index 000000000000..30b850c3bf2b
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
@@ -0,0 +1,171 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/canaan,k210-fpioa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K210 FPIOA Device Tree Bindings
+
+maintainers:
+  - Damien Le Moal <damien.lemoal@wdc.com>
+
+description:
+  The Canaan Kendryte K210 SoC Fully Programmable IO Array (FPIOA)
+  controller allows assiging any of 256 possible functions to any of
+  48 IO pins of the SoC. Pin function configuration is performed on
+  a per-pin basis.
+
+properties:
+  compatible:
+    const: canaan,k210-fpioa
+
+  reg:
+    maxItems: 1
+    description:
+      Address and length of the register set for the FPIOA controller.
+
+  clocks:
+    items:
+      - description: Controller reference clock source
+      - description: APB interface clock source
+
+  clock-names:
+    items:
+      - const: ref
+      - const: pclk
+
+  resets:
+    maxItems: 1
+
+  canaan,k210-sysctl-power:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: |
+      phandle of the K210 system controller node and offset of its
+      power domain control register.
+
+patternProperties:
+  '-pinmux$':
+    type: object
+    $ref: /schemas/pinctrl/pinmux-node.yaml
+    description:
+      FPIOA client devices use sub-nodes to define the desired pin
+      configuration. Client device sub-nodes use the pinux property
+      below.
+
+    properties:
+      pinmux:
+        description:
+          List of IO pins alternate functions. The values for each IO
+          pin is a combination of an IO pin number (0 to 47) with the
+          desired function for the IO pin. Functions are defined as
+          macros in include/dt-bindings/pinctrl/k210-fpioa.h.
+          The K210_FPIOA(IO pin, function) macro is provided to
+          facilitate the combination of IO pin numbers and functions.
+
+    required:
+      - pinmux
+
+    additionalProperties: false
+
+  '-pins$':
+    type: object
+    $ref: /schemas/pinctrl/pincfg-node.yaml
+    description:
+      FPIOA client devices use sub-nodes to define the desired
+      configuration of pins. Client device sub-nodes use the
+      properties below.
+
+    properties:
+      pins:
+        description:
+          List of IO pins affected by the properties specified in this
+          subnode. IO pins are identified using the pin names "IO_xx".
+          Pin configuration nodes can also define the power domain to
+          be used for the SoC pin groups A0 (IO pins 0-5),
+          A1 (IO pins 6-11), A2 (IO pins 12-17), B0 (IO pins 18-23),
+          B1 (IO pins 24-29), B2 (IO pins 30-35), B3 (IO pins 30-35),
+          C0 (IO pins 36-41) and C1 (IO pins 42-47) using the
+          power-source property.
+        items:
+          anyOf:
+            - pattern: "^(IO_([0-9]*))|(A[0-2])|(B[3-5])|(C[6-7])$"
+            - enum: [ IO_0, IO_1, IO_2, IO_3, IO_4, IO_5, IO_6, IO_7,
+                      IO_8, IO_9, IO_10, IO_11, IO_12, IO_13, IO_14,
+                      IO_15, IO_16, IO_17, IO_18, IO_19, IO_20, IO_21,
+                      IO_22, IO_23, IO_24, IO_25, IO_26, IO_27, IO_28,
+                      IO_29, IO_30, IO_31, IO_32, IO_33, IO_34, IO_35,
+                      IO_36, IO_37, IO_38, IO_39, IO_40, IO_41, IO_42,
+                      IO_43, IO_44, IO_45, IO_46, IO_47,
+                      A0, A1, A2, B3, B4, B5, C6, C7 ]
+      bias-disable: true
+
+      bias-pull-down: true
+
+      bias-pull-up: true
+
+      drive-strength: true
+
+      drive-strength-microamp: true
+
+      input-enable: true
+
+      input-disable: true
+
+      input-schmitt-enable: true
+
+      input-schmitt-disable: true
+
+      intput-polarity-invert:
+        description:
+          Enable or disable pin input polarity inversion.
+
+      output-enable: true
+
+      output-disable: true
+
+      output-high: true
+
+      output-low: true
+
+      output-polarity-invert:
+        description:
+          Enable or disable pin output polarity inversion.
+
+      slew-rate: true
+
+      power-source: true
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - canaan,k210-sysctl-power
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/pinctrl/k210-fpioa.h>
+    #include <dt-bindings/clock/k210-clk.h>
+    #include <dt-bindings/reset/k210-rst.h>
+
+    fpioa: pinmux@502B0000 {
+      compatible = "canaan,k210-fpioa";
+      reg = <0x502B0000 0x100>;
+      clocks = <&sysclk K210_CLK_FPIOA>,
+               <&sysclk K210_CLK_APB0>;
+      clock-names = "ref", "pclk";
+      resets = <&sysrst K210_RST_FPIOA>;
+      canaan,k210-sysctl-power = <&sysctl 108>;
+      pinctrl-0 = <&jtag_pinctrl>;
+      pinctrl-names = "default";
+
+      jtag_pinctrl: jtag-pinmux {
+        pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+                 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+                 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+                 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+      };
+    };
diff --git a/include/dt-bindings/pinctrl/k210-fpioa.h b/include/dt-bindings/pinctrl/k210-fpioa.h
new file mode 100644
index 000000000000..314285eab3a1
--- /dev/null
+++ b/include/dt-bindings/pinctrl/k210-fpioa.h
@@ -0,0 +1,276 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#ifndef PINCTRL_K210_FPIOA_H
+#define PINCTRL_K210_FPIOA_H
+
+/*
+ * Full list of FPIOA functions from
+ * kendryte-standalone-sdk/lib/drivers/include/fpioa.h
+ */
+#define K210_PCF_MASK		GENMASK(7, 0)
+#define K210_PCF_JTAG_TCLK	0   /* JTAG Test Clock */
+#define K210_PCF_JTAG_TDI	1   /* JTAG Test Data In */
+#define K210_PCF_JTAG_TMS	2   /* JTAG Test Mode Select */
+#define K210_PCF_JTAG_TDO	3   /* JTAG Test Data Out */
+#define K210_PCF_SPI0_D0	4   /* SPI0 Data 0 */
+#define K210_PCF_SPI0_D1	5   /* SPI0 Data 1 */
+#define K210_PCF_SPI0_D2	6   /* SPI0 Data 2 */
+#define K210_PCF_SPI0_D3	7   /* SPI0 Data 3 */
+#define K210_PCF_SPI0_D4	8   /* SPI0 Data 4 */
+#define K210_PCF_SPI0_D5	9   /* SPI0 Data 5 */
+#define K210_PCF_SPI0_D6	10  /* SPI0 Data 6 */
+#define K210_PCF_SPI0_D7	11  /* SPI0 Data 7 */
+#define K210_PCF_SPI0_SS0	12  /* SPI0 Chip Select 0 */
+#define K210_PCF_SPI0_SS1	13  /* SPI0 Chip Select 1 */
+#define K210_PCF_SPI0_SS2	14  /* SPI0 Chip Select 2 */
+#define K210_PCF_SPI0_SS3	15  /* SPI0 Chip Select 3 */
+#define K210_PCF_SPI0_ARB	16  /* SPI0 Arbitration */
+#define K210_PCF_SPI0_SCLK	17  /* SPI0 Serial Clock */
+#define K210_PCF_UARTHS_RX	18  /* UART High speed Receiver */
+#define K210_PCF_UARTHS_TX	19  /* UART High speed Transmitter */
+#define K210_PCF_RESV6		20  /* Reserved function */
+#define K210_PCF_RESV7		21  /* Reserved function */
+#define K210_PCF_CLK_SPI1	22  /* Clock SPI1 */
+#define K210_PCF_CLK_I2C1	23  /* Clock I2C1 */
+#define K210_PCF_GPIOHS0	24  /* GPIO High speed 0 */
+#define K210_PCF_GPIOHS1	25  /* GPIO High speed 1 */
+#define K210_PCF_GPIOHS2	26  /* GPIO High speed 2 */
+#define K210_PCF_GPIOHS3	27  /* GPIO High speed 3 */
+#define K210_PCF_GPIOHS4	28  /* GPIO High speed 4 */
+#define K210_PCF_GPIOHS5	29  /* GPIO High speed 5 */
+#define K210_PCF_GPIOHS6	30  /* GPIO High speed 6 */
+#define K210_PCF_GPIOHS7	31  /* GPIO High speed 7 */
+#define K210_PCF_GPIOHS8	32  /* GPIO High speed 8 */
+#define K210_PCF_GPIOHS9	33  /* GPIO High speed 9 */
+#define K210_PCF_GPIOHS10	34  /* GPIO High speed 10 */
+#define K210_PCF_GPIOHS11	35  /* GPIO High speed 11 */
+#define K210_PCF_GPIOHS12	36  /* GPIO High speed 12 */
+#define K210_PCF_GPIOHS13	37  /* GPIO High speed 13 */
+#define K210_PCF_GPIOHS14	38  /* GPIO High speed 14 */
+#define K210_PCF_GPIOHS15	39  /* GPIO High speed 15 */
+#define K210_PCF_GPIOHS16	40  /* GPIO High speed 16 */
+#define K210_PCF_GPIOHS17	41  /* GPIO High speed 17 */
+#define K210_PCF_GPIOHS18	42  /* GPIO High speed 18 */
+#define K210_PCF_GPIOHS19	43  /* GPIO High speed 19 */
+#define K210_PCF_GPIOHS20	44  /* GPIO High speed 20 */
+#define K210_PCF_GPIOHS21	45  /* GPIO High speed 21 */
+#define K210_PCF_GPIOHS22	46  /* GPIO High speed 22 */
+#define K210_PCF_GPIOHS23	47  /* GPIO High speed 23 */
+#define K210_PCF_GPIOHS24	48  /* GPIO High speed 24 */
+#define K210_PCF_GPIOHS25	49  /* GPIO High speed 25 */
+#define K210_PCF_GPIOHS26	50  /* GPIO High speed 26 */
+#define K210_PCF_GPIOHS27	51  /* GPIO High speed 27 */
+#define K210_PCF_GPIOHS28	52  /* GPIO High speed 28 */
+#define K210_PCF_GPIOHS29	53  /* GPIO High speed 29 */
+#define K210_PCF_GPIOHS30	54  /* GPIO High speed 30 */
+#define K210_PCF_GPIOHS31	55  /* GPIO High speed 31 */
+#define K210_PCF_GPIO0		56  /* GPIO pin 0 */
+#define K210_PCF_GPIO1		57  /* GPIO pin 1 */
+#define K210_PCF_GPIO2		58  /* GPIO pin 2 */
+#define K210_PCF_GPIO3		59  /* GPIO pin 3 */
+#define K210_PCF_GPIO4		60  /* GPIO pin 4 */
+#define K210_PCF_GPIO5		61  /* GPIO pin 5 */
+#define K210_PCF_GPIO6		62  /* GPIO pin 6 */
+#define K210_PCF_GPIO7		63  /* GPIO pin 7 */
+#define K210_PCF_UART1_RX	64  /* UART1 Receiver */
+#define K210_PCF_UART1_TX	65  /* UART1 Transmitter */
+#define K210_PCF_UART2_RX	66  /* UART2 Receiver */
+#define K210_PCF_UART2_TX	67  /* UART2 Transmitter */
+#define K210_PCF_UART3_RX	68  /* UART3 Receiver */
+#define K210_PCF_UART3_TX	69  /* UART3 Transmitter */
+#define K210_PCF_SPI1_D0	70  /* SPI1 Data 0 */
+#define K210_PCF_SPI1_D1	71  /* SPI1 Data 1 */
+#define K210_PCF_SPI1_D2	72  /* SPI1 Data 2 */
+#define K210_PCF_SPI1_D3	73  /* SPI1 Data 3 */
+#define K210_PCF_SPI1_D4	74  /* SPI1 Data 4 */
+#define K210_PCF_SPI1_D5	75  /* SPI1 Data 5 */
+#define K210_PCF_SPI1_D6	76  /* SPI1 Data 6 */
+#define K210_PCF_SPI1_D7	77  /* SPI1 Data 7 */
+#define K210_PCF_SPI1_SS0	78  /* SPI1 Chip Select 0 */
+#define K210_PCF_SPI1_SS1	79  /* SPI1 Chip Select 1 */
+#define K210_PCF_SPI1_SS2	80  /* SPI1 Chip Select 2 */
+#define K210_PCF_SPI1_SS3	81  /* SPI1 Chip Select 3 */
+#define K210_PCF_SPI1_ARB	82  /* SPI1 Arbitration */
+#define K210_PCF_SPI1_SCLK	83  /* SPI1 Serial Clock */
+#define K210_PCF_SPI2_D0	84  /* SPI2 Data 0 */
+#define K210_PCF_SPI2_SS	85  /* SPI2 Select */
+#define K210_PCF_SPI2_SCLK	86  /* SPI2 Serial Clock */
+#define K210_PCF_I2S0_MCLK	87  /* I2S0 Master Clock */
+#define K210_PCF_I2S0_SCLK	88  /* I2S0 Serial Clock(BCLK) */
+#define K210_PCF_I2S0_WS	89  /* I2S0 Word Select(LRCLK) */
+#define K210_PCF_I2S0_IN_D0	90  /* I2S0 Serial Data Input 0 */
+#define K210_PCF_I2S0_IN_D1	91  /* I2S0 Serial Data Input 1 */
+#define K210_PCF_I2S0_IN_D2	92  /* I2S0 Serial Data Input 2 */
+#define K210_PCF_I2S0_IN_D3	93  /* I2S0 Serial Data Input 3 */
+#define K210_PCF_I2S0_OUT_D0	94  /* I2S0 Serial Data Output 0 */
+#define K210_PCF_I2S0_OUT_D1	95  /* I2S0 Serial Data Output 1 */
+#define K210_PCF_I2S0_OUT_D2	96  /* I2S0 Serial Data Output 2 */
+#define K210_PCF_I2S0_OUT_D3	97  /* I2S0 Serial Data Output 3 */
+#define K210_PCF_I2S1_MCLK	98  /* I2S1 Master Clock */
+#define K210_PCF_I2S1_SCLK	99  /* I2S1 Serial Clock(BCLK) */
+#define K210_PCF_I2S1_WS	100 /* I2S1 Word Select(LRCLK) */
+#define K210_PCF_I2S1_IN_D0	101 /* I2S1 Serial Data Input 0 */
+#define K210_PCF_I2S1_IN_D1	102 /* I2S1 Serial Data Input 1 */
+#define K210_PCF_I2S1_IN_D2	103 /* I2S1 Serial Data Input 2 */
+#define K210_PCF_I2S1_IN_D3	104 /* I2S1 Serial Data Input 3 */
+#define K210_PCF_I2S1_OUT_D0	105 /* I2S1 Serial Data Output 0 */
+#define K210_PCF_I2S1_OUT_D1	106 /* I2S1 Serial Data Output 1 */
+#define K210_PCF_I2S1_OUT_D2	107 /* I2S1 Serial Data Output 2 */
+#define K210_PCF_I2S1_OUT_D3	108 /* I2S1 Serial Data Output 3 */
+#define K210_PCF_I2S2_MCLK	109 /* I2S2 Master Clock */
+#define K210_PCF_I2S2_SCLK	110 /* I2S2 Serial Clock(BCLK) */
+#define K210_PCF_I2S2_WS	111 /* I2S2 Word Select(LRCLK) */
+#define K210_PCF_I2S2_IN_D0	112 /* I2S2 Serial Data Input 0 */
+#define K210_PCF_I2S2_IN_D1	113 /* I2S2 Serial Data Input 1 */
+#define K210_PCF_I2S2_IN_D2	114 /* I2S2 Serial Data Input 2 */
+#define K210_PCF_I2S2_IN_D3	115 /* I2S2 Serial Data Input 3 */
+#define K210_PCF_I2S2_OUT_D0	116 /* I2S2 Serial Data Output 0 */
+#define K210_PCF_I2S2_OUT_D1	117 /* I2S2 Serial Data Output 1 */
+#define K210_PCF_I2S2_OUT_D2	118 /* I2S2 Serial Data Output 2 */
+#define K210_PCF_I2S2_OUT_D3	119 /* I2S2 Serial Data Output 3 */
+#define K210_PCF_RESV0		120 /* Reserved function */
+#define K210_PCF_RESV1		121 /* Reserved function */
+#define K210_PCF_RESV2		122 /* Reserved function */
+#define K210_PCF_RESV3		123 /* Reserved function */
+#define K210_PCF_RESV4		124 /* Reserved function */
+#define K210_PCF_RESV5		125 /* Reserved function */
+#define K210_PCF_I2C0_SCLK	126 /* I2C0 Serial Clock */
+#define K210_PCF_I2C0_SDA	127 /* I2C0 Serial Data */
+#define K210_PCF_I2C1_SCLK	128 /* I2C1 Serial Clock */
+#define K210_PCF_I2C1_SDA	129 /* I2C1 Serial Data */
+#define K210_PCF_I2C2_SCLK	130 /* I2C2 Serial Clock */
+#define K210_PCF_I2C2_SDA	131 /* I2C2 Serial Data */
+#define K210_PCF_DVP_XCLK	132 /* DVP System Clock */
+#define K210_PCF_DVP_RST	133 /* DVP System Reset */
+#define K210_PCF_DVP_PWDN	134 /* DVP Power Down Mode */
+#define K210_PCF_DVP_VSYNC	135 /* DVP Vertical Sync */
+#define K210_PCF_DVP_HSYNC	136 /* DVP Horizontal Sync */
+#define K210_PCF_DVP_PCLK	137 /* Pixel Clock */
+#define K210_PCF_DVP_D0		138 /* Data Bit 0 */
+#define K210_PCF_DVP_D1		139 /* Data Bit 1 */
+#define K210_PCF_DVP_D2		140 /* Data Bit 2 */
+#define K210_PCF_DVP_D3		141 /* Data Bit 3 */
+#define K210_PCF_DVP_D4		142 /* Data Bit 4 */
+#define K210_PCF_DVP_D5		143 /* Data Bit 5 */
+#define K210_PCF_DVP_D6		144 /* Data Bit 6 */
+#define K210_PCF_DVP_D7		145 /* Data Bit 7 */
+#define K210_PCF_SCCB_SCLK	146 /* Serial Camera Control Bus Clock */
+#define K210_PCF_SCCB_SDA	147 /* Serial Camera Control Bus Data */
+#define K210_PCF_UART1_CTS	148 /* UART1 Clear To Send */
+#define K210_PCF_UART1_DSR	149 /* UART1 Data Set Ready */
+#define K210_PCF_UART1_DCD	150 /* UART1 Data Carrier Detect */
+#define K210_PCF_UART1_RI	151 /* UART1 Ring Indicator */
+#define K210_PCF_UART1_SIR_IN	152 /* UART1 Serial Infrared Input */
+#define K210_PCF_UART1_DTR	153 /* UART1 Data Terminal Ready */
+#define K210_PCF_UART1_RTS	154 /* UART1 Request To Send */
+#define K210_PCF_UART1_OUT2	155 /* UART1 User-designated Output 2 */
+#define K210_PCF_UART1_OUT1	156 /* UART1 User-designated Output 1 */
+#define K210_PCF_UART1_SIR_OUT	157 /* UART1 Serial Infrared Output */
+#define K210_PCF_UART1_BAUD	158 /* UART1 Transmit Clock Output */
+#define K210_PCF_UART1_RE	159 /* UART1 Receiver Output Enable */
+#define K210_PCF_UART1_DE	160 /* UART1 Driver Output Enable */
+#define K210_PCF_UART1_RS485_EN	161 /* UART1 RS485 Enable */
+#define K210_PCF_UART2_CTS	162 /* UART2 Clear To Send */
+#define K210_PCF_UART2_DSR	163 /* UART2 Data Set Ready */
+#define K210_PCF_UART2_DCD	164 /* UART2 Data Carrier Detect */
+#define K210_PCF_UART2_RI	165 /* UART2 Ring Indicator */
+#define K210_PCF_UART2_SIR_IN	166 /* UART2 Serial Infrared Input */
+#define K210_PCF_UART2_DTR	167 /* UART2 Data Terminal Ready */
+#define K210_PCF_UART2_RTS	168 /* UART2 Request To Send */
+#define K210_PCF_UART2_OUT2	169 /* UART2 User-designated Output 2 */
+#define K210_PCF_UART2_OUT1	170 /* UART2 User-designated Output 1 */
+#define K210_PCF_UART2_SIR_OUT	171 /* UART2 Serial Infrared Output */
+#define K210_PCF_UART2_BAUD	172 /* UART2 Transmit Clock Output */
+#define K210_PCF_UART2_RE	173 /* UART2 Receiver Output Enable */
+#define K210_PCF_UART2_DE	174 /* UART2 Driver Output Enable */
+#define K210_PCF_UART2_RS485_EN	175 /* UART2 RS485 Enable */
+#define K210_PCF_UART3_CTS	176 /* UART3 Clear To Send */
+#define K210_PCF_UART3_DSR	177 /* UART3 Data Set Ready */
+#define K210_PCF_UART3_DCD	178 /* UART3 Data Carrier Detect */
+#define K210_PCF_UART3_RI	179 /* UART3 Ring Indicator */
+#define K210_PCF_UART3_SIR_IN	180 /* UART3 Serial Infrared Input */
+#define K210_PCF_UART3_DTR	181 /* UART3 Data Terminal Ready */
+#define K210_PCF_UART3_RTS	182 /* UART3 Request To Send */
+#define K210_PCF_UART3_OUT2	183 /* UART3 User-designated Output 2 */
+#define K210_PCF_UART3_OUT1	184 /* UART3 User-designated Output 1 */
+#define K210_PCF_UART3_SIR_OUT	185 /* UART3 Serial Infrared Output */
+#define K210_PCF_UART3_BAUD	186 /* UART3 Transmit Clock Output */
+#define K210_PCF_UART3_RE	187 /* UART3 Receiver Output Enable */
+#define K210_PCF_UART3_DE	188 /* UART3 Driver Output Enable */
+#define K210_PCF_UART3_RS485_EN	189 /* UART3 RS485 Enable */
+#define K210_PCF_TIMER0_TOGGLE1	190 /* TIMER0 Toggle Output 1 */
+#define K210_PCF_TIMER0_TOGGLE2	191 /* TIMER0 Toggle Output 2 */
+#define K210_PCF_TIMER0_TOGGLE3	192 /* TIMER0 Toggle Output 3 */
+#define K210_PCF_TIMER0_TOGGLE4	193 /* TIMER0 Toggle Output 4 */
+#define K210_PCF_TIMER1_TOGGLE1	194 /* TIMER1 Toggle Output 1 */
+#define K210_PCF_TIMER1_TOGGLE2	195 /* TIMER1 Toggle Output 2 */
+#define K210_PCF_TIMER1_TOGGLE3	196 /* TIMER1 Toggle Output 3 */
+#define K210_PCF_TIMER1_TOGGLE4	197 /* TIMER1 Toggle Output 4 */
+#define K210_PCF_TIMER2_TOGGLE1	198 /* TIMER2 Toggle Output 1 */
+#define K210_PCF_TIMER2_TOGGLE2	199 /* TIMER2 Toggle Output 2 */
+#define K210_PCF_TIMER2_TOGGLE3	200 /* TIMER2 Toggle Output 3 */
+#define K210_PCF_TIMER2_TOGGLE4	201 /* TIMER2 Toggle Output 4 */
+#define K210_PCF_CLK_SPI2	202 /* Clock SPI2 */
+#define K210_PCF_CLK_I2C2	203 /* Clock I2C2 */
+#define K210_PCF_INTERNAL0	204 /* Internal function signal 0 */
+#define K210_PCF_INTERNAL1	205 /* Internal function signal 1 */
+#define K210_PCF_INTERNAL2	206 /* Internal function signal 2 */
+#define K210_PCF_INTERNAL3	207 /* Internal function signal 3 */
+#define K210_PCF_INTERNAL4	208 /* Internal function signal 4 */
+#define K210_PCF_INTERNAL5	209 /* Internal function signal 5 */
+#define K210_PCF_INTERNAL6	210 /* Internal function signal 6 */
+#define K210_PCF_INTERNAL7	211 /* Internal function signal 7 */
+#define K210_PCF_INTERNAL8	212 /* Internal function signal 8 */
+#define K210_PCF_INTERNAL9	213 /* Internal function signal 9 */
+#define K210_PCF_INTERNAL10	214 /* Internal function signal 10 */
+#define K210_PCF_INTERNAL11	215 /* Internal function signal 11 */
+#define K210_PCF_INTERNAL12	216 /* Internal function signal 12 */
+#define K210_PCF_INTERNAL13	217 /* Internal function signal 13 */
+#define K210_PCF_INTERNAL14	218 /* Internal function signal 14 */
+#define K210_PCF_INTERNAL15	219 /* Internal function signal 15 */
+#define K210_PCF_INTERNAL16	220 /* Internal function signal 16 */
+#define K210_PCF_INTERNAL17	221 /* Internal function signal 17 */
+#define K210_PCF_CONSTANT	222 /* Constant function */
+#define K210_PCF_INTERNAL18	223 /* Internal function signal 18 */
+#define K210_PCF_DEBUG0		224 /* Debug function 0 */
+#define K210_PCF_DEBUG1		225 /* Debug function 1 */
+#define K210_PCF_DEBUG2		226 /* Debug function 2 */
+#define K210_PCF_DEBUG3		227 /* Debug function 3 */
+#define K210_PCF_DEBUG4		228 /* Debug function 4 */
+#define K210_PCF_DEBUG5		229 /* Debug function 5 */
+#define K210_PCF_DEBUG6		230 /* Debug function 6 */
+#define K210_PCF_DEBUG7		231 /* Debug function 7 */
+#define K210_PCF_DEBUG8		232 /* Debug function 8 */
+#define K210_PCF_DEBUG9		233 /* Debug function 9 */
+#define K210_PCF_DEBUG10	234 /* Debug function 10 */
+#define K210_PCF_DEBUG11	235 /* Debug function 11 */
+#define K210_PCF_DEBUG12	236 /* Debug function 12 */
+#define K210_PCF_DEBUG13	237 /* Debug function 13 */
+#define K210_PCF_DEBUG14	238 /* Debug function 14 */
+#define K210_PCF_DEBUG15	239 /* Debug function 15 */
+#define K210_PCF_DEBUG16	240 /* Debug function 16 */
+#define K210_PCF_DEBUG17	241 /* Debug function 17 */
+#define K210_PCF_DEBUG18	242 /* Debug function 18 */
+#define K210_PCF_DEBUG19	243 /* Debug function 19 */
+#define K210_PCF_DEBUG20	244 /* Debug function 20 */
+#define K210_PCF_DEBUG21	245 /* Debug function 21 */
+#define K210_PCF_DEBUG22	246 /* Debug function 22 */
+#define K210_PCF_DEBUG23	247 /* Debug function 23 */
+#define K210_PCF_DEBUG24	248 /* Debug function 24 */
+#define K210_PCF_DEBUG25	249 /* Debug function 25 */
+#define K210_PCF_DEBUG26	250 /* Debug function 26 */
+#define K210_PCF_DEBUG27	251 /* Debug function 27 */
+#define K210_PCF_DEBUG28	252 /* Debug function 28 */
+#define K210_PCF_DEBUG29	253 /* Debug function 29 */
+#define K210_PCF_DEBUG30	254 /* Debug function 30 */
+#define K210_PCF_DEBUG31	255 /* Debug function 31 */
+
+#define K210_FPIOA(pin, func)		(((pin) << 16) | (func))
+
+#define K210_PC_POWER_3V3	0
+#define K210_PC_POWER_1V8	1
+
+#endif /* PINCTRL_K210_FPIOA_H */
-- 
2.28.0


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

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

* [PATCH v4 10/21] dt-binding: mfd: Document canaan,k210-sysctl bindings
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Document the device tree bindings of the Canaan Kendryte K210 SoC
system controller driver in
Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../bindings/mfd/canaan,k210-sysctl.yaml      | 116 ++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml

diff --git a/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml b/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
new file mode 100644
index 000000000000..1847def8e8f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/canaan,k210-sysctl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K210 System Controller Device Tree Bindings
+
+maintainers:
+  - Damien Le Moal <damien.lemoal@wdc.com>
+
+description:
+  Canaan Inc. Kendryte K210 SoC system controller which provides a
+  register map for controlling the clocks, reset signals and pin power
+  domains of the SoC.
+
+properties:
+  compatible:
+    allOf:
+      - items:
+          - const: canaan,k210-sysctl
+          - const: syscon
+          - const: simple-mfd
+
+  clocks:
+    description:
+      System controller Advanced Power Bus (APB) interface clock source.
+
+  clock-names:
+    maxItems: 1
+    items:
+      - const: pclk
+
+  reg:
+    maxItems: 1
+    description:
+      Offset and length of the system controller register space.
+
+  reg-io-width:
+    const: 4
+
+  clock-controller:
+    # Child node
+    type: object
+    $ref: "../clock/canaan,k210-clk.yaml"
+    description:
+      Clock controller for the SoC clocks. This child node definition
+      should follow the bindings specified in
+      Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml.
+
+  reset-controller:
+    # Child node
+    type: object
+    $ref: "../reset/canaan,k210-rst.yaml"
+    description:
+      Reset controller for the SoC. This child node definition
+      should follow the bindings specified in
+      Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml.
+
+  syscon-reboot:
+    # Child node
+    type: object
+    $ref: "../power/reset/syscon-reboot.yaml"
+    description:
+      Reboot method for the SoC. This child node definition
+      should follow the bindings specified in
+      Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml.
+
+required:
+  - compatible
+  - clocks
+  - reg
+  - clock-controller
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/k210-clk.h>
+    #include <dt-bindings/reset/k210-rst.h>
+
+    clocks {
+      in0: osc {
+        compatible = "fixed-clock";
+        #clock-cells = <0>;
+        clock-frequency = <26000000>;
+      };
+    };
+
+    sysctl: syscon@50440000 {
+      compatible = "canaan,k210-sysctl",
+                   "syscon", "simple-mfd";
+      reg = <0x50440000 0x100>;
+      reg-io-width = <4>;
+      clocks = <&sysclk K210_CLK_APB1>;
+      clock-names = "pclk";
+
+      sysclk: clock-controller {
+        #clock-cells = <1>;
+        compatible = "canaan,k210-clk";
+        clocks = <&in0>;
+      };
+
+      sysrst: reset-controller {
+        compatible = "canaan,k210-rst";
+        #reset-cells = <1>;
+      };
+
+      reboot: syscon-reboot {
+        compatible = "syscon-reboot";
+        regmap = <&sysctl>;
+        offset = <48>;
+        mask = <1>;
+        value = <1>;
+      };
+    };
-- 
2.28.0


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

* [PATCH v4 10/21] dt-binding: mfd: Document canaan, k210-sysctl bindings
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Document the device tree bindings of the Canaan Kendryte K210 SoC
system controller driver in
Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../bindings/mfd/canaan,k210-sysctl.yaml      | 116 ++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml

diff --git a/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml b/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
new file mode 100644
index 000000000000..1847def8e8f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/canaan,k210-sysctl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K210 System Controller Device Tree Bindings
+
+maintainers:
+  - Damien Le Moal <damien.lemoal@wdc.com>
+
+description:
+  Canaan Inc. Kendryte K210 SoC system controller which provides a
+  register map for controlling the clocks, reset signals and pin power
+  domains of the SoC.
+
+properties:
+  compatible:
+    allOf:
+      - items:
+          - const: canaan,k210-sysctl
+          - const: syscon
+          - const: simple-mfd
+
+  clocks:
+    description:
+      System controller Advanced Power Bus (APB) interface clock source.
+
+  clock-names:
+    maxItems: 1
+    items:
+      - const: pclk
+
+  reg:
+    maxItems: 1
+    description:
+      Offset and length of the system controller register space.
+
+  reg-io-width:
+    const: 4
+
+  clock-controller:
+    # Child node
+    type: object
+    $ref: "../clock/canaan,k210-clk.yaml"
+    description:
+      Clock controller for the SoC clocks. This child node definition
+      should follow the bindings specified in
+      Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml.
+
+  reset-controller:
+    # Child node
+    type: object
+    $ref: "../reset/canaan,k210-rst.yaml"
+    description:
+      Reset controller for the SoC. This child node definition
+      should follow the bindings specified in
+      Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml.
+
+  syscon-reboot:
+    # Child node
+    type: object
+    $ref: "../power/reset/syscon-reboot.yaml"
+    description:
+      Reboot method for the SoC. This child node definition
+      should follow the bindings specified in
+      Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml.
+
+required:
+  - compatible
+  - clocks
+  - reg
+  - clock-controller
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/k210-clk.h>
+    #include <dt-bindings/reset/k210-rst.h>
+
+    clocks {
+      in0: osc {
+        compatible = "fixed-clock";
+        #clock-cells = <0>;
+        clock-frequency = <26000000>;
+      };
+    };
+
+    sysctl: syscon@50440000 {
+      compatible = "canaan,k210-sysctl",
+                   "syscon", "simple-mfd";
+      reg = <0x50440000 0x100>;
+      reg-io-width = <4>;
+      clocks = <&sysclk K210_CLK_APB1>;
+      clock-names = "pclk";
+
+      sysclk: clock-controller {
+        #clock-cells = <1>;
+        compatible = "canaan,k210-clk";
+        clocks = <&in0>;
+      };
+
+      sysrst: reset-controller {
+        compatible = "canaan,k210-rst";
+        #reset-cells = <1>;
+      };
+
+      reboot: syscon-reboot {
+        compatible = "syscon-reboot";
+        regmap = <&sysctl>;
+        offset = <48>;
+        mask = <1>;
+        value = <1>;
+      };
+    };
-- 
2.28.0


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

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

* [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a clock provider driver for the Canaan Kendryte K210 RISC-V SoC.
This new driver with the compatible string "canaan,k210-clk" implements
support for the full clock structure of the K210 SoC. Since it is
required for the correct operation of the SoC, this driver is
automatically selected for compilation when the SOC_CANAAN option is
selected.

With this change, the k210-sysctl driver is turned into a simple
platform driver which enables its power bus clock and triggers
populating its child nodes. This driver is also automatically selected
for compilation with the selection of SOC_CANAAN. The sysctl driver
retains the SOC early initialization code, but the implementation now
relies on the new function k210_clk_early_init() provided by the new
clk-k210 driver. This function declaration is done using the new header
file include/soc/canaan/k210-sysctl.h which also include register
definitions for the system controller.

The clock structure implemented and many of the coding ideas for the
driver come from the work by Sean Anderson on the K210 support for the
U-Boot project.

The MAINTAINERS file is updated, adding the entries "CANAAN/KENDRYTE
K210 SOC CLOCK DRIVER" and "CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER
DRIVER" with myself listed as maintainer for these drivers.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 MAINTAINERS                      |  16 +
 arch/riscv/Kconfig.socs          |   2 +
 drivers/clk/Kconfig              |   9 +
 drivers/clk/Makefile             |   1 +
 drivers/clk/clk-k210.c           | 959 +++++++++++++++++++++++++++++++
 drivers/soc/canaan/Kconfig       |  17 +-
 drivers/soc/canaan/Makefile      |   2 +-
 drivers/soc/canaan/k210-sysctl.c | 241 ++------
 include/soc/canaan/k210-sysctl.h |  43 ++
 9 files changed, 1073 insertions(+), 217 deletions(-)
 create mode 100644 drivers/clk/clk-k210.c
 create mode 100644 include/soc/canaan/k210-sysctl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 2daa6ee673f7..3da9a7a02f61 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3822,6 +3822,22 @@ W:	https://github.com/Cascoda/ca8210-linux.git
 F:	Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
 F:	drivers/net/ieee802154/ca8210.c
 
+CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-riscv@lists.infradead.org
+L:	linux-clk@vger.kernel.org (clock driver)
+S:	Maintained
+F:	Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
+F:	drivers/clk/clk-k210.c
+
+CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-riscv@lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
+F:	drivers/soc/canaan/
+F:	include/soc/canaan/
+
 CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
 M:	David Howells <dhowells@redhat.com>
 L:	linux-cachefs@redhat.com (moderated for non-subscribers)
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 88ac0d1a5da4..f2f9633087d1 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -29,6 +29,8 @@ config SOC_CANAAN
 	select SERIAL_SIFIVE if TTY
 	select SERIAL_SIFIVE_CONSOLE if TTY
 	select SIFIVE_PLIC
+	select SOC_K210_SYSCTL
+	select CLK_K210
 	help
 	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c715d4681a0b..6f10f1ecc8d6 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -359,6 +359,15 @@ config COMMON_CLK_FIXED_MMIO
 	help
 	  Support for Memory Mapped IO Fixed clocks
 
+config CLK_K210
+	bool "Clock driver for the Canaan Kendryte K210 SoC"
+	depends on RISCV && SOC_CANAAN
+	depends on COMMON_CLK && OF
+	help
+	  Support for the Kendryte K210 RISC-V SoC clocks. This option
+	  is automatically selected when the SOC_KENDRYTE option is selected
+	  in the "SOC selection" menu.
+
 source "drivers/clk/actions/Kconfig"
 source "drivers/clk/analogbits/Kconfig"
 source "drivers/clk/baikal-t1/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index da8fcf147eb1..ccac89e0fdfe 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_VT8500)		+= clk-vt8500.o
 obj-$(CONFIG_COMMON_CLK_VC5)		+= clk-versaclock5.o
 obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
+obj-$(CONFIG_CLK_K210)			+= clk-k210.o
 
 # please keep this section sorted lexicographically by directory path name
 obj-y					+= actions/
diff --git a/drivers/clk/clk-k210.c b/drivers/clk/clk-k210.c
new file mode 100644
index 000000000000..95d830a38911
--- /dev/null
+++ b/drivers/clk/clk-k210.c
@@ -0,0 +1,959 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ */
+#define pr_fmt(fmt)     "k210-clk: " fmt
+
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <asm/soc.h>
+#include <soc/canaan/k210-sysctl.h>
+
+#include <dt-bindings/clock/k210-clk.h>
+
+/*
+ * in0: fixed-rate 26MHz oscillator base clock.
+ */
+#define K210_IN0_RATE		26000000UL
+
+/*
+ * Clocks parameters.
+ */
+struct k210_clk_cfg {
+	u8 gate_reg;
+	u8 gate_bit;
+	u8 div_reg;
+	u8 div_shift;
+	u8 div_width;
+	u8 div_type;
+	u8 mux_reg;
+	u8 mux_bit;
+};
+
+enum k210_clk_div_type {
+	DIV_NONE,
+	DIV_ONE_BASED,
+	DIV_DOUBLE_ONE_BASED,
+	DIV_POWER_OF_TWO,
+};
+
+#define GATE(_reg, _bit)	\
+	.gate_reg = (_reg),	\
+	.gate_bit = (_bit)
+#define DIV(_reg, _shift, _width, _type)	\
+	.div_reg = (_reg),			\
+	.div_shift = (_shift),			\
+	.div_width = (_width),			\
+	.div_type = (_type)
+#define MUX(_reg, _bit)		\
+	.mux_reg = (_reg),	\
+	.mux_bit = (_bit)
+
+static struct k210_clk_cfg k210_clks[K210_NUM_CLKS] = {
+
+	/* Gated clocks, no mux, no divider */
+	[K210_CLK_CPU] = { GATE(K210_SYSCTL_EN_CENT, 0) },
+	[K210_CLK_DMA] = { GATE(K210_SYSCTL_EN_PERI, 1) },
+	[K210_CLK_FFT] = { GATE(K210_SYSCTL_EN_PERI, 4) },
+	[K210_CLK_GPIO] = { GATE(K210_SYSCTL_EN_PERI, 5) },
+	[K210_CLK_UART1] = { GATE(K210_SYSCTL_EN_PERI, 16) },
+	[K210_CLK_UART2] = { GATE(K210_SYSCTL_EN_PERI, 17) },
+	[K210_CLK_UART3] = { GATE(K210_SYSCTL_EN_PERI, 18) },
+	[K210_CLK_FPIOA] = { GATE(K210_SYSCTL_EN_PERI, 20) },
+	[K210_CLK_SHA] = { GATE(K210_SYSCTL_EN_PERI, 26) },
+	[K210_CLK_AES] = { GATE(K210_SYSCTL_EN_PERI, 19) },
+	[K210_CLK_OTP] = { GATE(K210_SYSCTL_EN_PERI, 27) },
+	[K210_CLK_RTC] = { GATE(K210_SYSCTL_EN_PERI, 29) },
+
+	/* Gated divider clocks */
+	[K210_CLK_SRAM0] = {
+		GATE(K210_SYSCTL_EN_CENT, 1),
+		DIV(K210_SYSCTL_THR0, 0, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_SRAM1] = {
+		GATE(K210_SYSCTL_EN_CENT, 2),
+		DIV(K210_SYSCTL_THR0, 4, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_ROM] = {
+		GATE(K210_SYSCTL_EN_PERI, 0),
+		DIV(K210_SYSCTL_THR0, 16, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_DVP] = {
+		GATE(K210_SYSCTL_EN_PERI, 3),
+		DIV(K210_SYSCTL_THR0, 12, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_APB0] = {
+		GATE(K210_SYSCTL_EN_CENT, 3),
+		DIV(K210_SYSCTL_SEL0, 3, 3, DIV_ONE_BASED)
+	},
+	[K210_CLK_APB1] = {
+		GATE(K210_SYSCTL_EN_CENT, 4),
+		DIV(K210_SYSCTL_SEL0, 6, 3, DIV_ONE_BASED)
+	},
+	[K210_CLK_APB2] = {
+		GATE(K210_SYSCTL_EN_CENT, 5),
+		DIV(K210_SYSCTL_SEL0, 9, 3, DIV_ONE_BASED)
+	},
+	[K210_CLK_AI] = {
+		GATE(K210_SYSCTL_EN_PERI, 2),
+		DIV(K210_SYSCTL_THR0, 8, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_SPI0] = {
+		GATE(K210_SYSCTL_EN_PERI, 6),
+		DIV(K210_SYSCTL_THR1, 0, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_SPI1] = {
+		GATE(K210_SYSCTL_EN_PERI, 7),
+		DIV(K210_SYSCTL_THR1, 8, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_SPI2] = {
+		GATE(K210_SYSCTL_EN_PERI, 8),
+		DIV(K210_SYSCTL_THR1, 16, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2C0] = {
+		GATE(K210_SYSCTL_EN_PERI, 13),
+		DIV(K210_SYSCTL_THR5, 8, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2C1] = {
+		GATE(K210_SYSCTL_EN_PERI, 14),
+		DIV(K210_SYSCTL_THR5, 16, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2C2] = {
+		GATE(K210_SYSCTL_EN_PERI, 15),
+		DIV(K210_SYSCTL_THR5, 24, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_WDT0] = {
+		GATE(K210_SYSCTL_EN_PERI, 24),
+		DIV(K210_SYSCTL_THR6, 0, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_WDT1] = {
+		GATE(K210_SYSCTL_EN_PERI, 25),
+		DIV(K210_SYSCTL_THR6, 8, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S0] = {
+		GATE(K210_SYSCTL_EN_PERI, 10),
+		DIV(K210_SYSCTL_THR3, 0, 16, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S1] = {
+		GATE(K210_SYSCTL_EN_PERI, 11),
+		DIV(K210_SYSCTL_THR3, 16, 16, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S2] = {
+		GATE(K210_SYSCTL_EN_PERI, 12),
+		DIV(K210_SYSCTL_THR4, 0, 16, DIV_DOUBLE_ONE_BASED)
+	},
+
+	/* Divider clocks, no gate, no mux */
+	[K210_CLK_I2S0_M] = {
+		DIV(K210_SYSCTL_THR4, 16, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S1_M] = {
+		DIV(K210_SYSCTL_THR4, 24, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S2_M] = {
+		DIV(K210_SYSCTL_THR4, 0, 8, DIV_DOUBLE_ONE_BASED)
+	},
+
+	/* Muxed gated divider clocks */
+	[K210_CLK_SPI3] = {
+		GATE(K210_SYSCTL_EN_PERI, 9),
+		DIV(K210_SYSCTL_THR1, 24, 8, DIV_DOUBLE_ONE_BASED),
+		MUX(K210_SYSCTL_SEL0, 12)
+	},
+	[K210_CLK_TIMER0] = {
+		GATE(K210_SYSCTL_EN_PERI, 21),
+		DIV(K210_SYSCTL_THR2,  0, 8, DIV_DOUBLE_ONE_BASED),
+		MUX(K210_SYSCTL_SEL0, 13)
+	},
+	[K210_CLK_TIMER1] = {
+		GATE(K210_SYSCTL_EN_PERI, 22),
+		DIV(K210_SYSCTL_THR2, 8, 8, DIV_DOUBLE_ONE_BASED),
+		MUX(K210_SYSCTL_SEL0, 14)
+	},
+	[K210_CLK_TIMER2] = {
+		GATE(K210_SYSCTL_EN_PERI, 23),
+		DIV(K210_SYSCTL_THR2, 16, 8, DIV_DOUBLE_ONE_BASED),
+		MUX(K210_SYSCTL_SEL0, 15)
+	},
+};
+
+/*
+ * PLL control register bits.
+ */
+#define K210_PLL_CLKR		GENMASK(3, 0)
+#define K210_PLL_CLKF		GENMASK(9, 4)
+#define K210_PLL_CLKOD		GENMASK(13, 10)
+#define K210_PLL_BWADJ		GENMASK(19, 14)
+#define K210_PLL_RESET		(1 << 20)
+#define K210_PLL_PWRD		(1 << 21)
+#define K210_PLL_INTFB		(1 << 22)
+#define K210_PLL_BYPASS		(1 << 23)
+#define K210_PLL_TEST		(1 << 24)
+#define K210_PLL_EN		(1 << 25)
+#define K210_PLL_SEL		GENMASK(27, 26) /* PLL2 only */
+
+/*
+ * PLL lock register bits.
+ */
+#define K210_PLL_LOCK		0
+#define K210_PLL_CLEAR_SLIP	2
+#define K210_PLL_TEST_OUT	3
+
+/*
+ * Clock selector register bits.
+ */
+#define K210_ACLK_SEL		BIT(0)
+#define K210_ACLK_DIV		GENMASK(2, 1)
+
+/*
+ * PLLs.
+ */
+enum k210_pll_id {
+	K210_PLL0, K210_PLL1, K210_PLL2, K210_PLL_NUM
+};
+
+struct k210_pll {
+enum k210_pll_id id;
+	/* PLL setup register */
+	void __iomem *reg;
+
+	/* Common lock register */
+	void __iomem *lock;
+
+	/* Offset and width of lock bits */
+	u8 lock_shift;
+	u8 lock_width;
+
+	struct clk_hw hw;
+};
+#define to_k210_pll(hw)	container_of(hw, struct k210_pll, hw)
+
+struct k210_pll_cfg {
+	/* PLL setup register offset */
+	u32 reg;
+
+	/* Offset and width fo the lock bits */
+	u8 lock_shift;
+	u8 lock_width;
+
+	/* PLL setup initial factors */
+	u32 r, f, od, bwadj;
+};
+
+/*
+ * PLL factors:
+ * By default, PLL0 runs at 780 MHz and PLL1 at 299 MHz.
+ * The first 2 sram banks depend on ACLK/CPU clock which is by default
+ * PLL0 rate divided by 2. Set PLL1 to 390 MHz so that the third sram
+ * bank has the same clock.
+ */
+static struct k210_pll_cfg k210_plls_cfg[] = {
+	{ K210_SYSCTL_PLL0,  0, 2, 0, 59, 1, 59 }, /* 780 MHz */
+	{ K210_SYSCTL_PLL1,  8, 1, 0, 59, 3, 59 }, /* 390 MHz */
+	{ K210_SYSCTL_PLL2, 16, 1, 0, 22, 1, 22 }, /* 299 MHz */
+};
+
+/*
+ * Clocks data.
+ */
+struct k210_clk {
+	void __iomem			*regs;
+	spinlock_t			clk_lock;
+	struct k210_pll			plls[K210_PLL_NUM];
+	struct clk_hw			aclk;
+	struct clk_hw			clks[K210_NUM_CLKS];
+	struct clk_hw_onecell_data	*clk_data;
+};
+
+static struct k210_clk *kcl;
+
+/*
+ * Set ACLK parent selector: 0 for IN0, 1 for PLL0.
+ */
+static void k210_aclk_set_selector(u8 sel)
+{
+	u32 reg = readl(kcl->regs + K210_SYSCTL_SEL0);
+
+	if (sel)
+		reg |= K210_ACLK_SEL;
+	else
+		reg &= K210_ACLK_SEL;
+	writel(reg, kcl->regs + K210_SYSCTL_SEL0);
+}
+
+static void k210_init_pll(struct k210_pll *pll, enum k210_pll_id id,
+			  void __iomem *base)
+{
+	pll->id = id;
+	pll->lock = base + K210_SYSCTL_PLL_LOCK;
+	pll->reg = base + k210_plls_cfg[id].reg;
+	pll->lock_shift = k210_plls_cfg[id].lock_shift;
+	pll->lock_width = k210_plls_cfg[id].lock_width;
+}
+
+static void k210_pll_wait_for_lock(struct k210_pll *pll)
+{
+	u32 reg, mask = GENMASK(pll->lock_width - 1, 0) << pll->lock_shift;
+
+	while (true) {
+		reg = readl(pll->lock);
+		if ((reg & mask) == mask)
+			break;
+
+		reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
+		writel(reg, pll->lock);
+	}
+}
+
+static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
+{
+	u32 reg = readl(pll->reg);
+	u32 mask = K210_PLL_PWRD | K210_PLL_EN;
+
+	if (reg & K210_PLL_RESET)
+		return false;
+
+	return (reg & mask) == mask;
+}
+
+static void k210_pll_enable_hw(struct k210_pll *pll)
+{
+	struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+
+	if (k210_pll_hw_is_enabled(pll))
+		goto unlock;
+
+	if (pll->id == K210_PLL0) {
+		/* Re-parent aclk to IN0 to keep the CPUs running */
+		k210_aclk_set_selector(0);
+	}
+
+	/* Set factors */
+	reg = readl(pll->reg);
+	reg &= ~GENMASK(19, 0);
+	reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
+	reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
+	reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
+	reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
+	reg |= K210_PLL_PWRD;
+	writel(reg, pll->reg);
+
+	/* Ensure reset is low before asserting it */
+	reg &= ~K210_PLL_RESET;
+	writel(reg, pll->reg);
+	reg |= K210_PLL_RESET;
+	writel(reg, pll->reg);
+	nop();
+	nop();
+	reg &= ~K210_PLL_RESET;
+	writel(reg, pll->reg);
+
+	k210_pll_wait_for_lock(pll);
+
+	reg &= ~K210_PLL_BYPASS;
+	reg |= K210_PLL_EN;
+	writel(reg, pll->reg);
+
+	if (pll->id == K210_PLL0) {
+		/* Re-parent aclk back to PLL0 */
+		k210_aclk_set_selector(1);
+	}
+unlock:
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+}
+
+static void k210_pll_disable_hw(struct k210_pll *pll)
+{
+	unsigned long flags;
+	u32 reg;
+
+	/*
+	 * Bypassing before powering off is important so child clocks don't stop
+	 * working. This is especially important for pll0, the indirect parent
+	 * of the cpu clock.
+	 */
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(pll->reg);
+	reg |= K210_PLL_BYPASS;
+	writel(reg, pll->reg);
+
+	reg &= ~K210_PLL_PWRD;
+	reg &= ~K210_PLL_EN;
+	writel(reg, pll->reg);
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+}
+
+static int k210_pll_enable(struct clk_hw *hw)
+{
+	k210_pll_enable_hw(to_k210_pll(hw));
+
+	return 0;
+}
+
+static void k210_pll_disable(struct clk_hw *hw)
+{
+	k210_pll_disable_hw(to_k210_pll(hw));
+}
+
+static int k210_pll_is_enabled(struct clk_hw *hw)
+{
+	return k210_pll_hw_is_enabled(to_k210_pll(hw));
+}
+
+static int k210_pll_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct k210_pll *pll = to_k210_pll(hw);
+	unsigned long flags;
+	int ret = 0;
+	u32 reg;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+
+	switch (pll->id) {
+	case K210_PLL0:
+	case K210_PLL1:
+		if (WARN_ON(index != 0))
+			ret = -EINVAL;
+		break;
+	case K210_PLL2:
+		if (WARN_ON(index > 2)) {
+			ret = -EINVAL;
+			break;
+		}
+		reg = readl(pll->reg);
+		reg &= ~K210_PLL_SEL;
+		reg |= FIELD_PREP(K210_PLL_SEL, index);
+		writel(reg, pll->reg);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+
+	return ret;
+}
+
+static u8 k210_pll_get_parent(struct clk_hw *hw)
+{
+	struct k210_pll *pll = to_k210_pll(hw);
+	u32 reg;
+
+	switch (pll->id) {
+	case K210_PLL0:
+	case K210_PLL1:
+		return 0;
+	case K210_PLL2:
+		reg = readl(pll->reg);
+		return FIELD_GET(K210_PLL_SEL, reg);
+	default:
+		return 0;
+	}
+}
+
+static unsigned long k210_pll_get_rate(struct clk_hw *hw,
+				       unsigned long parent_rate)
+{
+	struct k210_pll *pll = to_k210_pll(hw);
+	u32 reg = readl(pll->reg);
+	u32 r, f, od;
+
+	if (reg & K210_PLL_BYPASS)
+		return parent_rate;
+
+	if (!(reg & K210_PLL_PWRD))
+		return 0;
+
+	r = FIELD_GET(K210_PLL_CLKR, reg) + 1;
+	f = FIELD_GET(K210_PLL_CLKF, reg) + 1;
+	od = FIELD_GET(K210_PLL_CLKOD, reg) + 1;
+
+	return (u64)parent_rate * f / (r * od);
+}
+
+static const struct clk_ops k210_pll_ops = {
+	.enable		= k210_pll_enable,
+	.disable	= k210_pll_disable,
+	.is_enabled	= k210_pll_is_enabled,
+	.set_parent	= k210_pll_set_parent,
+	.get_parent	= k210_pll_get_parent,
+	.recalc_rate	= k210_pll_get_rate,
+};
+
+static const char *pll_parents[] = { NULL, "pll0", "pll1" };
+
+static struct clk_hw *k210_register_pll(enum k210_pll_id id, const char *name,
+				const char **parent_names, int num_parents,
+				unsigned long flags)
+{
+	struct k210_pll *pll = &kcl->plls[id];
+	struct clk_init_data init = {};
+	int ret;
+
+	init.name = name;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.flags = flags;
+	init.ops = &k210_pll_ops;
+	pll->hw.init = &init;
+
+	ret = clk_hw_register(NULL, &pll->hw);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &pll->hw;
+}
+
+static int k210_aclk_set_parent(struct clk_hw *hw, u8 index)
+{
+	if (WARN_ON(index > 1))
+		return -EINVAL;
+
+	k210_aclk_set_selector(index);
+
+	return 0;
+}
+
+static u8 k210_aclk_get_parent(struct clk_hw *hw)
+{
+	u32 sel = readl(kcl->regs + K210_SYSCTL_SEL0);
+
+	return (sel & K210_ACLK_SEL) ? 1 : 0;
+}
+
+static unsigned long k210_aclk_get_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	u32 reg = readl(kcl->regs + K210_SYSCTL_SEL0);
+	unsigned int shift;
+
+	if (!(reg & 0x1))
+		return parent_rate;
+
+	shift = FIELD_GET(K210_ACLK_DIV, reg);
+
+	return parent_rate / (2UL << shift);
+}
+
+static const struct clk_ops k210_aclk_ops = {
+	.set_parent	= k210_aclk_set_parent,
+	.get_parent	= k210_aclk_get_parent,
+	.recalc_rate	= k210_aclk_get_rate,
+};
+
+static const char *aclk_parents[] = { NULL, "pll0" };
+
+static struct clk_hw *k210_register_aclk(void)
+{
+	struct clk_init_data init = {};
+	int ret;
+
+	init.name = "aclk";
+	init.parent_names = aclk_parents;
+	init.num_parents = 2;
+	init.flags = 0;
+	init.ops = &k210_aclk_ops;
+	kcl->aclk.init = &init;
+
+	ret = clk_hw_register(NULL, &kcl->aclk);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &kcl->aclk;
+}
+
+#define to_k210_clk_id(hw)	((unsigned int)((hw) - &kcl->clks[0]))
+#define to_k210_clk_cfg(hw)	(&k210_clks[to_k210_clk_id(hw)])
+
+static u32 k210_clk_get_div_val(struct k210_clk_cfg *kclk)
+{
+	u32 reg = readl(kcl->regs + kclk->div_reg);
+
+	return (reg >> kclk->div_shift) & GENMASK(kclk->div_width - 1, 0);
+}
+
+static unsigned long k210_clk_divider(struct k210_clk_cfg *kclk,
+				      u32 div_val)
+{
+	switch (kclk->div_type) {
+	case DIV_ONE_BASED:
+		return div_val + 1;
+	case DIV_DOUBLE_ONE_BASED:
+		return (div_val + 1) * 2;
+	case DIV_POWER_OF_TWO:
+		return 2UL << div_val;
+	case DIV_NONE:
+	default:
+		return 0;
+	}
+}
+
+static int k210_clk_enable(struct clk_hw *hw)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long flags;
+	u32 reg;
+
+	if (!kclk->gate_reg)
+		return 0;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(kcl->regs + kclk->gate_reg);
+	reg |= BIT(kclk->gate_bit);
+	writel(reg, kcl->regs + kclk->gate_reg);
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+
+	return 0;
+}
+
+static void k210_clk_disable(struct clk_hw *hw)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long flags;
+	u32 reg;
+
+	if (!kclk->gate_reg)
+		return;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(kcl->regs + kclk->gate_reg);
+	reg &= ~BIT(kclk->gate_bit);
+	writel(reg, kcl->regs + kclk->gate_reg);
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+}
+
+static int k210_clk_is_enabled(struct clk_hw *hw)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+
+	if (!kclk->gate_reg)
+		return 1;
+
+	return readl(kcl->regs + kclk->gate_reg) & BIT(kclk->gate_bit);
+}
+
+static int k210_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long flags;
+	u32 reg;
+
+	if (!kclk->mux_reg) {
+		if (WARN_ON(index != 0))
+			return -EINVAL;
+		return 0;
+	}
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(kcl->regs + kclk->mux_reg);
+	if (index)
+		reg |= BIT(kclk->mux_bit);
+	else
+		reg &= ~BIT(kclk->mux_bit);
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+
+	return 0;
+}
+
+static u8 k210_clk_get_parent(struct clk_hw *hw)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long flags;
+	u32 reg, idx;
+
+	if (!kclk->mux_reg)
+		return 0;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(kcl->regs + kclk->mux_reg);
+	idx = (reg & BIT(kclk->mux_bit)) ? 1 : 0;
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+
+	return idx;
+}
+
+static unsigned long k210_clk_get_rate(struct clk_hw *hw,
+				       unsigned long parent_rate)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long divider;
+
+	if (!kclk->div_reg)
+		return parent_rate;
+
+	divider = k210_clk_divider(kclk, k210_clk_get_div_val(kclk));
+	if (WARN_ON(!divider))
+		return 0;
+
+	return parent_rate / divider;
+}
+
+static const struct clk_ops k210_clk_ops = {
+	.enable		= k210_clk_enable,
+	.is_enabled	= k210_clk_is_enabled,
+	.disable	= k210_clk_disable,
+	.set_parent	= k210_clk_set_parent,
+	.get_parent	= k210_clk_get_parent,
+	.recalc_rate	= k210_clk_get_rate,
+};
+
+static const char *mux_parents[] = { NULL, "pll0" };
+
+static struct clk_hw *k210_register_clk(int id, const char *name,
+					const char *parent, unsigned long flags)
+{
+	struct clk_init_data init = {};
+	int ret;
+
+	init.name = name;
+	if (parent) {
+		init.parent_names = &parent;
+		init.num_parents = 1;
+	} else {
+		init.parent_names = mux_parents;
+		init.num_parents = 2;
+	}
+	init.flags = flags;
+	init.ops = &k210_clk_ops;
+	kcl->clks[id].init = &init;
+
+	ret = clk_hw_register(NULL, &kcl->clks[id]);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &kcl->clks[id];
+}
+
+static void __init k210_clk_init(struct device_node *np)
+{
+	struct device_node *sysctl_np;
+	struct clk *in0_clk;
+	const char *in0;
+	struct clk_hw **hws;
+	int i, ret;
+
+	kcl = kzalloc(sizeof(*kcl), GFP_KERNEL);
+	if (!kcl)
+		return;
+
+	sysctl_np = of_find_compatible_node(NULL, NULL, "canaan,k210-sysctl");
+	if (!sysctl_np || sysctl_np != np->parent)
+		goto err;
+
+	kcl->regs = of_iomap(sysctl_np, 0);
+	if (!kcl->regs)
+		goto err;
+
+	kcl->clk_data = kzalloc(struct_size(kcl->clk_data, hws, K210_NUM_CLKS),
+				GFP_KERNEL);
+	if (!kcl->clk_data)
+		goto err;
+
+	for (i = 0; i < K210_PLL_NUM; i++)
+		k210_init_pll(&kcl->plls[i], i, kcl->regs);
+	spin_lock_init(&kcl->clk_lock);
+	kcl->clk_data->num = K210_NUM_CLKS;
+	hws = kcl->clk_data->hws;
+	for (i = 1; i < K210_NUM_CLKS; i++)
+		hws[i] = ERR_PTR(-EPROBE_DEFER);
+
+	/*
+	 * in0 is the system base fixed-rate 26MHz oscillator which
+	 * should already be defined by the device tree. If it is not,
+	 * create it here.
+	 */
+	in0_clk = of_clk_get(np, 0);
+	if (IS_ERR(in0_clk)) {
+		pr_warn("%pOFP: in0 oscillator not found\n", np);
+		hws[K210_CLK_IN0] =
+			clk_hw_register_fixed_rate(NULL, "in0", NULL,
+						   0, K210_IN0_RATE);
+	} else {
+		hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
+	}
+	if (IS_ERR(hws[K210_CLK_IN0])) {
+		pr_err("%pOFP: failed to get base oscillator\n", np);
+		goto err;
+	}
+
+	in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
+	aclk_parents[0] = in0;
+	pll_parents[0] = in0;
+	mux_parents[0] = in0;
+
+	/* PLLs */
+	hws[K210_CLK_PLL0] =
+		k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
+	hws[K210_CLK_PLL1] =
+		k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
+	hws[K210_CLK_PLL2] =
+		k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
+
+	/* aclk: muxed of in0 and pll0_d, no gate */
+	hws[K210_CLK_ACLK] = k210_register_aclk();
+
+	/*
+	 * Clocks with aclk as source: the CPU clock is obviously critical.
+	 * So is the CLINT clock as the scheduler clocksource.
+	 */
+	hws[K210_CLK_CPU] =
+		k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
+	hws[K210_CLK_CLINT] =
+		clk_hw_register_fixed_factor(NULL, "clint", "aclk",
+					     CLK_IS_CRITICAL, 1, 50);
+	hws[K210_CLK_DMA] =
+		k210_register_clk(K210_CLK_DMA, "dma", "aclk", 0);
+	hws[K210_CLK_FFT] =
+		k210_register_clk(K210_CLK_FFT, "fft", "aclk", 0);
+	hws[K210_CLK_ROM] =
+		k210_register_clk(K210_CLK_ROM, "rom", "aclk", 0);
+	hws[K210_CLK_DVP] =
+		k210_register_clk(K210_CLK_DVP, "dvp", "aclk", 0);
+	hws[K210_CLK_APB0] =
+		k210_register_clk(K210_CLK_APB0, "apb0", "aclk", 0);
+	hws[K210_CLK_APB1] =
+		k210_register_clk(K210_CLK_APB1, "apb1", "aclk", 0);
+	hws[K210_CLK_APB2] =
+		k210_register_clk(K210_CLK_APB2, "apb2", "aclk", 0);
+
+	/*
+	 * There is no sram driver taking a ref on the sram banks clocks.
+	 * So make them critical so they are not disabled due to being unused
+	 * as seen by the clock infrastructure.
+	 */
+	hws[K210_CLK_SRAM0] =
+		k210_register_clk(K210_CLK_SRAM0,
+				  "sram0", "aclk", CLK_IS_CRITICAL);
+	hws[K210_CLK_SRAM1] =
+		k210_register_clk(K210_CLK_SRAM1,
+				  "sram1", "aclk", CLK_IS_CRITICAL);
+
+	/* Clocks with PLL0 as source */
+	hws[K210_CLK_SPI0] =
+		k210_register_clk(K210_CLK_SPI0, "spi0", "pll0", 0);
+	hws[K210_CLK_SPI1] =
+		 k210_register_clk(K210_CLK_SPI1, "spi1", "pll0", 0);
+	hws[K210_CLK_SPI2] =
+		 k210_register_clk(K210_CLK_SPI2, "spi2", "pll0", 0);
+	hws[K210_CLK_I2C0] =
+		 k210_register_clk(K210_CLK_I2C0, "i2c0", "pll0", 0);
+	hws[K210_CLK_I2C1] =
+		 k210_register_clk(K210_CLK_I2C1, "i2c1", "pll0", 0);
+	hws[K210_CLK_I2C2] =
+		 k210_register_clk(K210_CLK_I2C2, "i2c2", "pll0", 0);
+
+	/*
+	 * Clocks with PLL1 as source: there is only the AI clock for the
+	 * (unused) KPU device. As this clock also drives the aisram bank
+	 * which is used as general memory, make it critical.
+	 */
+	 hws[K210_CLK_AI] =
+		 k210_register_clk(K210_CLK_AI, "ai", "pll1", CLK_IS_CRITICAL);
+
+	/* Clocks with PLL2 as source */
+	hws[K210_CLK_I2S0] =
+		 k210_register_clk(K210_CLK_I2S0, "i2s0", "pll2", 0);
+	hws[K210_CLK_I2S1] =
+		 k210_register_clk(K210_CLK_I2S1, "i2s1", "pll2", 0);
+	hws[K210_CLK_I2S2] =
+		k210_register_clk(K210_CLK_I2S2, "i2s2", "pll2", 0);
+	hws[K210_CLK_I2S0_M] =
+		k210_register_clk(K210_CLK_I2S0_M, "i2s0_m", "pll2", 0);
+	hws[K210_CLK_I2S1_M] =
+		k210_register_clk(K210_CLK_I2S1_M, "i2s1_m", "pll2", 0);
+	hws[K210_CLK_I2S2_M] =
+		k210_register_clk(K210_CLK_I2S2_M, "i2s2_m", "pll2", 0);
+
+	/* Clocks with IN0 as source */
+	hws[K210_CLK_WDT0] =
+		k210_register_clk(K210_CLK_WDT0, "wdt0", in0, 0);
+	hws[K210_CLK_WDT1] =
+		 k210_register_clk(K210_CLK_WDT1, "wdt1", in0, 0);
+	hws[K210_CLK_RTC] =
+		 k210_register_clk(K210_CLK_RTC, "rtc", in0, 0);
+
+	/* Clocks with APB0 as source */
+	hws[K210_CLK_GPIO] =
+		k210_register_clk(K210_CLK_GPIO, "gpio", "apb0", 0);
+	hws[K210_CLK_UART1] =
+		k210_register_clk(K210_CLK_UART1, "uart1", "apb0", 0);
+	hws[K210_CLK_UART2] =
+		k210_register_clk(K210_CLK_UART2, "uart2", "apb0", 0);
+	hws[K210_CLK_UART3] =
+		k210_register_clk(K210_CLK_UART3, "uart3", "apb0", 0);
+	hws[K210_CLK_FPIOA] =
+		k210_register_clk(K210_CLK_FPIOA, "fpioa", "apb0", 0);
+	hws[K210_CLK_SHA] =
+		k210_register_clk(K210_CLK_SHA, "sha", "apb0", 0);
+
+	/* Clocks with APB1 as source */
+	hws[K210_CLK_AES] =
+		 k210_register_clk(K210_CLK_AES, "aes", "apb1", 0);
+	hws[K210_CLK_OTP] =
+		 k210_register_clk(K210_CLK_OTP, "otp", "apb1", 0);
+
+	/* Muxed clocks with in0/pll0 as source */
+	hws[K210_CLK_SPI3] =
+		k210_register_clk(K210_CLK_SPI3, "spi3", NULL, 0);
+	hws[K210_CLK_TIMER0] =
+		k210_register_clk(K210_CLK_TIMER0, "timer0", NULL, 0);
+	hws[K210_CLK_TIMER1] =
+		k210_register_clk(K210_CLK_TIMER1, "timer1", NULL, 0);
+	hws[K210_CLK_TIMER2] =
+		k210_register_clk(K210_CLK_TIMER2, "timer2", NULL, 0);
+
+	for (i = 0; i < K210_NUM_CLKS; i++) {
+		if (IS_ERR(hws[i])) {
+			pr_err("%pOFP: register clock %d failed %ld\n",
+			       np, i, PTR_ERR(hws[i]));
+			goto err;
+		}
+	}
+
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
+	if (ret)
+		pr_err("%pOFP: add clock provider failed %d\n", np, ret);
+	else
+		pr_info("%pOFP: CPU running at %lu MHz\n",
+			np, clk_hw_get_rate(hws[K210_CLK_CPU]) / 1000000);
+
+	return;
+err:
+	pr_err("%pOFP: clock initialization failed\n", np);
+	iounmap(kcl->regs);
+	kfree(kcl->clk_data);
+	kfree(kcl);
+	kcl = NULL;
+}
+
+CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
+
+/*
+ * Enable PLL1 to be able to use the AI SRAM.
+ */
+void __init k210_clk_early_init(void __iomem *regs)
+{
+	struct k210_pll pll1;
+
+	/* Make sure aclk selector is set to PLL0 */
+	k210_aclk_set_selector(1);
+
+	/* Startup PLL1 to enable the aisram bank for general memory use */
+	k210_init_pll(&pll1, K210_PLL1, regs);
+	k210_pll_enable_hw(&pll1);
+}
diff --git a/drivers/soc/canaan/Kconfig b/drivers/soc/canaan/Kconfig
index 5232d13f07e5..86f7d50302a5 100644
--- a/drivers/soc/canaan/Kconfig
+++ b/drivers/soc/canaan/Kconfig
@@ -1,14 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
 
-if SOC_CANAAN
-
-config K210_SYSCTL
+config SOC_K210_SYSCTL
 	bool "Canaan Kendryte K210 SoC system controller"
-	default y
-	depends on RISCV
-	help
-	  Enables controlling the K210 various clocks and to enable
-	  general purpose use of the extra 2MB of SRAM normally
-	  reserved for the AI engine.
-
-endif
+	depends on RISCV && SOC_CANAAN && OF
+        select PM
+        select SIMPLE_PM_BUS
+        select SYSCON
+        select MFD_SYSCON
diff --git a/drivers/soc/canaan/Makefile b/drivers/soc/canaan/Makefile
index 002d9ce95c0d..570280ad7967 100644
--- a/drivers/soc/canaan/Makefile
+++ b/drivers/soc/canaan/Makefile
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_K210_SYSCTL)	+= k210-sysctl.o
+obj-$(CONFIG_SOC_K210_SYSCTL)	+= k210-sysctl.o
diff --git a/drivers/soc/canaan/k210-sysctl.c b/drivers/soc/canaan/k210-sysctl.c
index 4608fbca20e1..b01647fb661f 100644
--- a/drivers/soc/canaan/k210-sysctl.c
+++ b/drivers/soc/canaan/k210-sysctl.c
@@ -3,205 +3,45 @@
  * Copyright (c) 2019 Christoph Hellwig.
  * Copyright (c) 2019 Western Digital Corporation or its affiliates.
  */
-#include <linux/types.h>
 #include <linux/io.h>
-#include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/bitfield.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
 #include <asm/soc.h>
 
-#define K210_SYSCTL_CLK0_FREQ		26000000UL
+#include <soc/canaan/k210-sysctl.h>
 
-/* Registers base address */
-#define K210_SYSCTL_SYSCTL_BASE_ADDR	0x50440000ULL
-
-/* Registers */
-#define K210_SYSCTL_PLL0		0x08
-#define K210_SYSCTL_PLL1		0x0c
-/* clkr: 4bits, clkf1: 6bits, clkod: 4bits, bwadj: 4bits */
-#define   PLL_RESET		(1 << 20)
-#define   PLL_PWR		(1 << 21)
-#define   PLL_INTFB		(1 << 22)
-#define   PLL_BYPASS		(1 << 23)
-#define   PLL_TEST		(1 << 24)
-#define   PLL_OUT_EN		(1 << 25)
-#define   PLL_TEST_EN		(1 << 26)
-#define K210_SYSCTL_PLL_LOCK		0x18
-#define   PLL0_LOCK1		(1 << 0)
-#define   PLL0_LOCK2		(1 << 1)
-#define   PLL0_SLIP_CLEAR	(1 << 2)
-#define   PLL0_TEST_CLK_OUT	(1 << 3)
-#define   PLL1_LOCK1		(1 << 8)
-#define   PLL1_LOCK2		(1 << 9)
-#define   PLL1_SLIP_CLEAR	(1 << 10)
-#define   PLL1_TEST_CLK_OUT	(1 << 11)
-#define   PLL2_LOCK1		(1 << 16)
-#define   PLL2_LOCK2		(1 << 16)
-#define   PLL2_SLIP_CLEAR	(1 << 18)
-#define   PLL2_TEST_CLK_OUT	(1 << 19)
-#define K210_SYSCTL_CLKSEL0	0x20
-#define   CLKSEL_ACLK		(1 << 0)
-#define K210_SYSCTL_CLKEN_CENT		0x28
-#define   CLKEN_CPU		(1 << 0)
-#define   CLKEN_SRAM0		(1 << 1)
-#define   CLKEN_SRAM1		(1 << 2)
-#define   CLKEN_APB0		(1 << 3)
-#define   CLKEN_APB1		(1 << 4)
-#define   CLKEN_APB2		(1 << 5)
-#define K210_SYSCTL_CLKEN_PERI		0x2c
-#define   CLKEN_ROM		(1 << 0)
-#define   CLKEN_DMA		(1 << 1)
-#define   CLKEN_AI		(1 << 2)
-#define   CLKEN_DVP		(1 << 3)
-#define   CLKEN_FFT		(1 << 4)
-#define   CLKEN_GPIO		(1 << 5)
-#define   CLKEN_SPI0		(1 << 6)
-#define   CLKEN_SPI1		(1 << 7)
-#define   CLKEN_SPI2		(1 << 8)
-#define   CLKEN_SPI3		(1 << 9)
-#define   CLKEN_I2S0		(1 << 10)
-#define   CLKEN_I2S1		(1 << 11)
-#define   CLKEN_I2S2		(1 << 12)
-#define   CLKEN_I2C0		(1 << 13)
-#define   CLKEN_I2C1		(1 << 14)
-#define   CLKEN_I2C2		(1 << 15)
-#define   CLKEN_UART1		(1 << 16)
-#define   CLKEN_UART2		(1 << 17)
-#define   CLKEN_UART3		(1 << 18)
-#define   CLKEN_AES		(1 << 19)
-#define   CLKEN_FPIO		(1 << 20)
-#define   CLKEN_TIMER0		(1 << 21)
-#define   CLKEN_TIMER1		(1 << 22)
-#define   CLKEN_TIMER2		(1 << 23)
-#define   CLKEN_WDT0		(1 << 24)
-#define   CLKEN_WDT1		(1 << 25)
-#define   CLKEN_SHA		(1 << 26)
-#define   CLKEN_OTP		(1 << 27)
-#define   CLKEN_RTC		(1 << 29)
-
-struct k210_sysctl {
-	void __iomem		*regs;
-	struct clk_hw		hw;
-};
-
-static void k210_set_bits(u32 val, void __iomem *reg)
-{
-	writel(readl(reg) | val, reg);
-}
-
-static void k210_clear_bits(u32 val, void __iomem *reg)
-{
-	writel(readl(reg) & ~val, reg);
-}
-
-static void k210_pll1_enable(void __iomem *regs)
+static int __init k210_sysctl_probe(struct platform_device *pdev)
 {
-	u32 val;
+	struct device *dev = &pdev->dev;
+	struct clk *pclk;
+	int ret;
 
-	val = readl(regs + K210_SYSCTL_PLL1);
-	val &= ~GENMASK(19, 0);				/* clkr1 = 0 */
-	val |= FIELD_PREP(GENMASK(9, 4), 0x3B);		/* clkf1 = 59 */
-	val |= FIELD_PREP(GENMASK(13, 10), 0x3);	/* clkod1 = 3 */
-	val |= FIELD_PREP(GENMASK(19, 14), 0x3B);	/* bwadj1 = 59 */
-	writel(val, regs + K210_SYSCTL_PLL1);
+	dev_info(dev, "K210 system controller\n");
 
-	k210_clear_bits(PLL_BYPASS, regs + K210_SYSCTL_PLL1);
-	k210_set_bits(PLL_PWR, regs + K210_SYSCTL_PLL1);
-
-	/*
-	 * Reset the pll. The magic NOPs come from the Kendryte reference SDK.
-	 */
-	k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
-	k210_set_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
-	nop();
-	nop();
-	k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
-
-	for (;;) {
-		val = readl(regs + K210_SYSCTL_PLL_LOCK);
-		if (val & PLL1_LOCK2)
-			break;
-		writel(val | PLL1_SLIP_CLEAR, regs + K210_SYSCTL_PLL_LOCK);
+	/* Get power bus clock */
+	pclk = devm_clk_get(dev, NULL);
+	if (IS_ERR(pclk)) {
+		dev_err(dev, "Get bus clock failed\n");
+		return PTR_ERR(pclk);
 	}
 
-	k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL1);
-}
-
-static unsigned long k210_sysctl_clk_recalc_rate(struct clk_hw *hw,
-		unsigned long parent_rate)
-{
-	struct k210_sysctl *s = container_of(hw, struct k210_sysctl, hw);
-	u32 clksel0, pll0;
-	u64 pll0_freq, clkr0, clkf0, clkod0;
-
-	/*
-	 * If the clock selector is not set, use the base frequency.
-	 * Otherwise, use PLL0 frequency with a frequency divisor.
-	 */
-	clksel0 = readl(s->regs + K210_SYSCTL_CLKSEL0);
-	if (!(clksel0 & CLKSEL_ACLK))
-		return K210_SYSCTL_CLK0_FREQ;
-
-	/*
-	 * Get PLL0 frequency:
-	 * freq = base frequency * clkf0 / (clkr0 * clkod0)
-	 */
-	pll0 = readl(s->regs + K210_SYSCTL_PLL0);
-	clkr0 = 1 + FIELD_GET(GENMASK(3, 0), pll0);
-	clkf0 = 1 + FIELD_GET(GENMASK(9, 4), pll0);
-	clkod0 = 1 + FIELD_GET(GENMASK(13, 10), pll0);
-	pll0_freq = clkf0 * K210_SYSCTL_CLK0_FREQ / (clkr0 * clkod0);
-
-	/* Get the frequency divisor from the clock selector */
-	return pll0_freq / (2ULL << FIELD_GET(0x00000006, clksel0));
-}
-
-static const struct clk_ops k210_sysctl_clk_ops = {
-	.recalc_rate	= k210_sysctl_clk_recalc_rate,
-};
-
-static const struct clk_init_data k210_clk_init_data = {
-	.name		= "k210-sysctl-pll1",
-	.ops		= &k210_sysctl_clk_ops,
-};
-
-static int k210_sysctl_probe(struct platform_device *pdev)
-{
-	struct k210_sysctl *s;
-	int error;
-
-	pr_info("Kendryte K210 SoC sysctl\n");
-
-	s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
-	if (!s)
-		return -ENOMEM;
-
-	s->regs = devm_ioremap_resource(&pdev->dev,
-			platform_get_resource(pdev, IORESOURCE_MEM, 0));
-	if (IS_ERR(s->regs))
-		return PTR_ERR(s->regs);
-
-	s->hw.init = &k210_clk_init_data;
-	error = devm_clk_hw_register(&pdev->dev, &s->hw);
-	if (error) {
-		dev_err(&pdev->dev, "failed to register clk");
-		return error;
+	ret = clk_prepare_enable(pclk);
+	if (ret) {
+		dev_err(dev, "Enable bus clock failed\n");
+		return ret;
 	}
 
-	error = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
-					    &s->hw);
-	if (error) {
-		dev_err(&pdev->dev, "adding clk provider failed\n");
-		return error;
-	}
+	/* Populate children */
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		dev_err(dev, "Populate platform failed %d\n", ret);
 
-	return 0;
+	return ret;
 }
 
 static const struct of_device_id k210_sysctl_of_match[] = {
-	{ .compatible = "kendryte,k210-sysctl", },
+	{ .compatible = "canaan,k210-sysctl", },
 	{}
 };
 
@@ -212,12 +52,13 @@ static struct platform_driver k210_sysctl_driver = {
 	},
 	.probe			= k210_sysctl_probe,
 };
+builtin_platform_driver(k210_sysctl_driver);
 
-static int __init k210_sysctl_init(void)
-{
-	return platform_driver_register(&k210_sysctl_driver);
-}
-core_initcall(k210_sysctl_init);
+/*
+ * System controller registers base address and size.
+ */
+#define K210_SYSCTL_BASE_ADDR	0x50440000ULL
+#define K210_SYSCTL_BASE_SIZE	0x1000
 
 /*
  * This needs to be called very early during initialization, given that
@@ -225,24 +66,14 @@ core_initcall(k210_sysctl_init);
  */
 static void __init k210_soc_early_init(const void *fdt)
 {
-	void __iomem *regs;
-
-	regs = ioremap(K210_SYSCTL_SYSCTL_BASE_ADDR, 0x1000);
-	if (!regs)
-		panic("K210 sysctl ioremap");
-
-	/* Enable PLL1 to make the KPU SRAM useable */
-	k210_pll1_enable(regs);
-
-	k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL0);
+	void __iomem *sysctl_base;
 
-	k210_set_bits(CLKEN_CPU | CLKEN_SRAM0 | CLKEN_SRAM1,
-		      regs + K210_SYSCTL_CLKEN_CENT);
-	k210_set_bits(CLKEN_ROM | CLKEN_TIMER0 | CLKEN_RTC,
-		      regs + K210_SYSCTL_CLKEN_PERI);
+	sysctl_base = ioremap(K210_SYSCTL_BASE_ADDR, K210_SYSCTL_BASE_SIZE);
+	if (!sysctl_base)
+		panic("k210-sysctl: ioremap failed");
 
-	k210_set_bits(CLKSEL_ACLK, regs + K210_SYSCTL_CLKSEL0);
+	k210_clk_early_init(sysctl_base);
 
-	iounmap(regs);
+	iounmap(sysctl_base);
 }
-SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init);
+SOC_EARLY_INIT_DECLARE(k210_soc, "canaan,kendryte-k210", k210_soc_early_init);
diff --git a/include/soc/canaan/k210-sysctl.h b/include/soc/canaan/k210-sysctl.h
new file mode 100644
index 000000000000..50b21484f7c7
--- /dev/null
+++ b/include/soc/canaan/k210-sysctl.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#ifndef K210_SYSCTL_H
+#define K210_SYSCTL_H
+
+/*
+ * Kendryte K210 SoC system controller registers offsets.
+ * Taken from Kendryte SDK (kendryte-standalone-sdk).
+ */
+#define K210_SYSCTL_GIT_ID	0x00 /* Git short commit id */
+#define K210_SYSCTL_UART_BAUD	0x04 /* Default UARTHS baud rate */
+#define K210_SYSCTL_PLL0	0x08 /* PLL0 controller */
+#define K210_SYSCTL_PLL1	0x0C /* PLL1 controller */
+#define K210_SYSCTL_PLL2	0x10 /* PLL2 controller */
+#define K210_SYSCTL_PLL_LOCK	0x18 /* PLL lock tester */
+#define K210_SYSCTL_ROM_ERROR	0x1C /* AXI ROM detector */
+#define K210_SYSCTL_SEL0	0x20 /* Clock select controller 0 */
+#define K210_SYSCTL_SEL1	0x24 /* Clock select controller 1 */
+#define K210_SYSCTL_EN_CENT	0x28 /* Central clock enable */
+#define K210_SYSCTL_EN_PERI	0x2C /* Peripheral clock enable */
+#define K210_SYSCTL_SOFT_RESET	0x30 /* Soft reset ctrl */
+#define K210_SYSCTL_PERI_RESET	0x34 /* Peripheral reset controller */
+#define K210_SYSCTL_THR0	0x38 /* Clock threshold controller 0 */
+#define K210_SYSCTL_THR1	0x3C /* Clock threshold controller 1 */
+#define K210_SYSCTL_THR2	0x40 /* Clock threshold controller 2 */
+#define K210_SYSCTL_THR3	0x44 /* Clock threshold controller 3 */
+#define K210_SYSCTL_THR4	0x48 /* Clock threshold controller 4 */
+#define K210_SYSCTL_THR5	0x4C /* Clock threshold controller 5 */
+#define K210_SYSCTL_THR6	0x50 /* Clock threshold controller 6 */
+#define K210_SYSCTL_MISC	0x54 /* Miscellaneous controller */
+#define K210_SYSCTL_PERI	0x58 /* Peripheral controller */
+#define K210_SYSCTL_SPI_SLEEP	0x5C /* SPI sleep controller */
+#define K210_SYSCTL_RESET_STAT	0x60 /* Reset source status */
+#define K210_SYSCTL_DMA_SEL0	0x64 /* DMA handshake selector 0 */
+#define K210_SYSCTL_DMA_SEL1	0x68 /* DMA handshake selector 1 */
+#define K210_SYSCTL_POWER_SEL	0x6C /* IO Power Mode Select controller */
+
+void __init k210_clk_early_init(void __iomem *regs);
+
+#endif
-- 
2.28.0


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

* [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a clock provider driver for the Canaan Kendryte K210 RISC-V SoC.
This new driver with the compatible string "canaan,k210-clk" implements
support for the full clock structure of the K210 SoC. Since it is
required for the correct operation of the SoC, this driver is
automatically selected for compilation when the SOC_CANAAN option is
selected.

With this change, the k210-sysctl driver is turned into a simple
platform driver which enables its power bus clock and triggers
populating its child nodes. This driver is also automatically selected
for compilation with the selection of SOC_CANAAN. The sysctl driver
retains the SOC early initialization code, but the implementation now
relies on the new function k210_clk_early_init() provided by the new
clk-k210 driver. This function declaration is done using the new header
file include/soc/canaan/k210-sysctl.h which also include register
definitions for the system controller.

The clock structure implemented and many of the coding ideas for the
driver come from the work by Sean Anderson on the K210 support for the
U-Boot project.

The MAINTAINERS file is updated, adding the entries "CANAAN/KENDRYTE
K210 SOC CLOCK DRIVER" and "CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER
DRIVER" with myself listed as maintainer for these drivers.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 MAINTAINERS                      |  16 +
 arch/riscv/Kconfig.socs          |   2 +
 drivers/clk/Kconfig              |   9 +
 drivers/clk/Makefile             |   1 +
 drivers/clk/clk-k210.c           | 959 +++++++++++++++++++++++++++++++
 drivers/soc/canaan/Kconfig       |  17 +-
 drivers/soc/canaan/Makefile      |   2 +-
 drivers/soc/canaan/k210-sysctl.c | 241 ++------
 include/soc/canaan/k210-sysctl.h |  43 ++
 9 files changed, 1073 insertions(+), 217 deletions(-)
 create mode 100644 drivers/clk/clk-k210.c
 create mode 100644 include/soc/canaan/k210-sysctl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 2daa6ee673f7..3da9a7a02f61 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3822,6 +3822,22 @@ W:	https://github.com/Cascoda/ca8210-linux.git
 F:	Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
 F:	drivers/net/ieee802154/ca8210.c
 
+CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-riscv@lists.infradead.org
+L:	linux-clk@vger.kernel.org (clock driver)
+S:	Maintained
+F:	Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
+F:	drivers/clk/clk-k210.c
+
+CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-riscv@lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
+F:	drivers/soc/canaan/
+F:	include/soc/canaan/
+
 CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
 M:	David Howells <dhowells@redhat.com>
 L:	linux-cachefs@redhat.com (moderated for non-subscribers)
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 88ac0d1a5da4..f2f9633087d1 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -29,6 +29,8 @@ config SOC_CANAAN
 	select SERIAL_SIFIVE if TTY
 	select SERIAL_SIFIVE_CONSOLE if TTY
 	select SIFIVE_PLIC
+	select SOC_K210_SYSCTL
+	select CLK_K210
 	help
 	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c715d4681a0b..6f10f1ecc8d6 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -359,6 +359,15 @@ config COMMON_CLK_FIXED_MMIO
 	help
 	  Support for Memory Mapped IO Fixed clocks
 
+config CLK_K210
+	bool "Clock driver for the Canaan Kendryte K210 SoC"
+	depends on RISCV && SOC_CANAAN
+	depends on COMMON_CLK && OF
+	help
+	  Support for the Kendryte K210 RISC-V SoC clocks. This option
+	  is automatically selected when the SOC_KENDRYTE option is selected
+	  in the "SOC selection" menu.
+
 source "drivers/clk/actions/Kconfig"
 source "drivers/clk/analogbits/Kconfig"
 source "drivers/clk/baikal-t1/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index da8fcf147eb1..ccac89e0fdfe 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_VT8500)		+= clk-vt8500.o
 obj-$(CONFIG_COMMON_CLK_VC5)		+= clk-versaclock5.o
 obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
+obj-$(CONFIG_CLK_K210)			+= clk-k210.o
 
 # please keep this section sorted lexicographically by directory path name
 obj-y					+= actions/
diff --git a/drivers/clk/clk-k210.c b/drivers/clk/clk-k210.c
new file mode 100644
index 000000000000..95d830a38911
--- /dev/null
+++ b/drivers/clk/clk-k210.c
@@ -0,0 +1,959 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ */
+#define pr_fmt(fmt)     "k210-clk: " fmt
+
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <asm/soc.h>
+#include <soc/canaan/k210-sysctl.h>
+
+#include <dt-bindings/clock/k210-clk.h>
+
+/*
+ * in0: fixed-rate 26MHz oscillator base clock.
+ */
+#define K210_IN0_RATE		26000000UL
+
+/*
+ * Clocks parameters.
+ */
+struct k210_clk_cfg {
+	u8 gate_reg;
+	u8 gate_bit;
+	u8 div_reg;
+	u8 div_shift;
+	u8 div_width;
+	u8 div_type;
+	u8 mux_reg;
+	u8 mux_bit;
+};
+
+enum k210_clk_div_type {
+	DIV_NONE,
+	DIV_ONE_BASED,
+	DIV_DOUBLE_ONE_BASED,
+	DIV_POWER_OF_TWO,
+};
+
+#define GATE(_reg, _bit)	\
+	.gate_reg = (_reg),	\
+	.gate_bit = (_bit)
+#define DIV(_reg, _shift, _width, _type)	\
+	.div_reg = (_reg),			\
+	.div_shift = (_shift),			\
+	.div_width = (_width),			\
+	.div_type = (_type)
+#define MUX(_reg, _bit)		\
+	.mux_reg = (_reg),	\
+	.mux_bit = (_bit)
+
+static struct k210_clk_cfg k210_clks[K210_NUM_CLKS] = {
+
+	/* Gated clocks, no mux, no divider */
+	[K210_CLK_CPU] = { GATE(K210_SYSCTL_EN_CENT, 0) },
+	[K210_CLK_DMA] = { GATE(K210_SYSCTL_EN_PERI, 1) },
+	[K210_CLK_FFT] = { GATE(K210_SYSCTL_EN_PERI, 4) },
+	[K210_CLK_GPIO] = { GATE(K210_SYSCTL_EN_PERI, 5) },
+	[K210_CLK_UART1] = { GATE(K210_SYSCTL_EN_PERI, 16) },
+	[K210_CLK_UART2] = { GATE(K210_SYSCTL_EN_PERI, 17) },
+	[K210_CLK_UART3] = { GATE(K210_SYSCTL_EN_PERI, 18) },
+	[K210_CLK_FPIOA] = { GATE(K210_SYSCTL_EN_PERI, 20) },
+	[K210_CLK_SHA] = { GATE(K210_SYSCTL_EN_PERI, 26) },
+	[K210_CLK_AES] = { GATE(K210_SYSCTL_EN_PERI, 19) },
+	[K210_CLK_OTP] = { GATE(K210_SYSCTL_EN_PERI, 27) },
+	[K210_CLK_RTC] = { GATE(K210_SYSCTL_EN_PERI, 29) },
+
+	/* Gated divider clocks */
+	[K210_CLK_SRAM0] = {
+		GATE(K210_SYSCTL_EN_CENT, 1),
+		DIV(K210_SYSCTL_THR0, 0, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_SRAM1] = {
+		GATE(K210_SYSCTL_EN_CENT, 2),
+		DIV(K210_SYSCTL_THR0, 4, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_ROM] = {
+		GATE(K210_SYSCTL_EN_PERI, 0),
+		DIV(K210_SYSCTL_THR0, 16, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_DVP] = {
+		GATE(K210_SYSCTL_EN_PERI, 3),
+		DIV(K210_SYSCTL_THR0, 12, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_APB0] = {
+		GATE(K210_SYSCTL_EN_CENT, 3),
+		DIV(K210_SYSCTL_SEL0, 3, 3, DIV_ONE_BASED)
+	},
+	[K210_CLK_APB1] = {
+		GATE(K210_SYSCTL_EN_CENT, 4),
+		DIV(K210_SYSCTL_SEL0, 6, 3, DIV_ONE_BASED)
+	},
+	[K210_CLK_APB2] = {
+		GATE(K210_SYSCTL_EN_CENT, 5),
+		DIV(K210_SYSCTL_SEL0, 9, 3, DIV_ONE_BASED)
+	},
+	[K210_CLK_AI] = {
+		GATE(K210_SYSCTL_EN_PERI, 2),
+		DIV(K210_SYSCTL_THR0, 8, 4, DIV_ONE_BASED)
+	},
+	[K210_CLK_SPI0] = {
+		GATE(K210_SYSCTL_EN_PERI, 6),
+		DIV(K210_SYSCTL_THR1, 0, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_SPI1] = {
+		GATE(K210_SYSCTL_EN_PERI, 7),
+		DIV(K210_SYSCTL_THR1, 8, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_SPI2] = {
+		GATE(K210_SYSCTL_EN_PERI, 8),
+		DIV(K210_SYSCTL_THR1, 16, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2C0] = {
+		GATE(K210_SYSCTL_EN_PERI, 13),
+		DIV(K210_SYSCTL_THR5, 8, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2C1] = {
+		GATE(K210_SYSCTL_EN_PERI, 14),
+		DIV(K210_SYSCTL_THR5, 16, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2C2] = {
+		GATE(K210_SYSCTL_EN_PERI, 15),
+		DIV(K210_SYSCTL_THR5, 24, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_WDT0] = {
+		GATE(K210_SYSCTL_EN_PERI, 24),
+		DIV(K210_SYSCTL_THR6, 0, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_WDT1] = {
+		GATE(K210_SYSCTL_EN_PERI, 25),
+		DIV(K210_SYSCTL_THR6, 8, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S0] = {
+		GATE(K210_SYSCTL_EN_PERI, 10),
+		DIV(K210_SYSCTL_THR3, 0, 16, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S1] = {
+		GATE(K210_SYSCTL_EN_PERI, 11),
+		DIV(K210_SYSCTL_THR3, 16, 16, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S2] = {
+		GATE(K210_SYSCTL_EN_PERI, 12),
+		DIV(K210_SYSCTL_THR4, 0, 16, DIV_DOUBLE_ONE_BASED)
+	},
+
+	/* Divider clocks, no gate, no mux */
+	[K210_CLK_I2S0_M] = {
+		DIV(K210_SYSCTL_THR4, 16, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S1_M] = {
+		DIV(K210_SYSCTL_THR4, 24, 8, DIV_DOUBLE_ONE_BASED)
+	},
+	[K210_CLK_I2S2_M] = {
+		DIV(K210_SYSCTL_THR4, 0, 8, DIV_DOUBLE_ONE_BASED)
+	},
+
+	/* Muxed gated divider clocks */
+	[K210_CLK_SPI3] = {
+		GATE(K210_SYSCTL_EN_PERI, 9),
+		DIV(K210_SYSCTL_THR1, 24, 8, DIV_DOUBLE_ONE_BASED),
+		MUX(K210_SYSCTL_SEL0, 12)
+	},
+	[K210_CLK_TIMER0] = {
+		GATE(K210_SYSCTL_EN_PERI, 21),
+		DIV(K210_SYSCTL_THR2,  0, 8, DIV_DOUBLE_ONE_BASED),
+		MUX(K210_SYSCTL_SEL0, 13)
+	},
+	[K210_CLK_TIMER1] = {
+		GATE(K210_SYSCTL_EN_PERI, 22),
+		DIV(K210_SYSCTL_THR2, 8, 8, DIV_DOUBLE_ONE_BASED),
+		MUX(K210_SYSCTL_SEL0, 14)
+	},
+	[K210_CLK_TIMER2] = {
+		GATE(K210_SYSCTL_EN_PERI, 23),
+		DIV(K210_SYSCTL_THR2, 16, 8, DIV_DOUBLE_ONE_BASED),
+		MUX(K210_SYSCTL_SEL0, 15)
+	},
+};
+
+/*
+ * PLL control register bits.
+ */
+#define K210_PLL_CLKR		GENMASK(3, 0)
+#define K210_PLL_CLKF		GENMASK(9, 4)
+#define K210_PLL_CLKOD		GENMASK(13, 10)
+#define K210_PLL_BWADJ		GENMASK(19, 14)
+#define K210_PLL_RESET		(1 << 20)
+#define K210_PLL_PWRD		(1 << 21)
+#define K210_PLL_INTFB		(1 << 22)
+#define K210_PLL_BYPASS		(1 << 23)
+#define K210_PLL_TEST		(1 << 24)
+#define K210_PLL_EN		(1 << 25)
+#define K210_PLL_SEL		GENMASK(27, 26) /* PLL2 only */
+
+/*
+ * PLL lock register bits.
+ */
+#define K210_PLL_LOCK		0
+#define K210_PLL_CLEAR_SLIP	2
+#define K210_PLL_TEST_OUT	3
+
+/*
+ * Clock selector register bits.
+ */
+#define K210_ACLK_SEL		BIT(0)
+#define K210_ACLK_DIV		GENMASK(2, 1)
+
+/*
+ * PLLs.
+ */
+enum k210_pll_id {
+	K210_PLL0, K210_PLL1, K210_PLL2, K210_PLL_NUM
+};
+
+struct k210_pll {
+enum k210_pll_id id;
+	/* PLL setup register */
+	void __iomem *reg;
+
+	/* Common lock register */
+	void __iomem *lock;
+
+	/* Offset and width of lock bits */
+	u8 lock_shift;
+	u8 lock_width;
+
+	struct clk_hw hw;
+};
+#define to_k210_pll(hw)	container_of(hw, struct k210_pll, hw)
+
+struct k210_pll_cfg {
+	/* PLL setup register offset */
+	u32 reg;
+
+	/* Offset and width fo the lock bits */
+	u8 lock_shift;
+	u8 lock_width;
+
+	/* PLL setup initial factors */
+	u32 r, f, od, bwadj;
+};
+
+/*
+ * PLL factors:
+ * By default, PLL0 runs at 780 MHz and PLL1 at 299 MHz.
+ * The first 2 sram banks depend on ACLK/CPU clock which is by default
+ * PLL0 rate divided by 2. Set PLL1 to 390 MHz so that the third sram
+ * bank has the same clock.
+ */
+static struct k210_pll_cfg k210_plls_cfg[] = {
+	{ K210_SYSCTL_PLL0,  0, 2, 0, 59, 1, 59 }, /* 780 MHz */
+	{ K210_SYSCTL_PLL1,  8, 1, 0, 59, 3, 59 }, /* 390 MHz */
+	{ K210_SYSCTL_PLL2, 16, 1, 0, 22, 1, 22 }, /* 299 MHz */
+};
+
+/*
+ * Clocks data.
+ */
+struct k210_clk {
+	void __iomem			*regs;
+	spinlock_t			clk_lock;
+	struct k210_pll			plls[K210_PLL_NUM];
+	struct clk_hw			aclk;
+	struct clk_hw			clks[K210_NUM_CLKS];
+	struct clk_hw_onecell_data	*clk_data;
+};
+
+static struct k210_clk *kcl;
+
+/*
+ * Set ACLK parent selector: 0 for IN0, 1 for PLL0.
+ */
+static void k210_aclk_set_selector(u8 sel)
+{
+	u32 reg = readl(kcl->regs + K210_SYSCTL_SEL0);
+
+	if (sel)
+		reg |= K210_ACLK_SEL;
+	else
+		reg &= K210_ACLK_SEL;
+	writel(reg, kcl->regs + K210_SYSCTL_SEL0);
+}
+
+static void k210_init_pll(struct k210_pll *pll, enum k210_pll_id id,
+			  void __iomem *base)
+{
+	pll->id = id;
+	pll->lock = base + K210_SYSCTL_PLL_LOCK;
+	pll->reg = base + k210_plls_cfg[id].reg;
+	pll->lock_shift = k210_plls_cfg[id].lock_shift;
+	pll->lock_width = k210_plls_cfg[id].lock_width;
+}
+
+static void k210_pll_wait_for_lock(struct k210_pll *pll)
+{
+	u32 reg, mask = GENMASK(pll->lock_width - 1, 0) << pll->lock_shift;
+
+	while (true) {
+		reg = readl(pll->lock);
+		if ((reg & mask) == mask)
+			break;
+
+		reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
+		writel(reg, pll->lock);
+	}
+}
+
+static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
+{
+	u32 reg = readl(pll->reg);
+	u32 mask = K210_PLL_PWRD | K210_PLL_EN;
+
+	if (reg & K210_PLL_RESET)
+		return false;
+
+	return (reg & mask) == mask;
+}
+
+static void k210_pll_enable_hw(struct k210_pll *pll)
+{
+	struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+
+	if (k210_pll_hw_is_enabled(pll))
+		goto unlock;
+
+	if (pll->id == K210_PLL0) {
+		/* Re-parent aclk to IN0 to keep the CPUs running */
+		k210_aclk_set_selector(0);
+	}
+
+	/* Set factors */
+	reg = readl(pll->reg);
+	reg &= ~GENMASK(19, 0);
+	reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
+	reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
+	reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
+	reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
+	reg |= K210_PLL_PWRD;
+	writel(reg, pll->reg);
+
+	/* Ensure reset is low before asserting it */
+	reg &= ~K210_PLL_RESET;
+	writel(reg, pll->reg);
+	reg |= K210_PLL_RESET;
+	writel(reg, pll->reg);
+	nop();
+	nop();
+	reg &= ~K210_PLL_RESET;
+	writel(reg, pll->reg);
+
+	k210_pll_wait_for_lock(pll);
+
+	reg &= ~K210_PLL_BYPASS;
+	reg |= K210_PLL_EN;
+	writel(reg, pll->reg);
+
+	if (pll->id == K210_PLL0) {
+		/* Re-parent aclk back to PLL0 */
+		k210_aclk_set_selector(1);
+	}
+unlock:
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+}
+
+static void k210_pll_disable_hw(struct k210_pll *pll)
+{
+	unsigned long flags;
+	u32 reg;
+
+	/*
+	 * Bypassing before powering off is important so child clocks don't stop
+	 * working. This is especially important for pll0, the indirect parent
+	 * of the cpu clock.
+	 */
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(pll->reg);
+	reg |= K210_PLL_BYPASS;
+	writel(reg, pll->reg);
+
+	reg &= ~K210_PLL_PWRD;
+	reg &= ~K210_PLL_EN;
+	writel(reg, pll->reg);
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+}
+
+static int k210_pll_enable(struct clk_hw *hw)
+{
+	k210_pll_enable_hw(to_k210_pll(hw));
+
+	return 0;
+}
+
+static void k210_pll_disable(struct clk_hw *hw)
+{
+	k210_pll_disable_hw(to_k210_pll(hw));
+}
+
+static int k210_pll_is_enabled(struct clk_hw *hw)
+{
+	return k210_pll_hw_is_enabled(to_k210_pll(hw));
+}
+
+static int k210_pll_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct k210_pll *pll = to_k210_pll(hw);
+	unsigned long flags;
+	int ret = 0;
+	u32 reg;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+
+	switch (pll->id) {
+	case K210_PLL0:
+	case K210_PLL1:
+		if (WARN_ON(index != 0))
+			ret = -EINVAL;
+		break;
+	case K210_PLL2:
+		if (WARN_ON(index > 2)) {
+			ret = -EINVAL;
+			break;
+		}
+		reg = readl(pll->reg);
+		reg &= ~K210_PLL_SEL;
+		reg |= FIELD_PREP(K210_PLL_SEL, index);
+		writel(reg, pll->reg);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+
+	return ret;
+}
+
+static u8 k210_pll_get_parent(struct clk_hw *hw)
+{
+	struct k210_pll *pll = to_k210_pll(hw);
+	u32 reg;
+
+	switch (pll->id) {
+	case K210_PLL0:
+	case K210_PLL1:
+		return 0;
+	case K210_PLL2:
+		reg = readl(pll->reg);
+		return FIELD_GET(K210_PLL_SEL, reg);
+	default:
+		return 0;
+	}
+}
+
+static unsigned long k210_pll_get_rate(struct clk_hw *hw,
+				       unsigned long parent_rate)
+{
+	struct k210_pll *pll = to_k210_pll(hw);
+	u32 reg = readl(pll->reg);
+	u32 r, f, od;
+
+	if (reg & K210_PLL_BYPASS)
+		return parent_rate;
+
+	if (!(reg & K210_PLL_PWRD))
+		return 0;
+
+	r = FIELD_GET(K210_PLL_CLKR, reg) + 1;
+	f = FIELD_GET(K210_PLL_CLKF, reg) + 1;
+	od = FIELD_GET(K210_PLL_CLKOD, reg) + 1;
+
+	return (u64)parent_rate * f / (r * od);
+}
+
+static const struct clk_ops k210_pll_ops = {
+	.enable		= k210_pll_enable,
+	.disable	= k210_pll_disable,
+	.is_enabled	= k210_pll_is_enabled,
+	.set_parent	= k210_pll_set_parent,
+	.get_parent	= k210_pll_get_parent,
+	.recalc_rate	= k210_pll_get_rate,
+};
+
+static const char *pll_parents[] = { NULL, "pll0", "pll1" };
+
+static struct clk_hw *k210_register_pll(enum k210_pll_id id, const char *name,
+				const char **parent_names, int num_parents,
+				unsigned long flags)
+{
+	struct k210_pll *pll = &kcl->plls[id];
+	struct clk_init_data init = {};
+	int ret;
+
+	init.name = name;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.flags = flags;
+	init.ops = &k210_pll_ops;
+	pll->hw.init = &init;
+
+	ret = clk_hw_register(NULL, &pll->hw);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &pll->hw;
+}
+
+static int k210_aclk_set_parent(struct clk_hw *hw, u8 index)
+{
+	if (WARN_ON(index > 1))
+		return -EINVAL;
+
+	k210_aclk_set_selector(index);
+
+	return 0;
+}
+
+static u8 k210_aclk_get_parent(struct clk_hw *hw)
+{
+	u32 sel = readl(kcl->regs + K210_SYSCTL_SEL0);
+
+	return (sel & K210_ACLK_SEL) ? 1 : 0;
+}
+
+static unsigned long k210_aclk_get_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	u32 reg = readl(kcl->regs + K210_SYSCTL_SEL0);
+	unsigned int shift;
+
+	if (!(reg & 0x1))
+		return parent_rate;
+
+	shift = FIELD_GET(K210_ACLK_DIV, reg);
+
+	return parent_rate / (2UL << shift);
+}
+
+static const struct clk_ops k210_aclk_ops = {
+	.set_parent	= k210_aclk_set_parent,
+	.get_parent	= k210_aclk_get_parent,
+	.recalc_rate	= k210_aclk_get_rate,
+};
+
+static const char *aclk_parents[] = { NULL, "pll0" };
+
+static struct clk_hw *k210_register_aclk(void)
+{
+	struct clk_init_data init = {};
+	int ret;
+
+	init.name = "aclk";
+	init.parent_names = aclk_parents;
+	init.num_parents = 2;
+	init.flags = 0;
+	init.ops = &k210_aclk_ops;
+	kcl->aclk.init = &init;
+
+	ret = clk_hw_register(NULL, &kcl->aclk);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &kcl->aclk;
+}
+
+#define to_k210_clk_id(hw)	((unsigned int)((hw) - &kcl->clks[0]))
+#define to_k210_clk_cfg(hw)	(&k210_clks[to_k210_clk_id(hw)])
+
+static u32 k210_clk_get_div_val(struct k210_clk_cfg *kclk)
+{
+	u32 reg = readl(kcl->regs + kclk->div_reg);
+
+	return (reg >> kclk->div_shift) & GENMASK(kclk->div_width - 1, 0);
+}
+
+static unsigned long k210_clk_divider(struct k210_clk_cfg *kclk,
+				      u32 div_val)
+{
+	switch (kclk->div_type) {
+	case DIV_ONE_BASED:
+		return div_val + 1;
+	case DIV_DOUBLE_ONE_BASED:
+		return (div_val + 1) * 2;
+	case DIV_POWER_OF_TWO:
+		return 2UL << div_val;
+	case DIV_NONE:
+	default:
+		return 0;
+	}
+}
+
+static int k210_clk_enable(struct clk_hw *hw)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long flags;
+	u32 reg;
+
+	if (!kclk->gate_reg)
+		return 0;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(kcl->regs + kclk->gate_reg);
+	reg |= BIT(kclk->gate_bit);
+	writel(reg, kcl->regs + kclk->gate_reg);
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+
+	return 0;
+}
+
+static void k210_clk_disable(struct clk_hw *hw)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long flags;
+	u32 reg;
+
+	if (!kclk->gate_reg)
+		return;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(kcl->regs + kclk->gate_reg);
+	reg &= ~BIT(kclk->gate_bit);
+	writel(reg, kcl->regs + kclk->gate_reg);
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+}
+
+static int k210_clk_is_enabled(struct clk_hw *hw)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+
+	if (!kclk->gate_reg)
+		return 1;
+
+	return readl(kcl->regs + kclk->gate_reg) & BIT(kclk->gate_bit);
+}
+
+static int k210_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long flags;
+	u32 reg;
+
+	if (!kclk->mux_reg) {
+		if (WARN_ON(index != 0))
+			return -EINVAL;
+		return 0;
+	}
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(kcl->regs + kclk->mux_reg);
+	if (index)
+		reg |= BIT(kclk->mux_bit);
+	else
+		reg &= ~BIT(kclk->mux_bit);
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+
+	return 0;
+}
+
+static u8 k210_clk_get_parent(struct clk_hw *hw)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long flags;
+	u32 reg, idx;
+
+	if (!kclk->mux_reg)
+		return 0;
+
+	spin_lock_irqsave(&kcl->clk_lock, flags);
+	reg = readl(kcl->regs + kclk->mux_reg);
+	idx = (reg & BIT(kclk->mux_bit)) ? 1 : 0;
+	spin_unlock_irqrestore(&kcl->clk_lock, flags);
+
+	return idx;
+}
+
+static unsigned long k210_clk_get_rate(struct clk_hw *hw,
+				       unsigned long parent_rate)
+{
+	struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
+	unsigned long divider;
+
+	if (!kclk->div_reg)
+		return parent_rate;
+
+	divider = k210_clk_divider(kclk, k210_clk_get_div_val(kclk));
+	if (WARN_ON(!divider))
+		return 0;
+
+	return parent_rate / divider;
+}
+
+static const struct clk_ops k210_clk_ops = {
+	.enable		= k210_clk_enable,
+	.is_enabled	= k210_clk_is_enabled,
+	.disable	= k210_clk_disable,
+	.set_parent	= k210_clk_set_parent,
+	.get_parent	= k210_clk_get_parent,
+	.recalc_rate	= k210_clk_get_rate,
+};
+
+static const char *mux_parents[] = { NULL, "pll0" };
+
+static struct clk_hw *k210_register_clk(int id, const char *name,
+					const char *parent, unsigned long flags)
+{
+	struct clk_init_data init = {};
+	int ret;
+
+	init.name = name;
+	if (parent) {
+		init.parent_names = &parent;
+		init.num_parents = 1;
+	} else {
+		init.parent_names = mux_parents;
+		init.num_parents = 2;
+	}
+	init.flags = flags;
+	init.ops = &k210_clk_ops;
+	kcl->clks[id].init = &init;
+
+	ret = clk_hw_register(NULL, &kcl->clks[id]);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return &kcl->clks[id];
+}
+
+static void __init k210_clk_init(struct device_node *np)
+{
+	struct device_node *sysctl_np;
+	struct clk *in0_clk;
+	const char *in0;
+	struct clk_hw **hws;
+	int i, ret;
+
+	kcl = kzalloc(sizeof(*kcl), GFP_KERNEL);
+	if (!kcl)
+		return;
+
+	sysctl_np = of_find_compatible_node(NULL, NULL, "canaan,k210-sysctl");
+	if (!sysctl_np || sysctl_np != np->parent)
+		goto err;
+
+	kcl->regs = of_iomap(sysctl_np, 0);
+	if (!kcl->regs)
+		goto err;
+
+	kcl->clk_data = kzalloc(struct_size(kcl->clk_data, hws, K210_NUM_CLKS),
+				GFP_KERNEL);
+	if (!kcl->clk_data)
+		goto err;
+
+	for (i = 0; i < K210_PLL_NUM; i++)
+		k210_init_pll(&kcl->plls[i], i, kcl->regs);
+	spin_lock_init(&kcl->clk_lock);
+	kcl->clk_data->num = K210_NUM_CLKS;
+	hws = kcl->clk_data->hws;
+	for (i = 1; i < K210_NUM_CLKS; i++)
+		hws[i] = ERR_PTR(-EPROBE_DEFER);
+
+	/*
+	 * in0 is the system base fixed-rate 26MHz oscillator which
+	 * should already be defined by the device tree. If it is not,
+	 * create it here.
+	 */
+	in0_clk = of_clk_get(np, 0);
+	if (IS_ERR(in0_clk)) {
+		pr_warn("%pOFP: in0 oscillator not found\n", np);
+		hws[K210_CLK_IN0] =
+			clk_hw_register_fixed_rate(NULL, "in0", NULL,
+						   0, K210_IN0_RATE);
+	} else {
+		hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
+	}
+	if (IS_ERR(hws[K210_CLK_IN0])) {
+		pr_err("%pOFP: failed to get base oscillator\n", np);
+		goto err;
+	}
+
+	in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
+	aclk_parents[0] = in0;
+	pll_parents[0] = in0;
+	mux_parents[0] = in0;
+
+	/* PLLs */
+	hws[K210_CLK_PLL0] =
+		k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
+	hws[K210_CLK_PLL1] =
+		k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
+	hws[K210_CLK_PLL2] =
+		k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
+
+	/* aclk: muxed of in0 and pll0_d, no gate */
+	hws[K210_CLK_ACLK] = k210_register_aclk();
+
+	/*
+	 * Clocks with aclk as source: the CPU clock is obviously critical.
+	 * So is the CLINT clock as the scheduler clocksource.
+	 */
+	hws[K210_CLK_CPU] =
+		k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
+	hws[K210_CLK_CLINT] =
+		clk_hw_register_fixed_factor(NULL, "clint", "aclk",
+					     CLK_IS_CRITICAL, 1, 50);
+	hws[K210_CLK_DMA] =
+		k210_register_clk(K210_CLK_DMA, "dma", "aclk", 0);
+	hws[K210_CLK_FFT] =
+		k210_register_clk(K210_CLK_FFT, "fft", "aclk", 0);
+	hws[K210_CLK_ROM] =
+		k210_register_clk(K210_CLK_ROM, "rom", "aclk", 0);
+	hws[K210_CLK_DVP] =
+		k210_register_clk(K210_CLK_DVP, "dvp", "aclk", 0);
+	hws[K210_CLK_APB0] =
+		k210_register_clk(K210_CLK_APB0, "apb0", "aclk", 0);
+	hws[K210_CLK_APB1] =
+		k210_register_clk(K210_CLK_APB1, "apb1", "aclk", 0);
+	hws[K210_CLK_APB2] =
+		k210_register_clk(K210_CLK_APB2, "apb2", "aclk", 0);
+
+	/*
+	 * There is no sram driver taking a ref on the sram banks clocks.
+	 * So make them critical so they are not disabled due to being unused
+	 * as seen by the clock infrastructure.
+	 */
+	hws[K210_CLK_SRAM0] =
+		k210_register_clk(K210_CLK_SRAM0,
+				  "sram0", "aclk", CLK_IS_CRITICAL);
+	hws[K210_CLK_SRAM1] =
+		k210_register_clk(K210_CLK_SRAM1,
+				  "sram1", "aclk", CLK_IS_CRITICAL);
+
+	/* Clocks with PLL0 as source */
+	hws[K210_CLK_SPI0] =
+		k210_register_clk(K210_CLK_SPI0, "spi0", "pll0", 0);
+	hws[K210_CLK_SPI1] =
+		 k210_register_clk(K210_CLK_SPI1, "spi1", "pll0", 0);
+	hws[K210_CLK_SPI2] =
+		 k210_register_clk(K210_CLK_SPI2, "spi2", "pll0", 0);
+	hws[K210_CLK_I2C0] =
+		 k210_register_clk(K210_CLK_I2C0, "i2c0", "pll0", 0);
+	hws[K210_CLK_I2C1] =
+		 k210_register_clk(K210_CLK_I2C1, "i2c1", "pll0", 0);
+	hws[K210_CLK_I2C2] =
+		 k210_register_clk(K210_CLK_I2C2, "i2c2", "pll0", 0);
+
+	/*
+	 * Clocks with PLL1 as source: there is only the AI clock for the
+	 * (unused) KPU device. As this clock also drives the aisram bank
+	 * which is used as general memory, make it critical.
+	 */
+	 hws[K210_CLK_AI] =
+		 k210_register_clk(K210_CLK_AI, "ai", "pll1", CLK_IS_CRITICAL);
+
+	/* Clocks with PLL2 as source */
+	hws[K210_CLK_I2S0] =
+		 k210_register_clk(K210_CLK_I2S0, "i2s0", "pll2", 0);
+	hws[K210_CLK_I2S1] =
+		 k210_register_clk(K210_CLK_I2S1, "i2s1", "pll2", 0);
+	hws[K210_CLK_I2S2] =
+		k210_register_clk(K210_CLK_I2S2, "i2s2", "pll2", 0);
+	hws[K210_CLK_I2S0_M] =
+		k210_register_clk(K210_CLK_I2S0_M, "i2s0_m", "pll2", 0);
+	hws[K210_CLK_I2S1_M] =
+		k210_register_clk(K210_CLK_I2S1_M, "i2s1_m", "pll2", 0);
+	hws[K210_CLK_I2S2_M] =
+		k210_register_clk(K210_CLK_I2S2_M, "i2s2_m", "pll2", 0);
+
+	/* Clocks with IN0 as source */
+	hws[K210_CLK_WDT0] =
+		k210_register_clk(K210_CLK_WDT0, "wdt0", in0, 0);
+	hws[K210_CLK_WDT1] =
+		 k210_register_clk(K210_CLK_WDT1, "wdt1", in0, 0);
+	hws[K210_CLK_RTC] =
+		 k210_register_clk(K210_CLK_RTC, "rtc", in0, 0);
+
+	/* Clocks with APB0 as source */
+	hws[K210_CLK_GPIO] =
+		k210_register_clk(K210_CLK_GPIO, "gpio", "apb0", 0);
+	hws[K210_CLK_UART1] =
+		k210_register_clk(K210_CLK_UART1, "uart1", "apb0", 0);
+	hws[K210_CLK_UART2] =
+		k210_register_clk(K210_CLK_UART2, "uart2", "apb0", 0);
+	hws[K210_CLK_UART3] =
+		k210_register_clk(K210_CLK_UART3, "uart3", "apb0", 0);
+	hws[K210_CLK_FPIOA] =
+		k210_register_clk(K210_CLK_FPIOA, "fpioa", "apb0", 0);
+	hws[K210_CLK_SHA] =
+		k210_register_clk(K210_CLK_SHA, "sha", "apb0", 0);
+
+	/* Clocks with APB1 as source */
+	hws[K210_CLK_AES] =
+		 k210_register_clk(K210_CLK_AES, "aes", "apb1", 0);
+	hws[K210_CLK_OTP] =
+		 k210_register_clk(K210_CLK_OTP, "otp", "apb1", 0);
+
+	/* Muxed clocks with in0/pll0 as source */
+	hws[K210_CLK_SPI3] =
+		k210_register_clk(K210_CLK_SPI3, "spi3", NULL, 0);
+	hws[K210_CLK_TIMER0] =
+		k210_register_clk(K210_CLK_TIMER0, "timer0", NULL, 0);
+	hws[K210_CLK_TIMER1] =
+		k210_register_clk(K210_CLK_TIMER1, "timer1", NULL, 0);
+	hws[K210_CLK_TIMER2] =
+		k210_register_clk(K210_CLK_TIMER2, "timer2", NULL, 0);
+
+	for (i = 0; i < K210_NUM_CLKS; i++) {
+		if (IS_ERR(hws[i])) {
+			pr_err("%pOFP: register clock %d failed %ld\n",
+			       np, i, PTR_ERR(hws[i]));
+			goto err;
+		}
+	}
+
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
+	if (ret)
+		pr_err("%pOFP: add clock provider failed %d\n", np, ret);
+	else
+		pr_info("%pOFP: CPU running at %lu MHz\n",
+			np, clk_hw_get_rate(hws[K210_CLK_CPU]) / 1000000);
+
+	return;
+err:
+	pr_err("%pOFP: clock initialization failed\n", np);
+	iounmap(kcl->regs);
+	kfree(kcl->clk_data);
+	kfree(kcl);
+	kcl = NULL;
+}
+
+CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
+
+/*
+ * Enable PLL1 to be able to use the AI SRAM.
+ */
+void __init k210_clk_early_init(void __iomem *regs)
+{
+	struct k210_pll pll1;
+
+	/* Make sure aclk selector is set to PLL0 */
+	k210_aclk_set_selector(1);
+
+	/* Startup PLL1 to enable the aisram bank for general memory use */
+	k210_init_pll(&pll1, K210_PLL1, regs);
+	k210_pll_enable_hw(&pll1);
+}
diff --git a/drivers/soc/canaan/Kconfig b/drivers/soc/canaan/Kconfig
index 5232d13f07e5..86f7d50302a5 100644
--- a/drivers/soc/canaan/Kconfig
+++ b/drivers/soc/canaan/Kconfig
@@ -1,14 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
 
-if SOC_CANAAN
-
-config K210_SYSCTL
+config SOC_K210_SYSCTL
 	bool "Canaan Kendryte K210 SoC system controller"
-	default y
-	depends on RISCV
-	help
-	  Enables controlling the K210 various clocks and to enable
-	  general purpose use of the extra 2MB of SRAM normally
-	  reserved for the AI engine.
-
-endif
+	depends on RISCV && SOC_CANAAN && OF
+        select PM
+        select SIMPLE_PM_BUS
+        select SYSCON
+        select MFD_SYSCON
diff --git a/drivers/soc/canaan/Makefile b/drivers/soc/canaan/Makefile
index 002d9ce95c0d..570280ad7967 100644
--- a/drivers/soc/canaan/Makefile
+++ b/drivers/soc/canaan/Makefile
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_K210_SYSCTL)	+= k210-sysctl.o
+obj-$(CONFIG_SOC_K210_SYSCTL)	+= k210-sysctl.o
diff --git a/drivers/soc/canaan/k210-sysctl.c b/drivers/soc/canaan/k210-sysctl.c
index 4608fbca20e1..b01647fb661f 100644
--- a/drivers/soc/canaan/k210-sysctl.c
+++ b/drivers/soc/canaan/k210-sysctl.c
@@ -3,205 +3,45 @@
  * Copyright (c) 2019 Christoph Hellwig.
  * Copyright (c) 2019 Western Digital Corporation or its affiliates.
  */
-#include <linux/types.h>
 #include <linux/io.h>
-#include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include <linux/bitfield.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
 #include <asm/soc.h>
 
-#define K210_SYSCTL_CLK0_FREQ		26000000UL
+#include <soc/canaan/k210-sysctl.h>
 
-/* Registers base address */
-#define K210_SYSCTL_SYSCTL_BASE_ADDR	0x50440000ULL
-
-/* Registers */
-#define K210_SYSCTL_PLL0		0x08
-#define K210_SYSCTL_PLL1		0x0c
-/* clkr: 4bits, clkf1: 6bits, clkod: 4bits, bwadj: 4bits */
-#define   PLL_RESET		(1 << 20)
-#define   PLL_PWR		(1 << 21)
-#define   PLL_INTFB		(1 << 22)
-#define   PLL_BYPASS		(1 << 23)
-#define   PLL_TEST		(1 << 24)
-#define   PLL_OUT_EN		(1 << 25)
-#define   PLL_TEST_EN		(1 << 26)
-#define K210_SYSCTL_PLL_LOCK		0x18
-#define   PLL0_LOCK1		(1 << 0)
-#define   PLL0_LOCK2		(1 << 1)
-#define   PLL0_SLIP_CLEAR	(1 << 2)
-#define   PLL0_TEST_CLK_OUT	(1 << 3)
-#define   PLL1_LOCK1		(1 << 8)
-#define   PLL1_LOCK2		(1 << 9)
-#define   PLL1_SLIP_CLEAR	(1 << 10)
-#define   PLL1_TEST_CLK_OUT	(1 << 11)
-#define   PLL2_LOCK1		(1 << 16)
-#define   PLL2_LOCK2		(1 << 16)
-#define   PLL2_SLIP_CLEAR	(1 << 18)
-#define   PLL2_TEST_CLK_OUT	(1 << 19)
-#define K210_SYSCTL_CLKSEL0	0x20
-#define   CLKSEL_ACLK		(1 << 0)
-#define K210_SYSCTL_CLKEN_CENT		0x28
-#define   CLKEN_CPU		(1 << 0)
-#define   CLKEN_SRAM0		(1 << 1)
-#define   CLKEN_SRAM1		(1 << 2)
-#define   CLKEN_APB0		(1 << 3)
-#define   CLKEN_APB1		(1 << 4)
-#define   CLKEN_APB2		(1 << 5)
-#define K210_SYSCTL_CLKEN_PERI		0x2c
-#define   CLKEN_ROM		(1 << 0)
-#define   CLKEN_DMA		(1 << 1)
-#define   CLKEN_AI		(1 << 2)
-#define   CLKEN_DVP		(1 << 3)
-#define   CLKEN_FFT		(1 << 4)
-#define   CLKEN_GPIO		(1 << 5)
-#define   CLKEN_SPI0		(1 << 6)
-#define   CLKEN_SPI1		(1 << 7)
-#define   CLKEN_SPI2		(1 << 8)
-#define   CLKEN_SPI3		(1 << 9)
-#define   CLKEN_I2S0		(1 << 10)
-#define   CLKEN_I2S1		(1 << 11)
-#define   CLKEN_I2S2		(1 << 12)
-#define   CLKEN_I2C0		(1 << 13)
-#define   CLKEN_I2C1		(1 << 14)
-#define   CLKEN_I2C2		(1 << 15)
-#define   CLKEN_UART1		(1 << 16)
-#define   CLKEN_UART2		(1 << 17)
-#define   CLKEN_UART3		(1 << 18)
-#define   CLKEN_AES		(1 << 19)
-#define   CLKEN_FPIO		(1 << 20)
-#define   CLKEN_TIMER0		(1 << 21)
-#define   CLKEN_TIMER1		(1 << 22)
-#define   CLKEN_TIMER2		(1 << 23)
-#define   CLKEN_WDT0		(1 << 24)
-#define   CLKEN_WDT1		(1 << 25)
-#define   CLKEN_SHA		(1 << 26)
-#define   CLKEN_OTP		(1 << 27)
-#define   CLKEN_RTC		(1 << 29)
-
-struct k210_sysctl {
-	void __iomem		*regs;
-	struct clk_hw		hw;
-};
-
-static void k210_set_bits(u32 val, void __iomem *reg)
-{
-	writel(readl(reg) | val, reg);
-}
-
-static void k210_clear_bits(u32 val, void __iomem *reg)
-{
-	writel(readl(reg) & ~val, reg);
-}
-
-static void k210_pll1_enable(void __iomem *regs)
+static int __init k210_sysctl_probe(struct platform_device *pdev)
 {
-	u32 val;
+	struct device *dev = &pdev->dev;
+	struct clk *pclk;
+	int ret;
 
-	val = readl(regs + K210_SYSCTL_PLL1);
-	val &= ~GENMASK(19, 0);				/* clkr1 = 0 */
-	val |= FIELD_PREP(GENMASK(9, 4), 0x3B);		/* clkf1 = 59 */
-	val |= FIELD_PREP(GENMASK(13, 10), 0x3);	/* clkod1 = 3 */
-	val |= FIELD_PREP(GENMASK(19, 14), 0x3B);	/* bwadj1 = 59 */
-	writel(val, regs + K210_SYSCTL_PLL1);
+	dev_info(dev, "K210 system controller\n");
 
-	k210_clear_bits(PLL_BYPASS, regs + K210_SYSCTL_PLL1);
-	k210_set_bits(PLL_PWR, regs + K210_SYSCTL_PLL1);
-
-	/*
-	 * Reset the pll. The magic NOPs come from the Kendryte reference SDK.
-	 */
-	k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
-	k210_set_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
-	nop();
-	nop();
-	k210_clear_bits(PLL_RESET, regs + K210_SYSCTL_PLL1);
-
-	for (;;) {
-		val = readl(regs + K210_SYSCTL_PLL_LOCK);
-		if (val & PLL1_LOCK2)
-			break;
-		writel(val | PLL1_SLIP_CLEAR, regs + K210_SYSCTL_PLL_LOCK);
+	/* Get power bus clock */
+	pclk = devm_clk_get(dev, NULL);
+	if (IS_ERR(pclk)) {
+		dev_err(dev, "Get bus clock failed\n");
+		return PTR_ERR(pclk);
 	}
 
-	k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL1);
-}
-
-static unsigned long k210_sysctl_clk_recalc_rate(struct clk_hw *hw,
-		unsigned long parent_rate)
-{
-	struct k210_sysctl *s = container_of(hw, struct k210_sysctl, hw);
-	u32 clksel0, pll0;
-	u64 pll0_freq, clkr0, clkf0, clkod0;
-
-	/*
-	 * If the clock selector is not set, use the base frequency.
-	 * Otherwise, use PLL0 frequency with a frequency divisor.
-	 */
-	clksel0 = readl(s->regs + K210_SYSCTL_CLKSEL0);
-	if (!(clksel0 & CLKSEL_ACLK))
-		return K210_SYSCTL_CLK0_FREQ;
-
-	/*
-	 * Get PLL0 frequency:
-	 * freq = base frequency * clkf0 / (clkr0 * clkod0)
-	 */
-	pll0 = readl(s->regs + K210_SYSCTL_PLL0);
-	clkr0 = 1 + FIELD_GET(GENMASK(3, 0), pll0);
-	clkf0 = 1 + FIELD_GET(GENMASK(9, 4), pll0);
-	clkod0 = 1 + FIELD_GET(GENMASK(13, 10), pll0);
-	pll0_freq = clkf0 * K210_SYSCTL_CLK0_FREQ / (clkr0 * clkod0);
-
-	/* Get the frequency divisor from the clock selector */
-	return pll0_freq / (2ULL << FIELD_GET(0x00000006, clksel0));
-}
-
-static const struct clk_ops k210_sysctl_clk_ops = {
-	.recalc_rate	= k210_sysctl_clk_recalc_rate,
-};
-
-static const struct clk_init_data k210_clk_init_data = {
-	.name		= "k210-sysctl-pll1",
-	.ops		= &k210_sysctl_clk_ops,
-};
-
-static int k210_sysctl_probe(struct platform_device *pdev)
-{
-	struct k210_sysctl *s;
-	int error;
-
-	pr_info("Kendryte K210 SoC sysctl\n");
-
-	s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
-	if (!s)
-		return -ENOMEM;
-
-	s->regs = devm_ioremap_resource(&pdev->dev,
-			platform_get_resource(pdev, IORESOURCE_MEM, 0));
-	if (IS_ERR(s->regs))
-		return PTR_ERR(s->regs);
-
-	s->hw.init = &k210_clk_init_data;
-	error = devm_clk_hw_register(&pdev->dev, &s->hw);
-	if (error) {
-		dev_err(&pdev->dev, "failed to register clk");
-		return error;
+	ret = clk_prepare_enable(pclk);
+	if (ret) {
+		dev_err(dev, "Enable bus clock failed\n");
+		return ret;
 	}
 
-	error = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
-					    &s->hw);
-	if (error) {
-		dev_err(&pdev->dev, "adding clk provider failed\n");
-		return error;
-	}
+	/* Populate children */
+	ret = devm_of_platform_populate(dev);
+	if (ret)
+		dev_err(dev, "Populate platform failed %d\n", ret);
 
-	return 0;
+	return ret;
 }
 
 static const struct of_device_id k210_sysctl_of_match[] = {
-	{ .compatible = "kendryte,k210-sysctl", },
+	{ .compatible = "canaan,k210-sysctl", },
 	{}
 };
 
@@ -212,12 +52,13 @@ static struct platform_driver k210_sysctl_driver = {
 	},
 	.probe			= k210_sysctl_probe,
 };
+builtin_platform_driver(k210_sysctl_driver);
 
-static int __init k210_sysctl_init(void)
-{
-	return platform_driver_register(&k210_sysctl_driver);
-}
-core_initcall(k210_sysctl_init);
+/*
+ * System controller registers base address and size.
+ */
+#define K210_SYSCTL_BASE_ADDR	0x50440000ULL
+#define K210_SYSCTL_BASE_SIZE	0x1000
 
 /*
  * This needs to be called very early during initialization, given that
@@ -225,24 +66,14 @@ core_initcall(k210_sysctl_init);
  */
 static void __init k210_soc_early_init(const void *fdt)
 {
-	void __iomem *regs;
-
-	regs = ioremap(K210_SYSCTL_SYSCTL_BASE_ADDR, 0x1000);
-	if (!regs)
-		panic("K210 sysctl ioremap");
-
-	/* Enable PLL1 to make the KPU SRAM useable */
-	k210_pll1_enable(regs);
-
-	k210_set_bits(PLL_OUT_EN, regs + K210_SYSCTL_PLL0);
+	void __iomem *sysctl_base;
 
-	k210_set_bits(CLKEN_CPU | CLKEN_SRAM0 | CLKEN_SRAM1,
-		      regs + K210_SYSCTL_CLKEN_CENT);
-	k210_set_bits(CLKEN_ROM | CLKEN_TIMER0 | CLKEN_RTC,
-		      regs + K210_SYSCTL_CLKEN_PERI);
+	sysctl_base = ioremap(K210_SYSCTL_BASE_ADDR, K210_SYSCTL_BASE_SIZE);
+	if (!sysctl_base)
+		panic("k210-sysctl: ioremap failed");
 
-	k210_set_bits(CLKSEL_ACLK, regs + K210_SYSCTL_CLKSEL0);
+	k210_clk_early_init(sysctl_base);
 
-	iounmap(regs);
+	iounmap(sysctl_base);
 }
-SOC_EARLY_INIT_DECLARE(generic_k210, "kendryte,k210", k210_soc_early_init);
+SOC_EARLY_INIT_DECLARE(k210_soc, "canaan,kendryte-k210", k210_soc_early_init);
diff --git a/include/soc/canaan/k210-sysctl.h b/include/soc/canaan/k210-sysctl.h
new file mode 100644
index 000000000000..50b21484f7c7
--- /dev/null
+++ b/include/soc/canaan/k210-sysctl.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#ifndef K210_SYSCTL_H
+#define K210_SYSCTL_H
+
+/*
+ * Kendryte K210 SoC system controller registers offsets.
+ * Taken from Kendryte SDK (kendryte-standalone-sdk).
+ */
+#define K210_SYSCTL_GIT_ID	0x00 /* Git short commit id */
+#define K210_SYSCTL_UART_BAUD	0x04 /* Default UARTHS baud rate */
+#define K210_SYSCTL_PLL0	0x08 /* PLL0 controller */
+#define K210_SYSCTL_PLL1	0x0C /* PLL1 controller */
+#define K210_SYSCTL_PLL2	0x10 /* PLL2 controller */
+#define K210_SYSCTL_PLL_LOCK	0x18 /* PLL lock tester */
+#define K210_SYSCTL_ROM_ERROR	0x1C /* AXI ROM detector */
+#define K210_SYSCTL_SEL0	0x20 /* Clock select controller 0 */
+#define K210_SYSCTL_SEL1	0x24 /* Clock select controller 1 */
+#define K210_SYSCTL_EN_CENT	0x28 /* Central clock enable */
+#define K210_SYSCTL_EN_PERI	0x2C /* Peripheral clock enable */
+#define K210_SYSCTL_SOFT_RESET	0x30 /* Soft reset ctrl */
+#define K210_SYSCTL_PERI_RESET	0x34 /* Peripheral reset controller */
+#define K210_SYSCTL_THR0	0x38 /* Clock threshold controller 0 */
+#define K210_SYSCTL_THR1	0x3C /* Clock threshold controller 1 */
+#define K210_SYSCTL_THR2	0x40 /* Clock threshold controller 2 */
+#define K210_SYSCTL_THR3	0x44 /* Clock threshold controller 3 */
+#define K210_SYSCTL_THR4	0x48 /* Clock threshold controller 4 */
+#define K210_SYSCTL_THR5	0x4C /* Clock threshold controller 5 */
+#define K210_SYSCTL_THR6	0x50 /* Clock threshold controller 6 */
+#define K210_SYSCTL_MISC	0x54 /* Miscellaneous controller */
+#define K210_SYSCTL_PERI	0x58 /* Peripheral controller */
+#define K210_SYSCTL_SPI_SLEEP	0x5C /* SPI sleep controller */
+#define K210_SYSCTL_RESET_STAT	0x60 /* Reset source status */
+#define K210_SYSCTL_DMA_SEL0	0x64 /* DMA handshake selector 0 */
+#define K210_SYSCTL_DMA_SEL1	0x68 /* DMA handshake selector 1 */
+#define K210_SYSCTL_POWER_SEL	0x6C /* IO Power Mode Select controller */
+
+void __init k210_clk_early_init(void __iomem *regs);
+
+#endif
-- 
2.28.0


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

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

* [PATCH v4 12/21] riscv: Add Canaan Kendryte K210 FPIOA driver
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add the pinctrl-k210.c pinctrl driver for the Canaan Kendryte K210
field programmable IO array (FPIOA) to allow configuring the SoC pin
functions. The K210 has 48 programmable pins which can take any of 256
possible functions.

This patch is inspired from the k210 pinctrl driver for the u-boot
project and contains many direct contributions from Sean Anderson.

The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
SOC FPIOA DRIVER" with myself listed as maintainer for this driver.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 MAINTAINERS                    |   7 +
 arch/riscv/Kconfig.socs        |   2 +
 drivers/pinctrl/Kconfig        |  13 +
 drivers/pinctrl/Makefile       |   1 +
 drivers/pinctrl/pinctrl-k210.c | 984 +++++++++++++++++++++++++++++++++
 5 files changed, 1007 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-k210.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3da9a7a02f61..a059ab02fa8a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3830,6 +3830,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
 F:	drivers/clk/clk-k210.c
 
+CANAAN/KENDRYTE K210 SOC FPIOA DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-riscv@lists.infradead.org
+L:	linux-gpio@vger.kernel.org (pinctrl driver)
+F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
+F:	drivers/pinctrl/pinctrl-k210.c
+
 CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
 M:	Damien Le Moal <damien.lemoal@wdc.com>
 L:	linux-riscv@lists.infradead.org
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index f2f9633087d1..68bdd664b5c2 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -31,6 +31,8 @@ config SOC_CANAAN
 	select SIFIVE_PLIC
 	select SOC_K210_SYSCTL
 	select CLK_K210
+	select PINCTRL
+	select PINCTRL_K210
 	help
 	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 815095326e2d..fec380c27075 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -374,6 +374,19 @@ config PINCTRL_OCELOT
 	select OF_GPIO
 	select REGMAP_MMIO
 
+config PINCTRL_K210
+	bool "Pinctrl driver for the Canaan Kendryte K210 SoC"
+	depends on RISCV && SOC_CANAAN
+	depends on OF && HAS_IOMEM
+	select PINMUX
+	select GENERIC_PINCONF
+	select GPIOLIB
+	select OF_GPIO
+	select REGMAP_MMIO
+	help
+	  Add support for the Canaan Kendryte K210 RISC-V SOC Field
+	  Programmable IO Array (FPIOA) controller.
+
 source "drivers/pinctrl/actions/Kconfig"
 source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f53933b2ff02..d6f913adb04a 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 obj-$(CONFIG_PINCTRL_RK805)	+= pinctrl-rk805.o
 obj-$(CONFIG_PINCTRL_OCELOT)	+= pinctrl-ocelot.o
 obj-$(CONFIG_PINCTRL_EQUILIBRIUM)   += pinctrl-equilibrium.o
+obj-$(CONFIG_PINCTRL_K210)	+= pinctrl-k210.o
 
 obj-y				+= actions/
 obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c
new file mode 100644
index 000000000000..c1fd30b3b7da
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-k210.c
@@ -0,0 +1,984 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/io.h>
+
+#include <dt-bindings/pinctrl/k210-fpioa.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinctrl-utils.h"
+
+/*
+ * The K210 only implements 8 drive levels, even though
+ * there is register space for 16
+ */
+#define K210_PC_DRIVE_MASK	GENMASK(11, 8)
+#define K210_PC_DRIVE_SHIFT	8
+#define K210_PC_DRIVE_0		(0 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_1		(1 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_2		(2 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_3		(3 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_4		(4 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_5		(5 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_6		(6 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_7		(7 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_MAX	7
+#define K210_PC_MODE_MASK	GENMASK(23, 12)
+
+/*
+ * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE)
+ * where FUNCTION_OE is a physical signal from the function.
+ */
+#define K210_PC_OE		BIT(12) /* Output Enable */
+#define K210_PC_OE_INV		BIT(13) /* INVert Output Enable */
+#define K210_PC_DO_OE		BIT(14) /* set Data Out to Output Enable sig */
+#define K210_PC_DO_INV		BIT(15) /* INVert final Data Output */
+#define K210_PC_PU		BIT(16) /* Pull Up */
+#define K210_PC_PD		BIT(17) /* Pull Down */
+/* Strong pull up not implemented on K210 */
+#define K210_PC_SL		BIT(19) /* reduce SLew rate */
+/* Same semantics as OE above */
+#define K210_PC_IE		BIT(20) /* Input Enable */
+#define K210_PC_IE_INV		BIT(21) /* INVert Input Enable */
+#define K210_PC_DI_INV		BIT(22) /* INVert Data Input */
+#define K210_PC_ST		BIT(23) /* Schmitt Trigger */
+#define K210_PC_DI		BIT(31) /* raw Data Input */
+
+#define K210_PC_BIAS_MASK	(K210_PC_PU & K210_PC_PD)
+
+#define K210_PC_MODE_IN		(K210_PC_IE | K210_PC_ST)
+#define K210_PC_MODE_OUT	(K210_PC_DRIVE_7 | K210_PC_OE)
+#define K210_PC_MODE_I2C	(K210_PC_MODE_IN | K210_PC_SL | \
+				 K210_PC_OE | K210_PC_PU)
+#define K210_PC_MODE_SCCB	(K210_PC_MODE_I2C | \
+				 K210_PC_OE_INV | K210_PC_IE_INV)
+#define K210_PC_MODE_SPI	(K210_PC_MODE_IN | K210_PC_IE_INV | \
+				 K210_PC_MODE_OUT | K210_PC_OE_INV)
+#define K210_PC_MODE_GPIO	(K210_PC_MODE_IN | K210_PC_MODE_OUT)
+
+#define K210_PG_FUNC		GENMASK(7, 0)
+#define K210_PG_DO		BIT(8)
+#define K210_PG_PIN		GENMASK(22, 16)
+
+/*
+ * struct k210_fpioa: Kendryte K210 FPIOA memory mapped registers
+ * @pins: 48 32-bits IO pin registers
+ * @tie_en: 256 (one per function) input tie enable bits
+ * @tie_val: 256 (one per function) input tie value bits
+ */
+struct k210_fpioa {
+	u32 pins[48];
+	u32 tie_en[8];
+	u32 tie_val[8];
+};
+
+struct k210_fpioa_data {
+
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+
+	struct k210_fpioa __iomem *fpioa;
+	struct regmap *sysctl_map;
+	u32 power_offset;
+	struct clk *clk;
+	struct clk *pclk;
+};
+
+#define K210_PIN_NAME(i)	("IO_" #i)
+#define K210_PIN(i)		[(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i))
+
+static const struct pinctrl_pin_desc k210_pins[] = {
+	K210_PIN(0),  K210_PIN(1),  K210_PIN(2),
+	K210_PIN(3),  K210_PIN(4),  K210_PIN(5),
+	K210_PIN(6),  K210_PIN(7),  K210_PIN(8),
+	K210_PIN(9),  K210_PIN(10), K210_PIN(11),
+	K210_PIN(12), K210_PIN(13), K210_PIN(14),
+	K210_PIN(15), K210_PIN(16), K210_PIN(17),
+	K210_PIN(18), K210_PIN(19), K210_PIN(20),
+	K210_PIN(21), K210_PIN(22), K210_PIN(23),
+	K210_PIN(24), K210_PIN(25), K210_PIN(26),
+	K210_PIN(27), K210_PIN(28), K210_PIN(29),
+	K210_PIN(30), K210_PIN(31), K210_PIN(32),
+	K210_PIN(33), K210_PIN(34), K210_PIN(35),
+	K210_PIN(36), K210_PIN(37), K210_PIN(38),
+	K210_PIN(39), K210_PIN(40), K210_PIN(41),
+	K210_PIN(42), K210_PIN(43), K210_PIN(44),
+	K210_PIN(45), K210_PIN(46), K210_PIN(47)
+};
+
+#define K210_NPINS ARRAY_SIZE(k210_pins)
+
+/*
+ * Pin groups: each of the 48 programmable pins is a group.
+ * To this are added 8 power domain groups, which for the purposes of
+ * the pin subsystem, contain no pins. The power domain groups only exist
+ * to set the power level. The id should never be used (since there are
+ * no pins 48-55).
+ */
+static const char *const k210_group_names[] = {
+	/* The first 48 groups are for pins, one each */
+	K210_PIN_NAME(0),  K210_PIN_NAME(1),  K210_PIN_NAME(2),
+	K210_PIN_NAME(3),  K210_PIN_NAME(4),  K210_PIN_NAME(5),
+	K210_PIN_NAME(6),  K210_PIN_NAME(7),  K210_PIN_NAME(8),
+	K210_PIN_NAME(9),  K210_PIN_NAME(10), K210_PIN_NAME(11),
+	K210_PIN_NAME(12), K210_PIN_NAME(13), K210_PIN_NAME(14),
+	K210_PIN_NAME(15), K210_PIN_NAME(16), K210_PIN_NAME(17),
+	K210_PIN_NAME(18), K210_PIN_NAME(19), K210_PIN_NAME(20),
+	K210_PIN_NAME(21), K210_PIN_NAME(22), K210_PIN_NAME(23),
+	K210_PIN_NAME(24), K210_PIN_NAME(25), K210_PIN_NAME(26),
+	K210_PIN_NAME(27), K210_PIN_NAME(28), K210_PIN_NAME(29),
+	K210_PIN_NAME(30), K210_PIN_NAME(31), K210_PIN_NAME(32),
+	K210_PIN_NAME(33), K210_PIN_NAME(34), K210_PIN_NAME(35),
+	K210_PIN_NAME(36), K210_PIN_NAME(37), K210_PIN_NAME(38),
+	K210_PIN_NAME(39), K210_PIN_NAME(40), K210_PIN_NAME(41),
+	K210_PIN_NAME(42), K210_PIN_NAME(43), K210_PIN_NAME(44),
+	K210_PIN_NAME(45), K210_PIN_NAME(46), K210_PIN_NAME(47),
+	[48] = "A0", [49] = "A1", [50] = "A2",
+	[51] = "B3", [52] = "B4", [53] = "B5",
+	[54] = "C6", [55] = "C7"
+};
+
+#define K210_NGROUPS	ARRAY_SIZE(k210_group_names)
+
+enum k210_pinctrl_mode_id {
+	K210_PC_DEFAULT_DISABLED,
+	K210_PC_DEFAULT_IN,
+	K210_PC_DEFAULT_IN_TIE,
+	K210_PC_DEFAULT_OUT,
+	K210_PC_DEFAULT_I2C,
+	K210_PC_DEFAULT_SCCB,
+	K210_PC_DEFAULT_SPI,
+	K210_PC_DEFAULT_GPIO,
+	K210_PC_DEFAULT_INT13,
+};
+
+#define K210_PC_DEFAULT(mode) \
+	[K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode
+
+static const u32 k210_pinconf_mode_id_to_mode[] = {
+	[K210_PC_DEFAULT_DISABLED] = 0,
+	K210_PC_DEFAULT(IN),
+	[K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN,
+	K210_PC_DEFAULT(OUT),
+	K210_PC_DEFAULT(I2C),
+	K210_PC_DEFAULT(SCCB),
+	K210_PC_DEFAULT(SPI),
+	K210_PC_DEFAULT(GPIO),
+	[K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU,
+};
+
+#undef DEFAULT
+
+/*
+ * Pin functions configuration information.
+ */
+struct k210_pcf_info {
+	char name[15];
+	u8 mode_id;
+};
+
+#define K210_FUNC(id, mode)				\
+	[K210_PCF_##id] = {				\
+		.name = #id,				\
+		.mode_id = K210_PC_DEFAULT_##mode	\
+	}
+
+static const struct k210_pcf_info k210_pcf_infos[] = {
+	K210_FUNC(JTAG_TCLK,		IN),
+	K210_FUNC(JTAG_TDI,		IN),
+	K210_FUNC(JTAG_TMS,		IN),
+	K210_FUNC(JTAG_TDO,		OUT),
+	K210_FUNC(SPI0_D0,		SPI),
+	K210_FUNC(SPI0_D1,		SPI),
+	K210_FUNC(SPI0_D2,		SPI),
+	K210_FUNC(SPI0_D3,		SPI),
+	K210_FUNC(SPI0_D4,		SPI),
+	K210_FUNC(SPI0_D5,		SPI),
+	K210_FUNC(SPI0_D6,		SPI),
+	K210_FUNC(SPI0_D7,		SPI),
+	K210_FUNC(SPI0_SS0,		OUT),
+	K210_FUNC(SPI0_SS1,		OUT),
+	K210_FUNC(SPI0_SS2,		OUT),
+	K210_FUNC(SPI0_SS3,		OUT),
+	K210_FUNC(SPI0_ARB,		IN_TIE),
+	K210_FUNC(SPI0_SCLK,		OUT),
+	K210_FUNC(UARTHS_RX,		IN),
+	K210_FUNC(UARTHS_TX,		OUT),
+	K210_FUNC(RESV6,		IN),
+	K210_FUNC(RESV7,		IN),
+	K210_FUNC(CLK_SPI1,		OUT),
+	K210_FUNC(CLK_I2C1,		OUT),
+	K210_FUNC(GPIOHS0,		GPIO),
+	K210_FUNC(GPIOHS1,		GPIO),
+	K210_FUNC(GPIOHS2,		GPIO),
+	K210_FUNC(GPIOHS3,		GPIO),
+	K210_FUNC(GPIOHS4,		GPIO),
+	K210_FUNC(GPIOHS5,		GPIO),
+	K210_FUNC(GPIOHS6,		GPIO),
+	K210_FUNC(GPIOHS7,		GPIO),
+	K210_FUNC(GPIOHS8,		GPIO),
+	K210_FUNC(GPIOHS9,		GPIO),
+	K210_FUNC(GPIOHS10,		GPIO),
+	K210_FUNC(GPIOHS11,		GPIO),
+	K210_FUNC(GPIOHS12,		GPIO),
+	K210_FUNC(GPIOHS13,		GPIO),
+	K210_FUNC(GPIOHS14,		GPIO),
+	K210_FUNC(GPIOHS15,		GPIO),
+	K210_FUNC(GPIOHS16,		GPIO),
+	K210_FUNC(GPIOHS17,		GPIO),
+	K210_FUNC(GPIOHS18,		GPIO),
+	K210_FUNC(GPIOHS19,		GPIO),
+	K210_FUNC(GPIOHS20,		GPIO),
+	K210_FUNC(GPIOHS21,		GPIO),
+	K210_FUNC(GPIOHS22,		GPIO),
+	K210_FUNC(GPIOHS23,		GPIO),
+	K210_FUNC(GPIOHS24,		GPIO),
+	K210_FUNC(GPIOHS25,		GPIO),
+	K210_FUNC(GPIOHS26,		GPIO),
+	K210_FUNC(GPIOHS27,		GPIO),
+	K210_FUNC(GPIOHS28,		GPIO),
+	K210_FUNC(GPIOHS29,		GPIO),
+	K210_FUNC(GPIOHS30,		GPIO),
+	K210_FUNC(GPIOHS31,		GPIO),
+	K210_FUNC(GPIO0,		GPIO),
+	K210_FUNC(GPIO1,		GPIO),
+	K210_FUNC(GPIO2,		GPIO),
+	K210_FUNC(GPIO3,		GPIO),
+	K210_FUNC(GPIO4,		GPIO),
+	K210_FUNC(GPIO5,		GPIO),
+	K210_FUNC(GPIO6,		GPIO),
+	K210_FUNC(GPIO7,		GPIO),
+	K210_FUNC(UART1_RX,		IN),
+	K210_FUNC(UART1_TX,		OUT),
+	K210_FUNC(UART2_RX,		IN),
+	K210_FUNC(UART2_TX,		OUT),
+	K210_FUNC(UART3_RX,		IN),
+	K210_FUNC(UART3_TX,		OUT),
+	K210_FUNC(SPI1_D0,		SPI),
+	K210_FUNC(SPI1_D1,		SPI),
+	K210_FUNC(SPI1_D2,		SPI),
+	K210_FUNC(SPI1_D3,		SPI),
+	K210_FUNC(SPI1_D4,		SPI),
+	K210_FUNC(SPI1_D5,		SPI),
+	K210_FUNC(SPI1_D6,		SPI),
+	K210_FUNC(SPI1_D7,		SPI),
+	K210_FUNC(SPI1_SS0,		OUT),
+	K210_FUNC(SPI1_SS1,		OUT),
+	K210_FUNC(SPI1_SS2,		OUT),
+	K210_FUNC(SPI1_SS3,		OUT),
+	K210_FUNC(SPI1_ARB,		IN_TIE),
+	K210_FUNC(SPI1_SCLK,		OUT),
+	K210_FUNC(SPI2_D0,		SPI),
+	K210_FUNC(SPI2_SS,		IN),
+	K210_FUNC(SPI2_SCLK,		IN),
+	K210_FUNC(I2S0_MCLK,		OUT),
+	K210_FUNC(I2S0_SCLK,		OUT),
+	K210_FUNC(I2S0_WS,		OUT),
+	K210_FUNC(I2S0_IN_D0,		IN),
+	K210_FUNC(I2S0_IN_D1,		IN),
+	K210_FUNC(I2S0_IN_D2,		IN),
+	K210_FUNC(I2S0_IN_D3,		IN),
+	K210_FUNC(I2S0_OUT_D0,		OUT),
+	K210_FUNC(I2S0_OUT_D1,		OUT),
+	K210_FUNC(I2S0_OUT_D2,		OUT),
+	K210_FUNC(I2S0_OUT_D3,		OUT),
+	K210_FUNC(I2S1_MCLK,		OUT),
+	K210_FUNC(I2S1_SCLK,		OUT),
+	K210_FUNC(I2S1_WS,		OUT),
+	K210_FUNC(I2S1_IN_D0,		IN),
+	K210_FUNC(I2S1_IN_D1,		IN),
+	K210_FUNC(I2S1_IN_D2,		IN),
+	K210_FUNC(I2S1_IN_D3,		IN),
+	K210_FUNC(I2S1_OUT_D0,		OUT),
+	K210_FUNC(I2S1_OUT_D1,		OUT),
+	K210_FUNC(I2S1_OUT_D2,		OUT),
+	K210_FUNC(I2S1_OUT_D3,		OUT),
+	K210_FUNC(I2S2_MCLK,		OUT),
+	K210_FUNC(I2S2_SCLK,		OUT),
+	K210_FUNC(I2S2_WS,		OUT),
+	K210_FUNC(I2S2_IN_D0,		IN),
+	K210_FUNC(I2S2_IN_D1,		IN),
+	K210_FUNC(I2S2_IN_D2,		IN),
+	K210_FUNC(I2S2_IN_D3,		IN),
+	K210_FUNC(I2S2_OUT_D0,		OUT),
+	K210_FUNC(I2S2_OUT_D1,		OUT),
+	K210_FUNC(I2S2_OUT_D2,		OUT),
+	K210_FUNC(I2S2_OUT_D3,		OUT),
+	K210_FUNC(RESV0,		DISABLED),
+	K210_FUNC(RESV1,		DISABLED),
+	K210_FUNC(RESV2,		DISABLED),
+	K210_FUNC(RESV3,		DISABLED),
+	K210_FUNC(RESV4,		DISABLED),
+	K210_FUNC(RESV5,		DISABLED),
+	K210_FUNC(I2C0_SCLK,		I2C),
+	K210_FUNC(I2C0_SDA,		I2C),
+	K210_FUNC(I2C1_SCLK,		I2C),
+	K210_FUNC(I2C1_SDA,		I2C),
+	K210_FUNC(I2C2_SCLK,		I2C),
+	K210_FUNC(I2C2_SDA,		I2C),
+	K210_FUNC(DVP_XCLK,		OUT),
+	K210_FUNC(DVP_RST,		OUT),
+	K210_FUNC(DVP_PWDN,		OUT),
+	K210_FUNC(DVP_VSYNC,		IN),
+	K210_FUNC(DVP_HSYNC,		IN),
+	K210_FUNC(DVP_PCLK,		IN),
+	K210_FUNC(DVP_D0,		IN),
+	K210_FUNC(DVP_D1,		IN),
+	K210_FUNC(DVP_D2,		IN),
+	K210_FUNC(DVP_D3,		IN),
+	K210_FUNC(DVP_D4,		IN),
+	K210_FUNC(DVP_D5,		IN),
+	K210_FUNC(DVP_D6,		IN),
+	K210_FUNC(DVP_D7,		IN),
+	K210_FUNC(SCCB_SCLK,		SCCB),
+	K210_FUNC(SCCB_SDA,		SCCB),
+	K210_FUNC(UART1_CTS,		IN),
+	K210_FUNC(UART1_DSR,		IN),
+	K210_FUNC(UART1_DCD,		IN),
+	K210_FUNC(UART1_RI,		IN),
+	K210_FUNC(UART1_SIR_IN,		IN),
+	K210_FUNC(UART1_DTR,		OUT),
+	K210_FUNC(UART1_RTS,		OUT),
+	K210_FUNC(UART1_OUT2,		OUT),
+	K210_FUNC(UART1_OUT1,		OUT),
+	K210_FUNC(UART1_SIR_OUT,	OUT),
+	K210_FUNC(UART1_BAUD,		OUT),
+	K210_FUNC(UART1_RE,		OUT),
+	K210_FUNC(UART1_DE,		OUT),
+	K210_FUNC(UART1_RS485_EN,	OUT),
+	K210_FUNC(UART2_CTS,		IN),
+	K210_FUNC(UART2_DSR,		IN),
+	K210_FUNC(UART2_DCD,		IN),
+	K210_FUNC(UART2_RI,		IN),
+	K210_FUNC(UART2_SIR_IN,		IN),
+	K210_FUNC(UART2_DTR,		OUT),
+	K210_FUNC(UART2_RTS,		OUT),
+	K210_FUNC(UART2_OUT2,		OUT),
+	K210_FUNC(UART2_OUT1,		OUT),
+	K210_FUNC(UART2_SIR_OUT,	OUT),
+	K210_FUNC(UART2_BAUD,		OUT),
+	K210_FUNC(UART2_RE,		OUT),
+	K210_FUNC(UART2_DE,		OUT),
+	K210_FUNC(UART2_RS485_EN,	OUT),
+	K210_FUNC(UART3_CTS,		IN),
+	K210_FUNC(UART3_DSR,		IN),
+	K210_FUNC(UART3_DCD,		IN),
+	K210_FUNC(UART3_RI,		IN),
+	K210_FUNC(UART3_SIR_IN,		IN),
+	K210_FUNC(UART3_DTR,		OUT),
+	K210_FUNC(UART3_RTS,		OUT),
+	K210_FUNC(UART3_OUT2,		OUT),
+	K210_FUNC(UART3_OUT1,		OUT),
+	K210_FUNC(UART3_SIR_OUT,	OUT),
+	K210_FUNC(UART3_BAUD,		OUT),
+	K210_FUNC(UART3_RE,		OUT),
+	K210_FUNC(UART3_DE,		OUT),
+	K210_FUNC(UART3_RS485_EN,	OUT),
+	K210_FUNC(TIMER0_TOGGLE1,	OUT),
+	K210_FUNC(TIMER0_TOGGLE2,	OUT),
+	K210_FUNC(TIMER0_TOGGLE3,	OUT),
+	K210_FUNC(TIMER0_TOGGLE4,	OUT),
+	K210_FUNC(TIMER1_TOGGLE1,	OUT),
+	K210_FUNC(TIMER1_TOGGLE2,	OUT),
+	K210_FUNC(TIMER1_TOGGLE3,	OUT),
+	K210_FUNC(TIMER1_TOGGLE4,	OUT),
+	K210_FUNC(TIMER2_TOGGLE1,	OUT),
+	K210_FUNC(TIMER2_TOGGLE2,	OUT),
+	K210_FUNC(TIMER2_TOGGLE3,	OUT),
+	K210_FUNC(TIMER2_TOGGLE4,	OUT),
+	K210_FUNC(CLK_SPI2,		OUT),
+	K210_FUNC(CLK_I2C2,		OUT),
+	K210_FUNC(INTERNAL0,		OUT),
+	K210_FUNC(INTERNAL1,		OUT),
+	K210_FUNC(INTERNAL2,		OUT),
+	K210_FUNC(INTERNAL3,		OUT),
+	K210_FUNC(INTERNAL4,		OUT),
+	K210_FUNC(INTERNAL5,		OUT),
+	K210_FUNC(INTERNAL6,		OUT),
+	K210_FUNC(INTERNAL7,		OUT),
+	K210_FUNC(INTERNAL8,		OUT),
+	K210_FUNC(INTERNAL9,		IN),
+	K210_FUNC(INTERNAL10,		IN),
+	K210_FUNC(INTERNAL11,		IN),
+	K210_FUNC(INTERNAL12,		IN),
+	K210_FUNC(INTERNAL13,		INT13),
+	K210_FUNC(INTERNAL14,		I2C),
+	K210_FUNC(INTERNAL15,		IN),
+	K210_FUNC(INTERNAL16,		IN),
+	K210_FUNC(INTERNAL17,		IN),
+	K210_FUNC(CONSTANT,		DISABLED),
+	K210_FUNC(INTERNAL18,		IN),
+	K210_FUNC(DEBUG0,		OUT),
+	K210_FUNC(DEBUG1,		OUT),
+	K210_FUNC(DEBUG2,		OUT),
+	K210_FUNC(DEBUG3,		OUT),
+	K210_FUNC(DEBUG4,		OUT),
+	K210_FUNC(DEBUG5,		OUT),
+	K210_FUNC(DEBUG6,		OUT),
+	K210_FUNC(DEBUG7,		OUT),
+	K210_FUNC(DEBUG8,		OUT),
+	K210_FUNC(DEBUG9,		OUT),
+	K210_FUNC(DEBUG10,		OUT),
+	K210_FUNC(DEBUG11,		OUT),
+	K210_FUNC(DEBUG12,		OUT),
+	K210_FUNC(DEBUG13,		OUT),
+	K210_FUNC(DEBUG14,		OUT),
+	K210_FUNC(DEBUG15,		OUT),
+	K210_FUNC(DEBUG16,		OUT),
+	K210_FUNC(DEBUG17,		OUT),
+	K210_FUNC(DEBUG18,		OUT),
+	K210_FUNC(DEBUG19,		OUT),
+	K210_FUNC(DEBUG20,		OUT),
+	K210_FUNC(DEBUG21,		OUT),
+	K210_FUNC(DEBUG22,		OUT),
+	K210_FUNC(DEBUG23,		OUT),
+	K210_FUNC(DEBUG24,		OUT),
+	K210_FUNC(DEBUG25,		OUT),
+	K210_FUNC(DEBUG26,		OUT),
+	K210_FUNC(DEBUG27,		OUT),
+	K210_FUNC(DEBUG28,		OUT),
+	K210_FUNC(DEBUG29,		OUT),
+	K210_FUNC(DEBUG30,		OUT),
+	K210_FUNC(DEBUG31,		OUT),
+};
+
+#define PIN_CONFIG_OUTPUT_INVERT	(PIN_CONFIG_END + 1)
+#define PIN_CONFIG_INPUT_INVERT		(PIN_CONFIG_END + 2)
+
+static const struct pinconf_generic_params k210_pinconf_custom_params[] = {
+	{ "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1 },
+	{ "input-polarity-invert",  PIN_CONFIG_INPUT_INVERT, 1 },
+};
+
+/*
+ * Max drive strength in uA.
+ */
+static const int k210_pinconf_drive_strength[] = {
+	[0] = 11200,
+	[1] = 16800,
+	[2] = 22300,
+	[3] = 27800,
+	[4] = 33300,
+	[5] = 38700,
+	[6] = 44100,
+	[7] = 49500,
+};
+
+static int k210_pinconf_get_drive(unsigned int max_strength_ua)
+{
+	int i;
+
+	for (i = K210_PC_DRIVE_MAX; i; i--) {
+		if (k210_pinconf_drive_strength[i] <= max_strength_ua)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static void k210_pinmux_set_pin_function(struct pinctrl_dev *pctldev,
+					 u32 pin, u32 func)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+	const struct k210_pcf_info *info = &k210_pcf_infos[func];
+	u32 mode = k210_pinconf_mode_id_to_mode[info->mode_id];
+	u32 val = func | mode;
+
+	dev_dbg(pdata->dev, "set pin %u function %s (%u) -> 0x%08x\n",
+		pin, info->name, func, val);
+
+	writel(val, &pdata->fpioa->pins[pin]);
+}
+
+static int k210_pinconf_set_param(struct pinctrl_dev *pctldev,
+				  unsigned int pin,
+				  unsigned int param, unsigned int arg)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+	u32 val = readl(&pdata->fpioa->pins[pin]);
+	int drive;
+
+	dev_dbg(pdata->dev, "set pin %u param %u, arg 0x%x\n",
+		pin, param, arg);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		val &= ~K210_PC_BIAS_MASK;
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!arg)
+			return -EINVAL;
+		val |= K210_PC_PD;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (!arg)
+			return -EINVAL;
+		val |= K210_PC_PD;
+		break;
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		arg *= 1000;
+		fallthrough;
+	case PIN_CONFIG_DRIVE_STRENGTH_UA:
+		drive = k210_pinconf_get_drive(arg);
+		if (drive < 0)
+			return drive;
+		val &= ~K210_PC_DRIVE_MASK;
+		val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive);
+		break;
+	case PIN_CONFIG_INPUT_ENABLE:
+		if (arg)
+			val |= K210_PC_IE;
+		else
+			val &= ~K210_PC_IE;
+		break;
+	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+		if (arg)
+			val |= K210_PC_ST;
+		else
+			val &= ~K210_PC_ST;
+		break;
+	case PIN_CONFIG_OUTPUT:
+		k210_pinmux_set_pin_function(pctldev, pin, K210_PCF_CONSTANT);
+		val = readl(&pdata->fpioa->pins[pin]);
+		val |= K210_PC_MODE_OUT;
+		if (!arg)
+			val |= K210_PC_DO_INV;
+		break;
+	case PIN_CONFIG_OUTPUT_ENABLE:
+		if (arg)
+			val |= K210_PC_OE;
+		else
+			val &= ~K210_PC_OE;
+		break;
+	case PIN_CONFIG_SLEW_RATE:
+		if (arg)
+			val |= K210_PC_SL;
+		else
+			val &= ~K210_PC_SL;
+		break;
+	case PIN_CONFIG_OUTPUT_INVERT:
+		if (arg)
+			val |= K210_PC_DO_INV;
+		else
+			val &= ~K210_PC_DO_INV;
+		break;
+	case PIN_CONFIG_INPUT_INVERT:
+		if (arg)
+			val |= K210_PC_DI_INV;
+		else
+			val &= ~K210_PC_DI_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel(val, &pdata->fpioa->pins[pin]);
+
+	return 0;
+}
+
+static int k210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+			    unsigned long *configs, unsigned int num_configs)
+{
+	unsigned int param, arg;
+	int i, ret;
+
+	if (WARN_ON(pin >= K210_NPINS))
+		return -EINVAL;
+
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
+		ret = k210_pinconf_set_param(pctldev, pin, param, arg);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void k210_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+				  struct seq_file *s, unsigned int pin)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+	seq_printf(s, "%#x", readl(&pdata->fpioa->pins[pin]));
+}
+
+static int k210_pinconf_group_set(struct pinctrl_dev *pctldev,
+				  unsigned int selector, unsigned long *configs,
+				  unsigned int num_configs)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int param, arg;
+	u32 bit;
+	int i;
+
+	/* Pins should be configured with pinmux, not groups*/
+	if (selector < K210_NPINS)
+		return -EINVAL;
+
+	/* Otherwise it's a power domain */
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		if (param != PIN_CONFIG_POWER_SOURCE)
+			return -EINVAL;
+
+		arg = pinconf_to_config_argument(configs[i]);
+		bit = BIT(selector - K210_NPINS);
+		regmap_update_bits(pdata->sysctl_map,
+				   pdata->power_offset,
+				   bit, arg ? bit : 0);
+	}
+
+	return 0;
+}
+
+static void k210_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+					struct seq_file *s,
+					unsigned int selector)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+	int ret;
+	u32 val;
+
+	if (selector < K210_NPINS)
+		return k210_pinconf_dbg_show(pctldev, s, selector);
+
+	ret = regmap_read(pdata->sysctl_map, pdata->power_offset, &val);
+	if (ret) {
+		dev_err(pdata->dev, "Failed to read power reg\n");
+		return;
+	}
+
+	seq_printf(s, "%s: %s V", k210_group_names[selector],
+		   val & BIT(selector - K210_NPINS) ? "1.8" : "3.3");
+}
+
+static const struct pinconf_ops k210_pinconf_ops = {
+	.is_generic = true,
+	.pin_config_set = k210_pinconf_set,
+	.pin_config_group_set = k210_pinconf_group_set,
+	.pin_config_dbg_show = k210_pinconf_dbg_show,
+	.pin_config_group_dbg_show = k210_pinconf_group_dbg_show,
+};
+
+static int k210_pinmux_get_function_count(struct pinctrl_dev *pctldev)
+{
+	return ARRAY_SIZE(k210_pcf_infos);
+}
+
+static const char *k210_pinmux_get_function_name(struct pinctrl_dev *pctldev,
+						 unsigned int selector)
+{
+	return k210_pcf_infos[selector].name;
+}
+
+static int k210_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+					   unsigned int selector,
+					   const char * const **groups,
+					   unsigned int * const num_groups)
+{
+	/* Any function can be mapped to any pin */
+	*groups = k210_group_names;
+	*num_groups = K210_NPINS;
+
+	return 0;
+}
+
+static int k210_pinmux_set_mux(struct pinctrl_dev *pctldev,
+			       unsigned int function,
+			       unsigned int group)
+{
+	/* Can't mux power domains */
+	if (group >= K210_NPINS)
+		return -EINVAL;
+
+	k210_pinmux_set_pin_function(pctldev, group, function);
+
+	return 0;
+}
+
+static const struct pinmux_ops k210_pinmux_ops = {
+	.get_functions_count = k210_pinmux_get_function_count,
+	.get_function_name = k210_pinmux_get_function_name,
+	.get_function_groups = k210_pinmux_get_function_groups,
+	.set_mux = k210_pinmux_set_mux,
+	.strict = true,
+};
+
+static int k210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	return K210_NGROUPS;
+}
+
+static const char *k210_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+					       unsigned int group)
+{
+	return k210_group_names[group];
+}
+
+static int k210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+				       unsigned int group,
+				       const unsigned int **pins,
+				       unsigned int *npins)
+{
+	if (group >= K210_NPINS) {
+		*pins = NULL;
+		*npins = 0;
+		return 0;
+	}
+
+	*pins = &k210_pins[group].number;
+	*npins = 1;
+
+	return 0;
+}
+
+static void k210_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+				      struct seq_file *s, unsigned int offset)
+{
+	seq_printf(s, "%s", dev_name(pctldev->dev));
+}
+
+static int k210_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+					  struct device_node *np,
+					  struct pinctrl_map **map,
+					  unsigned int *reserved_maps,
+					  unsigned int *num_maps)
+{
+	struct property *prop;
+	const __be32 *p;
+	int ret, pinmux_groups;
+	u32 pinmux_group;
+	unsigned long *configs = NULL;
+	unsigned int num_configs = 0;
+	unsigned int reserve = 0;
+
+	ret = of_property_count_strings(np, "groups");
+	if (!ret)
+		return pinconf_generic_dt_subnode_to_map(pctldev, np, map,
+						reserved_maps, num_maps,
+						PIN_MAP_TYPE_CONFIGS_GROUP);
+
+	pinmux_groups = of_property_count_u32_elems(np, "pinmux");
+	if (pinmux_groups <= 0) {
+		/* Ignore this node */
+		return 0;
+	}
+
+	ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
+					      &num_configs);
+	if (ret < 0) {
+		dev_err(pctldev->dev, "%pOF: could not parse node property\n",
+			np);
+		return ret;
+	}
+
+	reserve = pinmux_groups * (1 + num_configs);
+	ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps,
+					reserve);
+	if (ret < 0)
+		goto exit;
+
+	of_property_for_each_u32(np, "pinmux", prop, p, pinmux_group) {
+		const char *group_name, *func_name;
+		u32 pin = FIELD_GET(K210_PG_PIN, pinmux_group);
+		u32 func = FIELD_GET(K210_PG_FUNC, pinmux_group);
+
+		if (pin >= K210_NPINS) {
+			ret = -EINVAL;
+			goto exit;
+		}
+
+		group_name = k210_group_names[pin];
+		func_name = k210_pcf_infos[func].name;
+
+		dev_dbg(pctldev->dev, "Pinmux %s: pin %u func %s\n",
+			np->name, pin, func_name);
+
+		ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps,
+						num_maps, group_name,
+						func_name);
+		if (ret < 0) {
+			dev_err(pctldev->dev, "%pOF add mux map failed %d\n",
+				np, ret);
+			goto exit;
+		}
+
+		if (num_configs) {
+			ret = pinctrl_utils_add_map_configs(pctldev, map,
+					reserved_maps, num_maps, group_name,
+					configs, num_configs,
+					PIN_MAP_TYPE_CONFIGS_PIN);
+			if (ret < 0) {
+				dev_err(pctldev->dev,
+					"%pOF add configs map failed %d\n",
+					np, ret);
+				goto exit;
+			}
+		}
+	}
+
+	ret = 0;
+
+exit:
+	kfree(configs);
+	return ret;
+}
+
+static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+				       struct device_node *np_config,
+				       struct pinctrl_map **map,
+				       unsigned int *num_maps)
+{
+	unsigned int reserved_maps;
+	struct device_node *np;
+	int ret;
+
+	reserved_maps = 0;
+	*map = NULL;
+	*num_maps = 0;
+
+	ret = k210_pinctrl_dt_subnode_to_map(pctldev, np_config, map,
+					     &reserved_maps, num_maps);
+	if (ret < 0)
+		goto err;
+
+	for_each_available_child_of_node(np_config, np) {
+		ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map,
+						     &reserved_maps, num_maps);
+		if (ret < 0)
+			goto err;
+	}
+	return 0;
+
+err:
+	pinctrl_utils_free_map(pctldev, *map, *num_maps);
+	return ret;
+}
+
+
+static const struct pinctrl_ops k210_pinctrl_ops = {
+	.get_groups_count = k210_pinctrl_get_groups_count,
+	.get_group_name = k210_pinctrl_get_group_name,
+	.get_group_pins = k210_pinctrl_get_group_pins,
+	.pin_dbg_show = k210_pinctrl_pin_dbg_show,
+	.dt_node_to_map = k210_pinctrl_dt_node_to_map,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static struct pinctrl_desc k210_pinctrl_desc = {
+	.name = "k210-pinctrl",
+	.pins = k210_pins,
+	.npins = K210_NPINS,
+	.pctlops = &k210_pinctrl_ops,
+	.pmxops = &k210_pinmux_ops,
+	.confops = &k210_pinconf_ops,
+	.custom_params = k210_pinconf_custom_params,
+	.num_custom_params = ARRAY_SIZE(k210_pinconf_custom_params),
+};
+
+static void k210_fpioa_init_ties(struct k210_fpioa_data *pdata)
+{
+	struct k210_fpioa __iomem *fpioa = pdata->fpioa;
+	u32 val;
+	int i, j;
+
+	dev_dbg(pdata->dev, "Init pin ties\n");
+
+	/* Init pin functions input ties */
+	for (i = 0; i < ARRAY_SIZE(fpioa->tie_en); i++) {
+		val = 0;
+		for (j = 0; j < 32; j++) {
+			if (k210_pcf_infos[i * 32 + j].mode_id ==
+			    K210_PC_DEFAULT_IN_TIE) {
+				dev_dbg(pdata->dev,
+					"tie_en function %d (%s)\n",
+					i * 32 + j,
+					k210_pcf_infos[i * 32 + j].name);
+				val |= BIT(j);
+			}
+		}
+
+		/* Set value before enable */
+		writel(val, &fpioa->tie_val[i]);
+		writel(val, &fpioa->tie_en[i]);
+	}
+}
+
+static int __init k210_fpioa_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct k210_fpioa_data *pdata;
+	int ret;
+
+	dev_info(dev, "K210 FPIOA pin controller\n");
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdata->dev = dev;
+	platform_set_drvdata(pdev, pdata);
+
+	pdata->fpioa = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pdata->fpioa))
+		return PTR_ERR(pdata->fpioa);
+
+	pdata->clk = devm_clk_get(dev, "ref");
+	if (IS_ERR(pdata->clk))
+		return PTR_ERR(pdata->clk);
+
+	ret = clk_prepare_enable(pdata->clk);
+	if (ret)
+		return ret;
+
+	pdata->pclk = devm_clk_get_optional(dev, "pclk");
+	if (!IS_ERR(pdata->pclk))
+		clk_prepare_enable(pdata->pclk);
+
+	pdata->sysctl_map =
+		syscon_regmap_lookup_by_phandle_args(np,
+						"canaan,k210-sysctl-power",
+						1, &pdata->power_offset);
+	if (IS_ERR(pdata->sysctl_map))
+		return PTR_ERR(pdata->sysctl_map);
+
+	k210_fpioa_init_ties(pdata);
+
+	pdata->pctl = pinctrl_register(&k210_pinctrl_desc, dev, (void *)pdata);
+	if (IS_ERR(pdata->pctl))
+		return PTR_ERR(pdata->pctl);
+
+	return 0;
+}
+
+static const struct of_device_id k210_fpioa_dt_ids[] = {
+	{ .compatible = "canaan,k210-fpioa" },
+};
+
+static struct platform_driver k210_fpioa_driver = {
+	.probe	= k210_fpioa_probe,
+	.driver = {
+		.name		= "k210-fpioa",
+		.of_match_table	= k210_fpioa_dt_ids,
+	},
+};
+builtin_platform_driver(k210_fpioa_driver);
-- 
2.28.0


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

* [PATCH v4 12/21] riscv: Add Canaan Kendryte K210 FPIOA driver
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add the pinctrl-k210.c pinctrl driver for the Canaan Kendryte K210
field programmable IO array (FPIOA) to allow configuring the SoC pin
functions. The K210 has 48 programmable pins which can take any of 256
possible functions.

This patch is inspired from the k210 pinctrl driver for the u-boot
project and contains many direct contributions from Sean Anderson.

The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
SOC FPIOA DRIVER" with myself listed as maintainer for this driver.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 MAINTAINERS                    |   7 +
 arch/riscv/Kconfig.socs        |   2 +
 drivers/pinctrl/Kconfig        |  13 +
 drivers/pinctrl/Makefile       |   1 +
 drivers/pinctrl/pinctrl-k210.c | 984 +++++++++++++++++++++++++++++++++
 5 files changed, 1007 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-k210.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3da9a7a02f61..a059ab02fa8a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3830,6 +3830,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
 F:	drivers/clk/clk-k210.c
 
+CANAAN/KENDRYTE K210 SOC FPIOA DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-riscv@lists.infradead.org
+L:	linux-gpio@vger.kernel.org (pinctrl driver)
+F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
+F:	drivers/pinctrl/pinctrl-k210.c
+
 CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
 M:	Damien Le Moal <damien.lemoal@wdc.com>
 L:	linux-riscv@lists.infradead.org
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index f2f9633087d1..68bdd664b5c2 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -31,6 +31,8 @@ config SOC_CANAAN
 	select SIFIVE_PLIC
 	select SOC_K210_SYSCTL
 	select CLK_K210
+	select PINCTRL
+	select PINCTRL_K210
 	help
 	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 815095326e2d..fec380c27075 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -374,6 +374,19 @@ config PINCTRL_OCELOT
 	select OF_GPIO
 	select REGMAP_MMIO
 
+config PINCTRL_K210
+	bool "Pinctrl driver for the Canaan Kendryte K210 SoC"
+	depends on RISCV && SOC_CANAAN
+	depends on OF && HAS_IOMEM
+	select PINMUX
+	select GENERIC_PINCONF
+	select GPIOLIB
+	select OF_GPIO
+	select REGMAP_MMIO
+	help
+	  Add support for the Canaan Kendryte K210 RISC-V SOC Field
+	  Programmable IO Array (FPIOA) controller.
+
 source "drivers/pinctrl/actions/Kconfig"
 source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f53933b2ff02..d6f913adb04a 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 obj-$(CONFIG_PINCTRL_RK805)	+= pinctrl-rk805.o
 obj-$(CONFIG_PINCTRL_OCELOT)	+= pinctrl-ocelot.o
 obj-$(CONFIG_PINCTRL_EQUILIBRIUM)   += pinctrl-equilibrium.o
+obj-$(CONFIG_PINCTRL_K210)	+= pinctrl-k210.o
 
 obj-y				+= actions/
 obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c
new file mode 100644
index 000000000000..c1fd30b3b7da
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-k210.c
@@ -0,0 +1,984 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/io.h>
+
+#include <dt-bindings/pinctrl/k210-fpioa.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinctrl-utils.h"
+
+/*
+ * The K210 only implements 8 drive levels, even though
+ * there is register space for 16
+ */
+#define K210_PC_DRIVE_MASK	GENMASK(11, 8)
+#define K210_PC_DRIVE_SHIFT	8
+#define K210_PC_DRIVE_0		(0 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_1		(1 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_2		(2 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_3		(3 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_4		(4 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_5		(5 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_6		(6 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_7		(7 << K210_PC_DRIVE_SHIFT)
+#define K210_PC_DRIVE_MAX	7
+#define K210_PC_MODE_MASK	GENMASK(23, 12)
+
+/*
+ * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE)
+ * where FUNCTION_OE is a physical signal from the function.
+ */
+#define K210_PC_OE		BIT(12) /* Output Enable */
+#define K210_PC_OE_INV		BIT(13) /* INVert Output Enable */
+#define K210_PC_DO_OE		BIT(14) /* set Data Out to Output Enable sig */
+#define K210_PC_DO_INV		BIT(15) /* INVert final Data Output */
+#define K210_PC_PU		BIT(16) /* Pull Up */
+#define K210_PC_PD		BIT(17) /* Pull Down */
+/* Strong pull up not implemented on K210 */
+#define K210_PC_SL		BIT(19) /* reduce SLew rate */
+/* Same semantics as OE above */
+#define K210_PC_IE		BIT(20) /* Input Enable */
+#define K210_PC_IE_INV		BIT(21) /* INVert Input Enable */
+#define K210_PC_DI_INV		BIT(22) /* INVert Data Input */
+#define K210_PC_ST		BIT(23) /* Schmitt Trigger */
+#define K210_PC_DI		BIT(31) /* raw Data Input */
+
+#define K210_PC_BIAS_MASK	(K210_PC_PU & K210_PC_PD)
+
+#define K210_PC_MODE_IN		(K210_PC_IE | K210_PC_ST)
+#define K210_PC_MODE_OUT	(K210_PC_DRIVE_7 | K210_PC_OE)
+#define K210_PC_MODE_I2C	(K210_PC_MODE_IN | K210_PC_SL | \
+				 K210_PC_OE | K210_PC_PU)
+#define K210_PC_MODE_SCCB	(K210_PC_MODE_I2C | \
+				 K210_PC_OE_INV | K210_PC_IE_INV)
+#define K210_PC_MODE_SPI	(K210_PC_MODE_IN | K210_PC_IE_INV | \
+				 K210_PC_MODE_OUT | K210_PC_OE_INV)
+#define K210_PC_MODE_GPIO	(K210_PC_MODE_IN | K210_PC_MODE_OUT)
+
+#define K210_PG_FUNC		GENMASK(7, 0)
+#define K210_PG_DO		BIT(8)
+#define K210_PG_PIN		GENMASK(22, 16)
+
+/*
+ * struct k210_fpioa: Kendryte K210 FPIOA memory mapped registers
+ * @pins: 48 32-bits IO pin registers
+ * @tie_en: 256 (one per function) input tie enable bits
+ * @tie_val: 256 (one per function) input tie value bits
+ */
+struct k210_fpioa {
+	u32 pins[48];
+	u32 tie_en[8];
+	u32 tie_val[8];
+};
+
+struct k210_fpioa_data {
+
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+
+	struct k210_fpioa __iomem *fpioa;
+	struct regmap *sysctl_map;
+	u32 power_offset;
+	struct clk *clk;
+	struct clk *pclk;
+};
+
+#define K210_PIN_NAME(i)	("IO_" #i)
+#define K210_PIN(i)		[(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i))
+
+static const struct pinctrl_pin_desc k210_pins[] = {
+	K210_PIN(0),  K210_PIN(1),  K210_PIN(2),
+	K210_PIN(3),  K210_PIN(4),  K210_PIN(5),
+	K210_PIN(6),  K210_PIN(7),  K210_PIN(8),
+	K210_PIN(9),  K210_PIN(10), K210_PIN(11),
+	K210_PIN(12), K210_PIN(13), K210_PIN(14),
+	K210_PIN(15), K210_PIN(16), K210_PIN(17),
+	K210_PIN(18), K210_PIN(19), K210_PIN(20),
+	K210_PIN(21), K210_PIN(22), K210_PIN(23),
+	K210_PIN(24), K210_PIN(25), K210_PIN(26),
+	K210_PIN(27), K210_PIN(28), K210_PIN(29),
+	K210_PIN(30), K210_PIN(31), K210_PIN(32),
+	K210_PIN(33), K210_PIN(34), K210_PIN(35),
+	K210_PIN(36), K210_PIN(37), K210_PIN(38),
+	K210_PIN(39), K210_PIN(40), K210_PIN(41),
+	K210_PIN(42), K210_PIN(43), K210_PIN(44),
+	K210_PIN(45), K210_PIN(46), K210_PIN(47)
+};
+
+#define K210_NPINS ARRAY_SIZE(k210_pins)
+
+/*
+ * Pin groups: each of the 48 programmable pins is a group.
+ * To this are added 8 power domain groups, which for the purposes of
+ * the pin subsystem, contain no pins. The power domain groups only exist
+ * to set the power level. The id should never be used (since there are
+ * no pins 48-55).
+ */
+static const char *const k210_group_names[] = {
+	/* The first 48 groups are for pins, one each */
+	K210_PIN_NAME(0),  K210_PIN_NAME(1),  K210_PIN_NAME(2),
+	K210_PIN_NAME(3),  K210_PIN_NAME(4),  K210_PIN_NAME(5),
+	K210_PIN_NAME(6),  K210_PIN_NAME(7),  K210_PIN_NAME(8),
+	K210_PIN_NAME(9),  K210_PIN_NAME(10), K210_PIN_NAME(11),
+	K210_PIN_NAME(12), K210_PIN_NAME(13), K210_PIN_NAME(14),
+	K210_PIN_NAME(15), K210_PIN_NAME(16), K210_PIN_NAME(17),
+	K210_PIN_NAME(18), K210_PIN_NAME(19), K210_PIN_NAME(20),
+	K210_PIN_NAME(21), K210_PIN_NAME(22), K210_PIN_NAME(23),
+	K210_PIN_NAME(24), K210_PIN_NAME(25), K210_PIN_NAME(26),
+	K210_PIN_NAME(27), K210_PIN_NAME(28), K210_PIN_NAME(29),
+	K210_PIN_NAME(30), K210_PIN_NAME(31), K210_PIN_NAME(32),
+	K210_PIN_NAME(33), K210_PIN_NAME(34), K210_PIN_NAME(35),
+	K210_PIN_NAME(36), K210_PIN_NAME(37), K210_PIN_NAME(38),
+	K210_PIN_NAME(39), K210_PIN_NAME(40), K210_PIN_NAME(41),
+	K210_PIN_NAME(42), K210_PIN_NAME(43), K210_PIN_NAME(44),
+	K210_PIN_NAME(45), K210_PIN_NAME(46), K210_PIN_NAME(47),
+	[48] = "A0", [49] = "A1", [50] = "A2",
+	[51] = "B3", [52] = "B4", [53] = "B5",
+	[54] = "C6", [55] = "C7"
+};
+
+#define K210_NGROUPS	ARRAY_SIZE(k210_group_names)
+
+enum k210_pinctrl_mode_id {
+	K210_PC_DEFAULT_DISABLED,
+	K210_PC_DEFAULT_IN,
+	K210_PC_DEFAULT_IN_TIE,
+	K210_PC_DEFAULT_OUT,
+	K210_PC_DEFAULT_I2C,
+	K210_PC_DEFAULT_SCCB,
+	K210_PC_DEFAULT_SPI,
+	K210_PC_DEFAULT_GPIO,
+	K210_PC_DEFAULT_INT13,
+};
+
+#define K210_PC_DEFAULT(mode) \
+	[K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode
+
+static const u32 k210_pinconf_mode_id_to_mode[] = {
+	[K210_PC_DEFAULT_DISABLED] = 0,
+	K210_PC_DEFAULT(IN),
+	[K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN,
+	K210_PC_DEFAULT(OUT),
+	K210_PC_DEFAULT(I2C),
+	K210_PC_DEFAULT(SCCB),
+	K210_PC_DEFAULT(SPI),
+	K210_PC_DEFAULT(GPIO),
+	[K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU,
+};
+
+#undef DEFAULT
+
+/*
+ * Pin functions configuration information.
+ */
+struct k210_pcf_info {
+	char name[15];
+	u8 mode_id;
+};
+
+#define K210_FUNC(id, mode)				\
+	[K210_PCF_##id] = {				\
+		.name = #id,				\
+		.mode_id = K210_PC_DEFAULT_##mode	\
+	}
+
+static const struct k210_pcf_info k210_pcf_infos[] = {
+	K210_FUNC(JTAG_TCLK,		IN),
+	K210_FUNC(JTAG_TDI,		IN),
+	K210_FUNC(JTAG_TMS,		IN),
+	K210_FUNC(JTAG_TDO,		OUT),
+	K210_FUNC(SPI0_D0,		SPI),
+	K210_FUNC(SPI0_D1,		SPI),
+	K210_FUNC(SPI0_D2,		SPI),
+	K210_FUNC(SPI0_D3,		SPI),
+	K210_FUNC(SPI0_D4,		SPI),
+	K210_FUNC(SPI0_D5,		SPI),
+	K210_FUNC(SPI0_D6,		SPI),
+	K210_FUNC(SPI0_D7,		SPI),
+	K210_FUNC(SPI0_SS0,		OUT),
+	K210_FUNC(SPI0_SS1,		OUT),
+	K210_FUNC(SPI0_SS2,		OUT),
+	K210_FUNC(SPI0_SS3,		OUT),
+	K210_FUNC(SPI0_ARB,		IN_TIE),
+	K210_FUNC(SPI0_SCLK,		OUT),
+	K210_FUNC(UARTHS_RX,		IN),
+	K210_FUNC(UARTHS_TX,		OUT),
+	K210_FUNC(RESV6,		IN),
+	K210_FUNC(RESV7,		IN),
+	K210_FUNC(CLK_SPI1,		OUT),
+	K210_FUNC(CLK_I2C1,		OUT),
+	K210_FUNC(GPIOHS0,		GPIO),
+	K210_FUNC(GPIOHS1,		GPIO),
+	K210_FUNC(GPIOHS2,		GPIO),
+	K210_FUNC(GPIOHS3,		GPIO),
+	K210_FUNC(GPIOHS4,		GPIO),
+	K210_FUNC(GPIOHS5,		GPIO),
+	K210_FUNC(GPIOHS6,		GPIO),
+	K210_FUNC(GPIOHS7,		GPIO),
+	K210_FUNC(GPIOHS8,		GPIO),
+	K210_FUNC(GPIOHS9,		GPIO),
+	K210_FUNC(GPIOHS10,		GPIO),
+	K210_FUNC(GPIOHS11,		GPIO),
+	K210_FUNC(GPIOHS12,		GPIO),
+	K210_FUNC(GPIOHS13,		GPIO),
+	K210_FUNC(GPIOHS14,		GPIO),
+	K210_FUNC(GPIOHS15,		GPIO),
+	K210_FUNC(GPIOHS16,		GPIO),
+	K210_FUNC(GPIOHS17,		GPIO),
+	K210_FUNC(GPIOHS18,		GPIO),
+	K210_FUNC(GPIOHS19,		GPIO),
+	K210_FUNC(GPIOHS20,		GPIO),
+	K210_FUNC(GPIOHS21,		GPIO),
+	K210_FUNC(GPIOHS22,		GPIO),
+	K210_FUNC(GPIOHS23,		GPIO),
+	K210_FUNC(GPIOHS24,		GPIO),
+	K210_FUNC(GPIOHS25,		GPIO),
+	K210_FUNC(GPIOHS26,		GPIO),
+	K210_FUNC(GPIOHS27,		GPIO),
+	K210_FUNC(GPIOHS28,		GPIO),
+	K210_FUNC(GPIOHS29,		GPIO),
+	K210_FUNC(GPIOHS30,		GPIO),
+	K210_FUNC(GPIOHS31,		GPIO),
+	K210_FUNC(GPIO0,		GPIO),
+	K210_FUNC(GPIO1,		GPIO),
+	K210_FUNC(GPIO2,		GPIO),
+	K210_FUNC(GPIO3,		GPIO),
+	K210_FUNC(GPIO4,		GPIO),
+	K210_FUNC(GPIO5,		GPIO),
+	K210_FUNC(GPIO6,		GPIO),
+	K210_FUNC(GPIO7,		GPIO),
+	K210_FUNC(UART1_RX,		IN),
+	K210_FUNC(UART1_TX,		OUT),
+	K210_FUNC(UART2_RX,		IN),
+	K210_FUNC(UART2_TX,		OUT),
+	K210_FUNC(UART3_RX,		IN),
+	K210_FUNC(UART3_TX,		OUT),
+	K210_FUNC(SPI1_D0,		SPI),
+	K210_FUNC(SPI1_D1,		SPI),
+	K210_FUNC(SPI1_D2,		SPI),
+	K210_FUNC(SPI1_D3,		SPI),
+	K210_FUNC(SPI1_D4,		SPI),
+	K210_FUNC(SPI1_D5,		SPI),
+	K210_FUNC(SPI1_D6,		SPI),
+	K210_FUNC(SPI1_D7,		SPI),
+	K210_FUNC(SPI1_SS0,		OUT),
+	K210_FUNC(SPI1_SS1,		OUT),
+	K210_FUNC(SPI1_SS2,		OUT),
+	K210_FUNC(SPI1_SS3,		OUT),
+	K210_FUNC(SPI1_ARB,		IN_TIE),
+	K210_FUNC(SPI1_SCLK,		OUT),
+	K210_FUNC(SPI2_D0,		SPI),
+	K210_FUNC(SPI2_SS,		IN),
+	K210_FUNC(SPI2_SCLK,		IN),
+	K210_FUNC(I2S0_MCLK,		OUT),
+	K210_FUNC(I2S0_SCLK,		OUT),
+	K210_FUNC(I2S0_WS,		OUT),
+	K210_FUNC(I2S0_IN_D0,		IN),
+	K210_FUNC(I2S0_IN_D1,		IN),
+	K210_FUNC(I2S0_IN_D2,		IN),
+	K210_FUNC(I2S0_IN_D3,		IN),
+	K210_FUNC(I2S0_OUT_D0,		OUT),
+	K210_FUNC(I2S0_OUT_D1,		OUT),
+	K210_FUNC(I2S0_OUT_D2,		OUT),
+	K210_FUNC(I2S0_OUT_D3,		OUT),
+	K210_FUNC(I2S1_MCLK,		OUT),
+	K210_FUNC(I2S1_SCLK,		OUT),
+	K210_FUNC(I2S1_WS,		OUT),
+	K210_FUNC(I2S1_IN_D0,		IN),
+	K210_FUNC(I2S1_IN_D1,		IN),
+	K210_FUNC(I2S1_IN_D2,		IN),
+	K210_FUNC(I2S1_IN_D3,		IN),
+	K210_FUNC(I2S1_OUT_D0,		OUT),
+	K210_FUNC(I2S1_OUT_D1,		OUT),
+	K210_FUNC(I2S1_OUT_D2,		OUT),
+	K210_FUNC(I2S1_OUT_D3,		OUT),
+	K210_FUNC(I2S2_MCLK,		OUT),
+	K210_FUNC(I2S2_SCLK,		OUT),
+	K210_FUNC(I2S2_WS,		OUT),
+	K210_FUNC(I2S2_IN_D0,		IN),
+	K210_FUNC(I2S2_IN_D1,		IN),
+	K210_FUNC(I2S2_IN_D2,		IN),
+	K210_FUNC(I2S2_IN_D3,		IN),
+	K210_FUNC(I2S2_OUT_D0,		OUT),
+	K210_FUNC(I2S2_OUT_D1,		OUT),
+	K210_FUNC(I2S2_OUT_D2,		OUT),
+	K210_FUNC(I2S2_OUT_D3,		OUT),
+	K210_FUNC(RESV0,		DISABLED),
+	K210_FUNC(RESV1,		DISABLED),
+	K210_FUNC(RESV2,		DISABLED),
+	K210_FUNC(RESV3,		DISABLED),
+	K210_FUNC(RESV4,		DISABLED),
+	K210_FUNC(RESV5,		DISABLED),
+	K210_FUNC(I2C0_SCLK,		I2C),
+	K210_FUNC(I2C0_SDA,		I2C),
+	K210_FUNC(I2C1_SCLK,		I2C),
+	K210_FUNC(I2C1_SDA,		I2C),
+	K210_FUNC(I2C2_SCLK,		I2C),
+	K210_FUNC(I2C2_SDA,		I2C),
+	K210_FUNC(DVP_XCLK,		OUT),
+	K210_FUNC(DVP_RST,		OUT),
+	K210_FUNC(DVP_PWDN,		OUT),
+	K210_FUNC(DVP_VSYNC,		IN),
+	K210_FUNC(DVP_HSYNC,		IN),
+	K210_FUNC(DVP_PCLK,		IN),
+	K210_FUNC(DVP_D0,		IN),
+	K210_FUNC(DVP_D1,		IN),
+	K210_FUNC(DVP_D2,		IN),
+	K210_FUNC(DVP_D3,		IN),
+	K210_FUNC(DVP_D4,		IN),
+	K210_FUNC(DVP_D5,		IN),
+	K210_FUNC(DVP_D6,		IN),
+	K210_FUNC(DVP_D7,		IN),
+	K210_FUNC(SCCB_SCLK,		SCCB),
+	K210_FUNC(SCCB_SDA,		SCCB),
+	K210_FUNC(UART1_CTS,		IN),
+	K210_FUNC(UART1_DSR,		IN),
+	K210_FUNC(UART1_DCD,		IN),
+	K210_FUNC(UART1_RI,		IN),
+	K210_FUNC(UART1_SIR_IN,		IN),
+	K210_FUNC(UART1_DTR,		OUT),
+	K210_FUNC(UART1_RTS,		OUT),
+	K210_FUNC(UART1_OUT2,		OUT),
+	K210_FUNC(UART1_OUT1,		OUT),
+	K210_FUNC(UART1_SIR_OUT,	OUT),
+	K210_FUNC(UART1_BAUD,		OUT),
+	K210_FUNC(UART1_RE,		OUT),
+	K210_FUNC(UART1_DE,		OUT),
+	K210_FUNC(UART1_RS485_EN,	OUT),
+	K210_FUNC(UART2_CTS,		IN),
+	K210_FUNC(UART2_DSR,		IN),
+	K210_FUNC(UART2_DCD,		IN),
+	K210_FUNC(UART2_RI,		IN),
+	K210_FUNC(UART2_SIR_IN,		IN),
+	K210_FUNC(UART2_DTR,		OUT),
+	K210_FUNC(UART2_RTS,		OUT),
+	K210_FUNC(UART2_OUT2,		OUT),
+	K210_FUNC(UART2_OUT1,		OUT),
+	K210_FUNC(UART2_SIR_OUT,	OUT),
+	K210_FUNC(UART2_BAUD,		OUT),
+	K210_FUNC(UART2_RE,		OUT),
+	K210_FUNC(UART2_DE,		OUT),
+	K210_FUNC(UART2_RS485_EN,	OUT),
+	K210_FUNC(UART3_CTS,		IN),
+	K210_FUNC(UART3_DSR,		IN),
+	K210_FUNC(UART3_DCD,		IN),
+	K210_FUNC(UART3_RI,		IN),
+	K210_FUNC(UART3_SIR_IN,		IN),
+	K210_FUNC(UART3_DTR,		OUT),
+	K210_FUNC(UART3_RTS,		OUT),
+	K210_FUNC(UART3_OUT2,		OUT),
+	K210_FUNC(UART3_OUT1,		OUT),
+	K210_FUNC(UART3_SIR_OUT,	OUT),
+	K210_FUNC(UART3_BAUD,		OUT),
+	K210_FUNC(UART3_RE,		OUT),
+	K210_FUNC(UART3_DE,		OUT),
+	K210_FUNC(UART3_RS485_EN,	OUT),
+	K210_FUNC(TIMER0_TOGGLE1,	OUT),
+	K210_FUNC(TIMER0_TOGGLE2,	OUT),
+	K210_FUNC(TIMER0_TOGGLE3,	OUT),
+	K210_FUNC(TIMER0_TOGGLE4,	OUT),
+	K210_FUNC(TIMER1_TOGGLE1,	OUT),
+	K210_FUNC(TIMER1_TOGGLE2,	OUT),
+	K210_FUNC(TIMER1_TOGGLE3,	OUT),
+	K210_FUNC(TIMER1_TOGGLE4,	OUT),
+	K210_FUNC(TIMER2_TOGGLE1,	OUT),
+	K210_FUNC(TIMER2_TOGGLE2,	OUT),
+	K210_FUNC(TIMER2_TOGGLE3,	OUT),
+	K210_FUNC(TIMER2_TOGGLE4,	OUT),
+	K210_FUNC(CLK_SPI2,		OUT),
+	K210_FUNC(CLK_I2C2,		OUT),
+	K210_FUNC(INTERNAL0,		OUT),
+	K210_FUNC(INTERNAL1,		OUT),
+	K210_FUNC(INTERNAL2,		OUT),
+	K210_FUNC(INTERNAL3,		OUT),
+	K210_FUNC(INTERNAL4,		OUT),
+	K210_FUNC(INTERNAL5,		OUT),
+	K210_FUNC(INTERNAL6,		OUT),
+	K210_FUNC(INTERNAL7,		OUT),
+	K210_FUNC(INTERNAL8,		OUT),
+	K210_FUNC(INTERNAL9,		IN),
+	K210_FUNC(INTERNAL10,		IN),
+	K210_FUNC(INTERNAL11,		IN),
+	K210_FUNC(INTERNAL12,		IN),
+	K210_FUNC(INTERNAL13,		INT13),
+	K210_FUNC(INTERNAL14,		I2C),
+	K210_FUNC(INTERNAL15,		IN),
+	K210_FUNC(INTERNAL16,		IN),
+	K210_FUNC(INTERNAL17,		IN),
+	K210_FUNC(CONSTANT,		DISABLED),
+	K210_FUNC(INTERNAL18,		IN),
+	K210_FUNC(DEBUG0,		OUT),
+	K210_FUNC(DEBUG1,		OUT),
+	K210_FUNC(DEBUG2,		OUT),
+	K210_FUNC(DEBUG3,		OUT),
+	K210_FUNC(DEBUG4,		OUT),
+	K210_FUNC(DEBUG5,		OUT),
+	K210_FUNC(DEBUG6,		OUT),
+	K210_FUNC(DEBUG7,		OUT),
+	K210_FUNC(DEBUG8,		OUT),
+	K210_FUNC(DEBUG9,		OUT),
+	K210_FUNC(DEBUG10,		OUT),
+	K210_FUNC(DEBUG11,		OUT),
+	K210_FUNC(DEBUG12,		OUT),
+	K210_FUNC(DEBUG13,		OUT),
+	K210_FUNC(DEBUG14,		OUT),
+	K210_FUNC(DEBUG15,		OUT),
+	K210_FUNC(DEBUG16,		OUT),
+	K210_FUNC(DEBUG17,		OUT),
+	K210_FUNC(DEBUG18,		OUT),
+	K210_FUNC(DEBUG19,		OUT),
+	K210_FUNC(DEBUG20,		OUT),
+	K210_FUNC(DEBUG21,		OUT),
+	K210_FUNC(DEBUG22,		OUT),
+	K210_FUNC(DEBUG23,		OUT),
+	K210_FUNC(DEBUG24,		OUT),
+	K210_FUNC(DEBUG25,		OUT),
+	K210_FUNC(DEBUG26,		OUT),
+	K210_FUNC(DEBUG27,		OUT),
+	K210_FUNC(DEBUG28,		OUT),
+	K210_FUNC(DEBUG29,		OUT),
+	K210_FUNC(DEBUG30,		OUT),
+	K210_FUNC(DEBUG31,		OUT),
+};
+
+#define PIN_CONFIG_OUTPUT_INVERT	(PIN_CONFIG_END + 1)
+#define PIN_CONFIG_INPUT_INVERT		(PIN_CONFIG_END + 2)
+
+static const struct pinconf_generic_params k210_pinconf_custom_params[] = {
+	{ "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1 },
+	{ "input-polarity-invert",  PIN_CONFIG_INPUT_INVERT, 1 },
+};
+
+/*
+ * Max drive strength in uA.
+ */
+static const int k210_pinconf_drive_strength[] = {
+	[0] = 11200,
+	[1] = 16800,
+	[2] = 22300,
+	[3] = 27800,
+	[4] = 33300,
+	[5] = 38700,
+	[6] = 44100,
+	[7] = 49500,
+};
+
+static int k210_pinconf_get_drive(unsigned int max_strength_ua)
+{
+	int i;
+
+	for (i = K210_PC_DRIVE_MAX; i; i--) {
+		if (k210_pinconf_drive_strength[i] <= max_strength_ua)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static void k210_pinmux_set_pin_function(struct pinctrl_dev *pctldev,
+					 u32 pin, u32 func)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+	const struct k210_pcf_info *info = &k210_pcf_infos[func];
+	u32 mode = k210_pinconf_mode_id_to_mode[info->mode_id];
+	u32 val = func | mode;
+
+	dev_dbg(pdata->dev, "set pin %u function %s (%u) -> 0x%08x\n",
+		pin, info->name, func, val);
+
+	writel(val, &pdata->fpioa->pins[pin]);
+}
+
+static int k210_pinconf_set_param(struct pinctrl_dev *pctldev,
+				  unsigned int pin,
+				  unsigned int param, unsigned int arg)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+	u32 val = readl(&pdata->fpioa->pins[pin]);
+	int drive;
+
+	dev_dbg(pdata->dev, "set pin %u param %u, arg 0x%x\n",
+		pin, param, arg);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		val &= ~K210_PC_BIAS_MASK;
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!arg)
+			return -EINVAL;
+		val |= K210_PC_PD;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (!arg)
+			return -EINVAL;
+		val |= K210_PC_PD;
+		break;
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		arg *= 1000;
+		fallthrough;
+	case PIN_CONFIG_DRIVE_STRENGTH_UA:
+		drive = k210_pinconf_get_drive(arg);
+		if (drive < 0)
+			return drive;
+		val &= ~K210_PC_DRIVE_MASK;
+		val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive);
+		break;
+	case PIN_CONFIG_INPUT_ENABLE:
+		if (arg)
+			val |= K210_PC_IE;
+		else
+			val &= ~K210_PC_IE;
+		break;
+	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+		if (arg)
+			val |= K210_PC_ST;
+		else
+			val &= ~K210_PC_ST;
+		break;
+	case PIN_CONFIG_OUTPUT:
+		k210_pinmux_set_pin_function(pctldev, pin, K210_PCF_CONSTANT);
+		val = readl(&pdata->fpioa->pins[pin]);
+		val |= K210_PC_MODE_OUT;
+		if (!arg)
+			val |= K210_PC_DO_INV;
+		break;
+	case PIN_CONFIG_OUTPUT_ENABLE:
+		if (arg)
+			val |= K210_PC_OE;
+		else
+			val &= ~K210_PC_OE;
+		break;
+	case PIN_CONFIG_SLEW_RATE:
+		if (arg)
+			val |= K210_PC_SL;
+		else
+			val &= ~K210_PC_SL;
+		break;
+	case PIN_CONFIG_OUTPUT_INVERT:
+		if (arg)
+			val |= K210_PC_DO_INV;
+		else
+			val &= ~K210_PC_DO_INV;
+		break;
+	case PIN_CONFIG_INPUT_INVERT:
+		if (arg)
+			val |= K210_PC_DI_INV;
+		else
+			val &= ~K210_PC_DI_INV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	writel(val, &pdata->fpioa->pins[pin]);
+
+	return 0;
+}
+
+static int k210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+			    unsigned long *configs, unsigned int num_configs)
+{
+	unsigned int param, arg;
+	int i, ret;
+
+	if (WARN_ON(pin >= K210_NPINS))
+		return -EINVAL;
+
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
+		ret = k210_pinconf_set_param(pctldev, pin, param, arg);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void k210_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+				  struct seq_file *s, unsigned int pin)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+
+	seq_printf(s, "%#x", readl(&pdata->fpioa->pins[pin]));
+}
+
+static int k210_pinconf_group_set(struct pinctrl_dev *pctldev,
+				  unsigned int selector, unsigned long *configs,
+				  unsigned int num_configs)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int param, arg;
+	u32 bit;
+	int i;
+
+	/* Pins should be configured with pinmux, not groups*/
+	if (selector < K210_NPINS)
+		return -EINVAL;
+
+	/* Otherwise it's a power domain */
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		if (param != PIN_CONFIG_POWER_SOURCE)
+			return -EINVAL;
+
+		arg = pinconf_to_config_argument(configs[i]);
+		bit = BIT(selector - K210_NPINS);
+		regmap_update_bits(pdata->sysctl_map,
+				   pdata->power_offset,
+				   bit, arg ? bit : 0);
+	}
+
+	return 0;
+}
+
+static void k210_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+					struct seq_file *s,
+					unsigned int selector)
+{
+	struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev);
+	int ret;
+	u32 val;
+
+	if (selector < K210_NPINS)
+		return k210_pinconf_dbg_show(pctldev, s, selector);
+
+	ret = regmap_read(pdata->sysctl_map, pdata->power_offset, &val);
+	if (ret) {
+		dev_err(pdata->dev, "Failed to read power reg\n");
+		return;
+	}
+
+	seq_printf(s, "%s: %s V", k210_group_names[selector],
+		   val & BIT(selector - K210_NPINS) ? "1.8" : "3.3");
+}
+
+static const struct pinconf_ops k210_pinconf_ops = {
+	.is_generic = true,
+	.pin_config_set = k210_pinconf_set,
+	.pin_config_group_set = k210_pinconf_group_set,
+	.pin_config_dbg_show = k210_pinconf_dbg_show,
+	.pin_config_group_dbg_show = k210_pinconf_group_dbg_show,
+};
+
+static int k210_pinmux_get_function_count(struct pinctrl_dev *pctldev)
+{
+	return ARRAY_SIZE(k210_pcf_infos);
+}
+
+static const char *k210_pinmux_get_function_name(struct pinctrl_dev *pctldev,
+						 unsigned int selector)
+{
+	return k210_pcf_infos[selector].name;
+}
+
+static int k210_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+					   unsigned int selector,
+					   const char * const **groups,
+					   unsigned int * const num_groups)
+{
+	/* Any function can be mapped to any pin */
+	*groups = k210_group_names;
+	*num_groups = K210_NPINS;
+
+	return 0;
+}
+
+static int k210_pinmux_set_mux(struct pinctrl_dev *pctldev,
+			       unsigned int function,
+			       unsigned int group)
+{
+	/* Can't mux power domains */
+	if (group >= K210_NPINS)
+		return -EINVAL;
+
+	k210_pinmux_set_pin_function(pctldev, group, function);
+
+	return 0;
+}
+
+static const struct pinmux_ops k210_pinmux_ops = {
+	.get_functions_count = k210_pinmux_get_function_count,
+	.get_function_name = k210_pinmux_get_function_name,
+	.get_function_groups = k210_pinmux_get_function_groups,
+	.set_mux = k210_pinmux_set_mux,
+	.strict = true,
+};
+
+static int k210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	return K210_NGROUPS;
+}
+
+static const char *k210_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+					       unsigned int group)
+{
+	return k210_group_names[group];
+}
+
+static int k210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+				       unsigned int group,
+				       const unsigned int **pins,
+				       unsigned int *npins)
+{
+	if (group >= K210_NPINS) {
+		*pins = NULL;
+		*npins = 0;
+		return 0;
+	}
+
+	*pins = &k210_pins[group].number;
+	*npins = 1;
+
+	return 0;
+}
+
+static void k210_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+				      struct seq_file *s, unsigned int offset)
+{
+	seq_printf(s, "%s", dev_name(pctldev->dev));
+}
+
+static int k210_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+					  struct device_node *np,
+					  struct pinctrl_map **map,
+					  unsigned int *reserved_maps,
+					  unsigned int *num_maps)
+{
+	struct property *prop;
+	const __be32 *p;
+	int ret, pinmux_groups;
+	u32 pinmux_group;
+	unsigned long *configs = NULL;
+	unsigned int num_configs = 0;
+	unsigned int reserve = 0;
+
+	ret = of_property_count_strings(np, "groups");
+	if (!ret)
+		return pinconf_generic_dt_subnode_to_map(pctldev, np, map,
+						reserved_maps, num_maps,
+						PIN_MAP_TYPE_CONFIGS_GROUP);
+
+	pinmux_groups = of_property_count_u32_elems(np, "pinmux");
+	if (pinmux_groups <= 0) {
+		/* Ignore this node */
+		return 0;
+	}
+
+	ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
+					      &num_configs);
+	if (ret < 0) {
+		dev_err(pctldev->dev, "%pOF: could not parse node property\n",
+			np);
+		return ret;
+	}
+
+	reserve = pinmux_groups * (1 + num_configs);
+	ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps,
+					reserve);
+	if (ret < 0)
+		goto exit;
+
+	of_property_for_each_u32(np, "pinmux", prop, p, pinmux_group) {
+		const char *group_name, *func_name;
+		u32 pin = FIELD_GET(K210_PG_PIN, pinmux_group);
+		u32 func = FIELD_GET(K210_PG_FUNC, pinmux_group);
+
+		if (pin >= K210_NPINS) {
+			ret = -EINVAL;
+			goto exit;
+		}
+
+		group_name = k210_group_names[pin];
+		func_name = k210_pcf_infos[func].name;
+
+		dev_dbg(pctldev->dev, "Pinmux %s: pin %u func %s\n",
+			np->name, pin, func_name);
+
+		ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps,
+						num_maps, group_name,
+						func_name);
+		if (ret < 0) {
+			dev_err(pctldev->dev, "%pOF add mux map failed %d\n",
+				np, ret);
+			goto exit;
+		}
+
+		if (num_configs) {
+			ret = pinctrl_utils_add_map_configs(pctldev, map,
+					reserved_maps, num_maps, group_name,
+					configs, num_configs,
+					PIN_MAP_TYPE_CONFIGS_PIN);
+			if (ret < 0) {
+				dev_err(pctldev->dev,
+					"%pOF add configs map failed %d\n",
+					np, ret);
+				goto exit;
+			}
+		}
+	}
+
+	ret = 0;
+
+exit:
+	kfree(configs);
+	return ret;
+}
+
+static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+				       struct device_node *np_config,
+				       struct pinctrl_map **map,
+				       unsigned int *num_maps)
+{
+	unsigned int reserved_maps;
+	struct device_node *np;
+	int ret;
+
+	reserved_maps = 0;
+	*map = NULL;
+	*num_maps = 0;
+
+	ret = k210_pinctrl_dt_subnode_to_map(pctldev, np_config, map,
+					     &reserved_maps, num_maps);
+	if (ret < 0)
+		goto err;
+
+	for_each_available_child_of_node(np_config, np) {
+		ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map,
+						     &reserved_maps, num_maps);
+		if (ret < 0)
+			goto err;
+	}
+	return 0;
+
+err:
+	pinctrl_utils_free_map(pctldev, *map, *num_maps);
+	return ret;
+}
+
+
+static const struct pinctrl_ops k210_pinctrl_ops = {
+	.get_groups_count = k210_pinctrl_get_groups_count,
+	.get_group_name = k210_pinctrl_get_group_name,
+	.get_group_pins = k210_pinctrl_get_group_pins,
+	.pin_dbg_show = k210_pinctrl_pin_dbg_show,
+	.dt_node_to_map = k210_pinctrl_dt_node_to_map,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static struct pinctrl_desc k210_pinctrl_desc = {
+	.name = "k210-pinctrl",
+	.pins = k210_pins,
+	.npins = K210_NPINS,
+	.pctlops = &k210_pinctrl_ops,
+	.pmxops = &k210_pinmux_ops,
+	.confops = &k210_pinconf_ops,
+	.custom_params = k210_pinconf_custom_params,
+	.num_custom_params = ARRAY_SIZE(k210_pinconf_custom_params),
+};
+
+static void k210_fpioa_init_ties(struct k210_fpioa_data *pdata)
+{
+	struct k210_fpioa __iomem *fpioa = pdata->fpioa;
+	u32 val;
+	int i, j;
+
+	dev_dbg(pdata->dev, "Init pin ties\n");
+
+	/* Init pin functions input ties */
+	for (i = 0; i < ARRAY_SIZE(fpioa->tie_en); i++) {
+		val = 0;
+		for (j = 0; j < 32; j++) {
+			if (k210_pcf_infos[i * 32 + j].mode_id ==
+			    K210_PC_DEFAULT_IN_TIE) {
+				dev_dbg(pdata->dev,
+					"tie_en function %d (%s)\n",
+					i * 32 + j,
+					k210_pcf_infos[i * 32 + j].name);
+				val |= BIT(j);
+			}
+		}
+
+		/* Set value before enable */
+		writel(val, &fpioa->tie_val[i]);
+		writel(val, &fpioa->tie_en[i]);
+	}
+}
+
+static int __init k210_fpioa_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct k210_fpioa_data *pdata;
+	int ret;
+
+	dev_info(dev, "K210 FPIOA pin controller\n");
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pdata->dev = dev;
+	platform_set_drvdata(pdev, pdata);
+
+	pdata->fpioa = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pdata->fpioa))
+		return PTR_ERR(pdata->fpioa);
+
+	pdata->clk = devm_clk_get(dev, "ref");
+	if (IS_ERR(pdata->clk))
+		return PTR_ERR(pdata->clk);
+
+	ret = clk_prepare_enable(pdata->clk);
+	if (ret)
+		return ret;
+
+	pdata->pclk = devm_clk_get_optional(dev, "pclk");
+	if (!IS_ERR(pdata->pclk))
+		clk_prepare_enable(pdata->pclk);
+
+	pdata->sysctl_map =
+		syscon_regmap_lookup_by_phandle_args(np,
+						"canaan,k210-sysctl-power",
+						1, &pdata->power_offset);
+	if (IS_ERR(pdata->sysctl_map))
+		return PTR_ERR(pdata->sysctl_map);
+
+	k210_fpioa_init_ties(pdata);
+
+	pdata->pctl = pinctrl_register(&k210_pinctrl_desc, dev, (void *)pdata);
+	if (IS_ERR(pdata->pctl))
+		return PTR_ERR(pdata->pctl);
+
+	return 0;
+}
+
+static const struct of_device_id k210_fpioa_dt_ids[] = {
+	{ .compatible = "canaan,k210-fpioa" },
+};
+
+static struct platform_driver k210_fpioa_driver = {
+	.probe	= k210_fpioa_probe,
+	.driver = {
+		.name		= "k210-fpioa",
+		.of_match_table	= k210_fpioa_dt_ids,
+	},
+};
+builtin_platform_driver(k210_fpioa_driver);
-- 
2.28.0


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

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

* [PATCH v4 13/21] riscv: Add Canaan Kendryte K210 reset controller
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a reset controller driver for the Canaan Kendryte K210 SoC. This
driver relies on its syscon compatible parent node (sysctl) for its
register mapping. Automatically select this driver for compilation
when the SOC_CANAAN option is selected.

The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
driver.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 MAINTAINERS                |   8 +++
 arch/riscv/Kconfig.socs    |   3 +
 drivers/reset/Kconfig      |   9 +++
 drivers/reset/Makefile     |   1 +
 drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
 5 files changed, 162 insertions(+)
 create mode 100644 drivers/reset/reset-k210.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a059ab02fa8a..c2b3d6e48cd5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3837,6 +3837,14 @@ L:	linux-gpio@vger.kernel.org (pinctrl driver)
 F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
 F:	drivers/pinctrl/pinctrl-k210.c
 
+CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-kernel@vger.kernel.org
+L:	linux-riscv@lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
+F:	drivers/reset/reset-k210.c
+
 CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
 M:	Damien Le Moal <damien.lemoal@wdc.com>
 L:	linux-riscv@lists.infradead.org
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 68bdd664b5c2..b3cd253ec2c2 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -33,6 +33,9 @@ config SOC_CANAAN
 	select CLK_K210
 	select PINCTRL
 	select PINCTRL_K210
+	select ARCH_HAS_RESET_CONTROLLER
+	select RESET_CONTROLLER
+	select RESET_K210
 	help
 	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 07d162b179fc..529d206cfdfd 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -245,6 +245,15 @@ config RESET_ZYNQ
 	help
 	  This enables the reset controller driver for Xilinx Zynq SoCs.
 
+config RESET_K210
+	bool "Reset controller driver for Canaan Kendryte K210 SoC"
+	depends on RISCV && SOC_CANAAN
+	depends on OF && MFD_SYSCON
+	help
+	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
+	  Say Y if you want to control reset signals provided by this
+	  controller.
+
 source "drivers/reset/sti/Kconfig"
 source "drivers/reset/hisilicon/Kconfig"
 source "drivers/reset/tegra/Kconfig"
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 16947610cc3b..1730a31e6871 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -33,4 +33,5 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
 obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
 obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
 obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
+obj-$(CONFIG_RESET_K210) += reset-k210.o
 
diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
new file mode 100644
index 000000000000..2cf9a63c763d
--- /dev/null
+++ b/drivers/reset/reset-k210.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <soc/canaan/k210-sysctl.h>
+
+#include <dt-bindings/reset/k210-rst.h>
+
+#define K210_RST_MASK	0x27FFFFFF
+
+struct k210_rst {
+	struct regmap *map;
+	struct reset_controller_dev rcdev;
+};
+
+static inline struct k210_rst *
+to_k210_rst(struct reset_controller_dev *rcdev)
+{
+	return container_of(rcdev, struct k210_rst, rcdev);
+}
+
+static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
+				  unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 bit = BIT(id);
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	dev_dbg(rcdev->dev, "assert %lu\n", id);
+
+	regmap_update_bits(ksr->map, K210_SYSCTL_PERI_RESET, bit, 1);
+
+	return 0;
+}
+
+static inline int k210_rst_deassert(struct reset_controller_dev *rcdev,
+				    unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 bit = BIT(id);
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	dev_dbg(rcdev->dev, "deassert %lu\n", id);
+
+	regmap_update_bits(ksr->map, K210_SYSCTL_PERI_RESET, bit, 0);
+
+	return 0;
+}
+
+static int k210_rst_reset(struct reset_controller_dev *rcdev,
+			  unsigned long id)
+{
+	int ret;
+
+	dev_dbg(rcdev->dev, "reset %lu\n", id);
+
+	ret = k210_rst_assert(rcdev, id);
+	if (ret == 0) {
+		udelay(10);
+		ret = k210_rst_deassert(rcdev, id);
+	}
+
+	return ret;
+}
+
+static int k210_rst_status(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 reg, bit = BIT(id);
+	int ret;
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	ret = regmap_read(ksr->map, K210_SYSCTL_PERI_RESET, &reg);
+	if (ret)
+		return ret;
+
+	return ret & bit;
+}
+
+static const struct reset_control_ops k210_rst_ops = {
+	.assert		= k210_rst_assert,
+	.deassert	= k210_rst_deassert,
+	.reset		= k210_rst_reset,
+	.status		= k210_rst_status,
+};
+
+static int __init k210_rst_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct k210_rst *ksr;
+
+	dev_info(dev, "K210 reset controller\n");
+
+	if (!dev->parent) {
+		dev_err(&pdev->dev, "No parent for K210 reset controller\n");
+		return -ENODEV;
+	}
+
+	ksr = devm_kzalloc(dev, sizeof(*ksr), GFP_KERNEL);
+	if (!ksr)
+		return -ENOMEM;
+
+	ksr->map = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(ksr->map))
+		return PTR_ERR(ksr->map);
+
+	ksr->rcdev.owner = THIS_MODULE;
+	ksr->rcdev.dev = dev;
+	ksr->rcdev.of_node = dev->of_node;
+	ksr->rcdev.nr_resets = fls(K210_RST_MASK);
+	ksr->rcdev.ops = &k210_rst_ops;
+
+	return devm_reset_controller_register(dev, &ksr->rcdev);
+}
+
+static const struct of_device_id k210_rst_dt_ids[] = {
+	{ .compatible = "canaan,k210-rst" },
+};
+
+static struct platform_driver k210_rst_driver = {
+	.probe	= k210_rst_probe,
+	.driver = {
+		.name		= "k210-rst",
+		.of_match_table	= k210_rst_dt_ids,
+	},
+};
+builtin_platform_driver(k210_rst_driver);
-- 
2.28.0


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

* [PATCH v4 13/21] riscv: Add Canaan Kendryte K210 reset controller
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a reset controller driver for the Canaan Kendryte K210 SoC. This
driver relies on its syscon compatible parent node (sysctl) for its
register mapping. Automatically select this driver for compilation
when the SOC_CANAAN option is selected.

The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
driver.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 MAINTAINERS                |   8 +++
 arch/riscv/Kconfig.socs    |   3 +
 drivers/reset/Kconfig      |   9 +++
 drivers/reset/Makefile     |   1 +
 drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
 5 files changed, 162 insertions(+)
 create mode 100644 drivers/reset/reset-k210.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a059ab02fa8a..c2b3d6e48cd5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3837,6 +3837,14 @@ L:	linux-gpio@vger.kernel.org (pinctrl driver)
 F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
 F:	drivers/pinctrl/pinctrl-k210.c
 
+CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
+M:	Damien Le Moal <damien.lemoal@wdc.com>
+L:	linux-kernel@vger.kernel.org
+L:	linux-riscv@lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
+F:	drivers/reset/reset-k210.c
+
 CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
 M:	Damien Le Moal <damien.lemoal@wdc.com>
 L:	linux-riscv@lists.infradead.org
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 68bdd664b5c2..b3cd253ec2c2 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -33,6 +33,9 @@ config SOC_CANAAN
 	select CLK_K210
 	select PINCTRL
 	select PINCTRL_K210
+	select ARCH_HAS_RESET_CONTROLLER
+	select RESET_CONTROLLER
+	select RESET_K210
 	help
 	  This enables support for Canaan Kendryte K210 SoC platform hardware.
 
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 07d162b179fc..529d206cfdfd 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -245,6 +245,15 @@ config RESET_ZYNQ
 	help
 	  This enables the reset controller driver for Xilinx Zynq SoCs.
 
+config RESET_K210
+	bool "Reset controller driver for Canaan Kendryte K210 SoC"
+	depends on RISCV && SOC_CANAAN
+	depends on OF && MFD_SYSCON
+	help
+	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
+	  Say Y if you want to control reset signals provided by this
+	  controller.
+
 source "drivers/reset/sti/Kconfig"
 source "drivers/reset/hisilicon/Kconfig"
 source "drivers/reset/tegra/Kconfig"
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 16947610cc3b..1730a31e6871 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -33,4 +33,5 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
 obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
 obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
 obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
+obj-$(CONFIG_RESET_K210) += reset-k210.o
 
diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
new file mode 100644
index 000000000000..2cf9a63c763d
--- /dev/null
+++ b/drivers/reset/reset-k210.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Western Digital Corporation or its affiliates.
+ */
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <soc/canaan/k210-sysctl.h>
+
+#include <dt-bindings/reset/k210-rst.h>
+
+#define K210_RST_MASK	0x27FFFFFF
+
+struct k210_rst {
+	struct regmap *map;
+	struct reset_controller_dev rcdev;
+};
+
+static inline struct k210_rst *
+to_k210_rst(struct reset_controller_dev *rcdev)
+{
+	return container_of(rcdev, struct k210_rst, rcdev);
+}
+
+static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
+				  unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 bit = BIT(id);
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	dev_dbg(rcdev->dev, "assert %lu\n", id);
+
+	regmap_update_bits(ksr->map, K210_SYSCTL_PERI_RESET, bit, 1);
+
+	return 0;
+}
+
+static inline int k210_rst_deassert(struct reset_controller_dev *rcdev,
+				    unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 bit = BIT(id);
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	dev_dbg(rcdev->dev, "deassert %lu\n", id);
+
+	regmap_update_bits(ksr->map, K210_SYSCTL_PERI_RESET, bit, 0);
+
+	return 0;
+}
+
+static int k210_rst_reset(struct reset_controller_dev *rcdev,
+			  unsigned long id)
+{
+	int ret;
+
+	dev_dbg(rcdev->dev, "reset %lu\n", id);
+
+	ret = k210_rst_assert(rcdev, id);
+	if (ret == 0) {
+		udelay(10);
+		ret = k210_rst_deassert(rcdev, id);
+	}
+
+	return ret;
+}
+
+static int k210_rst_status(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	struct k210_rst *ksr = to_k210_rst(rcdev);
+	u32 reg, bit = BIT(id);
+	int ret;
+
+	if (!(bit & K210_RST_MASK))
+		return -EINVAL;
+
+	ret = regmap_read(ksr->map, K210_SYSCTL_PERI_RESET, &reg);
+	if (ret)
+		return ret;
+
+	return ret & bit;
+}
+
+static const struct reset_control_ops k210_rst_ops = {
+	.assert		= k210_rst_assert,
+	.deassert	= k210_rst_deassert,
+	.reset		= k210_rst_reset,
+	.status		= k210_rst_status,
+};
+
+static int __init k210_rst_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct k210_rst *ksr;
+
+	dev_info(dev, "K210 reset controller\n");
+
+	if (!dev->parent) {
+		dev_err(&pdev->dev, "No parent for K210 reset controller\n");
+		return -ENODEV;
+	}
+
+	ksr = devm_kzalloc(dev, sizeof(*ksr), GFP_KERNEL);
+	if (!ksr)
+		return -ENOMEM;
+
+	ksr->map = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(ksr->map))
+		return PTR_ERR(ksr->map);
+
+	ksr->rcdev.owner = THIS_MODULE;
+	ksr->rcdev.dev = dev;
+	ksr->rcdev.of_node = dev->of_node;
+	ksr->rcdev.nr_resets = fls(K210_RST_MASK);
+	ksr->rcdev.ops = &k210_rst_ops;
+
+	return devm_reset_controller_register(dev, &ksr->rcdev);
+}
+
+static const struct of_device_id k210_rst_dt_ids[] = {
+	{ .compatible = "canaan,k210-rst" },
+};
+
+static struct platform_driver k210_rst_driver = {
+	.probe	= k210_rst_probe,
+	.driver = {
+		.name		= "k210-rst",
+		.of_match_table	= k210_rst_dt_ids,
+	},
+};
+builtin_platform_driver(k210_rst_driver);
-- 
2.28.0


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

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

* [PATCH v4 14/21] riscv: Update Canaan Kendryte K210 device tree
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Update the Canaan Kendryte K210 base device tree k210.dtsi to define
all peripherals of the SoC, their clocks and reset lines. The device
tree file k210.dts is renamed to k210_generic.dts and becomes the
default value selection of the SOC_CANAAN_K210_DTB_BUILTIN_SOURCE
configuration option. No device beside the serial console is defined by
this device tree. This makes this generic device tree suitable for all
known K210 boards using a builtin initramfs.

Most updates to the k210.dtsi file come from Sean Anderson's work on
U-Boot support for the K210.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/Kconfig.socs                     |   2 +-
 arch/riscv/boot/dts/canaan/k210.dts         |  23 -
 arch/riscv/boot/dts/canaan/k210.dtsi        | 562 ++++++++++++++++++--
 arch/riscv/boot/dts/canaan/k210_generic.dts |  46 ++
 4 files changed, 578 insertions(+), 55 deletions(-)
 delete mode 100644 arch/riscv/boot/dts/canaan/k210.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_generic.dts

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index b3cd253ec2c2..93a5c21077a3 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -56,7 +56,7 @@ config SOC_CANAAN_K210_DTB_SOURCE
 	string "Source file for the Canaan Kendryte K210 builtin DTB"
 	depends on SOC_CANAAN
 	depends on SOC_CANAAN_K210_DTB_BUILTIN
-	default "k210"
+	default "k210_generic"
 	help
 	  Base name (without suffix, relative to arch/riscv/boot/dts/canaan)
 	  for the DTS file that will be used to produce the DTB linked into the
diff --git a/arch/riscv/boot/dts/canaan/k210.dts b/arch/riscv/boot/dts/canaan/k210.dts
deleted file mode 100644
index 0d1f28fce6b2..000000000000
--- a/arch/riscv/boot/dts/canaan/k210.dts
+++ /dev/null
@@ -1,23 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2020 Western Digital Corporation or its affiliates.
- */
-
-/dts-v1/;
-
-#include "k210.dtsi"
-
-/ {
-	model = "Kendryte K210 generic";
-	compatible = "kendryte,k210";
-
-	chosen {
-		bootargs = "earlycon console=ttySIF0";
-		stdout-path = "serial0";
-	};
-};
-
-&uarths0 {
-	status = "okay";
-};
-
diff --git a/arch/riscv/boot/dts/canaan/k210.dtsi b/arch/riscv/boot/dts/canaan/k210.dtsi
index d2d0ff645632..594505d582fc 100644
--- a/arch/riscv/boot/dts/canaan/k210.dtsi
+++ b/arch/riscv/boot/dts/canaan/k210.dtsi
@@ -1,9 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright (C) 2019 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
  */
 #include <dt-bindings/clock/k210-clk.h>
+#include <dt-bindings/pinctrl/k210-fpioa.h>
+#include <dt-bindings/reset/k210-rst.h>
 
 / {
 	/*
@@ -12,10 +14,29 @@ / {
 	 */
 	#address-cells = <1>;
 	#size-cells = <1>;
-	compatible = "kendryte,k210";
+	compatible = "canaan,kendryte-k210";
 
 	aliases {
+		cpu0 = &cpu0;
+		cpu1 = &cpu1;
+		dma0 = &dmac0;
+		gpio0 = &gpio0;
+		gpio1 = &gpio1_0;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		pinctrl0 = &fpioa;
 		serial0 = &uarths0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		spi0 = &spi0;
+		spi1 = &spi1;
+		spi2 = &spi2;
+		spi3 = &spi3;
+		timer0 = &timer0;
+		timer1 = &timer1;
+		timer2 = &timer2;
 	};
 
 	/*
@@ -30,16 +51,15 @@ cpus {
 		timebase-frequency = <7800000>;
 		cpu0: cpu@0 {
 			device_type = "cpu";
+			compatible = "canaan,k210", "sifive,rocket0", "riscv";
 			reg = <0>;
-			compatible = "kendryte,k210", "sifive,rocket0", "riscv";
-			riscv,isa = "rv64imafdc";
+			riscv,isa = "rv64imafdgc";
 			mmu-type = "none";
-			i-cache-size = <0x8000>;
 			i-cache-block-size = <64>;
-			d-cache-size = <0x8000>;
+			i-cache-size = <0x8000>;
 			d-cache-block-size = <64>;
-			clocks = <&sysctl K210_CLK_CPU>;
-			clock-frequency = <390000000>;
+			d-cache-size = <0x8000>;
+			clocks = <&sysclk K210_CLK_CPU>;
 			cpu0_intc: interrupt-controller {
 				#interrupt-cells = <1>;
 				interrupt-controller;
@@ -48,16 +68,15 @@ cpu0_intc: interrupt-controller {
 		};
 		cpu1: cpu@1 {
 			device_type = "cpu";
+			compatible = "canaan,k210", "sifive,rocket0", "riscv";
 			reg = <1>;
-			compatible = "kendryte,k210", "sifive,rocket0", "riscv";
-			riscv,isa = "rv64imafdc";
+			riscv,isa = "rv64imafdgc";
 			mmu-type = "none";
-			i-cache-size = <0x8000>;
 			i-cache-block-size = <64>;
-			d-cache-size = <0x8000>;
+			i-cache-size = <0x8000>;
 			d-cache-block-size = <64>;
-			clocks = <&sysctl K210_CLK_CPU>;
-			clock-frequency = <390000000>;
+			d-cache-size = <0x8000>;
+			clocks = <&sysclk K210_CLK_CPU>;
 			cpu1_intc: interrupt-controller {
 				#interrupt-cells = <1>;
 				interrupt-controller;
@@ -68,14 +87,19 @@ cpu1_intc: interrupt-controller {
 
 	sram: memory@80000000 {
 		device_type = "memory";
+		compatible = "canaan,k210-sram";
 		reg = <0x80000000 0x400000>,
 		      <0x80400000 0x200000>,
 		      <0x80600000 0x200000>;
 		reg-names = "sram0", "sram1", "aisram";
+		clocks = <&sysclk K210_CLK_SRAM0>,
+			 <&sysclk K210_CLK_SRAM1>,
+			 <&sysclk K210_CLK_AI>;
+		clock-names = "sram0", "sram1", "aisram";
 	};
 
 	clocks {
-		in0: oscillator {
+		in0: osc {
 			compatible = "fixed-clock";
 			#clock-cells = <0>;
 			clock-frequency = <26000000>;
@@ -85,41 +109,517 @@ in0: oscillator {
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "kendryte,k210-soc", "simple-bus";
+		compatible = "canaan,k210-soc", "simple-bus";
 		ranges;
 		interrupt-parent = <&plic0>;
 
-		sysctl: sysctl@50440000 {
-			compatible = "kendryte,k210-sysctl", "simple-mfd";
-			reg = <0x50440000 0x1000>;
-			#clock-cells = <1>;
+		debug0: debug@0 {
+			compatible = "canaan,k210-debug", "riscv,debug";
+			reg = <0x0 0x1000>;
+			status = "disabled";
+		};
+
+		rom0: nvmem@1000 {
+			reg = <0x1000 0x1000>;
+			read-only;
+			status = "disabled";
 		};
 
 		clint0: clint@2000000 {
 			#interrupt-cells = <1>;
-			compatible = "riscv,clint0";
+			compatible = "canaan,k210-clint", "riscv,clint0";
 			reg = <0x2000000 0xC000>;
-			interrupts-extended =  <&cpu0_intc 3 &cpu0_intc 7
-						&cpu1_intc 3 &cpu1_intc 7>;
-			clocks = <&sysctl K210_CLK_ACLK>;
+			interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>,
+					      <&cpu1_intc 3>, <&cpu1_intc 7>;
+			clocks = <&sysclk K210_CLK_CLINT>;
 		};
 
-		plic0: interrupt-controller@c000000 {
+		plic0: interrupt-controller@C000000 {
 			#interrupt-cells = <1>;
-			interrupt-controller;
-			compatible = "kendryte,k210-plic0", "riscv,plic0";
+			compatible = "canaan,k210-plic", "riscv,plic0";
 			reg = <0xC000000 0x4000000>;
-			interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 0xffffffff>,
-					      <&cpu1_intc 11>, <&cpu1_intc 0xffffffff>;
+			interrupt-controller;
+			interrupts-extended = <&cpu0_intc 11>,
+					      <&cpu1_intc 11>;
 			riscv,ndev = <65>;
 			riscv,max-priority = <7>;
 		};
 
 		uarths0: serial@38000000 {
-			compatible = "kendryte,k210-uarths", "sifive,uart0";
+			compatible = "canaan,k210-uarths", "sifive,uart0";
 			reg = <0x38000000 0x1000>;
 			interrupts = <33>;
-			clocks = <&sysctl K210_CLK_CPU>;
+			clocks = <&sysclk K210_CLK_CPU>;
+			status = "disabled";
+		};
+
+		gpio0: gpio-controller@38001000 {
+			#interrupt-cells = <2>;
+			#gpio-cells = <2>;
+			compatible = "canaan,k210-gpiohs", "sifive,gpio0";
+			reg = <0x38001000 0x1000>;
+			interrupt-controller;
+			interrupts = <34 35 36 37 38 39 40 41
+				      42 43 44 45 46 47 48 49
+				      50 51 52 53 54 55 56 57
+				      58 59 60 61 62 63 64 65>;
+			gpio-controller;
+			ngpios = <32>;
+			status = "disabled";
+		};
+
+		kpu0: kpu@40800000 {
+			compatible = "canaan,k210-kpu";
+			reg = <0x40800000 0xc00000>;
+			interrupts = <25>;
+			clocks = <&sysclk K210_CLK_AI>;
+			status = "disabled";
+		};
+
+		fft0: fft@42000000 {
+			compatible = "canaan,k210-fft";
+			reg = <0x42000000 0x400000>;
+			interrupts = <26>;
+			clocks = <&sysclk K210_CLK_FFT>;
+			resets = <&sysrst K210_RST_FFT>;
+			status = "disabled";
+		};
+
+		dmac0: dma-controller@50000000 {
+			compatible = "canaan,k210-dmac", "snps,axi-dma-1.01a";
+			reg = <0x50000000 0x1000>;
+			interrupts = <27 28 29 30 31 32>;
+			clocks = <&sysclk K210_CLK_DMA>, <&sysclk K210_CLK_DMA>;
+			clock-names = "core-clk", "cfgr-clk";
+			resets = <&sysrst K210_RST_DMA>;
+			dma-channels = <6>;
+			snps,dma-masters = <2>;
+			snps,priority = <0 1 2 3 4 5>;
+			snps,data-width = <5>;
+			snps,block-size = <0x200000 0x200000 0x200000
+					   0x200000 0x200000 0x200000>;
+			snps,axi-max-burst-len = <256>;
+			status = "disabled";
+		};
+
+		apb0: bus@50200000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "canaan,k210-apb", "simple-pm-bus";
+			ranges;
+			clocks = <&sysclk K210_CLK_APB0>;
+
+			gpio1: gpio-controller@50200000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "canaan,k210-gpio",
+					     "snps,dw-apb-gpio";
+				reg = <0x50200000 0x80>;
+				clocks = <&sysclk K210_CLK_APB0>,
+					 <&sysclk K210_CLK_GPIO>;
+				clock-names = "bus", "db";
+				resets = <&sysrst K210_RST_GPIO>;
+				status = "disabled";
+
+				gpio1_0: gpio1@0 {
+					#gpio-cells = <2>;
+					#interrupt-cells = <2>;
+					compatible = "snps,dw-apb-gpio-port";
+					reg = <0>;
+					interrupt-controller;
+					interrupts = <23>;
+					gpio-controller;
+					ngpios = <8>;
+				};
+			};
+
+			uart1: serial@50210000 {
+				compatible = "canaan,k210-uart",
+					     "snps,dw-apb-uart";
+				reg = <0x50210000 0x100>;
+				interrupts = <11>;
+				clocks = <&sysclk K210_CLK_UART1>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "baudclk", "apb_pclk";
+				resets = <&sysrst K210_RST_UART1>;
+				reg-io-width = <4>;
+				reg-shift = <2>;
+				dcd-override;
+				dsr-override;
+				cts-override;
+				ri-override;
+				status = "disabled";
+			};
+
+			uart2: serial@50220000 {
+				compatible = "canaan,k210-uart",
+					     "snps,dw-apb-uart";
+				reg = <0x50220000 0x100>;
+				interrupts = <12>;
+				clocks = <&sysclk K210_CLK_UART2>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "baudclk", "apb_pclk";
+				resets = <&sysrst K210_RST_UART2>;
+				reg-io-width = <4>;
+				reg-shift = <2>;
+				dcd-override;
+				dsr-override;
+				cts-override;
+				ri-override;
+				status = "disabled";
+			};
+
+			uart3: serial@50230000 {
+				compatible = "canaan,k210-uart",
+					     "snps,dw-apb-uart";
+				reg = <0x50230000 0x100>;
+				interrupts = <13>;
+				clocks = <&sysclk K210_CLK_UART3>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "baudclk", "apb_pclk";
+				resets = <&sysrst K210_RST_UART3>;
+				reg-io-width = <4>;
+				reg-shift = <2>;
+				dcd-override;
+				dsr-override;
+				cts-override;
+				ri-override;
+				status = "disabled";
+			};
+
+			spi2: spi@50240000 {
+				compatible = "canaan,k210-spi",
+					     "snps,dw-apb-ssi-4.01",
+					     "snps,dw-apb-ssi";
+				spi-slave;
+				reg = <0x50240000 0x100>;
+				interrupts = <3>;
+				clocks = <&sysclk K210_CLK_SPI2>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ssi_clk", "pclk";
+				resets = <&sysrst K210_RST_SPI2>;
+				spi-max-frequency = <25000000>;
+				status = "disabled";
+			};
+
+			i2s0: i2s@50250000 {
+				compatible = "canaan,k210-i2s",
+					     "snps,designware-i2s";
+				reg = <0x50250000 0x200>;
+				interrupts = <5>;
+				clocks = <&sysclk K210_CLK_I2S0>;
+				clock-names = "i2sclk";
+				resets = <&sysrst K210_RST_I2S0>;
+				status = "disabled";
+			};
+
+			apu0: sound@520250200 {
+				compatible = "canaan,k210-apu";
+				reg = <0x50250200 0x200>;
+				status = "disabled";
+			};
+
+			i2s1: i2s@50260000 {
+				compatible = "canaan,k210-i2s",
+					     "snps,designware-i2s";
+				reg = <0x50260000 0x200>;
+				interrupts = <6>;
+				clocks = <&sysclk K210_CLK_I2S1>;
+				clock-names = "i2sclk";
+				resets = <&sysrst K210_RST_I2S1>;
+				status = "disabled";
+			};
+
+			i2s2: i2s@50270000 {
+				compatible = "canaan,k210-i2s",
+					     "snps,designware-i2s";
+				reg = <0x50270000 0x200>;
+				interrupts = <7>;
+				clocks = <&sysclk K210_CLK_I2S2>;
+				clock-names = "i2sclk";
+				resets = <&sysrst K210_RST_I2S2>;
+				status = "disabled";
+			};
+
+			i2c0: i2c@50280000 {
+				compatible = "canaan,k210-i2c",
+					     "snps,designware-i2c";
+				reg = <0x50280000 0x100>;
+				interrupts = <8>;
+				clocks = <&sysclk K210_CLK_I2C0>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ref", "pclk";
+				resets = <&sysrst K210_RST_I2C0>;
+				status = "disabled";
+			};
+
+			i2c1: i2c@50290000 {
+				compatible = "canaan,k210-i2c",
+					     "snps,designware-i2c";
+				reg = <0x50290000 0x100>;
+				interrupts = <9>;
+				clocks = <&sysclk K210_CLK_I2C1>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ref", "pclk";
+				resets = <&sysrst K210_RST_I2C1>;
+				status = "disabled";
+			};
+
+			i2c2: i2c@502A0000 {
+				compatible = "canaan,k210-i2c",
+					     "snps,designware-i2c";
+				reg = <0x502A0000 0x100>;
+				interrupts = <10>;
+				clocks = <&sysclk K210_CLK_I2C2>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ref", "pclk";
+				resets = <&sysrst K210_RST_I2C2>;
+				status = "disabled";
+			};
+
+			fpioa: pinmux@502B0000 {
+				compatible = "canaan,k210-fpioa";
+				reg = <0x502B0000 0x100>;
+				clocks = <&sysclk K210_CLK_FPIOA>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ref", "pclk";
+				resets = <&sysrst K210_RST_FPIOA>;
+				canaan,k210-sysctl-power = <&sysctl 108>;
+				status = "disabled";
+			};
+
+			sha256: sha256@502C0000 {
+				compatible = "canaan,k210-sha256";
+				reg = <0x502C0000 0x100>;
+				clocks = <&sysclk K210_CLK_SHA>;
+				resets = <&sysrst K210_RST_SHA>;
+				status = "disabled";
+			};
+
+			timer0: timer@502D0000 {
+				compatible = "canaan,k210-timer",
+					     "snps,dw-apb-timer";
+				reg = <0x502D0000 0x100>;
+				interrupts = <14 15>;
+				clocks = <&sysclk K210_CLK_TIMER0>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "timer", "pclk";
+				resets = <&sysrst K210_RST_TIMER0>;
+				status = "disabled";
+			};
+
+			timer1: timer@502E0000 {
+				compatible = "canaan,k210-timer",
+					     "snps,dw-apb-timer";
+				reg = <0x502E0000 0x100>;
+				interrupts = <16 17>;
+				clocks = <&sysclk K210_CLK_TIMER1>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "timer", "pclk";
+				resets = <&sysrst K210_RST_TIMER1>;
+				status = "disabled";
+			};
+
+			timer2: timer@502F0000 {
+				compatible = "canaan,k210-timer",
+					     "snps,dw-apb-timer";
+				reg = <0x502F0000 0x100>;
+				interrupts = <18 19>;
+				clocks = <&sysclk K210_CLK_TIMER2>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "timer", "pclk";
+				resets = <&sysrst K210_RST_TIMER2>;
+				status = "disabled";
+			};
+		};
+
+		apb1: bus@50400000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "canaan,k210-apb", "simple-pm-bus";
+			ranges;
+			clocks = <&sysclk K210_CLK_APB1>;
+
+			wdt0: watchdog@50400000 {
+				compatible = "canaan,k210-wdt", "snps,dw-wdt";
+				reg = <0x50400000 0x100>;
+				interrupts = <21>;
+				clocks = <&sysclk K210_CLK_WDT0>,
+					 <&sysclk K210_CLK_APB1>;
+				clock-names = "tclk", "pclk";
+				resets = <&sysrst K210_RST_WDT0>;
+				status = "disabled";
+			};
+
+			wdt1: watchdog@50410000 {
+				compatible = "canaan,k210-wdt", "snps,dw-wdt";
+				reg = <0x50410000 0x100>;
+				interrupts = <22>;
+				clocks = <&sysclk K210_CLK_WDT1>,
+					 <&sysclk K210_CLK_APB1>;
+				clock-names = "tclk", "pclk";
+				resets = <&sysrst K210_RST_WDT1>;
+				status = "disabled";
+			};
+
+			otp0: nvmem@50420000 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "canaan,k210-otp";
+				reg = <0x50420000 0x100>,
+				      <0x88000000 0x20000>;
+				reg-names = "reg", "mem";
+				clocks = <&sysclk K210_CLK_ROM>;
+				resets = <&sysrst K210_RST_ROM>;
+				read-only;
+				status = "disabled";
+
+				/* Bootloader */
+				firmware@00000 {
+					reg = <0x00000 0xC200>;
+				};
+
+				/*
+				 * config string as described in RISC-V
+				 * privileged spec 1.9
+				 */
+				config-1-9@1c000 {
+					reg = <0x1C000 0x1000>;
+				};
+
+				/*
+				 * Device tree containing only registers,
+				 * interrupts, and cpus
+				 */
+				fdt@1d000 {
+					reg = <0x1D000 0x2000>;
+				};
+
+				/* CPU/ROM credits */
+				credits@1f000 {
+					reg = <0x1F000 0x1000>;
+				};
+			};
+
+			dvp0: camera@50430000 {
+				compatible = "canaan,k210-dvp";
+				reg = <0x50430000 0x100>;
+				interrupts = <24>;
+				clocks = <&sysclk K210_CLK_DVP>;
+				resets = <&sysrst K210_RST_DVP>;
+				canaan,k210-misc-offset = <&sysctl 84>;
+				status = "disabled";
+			};
+
+			sysctl: syscon@50440000 {
+				compatible = "canaan,k210-sysctl",
+					     "syscon", "simple-mfd";
+				reg = <0x50440000 0x100>;
+				reg-io-width = <4>;
+				clocks = <&sysclk K210_CLK_APB1>;
+				clock-names = "pclk";
+
+				sysclk: clock-controller {
+					#clock-cells = <1>;
+					compatible = "canaan,k210-clk";
+					clocks = <&in0>;
+				};
+
+				sysrst: reset-controller {
+					compatible = "canaan,k210-rst";
+					#reset-cells = <1>;
+				};
+
+				reboot: syscon-reboot {
+					compatible = "syscon-reboot";
+					regmap = <&sysctl>;
+					offset = <48>;
+					mask = <1>;
+					value = <1>;
+				};
+			};
+
+			aes0: aes@50450000 {
+				compatible = "canaan,k210-aes";
+				reg = <0x50450000 0x100>;
+				clocks = <&sysclk K210_CLK_AES>;
+				resets = <&sysrst K210_RST_AES>;
+				status = "disabled";
+			};
+
+			rtc: rtc@50460000 {
+				compatible = "canaan,k210-rtc";
+				reg = <0x50460000 0x100>;
+				clocks = <&in0>;
+				resets = <&sysrst K210_RST_RTC>;
+				interrupts = <20>;
+				status = "disabled";
+			};
+		};
+
+		apb2: bus@52000000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "canaan,k210-apb", "simple-pm-bus";
+			ranges;
+			clocks = <&sysclk K210_CLK_APB2>;
+
+			spi0: spi@52000000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "canaan,k210-spi",
+					     "snps,dw-apb-ssi-4.01",
+					     "snps,dw-apb-ssi";
+				reg = <0x52000000 0x100>;
+				interrupts = <1>;
+				clocks = <&sysclk K210_CLK_SPI0>,
+					 <&sysclk K210_CLK_APB2>;
+				clock-names = "ssi_clk", "pclk";
+				resets = <&sysrst K210_RST_SPI0>;
+				reset-names = "spi";
+				spi-max-frequency = <25000000>;
+				num-cs = <4>;
+				reg-io-width = <4>;
+				status = "disabled";
+			};
+
+			spi1: spi@53000000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "canaan,k210-spi",
+					     "snps,dw-apb-ssi-4.01",
+					     "snps,dw-apb-ssi";
+				reg = <0x53000000 0x100>;
+				interrupts = <2>;
+				clocks = <&sysclk K210_CLK_SPI1>,
+					 <&sysclk K210_CLK_APB2>;
+				clock-names = "ssi_clk", "pclk";
+				resets = <&sysrst K210_RST_SPI1>;
+				reset-names = "spi";
+				spi-max-frequency = <25000000>;
+				num-cs = <4>;
+				reg-io-width = <4>;
+				status = "disabled";
+			};
+
+			spi3: spi@54000000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "canaan,k210-ssi",
+					     "snps,dwc-ssi-1.01a";
+				reg = <0x54000000 0x200>;
+				interrupts = <4>;
+				clocks = <&sysclk K210_CLK_SPI3>,
+					 <&sysclk K210_CLK_APB2>;
+				clock-names = "ssi_clk", "pclk";
+				resets = <&sysrst K210_RST_SPI3>;
+				reset-names = "spi";
+				/* Could possibly go up to 200 MHz */
+				spi-max-frequency = <100000000>;
+				num-cs = <4>;
+				reg-io-width = <4>;
+				status = "disabled";
+			};
 		};
 	};
 };
diff --git a/arch/riscv/boot/dts/canaan/k210_generic.dts b/arch/riscv/boot/dts/canaan/k210_generic.dts
new file mode 100644
index 000000000000..396c8ca4d24d
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_generic.dts
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Kendryte K210 generic";
+	compatible = "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&fpioa {
+	pinctrl-0 = <&jtag_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	jtag_pins: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pins: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
-- 
2.28.0


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

* [PATCH v4 14/21] riscv: Update Canaan Kendryte K210 device tree
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Update the Canaan Kendryte K210 base device tree k210.dtsi to define
all peripherals of the SoC, their clocks and reset lines. The device
tree file k210.dts is renamed to k210_generic.dts and becomes the
default value selection of the SOC_CANAAN_K210_DTB_BUILTIN_SOURCE
configuration option. No device beside the serial console is defined by
this device tree. This makes this generic device tree suitable for all
known K210 boards using a builtin initramfs.

Most updates to the k210.dtsi file come from Sean Anderson's work on
U-Boot support for the K210.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/Kconfig.socs                     |   2 +-
 arch/riscv/boot/dts/canaan/k210.dts         |  23 -
 arch/riscv/boot/dts/canaan/k210.dtsi        | 562 ++++++++++++++++++--
 arch/riscv/boot/dts/canaan/k210_generic.dts |  46 ++
 4 files changed, 578 insertions(+), 55 deletions(-)
 delete mode 100644 arch/riscv/boot/dts/canaan/k210.dts
 create mode 100644 arch/riscv/boot/dts/canaan/k210_generic.dts

diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index b3cd253ec2c2..93a5c21077a3 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -56,7 +56,7 @@ config SOC_CANAAN_K210_DTB_SOURCE
 	string "Source file for the Canaan Kendryte K210 builtin DTB"
 	depends on SOC_CANAAN
 	depends on SOC_CANAAN_K210_DTB_BUILTIN
-	default "k210"
+	default "k210_generic"
 	help
 	  Base name (without suffix, relative to arch/riscv/boot/dts/canaan)
 	  for the DTS file that will be used to produce the DTB linked into the
diff --git a/arch/riscv/boot/dts/canaan/k210.dts b/arch/riscv/boot/dts/canaan/k210.dts
deleted file mode 100644
index 0d1f28fce6b2..000000000000
--- a/arch/riscv/boot/dts/canaan/k210.dts
+++ /dev/null
@@ -1,23 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2020 Western Digital Corporation or its affiliates.
- */
-
-/dts-v1/;
-
-#include "k210.dtsi"
-
-/ {
-	model = "Kendryte K210 generic";
-	compatible = "kendryte,k210";
-
-	chosen {
-		bootargs = "earlycon console=ttySIF0";
-		stdout-path = "serial0";
-	};
-};
-
-&uarths0 {
-	status = "okay";
-};
-
diff --git a/arch/riscv/boot/dts/canaan/k210.dtsi b/arch/riscv/boot/dts/canaan/k210.dtsi
index d2d0ff645632..594505d582fc 100644
--- a/arch/riscv/boot/dts/canaan/k210.dtsi
+++ b/arch/riscv/boot/dts/canaan/k210.dtsi
@@ -1,9 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright (C) 2019 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
  */
 #include <dt-bindings/clock/k210-clk.h>
+#include <dt-bindings/pinctrl/k210-fpioa.h>
+#include <dt-bindings/reset/k210-rst.h>
 
 / {
 	/*
@@ -12,10 +14,29 @@ / {
 	 */
 	#address-cells = <1>;
 	#size-cells = <1>;
-	compatible = "kendryte,k210";
+	compatible = "canaan,kendryte-k210";
 
 	aliases {
+		cpu0 = &cpu0;
+		cpu1 = &cpu1;
+		dma0 = &dmac0;
+		gpio0 = &gpio0;
+		gpio1 = &gpio1_0;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		pinctrl0 = &fpioa;
 		serial0 = &uarths0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		spi0 = &spi0;
+		spi1 = &spi1;
+		spi2 = &spi2;
+		spi3 = &spi3;
+		timer0 = &timer0;
+		timer1 = &timer1;
+		timer2 = &timer2;
 	};
 
 	/*
@@ -30,16 +51,15 @@ cpus {
 		timebase-frequency = <7800000>;
 		cpu0: cpu@0 {
 			device_type = "cpu";
+			compatible = "canaan,k210", "sifive,rocket0", "riscv";
 			reg = <0>;
-			compatible = "kendryte,k210", "sifive,rocket0", "riscv";
-			riscv,isa = "rv64imafdc";
+			riscv,isa = "rv64imafdgc";
 			mmu-type = "none";
-			i-cache-size = <0x8000>;
 			i-cache-block-size = <64>;
-			d-cache-size = <0x8000>;
+			i-cache-size = <0x8000>;
 			d-cache-block-size = <64>;
-			clocks = <&sysctl K210_CLK_CPU>;
-			clock-frequency = <390000000>;
+			d-cache-size = <0x8000>;
+			clocks = <&sysclk K210_CLK_CPU>;
 			cpu0_intc: interrupt-controller {
 				#interrupt-cells = <1>;
 				interrupt-controller;
@@ -48,16 +68,15 @@ cpu0_intc: interrupt-controller {
 		};
 		cpu1: cpu@1 {
 			device_type = "cpu";
+			compatible = "canaan,k210", "sifive,rocket0", "riscv";
 			reg = <1>;
-			compatible = "kendryte,k210", "sifive,rocket0", "riscv";
-			riscv,isa = "rv64imafdc";
+			riscv,isa = "rv64imafdgc";
 			mmu-type = "none";
-			i-cache-size = <0x8000>;
 			i-cache-block-size = <64>;
-			d-cache-size = <0x8000>;
+			i-cache-size = <0x8000>;
 			d-cache-block-size = <64>;
-			clocks = <&sysctl K210_CLK_CPU>;
-			clock-frequency = <390000000>;
+			d-cache-size = <0x8000>;
+			clocks = <&sysclk K210_CLK_CPU>;
 			cpu1_intc: interrupt-controller {
 				#interrupt-cells = <1>;
 				interrupt-controller;
@@ -68,14 +87,19 @@ cpu1_intc: interrupt-controller {
 
 	sram: memory@80000000 {
 		device_type = "memory";
+		compatible = "canaan,k210-sram";
 		reg = <0x80000000 0x400000>,
 		      <0x80400000 0x200000>,
 		      <0x80600000 0x200000>;
 		reg-names = "sram0", "sram1", "aisram";
+		clocks = <&sysclk K210_CLK_SRAM0>,
+			 <&sysclk K210_CLK_SRAM1>,
+			 <&sysclk K210_CLK_AI>;
+		clock-names = "sram0", "sram1", "aisram";
 	};
 
 	clocks {
-		in0: oscillator {
+		in0: osc {
 			compatible = "fixed-clock";
 			#clock-cells = <0>;
 			clock-frequency = <26000000>;
@@ -85,41 +109,517 @@ in0: oscillator {
 	soc {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "kendryte,k210-soc", "simple-bus";
+		compatible = "canaan,k210-soc", "simple-bus";
 		ranges;
 		interrupt-parent = <&plic0>;
 
-		sysctl: sysctl@50440000 {
-			compatible = "kendryte,k210-sysctl", "simple-mfd";
-			reg = <0x50440000 0x1000>;
-			#clock-cells = <1>;
+		debug0: debug@0 {
+			compatible = "canaan,k210-debug", "riscv,debug";
+			reg = <0x0 0x1000>;
+			status = "disabled";
+		};
+
+		rom0: nvmem@1000 {
+			reg = <0x1000 0x1000>;
+			read-only;
+			status = "disabled";
 		};
 
 		clint0: clint@2000000 {
 			#interrupt-cells = <1>;
-			compatible = "riscv,clint0";
+			compatible = "canaan,k210-clint", "riscv,clint0";
 			reg = <0x2000000 0xC000>;
-			interrupts-extended =  <&cpu0_intc 3 &cpu0_intc 7
-						&cpu1_intc 3 &cpu1_intc 7>;
-			clocks = <&sysctl K210_CLK_ACLK>;
+			interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>,
+					      <&cpu1_intc 3>, <&cpu1_intc 7>;
+			clocks = <&sysclk K210_CLK_CLINT>;
 		};
 
-		plic0: interrupt-controller@c000000 {
+		plic0: interrupt-controller@C000000 {
 			#interrupt-cells = <1>;
-			interrupt-controller;
-			compatible = "kendryte,k210-plic0", "riscv,plic0";
+			compatible = "canaan,k210-plic", "riscv,plic0";
 			reg = <0xC000000 0x4000000>;
-			interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 0xffffffff>,
-					      <&cpu1_intc 11>, <&cpu1_intc 0xffffffff>;
+			interrupt-controller;
+			interrupts-extended = <&cpu0_intc 11>,
+					      <&cpu1_intc 11>;
 			riscv,ndev = <65>;
 			riscv,max-priority = <7>;
 		};
 
 		uarths0: serial@38000000 {
-			compatible = "kendryte,k210-uarths", "sifive,uart0";
+			compatible = "canaan,k210-uarths", "sifive,uart0";
 			reg = <0x38000000 0x1000>;
 			interrupts = <33>;
-			clocks = <&sysctl K210_CLK_CPU>;
+			clocks = <&sysclk K210_CLK_CPU>;
+			status = "disabled";
+		};
+
+		gpio0: gpio-controller@38001000 {
+			#interrupt-cells = <2>;
+			#gpio-cells = <2>;
+			compatible = "canaan,k210-gpiohs", "sifive,gpio0";
+			reg = <0x38001000 0x1000>;
+			interrupt-controller;
+			interrupts = <34 35 36 37 38 39 40 41
+				      42 43 44 45 46 47 48 49
+				      50 51 52 53 54 55 56 57
+				      58 59 60 61 62 63 64 65>;
+			gpio-controller;
+			ngpios = <32>;
+			status = "disabled";
+		};
+
+		kpu0: kpu@40800000 {
+			compatible = "canaan,k210-kpu";
+			reg = <0x40800000 0xc00000>;
+			interrupts = <25>;
+			clocks = <&sysclk K210_CLK_AI>;
+			status = "disabled";
+		};
+
+		fft0: fft@42000000 {
+			compatible = "canaan,k210-fft";
+			reg = <0x42000000 0x400000>;
+			interrupts = <26>;
+			clocks = <&sysclk K210_CLK_FFT>;
+			resets = <&sysrst K210_RST_FFT>;
+			status = "disabled";
+		};
+
+		dmac0: dma-controller@50000000 {
+			compatible = "canaan,k210-dmac", "snps,axi-dma-1.01a";
+			reg = <0x50000000 0x1000>;
+			interrupts = <27 28 29 30 31 32>;
+			clocks = <&sysclk K210_CLK_DMA>, <&sysclk K210_CLK_DMA>;
+			clock-names = "core-clk", "cfgr-clk";
+			resets = <&sysrst K210_RST_DMA>;
+			dma-channels = <6>;
+			snps,dma-masters = <2>;
+			snps,priority = <0 1 2 3 4 5>;
+			snps,data-width = <5>;
+			snps,block-size = <0x200000 0x200000 0x200000
+					   0x200000 0x200000 0x200000>;
+			snps,axi-max-burst-len = <256>;
+			status = "disabled";
+		};
+
+		apb0: bus@50200000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "canaan,k210-apb", "simple-pm-bus";
+			ranges;
+			clocks = <&sysclk K210_CLK_APB0>;
+
+			gpio1: gpio-controller@50200000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "canaan,k210-gpio",
+					     "snps,dw-apb-gpio";
+				reg = <0x50200000 0x80>;
+				clocks = <&sysclk K210_CLK_APB0>,
+					 <&sysclk K210_CLK_GPIO>;
+				clock-names = "bus", "db";
+				resets = <&sysrst K210_RST_GPIO>;
+				status = "disabled";
+
+				gpio1_0: gpio1@0 {
+					#gpio-cells = <2>;
+					#interrupt-cells = <2>;
+					compatible = "snps,dw-apb-gpio-port";
+					reg = <0>;
+					interrupt-controller;
+					interrupts = <23>;
+					gpio-controller;
+					ngpios = <8>;
+				};
+			};
+
+			uart1: serial@50210000 {
+				compatible = "canaan,k210-uart",
+					     "snps,dw-apb-uart";
+				reg = <0x50210000 0x100>;
+				interrupts = <11>;
+				clocks = <&sysclk K210_CLK_UART1>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "baudclk", "apb_pclk";
+				resets = <&sysrst K210_RST_UART1>;
+				reg-io-width = <4>;
+				reg-shift = <2>;
+				dcd-override;
+				dsr-override;
+				cts-override;
+				ri-override;
+				status = "disabled";
+			};
+
+			uart2: serial@50220000 {
+				compatible = "canaan,k210-uart",
+					     "snps,dw-apb-uart";
+				reg = <0x50220000 0x100>;
+				interrupts = <12>;
+				clocks = <&sysclk K210_CLK_UART2>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "baudclk", "apb_pclk";
+				resets = <&sysrst K210_RST_UART2>;
+				reg-io-width = <4>;
+				reg-shift = <2>;
+				dcd-override;
+				dsr-override;
+				cts-override;
+				ri-override;
+				status = "disabled";
+			};
+
+			uart3: serial@50230000 {
+				compatible = "canaan,k210-uart",
+					     "snps,dw-apb-uart";
+				reg = <0x50230000 0x100>;
+				interrupts = <13>;
+				clocks = <&sysclk K210_CLK_UART3>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "baudclk", "apb_pclk";
+				resets = <&sysrst K210_RST_UART3>;
+				reg-io-width = <4>;
+				reg-shift = <2>;
+				dcd-override;
+				dsr-override;
+				cts-override;
+				ri-override;
+				status = "disabled";
+			};
+
+			spi2: spi@50240000 {
+				compatible = "canaan,k210-spi",
+					     "snps,dw-apb-ssi-4.01",
+					     "snps,dw-apb-ssi";
+				spi-slave;
+				reg = <0x50240000 0x100>;
+				interrupts = <3>;
+				clocks = <&sysclk K210_CLK_SPI2>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ssi_clk", "pclk";
+				resets = <&sysrst K210_RST_SPI2>;
+				spi-max-frequency = <25000000>;
+				status = "disabled";
+			};
+
+			i2s0: i2s@50250000 {
+				compatible = "canaan,k210-i2s",
+					     "snps,designware-i2s";
+				reg = <0x50250000 0x200>;
+				interrupts = <5>;
+				clocks = <&sysclk K210_CLK_I2S0>;
+				clock-names = "i2sclk";
+				resets = <&sysrst K210_RST_I2S0>;
+				status = "disabled";
+			};
+
+			apu0: sound@520250200 {
+				compatible = "canaan,k210-apu";
+				reg = <0x50250200 0x200>;
+				status = "disabled";
+			};
+
+			i2s1: i2s@50260000 {
+				compatible = "canaan,k210-i2s",
+					     "snps,designware-i2s";
+				reg = <0x50260000 0x200>;
+				interrupts = <6>;
+				clocks = <&sysclk K210_CLK_I2S1>;
+				clock-names = "i2sclk";
+				resets = <&sysrst K210_RST_I2S1>;
+				status = "disabled";
+			};
+
+			i2s2: i2s@50270000 {
+				compatible = "canaan,k210-i2s",
+					     "snps,designware-i2s";
+				reg = <0x50270000 0x200>;
+				interrupts = <7>;
+				clocks = <&sysclk K210_CLK_I2S2>;
+				clock-names = "i2sclk";
+				resets = <&sysrst K210_RST_I2S2>;
+				status = "disabled";
+			};
+
+			i2c0: i2c@50280000 {
+				compatible = "canaan,k210-i2c",
+					     "snps,designware-i2c";
+				reg = <0x50280000 0x100>;
+				interrupts = <8>;
+				clocks = <&sysclk K210_CLK_I2C0>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ref", "pclk";
+				resets = <&sysrst K210_RST_I2C0>;
+				status = "disabled";
+			};
+
+			i2c1: i2c@50290000 {
+				compatible = "canaan,k210-i2c",
+					     "snps,designware-i2c";
+				reg = <0x50290000 0x100>;
+				interrupts = <9>;
+				clocks = <&sysclk K210_CLK_I2C1>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ref", "pclk";
+				resets = <&sysrst K210_RST_I2C1>;
+				status = "disabled";
+			};
+
+			i2c2: i2c@502A0000 {
+				compatible = "canaan,k210-i2c",
+					     "snps,designware-i2c";
+				reg = <0x502A0000 0x100>;
+				interrupts = <10>;
+				clocks = <&sysclk K210_CLK_I2C2>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ref", "pclk";
+				resets = <&sysrst K210_RST_I2C2>;
+				status = "disabled";
+			};
+
+			fpioa: pinmux@502B0000 {
+				compatible = "canaan,k210-fpioa";
+				reg = <0x502B0000 0x100>;
+				clocks = <&sysclk K210_CLK_FPIOA>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "ref", "pclk";
+				resets = <&sysrst K210_RST_FPIOA>;
+				canaan,k210-sysctl-power = <&sysctl 108>;
+				status = "disabled";
+			};
+
+			sha256: sha256@502C0000 {
+				compatible = "canaan,k210-sha256";
+				reg = <0x502C0000 0x100>;
+				clocks = <&sysclk K210_CLK_SHA>;
+				resets = <&sysrst K210_RST_SHA>;
+				status = "disabled";
+			};
+
+			timer0: timer@502D0000 {
+				compatible = "canaan,k210-timer",
+					     "snps,dw-apb-timer";
+				reg = <0x502D0000 0x100>;
+				interrupts = <14 15>;
+				clocks = <&sysclk K210_CLK_TIMER0>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "timer", "pclk";
+				resets = <&sysrst K210_RST_TIMER0>;
+				status = "disabled";
+			};
+
+			timer1: timer@502E0000 {
+				compatible = "canaan,k210-timer",
+					     "snps,dw-apb-timer";
+				reg = <0x502E0000 0x100>;
+				interrupts = <16 17>;
+				clocks = <&sysclk K210_CLK_TIMER1>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "timer", "pclk";
+				resets = <&sysrst K210_RST_TIMER1>;
+				status = "disabled";
+			};
+
+			timer2: timer@502F0000 {
+				compatible = "canaan,k210-timer",
+					     "snps,dw-apb-timer";
+				reg = <0x502F0000 0x100>;
+				interrupts = <18 19>;
+				clocks = <&sysclk K210_CLK_TIMER2>,
+					 <&sysclk K210_CLK_APB0>;
+				clock-names = "timer", "pclk";
+				resets = <&sysrst K210_RST_TIMER2>;
+				status = "disabled";
+			};
+		};
+
+		apb1: bus@50400000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "canaan,k210-apb", "simple-pm-bus";
+			ranges;
+			clocks = <&sysclk K210_CLK_APB1>;
+
+			wdt0: watchdog@50400000 {
+				compatible = "canaan,k210-wdt", "snps,dw-wdt";
+				reg = <0x50400000 0x100>;
+				interrupts = <21>;
+				clocks = <&sysclk K210_CLK_WDT0>,
+					 <&sysclk K210_CLK_APB1>;
+				clock-names = "tclk", "pclk";
+				resets = <&sysrst K210_RST_WDT0>;
+				status = "disabled";
+			};
+
+			wdt1: watchdog@50410000 {
+				compatible = "canaan,k210-wdt", "snps,dw-wdt";
+				reg = <0x50410000 0x100>;
+				interrupts = <22>;
+				clocks = <&sysclk K210_CLK_WDT1>,
+					 <&sysclk K210_CLK_APB1>;
+				clock-names = "tclk", "pclk";
+				resets = <&sysrst K210_RST_WDT1>;
+				status = "disabled";
+			};
+
+			otp0: nvmem@50420000 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "canaan,k210-otp";
+				reg = <0x50420000 0x100>,
+				      <0x88000000 0x20000>;
+				reg-names = "reg", "mem";
+				clocks = <&sysclk K210_CLK_ROM>;
+				resets = <&sysrst K210_RST_ROM>;
+				read-only;
+				status = "disabled";
+
+				/* Bootloader */
+				firmware@00000 {
+					reg = <0x00000 0xC200>;
+				};
+
+				/*
+				 * config string as described in RISC-V
+				 * privileged spec 1.9
+				 */
+				config-1-9@1c000 {
+					reg = <0x1C000 0x1000>;
+				};
+
+				/*
+				 * Device tree containing only registers,
+				 * interrupts, and cpus
+				 */
+				fdt@1d000 {
+					reg = <0x1D000 0x2000>;
+				};
+
+				/* CPU/ROM credits */
+				credits@1f000 {
+					reg = <0x1F000 0x1000>;
+				};
+			};
+
+			dvp0: camera@50430000 {
+				compatible = "canaan,k210-dvp";
+				reg = <0x50430000 0x100>;
+				interrupts = <24>;
+				clocks = <&sysclk K210_CLK_DVP>;
+				resets = <&sysrst K210_RST_DVP>;
+				canaan,k210-misc-offset = <&sysctl 84>;
+				status = "disabled";
+			};
+
+			sysctl: syscon@50440000 {
+				compatible = "canaan,k210-sysctl",
+					     "syscon", "simple-mfd";
+				reg = <0x50440000 0x100>;
+				reg-io-width = <4>;
+				clocks = <&sysclk K210_CLK_APB1>;
+				clock-names = "pclk";
+
+				sysclk: clock-controller {
+					#clock-cells = <1>;
+					compatible = "canaan,k210-clk";
+					clocks = <&in0>;
+				};
+
+				sysrst: reset-controller {
+					compatible = "canaan,k210-rst";
+					#reset-cells = <1>;
+				};
+
+				reboot: syscon-reboot {
+					compatible = "syscon-reboot";
+					regmap = <&sysctl>;
+					offset = <48>;
+					mask = <1>;
+					value = <1>;
+				};
+			};
+
+			aes0: aes@50450000 {
+				compatible = "canaan,k210-aes";
+				reg = <0x50450000 0x100>;
+				clocks = <&sysclk K210_CLK_AES>;
+				resets = <&sysrst K210_RST_AES>;
+				status = "disabled";
+			};
+
+			rtc: rtc@50460000 {
+				compatible = "canaan,k210-rtc";
+				reg = <0x50460000 0x100>;
+				clocks = <&in0>;
+				resets = <&sysrst K210_RST_RTC>;
+				interrupts = <20>;
+				status = "disabled";
+			};
+		};
+
+		apb2: bus@52000000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "canaan,k210-apb", "simple-pm-bus";
+			ranges;
+			clocks = <&sysclk K210_CLK_APB2>;
+
+			spi0: spi@52000000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "canaan,k210-spi",
+					     "snps,dw-apb-ssi-4.01",
+					     "snps,dw-apb-ssi";
+				reg = <0x52000000 0x100>;
+				interrupts = <1>;
+				clocks = <&sysclk K210_CLK_SPI0>,
+					 <&sysclk K210_CLK_APB2>;
+				clock-names = "ssi_clk", "pclk";
+				resets = <&sysrst K210_RST_SPI0>;
+				reset-names = "spi";
+				spi-max-frequency = <25000000>;
+				num-cs = <4>;
+				reg-io-width = <4>;
+				status = "disabled";
+			};
+
+			spi1: spi@53000000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "canaan,k210-spi",
+					     "snps,dw-apb-ssi-4.01",
+					     "snps,dw-apb-ssi";
+				reg = <0x53000000 0x100>;
+				interrupts = <2>;
+				clocks = <&sysclk K210_CLK_SPI1>,
+					 <&sysclk K210_CLK_APB2>;
+				clock-names = "ssi_clk", "pclk";
+				resets = <&sysrst K210_RST_SPI1>;
+				reset-names = "spi";
+				spi-max-frequency = <25000000>;
+				num-cs = <4>;
+				reg-io-width = <4>;
+				status = "disabled";
+			};
+
+			spi3: spi@54000000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "canaan,k210-ssi",
+					     "snps,dwc-ssi-1.01a";
+				reg = <0x54000000 0x200>;
+				interrupts = <4>;
+				clocks = <&sysclk K210_CLK_SPI3>,
+					 <&sysclk K210_CLK_APB2>;
+				clock-names = "ssi_clk", "pclk";
+				resets = <&sysrst K210_RST_SPI3>;
+				reset-names = "spi";
+				/* Could possibly go up to 200 MHz */
+				spi-max-frequency = <100000000>;
+				num-cs = <4>;
+				reg-io-width = <4>;
+				status = "disabled";
+			};
 		};
 	};
 };
diff --git a/arch/riscv/boot/dts/canaan/k210_generic.dts b/arch/riscv/boot/dts/canaan/k210_generic.dts
new file mode 100644
index 000000000000..396c8ca4d24d
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_generic.dts
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Kendryte K210 generic";
+	compatible = "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&fpioa {
+	pinctrl-0 = <&jtag_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	jtag_pins: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pins: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
-- 
2.28.0


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

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

* [PATCH v4 15/21] riscv: Add SiPeed MAIX BiT board device tree
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the SiPeed MAIX BiT and MAIX BiTm boards. This
device tree enables LEDs, gpio, i2c and spi/mmc SD card devices.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_maix_bit.dts | 227 +++++++++++++++++++
 1 file changed, 227 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_bit.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_maix_bit.dts b/arch/riscv/boot/dts/canaan/k210_maix_bit.dts
new file mode 100644
index 000000000000..a5a40f9cf812
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_maix_bit.dts
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "SiPeed MAIX BiT";
+	compatible = "sipeed,maix-bitm", "sipeed,maix-bit",
+		     "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		green {
+			gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		red {
+			gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		blue {
+			gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		boot {
+			label = "BOOT";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	pinctrl-names = "default";
+	pinctrl-0 = <&jtag_pinctrl>;
+	status = "okay";
+
+	jtag_pinctrl: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	gpio_pinctrl: gpio-pinmux {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(9, K210_PCF_GPIO1)>,
+			 <K210_FPIOA(10, K210_PCF_GPIO2)>,
+			 <K210_FPIOA(11, K210_PCF_GPIO3)>,
+			 <K210_FPIOA(12, K210_PCF_GPIO4)>,
+			 <K210_FPIOA(13, K210_PCF_GPIO5)>,
+			 <K210_FPIOA(14, K210_PCF_GPIO6)>,
+			 <K210_FPIOA(15, K210_PCF_GPIO7)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(17, K210_PCF_GPIOHS1)>,
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>,
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>,
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>,
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>,
+			 <K210_FPIOA(33, K210_PCF_GPIOHS17)>,
+			 <K210_FPIOA(34, K210_PCF_GPIOHS18)>,
+			 <K210_FPIOA(35, K210_PCF_GPIOHS19)>;
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
+	};
+
+	i2c1_pinctrl: i2c1-pinmux {
+		pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>,
+			 <K210_FPIOA(31, K210_PCF_I2C1_SDA)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&gpio_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pinctrl>;
+	pinctrl-names = "default";
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "sitronix,st7789v";
+		reg = <0>;
+		reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		dc-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
+		spi-max-frequency = <15000000>;
+		spi-cs-high;
+		status = "disabled";
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
+
+&spi3 {
+	spi-flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		broken-flash-reset;
+	};
+};
-- 
2.28.0


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

* [PATCH v4 15/21] riscv: Add SiPeed MAIX BiT board device tree
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the SiPeed MAIX BiT and MAIX BiTm boards. This
device tree enables LEDs, gpio, i2c and spi/mmc SD card devices.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_maix_bit.dts | 227 +++++++++++++++++++
 1 file changed, 227 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_bit.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_maix_bit.dts b/arch/riscv/boot/dts/canaan/k210_maix_bit.dts
new file mode 100644
index 000000000000..a5a40f9cf812
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_maix_bit.dts
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "SiPeed MAIX BiT";
+	compatible = "sipeed,maix-bitm", "sipeed,maix-bit",
+		     "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		green {
+			gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		red {
+			gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		blue {
+			gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		boot {
+			label = "BOOT";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	pinctrl-names = "default";
+	pinctrl-0 = <&jtag_pinctrl>;
+	status = "okay";
+
+	jtag_pinctrl: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	gpio_pinctrl: gpio-pinmux {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(9, K210_PCF_GPIO1)>,
+			 <K210_FPIOA(10, K210_PCF_GPIO2)>,
+			 <K210_FPIOA(11, K210_PCF_GPIO3)>,
+			 <K210_FPIOA(12, K210_PCF_GPIO4)>,
+			 <K210_FPIOA(13, K210_PCF_GPIO5)>,
+			 <K210_FPIOA(14, K210_PCF_GPIO6)>,
+			 <K210_FPIOA(15, K210_PCF_GPIO7)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(17, K210_PCF_GPIOHS1)>,
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>,
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>,
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>,
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>,
+			 <K210_FPIOA(33, K210_PCF_GPIOHS17)>,
+			 <K210_FPIOA(34, K210_PCF_GPIOHS18)>,
+			 <K210_FPIOA(35, K210_PCF_GPIOHS19)>;
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
+	};
+
+	i2c1_pinctrl: i2c1-pinmux {
+		pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>,
+			 <K210_FPIOA(31, K210_PCF_I2C1_SDA)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&gpio_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pinctrl>;
+	pinctrl-names = "default";
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "sitronix,st7789v";
+		reg = <0>;
+		reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		dc-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
+		spi-max-frequency = <15000000>;
+		spi-cs-high;
+		status = "disabled";
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
+
+&spi3 {
+	spi-flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		broken-flash-reset;
+	};
+};
-- 
2.28.0


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

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

* [PATCH v4 16/21] riscv: Add SiPeed MAIX DOCK board device tree
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the SiPeed MAIX DOCK m1 and m1w boards. This
device tree enables LEDs, gpio, i2c and spi/mmc SD card devices.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_maix_dock.dts | 229 ++++++++++++++++++
 1 file changed, 229 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_dock.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_maix_dock.dts b/arch/riscv/boot/dts/canaan/k210_maix_dock.dts
new file mode 100644
index 000000000000..abeaa9bad761
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_maix_dock.dts
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "SiPeed MAIX Dock";
+	compatible = "sipeed,maix-dock-m1wm", "sipeed,maix-dock-m1",
+		     "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		/*
+		 * Note: the board specification document green on gpio #4,
+		 * red on gpio #5 and blue on gpio #6. However, the board
+		 * is actually wired differently as defined here.
+		 */
+		blue {
+			gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		green {
+			gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		red {
+			gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		boot {
+			label = "BOOT";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	pinctrl-0 = <&jtag_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	jtag_pinctrl: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	gpio_pinctrl: gpio-pinmux {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(11, K210_PCF_GPIO3)>,
+			 <K210_FPIOA(12, K210_PCF_GPIO4)>,
+			 <K210_FPIOA(13, K210_PCF_GPIO5)>,
+			 <K210_FPIOA(14, K210_PCF_GPIO6)>,
+			 <K210_FPIOA(15, K210_PCF_GPIO7)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(17, K210_PCF_GPIOHS1)>,
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>,
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>,
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>,
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>,
+			 <K210_FPIOA(33, K210_PCF_GPIOHS17)>,
+			 <K210_FPIOA(34, K210_PCF_GPIOHS18)>,
+			 <K210_FPIOA(35, K210_PCF_GPIOHS19)>;
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
+	};
+
+	i2c1_pinctrl: i2c1-pinmux {
+		pinmux = <K210_FPIOA(9, K210_PCF_I2C1_SCLK)>,
+			 <K210_FPIOA(10, K210_PCF_I2C1_SDA)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&gpio_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pinctrl>;
+	pinctrl-names = "default";
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "sitronix,st7789v";
+		reg = <0>;
+		reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		dc-gpios = <&gpio0 22 0>;
+		spi-max-frequency = <15000000>;
+		status = "disabled";
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
+
+&spi3 {
+	spi-flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		broken-flash-reset;
+	};
+};
-- 
2.28.0


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

* [PATCH v4 16/21] riscv: Add SiPeed MAIX DOCK board device tree
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the SiPeed MAIX DOCK m1 and m1w boards. This
device tree enables LEDs, gpio, i2c and spi/mmc SD card devices.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_maix_dock.dts | 229 ++++++++++++++++++
 1 file changed, 229 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_dock.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_maix_dock.dts b/arch/riscv/boot/dts/canaan/k210_maix_dock.dts
new file mode 100644
index 000000000000..abeaa9bad761
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_maix_dock.dts
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "SiPeed MAIX Dock";
+	compatible = "sipeed,maix-dock-m1wm", "sipeed,maix-dock-m1",
+		     "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		/*
+		 * Note: the board specification document green on gpio #4,
+		 * red on gpio #5 and blue on gpio #6. However, the board
+		 * is actually wired differently as defined here.
+		 */
+		blue {
+			gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		green {
+			gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		red {
+			gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		boot {
+			label = "BOOT";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	pinctrl-0 = <&jtag_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	jtag_pinctrl: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	gpio_pinctrl: gpio-pinmux {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(11, K210_PCF_GPIO3)>,
+			 <K210_FPIOA(12, K210_PCF_GPIO4)>,
+			 <K210_FPIOA(13, K210_PCF_GPIO5)>,
+			 <K210_FPIOA(14, K210_PCF_GPIO6)>,
+			 <K210_FPIOA(15, K210_PCF_GPIO7)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(17, K210_PCF_GPIOHS1)>,
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>,
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>,
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>,
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>,
+			 <K210_FPIOA(33, K210_PCF_GPIOHS17)>,
+			 <K210_FPIOA(34, K210_PCF_GPIOHS18)>,
+			 <K210_FPIOA(35, K210_PCF_GPIOHS19)>;
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
+	};
+
+	i2c1_pinctrl: i2c1-pinmux {
+		pinmux = <K210_FPIOA(9, K210_PCF_I2C1_SCLK)>,
+			 <K210_FPIOA(10, K210_PCF_I2C1_SDA)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&gpio_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pinctrl>;
+	pinctrl-names = "default";
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "sitronix,st7789v";
+		reg = <0>;
+		reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		dc-gpios = <&gpio0 22 0>;
+		spi-max-frequency = <15000000>;
+		status = "disabled";
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
+
+&spi3 {
+	spi-flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		broken-flash-reset;
+	};
+};
-- 
2.28.0


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

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

* [PATCH v4 17/21] riscv: Add SiPeed MAIX GO board device tree
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the SiPeed MAIX GO board. This device tree
enables buttons, LEDs, gpio, i2c and spi/mmc SD card devices.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_maix_go.dts | 237 ++++++++++++++++++++
 1 file changed, 237 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_go.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_maix_go.dts b/arch/riscv/boot/dts/canaan/k210_maix_go.dts
new file mode 100644
index 000000000000..c3294dfaa3c6
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_maix_go.dts
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "SiPeed MAIX GO";
+	compatible = "sipeed,maix-go", "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		green {
+			gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		red {
+			gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		blue {
+			gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		up {
+			label = "UP";
+			linux,code = <BTN_1>;
+			gpios = <&gpio1_0 7 GPIO_ACTIVE_LOW>;
+		};
+
+		press {
+			label = "PRESS";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+
+		down {
+			label = "DOWN";
+			linux,code = <BTN_2>;
+			gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	pinctrl-0 = <&jtag_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	jtag_pinctrl: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	gpio_pinctrl: gpio-pinmux {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(9, K210_PCF_GPIO1)>,
+			 <K210_FPIOA(10, K210_PCF_GPIO2)>,
+			 <K210_FPIOA(11, K210_PCF_GPIO3)>,
+			 <K210_FPIOA(12, K210_PCF_GPIO4)>,
+			 <K210_FPIOA(13, K210_PCF_GPIO5)>,
+			 <K210_FPIOA(14, K210_PCF_GPIO6)>,
+			 <K210_FPIOA(15, K210_PCF_GPIO7)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(17, K210_PCF_GPIOHS1)>,
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>,
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>,
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>,
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>,
+			 <K210_FPIOA(33, K210_PCF_GPIOHS17)>,
+			 <K210_FPIOA(34, K210_PCF_GPIOHS18)>,
+			 <K210_FPIOA(35, K210_PCF_GPIOHS19)>;
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
+	};
+
+	i2c1_pinctrl: i2c1-pinmux {
+		pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>,
+			 <K210_FPIOA(31, K210_PCF_I2C1_SDA)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&gpio_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pinctrl>;
+	pinctrl-names = "default";
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "sitronix,st7789v";
+		reg = <0>;
+		reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		dc-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
+		spi-max-frequency = <15000000>;
+		status = "disabled";
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
+
+&spi3 {
+	spi-flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		broken-flash-reset;
+	};
+};
-- 
2.28.0


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

* [PATCH v4 17/21] riscv: Add SiPeed MAIX GO board device tree
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the SiPeed MAIX GO board. This device tree
enables buttons, LEDs, gpio, i2c and spi/mmc SD card devices.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_maix_go.dts | 237 ++++++++++++++++++++
 1 file changed, 237 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maix_go.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_maix_go.dts b/arch/riscv/boot/dts/canaan/k210_maix_go.dts
new file mode 100644
index 000000000000..c3294dfaa3c6
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_maix_go.dts
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "SiPeed MAIX GO";
+	compatible = "sipeed,maix-go", "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		green {
+			gpios = <&gpio1_0 4 GPIO_ACTIVE_LOW>;
+		};
+
+		red {
+			gpios = <&gpio1_0 5 GPIO_ACTIVE_LOW>;
+		};
+
+		blue {
+			gpios = <&gpio1_0 6 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		up {
+			label = "UP";
+			linux,code = <BTN_1>;
+			gpios = <&gpio1_0 7 GPIO_ACTIVE_LOW>;
+		};
+
+		press {
+			label = "PRESS";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+
+		down {
+			label = "DOWN";
+			linux,code = <BTN_2>;
+			gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	pinctrl-0 = <&jtag_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	jtag_pinctrl: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	gpio_pinctrl: gpio-pinmux {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(9, K210_PCF_GPIO1)>,
+			 <K210_FPIOA(10, K210_PCF_GPIO2)>,
+			 <K210_FPIOA(11, K210_PCF_GPIO3)>,
+			 <K210_FPIOA(12, K210_PCF_GPIO4)>,
+			 <K210_FPIOA(13, K210_PCF_GPIO5)>,
+			 <K210_FPIOA(14, K210_PCF_GPIO6)>,
+			 <K210_FPIOA(15, K210_PCF_GPIO7)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(17, K210_PCF_GPIOHS1)>,
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>,
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>,
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>,
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>,
+			 <K210_FPIOA(33, K210_PCF_GPIOHS17)>,
+			 <K210_FPIOA(34, K210_PCF_GPIOHS18)>,
+			 <K210_FPIOA(35, K210_PCF_GPIOHS19)>;
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIOHS13)>; /* cs */
+	};
+
+	i2c1_pinctrl: i2c1-pinmux {
+		pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>,
+			 <K210_FPIOA(31, K210_PCF_I2C1_SDA)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&gpio_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pinctrl>;
+	pinctrl-names = "default";
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "sitronix,st7789v";
+		reg = <0>;
+		reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		dc-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
+		spi-max-frequency = <15000000>;
+		status = "disabled";
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
+
+&spi3 {
+	spi-flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		broken-flash-reset;
+	};
+};
-- 
2.28.0


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

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

* [PATCH v4 18/21] riscv: Add SiPeed MAIXDUINO board device tree
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the SiPeed MAIXDUINO board. This device tree
enables LEDs and spi/mmc SD card device. Additionally, gpios and i2c
are also enabled and mapped to the board header pins as indicated on
the board itself.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_maixduino.dts | 201 ++++++++++++++++++
 1 file changed, 201 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maixduino.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_maixduino.dts b/arch/riscv/boot/dts/canaan/k210_maixduino.dts
new file mode 100644
index 000000000000..681f12b46894
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_maixduino.dts
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "SiPeed MAIXDUINO";
+	compatible = "sipeed,maixduino", "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		boot {
+			label = "BOOT";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	status = "okay";
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>, /* Header "0" */
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>; /* Header "1" */
+	};
+
+	gpio_pinctrl: gpio-pinmux {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(9, K210_PCF_GPIO1)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,  /* BOOT */
+			 <K210_FPIOA(21, K210_PCF_GPIOHS2)>,  /* Header "2" */
+			 <K210_FPIOA(22, K210_PCF_GPIOHS3)>,  /* Header "3" */
+			 <K210_FPIOA(23, K210_PCF_GPIOHS4)>,  /* Header "4" */
+			 <K210_FPIOA(24, K210_PCF_GPIOHS5)>,  /* Header "5" */
+			 <K210_FPIOA(32, K210_PCF_GPIOHS6)>,  /* Header "6" */
+			 <K210_FPIOA(15, K210_PCF_GPIOHS7)>,  /* Header "7" */
+			 <K210_FPIOA(14, K210_PCF_GPIOHS8)>,  /* Header "8" */
+			 <K210_FPIOA(13, K210_PCF_GPIOHS9)>,  /* Header "9" */
+			 <K210_FPIOA(12, K210_PCF_GPIOHS10)>, /* Header "10" */
+			 <K210_FPIOA(11, K210_PCF_GPIOHS11)>, /* Header "11" */
+			 <K210_FPIOA(10, K210_PCF_GPIOHS12)>, /* Header "12" */
+			 <K210_FPIOA(3,  K210_PCF_GPIOHS13)>; /* Header "13" */
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIO2)>; /* cs */
+	};
+
+	i2c1_pinctrl: i2c1-pinmux {
+		pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>, /* Header "scl" */
+			 <K210_FPIOA(31, K210_PCF_I2C1_SDA)>;  /* Header "sda" */
+	};
+
+	i2s1_pinctrl: i2s1-pinmux {
+		pinmux = <K210_FPIOA(33, K210_PCF_I2S1_WS)>,
+			 <K210_FPIOA(34, K210_PCF_I2S1_IN_D0)>,
+			 <K210_FPIOA(35, K210_PCF_I2S1_SCLK)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&gpio_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pinctrl>;
+	pinctrl-names = "default";
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "sitronix,st7789v";
+		reg = <0>;
+		reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		dc-gpios = <&gpio0 22 0>;
+		spi-max-frequency = <15000000>;
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio1_0 2 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
+
+&spi3 {
+	spi-flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		broken-flash-reset;
+	};
+};
-- 
2.28.0


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

* [PATCH v4 18/21] riscv: Add SiPeed MAIXDUINO board device tree
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the SiPeed MAIXDUINO board. This device tree
enables LEDs and spi/mmc SD card device. Additionally, gpios and i2c
are also enabled and mapped to the board header pins as indicated on
the board itself.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_maixduino.dts | 201 ++++++++++++++++++
 1 file changed, 201 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_maixduino.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_maixduino.dts b/arch/riscv/boot/dts/canaan/k210_maixduino.dts
new file mode 100644
index 000000000000..681f12b46894
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_maixduino.dts
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "SiPeed MAIXDUINO";
+	compatible = "sipeed,maixduino", "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		boot {
+			label = "BOOT";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	status = "okay";
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>, /* Header "0" */
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>; /* Header "1" */
+	};
+
+	gpio_pinctrl: gpio-pinmux {
+		pinmux = <K210_FPIOA(8, K210_PCF_GPIO0)>,
+			 <K210_FPIOA(9, K210_PCF_GPIO1)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,  /* BOOT */
+			 <K210_FPIOA(21, K210_PCF_GPIOHS2)>,  /* Header "2" */
+			 <K210_FPIOA(22, K210_PCF_GPIOHS3)>,  /* Header "3" */
+			 <K210_FPIOA(23, K210_PCF_GPIOHS4)>,  /* Header "4" */
+			 <K210_FPIOA(24, K210_PCF_GPIOHS5)>,  /* Header "5" */
+			 <K210_FPIOA(32, K210_PCF_GPIOHS6)>,  /* Header "6" */
+			 <K210_FPIOA(15, K210_PCF_GPIOHS7)>,  /* Header "7" */
+			 <K210_FPIOA(14, K210_PCF_GPIOHS8)>,  /* Header "8" */
+			 <K210_FPIOA(13, K210_PCF_GPIOHS9)>,  /* Header "9" */
+			 <K210_FPIOA(12, K210_PCF_GPIOHS10)>, /* Header "10" */
+			 <K210_FPIOA(11, K210_PCF_GPIOHS11)>, /* Header "11" */
+			 <K210_FPIOA(10, K210_PCF_GPIOHS12)>, /* Header "12" */
+			 <K210_FPIOA(3,  K210_PCF_GPIOHS13)>; /* Header "13" */
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(18, K210_PCF_I2S0_SCLK)>,
+			 <K210_FPIOA(19, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(20, K210_PCF_I2S0_IN_D0)>;
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(26, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(27, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(28, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(29, K210_PCF_GPIO2)>; /* cs */
+	};
+
+	i2c1_pinctrl: i2c1-pinmux {
+		pinmux = <K210_FPIOA(30, K210_PCF_I2C1_SCLK)>, /* Header "scl" */
+			 <K210_FPIOA(31, K210_PCF_I2C1_SDA)>;  /* Header "sda" */
+	};
+
+	i2s1_pinctrl: i2s1-pinmux {
+		pinmux = <K210_FPIOA(33, K210_PCF_I2S1_WS)>,
+			 <K210_FPIOA(34, K210_PCF_I2S1_IN_D0)>,
+			 <K210_FPIOA(35, K210_PCF_I2S1_SCLK)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(36, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(37, K210_PCF_GPIOHS21)>,  /* rst */
+			 <K210_FPIOA(38, K210_PCF_GPIOHS22)>,  /* dc */
+			 <K210_FPIOA(39, K210_PCF_SPI0_SCLK)>; /* wr */
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(40, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(41, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(42, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(43, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(44, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(45, K210_PCF_DVP_HSYNC)>,
+			 <K210_FPIOA(46, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(47, K210_PCF_DVP_PCLK)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio1 {
+	pinctrl-0 = <&gpio_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&i2c1 {
+	pinctrl-0 = <&i2c1_pinctrl>;
+	pinctrl-names = "default";
+	clock-frequency = <400000>;
+	status = "okay";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "sitronix,st7789v";
+		reg = <0>;
+		reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
+		dc-gpios = <&gpio0 22 0>;
+		spi-max-frequency = <15000000>;
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio1_0 2 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
+
+&spi3 {
+	spi-flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		m25p,fast-read;
+		broken-flash-reset;
+	};
+};
-- 
2.28.0


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

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

* [PATCH v4 19/21] riscv: Add Kendryte KD233 board device tree
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the Canaan Kendryte KD233 development board.
This device tree enables LEDs, some gpios and spi/mmc SD card device.
The WS2812B RGB LED and the 10 position rotary dip switch present on
the board are left undefined.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_kd233.dts | 178 ++++++++++++++++++++++
 1 file changed, 178 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_kd233.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_kd233.dts b/arch/riscv/boot/dts/canaan/k210_kd233.dts
new file mode 100644
index 000000000000..44852a27df93
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_kd233.dts
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Kendryte KD233";
+	compatible = "canaan,kendryte-kd233",
+		     "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led0 {
+			gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
+		};
+
+		led1 {
+			gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		key0 {
+			label = "KEY0";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	pinctrl-0 = <&jtag_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	jtag_pinctrl: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(6, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(7, K210_PCF_SPI0_SCLK)>, /* wr */
+			 <K210_FPIOA(8, K210_PCF_GPIOHS21)>;  /* dc */
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(9, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(10, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(11, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(12, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(13, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(14, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(15, K210_PCF_DVP_PCLK)>,
+			 <K210_FPIOA(17, K210_PCF_DVP_HSYNC)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(20, K210_PCF_GPIOHS4)>, /* Rot. dip sw line 8 */
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>, /* Rot. dip sw line 4 */
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>, /* Rot. dip sw line 2 */
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>, /* Rot. dip sw line 1 */
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(26, K210_PCF_GPIOHS10)>;
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(29, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(30, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(31, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>; /* cs */
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(33, K210_PCF_I2S0_IN_D0)>,
+			 <K210_FPIOA(34, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(35, K210_PCF_I2S0_SCLK)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "ilitek,ili9341";
+		reg = <0>;
+		dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
+		spi-max-frequency = <15000000>;
+		status = "disabled";
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
-- 
2.28.0


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

* [PATCH v4 19/21] riscv: Add Kendryte KD233 board device tree
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Add a device tree for the Canaan Kendryte KD233 development board.
This device tree enables LEDs, some gpios and spi/mmc SD card device.
The WS2812B RGB LED and the 10 position rotary dip switch present on
the board are left undefined.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/boot/dts/canaan/k210_kd233.dts | 178 ++++++++++++++++++++++
 1 file changed, 178 insertions(+)
 create mode 100644 arch/riscv/boot/dts/canaan/k210_kd233.dts

diff --git a/arch/riscv/boot/dts/canaan/k210_kd233.dts b/arch/riscv/boot/dts/canaan/k210_kd233.dts
new file mode 100644
index 000000000000..44852a27df93
--- /dev/null
+++ b/arch/riscv/boot/dts/canaan/k210_kd233.dts
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+/dts-v1/;
+
+#include "k210.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Kendryte KD233";
+	compatible = "canaan,kendryte-kd233",
+		     "canaan,kendryte-k210";
+
+	chosen {
+		bootargs = "earlycon console=ttySIF0";
+		stdout-path = "serial0:115200n8";
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		led0 {
+			gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
+		};
+
+		led1 {
+			gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		key0 {
+			label = "KEY0";
+			linux,code = <BTN_0>;
+			gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
+		};
+	};
+
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,format = "i2s";
+		status = "disabled";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&mic>;
+		};
+	};
+
+	mic: mic {
+		#sound-dai-cells = <0>;
+		compatible = "memsensing,msm261s4030h0";
+		status = "disabled";
+	};
+};
+
+&fpioa {
+	pinctrl-0 = <&jtag_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	jtag_pinctrl: jtag-pinmux {
+		pinmux = <K210_FPIOA(0, K210_PCF_JTAG_TCLK)>,
+			 <K210_FPIOA(1, K210_PCF_JTAG_TDI)>,
+			 <K210_FPIOA(2, K210_PCF_JTAG_TMS)>,
+			 <K210_FPIOA(3, K210_PCF_JTAG_TDO)>;
+	};
+
+	uarths_pinctrl: uarths-pinmux {
+		pinmux = <K210_FPIOA(4, K210_PCF_UARTHS_RX)>,
+			 <K210_FPIOA(5, K210_PCF_UARTHS_TX)>;
+	};
+
+	spi0_pinctrl: spi0-pinmux {
+		pinmux = <K210_FPIOA(6, K210_PCF_GPIOHS20)>,  /* cs */
+			 <K210_FPIOA(7, K210_PCF_SPI0_SCLK)>, /* wr */
+			 <K210_FPIOA(8, K210_PCF_GPIOHS21)>;  /* dc */
+	};
+
+	dvp_pinctrl: dvp-pinmux {
+		pinmux = <K210_FPIOA(9, K210_PCF_SCCB_SCLK)>,
+			 <K210_FPIOA(10, K210_PCF_SCCB_SDA)>,
+			 <K210_FPIOA(11, K210_PCF_DVP_RST)>,
+			 <K210_FPIOA(12, K210_PCF_DVP_VSYNC)>,
+			 <K210_FPIOA(13, K210_PCF_DVP_PWDN)>,
+			 <K210_FPIOA(14, K210_PCF_DVP_XCLK)>,
+			 <K210_FPIOA(15, K210_PCF_DVP_PCLK)>,
+			 <K210_FPIOA(17, K210_PCF_DVP_HSYNC)>;
+	};
+
+	gpiohs_pinctrl: gpiohs-pinmux {
+		pinmux = <K210_FPIOA(16, K210_PCF_GPIOHS0)>,
+			 <K210_FPIOA(20, K210_PCF_GPIOHS4)>, /* Rot. dip sw line 8 */
+			 <K210_FPIOA(21, K210_PCF_GPIOHS5)>, /* Rot. dip sw line 4 */
+			 <K210_FPIOA(22, K210_PCF_GPIOHS6)>, /* Rot. dip sw line 2 */
+			 <K210_FPIOA(23, K210_PCF_GPIOHS7)>, /* Rot. dip sw line 1 */
+			 <K210_FPIOA(24, K210_PCF_GPIOHS8)>,
+			 <K210_FPIOA(25, K210_PCF_GPIOHS9)>,
+			 <K210_FPIOA(26, K210_PCF_GPIOHS10)>;
+	};
+
+	spi1_pinctrl: spi1-pinmux {
+		pinmux = <K210_FPIOA(29, K210_PCF_SPI1_SCLK)>,
+			 <K210_FPIOA(30, K210_PCF_SPI1_D0)>,
+			 <K210_FPIOA(31, K210_PCF_SPI1_D1)>,
+			 <K210_FPIOA(32, K210_PCF_GPIOHS16)>; /* cs */
+	};
+
+	i2s0_pinctrl: i2s0-pinmux {
+		pinmux = <K210_FPIOA(33, K210_PCF_I2S0_IN_D0)>,
+			 <K210_FPIOA(34, K210_PCF_I2S0_WS)>,
+			 <K210_FPIOA(35, K210_PCF_I2S0_SCLK)>;
+	};
+};
+
+&uarths0 {
+	pinctrl-0 = <&uarths_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gpio0 {
+	pinctrl-0 = <&gpiohs_pinctrl>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&i2s0 {
+	#sound-dai-cells = <1>;
+	pinctrl-0 = <&i2s0_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&dvp0 {
+	pinctrl-0 = <&dvp_pinctrl>;
+	pinctrl-names = "default";
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
+
+	panel@0 {
+		compatible = "ilitek,ili9341";
+		reg = <0>;
+		dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
+		spi-max-frequency = <15000000>;
+		status = "disabled";
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pinctrl>;
+	pinctrl-names = "default";
+	num-cs = <1>;
+	cs-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
+	status = "okay";
+
+	slot@0 {
+		compatible = "mmc-spi-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		spi-max-frequency = <25000000>;
+		broken-cd;
+	};
+};
-- 
2.28.0


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

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

* [PATCH v4 20/21] riscv: Update Canaan Kendryte K210 defconfig
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:24   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Update the Kendryte k210 nommu default configuration file
(nommu_k210_defconfig) to include device drivers for reset, reboot,
I2C, SPI, gpio and LEDs support. Virtual Terminal support is also
disabled as no terminal devices are supported and enabled. Disabling
CONFIG_VT (removing the no longer needed override for
CONFIG_VGA_CONSOLE) reduces the kernel image size by about 65 KB.

This default configuration remains suitable for a system using an
initramfs cpio file linked into the kernel image.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/configs/nommu_k210_defconfig | 37 +++++++++++++++++++++----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/arch/riscv/configs/nommu_k210_defconfig b/arch/riscv/configs/nommu_k210_defconfig
index 368a28cf1467..ca5628673a19 100644
--- a/arch/riscv/configs/nommu_k210_defconfig
+++ b/arch/riscv/configs/nommu_k210_defconfig
@@ -1,17 +1,19 @@
 # CONFIG_CPU_ISOLATION is not set
-CONFIG_LOG_BUF_SHIFT=15
+CONFIG_LOG_BUF_SHIFT=13
 CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_FORCE=y
+# CONFIG_RD_GZIP is not set
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
 # CONFIG_RD_XZ is not set
 # CONFIG_RD_LZO is not set
 # CONFIG_RD_LZ4 is not set
+# CONFIG_RD_ZSTD is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSFS_SYSCALL is not set
 # CONFIG_FHANDLE is not set
 # CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
 # CONFIG_TIMERFD is not set
@@ -25,15 +27,16 @@ CONFIG_EMBEDDED=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLOB=y
-# CONFIG_SLAB_MERGE_DEFAULT is not set
 # CONFIG_MMU is not set
 CONFIG_SOC_CANAAN=y
+CONFIG_SOC_CANAAN_K210_DTB_SOURCE="k210_generic"
 CONFIG_MAXPHYSMEM_2GB=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_CMDLINE="earlycon console=ttySIF0"
 CONFIG_CMDLINE_FORCE=y
-CONFIG_JUMP_LABEL=y
+# CONFIG_SECCOMP is not set
+# CONFIG_STACKPROTECTOR is not set
 # CONFIG_BLOCK is not set
 CONFIG_BINFMT_FLAT=y
 # CONFIG_COREDUMP is not set
@@ -41,23 +44,47 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_INPUT_LEDS is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_LDISC_AUTOLOAD is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_DEVMEM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+# CONFIG_SPI_MEM is not set
+CONFIG_SPI_DESIGNWARE=y
+CONFIG_SPI_DW_MMIO=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_GPIO_CDEV_V1 is not set
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_SIFIVE=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
 # CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_USER=y
 # CONFIG_VIRTIO_MENU is not set
+# CONFIG_VHOST_MENU is not set
+# CONFIG_FILE_LOCKING is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY_USER is not set
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_LSM="[]"
 CONFIG_PRINTK_TIME=y
+# CONFIG_SYMBOLIC_ERRNAME is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_MISC is not set
 CONFIG_PANIC_ON_OOPS=y
 # CONFIG_SCHED_DEBUG is not set
-- 
2.28.0


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

* [PATCH v4 20/21] riscv: Update Canaan Kendryte K210 defconfig
@ 2020-12-02  3:24   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:24 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

Update the Kendryte k210 nommu default configuration file
(nommu_k210_defconfig) to include device drivers for reset, reboot,
I2C, SPI, gpio and LEDs support. Virtual Terminal support is also
disabled as no terminal devices are supported and enabled. Disabling
CONFIG_VT (removing the no longer needed override for
CONFIG_VGA_CONSOLE) reduces the kernel image size by about 65 KB.

This default configuration remains suitable for a system using an
initramfs cpio file linked into the kernel image.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 arch/riscv/configs/nommu_k210_defconfig | 37 +++++++++++++++++++++----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/arch/riscv/configs/nommu_k210_defconfig b/arch/riscv/configs/nommu_k210_defconfig
index 368a28cf1467..ca5628673a19 100644
--- a/arch/riscv/configs/nommu_k210_defconfig
+++ b/arch/riscv/configs/nommu_k210_defconfig
@@ -1,17 +1,19 @@
 # CONFIG_CPU_ISOLATION is not set
-CONFIG_LOG_BUF_SHIFT=15
+CONFIG_LOG_BUF_SHIFT=13
 CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_FORCE=y
+# CONFIG_RD_GZIP is not set
 # CONFIG_RD_BZIP2 is not set
 # CONFIG_RD_LZMA is not set
 # CONFIG_RD_XZ is not set
 # CONFIG_RD_LZO is not set
 # CONFIG_RD_LZ4 is not set
+# CONFIG_RD_ZSTD is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 # CONFIG_SYSFS_SYSCALL is not set
 # CONFIG_FHANDLE is not set
 # CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
 # CONFIG_SIGNALFD is not set
 # CONFIG_TIMERFD is not set
@@ -25,15 +27,16 @@ CONFIG_EMBEDDED=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_COMPAT_BRK is not set
 CONFIG_SLOB=y
-# CONFIG_SLAB_MERGE_DEFAULT is not set
 # CONFIG_MMU is not set
 CONFIG_SOC_CANAAN=y
+CONFIG_SOC_CANAAN_K210_DTB_SOURCE="k210_generic"
 CONFIG_MAXPHYSMEM_2GB=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_CMDLINE="earlycon console=ttySIF0"
 CONFIG_CMDLINE_FORCE=y
-CONFIG_JUMP_LABEL=y
+# CONFIG_SECCOMP is not set
+# CONFIG_STACKPROTECTOR is not set
 # CONFIG_BLOCK is not set
 CONFIG_BINFMT_FLAT=y
 # CONFIG_COREDUMP is not set
@@ -41,23 +44,47 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_INPUT_LEDS is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_LDISC_AUTOLOAD is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_DEVMEM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+# CONFIG_SPI_MEM is not set
+CONFIG_SPI_DESIGNWARE=y
+CONFIG_SPI_DW_MMIO=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_GPIO_CDEV_V1 is not set
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_SIFIVE=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
 # CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_USER=y
 # CONFIG_VIRTIO_MENU is not set
+# CONFIG_VHOST_MENU is not set
+# CONFIG_FILE_LOCKING is not set
 # CONFIG_DNOTIFY is not set
 # CONFIG_INOTIFY_USER is not set
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_LSM="[]"
 CONFIG_PRINTK_TIME=y
+# CONFIG_SYMBOLIC_ERRNAME is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_MISC is not set
 CONFIG_PANIC_ON_OOPS=y
 # CONFIG_SCHED_DEBUG is not set
-- 
2.28.0


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

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

* [PATCH v4 21/21] riscv: Add Canaan Kendryte K210 SD card defconfig
  2020-12-02  3:24 ` Damien Le Moal
@ 2020-12-02  3:25   ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:25 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

The nommu_k210_defconfig default configuration allows booting a Canaan
Kendryte K210 SoC based boards using an embedded intramfs cpio file.
Modifying this configuration to enable support for the board SD card is
not trivial for all users. To help beginners getting started with these
boards, add the nommu_k210_sdcard_defconfig default configuration file
to set all configuration options necessary to use the board mmc-spi sd
card for the root file system.

This new configuration adds support for the block layer, the mmc-spi
driver and modifies the boot options to specify the rootfs device as
mmcblk0p1 (first partition of the sd card block device). The ext2 file
system is selected by default to encourage its use as that results in
only about 4KB added to the kernel image size. As ext2 does not have
journaling, the boot options specify a read-only mount of the file
system. Similarly to the smaller nommu_k210_defconfig, this new default
configuration disables virtual terminal support to reduce the kernel
image size.

The default device tree selected is unchanged, specifying the simple
"k210_generic" device tree file. The user must change this setting to
specify the device tree suitable for the board being used
(k210_maix_bit, k210_maix_dock, k210_maix_go, k210_maixduino or
k210_kd233).

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../riscv/configs/nommu_k210_sdcard_defconfig | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)
 create mode 100644 arch/riscv/configs/nommu_k210_sdcard_defconfig

diff --git a/arch/riscv/configs/nommu_k210_sdcard_defconfig b/arch/riscv/configs/nommu_k210_sdcard_defconfig
new file mode 100644
index 000000000000..999905ee9d53
--- /dev/null
+++ b/arch/riscv/configs/nommu_k210_sdcard_defconfig
@@ -0,0 +1,93 @@
+# CONFIG_CPU_ISOLATION is not set
+CONFIG_LOG_BUF_SHIFT=13
+CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_IO_URING is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+# CONFIG_MEMBARRIER is not set
+# CONFIG_KALLSYMS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+# CONFIG_MMU is not set
+CONFIG_SOC_CANAAN=y
+CONFIG_SOC_CANAAN_K210_DTB_SOURCE="k210_generic"
+CONFIG_MAXPHYSMEM_2GB=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_CMDLINE="earlycon console=ttySIF0 rootdelay=2 root=/dev/mmcblk0p1 ro"
+CONFIG_CMDLINE_FORCE=y
+# CONFIG_SECCOMP is not set
+# CONFIG_STACKPROTECTOR is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_MQ_IOSCHED_DEADLINE is not set
+# CONFIG_MQ_IOSCHED_KYBER is not set
+CONFIG_BINFMT_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_INPUT_LEDS is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_LDISC_AUTOLOAD is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_DEVMEM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+# CONFIG_SPI_MEM is not set
+CONFIG_SPI_DESIGNWARE=y
+CONFIG_SPI_DW_MMIO=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_GPIO_CDEV_V1 is not set
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_SIFIVE=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+# CONFIG_HWMON is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
+CONFIG_MMC_SPI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_USER=y
+# CONFIG_VIRTIO_MENU is not set
+# CONFIG_VHOST_MENU is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_LSM="[]"
+CONFIG_PRINTK_TIME=y
+# CONFIG_SYMBOLIC_ERRNAME is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MISC is not set
+CONFIG_PANIC_ON_OOPS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_FTRACE is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
-- 
2.28.0


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

* [PATCH v4 21/21] riscv: Add Canaan Kendryte K210 SD card defconfig
@ 2020-12-02  3:25   ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-02  3:25 UTC (permalink / raw)
  To: Palmer Dabbelt, linux-riscv, Rob Herring, devicetree,
	Stephen Boyd, linux-clk, Linus Walleij, linux-gpio,
	Philipp Zabel
  Cc: Sean Anderson

The nommu_k210_defconfig default configuration allows booting a Canaan
Kendryte K210 SoC based boards using an embedded intramfs cpio file.
Modifying this configuration to enable support for the board SD card is
not trivial for all users. To help beginners getting started with these
boards, add the nommu_k210_sdcard_defconfig default configuration file
to set all configuration options necessary to use the board mmc-spi sd
card for the root file system.

This new configuration adds support for the block layer, the mmc-spi
driver and modifies the boot options to specify the rootfs device as
mmcblk0p1 (first partition of the sd card block device). The ext2 file
system is selected by default to encourage its use as that results in
only about 4KB added to the kernel image size. As ext2 does not have
journaling, the boot options specify a read-only mount of the file
system. Similarly to the smaller nommu_k210_defconfig, this new default
configuration disables virtual terminal support to reduce the kernel
image size.

The default device tree selected is unchanged, specifying the simple
"k210_generic" device tree file. The user must change this setting to
specify the device tree suitable for the board being used
(k210_maix_bit, k210_maix_dock, k210_maix_go, k210_maixduino or
k210_kd233).

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 .../riscv/configs/nommu_k210_sdcard_defconfig | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)
 create mode 100644 arch/riscv/configs/nommu_k210_sdcard_defconfig

diff --git a/arch/riscv/configs/nommu_k210_sdcard_defconfig b/arch/riscv/configs/nommu_k210_sdcard_defconfig
new file mode 100644
index 000000000000..999905ee9d53
--- /dev/null
+++ b/arch/riscv/configs/nommu_k210_sdcard_defconfig
@@ -0,0 +1,93 @@
+# CONFIG_CPU_ISOLATION is not set
+CONFIG_LOG_BUF_SHIFT=13
+CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SYSFS_SYSCALL is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+# CONFIG_IO_URING is not set
+# CONFIG_ADVISE_SYSCALLS is not set
+# CONFIG_MEMBARRIER is not set
+# CONFIG_KALLSYMS is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLOB=y
+# CONFIG_MMU is not set
+CONFIG_SOC_CANAAN=y
+CONFIG_SOC_CANAAN_K210_DTB_SOURCE="k210_generic"
+CONFIG_MAXPHYSMEM_2GB=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_CMDLINE="earlycon console=ttySIF0 rootdelay=2 root=/dev/mmcblk0p1 ro"
+CONFIG_CMDLINE_FORCE=y
+# CONFIG_SECCOMP is not set
+# CONFIG_STACKPROTECTOR is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_MQ_IOSCHED_DEADLINE is not set
+# CONFIG_MQ_IOSCHED_KYBER is not set
+CONFIG_BINFMT_FLAT=y
+# CONFIG_COREDUMP is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_BLK_DEV is not set
+# CONFIG_INPUT_LEDS is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_LDISC_AUTOLOAD is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_DEVMEM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+# CONFIG_SPI_MEM is not set
+CONFIG_SPI_DESIGNWARE=y
+CONFIG_SPI_DW_MMIO=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_GPIO_CDEV_V1 is not set
+CONFIG_GPIO_DWAPB=y
+CONFIG_GPIO_SIFIVE=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_SYSCON=y
+# CONFIG_HWMON is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
+CONFIG_MMC_SPI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_USER=y
+# CONFIG_VIRTIO_MENU is not set
+# CONFIG_VHOST_MENU is not set
+CONFIG_EXT2_FS=y
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_LSM="[]"
+CONFIG_PRINTK_TIME=y
+# CONFIG_SYMBOLIC_ERRNAME is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MISC is not set
+CONFIG_PANIC_ON_OOPS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_FTRACE is not set
+# CONFIG_RUNTIME_TESTING_MENU is not set
-- 
2.28.0


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

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

* Re: [PATCH v4 13/21] riscv: Add Canaan Kendryte K210 reset controller
  2020-12-02  3:24   ` Damien Le Moal
@ 2020-12-04 10:49     ` Philipp Zabel
  -1 siblings, 0 replies; 78+ messages in thread
From: Philipp Zabel @ 2020-12-04 10:49 UTC (permalink / raw)
  To: Damien Le Moal, Palmer Dabbelt, linux-riscv, Rob Herring,
	devicetree, Stephen Boyd, linux-clk, Linus Walleij, linux-gpio
  Cc: Sean Anderson

Hi Damien,

On Wed, 2020-12-02 at 12:24 +0900, Damien Le Moal wrote:
> Add a reset controller driver for the Canaan Kendryte K210 SoC. This
> driver relies on its syscon compatible parent node (sysctl) for its
> register mapping. Automatically select this driver for compilation
> when the SOC_CANAAN option is selected.
> 
> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
> SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
> driver.
> 
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
> ---
>  MAINTAINERS                |   8 +++
>  arch/riscv/Kconfig.socs    |   3 +
>  drivers/reset/Kconfig      |   9 +++
>  drivers/reset/Makefile     |   1 +
>  drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 162 insertions(+)
>  create mode 100644 drivers/reset/reset-k210.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a059ab02fa8a..c2b3d6e48cd5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3837,6 +3837,14 @@ L:	linux-gpio@vger.kernel.org (pinctrl driver)
>  F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
>  F:	drivers/pinctrl/pinctrl-k210.c
>  
> +CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
> +M:	Damien Le Moal <damien.lemoal@wdc.com>
> +L:	linux-kernel@vger.kernel.org
> +L:	linux-riscv@lists.infradead.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
> +F:	drivers/reset/reset-k210.c
> +
>  CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
>  M:	Damien Le Moal <damien.lemoal@wdc.com>
>  L:	linux-riscv@lists.infradead.org
> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> index 68bdd664b5c2..b3cd253ec2c2 100644
> --- a/arch/riscv/Kconfig.socs
> +++ b/arch/riscv/Kconfig.socs
> @@ -33,6 +33,9 @@ config SOC_CANAAN
>  	select CLK_K210
>  	select PINCTRL
>  	select PINCTRL_K210
> +	select ARCH_HAS_RESET_CONTROLLER
> +	select RESET_CONTROLLER
> +	select RESET_K210
>  	help
>  	  This enables support for Canaan Kendryte K210 SoC platform hardware.
>  
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 07d162b179fc..529d206cfdfd 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -245,6 +245,15 @@ config RESET_ZYNQ
>  	help
>  	  This enables the reset controller driver for Xilinx Zynq SoCs.
>  
> +config RESET_K210
> +	bool "Reset controller driver for Canaan Kendryte K210 SoC"
> +	depends on RISCV && SOC_CANAAN
> +	depends on OF && MFD_SYSCON
> +	help
> +	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
> +	  Say Y if you want to control reset signals provided by this
> +	  controller.
> +
>  source "drivers/reset/sti/Kconfig"
>  source "drivers/reset/hisilicon/Kconfig"
>  source "drivers/reset/tegra/Kconfig"
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 16947610cc3b..1730a31e6871 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -33,4 +33,5 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
>  obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
>  obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
>  obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
> +obj-$(CONFIG_RESET_K210) += reset-k210.o
>  
> diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
> new file mode 100644
> index 000000000000..2cf9a63c763d
> --- /dev/null
> +++ b/drivers/reset/reset-k210.c
> @@ -0,0 +1,141 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2020 Western Digital Corporation or its affiliates.
> + */
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/delay.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
> +#include <soc/canaan/k210-sysctl.h>
> +
> +#include <dt-bindings/reset/k210-rst.h>
> +
> +#define K210_RST_MASK	0x27FFFFFF
> +
> +struct k210_rst {
> +	struct regmap *map;
> +	struct reset_controller_dev rcdev;
> +};
> +
> +static inline struct k210_rst *
> +to_k210_rst(struct reset_controller_dev *rcdev)
> +{
> +	return container_of(rcdev, struct k210_rst, rcdev);
> +}
> +
> +static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
> +				  unsigned long id)
> +{
> +	struct k210_rst *ksr = to_k210_rst(rcdev);
> +	u32 bit = BIT(id);
> +
> +	if (!(bit & K210_RST_MASK))
> +		return -EINVAL;

Instead of checking this mask in the k210_rst_assert/deassert/status()
functions, you could implement a custom .of_xlate callback and disallow
requesting invalid resets in the first place.

regards
Philipp

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

* Re: [PATCH v4 13/21] riscv: Add Canaan Kendryte K210 reset controller
@ 2020-12-04 10:49     ` Philipp Zabel
  0 siblings, 0 replies; 78+ messages in thread
From: Philipp Zabel @ 2020-12-04 10:49 UTC (permalink / raw)
  To: Damien Le Moal, Palmer Dabbelt, linux-riscv, Rob Herring,
	devicetree, Stephen Boyd, linux-clk, Linus Walleij, linux-gpio
  Cc: Sean Anderson

Hi Damien,

On Wed, 2020-12-02 at 12:24 +0900, Damien Le Moal wrote:
> Add a reset controller driver for the Canaan Kendryte K210 SoC. This
> driver relies on its syscon compatible parent node (sysctl) for its
> register mapping. Automatically select this driver for compilation
> when the SOC_CANAAN option is selected.
> 
> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
> SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
> driver.
> 
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
> ---
>  MAINTAINERS                |   8 +++
>  arch/riscv/Kconfig.socs    |   3 +
>  drivers/reset/Kconfig      |   9 +++
>  drivers/reset/Makefile     |   1 +
>  drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 162 insertions(+)
>  create mode 100644 drivers/reset/reset-k210.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a059ab02fa8a..c2b3d6e48cd5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3837,6 +3837,14 @@ L:	linux-gpio@vger.kernel.org (pinctrl driver)
>  F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
>  F:	drivers/pinctrl/pinctrl-k210.c
>  
> +CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
> +M:	Damien Le Moal <damien.lemoal@wdc.com>
> +L:	linux-kernel@vger.kernel.org
> +L:	linux-riscv@lists.infradead.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
> +F:	drivers/reset/reset-k210.c
> +
>  CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
>  M:	Damien Le Moal <damien.lemoal@wdc.com>
>  L:	linux-riscv@lists.infradead.org
> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> index 68bdd664b5c2..b3cd253ec2c2 100644
> --- a/arch/riscv/Kconfig.socs
> +++ b/arch/riscv/Kconfig.socs
> @@ -33,6 +33,9 @@ config SOC_CANAAN
>  	select CLK_K210
>  	select PINCTRL
>  	select PINCTRL_K210
> +	select ARCH_HAS_RESET_CONTROLLER
> +	select RESET_CONTROLLER
> +	select RESET_K210
>  	help
>  	  This enables support for Canaan Kendryte K210 SoC platform hardware.
>  
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 07d162b179fc..529d206cfdfd 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -245,6 +245,15 @@ config RESET_ZYNQ
>  	help
>  	  This enables the reset controller driver for Xilinx Zynq SoCs.
>  
> +config RESET_K210
> +	bool "Reset controller driver for Canaan Kendryte K210 SoC"
> +	depends on RISCV && SOC_CANAAN
> +	depends on OF && MFD_SYSCON
> +	help
> +	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
> +	  Say Y if you want to control reset signals provided by this
> +	  controller.
> +
>  source "drivers/reset/sti/Kconfig"
>  source "drivers/reset/hisilicon/Kconfig"
>  source "drivers/reset/tegra/Kconfig"
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 16947610cc3b..1730a31e6871 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -33,4 +33,5 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
>  obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
>  obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
>  obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
> +obj-$(CONFIG_RESET_K210) += reset-k210.o
>  
> diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
> new file mode 100644
> index 000000000000..2cf9a63c763d
> --- /dev/null
> +++ b/drivers/reset/reset-k210.c
> @@ -0,0 +1,141 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2020 Western Digital Corporation or its affiliates.
> + */
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +#include <linux/delay.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
> +#include <soc/canaan/k210-sysctl.h>
> +
> +#include <dt-bindings/reset/k210-rst.h>
> +
> +#define K210_RST_MASK	0x27FFFFFF
> +
> +struct k210_rst {
> +	struct regmap *map;
> +	struct reset_controller_dev rcdev;
> +};
> +
> +static inline struct k210_rst *
> +to_k210_rst(struct reset_controller_dev *rcdev)
> +{
> +	return container_of(rcdev, struct k210_rst, rcdev);
> +}
> +
> +static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
> +				  unsigned long id)
> +{
> +	struct k210_rst *ksr = to_k210_rst(rcdev);
> +	u32 bit = BIT(id);
> +
> +	if (!(bit & K210_RST_MASK))
> +		return -EINVAL;

Instead of checking this mask in the k210_rst_assert/deassert/status()
functions, you could implement a custom .of_xlate callback and disallow
requesting invalid resets in the first place.

regards
Philipp

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

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

* Re: [PATCH v4 13/21] riscv: Add Canaan Kendryte K210 reset controller
  2020-12-04 10:49     ` Philipp Zabel
@ 2020-12-04 11:16       ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-04 11:16 UTC (permalink / raw)
  To: Philipp Zabel, Palmer Dabbelt, linux-riscv, Rob Herring,
	devicetree, Stephen Boyd, linux-clk, Linus Walleij, linux-gpio
  Cc: Sean Anderson

On 2020/12/04 19:49, Philipp Zabel wrote:
> Hi Damien,
> 
> On Wed, 2020-12-02 at 12:24 +0900, Damien Le Moal wrote:
>> Add a reset controller driver for the Canaan Kendryte K210 SoC. This
>> driver relies on its syscon compatible parent node (sysctl) for its
>> register mapping. Automatically select this driver for compilation
>> when the SOC_CANAAN option is selected.
>>
>> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
>> SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
>> driver.
>>
>> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
>> ---
>>  MAINTAINERS                |   8 +++
>>  arch/riscv/Kconfig.socs    |   3 +
>>  drivers/reset/Kconfig      |   9 +++
>>  drivers/reset/Makefile     |   1 +
>>  drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
>>  5 files changed, 162 insertions(+)
>>  create mode 100644 drivers/reset/reset-k210.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index a059ab02fa8a..c2b3d6e48cd5 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -3837,6 +3837,14 @@ L:	linux-gpio@vger.kernel.org (pinctrl driver)
>>  F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
>>  F:	drivers/pinctrl/pinctrl-k210.c
>>  
>> +CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
>> +M:	Damien Le Moal <damien.lemoal@wdc.com>
>> +L:	linux-kernel@vger.kernel.org
>> +L:	linux-riscv@lists.infradead.org
>> +S:	Maintained
>> +F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
>> +F:	drivers/reset/reset-k210.c
>> +
>>  CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
>>  M:	Damien Le Moal <damien.lemoal@wdc.com>
>>  L:	linux-riscv@lists.infradead.org
>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
>> index 68bdd664b5c2..b3cd253ec2c2 100644
>> --- a/arch/riscv/Kconfig.socs
>> +++ b/arch/riscv/Kconfig.socs
>> @@ -33,6 +33,9 @@ config SOC_CANAAN
>>  	select CLK_K210
>>  	select PINCTRL
>>  	select PINCTRL_K210
>> +	select ARCH_HAS_RESET_CONTROLLER
>> +	select RESET_CONTROLLER
>> +	select RESET_K210
>>  	help
>>  	  This enables support for Canaan Kendryte K210 SoC platform hardware.
>>  
>> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
>> index 07d162b179fc..529d206cfdfd 100644
>> --- a/drivers/reset/Kconfig
>> +++ b/drivers/reset/Kconfig
>> @@ -245,6 +245,15 @@ config RESET_ZYNQ
>>  	help
>>  	  This enables the reset controller driver for Xilinx Zynq SoCs.
>>  
>> +config RESET_K210
>> +	bool "Reset controller driver for Canaan Kendryte K210 SoC"
>> +	depends on RISCV && SOC_CANAAN
>> +	depends on OF && MFD_SYSCON
>> +	help
>> +	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
>> +	  Say Y if you want to control reset signals provided by this
>> +	  controller.
>> +
>>  source "drivers/reset/sti/Kconfig"
>>  source "drivers/reset/hisilicon/Kconfig"
>>  source "drivers/reset/tegra/Kconfig"
>> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
>> index 16947610cc3b..1730a31e6871 100644
>> --- a/drivers/reset/Makefile
>> +++ b/drivers/reset/Makefile
>> @@ -33,4 +33,5 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
>>  obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
>>  obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
>>  obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
>> +obj-$(CONFIG_RESET_K210) += reset-k210.o
>>  
>> diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
>> new file mode 100644
>> index 000000000000..2cf9a63c763d
>> --- /dev/null
>> +++ b/drivers/reset/reset-k210.c
>> @@ -0,0 +1,141 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (c) 2020 Western Digital Corporation or its affiliates.
>> + */
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset-controller.h>
>> +#include <linux/delay.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/regmap.h>
>> +#include <soc/canaan/k210-sysctl.h>
>> +
>> +#include <dt-bindings/reset/k210-rst.h>
>> +
>> +#define K210_RST_MASK	0x27FFFFFF
>> +
>> +struct k210_rst {
>> +	struct regmap *map;
>> +	struct reset_controller_dev rcdev;
>> +};
>> +
>> +static inline struct k210_rst *
>> +to_k210_rst(struct reset_controller_dev *rcdev)
>> +{
>> +	return container_of(rcdev, struct k210_rst, rcdev);
>> +}
>> +
>> +static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
>> +				  unsigned long id)
>> +{
>> +	struct k210_rst *ksr = to_k210_rst(rcdev);
>> +	u32 bit = BIT(id);
>> +
>> +	if (!(bit & K210_RST_MASK))
>> +		return -EINVAL;
> 
> Instead of checking this mask in the k210_rst_assert/deassert/status()
> functions, you could implement a custom .of_xlate callback and disallow
> requesting invalid resets in the first place.

OK. I did not know about this. Will look into it and send a v5.

Thanks !

> 
> regards
> Philipp
> 


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH v4 13/21] riscv: Add Canaan Kendryte K210 reset controller
@ 2020-12-04 11:16       ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-04 11:16 UTC (permalink / raw)
  To: Philipp Zabel, Palmer Dabbelt, linux-riscv, Rob Herring,
	devicetree, Stephen Boyd, linux-clk, Linus Walleij, linux-gpio
  Cc: Sean Anderson

On 2020/12/04 19:49, Philipp Zabel wrote:
> Hi Damien,
> 
> On Wed, 2020-12-02 at 12:24 +0900, Damien Le Moal wrote:
>> Add a reset controller driver for the Canaan Kendryte K210 SoC. This
>> driver relies on its syscon compatible parent node (sysctl) for its
>> register mapping. Automatically select this driver for compilation
>> when the SOC_CANAAN option is selected.
>>
>> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210
>> SOC RESET CONTROLLER DRIVER" with myself listed as maintainer for this
>> driver.
>>
>> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
>> ---
>>  MAINTAINERS                |   8 +++
>>  arch/riscv/Kconfig.socs    |   3 +
>>  drivers/reset/Kconfig      |   9 +++
>>  drivers/reset/Makefile     |   1 +
>>  drivers/reset/reset-k210.c | 141 +++++++++++++++++++++++++++++++++++++
>>  5 files changed, 162 insertions(+)
>>  create mode 100644 drivers/reset/reset-k210.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index a059ab02fa8a..c2b3d6e48cd5 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -3837,6 +3837,14 @@ L:	linux-gpio@vger.kernel.org (pinctrl driver)
>>  F:	Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
>>  F:	drivers/pinctrl/pinctrl-k210.c
>>  
>> +CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER
>> +M:	Damien Le Moal <damien.lemoal@wdc.com>
>> +L:	linux-kernel@vger.kernel.org
>> +L:	linux-riscv@lists.infradead.org
>> +S:	Maintained
>> +F:	Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
>> +F:	drivers/reset/reset-k210.c
>> +
>>  CANAAN/KENDRYTE K210 SOC SYSTEM CONTROLLER DRIVER
>>  M:	Damien Le Moal <damien.lemoal@wdc.com>
>>  L:	linux-riscv@lists.infradead.org
>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
>> index 68bdd664b5c2..b3cd253ec2c2 100644
>> --- a/arch/riscv/Kconfig.socs
>> +++ b/arch/riscv/Kconfig.socs
>> @@ -33,6 +33,9 @@ config SOC_CANAAN
>>  	select CLK_K210
>>  	select PINCTRL
>>  	select PINCTRL_K210
>> +	select ARCH_HAS_RESET_CONTROLLER
>> +	select RESET_CONTROLLER
>> +	select RESET_K210
>>  	help
>>  	  This enables support for Canaan Kendryte K210 SoC platform hardware.
>>  
>> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
>> index 07d162b179fc..529d206cfdfd 100644
>> --- a/drivers/reset/Kconfig
>> +++ b/drivers/reset/Kconfig
>> @@ -245,6 +245,15 @@ config RESET_ZYNQ
>>  	help
>>  	  This enables the reset controller driver for Xilinx Zynq SoCs.
>>  
>> +config RESET_K210
>> +	bool "Reset controller driver for Canaan Kendryte K210 SoC"
>> +	depends on RISCV && SOC_CANAAN
>> +	depends on OF && MFD_SYSCON
>> +	help
>> +	  Support for the Canaan Kendryte K210 RISC-V SoC reset controller.
>> +	  Say Y if you want to control reset signals provided by this
>> +	  controller.
>> +
>>  source "drivers/reset/sti/Kconfig"
>>  source "drivers/reset/hisilicon/Kconfig"
>>  source "drivers/reset/tegra/Kconfig"
>> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
>> index 16947610cc3b..1730a31e6871 100644
>> --- a/drivers/reset/Makefile
>> +++ b/drivers/reset/Makefile
>> @@ -33,4 +33,5 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
>>  obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
>>  obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
>>  obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
>> +obj-$(CONFIG_RESET_K210) += reset-k210.o
>>  
>> diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c
>> new file mode 100644
>> index 000000000000..2cf9a63c763d
>> --- /dev/null
>> +++ b/drivers/reset/reset-k210.c
>> @@ -0,0 +1,141 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (c) 2020 Western Digital Corporation or its affiliates.
>> + */
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset-controller.h>
>> +#include <linux/delay.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/regmap.h>
>> +#include <soc/canaan/k210-sysctl.h>
>> +
>> +#include <dt-bindings/reset/k210-rst.h>
>> +
>> +#define K210_RST_MASK	0x27FFFFFF
>> +
>> +struct k210_rst {
>> +	struct regmap *map;
>> +	struct reset_controller_dev rcdev;
>> +};
>> +
>> +static inline struct k210_rst *
>> +to_k210_rst(struct reset_controller_dev *rcdev)
>> +{
>> +	return container_of(rcdev, struct k210_rst, rcdev);
>> +}
>> +
>> +static inline int k210_rst_assert(struct reset_controller_dev *rcdev,
>> +				  unsigned long id)
>> +{
>> +	struct k210_rst *ksr = to_k210_rst(rcdev);
>> +	u32 bit = BIT(id);
>> +
>> +	if (!(bit & K210_RST_MASK))
>> +		return -EINVAL;
> 
> Instead of checking this mask in the k210_rst_assert/deassert/status()
> functions, you could implement a custom .of_xlate callback and disallow
> requesting invalid resets in the first place.

OK. I did not know about this. Will look into it and send a v5.

Thanks !

> 
> regards
> Philipp
> 


-- 
Damien Le Moal
Western Digital Research

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

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

* Re: [PATCH v4 04/21] riscv: Fix builtin DTB handling
  2020-12-02  3:24   ` Damien Le Moal
@ 2020-12-04 15:11     ` Geert Uytterhoeven
  -1 siblings, 0 replies; 78+ messages in thread
From: Geert Uytterhoeven @ 2020-12-04 15:11 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: Palmer Dabbelt, linux-riscv, Rob Herring,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Stephen Boyd, linux-clk, Linus Walleij, open list:GPIO SUBSYSTEM,
	Philipp Zabel, Sean Anderson

Hi Damien,

On Wed, Dec 2, 2020 at 4:26 AM Damien Le Moal <damien.lemoal@wdc.com> wrote:
> All SiPeed K210 MAIX boards have the exact same vendor, arch and
> implementation IDs, preventing differentiation to select the correct
> device tree to use through the SOC_BUILTIN_DTB_DECLARE() macro. This
> result in this macro to be useless and mandates changing the code of
> the sysctl driver to change the builtin device tree suitable for the
> target board.
>
> Fix this problem by removing the SOC_BUILTIN_DTB_DECLARE() macro since
> it is used only for the K210 support. The code searching the builtin
> DTBs using the vendor, arch an implementation IDs is also removed.
> Support for builtin DTB falls back to the simpler and more traditional
> handling of builtin DTB using the CONFIG_BUILTIN_DTB option, similarly
> to other architectures.
>
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>

> --- a/arch/riscv/boot/dts/kendryte/Makefile
> +++ b/arch/riscv/boot/dts/kendryte/Makefile
> @@ -1,4 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0
> -dtb-$(CONFIG_SOC_KENDRYTE_K210_DTB) += k210.dtb
> -
> +ifneq ($(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE),"")
> +dtb-y += $(strip $(shell echo $(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE))).dtb
>  obj-$(CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
> +endif

This break compiling a kernel for non-K210 systems (e.g. defconfig),
as reported before in
https://lore.kernel.org/linux-clk/202011151230.QP1ISPQo-lkp@intel.com/

I think this can be fixed using:

--- a/arch/riscv/boot/dts/Makefile
+++ b/arch/riscv/boot/dts/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 subdir-y += sifive
-subdir-y += canaan
+subdir-$(CONFIG_SOC_CANAAN) += canaan

 obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))

(yes, I've already renamed kendryte to canaan ;-)

Gr{oetje,eeting}s,

                        Geert

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

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

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

* Re: [PATCH v4 04/21] riscv: Fix builtin DTB handling
@ 2020-12-04 15:11     ` Geert Uytterhoeven
  0 siblings, 0 replies; 78+ messages in thread
From: Geert Uytterhoeven @ 2020-12-04 15:11 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Stephen Boyd, Linus Walleij, Sean Anderson,
	open list:GPIO SUBSYSTEM, Rob Herring, Palmer Dabbelt,
	Philipp Zabel, linux-riscv, linux-clk

Hi Damien,

On Wed, Dec 2, 2020 at 4:26 AM Damien Le Moal <damien.lemoal@wdc.com> wrote:
> All SiPeed K210 MAIX boards have the exact same vendor, arch and
> implementation IDs, preventing differentiation to select the correct
> device tree to use through the SOC_BUILTIN_DTB_DECLARE() macro. This
> result in this macro to be useless and mandates changing the code of
> the sysctl driver to change the builtin device tree suitable for the
> target board.
>
> Fix this problem by removing the SOC_BUILTIN_DTB_DECLARE() macro since
> it is used only for the K210 support. The code searching the builtin
> DTBs using the vendor, arch an implementation IDs is also removed.
> Support for builtin DTB falls back to the simpler and more traditional
> handling of builtin DTB using the CONFIG_BUILTIN_DTB option, similarly
> to other architectures.
>
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>

> --- a/arch/riscv/boot/dts/kendryte/Makefile
> +++ b/arch/riscv/boot/dts/kendryte/Makefile
> @@ -1,4 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0
> -dtb-$(CONFIG_SOC_KENDRYTE_K210_DTB) += k210.dtb
> -
> +ifneq ($(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE),"")
> +dtb-y += $(strip $(shell echo $(CONFIG_SOC_KENDRYTE_K210_DTB_SOURCE))).dtb
>  obj-$(CONFIG_SOC_KENDRYTE_K210_DTB_BUILTIN) += $(addsuffix .o, $(dtb-y))
> +endif

This break compiling a kernel for non-K210 systems (e.g. defconfig),
as reported before in
https://lore.kernel.org/linux-clk/202011151230.QP1ISPQo-lkp@intel.com/

I think this can be fixed using:

--- a/arch/riscv/boot/dts/Makefile
+++ b/arch/riscv/boot/dts/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 subdir-y += sifive
-subdir-y += canaan
+subdir-$(CONFIG_SOC_CANAAN) += canaan

 obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))

(yes, I've already renamed kendryte to canaan ;-)

Gr{oetje,eeting}s,

                        Geert

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

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

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

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

* Re: [PATCH v4 01/21] riscv: Fix kernel time_init()
  2020-12-02  3:24   ` Damien Le Moal
@ 2020-12-05  5:41     ` Stephen Boyd
  -1 siblings, 0 replies; 78+ messages in thread
From: Stephen Boyd @ 2020-12-05  5:41 UTC (permalink / raw)
  To: Damien Le Moal, Linus Walleij, Palmer Dabbelt, Philipp Zabel,
	Rob Herring, devicetree, linux-clk, linux-gpio, linux-riscv
  Cc: Sean Anderson

Quoting Damien Le Moal (2020-12-01 19:24:40)
> If of_clk_init() is not called in time_init(), clock providers defined
> in the system device tree are not initialized, resulting in failures for
> other devices to initialize due to missing clocks.
> Similarly to other architectures and to the default kernel time_init()
> implementation, call of_clk_init() before executing timer_probe() in
> time_init().
> 
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
> ---

Acked-by: Stephen Boyd <sboyd@kernel.org>

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

* Re: [PATCH v4 01/21] riscv: Fix kernel time_init()
@ 2020-12-05  5:41     ` Stephen Boyd
  0 siblings, 0 replies; 78+ messages in thread
From: Stephen Boyd @ 2020-12-05  5:41 UTC (permalink / raw)
  To: Damien Le Moal, Linus Walleij, Palmer Dabbelt, Philipp Zabel,
	Rob Herring, devicetree, linux-clk, linux-gpio, linux-riscv
  Cc: Sean Anderson

Quoting Damien Le Moal (2020-12-01 19:24:40)
> If of_clk_init() is not called in time_init(), clock providers defined
> in the system device tree are not initialized, resulting in failures for
> other devices to initialize due to missing clocks.
> Similarly to other architectures and to the default kernel time_init()
> implementation, call of_clk_init() before executing timer_probe() in
> time_init().
> 
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
> ---

Acked-by: Stephen Boyd <sboyd@kernel.org>

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

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

* Re: [PATCH v4 07/21] dt-binding: clock: Document canaan,k210-clk bindings
  2020-12-02  3:24   ` [PATCH v4 07/21] dt-binding: clock: Document canaan, k210-clk bindings Damien Le Moal
@ 2020-12-05  5:46     ` Stephen Boyd
  -1 siblings, 0 replies; 78+ messages in thread
From: Stephen Boyd @ 2020-12-05  5:46 UTC (permalink / raw)
  To: Damien Le Moal, Linus Walleij, Palmer Dabbelt, Philipp Zabel,
	Rob Herring, devicetree, linux-clk, linux-gpio, linux-riscv
  Cc: Sean Anderson

Quoting Damien Le Moal (2020-12-01 19:24:46)
> diff --git a/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> new file mode 100644
> index 000000000000..3547916a2421
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> @@ -0,0 +1,55 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/canaan,k210-clk.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Canaan Kendryte K210 Clock Device Tree Bindings
> +
> +maintainers:
> +  - Damien Le Moal <damien.lemoal@wdc.com>
> +
> +description: |
> +  Canaan Kendryte K210 SoC clocks driver bindings. The clock
> +  controller node must be defined as a child node of the K210
> +  system controller node.
> +
> +  See also:
> +  - dt-bindings/clock/k210-clk.h
> +
> +properties:
> +  compatible:
> +    const: canaan,k210-clk
> +
> +  clocks:
> +    maxItems: 1
> +    description:
> +      System fixed rate oscillator clock.

Is it optional? I suspect not and it can always be specified, so drop
maxItems.

> +
> +  '#clock-cells':
> +    const: 1
> +
> +required:
> +  - compatible
> +  - '#clock-cells'
> +  - clocks

Maybe also add clock-names as an optional property, but doesn't really
matter if there's only one clk.

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

* Re: [PATCH v4 07/21] dt-binding: clock: Document canaan, k210-clk bindings
@ 2020-12-05  5:46     ` Stephen Boyd
  0 siblings, 0 replies; 78+ messages in thread
From: Stephen Boyd @ 2020-12-05  5:46 UTC (permalink / raw)
  To: Damien Le Moal, Linus Walleij, Palmer Dabbelt, Philipp Zabel,
	Rob Herring, devicetree, linux-clk, linux-gpio, linux-riscv
  Cc: Sean Anderson

Quoting Damien Le Moal (2020-12-01 19:24:46)
> diff --git a/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> new file mode 100644
> index 000000000000..3547916a2421
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> @@ -0,0 +1,55 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/canaan,k210-clk.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Canaan Kendryte K210 Clock Device Tree Bindings
> +
> +maintainers:
> +  - Damien Le Moal <damien.lemoal@wdc.com>
> +
> +description: |
> +  Canaan Kendryte K210 SoC clocks driver bindings. The clock
> +  controller node must be defined as a child node of the K210
> +  system controller node.
> +
> +  See also:
> +  - dt-bindings/clock/k210-clk.h
> +
> +properties:
> +  compatible:
> +    const: canaan,k210-clk
> +
> +  clocks:
> +    maxItems: 1
> +    description:
> +      System fixed rate oscillator clock.

Is it optional? I suspect not and it can always be specified, so drop
maxItems.

> +
> +  '#clock-cells':
> +    const: 1
> +
> +required:
> +  - compatible
> +  - '#clock-cells'
> +  - clocks

Maybe also add clock-names as an optional property, but doesn't really
matter if there's only one clk.

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-02  3:24   ` Damien Le Moal
@ 2020-12-05  6:19     ` Stephen Boyd
  -1 siblings, 0 replies; 78+ messages in thread
From: Stephen Boyd @ 2020-12-05  6:19 UTC (permalink / raw)
  To: Damien Le Moal, Linus Walleij, Palmer Dabbelt, Philipp Zabel,
	Rob Herring, devicetree, linux-clk, linux-gpio, linux-riscv
  Cc: Sean Anderson

Quoting Damien Le Moal (2020-12-01 19:24:50)
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2daa6ee673f7..3da9a7a02f61 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
>  F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
>  F:     drivers/net/ieee802154/ca8210.c
>  
> +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
> +M:     Damien Le Moal <damien.lemoal@wdc.com>
> +L:     linux-riscv@lists.infradead.org
> +L:     linux-clk@vger.kernel.org (clock driver)

Is this needed? I think we cover all of drivers/clk/ and bindings/clock
already.

> +S:     Maintained
> +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> +F:     drivers/clk/clk-k210.c
> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> index 88ac0d1a5da4..f2f9633087d1 100644
> --- a/arch/riscv/Kconfig.socs
> +++ b/arch/riscv/Kconfig.socs
> @@ -29,6 +29,8 @@ config SOC_CANAAN
>         select SERIAL_SIFIVE if TTY
>         select SERIAL_SIFIVE_CONSOLE if TTY
>         select SIFIVE_PLIC
> +       select SOC_K210_SYSCTL
> +       select CLK_K210

Any reason to do this vs. just make it the default?

>         help
>           This enables support for Canaan Kendryte K210 SoC platform hardware.
>  
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index c715d4681a0b..6f10f1ecc8d6 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -359,6 +359,15 @@ config COMMON_CLK_FIXED_MMIO
>         help
>           Support for Memory Mapped IO Fixed clocks
>  
> +config CLK_K210

Every one else is using COMMON_CLK_ prefix so probably should follow
suit and then sort alphabetically.

> +       bool "Clock driver for the Canaan Kendryte K210 SoC"
> +       depends on RISCV && SOC_CANAAN
> +       depends on COMMON_CLK && OF

i.e. default SOC_CANAAN here

> +       help
> +         Support for the Kendryte K210 RISC-V SoC clocks. This option
> +         is automatically selected when the SOC_KENDRYTE option is selected
> +         in the "SOC selection" menu.
> +
>  source "drivers/clk/actions/Kconfig"
>  source "drivers/clk/analogbits/Kconfig"
>  source "drivers/clk/baikal-t1/Kconfig"
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index da8fcf147eb1..ccac89e0fdfe 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_VT8500)             += clk-vt8500.o
>  obj-$(CONFIG_COMMON_CLK_VC5)           += clk-versaclock5.o
>  obj-$(CONFIG_COMMON_CLK_WM831X)                += clk-wm831x.o
>  obj-$(CONFIG_COMMON_CLK_XGENE)         += clk-xgene.o
> +obj-$(CONFIG_CLK_K210)                 += clk-k210.o

Same sort order please.

>  
>  # please keep this section sorted lexicographically by directory path name
>  obj-y                                  += actions/
> diff --git a/drivers/clk/clk-k210.c b/drivers/clk/clk-k210.c
> new file mode 100644
> index 000000000000..95d830a38911
> --- /dev/null
> +++ b/drivers/clk/clk-k210.c
> @@ -0,0 +1,959 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
> + * Copyright (c) 2019 Western Digital Corporation or its affiliates.
> + */
> +#define pr_fmt(fmt)     "k210-clk: " fmt
> +
> +#include <linux/io.h>
> +#include <linux/spinlock.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_address.h>
> +#include <linux/clk.h>

Preferably this include is dropped.

> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>

Is this used? Hopefully no.

> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <asm/soc.h>
> +#include <soc/canaan/k210-sysctl.h>
> +
> +#include <dt-bindings/clock/k210-clk.h>
> +
> +/*
> + * in0: fixed-rate 26MHz oscillator base clock.
> + */
> +#define K210_IN0_RATE          26000000UL
> +
> +/*
> + * Clocks parameters.
> + */
> +struct k210_clk_cfg {
> +       u8 gate_reg;
> +       u8 gate_bit;
> +       u8 div_reg;
> +       u8 div_shift;
> +       u8 div_width;
> +       u8 div_type;
> +       u8 mux_reg;
> +       u8 mux_bit;
> +};
> +
> +enum k210_clk_div_type {
> +       DIV_NONE,
> +       DIV_ONE_BASED,
> +       DIV_DOUBLE_ONE_BASED,
> +       DIV_POWER_OF_TWO,
> +};
> +
> +#define GATE(_reg, _bit)       \
> +       .gate_reg = (_reg),     \
> +       .gate_bit = (_bit)
> +#define DIV(_reg, _shift, _width, _type)       \
> +       .div_reg = (_reg),                      \
> +       .div_shift = (_shift),                  \
> +       .div_width = (_width),                  \
> +       .div_type = (_type)
> +#define MUX(_reg, _bit)                \
> +       .mux_reg = (_reg),      \
> +       .mux_bit = (_bit)
> +
> +static struct k210_clk_cfg k210_clks[K210_NUM_CLKS] = {
> +
> +       /* Gated clocks, no mux, no divider */
> +       [K210_CLK_CPU] = { GATE(K210_SYSCTL_EN_CENT, 0) },
> +       [K210_CLK_DMA] = { GATE(K210_SYSCTL_EN_PERI, 1) },
> +       [K210_CLK_FFT] = { GATE(K210_SYSCTL_EN_PERI, 4) },
> +       [K210_CLK_GPIO] = { GATE(K210_SYSCTL_EN_PERI, 5) },
> +       [K210_CLK_UART1] = { GATE(K210_SYSCTL_EN_PERI, 16) },
> +       [K210_CLK_UART2] = { GATE(K210_SYSCTL_EN_PERI, 17) },
> +       [K210_CLK_UART3] = { GATE(K210_SYSCTL_EN_PERI, 18) },
> +       [K210_CLK_FPIOA] = { GATE(K210_SYSCTL_EN_PERI, 20) },
> +       [K210_CLK_SHA] = { GATE(K210_SYSCTL_EN_PERI, 26) },
> +       [K210_CLK_AES] = { GATE(K210_SYSCTL_EN_PERI, 19) },
> +       [K210_CLK_OTP] = { GATE(K210_SYSCTL_EN_PERI, 27) },
> +       [K210_CLK_RTC] = { GATE(K210_SYSCTL_EN_PERI, 29) },
> +
> +       /* Gated divider clocks */
> +       [K210_CLK_SRAM0] = {
> +               GATE(K210_SYSCTL_EN_CENT, 1),
> +               DIV(K210_SYSCTL_THR0, 0, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_SRAM1] = {
> +               GATE(K210_SYSCTL_EN_CENT, 2),
> +               DIV(K210_SYSCTL_THR0, 4, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_ROM] = {
> +               GATE(K210_SYSCTL_EN_PERI, 0),
> +               DIV(K210_SYSCTL_THR0, 16, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_DVP] = {
> +               GATE(K210_SYSCTL_EN_PERI, 3),
> +               DIV(K210_SYSCTL_THR0, 12, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_APB0] = {
> +               GATE(K210_SYSCTL_EN_CENT, 3),
> +               DIV(K210_SYSCTL_SEL0, 3, 3, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_APB1] = {
> +               GATE(K210_SYSCTL_EN_CENT, 4),
> +               DIV(K210_SYSCTL_SEL0, 6, 3, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_APB2] = {
> +               GATE(K210_SYSCTL_EN_CENT, 5),
> +               DIV(K210_SYSCTL_SEL0, 9, 3, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_AI] = {
> +               GATE(K210_SYSCTL_EN_PERI, 2),
> +               DIV(K210_SYSCTL_THR0, 8, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_SPI0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 6),
> +               DIV(K210_SYSCTL_THR1, 0, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_SPI1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 7),
> +               DIV(K210_SYSCTL_THR1, 8, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_SPI2] = {
> +               GATE(K210_SYSCTL_EN_PERI, 8),
> +               DIV(K210_SYSCTL_THR1, 16, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2C0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 13),
> +               DIV(K210_SYSCTL_THR5, 8, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2C1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 14),
> +               DIV(K210_SYSCTL_THR5, 16, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2C2] = {
> +               GATE(K210_SYSCTL_EN_PERI, 15),
> +               DIV(K210_SYSCTL_THR5, 24, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_WDT0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 24),
> +               DIV(K210_SYSCTL_THR6, 0, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_WDT1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 25),
> +               DIV(K210_SYSCTL_THR6, 8, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 10),
> +               DIV(K210_SYSCTL_THR3, 0, 16, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 11),
> +               DIV(K210_SYSCTL_THR3, 16, 16, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S2] = {
> +               GATE(K210_SYSCTL_EN_PERI, 12),
> +               DIV(K210_SYSCTL_THR4, 0, 16, DIV_DOUBLE_ONE_BASED)
> +       },
> +
> +       /* Divider clocks, no gate, no mux */
> +       [K210_CLK_I2S0_M] = {
> +               DIV(K210_SYSCTL_THR4, 16, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S1_M] = {
> +               DIV(K210_SYSCTL_THR4, 24, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S2_M] = {
> +               DIV(K210_SYSCTL_THR4, 0, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +
> +       /* Muxed gated divider clocks */
> +       [K210_CLK_SPI3] = {
> +               GATE(K210_SYSCTL_EN_PERI, 9),
> +               DIV(K210_SYSCTL_THR1, 24, 8, DIV_DOUBLE_ONE_BASED),
> +               MUX(K210_SYSCTL_SEL0, 12)
> +       },
> +       [K210_CLK_TIMER0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 21),
> +               DIV(K210_SYSCTL_THR2,  0, 8, DIV_DOUBLE_ONE_BASED),
> +               MUX(K210_SYSCTL_SEL0, 13)
> +       },
> +       [K210_CLK_TIMER1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 22),
> +               DIV(K210_SYSCTL_THR2, 8, 8, DIV_DOUBLE_ONE_BASED),
> +               MUX(K210_SYSCTL_SEL0, 14)
> +       },
> +       [K210_CLK_TIMER2] = {
> +               GATE(K210_SYSCTL_EN_PERI, 23),
> +               DIV(K210_SYSCTL_THR2, 16, 8, DIV_DOUBLE_ONE_BASED),
> +               MUX(K210_SYSCTL_SEL0, 15)
> +       },
> +};
> +
> +/*
> + * PLL control register bits.
> + */
> +#define K210_PLL_CLKR          GENMASK(3, 0)
> +#define K210_PLL_CLKF          GENMASK(9, 4)
> +#define K210_PLL_CLKOD         GENMASK(13, 10)
> +#define K210_PLL_BWADJ         GENMASK(19, 14)
> +#define K210_PLL_RESET         (1 << 20)
> +#define K210_PLL_PWRD          (1 << 21)
> +#define K210_PLL_INTFB         (1 << 22)
> +#define K210_PLL_BYPASS                (1 << 23)
> +#define K210_PLL_TEST          (1 << 24)
> +#define K210_PLL_EN            (1 << 25)
> +#define K210_PLL_SEL           GENMASK(27, 26) /* PLL2 only */
> +
> +/*
> + * PLL lock register bits.
> + */
> +#define K210_PLL_LOCK          0
> +#define K210_PLL_CLEAR_SLIP    2
> +#define K210_PLL_TEST_OUT      3
> +
> +/*
> + * Clock selector register bits.
> + */
> +#define K210_ACLK_SEL          BIT(0)
> +#define K210_ACLK_DIV          GENMASK(2, 1)
> +
> +/*
> + * PLLs.
> + */
> +enum k210_pll_id {
> +       K210_PLL0, K210_PLL1, K210_PLL2, K210_PLL_NUM
> +};
> +
> +struct k210_pll {
> +enum k210_pll_id id;

Not sure what happened here but it's not tabbed.

> +       /* PLL setup register */
> +       void __iomem *reg;
> +
> +       /* Common lock register */
> +       void __iomem *lock;
> +
> +       /* Offset and width of lock bits */
> +       u8 lock_shift;
> +       u8 lock_width;
> +
> +       struct clk_hw hw;
> +};
> +#define to_k210_pll(hw)        container_of(hw, struct k210_pll, hw)
> +
> +struct k210_pll_cfg {
> +       /* PLL setup register offset */
> +       u32 reg;
> +
> +       /* Offset and width fo the lock bits */
> +       u8 lock_shift;
> +       u8 lock_width;
> +
> +       /* PLL setup initial factors */
> +       u32 r, f, od, bwadj;

Please have one line per struct member. I guess our kernel style is to
do that so we can quickly see how many members there are.

> +};
> +
> +/*
> + * PLL factors:
> + * By default, PLL0 runs at 780 MHz and PLL1 at 299 MHz.
> + * The first 2 sram banks depend on ACLK/CPU clock which is by default
> + * PLL0 rate divided by 2. Set PLL1 to 390 MHz so that the third sram
> + * bank has the same clock.
> + */
> +static struct k210_pll_cfg k210_plls_cfg[] = {
> +       { K210_SYSCTL_PLL0,  0, 2, 0, 59, 1, 59 }, /* 780 MHz */
> +       { K210_SYSCTL_PLL1,  8, 1, 0, 59, 3, 59 }, /* 390 MHz */
> +       { K210_SYSCTL_PLL2, 16, 1, 0, 22, 1, 22 }, /* 299 MHz */
> +};
> +
> +/*
> + * Clocks data.

This comment could be kernel-doc and be more helpful.

> + */
> +struct k210_clk {
> +       void __iomem                    *regs;
> +       spinlock_t                      clk_lock;
> +       struct k210_pll                 plls[K210_PLL_NUM];
> +       struct clk_hw                   aclk;
> +       struct clk_hw                   clks[K210_NUM_CLKS];
> +       struct clk_hw_onecell_data      *clk_data;
> +};
> +
> +static struct k210_clk *kcl;
> +
> +/*
> + * Set ACLK parent selector: 0 for IN0, 1 for PLL0.
> + */
> +static void k210_aclk_set_selector(u8 sel)
> +{
> +       u32 reg = readl(kcl->regs + K210_SYSCTL_SEL0);
> +
> +       if (sel)
> +               reg |= K210_ACLK_SEL;
> +       else
> +               reg &= K210_ACLK_SEL;
> +       writel(reg, kcl->regs + K210_SYSCTL_SEL0);
> +}
> +
> +static void k210_init_pll(struct k210_pll *pll, enum k210_pll_id id,
> +                         void __iomem *base)
> +{
> +       pll->id = id;
> +       pll->lock = base + K210_SYSCTL_PLL_LOCK;
> +       pll->reg = base + k210_plls_cfg[id].reg;
> +       pll->lock_shift = k210_plls_cfg[id].lock_shift;
> +       pll->lock_width = k210_plls_cfg[id].lock_width;
> +}
> +
> +static void k210_pll_wait_for_lock(struct k210_pll *pll)
> +{
> +       u32 reg, mask = GENMASK(pll->lock_width - 1, 0) << pll->lock_shift;

GENMASK should take the pll->lock_shift instead of shifting it after the
fact. That way we don't have to think about overflow.

> +
> +       while (true) {
> +               reg = readl(pll->lock);
> +               if ((reg & mask) == mask)
> +                       break;
> +
> +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
> +               writel(reg, pll->lock);

Is this readl_poll_timeout?

> +       }
> +}
> +
> +static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
> +{
> +       u32 reg = readl(pll->reg);
> +       u32 mask = K210_PLL_PWRD | K210_PLL_EN;
> +
> +       if (reg & K210_PLL_RESET)
> +               return false;
> +
> +       return (reg & mask) == mask;
> +}
> +
> +static void k210_pll_enable_hw(struct k210_pll *pll)
> +{
> +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
> +       unsigned long flags;
> +       u32 reg;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +
> +       if (k210_pll_hw_is_enabled(pll))
> +               goto unlock;
> +
> +       if (pll->id == K210_PLL0) {
> +               /* Re-parent aclk to IN0 to keep the CPUs running */
> +               k210_aclk_set_selector(0);
> +       }
> +
> +       /* Set factors */
> +       reg = readl(pll->reg);
> +       reg &= ~GENMASK(19, 0);
> +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
> +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
> +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
> +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
> +       reg |= K210_PLL_PWRD;
> +       writel(reg, pll->reg);
> +
> +       /* Ensure reset is low before asserting it */
> +       reg &= ~K210_PLL_RESET;
> +       writel(reg, pll->reg);
> +       reg |= K210_PLL_RESET;
> +       writel(reg, pll->reg);
> +       nop();
> +       nop();

Are these nops needed for some reason? Any comment to add here? It's
basically non-portable code and hopefully nothing is inserted into that
writel function that shouldn't be there.

> +       reg &= ~K210_PLL_RESET;
> +       writel(reg, pll->reg);
> +
> +       k210_pll_wait_for_lock(pll);
> +
> +       reg &= ~K210_PLL_BYPASS;
> +       reg |= K210_PLL_EN;
> +       writel(reg, pll->reg);
> +
> +       if (pll->id == K210_PLL0) {
> +               /* Re-parent aclk back to PLL0 */
> +               k210_aclk_set_selector(1);
> +       }
> +unlock:
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +}
> +
> +static void k210_pll_disable_hw(struct k210_pll *pll)
> +{
> +       unsigned long flags;
> +       u32 reg;
> +
> +       /*
> +        * Bypassing before powering off is important so child clocks don't stop
> +        * working. This is especially important for pll0, the indirect parent
> +        * of the cpu clock.
> +        */
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(pll->reg);
> +       reg |= K210_PLL_BYPASS;
> +       writel(reg, pll->reg);
> +
> +       reg &= ~K210_PLL_PWRD;
> +       reg &= ~K210_PLL_EN;
> +       writel(reg, pll->reg);
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +}
> +
> +static int k210_pll_enable(struct clk_hw *hw)
> +{
> +       k210_pll_enable_hw(to_k210_pll(hw));
> +
> +       return 0;
> +}
> +
> +static void k210_pll_disable(struct clk_hw *hw)
> +{
> +       k210_pll_disable_hw(to_k210_pll(hw));
> +}
> +
> +static int k210_pll_is_enabled(struct clk_hw *hw)
> +{
> +       return k210_pll_hw_is_enabled(to_k210_pll(hw));
> +}
> +
> +static int k210_pll_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       struct k210_pll *pll = to_k210_pll(hw);
> +       unsigned long flags;
> +       int ret = 0;
> +       u32 reg;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +
> +       switch (pll->id) {
> +       case K210_PLL0:
> +       case K210_PLL1:
> +               if (WARN_ON(index != 0))
> +                       ret = -EINVAL;
> +               break;
> +       case K210_PLL2:

Instead of a pll->id can we have two different clk ops?

> +               if (WARN_ON(index > 2)) {
> +                       ret = -EINVAL;
> +                       break;
> +               }
> +               reg = readl(pll->reg);
> +               reg &= ~K210_PLL_SEL;
> +               reg |= FIELD_PREP(K210_PLL_SEL, index);
> +               writel(reg, pll->reg);
> +               break;
> +       default:
> +               ret = -EINVAL;
> +               break;
> +       }
> +
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +
> +       return ret;
> +}
> +
> +static u8 k210_pll_get_parent(struct clk_hw *hw)
> +{
> +       struct k210_pll *pll = to_k210_pll(hw);
> +       u32 reg;
> +
> +       switch (pll->id) {
> +       case K210_PLL0:
> +       case K210_PLL1:
> +               return 0;
> +       case K210_PLL2:
> +               reg = readl(pll->reg);
> +               return FIELD_GET(K210_PLL_SEL, reg);
> +       default:
> +               return 0;
> +       }
> +}
> +
> +static unsigned long k210_pll_get_rate(struct clk_hw *hw,
> +                                      unsigned long parent_rate)
> +{
> +       struct k210_pll *pll = to_k210_pll(hw);
> +       u32 reg = readl(pll->reg);
> +       u32 r, f, od;
> +
> +       if (reg & K210_PLL_BYPASS)
> +               return parent_rate;
> +
> +       if (!(reg & K210_PLL_PWRD))
> +               return 0;
> +
> +       r = FIELD_GET(K210_PLL_CLKR, reg) + 1;
> +       f = FIELD_GET(K210_PLL_CLKF, reg) + 1;
> +       od = FIELD_GET(K210_PLL_CLKOD, reg) + 1;
> +
> +       return (u64)parent_rate * f / (r * od);
> +}
> +
> +static const struct clk_ops k210_pll_ops = {
> +       .enable         = k210_pll_enable,
> +       .disable        = k210_pll_disable,
> +       .is_enabled     = k210_pll_is_enabled,
> +       .set_parent     = k210_pll_set_parent,
> +       .get_parent     = k210_pll_get_parent,
> +       .recalc_rate    = k210_pll_get_rate,
> +};
> +
> +static const char *pll_parents[] = { NULL, "pll0", "pll1" };

This should get a k210 prefix as to not pollute the global namespace of
kernel symbols (of which there are so many!).

> +
> +static struct clk_hw *k210_register_pll(enum k210_pll_id id, const char *name,
> +                               const char **parent_names, int num_parents,
> +                               unsigned long flags)
> +{
> +       struct k210_pll *pll = &kcl->plls[id];
> +       struct clk_init_data init = {};
> +       int ret;
> +
> +       init.name = name;
> +       init.parent_names = parent_names;
> +       init.num_parents = num_parents;
> +       init.flags = flags;
> +       init.ops = &k210_pll_ops;
> +       pll->hw.init = &init;
> +
> +       ret = clk_hw_register(NULL, &pll->hw);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       return &pll->hw;
> +}
> +
> +static int k210_aclk_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       if (WARN_ON(index > 1))

Is this possible? What am I going to do as a user if this happens?

> +               return -EINVAL;
> +
> +       k210_aclk_set_selector(index);
> +
> +       return 0;
> +}
> +
> +static u8 k210_aclk_get_parent(struct clk_hw *hw)
> +{
> +       u32 sel = readl(kcl->regs + K210_SYSCTL_SEL0);
> +
> +       return (sel & K210_ACLK_SEL) ? 1 : 0;

Preferably write as

	u32 sel;

	sel = readl(kclk->regs + K210_SYSCTL_SEL0);
	sel &= K210_ACLK_SEL;

	return sel ? 1 : 0; 

> +}
> +
> +static unsigned long k210_aclk_get_rate(struct clk_hw *hw,
> +                                       unsigned long parent_rate)
> +{
> +       u32 reg = readl(kcl->regs + K210_SYSCTL_SEL0);
> +       unsigned int shift;
> +
> +       if (!(reg & 0x1))
> +               return parent_rate;
> +
> +       shift = FIELD_GET(K210_ACLK_DIV, reg);
> +
> +       return parent_rate / (2UL << shift);
> +}
> +
> +static const struct clk_ops k210_aclk_ops = {
> +       .set_parent     = k210_aclk_set_parent,
> +       .get_parent     = k210_aclk_get_parent,
> +       .recalc_rate    = k210_aclk_get_rate,
> +};
> +
> +static const char *aclk_parents[] = { NULL, "pll0" };
> +
> +static struct clk_hw *k210_register_aclk(void)
> +{
> +       struct clk_init_data init = {};
> +       int ret;
> +
> +       init.name = "aclk";
> +       init.parent_names = aclk_parents;
> +       init.num_parents = 2;
> +       init.flags = 0;

Remove? It's the default now that init = {}.

> +       init.ops = &k210_aclk_ops;
> +       kcl->aclk.init = &init;
> +
> +       ret = clk_hw_register(NULL, &kcl->aclk);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       return &kcl->aclk;
> +}
> +
> +#define to_k210_clk_id(hw)     ((unsigned int)((hw) - &kcl->clks[0]))
> +#define to_k210_clk_cfg(hw)    (&k210_clks[to_k210_clk_id(hw)])
> +
> +static u32 k210_clk_get_div_val(struct k210_clk_cfg *kclk)
> +{
> +       u32 reg = readl(kcl->regs + kclk->div_reg);
> +
> +       return (reg >> kclk->div_shift) & GENMASK(kclk->div_width - 1, 0);

Use FIELD_GET()?

> +}
> +
> +static unsigned long k210_clk_divider(struct k210_clk_cfg *kclk,
> +                                     u32 div_val)
> +{
> +       switch (kclk->div_type) {
> +       case DIV_ONE_BASED:
> +               return div_val + 1;
> +       case DIV_DOUBLE_ONE_BASED:
> +               return (div_val + 1) * 2;
> +       case DIV_POWER_OF_TWO:
> +               return 2UL << div_val;
> +       case DIV_NONE:
> +       default:
> +               return 0;
> +       }
> +}
> +
> +static int k210_clk_enable(struct clk_hw *hw)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long flags;
> +       u32 reg;
> +
> +       if (!kclk->gate_reg)
> +               return 0;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(kcl->regs + kclk->gate_reg);
> +       reg |= BIT(kclk->gate_bit);
> +       writel(reg, kcl->regs + kclk->gate_reg);
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +
> +       return 0;
> +}
> +
> +static void k210_clk_disable(struct clk_hw *hw)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long flags;
> +       u32 reg;
> +
> +       if (!kclk->gate_reg)
> +               return;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(kcl->regs + kclk->gate_reg);
> +       reg &= ~BIT(kclk->gate_bit);
> +       writel(reg, kcl->regs + kclk->gate_reg);
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +}
> +
> +static int k210_clk_is_enabled(struct clk_hw *hw)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +
> +       if (!kclk->gate_reg)
> +               return 1;
> +
> +       return readl(kcl->regs + kclk->gate_reg) & BIT(kclk->gate_bit);
> +}
> +
> +static int k210_clk_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long flags;
> +       u32 reg;
> +
> +       if (!kclk->mux_reg) {
> +               if (WARN_ON(index != 0))
> +                       return -EINVAL;
> +               return 0;
> +       }
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(kcl->regs + kclk->mux_reg);
> +       if (index)
> +               reg |= BIT(kclk->mux_bit);
> +       else
> +               reg &= ~BIT(kclk->mux_bit);
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +
> +       return 0;
> +}
> +
> +static u8 k210_clk_get_parent(struct clk_hw *hw)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long flags;
> +       u32 reg, idx;
> +
> +       if (!kclk->mux_reg)
> +               return 0;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(kcl->regs + kclk->mux_reg);
> +       idx = (reg & BIT(kclk->mux_bit)) ? 1 : 0;
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +
> +       return idx;
> +}
> +
> +static unsigned long k210_clk_get_rate(struct clk_hw *hw,
> +                                      unsigned long parent_rate)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long divider;
> +
> +       if (!kclk->div_reg)
> +               return parent_rate;
> +
> +       divider = k210_clk_divider(kclk, k210_clk_get_div_val(kclk));
> +       if (WARN_ON(!divider))
> +               return 0;
> +
> +       return parent_rate / divider;
> +}
> +
> +static const struct clk_ops k210_clk_ops = {
> +       .enable         = k210_clk_enable,
> +       .is_enabled     = k210_clk_is_enabled,
> +       .disable        = k210_clk_disable,
> +       .set_parent     = k210_clk_set_parent,
> +       .get_parent     = k210_clk_get_parent,
> +       .recalc_rate    = k210_clk_get_rate,
> +};
> +
> +static const char *mux_parents[] = { NULL, "pll0" };
> +
> +static struct clk_hw *k210_register_clk(int id, const char *name,
> +                                       const char *parent, unsigned long flags)
> +{
> +       struct clk_init_data init = {};
> +       int ret;
> +
> +       init.name = name;
> +       if (parent) {
> +               init.parent_names = &parent;
> +               init.num_parents = 1;
> +       } else {
> +               init.parent_names = mux_parents;
> +               init.num_parents = 2;
> +       }
> +       init.flags = flags;
> +       init.ops = &k210_clk_ops;
> +       kcl->clks[id].init = &init;
> +
> +       ret = clk_hw_register(NULL, &kcl->clks[id]);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       return &kcl->clks[id];
> +}
> +
> +static void __init k210_clk_init(struct device_node *np)
> +{
> +       struct device_node *sysctl_np;
> +       struct clk *in0_clk;
> +       const char *in0;
> +       struct clk_hw **hws;
> +       int i, ret;
> +
> +       kcl = kzalloc(sizeof(*kcl), GFP_KERNEL);
> +       if (!kcl)
> +               return;
> +
> +       sysctl_np = of_find_compatible_node(NULL, NULL, "canaan,k210-sysctl");
> +       if (!sysctl_np || sysctl_np != np->parent)
> +               goto err;
> +
> +       kcl->regs = of_iomap(sysctl_np, 0);
> +       if (!kcl->regs)
> +               goto err;
> +
> +       kcl->clk_data = kzalloc(struct_size(kcl->clk_data, hws, K210_NUM_CLKS),
> +                               GFP_KERNEL);
> +       if (!kcl->clk_data)
> +               goto err;
> +
> +       for (i = 0; i < K210_PLL_NUM; i++)
> +               k210_init_pll(&kcl->plls[i], i, kcl->regs);
> +       spin_lock_init(&kcl->clk_lock);
> +       kcl->clk_data->num = K210_NUM_CLKS;
> +       hws = kcl->clk_data->hws;
> +       for (i = 1; i < K210_NUM_CLKS; i++)
> +               hws[i] = ERR_PTR(-EPROBE_DEFER);
> +
> +       /*
> +        * in0 is the system base fixed-rate 26MHz oscillator which
> +        * should already be defined by the device tree. If it is not,
> +        * create it here.

Are there old DTBs that don't have this? Sadface.

> +        */
> +       in0_clk = of_clk_get(np, 0);
> +       if (IS_ERR(in0_clk)) {
> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> +               hws[K210_CLK_IN0] =
> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> +                                                  0, K210_IN0_RATE);
> +       } else {
> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> +       }
> +       if (IS_ERR(hws[K210_CLK_IN0])) {
> +               pr_err("%pOFP: failed to get base oscillator\n", np);
> +               goto err;
> +       }
> +
> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> +       aclk_parents[0] = in0;
> +       pll_parents[0] = in0;
> +       mux_parents[0] = in0;

Can we use the new way of specifying clk parents so that we don't have
to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
the core can handl that all instead of this driver.

> +
> +       /* PLLs */
> +       hws[K210_CLK_PLL0] =
> +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
> +       hws[K210_CLK_PLL1] =
> +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
> +       hws[K210_CLK_PLL2] =
> +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
> +
> +       /* aclk: muxed of in0 and pll0_d, no gate */
> +       hws[K210_CLK_ACLK] = k210_register_aclk();
> +
> +       /*
> +        * Clocks with aclk as source: the CPU clock is obviously critical.
> +        * So is the CLINT clock as the scheduler clocksource.
> +        */
> +       hws[K210_CLK_CPU] =
> +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
> +       hws[K210_CLK_CLINT] =
> +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
> +                                            CLK_IS_CRITICAL, 1, 50);

Is anyone getting these clks? It's nice and all to model things in the
clk framework but if they never have a consumer then it is sort of
useless and just wastes memory and causes more overhead.

> +       hws[K210_CLK_DMA] =
> +               k210_register_clk(K210_CLK_DMA, "dma", "aclk", 0);
> +       hws[K210_CLK_FFT] =
> +               k210_register_clk(K210_CLK_FFT, "fft", "aclk", 0);
> +       hws[K210_CLK_ROM] =
> +               k210_register_clk(K210_CLK_ROM, "rom", "aclk", 0);
> +       hws[K210_CLK_DVP] =
> +               k210_register_clk(K210_CLK_DVP, "dvp", "aclk", 0);
> +       hws[K210_CLK_APB0] =
> +               k210_register_clk(K210_CLK_APB0, "apb0", "aclk", 0);
> +       hws[K210_CLK_APB1] =
> +               k210_register_clk(K210_CLK_APB1, "apb1", "aclk", 0);
> +       hws[K210_CLK_APB2] =
> +               k210_register_clk(K210_CLK_APB2, "apb2", "aclk", 0);
> +
> +       /*
> +        * There is no sram driver taking a ref on the sram banks clocks.
> +        * So make them critical so they are not disabled due to being unused
> +        * as seen by the clock infrastructure.
> +        */
> +       hws[K210_CLK_SRAM0] =
> +               k210_register_clk(K210_CLK_SRAM0,
> +                                 "sram0", "aclk", CLK_IS_CRITICAL);
> +       hws[K210_CLK_SRAM1] =
> +               k210_register_clk(K210_CLK_SRAM1,
> +                                 "sram1", "aclk", CLK_IS_CRITICAL);
> +
> +       /* Clocks with PLL0 as source */
> +       hws[K210_CLK_SPI0] =
> +               k210_register_clk(K210_CLK_SPI0, "spi0", "pll0", 0);
> +       hws[K210_CLK_SPI1] =
> +                k210_register_clk(K210_CLK_SPI1, "spi1", "pll0", 0);
> +       hws[K210_CLK_SPI2] =
> +                k210_register_clk(K210_CLK_SPI2, "spi2", "pll0", 0);
> +       hws[K210_CLK_I2C0] =
> +                k210_register_clk(K210_CLK_I2C0, "i2c0", "pll0", 0);
> +       hws[K210_CLK_I2C1] =
> +                k210_register_clk(K210_CLK_I2C1, "i2c1", "pll0", 0);
> +       hws[K210_CLK_I2C2] =
> +                k210_register_clk(K210_CLK_I2C2, "i2c2", "pll0", 0);
> +
> +       /*
> +        * Clocks with PLL1 as source: there is only the AI clock for the
> +        * (unused) KPU device. As this clock also drives the aisram bank
> +        * which is used as general memory, make it critical.
> +        */
> +        hws[K210_CLK_AI] =
> +                k210_register_clk(K210_CLK_AI, "ai", "pll1", CLK_IS_CRITICAL);
> +
> +       /* Clocks with PLL2 as source */
> +       hws[K210_CLK_I2S0] =
> +                k210_register_clk(K210_CLK_I2S0, "i2s0", "pll2", 0);
> +       hws[K210_CLK_I2S1] =
> +                k210_register_clk(K210_CLK_I2S1, "i2s1", "pll2", 0);
> +       hws[K210_CLK_I2S2] =
> +               k210_register_clk(K210_CLK_I2S2, "i2s2", "pll2", 0);
> +       hws[K210_CLK_I2S0_M] =
> +               k210_register_clk(K210_CLK_I2S0_M, "i2s0_m", "pll2", 0);
> +       hws[K210_CLK_I2S1_M] =
> +               k210_register_clk(K210_CLK_I2S1_M, "i2s1_m", "pll2", 0);
> +       hws[K210_CLK_I2S2_M] =
> +               k210_register_clk(K210_CLK_I2S2_M, "i2s2_m", "pll2", 0);
> +
> +       /* Clocks with IN0 as source */
> +       hws[K210_CLK_WDT0] =
> +               k210_register_clk(K210_CLK_WDT0, "wdt0", in0, 0);
> +       hws[K210_CLK_WDT1] =
> +                k210_register_clk(K210_CLK_WDT1, "wdt1", in0, 0);
> +       hws[K210_CLK_RTC] =
> +                k210_register_clk(K210_CLK_RTC, "rtc", in0, 0);
> +
> +       /* Clocks with APB0 as source */
> +       hws[K210_CLK_GPIO] =
> +               k210_register_clk(K210_CLK_GPIO, "gpio", "apb0", 0);
> +       hws[K210_CLK_UART1] =
> +               k210_register_clk(K210_CLK_UART1, "uart1", "apb0", 0);
> +       hws[K210_CLK_UART2] =
> +               k210_register_clk(K210_CLK_UART2, "uart2", "apb0", 0);
> +       hws[K210_CLK_UART3] =
> +               k210_register_clk(K210_CLK_UART3, "uart3", "apb0", 0);
> +       hws[K210_CLK_FPIOA] =
> +               k210_register_clk(K210_CLK_FPIOA, "fpioa", "apb0", 0);
> +       hws[K210_CLK_SHA] =
> +               k210_register_clk(K210_CLK_SHA, "sha", "apb0", 0);
> +
> +       /* Clocks with APB1 as source */
> +       hws[K210_CLK_AES] =
> +                k210_register_clk(K210_CLK_AES, "aes", "apb1", 0);
> +       hws[K210_CLK_OTP] =
> +                k210_register_clk(K210_CLK_OTP, "otp", "apb1", 0);
> +
> +       /* Muxed clocks with in0/pll0 as source */
> +       hws[K210_CLK_SPI3] =
> +               k210_register_clk(K210_CLK_SPI3, "spi3", NULL, 0);
> +       hws[K210_CLK_TIMER0] =
> +               k210_register_clk(K210_CLK_TIMER0, "timer0", NULL, 0);
> +       hws[K210_CLK_TIMER1] =
> +               k210_register_clk(K210_CLK_TIMER1, "timer1", NULL, 0);
> +       hws[K210_CLK_TIMER2] =
> +               k210_register_clk(K210_CLK_TIMER2, "timer2", NULL, 0);
> +
> +       for (i = 0; i < K210_NUM_CLKS; i++) {
> +               if (IS_ERR(hws[i])) {
> +                       pr_err("%pOFP: register clock %d failed %ld\n",
> +                              np, i, PTR_ERR(hws[i]));
> +                       goto err;
> +               }
> +       }
> +
> +       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
> +       if (ret)
> +               pr_err("%pOFP: add clock provider failed %d\n", np, ret);
> +       else
> +               pr_info("%pOFP: CPU running at %lu MHz\n",

Is this important? Is there a CPUfreq driver that runs and tells us the
boot CPU frequency instead? Doesn't feel like we care in the clk driver
about this.

> +                       np, clk_hw_get_rate(hws[K210_CLK_CPU]) / 1000000);
> +
> +       return;
> +err:
> +       pr_err("%pOFP: clock initialization failed\n", np);
> +       iounmap(kcl->regs);
> +       kfree(kcl->clk_data);
> +       kfree(kcl);
> +       kcl = NULL;

Why?

> +}
> +
> +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);

Is this needed or can this just be a plain platform driver? If something
is needed early for a clocksource or clockevent then the driver can be
split to register those few clks early from this hook and then register
the rest later when the platform device probes. That's what
CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
is incorrect.

> +
> +/*
> + * Enable PLL1 to be able to use the AI SRAM.
> + */
> +void __init k210_clk_early_init(void __iomem *regs)
> +{
> +       struct k210_pll pll1;
> +
> +       /* Make sure aclk selector is set to PLL0 */
> +       k210_aclk_set_selector(1);
> +
> +       /* Startup PLL1 to enable the aisram bank for general memory use */
> +       k210_init_pll(&pll1, K210_PLL1, regs);
> +       k210_pll_enable_hw(&pll1);
> +}
> diff --git a/include/soc/canaan/k210-sysctl.h b/include/soc/canaan/k210-sysctl.h
> new file mode 100644
> index 000000000000..50b21484f7c7
> --- /dev/null
> +++ b/include/soc/canaan/k210-sysctl.h
[...]
> +#define K210_SYSCTL_DMA_SEL0   0x64 /* DMA handshake selector 0 */
> +#define K210_SYSCTL_DMA_SEL1   0x68 /* DMA handshake selector 1 */
> +#define K210_SYSCTL_POWER_SEL  0x6C /* IO Power Mode Select controller */
> +
> +void __init k210_clk_early_init(void __iomem *regs);

We don't need __init in header files. Please remove the marking.

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-05  6:19     ` Stephen Boyd
  0 siblings, 0 replies; 78+ messages in thread
From: Stephen Boyd @ 2020-12-05  6:19 UTC (permalink / raw)
  To: Damien Le Moal, Linus Walleij, Palmer Dabbelt, Philipp Zabel,
	Rob Herring, devicetree, linux-clk, linux-gpio, linux-riscv
  Cc: Sean Anderson

Quoting Damien Le Moal (2020-12-01 19:24:50)
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2daa6ee673f7..3da9a7a02f61 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
>  F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
>  F:     drivers/net/ieee802154/ca8210.c
>  
> +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
> +M:     Damien Le Moal <damien.lemoal@wdc.com>
> +L:     linux-riscv@lists.infradead.org
> +L:     linux-clk@vger.kernel.org (clock driver)

Is this needed? I think we cover all of drivers/clk/ and bindings/clock
already.

> +S:     Maintained
> +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> +F:     drivers/clk/clk-k210.c
> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> index 88ac0d1a5da4..f2f9633087d1 100644
> --- a/arch/riscv/Kconfig.socs
> +++ b/arch/riscv/Kconfig.socs
> @@ -29,6 +29,8 @@ config SOC_CANAAN
>         select SERIAL_SIFIVE if TTY
>         select SERIAL_SIFIVE_CONSOLE if TTY
>         select SIFIVE_PLIC
> +       select SOC_K210_SYSCTL
> +       select CLK_K210

Any reason to do this vs. just make it the default?

>         help
>           This enables support for Canaan Kendryte K210 SoC platform hardware.
>  
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index c715d4681a0b..6f10f1ecc8d6 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -359,6 +359,15 @@ config COMMON_CLK_FIXED_MMIO
>         help
>           Support for Memory Mapped IO Fixed clocks
>  
> +config CLK_K210

Every one else is using COMMON_CLK_ prefix so probably should follow
suit and then sort alphabetically.

> +       bool "Clock driver for the Canaan Kendryte K210 SoC"
> +       depends on RISCV && SOC_CANAAN
> +       depends on COMMON_CLK && OF

i.e. default SOC_CANAAN here

> +       help
> +         Support for the Kendryte K210 RISC-V SoC clocks. This option
> +         is automatically selected when the SOC_KENDRYTE option is selected
> +         in the "SOC selection" menu.
> +
>  source "drivers/clk/actions/Kconfig"
>  source "drivers/clk/analogbits/Kconfig"
>  source "drivers/clk/baikal-t1/Kconfig"
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index da8fcf147eb1..ccac89e0fdfe 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_VT8500)             += clk-vt8500.o
>  obj-$(CONFIG_COMMON_CLK_VC5)           += clk-versaclock5.o
>  obj-$(CONFIG_COMMON_CLK_WM831X)                += clk-wm831x.o
>  obj-$(CONFIG_COMMON_CLK_XGENE)         += clk-xgene.o
> +obj-$(CONFIG_CLK_K210)                 += clk-k210.o

Same sort order please.

>  
>  # please keep this section sorted lexicographically by directory path name
>  obj-y                                  += actions/
> diff --git a/drivers/clk/clk-k210.c b/drivers/clk/clk-k210.c
> new file mode 100644
> index 000000000000..95d830a38911
> --- /dev/null
> +++ b/drivers/clk/clk-k210.c
> @@ -0,0 +1,959 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
> + * Copyright (c) 2019 Western Digital Corporation or its affiliates.
> + */
> +#define pr_fmt(fmt)     "k210-clk: " fmt
> +
> +#include <linux/io.h>
> +#include <linux/spinlock.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_address.h>
> +#include <linux/clk.h>

Preferably this include is dropped.

> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>

Is this used? Hopefully no.

> +#include <linux/bitfield.h>
> +#include <linux/delay.h>
> +#include <asm/soc.h>
> +#include <soc/canaan/k210-sysctl.h>
> +
> +#include <dt-bindings/clock/k210-clk.h>
> +
> +/*
> + * in0: fixed-rate 26MHz oscillator base clock.
> + */
> +#define K210_IN0_RATE          26000000UL
> +
> +/*
> + * Clocks parameters.
> + */
> +struct k210_clk_cfg {
> +       u8 gate_reg;
> +       u8 gate_bit;
> +       u8 div_reg;
> +       u8 div_shift;
> +       u8 div_width;
> +       u8 div_type;
> +       u8 mux_reg;
> +       u8 mux_bit;
> +};
> +
> +enum k210_clk_div_type {
> +       DIV_NONE,
> +       DIV_ONE_BASED,
> +       DIV_DOUBLE_ONE_BASED,
> +       DIV_POWER_OF_TWO,
> +};
> +
> +#define GATE(_reg, _bit)       \
> +       .gate_reg = (_reg),     \
> +       .gate_bit = (_bit)
> +#define DIV(_reg, _shift, _width, _type)       \
> +       .div_reg = (_reg),                      \
> +       .div_shift = (_shift),                  \
> +       .div_width = (_width),                  \
> +       .div_type = (_type)
> +#define MUX(_reg, _bit)                \
> +       .mux_reg = (_reg),      \
> +       .mux_bit = (_bit)
> +
> +static struct k210_clk_cfg k210_clks[K210_NUM_CLKS] = {
> +
> +       /* Gated clocks, no mux, no divider */
> +       [K210_CLK_CPU] = { GATE(K210_SYSCTL_EN_CENT, 0) },
> +       [K210_CLK_DMA] = { GATE(K210_SYSCTL_EN_PERI, 1) },
> +       [K210_CLK_FFT] = { GATE(K210_SYSCTL_EN_PERI, 4) },
> +       [K210_CLK_GPIO] = { GATE(K210_SYSCTL_EN_PERI, 5) },
> +       [K210_CLK_UART1] = { GATE(K210_SYSCTL_EN_PERI, 16) },
> +       [K210_CLK_UART2] = { GATE(K210_SYSCTL_EN_PERI, 17) },
> +       [K210_CLK_UART3] = { GATE(K210_SYSCTL_EN_PERI, 18) },
> +       [K210_CLK_FPIOA] = { GATE(K210_SYSCTL_EN_PERI, 20) },
> +       [K210_CLK_SHA] = { GATE(K210_SYSCTL_EN_PERI, 26) },
> +       [K210_CLK_AES] = { GATE(K210_SYSCTL_EN_PERI, 19) },
> +       [K210_CLK_OTP] = { GATE(K210_SYSCTL_EN_PERI, 27) },
> +       [K210_CLK_RTC] = { GATE(K210_SYSCTL_EN_PERI, 29) },
> +
> +       /* Gated divider clocks */
> +       [K210_CLK_SRAM0] = {
> +               GATE(K210_SYSCTL_EN_CENT, 1),
> +               DIV(K210_SYSCTL_THR0, 0, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_SRAM1] = {
> +               GATE(K210_SYSCTL_EN_CENT, 2),
> +               DIV(K210_SYSCTL_THR0, 4, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_ROM] = {
> +               GATE(K210_SYSCTL_EN_PERI, 0),
> +               DIV(K210_SYSCTL_THR0, 16, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_DVP] = {
> +               GATE(K210_SYSCTL_EN_PERI, 3),
> +               DIV(K210_SYSCTL_THR0, 12, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_APB0] = {
> +               GATE(K210_SYSCTL_EN_CENT, 3),
> +               DIV(K210_SYSCTL_SEL0, 3, 3, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_APB1] = {
> +               GATE(K210_SYSCTL_EN_CENT, 4),
> +               DIV(K210_SYSCTL_SEL0, 6, 3, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_APB2] = {
> +               GATE(K210_SYSCTL_EN_CENT, 5),
> +               DIV(K210_SYSCTL_SEL0, 9, 3, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_AI] = {
> +               GATE(K210_SYSCTL_EN_PERI, 2),
> +               DIV(K210_SYSCTL_THR0, 8, 4, DIV_ONE_BASED)
> +       },
> +       [K210_CLK_SPI0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 6),
> +               DIV(K210_SYSCTL_THR1, 0, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_SPI1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 7),
> +               DIV(K210_SYSCTL_THR1, 8, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_SPI2] = {
> +               GATE(K210_SYSCTL_EN_PERI, 8),
> +               DIV(K210_SYSCTL_THR1, 16, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2C0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 13),
> +               DIV(K210_SYSCTL_THR5, 8, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2C1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 14),
> +               DIV(K210_SYSCTL_THR5, 16, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2C2] = {
> +               GATE(K210_SYSCTL_EN_PERI, 15),
> +               DIV(K210_SYSCTL_THR5, 24, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_WDT0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 24),
> +               DIV(K210_SYSCTL_THR6, 0, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_WDT1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 25),
> +               DIV(K210_SYSCTL_THR6, 8, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 10),
> +               DIV(K210_SYSCTL_THR3, 0, 16, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 11),
> +               DIV(K210_SYSCTL_THR3, 16, 16, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S2] = {
> +               GATE(K210_SYSCTL_EN_PERI, 12),
> +               DIV(K210_SYSCTL_THR4, 0, 16, DIV_DOUBLE_ONE_BASED)
> +       },
> +
> +       /* Divider clocks, no gate, no mux */
> +       [K210_CLK_I2S0_M] = {
> +               DIV(K210_SYSCTL_THR4, 16, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S1_M] = {
> +               DIV(K210_SYSCTL_THR4, 24, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +       [K210_CLK_I2S2_M] = {
> +               DIV(K210_SYSCTL_THR4, 0, 8, DIV_DOUBLE_ONE_BASED)
> +       },
> +
> +       /* Muxed gated divider clocks */
> +       [K210_CLK_SPI3] = {
> +               GATE(K210_SYSCTL_EN_PERI, 9),
> +               DIV(K210_SYSCTL_THR1, 24, 8, DIV_DOUBLE_ONE_BASED),
> +               MUX(K210_SYSCTL_SEL0, 12)
> +       },
> +       [K210_CLK_TIMER0] = {
> +               GATE(K210_SYSCTL_EN_PERI, 21),
> +               DIV(K210_SYSCTL_THR2,  0, 8, DIV_DOUBLE_ONE_BASED),
> +               MUX(K210_SYSCTL_SEL0, 13)
> +       },
> +       [K210_CLK_TIMER1] = {
> +               GATE(K210_SYSCTL_EN_PERI, 22),
> +               DIV(K210_SYSCTL_THR2, 8, 8, DIV_DOUBLE_ONE_BASED),
> +               MUX(K210_SYSCTL_SEL0, 14)
> +       },
> +       [K210_CLK_TIMER2] = {
> +               GATE(K210_SYSCTL_EN_PERI, 23),
> +               DIV(K210_SYSCTL_THR2, 16, 8, DIV_DOUBLE_ONE_BASED),
> +               MUX(K210_SYSCTL_SEL0, 15)
> +       },
> +};
> +
> +/*
> + * PLL control register bits.
> + */
> +#define K210_PLL_CLKR          GENMASK(3, 0)
> +#define K210_PLL_CLKF          GENMASK(9, 4)
> +#define K210_PLL_CLKOD         GENMASK(13, 10)
> +#define K210_PLL_BWADJ         GENMASK(19, 14)
> +#define K210_PLL_RESET         (1 << 20)
> +#define K210_PLL_PWRD          (1 << 21)
> +#define K210_PLL_INTFB         (1 << 22)
> +#define K210_PLL_BYPASS                (1 << 23)
> +#define K210_PLL_TEST          (1 << 24)
> +#define K210_PLL_EN            (1 << 25)
> +#define K210_PLL_SEL           GENMASK(27, 26) /* PLL2 only */
> +
> +/*
> + * PLL lock register bits.
> + */
> +#define K210_PLL_LOCK          0
> +#define K210_PLL_CLEAR_SLIP    2
> +#define K210_PLL_TEST_OUT      3
> +
> +/*
> + * Clock selector register bits.
> + */
> +#define K210_ACLK_SEL          BIT(0)
> +#define K210_ACLK_DIV          GENMASK(2, 1)
> +
> +/*
> + * PLLs.
> + */
> +enum k210_pll_id {
> +       K210_PLL0, K210_PLL1, K210_PLL2, K210_PLL_NUM
> +};
> +
> +struct k210_pll {
> +enum k210_pll_id id;

Not sure what happened here but it's not tabbed.

> +       /* PLL setup register */
> +       void __iomem *reg;
> +
> +       /* Common lock register */
> +       void __iomem *lock;
> +
> +       /* Offset and width of lock bits */
> +       u8 lock_shift;
> +       u8 lock_width;
> +
> +       struct clk_hw hw;
> +};
> +#define to_k210_pll(hw)        container_of(hw, struct k210_pll, hw)
> +
> +struct k210_pll_cfg {
> +       /* PLL setup register offset */
> +       u32 reg;
> +
> +       /* Offset and width fo the lock bits */
> +       u8 lock_shift;
> +       u8 lock_width;
> +
> +       /* PLL setup initial factors */
> +       u32 r, f, od, bwadj;

Please have one line per struct member. I guess our kernel style is to
do that so we can quickly see how many members there are.

> +};
> +
> +/*
> + * PLL factors:
> + * By default, PLL0 runs at 780 MHz and PLL1 at 299 MHz.
> + * The first 2 sram banks depend on ACLK/CPU clock which is by default
> + * PLL0 rate divided by 2. Set PLL1 to 390 MHz so that the third sram
> + * bank has the same clock.
> + */
> +static struct k210_pll_cfg k210_plls_cfg[] = {
> +       { K210_SYSCTL_PLL0,  0, 2, 0, 59, 1, 59 }, /* 780 MHz */
> +       { K210_SYSCTL_PLL1,  8, 1, 0, 59, 3, 59 }, /* 390 MHz */
> +       { K210_SYSCTL_PLL2, 16, 1, 0, 22, 1, 22 }, /* 299 MHz */
> +};
> +
> +/*
> + * Clocks data.

This comment could be kernel-doc and be more helpful.

> + */
> +struct k210_clk {
> +       void __iomem                    *regs;
> +       spinlock_t                      clk_lock;
> +       struct k210_pll                 plls[K210_PLL_NUM];
> +       struct clk_hw                   aclk;
> +       struct clk_hw                   clks[K210_NUM_CLKS];
> +       struct clk_hw_onecell_data      *clk_data;
> +};
> +
> +static struct k210_clk *kcl;
> +
> +/*
> + * Set ACLK parent selector: 0 for IN0, 1 for PLL0.
> + */
> +static void k210_aclk_set_selector(u8 sel)
> +{
> +       u32 reg = readl(kcl->regs + K210_SYSCTL_SEL0);
> +
> +       if (sel)
> +               reg |= K210_ACLK_SEL;
> +       else
> +               reg &= K210_ACLK_SEL;
> +       writel(reg, kcl->regs + K210_SYSCTL_SEL0);
> +}
> +
> +static void k210_init_pll(struct k210_pll *pll, enum k210_pll_id id,
> +                         void __iomem *base)
> +{
> +       pll->id = id;
> +       pll->lock = base + K210_SYSCTL_PLL_LOCK;
> +       pll->reg = base + k210_plls_cfg[id].reg;
> +       pll->lock_shift = k210_plls_cfg[id].lock_shift;
> +       pll->lock_width = k210_plls_cfg[id].lock_width;
> +}
> +
> +static void k210_pll_wait_for_lock(struct k210_pll *pll)
> +{
> +       u32 reg, mask = GENMASK(pll->lock_width - 1, 0) << pll->lock_shift;

GENMASK should take the pll->lock_shift instead of shifting it after the
fact. That way we don't have to think about overflow.

> +
> +       while (true) {
> +               reg = readl(pll->lock);
> +               if ((reg & mask) == mask)
> +                       break;
> +
> +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
> +               writel(reg, pll->lock);

Is this readl_poll_timeout?

> +       }
> +}
> +
> +static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
> +{
> +       u32 reg = readl(pll->reg);
> +       u32 mask = K210_PLL_PWRD | K210_PLL_EN;
> +
> +       if (reg & K210_PLL_RESET)
> +               return false;
> +
> +       return (reg & mask) == mask;
> +}
> +
> +static void k210_pll_enable_hw(struct k210_pll *pll)
> +{
> +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
> +       unsigned long flags;
> +       u32 reg;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +
> +       if (k210_pll_hw_is_enabled(pll))
> +               goto unlock;
> +
> +       if (pll->id == K210_PLL0) {
> +               /* Re-parent aclk to IN0 to keep the CPUs running */
> +               k210_aclk_set_selector(0);
> +       }
> +
> +       /* Set factors */
> +       reg = readl(pll->reg);
> +       reg &= ~GENMASK(19, 0);
> +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
> +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
> +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
> +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
> +       reg |= K210_PLL_PWRD;
> +       writel(reg, pll->reg);
> +
> +       /* Ensure reset is low before asserting it */
> +       reg &= ~K210_PLL_RESET;
> +       writel(reg, pll->reg);
> +       reg |= K210_PLL_RESET;
> +       writel(reg, pll->reg);
> +       nop();
> +       nop();

Are these nops needed for some reason? Any comment to add here? It's
basically non-portable code and hopefully nothing is inserted into that
writel function that shouldn't be there.

> +       reg &= ~K210_PLL_RESET;
> +       writel(reg, pll->reg);
> +
> +       k210_pll_wait_for_lock(pll);
> +
> +       reg &= ~K210_PLL_BYPASS;
> +       reg |= K210_PLL_EN;
> +       writel(reg, pll->reg);
> +
> +       if (pll->id == K210_PLL0) {
> +               /* Re-parent aclk back to PLL0 */
> +               k210_aclk_set_selector(1);
> +       }
> +unlock:
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +}
> +
> +static void k210_pll_disable_hw(struct k210_pll *pll)
> +{
> +       unsigned long flags;
> +       u32 reg;
> +
> +       /*
> +        * Bypassing before powering off is important so child clocks don't stop
> +        * working. This is especially important for pll0, the indirect parent
> +        * of the cpu clock.
> +        */
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(pll->reg);
> +       reg |= K210_PLL_BYPASS;
> +       writel(reg, pll->reg);
> +
> +       reg &= ~K210_PLL_PWRD;
> +       reg &= ~K210_PLL_EN;
> +       writel(reg, pll->reg);
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +}
> +
> +static int k210_pll_enable(struct clk_hw *hw)
> +{
> +       k210_pll_enable_hw(to_k210_pll(hw));
> +
> +       return 0;
> +}
> +
> +static void k210_pll_disable(struct clk_hw *hw)
> +{
> +       k210_pll_disable_hw(to_k210_pll(hw));
> +}
> +
> +static int k210_pll_is_enabled(struct clk_hw *hw)
> +{
> +       return k210_pll_hw_is_enabled(to_k210_pll(hw));
> +}
> +
> +static int k210_pll_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       struct k210_pll *pll = to_k210_pll(hw);
> +       unsigned long flags;
> +       int ret = 0;
> +       u32 reg;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +
> +       switch (pll->id) {
> +       case K210_PLL0:
> +       case K210_PLL1:
> +               if (WARN_ON(index != 0))
> +                       ret = -EINVAL;
> +               break;
> +       case K210_PLL2:

Instead of a pll->id can we have two different clk ops?

> +               if (WARN_ON(index > 2)) {
> +                       ret = -EINVAL;
> +                       break;
> +               }
> +               reg = readl(pll->reg);
> +               reg &= ~K210_PLL_SEL;
> +               reg |= FIELD_PREP(K210_PLL_SEL, index);
> +               writel(reg, pll->reg);
> +               break;
> +       default:
> +               ret = -EINVAL;
> +               break;
> +       }
> +
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +
> +       return ret;
> +}
> +
> +static u8 k210_pll_get_parent(struct clk_hw *hw)
> +{
> +       struct k210_pll *pll = to_k210_pll(hw);
> +       u32 reg;
> +
> +       switch (pll->id) {
> +       case K210_PLL0:
> +       case K210_PLL1:
> +               return 0;
> +       case K210_PLL2:
> +               reg = readl(pll->reg);
> +               return FIELD_GET(K210_PLL_SEL, reg);
> +       default:
> +               return 0;
> +       }
> +}
> +
> +static unsigned long k210_pll_get_rate(struct clk_hw *hw,
> +                                      unsigned long parent_rate)
> +{
> +       struct k210_pll *pll = to_k210_pll(hw);
> +       u32 reg = readl(pll->reg);
> +       u32 r, f, od;
> +
> +       if (reg & K210_PLL_BYPASS)
> +               return parent_rate;
> +
> +       if (!(reg & K210_PLL_PWRD))
> +               return 0;
> +
> +       r = FIELD_GET(K210_PLL_CLKR, reg) + 1;
> +       f = FIELD_GET(K210_PLL_CLKF, reg) + 1;
> +       od = FIELD_GET(K210_PLL_CLKOD, reg) + 1;
> +
> +       return (u64)parent_rate * f / (r * od);
> +}
> +
> +static const struct clk_ops k210_pll_ops = {
> +       .enable         = k210_pll_enable,
> +       .disable        = k210_pll_disable,
> +       .is_enabled     = k210_pll_is_enabled,
> +       .set_parent     = k210_pll_set_parent,
> +       .get_parent     = k210_pll_get_parent,
> +       .recalc_rate    = k210_pll_get_rate,
> +};
> +
> +static const char *pll_parents[] = { NULL, "pll0", "pll1" };

This should get a k210 prefix as to not pollute the global namespace of
kernel symbols (of which there are so many!).

> +
> +static struct clk_hw *k210_register_pll(enum k210_pll_id id, const char *name,
> +                               const char **parent_names, int num_parents,
> +                               unsigned long flags)
> +{
> +       struct k210_pll *pll = &kcl->plls[id];
> +       struct clk_init_data init = {};
> +       int ret;
> +
> +       init.name = name;
> +       init.parent_names = parent_names;
> +       init.num_parents = num_parents;
> +       init.flags = flags;
> +       init.ops = &k210_pll_ops;
> +       pll->hw.init = &init;
> +
> +       ret = clk_hw_register(NULL, &pll->hw);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       return &pll->hw;
> +}
> +
> +static int k210_aclk_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       if (WARN_ON(index > 1))

Is this possible? What am I going to do as a user if this happens?

> +               return -EINVAL;
> +
> +       k210_aclk_set_selector(index);
> +
> +       return 0;
> +}
> +
> +static u8 k210_aclk_get_parent(struct clk_hw *hw)
> +{
> +       u32 sel = readl(kcl->regs + K210_SYSCTL_SEL0);
> +
> +       return (sel & K210_ACLK_SEL) ? 1 : 0;

Preferably write as

	u32 sel;

	sel = readl(kclk->regs + K210_SYSCTL_SEL0);
	sel &= K210_ACLK_SEL;

	return sel ? 1 : 0; 

> +}
> +
> +static unsigned long k210_aclk_get_rate(struct clk_hw *hw,
> +                                       unsigned long parent_rate)
> +{
> +       u32 reg = readl(kcl->regs + K210_SYSCTL_SEL0);
> +       unsigned int shift;
> +
> +       if (!(reg & 0x1))
> +               return parent_rate;
> +
> +       shift = FIELD_GET(K210_ACLK_DIV, reg);
> +
> +       return parent_rate / (2UL << shift);
> +}
> +
> +static const struct clk_ops k210_aclk_ops = {
> +       .set_parent     = k210_aclk_set_parent,
> +       .get_parent     = k210_aclk_get_parent,
> +       .recalc_rate    = k210_aclk_get_rate,
> +};
> +
> +static const char *aclk_parents[] = { NULL, "pll0" };
> +
> +static struct clk_hw *k210_register_aclk(void)
> +{
> +       struct clk_init_data init = {};
> +       int ret;
> +
> +       init.name = "aclk";
> +       init.parent_names = aclk_parents;
> +       init.num_parents = 2;
> +       init.flags = 0;

Remove? It's the default now that init = {}.

> +       init.ops = &k210_aclk_ops;
> +       kcl->aclk.init = &init;
> +
> +       ret = clk_hw_register(NULL, &kcl->aclk);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       return &kcl->aclk;
> +}
> +
> +#define to_k210_clk_id(hw)     ((unsigned int)((hw) - &kcl->clks[0]))
> +#define to_k210_clk_cfg(hw)    (&k210_clks[to_k210_clk_id(hw)])
> +
> +static u32 k210_clk_get_div_val(struct k210_clk_cfg *kclk)
> +{
> +       u32 reg = readl(kcl->regs + kclk->div_reg);
> +
> +       return (reg >> kclk->div_shift) & GENMASK(kclk->div_width - 1, 0);

Use FIELD_GET()?

> +}
> +
> +static unsigned long k210_clk_divider(struct k210_clk_cfg *kclk,
> +                                     u32 div_val)
> +{
> +       switch (kclk->div_type) {
> +       case DIV_ONE_BASED:
> +               return div_val + 1;
> +       case DIV_DOUBLE_ONE_BASED:
> +               return (div_val + 1) * 2;
> +       case DIV_POWER_OF_TWO:
> +               return 2UL << div_val;
> +       case DIV_NONE:
> +       default:
> +               return 0;
> +       }
> +}
> +
> +static int k210_clk_enable(struct clk_hw *hw)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long flags;
> +       u32 reg;
> +
> +       if (!kclk->gate_reg)
> +               return 0;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(kcl->regs + kclk->gate_reg);
> +       reg |= BIT(kclk->gate_bit);
> +       writel(reg, kcl->regs + kclk->gate_reg);
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +
> +       return 0;
> +}
> +
> +static void k210_clk_disable(struct clk_hw *hw)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long flags;
> +       u32 reg;
> +
> +       if (!kclk->gate_reg)
> +               return;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(kcl->regs + kclk->gate_reg);
> +       reg &= ~BIT(kclk->gate_bit);
> +       writel(reg, kcl->regs + kclk->gate_reg);
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +}
> +
> +static int k210_clk_is_enabled(struct clk_hw *hw)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +
> +       if (!kclk->gate_reg)
> +               return 1;
> +
> +       return readl(kcl->regs + kclk->gate_reg) & BIT(kclk->gate_bit);
> +}
> +
> +static int k210_clk_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long flags;
> +       u32 reg;
> +
> +       if (!kclk->mux_reg) {
> +               if (WARN_ON(index != 0))
> +                       return -EINVAL;
> +               return 0;
> +       }
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(kcl->regs + kclk->mux_reg);
> +       if (index)
> +               reg |= BIT(kclk->mux_bit);
> +       else
> +               reg &= ~BIT(kclk->mux_bit);
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +
> +       return 0;
> +}
> +
> +static u8 k210_clk_get_parent(struct clk_hw *hw)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long flags;
> +       u32 reg, idx;
> +
> +       if (!kclk->mux_reg)
> +               return 0;
> +
> +       spin_lock_irqsave(&kcl->clk_lock, flags);
> +       reg = readl(kcl->regs + kclk->mux_reg);
> +       idx = (reg & BIT(kclk->mux_bit)) ? 1 : 0;
> +       spin_unlock_irqrestore(&kcl->clk_lock, flags);
> +
> +       return idx;
> +}
> +
> +static unsigned long k210_clk_get_rate(struct clk_hw *hw,
> +                                      unsigned long parent_rate)
> +{
> +       struct k210_clk_cfg *kclk = to_k210_clk_cfg(hw);
> +       unsigned long divider;
> +
> +       if (!kclk->div_reg)
> +               return parent_rate;
> +
> +       divider = k210_clk_divider(kclk, k210_clk_get_div_val(kclk));
> +       if (WARN_ON(!divider))
> +               return 0;
> +
> +       return parent_rate / divider;
> +}
> +
> +static const struct clk_ops k210_clk_ops = {
> +       .enable         = k210_clk_enable,
> +       .is_enabled     = k210_clk_is_enabled,
> +       .disable        = k210_clk_disable,
> +       .set_parent     = k210_clk_set_parent,
> +       .get_parent     = k210_clk_get_parent,
> +       .recalc_rate    = k210_clk_get_rate,
> +};
> +
> +static const char *mux_parents[] = { NULL, "pll0" };
> +
> +static struct clk_hw *k210_register_clk(int id, const char *name,
> +                                       const char *parent, unsigned long flags)
> +{
> +       struct clk_init_data init = {};
> +       int ret;
> +
> +       init.name = name;
> +       if (parent) {
> +               init.parent_names = &parent;
> +               init.num_parents = 1;
> +       } else {
> +               init.parent_names = mux_parents;
> +               init.num_parents = 2;
> +       }
> +       init.flags = flags;
> +       init.ops = &k210_clk_ops;
> +       kcl->clks[id].init = &init;
> +
> +       ret = clk_hw_register(NULL, &kcl->clks[id]);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       return &kcl->clks[id];
> +}
> +
> +static void __init k210_clk_init(struct device_node *np)
> +{
> +       struct device_node *sysctl_np;
> +       struct clk *in0_clk;
> +       const char *in0;
> +       struct clk_hw **hws;
> +       int i, ret;
> +
> +       kcl = kzalloc(sizeof(*kcl), GFP_KERNEL);
> +       if (!kcl)
> +               return;
> +
> +       sysctl_np = of_find_compatible_node(NULL, NULL, "canaan,k210-sysctl");
> +       if (!sysctl_np || sysctl_np != np->parent)
> +               goto err;
> +
> +       kcl->regs = of_iomap(sysctl_np, 0);
> +       if (!kcl->regs)
> +               goto err;
> +
> +       kcl->clk_data = kzalloc(struct_size(kcl->clk_data, hws, K210_NUM_CLKS),
> +                               GFP_KERNEL);
> +       if (!kcl->clk_data)
> +               goto err;
> +
> +       for (i = 0; i < K210_PLL_NUM; i++)
> +               k210_init_pll(&kcl->plls[i], i, kcl->regs);
> +       spin_lock_init(&kcl->clk_lock);
> +       kcl->clk_data->num = K210_NUM_CLKS;
> +       hws = kcl->clk_data->hws;
> +       for (i = 1; i < K210_NUM_CLKS; i++)
> +               hws[i] = ERR_PTR(-EPROBE_DEFER);
> +
> +       /*
> +        * in0 is the system base fixed-rate 26MHz oscillator which
> +        * should already be defined by the device tree. If it is not,
> +        * create it here.

Are there old DTBs that don't have this? Sadface.

> +        */
> +       in0_clk = of_clk_get(np, 0);
> +       if (IS_ERR(in0_clk)) {
> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> +               hws[K210_CLK_IN0] =
> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> +                                                  0, K210_IN0_RATE);
> +       } else {
> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> +       }
> +       if (IS_ERR(hws[K210_CLK_IN0])) {
> +               pr_err("%pOFP: failed to get base oscillator\n", np);
> +               goto err;
> +       }
> +
> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> +       aclk_parents[0] = in0;
> +       pll_parents[0] = in0;
> +       mux_parents[0] = in0;

Can we use the new way of specifying clk parents so that we don't have
to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
the core can handl that all instead of this driver.

> +
> +       /* PLLs */
> +       hws[K210_CLK_PLL0] =
> +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
> +       hws[K210_CLK_PLL1] =
> +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
> +       hws[K210_CLK_PLL2] =
> +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
> +
> +       /* aclk: muxed of in0 and pll0_d, no gate */
> +       hws[K210_CLK_ACLK] = k210_register_aclk();
> +
> +       /*
> +        * Clocks with aclk as source: the CPU clock is obviously critical.
> +        * So is the CLINT clock as the scheduler clocksource.
> +        */
> +       hws[K210_CLK_CPU] =
> +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
> +       hws[K210_CLK_CLINT] =
> +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
> +                                            CLK_IS_CRITICAL, 1, 50);

Is anyone getting these clks? It's nice and all to model things in the
clk framework but if they never have a consumer then it is sort of
useless and just wastes memory and causes more overhead.

> +       hws[K210_CLK_DMA] =
> +               k210_register_clk(K210_CLK_DMA, "dma", "aclk", 0);
> +       hws[K210_CLK_FFT] =
> +               k210_register_clk(K210_CLK_FFT, "fft", "aclk", 0);
> +       hws[K210_CLK_ROM] =
> +               k210_register_clk(K210_CLK_ROM, "rom", "aclk", 0);
> +       hws[K210_CLK_DVP] =
> +               k210_register_clk(K210_CLK_DVP, "dvp", "aclk", 0);
> +       hws[K210_CLK_APB0] =
> +               k210_register_clk(K210_CLK_APB0, "apb0", "aclk", 0);
> +       hws[K210_CLK_APB1] =
> +               k210_register_clk(K210_CLK_APB1, "apb1", "aclk", 0);
> +       hws[K210_CLK_APB2] =
> +               k210_register_clk(K210_CLK_APB2, "apb2", "aclk", 0);
> +
> +       /*
> +        * There is no sram driver taking a ref on the sram banks clocks.
> +        * So make them critical so they are not disabled due to being unused
> +        * as seen by the clock infrastructure.
> +        */
> +       hws[K210_CLK_SRAM0] =
> +               k210_register_clk(K210_CLK_SRAM0,
> +                                 "sram0", "aclk", CLK_IS_CRITICAL);
> +       hws[K210_CLK_SRAM1] =
> +               k210_register_clk(K210_CLK_SRAM1,
> +                                 "sram1", "aclk", CLK_IS_CRITICAL);
> +
> +       /* Clocks with PLL0 as source */
> +       hws[K210_CLK_SPI0] =
> +               k210_register_clk(K210_CLK_SPI0, "spi0", "pll0", 0);
> +       hws[K210_CLK_SPI1] =
> +                k210_register_clk(K210_CLK_SPI1, "spi1", "pll0", 0);
> +       hws[K210_CLK_SPI2] =
> +                k210_register_clk(K210_CLK_SPI2, "spi2", "pll0", 0);
> +       hws[K210_CLK_I2C0] =
> +                k210_register_clk(K210_CLK_I2C0, "i2c0", "pll0", 0);
> +       hws[K210_CLK_I2C1] =
> +                k210_register_clk(K210_CLK_I2C1, "i2c1", "pll0", 0);
> +       hws[K210_CLK_I2C2] =
> +                k210_register_clk(K210_CLK_I2C2, "i2c2", "pll0", 0);
> +
> +       /*
> +        * Clocks with PLL1 as source: there is only the AI clock for the
> +        * (unused) KPU device. As this clock also drives the aisram bank
> +        * which is used as general memory, make it critical.
> +        */
> +        hws[K210_CLK_AI] =
> +                k210_register_clk(K210_CLK_AI, "ai", "pll1", CLK_IS_CRITICAL);
> +
> +       /* Clocks with PLL2 as source */
> +       hws[K210_CLK_I2S0] =
> +                k210_register_clk(K210_CLK_I2S0, "i2s0", "pll2", 0);
> +       hws[K210_CLK_I2S1] =
> +                k210_register_clk(K210_CLK_I2S1, "i2s1", "pll2", 0);
> +       hws[K210_CLK_I2S2] =
> +               k210_register_clk(K210_CLK_I2S2, "i2s2", "pll2", 0);
> +       hws[K210_CLK_I2S0_M] =
> +               k210_register_clk(K210_CLK_I2S0_M, "i2s0_m", "pll2", 0);
> +       hws[K210_CLK_I2S1_M] =
> +               k210_register_clk(K210_CLK_I2S1_M, "i2s1_m", "pll2", 0);
> +       hws[K210_CLK_I2S2_M] =
> +               k210_register_clk(K210_CLK_I2S2_M, "i2s2_m", "pll2", 0);
> +
> +       /* Clocks with IN0 as source */
> +       hws[K210_CLK_WDT0] =
> +               k210_register_clk(K210_CLK_WDT0, "wdt0", in0, 0);
> +       hws[K210_CLK_WDT1] =
> +                k210_register_clk(K210_CLK_WDT1, "wdt1", in0, 0);
> +       hws[K210_CLK_RTC] =
> +                k210_register_clk(K210_CLK_RTC, "rtc", in0, 0);
> +
> +       /* Clocks with APB0 as source */
> +       hws[K210_CLK_GPIO] =
> +               k210_register_clk(K210_CLK_GPIO, "gpio", "apb0", 0);
> +       hws[K210_CLK_UART1] =
> +               k210_register_clk(K210_CLK_UART1, "uart1", "apb0", 0);
> +       hws[K210_CLK_UART2] =
> +               k210_register_clk(K210_CLK_UART2, "uart2", "apb0", 0);
> +       hws[K210_CLK_UART3] =
> +               k210_register_clk(K210_CLK_UART3, "uart3", "apb0", 0);
> +       hws[K210_CLK_FPIOA] =
> +               k210_register_clk(K210_CLK_FPIOA, "fpioa", "apb0", 0);
> +       hws[K210_CLK_SHA] =
> +               k210_register_clk(K210_CLK_SHA, "sha", "apb0", 0);
> +
> +       /* Clocks with APB1 as source */
> +       hws[K210_CLK_AES] =
> +                k210_register_clk(K210_CLK_AES, "aes", "apb1", 0);
> +       hws[K210_CLK_OTP] =
> +                k210_register_clk(K210_CLK_OTP, "otp", "apb1", 0);
> +
> +       /* Muxed clocks with in0/pll0 as source */
> +       hws[K210_CLK_SPI3] =
> +               k210_register_clk(K210_CLK_SPI3, "spi3", NULL, 0);
> +       hws[K210_CLK_TIMER0] =
> +               k210_register_clk(K210_CLK_TIMER0, "timer0", NULL, 0);
> +       hws[K210_CLK_TIMER1] =
> +               k210_register_clk(K210_CLK_TIMER1, "timer1", NULL, 0);
> +       hws[K210_CLK_TIMER2] =
> +               k210_register_clk(K210_CLK_TIMER2, "timer2", NULL, 0);
> +
> +       for (i = 0; i < K210_NUM_CLKS; i++) {
> +               if (IS_ERR(hws[i])) {
> +                       pr_err("%pOFP: register clock %d failed %ld\n",
> +                              np, i, PTR_ERR(hws[i]));
> +                       goto err;
> +               }
> +       }
> +
> +       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
> +       if (ret)
> +               pr_err("%pOFP: add clock provider failed %d\n", np, ret);
> +       else
> +               pr_info("%pOFP: CPU running at %lu MHz\n",

Is this important? Is there a CPUfreq driver that runs and tells us the
boot CPU frequency instead? Doesn't feel like we care in the clk driver
about this.

> +                       np, clk_hw_get_rate(hws[K210_CLK_CPU]) / 1000000);
> +
> +       return;
> +err:
> +       pr_err("%pOFP: clock initialization failed\n", np);
> +       iounmap(kcl->regs);
> +       kfree(kcl->clk_data);
> +       kfree(kcl);
> +       kcl = NULL;

Why?

> +}
> +
> +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);

Is this needed or can this just be a plain platform driver? If something
is needed early for a clocksource or clockevent then the driver can be
split to register those few clks early from this hook and then register
the rest later when the platform device probes. That's what
CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
is incorrect.

> +
> +/*
> + * Enable PLL1 to be able to use the AI SRAM.
> + */
> +void __init k210_clk_early_init(void __iomem *regs)
> +{
> +       struct k210_pll pll1;
> +
> +       /* Make sure aclk selector is set to PLL0 */
> +       k210_aclk_set_selector(1);
> +
> +       /* Startup PLL1 to enable the aisram bank for general memory use */
> +       k210_init_pll(&pll1, K210_PLL1, regs);
> +       k210_pll_enable_hw(&pll1);
> +}
> diff --git a/include/soc/canaan/k210-sysctl.h b/include/soc/canaan/k210-sysctl.h
> new file mode 100644
> index 000000000000..50b21484f7c7
> --- /dev/null
> +++ b/include/soc/canaan/k210-sysctl.h
[...]
> +#define K210_SYSCTL_DMA_SEL0   0x64 /* DMA handshake selector 0 */
> +#define K210_SYSCTL_DMA_SEL1   0x68 /* DMA handshake selector 1 */
> +#define K210_SYSCTL_POWER_SEL  0x6C /* IO Power Mode Select controller */
> +
> +void __init k210_clk_early_init(void __iomem *regs);

We don't need __init in header files. Please remove the marking.

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-05  6:19     ` Stephen Boyd
@ 2020-12-05  7:43       ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-05  7:43 UTC (permalink / raw)
  To: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk
  Cc: seanga2

Hi Stephen,

Thank you for the review. I will address all your comments.
I just have a few questions below.

On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> Quoting Damien Le Moal (2020-12-01 19:24:50)
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 2daa6ee673f7..3da9a7a02f61 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
> >  F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
> >  F:     drivers/net/ieee802154/ca8210.c
> >  
> > 
> > 
> > 
> > +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
> > +M:     Damien Le Moal <damien.lemoal@wdc.com>
> > +L:     linux-riscv@lists.infradead.org
> > +L:     linux-clk@vger.kernel.org (clock driver)
> 
> Is this needed? I think we cover all of drivers/clk/ and bindings/clock
> already.

I was not sure about that so I added the entry. Will remove it.

> 
> > +S:     Maintained
> > +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> > +F:     drivers/clk/clk-k210.c
> > diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> > index 88ac0d1a5da4..f2f9633087d1 100644
> > --- a/arch/riscv/Kconfig.socs
> > +++ b/arch/riscv/Kconfig.socs
> > @@ -29,6 +29,8 @@ config SOC_CANAAN
> >         select SERIAL_SIFIVE if TTY
> >         select SERIAL_SIFIVE_CONSOLE if TTY
> >         select SIFIVE_PLIC
> > +       select SOC_K210_SYSCTL
> > +       select CLK_K210
> 
> Any reason to do this vs. just make it the default?

I do not understand here... Just selecting the drivers needed for the SoC here.
Is there any other way of doing this ?

[...]
> > +
> > +       while (true) {
> > +               reg = readl(pll->lock);
> > +               if ((reg & mask) == mask)
> > +                       break;
> > +
> > +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
> > +               writel(reg, pll->lock);
> 
> Is this readl_poll_timeout?

Oh. Yes, it is. I did not know about this function. Will change the code to use
it.

> 
> > +       }
> > +}
> > +
> > +static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
> > +{
> > +       u32 reg = readl(pll->reg);
> > +       u32 mask = K210_PLL_PWRD | K210_PLL_EN;
> > +
> > +       if (reg & K210_PLL_RESET)
> > +               return false;
> > +
> > +       return (reg & mask) == mask;
> > +}
> > +
> > +static void k210_pll_enable_hw(struct k210_pll *pll)
> > +{
> > +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
> > +       unsigned long flags;
> > +       u32 reg;
> > +
> > +       spin_lock_irqsave(&kcl->clk_lock, flags);
> > +
> > +       if (k210_pll_hw_is_enabled(pll))
> > +               goto unlock;
> > +
> > +       if (pll->id == K210_PLL0) {
> > +               /* Re-parent aclk to IN0 to keep the CPUs running */
> > +               k210_aclk_set_selector(0);
> > +       }
> > +
> > +       /* Set factors */
> > +       reg = readl(pll->reg);
> > +       reg &= ~GENMASK(19, 0);
> > +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
> > +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
> > +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
> > +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
> > +       reg |= K210_PLL_PWRD;
> > +       writel(reg, pll->reg);
> > +
> > +       /* Ensure reset is low before asserting it */
> > +       reg &= ~K210_PLL_RESET;
> > +       writel(reg, pll->reg);
> > +       reg |= K210_PLL_RESET;
> > +       writel(reg, pll->reg);
> > +       nop();
> > +       nop();
> 
> Are these nops needed for some reason? Any comment to add here? It's
> basically non-portable code and hopefully nothing is inserted into that
> writel function that shouldn't be there.

No clue... They are "magic" nops that are present in the K210 SDK from
Kendryte. I copied that, but do not actually know if they are really needed. I
am working without any specs for the hardware: the Kendryte SDK is my main
source of information here. I will try to remove them or just replace this with
a delay() call a nd see what happens.

[...]
> > +static int k210_aclk_set_parent(struct clk_hw *hw, u8 index)
> > +{
> > +       if (WARN_ON(index > 1))
> 
> Is this possible? What am I going to do as a user if this happens?

No, it is not possible. Will remove this. I could put a BUG_ON(), but I am not
a fan this extreme.

[...]
> > +       /*
> > +        * in0 is the system base fixed-rate 26MHz oscillator which
> > +        * should already be defined by the device tree. If it is not,
> > +        * create it here.
> 
> Are there old DTBs that don't have this? Sadface.

No, not any old DTB. Will remove that.

> 
> > +        */
> > +       in0_clk = of_clk_get(np, 0);
> > +       if (IS_ERR(in0_clk)) {
> > +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> > +               hws[K210_CLK_IN0] =
> > +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> > +                                                  0, K210_IN0_RATE);
> > +       } else {
> > +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> > +       }
> > +       if (IS_ERR(hws[K210_CLK_IN0])) {
> > +               pr_err("%pOFP: failed to get base oscillator\n", np);
> > +               goto err;
> > +       }
> > +
> > +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> > +       aclk_parents[0] = in0;
> > +       pll_parents[0] = in0;
> > +       mux_parents[0] = in0;
> 
> Can we use the new way of specifying clk parents so that we don't have
> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
> the core can handl that all instead of this driver.

Not sure what new way of specifying the parent you are referring to here.
clk_hw_set_parent() ?

> 
> > +
> > +       /* PLLs */
> > +       hws[K210_CLK_PLL0] =
> > +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
> > +       hws[K210_CLK_PLL1] =
> > +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
> > +       hws[K210_CLK_PLL2] =
> > +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
> > +
> > +       /* aclk: muxed of in0 and pll0_d, no gate */
> > +       hws[K210_CLK_ACLK] = k210_register_aclk();
> > +
> > +       /*
> > +        * Clocks with aclk as source: the CPU clock is obviously critical.
> > +        * So is the CLINT clock as the scheduler clocksource.
> > +        */
> > +       hws[K210_CLK_CPU] =
> > +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
> > +       hws[K210_CLK_CLINT] =
> > +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
> > +                                            CLK_IS_CRITICAL, 1, 50);
> 
> Is anyone getting these clks? It's nice and all to model things in the
> clk framework but if they never have a consumer then it is sort of
> useless and just wastes memory and causes more overhead.

The CPU and SRAM clocks do not have any consumer, so I could remove them (just
enable the HW but not represent them as clocks in the driver). There is no
direct consumer of ACLK but it is the parent of multiple clocks, including the
SRAM clocks. So it needs to be represented as a clock and kept alive even if
all the peripheral drivers needing it are disabled. Otherwise, the system just
stops (SRAM accesses hang).

[...]
> > +       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
> > +       if (ret)
> > +               pr_err("%pOFP: add clock provider failed %d\n", np, ret);
> > +       else
> > +               pr_info("%pOFP: CPU running at %lu MHz\n",
> 
> Is this important? Is there a CPUfreq driver that runs and tells us the
> boot CPU frequency instead? Doesn't feel like we care in the clk driver
> about this.

There is no CPU freq driver that gives this frequency that I know of. That is
why I added the message since the driver basically just comes up using the
default HW settings for the SoC. CPU freq speed can be changed though by
increasing the PLL freq. Just not supporting this for now as it is tricky to
do: the SRAM clocks depend on aclk and PLL1 and if these are not the same
value, the system hangs (most likely because we end up with the sram banks
running at different speeds, which the SoC cache does not like). 

[...]
> > +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
> 
> Is this needed or can this just be a plain platform driver? If something
> is needed early for a clocksource or clockevent then the driver can be
> split to register those few clks early from this hook and then register
> the rest later when the platform device probes. That's what
> CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
> is incorrect.

I think I can clean this up: aclk and clint clocks are needed early but others
can likely be deferred. Will fix this up.

Thanks !

-- 
Damien Le Moal
Western Digital

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-05  7:43       ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-05  7:43 UTC (permalink / raw)
  To: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk
  Cc: seanga2

Hi Stephen,

Thank you for the review. I will address all your comments.
I just have a few questions below.

On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> Quoting Damien Le Moal (2020-12-01 19:24:50)
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 2daa6ee673f7..3da9a7a02f61 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
> >  F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
> >  F:     drivers/net/ieee802154/ca8210.c
> >  
> > 
> > 
> > 
> > +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
> > +M:     Damien Le Moal <damien.lemoal@wdc.com>
> > +L:     linux-riscv@lists.infradead.org
> > +L:     linux-clk@vger.kernel.org (clock driver)
> 
> Is this needed? I think we cover all of drivers/clk/ and bindings/clock
> already.

I was not sure about that so I added the entry. Will remove it.

> 
> > +S:     Maintained
> > +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> > +F:     drivers/clk/clk-k210.c
> > diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> > index 88ac0d1a5da4..f2f9633087d1 100644
> > --- a/arch/riscv/Kconfig.socs
> > +++ b/arch/riscv/Kconfig.socs
> > @@ -29,6 +29,8 @@ config SOC_CANAAN
> >         select SERIAL_SIFIVE if TTY
> >         select SERIAL_SIFIVE_CONSOLE if TTY
> >         select SIFIVE_PLIC
> > +       select SOC_K210_SYSCTL
> > +       select CLK_K210
> 
> Any reason to do this vs. just make it the default?

I do not understand here... Just selecting the drivers needed for the SoC here.
Is there any other way of doing this ?

[...]
> > +
> > +       while (true) {
> > +               reg = readl(pll->lock);
> > +               if ((reg & mask) == mask)
> > +                       break;
> > +
> > +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
> > +               writel(reg, pll->lock);
> 
> Is this readl_poll_timeout?

Oh. Yes, it is. I did not know about this function. Will change the code to use
it.

> 
> > +       }
> > +}
> > +
> > +static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
> > +{
> > +       u32 reg = readl(pll->reg);
> > +       u32 mask = K210_PLL_PWRD | K210_PLL_EN;
> > +
> > +       if (reg & K210_PLL_RESET)
> > +               return false;
> > +
> > +       return (reg & mask) == mask;
> > +}
> > +
> > +static void k210_pll_enable_hw(struct k210_pll *pll)
> > +{
> > +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
> > +       unsigned long flags;
> > +       u32 reg;
> > +
> > +       spin_lock_irqsave(&kcl->clk_lock, flags);
> > +
> > +       if (k210_pll_hw_is_enabled(pll))
> > +               goto unlock;
> > +
> > +       if (pll->id == K210_PLL0) {
> > +               /* Re-parent aclk to IN0 to keep the CPUs running */
> > +               k210_aclk_set_selector(0);
> > +       }
> > +
> > +       /* Set factors */
> > +       reg = readl(pll->reg);
> > +       reg &= ~GENMASK(19, 0);
> > +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
> > +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
> > +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
> > +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
> > +       reg |= K210_PLL_PWRD;
> > +       writel(reg, pll->reg);
> > +
> > +       /* Ensure reset is low before asserting it */
> > +       reg &= ~K210_PLL_RESET;
> > +       writel(reg, pll->reg);
> > +       reg |= K210_PLL_RESET;
> > +       writel(reg, pll->reg);
> > +       nop();
> > +       nop();
> 
> Are these nops needed for some reason? Any comment to add here? It's
> basically non-portable code and hopefully nothing is inserted into that
> writel function that shouldn't be there.

No clue... They are "magic" nops that are present in the K210 SDK from
Kendryte. I copied that, but do not actually know if they are really needed. I
am working without any specs for the hardware: the Kendryte SDK is my main
source of information here. I will try to remove them or just replace this with
a delay() call a nd see what happens.

[...]
> > +static int k210_aclk_set_parent(struct clk_hw *hw, u8 index)
> > +{
> > +       if (WARN_ON(index > 1))
> 
> Is this possible? What am I going to do as a user if this happens?

No, it is not possible. Will remove this. I could put a BUG_ON(), but I am not
a fan this extreme.

[...]
> > +       /*
> > +        * in0 is the system base fixed-rate 26MHz oscillator which
> > +        * should already be defined by the device tree. If it is not,
> > +        * create it here.
> 
> Are there old DTBs that don't have this? Sadface.

No, not any old DTB. Will remove that.

> 
> > +        */
> > +       in0_clk = of_clk_get(np, 0);
> > +       if (IS_ERR(in0_clk)) {
> > +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> > +               hws[K210_CLK_IN0] =
> > +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> > +                                                  0, K210_IN0_RATE);
> > +       } else {
> > +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> > +       }
> > +       if (IS_ERR(hws[K210_CLK_IN0])) {
> > +               pr_err("%pOFP: failed to get base oscillator\n", np);
> > +               goto err;
> > +       }
> > +
> > +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> > +       aclk_parents[0] = in0;
> > +       pll_parents[0] = in0;
> > +       mux_parents[0] = in0;
> 
> Can we use the new way of specifying clk parents so that we don't have
> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
> the core can handl that all instead of this driver.

Not sure what new way of specifying the parent you are referring to here.
clk_hw_set_parent() ?

> 
> > +
> > +       /* PLLs */
> > +       hws[K210_CLK_PLL0] =
> > +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
> > +       hws[K210_CLK_PLL1] =
> > +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
> > +       hws[K210_CLK_PLL2] =
> > +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
> > +
> > +       /* aclk: muxed of in0 and pll0_d, no gate */
> > +       hws[K210_CLK_ACLK] = k210_register_aclk();
> > +
> > +       /*
> > +        * Clocks with aclk as source: the CPU clock is obviously critical.
> > +        * So is the CLINT clock as the scheduler clocksource.
> > +        */
> > +       hws[K210_CLK_CPU] =
> > +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
> > +       hws[K210_CLK_CLINT] =
> > +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
> > +                                            CLK_IS_CRITICAL, 1, 50);
> 
> Is anyone getting these clks? It's nice and all to model things in the
> clk framework but if they never have a consumer then it is sort of
> useless and just wastes memory and causes more overhead.

The CPU and SRAM clocks do not have any consumer, so I could remove them (just
enable the HW but not represent them as clocks in the driver). There is no
direct consumer of ACLK but it is the parent of multiple clocks, including the
SRAM clocks. So it needs to be represented as a clock and kept alive even if
all the peripheral drivers needing it are disabled. Otherwise, the system just
stops (SRAM accesses hang).

[...]
> > +       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
> > +       if (ret)
> > +               pr_err("%pOFP: add clock provider failed %d\n", np, ret);
> > +       else
> > +               pr_info("%pOFP: CPU running at %lu MHz\n",
> 
> Is this important? Is there a CPUfreq driver that runs and tells us the
> boot CPU frequency instead? Doesn't feel like we care in the clk driver
> about this.

There is no CPU freq driver that gives this frequency that I know of. That is
why I added the message since the driver basically just comes up using the
default HW settings for the SoC. CPU freq speed can be changed though by
increasing the PLL freq. Just not supporting this for now as it is tricky to
do: the SRAM clocks depend on aclk and PLL1 and if these are not the same
value, the system hangs (most likely because we end up with the sram banks
running at different speeds, which the SoC cache does not like). 

[...]
> > +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
> 
> Is this needed or can this just be a plain platform driver? If something
> is needed early for a clocksource or clockevent then the driver can be
> split to register those few clks early from this hook and then register
> the rest later when the platform device probes. That's what
> CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
> is incorrect.

I think I can clean this up: aclk and clint clocks are needed early but others
can likely be deferred. Will fix this up.

Thanks !

-- 
Damien Le Moal
Western Digital
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-05  7:43       ` Damien Le Moal
@ 2020-12-05 13:43         ` Sean Anderson
  -1 siblings, 0 replies; 78+ messages in thread
From: Sean Anderson @ 2020-12-05 13:43 UTC (permalink / raw)
  To: Damien Le Moal, linux-riscv, devicetree, linux-gpio, palmer,
	sboyd, linus.walleij, p.zabel, robh+dt, linux-clk

On 12/5/20 2:43 AM, Damien Le Moal wrote:
> Hi Stephen,
> 
> Thank you for the review. I will address all your comments.
> I just have a few questions below.
> 
> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>> Quoting Damien Le Moal (2020-12-01 19:24:50)
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 2daa6ee673f7..3da9a7a02f61 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
>>>   F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
>>>   F:     drivers/net/ieee802154/ca8210.c
>>>   
>>>
>>>
>>>
>>> +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
>>> +M:     Damien Le Moal <damien.lemoal@wdc.com>
>>> +L:     linux-riscv@lists.infradead.org
>>> +L:     linux-clk@vger.kernel.org (clock driver)
>>
>> Is this needed? I think we cover all of drivers/clk/ and bindings/clock
>> already.
> 
> I was not sure about that so I added the entry. Will remove it.
> 
>>
>>> +S:     Maintained
>>> +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
>>> +F:     drivers/clk/clk-k210.c
>>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
>>> index 88ac0d1a5da4..f2f9633087d1 100644
>>> --- a/arch/riscv/Kconfig.socs
>>> +++ b/arch/riscv/Kconfig.socs
>>> @@ -29,6 +29,8 @@ config SOC_CANAAN
>>>          select SERIAL_SIFIVE if TTY
>>>          select SERIAL_SIFIVE_CONSOLE if TTY
>>>          select SIFIVE_PLIC
>>> +       select SOC_K210_SYSCTL
>>> +       select CLK_K210
>>
>> Any reason to do this vs. just make it the default?
> 
> I do not understand here... Just selecting the drivers needed for the SoC here.
> Is there any other way of doing this ?
> 
> [...]
>>> +
>>> +       while (true) {
>>> +               reg = readl(pll->lock);
>>> +               if ((reg & mask) == mask)
>>> +                       break;
>>> +
>>> +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
>>> +               writel(reg, pll->lock);
>>
>> Is this readl_poll_timeout?
> 
> Oh. Yes, it is. I did not know about this function. Will change the code to use
> it.

FWIW the timeout could be incorrect since we might be configuring a
parent of ACLK. And realistically the only way this fails is if a user
has edited this file and put in invalid PLL parameters. I don't think
you gain much by adding a timeout.

>>
>>> +       }
>>> +}
>>> +
>>> +static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
>>> +{
>>> +       u32 reg = readl(pll->reg);
>>> +       u32 mask = K210_PLL_PWRD | K210_PLL_EN;
>>> +
>>> +       if (reg & K210_PLL_RESET)
>>> +               return false;
>>> +
>>> +       return (reg & mask) == mask;
>>> +}
>>> +
>>> +static void k210_pll_enable_hw(struct k210_pll *pll)
>>> +{
>>> +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
>>> +       unsigned long flags;
>>> +       u32 reg;
>>> +
>>> +       spin_lock_irqsave(&kcl->clk_lock, flags);
>>> +
>>> +       if (k210_pll_hw_is_enabled(pll))
>>> +               goto unlock;
>>> +
>>> +       if (pll->id == K210_PLL0) {
>>> +               /* Re-parent aclk to IN0 to keep the CPUs running */
>>> +               k210_aclk_set_selector(0);
>>> +       }
>>> +
>>> +       /* Set factors */
>>> +       reg = readl(pll->reg);
>>> +       reg &= ~GENMASK(19, 0);
>>> +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
>>> +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
>>> +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
>>> +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
>>> +       reg |= K210_PLL_PWRD;
>>> +       writel(reg, pll->reg);
>>> +
>>> +       /* Ensure reset is low before asserting it */
>>> +       reg &= ~K210_PLL_RESET;
>>> +       writel(reg, pll->reg);
>>> +       reg |= K210_PLL_RESET;
>>> +       writel(reg, pll->reg);
>>> +       nop();
>>> +       nop();
>>
>> Are these nops needed for some reason? Any comment to add here? It's
>> basically non-portable code and hopefully nothing is inserted into that
>> writel function that shouldn't be there.
> 
> No clue... They are "magic" nops that are present in the K210 SDK from
> Kendryte. I copied that, but do not actually know if they are really needed. I
> am working without any specs for the hardware: the Kendryte SDK is my main
> source of information here. I will try to remove them or just replace this with
> a delay() call a nd see what happens.

Basically any delay should work as long as it takes more than 2
instructions ;) Of course, anything longer than that just delays startup
for no reason.

--Sean

> 
> [...]
>>> +static int k210_aclk_set_parent(struct clk_hw *hw, u8 index)
>>> +{
>>> +       if (WARN_ON(index > 1))
>>
>> Is this possible? What am I going to do as a user if this happens?
> 
> No, it is not possible. Will remove this. I could put a BUG_ON(), but I am not
> a fan this extreme.
> 
> [...]
>>> +       /*
>>> +        * in0 is the system base fixed-rate 26MHz oscillator which
>>> +        * should already be defined by the device tree. If it is not,
>>> +        * create it here.
>>
>> Are there old DTBs that don't have this? Sadface.
> 
> No, not any old DTB. Will remove that.
> 
>>
>>> +        */
>>> +       in0_clk = of_clk_get(np, 0);
>>> +       if (IS_ERR(in0_clk)) {
>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>> +               hws[K210_CLK_IN0] =
>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>> +                                                  0, K210_IN0_RATE);
>>> +       } else {
>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>> +       }
>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>> +               goto err;
>>> +       }
>>> +
>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>> +       aclk_parents[0] = in0;
>>> +       pll_parents[0] = in0;
>>> +       mux_parents[0] = in0;
>>
>> Can we use the new way of specifying clk parents so that we don't have
>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>> the core can handl that all instead of this driver.
> 
> Not sure what new way of specifying the parent you are referring to here.
> clk_hw_set_parent() ?
> 
>>
>>> +
>>> +       /* PLLs */
>>> +       hws[K210_CLK_PLL0] =
>>> +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
>>> +       hws[K210_CLK_PLL1] =
>>> +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
>>> +       hws[K210_CLK_PLL2] =
>>> +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
>>> +
>>> +       /* aclk: muxed of in0 and pll0_d, no gate */
>>> +       hws[K210_CLK_ACLK] = k210_register_aclk();
>>> +
>>> +       /*
>>> +        * Clocks with aclk as source: the CPU clock is obviously critical.
>>> +        * So is the CLINT clock as the scheduler clocksource.
>>> +        */
>>> +       hws[K210_CLK_CPU] =
>>> +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
>>> +       hws[K210_CLK_CLINT] =
>>> +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
>>> +                                            CLK_IS_CRITICAL, 1, 50);
>>
>> Is anyone getting these clks? It's nice and all to model things in the
>> clk framework but if they never have a consumer then it is sort of
>> useless and just wastes memory and causes more overhead.
> 
> The CPU and SRAM clocks do not have any consumer, so I could remove them (just
> enable the HW but not represent them as clocks in the driver). There is no
> direct consumer of ACLK but it is the parent of multiple clocks, including the
> SRAM clocks. So it needs to be represented as a clock and kept alive even if
> all the peripheral drivers needing it are disabled. Otherwise, the system just
> stops (SRAM accesses hang).
> 
> [...]
>>> +       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
>>> +       if (ret)
>>> +               pr_err("%pOFP: add clock provider failed %d\n", np, ret);
>>> +       else
>>> +               pr_info("%pOFP: CPU running at %lu MHz\n",
>>
>> Is this important? Is there a CPUfreq driver that runs and tells us the
>> boot CPU frequency instead? Doesn't feel like we care in the clk driver
>> about this.
> 
> There is no CPU freq driver that gives this frequency that I know of. That is
> why I added the message since the driver basically just comes up using the
> default HW settings for the SoC. CPU freq speed can be changed though by
> increasing the PLL freq. Just not supporting this for now as it is tricky to
> do: the SRAM clocks depend on aclk and PLL1 and if these are not the same
> value, the system hangs (most likely because we end up with the sram banks
> running at different speeds, which the SoC cache does not like).
> 
> [...]
>>> +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
>>
>> Is this needed or can this just be a plain platform driver? If something
>> is needed early for a clocksource or clockevent then the driver can be
>> split to register those few clks early from this hook and then register
>> the rest later when the platform device probes. That's what
>> CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
>> is incorrect.
> 
> I think I can clean this up: aclk and clint clocks are needed early but others
> can likely be deferred. Will fix this up.
> 
> Thanks !
> 


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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-05 13:43         ` Sean Anderson
  0 siblings, 0 replies; 78+ messages in thread
From: Sean Anderson @ 2020-12-05 13:43 UTC (permalink / raw)
  To: Damien Le Moal, linux-riscv, devicetree, linux-gpio, palmer,
	sboyd, linus.walleij, p.zabel, robh+dt, linux-clk

On 12/5/20 2:43 AM, Damien Le Moal wrote:
> Hi Stephen,
> 
> Thank you for the review. I will address all your comments.
> I just have a few questions below.
> 
> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>> Quoting Damien Le Moal (2020-12-01 19:24:50)
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 2daa6ee673f7..3da9a7a02f61 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
>>>   F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
>>>   F:     drivers/net/ieee802154/ca8210.c
>>>   
>>>
>>>
>>>
>>> +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
>>> +M:     Damien Le Moal <damien.lemoal@wdc.com>
>>> +L:     linux-riscv@lists.infradead.org
>>> +L:     linux-clk@vger.kernel.org (clock driver)
>>
>> Is this needed? I think we cover all of drivers/clk/ and bindings/clock
>> already.
> 
> I was not sure about that so I added the entry. Will remove it.
> 
>>
>>> +S:     Maintained
>>> +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
>>> +F:     drivers/clk/clk-k210.c
>>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
>>> index 88ac0d1a5da4..f2f9633087d1 100644
>>> --- a/arch/riscv/Kconfig.socs
>>> +++ b/arch/riscv/Kconfig.socs
>>> @@ -29,6 +29,8 @@ config SOC_CANAAN
>>>          select SERIAL_SIFIVE if TTY
>>>          select SERIAL_SIFIVE_CONSOLE if TTY
>>>          select SIFIVE_PLIC
>>> +       select SOC_K210_SYSCTL
>>> +       select CLK_K210
>>
>> Any reason to do this vs. just make it the default?
> 
> I do not understand here... Just selecting the drivers needed for the SoC here.
> Is there any other way of doing this ?
> 
> [...]
>>> +
>>> +       while (true) {
>>> +               reg = readl(pll->lock);
>>> +               if ((reg & mask) == mask)
>>> +                       break;
>>> +
>>> +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
>>> +               writel(reg, pll->lock);
>>
>> Is this readl_poll_timeout?
> 
> Oh. Yes, it is. I did not know about this function. Will change the code to use
> it.

FWIW the timeout could be incorrect since we might be configuring a
parent of ACLK. And realistically the only way this fails is if a user
has edited this file and put in invalid PLL parameters. I don't think
you gain much by adding a timeout.

>>
>>> +       }
>>> +}
>>> +
>>> +static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
>>> +{
>>> +       u32 reg = readl(pll->reg);
>>> +       u32 mask = K210_PLL_PWRD | K210_PLL_EN;
>>> +
>>> +       if (reg & K210_PLL_RESET)
>>> +               return false;
>>> +
>>> +       return (reg & mask) == mask;
>>> +}
>>> +
>>> +static void k210_pll_enable_hw(struct k210_pll *pll)
>>> +{
>>> +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
>>> +       unsigned long flags;
>>> +       u32 reg;
>>> +
>>> +       spin_lock_irqsave(&kcl->clk_lock, flags);
>>> +
>>> +       if (k210_pll_hw_is_enabled(pll))
>>> +               goto unlock;
>>> +
>>> +       if (pll->id == K210_PLL0) {
>>> +               /* Re-parent aclk to IN0 to keep the CPUs running */
>>> +               k210_aclk_set_selector(0);
>>> +       }
>>> +
>>> +       /* Set factors */
>>> +       reg = readl(pll->reg);
>>> +       reg &= ~GENMASK(19, 0);
>>> +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
>>> +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
>>> +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
>>> +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
>>> +       reg |= K210_PLL_PWRD;
>>> +       writel(reg, pll->reg);
>>> +
>>> +       /* Ensure reset is low before asserting it */
>>> +       reg &= ~K210_PLL_RESET;
>>> +       writel(reg, pll->reg);
>>> +       reg |= K210_PLL_RESET;
>>> +       writel(reg, pll->reg);
>>> +       nop();
>>> +       nop();
>>
>> Are these nops needed for some reason? Any comment to add here? It's
>> basically non-portable code and hopefully nothing is inserted into that
>> writel function that shouldn't be there.
> 
> No clue... They are "magic" nops that are present in the K210 SDK from
> Kendryte. I copied that, but do not actually know if they are really needed. I
> am working without any specs for the hardware: the Kendryte SDK is my main
> source of information here. I will try to remove them or just replace this with
> a delay() call a nd see what happens.

Basically any delay should work as long as it takes more than 2
instructions ;) Of course, anything longer than that just delays startup
for no reason.

--Sean

> 
> [...]
>>> +static int k210_aclk_set_parent(struct clk_hw *hw, u8 index)
>>> +{
>>> +       if (WARN_ON(index > 1))
>>
>> Is this possible? What am I going to do as a user if this happens?
> 
> No, it is not possible. Will remove this. I could put a BUG_ON(), but I am not
> a fan this extreme.
> 
> [...]
>>> +       /*
>>> +        * in0 is the system base fixed-rate 26MHz oscillator which
>>> +        * should already be defined by the device tree. If it is not,
>>> +        * create it here.
>>
>> Are there old DTBs that don't have this? Sadface.
> 
> No, not any old DTB. Will remove that.
> 
>>
>>> +        */
>>> +       in0_clk = of_clk_get(np, 0);
>>> +       if (IS_ERR(in0_clk)) {
>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>> +               hws[K210_CLK_IN0] =
>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>> +                                                  0, K210_IN0_RATE);
>>> +       } else {
>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>> +       }
>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>> +               goto err;
>>> +       }
>>> +
>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>> +       aclk_parents[0] = in0;
>>> +       pll_parents[0] = in0;
>>> +       mux_parents[0] = in0;
>>
>> Can we use the new way of specifying clk parents so that we don't have
>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>> the core can handl that all instead of this driver.
> 
> Not sure what new way of specifying the parent you are referring to here.
> clk_hw_set_parent() ?
> 
>>
>>> +
>>> +       /* PLLs */
>>> +       hws[K210_CLK_PLL0] =
>>> +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
>>> +       hws[K210_CLK_PLL1] =
>>> +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
>>> +       hws[K210_CLK_PLL2] =
>>> +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
>>> +
>>> +       /* aclk: muxed of in0 and pll0_d, no gate */
>>> +       hws[K210_CLK_ACLK] = k210_register_aclk();
>>> +
>>> +       /*
>>> +        * Clocks with aclk as source: the CPU clock is obviously critical.
>>> +        * So is the CLINT clock as the scheduler clocksource.
>>> +        */
>>> +       hws[K210_CLK_CPU] =
>>> +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
>>> +       hws[K210_CLK_CLINT] =
>>> +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
>>> +                                            CLK_IS_CRITICAL, 1, 50);
>>
>> Is anyone getting these clks? It's nice and all to model things in the
>> clk framework but if they never have a consumer then it is sort of
>> useless and just wastes memory and causes more overhead.
> 
> The CPU and SRAM clocks do not have any consumer, so I could remove them (just
> enable the HW but not represent them as clocks in the driver). There is no
> direct consumer of ACLK but it is the parent of multiple clocks, including the
> SRAM clocks. So it needs to be represented as a clock and kept alive even if
> all the peripheral drivers needing it are disabled. Otherwise, the system just
> stops (SRAM accesses hang).
> 
> [...]
>>> +       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
>>> +       if (ret)
>>> +               pr_err("%pOFP: add clock provider failed %d\n", np, ret);
>>> +       else
>>> +               pr_info("%pOFP: CPU running at %lu MHz\n",
>>
>> Is this important? Is there a CPUfreq driver that runs and tells us the
>> boot CPU frequency instead? Doesn't feel like we care in the clk driver
>> about this.
> 
> There is no CPU freq driver that gives this frequency that I know of. That is
> why I added the message since the driver basically just comes up using the
> default HW settings for the SoC. CPU freq speed can be changed though by
> increasing the PLL freq. Just not supporting this for now as it is tricky to
> do: the SRAM clocks depend on aclk and PLL1 and if these are not the same
> value, the system hangs (most likely because we end up with the sram banks
> running at different speeds, which the SoC cache does not like).
> 
> [...]
>>> +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
>>
>> Is this needed or can this just be a plain platform driver? If something
>> is needed early for a clocksource or clockevent then the driver can be
>> split to register those few clks early from this hook and then register
>> the rest later when the platform device probes. That's what
>> CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
>> is incorrect.
> 
> I think I can clean this up: aclk and clint clocks are needed early but others
> can likely be deferred. Will fix this up.
> 
> Thanks !
> 


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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-05 13:43         ` Sean Anderson
@ 2020-12-05 14:13           ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-05 14:13 UTC (permalink / raw)
  To: linux-riscv, devicetree, linux-gpio, linus.walleij, palmer,
	seanga2, p.zabel, sboyd, robh+dt, linux-clk

On Sat, 2020-12-05 at 08:43 -0500, Sean Anderson wrote:
> On 12/5/20 2:43 AM, Damien Le Moal wrote:
> > Hi Stephen,
> > 
> > Thank you for the review. I will address all your comments.
> > I just have a few questions below.
> > 
> > On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> > > Quoting Damien Le Moal (2020-12-01 19:24:50)
> > > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > > index 2daa6ee673f7..3da9a7a02f61 100644
> > > > --- a/MAINTAINERS
> > > > +++ b/MAINTAINERS
> > > > @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
> > > >   F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
> > > >   F:     drivers/net/ieee802154/ca8210.c
> > > >   
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
> > > > +M:     Damien Le Moal <damien.lemoal@wdc.com>
> > > > +L:     linux-riscv@lists.infradead.org
> > > > +L:     linux-clk@vger.kernel.org (clock driver)
> > > 
> > > Is this needed? I think we cover all of drivers/clk/ and bindings/clock
> > > already.
> > 
> > I was not sure about that so I added the entry. Will remove it.
> > 
> > > 
> > > > +S:     Maintained
> > > > +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> > > > +F:     drivers/clk/clk-k210.c
> > > > diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> > > > index 88ac0d1a5da4..f2f9633087d1 100644
> > > > --- a/arch/riscv/Kconfig.socs
> > > > +++ b/arch/riscv/Kconfig.socs
> > > > @@ -29,6 +29,8 @@ config SOC_CANAAN
> > > >          select SERIAL_SIFIVE if TTY
> > > >          select SERIAL_SIFIVE_CONSOLE if TTY
> > > >          select SIFIVE_PLIC
> > > > +       select SOC_K210_SYSCTL
> > > > +       select CLK_K210
> > > 
> > > Any reason to do this vs. just make it the default?
> > 
> > I do not understand here... Just selecting the drivers needed for the SoC here.
> > Is there any other way of doing this ?
> > 
> > [...]
> > > > +
> > > > +       while (true) {
> > > > +               reg = readl(pll->lock);
> > > > +               if ((reg & mask) == mask)
> > > > +                       break;
> > > > +
> > > > +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
> > > > +               writel(reg, pll->lock);
> > > 
> > > Is this readl_poll_timeout?
> > 
> > Oh. Yes, it is. I did not know about this function. Will change the code to use
> > it.
> 
> FWIW the timeout could be incorrect since we might be configuring a
> parent of ACLK. And realistically the only way this fails is if a user
> has edited this file and put in invalid PLL parameters. I don't think
> you gain much by adding a timeout.

readl_poll_timeout() allows a timeout of 0 for "no timeout". It is not easy to
use this macro due to the stop condition interface, which is not through a
callback. This makes the code very ugly to get the writel() call added in the
stop condition for each iteration of the poll loop. So I left the code as is.

> 
> > > 
> > > > +       }
> > > > +}
> > > > +
> > > > +static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
> > > > +{
> > > > +       u32 reg = readl(pll->reg);
> > > > +       u32 mask = K210_PLL_PWRD | K210_PLL_EN;
> > > > +
> > > > +       if (reg & K210_PLL_RESET)
> > > > +               return false;
> > > > +
> > > > +       return (reg & mask) == mask;
> > > > +}
> > > > +
> > > > +static void k210_pll_enable_hw(struct k210_pll *pll)
> > > > +{
> > > > +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
> > > > +       unsigned long flags;
> > > > +       u32 reg;
> > > > +
> > > > +       spin_lock_irqsave(&kcl->clk_lock, flags);
> > > > +
> > > > +       if (k210_pll_hw_is_enabled(pll))
> > > > +               goto unlock;
> > > > +
> > > > +       if (pll->id == K210_PLL0) {
> > > > +               /* Re-parent aclk to IN0 to keep the CPUs running */
> > > > +               k210_aclk_set_selector(0);
> > > > +       }
> > > > +
> > > > +       /* Set factors */
> > > > +       reg = readl(pll->reg);
> > > > +       reg &= ~GENMASK(19, 0);
> > > > +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
> > > > +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
> > > > +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
> > > > +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
> > > > +       reg |= K210_PLL_PWRD;
> > > > +       writel(reg, pll->reg);
> > > > +
> > > > +       /* Ensure reset is low before asserting it */
> > > > +       reg &= ~K210_PLL_RESET;
> > > > +       writel(reg, pll->reg);
> > > > +       reg |= K210_PLL_RESET;
> > > > +       writel(reg, pll->reg);
> > > > +       nop();
> > > > +       nop();
> > > 
> > > Are these nops needed for some reason? Any comment to add here? It's
> > > basically non-portable code and hopefully nothing is inserted into that
> > > writel function that shouldn't be there.
> > 
> > No clue... They are "magic" nops that are present in the K210 SDK from
> > Kendryte. I copied that, but do not actually know if they are really needed. I
> > am working without any specs for the hardware: the Kendryte SDK is my main
> > source of information here. I will try to remove them or just replace this with
> > a delay() call a nd see what happens.
> 
> Basically any delay should work as long as it takes more than 2
> instructions ;) Of course, anything longer than that just delays startup
> for no reason.

Removing the nop() does work. Not sure if that is solid though.
Any other xxdelay() call fails, including __delay() (CPU cycles). I guess
because at this early stage, there is no information yet on the CPU
frequency/timers and k210_clk_early_init() hangs. So I think I will keep the
nop(). This driver being only for this SoC, I do not think it is a big issue in
terms of portability, for now at least.


-- 
Damien Le Moal
Western Digital

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-05 14:13           ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-05 14:13 UTC (permalink / raw)
  To: linux-riscv, devicetree, linux-gpio, linus.walleij, palmer,
	seanga2, p.zabel, sboyd, robh+dt, linux-clk

On Sat, 2020-12-05 at 08:43 -0500, Sean Anderson wrote:
> On 12/5/20 2:43 AM, Damien Le Moal wrote:
> > Hi Stephen,
> > 
> > Thank you for the review. I will address all your comments.
> > I just have a few questions below.
> > 
> > On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> > > Quoting Damien Le Moal (2020-12-01 19:24:50)
> > > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > > index 2daa6ee673f7..3da9a7a02f61 100644
> > > > --- a/MAINTAINERS
> > > > +++ b/MAINTAINERS
> > > > @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
> > > >   F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
> > > >   F:     drivers/net/ieee802154/ca8210.c
> > > >   
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
> > > > +M:     Damien Le Moal <damien.lemoal@wdc.com>
> > > > +L:     linux-riscv@lists.infradead.org
> > > > +L:     linux-clk@vger.kernel.org (clock driver)
> > > 
> > > Is this needed? I think we cover all of drivers/clk/ and bindings/clock
> > > already.
> > 
> > I was not sure about that so I added the entry. Will remove it.
> > 
> > > 
> > > > +S:     Maintained
> > > > +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> > > > +F:     drivers/clk/clk-k210.c
> > > > diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> > > > index 88ac0d1a5da4..f2f9633087d1 100644
> > > > --- a/arch/riscv/Kconfig.socs
> > > > +++ b/arch/riscv/Kconfig.socs
> > > > @@ -29,6 +29,8 @@ config SOC_CANAAN
> > > >          select SERIAL_SIFIVE if TTY
> > > >          select SERIAL_SIFIVE_CONSOLE if TTY
> > > >          select SIFIVE_PLIC
> > > > +       select SOC_K210_SYSCTL
> > > > +       select CLK_K210
> > > 
> > > Any reason to do this vs. just make it the default?
> > 
> > I do not understand here... Just selecting the drivers needed for the SoC here.
> > Is there any other way of doing this ?
> > 
> > [...]
> > > > +
> > > > +       while (true) {
> > > > +               reg = readl(pll->lock);
> > > > +               if ((reg & mask) == mask)
> > > > +                       break;
> > > > +
> > > > +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
> > > > +               writel(reg, pll->lock);
> > > 
> > > Is this readl_poll_timeout?
> > 
> > Oh. Yes, it is. I did not know about this function. Will change the code to use
> > it.
> 
> FWIW the timeout could be incorrect since we might be configuring a
> parent of ACLK. And realistically the only way this fails is if a user
> has edited this file and put in invalid PLL parameters. I don't think
> you gain much by adding a timeout.

readl_poll_timeout() allows a timeout of 0 for "no timeout". It is not easy to
use this macro due to the stop condition interface, which is not through a
callback. This makes the code very ugly to get the writel() call added in the
stop condition for each iteration of the poll loop. So I left the code as is.

> 
> > > 
> > > > +       }
> > > > +}
> > > > +
> > > > +static bool k210_pll_hw_is_enabled(struct k210_pll *pll)
> > > > +{
> > > > +       u32 reg = readl(pll->reg);
> > > > +       u32 mask = K210_PLL_PWRD | K210_PLL_EN;
> > > > +
> > > > +       if (reg & K210_PLL_RESET)
> > > > +               return false;
> > > > +
> > > > +       return (reg & mask) == mask;
> > > > +}
> > > > +
> > > > +static void k210_pll_enable_hw(struct k210_pll *pll)
> > > > +{
> > > > +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
> > > > +       unsigned long flags;
> > > > +       u32 reg;
> > > > +
> > > > +       spin_lock_irqsave(&kcl->clk_lock, flags);
> > > > +
> > > > +       if (k210_pll_hw_is_enabled(pll))
> > > > +               goto unlock;
> > > > +
> > > > +       if (pll->id == K210_PLL0) {
> > > > +               /* Re-parent aclk to IN0 to keep the CPUs running */
> > > > +               k210_aclk_set_selector(0);
> > > > +       }
> > > > +
> > > > +       /* Set factors */
> > > > +       reg = readl(pll->reg);
> > > > +       reg &= ~GENMASK(19, 0);
> > > > +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
> > > > +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
> > > > +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
> > > > +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
> > > > +       reg |= K210_PLL_PWRD;
> > > > +       writel(reg, pll->reg);
> > > > +
> > > > +       /* Ensure reset is low before asserting it */
> > > > +       reg &= ~K210_PLL_RESET;
> > > > +       writel(reg, pll->reg);
> > > > +       reg |= K210_PLL_RESET;
> > > > +       writel(reg, pll->reg);
> > > > +       nop();
> > > > +       nop();
> > > 
> > > Are these nops needed for some reason? Any comment to add here? It's
> > > basically non-portable code and hopefully nothing is inserted into that
> > > writel function that shouldn't be there.
> > 
> > No clue... They are "magic" nops that are present in the K210 SDK from
> > Kendryte. I copied that, but do not actually know if they are really needed. I
> > am working without any specs for the hardware: the Kendryte SDK is my main
> > source of information here. I will try to remove them or just replace this with
> > a delay() call a nd see what happens.
> 
> Basically any delay should work as long as it takes more than 2
> instructions ;) Of course, anything longer than that just delays startup
> for no reason.

Removing the nop() does work. Not sure if that is solid though.
Any other xxdelay() call fails, including __delay() (CPU cycles). I guess
because at this early stage, there is no information yet on the CPU
frequency/timers and k210_clk_early_init() hangs. So I think I will keep the
nop(). This driver being only for this SoC, I do not think it is a big issue in
terms of portability, for now at least.


-- 
Damien Le Moal
Western Digital
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-05  6:19     ` Stephen Boyd
@ 2020-12-07  3:50       ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-07  3:50 UTC (permalink / raw)
  To: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk
  Cc: seanga2

Hi Stephen,

I prepared a v5 series addressing your comments (and other comments).
I will post that later today after some more tests.

Below are some comments on how I addressed some of your remarks.

On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> > +S:     Maintained
> > +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> > +F:     drivers/clk/clk-k210.c
> > diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> > index 88ac0d1a5da4..f2f9633087d1 100644
> > --- a/arch/riscv/Kconfig.socs
> > +++ b/arch/riscv/Kconfig.socs
> > @@ -29,6 +29,8 @@ config SOC_CANAAN
> >         select SERIAL_SIFIVE if TTY
> >         select SERIAL_SIFIVE_CONSOLE if TTY
> >         select SIFIVE_PLIC
> > +       select SOC_K210_SYSCTL
> > +       select CLK_K210
> 
> Any reason to do this vs. just make it the default?

I understood what you meant and added the change.

> > diff --git a/drivers/clk/clk-k210.c b/drivers/clk/clk-k210.c
> > new file mode 100644
> > index 000000000000..95d830a38911
> > --- /dev/null
> > +++ b/drivers/clk/clk-k210.c
> > @@ -0,0 +1,959 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
> > + * Copyright (c) 2019 Western Digital Corporation or its affiliates.
> > + */
> > +#define pr_fmt(fmt)     "k210-clk: " fmt
> > +
> > +#include <linux/io.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/of.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/of_address.h>
> > +#include <linux/clk.h>
> 
> Preferably this include is dropped.

Fixed (see comment below about "in0" handling).

> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> 
> Is this used? Hopefully no.

Removed it, it was not needed.

> > +
> > +       while (true) {
> > +               reg = readl(pll->lock);
> > +               if ((reg & mask) == mask)
> > +                       break;
> > +
> > +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
> > +               writel(reg, pll->lock);
> 
> Is this readl_poll_timeout?

As mentioned in a previous email, using readl_poll_timeout() make the code
harder since for each poll loop the CLEAR SLIP bit needs to be set. So I kept
this as is.

> > +static void k210_pll_enable_hw(struct k210_pll *pll)
> > +{
> > +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
> > +       unsigned long flags;
> > +       u32 reg;
> > +
> > +       spin_lock_irqsave(&kcl->clk_lock, flags);
> > +
> > +       if (k210_pll_hw_is_enabled(pll))
> > +               goto unlock;
> > +
> > +       if (pll->id == K210_PLL0) {
> > +               /* Re-parent aclk to IN0 to keep the CPUs running */
> > +               k210_aclk_set_selector(0);
> > +       }
> > +
> > +       /* Set factors */
> > +       reg = readl(pll->reg);
> > +       reg &= ~GENMASK(19, 0);
> > +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
> > +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
> > +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
> > +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
> > +       reg |= K210_PLL_PWRD;
> > +       writel(reg, pll->reg);
> > +
> > +       /* Ensure reset is low before asserting it */
> > +       reg &= ~K210_PLL_RESET;
> > +       writel(reg, pll->reg);
> > +       reg |= K210_PLL_RESET;
> > +       writel(reg, pll->reg);
> > +       nop();
> > +       nop();
> 
> Are these nops needed for some reason? Any comment to add here? It's
> basically non-portable code and hopefully nothing is inserted into that
> writel function that shouldn't be there.

I kept this as is since this function is called from k210_clk_early_init() (SoC
early initialization, before the DTB is parsed). From that context, delay()
functions cannot be used. Since this driver is very specific to this RISC-V
SoC, I do not think there is any portability issue.

> > +static u32 k210_clk_get_div_val(struct k210_clk_cfg *kclk)
> > +{
> > +       u32 reg = readl(kcl->regs + kclk->div_reg);
> > +
> > +       return (reg >> kclk->div_shift) & GENMASK(kclk->div_width - 1, 0);
> 
> Use FIELD_GET()?

Unfortunately, FIELD_GET() requires a mask that is a constant, which is not the
case here.

> > +       in0_clk = of_clk_get(np, 0);
> > +       if (IS_ERR(in0_clk)) {
> > +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> > +               hws[K210_CLK_IN0] =
> > +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> > +                                                  0, K210_IN0_RATE);
> > +       } else {
> > +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> > +       }
> > +       if (IS_ERR(hws[K210_CLK_IN0])) {
> > +               pr_err("%pOFP: failed to get base oscillator\n", np);
> > +               goto err;
> > +       }
> > +
> > +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> > +       aclk_parents[0] = in0;
> > +       pll_parents[0] = in0;
> > +       mux_parents[0] = in0;
> 
> Can we use the new way of specifying clk parents so that we don't have
> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
> the core can handl that all instead of this driver.

I removed all this by adding:

clock-output-names = "in0";

to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
the parents clock names arrays do not need run-time update.

> 
> > +
> > +       /* PLLs */
> > +       hws[K210_CLK_PLL0] =
> > +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
> > +       hws[K210_CLK_PLL1] =
> > +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
> > +       hws[K210_CLK_PLL2] =
> > +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
> > +
> > +       /* aclk: muxed of in0 and pll0_d, no gate */
> > +       hws[K210_CLK_ACLK] = k210_register_aclk();
> > +
> > +       /*
> > +        * Clocks with aclk as source: the CPU clock is obviously critical.
> > +        * So is the CLINT clock as the scheduler clocksource.
> > +        */
> > +       hws[K210_CLK_CPU] =
> > +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
> > +       hws[K210_CLK_CLINT] =
> > +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
> > +                                            CLK_IS_CRITICAL, 1, 50);
> 
> Is anyone getting these clks? It's nice and all to model things in the
> clk framework but if they never have a consumer then it is sort of
> useless and just wastes memory and causes more overhead.

I dropped the CLINT clock as it is not needed by the clint driver and a clock
property is not documented for it. I kept the CPU clock as it is referenced by
the uarths (serial console) driver.
I also removed IN0, the PLLs and ACLK from the clock data array since these are
not referenced in the device tree.

> > +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
> 
> Is this needed or can this just be a plain platform driver? If something
> is needed early for a clocksource or clockevent then the driver can be
> split to register those few clks early from this hook and then register
> the rest later when the platform device probes. That's what
> CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
> is incorrect.

I tried to split the driver into the early init and platform driver parts but
there is a circular dependency with the sysctl driver: sysctl defines the k210-
clk node (for the regmap) but sysctl has a reference to its advanced power bus
clock too. This dependencies cannot be resolved elegantly. So I changed the
driver declaration to use CLK_OF_DECLARE() instead of CLK_OF_DECLARE_DRIVER().

Thanks !

-- 
Damien Le Moal
Western Digital

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-07  3:50       ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-07  3:50 UTC (permalink / raw)
  To: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk
  Cc: seanga2

Hi Stephen,

I prepared a v5 series addressing your comments (and other comments).
I will post that later today after some more tests.

Below are some comments on how I addressed some of your remarks.

On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> > +S:     Maintained
> > +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
> > +F:     drivers/clk/clk-k210.c
> > diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
> > index 88ac0d1a5da4..f2f9633087d1 100644
> > --- a/arch/riscv/Kconfig.socs
> > +++ b/arch/riscv/Kconfig.socs
> > @@ -29,6 +29,8 @@ config SOC_CANAAN
> >         select SERIAL_SIFIVE if TTY
> >         select SERIAL_SIFIVE_CONSOLE if TTY
> >         select SIFIVE_PLIC
> > +       select SOC_K210_SYSCTL
> > +       select CLK_K210
> 
> Any reason to do this vs. just make it the default?

I understood what you meant and added the change.

> > diff --git a/drivers/clk/clk-k210.c b/drivers/clk/clk-k210.c
> > new file mode 100644
> > index 000000000000..95d830a38911
> > --- /dev/null
> > +++ b/drivers/clk/clk-k210.c
> > @@ -0,0 +1,959 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
> > + * Copyright (c) 2019 Western Digital Corporation or its affiliates.
> > + */
> > +#define pr_fmt(fmt)     "k210-clk: " fmt
> > +
> > +#include <linux/io.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/of.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/of_address.h>
> > +#include <linux/clk.h>
> 
> Preferably this include is dropped.

Fixed (see comment below about "in0" handling).

> > +#include <linux/clk-provider.h>
> > +#include <linux/clkdev.h>
> 
> Is this used? Hopefully no.

Removed it, it was not needed.

> > +
> > +       while (true) {
> > +               reg = readl(pll->lock);
> > +               if ((reg & mask) == mask)
> > +                       break;
> > +
> > +               reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP);
> > +               writel(reg, pll->lock);
> 
> Is this readl_poll_timeout?

As mentioned in a previous email, using readl_poll_timeout() make the code
harder since for each poll loop the CLEAR SLIP bit needs to be set. So I kept
this as is.

> > +static void k210_pll_enable_hw(struct k210_pll *pll)
> > +{
> > +       struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id];
> > +       unsigned long flags;
> > +       u32 reg;
> > +
> > +       spin_lock_irqsave(&kcl->clk_lock, flags);
> > +
> > +       if (k210_pll_hw_is_enabled(pll))
> > +               goto unlock;
> > +
> > +       if (pll->id == K210_PLL0) {
> > +               /* Re-parent aclk to IN0 to keep the CPUs running */
> > +               k210_aclk_set_selector(0);
> > +       }
> > +
> > +       /* Set factors */
> > +       reg = readl(pll->reg);
> > +       reg &= ~GENMASK(19, 0);
> > +       reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r);
> > +       reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f);
> > +       reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od);
> > +       reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj);
> > +       reg |= K210_PLL_PWRD;
> > +       writel(reg, pll->reg);
> > +
> > +       /* Ensure reset is low before asserting it */
> > +       reg &= ~K210_PLL_RESET;
> > +       writel(reg, pll->reg);
> > +       reg |= K210_PLL_RESET;
> > +       writel(reg, pll->reg);
> > +       nop();
> > +       nop();
> 
> Are these nops needed for some reason? Any comment to add here? It's
> basically non-portable code and hopefully nothing is inserted into that
> writel function that shouldn't be there.

I kept this as is since this function is called from k210_clk_early_init() (SoC
early initialization, before the DTB is parsed). From that context, delay()
functions cannot be used. Since this driver is very specific to this RISC-V
SoC, I do not think there is any portability issue.

> > +static u32 k210_clk_get_div_val(struct k210_clk_cfg *kclk)
> > +{
> > +       u32 reg = readl(kcl->regs + kclk->div_reg);
> > +
> > +       return (reg >> kclk->div_shift) & GENMASK(kclk->div_width - 1, 0);
> 
> Use FIELD_GET()?

Unfortunately, FIELD_GET() requires a mask that is a constant, which is not the
case here.

> > +       in0_clk = of_clk_get(np, 0);
> > +       if (IS_ERR(in0_clk)) {
> > +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> > +               hws[K210_CLK_IN0] =
> > +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> > +                                                  0, K210_IN0_RATE);
> > +       } else {
> > +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> > +       }
> > +       if (IS_ERR(hws[K210_CLK_IN0])) {
> > +               pr_err("%pOFP: failed to get base oscillator\n", np);
> > +               goto err;
> > +       }
> > +
> > +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> > +       aclk_parents[0] = in0;
> > +       pll_parents[0] = in0;
> > +       mux_parents[0] = in0;
> 
> Can we use the new way of specifying clk parents so that we don't have
> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
> the core can handl that all instead of this driver.

I removed all this by adding:

clock-output-names = "in0";

to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
the parents clock names arrays do not need run-time update.

> 
> > +
> > +       /* PLLs */
> > +       hws[K210_CLK_PLL0] =
> > +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
> > +       hws[K210_CLK_PLL1] =
> > +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
> > +       hws[K210_CLK_PLL2] =
> > +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
> > +
> > +       /* aclk: muxed of in0 and pll0_d, no gate */
> > +       hws[K210_CLK_ACLK] = k210_register_aclk();
> > +
> > +       /*
> > +        * Clocks with aclk as source: the CPU clock is obviously critical.
> > +        * So is the CLINT clock as the scheduler clocksource.
> > +        */
> > +       hws[K210_CLK_CPU] =
> > +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
> > +       hws[K210_CLK_CLINT] =
> > +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
> > +                                            CLK_IS_CRITICAL, 1, 50);
> 
> Is anyone getting these clks? It's nice and all to model things in the
> clk framework but if they never have a consumer then it is sort of
> useless and just wastes memory and causes more overhead.

I dropped the CLINT clock as it is not needed by the clint driver and a clock
property is not documented for it. I kept the CPU clock as it is referenced by
the uarths (serial console) driver.
I also removed IN0, the PLLs and ACLK from the clock data array since these are
not referenced in the device tree.

> > +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
> 
> Is this needed or can this just be a plain platform driver? If something
> is needed early for a clocksource or clockevent then the driver can be
> split to register those few clks early from this hook and then register
> the rest later when the platform device probes. That's what
> CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
> is incorrect.

I tried to split the driver into the early init and platform driver parts but
there is a circular dependency with the sysctl driver: sysctl defines the k210-
clk node (for the regmap) but sysctl has a reference to its advanced power bus
clock too. This dependencies cannot be resolved elegantly. So I changed the
driver declaration to use CLK_OF_DECLARE() instead of CLK_OF_DECLARE_DRIVER().

Thanks !

-- 
Damien Le Moal
Western Digital
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-07  3:50       ` Damien Le Moal
@ 2020-12-07  8:43         ` Geert Uytterhoeven
  -1 siblings, 0 replies; 78+ messages in thread
From: Geert Uytterhoeven @ 2020-12-07  8:43 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk, seanga2

Hi Damien,

On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
> I prepared a v5 series addressing your comments (and other comments).
> I will post that later today after some more tests.

Thanks, already looking at k210-sysctl-v18...

> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> > > --- /dev/null
> > > +++ b/drivers/clk/clk-k210.c

> > > +       in0_clk = of_clk_get(np, 0);
> > > +       if (IS_ERR(in0_clk)) {
> > > +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> > > +               hws[K210_CLK_IN0] =
> > > +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> > > +                                                  0, K210_IN0_RATE);
> > > +       } else {
> > > +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> > > +       }
> > > +       if (IS_ERR(hws[K210_CLK_IN0])) {
> > > +               pr_err("%pOFP: failed to get base oscillator\n", np);
> > > +               goto err;
> > > +       }
> > > +
> > > +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> > > +       aclk_parents[0] = in0;
> > > +       pll_parents[0] = in0;
> > > +       mux_parents[0] = in0;
> >
> > Can we use the new way of specifying clk parents so that we don't have
> > to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
> > the core can handl that all instead of this driver.
>
> I removed all this by adding:
>
> clock-output-names = "in0";
>
> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
> the parents clock names arrays do not need run-time update.

"clock-output-names" is deprecated for clocks with a single output:
the clock name will be taken from the node name.
However, relying on a clock name like this is fragile.
Instead, your driver should use the phandle from the clocks property,
using of_clk_get_by_name() or of_clk_get().

Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?

Gr{oetje,eeting}s,

                        Geert

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

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-07  8:43         ` Geert Uytterhoeven
  0 siblings, 0 replies; 78+ messages in thread
From: Geert Uytterhoeven @ 2020-12-07  8:43 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: devicetree, sboyd, linus.walleij, seanga2, linux-gpio, robh+dt,
	palmer, p.zabel, linux-riscv, linux-clk

Hi Damien,

On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
> I prepared a v5 series addressing your comments (and other comments).
> I will post that later today after some more tests.

Thanks, already looking at k210-sysctl-v18...

> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> > > --- /dev/null
> > > +++ b/drivers/clk/clk-k210.c

> > > +       in0_clk = of_clk_get(np, 0);
> > > +       if (IS_ERR(in0_clk)) {
> > > +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> > > +               hws[K210_CLK_IN0] =
> > > +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> > > +                                                  0, K210_IN0_RATE);
> > > +       } else {
> > > +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> > > +       }
> > > +       if (IS_ERR(hws[K210_CLK_IN0])) {
> > > +               pr_err("%pOFP: failed to get base oscillator\n", np);
> > > +               goto err;
> > > +       }
> > > +
> > > +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> > > +       aclk_parents[0] = in0;
> > > +       pll_parents[0] = in0;
> > > +       mux_parents[0] = in0;
> >
> > Can we use the new way of specifying clk parents so that we don't have
> > to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
> > the core can handl that all instead of this driver.
>
> I removed all this by adding:
>
> clock-output-names = "in0";
>
> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
> the parents clock names arrays do not need run-time update.

"clock-output-names" is deprecated for clocks with a single output:
the clock name will be taken from the node name.
However, relying on a clock name like this is fragile.
Instead, your driver should use the phandle from the clocks property,
using of_clk_get_by_name() or of_clk_get().

Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?

Gr{oetje,eeting}s,

                        Geert

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

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

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-07  8:43         ` Geert Uytterhoeven
@ 2020-12-07  9:55           ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-07  9:55 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk, seanga2

On 2020/12/07 17:44, Geert Uytterhoeven wrote:
> Hi Damien,
> 
> On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>> I prepared a v5 series addressing your comments (and other comments).
>> I will post that later today after some more tests.
> 
> Thanks, already looking at k210-sysctl-v18...
> 
>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>>> --- /dev/null
>>>> +++ b/drivers/clk/clk-k210.c
> 
>>>> +       in0_clk = of_clk_get(np, 0);
>>>> +       if (IS_ERR(in0_clk)) {
>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>> +               hws[K210_CLK_IN0] =
>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>> +                                                  0, K210_IN0_RATE);
>>>> +       } else {
>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>> +       }
>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>> +               goto err;
>>>> +       }
>>>> +
>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>> +       aclk_parents[0] = in0;
>>>> +       pll_parents[0] = in0;
>>>> +       mux_parents[0] = in0;
>>>
>>> Can we use the new way of specifying clk parents so that we don't have
>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>> the core can handl that all instead of this driver.
>>
>> I removed all this by adding:
>>
>> clock-output-names = "in0";
>>
>> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
>> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
>> the parents clock names arrays do not need run-time update.
> 
> "clock-output-names" is deprecated for clocks with a single output:
> the clock name will be taken from the node name.

Arg. I missed that.

> However, relying on a clock name like this is fragile.
> Instead, your driver should use the phandle from the clocks property,
> using of_clk_get_by_name() or of_clk_get().

That is what all versions before V5 used. But Stephen mentioned that the driver
should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
Easy to revert back.

> 
> Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?

Another solution to this would be to simply remove the fixed-rate clock node
from the DT and have the k210 clock driver unconditionally create that clock
(that is one line !). That actually may be even more simple than the previous
version, albeit at the cost of having the DT not being a perfect description of
the hardware. I am fine with that though.

Thoughts ?

> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-07  9:55           ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-07  9:55 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: devicetree, sboyd, linus.walleij, seanga2, linux-gpio, robh+dt,
	palmer, p.zabel, linux-riscv, linux-clk

On 2020/12/07 17:44, Geert Uytterhoeven wrote:
> Hi Damien,
> 
> On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>> I prepared a v5 series addressing your comments (and other comments).
>> I will post that later today after some more tests.
> 
> Thanks, already looking at k210-sysctl-v18...
> 
>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>>> --- /dev/null
>>>> +++ b/drivers/clk/clk-k210.c
> 
>>>> +       in0_clk = of_clk_get(np, 0);
>>>> +       if (IS_ERR(in0_clk)) {
>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>> +               hws[K210_CLK_IN0] =
>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>> +                                                  0, K210_IN0_RATE);
>>>> +       } else {
>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>> +       }
>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>> +               goto err;
>>>> +       }
>>>> +
>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>> +       aclk_parents[0] = in0;
>>>> +       pll_parents[0] = in0;
>>>> +       mux_parents[0] = in0;
>>>
>>> Can we use the new way of specifying clk parents so that we don't have
>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>> the core can handl that all instead of this driver.
>>
>> I removed all this by adding:
>>
>> clock-output-names = "in0";
>>
>> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
>> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
>> the parents clock names arrays do not need run-time update.
> 
> "clock-output-names" is deprecated for clocks with a single output:
> the clock name will be taken from the node name.

Arg. I missed that.

> However, relying on a clock name like this is fragile.
> Instead, your driver should use the phandle from the clocks property,
> using of_clk_get_by_name() or of_clk_get().

That is what all versions before V5 used. But Stephen mentioned that the driver
should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
Easy to revert back.

> 
> Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?

Another solution to this would be to simply remove the fixed-rate clock node
from the DT and have the k210 clock driver unconditionally create that clock
(that is one line !). That actually may be even more simple than the previous
version, albeit at the cost of having the DT not being a perfect description of
the hardware. I am fine with that though.

Thoughts ?

> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 


-- 
Damien Le Moal
Western Digital Research

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-07  9:55           ` Damien Le Moal
@ 2020-12-07 10:06             ` Geert Uytterhoeven
  -1 siblings, 0 replies; 78+ messages in thread
From: Geert Uytterhoeven @ 2020-12-07 10:06 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk, seanga2

Hi Damien,

On Mon, Dec 7, 2020 at 10:55 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
> On 2020/12/07 17:44, Geert Uytterhoeven wrote:
> > On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
> >> I prepared a v5 series addressing your comments (and other comments).
> >> I will post that later today after some more tests.
> >
> > Thanks, already looking at k210-sysctl-v18...
> >
> >> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> >>>> --- /dev/null
> >>>> +++ b/drivers/clk/clk-k210.c
> >
> >>>> +       in0_clk = of_clk_get(np, 0);
> >>>> +       if (IS_ERR(in0_clk)) {
> >>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> >>>> +               hws[K210_CLK_IN0] =
> >>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> >>>> +                                                  0, K210_IN0_RATE);
> >>>> +       } else {
> >>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> >>>> +       }
> >>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
> >>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
> >>>> +               goto err;
> >>>> +       }
> >>>> +
> >>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> >>>> +       aclk_parents[0] = in0;
> >>>> +       pll_parents[0] = in0;
> >>>> +       mux_parents[0] = in0;
> >>>
> >>> Can we use the new way of specifying clk parents so that we don't have
> >>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
> >>> the core can handl that all instead of this driver.
> >>
> >> I removed all this by adding:
> >>
> >> clock-output-names = "in0";
> >>
> >> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
> >> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
> >> the parents clock names arrays do not need run-time update.
> >
> > "clock-output-names" is deprecated for clocks with a single output:
> > the clock name will be taken from the node name.
>
> Arg. I missed that.
>
> > However, relying on a clock name like this is fragile.
> > Instead, your driver should use the phandle from the clocks property,
> > using of_clk_get_by_name() or of_clk_get().
>
> That is what all versions before V5 used. But Stephen mentioned that the driver
> should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
> Easy to revert back.
>
> > Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?
>
> Another solution to this would be to simply remove the fixed-rate clock node
> from the DT and have the k210 clock driver unconditionally create that clock
> (that is one line !). That actually may be even more simple than the previous
> version, albeit at the cost of having the DT not being a perfect description of
> the hardware. I am fine with that though.
>
> Thoughts ?

If there's an external crystal, DT should describe it.
Does the K210 support different crystal frequencies?

Anyway, I'm very interested in what the (new) proper way of handling this
is...

Gr{oetje,eeting}s,

                        Geert

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

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-07 10:06             ` Geert Uytterhoeven
  0 siblings, 0 replies; 78+ messages in thread
From: Geert Uytterhoeven @ 2020-12-07 10:06 UTC (permalink / raw)
  To: Damien Le Moal
  Cc: devicetree, sboyd, linus.walleij, seanga2, linux-gpio, robh+dt,
	palmer, p.zabel, linux-riscv, linux-clk

Hi Damien,

On Mon, Dec 7, 2020 at 10:55 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
> On 2020/12/07 17:44, Geert Uytterhoeven wrote:
> > On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
> >> I prepared a v5 series addressing your comments (and other comments).
> >> I will post that later today after some more tests.
> >
> > Thanks, already looking at k210-sysctl-v18...
> >
> >> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
> >>>> --- /dev/null
> >>>> +++ b/drivers/clk/clk-k210.c
> >
> >>>> +       in0_clk = of_clk_get(np, 0);
> >>>> +       if (IS_ERR(in0_clk)) {
> >>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
> >>>> +               hws[K210_CLK_IN0] =
> >>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
> >>>> +                                                  0, K210_IN0_RATE);
> >>>> +       } else {
> >>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
> >>>> +       }
> >>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
> >>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
> >>>> +               goto err;
> >>>> +       }
> >>>> +
> >>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
> >>>> +       aclk_parents[0] = in0;
> >>>> +       pll_parents[0] = in0;
> >>>> +       mux_parents[0] = in0;
> >>>
> >>> Can we use the new way of specifying clk parents so that we don't have
> >>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
> >>> the core can handl that all instead of this driver.
> >>
> >> I removed all this by adding:
> >>
> >> clock-output-names = "in0";
> >>
> >> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
> >> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
> >> the parents clock names arrays do not need run-time update.
> >
> > "clock-output-names" is deprecated for clocks with a single output:
> > the clock name will be taken from the node name.
>
> Arg. I missed that.
>
> > However, relying on a clock name like this is fragile.
> > Instead, your driver should use the phandle from the clocks property,
> > using of_clk_get_by_name() or of_clk_get().
>
> That is what all versions before V5 used. But Stephen mentioned that the driver
> should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
> Easy to revert back.
>
> > Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?
>
> Another solution to this would be to simply remove the fixed-rate clock node
> from the DT and have the k210 clock driver unconditionally create that clock
> (that is one line !). That actually may be even more simple than the previous
> version, albeit at the cost of having the DT not being a perfect description of
> the hardware. I am fine with that though.
>
> Thoughts ?

If there's an external crystal, DT should describe it.
Does the K210 support different crystal frequencies?

Anyway, I'm very interested in what the (new) proper way of handling this
is...

Gr{oetje,eeting}s,

                        Geert

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

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

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-07 10:06             ` Geert Uytterhoeven
@ 2020-12-07 10:14               ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-07 10:14 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk, seanga2

On 2020/12/07 19:06, Geert Uytterhoeven wrote:
> Hi Damien,
> 
> On Mon, Dec 7, 2020 at 10:55 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>> On 2020/12/07 17:44, Geert Uytterhoeven wrote:
>>> On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>> I prepared a v5 series addressing your comments (and other comments).
>>>> I will post that later today after some more tests.
>>>
>>> Thanks, already looking at k210-sysctl-v18...
>>>
>>>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/clk-k210.c
>>>
>>>>>> +       in0_clk = of_clk_get(np, 0);
>>>>>> +       if (IS_ERR(in0_clk)) {
>>>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>>>> +               hws[K210_CLK_IN0] =
>>>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>>>> +                                                  0, K210_IN0_RATE);
>>>>>> +       } else {
>>>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>>>> +       }
>>>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>>>> +               goto err;
>>>>>> +       }
>>>>>> +
>>>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>>>> +       aclk_parents[0] = in0;
>>>>>> +       pll_parents[0] = in0;
>>>>>> +       mux_parents[0] = in0;
>>>>>
>>>>> Can we use the new way of specifying clk parents so that we don't have
>>>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>>>> the core can handl that all instead of this driver.
>>>>
>>>> I removed all this by adding:
>>>>
>>>> clock-output-names = "in0";
>>>>
>>>> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
>>>> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
>>>> the parents clock names arrays do not need run-time update.
>>>
>>> "clock-output-names" is deprecated for clocks with a single output:
>>> the clock name will be taken from the node name.
>>
>> Arg. I missed that.
>>
>>> However, relying on a clock name like this is fragile.
>>> Instead, your driver should use the phandle from the clocks property,
>>> using of_clk_get_by_name() or of_clk_get().
>>
>> That is what all versions before V5 used. But Stephen mentioned that the driver
>> should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
>> Easy to revert back.
>>
>>> Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?
>>
>> Another solution to this would be to simply remove the fixed-rate clock node
>> from the DT and have the k210 clock driver unconditionally create that clock
>> (that is one line !). That actually may be even more simple than the previous
>> version, albeit at the cost of having the DT not being a perfect description of
>> the hardware. I am fine with that though.
>>
>> Thoughts ?
> 
> If there's an external crystal, DT should describe it.
> Does the K210 support different crystal frequencies?

I am not 100% sure if this oscillator is part of the SoC or if it is an external
input to it. Probably not. Hard to tell by just looking at the boards. I have
the boards drawings though, so  I will check. The frequency seems to be fixed by
hardware: frequencies of the PLLs can be changed to change the CPU frequency,
but the Kendryte SDK does not point to any way allowing changing the base
frequency of the oscillator.

> Anyway, I'm very interested in what the (new) proper way of handling this
> is...
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds
> 


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-07 10:14               ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-07 10:14 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: devicetree, sboyd, linus.walleij, seanga2, linux-gpio, robh+dt,
	palmer, p.zabel, linux-riscv, linux-clk

On 2020/12/07 19:06, Geert Uytterhoeven wrote:
> Hi Damien,
> 
> On Mon, Dec 7, 2020 at 10:55 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>> On 2020/12/07 17:44, Geert Uytterhoeven wrote:
>>> On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>> I prepared a v5 series addressing your comments (and other comments).
>>>> I will post that later today after some more tests.
>>>
>>> Thanks, already looking at k210-sysctl-v18...
>>>
>>>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/clk-k210.c
>>>
>>>>>> +       in0_clk = of_clk_get(np, 0);
>>>>>> +       if (IS_ERR(in0_clk)) {
>>>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>>>> +               hws[K210_CLK_IN0] =
>>>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>>>> +                                                  0, K210_IN0_RATE);
>>>>>> +       } else {
>>>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>>>> +       }
>>>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>>>> +               goto err;
>>>>>> +       }
>>>>>> +
>>>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>>>> +       aclk_parents[0] = in0;
>>>>>> +       pll_parents[0] = in0;
>>>>>> +       mux_parents[0] = in0;
>>>>>
>>>>> Can we use the new way of specifying clk parents so that we don't have
>>>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>>>> the core can handl that all instead of this driver.
>>>>
>>>> I removed all this by adding:
>>>>
>>>> clock-output-names = "in0";
>>>>
>>>> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
>>>> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
>>>> the parents clock names arrays do not need run-time update.
>>>
>>> "clock-output-names" is deprecated for clocks with a single output:
>>> the clock name will be taken from the node name.
>>
>> Arg. I missed that.
>>
>>> However, relying on a clock name like this is fragile.
>>> Instead, your driver should use the phandle from the clocks property,
>>> using of_clk_get_by_name() or of_clk_get().
>>
>> That is what all versions before V5 used. But Stephen mentioned that the driver
>> should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
>> Easy to revert back.
>>
>>> Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?
>>
>> Another solution to this would be to simply remove the fixed-rate clock node
>> from the DT and have the k210 clock driver unconditionally create that clock
>> (that is one line !). That actually may be even more simple than the previous
>> version, albeit at the cost of having the DT not being a perfect description of
>> the hardware. I am fine with that though.
>>
>> Thoughts ?
> 
> If there's an external crystal, DT should describe it.
> Does the K210 support different crystal frequencies?

I am not 100% sure if this oscillator is part of the SoC or if it is an external
input to it. Probably not. Hard to tell by just looking at the boards. I have
the boards drawings though, so  I will check. The frequency seems to be fixed by
hardware: frequencies of the PLLs can be changed to change the CPU frequency,
but the Kendryte SDK does not point to any way allowing changing the base
frequency of the oscillator.

> Anyway, I'm very interested in what the (new) proper way of handling this
> is...
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds
> 


-- 
Damien Le Moal
Western Digital Research

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-07 10:06             ` Geert Uytterhoeven
@ 2020-12-07 11:34               ` Damien Le Moal
  -1 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-07 11:34 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk, seanga2

On 2020/12/07 19:06, Geert Uytterhoeven wrote:
> Hi Damien,
> 
> On Mon, Dec 7, 2020 at 10:55 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>> On 2020/12/07 17:44, Geert Uytterhoeven wrote:
>>> On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>> I prepared a v5 series addressing your comments (and other comments).
>>>> I will post that later today after some more tests.
>>>
>>> Thanks, already looking at k210-sysctl-v18...
>>>
>>>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/clk-k210.c
>>>
>>>>>> +       in0_clk = of_clk_get(np, 0);
>>>>>> +       if (IS_ERR(in0_clk)) {
>>>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>>>> +               hws[K210_CLK_IN0] =
>>>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>>>> +                                                  0, K210_IN0_RATE);
>>>>>> +       } else {
>>>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>>>> +       }
>>>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>>>> +               goto err;
>>>>>> +       }
>>>>>> +
>>>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>>>> +       aclk_parents[0] = in0;
>>>>>> +       pll_parents[0] = in0;
>>>>>> +       mux_parents[0] = in0;
>>>>>
>>>>> Can we use the new way of specifying clk parents so that we don't have
>>>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>>>> the core can handl that all instead of this driver.
>>>>
>>>> I removed all this by adding:
>>>>
>>>> clock-output-names = "in0";
>>>>
>>>> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
>>>> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
>>>> the parents clock names arrays do not need run-time update.
>>>
>>> "clock-output-names" is deprecated for clocks with a single output:
>>> the clock name will be taken from the node name.
>>
>> Arg. I missed that.
>>
>>> However, relying on a clock name like this is fragile.
>>> Instead, your driver should use the phandle from the clocks property,
>>> using of_clk_get_by_name() or of_clk_get().
>>
>> That is what all versions before V5 used. But Stephen mentioned that the driver
>> should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
>> Easy to revert back.
>>
>>> Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?
>>
>> Another solution to this would be to simply remove the fixed-rate clock node
>> from the DT and have the k210 clock driver unconditionally create that clock
>> (that is one line !). That actually may be even more simple than the previous
>> version, albeit at the cost of having the DT not being a perfect description of
>> the hardware. I am fine with that though.
>>
>> Thoughts ?
> 
> If there's an external crystal, DT should describe it.
> Does the K210 support different crystal frequencies?
> 
> Anyway, I'm very interested in what the (new) proper way of handling this
> is...

FYI, I pushed k210-sysctl-v19 to github, restoring the use of of_clk_get() and
__clk_get_name(). No other changes from v18. I have the patches and cover letter
ready to go as V5, but I would like to hear from Stephen first.

Best.

> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds
> 


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-07 11:34               ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-07 11:34 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: devicetree, sboyd, linus.walleij, seanga2, linux-gpio, robh+dt,
	palmer, p.zabel, linux-riscv, linux-clk

On 2020/12/07 19:06, Geert Uytterhoeven wrote:
> Hi Damien,
> 
> On Mon, Dec 7, 2020 at 10:55 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>> On 2020/12/07 17:44, Geert Uytterhoeven wrote:
>>> On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>> I prepared a v5 series addressing your comments (and other comments).
>>>> I will post that later today after some more tests.
>>>
>>> Thanks, already looking at k210-sysctl-v18...
>>>
>>>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/clk/clk-k210.c
>>>
>>>>>> +       in0_clk = of_clk_get(np, 0);
>>>>>> +       if (IS_ERR(in0_clk)) {
>>>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>>>> +               hws[K210_CLK_IN0] =
>>>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>>>> +                                                  0, K210_IN0_RATE);
>>>>>> +       } else {
>>>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>>>> +       }
>>>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>>>> +               goto err;
>>>>>> +       }
>>>>>> +
>>>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>>>> +       aclk_parents[0] = in0;
>>>>>> +       pll_parents[0] = in0;
>>>>>> +       mux_parents[0] = in0;
>>>>>
>>>>> Can we use the new way of specifying clk parents so that we don't have
>>>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>>>> the core can handl that all instead of this driver.
>>>>
>>>> I removed all this by adding:
>>>>
>>>> clock-output-names = "in0";
>>>>
>>>> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
>>>> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
>>>> the parents clock names arrays do not need run-time update.
>>>
>>> "clock-output-names" is deprecated for clocks with a single output:
>>> the clock name will be taken from the node name.
>>
>> Arg. I missed that.
>>
>>> However, relying on a clock name like this is fragile.
>>> Instead, your driver should use the phandle from the clocks property,
>>> using of_clk_get_by_name() or of_clk_get().
>>
>> That is what all versions before V5 used. But Stephen mentioned that the driver
>> should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
>> Easy to revert back.
>>
>>> Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?
>>
>> Another solution to this would be to simply remove the fixed-rate clock node
>> from the DT and have the k210 clock driver unconditionally create that clock
>> (that is one line !). That actually may be even more simple than the previous
>> version, albeit at the cost of having the DT not being a perfect description of
>> the hardware. I am fine with that though.
>>
>> Thoughts ?
> 
> If there's an external crystal, DT should describe it.
> Does the K210 support different crystal frequencies?
> 
> Anyway, I'm very interested in what the (new) proper way of handling this
> is...

FYI, I pushed k210-sysctl-v19 to github, restoring the use of of_clk_get() and
__clk_get_name(). No other changes from v18. I have the patches and cover letter
ready to go as V5, but I would like to hear from Stephen first.

Best.

> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds
> 


-- 
Damien Le Moal
Western Digital Research

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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
  2020-12-07 10:14               ` Damien Le Moal
@ 2020-12-07 22:58                 ` Sean Anderson
  -1 siblings, 0 replies; 78+ messages in thread
From: Sean Anderson @ 2020-12-07 22:58 UTC (permalink / raw)
  To: Damien Le Moal, Geert Uytterhoeven
  Cc: linux-riscv, devicetree, linux-gpio, palmer, sboyd,
	linus.walleij, p.zabel, robh+dt, linux-clk

On 12/7/20 5:14 AM, Damien Le Moal wrote:
> On 2020/12/07 19:06, Geert Uytterhoeven wrote:
>> Hi Damien,
>>
>> On Mon, Dec 7, 2020 at 10:55 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>> On 2020/12/07 17:44, Geert Uytterhoeven wrote:
>>>> On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>>> I prepared a v5 series addressing your comments (and other comments).
>>>>> I will post that later today after some more tests.
>>>>
>>>> Thanks, already looking at k210-sysctl-v18...
>>>>
>>>>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/clk/clk-k210.c
>>>>
>>>>>>> +       in0_clk = of_clk_get(np, 0);
>>>>>>> +       if (IS_ERR(in0_clk)) {
>>>>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>>>>> +               hws[K210_CLK_IN0] =
>>>>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>>>>> +                                                  0, K210_IN0_RATE);
>>>>>>> +       } else {
>>>>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>>>>> +       }
>>>>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>>>>> +               goto err;
>>>>>>> +       }
>>>>>>> +
>>>>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>>>>> +       aclk_parents[0] = in0;
>>>>>>> +       pll_parents[0] = in0;
>>>>>>> +       mux_parents[0] = in0;
>>>>>>
>>>>>> Can we use the new way of specifying clk parents so that we don't have
>>>>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>>>>> the core can handl that all instead of this driver.
>>>>>
>>>>> I removed all this by adding:
>>>>>
>>>>> clock-output-names = "in0";
>>>>>
>>>>> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
>>>>> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
>>>>> the parents clock names arrays do not need run-time update.
>>>>
>>>> "clock-output-names" is deprecated for clocks with a single output:
>>>> the clock name will be taken from the node name.
>>>
>>> Arg. I missed that.
>>>
>>>> However, relying on a clock name like this is fragile.
>>>> Instead, your driver should use the phandle from the clocks property,
>>>> using of_clk_get_by_name() or of_clk_get().
>>>
>>> That is what all versions before V5 used. But Stephen mentioned that the driver
>>> should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
>>> Easy to revert back.
>>>
>>>> Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?
>>>
>>> Another solution to this would be to simply remove the fixed-rate clock node
>>> from the DT and have the k210 clock driver unconditionally create that clock
>>> (that is one line !). That actually may be even more simple than the previous
>>> version, albeit at the cost of having the DT not being a perfect description of
>>> the hardware. I am fine with that though.
>>>
>>> Thoughts ?
>>
>> If there's an external crystal, DT should describe it.
>> Does the K210 support different crystal frequencies?
> 
> I am not 100% sure if this oscillator is part of the SoC or if it is an external
> input to it. Probably not. Hard to tell by just looking at the boards.

It's an external crystal. For example, it is U6 on the maix bit. This is
why I put it as a separate clock instead of including it with the rest.

--Sean

> I have
> the boards drawings though, so  I will check. The frequency seems to be fixed by
> hardware: frequencies of the PLLs can be changed to change the CPU frequency,
> but the Kendryte SDK does not point to any way allowing changing the base
> frequency of the oscillator> 
>> Anyway, I'm very interested in what the (new) proper way of handling this
>> is...
>>
>> Gr{oetje,eeting}s,
>>
>>                          Geert
>>
>> --
>> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>>
>> In personal conversations with technical people, I call myself a hacker. But
>> when I'm talking to journalists I just say "programmer" or something like that.
>>                                  -- Linus Torvalds
>>
> 
> 


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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-07 22:58                 ` Sean Anderson
  0 siblings, 0 replies; 78+ messages in thread
From: Sean Anderson @ 2020-12-07 22:58 UTC (permalink / raw)
  To: Damien Le Moal, Geert Uytterhoeven
  Cc: devicetree, sboyd, linus.walleij, linux-gpio, robh+dt, palmer,
	p.zabel, linux-riscv, linux-clk

On 12/7/20 5:14 AM, Damien Le Moal wrote:
> On 2020/12/07 19:06, Geert Uytterhoeven wrote:
>> Hi Damien,
>>
>> On Mon, Dec 7, 2020 at 10:55 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>> On 2020/12/07 17:44, Geert Uytterhoeven wrote:
>>>> On Mon, Dec 7, 2020 at 4:52 AM Damien Le Moal <Damien.LeMoal@wdc.com> wrote:
>>>>> I prepared a v5 series addressing your comments (and other comments).
>>>>> I will post that later today after some more tests.
>>>>
>>>> Thanks, already looking at k210-sysctl-v18...
>>>>
>>>>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/clk/clk-k210.c
>>>>
>>>>>>> +       in0_clk = of_clk_get(np, 0);
>>>>>>> +       if (IS_ERR(in0_clk)) {
>>>>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>>>>> +               hws[K210_CLK_IN0] =
>>>>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>>>>> +                                                  0, K210_IN0_RATE);
>>>>>>> +       } else {
>>>>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>>>>> +       }
>>>>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>>>>> +               goto err;
>>>>>>> +       }
>>>>>>> +
>>>>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>>>>> +       aclk_parents[0] = in0;
>>>>>>> +       pll_parents[0] = in0;
>>>>>>> +       mux_parents[0] = in0;
>>>>>>
>>>>>> Can we use the new way of specifying clk parents so that we don't have
>>>>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>>>>> the core can handl that all instead of this driver.
>>>>>
>>>>> I removed all this by adding:
>>>>>
>>>>> clock-output-names = "in0";
>>>>>
>>>>> to the DT fixed-rate oscillator clock node (and documented that too). Doing so,
>>>>> clk_hw_get_name(), __clk_get_hw() and of_clk_get() are not needed anymore and
>>>>> the parents clock names arrays do not need run-time update.
>>>>
>>>> "clock-output-names" is deprecated for clocks with a single output:
>>>> the clock name will be taken from the node name.
>>>
>>> Arg. I missed that.
>>>
>>>> However, relying on a clock name like this is fragile.
>>>> Instead, your driver should use the phandle from the clocks property,
>>>> using of_clk_get_by_name() or of_clk_get().
>>>
>>> That is what all versions before V5 used. But Stephen mentioned that the driver
>>> should not, if possible, use of_clk_get()/__clk_get_name(). Hence the change.
>>> Easy to revert back.
>>>
>>>> Stephen: I'm a bit puzzled, as you suggest _not_ using of_clk_get()?
>>>
>>> Another solution to this would be to simply remove the fixed-rate clock node
>>> from the DT and have the k210 clock driver unconditionally create that clock
>>> (that is one line !). That actually may be even more simple than the previous
>>> version, albeit at the cost of having the DT not being a perfect description of
>>> the hardware. I am fine with that though.
>>>
>>> Thoughts ?
>>
>> If there's an external crystal, DT should describe it.
>> Does the K210 support different crystal frequencies?
> 
> I am not 100% sure if this oscillator is part of the SoC or if it is an external
> input to it. Probably not. Hard to tell by just looking at the boards.

It's an external crystal. For example, it is U6 on the maix bit. This is
why I put it as a separate clock instead of including it with the rest.

--Sean

> I have
> the boards drawings though, so  I will check. The frequency seems to be fixed by
> hardware: frequencies of the PLLs can be changed to change the CPU frequency,
> but the Kendryte SDK does not point to any way allowing changing the base
> frequency of the oscillator> 
>> Anyway, I'm very interested in what the (new) proper way of handling this
>> is...
>>
>> Gr{oetje,eeting}s,
>>
>>                          Geert
>>
>> --
>> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>>
>> In personal conversations with technical people, I call myself a hacker. But
>> when I'm talking to journalists I just say "programmer" or something like that.
>>                                  -- Linus Torvalds
>>
> 
> 


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

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
       [not found]       ` <160736612827.1580929.7802371235304556600@swboyd.mtv.corp.google.com>
@ 2020-12-08  7:48           ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-08  7:48 UTC (permalink / raw)
  To: Stephen Boyd, devicetree, linus.walleij, linux-clk, linux-gpio,
	linux-riscv, p.zabel, palmer, robh+dt
  Cc: seanga2@

On 2020/12/08 3:35, Stephen Boyd wrote:
> Quoting Damien Le Moal (2020-12-04 23:43:14)
>> Hi Stephen,
>>
>> Thank you for the review. I will address all your comments.
>> I just have a few questions below.
>>
>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>> Quoting Damien Le Moal (2020-12-01 19:24:50)
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index 2daa6ee673f7..3da9a7a02f61 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
>>>>  F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
>>>>  F:     drivers/net/ieee802154/ca8210.c
>>>>  
>>>>
>>>>
>>>>
>>>> +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
>>>> +M:     Damien Le Moal <damien.lemoal@wdc.com>
>>>> +L:     linux-riscv@lists.infradead.org
>>>> +L:     linux-clk@vger.kernel.org (clock driver)
>>>
>>> Is this needed? I think we cover all of drivers/clk/ and bindings/clock
>>> already.
>>
>> I was not sure about that so I added the entry. Will remove it.
>>
>>>
>>>> +S:     Maintained
>>>> +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
>>>> +F:     drivers/clk/clk-k210.c
>>>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
>>>> index 88ac0d1a5da4..f2f9633087d1 100644
>>>> --- a/arch/riscv/Kconfig.socs
>>>> +++ b/arch/riscv/Kconfig.socs
>>>> @@ -29,6 +29,8 @@ config SOC_CANAAN
>>>>         select SERIAL_SIFIVE if TTY
>>>>         select SERIAL_SIFIVE_CONSOLE if TTY
>>>>         select SIFIVE_PLIC
>>>> +       select SOC_K210_SYSCTL
>>>> +       select CLK_K210
>>>
>>> Any reason to do this vs. just make it the default?
>>
>> I do not understand here... Just selecting the drivers needed for the SoC here.
>> Is there any other way of doing this ?
> 
> Could use the 'default CONFIG_FOO' on the CLK_K210 symbol instead.

Got it. I made this change for the clk driver and for other drivers too.

> 
>>>> +       writel(reg, pll->reg);
>>>> +       reg |= K210_PLL_RESET;
>>>> +       writel(reg, pll->reg);
>>>> +       nop();
>>>> +       nop();
>>>
>>> Are these nops needed for some reason? Any comment to add here? It's
>>> basically non-portable code and hopefully nothing is inserted into that
>>> writel function that shouldn't be there.
>>
>> No clue... They are "magic" nops that are present in the K210 SDK from
>> Kendryte. I copied that, but do not actually know if they are really needed. I
>> am working without any specs for the hardware: the Kendryte SDK is my main
>> source of information here. I will try to remove them or just replace this with
>> a delay() call a nd see what happens.
> 
> Ok.

As mentioned in previous email, I kept the nop() calls as using delay()
functions does not work due to the early execution of this code.

> 
>>>> +        */
>>>> +       in0_clk = of_clk_get(np, 0);
>>>> +       if (IS_ERR(in0_clk)) {
>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>> +               hws[K210_CLK_IN0] =
>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>> +                                                  0, K210_IN0_RATE);
>>>> +       } else {
>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>> +       }
>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>> +               goto err;
>>>> +       }
>>>> +
>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>> +       aclk_parents[0] = in0;
>>>> +       pll_parents[0] = in0;
>>>> +       mux_parents[0] = in0;
>>>
>>> Can we use the new way of specifying clk parents so that we don't have
>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>> the core can handl that all instead of this driver.
>>
>> Not sure what new way of specifying the parent you are referring to here.
>> clk_hw_set_parent() ?
> 
> Use struct clk_parent_data please.

I ended up using parent_hws instead of parent_names in the init structure. Using
parent_hws was simpler than using parent_data. That nicely cleaned up the code I
think.

>>>> +
>>>> +       /* PLLs */
>>>> +       hws[K210_CLK_PLL0] =
>>>> +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
>>>> +       hws[K210_CLK_PLL1] =
>>>> +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
>>>> +       hws[K210_CLK_PLL2] =
>>>> +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
>>>> +
>>>> +       /* aclk: muxed of in0 and pll0_d, no gate */
>>>> +       hws[K210_CLK_ACLK] = k210_register_aclk();
>>>> +
>>>> +       /*
>>>> +        * Clocks with aclk as source: the CPU clock is obviously critical.
>>>> +        * So is the CLINT clock as the scheduler clocksource.
>>>> +        */
>>>> +       hws[K210_CLK_CPU] =
>>>> +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
>>>> +       hws[K210_CLK_CLINT] =
>>>> +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
>>>> +                                            CLK_IS_CRITICAL, 1, 50);
>>>
>>> Is anyone getting these clks? It's nice and all to model things in the
>>> clk framework but if they never have a consumer then it is sort of
>>> useless and just wastes memory and causes more overhead.
>>
>> The CPU and SRAM clocks do not have any consumer, so I could remove them (just
>> enable the HW but not represent them as clocks in the driver). There is no
>> direct consumer of ACLK but it is the parent of multiple clocks, including the
>> SRAM clocks. So it needs to be represented as a clock and kept alive even if
>> all the peripheral drivers needing it are disabled. Otherwise, the system just
>> stops (SRAM accesses hang).
> 
> Ok it seems like these could just be enabled once at probe and then
> ignored? I prefer that as it's simpler.

I removed the CLINT clock as it is completely unused. I kept the CPU clock as it
is referenced by the uarths device node. The 3 SRAM clocks are not referenced,
but I kept them as is as switching to special code for these instead of using
the clock infrastructure would have just generated more code for not much gains
(beside a tiny memory saving maybe).

>>>> +       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
>>>> +       if (ret)
>>>> +               pr_err("%pOFP: add clock provider failed %d\n", np, ret);
>>>> +       else
>>>> +               pr_info("%pOFP: CPU running at %lu MHz\n",
>>>
>>> Is this important? Is there a CPUfreq driver that runs and tells us the
>>> boot CPU frequency instead? Doesn't feel like we care in the clk driver
>>> about this.
>>
>> There is no CPU freq driver that gives this frequency that I know of. That is
>> why I added the message since the driver basically just comes up using the
>> default HW settings for the SoC. CPU freq speed can be changed though by
>> increasing the PLL freq. Just not supporting this for now as it is tricky to
>> do: the SRAM clocks depend on aclk and PLL1 and if these are not the same
>> value, the system hangs (most likely because we end up with the sram banks
>> running at different speeds, which the SoC cache does not like). 
> 
> It would be visible in sysfs if there was a cpufreq driver. Can we use
> that?

I checked and there is no cpufreq information is sysfs. So unless you insist, I
would like to keep this message for information to the user.

> 
>>
>> [...]
>>>> +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
>>>
>>> Is this needed or can this just be a plain platform driver? If something
>>> is needed early for a clocksource or clockevent then the driver can be
>>> split to register those few clks early from this hook and then register
>>> the rest later when the platform device probes. That's what
>>> CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
>>> is incorrect.
>>
>> I think I can clean this up: aclk and clint clocks are needed early but others
>> can likely be deferred. Will fix this up.
>>
> 
> Ok. Thanks!

I tried hard with this one, but as mentioned in a previous email, there is a
circular dependency with the sysctl driver which prevents anything from being
initialized if I use a platform driver. So I switched to declaring the clock
driver using CLK_OF_DECLARE().

Note: I posted v5 but the clk driver patch 11/21 is "held until the list
moderator can review it for approval". The reason is the patch size:
    Message body is too big: 41706 bytes with a limit of 40 KB

Palmer: Who is the list moderator ? Is it you ?

Thanks for all your comments !


-- 
Damien Le Moal
Western Digital Research

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

* Re: [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver
@ 2020-12-08  7:48           ` Damien Le Moal
  0 siblings, 0 replies; 78+ messages in thread
From: Damien Le Moal @ 2020-12-08  7:48 UTC (permalink / raw)
  To: Stephen Boyd, devicetree, linus.walleij, linux-clk, linux-gpio,
	linux-riscv, p.zabel, palmer, robh+dt
  Cc: seanga2@

On 2020/12/08 3:35, Stephen Boyd wrote:
> Quoting Damien Le Moal (2020-12-04 23:43:14)
>> Hi Stephen,
>>
>> Thank you for the review. I will address all your comments.
>> I just have a few questions below.
>>
>> On Fri, 2020-12-04 at 22:19 -0800, Stephen Boyd wrote:
>>> Quoting Damien Le Moal (2020-12-01 19:24:50)
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index 2daa6ee673f7..3da9a7a02f61 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -3822,6 +3822,22 @@ W:       https://github.com/Cascoda/ca8210-linux.git
>>>>  F:     Documentation/devicetree/bindings/net/ieee802154/ca8210.txt
>>>>  F:     drivers/net/ieee802154/ca8210.c
>>>>  
>>>>
>>>>
>>>>
>>>> +CANAAN/KENDRYTE K210 SOC CLOCK DRIVER
>>>> +M:     Damien Le Moal <damien.lemoal@wdc.com>
>>>> +L:     linux-riscv@lists.infradead.org
>>>> +L:     linux-clk@vger.kernel.org (clock driver)
>>>
>>> Is this needed? I think we cover all of drivers/clk/ and bindings/clock
>>> already.
>>
>> I was not sure about that so I added the entry. Will remove it.
>>
>>>
>>>> +S:     Maintained
>>>> +F:     Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
>>>> +F:     drivers/clk/clk-k210.c
>>>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
>>>> index 88ac0d1a5da4..f2f9633087d1 100644
>>>> --- a/arch/riscv/Kconfig.socs
>>>> +++ b/arch/riscv/Kconfig.socs
>>>> @@ -29,6 +29,8 @@ config SOC_CANAAN
>>>>         select SERIAL_SIFIVE if TTY
>>>>         select SERIAL_SIFIVE_CONSOLE if TTY
>>>>         select SIFIVE_PLIC
>>>> +       select SOC_K210_SYSCTL
>>>> +       select CLK_K210
>>>
>>> Any reason to do this vs. just make it the default?
>>
>> I do not understand here... Just selecting the drivers needed for the SoC here.
>> Is there any other way of doing this ?
> 
> Could use the 'default CONFIG_FOO' on the CLK_K210 symbol instead.

Got it. I made this change for the clk driver and for other drivers too.

> 
>>>> +       writel(reg, pll->reg);
>>>> +       reg |= K210_PLL_RESET;
>>>> +       writel(reg, pll->reg);
>>>> +       nop();
>>>> +       nop();
>>>
>>> Are these nops needed for some reason? Any comment to add here? It's
>>> basically non-portable code and hopefully nothing is inserted into that
>>> writel function that shouldn't be there.
>>
>> No clue... They are "magic" nops that are present in the K210 SDK from
>> Kendryte. I copied that, but do not actually know if they are really needed. I
>> am working without any specs for the hardware: the Kendryte SDK is my main
>> source of information here. I will try to remove them or just replace this with
>> a delay() call a nd see what happens.
> 
> Ok.

As mentioned in previous email, I kept the nop() calls as using delay()
functions does not work due to the early execution of this code.

> 
>>>> +        */
>>>> +       in0_clk = of_clk_get(np, 0);
>>>> +       if (IS_ERR(in0_clk)) {
>>>> +               pr_warn("%pOFP: in0 oscillator not found\n", np);
>>>> +               hws[K210_CLK_IN0] =
>>>> +                       clk_hw_register_fixed_rate(NULL, "in0", NULL,
>>>> +                                                  0, K210_IN0_RATE);
>>>> +       } else {
>>>> +               hws[K210_CLK_IN0] = __clk_get_hw(in0_clk);
>>>> +       }
>>>> +       if (IS_ERR(hws[K210_CLK_IN0])) {
>>>> +               pr_err("%pOFP: failed to get base oscillator\n", np);
>>>> +               goto err;
>>>> +       }
>>>> +
>>>> +       in0 = clk_hw_get_name(hws[K210_CLK_IN0]);
>>>> +       aclk_parents[0] = in0;
>>>> +       pll_parents[0] = in0;
>>>> +       mux_parents[0] = in0;
>>>
>>> Can we use the new way of specifying clk parents so that we don't have
>>> to use __clk_get_hw(), of_clk_get(), and clk_hw_get_name()? Hopefully
>>> the core can handl that all instead of this driver.
>>
>> Not sure what new way of specifying the parent you are referring to here.
>> clk_hw_set_parent() ?
> 
> Use struct clk_parent_data please.

I ended up using parent_hws instead of parent_names in the init structure. Using
parent_hws was simpler than using parent_data. That nicely cleaned up the code I
think.

>>>> +
>>>> +       /* PLLs */
>>>> +       hws[K210_CLK_PLL0] =
>>>> +               k210_register_pll(K210_PLL0, "pll0", pll_parents, 1, 0);
>>>> +       hws[K210_CLK_PLL1] =
>>>> +               k210_register_pll(K210_PLL1, "pll1", pll_parents, 1, 0);
>>>> +       hws[K210_CLK_PLL2] =
>>>> +               k210_register_pll(K210_PLL2, "pll2", pll_parents, 3, 0);
>>>> +
>>>> +       /* aclk: muxed of in0 and pll0_d, no gate */
>>>> +       hws[K210_CLK_ACLK] = k210_register_aclk();
>>>> +
>>>> +       /*
>>>> +        * Clocks with aclk as source: the CPU clock is obviously critical.
>>>> +        * So is the CLINT clock as the scheduler clocksource.
>>>> +        */
>>>> +       hws[K210_CLK_CPU] =
>>>> +               k210_register_clk(K210_CLK_CPU, "cpu", "aclk", CLK_IS_CRITICAL);
>>>> +       hws[K210_CLK_CLINT] =
>>>> +               clk_hw_register_fixed_factor(NULL, "clint", "aclk",
>>>> +                                            CLK_IS_CRITICAL, 1, 50);
>>>
>>> Is anyone getting these clks? It's nice and all to model things in the
>>> clk framework but if they never have a consumer then it is sort of
>>> useless and just wastes memory and causes more overhead.
>>
>> The CPU and SRAM clocks do not have any consumer, so I could remove them (just
>> enable the HW but not represent them as clocks in the driver). There is no
>> direct consumer of ACLK but it is the parent of multiple clocks, including the
>> SRAM clocks. So it needs to be represented as a clock and kept alive even if
>> all the peripheral drivers needing it are disabled. Otherwise, the system just
>> stops (SRAM accesses hang).
> 
> Ok it seems like these could just be enabled once at probe and then
> ignored? I prefer that as it's simpler.

I removed the CLINT clock as it is completely unused. I kept the CPU clock as it
is referenced by the uarths device node. The 3 SRAM clocks are not referenced,
but I kept them as is as switching to special code for these instead of using
the clock infrastructure would have just generated more code for not much gains
(beside a tiny memory saving maybe).

>>>> +       ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, kcl->clk_data);
>>>> +       if (ret)
>>>> +               pr_err("%pOFP: add clock provider failed %d\n", np, ret);
>>>> +       else
>>>> +               pr_info("%pOFP: CPU running at %lu MHz\n",
>>>
>>> Is this important? Is there a CPUfreq driver that runs and tells us the
>>> boot CPU frequency instead? Doesn't feel like we care in the clk driver
>>> about this.
>>
>> There is no CPU freq driver that gives this frequency that I know of. That is
>> why I added the message since the driver basically just comes up using the
>> default HW settings for the SoC. CPU freq speed can be changed though by
>> increasing the PLL freq. Just not supporting this for now as it is tricky to
>> do: the SRAM clocks depend on aclk and PLL1 and if these are not the same
>> value, the system hangs (most likely because we end up with the sram banks
>> running at different speeds, which the SoC cache does not like). 
> 
> It would be visible in sysfs if there was a cpufreq driver. Can we use
> that?

I checked and there is no cpufreq information is sysfs. So unless you insist, I
would like to keep this message for information to the user.

> 
>>
>> [...]
>>>> +CLK_OF_DECLARE_DRIVER(k210_clk, "canaan,k210-clk", k210_clk_init);
>>>
>>> Is this needed or can this just be a plain platform driver? If something
>>> is needed early for a clocksource or clockevent then the driver can be
>>> split to register those few clks early from this hook and then register
>>> the rest later when the platform device probes. That's what
>>> CLK_OF_DECLARE_DRIVER is for. A DECLARE_DRIVER without a platform driver
>>> is incorrect.
>>
>> I think I can clean this up: aclk and clint clocks are needed early but others
>> can likely be deferred. Will fix this up.
>>
> 
> Ok. Thanks!

I tried hard with this one, but as mentioned in a previous email, there is a
circular dependency with the sysctl driver which prevents anything from being
initialized if I use a platform driver. So I switched to declaring the clock
driver using CLK_OF_DECLARE().

Note: I posted v5 but the clk driver patch 11/21 is "held until the list
moderator can review it for approval". The reason is the patch size:
    Message body is too big: 41706 bytes with a limit of 40 KB

Palmer: Who is the list moderator ? Is it you ?

Thanks for all your comments !


-- 
Damien Le Moal
Western Digital Research

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

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

end of thread, other threads:[~2020-12-08  7:49 UTC | newest]

Thread overview: 78+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-02  3:24 [PATCH v4 00/21] RISC-V Kendryte K210 support improvements Damien Le Moal
2020-12-02  3:24 ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 01/21] riscv: Fix kernel time_init() Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-05  5:41   ` Stephen Boyd
2020-12-05  5:41     ` Stephen Boyd
2020-12-02  3:24 ` [PATCH v4 02/21] riscv: Fix sifive serial driver Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 03/21] riscv: Enable interrupts during syscalls with M-Mode Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 04/21] riscv: Fix builtin DTB handling Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-04 15:11   ` Geert Uytterhoeven
2020-12-04 15:11     ` Geert Uytterhoeven
2020-12-02  3:24 ` [PATCH v4 05/21] riscv: Use vendor name for K210 SoC support Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 06/21] dt-bindings: Add Canaan vendor prefix Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 07/21] dt-binding: clock: Document canaan,k210-clk bindings Damien Le Moal
2020-12-02  3:24   ` [PATCH v4 07/21] dt-binding: clock: Document canaan, k210-clk bindings Damien Le Moal
2020-12-05  5:46   ` [PATCH v4 07/21] dt-binding: clock: Document canaan,k210-clk bindings Stephen Boyd
2020-12-05  5:46     ` [PATCH v4 07/21] dt-binding: clock: Document canaan, k210-clk bindings Stephen Boyd
2020-12-02  3:24 ` [PATCH v4 08/21] dt-bindings: reset: Document canaan,k210-rst bindings Damien Le Moal
2020-12-02  3:24   ` [PATCH v4 08/21] dt-bindings: reset: Document canaan, k210-rst bindings Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 09/21] dt-bindings: pinctrl: Document canaan,k210-fpioa bindings Damien Le Moal
2020-12-02  3:24   ` [PATCH v4 09/21] dt-bindings: pinctrl: Document canaan, k210-fpioa bindings Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 10/21] dt-binding: mfd: Document canaan,k210-sysctl bindings Damien Le Moal
2020-12-02  3:24   ` [PATCH v4 10/21] dt-binding: mfd: Document canaan, k210-sysctl bindings Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 11/21] riscv: Add Canaan Kendryte K210 clock driver Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-05  6:19   ` Stephen Boyd
2020-12-05  6:19     ` Stephen Boyd
2020-12-05  7:43     ` Damien Le Moal
2020-12-05  7:43       ` Damien Le Moal
2020-12-05 13:43       ` Sean Anderson
2020-12-05 13:43         ` Sean Anderson
2020-12-05 14:13         ` Damien Le Moal
2020-12-05 14:13           ` Damien Le Moal
     [not found]       ` <160736612827.1580929.7802371235304556600@swboyd.mtv.corp.google.com>
2020-12-08  7:48         ` Damien Le Moal
2020-12-08  7:48           ` Damien Le Moal
2020-12-07  3:50     ` Damien Le Moal
2020-12-07  3:50       ` Damien Le Moal
2020-12-07  8:43       ` Geert Uytterhoeven
2020-12-07  8:43         ` Geert Uytterhoeven
2020-12-07  9:55         ` Damien Le Moal
2020-12-07  9:55           ` Damien Le Moal
2020-12-07 10:06           ` Geert Uytterhoeven
2020-12-07 10:06             ` Geert Uytterhoeven
2020-12-07 10:14             ` Damien Le Moal
2020-12-07 10:14               ` Damien Le Moal
2020-12-07 22:58               ` Sean Anderson
2020-12-07 22:58                 ` Sean Anderson
2020-12-07 11:34             ` Damien Le Moal
2020-12-07 11:34               ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 12/21] riscv: Add Canaan Kendryte K210 FPIOA driver Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 13/21] riscv: Add Canaan Kendryte K210 reset controller Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-04 10:49   ` Philipp Zabel
2020-12-04 10:49     ` Philipp Zabel
2020-12-04 11:16     ` Damien Le Moal
2020-12-04 11:16       ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 14/21] riscv: Update Canaan Kendryte K210 device tree Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 15/21] riscv: Add SiPeed MAIX BiT board " Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 16/21] riscv: Add SiPeed MAIX DOCK " Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 17/21] riscv: Add SiPeed MAIX GO " Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 18/21] riscv: Add SiPeed MAIXDUINO " Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 19/21] riscv: Add Kendryte KD233 " Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:24 ` [PATCH v4 20/21] riscv: Update Canaan Kendryte K210 defconfig Damien Le Moal
2020-12-02  3:24   ` Damien Le Moal
2020-12-02  3:25 ` [PATCH v4 21/21] riscv: Add Canaan Kendryte K210 SD card defconfig Damien Le Moal
2020-12-02  3:25   ` Damien Le Moal

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.