Skip to contentSkip to conversation

Add Sunplus SP7021 SoC Support

PATCH Superseded Qin Jian 2 participants 13 messages Jan 21, 2022 – Jan 25, 2022

Subsystems (7)

v8 of 20 Superseded Latest is v20 →

lore
Share & tools
lore

Qin Jian

author maintainer
#0 lore raw

v8 cover Add Sunplus SP7021 SoC Support

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 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: vendor-prefixes: Add Sunplus
dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards
dt-bindings: reset: Add bindings for SP7021 reset driver
reset: Add Sunplus SP7021 reset driver
dt-bindings: clock: Add bindings for SP7021 clock driver
clk: Add Sunplus SP7021 clock driver
dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt
controller
irqchip: Add Sunplus SP7021 interrupt controller driver
ARM: sunplus: Add initial support for Sunplus SP7021 SoC
ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig

 .../bindings/arm/sunplus,sp7021.yaml          |  27 +
 .../bindings/clock/sunplus,sp7021-clkc.yaml   |  52 ++
 .../sunplus,sp7021-intc.yaml                  |  62 ++
 .../bindings/reset/sunplus,reset.yaml         |  38 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |  17 +
 arch/arm/Kconfig                              |   2 +
 arch/arm/Makefile                             |   1 +
 arch/arm/configs/multi_v7_defconfig           |   1 +
 arch/arm/configs/sp7021_defconfig             |  61 ++
 arch/arm/mach-sunplus/Kconfig                 |  26 +
 arch/arm/mach-sunplus/Makefile                |   9 +
 arch/arm/mach-sunplus/sp7021.c                |  16 +
 drivers/clk/Kconfig                           |   9 +
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-sp7021.c                      | 753 ++++++++++++++++++
 drivers/irqchip/Kconfig                       |   9 +
 drivers/irqchip/Makefile                      |   1 +
 drivers/irqchip/irq-sp7021-intc.c             | 288 +++++++
 drivers/reset/Kconfig                         |   9 +
 drivers/reset/Makefile                        |   1 +
 drivers/reset/reset-sunplus.c                 | 130 +++
 include/dt-bindings/clock/sp-sp7021.h         | 112 +++
 include/dt-bindings/reset/sp-sp7021.h         |  97 +++
 24 files changed, 1724 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/configs/sp7021_defconfig
 create mode 100644 arch/arm/mach-sunplus/Kconfig
 create mode 100644 arch/arm/mach-sunplus/Makefile
 create mode 100644 arch/arm/mach-sunplus/sp7021.c
 create mode 100644 drivers/clk/clk-sp7021.c
 create mode 100644 drivers/irqchip/irq-sp7021-intc.c
 create mode 100644 drivers/reset/reset-sunplus.c
 create mode 100644 include/dt-bindings/clock/sp-sp7021.h
 create mode 100644 include/dt-bindings/reset/sp-sp7021.h
Signature · 1 line
2.33.1
author maintainer
#1 lore raw

PATCH v8 1/10 dt-bindings: vendor-prefixes: Add Sunplus

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

---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)
Documentation/devicetree/bindings/vendor-prefixes.yaml +2 -0
index a867f7102..50d4ee5ac 100644
@@ -1131,6 +1131,8 @@ patternProperties:
     description: Summit microelectronics
   "^sunchip,.*":
     description: Shenzhen Sunchip Technology Co., Ltd
+  "^sunplus,.*":
+    description: Sunplus Technology Co., Ltd.
   "^SUNW,.*":
     description: Sun Microsystems, Inc
   "^supermicro,.*":
Signature · 1 line
2.33.1
author maintainer
#2 lore raw

PATCH v8 2/10 dt-bindings: arm: sunplus: Add bindings for Sunplus SP7021 SoC boards

In reply to Qin Jian

This introduces bindings for boards based Sunplus SP7021 SoC.

---
 .../bindings/arm/sunplus,sp7021.yaml          | 27 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++++
 2 files changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml new file +27 -0
new file mode 100644
index 000000000..5b9985b73
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/sunplus,sp7021.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 Boards Device Tree Bindings
+
+maintainers:
+  - qinjian <[email protected]>
+
+description: |
+  ARM platforms using Sunplus SP7021, an ARM Cortex A7 (4-cores) based SoC.
+  Wiki: https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      - items:
+          - const: sunplus,sp7021-achip
+
+additionalProperties: true
+
+...
MAINTAINERS +7 -0
index e0bca0de0..6a5422f10 100644
@@ -2655,6 +2655,13 @@ F:	drivers/clocksource/armv7m_systick.c
 N:	stm32
 N:	stm
 
+ARM/SUNPLUS SP7021 SOC SUPPORT
+M:	Qin Jian <[email protected]>
+L:	[email protected] (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 <[email protected]>
 M:	Sebastian Hesselbarth <[email protected]>
Signature · 7 lines
2.33.1


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
author maintainer
#3 lore raw

PATCH v8 3/10 dt-bindings: reset: Add bindings for SP7021 reset driver

In reply to Qin Jian

Add documentation to describe Sunplus SP7021 reset driver bindings.

---
 .../bindings/reset/sunplus,reset.yaml         | 38 ++++++++
 MAINTAINERS                                   |  2 +
 include/dt-bindings/reset/sp-sp7021.h         | 97 +++++++++++++++++++
 3 files changed, 137 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 create mode 100644 include/dt-bindings/reset/sp-sp7021.h
Documentation/devicetree/bindings/reset/sunplus,reset.yaml new file +38 -0
new file mode 100644
index 000000000..c083c821f
@@ -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 <[email protected]>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-reset
+
+  "#reset-cells":
+    const: 1
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - "#reset-cells"
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    rstc: reset@9c000054 {
+      compatible = "sunplus,sp7021-reset";
+      #reset-cells = <1>;
+      reg = <0x9c000054 0x28>;
+    };
+
+...
MAINTAINERS +2 -0
index 6a5422f10..652f42cab 100644
@@ -2661,6 +2661,8 @@ L:	[email protected] (moderated for mon-subscribers)
 S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
 M:	Jisheng Zhang <[email protected]>
include/dt-bindings/reset/sp-sp7021.h new file +97 -0

97 lines not on this page · raw message

Signature · 1 line
2.33.1
author maintainer
#4 lore raw

PATCH v8 4/10 reset: Add Sunplus SP7021 reset driver

In reply to Qin Jian

Add reset driver for Sunplus SP7021 SoC.

---
 MAINTAINERS                   |   1 +
 drivers/reset/Kconfig         |   9 +++
 drivers/reset/Makefile        |   1 +
 drivers/reset/reset-sunplus.c | 130 ++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+)
 create mode 100644 drivers/reset/reset-sunplus.c
MAINTAINERS +1 -0
index 652f42cab..6caffd6d0 100644
@@ -2662,6 +2662,7 @@ S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
drivers/reset/Kconfig +9 -0
index be799a5ab..fb14456a8 100644
@@ -224,6 +224,15 @@ config RESET_SOCFPGA
 	  This enables the reset driver for the SoCFPGA ARMv7 platforms. This
 	  driver gets initialized early during platform init calls.
 
+config RESET_SUNPLUS
+	bool "Sunplus SoCs Reset Driver" if COMPILE_TEST
+	default ARCH_SUNPLUS
+	help
+	  This enables the reset driver support for Sunplus SoCs.
+	  The reset lines that can be asserted and deasserted by toggling bits
+	  in a contiguous, exclusive register space. The register is HIWORD_MASKED,
+	  which means each register hold 16 reset lines.
+
 config RESET_SUNXI
 	bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI
 	default ARCH_SUNXI
drivers/reset/Makefile +1 -0
index 21d46d886..f03403e97 100644
@@ -29,6 +29,7 @@ obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
 obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
drivers/reset/reset-sunplus.c new file +130 -0

130 lines not on this page · raw message

Signature · 1 line
2.33.1
author maintainer
#5 lore raw

PATCH v8 5/10 dt-bindings: clock: Add bindings for SP7021 clock driver

In reply to Qin Jian

Add documentation to describe Sunplus SP7021 clock driver bindings.

---
Add clocks & clock-names.

---
 .../bindings/clock/sunplus,sp7021-clkc.yaml   |  52 ++++++++
 MAINTAINERS                                   |   2 +
 include/dt-bindings/clock/sp-sp7021.h         | 112 ++++++++++++++++++
 3 files changed, 166 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 create mode 100644 include/dt-bindings/clock/sp-sp7021.h
Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml new file +52 -0
new file mode 100644
index 000000000..e6d098cf4
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/sunplus,sp7021-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SP7021 SoC Clock Controller Binding
+
+maintainers:
+  - Qin Jian <[email protected]>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-clkc
+
+  "#clock-cells":
+    const: 1
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: External oscillator clock
+      - description: System clock
+
+  clock-names:
+    items:
+      - const: extclk
+      - const: pllsys
+
+required:
+  - compatible
+  - "#clock-cells"
+  - reg
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    clkc: clock-controller@9c000000 {
+      compatible = "sunplus,sp7021-clkc";
+      #clock-cells = <1>;
+      reg = <0x9c000000 0x280>;
+      clocks = <&extclk>, <&clkc PLL_SYS>;
+      clock-names = "extclk", "pllsys";
+    };
+
+...
MAINTAINERS +2 -0
index 6caffd6d0..90ebb823f 100644
@@ -2661,8 +2661,10 @@ L:	[email protected] (moderated for mon-subscribers)
 S:	Maintained
 W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
+F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 F:	drivers/reset/reset-sunplus.c
+F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
 
 ARM/Synaptics SoC support
include/dt-bindings/clock/sp-sp7021.h new file +112 -0

112 lines not on this page · raw message

Signature · 1 line
2.33.1
author maintainer
#7 lore raw

PATCH v8 6/10 clk: Add Sunplus SP7021 clock driver

In reply to Qin Jian

Add clock driver for Sunplus SP7021 SoC.

---
Fix the comments from Stephen Boyd.

---
 MAINTAINERS              |   1 +
 drivers/clk/Kconfig      |   9 +
 drivers/clk/Makefile     |   1 +
 drivers/clk/clk-sp7021.c | 753 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 764 insertions(+)
 create mode 100644 drivers/clk/clk-sp7021.c
MAINTAINERS +1 -0
index 90ebb823f..5069f552f 100644
@@ -2663,6 +2663,7 @@ W:	https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
 F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	drivers/clk/clk-sp7021.c
 F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
drivers/clk/Kconfig +9 -0
index c5b3dc973..91656de22 100644
@@ -334,6 +334,15 @@ config COMMON_CLK_VC5
 	  This driver supports the IDT VersaClock 5 and VersaClock 6
 	  programmable clock generators.
 
+config COMMON_CLK_SP7021
+	bool "Clock driver for Sunplus SP7021 SoC"
+	default SOC_SP7021
+	help
+	  This driver supports the Sunplus SP7021 SoC clocks.
+	  It implements SP7021 PLLs/gate.
+	  Not all features of the PLL are currently supported
+	  by the driver.
+
 config COMMON_CLK_STM32MP157
 	def_bool COMMON_CLK && MACH_STM32MP157
 	help
drivers/clk/Makefile +1 -0
index e42312121..f15bb5070 100644
@@ -60,6 +60,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351)		+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)		+= clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI544)		+= clk-si544.o
 obj-$(CONFIG_COMMON_CLK_SI570)		+= clk-si570.o
+obj-$(CONFIG_COMMON_CLK_SP7021)		+= clk-sp7021.o
 obj-$(CONFIG_COMMON_CLK_STM32F)		+= clk-stm32f4.o
 obj-$(CONFIG_COMMON_CLK_STM32H7)	+= clk-stm32h7.o
 obj-$(CONFIG_COMMON_CLK_STM32MP157)	+= clk-stm32mp1.o
drivers/clk/clk-sp7021.c new file +753 -0

753 lines not on this page · raw message

Signature · 1 line
2.33.1
maintainer
#8 lore raw

Re: [PATCH v8 06/10] clk: Add Sunplus SP7021 clock driver

Quoting Qin Jian (2022-01-20 23:53:14)

drivers/clk/Kconfig config COMMON_CLK_VC5 · line 339

Quoted 11 lines
drivers/clk/Kconfig +3 -0
index c5b3dc973..91656de22 100644
@@ -334,6 +334,15 @@ config COMMON_CLK_VC5
          This driver supports the IDT VersaClock 5 and VersaClock 6
          programmable clock generators.
 
+config COMMON_CLK_SP7021
+       bool "Clock driver for Sunplus SP7021 SoC"
+       default SOC_SP7021

Also would be good to have

	depends on SOC_SP7021 || COMPILE_TEST
Quoted 15 lines
drivers/clk/Kconfig +6 -0
+       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
drivers/clk/clk-sp7021.c new file +0 -0
new file mode 100644
index 000000000..8a3e28a2a

drivers/clk/clk-sp7021.c line 8

Quoted 8 lines
drivers/clk/clk-sp7021.c new file +8 -0
@@ -0,0 +1,753 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Copyright (C) Sunplus Technology Co., Ltd.
+ *       All rights reserved.
+ */
+//#define DEBUG
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>

IS the clkdev get path used? If not, please drop it.

Quoted 60 lines
drivers/clk/clk-sp7021.c new file +60 -0
+#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/sp-sp7021.h>
+
+#define REG(i)         (pll_regs + (i) * 4)
+
+#define PLLA_CTL       REG(7)
+#define PLLE_CTL       REG(12)
+#define PLLF_CTL       REG(13)
+#define PLLTV_CTL      REG(14)
+#define PLLSYS_CTL     REG(26)
+
+/* 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 */
+};
+

drivers/clk/clk-sp7021.c line 78

Quoted 10 lines
drivers/clk/clk-sp7021.c new file +10 -0
+#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_CRITICAL     BIT(31) /* clock is critical */
+#define F_EXTCLK       BIT(16) /* parent clock is EXTCLK */
+const struct clk_parent_data parents[] = {

static? 'parents' is too generic, and this is in the global namespace. Please make it driver specific.

drivers/clk/clk-sp7021.c line 81

Quoted 3 lines
drivers/clk/clk-sp7021.c new file +3 -0
+       { .name = "pllsys" },
+       { .name = "extclk" },
+       { .name = "plle" },

The .name member of clk_parent_data shouldn't be used for new drivers or bindings. Instead, use .fw_name or the .index, preferably the index so the struct is smaller.

drivers/clk/clk-sp7021.c line 88

Quoted 7 lines
drivers/clk/clk-sp7021.c new file +7 -0
+};
+
+#define PD_PLLSYS      (&parents[0])
+#define PD_EXTCLK      (&parents[1])
+#define PD_PLLE                (&parents[2])
+
+static const u32 gates[] = {

'gates' is too generic, please name this something driver specific.

Quoted 7 lines
drivers/clk/clk-sp7021.c new file +7 -0
+       CLK_SYSTEM                      | F_CRITICAL,
+       CLK_RTC,
+       CLK_IOCTL                       | F_CRITICAL,
+       CLK_IOP                         | F_CRITICAL,
+       CLK_OTPRX,
+       CLK_NOC,
+       CLK_BR,

drivers/clk/clk-sp7021.c line 105

Quoted 10 lines
drivers/clk/clk-sp7021.c new file +10 -0
+       CLK_RBUS_L00                    | F_CRITICAL,
+       CLK_SPIFL,
+       CLK_SDCTRL0                     | F_CRITICAL,
+       CLK_PERI0       | F_EXTCLK,
+       CLK_A926                        | F_CRITICAL,
+       CLK_UMCTL2                      | F_CRITICAL,
+       CLK_PERI1       | F_EXTCLK,
+
+       CLK_DDR_PHY0                    | F_CRITICAL,
+       CLK_ACHIP                       | F_CRITICAL,

Do these gates have children? What is the benefit of modeling critical clks that have no children? It would be simpler to make sure they're enabled at driver probe time and then not do anything else and skip registering them with the clk framework when they'll do nothing.

Quoted 98 lines
drivers/clk/clk-sp7021.c new file +98 -0
+       CLK_STC0,
+       CLK_STC_AV0,
+       CLK_STC_AV1,
+       CLK_STC_AV2,
+       CLK_UA0         | F_EXTCLK,
+       CLK_UA1         | F_EXTCLK,
+       CLK_UA2         | F_EXTCLK,
+       CLK_UA3         | F_EXTCLK,
+       CLK_UA4         | F_EXTCLK,
+       CLK_HWUA        | F_EXTCLK,
+       CLK_DDC0,
+       CLK_UADMA       | F_EXTCLK,
+
+       CLK_CBDMA0,
+       CLK_CBDMA1,
+       CLK_SPI_COMBO_0,
+       CLK_SPI_COMBO_1,
+       CLK_SPI_COMBO_2,
+       CLK_SPI_COMBO_3,
+       CLK_AUD,
+       CLK_USBC0,
+       CLK_USBC1,
+       CLK_UPHY0,
+       CLK_UPHY1,
+
+       CLK_I2CM0,
+       CLK_I2CM1,
+       CLK_I2CM2,
+       CLK_I2CM3,
+       CLK_PMC,
+       CLK_CARD_CTL0,
+       CLK_CARD_CTL1,
+
+       CLK_CARD_CTL4,
+       CLK_BCH,
+       CLK_DDFCH,
+       CLK_CSIIW0,
+       CLK_CSIIW1,
+       CLK_MIPICSI0,
+       CLK_MIPICSI1,
+
+       CLK_HDMI_TX,
+       CLK_VPOST,
+
+       CLK_TGEN,
+       CLK_DMIX,
+       CLK_TCON,
+       CLK_INTERRUPT                   | F_CRITICAL,
+
+       CLK_RGST                        | F_CRITICAL,
+       CLK_GPIO,
+       CLK_RBUS_TOP                    | F_CRITICAL,
+
+       CLK_MAILBOX,
+       CLK_SPIND,
+       CLK_I2C2CBUS,
+       CLK_SEC,
+       CLK_GPOST0,
+       CLK_DVE,
+
+       CLK_OSD0,
+       CLK_DISP_PWM,
+       CLK_UADBG,
+       CLK_DUMMY_MASTER,
+       CLK_FIO_CTL,
+       CLK_FPGA,
+       CLK_L2SW,
+       CLK_ICM,
+       CLK_AXI_GLOBAL,
+};
+
+static DEFINE_SPINLOCK(plla_lock);
+static DEFINE_SPINLOCK(plle_lock);
+static DEFINE_SPINLOCK(pllf_lock);
+static DEFINE_SPINLOCK(pllsys_lock);
+static DEFINE_SPINLOCK(plltv_lock);
+
+#define _M             1000000UL
+#define F_27M          (27 * _M)
+
+/*********************************** PLL_TV **********************************/
+
+/* TODO: set proper FVCO range */
+#define FVCO_MIN       (100 * _M)
+#define FVCO_MAX       (200 * _M)
+
+#define F_MIN          (FVCO_MIN / 8)
+#define F_MAX          (FVCO_MAX)
+
+static long plltv_integer_div(struct sp_pll *clk, unsigned long freq)
+{
+       /* valid m values: 27M must be divisible by m, 0 means end */
+       static const u32 m_table[] = {
+               1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 0
+       };
+       u32 m, n, r;
+       unsigned long fvco, nf;
+

drivers/clk/clk-sp7021.c line 213

Quoted 10 lines
drivers/clk/clk-sp7021.c new file +10 -0
+       /* check freq */
+       if (freq < F_MIN) {
+               pr_warn("%s: %s freq:%lu < F_MIN:%lu, round up\n",
+                       __func__, clk_hw_get_name(&clk->hw), freq, F_MIN);
+               freq = F_MIN;
+       } else if (freq > F_MAX) {
+               pr_warn("%s: %s freq:%lu > F_MAX:%lu, round down\n",
+                       __func__, clk_hw_get_name(&clk->hw), freq, F_MAX);
+               freq = F_MAX;
+       }

Just use clamp() and ignore the warnings?

Quoted 63 lines
drivers/clk/clk-sp7021.c new file +63 -0
+
+       /* 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;
+

drivers/clk/clk-sp7021.c line 286

Quoted 10 lines
drivers/clk/clk-sp7021.c new file +10 -0
+       /* check freq */
+       if (freq < F_MIN) {
+               pr_warn("%s: %s freq:%lu < F_MIN:%lu, round up\n",
+                       __func__, clk_hw_get_name(&clk->hw), freq, F_MIN);
+               freq = F_MIN;
+       } else if (freq > F_MAX) {
+               pr_warn("%s: %s freq:%lu > F_MAX:%lu, round down\n",
+                       __func__, clk_hw_get_name(&clk->hw), freq, F_MAX);
+               freq = F_MAX;
+       }

Just use clamp() and ignore the warnings?

Quoted 12 lines
drivers/clk/clk-sp7021.c new file +12 -0
+
+       /* 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];

drivers/clk/clk-sp7021.c line 308

Quoted 10 lines
drivers/clk/clk-sp7021.c new file +10 -0
+               u32 ms = 1;
+
+               /* SDM_MOD 0/1 */
+               for (sdm = 0; sdm <= 1; sdm++) {
+                       u32 mod = mods[sdm];
+
+                       /* DIVM 1~32 */
+                       for (m = ms; m <= 32; m++) {
+                               u32 df; /* diff freq */
+                               u32 df_quotient = 0, df_remainder = 0;

Please leave these unassigned.

Quoted 227 lines
drivers/clk/clk-sp7021.c new file +227 -0
+
+                               nf = fvco * m;
+                               nint = nf / pp[3];
+
+                               if (nint < pp[1])
+                                       continue;
+                               if (nint > pp[1])
+                                       break;
+
+                               nfra = (((nf % pp[3]) * mod * pp[4]) + (F_27M / 2)) / F_27M;
+                               if (nfra)
+                                       df = (f * (nint + pp[2]) / pp[0]) -
+                                            (f * (mod - nfra) / mod / pp[4]);
+                               else
+                                       df = (f * (nint) / pp[0]);
+
+                               df_quotient  = df / m;
+                               df_remainder = ((df % m) * 1000) / m;
+
+                               if (freq > df_quotient) {
+                                       df_quotient  = freq - df_quotient - 1;
+                                       df_remainder = 1000 - df_remainder;
+                               } else {
+                                       df_quotient = df_quotient - freq;
+                               }
+
+                               if (df_quotient_min > df_quotient ||
+                                   (df_quotient_min == df_quotient &&
+                                   df_remainder_min > df_remainder)) {
+                                       /* found a closer freq, save parameters */
+                                       clk->p[SEL_FRA] = 1;
+                                       clk->p[SDM_MOD] = sdm;
+                                       clk->p[PH_SEL]  = ph;
+                                       clk->p[NFRA]    = nfra;
+                                       clk->p[DIVR]    = r;
+                                       clk->p[DIVM]    = m;
+
+                                       fout = df / m;
+                                       df_quotient_min = df_quotient;
+                                       df_remainder_min = df_remainder;
+                               }
+                       }
+               }
+       }
+
+       if (!fout) {
+               pr_err("%s: %s freq:%lu not found a valid setting\n",
+                      __func__, clk_hw_get_name(&clk->hw), freq);
+               return -EINVAL;
+       }
+
+       return fout;
+}
+
+static long plltv_div(struct sp_pll *clk, unsigned long freq)
+{
+       if (freq % 100)
+               return plltv_fractional_div(clk, freq);
+
+       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;
+

drivers/clk/clk-sp7021.c line 545

Quoted 10 lines
drivers/clk/clk-sp7021.c new file +10 -0
+       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);

Please add braces to all these if arms, because the else if below has one.

Quoted 102 lines
drivers/clk/clk-sp7021.c new file +102 -0
+       else if (clk->div_width) {
+               u32 fbdiv = sp_pll_calc_div(clk, rate);
+               u32 mask = GENMASK(clk->div_shift + clk->div_width - 1, clk->div_shift);
+
+               reg |= (mask << 16) | (((fbdiv - 1) << clk->div_shift) & mask);
+       }
+
+       writel(reg, clk->reg);
+
+       spin_unlock_irqrestore(clk->lock, flags);
+
+       return 0;
+}
+
+static int sp_pll_enable(struct clk_hw *hw)
+{
+       struct sp_pll *clk = to_sp_pll(hw);
+       unsigned long flags;
+
+       spin_lock_irqsave(clk->lock, flags);
+       writel(BIT(clk->pd_bit + 16) | BIT(clk->pd_bit), clk->reg); /* power up */
+       spin_unlock_irqrestore(clk->lock, flags);
+
+       return 0;
+}
+
+static void sp_pll_disable(struct clk_hw *hw)
+{
+       struct sp_pll *clk = to_sp_pll(hw);
+       unsigned long flags;
+
+       spin_lock_irqsave(clk->lock, flags);
+       writel(BIT(clk->pd_bit + 16), clk->reg); /* power down */
+       spin_unlock_irqrestore(clk->lock, flags);
+}
+
+static int sp_pll_is_enabled(struct clk_hw *hw)
+{
+       struct sp_pll *clk = to_sp_pll(hw);
+
+       return readl(clk->reg) & BIT(clk->pd_bit);
+}
+
+static const struct clk_ops sp_pll_ops = {
+       .enable = sp_pll_enable,
+       .disable = sp_pll_disable,
+       .is_enabled = sp_pll_is_enabled,
+       .round_rate = sp_pll_round_rate,
+       .recalc_rate = sp_pll_recalc_rate,
+       .set_rate = sp_pll_set_rate
+};
+
+static const struct clk_ops sp_pll_sub_ops = {
+       .enable = sp_pll_enable,
+       .disable = sp_pll_disable,
+       .is_enabled = sp_pll_is_enabled,
+       .recalc_rate = sp_pll_recalc_rate,
+};
+
+struct clk_hw *sp_pll_register(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);
+               hw = ERR_PTR(ret);
+       } else {
+               pr_debug("%-20s%lu\n", name, clk_hw_get_rate(hw));
+               devm_clk_hw_register_clkdev(dev, hw, NULL, name);
+       }
+
+       return hw;
+}

drivers/clk/clk-sp7021.c line 657

Quoted 10 lines
drivers/clk/clk-sp7021.c new file +10 -0
+
+static int sp7021_clk_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       int i, ret;
+       struct clk_hw **hws;
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       sp_clk_base = devm_ioremap(dev, res->start, resource_size(res));

Use devm_platform_ioremap_resource()?

drivers/clk/clk-sp7021.c line 658

Quoted 1 line
drivers/clk/clk-sp7021.c new file +1 -0
+       if (WARN_ON(!sp_clk_base))

Drop the WARN_ON() as it already prints a stacktrace if things fail.

Quoted 85 lines
drivers/clk/clk-sp7021.c new file +85 -0
+               return -ENXIO;
+
+       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;
+
+       /* PLL_A */
+       hws[PLL_A] = sp_pll_register(dev, "plla", PD_EXTCLK, 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_EXTCLK, PLLE_CTL,
+                                    6, 2, 50000000, 0, 0, &plle_lock);
+       if (IS_ERR(hws[PLL_E]))
+               return PTR_ERR(hws[PLL_E]);
+       hws[PLL_E_2P5] = sp_pll_register(dev, "plle_2p5", PD_PLLE, 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_PLLE, 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_PLLE, 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_EXTCLK, 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_EXTCLK, 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]);
+       ret = devm_clk_hw_register_clkdev(dev, hws[PLL_TV_A], NULL, "plltv_a");
+       if (ret)
+               return ret;
+
+       /* PLL_SYS */
+       hws[PLL_SYS] = sp_pll_register(dev, "pllsys", PD_EXTCLK, PLLSYS_CTL,
+                                      10, 9, 13500000, 0, 4, &pllsys_lock);
+       if (IS_ERR(hws[PLL_SYS]))
+               return PTR_ERR(hws[PLL_SYS]);
+
+       /* gates */
+       for (i = 0; i < ARRAY_SIZE(gates); i++) {
+               u32 f = gates[i];
+               const char *parent_name = parents[!!(f & F_EXTCLK)].name;
+               bool critical = f & F_CRITICAL;
+               int j = f & 0xffff;
+               char s[10];
+
+               sprintf(s, "clken%02x", j);
+               hws[j] = clk_hw_register_gate(dev, s, parent_name,
+                                             critical ? CLK_IS_CRITICAL : 0,
+                                             clk_regs + (j >> 4) * 4,
+                                             j & 0x0f,
+                                             CLK_GATE_HIWORD_MASK, NULL);
+               if (IS_ERR(hws[j]))
+                       return PTR_ERR(hws[j]);
+       }
+
+       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", },
+       { }

drivers/clk/clk-sp7021.c line 753

Quoted 10 lines
drivers/clk/clk-sp7021.c new file +10 -0
+};
+
+static struct platform_driver sp7021_clk_driver = {
+       .probe  = sp7021_clk_probe,
+       .driver = {
+               .name = "sp7021-clk",
+               .of_match_table = sp7021_clk_dt_ids,
+       },
+};
+builtin_platform_driver(sp7021_clk_driver);

Can it be a module?

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

author maintainer
#9 lore raw

PATCH v8 7/10 dt-bindings: interrupt-controller: Add bindings for SP7021 interrupt controller

In reply to Qin Jian

Add documentation to describe Sunplus SP7021 interrupt controller bindings.

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

PATCH v8 8/10 irqchip: Add Sunplus SP7021 interrupt controller driver

In reply to 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.

---
Fix the comments from Marc.

---
 MAINTAINERS                       |   1 +
 drivers/irqchip/Kconfig           |   9 +
 drivers/irqchip/Makefile          |   1 +
 drivers/irqchip/irq-sp7021-intc.c | 288 ++++++++++++++++++++++++++++++
 4 files changed, 299 insertions(+)
 create mode 100644 drivers/irqchip/irq-sp7021-intc.c
MAINTAINERS +1 -0
index 6b3bbe021..febbd97bf 100644
@@ -2665,6 +2665,7 @@ F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
 F:	drivers/clk/clk-sp7021.c
+F:	drivers/irqchip/irq-sp7021-intc.c
 F:	drivers/reset/reset-sunplus.c
 F:	include/dt-bindings/clock/sp-sp7021.h
 F:	include/dt-bindings/reset/sp-sp7021.h
drivers/irqchip/Kconfig +9 -0
index aca7b595c..32d7a8e0c 100644
@@ -602,4 +602,13 @@ config APPLE_AIC
 	  Support for the Apple Interrupt Controller found on Apple Silicon SoCs,
 	  such as the M1.
 
+config SUNPLUS_SP7021_INTC
+	bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST
+	default SOC_SP7021
+	help
+	  Support for the Sunplus SP7021 Interrupt Controller IP core.
+	  SP7021 SoC has 2 Chips: C-Chip & P-Chip. This is used as a
+	  chained controller, routing all interrupt source in P-Chip to
+	  the primary controller on C-Chip.
+
 endmenu
drivers/irqchip/Makefile +1 -0
index f88cbf36a..75411f654 100644
@@ -116,3 +116,4 @@ obj-$(CONFIG_MACH_REALTEK_RTL)		+= irq-realtek-rtl.o
 obj-$(CONFIG_WPCM450_AIC)		+= irq-wpcm450-aic.o
 obj-$(CONFIG_IRQ_IDT3243X)		+= irq-idt3243x.o
 obj-$(CONFIG_APPLE_AIC)			+= irq-apple-aic.o
+obj-$(CONFIG_SUNPLUS_SP7021_INTC)	+= irq-sp7021-intc.o
drivers/irqchip/irq-sp7021-intc.c new file +288 -0

288 lines not on this page · raw message

Signature · 1 line
2.33.1
author maintainer
#11 lore raw

PATCH v8 9/10 ARM: sunplus: Add initial support for Sunplus SP7021 SoC

In reply to Qin Jian

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

---
 MAINTAINERS                    |  1 +
 arch/arm/Kconfig               |  2 ++
 arch/arm/Makefile              |  1 +
 arch/arm/mach-sunplus/Kconfig  | 26 ++++++++++++++++++++++++++
 arch/arm/mach-sunplus/Makefile |  9 +++++++++
 arch/arm/mach-sunplus/sp7021.c | 16 ++++++++++++++++
 6 files changed, 55 insertions(+)
 create mode 100644 arch/arm/mach-sunplus/Kconfig
 create mode 100644 arch/arm/mach-sunplus/Makefile
 create mode 100644 arch/arm/mach-sunplus/sp7021.c
MAINTAINERS +1 -0
index febbd97bf..0ae537a41 100644
@@ -2664,6 +2664,7 @@ F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	arch/arm/mach-sunplus/
 F:	drivers/clk/clk-sp7021.c
 F:	drivers/irqchip/irq-sp7021-intc.c
 F:	drivers/reset/reset-sunplus.c
arch/arm/Kconfig +2 -0
index 59baf6c13..8c7883b5a 100644
@@ -689,6 +689,8 @@ source "arch/arm/mach-sti/Kconfig"
 
 source "arch/arm/mach-stm32/Kconfig"
 
+source "arch/arm/mach-sunplus/Kconfig"
+
 source "arch/arm/mach-sunxi/Kconfig"
 
 source "arch/arm/mach-tegra/Kconfig"
arch/arm/Makefile +1 -0
index 847c31e7c..973ffb830 100644
@@ -212,6 +212,7 @@ machine-$(CONFIG_ARCH_RENESAS)	 	+= shmobile
 machine-$(CONFIG_ARCH_INTEL_SOCFPGA)	+= socfpga
 machine-$(CONFIG_ARCH_STI)		+= sti
 machine-$(CONFIG_ARCH_STM32)		+= stm32
+machine-$(CONFIG_ARCH_SUNPLUS)		+= sunplus
 machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
 machine-$(CONFIG_ARCH_TEGRA)		+= tegra
 machine-$(CONFIG_ARCH_U8500)		+= ux500
arch/arm/mach-sunplus/Kconfig new file +26 -0
new file mode 100644
index 000000000..e720606dd
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+menuconfig ARCH_SUNPLUS
+	bool "Sunplus SoCs"
+	depends on ARCH_MULTI_V7
+	help
+	  Support for Sunplus SoC family: SP7021 and succeeding SoC-based systems,
+	  such as the Banana Pi BPI-F2S development board (and derivatives).
+	  (<http://www.sinovoip.com.cn/ecp_view.asp?id=586>)
+	  (<https://tibbo.com/store/plus1.html>)
+
+config SOC_SP7021
+	bool "Sunplus SP7021 SoC support"
+	depends on ARCH_SUNPLUS
+	default ARCH_SUNPLUS
+	select ARM_GIC
+	select ARM_PSCI
+	select PINCTRL
+	select PINCTRL_SPPCTL
+	select SERIAL_SUNPLUS
+	select SERIAL_SUNPLUS_CONSOLE
+	help
+	  Support for Sunplus SP7021 SoC. It is based on ARM 4-core
+	  Cortex-A7 with various peripherals (ex: I2C, SPI, SDIO,
+	  Ethernet and etc.), FPGA interface,  chip-to-chip bus.
+	  It is designed for industrial control.
arch/arm/mach-sunplus/Makefile new file +9 -0
new file mode 100644
index 000000000..c902580a7
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-$(CONFIG_SOC_SP7021)	+= sp7021.o
+
arch/arm/mach-sunplus/sp7021.c new file +16 -0
new file mode 100644
index 000000000..774d0a5bd
@@ -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
Signature · 1 line
2.33.1
author maintainer
#12 lore raw

PATCH v8 10/10 ARM: sp7021_defconfig: Add Sunplus SP7021 defconfig

In reply to Qin Jian

Add generic Sunplus SP7021 based board defconfig

---
 MAINTAINERS                         |  1 +
 arch/arm/configs/multi_v7_defconfig |  1 +
 arch/arm/configs/sp7021_defconfig   | 61 +++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)
 create mode 100644 arch/arm/configs/sp7021_defconfig
MAINTAINERS +1 -0
index 0ae537a41..9340f8760 100644
@@ -2664,6 +2664,7 @@ F:	Documentation/devicetree/bindings/arm/sunplus,sp7021.yaml
 F:	Documentation/devicetree/bindings/clock/sunplus,sp7021-clkc.yaml
 F:	Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.yaml
 F:	Documentation/devicetree/bindings/reset/sunplus,reset.yaml
+F:	arch/arm/configs/sp7021_*defconfig
 F:	arch/arm/mach-sunplus/
 F:	drivers/clk/clk-sp7021.c
 F:	drivers/irqchip/irq-sp7021-intc.c
arch/arm/configs/multi_v7_defconfig +1 -0
index b4f74454f..585e3b5d3 100644
@@ -87,6 +87,7 @@ CONFIG_MACH_SPEAR1310=y
 CONFIG_MACH_SPEAR1340=y
 CONFIG_ARCH_STI=y
 CONFIG_ARCH_STM32=y
+CONFIG_ARCH_SUNPLUS=y
 CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_TEGRA=y
 CONFIG_ARCH_UNIPHIER=y
arch/arm/configs/sp7021_defconfig new file +61 -0

61 lines not on this page · raw message

Signature · 1 line
2.33.1