All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/10] Add Sunplus SP7021 SoC Support
@ 2021-12-22  7:05 ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:05 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

This patch series add Sunplus SP7021 SoC support.

Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates many
peripherals (ex: UART, I2C, SPI, SDIO, eMMC, USB, SD card and etc.) into a
single chip. It is designed for industrial control.

SP7021 consists of two chips (dies) in a package. One is called C-chip
(computing chip). It is a 4-core ARM Cortex A7 CPU. It adopts high-level
process (22 nm) for high performance computing. The other is called P-
chip (peripheral chip). It has many peripherals and an ARM A926 added
especially for real-time control. P-chip is made for customers. It adopts
low-level process (ex: 0.11 um) to reduce cost.

Refer to (for documentations):
https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview

Refer to (applications):
https://tibbo.com/store/plus1.html

Refer to (applications):
http://www.sinovoip.com.cn/ecp_view.asp?id=586

Changes in v7:
- sunplus,sp7021-clkc.yaml: Add clocks & clock-names
- clk-sp7021.c: fix the comments form Stephen Boyd
- irq-sp7021-intc.c: fix the comments from Marc

Changes in v6:
- reset-sunplus.c: fix the comments from Philipp
- irq-sp7021-intc.c: fix the comments from Marc
- mach-sunplus: fix the comments from Arnd

Changes in v5:
- reset-sunplus.c: fix strict checks
- clk/Kconfig: fix spell
- clk-sp7021.c: using bitfield ops, fix strict checks
- irqchip/Kconfig: fix spell
- irq-sp7021-intc.c: cleanup error path in probe, fix strict checks
- arm/Kconfig: fix spell & typo, remove CONFIG_SERIAL_SUNPLUS
- mach-sunplus/Kconfig: fix typo
- sp7021_defconfig: add CONFIG_SERIAL_SUNPLUS

Changes in v4:
- mach-sunplus: add initial support for SP7021
- sp7021_defconfig: add generic SP7021 defconfig
- reset-sunplus: remove Q645 support
- reset-sunplus.c: refine code based on Philipp's review
- clk-sp7021: clock defines add prefix, more clean up

Changes in v3:
- sp7021-intc: remove primary controller mode due to P-chip running Linux
  not supported any more.
- sp7021-intc.h: removed, not set ext through the DT but sp_intc_set_ext()
- sunplus,sp7021-intc.yaml: update descriptions for above changes
- irq-sp7021-intc.c: more cleanup based on Marc's review
- all driver's Kconfig removed default, it's selected by platform config

Changes in v2:
- sunplus,sp7021-intc.yaml: add descrption for "#interrupt-cells", interrupts
- sunplus,sp7021-intc.yaml: drop "ext0-mask"/"ext1-mask" from DT
- sunplus,sp7021-intc.yaml: fix example.dt too long error
- irq-sp7021-intc.c: major rewrite
- all files with dual license

Qin Jian (10):
  dt-bindings: vendor-prefixes: Add Sunplus
  dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards
  dt-bindings: reset: Add bindings for SP7021 reset driver
  reset: Add Sunplus SP7021 reset driver
  dt-bindings: clock: Add bindings for SP7021 clock driver
  clk: Add Sunplus SP7021 clock driver
  dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt
    controller
  irqchip: Add Sunplus SP7021 interrupt controller driver
  ARM: sunplus: Add initial support for Sunplus SP7021 SoC
  ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig

 .../bindings/arm/sunplus,sp7021.yaml          |  27 +
 .../bindings/clock/sunplus,sp7021-clkc.yaml   |  52 ++
 .../sunplus,sp7021-intc.yaml                  |  62 ++
 .../bindings/reset/sunplus,reset.yaml         |  38 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |  17 +
 arch/arm/Kconfig                              |   2 +
 arch/arm/Makefile                             |   1 +
 arch/arm/configs/multi_v7_defconfig           |   1 +
 arch/arm/configs/sp7021_defconfig             |  61 ++
 arch/arm/mach-sunplus/Kconfig                 |  26 +
 arch/arm/mach-sunplus/Makefile                |   9 +
 arch/arm/mach-sunplus/sp7021.c                |  16 +
 drivers/clk/Kconfig                           |  10 +-
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-sp7021.c                      | 705 ++++++++++++++++++
 drivers/irqchip/Kconfig                       |   9 +
 drivers/irqchip/Makefile                      |   1 +
 drivers/irqchip/irq-sp7021-intc.c             | 288 +++++++
 drivers/reset/Kconfig                         |   9 +
 drivers/reset/Makefile                        |   1 +
 drivers/reset/reset-sunplus.c                 | 130 ++++
 include/dt-bindings/clock/sp-sp7021.h         | 112 +++
 include/dt-bindings/reset/sp-sp7021.h         |  97 +++
 24 files changed, 1676 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 create mode 100644 Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 create mode 100644 arch/arm/configs/sp7021_defconfig
 create mode 100644 arch/arm/mach-sunplus/Kconfig
 create mode 100644 arch/arm/mach-sunplus/Makefile
 create mode 100644 arch/arm/mach-sunplus/sp7021.c
 create mode 100644 drivers/clk/clk-sp7021.c
 create mode 100644 drivers/irqchip/irq-sp7021-intc.c
 create mode 100644 drivers/reset/reset-sunplus.c
 create mode 100644 include/dt-bindings/clock/sp-sp7021.h
 create mode 100644 include/dt-bindings/reset/sp-sp7021.h

-- 
2.33.1


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

* [PATCH v7 00/10] Add Sunplus SP7021 SoC Support
@ 2021-12-22  7:05 ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:05 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

This patch series add Sunplus SP7021 SoC support.

Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates many
peripherals (ex: UART, I2C, SPI, SDIO, eMMC, USB, SD card and etc.) into a
single chip. It is designed for industrial control.

SP7021 consists of two chips (dies) in a package. One is called C-chip
(computing chip). It is a 4-core ARM Cortex A7 CPU. It adopts high-level
process (22 nm) for high performance computing. The other is called P-
chip (peripheral chip). It has many peripherals and an ARM A926 added
especially for real-time control. P-chip is made for customers. It adopts
low-level process (ex: 0.11 um) to reduce cost.

Refer to (for documentations):
https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview

Refer to (applications):
https://tibbo.com/store/plus1.html

Refer to (applications):
http://www.sinovoip.com.cn/ecp_view.asp?id=586

Changes in v7:
- sunplus,sp7021-clkc.yaml: Add clocks & clock-names
- clk-sp7021.c: fix the comments form Stephen Boyd
- irq-sp7021-intc.c: fix the comments from Marc

Changes in v6:
- reset-sunplus.c: fix the comments from Philipp
- irq-sp7021-intc.c: fix the comments from Marc
- mach-sunplus: fix the comments from Arnd

Changes in v5:
- reset-sunplus.c: fix strict checks
- clk/Kconfig: fix spell
- clk-sp7021.c: using bitfield ops, fix strict checks
- irqchip/Kconfig: fix spell
- irq-sp7021-intc.c: cleanup error path in probe, fix strict checks
- arm/Kconfig: fix spell & typo, remove CONFIG_SERIAL_SUNPLUS
- mach-sunplus/Kconfig: fix typo
- sp7021_defconfig: add CONFIG_SERIAL_SUNPLUS

Changes in v4:
- mach-sunplus: add initial support for SP7021
- sp7021_defconfig: add generic SP7021 defconfig
- reset-sunplus: remove Q645 support
- reset-sunplus.c: refine code based on Philipp's review
- clk-sp7021: clock defines add prefix, more clean up

Changes in v3:
- sp7021-intc: remove primary controller mode due to P-chip running Linux
  not supported any more.
- sp7021-intc.h: removed, not set ext through the DT but sp_intc_set_ext()
- sunplus,sp7021-intc.yaml: update descriptions for above changes
- irq-sp7021-intc.c: more cleanup based on Marc's review
- all driver's Kconfig removed default, it's selected by platform config

Changes in v2:
- sunplus,sp7021-intc.yaml: add descrption for "#interrupt-cells", interrupts
- sunplus,sp7021-intc.yaml: drop "ext0-mask"/"ext1-mask" from DT
- sunplus,sp7021-intc.yaml: fix example.dt too long error
- irq-sp7021-intc.c: major rewrite
- all files with dual license

Qin Jian (10):
  dt-bindings: vendor-prefixes: Add Sunplus
  dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards
  dt-bindings: reset: Add bindings for SP7021 reset driver
  reset: Add Sunplus SP7021 reset driver
  dt-bindings: clock: Add bindings for SP7021 clock driver
  clk: Add Sunplus SP7021 clock driver
  dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt
    controller
  irqchip: Add Sunplus SP7021 interrupt controller driver
  ARM: sunplus: Add initial support for Sunplus SP7021 SoC
  ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig

 .../bindings/arm/sunplus,sp7021.yaml          |  27 +
 .../bindings/clock/sunplus,sp7021-clkc.yaml   |  52 ++
 .../sunplus,sp7021-intc.yaml                  |  62 ++
 .../bindings/reset/sunplus,reset.yaml         |  38 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |  17 +
 arch/arm/Kconfig                              |   2 +
 arch/arm/Makefile                             |   1 +
 arch/arm/configs/multi_v7_defconfig           |   1 +
 arch/arm/configs/sp7021_defconfig             |  61 ++
 arch/arm/mach-sunplus/Kconfig                 |  26 +
 arch/arm/mach-sunplus/Makefile                |   9 +
 arch/arm/mach-sunplus/sp7021.c                |  16 +
 drivers/clk/Kconfig                           |  10 +-
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-sp7021.c                      | 705 ++++++++++++++++++
 drivers/irqchip/Kconfig                       |   9 +
 drivers/irqchip/Makefile                      |   1 +
 drivers/irqchip/irq-sp7021-intc.c             | 288 +++++++
 drivers/reset/Kconfig                         |   9 +
 drivers/reset/Makefile                        |   1 +
 drivers/reset/reset-sunplus.c                 | 130 ++++
 include/dt-bindings/clock/sp-sp7021.h         | 112 +++
 include/dt-bindings/reset/sp-sp7021.h         |  97 +++
 24 files changed, 1676 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 create mode 100644 Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 create mode 100644 arch/arm/configs/sp7021_defconfig
 create mode 100644 arch/arm/mach-sunplus/Kconfig
 create mode 100644 arch/arm/mach-sunplus/Makefile
 create mode 100644 arch/arm/mach-sunplus/sp7021.c
 create mode 100644 drivers/clk/clk-sp7021.c
 create mode 100644 drivers/irqchip/irq-sp7021-intc.c
 create mode 100644 drivers/reset/reset-sunplus.c
 create mode 100644 include/dt-bindings/clock/sp-sp7021.h
 create mode 100644 include/dt-bindings/reset/sp-sp7021.h

-- 
2.33.1


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

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

* [PATCH v7 01/10] dt-bindings: vendor-prefixes: Add Sunplus
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:05   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:05 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian, Rob Herring

Add vendor prefix for Sunplus Technology Co., Ltd. (http://www.sunplus.com)

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.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 a867f7102..50d4ee5ac 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1131,6 +1131,8 @@ patternProperties:
     description: Summit microelectronics
   "^sunchip,.*":
     description: Shenzhen Sunchip Technology Co., Ltd
+  "^sunplus,.*":
+    description: Sunplus Technology Co., Ltd.
   "^SUNW,.*":
     description: Sun Microsystems, Inc
   "^supermicro,.*":
-- 
2.33.1


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

* [PATCH v7 01/10] dt-bindings: vendor-prefixes: Add Sunplus
@ 2021-12-22  7:05   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:05 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian, Rob Herring

Add vendor prefix for Sunplus Technology Co., Ltd. (http://www.sunplus.com)

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.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 a867f7102..50d4ee5ac 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1131,6 +1131,8 @@ patternProperties:
     description: Summit microelectronics
   "^sunchip,.*":
     description: Shenzhen Sunchip Technology Co., Ltd
+  "^sunplus,.*":
+    description: Sunplus Technology Co., Ltd.
   "^SUNW,.*":
     description: Sun Microsystems, Inc
   "^supermicro,.*":
-- 
2.33.1


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

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

* [PATCH v7 02/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:05   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:05 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian, Rob Herring

This introduces bindings for boards based Sunplus SP7021 SoC.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 .../bindings/arm/sunplus,sp7021.yaml          | 27 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++++
 2 files changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml

diff --git a/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml b/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
new file mode 100644
index 000000000..5b9985b73
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/sunplus,sp7021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 Boards Device Tree Bindings
+
+maintainers:
+  - qinjian <qinjian@cqplus1.com>
+
+description: |
+  ARM platforms using Sunplus SP7021, an ARM Cortex A7 (4-cores) based SoC.
+  Wiki: https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - items:
+          - const: sunplus,sp7021-achip
+
+additionalProperties: true
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index e0bca0de0..6a5422f10 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2655,6 +2655,13 @@ F:	drivers/clocksource/armv7m_systick.c
 N:	stm32
 N:	stm
 
+ARM/SUNPLUS SP7021 SOC SUPPORT
+M:	Qin Jian <qinjian@cqplus1.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for mon-subscribers)
+S:	Maintained
+W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
+F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+
 ARM/Synaptics SoC support
 M:	Jisheng Zhang <Jisheng.Zhang@synaptics.com>
 M:	Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
-- 
2.33.1


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

* [PATCH v7 02/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards
@ 2021-12-22  7:05   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:05 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian, Rob Herring

This introduces bindings for boards based Sunplus SP7021 SoC.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 .../bindings/arm/sunplus,sp7021.yaml          | 27 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++++
 2 files changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml

diff --git a/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml b/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
new file mode 100644
index 000000000..5b9985b73
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/sunplus,sp7021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 Boards Device Tree Bindings
+
+maintainers:
+  - qinjian <qinjian@cqplus1.com>
+
+description: |
+  ARM platforms using Sunplus SP7021, an ARM Cortex A7 (4-cores) based SoC.
+  Wiki: https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - items:
+          - const: sunplus,sp7021-achip
+
+additionalProperties: true
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index e0bca0de0..6a5422f10 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2655,6 +2655,13 @@ F:	drivers/clocksource/armv7m_systick.c
 N:	stm32
 N:	stm
 
+ARM/SUNPLUS SP7021 SOC SUPPORT
+M:	Qin Jian <qinjian@cqplus1.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for mon-subscribers)
+S:	Maintained
+W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
+F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+
 ARM/Synaptics SoC support
 M:	Jisheng Zhang <Jisheng.Zhang@synaptics.com>
 M:	Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
-- 
2.33.1


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

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

* [PATCH v7 03/10] dt-bindings: reset: Add bindings for SP7021 reset driver
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:05   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:05 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian, Rob Herring

Add documentation to describe Sunplus SP7021 reset driver bindings.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 .../bindings/reset/sunplus,reset.yaml         | 38 ++++++++
 MAINTAINERS                                   |  2 +
 include/dt-bindings/reset/sp-sp7021.h         | 97 +++++++++++++++++++
 3 files changed, 137 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 create mode 100644 include/dt-bindings/reset/sp-sp7021.h

diff --git a/Documentation/devicetree/bindings/reset/sunplus,reset.yaml b/Documentation/devicetree/bindings/reset/sunplus,reset.yaml
new file mode 100644
index 000000000..c083c821f
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/sunplus,reset.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/reset/sunplus,reset.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Sunplus SoC Reset Controller
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-reset
+
+  "#reset-cells":
+    const: 1
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - "#reset-cells"
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    rstc: reset@9c000054 {
+      compatible = "sunplus,sp7021-reset";
+      #reset-cells = <1>;
+      reg = <0x9c000054 0x28>;
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 6a5422f10..652f42cab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2661,6 +2661,8 @@ L:	linux-arm-kernel@lists.infradead.org (moderated for mon-subscribers)
 S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
 M:	Jisheng Zhang <Jisheng.Zhang@synaptics.com>
diff --git a/include/dt-bindings/reset/sp-sp7021.h b/include/dt-bindings/reset/sp-sp7021.h
new file mode 100644
index 000000000..fd2a50327
--- /dev/null
+++ b/include/dt-bindings/reset/sp-sp7021.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#ifndef _DT_BINDINGS_RST_SUNPLUS_SP7021_H
+#define _DT_BINDINGS_RST_SUNPLUS_SP7021_H
+
+/* mo_reset0 ~ mo_reset9 */
+#define RST_SYSTEM		0x00
+#define RST_RTC			0x02
+#define RST_IOCTL		0x03
+#define RST_IOP			0x04
+#define RST_OTPRX		0x05
+#define RST_NOC			0x06
+#define RST_BR			0x07
+#define RST_RBUS_L00	        0x08
+#define RST_SPIFL		0x09
+#define RST_SDCTRL0		0x0a
+#define RST_PERI0		0x0b
+#define RST_A926		0x0d
+#define RST_UMCTL2		0x0e
+#define RST_PERI1		0x0f
+
+#define RST_DDR_PHY0	        0x10
+#define RST_ACHIP		0x12
+#define RST_STC0		0x14
+#define RST_STC_AV0		0x15
+#define RST_STC_AV1		0x16
+#define RST_STC_AV2		0x17
+#define RST_UA0			0x18
+#define RST_UA1			0x19
+#define RST_UA2			0x1a
+#define RST_UA3			0x1b
+#define RST_UA4			0x1c
+#define RST_HWUA		0x1d
+#define RST_DDC0		0x1e
+#define RST_UADMA		0x1f
+
+#define RST_CBDMA0		0x20
+#define RST_CBDMA1		0x21
+#define RST_SPI_COMBO_0	        0x22
+#define RST_SPI_COMBO_1	        0x23
+#define RST_SPI_COMBO_2	        0x24
+#define RST_SPI_COMBO_3	        0x25
+#define RST_AUD			0x26
+#define RST_USBC0		0x2a
+#define RST_USBC1		0x2b
+#define RST_UPHY0		0x2d
+#define RST_UPHY1		0x2e
+
+#define RST_I2CM0		0x30
+#define RST_I2CM1		0x31
+#define RST_I2CM2		0x32
+#define RST_I2CM3		0x33
+#define RST_PMC			0x3d
+#define RST_CARD_CTL0	        0x3e
+#define RST_CARD_CTL1	        0x3f
+
+#define RST_CARD_CTL4	        0x42
+#define RST_BCH			0x44
+#define RST_DDFCH		0x4b
+#define RST_CSIIW0		0x4c
+#define RST_CSIIW1		0x4d
+#define RST_MIPICSI0	        0x4e
+#define RST_MIPICSI1	        0x4f
+
+#define RST_HDMI_TX		0x50
+#define RST_VPOST		0x55
+
+#define RST_TGEN		0x60
+#define RST_DMIX		0x61
+#define RST_TCON		0x6a
+#define RST_INTERRUPT	        0x6f
+
+#define RST_RGST		0x70
+#define RST_GPIO		0x73
+#define RST_RBUS_TOP	        0x74
+
+#define RST_MAILBOX		0x86
+#define RST_SPIND		0x8a
+#define RST_I2C2CBUS	        0x8b
+#define RST_SEC			0x8d
+#define RST_DVE			0x8e
+#define RST_GPOST0		0x8f
+
+#define RST_OSD0		0x90
+#define RST_DISP_PWM	        0x92
+#define RST_UADBG		0x93
+#define RST_DUMMY_MASTER	0x94
+#define RST_FIO_CTL		0x95
+#define RST_FPGA		0x96
+#define RST_L2SW		0x97
+#define RST_ICM			0x98
+#define RST_AXI_GLOBAL	        0x99
+
+#endif
-- 
2.33.1


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

* [PATCH v7 03/10] dt-bindings: reset: Add bindings for SP7021 reset driver
@ 2021-12-22  7:05   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:05 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian, Rob Herring

Add documentation to describe Sunplus SP7021 reset driver bindings.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 .../bindings/reset/sunplus,reset.yaml         | 38 ++++++++
 MAINTAINERS                                   |  2 +
 include/dt-bindings/reset/sp-sp7021.h         | 97 +++++++++++++++++++
 3 files changed, 137 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 create mode 100644 include/dt-bindings/reset/sp-sp7021.h

diff --git a/Documentation/devicetree/bindings/reset/sunplus,reset.yaml b/Documentation/devicetree/bindings/reset/sunplus,reset.yaml
new file mode 100644
index 000000000..c083c821f
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/sunplus,reset.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/reset/sunplus,reset.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Sunplus SoC Reset Controller
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-reset
+
+  "#reset-cells":
+    const: 1
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - "#reset-cells"
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    rstc: reset@9c000054 {
+      compatible = "sunplus,sp7021-reset";
+      #reset-cells = <1>;
+      reg = <0x9c000054 0x28>;
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 6a5422f10..652f42cab 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2661,6 +2661,8 @@ L:	linux-arm-kernel@lists.infradead.org (moderated for mon-subscribers)
 S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
 M:	Jisheng Zhang <Jisheng.Zhang@synaptics.com>
diff --git a/include/dt-bindings/reset/sp-sp7021.h b/include/dt-bindings/reset/sp-sp7021.h
new file mode 100644
index 000000000..fd2a50327
--- /dev/null
+++ b/include/dt-bindings/reset/sp-sp7021.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#ifndef _DT_BINDINGS_RST_SUNPLUS_SP7021_H
+#define _DT_BINDINGS_RST_SUNPLUS_SP7021_H
+
+/* mo_reset0 ~ mo_reset9 */
+#define RST_SYSTEM		0x00
+#define RST_RTC			0x02
+#define RST_IOCTL		0x03
+#define RST_IOP			0x04
+#define RST_OTPRX		0x05
+#define RST_NOC			0x06
+#define RST_BR			0x07
+#define RST_RBUS_L00	        0x08
+#define RST_SPIFL		0x09
+#define RST_SDCTRL0		0x0a
+#define RST_PERI0		0x0b
+#define RST_A926		0x0d
+#define RST_UMCTL2		0x0e
+#define RST_PERI1		0x0f
+
+#define RST_DDR_PHY0	        0x10
+#define RST_ACHIP		0x12
+#define RST_STC0		0x14
+#define RST_STC_AV0		0x15
+#define RST_STC_AV1		0x16
+#define RST_STC_AV2		0x17
+#define RST_UA0			0x18
+#define RST_UA1			0x19
+#define RST_UA2			0x1a
+#define RST_UA3			0x1b
+#define RST_UA4			0x1c
+#define RST_HWUA		0x1d
+#define RST_DDC0		0x1e
+#define RST_UADMA		0x1f
+
+#define RST_CBDMA0		0x20
+#define RST_CBDMA1		0x21
+#define RST_SPI_COMBO_0	        0x22
+#define RST_SPI_COMBO_1	        0x23
+#define RST_SPI_COMBO_2	        0x24
+#define RST_SPI_COMBO_3	        0x25
+#define RST_AUD			0x26
+#define RST_USBC0		0x2a
+#define RST_USBC1		0x2b
+#define RST_UPHY0		0x2d
+#define RST_UPHY1		0x2e
+
+#define RST_I2CM0		0x30
+#define RST_I2CM1		0x31
+#define RST_I2CM2		0x32
+#define RST_I2CM3		0x33
+#define RST_PMC			0x3d
+#define RST_CARD_CTL0	        0x3e
+#define RST_CARD_CTL1	        0x3f
+
+#define RST_CARD_CTL4	        0x42
+#define RST_BCH			0x44
+#define RST_DDFCH		0x4b
+#define RST_CSIIW0		0x4c
+#define RST_CSIIW1		0x4d
+#define RST_MIPICSI0	        0x4e
+#define RST_MIPICSI1	        0x4f
+
+#define RST_HDMI_TX		0x50
+#define RST_VPOST		0x55
+
+#define RST_TGEN		0x60
+#define RST_DMIX		0x61
+#define RST_TCON		0x6a
+#define RST_INTERRUPT	        0x6f
+
+#define RST_RGST		0x70
+#define RST_GPIO		0x73
+#define RST_RBUS_TOP	        0x74
+
+#define RST_MAILBOX		0x86
+#define RST_SPIND		0x8a
+#define RST_I2C2CBUS	        0x8b
+#define RST_SEC			0x8d
+#define RST_DVE			0x8e
+#define RST_GPOST0		0x8f
+
+#define RST_OSD0		0x90
+#define RST_DISP_PWM	        0x92
+#define RST_UADBG		0x93
+#define RST_DUMMY_MASTER	0x94
+#define RST_FIO_CTL		0x95
+#define RST_FPGA		0x96
+#define RST_L2SW		0x97
+#define RST_ICM			0x98
+#define RST_AXI_GLOBAL	        0x99
+
+#endif
-- 
2.33.1


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

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

* [PATCH v7 04/10] reset: Add Sunplus SP7021 reset driver
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:06   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add reset driver for Sunplus SP7021 SoC.

Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 MAINTAINERS                   |   1 +
 drivers/reset/Kconfig         |   9 +++
 drivers/reset/Makefile        |   1 +
 drivers/reset/reset-sunplus.c | 130 ++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+)
 create mode 100644 drivers/reset/reset-sunplus.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 652f42cab..6caffd6d0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2662,6 +2662,7 @@ S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index be799a5ab..fb14456a8 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -224,6 +224,15 @@ config RESET_SOCFPGA
 	  This enables the reset driver for the SoCFPGA ARMv7 platforms. This
 	  driver gets initialized early during platform init calls.
 
+config RESET_SUNPLUS
+	bool "Sunplus SoCs Reset Driver" if COMPILE_TEST
+	default ARCH_SUNPLUS
+	help
+	  This enables the reset driver support for Sunplus SoCs.
+	  The reset lines that can be asserted and deasserted by toggling bits
+	  in a contiguous, exclusive register space. The register is HIWORD_MASKED,
+	  which means each register hold 16 reset lines.
+
 config RESET_SUNXI
 	bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI
 	default ARCH_SUNXI
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 21d46d886..f03403e97 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
 obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
diff --git a/drivers/reset/reset-sunplus.c b/drivers/reset/reset-sunplus.c
new file mode 100644
index 000000000..113b36b57
--- /dev/null
+++ b/drivers/reset/reset-sunplus.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * SP7021 reset driver
+ *
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/reboot.h>
+
+/* HIWORD_MASK_REG BITS */
+#define BITS_PER_HWM_REG	16
+
+struct sp_reset {
+	struct reset_controller_dev rcdev;
+	struct notifier_block notifier;
+	void __iomem *base;
+};
+
+static inline struct sp_reset *to_sp_reset(struct reset_controller_dev *rcdev)
+{
+	return container_of(rcdev, struct sp_reset, rcdev);
+}
+
+static int sp_reset_update(struct reset_controller_dev *rcdev,
+			   unsigned long id, bool assert)
+{
+	struct sp_reset *reset = to_sp_reset(rcdev);
+	int index = id / BITS_PER_HWM_REG;
+	int shift = id % BITS_PER_HWM_REG;
+	u32 val;
+
+	val = (1 << (16 + shift)) | (assert << shift);
+	writel(val, reset->base + (index * 4));
+
+	return 0;
+}
+
+static int sp_reset_assert(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	return sp_reset_update(rcdev, id, true);
+}
+
+static int sp_reset_deassert(struct reset_controller_dev *rcdev,
+			     unsigned long id)
+{
+	return sp_reset_update(rcdev, id, false);
+}
+
+static int sp_reset_status(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	struct sp_reset *reset = to_sp_reset(rcdev);
+	int index = id / BITS_PER_HWM_REG;
+	int shift = id % BITS_PER_HWM_REG;
+	u32 reg;
+
+	reg = readl(reset->base + (index * 4));
+
+	return !!(reg & BIT(shift));
+}
+
+static const struct reset_control_ops sp_reset_ops = {
+	.assert   = sp_reset_assert,
+	.deassert = sp_reset_deassert,
+	.status   = sp_reset_status,
+};
+
+static int sp_restart(struct notifier_block *nb, unsigned long mode,
+		      void *cmd)
+{
+	struct sp_reset *reset = container_of(nb, struct sp_reset, notifier);
+
+	sp_reset_assert(&reset->rcdev, 0);
+	sp_reset_deassert(&reset->rcdev, 0);
+
+	return NOTIFY_DONE;
+}
+
+static int sp_reset_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sp_reset *reset;
+	struct resource *res;
+	int ret;
+
+	reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL);
+	if (!reset)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reset->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reset->base))
+		return PTR_ERR(reset->base);
+
+	reset->rcdev.ops = &sp_reset_ops;
+	reset->rcdev.owner = THIS_MODULE;
+	reset->rcdev.of_node = dev->of_node;
+	reset->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_HWM_REG;
+
+	ret = devm_reset_controller_register(dev, &reset->rcdev);
+	if (ret)
+		return ret;
+
+	reset->notifier.notifier_call = sp_restart;
+	reset->notifier.priority = 192;
+
+	return register_restart_handler(&reset->notifier);
+}
+
+static const struct of_device_id sp_reset_dt_ids[] = {
+	{.compatible = "sunplus,sp7021-reset",},
+	{ /* sentinel */ },
+};
+
+static struct platform_driver sp_reset_driver = {
+	.probe = sp_reset_probe,
+	.driver = {
+		.name			= "sunplus-reset",
+		.of_match_table		= sp_reset_dt_ids,
+		.suppress_bind_attrs	= true,
+	},
+};
+builtin_platform_driver(sp_reset_driver);
-- 
2.33.1


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

* [PATCH v7 04/10] reset: Add Sunplus SP7021 reset driver
@ 2021-12-22  7:06   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add reset driver for Sunplus SP7021 SoC.

Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 MAINTAINERS                   |   1 +
 drivers/reset/Kconfig         |   9 +++
 drivers/reset/Makefile        |   1 +
 drivers/reset/reset-sunplus.c | 130 ++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+)
 create mode 100644 drivers/reset/reset-sunplus.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 652f42cab..6caffd6d0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2662,6 +2662,7 @@ S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index be799a5ab..fb14456a8 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -224,6 +224,15 @@ config RESET_SOCFPGA
 	  This enables the reset driver for the SoCFPGA ARMv7 platforms. This
 	  driver gets initialized early during platform init calls.
 
+config RESET_SUNPLUS
+	bool "Sunplus SoCs Reset Driver" if COMPILE_TEST
+	default ARCH_SUNPLUS
+	help
+	  This enables the reset driver support for Sunplus SoCs.
+	  The reset lines that can be asserted and deasserted by toggling bits
+	  in a contiguous, exclusive register space. The register is HIWORD_MASKED,
+	  which means each register hold 16 reset lines.
+
 config RESET_SUNXI
 	bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI
 	default ARCH_SUNXI
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 21d46d886..f03403e97 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
 obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
diff --git a/drivers/reset/reset-sunplus.c b/drivers/reset/reset-sunplus.c
new file mode 100644
index 000000000..113b36b57
--- /dev/null
+++ b/drivers/reset/reset-sunplus.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * SP7021 reset driver
+ *
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/reboot.h>
+
+/* HIWORD_MASK_REG BITS */
+#define BITS_PER_HWM_REG	16
+
+struct sp_reset {
+	struct reset_controller_dev rcdev;
+	struct notifier_block notifier;
+	void __iomem *base;
+};
+
+static inline struct sp_reset *to_sp_reset(struct reset_controller_dev *rcdev)
+{
+	return container_of(rcdev, struct sp_reset, rcdev);
+}
+
+static int sp_reset_update(struct reset_controller_dev *rcdev,
+			   unsigned long id, bool assert)
+{
+	struct sp_reset *reset = to_sp_reset(rcdev);
+	int index = id / BITS_PER_HWM_REG;
+	int shift = id % BITS_PER_HWM_REG;
+	u32 val;
+
+	val = (1 << (16 + shift)) | (assert << shift);
+	writel(val, reset->base + (index * 4));
+
+	return 0;
+}
+
+static int sp_reset_assert(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	return sp_reset_update(rcdev, id, true);
+}
+
+static int sp_reset_deassert(struct reset_controller_dev *rcdev,
+			     unsigned long id)
+{
+	return sp_reset_update(rcdev, id, false);
+}
+
+static int sp_reset_status(struct reset_controller_dev *rcdev,
+			   unsigned long id)
+{
+	struct sp_reset *reset = to_sp_reset(rcdev);
+	int index = id / BITS_PER_HWM_REG;
+	int shift = id % BITS_PER_HWM_REG;
+	u32 reg;
+
+	reg = readl(reset->base + (index * 4));
+
+	return !!(reg & BIT(shift));
+}
+
+static const struct reset_control_ops sp_reset_ops = {
+	.assert   = sp_reset_assert,
+	.deassert = sp_reset_deassert,
+	.status   = sp_reset_status,
+};
+
+static int sp_restart(struct notifier_block *nb, unsigned long mode,
+		      void *cmd)
+{
+	struct sp_reset *reset = container_of(nb, struct sp_reset, notifier);
+
+	sp_reset_assert(&reset->rcdev, 0);
+	sp_reset_deassert(&reset->rcdev, 0);
+
+	return NOTIFY_DONE;
+}
+
+static int sp_reset_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sp_reset *reset;
+	struct resource *res;
+	int ret;
+
+	reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL);
+	if (!reset)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reset->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reset->base))
+		return PTR_ERR(reset->base);
+
+	reset->rcdev.ops = &sp_reset_ops;
+	reset->rcdev.owner = THIS_MODULE;
+	reset->rcdev.of_node = dev->of_node;
+	reset->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_HWM_REG;
+
+	ret = devm_reset_controller_register(dev, &reset->rcdev);
+	if (ret)
+		return ret;
+
+	reset->notifier.notifier_call = sp_restart;
+	reset->notifier.priority = 192;
+
+	return register_restart_handler(&reset->notifier);
+}
+
+static const struct of_device_id sp_reset_dt_ids[] = {
+	{.compatible = "sunplus,sp7021-reset",},
+	{ /* sentinel */ },
+};
+
+static struct platform_driver sp_reset_driver = {
+	.probe = sp_reset_probe,
+	.driver = {
+		.name			= "sunplus-reset",
+		.of_match_table		= sp_reset_dt_ids,
+		.suppress_bind_attrs	= true,
+	},
+};
+builtin_platform_driver(sp_reset_driver);
-- 
2.33.1


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

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

* [PATCH v7 05/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:06   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add documentation to describe Sunplus SP7021 clock driver bindings.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Add clocks & clock-names.
---
 .../bindings/clock/sunplus,sp7021-clkc.yaml   |  52 ++++++++
 MAINTAINERS                                   |   2 +
 include/dt-bindings/clock/sp-sp7021.h         | 112 ++++++++++++++++++
 3 files changed, 166 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 create mode 100644 include/dt-bindings/clock/sp-sp7021.h

diff --git a/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml b/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
new file mode 100644
index 000000000..e6d098cf4
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/sunplus,sp7021-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 SoC Clock Controller Binding
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-clkc
+
+  "#clock-cells":
+    const: 1
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: External oscillator clock
+      - description: System clock
+
+  clock-names:
+    items:
+      - const: extclk
+      - const: pllsys
+
+required:
+  - compatible
+  - "#clock-cells"
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    clkc: clock-controller@9c000000 {
+      compatible = "sunplus,sp7021-clkc";
+      #clock-cells = <1>;
+      reg = <0x9c000000 0x280>;
+      clocks = <&extclk>, <&clkc PLL_SYS>;
+      clock-names = "extclk", "pllsys";
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 6caffd6d0..90ebb823f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2661,8 +2661,10 @@ L:	linux-arm-kernel@lists.infradead.org (moderated for mon-subscribers)
 S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 F:	drivers/reset/reset-sunplus.c
+F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
diff --git a/include/dt-bindings/clock/sp-sp7021.h b/include/dt-bindings/clock/sp-sp7021.h
new file mode 100644
index 000000000..45dac6de8
--- /dev/null
+++ b/include/dt-bindings/clock/sp-sp7021.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#ifndef _DT_BINDINGS_CLOCK_SUNPLUS_SP7021_H
+#define _DT_BINDINGS_CLOCK_SUNPLUS_SP7021_H
+
+#define XTAL			27000000
+
+/* plls */
+#define PLL_A			0
+#define PLL_E			1
+#define PLL_E_2P5		2
+#define PLL_E_25		3
+#define PLL_E_112P5		4
+#define PLL_F			5
+#define PLL_TV			6
+#define PLL_TV_A		7
+#define PLL_SYS			8
+
+/* gates: mo_clken0 ~ mo_clken9 */
+#define CLK_SYSTEM		0x10
+#define CLK_RTC			0x12
+#define CLK_IOCTL		0x13
+#define CLK_IOP			0x14
+#define CLK_OTPRX		0x15
+#define CLK_NOC			0x16
+#define CLK_BR			0x17
+#define CLK_RBUS_L00	        0x18
+#define CLK_SPIFL		0x19
+#define CLK_SDCTRL0		0x1a
+#define CLK_PERI0		0x1b
+#define CLK_A926		0x1d
+#define CLK_UMCTL2		0x1e
+#define CLK_PERI1		0x1f
+
+#define CLK_DDR_PHY0	        0x20
+#define CLK_ACHIP		0x22
+#define CLK_STC0		0x24
+#define CLK_STC_AV0		0x25
+#define CLK_STC_AV1		0x26
+#define CLK_STC_AV2		0x27
+#define CLK_UA0			0x28
+#define CLK_UA1			0x29
+#define CLK_UA2			0x2a
+#define CLK_UA3			0x2b
+#define CLK_UA4			0x2c
+#define CLK_HWUA		0x2d
+#define CLK_DDC0		0x2e
+#define CLK_UADMA		0x2f
+
+#define CLK_CBDMA0		0x30
+#define CLK_CBDMA1		0x31
+#define CLK_SPI_COMBO_0	        0x32
+#define CLK_SPI_COMBO_1	        0x33
+#define CLK_SPI_COMBO_2	        0x34
+#define CLK_SPI_COMBO_3	        0x35
+#define CLK_AUD			0x36
+#define CLK_USBC0		0x3a
+#define CLK_USBC1		0x3b
+#define CLK_UPHY0		0x3d
+#define CLK_UPHY1		0x3e
+
+#define CLK_I2CM0		0x40
+#define CLK_I2CM1		0x41
+#define CLK_I2CM2		0x42
+#define CLK_I2CM3		0x43
+#define CLK_PMC			0x4d
+#define CLK_CARD_CTL0	        0x4e
+#define CLK_CARD_CTL1	        0x4f
+
+#define CLK_CARD_CTL4	        0x52
+#define CLK_BCH			0x54
+#define CLK_DDFCH		0x5b
+#define CLK_CSIIW0		0x5c
+#define CLK_CSIIW1		0x5d
+#define CLK_MIPICSI0	        0x5e
+#define CLK_MIPICSI1	        0x5f
+
+#define CLK_HDMI_TX		0x60
+#define CLK_VPOST		0x65
+
+#define CLK_TGEN		0x70
+#define CLK_DMIX		0x71
+#define CLK_TCON		0x7a
+#define CLK_INTERRUPT	        0x7f
+
+#define CLK_RGST		0x80
+#define CLK_GPIO		0x83
+#define CLK_RBUS_TOP	        0x84
+
+#define CLK_MAILBOX		0x96
+#define CLK_SPIND		0x9a
+#define CLK_I2C2CBUS	        0x9b
+#define CLK_SEC			0x9d
+#define CLK_DVE			0x9e
+#define CLK_GPOST0		0x9f
+
+#define CLK_OSD0		0xa0
+#define CLK_DISP_PWM	        0xa2
+#define CLK_UADBG		0xa3
+#define CLK_DUMMY_MASTER	0xa4
+#define CLK_FIO_CTL		0xa5
+#define CLK_FPGA		0xa6
+#define CLK_L2SW		0xa7
+#define CLK_ICM			0xa8
+#define CLK_AXI_GLOBAL	        0xa9
+
+#define CLK_MAX			0xb0
+
+#endif
-- 
2.33.1


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

* [PATCH v7 05/10] dt-bindings: clock: Add bindings for SP7021 clock driver
@ 2021-12-22  7:06   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add documentation to describe Sunplus SP7021 clock driver bindings.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Add clocks & clock-names.
---
 .../bindings/clock/sunplus,sp7021-clkc.yaml   |  52 ++++++++
 MAINTAINERS                                   |   2 +
 include/dt-bindings/clock/sp-sp7021.h         | 112 ++++++++++++++++++
 3 files changed, 166 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 create mode 100644 include/dt-bindings/clock/sp-sp7021.h

diff --git a/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml b/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
new file mode 100644
index 000000000..e6d098cf4
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/sunplus,sp7021-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 SoC Clock Controller Binding
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-clkc
+
+  "#clock-cells":
+    const: 1
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: External oscillator clock
+      - description: System clock
+
+  clock-names:
+    items:
+      - const: extclk
+      - const: pllsys
+
+required:
+  - compatible
+  - "#clock-cells"
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    clkc: clock-controller@9c000000 {
+      compatible = "sunplus,sp7021-clkc";
+      #clock-cells = <1>;
+      reg = <0x9c000000 0x280>;
+      clocks = <&extclk>, <&clkc PLL_SYS>;
+      clock-names = "extclk", "pllsys";
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 6caffd6d0..90ebb823f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2661,8 +2661,10 @@ L:	linux-arm-kernel@lists.infradead.org (moderated for mon-subscribers)
 S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 F:	drivers/reset/reset-sunplus.c
+F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
diff --git a/include/dt-bindings/clock/sp-sp7021.h b/include/dt-bindings/clock/sp-sp7021.h
new file mode 100644
index 000000000..45dac6de8
--- /dev/null
+++ b/include/dt-bindings/clock/sp-sp7021.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#ifndef _DT_BINDINGS_CLOCK_SUNPLUS_SP7021_H
+#define _DT_BINDINGS_CLOCK_SUNPLUS_SP7021_H
+
+#define XTAL			27000000
+
+/* plls */
+#define PLL_A			0
+#define PLL_E			1
+#define PLL_E_2P5		2
+#define PLL_E_25		3
+#define PLL_E_112P5		4
+#define PLL_F			5
+#define PLL_TV			6
+#define PLL_TV_A		7
+#define PLL_SYS			8
+
+/* gates: mo_clken0 ~ mo_clken9 */
+#define CLK_SYSTEM		0x10
+#define CLK_RTC			0x12
+#define CLK_IOCTL		0x13
+#define CLK_IOP			0x14
+#define CLK_OTPRX		0x15
+#define CLK_NOC			0x16
+#define CLK_BR			0x17
+#define CLK_RBUS_L00	        0x18
+#define CLK_SPIFL		0x19
+#define CLK_SDCTRL0		0x1a
+#define CLK_PERI0		0x1b
+#define CLK_A926		0x1d
+#define CLK_UMCTL2		0x1e
+#define CLK_PERI1		0x1f
+
+#define CLK_DDR_PHY0	        0x20
+#define CLK_ACHIP		0x22
+#define CLK_STC0		0x24
+#define CLK_STC_AV0		0x25
+#define CLK_STC_AV1		0x26
+#define CLK_STC_AV2		0x27
+#define CLK_UA0			0x28
+#define CLK_UA1			0x29
+#define CLK_UA2			0x2a
+#define CLK_UA3			0x2b
+#define CLK_UA4			0x2c
+#define CLK_HWUA		0x2d
+#define CLK_DDC0		0x2e
+#define CLK_UADMA		0x2f
+
+#define CLK_CBDMA0		0x30
+#define CLK_CBDMA1		0x31
+#define CLK_SPI_COMBO_0	        0x32
+#define CLK_SPI_COMBO_1	        0x33
+#define CLK_SPI_COMBO_2	        0x34
+#define CLK_SPI_COMBO_3	        0x35
+#define CLK_AUD			0x36
+#define CLK_USBC0		0x3a
+#define CLK_USBC1		0x3b
+#define CLK_UPHY0		0x3d
+#define CLK_UPHY1		0x3e
+
+#define CLK_I2CM0		0x40
+#define CLK_I2CM1		0x41
+#define CLK_I2CM2		0x42
+#define CLK_I2CM3		0x43
+#define CLK_PMC			0x4d
+#define CLK_CARD_CTL0	        0x4e
+#define CLK_CARD_CTL1	        0x4f
+
+#define CLK_CARD_CTL4	        0x52
+#define CLK_BCH			0x54
+#define CLK_DDFCH		0x5b
+#define CLK_CSIIW0		0x5c
+#define CLK_CSIIW1		0x5d
+#define CLK_MIPICSI0	        0x5e
+#define CLK_MIPICSI1	        0x5f
+
+#define CLK_HDMI_TX		0x60
+#define CLK_VPOST		0x65
+
+#define CLK_TGEN		0x70
+#define CLK_DMIX		0x71
+#define CLK_TCON		0x7a
+#define CLK_INTERRUPT	        0x7f
+
+#define CLK_RGST		0x80
+#define CLK_GPIO		0x83
+#define CLK_RBUS_TOP	        0x84
+
+#define CLK_MAILBOX		0x96
+#define CLK_SPIND		0x9a
+#define CLK_I2C2CBUS	        0x9b
+#define CLK_SEC			0x9d
+#define CLK_DVE			0x9e
+#define CLK_GPOST0		0x9f
+
+#define CLK_OSD0		0xa0
+#define CLK_DISP_PWM	        0xa2
+#define CLK_UADBG		0xa3
+#define CLK_DUMMY_MASTER	0xa4
+#define CLK_FIO_CTL		0xa5
+#define CLK_FPGA		0xa6
+#define CLK_L2SW		0xa7
+#define CLK_ICM			0xa8
+#define CLK_AXI_GLOBAL	        0xa9
+
+#define CLK_MAX			0xb0
+
+#endif
-- 
2.33.1


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

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

* [PATCH v7 06/10] clk: Add Sunplus SP7021 clock driver
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:06   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add clock driver for Sunplus SP7021 SoC.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Fix the comments from Stephen Boyd.
---
 MAINTAINERS              |   1 +
 drivers/clk/Kconfig      |  10 +-
 drivers/clk/Makefile     |   1 +
 drivers/clk/clk-sp7021.c | 705 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 716 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/clk-sp7021.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 90ebb823f..5069f552f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2663,6 +2663,7 @@ W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	drivers/clk/clk-sp7021.c
 F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c5b3dc973..4a186ccf6 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -334,6 +334,15 @@ config COMMON_CLK_VC5
 	  This driver supports the IDT VersaClock 5 and VersaClock 6
 	  programmable clock generators.
 
+config COMMON_CLK_SP7021
+	bool "Clock driver for Sunplus SP7021 SoC"
+	default SOC_SP7021
+	help
+	  This driver supports the Sunplus SP7021 SoC clocks.
+	  It implements SP7021 PLLs/gate.
+	  Not all features of the PLL are currently supported
+	  by the driver.
+
 config COMMON_CLK_STM32MP157
 	def_bool COMMON_CLK && MACH_STM32MP157
 	help
@@ -366,7 +375,6 @@ config COMMON_CLK_MMP2
 
 config COMMON_CLK_MMP2_AUDIO
         tristate "Clock driver for MMP2 Audio subsystem"
-        depends on COMMON_CLK_MMP2 || COMPILE_TEST
         help
           This driver supports clocks for Audio subsystem on MMP2 SoC.
 
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e42312121..f15bb5070 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351)		+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)		+= clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI544)		+= clk-si544.o
 obj-$(CONFIG_COMMON_CLK_SI570)		+= clk-si570.o
+obj-$(CONFIG_COMMON_CLK_SP7021)		+= clk-sp7021.o
 obj-$(CONFIG_COMMON_CLK_STM32F)		+= clk-stm32f4.o
 obj-$(CONFIG_COMMON_CLK_STM32H7)	+= clk-stm32h7.o
 obj-$(CONFIG_COMMON_CLK_STM32MP157)	+= clk-stm32mp1.o
diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c
new file mode 100644
index 000000000..6df87f0a6
--- /dev/null
+++ b/drivers/clk/clk-sp7021.c
@@ -0,0 +1,705 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+//#define DEBUG
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/bitfield.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <dt-bindings/clock/sp-sp7021.h>
+
+#define REG(i)		(pll_regs + (i) * 4)
+
+#define PLLA_CTL	REG(7)
+#define PLLE_CTL	REG(12)
+#define PLLF_CTL	REG(13)
+#define PLLTV_CTL	REG(14)
+#define PLLSYS_CTL	REG(26)
+
+#define EXTCLK		"extclk"
+
+/* speical div_width values for PLLTV/PLLA */
+#define DIV_TV		33
+#define DIV_A		34
+
+/* PLLTV parameters */
+enum {
+	SEL_FRA,
+	SDM_MOD,
+	PH_SEL,
+	NFRA,
+	DIVR,
+	DIVN,
+	DIVM,
+	P_MAX
+};
+
+#define MASK_SEL_FRA	GENMASK(1, 1)
+#define MASK_SDM_MOD	GENMASK(2, 2)
+#define MASK_PH_SEL	GENMASK(4, 4)
+#define MASK_NFRA	GENMASK(12, 6)
+#define MASK_DIVR	GENMASK(8, 7)
+#define MASK_DIVN	GENMASK(7, 0)
+#define MASK_DIVM	GENMASK(14, 8)
+
+/* HIWORD_MASK FIELD_PREP */
+#define HWM_FIELD_PREP(mask, value)		\
+({						\
+	u32 m = mask;				\
+	(m << 16) | FIELD_PREP(m, value);	\
+})
+
+struct sp_pll {
+	struct clk_hw hw;
+	void __iomem *reg;
+	spinlock_t *lock;	/* lock for reg */
+	int div_shift;
+	int div_width;
+	int pd_bit;		/* power down bit idx */
+	int bp_bit;		/* bypass bit idx */
+	unsigned long brate;	/* base rate, TODO: replace brate with muldiv */
+	u32 p[P_MAX];		/* for hold PLLTV/PLLA parameters */
+};
+
+#define to_sp_pll(_hw)	container_of(_hw, struct sp_pll, hw)
+
+#define clk_regs	(sp_clk_base + 0x000) /* G0 ~ CLKEN */
+#define pll_regs	(sp_clk_base + 0x200) /* G4 ~ PLL */
+static void __iomem *sp_clk_base;
+static struct clk_hw_onecell_data *sp_clk_data;
+
+#define P_EXTCLK	BIT(16)
+const struct clk_parent_data parents[] = {
+	{ .fw_name = "pllsys" },
+	{ .fw_name = "extclk" },
+};
+
+static const u32 gates[] = {
+	CLK_SYSTEM,
+	CLK_RTC,
+	CLK_IOCTL,
+	CLK_IOP,
+	CLK_OTPRX,
+	CLK_NOC,
+	CLK_BR,
+	CLK_RBUS_L00,
+	CLK_SPIFL,
+	CLK_SDCTRL0,
+	CLK_PERI0 | P_EXTCLK,
+	CLK_A926,
+	CLK_UMCTL2,
+	CLK_PERI1 | P_EXTCLK,
+
+	CLK_DDR_PHY0,
+	CLK_ACHIP,
+	CLK_STC0,
+	CLK_STC_AV0,
+	CLK_STC_AV1,
+	CLK_STC_AV2,
+	CLK_UA0 | P_EXTCLK,
+	CLK_UA1 | P_EXTCLK,
+	CLK_UA2 | P_EXTCLK,
+	CLK_UA3 | P_EXTCLK,
+	CLK_UA4 | P_EXTCLK,
+	CLK_HWUA | P_EXTCLK,
+	CLK_DDC0,
+	CLK_UADMA | P_EXTCLK,
+
+	CLK_CBDMA0,
+	CLK_CBDMA1,
+	CLK_SPI_COMBO_0,
+	CLK_SPI_COMBO_1,
+	CLK_SPI_COMBO_2,
+	CLK_SPI_COMBO_3,
+	CLK_AUD,
+	CLK_USBC0,
+	CLK_USBC1,
+	CLK_UPHY0,
+	CLK_UPHY1,
+
+	CLK_I2CM0,
+	CLK_I2CM1,
+	CLK_I2CM2,
+	CLK_I2CM3,
+	CLK_PMC,
+	CLK_CARD_CTL0,
+	CLK_CARD_CTL1,
+
+	CLK_CARD_CTL4,
+	CLK_BCH,
+	CLK_DDFCH,
+	CLK_CSIIW0,
+	CLK_CSIIW1,
+	CLK_MIPICSI0,
+	CLK_MIPICSI1,
+
+	CLK_HDMI_TX,
+	CLK_VPOST,
+
+	CLK_TGEN,
+	CLK_DMIX,
+	CLK_TCON,
+	CLK_INTERRUPT,
+
+	CLK_RGST,
+	CLK_GPIO,
+	CLK_RBUS_TOP,
+
+	CLK_MAILBOX,
+	CLK_SPIND,
+	CLK_I2C2CBUS,
+	CLK_SEC,
+	CLK_GPOST0,
+	CLK_DVE,
+
+	CLK_OSD0,
+	CLK_DISP_PWM,
+	CLK_UADBG,
+	CLK_DUMMY_MASTER,
+	CLK_FIO_CTL,
+	CLK_FPGA,
+	CLK_L2SW,
+	CLK_ICM,
+	CLK_AXI_GLOBAL,
+};
+
+static DEFINE_SPINLOCK(plla_lock);
+static DEFINE_SPINLOCK(plle_lock);
+static DEFINE_SPINLOCK(pllf_lock);
+static DEFINE_SPINLOCK(pllsys_lock);
+static DEFINE_SPINLOCK(plltv_lock);
+
+#define _M		1000000UL
+#define F_27M		(27 * _M)
+
+/*********************************** PLL_TV **********************************/
+
+/* TODO: set proper FVCO range */
+#define FVCO_MIN	(100 * _M)
+#define FVCO_MAX	(200 * _M)
+
+#define F_MIN		(FVCO_MIN / 8)
+#define F_MAX		(FVCO_MAX)
+
+static long plltv_integer_div(struct sp_pll *clk, unsigned long freq)
+{
+	/* valid m values: 27M must be divisible by m, 0 means end */
+	static const u32 m_table[] = {
+		1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 0
+	};
+	u32 m, n, r;
+	unsigned long fvco, nf;
+
+	/* check freq */
+	if (freq < F_MIN) {
+		pr_warn("%s: %s freq:%lu < F_MIN:%lu, round up\n",
+			__func__, clk_hw_get_name(&clk->hw), freq, F_MIN);
+		freq = F_MIN;
+	} else if (freq > F_MAX) {
+		pr_warn("%s: %s freq:%lu > F_MAX:%lu, round down\n",
+			__func__, clk_hw_get_name(&clk->hw), freq, F_MAX);
+		freq = F_MAX;
+	}
+
+	/* DIVR 0~3 */
+	for (r = 0; r <= 3; r++) {
+		fvco = freq << r;
+		if (fvco <= FVCO_MAX)
+			break;
+	}
+
+	/* DIVM */
+	for (m = 0; m_table[m]; m++) {
+		nf = fvco * m_table[m];
+		n = nf / F_27M;
+		if ((n * F_27M) == nf)
+			break;
+	}
+	m = m_table[m];
+
+	if (!m) {
+		pr_err("%s: %s freq:%lu not found a valid setting\n",
+		       __func__, clk_hw_get_name(&clk->hw), freq);
+		return -EINVAL;
+	}
+
+	/* save parameters */
+	clk->p[SEL_FRA] = 0;
+	clk->p[DIVR]    = r;
+	clk->p[DIVN]    = n;
+	clk->p[DIVM]    = m;
+
+	return freq;
+}
+
+/* parameters for PLLTV fractional divider */
+static const u32 pt[][5] = {
+	/* conventional fractional */
+	{
+		1,			// factor
+		5,			// 5 * p0 (nint)
+		1,			// 1 * p0
+		F_27M,			// F_27M / p0
+		1,			// p0 / p2
+	},
+	/* phase rotation */
+	{
+		10,			// factor
+		54,			// 5.4 * p0 (nint)
+		2,			// 0.2 * p0
+		F_27M / 10,		// F_27M / p0
+		5,			// p0 / p2
+	},
+};
+
+static const u32 mods[] = { 91, 55 }; /* SDM_MOD mod values */
+
+static long plltv_fractional_div(struct sp_pll *clk, unsigned long freq)
+{
+	u32 m, r;
+	u32 nint, nfra;
+	u32 df_quotient_min = 210000000;
+	u32 df_remainder_min = 0;
+	unsigned long fvco, nf, f, fout = 0;
+	int sdm, ph;
+
+	/* check freq */
+	if (freq < F_MIN) {
+		pr_warn("%s: %s freq:%lu < F_MIN:%lu, round up\n",
+			__func__, clk_hw_get_name(&clk->hw), freq, F_MIN);
+		freq = F_MIN;
+	} else if (freq > F_MAX) {
+		pr_warn("%s: %s freq:%lu > F_MAX:%lu, round down\n",
+			__func__, clk_hw_get_name(&clk->hw), freq, F_MAX);
+		freq = F_MAX;
+	}
+
+	/* DIVR 0~3 */
+	for (r = 0; r <= 3; r++) {
+		fvco = freq << r;
+		if (fvco <= FVCO_MAX)
+			break;
+	}
+	f = F_27M >> r;
+
+	/* PH_SEL 1/0 */
+	for (ph = 1; ph >= 0; ph--) {
+		const u32 *pp = pt[ph];
+		u32 ms = 1;
+
+		/* SDM_MOD 0/1 */
+		for (sdm = 0; sdm <= 1; sdm++) {
+			u32 mod = mods[sdm];
+
+			/* DIVM 1~32 */
+			for (m = ms; m <= 32; m++) {
+				u32 df; /* diff freq */
+				u32 df_quotient = 0, df_remainder = 0;
+
+				nf = fvco * m;
+				nint = nf / pp[3];
+
+				if (nint < pp[1])
+					continue;
+				if (nint > pp[1])
+					break;
+
+				nfra = (((nf % pp[3]) * mod * pp[4]) + (F_27M / 2)) / F_27M;
+				if (nfra)
+					df = (f * (nint + pp[2]) / pp[0]) -
+						    (f * (mod - nfra) / mod / pp[4]);
+				else
+					df = (f * (nint) / pp[0]);
+
+				df_quotient  = df / m;
+				df_remainder = ((df % m) * 1000) / m;
+
+				if (freq > df_quotient) {
+					df_quotient  = freq - df_quotient - 1;
+					df_remainder = 1000 - df_remainder;
+				} else {
+					df_quotient = df_quotient - freq;
+				}
+
+				if (df_quotient_min > df_quotient ||
+				    (df_quotient_min == df_quotient &&
+				    df_remainder_min > df_remainder)) {
+					/* found a closer freq, save parameters */
+					clk->p[SEL_FRA] = 1;
+					clk->p[SDM_MOD] = sdm;
+					clk->p[PH_SEL]  = ph;
+					clk->p[NFRA]    = nfra;
+					clk->p[DIVR]    = r;
+					clk->p[DIVM]    = m;
+
+					fout = df / m;
+					df_quotient_min = df_quotient;
+					df_remainder_min = df_remainder;
+				}
+			}
+		}
+	}
+
+	if (!fout) {
+		pr_err("%s: %s freq:%lu not found a valid setting\n",
+		       __func__, clk_hw_get_name(&clk->hw), freq);
+		return -EINVAL;
+	}
+
+	return fout;
+}
+
+static long plltv_div(struct sp_pll *clk, unsigned long freq)
+{
+	if (freq % 100)
+		return plltv_fractional_div(clk, freq);
+	else
+		return plltv_integer_div(clk, freq);
+}
+
+static void plltv_set_rate(struct sp_pll *clk)
+{
+	u32 reg;
+
+	reg  = HWM_FIELD_PREP(MASK_SEL_FRA, clk->p[SEL_FRA]);
+	reg |= HWM_FIELD_PREP(MASK_SDM_MOD, clk->p[SDM_MOD]);
+	reg |= HWM_FIELD_PREP(MASK_PH_SEL, clk->p[PH_SEL]);
+	reg |= HWM_FIELD_PREP(MASK_NFRA, clk->p[NFRA]);
+	writel(reg, clk->reg);
+
+	reg  = HWM_FIELD_PREP(MASK_DIVR, clk->p[DIVR]);
+	writel(reg, clk->reg + 4);
+
+	reg  = HWM_FIELD_PREP(MASK_DIVN, clk->p[DIVN] - 1);
+	reg |= HWM_FIELD_PREP(MASK_DIVM, clk->p[DIVM] - 1);
+	writel(reg, clk->reg + 8);
+}
+
+/*********************************** PLL_A ***********************************/
+
+/* from Q628_PLLs_REG_setting.xlsx */
+static const struct {
+	u32 rate;
+	u32 regs[5];
+} pa[] = {
+	{
+		.rate = 135475200,
+		.regs = {
+			0x4801,
+			0x02df,
+			0x248f,
+			0x0211,
+			0x33e9
+		}
+	},
+	{
+		.rate = 147456000,
+		.regs = {
+			0x4801,
+			0x1adf,
+			0x2490,
+			0x0349,
+			0x33e9
+		}
+	},
+	{
+		.rate = 196608000,
+		.regs = {
+			0x4801,
+			0x42ef,
+			0x2495,
+			0x01c6,
+			0x33e9
+		}
+	},
+};
+
+static void plla_set_rate(struct sp_pll *clk)
+{
+	const u32 *pp = pa[clk->p[0]].regs;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pa->regs); i++)
+		writel(0xffff0000 | pp[i], clk->reg + (i * 4));
+}
+
+static long plla_round_rate(struct sp_pll *clk, unsigned long rate)
+{
+	int i = ARRAY_SIZE(pa);
+
+	while (--i) {
+		if (rate >= pa[i].rate)
+			break;
+	}
+	clk->p[0] = i;
+	return pa[i].rate;
+}
+
+/********************************** SP_PLL ***********************************/
+
+static long sp_pll_calc_div(struct sp_pll *clk, unsigned long rate)
+{
+	u32 fbdiv;
+	u32 max = 1 << clk->div_width;
+
+	fbdiv = DIV_ROUND_CLOSEST(rate, clk->brate);
+	if (fbdiv > max)
+		fbdiv = max;
+	return fbdiv;
+}
+
+static long sp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+			      unsigned long *prate)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	long ret;
+
+	if (rate == *prate)
+		ret = *prate; /* bypass */
+	else if (clk->div_width == DIV_A) {
+		ret = plla_round_rate(clk, rate);
+	} else if (clk->div_width == DIV_TV) {
+		ret = plltv_div(clk, rate);
+		if (ret < 0)
+			ret = *prate;
+	} else {
+		ret = sp_pll_calc_div(clk, rate) * clk->brate;
+	}
+
+	return ret;
+}
+
+static unsigned long sp_pll_recalc_rate(struct clk_hw *hw,
+					unsigned long prate)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	u32 reg = readl(clk->reg);
+	unsigned long ret;
+
+	if (reg & BIT(clk->bp_bit))
+		ret = prate; /* bypass */
+	else if (clk->div_width == DIV_A)
+		ret = pa[clk->p[0]].rate;
+	else if (clk->div_width == DIV_TV) {
+		u32 m, r, reg2;
+
+		r = FIELD_GET(MASK_DIVR, readl(clk->reg + 4));
+		reg2 = readl(clk->reg + 8);
+		m = FIELD_GET(MASK_DIVM, reg2) + 1;
+
+		if (reg & BIT(1)) { /* SEL_FRA */
+			/* fractional divider */
+			u32 sdm  = FIELD_GET(MASK_SDM_MOD, reg);
+			u32 ph   = FIELD_GET(MASK_PH_SEL, reg);
+			u32 nfra = FIELD_GET(MASK_NFRA, reg);
+			const u32 *pp = pt[ph];
+
+			ret = prate >> r;
+			ret = (ret * (pp[1] + pp[2]) / pp[0]) -
+				  (ret * (mods[sdm] - nfra) / mods[sdm] / pp[4]);
+			ret /= m;
+		} else {
+			/* integer divider */
+			u32 n = FIELD_GET(MASK_DIVN, reg2) + 1;
+
+			ret = (prate / m * n) >> r;
+		}
+	} else {
+		u32 fbdiv = ((reg >> clk->div_shift) & ((1 << clk->div_width) - 1)) + 1;
+
+		ret = clk->brate * fbdiv;
+	}
+
+	return ret;
+}
+
+static int sp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+			   unsigned long prate)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(clk->lock, flags);
+
+	reg = BIT(clk->bp_bit + 16); /* HIWORD_MASK */
+
+	if (rate == prate)
+		reg |= BIT(clk->bp_bit); /* bypass */
+	else if (clk->div_width == DIV_A)
+		plla_set_rate(clk);
+	else if (clk->div_width == DIV_TV)
+		plltv_set_rate(clk);
+	else if (clk->div_width) {
+		u32 fbdiv = sp_pll_calc_div(clk, rate);
+		u32 mask = GENMASK(clk->div_shift + clk->div_width - 1, clk->div_shift);
+
+		reg |= (mask << 16) | (((fbdiv - 1) << clk->div_shift) & mask);
+	}
+
+	writel(reg, clk->reg);
+
+	spin_unlock_irqrestore(clk->lock, flags);
+
+	return 0;
+}
+
+static int sp_pll_enable(struct clk_hw *hw)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(clk->lock, flags);
+	writel(BIT(clk->pd_bit + 16) | BIT(clk->pd_bit), clk->reg); /* power up */
+	spin_unlock_irqrestore(clk->lock, flags);
+
+	return 0;
+}
+
+static void sp_pll_disable(struct clk_hw *hw)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(clk->lock, flags);
+	writel(BIT(clk->pd_bit + 16), clk->reg); /* power down */
+	spin_unlock_irqrestore(clk->lock, flags);
+}
+
+static int sp_pll_is_enabled(struct clk_hw *hw)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+
+	return readl(clk->reg) & BIT(clk->pd_bit);
+}
+
+static const struct clk_ops sp_pll_ops = {
+	.enable = sp_pll_enable,
+	.disable = sp_pll_disable,
+	.is_enabled = sp_pll_is_enabled,
+	.round_rate = sp_pll_round_rate,
+	.recalc_rate = sp_pll_recalc_rate,
+	.set_rate = sp_pll_set_rate
+};
+
+static const struct clk_ops sp_pll_sub_ops = {
+	.enable = sp_pll_enable,
+	.disable = sp_pll_disable,
+	.is_enabled = sp_pll_is_enabled,
+	.recalc_rate = sp_pll_recalc_rate,
+};
+
+struct clk_hw *sp_pll_register(const char *name, const char *parent,
+			       void __iomem *reg, int pd_bit, int bp_bit,
+			       unsigned long brate, int shift, int width,
+			       spinlock_t *lock)
+{
+	struct sp_pll *pll;
+	struct clk_hw *hw;
+	struct clk_init_data initd = {
+		.name = name,
+		.parent_names = &parent,
+		.ops = (bp_bit >= 0) ? &sp_pll_ops : &sp_pll_sub_ops,
+		.num_parents = 1,
+	};
+	int ret;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	if (reg == PLLSYS_CTL) /* system clock, should not be closed */
+		initd.flags |= CLK_IS_CRITICAL;
+
+	pll->hw.init = &initd;
+	pll->reg = reg;
+	pll->pd_bit = pd_bit;
+	pll->bp_bit = bp_bit;
+	pll->brate = brate;
+	pll->div_shift = shift;
+	pll->div_width = width;
+	pll->lock = lock;
+
+	hw = &pll->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(pll);
+		hw = ERR_PTR(ret);
+	} else {
+		pr_info("%-20s%lu\n", name, clk_hw_get_rate(hw));
+		clk_hw_register_clkdev(hw, NULL, name);
+	}
+
+	return hw;
+}
+
+static void __init sp_clk_setup(struct device_node *np)
+{
+	int i, j;
+	struct clk_hw **hws;
+
+	sp_clk_base = of_iomap(np, 0);
+	if (WARN_ON(!sp_clk_base))
+		return; /* -ENXIO */
+
+	sp_clk_data = kzalloc(struct_size(sp_clk_data, hws, CLK_MAX), GFP_KERNEL);
+	if (!sp_clk_data)
+		return; /* -ENOMEM */
+
+	hws = sp_clk_data->hws;
+
+	/* PLL_A */
+	hws[PLL_A] = sp_pll_register("plla", EXTCLK, PLLA_CTL, 11, 12,
+				     27000000, 0, DIV_A, &plla_lock);
+
+	/* PLL_E */
+	hws[PLL_E] = sp_pll_register("plle", EXTCLK, PLLE_CTL, 6, 2,
+				     50000000, 0, 0, &plle_lock);
+	hws[PLL_E_2P5] = sp_pll_register("plle_2p5", "plle", PLLE_CTL, 13, -1,
+					 2500000, 0, 0, &plle_lock);
+	hws[PLL_E_25] = sp_pll_register("plle_25", "plle", PLLE_CTL, 12, -1,
+					25000000, 0, 0, &plle_lock);
+	hws[PLL_E_112P5] = sp_pll_register("plle_112p5", "plle", PLLE_CTL, 11, -1,
+					   112500000, 0, 0, &plle_lock);
+
+	/* PLL_F */
+	hws[PLL_F] = sp_pll_register("pllf", EXTCLK, PLLF_CTL, 0, 10,
+				     13500000, 1, 4, &pllf_lock);
+
+	/* PLL_TV */
+	hws[PLL_TV] = sp_pll_register("plltv", EXTCLK, PLLTV_CTL, 0, 15,
+				      27000000, 0, DIV_TV, &plltv_lock);
+	hws[PLL_TV_A] = clk_hw_register_divider(NULL, "plltv_a", "plltv", 0,
+						PLLTV_CTL + 4, 5, 1,
+						CLK_DIVIDER_POWER_OF_TWO,
+						&plltv_lock);
+	clk_hw_register_clkdev(hws[PLL_TV_A], NULL, "plltv_a");
+
+	/* PLL_SYS */
+	hws[PLL_SYS] = sp_pll_register("pllsys", EXTCLK, PLLSYS_CTL, 10, 9,
+				       13500000, 0, 4, &pllsys_lock);
+
+	/* gates */
+	for (i = 0; i < ARRAY_SIZE(gates); i++) {
+		char s[10];
+
+		j = gates[i] & 0xffff;
+		sprintf(s, "clken%02x", j);
+		hws[j] = clk_hw_register_gate(NULL, s,
+					      parents[gates[i] >> 16].fw_name,
+					      CLK_IGNORE_UNUSED,
+					      clk_regs + (j >> 4) * 4, j & 0x0f,
+					      CLK_GATE_HIWORD_MASK, NULL);
+	}
+
+	sp_clk_data->num = CLK_MAX;
+	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, sp_clk_data);
+}
+
+CLK_OF_DECLARE_DRIVER(sp_clkc, "sunplus,sp7021-clkc", sp_clk_setup);
-- 
2.33.1


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

* [PATCH v7 06/10] clk: Add Sunplus SP7021 clock driver
@ 2021-12-22  7:06   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add clock driver for Sunplus SP7021 SoC.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Fix the comments from Stephen Boyd.
---
 MAINTAINERS              |   1 +
 drivers/clk/Kconfig      |  10 +-
 drivers/clk/Makefile     |   1 +
 drivers/clk/clk-sp7021.c | 705 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 716 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/clk-sp7021.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 90ebb823f..5069f552f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2663,6 +2663,7 @@ W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	drivers/clk/clk-sp7021.c
 F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c5b3dc973..4a186ccf6 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -334,6 +334,15 @@ config COMMON_CLK_VC5
 	  This driver supports the IDT VersaClock 5 and VersaClock 6
 	  programmable clock generators.
 
+config COMMON_CLK_SP7021
+	bool "Clock driver for Sunplus SP7021 SoC"
+	default SOC_SP7021
+	help
+	  This driver supports the Sunplus SP7021 SoC clocks.
+	  It implements SP7021 PLLs/gate.
+	  Not all features of the PLL are currently supported
+	  by the driver.
+
 config COMMON_CLK_STM32MP157
 	def_bool COMMON_CLK && MACH_STM32MP157
 	help
@@ -366,7 +375,6 @@ config COMMON_CLK_MMP2
 
 config COMMON_CLK_MMP2_AUDIO
         tristate "Clock driver for MMP2 Audio subsystem"
-        depends on COMMON_CLK_MMP2 || COMPILE_TEST
         help
           This driver supports clocks for Audio subsystem on MMP2 SoC.
 
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e42312121..f15bb5070 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351)		+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)		+= clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI544)		+= clk-si544.o
 obj-$(CONFIG_COMMON_CLK_SI570)		+= clk-si570.o
+obj-$(CONFIG_COMMON_CLK_SP7021)		+= clk-sp7021.o
 obj-$(CONFIG_COMMON_CLK_STM32F)		+= clk-stm32f4.o
 obj-$(CONFIG_COMMON_CLK_STM32H7)	+= clk-stm32h7.o
 obj-$(CONFIG_COMMON_CLK_STM32MP157)	+= clk-stm32mp1.o
diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c
new file mode 100644
index 000000000..6df87f0a6
--- /dev/null
+++ b/drivers/clk/clk-sp7021.c
@@ -0,0 +1,705 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+//#define DEBUG
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/bitfield.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <dt-bindings/clock/sp-sp7021.h>
+
+#define REG(i)		(pll_regs + (i) * 4)
+
+#define PLLA_CTL	REG(7)
+#define PLLE_CTL	REG(12)
+#define PLLF_CTL	REG(13)
+#define PLLTV_CTL	REG(14)
+#define PLLSYS_CTL	REG(26)
+
+#define EXTCLK		"extclk"
+
+/* speical div_width values for PLLTV/PLLA */
+#define DIV_TV		33
+#define DIV_A		34
+
+/* PLLTV parameters */
+enum {
+	SEL_FRA,
+	SDM_MOD,
+	PH_SEL,
+	NFRA,
+	DIVR,
+	DIVN,
+	DIVM,
+	P_MAX
+};
+
+#define MASK_SEL_FRA	GENMASK(1, 1)
+#define MASK_SDM_MOD	GENMASK(2, 2)
+#define MASK_PH_SEL	GENMASK(4, 4)
+#define MASK_NFRA	GENMASK(12, 6)
+#define MASK_DIVR	GENMASK(8, 7)
+#define MASK_DIVN	GENMASK(7, 0)
+#define MASK_DIVM	GENMASK(14, 8)
+
+/* HIWORD_MASK FIELD_PREP */
+#define HWM_FIELD_PREP(mask, value)		\
+({						\
+	u32 m = mask;				\
+	(m << 16) | FIELD_PREP(m, value);	\
+})
+
+struct sp_pll {
+	struct clk_hw hw;
+	void __iomem *reg;
+	spinlock_t *lock;	/* lock for reg */
+	int div_shift;
+	int div_width;
+	int pd_bit;		/* power down bit idx */
+	int bp_bit;		/* bypass bit idx */
+	unsigned long brate;	/* base rate, TODO: replace brate with muldiv */
+	u32 p[P_MAX];		/* for hold PLLTV/PLLA parameters */
+};
+
+#define to_sp_pll(_hw)	container_of(_hw, struct sp_pll, hw)
+
+#define clk_regs	(sp_clk_base + 0x000) /* G0 ~ CLKEN */
+#define pll_regs	(sp_clk_base + 0x200) /* G4 ~ PLL */
+static void __iomem *sp_clk_base;
+static struct clk_hw_onecell_data *sp_clk_data;
+
+#define P_EXTCLK	BIT(16)
+const struct clk_parent_data parents[] = {
+	{ .fw_name = "pllsys" },
+	{ .fw_name = "extclk" },
+};
+
+static const u32 gates[] = {
+	CLK_SYSTEM,
+	CLK_RTC,
+	CLK_IOCTL,
+	CLK_IOP,
+	CLK_OTPRX,
+	CLK_NOC,
+	CLK_BR,
+	CLK_RBUS_L00,
+	CLK_SPIFL,
+	CLK_SDCTRL0,
+	CLK_PERI0 | P_EXTCLK,
+	CLK_A926,
+	CLK_UMCTL2,
+	CLK_PERI1 | P_EXTCLK,
+
+	CLK_DDR_PHY0,
+	CLK_ACHIP,
+	CLK_STC0,
+	CLK_STC_AV0,
+	CLK_STC_AV1,
+	CLK_STC_AV2,
+	CLK_UA0 | P_EXTCLK,
+	CLK_UA1 | P_EXTCLK,
+	CLK_UA2 | P_EXTCLK,
+	CLK_UA3 | P_EXTCLK,
+	CLK_UA4 | P_EXTCLK,
+	CLK_HWUA | P_EXTCLK,
+	CLK_DDC0,
+	CLK_UADMA | P_EXTCLK,
+
+	CLK_CBDMA0,
+	CLK_CBDMA1,
+	CLK_SPI_COMBO_0,
+	CLK_SPI_COMBO_1,
+	CLK_SPI_COMBO_2,
+	CLK_SPI_COMBO_3,
+	CLK_AUD,
+	CLK_USBC0,
+	CLK_USBC1,
+	CLK_UPHY0,
+	CLK_UPHY1,
+
+	CLK_I2CM0,
+	CLK_I2CM1,
+	CLK_I2CM2,
+	CLK_I2CM3,
+	CLK_PMC,
+	CLK_CARD_CTL0,
+	CLK_CARD_CTL1,
+
+	CLK_CARD_CTL4,
+	CLK_BCH,
+	CLK_DDFCH,
+	CLK_CSIIW0,
+	CLK_CSIIW1,
+	CLK_MIPICSI0,
+	CLK_MIPICSI1,
+
+	CLK_HDMI_TX,
+	CLK_VPOST,
+
+	CLK_TGEN,
+	CLK_DMIX,
+	CLK_TCON,
+	CLK_INTERRUPT,
+
+	CLK_RGST,
+	CLK_GPIO,
+	CLK_RBUS_TOP,
+
+	CLK_MAILBOX,
+	CLK_SPIND,
+	CLK_I2C2CBUS,
+	CLK_SEC,
+	CLK_GPOST0,
+	CLK_DVE,
+
+	CLK_OSD0,
+	CLK_DISP_PWM,
+	CLK_UADBG,
+	CLK_DUMMY_MASTER,
+	CLK_FIO_CTL,
+	CLK_FPGA,
+	CLK_L2SW,
+	CLK_ICM,
+	CLK_AXI_GLOBAL,
+};
+
+static DEFINE_SPINLOCK(plla_lock);
+static DEFINE_SPINLOCK(plle_lock);
+static DEFINE_SPINLOCK(pllf_lock);
+static DEFINE_SPINLOCK(pllsys_lock);
+static DEFINE_SPINLOCK(plltv_lock);
+
+#define _M		1000000UL
+#define F_27M		(27 * _M)
+
+/*********************************** PLL_TV **********************************/
+
+/* TODO: set proper FVCO range */
+#define FVCO_MIN	(100 * _M)
+#define FVCO_MAX	(200 * _M)
+
+#define F_MIN		(FVCO_MIN / 8)
+#define F_MAX		(FVCO_MAX)
+
+static long plltv_integer_div(struct sp_pll *clk, unsigned long freq)
+{
+	/* valid m values: 27M must be divisible by m, 0 means end */
+	static const u32 m_table[] = {
+		1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 0
+	};
+	u32 m, n, r;
+	unsigned long fvco, nf;
+
+	/* check freq */
+	if (freq < F_MIN) {
+		pr_warn("%s: %s freq:%lu < F_MIN:%lu, round up\n",
+			__func__, clk_hw_get_name(&clk->hw), freq, F_MIN);
+		freq = F_MIN;
+	} else if (freq > F_MAX) {
+		pr_warn("%s: %s freq:%lu > F_MAX:%lu, round down\n",
+			__func__, clk_hw_get_name(&clk->hw), freq, F_MAX);
+		freq = F_MAX;
+	}
+
+	/* DIVR 0~3 */
+	for (r = 0; r <= 3; r++) {
+		fvco = freq << r;
+		if (fvco <= FVCO_MAX)
+			break;
+	}
+
+	/* DIVM */
+	for (m = 0; m_table[m]; m++) {
+		nf = fvco * m_table[m];
+		n = nf / F_27M;
+		if ((n * F_27M) == nf)
+			break;
+	}
+	m = m_table[m];
+
+	if (!m) {
+		pr_err("%s: %s freq:%lu not found a valid setting\n",
+		       __func__, clk_hw_get_name(&clk->hw), freq);
+		return -EINVAL;
+	}
+
+	/* save parameters */
+	clk->p[SEL_FRA] = 0;
+	clk->p[DIVR]    = r;
+	clk->p[DIVN]    = n;
+	clk->p[DIVM]    = m;
+
+	return freq;
+}
+
+/* parameters for PLLTV fractional divider */
+static const u32 pt[][5] = {
+	/* conventional fractional */
+	{
+		1,			// factor
+		5,			// 5 * p0 (nint)
+		1,			// 1 * p0
+		F_27M,			// F_27M / p0
+		1,			// p0 / p2
+	},
+	/* phase rotation */
+	{
+		10,			// factor
+		54,			// 5.4 * p0 (nint)
+		2,			// 0.2 * p0
+		F_27M / 10,		// F_27M / p0
+		5,			// p0 / p2
+	},
+};
+
+static const u32 mods[] = { 91, 55 }; /* SDM_MOD mod values */
+
+static long plltv_fractional_div(struct sp_pll *clk, unsigned long freq)
+{
+	u32 m, r;
+	u32 nint, nfra;
+	u32 df_quotient_min = 210000000;
+	u32 df_remainder_min = 0;
+	unsigned long fvco, nf, f, fout = 0;
+	int sdm, ph;
+
+	/* check freq */
+	if (freq < F_MIN) {
+		pr_warn("%s: %s freq:%lu < F_MIN:%lu, round up\n",
+			__func__, clk_hw_get_name(&clk->hw), freq, F_MIN);
+		freq = F_MIN;
+	} else if (freq > F_MAX) {
+		pr_warn("%s: %s freq:%lu > F_MAX:%lu, round down\n",
+			__func__, clk_hw_get_name(&clk->hw), freq, F_MAX);
+		freq = F_MAX;
+	}
+
+	/* DIVR 0~3 */
+	for (r = 0; r <= 3; r++) {
+		fvco = freq << r;
+		if (fvco <= FVCO_MAX)
+			break;
+	}
+	f = F_27M >> r;
+
+	/* PH_SEL 1/0 */
+	for (ph = 1; ph >= 0; ph--) {
+		const u32 *pp = pt[ph];
+		u32 ms = 1;
+
+		/* SDM_MOD 0/1 */
+		for (sdm = 0; sdm <= 1; sdm++) {
+			u32 mod = mods[sdm];
+
+			/* DIVM 1~32 */
+			for (m = ms; m <= 32; m++) {
+				u32 df; /* diff freq */
+				u32 df_quotient = 0, df_remainder = 0;
+
+				nf = fvco * m;
+				nint = nf / pp[3];
+
+				if (nint < pp[1])
+					continue;
+				if (nint > pp[1])
+					break;
+
+				nfra = (((nf % pp[3]) * mod * pp[4]) + (F_27M / 2)) / F_27M;
+				if (nfra)
+					df = (f * (nint + pp[2]) / pp[0]) -
+						    (f * (mod - nfra) / mod / pp[4]);
+				else
+					df = (f * (nint) / pp[0]);
+
+				df_quotient  = df / m;
+				df_remainder = ((df % m) * 1000) / m;
+
+				if (freq > df_quotient) {
+					df_quotient  = freq - df_quotient - 1;
+					df_remainder = 1000 - df_remainder;
+				} else {
+					df_quotient = df_quotient - freq;
+				}
+
+				if (df_quotient_min > df_quotient ||
+				    (df_quotient_min == df_quotient &&
+				    df_remainder_min > df_remainder)) {
+					/* found a closer freq, save parameters */
+					clk->p[SEL_FRA] = 1;
+					clk->p[SDM_MOD] = sdm;
+					clk->p[PH_SEL]  = ph;
+					clk->p[NFRA]    = nfra;
+					clk->p[DIVR]    = r;
+					clk->p[DIVM]    = m;
+
+					fout = df / m;
+					df_quotient_min = df_quotient;
+					df_remainder_min = df_remainder;
+				}
+			}
+		}
+	}
+
+	if (!fout) {
+		pr_err("%s: %s freq:%lu not found a valid setting\n",
+		       __func__, clk_hw_get_name(&clk->hw), freq);
+		return -EINVAL;
+	}
+
+	return fout;
+}
+
+static long plltv_div(struct sp_pll *clk, unsigned long freq)
+{
+	if (freq % 100)
+		return plltv_fractional_div(clk, freq);
+	else
+		return plltv_integer_div(clk, freq);
+}
+
+static void plltv_set_rate(struct sp_pll *clk)
+{
+	u32 reg;
+
+	reg  = HWM_FIELD_PREP(MASK_SEL_FRA, clk->p[SEL_FRA]);
+	reg |= HWM_FIELD_PREP(MASK_SDM_MOD, clk->p[SDM_MOD]);
+	reg |= HWM_FIELD_PREP(MASK_PH_SEL, clk->p[PH_SEL]);
+	reg |= HWM_FIELD_PREP(MASK_NFRA, clk->p[NFRA]);
+	writel(reg, clk->reg);
+
+	reg  = HWM_FIELD_PREP(MASK_DIVR, clk->p[DIVR]);
+	writel(reg, clk->reg + 4);
+
+	reg  = HWM_FIELD_PREP(MASK_DIVN, clk->p[DIVN] - 1);
+	reg |= HWM_FIELD_PREP(MASK_DIVM, clk->p[DIVM] - 1);
+	writel(reg, clk->reg + 8);
+}
+
+/*********************************** PLL_A ***********************************/
+
+/* from Q628_PLLs_REG_setting.xlsx */
+static const struct {
+	u32 rate;
+	u32 regs[5];
+} pa[] = {
+	{
+		.rate = 135475200,
+		.regs = {
+			0x4801,
+			0x02df,
+			0x248f,
+			0x0211,
+			0x33e9
+		}
+	},
+	{
+		.rate = 147456000,
+		.regs = {
+			0x4801,
+			0x1adf,
+			0x2490,
+			0x0349,
+			0x33e9
+		}
+	},
+	{
+		.rate = 196608000,
+		.regs = {
+			0x4801,
+			0x42ef,
+			0x2495,
+			0x01c6,
+			0x33e9
+		}
+	},
+};
+
+static void plla_set_rate(struct sp_pll *clk)
+{
+	const u32 *pp = pa[clk->p[0]].regs;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pa->regs); i++)
+		writel(0xffff0000 | pp[i], clk->reg + (i * 4));
+}
+
+static long plla_round_rate(struct sp_pll *clk, unsigned long rate)
+{
+	int i = ARRAY_SIZE(pa);
+
+	while (--i) {
+		if (rate >= pa[i].rate)
+			break;
+	}
+	clk->p[0] = i;
+	return pa[i].rate;
+}
+
+/********************************** SP_PLL ***********************************/
+
+static long sp_pll_calc_div(struct sp_pll *clk, unsigned long rate)
+{
+	u32 fbdiv;
+	u32 max = 1 << clk->div_width;
+
+	fbdiv = DIV_ROUND_CLOSEST(rate, clk->brate);
+	if (fbdiv > max)
+		fbdiv = max;
+	return fbdiv;
+}
+
+static long sp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+			      unsigned long *prate)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	long ret;
+
+	if (rate == *prate)
+		ret = *prate; /* bypass */
+	else if (clk->div_width == DIV_A) {
+		ret = plla_round_rate(clk, rate);
+	} else if (clk->div_width == DIV_TV) {
+		ret = plltv_div(clk, rate);
+		if (ret < 0)
+			ret = *prate;
+	} else {
+		ret = sp_pll_calc_div(clk, rate) * clk->brate;
+	}
+
+	return ret;
+}
+
+static unsigned long sp_pll_recalc_rate(struct clk_hw *hw,
+					unsigned long prate)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	u32 reg = readl(clk->reg);
+	unsigned long ret;
+
+	if (reg & BIT(clk->bp_bit))
+		ret = prate; /* bypass */
+	else if (clk->div_width == DIV_A)
+		ret = pa[clk->p[0]].rate;
+	else if (clk->div_width == DIV_TV) {
+		u32 m, r, reg2;
+
+		r = FIELD_GET(MASK_DIVR, readl(clk->reg + 4));
+		reg2 = readl(clk->reg + 8);
+		m = FIELD_GET(MASK_DIVM, reg2) + 1;
+
+		if (reg & BIT(1)) { /* SEL_FRA */
+			/* fractional divider */
+			u32 sdm  = FIELD_GET(MASK_SDM_MOD, reg);
+			u32 ph   = FIELD_GET(MASK_PH_SEL, reg);
+			u32 nfra = FIELD_GET(MASK_NFRA, reg);
+			const u32 *pp = pt[ph];
+
+			ret = prate >> r;
+			ret = (ret * (pp[1] + pp[2]) / pp[0]) -
+				  (ret * (mods[sdm] - nfra) / mods[sdm] / pp[4]);
+			ret /= m;
+		} else {
+			/* integer divider */
+			u32 n = FIELD_GET(MASK_DIVN, reg2) + 1;
+
+			ret = (prate / m * n) >> r;
+		}
+	} else {
+		u32 fbdiv = ((reg >> clk->div_shift) & ((1 << clk->div_width) - 1)) + 1;
+
+		ret = clk->brate * fbdiv;
+	}
+
+	return ret;
+}
+
+static int sp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+			   unsigned long prate)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(clk->lock, flags);
+
+	reg = BIT(clk->bp_bit + 16); /* HIWORD_MASK */
+
+	if (rate == prate)
+		reg |= BIT(clk->bp_bit); /* bypass */
+	else if (clk->div_width == DIV_A)
+		plla_set_rate(clk);
+	else if (clk->div_width == DIV_TV)
+		plltv_set_rate(clk);
+	else if (clk->div_width) {
+		u32 fbdiv = sp_pll_calc_div(clk, rate);
+		u32 mask = GENMASK(clk->div_shift + clk->div_width - 1, clk->div_shift);
+
+		reg |= (mask << 16) | (((fbdiv - 1) << clk->div_shift) & mask);
+	}
+
+	writel(reg, clk->reg);
+
+	spin_unlock_irqrestore(clk->lock, flags);
+
+	return 0;
+}
+
+static int sp_pll_enable(struct clk_hw *hw)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(clk->lock, flags);
+	writel(BIT(clk->pd_bit + 16) | BIT(clk->pd_bit), clk->reg); /* power up */
+	spin_unlock_irqrestore(clk->lock, flags);
+
+	return 0;
+}
+
+static void sp_pll_disable(struct clk_hw *hw)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(clk->lock, flags);
+	writel(BIT(clk->pd_bit + 16), clk->reg); /* power down */
+	spin_unlock_irqrestore(clk->lock, flags);
+}
+
+static int sp_pll_is_enabled(struct clk_hw *hw)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+
+	return readl(clk->reg) & BIT(clk->pd_bit);
+}
+
+static const struct clk_ops sp_pll_ops = {
+	.enable = sp_pll_enable,
+	.disable = sp_pll_disable,
+	.is_enabled = sp_pll_is_enabled,
+	.round_rate = sp_pll_round_rate,
+	.recalc_rate = sp_pll_recalc_rate,
+	.set_rate = sp_pll_set_rate
+};
+
+static const struct clk_ops sp_pll_sub_ops = {
+	.enable = sp_pll_enable,
+	.disable = sp_pll_disable,
+	.is_enabled = sp_pll_is_enabled,
+	.recalc_rate = sp_pll_recalc_rate,
+};
+
+struct clk_hw *sp_pll_register(const char *name, const char *parent,
+			       void __iomem *reg, int pd_bit, int bp_bit,
+			       unsigned long brate, int shift, int width,
+			       spinlock_t *lock)
+{
+	struct sp_pll *pll;
+	struct clk_hw *hw;
+	struct clk_init_data initd = {
+		.name = name,
+		.parent_names = &parent,
+		.ops = (bp_bit >= 0) ? &sp_pll_ops : &sp_pll_sub_ops,
+		.num_parents = 1,
+	};
+	int ret;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	if (reg == PLLSYS_CTL) /* system clock, should not be closed */
+		initd.flags |= CLK_IS_CRITICAL;
+
+	pll->hw.init = &initd;
+	pll->reg = reg;
+	pll->pd_bit = pd_bit;
+	pll->bp_bit = bp_bit;
+	pll->brate = brate;
+	pll->div_shift = shift;
+	pll->div_width = width;
+	pll->lock = lock;
+
+	hw = &pll->hw;
+	ret = clk_hw_register(NULL, hw);
+	if (ret) {
+		kfree(pll);
+		hw = ERR_PTR(ret);
+	} else {
+		pr_info("%-20s%lu\n", name, clk_hw_get_rate(hw));
+		clk_hw_register_clkdev(hw, NULL, name);
+	}
+
+	return hw;
+}
+
+static void __init sp_clk_setup(struct device_node *np)
+{
+	int i, j;
+	struct clk_hw **hws;
+
+	sp_clk_base = of_iomap(np, 0);
+	if (WARN_ON(!sp_clk_base))
+		return; /* -ENXIO */
+
+	sp_clk_data = kzalloc(struct_size(sp_clk_data, hws, CLK_MAX), GFP_KERNEL);
+	if (!sp_clk_data)
+		return; /* -ENOMEM */
+
+	hws = sp_clk_data->hws;
+
+	/* PLL_A */
+	hws[PLL_A] = sp_pll_register("plla", EXTCLK, PLLA_CTL, 11, 12,
+				     27000000, 0, DIV_A, &plla_lock);
+
+	/* PLL_E */
+	hws[PLL_E] = sp_pll_register("plle", EXTCLK, PLLE_CTL, 6, 2,
+				     50000000, 0, 0, &plle_lock);
+	hws[PLL_E_2P5] = sp_pll_register("plle_2p5", "plle", PLLE_CTL, 13, -1,
+					 2500000, 0, 0, &plle_lock);
+	hws[PLL_E_25] = sp_pll_register("plle_25", "plle", PLLE_CTL, 12, -1,
+					25000000, 0, 0, &plle_lock);
+	hws[PLL_E_112P5] = sp_pll_register("plle_112p5", "plle", PLLE_CTL, 11, -1,
+					   112500000, 0, 0, &plle_lock);
+
+	/* PLL_F */
+	hws[PLL_F] = sp_pll_register("pllf", EXTCLK, PLLF_CTL, 0, 10,
+				     13500000, 1, 4, &pllf_lock);
+
+	/* PLL_TV */
+	hws[PLL_TV] = sp_pll_register("plltv", EXTCLK, PLLTV_CTL, 0, 15,
+				      27000000, 0, DIV_TV, &plltv_lock);
+	hws[PLL_TV_A] = clk_hw_register_divider(NULL, "plltv_a", "plltv", 0,
+						PLLTV_CTL + 4, 5, 1,
+						CLK_DIVIDER_POWER_OF_TWO,
+						&plltv_lock);
+	clk_hw_register_clkdev(hws[PLL_TV_A], NULL, "plltv_a");
+
+	/* PLL_SYS */
+	hws[PLL_SYS] = sp_pll_register("pllsys", EXTCLK, PLLSYS_CTL, 10, 9,
+				       13500000, 0, 4, &pllsys_lock);
+
+	/* gates */
+	for (i = 0; i < ARRAY_SIZE(gates); i++) {
+		char s[10];
+
+		j = gates[i] & 0xffff;
+		sprintf(s, "clken%02x", j);
+		hws[j] = clk_hw_register_gate(NULL, s,
+					      parents[gates[i] >> 16].fw_name,
+					      CLK_IGNORE_UNUSED,
+					      clk_regs + (j >> 4) * 4, j & 0x0f,
+					      CLK_GATE_HIWORD_MASK, NULL);
+	}
+
+	sp_clk_data->num = CLK_MAX;
+	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, sp_clk_data);
+}
+
+CLK_OF_DECLARE_DRIVER(sp_clkc, "sunplus,sp7021-clkc", sp_clk_setup);
-- 
2.33.1


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

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

* [PATCH v7 07/10] dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt controller
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:06   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian, Rob Herring

Add documentation to describe Sunplus SP7021 interrupt controller bindings.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 .../sunplus,sp7021-intc.yaml                  | 62 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 63 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml

diff --git a/Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
new file mode 100644
index 000000000..5daeab63c
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/sunplus,sp7021-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 SoC Interrupt Controller Device Tree Bindings
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    items:
+      - const: sunplus,sp7021-intc
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+    description:
+      The first cell is the IRQ number, the second cell is the trigger
+      type as defined in interrupt.txt in this directory.
+
+  reg:
+    maxItems: 2
+    description:
+      Specifies base physical address(s) and size of the controller regs.
+      The 1st region include type/polarity/priority/mask regs.
+      The 2nd region include clear/masked_ext0/masked_ext1/group regs.
+
+  interrupts:
+    maxItems: 2
+    description:
+      EXT_INT0 & EXT_INT1, 2 interrupts references to primary interrupt
+      controller.
+
+required:
+  - compatible
+  - interrupt-controller
+  - "#interrupt-cells"
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    intc: interrupt-controller@9c000780 {
+        compatible = "sunplus,sp7021-intc";
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        reg = <0x9c000780 0x80>, <0x9c000a80 0x80>;
+        interrupt-parent = <&gic>;
+        interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, /* EXT_INT0 */
+                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; /* EXT_INT1 */
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 5069f552f..6b3bbe021 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2662,6 +2662,7 @@ S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
+F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 F:	drivers/clk/clk-sp7021.c
 F:	drivers/reset/reset-sunplus.c
-- 
2.33.1


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

* [PATCH v7 07/10] dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt controller
@ 2021-12-22  7:06   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian, Rob Herring

Add documentation to describe Sunplus SP7021 interrupt controller bindings.

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 .../sunplus,sp7021-intc.yaml                  | 62 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 63 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml

diff --git a/Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
new file mode 100644
index 000000000..5daeab63c
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/sunplus,sp7021-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 SoC Interrupt Controller Device Tree Bindings
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    items:
+      - const: sunplus,sp7021-intc
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+    description:
+      The first cell is the IRQ number, the second cell is the trigger
+      type as defined in interrupt.txt in this directory.
+
+  reg:
+    maxItems: 2
+    description:
+      Specifies base physical address(s) and size of the controller regs.
+      The 1st region include type/polarity/priority/mask regs.
+      The 2nd region include clear/masked_ext0/masked_ext1/group regs.
+
+  interrupts:
+    maxItems: 2
+    description:
+      EXT_INT0 & EXT_INT1, 2 interrupts references to primary interrupt
+      controller.
+
+required:
+  - compatible
+  - interrupt-controller
+  - "#interrupt-cells"
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    intc: interrupt-controller@9c000780 {
+        compatible = "sunplus,sp7021-intc";
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        reg = <0x9c000780 0x80>, <0x9c000a80 0x80>;
+        interrupt-parent = <&gic>;
+        interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, /* EXT_INT0 */
+                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; /* EXT_INT1 */
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 5069f552f..6b3bbe021 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2662,6 +2662,7 @@ S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
+F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 F:	drivers/clk/clk-sp7021.c
 F:	drivers/reset/reset-sunplus.c
-- 
2.33.1


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

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

* [PATCH v7 08/10] irqchip: Add Sunplus SP7021 interrupt controller driver
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:06   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add interrupt controller driver for Sunplus SP7021 SoC.

This is the interrupt controller in P-chip which collects all interrupt
sources in P-chip and routes them to parent interrupt controller in C-chip.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Fix the comments from Marc.
---
 MAINTAINERS                       |   1 +
 drivers/irqchip/Kconfig           |   9 +
 drivers/irqchip/Makefile          |   1 +
 drivers/irqchip/irq-sp7021-intc.c | 288 ++++++++++++++++++++++++++++++
 4 files changed, 299 insertions(+)
 create mode 100644 drivers/irqchip/irq-sp7021-intc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6b3bbe021..febbd97bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2665,6 +2665,7 @@ F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 F:	drivers/clk/clk-sp7021.c
+F:	drivers/irqchip/irq-sp7021-intc.c
 F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index aca7b595c..32d7a8e0c 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -602,4 +602,13 @@ config APPLE_AIC
 	  Support for the Apple Interrupt Controller found on Apple Silicon SoCs,
 	  such as the M1.
 
+config SUNPLUS_SP7021_INTC
+	bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST
+	default SOC_SP7021
+	help
+	  Support for the Sunplus SP7021 Interrupt Controller IP core.
+	  SP7021 SoC has 2 Chips: C-Chip & P-Chip. This is used as a
+	  chained controller, routing all interrupt source in P-Chip to
+	  the primary controller on C-Chip.
+
 endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index f88cbf36a..75411f654 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -116,3 +116,4 @@ obj-$(CONFIG_MACH_REALTEK_RTL)		+= irq-realtek-rtl.o
 obj-$(CONFIG_WPCM450_AIC)		+= irq-wpcm450-aic.o
 obj-$(CONFIG_IRQ_IDT3243X)		+= irq-idt3243x.o
 obj-$(CONFIG_APPLE_AIC)			+= irq-apple-aic.o
+obj-$(CONFIG_SUNPLUS_SP7021_INTC)	+= irq-sp7021-intc.o
diff --git a/drivers/irqchip/irq-sp7021-intc.c b/drivers/irqchip/irq-sp7021-intc.c
new file mode 100644
index 000000000..d1821a955
--- /dev/null
+++ b/drivers/irqchip/irq-sp7021-intc.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define SP_INTC_HWIRQ_MIN	0
+#define SP_INTC_HWIRQ_MAX	223
+
+#define SP_INTC_NR_IRQS		(SP_INTC_HWIRQ_MAX - SP_INTC_HWIRQ_MIN + 1)
+#define SP_INTC_NR_GROUPS	DIV_ROUND_UP(SP_INTC_NR_IRQS, 32)
+#define SP_INTC_REG_SIZE	(SP_INTC_NR_GROUPS * 4)
+
+/* REG_GROUP_0 regs */
+#define REG_INTR_TYPE		(sp_intc.g0)
+#define REG_INTR_POLARITY	(REG_INTR_TYPE     + SP_INTC_REG_SIZE)
+#define REG_INTR_PRIORITY	(REG_INTR_POLARITY + SP_INTC_REG_SIZE)
+#define REG_INTR_MASK		(REG_INTR_PRIORITY + SP_INTC_REG_SIZE)
+
+/* REG_GROUP_1 regs */
+#define REG_INTR_CLEAR		(sp_intc.g1)
+#define REG_MASKED_EXT1		(REG_INTR_CLEAR    + SP_INTC_REG_SIZE)
+#define REG_MASKED_EXT0		(REG_MASKED_EXT1   + SP_INTC_REG_SIZE)
+#define REG_INTR_GROUP		(REG_INTR_CLEAR    + 31 * 4)
+
+#define GROUP_MASK		(BIT(SP_INTC_NR_GROUPS) - 1)
+#define GROUP_SHIFT_EXT1	(0)
+#define GROUP_SHIFT_EXT0	(8)
+
+/*
+ * When GPIO_INT0~7 set to edge trigger, doesn't work properly.
+ * WORKAROUND: change it to level trigger, and toggle the polarity
+ * at ACK/Handler to make the HW work.
+ */
+#define GPIO_INT0_HWIRQ		120
+#define GPIO_INT7_HWIRQ		127
+#define IS_GPIO_INT(irq)					\
+({								\
+	u32 i = irq;						\
+	(i >= GPIO_INT0_HWIRQ) && (i <= GPIO_INT7_HWIRQ);	\
+})
+
+/* index of states */
+enum {
+	_IS_EDGE = 0,
+	_IS_LOW,
+	_IS_ACTIVE
+};
+
+#define STATE_BIT(irq, idx)		(((irq) - GPIO_INT0_HWIRQ) * 3 + (idx))
+#define ASSIGN_STATE(irq, idx, v)	assign_bit(STATE_BIT(irq, idx), sp_intc.states, v)
+#define TEST_STATE(irq, idx)		test_bit(STATE_BIT(irq, idx), sp_intc.states)
+
+static struct sp_intctl {
+	/*
+	 * REG_GROUP_0: include type/polarity/priority/mask regs.
+	 * REG_GROUP_1: include clear/masked_ext0/masked_ext1/group regs.
+	 */
+	void __iomem *g0; // REG_GROUP_0 base
+	void __iomem *g1; // REG_GROUP_1 base
+
+	struct irq_domain *domain;
+	raw_spinlock_t lock;
+
+	/*
+	 * store GPIO_INT states
+	 * each interrupt has 3 states: is_edge, is_low, is_active
+	 */
+	DECLARE_BITMAP(states, (GPIO_INT7_HWIRQ - GPIO_INT0_HWIRQ + 1) * 3);
+} sp_intc;
+
+static struct irq_chip sp_intc_chip;
+
+static void sp_intc_assign_bit(u32 hwirq, void __iomem *base, bool value)
+{
+	u32 offset, mask;
+	unsigned long flags;
+	void __iomem *reg;
+
+	offset = (hwirq / 32) * 4;
+	reg = base + offset;
+
+	raw_spin_lock_irqsave(&sp_intc.lock, flags);
+	mask = readl_relaxed(reg);
+	if (value)
+		mask |= BIT(hwirq % 32);
+	else
+		mask &= ~BIT(hwirq % 32);
+	writel_relaxed(mask, reg);
+	raw_spin_unlock_irqrestore(&sp_intc.lock, flags);
+}
+
+static void sp_intc_ack_irq(struct irq_data *d)
+{
+	u32 hwirq = d->hwirq;
+
+	if (unlikely(IS_GPIO_INT(hwirq) && TEST_STATE(hwirq, _IS_EDGE))) { // WORKAROUND
+		sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, !TEST_STATE(hwirq, _IS_LOW));
+		ASSIGN_STATE(hwirq, _IS_ACTIVE, true);
+	}
+
+	sp_intc_assign_bit(hwirq, REG_INTR_CLEAR, 1);
+}
+
+static void sp_intc_mask_irq(struct irq_data *d)
+{
+	sp_intc_assign_bit(d->hwirq, REG_INTR_MASK, 0);
+}
+
+static void sp_intc_unmask_irq(struct irq_data *d)
+{
+	sp_intc_assign_bit(d->hwirq, REG_INTR_MASK, 1);
+}
+
+static int sp_intc_set_type(struct irq_data *d, unsigned int type)
+{
+	u32 hwirq = d->hwirq;
+	bool is_edge = !(type & IRQ_TYPE_LEVEL_MASK);
+	bool is_low = (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_EDGE_FALLING);
+
+	irq_set_handler_locked(d, is_edge ? handle_edge_irq : handle_level_irq);
+
+	if (unlikely(IS_GPIO_INT(hwirq) && is_edge)) { // WORKAROUND
+		/* store states */
+		ASSIGN_STATE(hwirq, _IS_EDGE, is_edge);
+		ASSIGN_STATE(hwirq, _IS_LOW, is_low);
+		ASSIGN_STATE(hwirq, _IS_ACTIVE, false);
+		/* change to level */
+		is_edge = false;
+	}
+
+	sp_intc_assign_bit(hwirq, REG_INTR_TYPE, is_edge);
+	sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, is_low);
+
+	return 0;
+}
+
+static int sp_intc_get_ext_irq(int ext_num)
+{
+	void __iomem *base = ext_num ? REG_MASKED_EXT1 : REG_MASKED_EXT0;
+	u32 shift = ext_num ? GROUP_SHIFT_EXT1 : GROUP_SHIFT_EXT0;
+	u32 groups;
+	u32 pending_group;
+	u32 group;
+	u32 pending_irq;
+
+	groups = readl_relaxed(REG_INTR_GROUP);
+	pending_group = (groups >> shift) & GROUP_MASK;
+	if (!pending_group)
+		return -1;
+
+	group = fls(pending_group) - 1;
+	pending_irq = readl_relaxed(base + group * 4);
+	if (!pending_irq)
+		return -1;
+
+	return (group * 32) + fls(pending_irq) - 1;
+}
+
+static void sp_intc_handle_ext_cascaded(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	int ext_num = (int)irq_desc_get_handler_data(desc);
+	int hwirq;
+
+	chained_irq_enter(chip, desc);
+
+	while ((hwirq = sp_intc_get_ext_irq(ext_num)) >= 0) {
+		if (unlikely(IS_GPIO_INT(hwirq) && TEST_STATE(hwirq, _IS_ACTIVE))) { // WORKAROUND
+			ASSIGN_STATE(hwirq, _IS_ACTIVE, false);
+			sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, TEST_STATE(hwirq, _IS_LOW));
+		} else {
+			generic_handle_domain_irq(sp_intc.domain, hwirq);
+		}
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+#ifdef CONFIG_SMP
+static int sp_intc_set_affinity(struct irq_data *d, const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+#endif
+
+static struct irq_chip sp_intc_chip = {
+	.name = "sp_intc",
+	.irq_ack = sp_intc_ack_irq,
+	.irq_mask = sp_intc_mask_irq,
+	.irq_unmask = sp_intc_unmask_irq,
+	.irq_set_type = sp_intc_set_type,
+#ifdef CONFIG_SMP
+	.irq_set_affinity = sp_intc_set_affinity,
+#endif
+};
+
+static int sp_intc_irq_domain_map(struct irq_domain *domain,
+				  unsigned int irq, irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &sp_intc_chip, handle_level_irq);
+	irq_set_chip_data(irq, &sp_intc_chip);
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops sp_intc_dm_ops = {
+	.xlate = irq_domain_xlate_twocell,
+	.map = sp_intc_irq_domain_map,
+};
+
+static int sp_intc_irq_map(struct device_node *node, int i)
+{
+	unsigned int irq;
+
+	irq = irq_of_parse_and_map(node, i);
+	if (!irq)
+		return -ENOENT;
+
+	irq_set_chained_handler_and_data(irq, sp_intc_handle_ext_cascaded, (void *)i);
+
+	return 0;
+}
+
+static int __init sp_intc_init_dt(struct device_node *node, struct device_node *parent)
+{
+	int i, ret;
+
+	sp_intc.g0 = of_iomap(node, 0);
+	if (!sp_intc.g0)
+		return -ENXIO;
+
+	sp_intc.g1 = of_iomap(node, 1);
+	if (!sp_intc.g1) {
+		ret = -ENXIO;
+		goto out_unmap0;
+	}
+
+	ret = sp_intc_irq_map(node, 0); // EXT_INT0
+	if (ret)
+		goto out_unmap1;
+
+	ret = sp_intc_irq_map(node, 1); // EXT_INT1
+	if (ret)
+		goto out_unmap1;
+
+	/* initial regs */
+	for (i = 0; i < SP_INTC_NR_GROUPS; i++) {
+		/* all mask */
+		writel_relaxed(0, REG_INTR_MASK + i * 4);
+		/* all edge */
+		writel_relaxed(~0, REG_INTR_TYPE + i * 4);
+		/* all high-active */
+		writel_relaxed(0, REG_INTR_POLARITY + i * 4);
+		/* all EXT_INT0 */
+		writel_relaxed(~0, REG_INTR_PRIORITY + i * 4);
+		/* all clear */
+		writel_relaxed(~0, REG_INTR_CLEAR + i * 4);
+	}
+
+	sp_intc.domain = irq_domain_add_linear(node, SP_INTC_NR_IRQS,
+					       &sp_intc_dm_ops, &sp_intc);
+	if (!sp_intc.domain) {
+		ret = -ENOMEM;
+		goto out_unmap1;
+	}
+
+	raw_spin_lock_init(&sp_intc.lock);
+
+	return 0;
+
+out_unmap1:
+	iounmap(sp_intc.g1);
+out_unmap0:
+	iounmap(sp_intc.g0);
+
+	return ret;
+}
+
+IRQCHIP_DECLARE(sp_intc, "sunplus,sp7021-intc", sp_intc_init_dt);
-- 
2.33.1


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

* [PATCH v7 08/10] irqchip: Add Sunplus SP7021 interrupt controller driver
@ 2021-12-22  7:06   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add interrupt controller driver for Sunplus SP7021 SoC.

This is the interrupt controller in P-chip which collects all interrupt
sources in P-chip and routes them to parent interrupt controller in C-chip.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Fix the comments from Marc.
---
 MAINTAINERS                       |   1 +
 drivers/irqchip/Kconfig           |   9 +
 drivers/irqchip/Makefile          |   1 +
 drivers/irqchip/irq-sp7021-intc.c | 288 ++++++++++++++++++++++++++++++
 4 files changed, 299 insertions(+)
 create mode 100644 drivers/irqchip/irq-sp7021-intc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6b3bbe021..febbd97bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2665,6 +2665,7 @@ F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 F:	drivers/clk/clk-sp7021.c
+F:	drivers/irqchip/irq-sp7021-intc.c
 F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index aca7b595c..32d7a8e0c 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -602,4 +602,13 @@ config APPLE_AIC
 	  Support for the Apple Interrupt Controller found on Apple Silicon SoCs,
 	  such as the M1.
 
+config SUNPLUS_SP7021_INTC
+	bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST
+	default SOC_SP7021
+	help
+	  Support for the Sunplus SP7021 Interrupt Controller IP core.
+	  SP7021 SoC has 2 Chips: C-Chip & P-Chip. This is used as a
+	  chained controller, routing all interrupt source in P-Chip to
+	  the primary controller on C-Chip.
+
 endmenu
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index f88cbf36a..75411f654 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -116,3 +116,4 @@ obj-$(CONFIG_MACH_REALTEK_RTL)		+= irq-realtek-rtl.o
 obj-$(CONFIG_WPCM450_AIC)		+= irq-wpcm450-aic.o
 obj-$(CONFIG_IRQ_IDT3243X)		+= irq-idt3243x.o
 obj-$(CONFIG_APPLE_AIC)			+= irq-apple-aic.o
+obj-$(CONFIG_SUNPLUS_SP7021_INTC)	+= irq-sp7021-intc.o
diff --git a/drivers/irqchip/irq-sp7021-intc.c b/drivers/irqchip/irq-sp7021-intc.c
new file mode 100644
index 000000000..d1821a955
--- /dev/null
+++ b/drivers/irqchip/irq-sp7021-intc.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define SP_INTC_HWIRQ_MIN	0
+#define SP_INTC_HWIRQ_MAX	223
+
+#define SP_INTC_NR_IRQS		(SP_INTC_HWIRQ_MAX - SP_INTC_HWIRQ_MIN + 1)
+#define SP_INTC_NR_GROUPS	DIV_ROUND_UP(SP_INTC_NR_IRQS, 32)
+#define SP_INTC_REG_SIZE	(SP_INTC_NR_GROUPS * 4)
+
+/* REG_GROUP_0 regs */
+#define REG_INTR_TYPE		(sp_intc.g0)
+#define REG_INTR_POLARITY	(REG_INTR_TYPE     + SP_INTC_REG_SIZE)
+#define REG_INTR_PRIORITY	(REG_INTR_POLARITY + SP_INTC_REG_SIZE)
+#define REG_INTR_MASK		(REG_INTR_PRIORITY + SP_INTC_REG_SIZE)
+
+/* REG_GROUP_1 regs */
+#define REG_INTR_CLEAR		(sp_intc.g1)
+#define REG_MASKED_EXT1		(REG_INTR_CLEAR    + SP_INTC_REG_SIZE)
+#define REG_MASKED_EXT0		(REG_MASKED_EXT1   + SP_INTC_REG_SIZE)
+#define REG_INTR_GROUP		(REG_INTR_CLEAR    + 31 * 4)
+
+#define GROUP_MASK		(BIT(SP_INTC_NR_GROUPS) - 1)
+#define GROUP_SHIFT_EXT1	(0)
+#define GROUP_SHIFT_EXT0	(8)
+
+/*
+ * When GPIO_INT0~7 set to edge trigger, doesn't work properly.
+ * WORKAROUND: change it to level trigger, and toggle the polarity
+ * at ACK/Handler to make the HW work.
+ */
+#define GPIO_INT0_HWIRQ		120
+#define GPIO_INT7_HWIRQ		127
+#define IS_GPIO_INT(irq)					\
+({								\
+	u32 i = irq;						\
+	(i >= GPIO_INT0_HWIRQ) && (i <= GPIO_INT7_HWIRQ);	\
+})
+
+/* index of states */
+enum {
+	_IS_EDGE = 0,
+	_IS_LOW,
+	_IS_ACTIVE
+};
+
+#define STATE_BIT(irq, idx)		(((irq) - GPIO_INT0_HWIRQ) * 3 + (idx))
+#define ASSIGN_STATE(irq, idx, v)	assign_bit(STATE_BIT(irq, idx), sp_intc.states, v)
+#define TEST_STATE(irq, idx)		test_bit(STATE_BIT(irq, idx), sp_intc.states)
+
+static struct sp_intctl {
+	/*
+	 * REG_GROUP_0: include type/polarity/priority/mask regs.
+	 * REG_GROUP_1: include clear/masked_ext0/masked_ext1/group regs.
+	 */
+	void __iomem *g0; // REG_GROUP_0 base
+	void __iomem *g1; // REG_GROUP_1 base
+
+	struct irq_domain *domain;
+	raw_spinlock_t lock;
+
+	/*
+	 * store GPIO_INT states
+	 * each interrupt has 3 states: is_edge, is_low, is_active
+	 */
+	DECLARE_BITMAP(states, (GPIO_INT7_HWIRQ - GPIO_INT0_HWIRQ + 1) * 3);
+} sp_intc;
+
+static struct irq_chip sp_intc_chip;
+
+static void sp_intc_assign_bit(u32 hwirq, void __iomem *base, bool value)
+{
+	u32 offset, mask;
+	unsigned long flags;
+	void __iomem *reg;
+
+	offset = (hwirq / 32) * 4;
+	reg = base + offset;
+
+	raw_spin_lock_irqsave(&sp_intc.lock, flags);
+	mask = readl_relaxed(reg);
+	if (value)
+		mask |= BIT(hwirq % 32);
+	else
+		mask &= ~BIT(hwirq % 32);
+	writel_relaxed(mask, reg);
+	raw_spin_unlock_irqrestore(&sp_intc.lock, flags);
+}
+
+static void sp_intc_ack_irq(struct irq_data *d)
+{
+	u32 hwirq = d->hwirq;
+
+	if (unlikely(IS_GPIO_INT(hwirq) && TEST_STATE(hwirq, _IS_EDGE))) { // WORKAROUND
+		sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, !TEST_STATE(hwirq, _IS_LOW));
+		ASSIGN_STATE(hwirq, _IS_ACTIVE, true);
+	}
+
+	sp_intc_assign_bit(hwirq, REG_INTR_CLEAR, 1);
+}
+
+static void sp_intc_mask_irq(struct irq_data *d)
+{
+	sp_intc_assign_bit(d->hwirq, REG_INTR_MASK, 0);
+}
+
+static void sp_intc_unmask_irq(struct irq_data *d)
+{
+	sp_intc_assign_bit(d->hwirq, REG_INTR_MASK, 1);
+}
+
+static int sp_intc_set_type(struct irq_data *d, unsigned int type)
+{
+	u32 hwirq = d->hwirq;
+	bool is_edge = !(type & IRQ_TYPE_LEVEL_MASK);
+	bool is_low = (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_EDGE_FALLING);
+
+	irq_set_handler_locked(d, is_edge ? handle_edge_irq : handle_level_irq);
+
+	if (unlikely(IS_GPIO_INT(hwirq) && is_edge)) { // WORKAROUND
+		/* store states */
+		ASSIGN_STATE(hwirq, _IS_EDGE, is_edge);
+		ASSIGN_STATE(hwirq, _IS_LOW, is_low);
+		ASSIGN_STATE(hwirq, _IS_ACTIVE, false);
+		/* change to level */
+		is_edge = false;
+	}
+
+	sp_intc_assign_bit(hwirq, REG_INTR_TYPE, is_edge);
+	sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, is_low);
+
+	return 0;
+}
+
+static int sp_intc_get_ext_irq(int ext_num)
+{
+	void __iomem *base = ext_num ? REG_MASKED_EXT1 : REG_MASKED_EXT0;
+	u32 shift = ext_num ? GROUP_SHIFT_EXT1 : GROUP_SHIFT_EXT0;
+	u32 groups;
+	u32 pending_group;
+	u32 group;
+	u32 pending_irq;
+
+	groups = readl_relaxed(REG_INTR_GROUP);
+	pending_group = (groups >> shift) & GROUP_MASK;
+	if (!pending_group)
+		return -1;
+
+	group = fls(pending_group) - 1;
+	pending_irq = readl_relaxed(base + group * 4);
+	if (!pending_irq)
+		return -1;
+
+	return (group * 32) + fls(pending_irq) - 1;
+}
+
+static void sp_intc_handle_ext_cascaded(struct irq_desc *desc)
+{
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	int ext_num = (int)irq_desc_get_handler_data(desc);
+	int hwirq;
+
+	chained_irq_enter(chip, desc);
+
+	while ((hwirq = sp_intc_get_ext_irq(ext_num)) >= 0) {
+		if (unlikely(IS_GPIO_INT(hwirq) && TEST_STATE(hwirq, _IS_ACTIVE))) { // WORKAROUND
+			ASSIGN_STATE(hwirq, _IS_ACTIVE, false);
+			sp_intc_assign_bit(hwirq, REG_INTR_POLARITY, TEST_STATE(hwirq, _IS_LOW));
+		} else {
+			generic_handle_domain_irq(sp_intc.domain, hwirq);
+		}
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+#ifdef CONFIG_SMP
+static int sp_intc_set_affinity(struct irq_data *d, const struct cpumask *mask, bool force)
+{
+	return -EINVAL;
+}
+#endif
+
+static struct irq_chip sp_intc_chip = {
+	.name = "sp_intc",
+	.irq_ack = sp_intc_ack_irq,
+	.irq_mask = sp_intc_mask_irq,
+	.irq_unmask = sp_intc_unmask_irq,
+	.irq_set_type = sp_intc_set_type,
+#ifdef CONFIG_SMP
+	.irq_set_affinity = sp_intc_set_affinity,
+#endif
+};
+
+static int sp_intc_irq_domain_map(struct irq_domain *domain,
+				  unsigned int irq, irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &sp_intc_chip, handle_level_irq);
+	irq_set_chip_data(irq, &sp_intc_chip);
+	irq_set_noprobe(irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops sp_intc_dm_ops = {
+	.xlate = irq_domain_xlate_twocell,
+	.map = sp_intc_irq_domain_map,
+};
+
+static int sp_intc_irq_map(struct device_node *node, int i)
+{
+	unsigned int irq;
+
+	irq = irq_of_parse_and_map(node, i);
+	if (!irq)
+		return -ENOENT;
+
+	irq_set_chained_handler_and_data(irq, sp_intc_handle_ext_cascaded, (void *)i);
+
+	return 0;
+}
+
+static int __init sp_intc_init_dt(struct device_node *node, struct device_node *parent)
+{
+	int i, ret;
+
+	sp_intc.g0 = of_iomap(node, 0);
+	if (!sp_intc.g0)
+		return -ENXIO;
+
+	sp_intc.g1 = of_iomap(node, 1);
+	if (!sp_intc.g1) {
+		ret = -ENXIO;
+		goto out_unmap0;
+	}
+
+	ret = sp_intc_irq_map(node, 0); // EXT_INT0
+	if (ret)
+		goto out_unmap1;
+
+	ret = sp_intc_irq_map(node, 1); // EXT_INT1
+	if (ret)
+		goto out_unmap1;
+
+	/* initial regs */
+	for (i = 0; i < SP_INTC_NR_GROUPS; i++) {
+		/* all mask */
+		writel_relaxed(0, REG_INTR_MASK + i * 4);
+		/* all edge */
+		writel_relaxed(~0, REG_INTR_TYPE + i * 4);
+		/* all high-active */
+		writel_relaxed(0, REG_INTR_POLARITY + i * 4);
+		/* all EXT_INT0 */
+		writel_relaxed(~0, REG_INTR_PRIORITY + i * 4);
+		/* all clear */
+		writel_relaxed(~0, REG_INTR_CLEAR + i * 4);
+	}
+
+	sp_intc.domain = irq_domain_add_linear(node, SP_INTC_NR_IRQS,
+					       &sp_intc_dm_ops, &sp_intc);
+	if (!sp_intc.domain) {
+		ret = -ENOMEM;
+		goto out_unmap1;
+	}
+
+	raw_spin_lock_init(&sp_intc.lock);
+
+	return 0;
+
+out_unmap1:
+	iounmap(sp_intc.g1);
+out_unmap0:
+	iounmap(sp_intc.g0);
+
+	return ret;
+}
+
+IRQCHIP_DECLARE(sp_intc, "sunplus,sp7021-intc", sp_intc_init_dt);
-- 
2.33.1


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

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

* [PATCH v7 09/10] ARM: sunplus: Add initial support for Sunplus SP7021 SoC
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:06   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

This patch aims to add an initial support for Sunplus SP7021 SoC.

Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 MAINTAINERS                    |  1 +
 arch/arm/Kconfig               |  2 ++
 arch/arm/Makefile              |  1 +
 arch/arm/mach-sunplus/Kconfig  | 26 ++++++++++++++++++++++++++
 arch/arm/mach-sunplus/Makefile |  9 +++++++++
 arch/arm/mach-sunplus/sp7021.c | 16 ++++++++++++++++
 6 files changed, 55 insertions(+)
 create mode 100644 arch/arm/mach-sunplus/Kconfig
 create mode 100644 arch/arm/mach-sunplus/Makefile
 create mode 100644 arch/arm/mach-sunplus/sp7021.c

diff --git a/MAINTAINERS b/MAINTAINERS
index febbd97bf..0ae537a41 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2664,6 +2664,7 @@ F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	arch/arm/mach-sunplus/
 F:	drivers/clk/clk-sp7021.c
 F:	drivers/irqchip/irq-sp7021-intc.c
 F:	drivers/reset/reset-sunplus.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 59baf6c13..8c7883b5a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -689,6 +689,8 @@ source "arch/arm/mach-sti/Kconfig"
 
 source "arch/arm/mach-stm32/Kconfig"
 
+source "arch/arm/mach-sunplus/Kconfig"
+
 source "arch/arm/mach-sunxi/Kconfig"
 
 source "arch/arm/mach-tegra/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 847c31e7c..973ffb830 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -212,6 +212,7 @@ machine-$(CONFIG_ARCH_RENESAS)	 	+= shmobile
 machine-$(CONFIG_ARCH_INTEL_SOCFPGA)	+= socfpga
 machine-$(CONFIG_ARCH_STI)		+= sti
 machine-$(CONFIG_ARCH_STM32)		+= stm32
+machine-$(CONFIG_ARCH_SUNPLUS)		+= sunplus
 machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
 machine-$(CONFIG_ARCH_TEGRA)		+= tegra
 machine-$(CONFIG_ARCH_U8500)		+= ux500
diff --git a/arch/arm/mach-sunplus/Kconfig b/arch/arm/mach-sunplus/Kconfig
new file mode 100644
index 000000000..e720606dd
--- /dev/null
+++ b/arch/arm/mach-sunplus/Kconfig
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+menuconfig ARCH_SUNPLUS
+	bool "Sunplus SoCs"
+	depends on ARCH_MULTI_V7
+	help
+	  Support for Sunplus SoC family: SP7021 and succeeding SoC-based systems,
+	  such as the Banana Pi BPI-F2S development board (and derivatives).
+	  (<http://www.sinovoip.com.cn/ecp_view.asp?id=586>)
+	  (<https://tibbo.com/store/plus1.html>)
+
+config SOC_SP7021
+	bool "Sunplus SP7021 SoC support"
+	depends on ARCH_SUNPLUS
+	default ARCH_SUNPLUS
+	select ARM_GIC
+	select ARM_PSCI
+	select PINCTRL
+	select PINCTRL_SPPCTL
+	select SERIAL_SUNPLUS
+	select SERIAL_SUNPLUS_CONSOLE
+	help
+	  Support for Sunplus SP7021 SoC. It is based on ARM 4-core
+	  Cortex-A7 with various peripherals (ex: I2C, SPI, SDIO,
+	  Ethernet and etc.), FPGA interface,  chip-to-chip bus.
+	  It is designed for industrial control.
diff --git a/arch/arm/mach-sunplus/Makefile b/arch/arm/mach-sunplus/Makefile
new file mode 100644
index 000000000..c902580a7
--- /dev/null
+++ b/arch/arm/mach-sunplus/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-$(CONFIG_SOC_SP7021)	+= sp7021.o
+
diff --git a/arch/arm/mach-sunplus/sp7021.c b/arch/arm/mach-sunplus/sp7021.c
new file mode 100644
index 000000000..774d0a5bd
--- /dev/null
+++ b/arch/arm/mach-sunplus/sp7021.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#include <linux/kernel.h>
+#include <asm/mach/arch.h>
+
+static const char *sp7021_compat[] __initconst = {
+	"sunplus,sp7021",
+	NULL
+};
+
+DT_MACHINE_START(SP7021_DT, "SP7021")
+	.dt_compat	= sp7021_compat,
+MACHINE_END
-- 
2.33.1


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

* [PATCH v7 09/10] ARM: sunplus: Add initial support for Sunplus SP7021 SoC
@ 2021-12-22  7:06   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

This patch aims to add an initial support for Sunplus SP7021 SoC.

Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 MAINTAINERS                    |  1 +
 arch/arm/Kconfig               |  2 ++
 arch/arm/Makefile              |  1 +
 arch/arm/mach-sunplus/Kconfig  | 26 ++++++++++++++++++++++++++
 arch/arm/mach-sunplus/Makefile |  9 +++++++++
 arch/arm/mach-sunplus/sp7021.c | 16 ++++++++++++++++
 6 files changed, 55 insertions(+)
 create mode 100644 arch/arm/mach-sunplus/Kconfig
 create mode 100644 arch/arm/mach-sunplus/Makefile
 create mode 100644 arch/arm/mach-sunplus/sp7021.c

diff --git a/MAINTAINERS b/MAINTAINERS
index febbd97bf..0ae537a41 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2664,6 +2664,7 @@ F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	arch/arm/mach-sunplus/
 F:	drivers/clk/clk-sp7021.c
 F:	drivers/irqchip/irq-sp7021-intc.c
 F:	drivers/reset/reset-sunplus.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 59baf6c13..8c7883b5a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -689,6 +689,8 @@ source "arch/arm/mach-sti/Kconfig"
 
 source "arch/arm/mach-stm32/Kconfig"
 
+source "arch/arm/mach-sunplus/Kconfig"
+
 source "arch/arm/mach-sunxi/Kconfig"
 
 source "arch/arm/mach-tegra/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 847c31e7c..973ffb830 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -212,6 +212,7 @@ machine-$(CONFIG_ARCH_RENESAS)	 	+= shmobile
 machine-$(CONFIG_ARCH_INTEL_SOCFPGA)	+= socfpga
 machine-$(CONFIG_ARCH_STI)		+= sti
 machine-$(CONFIG_ARCH_STM32)		+= stm32
+machine-$(CONFIG_ARCH_SUNPLUS)		+= sunplus
 machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
 machine-$(CONFIG_ARCH_TEGRA)		+= tegra
 machine-$(CONFIG_ARCH_U8500)		+= ux500
diff --git a/arch/arm/mach-sunplus/Kconfig b/arch/arm/mach-sunplus/Kconfig
new file mode 100644
index 000000000..e720606dd
--- /dev/null
+++ b/arch/arm/mach-sunplus/Kconfig
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+menuconfig ARCH_SUNPLUS
+	bool "Sunplus SoCs"
+	depends on ARCH_MULTI_V7
+	help
+	  Support for Sunplus SoC family: SP7021 and succeeding SoC-based systems,
+	  such as the Banana Pi BPI-F2S development board (and derivatives).
+	  (<http://www.sinovoip.com.cn/ecp_view.asp?id=586>)
+	  (<https://tibbo.com/store/plus1.html>)
+
+config SOC_SP7021
+	bool "Sunplus SP7021 SoC support"
+	depends on ARCH_SUNPLUS
+	default ARCH_SUNPLUS
+	select ARM_GIC
+	select ARM_PSCI
+	select PINCTRL
+	select PINCTRL_SPPCTL
+	select SERIAL_SUNPLUS
+	select SERIAL_SUNPLUS_CONSOLE
+	help
+	  Support for Sunplus SP7021 SoC. It is based on ARM 4-core
+	  Cortex-A7 with various peripherals (ex: I2C, SPI, SDIO,
+	  Ethernet and etc.), FPGA interface,  chip-to-chip bus.
+	  It is designed for industrial control.
diff --git a/arch/arm/mach-sunplus/Makefile b/arch/arm/mach-sunplus/Makefile
new file mode 100644
index 000000000..c902580a7
--- /dev/null
+++ b/arch/arm/mach-sunplus/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-$(CONFIG_SOC_SP7021)	+= sp7021.o
+
diff --git a/arch/arm/mach-sunplus/sp7021.c b/arch/arm/mach-sunplus/sp7021.c
new file mode 100644
index 000000000..774d0a5bd
--- /dev/null
+++ b/arch/arm/mach-sunplus/sp7021.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#include <linux/kernel.h>
+#include <asm/mach/arch.h>
+
+static const char *sp7021_compat[] __initconst = {
+	"sunplus,sp7021",
+	NULL
+};
+
+DT_MACHINE_START(SP7021_DT, "SP7021")
+	.dt_compat	= sp7021_compat,
+MACHINE_END
-- 
2.33.1


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

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

* [PATCH v7 10/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig
  2021-12-22  7:05 ` Qin Jian
@ 2021-12-22  7:06   ` Qin Jian
  -1 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add generic Sunplus SP7021 based board defconfig

Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 MAINTAINERS                         |  1 +
 arch/arm/configs/multi_v7_defconfig |  1 +
 arch/arm/configs/sp7021_defconfig   | 61 +++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)
 create mode 100644 arch/arm/configs/sp7021_defconfig

diff --git a/MAINTAINERS b/MAINTAINERS
index 0ae537a41..9340f8760 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2664,6 +2664,7 @@ F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	arch/arm/configs/sp7021_*defconfig
 F:	arch/arm/mach-sunplus/
 F:	drivers/clk/clk-sp7021.c
 F:	drivers/irqchip/irq-sp7021-intc.c
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index b4f74454f..585e3b5d3 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -87,6 +87,7 @@ CONFIG_MACH_SPEAR1310=y
 CONFIG_MACH_SPEAR1340=y
 CONFIG_ARCH_STI=y
 CONFIG_ARCH_STM32=y
+CONFIG_ARCH_SUNPLUS=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_TEGRA=y
 CONFIG_ARCH_UNIPHIER=y
diff --git a/arch/arm/configs/sp7021_defconfig b/arch/arm/configs/sp7021_defconfig
new file mode 100644
index 000000000..cda16d33a
--- /dev/null
+++ b/arch/arm/configs/sp7021_defconfig
@@ -0,0 +1,61 @@
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# 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_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PERF_EVENTS=y
+CONFIG_SLAB=y
+CONFIG_ARCH_SUNPLUS=y
+# CONFIG_VDSO is not set
+CONFIG_SMP=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+CONFIG_THUMB2_KERNEL=y
+CONFIG_FORCE_MAX_ZONEORDER=12
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_INPUT_SPARSEKMAP=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_STAGING=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RESET_CONTROLLER=y
+CONFIG_EXT4_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FANOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="utf8"
+CONFIG_EXFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_USER=y
-- 
2.33.1


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

* [PATCH v7 10/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig
@ 2021-12-22  7:06   ` Qin Jian
  0 siblings, 0 replies; 34+ messages in thread
From: Qin Jian @ 2021-12-22  7:06 UTC (permalink / raw)
  To: robh+dt
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Add generic Sunplus SP7021 based board defconfig

Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 MAINTAINERS                         |  1 +
 arch/arm/configs/multi_v7_defconfig |  1 +
 arch/arm/configs/sp7021_defconfig   | 61 +++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)
 create mode 100644 arch/arm/configs/sp7021_defconfig

diff --git a/MAINTAINERS b/MAINTAINERS
index 0ae537a41..9340f8760 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2664,6 +2664,7 @@ F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	arch/arm/configs/sp7021_*defconfig
 F:	arch/arm/mach-sunplus/
 F:	drivers/clk/clk-sp7021.c
 F:	drivers/irqchip/irq-sp7021-intc.c
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index b4f74454f..585e3b5d3 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -87,6 +87,7 @@ CONFIG_MACH_SPEAR1310=y
 CONFIG_MACH_SPEAR1340=y
 CONFIG_ARCH_STI=y
 CONFIG_ARCH_STM32=y
+CONFIG_ARCH_SUNPLUS=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_TEGRA=y
 CONFIG_ARCH_UNIPHIER=y
diff --git a/arch/arm/configs/sp7021_defconfig b/arch/arm/configs/sp7021_defconfig
new file mode 100644
index 000000000..cda16d33a
--- /dev/null
+++ b/arch/arm/configs/sp7021_defconfig
@@ -0,0 +1,61 @@
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# 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_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PERF_EVENTS=y
+CONFIG_SLAB=y
+CONFIG_ARCH_SUNPLUS=y
+# CONFIG_VDSO is not set
+CONFIG_SMP=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+CONFIG_THUMB2_KERNEL=y
+CONFIG_FORCE_MAX_ZONEORDER=12
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_INPUT_SPARSEKMAP=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_STAGING=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_RESET_CONTROLLER=y
+CONFIG_EXT4_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FANOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="utf8"
+CONFIG_EXFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_USER=y
-- 
2.33.1


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

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

* Re: [PATCH v7 05/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2021-12-22  7:06   ` Qin Jian
@ 2021-12-22 17:05     ` Rob Herring
  -1 siblings, 0 replies; 34+ messages in thread
From: Rob Herring @ 2021-12-22 17:05 UTC (permalink / raw)
  To: Qin Jian
  Cc: mturquette, stefan.wahren, linux-arm-kernel, linux-clk, linux,
	devicetree, maz, wells.lu, tglx, robh+dt, broonie, linux-kernel,
	sboyd, arnd, p.zabel

On Wed, 22 Dec 2021 15:06:01 +0800, Qin Jian wrote:
> Add documentation to describe Sunplus SP7021 clock driver bindings.
> 
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---
> Add clocks & clock-names.
> ---
>  .../bindings/clock/sunplus,sp7021-clkc.yaml   |  52 ++++++++
>  MAINTAINERS                                   |   2 +
>  include/dt-bindings/clock/sp-sp7021.h         | 112 ++++++++++++++++++
>  3 files changed, 166 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
>  create mode 100644 include/dt-bindings/clock/sp-sp7021.h
> 

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v7 05/10] dt-bindings: clock: Add bindings for SP7021 clock driver
@ 2021-12-22 17:05     ` Rob Herring
  0 siblings, 0 replies; 34+ messages in thread
From: Rob Herring @ 2021-12-22 17:05 UTC (permalink / raw)
  To: Qin Jian
  Cc: mturquette, stefan.wahren, linux-arm-kernel, linux-clk, linux,
	devicetree, maz, wells.lu, tglx, robh+dt, broonie, linux-kernel,
	sboyd, arnd, p.zabel

On Wed, 22 Dec 2021 15:06:01 +0800, Qin Jian wrote:
> Add documentation to describe Sunplus SP7021 clock driver bindings.
> 
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---
> Add clocks & clock-names.
> ---
>  .../bindings/clock/sunplus,sp7021-clkc.yaml   |  52 ++++++++
>  MAINTAINERS                                   |   2 +
>  include/dt-bindings/clock/sp-sp7021.h         | 112 ++++++++++++++++++
>  3 files changed, 166 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
>  create mode 100644 include/dt-bindings/clock/sp-sp7021.h
> 

Reviewed-by: Rob Herring <robh@kernel.org>

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

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

* Re: [PATCH v7 05/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2021-12-22  7:06   ` Qin Jian
@ 2022-01-06  0:36     ` Stephen Boyd
  -1 siblings, 0 replies; 34+ messages in thread
From: Stephen Boyd @ 2022-01-06  0:36 UTC (permalink / raw)
  To: Qin Jian, robh+dt
  Cc: mturquette, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Quoting Qin Jian (2021-12-21 23:06:01)
> Add documentation to describe Sunplus SP7021 clock driver bindings.
> 
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---

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

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

* Re: [PATCH v7 05/10] dt-bindings: clock: Add bindings for SP7021 clock driver
@ 2022-01-06  0:36     ` Stephen Boyd
  0 siblings, 0 replies; 34+ messages in thread
From: Stephen Boyd @ 2022-01-06  0:36 UTC (permalink / raw)
  To: Qin Jian, robh+dt
  Cc: mturquette, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Quoting Qin Jian (2021-12-21 23:06:01)
> Add documentation to describe Sunplus SP7021 clock driver bindings.
> 
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---

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

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

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

* Re: [PATCH v7 06/10] clk: Add Sunplus SP7021 clock driver
  2021-12-22  7:06   ` Qin Jian
@ 2022-01-06  0:42     ` Stephen Boyd
  -1 siblings, 0 replies; 34+ messages in thread
From: Stephen Boyd @ 2022-01-06  0:42 UTC (permalink / raw)
  To: Qin Jian, robh+dt
  Cc: mturquette, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Quoting Qin Jian (2021-12-21 23:06:02)
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index c5b3dc973..4a186ccf6 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -334,6 +334,15 @@ config COMMON_CLK_VC5
>           This driver supports the IDT VersaClock 5 and VersaClock 6
>           programmable clock generators.
>  
> +config COMMON_CLK_SP7021
> +       bool "Clock driver for Sunplus SP7021 SoC"
> +       default SOC_SP7021
> +       help
> +         This driver supports the Sunplus SP7021 SoC clocks.
> +         It implements SP7021 PLLs/gate.
> +         Not all features of the PLL are currently supported
> +         by the driver.
> +
>  config COMMON_CLK_STM32MP157
>         def_bool COMMON_CLK && MACH_STM32MP157
>         help
> @@ -366,7 +375,6 @@ config COMMON_CLK_MMP2
>  
>  config COMMON_CLK_MMP2_AUDIO
>          tristate "Clock driver for MMP2 Audio subsystem"
> -        depends on COMMON_CLK_MMP2 || COMPILE_TEST
>          help
>            This driver supports clocks for Audio subsystem on MMP2 SoC.
>  

What's the relevance of this hunk to this patch? Can you drop this part?

> diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c
> new file mode 100644
> index 000000000..6df87f0a6
> --- /dev/null
> +++ b/drivers/clk/clk-sp7021.c
> @@ -0,0 +1,705 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +/*
> + * Copyright (C) Sunplus Technology Co., Ltd.
> + *       All rights reserved.
> + */
> +//#define DEBUG
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/bitfield.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <dt-bindings/clock/sp-sp7021.h>
> +
> +#define REG(i)         (pll_regs + (i) * 4)
> +
[....]
> +
> +static long plltv_div(struct sp_pll *clk, unsigned long freq)
> +{
> +       if (freq % 100)
> +               return plltv_fractional_div(clk, freq);
> +       else
> +               return plltv_integer_div(clk, freq);

Drop else please

> +}
> +
> +static void plltv_set_rate(struct sp_pll *clk)
> +{
> +       u32 reg;
> +
> +       reg  = HWM_FIELD_PREP(MASK_SEL_FRA, clk->p[SEL_FRA]);
> +       reg |= HWM_FIELD_PREP(MASK_SDM_MOD, clk->p[SDM_MOD]);
> +       reg |= HWM_FIELD_PREP(MASK_PH_SEL, clk->p[PH_SEL]);
> +       reg |= HWM_FIELD_PREP(MASK_NFRA, clk->p[NFRA]);
> +       writel(reg, clk->reg);
> +
> +       reg  = HWM_FIELD_PREP(MASK_DIVR, clk->p[DIVR]);
[...]
> +       .set_rate = sp_pll_set_rate
> +};
> +
> +static const struct clk_ops sp_pll_sub_ops = {
> +       .enable = sp_pll_enable,
> +       .disable = sp_pll_disable,
> +       .is_enabled = sp_pll_is_enabled,
> +       .recalc_rate = sp_pll_recalc_rate,
> +};
> +
> +struct clk_hw *sp_pll_register(const char *name, const char *parent,
> +                              void __iomem *reg, int pd_bit, int bp_bit,
> +                              unsigned long brate, int shift, int width,
> +                              spinlock_t *lock)
> +{
> +       struct sp_pll *pll;
> +       struct clk_hw *hw;
> +       struct clk_init_data initd = {
> +               .name = name,
> +               .parent_names = &parent,

Any chance clk_parent_data can be used instead of string names?

> +               .ops = (bp_bit >= 0) ? &sp_pll_ops : &sp_pll_sub_ops,
> +               .num_parents = 1,
> +       };
> +       int ret;
> +
> +       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
> +       if (!pll)
> +               return ERR_PTR(-ENOMEM);
> +
> +       if (reg == PLLSYS_CTL) /* system clock, should not be closed */

s/closed/disabled/

> +               initd.flags |= CLK_IS_CRITICAL;
> +
> +       pll->hw.init = &initd;
> +       pll->reg = reg;
> +       pll->pd_bit = pd_bit;
> +       pll->bp_bit = bp_bit;
> +       pll->brate = brate;
> +       pll->div_shift = shift;
> +       pll->div_width = width;
> +       pll->lock = lock;
> +
> +       hw = &pll->hw;
> +       ret = clk_hw_register(NULL, hw);
> +       if (ret) {
> +               kfree(pll);
> +               hw = ERR_PTR(ret);
> +       } else {
> +               pr_info("%-20s%lu\n", name, clk_hw_get_rate(hw));

Drop this print or make it pr_debug()

> +               clk_hw_register_clkdev(hw, NULL, name);
> +       }
> +
> +       return hw;
> +}
> +
> +static void __init sp_clk_setup(struct device_node *np)
> +{
> +       int i, j;
> +       struct clk_hw **hws;
> +
> +       sp_clk_base = of_iomap(np, 0);
> +       if (WARN_ON(!sp_clk_base))
> +               return; /* -ENXIO */
> +
> +       sp_clk_data = kzalloc(struct_size(sp_clk_data, hws, CLK_MAX), GFP_KERNEL);
> +       if (!sp_clk_data)
> +               return; /* -ENOMEM */
> +
> +       hws = sp_clk_data->hws;
> +
> +       /* PLL_A */
> +       hws[PLL_A] = sp_pll_register("plla", EXTCLK, PLLA_CTL, 11, 12,
> +                                    27000000, 0, DIV_A, &plla_lock);
> +
> +       /* PLL_E */
> +       hws[PLL_E] = sp_pll_register("plle", EXTCLK, PLLE_CTL, 6, 2,
> +                                    50000000, 0, 0, &plle_lock);
> +       hws[PLL_E_2P5] = sp_pll_register("plle_2p5", "plle", PLLE_CTL, 13, -1,
> +                                        2500000, 0, 0, &plle_lock);
> +       hws[PLL_E_25] = sp_pll_register("plle_25", "plle", PLLE_CTL, 12, -1,
> +                                       25000000, 0, 0, &plle_lock);
> +       hws[PLL_E_112P5] = sp_pll_register("plle_112p5", "plle", PLLE_CTL, 11, -1,
> +                                          112500000, 0, 0, &plle_lock);
> +
> +       /* PLL_F */
> +       hws[PLL_F] = sp_pll_register("pllf", EXTCLK, PLLF_CTL, 0, 10,
> +                                    13500000, 1, 4, &pllf_lock);
> +
> +       /* PLL_TV */
> +       hws[PLL_TV] = sp_pll_register("plltv", EXTCLK, PLLTV_CTL, 0, 15,
> +                                     27000000, 0, DIV_TV, &plltv_lock);
> +       hws[PLL_TV_A] = clk_hw_register_divider(NULL, "plltv_a", "plltv", 0,
> +                                               PLLTV_CTL + 4, 5, 1,
> +                                               CLK_DIVIDER_POWER_OF_TWO,
> +                                               &plltv_lock);
> +       clk_hw_register_clkdev(hws[PLL_TV_A], NULL, "plltv_a");
> +
> +       /* PLL_SYS */
> +       hws[PLL_SYS] = sp_pll_register("pllsys", EXTCLK, PLLSYS_CTL, 10, 9,
> +                                      13500000, 0, 4, &pllsys_lock);
> +
> +       /* gates */
> +       for (i = 0; i < ARRAY_SIZE(gates); i++) {
> +               char s[10];
> +
> +               j = gates[i] & 0xffff;
> +               sprintf(s, "clken%02x", j);
> +               hws[j] = clk_hw_register_gate(NULL, s,
> +                                             parents[gates[i] >> 16].fw_name,
> +                                             CLK_IGNORE_UNUSED,

Why CLK_IGNORE_UNUSED? There should be a comment or it should be
replaced with CLK_IS_CRITICAL.

> +                                             clk_regs + (j >> 4) * 4, j & 0x0f,
> +                                             CLK_GATE_HIWORD_MASK, NULL);
> +       }
> +
> +       sp_clk_data->num = CLK_MAX;
> +       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, sp_clk_data);
> +}
> +
> +CLK_OF_DECLARE_DRIVER(sp_clkc, "sunplus,sp7021-clkc", sp_clk_setup);

Why CLK_OF_DECLARE_DRIVER? There should be a comment but better would be
to make a platform driver instead. If the platform driver can't be used,
we need to know what other device driver is probing based on this clkc
compatible string.

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

* Re: [PATCH v7 06/10] clk: Add Sunplus SP7021 clock driver
@ 2022-01-06  0:42     ` Stephen Boyd
  0 siblings, 0 replies; 34+ messages in thread
From: Stephen Boyd @ 2022-01-06  0:42 UTC (permalink / raw)
  To: Qin Jian, robh+dt
  Cc: mturquette, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu, Qin Jian

Quoting Qin Jian (2021-12-21 23:06:02)
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index c5b3dc973..4a186ccf6 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -334,6 +334,15 @@ config COMMON_CLK_VC5
>           This driver supports the IDT VersaClock 5 and VersaClock 6
>           programmable clock generators.
>  
> +config COMMON_CLK_SP7021
> +       bool "Clock driver for Sunplus SP7021 SoC"
> +       default SOC_SP7021
> +       help
> +         This driver supports the Sunplus SP7021 SoC clocks.
> +         It implements SP7021 PLLs/gate.
> +         Not all features of the PLL are currently supported
> +         by the driver.
> +
>  config COMMON_CLK_STM32MP157
>         def_bool COMMON_CLK && MACH_STM32MP157
>         help
> @@ -366,7 +375,6 @@ config COMMON_CLK_MMP2
>  
>  config COMMON_CLK_MMP2_AUDIO
>          tristate "Clock driver for MMP2 Audio subsystem"
> -        depends on COMMON_CLK_MMP2 || COMPILE_TEST
>          help
>            This driver supports clocks for Audio subsystem on MMP2 SoC.
>  

What's the relevance of this hunk to this patch? Can you drop this part?

> diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c
> new file mode 100644
> index 000000000..6df87f0a6
> --- /dev/null
> +++ b/drivers/clk/clk-sp7021.c
> @@ -0,0 +1,705 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +/*
> + * Copyright (C) Sunplus Technology Co., Ltd.
> + *       All rights reserved.
> + */
> +//#define DEBUG
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/bitfield.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <dt-bindings/clock/sp-sp7021.h>
> +
> +#define REG(i)         (pll_regs + (i) * 4)
> +
[....]
> +
> +static long plltv_div(struct sp_pll *clk, unsigned long freq)
> +{
> +       if (freq % 100)
> +               return plltv_fractional_div(clk, freq);
> +       else
> +               return plltv_integer_div(clk, freq);

Drop else please

> +}
> +
> +static void plltv_set_rate(struct sp_pll *clk)
> +{
> +       u32 reg;
> +
> +       reg  = HWM_FIELD_PREP(MASK_SEL_FRA, clk->p[SEL_FRA]);
> +       reg |= HWM_FIELD_PREP(MASK_SDM_MOD, clk->p[SDM_MOD]);
> +       reg |= HWM_FIELD_PREP(MASK_PH_SEL, clk->p[PH_SEL]);
> +       reg |= HWM_FIELD_PREP(MASK_NFRA, clk->p[NFRA]);
> +       writel(reg, clk->reg);
> +
> +       reg  = HWM_FIELD_PREP(MASK_DIVR, clk->p[DIVR]);
[...]
> +       .set_rate = sp_pll_set_rate
> +};
> +
> +static const struct clk_ops sp_pll_sub_ops = {
> +       .enable = sp_pll_enable,
> +       .disable = sp_pll_disable,
> +       .is_enabled = sp_pll_is_enabled,
> +       .recalc_rate = sp_pll_recalc_rate,
> +};
> +
> +struct clk_hw *sp_pll_register(const char *name, const char *parent,
> +                              void __iomem *reg, int pd_bit, int bp_bit,
> +                              unsigned long brate, int shift, int width,
> +                              spinlock_t *lock)
> +{
> +       struct sp_pll *pll;
> +       struct clk_hw *hw;
> +       struct clk_init_data initd = {
> +               .name = name,
> +               .parent_names = &parent,

Any chance clk_parent_data can be used instead of string names?

> +               .ops = (bp_bit >= 0) ? &sp_pll_ops : &sp_pll_sub_ops,
> +               .num_parents = 1,
> +       };
> +       int ret;
> +
> +       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
> +       if (!pll)
> +               return ERR_PTR(-ENOMEM);
> +
> +       if (reg == PLLSYS_CTL) /* system clock, should not be closed */

s/closed/disabled/

> +               initd.flags |= CLK_IS_CRITICAL;
> +
> +       pll->hw.init = &initd;
> +       pll->reg = reg;
> +       pll->pd_bit = pd_bit;
> +       pll->bp_bit = bp_bit;
> +       pll->brate = brate;
> +       pll->div_shift = shift;
> +       pll->div_width = width;
> +       pll->lock = lock;
> +
> +       hw = &pll->hw;
> +       ret = clk_hw_register(NULL, hw);
> +       if (ret) {
> +               kfree(pll);
> +               hw = ERR_PTR(ret);
> +       } else {
> +               pr_info("%-20s%lu\n", name, clk_hw_get_rate(hw));

Drop this print or make it pr_debug()

> +               clk_hw_register_clkdev(hw, NULL, name);
> +       }
> +
> +       return hw;
> +}
> +
> +static void __init sp_clk_setup(struct device_node *np)
> +{
> +       int i, j;
> +       struct clk_hw **hws;
> +
> +       sp_clk_base = of_iomap(np, 0);
> +       if (WARN_ON(!sp_clk_base))
> +               return; /* -ENXIO */
> +
> +       sp_clk_data = kzalloc(struct_size(sp_clk_data, hws, CLK_MAX), GFP_KERNEL);
> +       if (!sp_clk_data)
> +               return; /* -ENOMEM */
> +
> +       hws = sp_clk_data->hws;
> +
> +       /* PLL_A */
> +       hws[PLL_A] = sp_pll_register("plla", EXTCLK, PLLA_CTL, 11, 12,
> +                                    27000000, 0, DIV_A, &plla_lock);
> +
> +       /* PLL_E */
> +       hws[PLL_E] = sp_pll_register("plle", EXTCLK, PLLE_CTL, 6, 2,
> +                                    50000000, 0, 0, &plle_lock);
> +       hws[PLL_E_2P5] = sp_pll_register("plle_2p5", "plle", PLLE_CTL, 13, -1,
> +                                        2500000, 0, 0, &plle_lock);
> +       hws[PLL_E_25] = sp_pll_register("plle_25", "plle", PLLE_CTL, 12, -1,
> +                                       25000000, 0, 0, &plle_lock);
> +       hws[PLL_E_112P5] = sp_pll_register("plle_112p5", "plle", PLLE_CTL, 11, -1,
> +                                          112500000, 0, 0, &plle_lock);
> +
> +       /* PLL_F */
> +       hws[PLL_F] = sp_pll_register("pllf", EXTCLK, PLLF_CTL, 0, 10,
> +                                    13500000, 1, 4, &pllf_lock);
> +
> +       /* PLL_TV */
> +       hws[PLL_TV] = sp_pll_register("plltv", EXTCLK, PLLTV_CTL, 0, 15,
> +                                     27000000, 0, DIV_TV, &plltv_lock);
> +       hws[PLL_TV_A] = clk_hw_register_divider(NULL, "plltv_a", "plltv", 0,
> +                                               PLLTV_CTL + 4, 5, 1,
> +                                               CLK_DIVIDER_POWER_OF_TWO,
> +                                               &plltv_lock);
> +       clk_hw_register_clkdev(hws[PLL_TV_A], NULL, "plltv_a");
> +
> +       /* PLL_SYS */
> +       hws[PLL_SYS] = sp_pll_register("pllsys", EXTCLK, PLLSYS_CTL, 10, 9,
> +                                      13500000, 0, 4, &pllsys_lock);
> +
> +       /* gates */
> +       for (i = 0; i < ARRAY_SIZE(gates); i++) {
> +               char s[10];
> +
> +               j = gates[i] & 0xffff;
> +               sprintf(s, "clken%02x", j);
> +               hws[j] = clk_hw_register_gate(NULL, s,
> +                                             parents[gates[i] >> 16].fw_name,
> +                                             CLK_IGNORE_UNUSED,

Why CLK_IGNORE_UNUSED? There should be a comment or it should be
replaced with CLK_IS_CRITICAL.

> +                                             clk_regs + (j >> 4) * 4, j & 0x0f,
> +                                             CLK_GATE_HIWORD_MASK, NULL);
> +       }
> +
> +       sp_clk_data->num = CLK_MAX;
> +       of_clk_add_hw_provider(np, of_clk_hw_onecell_get, sp_clk_data);
> +}
> +
> +CLK_OF_DECLARE_DRIVER(sp_clkc, "sunplus,sp7021-clkc", sp_clk_setup);

Why CLK_OF_DECLARE_DRIVER? There should be a comment but better would be
to make a platform driver instead. If the platform driver can't be used,
we need to know what other device driver is probing based on this clkc
compatible string.

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

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

* RE: [PATCH v7 06/10] clk: Add Sunplus SP7021 clock driver
  2022-01-06  0:42     ` Stephen Boyd
@ 2022-01-07  7:55       ` qinjian[覃健]
  -1 siblings, 0 replies; 34+ messages in thread
From: qinjian[覃健] @ 2022-01-07  7:55 UTC (permalink / raw)
  To: Stephen Boyd, robh+dt
  Cc: mturquette, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Wells Lu 呂芳騰

> > +
> > +CLK_OF_DECLARE_DRIVER(sp_clkc, "sunplus,sp7021-clkc", sp_clk_setup);
> 
> Why CLK_OF_DECLARE_DRIVER? There should be a comment but better would be
> to make a platform driver instead. If the platform driver can't be used,
> we need to know what other device driver is probing based on this clkc
> compatible string.

Dear Stephen,

Sorry, I don't understand your comment.
Did you mean, like below:

static int sp7021_clk_probe(struct platform_device *pdev)
{
	......
	sp_clk_data->num = CLK_MAX;
	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, sp_clk_data);
}

static const struct of_device_id sp7021_clk_dt_ids[] = {
	{ .compatible = "sunplus,sp7021-clkc", },
	{ }
};
MODULE_DEVICE_TABLE(of, sp7021_clk_dt_ids);

static struct platform_driver sp7021_clk_driver = {
	.probe  = sp7021_clk_probe,
	.driver = {
		.name = "sp7021-clk",
		.of_match_table = sp7021_clk_dt_ids,
	},
};
builtin_platform_driver(sp7021_clk_driver);


But, It's doesn't work. 
Most other clk drivers used CLK_OF_DECLARE_DRIVER or CLK_OF_DECLARE.
I just take these as the reference and it's working.

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

* RE: [PATCH v7 06/10] clk: Add Sunplus SP7021 clock driver
@ 2022-01-07  7:55       ` qinjian[覃健]
  0 siblings, 0 replies; 34+ messages in thread
From: qinjian[覃健] @ 2022-01-07  7:55 UTC (permalink / raw)
  To: Stephen Boyd, robh+dt
  Cc: mturquette, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Wells Lu 呂芳騰

> > +
> > +CLK_OF_DECLARE_DRIVER(sp_clkc, "sunplus,sp7021-clkc", sp_clk_setup);
> 
> Why CLK_OF_DECLARE_DRIVER? There should be a comment but better would be
> to make a platform driver instead. If the platform driver can't be used,
> we need to know what other device driver is probing based on this clkc
> compatible string.

Dear Stephen,

Sorry, I don't understand your comment.
Did you mean, like below:

static int sp7021_clk_probe(struct platform_device *pdev)
{
	......
	sp_clk_data->num = CLK_MAX;
	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, sp_clk_data);
}

static const struct of_device_id sp7021_clk_dt_ids[] = {
	{ .compatible = "sunplus,sp7021-clkc", },
	{ }
};
MODULE_DEVICE_TABLE(of, sp7021_clk_dt_ids);

static struct platform_driver sp7021_clk_driver = {
	.probe  = sp7021_clk_probe,
	.driver = {
		.name = "sp7021-clk",
		.of_match_table = sp7021_clk_dt_ids,
	},
};
builtin_platform_driver(sp7021_clk_driver);


But, It's doesn't work. 
Most other clk drivers used CLK_OF_DECLARE_DRIVER or CLK_OF_DECLARE.
I just take these as the reference and it's working.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v7 01/10] dt-bindings: vendor-prefixes: Add Sunplus
  2021-12-22  7:05   ` Qin Jian
@ 2022-01-10  0:56     ` Rob Herring
  -1 siblings, 0 replies; 34+ messages in thread
From: Rob Herring @ 2022-01-10  0:56 UTC (permalink / raw)
  To: Qin Jian
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu

On Wed, Dec 22, 2021 at 03:05:57PM +0800, Qin Jian wrote:
> Add vendor prefix for Sunplus Technology Co., Ltd. (http://www.sunplus.com)
> 
> Acked-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  1 file changed, 2 insertions(+)

As this one is a dependency for other series, applied for 5.17.

Rob

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

* Re: [PATCH v7 01/10] dt-bindings: vendor-prefixes: Add Sunplus
@ 2022-01-10  0:56     ` Rob Herring
  0 siblings, 0 replies; 34+ messages in thread
From: Rob Herring @ 2022-01-10  0:56 UTC (permalink / raw)
  To: Qin Jian
  Cc: mturquette, sboyd, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, wells.lu

On Wed, Dec 22, 2021 at 03:05:57PM +0800, Qin Jian wrote:
> Add vendor prefix for Sunplus Technology Co., Ltd. (http://www.sunplus.com)
> 
> Acked-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  1 file changed, 2 insertions(+)

As this one is a dependency for other series, applied for 5.17.

Rob

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

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

* RE: [PATCH v7 06/10] clk: Add Sunplus SP7021 clock driver
       [not found]       ` <20220108004112.2AB34C36AE9@smtp.kernel.org>
@ 2022-01-10  6:37           ` qinjian[覃健]
  0 siblings, 0 replies; 34+ messages in thread
From: qinjian[覃健] @ 2022-01-10  6:37 UTC (permalink / raw)
  To: Stephen Boyd, robh+dt
  Cc: mturquette, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Wells Lu 呂芳騰

> > > > +
> > > > +CLK_OF_DECLARE_DRIVER(sp_clkc, "sunplus,sp7021-clkc", sp_clk_setup);
> > >
> > > Why CLK_OF_DECLARE_DRIVER? There should be a comment but better would be
> > > to make a platform driver instead. If the platform driver can't be used,
> > > we need to know what other device driver is probing based on this clkc
> > > compatible string.
> >
> > Dear Stephen,
> >
> > Sorry, I don't understand your comment.
> > Did you mean, like below:
> >
> > static int sp7021_clk_probe(struct platform_device *pdev)
> > {
> >         ......
> >         sp_clk_data->num = CLK_MAX;
> >         return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, sp_clk_data);
> > }
> >
> > static const struct of_device_id sp7021_clk_dt_ids[] = {
> >         { .compatible = "sunplus,sp7021-clkc", },
> >         { }
> > };
> > MODULE_DEVICE_TABLE(of, sp7021_clk_dt_ids);
> >
> > static struct platform_driver sp7021_clk_driver = {
> >         .probe  = sp7021_clk_probe,
> >         .driver = {
> >                 .name = "sp7021-clk",
> >                 .of_match_table = sp7021_clk_dt_ids,
> >         },
> > };
> > builtin_platform_driver(sp7021_clk_driver);
> >
> >
> > But, It's doesn't work.
> 
> Why doesn't it work?
> 
> > Most other clk drivers used CLK_OF_DECLARE_DRIVER or CLK_OF_DECLARE.
> > I just take these as the reference and it's working.
> 
> CLK_OF_DECLARE is for clks that need to be registered so the main
> irqchip and/or clocksource/clockevent can operate properly.
> CLK_OF_DECLARE_DRIVER is for the case that there's another driver that
> will attach to the device node that has the compatible string.

After some trace, I found:
In our dts, 'clkc' node defined @ clocks:
	clocks {
		...
		clkc: clock-controller@9c000000 {
			#clock-cells = <1>;
			compatible = "sunplus,sp7021-clkc";
			reg = <0x9c000000 0x280>; // G0:CLKEN ~ G4:PLL
			clocks = <&extclk>, <&clkc PLL_SYS>;
			clock-names = "extclk", "pllsys";
		};
	};
	soc {
		...
	}
In this case, clk driver write as platform driver not work (sp7021_clk_probe not called)
But, CLK_OF_DECLARE and CLK_OF_DECLARE_DRIVER both worked (called from clk_of_init)

Then, I move the 'clkc' mode from 'clocks' to 'soc':
	clocks {
		...
	};
	soc {
		...
		clkc: clock-controller@9c000000 {
			#clock-cells = <1>;
			compatible = "sunplus,sp7021-clkc";
			reg = <0x9c000000 0x280>; // G0:CLKEN ~ G4:PLL
			clocks = <&extclk>, <&clkc PLL_SYS>;
			clock-names = "extclk", "pllsys";
		};
	}
In this case, clk driver write as platform driver worked (called from platform_probe)
CLK_OF_DECLARE and CLK_OF_DECLARE_DRIVER also both worked. (still called from clk_of_init, more early than platform_probe)

It looks like CLK_OF_DECLARE/CLK_OF_DECLARE_DRIVER is better than platform driver.
Why you prefer platform driver?



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

* RE: [PATCH v7 06/10] clk: Add Sunplus SP7021 clock driver
@ 2022-01-10  6:37           ` qinjian[覃健]
  0 siblings, 0 replies; 34+ messages in thread
From: qinjian[覃健] @ 2022-01-10  6:37 UTC (permalink / raw)
  To: Stephen Boyd, robh+dt
  Cc: mturquette, tglx, maz, p.zabel, linux, broonie, arnd,
	stefan.wahren, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Wells Lu 呂芳騰

> > > > +
> > > > +CLK_OF_DECLARE_DRIVER(sp_clkc, "sunplus,sp7021-clkc", sp_clk_setup);
> > >
> > > Why CLK_OF_DECLARE_DRIVER? There should be a comment but better would be
> > > to make a platform driver instead. If the platform driver can't be used,
> > > we need to know what other device driver is probing based on this clkc
> > > compatible string.
> >
> > Dear Stephen,
> >
> > Sorry, I don't understand your comment.
> > Did you mean, like below:
> >
> > static int sp7021_clk_probe(struct platform_device *pdev)
> > {
> >         ......
> >         sp_clk_data->num = CLK_MAX;
> >         return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, sp_clk_data);
> > }
> >
> > static const struct of_device_id sp7021_clk_dt_ids[] = {
> >         { .compatible = "sunplus,sp7021-clkc", },
> >         { }
> > };
> > MODULE_DEVICE_TABLE(of, sp7021_clk_dt_ids);
> >
> > static struct platform_driver sp7021_clk_driver = {
> >         .probe  = sp7021_clk_probe,
> >         .driver = {
> >                 .name = "sp7021-clk",
> >                 .of_match_table = sp7021_clk_dt_ids,
> >         },
> > };
> > builtin_platform_driver(sp7021_clk_driver);
> >
> >
> > But, It's doesn't work.
> 
> Why doesn't it work?
> 
> > Most other clk drivers used CLK_OF_DECLARE_DRIVER or CLK_OF_DECLARE.
> > I just take these as the reference and it's working.
> 
> CLK_OF_DECLARE is for clks that need to be registered so the main
> irqchip and/or clocksource/clockevent can operate properly.
> CLK_OF_DECLARE_DRIVER is for the case that there's another driver that
> will attach to the device node that has the compatible string.

After some trace, I found:
In our dts, 'clkc' node defined @ clocks:
	clocks {
		...
		clkc: clock-controller@9c000000 {
			#clock-cells = <1>;
			compatible = "sunplus,sp7021-clkc";
			reg = <0x9c000000 0x280>; // G0:CLKEN ~ G4:PLL
			clocks = <&extclk>, <&clkc PLL_SYS>;
			clock-names = "extclk", "pllsys";
		};
	};
	soc {
		...
	}
In this case, clk driver write as platform driver not work (sp7021_clk_probe not called)
But, CLK_OF_DECLARE and CLK_OF_DECLARE_DRIVER both worked (called from clk_of_init)

Then, I move the 'clkc' mode from 'clocks' to 'soc':
	clocks {
		...
	};
	soc {
		...
		clkc: clock-controller@9c000000 {
			#clock-cells = <1>;
			compatible = "sunplus,sp7021-clkc";
			reg = <0x9c000000 0x280>; // G0:CLKEN ~ G4:PLL
			clocks = <&extclk>, <&clkc PLL_SYS>;
			clock-names = "extclk", "pllsys";
		};
	}
In this case, clk driver write as platform driver worked (called from platform_probe)
CLK_OF_DECLARE and CLK_OF_DECLARE_DRIVER also both worked. (still called from clk_of_init, more early than platform_probe)

It looks like CLK_OF_DECLARE/CLK_OF_DECLARE_DRIVER is better than platform driver.
Why you prefer platform driver?


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

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

end of thread, other threads:[~2022-01-10  6:51 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-22  7:05 [PATCH v7 00/10] Add Sunplus SP7021 SoC Support Qin Jian
2021-12-22  7:05 ` Qin Jian
2021-12-22  7:05 ` [PATCH v7 01/10] dt-bindings: vendor-prefixes: Add Sunplus Qin Jian
2021-12-22  7:05   ` Qin Jian
2022-01-10  0:56   ` Rob Herring
2022-01-10  0:56     ` Rob Herring
2021-12-22  7:05 ` [PATCH v7 02/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards Qin Jian
2021-12-22  7:05   ` Qin Jian
2021-12-22  7:05 ` [PATCH v7 03/10] dt-bindings: reset: Add bindings for SP7021 reset driver Qin Jian
2021-12-22  7:05   ` Qin Jian
2021-12-22  7:06 ` [PATCH v7 04/10] reset: Add Sunplus " Qin Jian
2021-12-22  7:06   ` Qin Jian
2021-12-22  7:06 ` [PATCH v7 05/10] dt-bindings: clock: Add bindings for SP7021 clock driver Qin Jian
2021-12-22  7:06   ` Qin Jian
2021-12-22 17:05   ` Rob Herring
2021-12-22 17:05     ` Rob Herring
2022-01-06  0:36   ` Stephen Boyd
2022-01-06  0:36     ` Stephen Boyd
2021-12-22  7:06 ` [PATCH v7 06/10] clk: Add Sunplus " Qin Jian
2021-12-22  7:06   ` Qin Jian
2022-01-06  0:42   ` Stephen Boyd
2022-01-06  0:42     ` Stephen Boyd
2022-01-07  7:55     ` qinjian[覃健]
2022-01-07  7:55       ` qinjian[覃健]
     [not found]       ` <20220108004112.2AB34C36AE9@smtp.kernel.org>
2022-01-10  6:37         ` qinjian[覃健]
2022-01-10  6:37           ` qinjian[覃健]
2021-12-22  7:06 ` [PATCH v7 07/10] dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt controller Qin Jian
2021-12-22  7:06   ` Qin Jian
2021-12-22  7:06 ` [PATCH v7 08/10] irqchip: Add Sunplus SP7021 interrupt controller driver Qin Jian
2021-12-22  7:06   ` Qin Jian
2021-12-22  7:06 ` [PATCH v7 09/10] ARM: sunplus: Add initial support for Sunplus SP7021 SoC Qin Jian
2021-12-22  7:06   ` Qin Jian
2021-12-22  7:06 ` [PATCH v7 10/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig Qin Jian
2021-12-22  7:06   ` Qin Jian

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.