linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v15 00/10] Add Sunplus SP7021 SoC Support
@ 2022-05-12  6:30 Qin Jian
  2022-05-12  6:30 ` [PATCH v15 01/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards Qin Jian
                   ` (10 more replies)
  0 siblings, 11 replies; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:30 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, 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 v15:
- Add Sunplus SP7021-demo-v3 board dts
- Refine yaml title
- Rename dt-binding header filename to match compatible string

Changes in v14:
- clock/sp-sp7021.h: Fix the comments from Krzysztof
- sunplus,sp7021-clkc.yaml: Fix the comments from Rob

Changes in v13:
- reset/sp-sp7021.h: Move HW mapping from dt-binding header to driver
- reset-sunplus.c: Move HW mapping from dt-binding header to driver
- clock/sp-sp7021.h: Move HW mapping from dt-binding header to driver
- clk-sp7021.c: Fix the comments from Arnd
- irq-sp7021-intc.c: Remove empty set_affinity callback function
- sp7021_defconfig: Fix the comments from Arnd

Changes in v12:
- sunplus,sp7021-clkc.yaml: Move 'reg' after 'compatible'
- sunplus,sp7021-intc.yaml: Move 'reg' after 'compatible'
- sunplus,reset.yaml: Move 'reg' after 'compatible'
- Remove wrong reviewed-tags

Changes in v11:
- clk-sp7021.c: Remove the dead code

Changes in v10:
- arm/sunplus,sp7021.yaml: Add SoC compatible: "sunplus,sp7021"
- clock/sunplus,sp7021-clkc.yaml: Remove the internal clock parent from DTS
- clk-sp7021.c: Refine the macro DBG_CLK
- clk-sp7021.c: Refine the clock_parent_data

Changes in v9:
- clk/Kconfig: fix the comments form Stephen Boyd
- clk-sp7021.c: fix the comments form Stephen Boyd

Changes in v8:
- clk-sp7021.c: fix the comments form Stephen Boyd

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: 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
  ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree

 .../bindings/arm/sunplus,sp7021.yaml          |  29 +
 .../bindings/clock/sunplus,sp7021-clkc.yaml   |  51 ++
 .../sunplus,sp7021-intc.yaml                  |  62 ++
 .../bindings/reset/sunplus,reset.yaml         |  38 +
 MAINTAINERS                                   |  18 +
 arch/arm/Kconfig                              |   2 +
 arch/arm/Makefile                             |   1 +
 arch/arm/boot/dts/sunplus-sp7021-achip.dtsi   |  85 +++
 arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts  |  27 +
 arch/arm/boot/dts/sunplus-sp7021.dtsi         | 369 +++++++++
 arch/arm/configs/multi_v7_defconfig           |   1 +
 arch/arm/configs/sp7021_defconfig             |  59 ++
 arch/arm/mach-sunplus/Kconfig                 |  27 +
 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                      | 721 ++++++++++++++++++
 drivers/irqchip/Kconfig                       |   9 +
 drivers/irqchip/Makefile                      |   2 +
 drivers/irqchip/irq-sp7021-intc.c             | 278 +++++++
 drivers/reset/Kconfig                         |   9 +
 drivers/reset/Makefile                        |   1 +
 drivers/reset/reset-sunplus.c                 | 212 +++++
 .../dt-bindings/clock/sunplus,sp7021-clkc.h   |  88 +++
 .../dt-bindings/reset/sunplus,sp7021-reset.h  |  87 +++
 26 files changed, 2212 insertions(+)
 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/boot/dts/sunplus-sp7021-achip.dtsi
 create mode 100644 arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
 create mode 100644 arch/arm/boot/dts/sunplus-sp7021.dtsi
 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/sunplus,sp7021-clkc.h
 create mode 100644 include/dt-bindings/reset/sunplus,sp7021-reset.h

-- 
2.33.1


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

* [PATCH v15 01/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
@ 2022-05-12  6:30 ` Qin Jian
  2022-05-16 18:29   ` Rob Herring
  2022-05-12  6:30 ` [PATCH v15 02/10] dt-bindings: reset: Add bindings for SP7021 reset driver Qin Jian
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:30 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Qin Jian

This introduces bindings for boards based Sunplus SP7021 SoC.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Remove "Device Tree Bindings" from title
Add board compatible "sunplus,sp7021-demo-v3"
---
 .../bindings/arm/sunplus,sp7021.yaml          | 29 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++++
 2 files changed, 36 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..def7d0cfe
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
@@ -0,0 +1,29 @@
+# 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
+
+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:
+    items:
+      - enum:
+          - sunplus,sp7021-achip
+          - sunplus,sp7021-demo-v3
+      - const: sunplus,sp7021
+
+additionalProperties: true
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index cd0f68d4a..8b5e2e639 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2738,6 +2738,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 <jszhang@kernel.org>
 M:	Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
-- 
2.33.1


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

* [PATCH v15 02/10] dt-bindings: reset: Add bindings for SP7021 reset driver
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
  2022-05-12  6:30 ` [PATCH v15 01/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards Qin Jian
@ 2022-05-12  6:30 ` Qin Jian
  2022-05-12  6:30 ` [PATCH v15 03/10] reset: Add Sunplus " Qin Jian
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:30 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Qin Jian, Rob Herring

Add documentation to describe Sunplus SP7021 reset driver bindings.

Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Rename sp-sp7021.h to sunplus,sp7021-reset.h
---
 .../bindings/reset/sunplus,reset.yaml         | 38 ++++++++
 MAINTAINERS                                   |  2 +
 .../dt-bindings/reset/sunplus,sp7021-reset.h  | 87 +++++++++++++++++++
 3 files changed, 127 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 create mode 100644 include/dt-bindings/reset/sunplus,sp7021-reset.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..f24646ba9
--- /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
+
+  reg:
+    maxItems: 1
+
+  "#reset-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - "#reset-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    rstc: reset@9c000054 {
+      compatible = "sunplus,sp7021-reset";
+      reg = <0x9c000054 0x28>;
+      #reset-cells = <1>;
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 8b5e2e639..07bacd09f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2744,6 +2744,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/sunplus,sp7021-reset.h
 
 ARM/Synaptics SoC support
 M:	Jisheng Zhang <jszhang@kernel.org>
diff --git a/include/dt-bindings/reset/sunplus,sp7021-reset.h b/include/dt-bindings/reset/sunplus,sp7021-reset.h
new file mode 100644
index 000000000..ab4867073
--- /dev/null
+++ b/include/dt-bindings/reset/sunplus,sp7021-reset.h
@@ -0,0 +1,87 @@
+/* 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
+
+#define RST_SYSTEM              0
+#define RST_RTC                 1
+#define RST_IOCTL               2
+#define RST_IOP                 3
+#define RST_OTPRX               4
+#define RST_NOC                 5
+#define RST_BR                  6
+#define RST_RBUS_L00            7
+#define RST_SPIFL               8
+#define RST_SDCTRL0             9
+#define RST_PERI0               10
+#define RST_A926                11
+#define RST_UMCTL2              12
+#define RST_PERI1               13
+#define RST_DDR_PHY0            14
+#define RST_ACHIP               15
+#define RST_STC0                16
+#define RST_STC_AV0             17
+#define RST_STC_AV1             18
+#define RST_STC_AV2             19
+#define RST_UA0                 20
+#define RST_UA1                 21
+#define RST_UA2                 22
+#define RST_UA3                 23
+#define RST_UA4                 24
+#define RST_HWUA                25
+#define RST_DDC0                26
+#define RST_UADMA               27
+#define RST_CBDMA0              28
+#define RST_CBDMA1              29
+#define RST_SPI_COMBO_0         30
+#define RST_SPI_COMBO_1         31
+#define RST_SPI_COMBO_2         32
+#define RST_SPI_COMBO_3         33
+#define RST_AUD                 34
+#define RST_USBC0               35
+#define RST_USBC1               36
+#define RST_UPHY0               37
+#define RST_UPHY1               38
+#define RST_I2CM0               39
+#define RST_I2CM1               40
+#define RST_I2CM2               41
+#define RST_I2CM3               42
+#define RST_PMC                 43
+#define RST_CARD_CTL0           44
+#define RST_CARD_CTL1           45
+#define RST_CARD_CTL4           46
+#define RST_BCH                 47
+#define RST_DDFCH               48
+#define RST_CSIIW0              49
+#define RST_CSIIW1              50
+#define RST_MIPICSI0            51
+#define RST_MIPICSI1            52
+#define RST_HDMI_TX             53
+#define RST_VPOST               54
+#define RST_TGEN                55
+#define RST_DMIX                56
+#define RST_TCON                57
+#define RST_INTERRUPT           58
+#define RST_RGST                59
+#define RST_GPIO                60
+#define RST_RBUS_TOP            61
+#define RST_MAILBOX             62
+#define RST_SPIND               63
+#define RST_I2C2CBUS            64
+#define RST_SEC                 65
+#define RST_DVE                 66
+#define RST_GPOST0              67
+#define RST_OSD0                68
+#define RST_DISP_PWM            69
+#define RST_UADBG               70
+#define RST_DUMMY_MASTER        71
+#define RST_FIO_CTL             72
+#define RST_FPGA                73
+#define RST_L2SW                74
+#define RST_ICM                 75
+#define RST_AXI_GLOBAL          76
+
+#endif
-- 
2.33.1


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

* [PATCH v15 03/10] reset: Add Sunplus SP7021 reset driver
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
  2022-05-12  6:30 ` [PATCH v15 01/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards Qin Jian
  2022-05-12  6:30 ` [PATCH v15 02/10] dt-bindings: reset: Add bindings for SP7021 reset driver Qin Jian
@ 2022-05-12  6:30 ` Qin Jian
  2022-05-12  6:30 ` [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver Qin Jian
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:30 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, 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 | 212 ++++++++++++++++++++++++++++++++++
 4 files changed, 223 insertions(+)
 create mode 100644 drivers/reset/reset-sunplus.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 07bacd09f..4988db270 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2745,6 +2745,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/sunplus,sp7021-reset.h
 
 ARM/Synaptics SoC support
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 6f8ba0ddc..36825787e 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -231,6 +231,15 @@ config RESET_STARFIVE_JH7100
 	help
 	  This enables the reset controller driver for the StarFive JH7100 SoC.
 
+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 bd0a97be1..cadc46d3e 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_RESET_STARFIVE_JH7100) += reset-starfive-jh7100.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..2f23ecaa7
--- /dev/null
+++ b/drivers/reset/reset-sunplus.c
@@ -0,0 +1,212 @@
+// 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
+
+/* resets HW info: reg_index_shift */
+static const u32 sp_resets[] = {
+/* SP7021: mo_reset0 ~ mo_reset9 */
+	0x00,
+	0x02,
+	0x03,
+	0x04,
+	0x05,
+	0x06,
+	0x07,
+	0x08,
+	0x09,
+	0x0a,
+	0x0b,
+	0x0d,
+	0x0e,
+	0x0f,
+	0x10,
+	0x12,
+	0x14,
+	0x15,
+	0x16,
+	0x17,
+	0x18,
+	0x19,
+	0x1a,
+	0x1b,
+	0x1c,
+	0x1d,
+	0x1e,
+	0x1f,
+	0x20,
+	0x21,
+	0x22,
+	0x23,
+	0x24,
+	0x25,
+	0x26,
+	0x2a,
+	0x2b,
+	0x2d,
+	0x2e,
+	0x30,
+	0x31,
+	0x32,
+	0x33,
+	0x3d,
+	0x3e,
+	0x3f,
+	0x42,
+	0x44,
+	0x4b,
+	0x4c,
+	0x4d,
+	0x4e,
+	0x4f,
+	0x50,
+	0x55,
+	0x60,
+	0x61,
+	0x6a,
+	0x6f,
+	0x70,
+	0x73,
+	0x74,
+	0x86,
+	0x8a,
+	0x8b,
+	0x8d,
+	0x8e,
+	0x8f,
+	0x90,
+	0x92,
+	0x93,
+	0x94,
+	0x95,
+	0x96,
+	0x97,
+	0x98,
+	0x99,
+};
+
+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 = sp_resets[id] / BITS_PER_HWM_REG;
+	int shift = sp_resets[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 = sp_resets[id] / BITS_PER_HWM_REG;
+	int shift = sp_resets[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] 27+ messages in thread

* [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
                   ` (2 preceding siblings ...)
  2022-05-12  6:30 ` [PATCH v15 03/10] reset: Add Sunplus " Qin Jian
@ 2022-05-12  6:30 ` Qin Jian
  2022-05-12 10:24   ` Krzysztof Kozlowski
  2022-05-17  2:19   ` Stephen Boyd
  2022-05-12  6:31 ` [PATCH v15 05/10] clk: Add Sunplus " Qin Jian
                   ` (6 subsequent siblings)
  10 siblings, 2 replies; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:30 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Qin Jian

Add documentation to describe Sunplus SP7021 clock driver bindings.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Remove "Binding" from yaml title
Rename sp-sp7021.h to sunplus,sp7021-clkc.h
---
 .../bindings/clock/sunplus,sp7021-clkc.yaml   | 51 +++++++++++
 MAINTAINERS                                   |  2 +
 .../dt-bindings/clock/sunplus,sp7021-clkc.h   | 88 +++++++++++++++++++
 3 files changed, 141 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 create mode 100644 include/dt-bindings/clock/sunplus,sp7021-clkc.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..119961a17
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
@@ -0,0 +1,51 @@
+# 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
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-clkc
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  "#clock-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - "#clock-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+
+    extclk: osc0 {
+      compatible = "fixed-clock";
+      #clock-cells = <0>;
+      clock-frequency = <27000000>;
+      clock-output-names = "extclk";
+    };
+
+    clkc: clock-controller@9c000000 {
+      compatible = "sunplus,sp7021-clkc";
+      reg = <0x9c000000 0x280>;
+      clocks = <&extclk>;
+      #clock-cells = <1>;
+    };
+
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 4988db270..cd1b2ffc4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2744,8 +2744,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/sunplus,sp7021-clkc.h
 F:	include/dt-bindings/reset/sunplus,sp7021-reset.h
 
 ARM/Synaptics SoC support
diff --git a/include/dt-bindings/clock/sunplus,sp7021-clkc.h b/include/dt-bindings/clock/sunplus,sp7021-clkc.h
new file mode 100644
index 000000000..cd84321eb
--- /dev/null
+++ b/include/dt-bindings/clock/sunplus,sp7021-clkc.h
@@ -0,0 +1,88 @@
+/* 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
+
+/* gates */
+#define CLK_RTC         0
+#define CLK_OTPRX       1
+#define CLK_NOC         2
+#define CLK_BR          3
+#define CLK_SPIFL       4
+#define CLK_PERI0       5
+#define CLK_PERI1       6
+#define CLK_STC0        7
+#define CLK_STC_AV0     8
+#define CLK_STC_AV1     9
+#define CLK_STC_AV2     10
+#define CLK_UA0         11
+#define CLK_UA1         12
+#define CLK_UA2         13
+#define CLK_UA3         14
+#define CLK_UA4         15
+#define CLK_HWUA        16
+#define CLK_DDC0        17
+#define CLK_UADMA       18
+#define CLK_CBDMA0      19
+#define CLK_CBDMA1      20
+#define CLK_SPI_COMBO_0 21
+#define CLK_SPI_COMBO_1 22
+#define CLK_SPI_COMBO_2 23
+#define CLK_SPI_COMBO_3 24
+#define CLK_AUD         25
+#define CLK_USBC0       26
+#define CLK_USBC1       27
+#define CLK_UPHY0       28
+#define CLK_UPHY1       29
+#define CLK_I2CM0       30
+#define CLK_I2CM1       31
+#define CLK_I2CM2       32
+#define CLK_I2CM3       33
+#define CLK_PMC         34
+#define CLK_CARD_CTL0   35
+#define CLK_CARD_CTL1   36
+#define CLK_CARD_CTL4   37
+#define CLK_BCH         38
+#define CLK_DDFCH       39
+#define CLK_CSIIW0      40
+#define CLK_CSIIW1      41
+#define CLK_MIPICSI0    42
+#define CLK_MIPICSI1    43
+#define CLK_HDMI_TX     44
+#define CLK_VPOST       45
+#define CLK_TGEN        46
+#define CLK_DMIX        47
+#define CLK_TCON        48
+#define CLK_GPIO        49
+#define CLK_MAILBOX     50
+#define CLK_SPIND       51
+#define CLK_I2C2CBUS    52
+#define CLK_SEC         53
+#define CLK_DVE         54
+#define CLK_GPOST0      55
+#define CLK_OSD0        56
+#define CLK_DISP_PWM    57
+#define CLK_UADBG       58
+#define CLK_FIO_CTL     59
+#define CLK_FPGA        60
+#define CLK_L2SW        61
+#define CLK_ICM         62
+#define CLK_AXI_GLOBAL  63
+
+/* plls */
+#define PLL_A           64
+#define PLL_E           65
+#define PLL_E_2P5       66
+#define PLL_E_25        67
+#define PLL_E_112P5     68
+#define PLL_F           69
+#define PLL_TV          70
+#define PLL_TV_A        71
+#define PLL_SYS         72
+
+#define CLK_MAX         73
+
+#endif
-- 
2.33.1


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

* [PATCH v15 05/10] clk: Add Sunplus SP7021 clock driver
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
                   ` (3 preceding siblings ...)
  2022-05-12  6:30 ` [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver Qin Jian
@ 2022-05-12  6:31 ` Qin Jian
  2022-05-17  2:17   ` Stephen Boyd
  2022-05-12  6:31 ` [PATCH v15 06/10] dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt controller Qin Jian
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:31 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Qin Jian

Add clock driver for Sunplus SP7021 SoC.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
Rename sp-sp7021.h to sunplus,sp7021-clkc.h
---
 MAINTAINERS              |   1 +
 drivers/clk/Kconfig      |  10 +
 drivers/clk/Makefile     |   1 +
 drivers/clk/clk-sp7021.c | 721 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 733 insertions(+)
 create mode 100644 drivers/clk/clk-sp7021.c

diff --git a/MAINTAINERS b/MAINTAINERS
index cd1b2ffc4..26b77b68b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2746,6 +2746,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/sunplus,sp7021-clkc.h
 F:	include/dt-bindings/reset/sunplus,sp7021-reset.h
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index d4d67fbae..9eedeea78 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -351,6 +351,16 @@ 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"
+	depends on SOC_SP7021 || COMPILE_TEST
+	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
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 16e588630..377ea7f7b 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -61,6 +61,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..7d71bc276
--- /dev/null
+++ b/drivers/clk/clk-sp7021.c
@@ -0,0 +1,721 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+#include <linux/module.h>
+#include <linux/clk-provider.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 <linux/platform_device.h>
+#include <dt-bindings/clock/sunplus,sp7021-clkc.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)
+
+/* 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 F_EXTCLK	BIT(16)	/* parent clock is EXTCLK */
+
+/* gates HW info: reg_index_shift | parent */
+static const u32 sp_clk_gates[] = {
+	0x12,
+	0x15,
+	0x16,
+	0x17,
+	0x19,
+	0x1b | F_EXTCLK,
+	0x1f | F_EXTCLK,
+	0x24,
+	0x25,
+	0x26,
+	0x27,
+	0x28 | F_EXTCLK,
+	0x29 | F_EXTCLK,
+	0x2a | F_EXTCLK,
+	0x2b | F_EXTCLK,
+	0x2c | F_EXTCLK,
+	0x2d | F_EXTCLK,
+	0x2e,
+	0x2f | F_EXTCLK,
+	0x30,
+	0x31,
+	0x32,
+	0x33,
+	0x34,
+	0x35,
+	0x36,
+	0x3a,
+	0x3b,
+	0x3d,
+	0x3e,
+	0x40,
+	0x41,
+	0x42,
+	0x43,
+	0x4d,
+	0x4e,
+	0x4f,
+	0x52,
+	0x54,
+	0x5b,
+	0x5c,
+	0x5d,
+	0x5e,
+	0x5f,
+	0x60,
+	0x65,
+	0x70,
+	0x71,
+	0x7a,
+	0x83,
+	0x96,
+	0x9a,
+	0x9b,
+	0x9d,
+	0x9e,
+	0x9f,
+	0xa0,
+	0xa2,
+	0xa3,
+	0xa5,
+	0xa6,
+	0xa7,
+	0xa8,
+	0xa9,
+};
+
+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;
+
+	freq = clamp(freq, F_MIN, 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;
+
+	freq = clamp(freq, F_MIN, 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, df_remainder;
+
+				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);
+
+	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);
+
+	writel(BIT(clk->pd_bit + 16) | BIT(clk->pd_bit), clk->reg); /* power up */
+
+	return 0;
+}
+
+static void sp_pll_disable(struct clk_hw *hw)
+{
+	struct sp_pll *clk = to_sp_pll(hw);
+
+	writel(BIT(clk->pd_bit + 16), clk->reg); /* power down */
+}
+
+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,
+};
+
+static void dbg_clk(struct clk_hw *hw)
+{
+	const char *name = clk_hw_get_name(hw);
+	unsigned long rate = clk_hw_get_rate(hw);
+
+	pr_debug("%-20s%lu\n", name, rate);
+}
+
+static struct clk_hw *sp_pll_register(struct device *dev, const char *name,
+				      const struct clk_parent_data *parent_data,
+				      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_data = parent_data,
+		.ops = (bp_bit >= 0) ? &sp_pll_ops : &sp_pll_sub_ops,
+		.num_parents = 1,
+		/* system clock, should not be disabled */
+		.flags = (reg == PLLSYS_CTL) ? CLK_IS_CRITICAL : 0,
+	};
+	int ret;
+
+	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	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 = devm_clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(pll);
+		return ERR_PTR(ret);
+	}
+	dbg_clk(hw);
+
+	return hw;
+}
+
+static int sp7021_clk_probe(struct platform_device *pdev)
+{
+	static const u32 sp_clken[] = {
+		0x67ef, 0x03ff, 0xff03, 0xfff0, 0x0004, /* G0.1~5  */
+		0x0000, 0x8000, 0xffff, 0x0040, 0x0000, /* G0.6~10 */
+	};
+	static struct clk_parent_data pd_ext, pd_sys, pd_e;
+	struct device *dev = &pdev->dev;
+	struct clk_hw **hws;
+	struct resource *res;
+	int i;
+
+	/* This memory region include multi HW regs in discontinuous order.
+	 * clk driver used some discontinuous areas in the memory region.
+	 * Using devm_platform_ioremap_resource() would conflicted with other drivers.
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sp_clk_base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!sp_clk_base)
+		return -ENXIO;
+
+	/* enable default clks */
+	for (i = 0; i < ARRAY_SIZE(sp_clken); i++)
+		writel((sp_clken[i] << 16) | sp_clken[i], sp_clk_base + 4 * (1 + i));
+
+	sp_clk_data = devm_kzalloc(dev, struct_size(sp_clk_data, hws, CLK_MAX),
+				   GFP_KERNEL);
+	if (!sp_clk_data)
+		return -ENOMEM;
+
+	hws = sp_clk_data->hws;
+	pd_ext.index = 0; /* clocks = <&extclk>; */
+
+	/* PLL_A */
+	hws[PLL_A] = sp_pll_register(dev, "plla", &pd_ext, PLLA_CTL,
+				     11, 12, 27000000, 0, DIV_A, &plla_lock);
+	if (IS_ERR(hws[PLL_A]))
+		return PTR_ERR(hws[PLL_A]);
+
+	/* PLL_E */
+	hws[PLL_E] = sp_pll_register(dev, "plle", &pd_ext, PLLE_CTL,
+				     6, 2, 50000000, 0, 0, &plle_lock);
+	if (IS_ERR(hws[PLL_E]))
+		return PTR_ERR(hws[PLL_E]);
+	pd_e.hw = hws[PLL_E];
+	hws[PLL_E_2P5] = sp_pll_register(dev, "plle_2p5", &pd_e, PLLE_CTL,
+					 13, -1, 2500000, 0, 0, &plle_lock);
+	if (IS_ERR(hws[PLL_E_2P5]))
+		return PTR_ERR(hws[PLL_E_2P5]);
+	hws[PLL_E_25] = sp_pll_register(dev, "plle_25", &pd_e, PLLE_CTL,
+					12, -1, 25000000, 0, 0, &plle_lock);
+	if (IS_ERR(hws[PLL_E_25]))
+		return PTR_ERR(hws[PLL_E_25]);
+	hws[PLL_E_112P5] = sp_pll_register(dev, "plle_112p5", &pd_e, PLLE_CTL,
+					   11, -1, 112500000, 0, 0, &plle_lock);
+	if (IS_ERR(hws[PLL_E_112P5]))
+		return PTR_ERR(hws[PLL_E_112P5]);
+
+	/* PLL_F */
+	hws[PLL_F] = sp_pll_register(dev, "pllf", &pd_ext, PLLF_CTL,
+				     0, 10, 13500000, 1, 4, &pllf_lock);
+	if (IS_ERR(hws[PLL_F]))
+		return PTR_ERR(hws[PLL_F]);
+
+	/* PLL_TV */
+	hws[PLL_TV] = sp_pll_register(dev, "plltv", &pd_ext, PLLTV_CTL,
+				      0, 15, 27000000, 0, DIV_TV, &plltv_lock);
+	if (IS_ERR(hws[PLL_TV]))
+		return PTR_ERR(hws[PLL_TV]);
+	hws[PLL_TV_A] = devm_clk_hw_register_divider(dev, "plltv_a", "plltv", 0,
+						     PLLTV_CTL + 4, 5, 1,
+						     CLK_DIVIDER_POWER_OF_TWO,
+						     &plltv_lock);
+	if (IS_ERR(hws[PLL_TV_A]))
+		return PTR_ERR(hws[PLL_TV_A]);
+	dbg_clk(hws[PLL_TV_A]);
+
+	/* PLL_SYS */
+	hws[PLL_SYS] = sp_pll_register(dev, "pllsys", &pd_ext, PLLSYS_CTL,
+				       10, 9, 13500000, 0, 4, &pllsys_lock);
+	if (IS_ERR(hws[PLL_SYS]))
+		return PTR_ERR(hws[PLL_SYS]);
+	pd_sys.hw = hws[PLL_SYS];
+
+	/* gates */
+	for (i = 0; i < ARRAY_SIZE(sp_clk_gates); i++) {
+		char name[10];
+		u32 f = sp_clk_gates[i];
+		int j = f & 0xffff;
+		struct clk_parent_data *pd = (f & F_EXTCLK) ? &pd_ext : &pd_sys;
+
+		sprintf(name, "%02d_0x%02x", i, j);
+		hws[i] = clk_hw_register_gate_parent_data(dev, name, pd, 0,
+							  clk_regs + (j >> 4) * 4,
+							  j & 0x0f,
+							  CLK_GATE_HIWORD_MASK,
+							  NULL);
+		if (IS_ERR(hws[i]))
+			return PTR_ERR(hws[i]);
+		dbg_clk(hws[i]);
+	}
+
+	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", },
+	{ }
+};
+
+static struct platform_driver sp7021_clk_driver = {
+	.probe  = sp7021_clk_probe,
+	.driver = {
+		.name = "sp7021-clk",
+		.of_match_table = sp7021_clk_dt_ids,
+	},
+};
+module_platform_driver(sp7021_clk_driver);
+
+MODULE_AUTHOR("Sunplus Technology");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Clock driver for Sunplus SP7021 SoC");
-- 
2.33.1


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

* [PATCH v15 06/10] dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt controller
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
                   ` (4 preceding siblings ...)
  2022-05-12  6:31 ` [PATCH v15 05/10] clk: Add Sunplus " Qin Jian
@ 2022-05-12  6:31 ` Qin Jian
  2022-05-12  6:31 ` [PATCH v15 07/10] irqchip: Add Sunplus SP7021 interrupt controller driver Qin Jian
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:31 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, 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>
---
Remove "Device Tree Bindings" from title
---
 .../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..bd0021dba
--- /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
+
+maintainers:
+  - Qin Jian <qinjian@cqplus1.com>
+
+properties:
+  compatible:
+    items:
+      - const: sunplus,sp7021-intc
+
+  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.
+
+  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.
+
+  interrupts:
+    maxItems: 2
+    description:
+      EXT_INT0 & EXT_INT1, 2 interrupts references to primary interrupt
+      controller.
+
+required:
+  - compatible
+  - reg
+  - interrupt-controller
+  - "#interrupt-cells"
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    intc: interrupt-controller@9c000780 {
+        compatible = "sunplus,sp7021-intc";
+        reg = <0x9c000780 0x80>, <0x9c000a80 0x80>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        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 26b77b68b..8dfab70f0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2745,6 +2745,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] 27+ messages in thread

* [PATCH v15 07/10] irqchip: Add Sunplus SP7021 interrupt controller driver
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
                   ` (5 preceding siblings ...)
  2022-05-12  6:31 ` [PATCH v15 06/10] dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt controller Qin Jian
@ 2022-05-12  6:31 ` Qin Jian
  2022-05-12  6:31 ` [PATCH v15 08/10] ARM: sunplus: Add initial support for Sunplus SP7021 SoC Qin Jian
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:31 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, 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.

Acked-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 MAINTAINERS                       |   1 +
 drivers/irqchip/Kconfig           |   9 +
 drivers/irqchip/Makefile          |   2 +
 drivers/irqchip/irq-sp7021-intc.c | 278 ++++++++++++++++++++++++++++++
 4 files changed, 290 insertions(+)
 create mode 100644 drivers/irqchip/irq-sp7021-intc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 8dfab70f0..762beec05 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2748,6 +2748,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/sunplus,sp7021-clkc.h
 F:	include/dt-bindings/reset/sunplus,sp7021-reset.h
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 7038957f4..f5c2596bc 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -617,4 +617,13 @@ config MCHP_EIC
 	help
 	  Support for Microchip External Interrupt Controller.
 
+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 c1f611cbf..eb0ac83ff 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -117,3 +117,5 @@ 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_MCHP_EIC)			+= irq-mchp-eic.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..b45c1a601
--- /dev/null
+++ b/drivers/irqchip/irq-sp7021-intc.c
@@ -0,0 +1,278 @@
+// 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);
+}
+
+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,
+};
+
+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] 27+ messages in thread

* [PATCH v15 08/10] ARM: sunplus: Add initial support for Sunplus SP7021 SoC
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
                   ` (6 preceding siblings ...)
  2022-05-12  6:31 ` [PATCH v15 07/10] irqchip: Add Sunplus SP7021 interrupt controller driver Qin Jian
@ 2022-05-12  6:31 ` Qin Jian
  2022-05-12  6:31 ` [PATCH v15 09/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig Qin Jian
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:31 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, 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  | 27 +++++++++++++++++++++++++++
 arch/arm/mach-sunplus/Makefile |  9 +++++++++
 arch/arm/mach-sunplus/sp7021.c | 16 ++++++++++++++++
 6 files changed, 56 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 762beec05..ad52b0a2d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2747,6 +2747,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 4c97cb40e..1ee9a27a3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -693,6 +693,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 77172d555..1e19d2f4b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -216,6 +216,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..be20425c2
--- /dev/null
+++ b/arch/arm/mach-sunplus/Kconfig
@@ -0,0 +1,27 @@
+# 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 HAVE_ARM_ARCH_TIMER
+	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] 27+ messages in thread

* [PATCH v15 09/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
                   ` (7 preceding siblings ...)
  2022-05-12  6:31 ` [PATCH v15 08/10] ARM: sunplus: Add initial support for Sunplus SP7021 SoC Qin Jian
@ 2022-05-12  6:31 ` Qin Jian
  2022-05-13 11:27   ` Arnd Bergmann
  2022-05-12  6:31 ` [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree Qin Jian
  2022-05-13 11:29 ` [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Arnd Bergmann
  10 siblings, 1 reply; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:31 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Qin Jian

Add generic Sunplus SP7021 based board defconfig

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

diff --git a/MAINTAINERS b/MAINTAINERS
index ad52b0a2d..9cf30e776 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2747,6 +2747,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 8863fa969..a3bd9dbd8 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -86,6 +86,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..703b9aaa4
--- /dev/null
+++ b/arch/arm/configs/sp7021_defconfig
@@ -0,0 +1,59 @@
+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_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_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] 27+ messages in thread

* [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
                   ` (8 preceding siblings ...)
  2022-05-12  6:31 ` [PATCH v15 09/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig Qin Jian
@ 2022-05-12  6:31 ` Qin Jian
  2022-05-12 10:28   ` Krzysztof Kozlowski
  2022-05-13 11:29 ` [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Arnd Bergmann
  10 siblings, 1 reply; 27+ messages in thread
From: Qin Jian @ 2022-05-12  6:31 UTC (permalink / raw)
  To: sboyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Qin Jian

Add the basic support for Sunplus SP7021-Demo-V3 board.

Signed-off-by: Qin Jian <qinjian@cqplus1.com>
---
 MAINTAINERS                                  |   1 +
 arch/arm/boot/dts/sunplus-sp7021-achip.dtsi  |  85 +++++
 arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts |  27 ++
 arch/arm/boot/dts/sunplus-sp7021.dtsi        | 369 +++++++++++++++++++
 4 files changed, 482 insertions(+)
 create mode 100644 arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
 create mode 100644 arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
 create mode 100644 arch/arm/boot/dts/sunplus-sp7021.dtsi

diff --git a/MAINTAINERS b/MAINTAINERS
index 9cf30e776..b55ec0768 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2747,6 +2747,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/boot/dts/sunplus-sp7021*.dts*
 F:	arch/arm/configs/sp7021_*defconfig
 F:	arch/arm/mach-sunplus/
 F:	drivers/clk/clk-sp7021.c
diff --git a/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
new file mode 100644
index 000000000..1560c95d9
--- /dev/null
+++ b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for Sunplus SP7021
+ *
+ * Copyright (C) 2021 Sunplus Technology Co.
+ */
+
+#include "sunplus-sp7021.dtsi"
+
+/ {
+	compatible = "sunplus,sp7021-achip";
+	model = "Sunplus SP7021 (CA7)";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	interrupt-parent = <&gic>;
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		extclk: clk@osc0 {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <27000000>;
+			clock-output-names = "extclk";
+		};
+
+		divextclk: clk@0 {
+			compatible = "fixed-factor-clock";
+			#clock-cells = <0>;
+			clocks  = <&extclk>;
+			clock-mult = <1>;
+			clock-div = <2>;
+			clock-output-names = "extdivclk";
+		};
+
+		A_pll0: clk@A_pll0 {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <2000000000>;
+			clock-output-names = "A_pll0";
+		};
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <0>;
+			clock-frequency = <931000000>;
+		};
+		cpu1: cpu@1 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <1>;
+			clock-frequency = <931000000>;
+		};
+		cpu2: cpu@2 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <2>;
+			clock-frequency = <931000000>;
+		};
+		cpu3: cpu@3 {
+			compatible = "arm,cortex-a7";
+			device_type = "cpu";
+			reg = <3>;
+			clock-frequency = <931000000>;
+		};
+	};
+
+	arm-pmu {
+		compatible = "arm,cortex-a7-pmu";
+		interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+	};
+
+};
diff --git a/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts b/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
new file mode 100644
index 000000000..05e164115
--- /dev/null
+++ b/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for Sunplus SP7021 Demo V3 SBC board
+ *
+ * Copyright (C) Sunplus Technology Co.
+ */
+
+/dts-v1/;
+
+#include "sunplus-sp7021-achip.dtsi"
+
+/ {
+	compatible = "sunplus,sp7021-demo-v3";
+	model = "SP7021/CA7/Demo_V3";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	chosen {
+		bootargs = "console=ttyS0,115200 loglevel=8 earlycon";
+		stdout-path = "serial0:115200n8";
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x20000000>;
+	};
+};
diff --git a/arch/arm/boot/dts/sunplus-sp7021.dtsi b/arch/arm/boot/dts/sunplus-sp7021.dtsi
new file mode 100644
index 000000000..4777abdce
--- /dev/null
+++ b/arch/arm/boot/dts/sunplus-sp7021.dtsi
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for Sunplus SP7021
+ *
+ * Copyright (C) 2021 Sunplus Technology Co.
+ */
+
+#include <dt-bindings/clock/sunplus,sp7021-clkc.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/reset/sunplus,sp7021-reset.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sppctl-sp7021.h>
+
+/ {
+	compatible = "sunplus,sp7021";
+	model = "Sunplus SP7021";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+	};
+
+	soc@A {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		interrupt-parent = <&gic>;
+
+		gic: interrupt-controller@CPU {
+			compatible = "arm,cortex-a7-gic";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0x9f101000 0x1000>,
+			      <0x9f102000 0x2000>,
+			      <0x9f104000 0x2000>,
+			      <0x9f106000 0x2000>;
+		};
+
+		timer: timer@CPU {
+			compatible = "arm,armv7-timer";
+			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+				     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+			clock-frequency = <27000000>;
+			arm,cpu-registers-not-fw-configured;
+		};
+	};
+
+	soc@B {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		interrupt-parent = <&intc>;
+
+		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 */
+		};
+
+		clkc: clock-controller@9c000000 {
+			compatible = "sunplus,sp7021-clkc";
+			reg = <0x9c000000 0x280>;
+			#clock-cells = <1>;
+			clocks = <&extclk>;
+		};
+
+		rstc: reset@9c000054 {
+			compatible = "sunplus,sp7021-reset";
+			reg = <0x9c000054 0x28>;
+			#reset-cells = <1>;
+		};
+
+		rtc: serial@9c003a00 {
+			compatible = "sunplus,sp7021-rtc";
+			reg = <0x9c003a00 0x80>;
+			reg-names = "rtc";
+			clocks = <&clkc CLK_RTC>;
+			resets = <&rstc RST_RTC>;
+			interrupt-parent = <&intc>;
+			interrupts = <163 IRQ_TYPE_EDGE_RISING>;
+		};
+
+		otp: otp@9c00af00 {
+			compatible = "sunplus,sp7021-ocotp";
+			reg = <0x9c00af00 0x34>, <0x9c00af80 0x58>;
+			reg-names = "hb_gpio", "otprx";
+			clocks = <&clkc CLK_OTPRX>;
+			resets = <&rstc RST_OTPRX>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			therm_calib: thermal-calibration@14 {
+				reg = <0x14 0x3>;
+			};
+			disc_vol: disconnect-voltage@18 {
+				reg = <0x18 0x2>;
+			};
+			mac_addr0: mac-address0@34 {
+				reg = <0x34 0x6>;
+			};
+			mac_addr1: mac-address1@3a {
+				reg = <0x3a 0x6>;
+			};
+		};
+
+		led {
+			compatible = "gpio-leds";
+			pinctrl-names = "default";
+			pinctrl-0 = <&leds_pins>;
+			system-led {
+				label = "system-led";
+				gpios = <&pctl 0 GPIO_ACTIVE_HIGH>;
+				default-state = "off";
+				linux,default-trigger = "heartbeat";
+			};
+		};
+
+		uart0: serial@9c000900 {
+			compatible = "sunplus,sp7021-uart";
+			reg = <0x9c000900 0x80>;
+			interrupt-parent = <&intc>;
+			interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_UA0>;
+			resets = <&rstc RST_UA0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart0_pins>;
+		};
+
+		uart1: serial@9c000980 {
+			compatible = "sunplus,sp7021-uart";
+			reg = <0x9c000980 0x80>;
+			interrupt-parent = <&intc>;
+			interrupts = <54 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_UA1>;
+			resets = <&rstc RST_UA1>;
+			status = "disabled";
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart1_pins>;
+		};
+
+		uart2: serial@9c000800 {
+			compatible = "sunplus,sp7021-uart";
+			reg = <0x9c000800 0x80>;
+			interrupt-parent = <&intc>;
+			interrupts = <55 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_UA2>;
+			resets = <&rstc RST_UA2>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart2_pins>;
+			status = "disabled";
+		};
+
+		uart3: serial@9c000880 {
+			compatible = "sunplus,sp7021-uart";
+			reg = <0x9c000880 0x80>;
+			interrupt-parent = <&intc>;
+			interrupts = <56 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_UA3>;
+			resets = <&rstc RST_UA3>;
+			status = "disabled";
+		};
+
+		uart4: serial@9c008780 {
+			compatible = "sunplus,sp7021-uart";
+			reg = <0x9c008780 0x80>;
+			interrupt-parent = <&intc>;
+			interrupts = <134 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_UA4>;
+			resets = <&rstc RST_UA4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart4_pins>;
+			status = "disabled";
+		};
+
+		spi_controller0: spi@9c002d80 {
+			compatible = "sunplus,sp7021-spi";
+			reg = <0x9c002d80 0x80>, <0x9c002e00 0x80>;
+			reg-names = "master", "slave";
+			interrupt-parent = <&intc>;
+			interrupt-names = "dma_w",
+					  "master_risc",
+					  "slave_risc";
+			interrupts = <144 IRQ_TYPE_LEVEL_HIGH>,
+				     <146 IRQ_TYPE_LEVEL_HIGH>,
+				     <145 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_SPI_COMBO_0>;
+			resets = <&rstc RST_SPI_COMBO_0>;
+
+			pinctrl-names = "default";
+			pinctrl-0 = <&spi0_pins>;
+			cs-gpios = <&pctl 26 GPIO_ACTIVE_LOW>, <&pctl 28 GPIO_ACTIVE_LOW>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			spi@0 {
+				compatible = "rohm,dh2228fv";
+				spi-max-frequency = <5000000>;
+				reg = <0x0>;
+				status = "okay";
+			};
+			spi@1 {
+				compatible = "rohm,dh2228fv";
+				spi-max-frequency = <5000000>;
+				reg = <0x1>;
+				status = "okay";
+			};
+		};
+
+		spi_controller1: spi@9c00f480 {
+			compatible = "sunplus,sp7021-spi";
+			reg = <0x9c00f480 0x80>, <0x9c00f500 0x80>;
+			reg-names = "master", "slave";
+			interrupt-parent = <&intc>;
+			interrupt-names = "dma_w",
+					  "master_risc",
+					  "slave_risc";
+			interrupts = <67 IRQ_TYPE_LEVEL_HIGH>,
+				     <69 IRQ_TYPE_LEVEL_HIGH>,
+				     <68 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_SPI_COMBO_1>;
+			resets = <&rstc RST_SPI_COMBO_1>;
+			spi-max-frequency = <25000000>;
+			status = "disabled";
+		};
+
+		spi_controller2: spi@9c00f600 {
+			compatible = "sunplus,sp7021-spi";
+			reg = <0x9c00f600 0x80>, <0x9c00f680 0x80>;
+			reg-names = "master", "slave";
+			interrupt-parent = <&intc>;
+			interrupt-names = "dma_w",
+					  "master_risc",
+					  "slave_risc";
+			interrupts = <70 IRQ_TYPE_LEVEL_HIGH>,
+				     <72 IRQ_TYPE_LEVEL_HIGH>,
+				     <71 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_SPI_COMBO_2>;
+			resets = <&rstc RST_SPI_COMBO_2>;
+			spi-max-frequency = <25000000>;
+			status = "disabled";
+		};
+
+		spi_controller3: spi@9c00f780 {
+			compatible = "sunplus,sp7021-spi";
+			reg = <0x9c00f780 0x80>, <0x9c00f800 0x80>;
+			reg-names = "master", "slave";
+			interrupt-parent = <&intc>;
+			interrupt-names = "dma_w",
+					  "master_risc",
+					  "slave_risc";
+			interrupts = <73 IRQ_TYPE_LEVEL_HIGH>,
+				     <75 IRQ_TYPE_LEVEL_HIGH>,
+				     <74 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clkc CLK_SPI_COMBO_3>;
+			resets = <&rstc RST_SPI_COMBO_3>;
+			spi-max-frequency = <25000000>;
+			status = "disabled";
+		};
+
+		pctl: pinctl@9c000100 {
+			compatible = "sunplus,sp7021-pctl";
+			reg = <0x9C000100 0x100>,
+			      <0x9C000300 0x100>,
+			      <0x9C0032e4 0x1C>,
+			      <0x9C000080 0x20>;
+			reg-names = "moon2", "gpioxt", "first", "moon1";
+			gpio-controller;
+			#gpio-cells = <2>;
+			clocks = <&clkc CLK_GPIO>;
+			resets = <&rstc RST_GPIO>;
+			pinctrl-names = "default";
+
+			leds_pins: pinmux_gpio_leds-pins {
+				sunplus,pins = < SPPCTL_IOPAD(0,SPPCTL_PCTL_G_GPIO,0,SPPCTL_PCTL_L_OUT) >;
+			};
+
+			emmc_pins: emmc-pins {
+				function = "CARD0_EMMC";
+				groups = "CARD0_EMMC";
+			};
+
+			sdcard-pins {
+				function = "SD_CARD";
+				groups = "SD_CARD";
+				sunplus,pins = < SPPCTL_IOPAD(91, SPPCTL_PCTL_G_GPIO, 0, 0) >;
+			};
+
+			emac_pins: pinmux_emac_demo_board_v3-pins {
+				sunplus,pins = <
+					SPPCTL_IOPAD(49,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_CLK_OUT,0)
+					SPPCTL_IOPAD(44,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_MAC_SMI_MDC,0)
+					SPPCTL_IOPAD(43,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_MAC_SMI_MDIO,0)
+					SPPCTL_IOPAD(52,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_TXEN,0)
+					SPPCTL_IOPAD(50,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_TXD0,0)
+					SPPCTL_IOPAD(51,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_TXD1,0)
+					SPPCTL_IOPAD(46,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_CRSDV,0)
+					SPPCTL_IOPAD(47,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_RXD0,0)
+					SPPCTL_IOPAD(48,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_RXD1,0)
+					SPPCTL_IOPAD(45,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P0_MAC_RMII_RXER,0)
+					SPPCTL_IOPAD(59,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_TXEN,0)
+					SPPCTL_IOPAD(57,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_TXD0,0)
+					SPPCTL_IOPAD(58,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_TXD1,0)
+					SPPCTL_IOPAD(54,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_CRSDV,0)
+					SPPCTL_IOPAD(55,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_RXD0,0)
+					SPPCTL_IOPAD(56,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_RXD1,0)
+					SPPCTL_IOPAD(53,SPPCTL_PCTL_G_PMUX,MUXF_L2SW_P1_MAC_RMII_RXER,0)
+				>;
+				sunplus,zerofunc = <
+					MUXF_L2SW_LED_FLASH0
+					MUXF_L2SW_LED_FLASH1
+					MUXF_L2SW_LED_ON0
+					MUXF_L2SW_LED_ON1
+					MUXF_DAISY_MODE
+				>;
+			};
+
+			uart0_pins: pinmux_uart0-pins {
+				function = "UA0";
+				groups = "UA0";
+			};
+
+			uart1_pins: pinmux_uart1-pins {
+				sunplus,pins = <
+					SPPCTL_IOPAD(14,SPPCTL_PCTL_G_PMUX,MUXF_UA4_TX,0)
+					SPPCTL_IOPAD(16,SPPCTL_PCTL_G_PMUX,MUXF_UA4_RX,0)
+				>;
+			};
+
+			uart2_pins: pinmux_uart2-pins {
+				sunplus,pins = <
+					SPPCTL_IOPAD(16,SPPCTL_PCTL_G_PMUX,MUXF_UA2_TX,0)
+					SPPCTL_IOPAD(17,SPPCTL_PCTL_G_PMUX,MUXF_UA2_RX,0)
+					SPPCTL_IOPAD(18,SPPCTL_PCTL_G_PMUX,MUXF_UA2_RTS,0)
+					SPPCTL_IOPAD(19,SPPCTL_PCTL_G_PMUX,MUXF_UA2_CTS,0)
+				>;
+			};
+
+			uart4_pins: pinmux_uart4-pins {
+				sunplus,pins = <
+					SPPCTL_IOPAD(22,SPPCTL_PCTL_G_PMUX,MUXF_UA4_TX,0)
+					SPPCTL_IOPAD(20,SPPCTL_PCTL_G_PMUX,MUXF_UA4_RX,0)
+					SPPCTL_IOPAD(23,SPPCTL_PCTL_G_PMUX,MUXF_UA4_RTS,0)
+					SPPCTL_IOPAD(21,SPPCTL_PCTL_G_PMUX,MUXF_UA4_CTS,0)
+				>;
+			};
+
+			spi0_pins: pinmux_spi0-pins {
+				sunplus,pins = <
+					SPPCTL_IOPAD(26,SPPCTL_PCTL_G_GPIO,0,0)
+					SPPCTL_IOPAD(28,SPPCTL_PCTL_G_GPIO,0,0)
+					SPPCTL_IOPAD(23,SPPCTL_PCTL_G_PMUX,MUXF_SPI0S_DO,0)
+					SPPCTL_IOPAD(25,SPPCTL_PCTL_G_PMUX,MUXF_SPI0S_DI,0)
+					SPPCTL_IOPAD(27,SPPCTL_PCTL_G_PMUX,MUXF_SPI0S_CLK,0)
+				>;
+			};
+		};
+	};
+};
-- 
2.33.1


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

* Re: [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2022-05-12  6:30 ` [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver Qin Jian
@ 2022-05-12 10:24   ` Krzysztof Kozlowski
  2022-05-12 10:45     ` qinjian[覃健]
  2022-05-17  2:19   ` Stephen Boyd
  1 sibling, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-12 10:24 UTC (permalink / raw)
  To: Qin Jian, sboyd
  Cc: robh+dt, mturquette, tglx, maz, p.zabel, linux, arnd,
	linux-arm-kernel, devicetree, linux-kernel, linux-clk

On 12/05/2022 08:30, Qin Jian wrote:
> Add documentation to describe Sunplus SP7021 clock driver bindings.
> 
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---
> Remove "Binding" from yaml title
> Rename sp-sp7021.h to sunplus,sp7021-clkc.h

Thanks.

> ---
>  .../bindings/clock/sunplus,sp7021-clkc.yaml   | 51 +++++++++++
>  MAINTAINERS                                   |  2 +
>  .../dt-bindings/clock/sunplus,sp7021-clkc.h   | 88 +++++++++++++++++++
>  3 files changed, 141 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
>  create mode 100644 include/dt-bindings/clock/sunplus,sp7021-clkc.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..119961a17
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
> @@ -0,0 +1,51 @@
> +# 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
> +
> +maintainers:
> +  - Qin Jian <qinjian@cqplus1.com>
> +
> +properties:
> +  compatible:
> +    const: sunplus,sp7021-clkc
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  "#clock-cells":
> +    const: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - "#clock-cells"
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +

Same as in v14. Please go through the comments thoroughly so reviewers
will not waste time repeating the same twice.

Best regards,
Krzysztof

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

* Re: [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree
  2022-05-12  6:31 ` [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree Qin Jian
@ 2022-05-12 10:28   ` Krzysztof Kozlowski
  2022-05-13  7:44     ` qinjian[覃健]
  0 siblings, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-12 10:28 UTC (permalink / raw)
  To: Qin Jian, sboyd
  Cc: robh+dt, mturquette, tglx, maz, p.zabel, linux, arnd,
	linux-arm-kernel, devicetree, linux-kernel, linux-clk

On 12/05/2022 08:31, Qin Jian wrote:
> Add the basic support for Sunplus SP7021-Demo-V3 board.
> 
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---
>  MAINTAINERS                                  |   1 +
>  arch/arm/boot/dts/sunplus-sp7021-achip.dtsi  |  85 +++++
>  arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts |  27 ++
>  arch/arm/boot/dts/sunplus-sp7021.dtsi        | 369 +++++++++++++++++++
>  4 files changed, 482 insertions(+)
>  create mode 100644 arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
>  create mode 100644 arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
>  create mode 100644 arch/arm/boot/dts/sunplus-sp7021.dtsi
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9cf30e776..b55ec0768 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2747,6 +2747,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/boot/dts/sunplus-sp7021*.dts*
>  F:	arch/arm/configs/sp7021_*defconfig
>  F:	arch/arm/mach-sunplus/
>  F:	drivers/clk/clk-sp7021.c
> diff --git a/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
> new file mode 100644
> index 000000000..1560c95d9
> --- /dev/null
> +++ b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
> @@ -0,0 +1,85 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Device Tree Source for Sunplus SP7021
> + *
> + * Copyright (C) 2021 Sunplus Technology Co.
> + */
> +
> +#include "sunplus-sp7021.dtsi"
> +
> +/ {
> +	compatible = "sunplus,sp7021-achip";

This does not match your bindings.

> +	model = "Sunplus SP7021 (CA7)";
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	interrupt-parent = <&gic>;
> +
> +	clocks {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		extclk: clk@osc0 {

This is not a valid device tree. Please run make dtbs_check and compile
dtbs with W=1.

> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <27000000>;
> +			clock-output-names = "extclk";
> +		};
> +
> +		divextclk: clk@0 {

How is it suppose to pass any automated checks if there is no unit address?

> +			compatible = "fixed-factor-clock";
> +			#clock-cells = <0>;
> +			clocks  = <&extclk>;
> +			clock-mult = <1>;
> +			clock-div = <2>;
> +			clock-output-names = "extdivclk";
> +		};
> +
> +		A_pll0: clk@A_pll0 {

This is not a valid device tree.

> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <2000000000>;
> +			clock-output-names = "A_pll0";
> +		};
> +	};
> +
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		cpu0: cpu@0 {
> +			compatible = "arm,cortex-a7";
> +			device_type = "cpu";
> +			reg = <0>;
> +			clock-frequency = <931000000>;
> +		};
> +		cpu1: cpu@1 {
> +			compatible = "arm,cortex-a7";
> +			device_type = "cpu";
> +			reg = <1>;
> +			clock-frequency = <931000000>;
> +		};
> +		cpu2: cpu@2 {
> +			compatible = "arm,cortex-a7";
> +			device_type = "cpu";
> +			reg = <2>;
> +			clock-frequency = <931000000>;
> +		};
> +		cpu3: cpu@3 {
> +			compatible = "arm,cortex-a7";
> +			device_type = "cpu";
> +			reg = <3>;
> +			clock-frequency = <931000000>;
> +		};
> +	};
> +
> +	arm-pmu {
> +		compatible = "arm,cortex-a7-pmu";
> +		interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>,
> +			     <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
> +	};
> +
> +};
> diff --git a/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts b/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
> new file mode 100644
> index 000000000..05e164115
> --- /dev/null
> +++ b/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
> @@ -0,0 +1,27 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Device Tree Source for Sunplus SP7021 Demo V3 SBC board
> + *
> + * Copyright (C) Sunplus Technology Co.
> + */
> +
> +/dts-v1/;
> +
> +#include "sunplus-sp7021-achip.dtsi"
> +
> +/ {
> +	compatible = "sunplus,sp7021-demo-v3";

This does not match your bindings.

Please run make dtbs_check.

> +	model = "SP7021/CA7/Demo_V3";
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +
> +	chosen {
> +		bootargs = "console=ttyS0,115200 loglevel=8 earlycon";

No bootargs.

I'll stop reviewing. This either does not compile, does not work or does
not pass automated checks. There is no point to use reviewers time if
the tools are doing the same job, so use the tools and then submit DTS.

Best regards,
Krzysztof

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

* RE: [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2022-05-12 10:24   ` Krzysztof Kozlowski
@ 2022-05-12 10:45     ` qinjian[覃健]
  2022-05-12 10:54       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 27+ messages in thread
From: qinjian[覃健] @ 2022-05-12 10:45 UTC (permalink / raw)
  To: Krzysztof Kozlowski, sboyd
  Cc: robh+dt, mturquette, tglx, maz, p.zabel, linux, arnd,
	linux-arm-kernel, devicetree, linux-kernel, linux-clk

> On 12/05/2022 08:30, Qin Jian wrote:
> > Add documentation to describe Sunplus SP7021 clock driver bindings.
> >
> > Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> > ---
> > Remove "Binding" from yaml title
> > Rename sp-sp7021.h to sunplus,sp7021-clkc.h
> 
> Thanks.
> 
> > ---
> >  .../bindings/clock/sunplus,sp7021-clkc.yaml   | 51 +++++++++++
> >  MAINTAINERS                                   |  2 +
> >  .../dt-bindings/clock/sunplus,sp7021-clkc.h   | 88 +++++++++++++++++++
> >  3 files changed, 141 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
> >  create mode 100644 include/dt-bindings/clock/sunplus,sp7021-clkc.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..119961a17
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
> > @@ -0,0 +1,51 @@
> > +# 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
> > +
> > +maintainers:
> > +  - Qin Jian <qinjian@cqplus1.com>
> > +
> > +properties:
> > +  compatible:
> > +    const: sunplus,sp7021-clkc
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    maxItems: 1
> > +
> > +  "#clock-cells":
> > +    const: 1
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - clocks
> > +  - "#clock-cells"
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +
> 
> Same as in v14. Please go through the comments thoroughly so reviewers
> will not waste time repeating the same twice.
> 

Sorry, I don’t understand your meaning.
Could you explain more, thanks.



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

* Re: [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2022-05-12 10:45     ` qinjian[覃健]
@ 2022-05-12 10:54       ` Krzysztof Kozlowski
  2022-05-13  3:22         ` qinjian[覃健]
  0 siblings, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-12 10:54 UTC (permalink / raw)
  To: qinjian[覃健], sboyd
  Cc: robh+dt, mturquette, tglx, maz, p.zabel, linux, arnd,
	linux-arm-kernel, devicetree, linux-kernel, linux-clk

On 12/05/2022 12:45, qinjian[覃健] wrote:
>>> +
>>> +examples:
>>> +  - |
>>> +
>>
>> Same as in v14. Please go through the comments thoroughly so reviewers
>> will not waste time repeating the same twice.
>>
> 
> Sorry, I don’t understand your meaning.
> Could you explain more, thanks.

I commented in your v14. Please apply the comment or keep discussion
running. Don't ignore my comment.

Best regards,
Krzysztof

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

* RE: [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2022-05-12 10:54       ` Krzysztof Kozlowski
@ 2022-05-13  3:22         ` qinjian[覃健]
  0 siblings, 0 replies; 27+ messages in thread
From: qinjian[覃健] @ 2022-05-13  3:22 UTC (permalink / raw)
  To: Krzysztof Kozlowski, sboyd
  Cc: robh+dt, mturquette, tglx, maz, p.zabel, linux, arnd,
	linux-arm-kernel, devicetree, linux-kernel, linux-clk

> On 12/05/2022 12:45, qinjian[覃健] wrote:
> >>> +
> >>> +examples:
> >>> +  - |
> >>> +
> >>
> >> Same as in v14. Please go through the comments thoroughly so reviewers
> >> will not waste time repeating the same twice.
> >>
> >
> > Sorry, I don’t understand your meaning.
> > Could you explain more, thanks.
> 
> I commented in your v14. Please apply the comment or keep discussion
> running. Don't ignore my comment.
> 

Sorry, I missed your comment: "No need for blank line".
I'll fix it later.

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

* RE: [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree
  2022-05-12 10:28   ` Krzysztof Kozlowski
@ 2022-05-13  7:44     ` qinjian[覃健]
  2022-05-13  8:10       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 27+ messages in thread
From: qinjian[覃健] @ 2022-05-13  7:44 UTC (permalink / raw)
  To: Krzysztof Kozlowski, sboyd
  Cc: robh+dt, mturquette, tglx, maz, p.zabel, linux, arnd,
	linux-arm-kernel, devicetree, linux-kernel, linux-clk

> > diff --git a/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
> > new file mode 100644
> > index 000000000..1560c95d9
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
> > @@ -0,0 +1,85 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Device Tree Source for Sunplus SP7021
> > + *
> > + * Copyright (C) 2021 Sunplus Technology Co.
> > + */
> > +
> > +#include "sunplus-sp7021.dtsi"
> > +
> > +/ {
> > +	compatible = "sunplus,sp7021-achip";
> 
> This does not match your bindings.
> 

> > +++ b/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
> > @@ -0,0 +1,27 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Device Tree Source for Sunplus SP7021 Demo V3 SBC board
> > + *
> > + * Copyright (C) Sunplus Technology Co.
> > + */
> > +
> > +/dts-v1/;
> > +
> > +#include "sunplus-sp7021-achip.dtsi"
> > +
> > +/ {
> > +	compatible = "sunplus,sp7021-demo-v3";
> 
> This does not match your bindings.
> 
> Please run make dtbs_check.

I did passed the make dtbs_check.
compatible string: "sunplus,sp7021", "sunplus,sp7021-achip", "sunplus,sp7021-demo-v3"
all defined @ Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml [1]

[1] https://lore.kernel.org/lkml/6107a68008f2d71d2c7868d4d94cb66c5b5fc134.1652329411.git.qinjian@cqplus1.com/
 


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

* Re: [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree
  2022-05-13  7:44     ` qinjian[覃健]
@ 2022-05-13  8:10       ` Krzysztof Kozlowski
  2022-05-13  9:47         ` qinjian[覃健]
  0 siblings, 1 reply; 27+ messages in thread
From: Krzysztof Kozlowski @ 2022-05-13  8:10 UTC (permalink / raw)
  To: qinjian[覃健], sboyd
  Cc: robh+dt, mturquette, tglx, maz, p.zabel, linux, arnd,
	linux-arm-kernel, devicetree, linux-kernel, linux-clk

On 13/05/2022 09:44, qinjian[覃健] wrote:
>>> diff --git a/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
>>> new file mode 100644
>>> index 000000000..1560c95d9
>>> --- /dev/null
>>> +++ b/arch/arm/boot/dts/sunplus-sp7021-achip.dtsi
>>> @@ -0,0 +1,85 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Device Tree Source for Sunplus SP7021
>>> + *
>>> + * Copyright (C) 2021 Sunplus Technology Co.
>>> + */
>>> +
>>> +#include "sunplus-sp7021.dtsi"
>>> +
>>> +/ {
>>> +	compatible = "sunplus,sp7021-achip";
>>
>> This does not match your bindings.
>>
> 
>>> +++ b/arch/arm/boot/dts/sunplus-sp7021-demo-v3.dts
>>> @@ -0,0 +1,27 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Device Tree Source for Sunplus SP7021 Demo V3 SBC board
>>> + *
>>> + * Copyright (C) Sunplus Technology Co.
>>> + */
>>> +
>>> +/dts-v1/;
>>> +
>>> +#include "sunplus-sp7021-achip.dtsi"
>>> +
>>> +/ {
>>> +	compatible = "sunplus,sp7021-demo-v3";
>>
>> This does not match your bindings.
>>
>> Please run make dtbs_check.
> 
> I did passed the make dtbs_check.
> compatible string: "sunplus,sp7021", "sunplus,sp7021-achip", "sunplus,sp7021-demo-v3"
> all defined @ Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml [1]

How this can pass the check if it is entirely different compatible and
does not match schema? The code is not correct. If you test your DTS
with dtbs_check you will see:

	sunplus-sp7021-demo-v3.dtb: /: compatible: ['sunplus,sp7021-demo-v3']
is too short


Additionally:
1. Your DTBs do not compile, missing Makefile entry.

2. You have to fix whitespace issues in your patches:

.git/rebase-apply/patch:48: new blank line at EOF.

+

warning: 1 line adds whitespace errors.

.git/rebase-apply/patch:97: new blank line at EOF.

+

warning: 1

Best regards,
Krzysztof

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

* RE: [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree
  2022-05-13  8:10       ` Krzysztof Kozlowski
@ 2022-05-13  9:47         ` qinjian[覃健]
  0 siblings, 0 replies; 27+ messages in thread
From: qinjian[覃健] @ 2022-05-13  9:47 UTC (permalink / raw)
  To: Krzysztof Kozlowski, sboyd
  Cc: robh+dt, mturquette, tglx, maz, p.zabel, linux, arnd,
	linux-arm-kernel, devicetree, linux-kernel, linux-clk

> >
> > I did passed the make dtbs_check.
> > compatible string: "sunplus,sp7021", "sunplus,sp7021-achip", "sunplus,sp7021-demo-v3"
> > all defined @ Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml [1]
> 
> How this can pass the check if it is entirely different compatible and
> does not match schema? The code is not correct. If you test your DTS
> with dtbs_check you will see:
> 
> 	sunplus-sp7021-demo-v3.dtb: /: compatible: ['sunplus,sp7021-demo-v3']
> is too short
> 
> 
> Additionally:
> 1. Your DTBs do not compile, missing Makefile entry.
> 

Got it, I compiled the dtb with command: make sunplus-sp7021-demo-v3.dtb
After I add it to arch/arm/boot/dts/Makefile,
make dtbs_check got the error.
Thanks for your patient guidance.


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

* Re: [PATCH v15 09/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig
  2022-05-12  6:31 ` [PATCH v15 09/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig Qin Jian
@ 2022-05-13 11:27   ` Arnd Bergmann
  0 siblings, 0 replies; 27+ messages in thread
From: Arnd Bergmann @ 2022-05-13 11:27 UTC (permalink / raw)
  To: Qin Jian
  Cc: Stephen Boyd, Krzysztof Kozlowski, Rob Herring,
	Michael Turquette, Thomas Gleixner, Marc Zyngier, Philipp Zabel,
	Russell King - ARM Linux, Arnd Bergmann, Linux ARM, DTML,
	Linux Kernel Mailing List, linux-clk

On Thu, May 12, 2022 at 8:31 AM Qin Jian <qinjian@cqplus1.com> wrote:
>
> Add generic Sunplus SP7021 based board defconfig
>
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>

Reviewed-by: Arnd Bergmann <arnd@arndb.de>

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

* Re: [PATCH v15 00/10] Add Sunplus SP7021 SoC Support
  2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
                   ` (9 preceding siblings ...)
  2022-05-12  6:31 ` [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree Qin Jian
@ 2022-05-13 11:29 ` Arnd Bergmann
  10 siblings, 0 replies; 27+ messages in thread
From: Arnd Bergmann @ 2022-05-13 11:29 UTC (permalink / raw)
  To: Qin Jian
  Cc: Stephen Boyd, Krzysztof Kozlowski, Rob Herring,
	Michael Turquette, Thomas Gleixner, Marc Zyngier, Philipp Zabel,
	Russell King - ARM Linux, Arnd Bergmann, Linux ARM, DTML,
	Linux Kernel Mailing List, linux-clk

On Thu, May 12, 2022 at 8:30 AM Qin Jian <qinjian@cqplus1.com> wrote:
>
> 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.

It looks like there are still some remaining review comments, and the clk
driver is missing a review. Since we are close to 5.18-rc7, I think it's
too late for the coming merge window, and you should target 5.20,
with a rebase on top of v5.19-rc1 once that is out.

If you get no replies on the clk driver, maybe try splitting that out and
post it separately to the clk maintainers. I know they are rather
backlogged on review time.

       Arnd

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

* Re: [PATCH v15 01/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards
  2022-05-12  6:30 ` [PATCH v15 01/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards Qin Jian
@ 2022-05-16 18:29   ` Rob Herring
  0 siblings, 0 replies; 27+ messages in thread
From: Rob Herring @ 2022-05-16 18:29 UTC (permalink / raw)
  To: Qin Jian
  Cc: p.zabel, sboyd, arnd, devicetree, krzysztof.kozlowski, linux-clk,
	tglx, mturquette, robh+dt, linux-kernel, linux-arm-kernel, maz,
	linux

On Thu, 12 May 2022 14:30:56 +0800, Qin Jian wrote:
> This introduces bindings for boards based Sunplus SP7021 SoC.
> 
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> Signed-off-by: Qin Jian <qinjian@cqplus1.com>
> ---
> Remove "Device Tree Bindings" from title
> Add board compatible "sunplus,sp7021-demo-v3"
> ---
>  .../bindings/arm/sunplus,sp7021.yaml          | 29 +++++++++++++++++++
>  MAINTAINERS                                   |  7 +++++
>  2 files changed, 36 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
> 

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

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

* Re: [PATCH v15 05/10] clk: Add Sunplus SP7021 clock driver
  2022-05-12  6:31 ` [PATCH v15 05/10] clk: Add Sunplus " Qin Jian
@ 2022-05-17  2:17   ` Stephen Boyd
  2022-05-17  9:30     ` qinjian[覃健]
  0 siblings, 1 reply; 27+ messages in thread
From: Stephen Boyd @ 2022-05-17  2:17 UTC (permalink / raw)
  To: Qin Jian
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Qin Jian

Quoting Qin Jian (2022-05-11 23:31:00)
> diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c
> new file mode 100644
> index 000000000..7d71bc276
> --- /dev/null
> +++ b/drivers/clk/clk-sp7021.c
> @@ -0,0 +1,721 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +/*
> + * Copyright (C) Sunplus Technology Co., Ltd.
> + *       All rights reserved.
> + */
> +#include <linux/module.h>
> +#include <linux/clk-provider.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 <linux/platform_device.h>
> +#include <dt-bindings/clock/sunplus,sp7021-clkc.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)
> +
> +/* 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;

Why are these globals? Please allocate them locally in driver probe and
reference them without using a global.

> +
> +#define F_EXTCLK       BIT(16) /* parent clock is EXTCLK */
> +
> +/* gates HW info: reg_index_shift | parent */
> +static const u32 sp_clk_gates[] = {

Please make a struct sp_clk_gate_info

	struct sp_clk_gate_info {
		u16	reg;
		bool	ext_parent;
	};

Or 'ext_parent' can be u16 if struct packing with a bool on the end
fails due to alignment issues.

> +       0x12,
> +       0x15,
> +       0x16,
> +       0x17,
> +       0x19,
> +       0x1b | F_EXTCLK,
> +       0x1f | F_EXTCLK,
> +       0x24,
> +       0x25,
> +       0x26,
> +       0x27,
> +       0x28 | F_EXTCLK,
> +       0x29 | F_EXTCLK,
> +       0x2a | F_EXTCLK,
> +       0x2b | F_EXTCLK,
> +       0x2c | F_EXTCLK,
> +       0x2d | F_EXTCLK,
> +       0x2e,
> +       0x2f | F_EXTCLK,
> +       0x30,
> +       0x31,
> +       0x32,
> +       0x33,
> +       0x34,
> +       0x35,
> +       0x36,
> +       0x3a,
> +       0x3b,
> +       0x3d,
> +       0x3e,
> +       0x40,
> +       0x41,
> +       0x42,
> +       0x43,
> +       0x4d,
> +       0x4e,
> +       0x4f,
> +       0x52,
> +       0x54,
> +       0x5b,
> +       0x5c,
> +       0x5d,
> +       0x5e,
> +       0x5f,
> +       0x60,
> +       0x65,
> +       0x70,
> +       0x71,
> +       0x7a,
> +       0x83,
> +       0x96,
> +       0x9a,
> +       0x9b,
> +       0x9d,
> +       0x9e,
> +       0x9f,
> +       0xa0,
> +       0xa2,
> +       0xa3,
> +       0xa5,
> +       0xa6,
> +       0xa7,
> +       0xa8,
> +       0xa9,
> +};
> +
> +static DEFINE_SPINLOCK(plla_lock);

The name of the spinlock will be inserted directly into any lockdep
report. Can these locks be part of some allocated structure instead of
being static globals? Then the struct name will be encoded during
spin_lock_init() which will be more helpful assuming the struct name is
driver specific.

> +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;
> +
> +       freq = clamp(freq, F_MIN, 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++) {

Use ARRAY_SIZE and remove the comment about and value of 0 from the end?

> +               nf = fvco * m_table[m];
> +               n = nf / F_27M;
> +               if ((n * F_27M) == nf)
> +                       break;
> +       }
> +       m = m_table[m];
> +
> +       if (!m) {

This can be resolved with a 'return' from a subfunction or a goto.

> +               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

Don't use // for comments.

> +               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 */

Maybe call it sdm_mod_vals[] and drop the comment?

> +
> +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;
> +
> +       freq = clamp(freq, F_MIN, 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;

this is 1

> +
> +               /* SDM_MOD 0/1 */
> +               for (sdm = 0; sdm <= 1; sdm++) {
> +                       u32 mod = mods[sdm];
> +
> +                       /* DIVM 1~32 */
> +                       for (m = ms; m <= 32; m++) {

and still 1? Just use 1 instead of another local variable?

> +                               u32 df; /* diff freq */
> +                               u32 df_quotient, df_remainder;
> +
> +                               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]);

This is quite long and I am concerned about overflow. Can we have more
local variables to help break up the statement?

> +                               else
> +                                       df = (f * (nint) / pp[0]);

Drop useless parenthesis please.

> +
> +                               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;

Where does 1000 come from?

> +                               } 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);
> +
> +       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 */

Make a define for BIT(1) please. 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);

Please push the lock down. Maybe that means having two conditionals?
Either way, it is too large because it calls into plla_set_rate() and
plltv_set_rate() with the lock held.

> +
> +       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);

This is a really long line.

> +       }
> +
> +       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);
> +
> +       writel(BIT(clk->pd_bit + 16) | BIT(clk->pd_bit), clk->reg); /* power up */

The comment is pretty useless, this is what pll enable would do.
> +
> +       return 0;
> +}
> +
> +static void sp_pll_disable(struct clk_hw *hw)
> +{
> +       struct sp_pll *clk = to_sp_pll(hw);
> +
> +       writel(BIT(clk->pd_bit + 16), clk->reg); /* power down */

Same.

> +}
> +
> +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,
> +};
> +
> +static void dbg_clk(struct clk_hw *hw)
> +{
> +       const char *name = clk_hw_get_name(hw);
> +       unsigned long rate = clk_hw_get_rate(hw);
> +
> +       pr_debug("%-20s%lu\n", name, rate);

This doesn't provide anything more than normal clk debugfs so just
remove?

> +}
> +
> +static struct clk_hw *sp_pll_register(struct device *dev, const char *name,
> +                                     const struct clk_parent_data *parent_data,
> +                                     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_data = parent_data,
> +               .ops = (bp_bit >= 0) ? &sp_pll_ops : &sp_pll_sub_ops,
> +               .num_parents = 1,
> +               /* system clock, should not be disabled */
> +               .flags = (reg == PLLSYS_CTL) ? CLK_IS_CRITICAL : 0,
> +       };
> +       int ret;
> +
> +       pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
> +       if (!pll)
> +               return ERR_PTR(-ENOMEM);
> +
> +       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 = devm_clk_hw_register(dev, hw);
> +       if (ret) {
> +               kfree(pll);
> +               return ERR_PTR(ret);
> +       }
> +       dbg_clk(hw);
> +
> +       return hw;
> +}
> +
> +static int sp7021_clk_probe(struct platform_device *pdev)
> +{
> +       static const u32 sp_clken[] = {
> +               0x67ef, 0x03ff, 0xff03, 0xfff0, 0x0004, /* G0.1~5  */
> +               0x0000, 0x8000, 0xffff, 0x0040, 0x0000, /* G0.6~10 */
> +       };
> +       static struct clk_parent_data pd_ext, pd_sys, pd_e;
> +       struct device *dev = &pdev->dev;
> +       struct clk_hw **hws;
> +       struct resource *res;
> +       int i;
> +
> +       /* This memory region include multi HW regs in discontinuous order.

The /* should be on a line by itself.

> +        * clk driver used some discontinuous areas in the memory region.
> +        * Using devm_platform_ioremap_resource() would conflicted with other drivers.

What other drivers?

> +        */
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       sp_clk_base = devm_ioremap(dev, res->start, resource_size(res));
> +       if (!sp_clk_base)
> +               return -ENXIO;
> +
> +       /* enable default clks */
> +       for (i = 0; i < ARRAY_SIZE(sp_clken); i++)
> +               writel((sp_clken[i] << 16) | sp_clken[i], sp_clk_base + 4 * (1 + i));
> +
> +       sp_clk_data = devm_kzalloc(dev, struct_size(sp_clk_data, hws, CLK_MAX),
> +                                  GFP_KERNEL);
> +       if (!sp_clk_data)
> +               return -ENOMEM;
> +
> +       hws = sp_clk_data->hws;
> +       pd_ext.index = 0; /* clocks = <&extclk>; */

Remove comment please.

> +
> +       /* PLL_A */
> +       hws[PLL_A] = sp_pll_register(dev, "plla", &pd_ext, PLLA_CTL,
> +                                    11, 12, 27000000, 0, DIV_A, &plla_lock);
> +       if (IS_ERR(hws[PLL_A]))
> +               return PTR_ERR(hws[PLL_A]);
> +
> +       /* PLL_E */
> +       hws[PLL_E] = sp_pll_register(dev, "plle", &pd_ext, PLLE_CTL,
> +                                    6, 2, 50000000, 0, 0, &plle_lock);
> +       if (IS_ERR(hws[PLL_E]))
> +               return PTR_ERR(hws[PLL_E]);
> +       pd_e.hw = hws[PLL_E];
> +       hws[PLL_E_2P5] = sp_pll_register(dev, "plle_2p5", &pd_e, PLLE_CTL,
> +                                        13, -1, 2500000, 0, 0, &plle_lock);
> +       if (IS_ERR(hws[PLL_E_2P5]))
> +               return PTR_ERR(hws[PLL_E_2P5]);
> +       hws[PLL_E_25] = sp_pll_register(dev, "plle_25", &pd_e, PLLE_CTL,
> +                                       12, -1, 25000000, 0, 0, &plle_lock);
> +       if (IS_ERR(hws[PLL_E_25]))
> +               return PTR_ERR(hws[PLL_E_25]);
> +       hws[PLL_E_112P5] = sp_pll_register(dev, "plle_112p5", &pd_e, PLLE_CTL,
> +                                          11, -1, 112500000, 0, 0, &plle_lock);
> +       if (IS_ERR(hws[PLL_E_112P5]))
> +               return PTR_ERR(hws[PLL_E_112P5]);
> +
> +       /* PLL_F */
> +       hws[PLL_F] = sp_pll_register(dev, "pllf", &pd_ext, PLLF_CTL,
> +                                    0, 10, 13500000, 1, 4, &pllf_lock);
> +       if (IS_ERR(hws[PLL_F]))
> +               return PTR_ERR(hws[PLL_F]);
> +
> +       /* PLL_TV */
> +       hws[PLL_TV] = sp_pll_register(dev, "plltv", &pd_ext, PLLTV_CTL,
> +                                     0, 15, 27000000, 0, DIV_TV, &plltv_lock);
> +       if (IS_ERR(hws[PLL_TV]))
> +               return PTR_ERR(hws[PLL_TV]);
> +       hws[PLL_TV_A] = devm_clk_hw_register_divider(dev, "plltv_a", "plltv", 0,
> +                                                    PLLTV_CTL + 4, 5, 1,
> +                                                    CLK_DIVIDER_POWER_OF_TWO,
> +                                                    &plltv_lock);
> +       if (IS_ERR(hws[PLL_TV_A]))
> +               return PTR_ERR(hws[PLL_TV_A]);
> +       dbg_clk(hws[PLL_TV_A]);
> +
> +       /* PLL_SYS */
> +       hws[PLL_SYS] = sp_pll_register(dev, "pllsys", &pd_ext, PLLSYS_CTL,
> +                                      10, 9, 13500000, 0, 4, &pllsys_lock);
> +       if (IS_ERR(hws[PLL_SYS]))
> +               return PTR_ERR(hws[PLL_SYS]);
> +       pd_sys.hw = hws[PLL_SYS];
> +
> +       /* gates */
> +       for (i = 0; i < ARRAY_SIZE(sp_clk_gates); i++) {
> +               char name[10];
> +               u32 f = sp_clk_gates[i];
> +               int j = f & 0xffff;
> +               struct clk_parent_data *pd = (f & F_EXTCLK) ? &pd_ext : &pd_sys;
> +
> +               sprintf(name, "%02d_0x%02x", i, j);
> +               hws[i] = clk_hw_register_gate_parent_data(dev, name, pd, 0,
> +                                                         clk_regs + (j >> 4) * 4,
> +                                                         j & 0x0f,
> +                                                         CLK_GATE_HIWORD_MASK,
> +                                                         NULL);
> +               if (IS_ERR(hws[i]))
> +                       return PTR_ERR(hws[i]);
> +               dbg_clk(hws[i]);
> +       }
> +
> +       sp_clk_data->num = CLK_MAX;
> +       return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, sp_clk_data);

We leaked a bunch of clk_hw_register_gate_parent_data() calls here if
this failed.

> +}
> +
> +static const struct of_device_id sp7021_clk_dt_ids[] = {
> +       { .compatible = "sunplus,sp7021-clkc", },
> +       { }
> +};

Missing MODULE_DEVICE_TABLE, but see below.

> +
> +static struct platform_driver sp7021_clk_driver = {
> +       .probe  = sp7021_clk_probe,
> +       .driver = {
> +               .name = "sp7021-clk",
> +               .of_match_table = sp7021_clk_dt_ids,
> +       },
> +};
> +module_platform_driver(sp7021_clk_driver);
> +
> +MODULE_AUTHOR("Sunplus Technology");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Clock driver for Sunplus SP7021 SoC");

Is it a module? The Kconfig is bool, so either make that tristate or
remove modular support from this driver. Preferably make it tristate.

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

* Re: [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2022-05-12  6:30 ` [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver Qin Jian
  2022-05-12 10:24   ` Krzysztof Kozlowski
@ 2022-05-17  2:19   ` Stephen Boyd
  2022-05-17  9:37     ` qinjian[覃健]
  1 sibling, 1 reply; 27+ messages in thread
From: Stephen Boyd @ 2022-05-17  2:19 UTC (permalink / raw)
  To: Qin Jian
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk, Qin Jian

Quoting Qin Jian (2022-05-11 23:30:59)
> +
> +    extclk: osc0 {
> +      compatible = "fixed-clock";
> +      #clock-cells = <0>;
> +      clock-frequency = <27000000>;
> +      clock-output-names = "extclk";
> +    };
> +
> +    clkc: clock-controller@9c000000 {
> +      compatible = "sunplus,sp7021-clkc";
> +      reg = <0x9c000000 0x280>;

The question is what other device compatible is in here? The reset
controller?

> +      clocks = <&extclk>;
> +      #clock-cells = <1>;
> +    };
> +

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

* RE: [PATCH v15 05/10] clk: Add Sunplus SP7021 clock driver
  2022-05-17  2:17   ` Stephen Boyd
@ 2022-05-17  9:30     ` qinjian[覃健]
       [not found]       ` <20220518202049.6055BC385A9@smtp.kernel.org>
  0 siblings, 1 reply; 27+ messages in thread
From: qinjian[覃健] @ 2022-05-17  9:30 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk

> > +               nf = fvco * m_table[m];
> > +               n = nf / F_27M;
> > +               if ((n * F_27M) == nf)
> > +                       break;
> > +       }
> > +       m = m_table[m];
> > +
> > +       if (!m) {
> 
> This can be resolved with a 'return' from a subfunction or a goto.

Sorry, Could you explain more clear?
Did you means like:
	If (!m) {
		ret = -EINVAL;
		goto err_not_found;
	}
	...
	return freq;

err_not_found:
	...
	return ret;
}

> 
> > +               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;
> > +}




> > +
> > +                               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;
> 
> Where does 1000 come from?

1000 is come from "borrow 1" in last operation.

> 
> > +                               } else {
> > +                                       df_quotient = df_quotient - freq;
> > +                               }
> > +




> > +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);
> 
> Please push the lock down. Maybe that means having two conditionals?
> Either way, it is too large because it calls into plla_set_rate() and
> plltv_set_rate() with the lock held.

Sorry, I don't understand "push the lock down. Maybe that means having two conditionals?" what means.
The plla_set_rate() & plltv_set_rate() is only include simple operations & HW reg writes.
I think it should be called with lock held.

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 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);
}




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

* RE: [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver
  2022-05-17  2:19   ` Stephen Boyd
@ 2022-05-17  9:37     ` qinjian[覃健]
  0 siblings, 0 replies; 27+ messages in thread
From: qinjian[覃健] @ 2022-05-17  9:37 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk

> > +    clkc: clock-controller@9c000000 {
> > +      compatible = "sunplus,sp7021-clkc";
> > +      reg = <0x9c000000 0x280>;
> 
> The question is what other device compatible is in here? The reset
> controller?
> 

This reg region conflict with reset/pinmux/usbc/uphy drivers.
To use devm_platform_ioremap_resource,
I must split up the origin 1 region into 4 small pieces,
and call devm_platform_ioremap_resource() 4 times.
Did I should follow this way?


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

* RE: [PATCH v15 05/10] clk: Add Sunplus SP7021 clock driver
       [not found]       ` <20220518202049.6055BC385A9@smtp.kernel.org>
@ 2022-05-19  2:16         ` qinjian[覃健]
  0 siblings, 0 replies; 27+ messages in thread
From: qinjian[覃健] @ 2022-05-19  2:16 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: krzysztof.kozlowski, robh+dt, mturquette, tglx, maz, p.zabel,
	linux, arnd, linux-arm-kernel, devicetree, linux-kernel,
	linux-clk

> > > > +
> > > > +                               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;
> > >
> > > Where does 1000 come from?
> >
> > 1000 is come from "borrow 1" in last operation.
> 
> It's scaling the value right? What is being scaled? Are we converting
> units to Hz from kHz?

Here just using integer replacement floating point operation, for example:
df = 13, m = 3
13 / 3 = 4.33333333
df_quotient = 4
df_remainder = 0.3333333 * 1000 (accurate to 3 decimal places) = 333


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

end of thread, other threads:[~2022-05-19  2:29 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-12  6:30 [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Qin Jian
2022-05-12  6:30 ` [PATCH v15 01/10] dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards Qin Jian
2022-05-16 18:29   ` Rob Herring
2022-05-12  6:30 ` [PATCH v15 02/10] dt-bindings: reset: Add bindings for SP7021 reset driver Qin Jian
2022-05-12  6:30 ` [PATCH v15 03/10] reset: Add Sunplus " Qin Jian
2022-05-12  6:30 ` [PATCH v15 04/10] dt-bindings: clock: Add bindings for SP7021 clock driver Qin Jian
2022-05-12 10:24   ` Krzysztof Kozlowski
2022-05-12 10:45     ` qinjian[覃健]
2022-05-12 10:54       ` Krzysztof Kozlowski
2022-05-13  3:22         ` qinjian[覃健]
2022-05-17  2:19   ` Stephen Boyd
2022-05-17  9:37     ` qinjian[覃健]
2022-05-12  6:31 ` [PATCH v15 05/10] clk: Add Sunplus " Qin Jian
2022-05-17  2:17   ` Stephen Boyd
2022-05-17  9:30     ` qinjian[覃健]
     [not found]       ` <20220518202049.6055BC385A9@smtp.kernel.org>
2022-05-19  2:16         ` qinjian[覃健]
2022-05-12  6:31 ` [PATCH v15 06/10] dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt controller Qin Jian
2022-05-12  6:31 ` [PATCH v15 07/10] irqchip: Add Sunplus SP7021 interrupt controller driver Qin Jian
2022-05-12  6:31 ` [PATCH v15 08/10] ARM: sunplus: Add initial support for Sunplus SP7021 SoC Qin Jian
2022-05-12  6:31 ` [PATCH v15 09/10] ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig Qin Jian
2022-05-13 11:27   ` Arnd Bergmann
2022-05-12  6:31 ` [PATCH v15 10/10] ARM: dts: Add Sunplus SP7021-Demo-V3 board device tree Qin Jian
2022-05-12 10:28   ` Krzysztof Kozlowski
2022-05-13  7:44     ` qinjian[覃健]
2022-05-13  8:10       ` Krzysztof Kozlowski
2022-05-13  9:47         ` qinjian[覃健]
2022-05-13 11:29 ` [PATCH v15 00/10] Add Sunplus SP7021 SoC Support Arnd Bergmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).