From afa50d05b315b2829a384f1a5199e0fec3f5c7bf Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Jul 2026 14:56:31 +0800 Subject: [PATCH 01/17] dt-bindings: add ZhiHe A210 SoC binding documentation Add devicetree binding schema documentation for the ZhiHe A210 SoC, covering clock, reset, pinctrl, power domain, mailbox, AON firmware, regulator, IOPMP, DWMAC, BMU and memtester. Also register the "zhihe" vendor prefix and add A210 compatibles to the existing dw-axi-dmac and dwcmshc-sdhci bindings. Signed-off-by: Zhiguo Zhu --- .../bindings/clock/zhihe,a210-ccu.yaml | 67 +++++++++++++ .../bindings/clock/zhihe,a210-clk.yaml | 76 ++++++++++++++ .../bindings/dma/snps,dw-axi-dmac.yaml | 1 + .../bindings/firmware/zhihe,a210-aon.yaml | 74 ++++++++++++++ .../bindings/mailbox/zhihe,a210-mailbox.yaml | 98 +++++++++++++++++++ .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 1 + .../bindings/net/zhihe,a210-dwmac.yaml | 95 ++++++++++++++++++ .../bindings/pinctrl/zhihe,a210-pinctrl.yaml | 49 ++++++++++ .../power/zhihe,a210-power-domain.yaml | 98 +++++++++++++++++++ .../regulator/zhihe,a210-aon-regulator.yaml | 60 ++++++++++++ .../reset/zhihe,a210-reset-controller.yaml | 51 ++++++++++ .../reset/zhihe,a210-reset-sample.yaml | 65 ++++++++++++ .../devicetree/bindings/riscv/zhihe.yaml | 29 ++++++ .../bindings/soc/zhihe/zhihe,a210-iopmp.yaml | 43 ++++++++ .../devicetree/bindings/vendor-prefixes.yaml | 2 + 15 files changed, 809 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/zhihe,a210-ccu.yaml create mode 100644 Documentation/devicetree/bindings/clock/zhihe,a210-clk.yaml create mode 100644 Documentation/devicetree/bindings/firmware/zhihe,a210-aon.yaml create mode 100644 Documentation/devicetree/bindings/mailbox/zhihe,a210-mailbox.yaml create mode 100644 Documentation/devicetree/bindings/net/zhihe,a210-dwmac.yaml create mode 100644 Documentation/devicetree/bindings/pinctrl/zhihe,a210-pinctrl.yaml create mode 100644 Documentation/devicetree/bindings/power/zhihe,a210-power-domain.yaml create mode 100644 Documentation/devicetree/bindings/regulator/zhihe,a210-aon-regulator.yaml create mode 100644 Documentation/devicetree/bindings/reset/zhihe,a210-reset-controller.yaml create mode 100644 Documentation/devicetree/bindings/reset/zhihe,a210-reset-sample.yaml create mode 100644 Documentation/devicetree/bindings/riscv/zhihe.yaml create mode 100644 Documentation/devicetree/bindings/soc/zhihe/zhihe,a210-iopmp.yaml diff --git a/Documentation/devicetree/bindings/clock/zhihe,a210-ccu.yaml b/Documentation/devicetree/bindings/clock/zhihe,a210-ccu.yaml new file mode 100644 index 0000000000000..d1b6d5719e0cd --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zhihe,a210-ccu.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zhihe,a210-ccu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 Clock Control Unit (CCU) + +maintainers: + - Zhiguo Zhu + +description: + The CCU (Clock Control Unit) is a hardware-level automatic clock + management block embedded in each power domain of the Zhihe A210 SoC. + Unlike the main clock controller (zhihe,a210-clk) which provides PLL, + divider, gate and mux operations driven by software, the CCU + autonomously sequences clock gating or scaling delays when its parent + power domain transitions between power states. It does not expose + clock outputs to consumers and is not required for basic SoC + operation; the system functions correctly without CCU nodes present. + +properties: + compatible: + const: zhihe,a210-ccu + + reg: + minItems: 1 + maxItems: 8 + + zhihe,ccu-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + description: + CCU operating mode. 0 (default) selects gating mode where clocks + are simply gated/ungated during power transitions. 1 selects + scaling mode where clock frequencies are ramped gradually. + Most power domains use gating mode; this property can be omitted + in that case. + + zhihe,ccu-dly-time: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Per-CCU delay time value. + + zhihe,ccu-dly-time-step: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Per-CCU delay time step value. + + zhihe,ccu-ratio: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Per-CCU divider ratio (scaling mode only). + +required: + - compatible + - reg + - zhihe,ccu-dly-time + - zhihe,ccu-dly-time-step + +additionalProperties: false + +examples: + - | + clock-controller@5910000 { + compatible = "zhihe,a210-ccu"; + reg = <0x05910000 0x2c>, <0x05920000 0x2c>; + zhihe,ccu-dly-time = <0x5e 0x5e>; + zhihe,ccu-dly-time-step = <0x3 0x3>; + }; diff --git a/Documentation/devicetree/bindings/clock/zhihe,a210-clk.yaml b/Documentation/devicetree/bindings/clock/zhihe,a210-clk.yaml new file mode 100644 index 0000000000000..0e582bd4a56bd --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zhihe,a210-clk.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zhihe,a210-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 Clock Controller + +maintainers: + - Zhiguo Zhu + +description: + The Zhihe A210 SoC contains several clock controllers spread across + different subsystems (top, peri, gpu, pcie, usb, vi, vp, vo, npu, d2d). + Each controller manages PLLs, dividers, gates and muxes for its + subsystem. The register regions consumed by a controller depend on the + specific compatible string. + +properties: + compatible: + enum: + - zhihe,a210-clk + - zhihe,a210-peri-clk + - zhihe,a210-gpu-clk + - zhihe,a210-pcie-clk + - zhihe,a210-usb-clk + - zhihe,a210-vi-clk + - zhihe,a210-vp-clk + - zhihe,a210-vo-clk + - zhihe,a210-npu-clk + - zhihe,a210-clk-emu + - zhihe,a210-clk-haps + + reg: + minItems: 1 + maxItems: 9 + + reg-names: + minItems: 1 + maxItems: 9 + + clocks: + description: Input reference oscillators. + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + maxItems: 3 + items: + enum: + - osc-32k + - osc-24m + - rc-24m + + "#clock-cells": + const: 1 + +required: + - compatible + - reg + - reg-names + - "#clock-cells" + +additionalProperties: false + +examples: + - | + clock-controller@260000 { + compatible = "zhihe,a210-clk"; + reg = <0x00260000 0x1000>; + reg-names = "pll-wrap"; + clocks = <&osc_32k>, <&osc_24m>, <&rc_24m>; + clock-names = "osc-32k", "osc-24m", "rc-24m"; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml index 363cf8bd150da..58310daaf515d 100644 --- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml @@ -21,6 +21,7 @@ properties: - snps,axi-dma-1.01a - intel,kmb-axi-dma - starfive,jh7110-axi-dma + - zhihe,a210-axi-dma reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/firmware/zhihe,a210-aon.yaml b/Documentation/devicetree/bindings/firmware/zhihe,a210-aon.yaml new file mode 100644 index 0000000000000..c25ab52e0a895 --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/zhihe,a210-aon.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/firmware/zhihe,a210-aon.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 AON (Always-On) Subsystem Firmware + +maintainers: + - Zhiguo Zhu + +description: + The Always-On (AON) subsystem of the Zhihe A210 SoC runs a dedicated + firmware and communicates with the application processor over a + mailbox. This node describes the AON control registers, its firmware + image and the mailbox channel used to reach it. + +properties: + compatible: + const: zhihe,a210-aon + + reg: + minItems: 3 + maxItems: 3 + + reg-names: + minItems: 3 + maxItems: 3 + items: + enum: + - aon-base + - aon-reset + - aon-sync + + firmware-name: + maxItems: 1 + description: Name of the AON firmware image to load. + + mboxes: + maxItems: 1 + + mbox-names: + items: + - const: aon0 + + zhihe,protocol-version: + $ref: /schemas/types.yaml#/definitions/uint32 + description: AON protocol version. + + "#mbox-cells": + const: 2 + +required: + - compatible + - reg + - reg-names + - mboxes + +additionalProperties: false + +examples: + - | + aon { + compatible = "zhihe,a210-aon"; + reg = <0x308f8000 0x10000>, + <0x30842018 0x4>, + <0x30846144 0x4>; + reg-names = "aon-base", "aon-reset", "aon-sync"; + firmware-name = "a210-aon.bin"; + mboxes = <&mbox_920 1 0>; + mbox-names = "aon0"; + #mbox-cells = <2>; + zhihe,protocol-version = <1>; + }; diff --git a/Documentation/devicetree/bindings/mailbox/zhihe,a210-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/zhihe,a210-mailbox.yaml new file mode 100644 index 0000000000000..2222dc60c68c1 --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/zhihe,a210-mailbox.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mailbox/zhihe,a210-mailbox.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 Mailbox Controller + +maintainers: + - Zhiguo Zhu + +description: + Mailbox controller for the Zhihe A210 SoC providing inter-processor + communication channels between the application processor and other + cores such as the AON (Always-On) subsystem. + +properties: + compatible: + enum: + - zhihe,a210-mailbox + - zhihe,a210-mailbox-v2 + + reg: + minItems: 1 + maxItems: 8 + + reg-names: + minItems: 1 + maxItems: 8 + items: + enum: + - interrupt + - local0 + - local1 + - remote0 + - remote1 + - remote2 + + clocks: + minItems: 1 + maxItems: 2 + + resets: + minItems: 1 + maxItems: 2 + + interrupts: + maxItems: 1 + + zhihe,icu-cpu-id: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Local ICU CPU index for this mailbox instance. + + "#mbox-cells": + const: 2 + +required: + - compatible + - reg + - reg-names + - interrupts + - "#mbox-cells" + +allOf: + - if: + properties: + compatible: + const: zhihe,a210-mailbox-v2 + then: + properties: + reg: + minItems: 3 + reg-names: + minItems: 3 + else: + properties: + reg: + minItems: 4 + reg-names: + minItems: 4 + +additionalProperties: false + +examples: + - | + mailbox@321000 { + compatible = "zhihe,a210-mailbox-v2"; + reg = <0x00321000 0x1000>, + <0x00320000 0x1000>, + <0x00311000 0x1000>; + reg-names = "interrupt", "local0", "remote0"; + clocks = <&clk_peri 0>, <&clk_peri 1>; + resets = <&rst 0>, <&rst 1>; + interrupt-parent = <&intc>; + interrupts = <336>; + zhihe,icu-cpu-id = <0>; + #mbox-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml index 42804d9552934..310b7738fbe68 100644 --- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml @@ -20,6 +20,7 @@ properties: - rockchip,rk3588-dwcmshc - snps,dwcmshc-sdhci - thead,th1520-dwcmshc + - zhihe,a210-dwcmshc reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/net/zhihe,a210-dwmac.yaml b/Documentation/devicetree/bindings/net/zhihe,a210-dwmac.yaml new file mode 100644 index 0000000000000..373756fb2e2ac --- /dev/null +++ b/Documentation/devicetree/bindings/net/zhihe,a210-dwmac.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/zhihe,a210-dwmac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 DWMAC Ethernet controller + +maintainers: + - Zhiguo Zhu + +description: + The Zhihe A210 integrates a Synopsys DesignWare MAC (dwmac-5.20) with + an SoC-specific glue layer. The node also carries the standard + snps,dwmac properties documented in net/snps,dwmac.yaml. + +select: + properties: + compatible: + contains: + const: zhihe,a210-dwmac + required: + - compatible + +properties: + compatible: + items: + - const: zhihe,a210-dwmac + - const: snps,dwmac-5.20 + + reg: + maxItems: 1 + + reg-names: + const: gmac + + clocks: + minItems: 4 + maxItems: 4 + + clock-names: + items: + - const: stmmaceth + - const: pclk + - const: x2h-aclk + - const: x2h-hclk + + zhihe,gmacsys: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon node controlling GMAC interface mode and + timing delays. + + rx-clk-delay: + $ref: /schemas/types.yaml#/definitions/uint32 + description: RGMII RX clock delay setting. + + tx-clk-delay: + $ref: /schemas/types.yaml#/definitions/uint32 + description: RGMII TX clock delay setting. + + snps,pbl: + description: Programmable burst length. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 4, 8, 16, 32] + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - zhihe,gmacsys + +allOf: + - $ref: snps,dwmac.yaml# + +unevaluatedProperties: true + +examples: + - | + ethernet@2100000 { + compatible = "zhihe,a210-dwmac", "snps,dwmac-5.20"; + reg = <0x02100000 0x10000>; + interrupt-parent = <&intc>; + interrupts = <277>; + interrupt-names = "macirq"; + phy-mode = "rgmii-id"; + clocks = <&clk_peri 0>, <&clk_peri 1>, + <&clk_peri 2>, <&clk_peri 3>; + clock-names = "stmmaceth", "pclk", "x2h-aclk", "x2h-hclk"; + resets = <&rst 0>, <&rst 1>; + reset-names = "stmmaceth", "ahb"; + zhihe,gmacsys = <&gmac0_sys>; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/zhihe,a210-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/zhihe,a210-pinctrl.yaml new file mode 100644 index 0000000000000..fdd0c30f77af7 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/zhihe,a210-pinctrl.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/zhihe,a210-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 Pin Controller + +maintainers: + - Zhiguo Zhu + +description: + Pin controller for the Zhihe A210 SoC. The A210 has several pad + controller instances (AON and PERI pad controllers). Each instance is + identified by its compatible string and provides pin multiplexing and + configuration for its pad group. + +properties: + compatible: + enum: + - zhihe,a210-aon-pinctrl + - zhihe,a210-peri1-pinctrl + - zhihe,a210-peri2-pinctrl + - zhihe,a210-peri3-pinctrl + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: pclk + +required: + - compatible + - reg + +additionalProperties: true + +examples: + - | + pinctrl@30848000 { + compatible = "zhihe,a210-aon-pinctrl"; + reg = <0x30848000 0x2000>; + clocks = <&aon_110m>; + clock-names = "pclk"; + }; diff --git a/Documentation/devicetree/bindings/power/zhihe,a210-power-domain.yaml b/Documentation/devicetree/bindings/power/zhihe,a210-power-domain.yaml new file mode 100644 index 0000000000000..a07a55a3d6cd0 --- /dev/null +++ b/Documentation/devicetree/bindings/power/zhihe,a210-power-domain.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/zhihe,a210-power-domain.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 Power Domain Controller + +maintainers: + - Zhiguo Zhu + +description: + Power domain controller for the Zhihe A210 SoC. It manages power + gating of the various hardware subsystems through PCU/PPU units. Each + power domain is described by a child node identified by a reg + property. Domains may reference IOPMP protection devices and contain + clock control unit (ccu) subnodes. + +properties: + compatible: + const: zhihe,a210-power-domain + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^(power-domain|[a-z0-9-]+-power-domain)@[0-9a-f]+$": + type: object + description: A single power domain provided by the controller. + + properties: + "#power-domain-cells": + const: 0 + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + ranges: true + + reg: + maxItems: 1 + description: Power domain identifier. + + iopmps: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: IOPMP protection devices controlled with this domain. + + power-domains: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 32 + + resets: + minItems: 1 + maxItems: 32 + + pmic-supply: + description: Regulator phandle powering this domain. + + patternProperties: + "^clock-controller@[0-9a-f]+$": + type: object + description: Clock control unit associated with the domain. + $ref: /schemas/clock/zhihe,a210-ccu.yaml# + + required: + - "#power-domain-cells" + - reg + + additionalProperties: false + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include + + power-controller { + compatible = "zhihe,a210-power-domain"; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@0 { + reg = ; + #power-domain-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/zhihe,a210-aon-regulator.yaml b/Documentation/devicetree/bindings/regulator/zhihe,a210-aon-regulator.yaml new file mode 100644 index 0000000000000..b4c8d4166c6bd --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/zhihe,a210-aon-regulator.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/zhihe,a210-aon-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 AON Regulator + +maintainers: + - Zhiguo Zhu + +description: + Virtual regulator provider for the Zhihe A210 SoC. The regulators are + physically controlled by the Always-On (AON) subsystem firmware and + are accessed from the application processor over the AON mailbox. + Each supported rail is described by a child node. The + zhihe,regulator-id property identifies the corresponding AON firmware + regulator ID, while regulator-name remains the standard + consumer-visible regulator name. + +properties: + compatible: + const: zhihe,a210-aon-regulator + +patternProperties: + "^[a-z0-9]+(-[a-z0-9]+)+$": + type: object + + allOf: + - $ref: regulator.yaml# + + properties: + zhihe,regulator-id: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 19 + description: AON firmware regulator ID. + + required: + - zhihe,regulator-id + + unevaluatedProperties: false + +required: + - compatible + +additionalProperties: false + +examples: + - | + regulators { + compatible = "zhihe,a210-aon-regulator"; + + dvdd-core { + zhihe,regulator-id = <14>; + regulator-name = "vdd-cpu"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1000000>; + }; + }; diff --git a/Documentation/devicetree/bindings/reset/zhihe,a210-reset-controller.yaml b/Documentation/devicetree/bindings/reset/zhihe,a210-reset-controller.yaml new file mode 100644 index 0000000000000..a5a53f1154789 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/zhihe,a210-reset-controller.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reset/zhihe,a210-reset-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 Reset Controller + +maintainers: + - Zhiguo Zhu + +description: + Reset controllers for the Zhihe A210 SoC. Each subsystem exposes a + separate reset controller register block and has its own compatible. + +properties: + compatible: + enum: + - zhihe,a210-vp-reset + - zhihe,a210-vi-reset + - zhihe,a210-npu-reset + - zhihe,a210-vo-reset + - zhihe,a210-peri0-reset + - zhihe,a210-peri1-reset + - zhihe,a210-peri2-reset + - zhihe,a210-peri3-reset + - zhihe,a210-pcie-reset + - zhihe,a210-usb-reset + - zhihe,a210-tee-reset + - zhihe,a210-gpu-reset + + reg: + maxItems: 1 + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - "#reset-cells" + +additionalProperties: false + +examples: + - | + reset-controller@6b20400 { + compatible = "zhihe,a210-vp-reset"; + reg = <0x06b20400 0x200>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/reset/zhihe,a210-reset-sample.yaml b/Documentation/devicetree/bindings/reset/zhihe,a210-reset-sample.yaml new file mode 100644 index 0000000000000..ba423d05a067f --- /dev/null +++ b/Documentation/devicetree/bindings/reset/zhihe,a210-reset-sample.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reset/zhihe,a210-reset-sample.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 CPU Reset (reset-sample) + +maintainers: + - Zhiguo Zhu + +description: + CPU bring-up / reset helper for the Zhihe A210 SoC. It programs the + per-cluster boot entry address and controls the software reset of the + C908/C920 CPU clusters. + +properties: + compatible: + const: zhihe,a210-reset-sample + + reg: + maxItems: 1 + + plic-delegate: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: PLIC delegation control register address. + + entry-reg: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: SYSREG registers used to set the per-cluster reset boot + address. + + entry-cnt: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Number of CPUs in each cluster. + + control-reg: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Software reset control registers for each cluster. + + control-val: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: Software reset control values for each cluster. + +required: + - compatible + - reg + - entry-reg + - entry-cnt + - control-reg + - control-val + +additionalProperties: false + +examples: + - | + reset-sample { + compatible = "zhihe,a210-reset-sample"; + reg = <0x00 0x00>; + plic-delegate = <0x181ffffc>; + entry-reg = <0x10148040 0x10148060>; + entry-cnt = <4 4>; + control-reg = <0x10144004 0x10144008>; + control-val = <0x1f 0x1f>; + }; diff --git a/Documentation/devicetree/bindings/riscv/zhihe.yaml b/Documentation/devicetree/bindings/riscv/zhihe.yaml new file mode 100644 index 0000000000000..2cfff7665b040 --- /dev/null +++ b/Documentation/devicetree/bindings/riscv/zhihe.yaml @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/riscv/zhihe.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe SoC-based boards + +maintainers: + - Zhiguo Zhu + +description: + Zhihe SoC-based boards + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - description: Zhihe A210 evaluation board + items: + - enum: + - zhihe,a210-dev + - zhihe,a210-evb + - const: zhihe,a210 + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/soc/zhihe/zhihe,a210-iopmp.yaml b/Documentation/devicetree/bindings/soc/zhihe/zhihe,a210-iopmp.yaml new file mode 100644 index 0000000000000..402e9326f9915 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/zhihe/zhihe,a210-iopmp.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/zhihe/zhihe,a210-iopmp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zhihe A210 IOPMP Controller + +maintainers: + - Zhiguo Zhu + +description: + IO Physical Memory Protection (IOPMP) controller used on Zhihe SoCs + to restrict peripheral DMA access to memory. Each named register + region corresponds to an IOPMP instance guarding a particular + subsystem. + +properties: + compatible: + const: zhihe,a210-iopmp + + reg: + minItems: 1 + maxItems: 16 + + reg-names: + minItems: 1 + maxItems: 16 + +required: + - compatible + - reg + - reg-names + +additionalProperties: false + +examples: + - | + iopmp@26b12000 { + compatible = "zhihe,a210-iopmp"; + reg = <0x26b12000 0x1000>, <0x26372000 0x1000>; + reg-names = "vp-iopmp", "vi-iopmp"; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 6cafa0ad7f45e..5b3334465242a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1590,6 +1590,8 @@ patternProperties: description: Zealz "^zeitec,.*": description: ZEITEC Semiconductor Co., LTD. + "^zhihe,.*": + description: Zhihe Computing Limited "^zidoo,.*": description: Shenzhen Zidoo Technology Co., Ltd. "^zii,.*": From cba24abd793de026504a811f73b7a756f4cb8911 Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Jul 2026 09:15:18 +0800 Subject: [PATCH 02/17] riscv: add ARCH_ZHIHE Kconfig option Introduce the ARCH_ZHIHE platform Kconfig symbol to enable support for ZhiHe SoCs. Signed-off-by: Zhiguo Zhu --- arch/riscv/Kconfig.socs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs index 02adfcb446e23..31209d24d8633 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -83,6 +83,16 @@ config ARCH_ULTRARISC config ARCH_VIRT def_bool SOC_VIRT +config ARCH_ZHIHE + bool "ZhiHe SoCs" + select CLOCKSOURCE_VALIDATE_LAST_CYCLE + help + This enables support for ZhiHe SoC platform hardware. + + ZhiHe SoCs are RISC-V based application processors with + integrated peripherals including clock controllers, power + domains, and reset controllers. + config SOC_VIRT bool "QEMU Virt Machine" select CLINT_TIMER if RISCV_M_MODE From 45e393546501e9ff66b9be61fb85c2636070dbd1 Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Jul 2026 14:56:08 +0800 Subject: [PATCH 03/17] dt-bindings: add ZhiHe A210 header files Add dt-bindings header files for the ZhiHe A210 SoC: - clock/a210-clock.h: clock IDs - reset/a210-reset.h: reset IDs - power/a210-power.h: power domain IDs - iopmp/a210-iopmp.h: IOPMP IDs These headers are referenced by both device tree sources and drivers. Signed-off-by: Zhiguo Zhu --- include/dt-bindings/clock/a210-clock.h | 615 +++++++++++++++++++++++++ include/dt-bindings/iopmp/a210-iopmp.h | 94 ++++ include/dt-bindings/power/a210-power.h | 42 ++ include/dt-bindings/reset/a210-reset.h | 352 ++++++++++++++ 4 files changed, 1103 insertions(+) create mode 100644 include/dt-bindings/clock/a210-clock.h create mode 100644 include/dt-bindings/iopmp/a210-iopmp.h create mode 100644 include/dt-bindings/power/a210-power.h create mode 100644 include/dt-bindings/reset/a210-reset.h diff --git a/include/dt-bindings/clock/a210-clock.h b/include/dt-bindings/clock/a210-clock.h new file mode 100644 index 0000000000000..5801d7c712d88 --- /dev/null +++ b/include/dt-bindings/clock/a210-clock.h @@ -0,0 +1,615 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +#ifndef _A210_CLK_H +#define _A210_CLK_H + +// PLL_WRAP +#define AUDIO0_PLL_FOUTVCO 0 +#define AUDIO0_PLL_FOUTPOSTDIV 1 +#define AUDIO0_PLL_FOUT2 2 +#define AUDIO1_PLL_FOUTVCO 3 +#define AUDIO1_PLL_FOUTPOSTDIV 4 +#define AUDIO1_PLL_FOUT2 5 +#define GMAC_PLL_FOUTVCO 6 +#define GMAC_PLL_FOUTPOSTDIV 7 +#define GMAC_PLL_FOUT1PH0 8 +#define DVFS_PLL_FOUTVCO 9 +#define DPU0_PLL_FOUTPOSTDIV 10 +#define DPU1_PLL_FOUTVCO 11 +#define DPU1_PLL_FOUTPOSTDIV 12 +#define DPU2_PLL_FOUTVCO 13 +#define DPU2_PLL_FOUTPOSTDIV 14 +#define VIDEO_PLL_FOUTVCO 15 +#define VIDEO_PLL_FOUTPOSTDIV 16 +#define VIDEO_PLL_FOUT1PH0 17 +#define VIDEO_PLL_FOUT3 18 +#define TEE_PLL_FOUTVCO 19 +// TOP_CRG +#define IOMMU_PTW_ACLK_DIV 20 +#define NOC_CCLK_DIV 21 +#define NOC_CCLK_MUX 22 +#define TOP_CFG_ACLK_DIV 23 +#define TOP_PCLK_DIV 24 +#define TOP_CPU_BAK_PLL0_CLK_DIV4 25 +#define TOP_CPUSYS_PIC_CLK_DIV 26 +#define TOP_CPU_DDR1_ACLK_MUX 27 +#define TOP_CPU_DDR0_ACLK_MUX 28 +#define TOP_CPU_BAK_PLL0_CLK_MUX0 29 +#define TOP_CPU_BAK_PLL0_CLK_DIV0 30 +#define TOP_CPU_BAK_PLL0_CLK_DIV1 31 +#define TOP_CPU_BAK_PLL0_CLK_DIV3 32 +#define TOP_CPUSYS_PIC_CLK_MUX 33 +#define TOP_CPU_BAK_PLL0_CLK_MUX 34 +#define TOP_CPU_BAK_PLL1_CLK_DIV1 35 +#define TOP_CPUSYS_BUS_CLK_DIV 36 +#define TOP_CPUSYS_BUS_CLK_MUX 37 +#define TOP_CPU_BAK_PLL1_CLK_DIV0 38 +#define TOP_CPU_BAK_PLL1_CLK_MUX0 39 +#define TOP_CPU_BAK_PLL1_CLK_DIV3 40 +#define TOP_CPU_BAK_PLL1_CLK_MUX 41 +#define TOP_D2D_REF_CLK_MUX 42 +#define TOP_D2D_SCAN_CLK0_DIV 43 +#define TOP_D2D_SCAN_CLK1_DIV 44 +#define TOP_D2D_ACLK_DIV 45 +#define TOP_D2D_ACLK_MUX 46 +#define AMUX_CLK_DIV 47 +#define TOP_GPU_CORE_CLK_DIV 48 +#define TOP_GPU_CORE_CLK_MUX 49 +#define TOP_PCIE_SCAN_REF_CLK1_DIV 50 +#define TOP_PCIE_SCAN_REF_CLK0_DIV 51 +#define TOP_PCIE_AXI_M_ACLK_DIV 52 +#define TOP_PCIE_AXI_M_ACLK_MUX 53 +#define TOP_PERI_SPI_SSI_CLK0_DIV 54 +#define TOP_PERI_MST_ACLK0_DIV 55 +#define TOP_PERI_TIMER_CLK_MUX 56 +#define TOP_PERI_I2S_8CH0_SRC_CLK_MUX 57 +#define TOP_PERI_I2S_2CH0_SRC_CLK_MUX 58 +#define TOP_PERI_QSPI_SSI_CLK_MUX0 59 +#define TOP_PERI_QSPI0_SSI_CLK_DIV0 60 +#define TOP_PERI_QSPI0_SSI_CLK_DIV1 61 +#define TOP_PERI_SPI_SSI_CLK1_DIV 62 +#define TOP_PERI_HIRES_CLK0_DIV 63 +#define TOP_PERI_HIRES_CLK1_DIV 64 +#define TOP_PERI_TDM_SRC_CLK_MUX 65 +#define TOP_UART_SCLK_MUX 66 +#define TOP_PERI_I2S_2CH1_SRC_CLK_MUX 67 +#define TOP_PERI_PDM_MCLK_MUX 68 +#define TOP_PERI_I2S_2CH2_SRC_CLK_MUX 69 +#define TOP_PERI_QSPI_SSI_CLK_MUX1 70 +#define TOP_PERI_QSPI1_SSI_CLK_DIV0 71 +#define TOP_PERI_QSPI1_SSI_CLK_DIV1 72 +#define TOP_PERI_MST_CLK1_DIV 73 +#define TOP_PERI_EMMC_REF_CLK_DIV 74 +#define TOP_PERI_PDM_MCLK_DIV 75 +#define TOP_PERI_EMMC_REF_CLK_MUX 76 +#define TOP_PAD_SENSOR_VCLK_MUX1 77 +#define TOP_PAD_SENSOR_VCLK_MUX0 78 +#define TOP_PAD_SENSOR_VCLK1_DIV 79 +#define TOP_PAD_SENSOR_VCLK0_DIV 80 +#define TOP_TEE_CLK_DIV 81 +#define TOP_TEE_CLK_MUX 82 +#define TOP_USB_BUS_ACLK_DIV 83 +#define TOP_USB_DP_AUX_CLK_DIV 84 +#define TOP_VP_ACLK_MUX 85 +#define TOP_VP_ACLK_DIV 86 +#define TOP_VP_G2D_CCLK_DIV 87 +#define TOP_VP_G2D_CCLK_MUX 88 +#define TOP_VP_VDEC_CCLK_DIV 89 +#define TOP_VP_VDEC_CCLK_MUX 90 +#define TOP_VP_VENC_CCLK_DIV 91 +#define TOP_VP_VENC_CCLK_MUX 92 +#define TOP_NPU_ACLK_DIV 93 +#define TOP_NPU_ACLK_MUX 94 +#define TOP_NPU_CCLK_DIV 95 +#define TOP_NPU_CCLK_MUX 96 +#define TOP_USB_USB20_SCAN_REF_CLK_DIV 97 +#define TOP_USB_SCAN_REF_CLK3_DIV 98 +#define TOP_USB_SCAN_REF_CLK2_DIV 99 +#define TOP_USB_SCAN_REF_CLK1_DIV 100 +#define TOP_USB_SCAN_REF_CLK0_DIV 101 +#define TOP_CPU_BAK_PLL1_CLK_DIV4 102 +#define SW_TOP_PAD_SENSOR_VCLK1_EN 103 +#define SW_TOP_PAD_SENSOR_VCLK0_EN 104 +#define SW_NOC_CCLK_EN 105 +#define SW_TOP_OSC_CLK_LOGIC_EN 106 +#define SW_IOMMU_PTW_330_ACLK_EN 107 +#define SW_AMUX_660_CLK_EN 108 +#define SW_NPU_SS_CLK_EN 109 +#define SW_CPU_SS_CLK_EN 110 +#define SW_DDR_SS_CLK_EN 111 +#define SW_D2D_SS_CLK_EN 112 +#define SW_VP_SS_CLK_EN 113 +#define SW_VO_SS_CLK_EN 114 +#define SW_VI_SS_CLK_EN 115 +#define SW_PCIE_SS_CLK_EN 116 +#define SW_USB_SS_CLK_EN 117 +#define SW_PERI1_SS_CLK_EN 118 +#define SW_PERI3_SS_CLK_EN 119 +#define SW_GPU_SS_CLK_EN 120 +// CPU_SS_CLK_SYSREG +#define C908_CPU_TO_CDE_CLK_MUX 121 +#define C920_CPU_TO_CDE_CLK_MUX 122 +// CPU_SS_CPU_PLL +#define C908_PLL_FOUTVCO 123 +#define C920_PLL_FOUTVCO 124 +// GPU_SS_SYSREG +#define SW_PWR_WRAP_X2P_PCLK_EN 125 +#define SW_PWR_WRAP_SYSREG_PCLK_EN 126 +#define SW_PWR_WRAP_DFMU_PCLK_EN 127 +#define SW_PWR_WRAP_X2P_ACLK_EN 128 +#define SW_PWR_WRAP_CFG_ACLK_EN 129 +#define SW_PWR_WRAP_CFG_AAB_MST_ACLK_EN 130 +#define SW_PWR_WRAP_GPU_SYS_CLK_EN 131 +#define SW_PWR_WRAP_MEMIF_AAB_SLV_CORE_CLK_EN 132 +#define SW_PWR_WRAP_DFMU_CORE_CLK_EN 133 +#define SW_PWR_WRAP_GPU_CORE_CLK_EN 134 +// GPU_SS_TOP_SYSREG +#define SW_TOP_CFG_AAB_SLV_ACLK_EN 135 +#define SW_TOP_X2P_PCLK_EN 136 +#define SW_TOP_SYSREG_PCLK_EN 137 +#define SW_TOP_X2P_ACLK_EN 138 +#define SW_TOP_CFG_ACLK_EN 139 +#define SW_TOP_AFENCE_ACLK_EN 140 +#define SW_MEMIF_AAB_MST_BUS_CLK_EN 141 +// NPU_CRG +#define NPU_CCLK_BUF_CDE_RATIO 142 +#define NPU_CCLK_BUF_CDE_MUX 143 +#define NPU_ACLK_BUF_CDE_RATIO 144 +#define NPU_ACLK_BUF_CDE_MUX 145 +#define SW_DROOP_PCLK_EN 146 +#define SW_DROOP_CLK_EN 147 +#define SW_DROOP_CCTRL_PCLK_EN 148 +#define SW_DROOP_CCTRL_CLK_EN 149 +#define SW_SEMA_PCLK_EN 150 +#define SW_SEMA_ACLK_EN 151 +#define SW_NPU_X2P_ACLK_EN 152 +#define SW_NPU_X2H_ACLK_EN 153 +#define SW_NPU_PTW_CCU_PCLK_EN 154 +#define SW_NPU_PTW_CCU_CLK_EN 155 +#define SW_NPU_PCTRL_PCLK_EN 156 +#define SW_NPU_PCTRL_EN 157 +#define SW_NPU_LPE_C_PCLK_EN 158 +#define SW_NPU_LPE_C_CLK_EN 159 +#define SW_NPU_LPC_C_CLK_EN 160 +#define SW_NPU_IP_HCLK_EN 161 +#define SW_NPU_IP_CCLK_EN 162 +#define SW_NPU_IP_ACLK_EN 163 +#define SW_NPU_DFMU_PTWCLK_EN 164 +#define SW_NPU_DFMU_PCLK_EN 165 +#define SW_NPU_CLK_CALC_EN 166 +#define SW_NPU_AXI_M2S1_ACLK_EN 167 +#define SW_NPU_AXI_CCU_PCLK_EN 168 +#define SW_NPU_AXI_CCU_CLK_EN 169 +#define SW_NPU_AXI_ACLK_EN 170 +#define SW_NPU_AFENCE_EN 171 +#define SW_NPU_AAB_MST_ACLK_EN 172 +#define SW_DFMU_ACLK_EN 173 +// NPU_TOP_CRG +#define SW_NPUSS_AAB_SLV_CLK_EN 174 +#define SW_NPUSS_FENCE_CLK_EN 175 +// DDR0_SYSREG +#define DDR0_PHY_DFICLK_EN 176 +#define DDR0_DDRC_ACLK_EN 177 +#define DDR0_DDRC_CCLK_EN 178 +#define DDR0_SBR_CLK_EN 179 +// DDR1_SYSREG +#define DDR1_PHY_DFICLK_EN 180 +#define DDR1_DDRC_ACLK_EN 181 +#define DDR1_DDRC_CCLK_EN 182 +#define DDR1_SBR_CLK_EN 183 +// SLC_DUAL_SYSREG +#define DDR_PLL_FOUTVCO 184 +#define DDR_PLL_FOUTPOSTDIV 185 +#define DDR_PLL_FOUT1PH0 186 +#define DDR_PLL_FOUT2 187 +#define DDR_PLL_FOUT4 188 +#define DDR_PLL_CLK_SEL 505 +#define DDR_PLL_CLK_EN 506 +#define DDR_CBUS2DDR_ACLK0 507 +#define DDR_CBUS2DDR_ACLK1 508 +// D2D_CRG_REG_T +#define D2D_SS_CTRL0_CLK_EN 189 +#define D2D_SS_CTRL1_CLK_EN 190 +// PCIE_CPR +#define AXI4_PCIE_MST_PCLK_EN 191 +#define AXI4_PCIE_MST_ACLK_EN 192 +#define X2X_PERI3_MST_ACLK_EN 193 +#define X2X_PERI3_SLV_ACLK_EN 194 +#define PCIE_SS_DFMU_ACLK_EN 195 +#define PCIE_SS_DFMU_IOMMU_PTW_ACLK_EN 196 +#define PCIE_SS_DFMU_PCLK_EN 197 +#define E16PHY_PCLK_EN 198 +#define SATA_MST_AFENCE_ACLK_EN 199 +#define SATA_SLV_AFENCE_ACLK_EN 200 +#define SATA_GEN3X2_ACLK_EN 201 +#define X2X_SATA_SLV_ACLK_EN 202 +#define X2X_SATA_MST_ACLK_EN 203 +#define SATA_RXOOB1_CLK_EN 204 +#define SATA_RXOOB0_CLK_EN 205 +#define SATA_PMALIVE_CLK_EN 206 +#define PCIE_DM_MST_AFENCE_ACLK_EN 207 +#define PCIE_DM_SLV_AFENCE_ACLK_EN 208 +#define PCIE_DM_GEN3X4_AUX_CLK_EN 209 +#define PCIE_DM_GEN3X4_MST_ACLK_EN 210 +#define PCIE_DM_GEN3X4_PCLK_EN 211 +#define PCIE_DM_GEN3X4_SLV_ACLK_EN 212 +#define PCIE_RP_MST_AFENCE_ACLK_EN 213 +#define PCIE_RP_SLV_AFENCE_ACLK_EN 214 +#define PCIE_RP_GEN3X1_AUX_CLK_EN 215 +#define PCIE_RP_GEN3X1_MST_ACLK_EN 216 +#define PCIE_RP_GEN3X1_PCLK_EN 217 +#define PCIE_RP_GEN3X1_SLV_ACLK_EN 218 +// USB_CPR +#define USB_SS_AXI_MST_PCLK_EN 219 +#define USB_SS_AXI_MST_ACLK_EN 220 +#define USB_SS_DFMU_IOMMU_PTW_ACLK_EN 221 +#define USB_SS_DFMU_ACLK_EN 222 +#define USB_SS_DFMU_PCLK_EN 223 +#define DPTX_I2S_CLK_EN 224 +#define DPTX_IPI_CLK_EN 225 +#define DPTX_AUX_CLK_EN 226 +#define DPTX_GTC_CLK_EN 227 +#define DPTX_PCLK_EN 228 +#define USB31_SLV_AFENCE_ACLK_EN 229 +#define USB31_REF_CLK_EN 230 +#define USB31_SUSPEND_CLK_EN 231 +#define USB31_BUS_CLK_EN 232 +#define USB31_PCLK_EN 233 +#define C10PHY_SUSPEND_CLK_EN 234 +#define C10PHY_PCLK_EN 235 +#define USB2_SYSREG_PCLK_EN 236 +#define USB2_AXI_MST_ACLK_EN 237 +#define USB2_AHB_SLV_HCLK_EN 238 +#define USB2_H2P_HCLK_EN 239 +#define USB2_SLV_AFENCE_ACLK_EN 240 +#define USB2_X2H_ACLK_EN 241 +#define USB2_X2H_HCLK_EN 242 +#define USB2_WRAP_A2X1_ACLK_EN 243 +#define USB2_WRAP_A2X1_HCLK_EN 244 +#define USB2_WRAP_A2X0_ACLK_EN 245 +#define USB2_WRAP_A2X0_HCLK_EN 246 +#define USB2_WRAP1_HCLK_EN 247 +#define USB2_WRAP0_HCLK_EN 248 +#define USB_SS_PERI2_SLV_AFENCE_ACLK_EN 249 +#define USB_SS_PERI2_CFG_ACLK_EN 250 +// VI_SYSREG +#define VI_DW_SCLK_EN 251 +#define VI_VSE_CLK_EN 252 +#define VI_DWE_CLK_EN 253 +#define VI_DW200_ACLK_EN 254 +#define VI_DW200_HCLK_EN 255 +#define VI_DECOMP_CLK_EN 256 +#define VI_COMP1_CLK_EN 257 +#define VI_COMP0_CLK_EN 258 +#define VI_VSEOUT_CLK_EN 259 +#define VI_DECOUT_CLK_EN 260 +#define VI_ISPOUT_CLK_EN 261 +#define VI_COMP_ACLK_EN 262 +#define VI_COMP_PCLK_EN 263 +#define VI_ISP_CLK_EN 264 +#define VI_VIPRE_ACLK_EN 265 +#define VI_VIPRE_SCLK_EN 266 +#define VI_VIPRE_I1_PIXCLK_EN 267 +#define VI_VIPRE_I0_PIXCLK_EN 268 +#define VI_VIPRE_PCLK_EN 269 +#define VI_MIPI1_CSI1_PIXCLK_EN 270 +#define VI_MIPI1_CSI0_PIXCLK_EN 271 +#define VI_MIPI1B_CFGCLK_EN 272 +#define VI_MIPI1A_CFGCLK_EN 273 +#define VI_MIPI1CSI1_PCLK_EN 274 +#define VI_MIPI1CSI0_PCLK_EN 275 +#define VI_MIPI0_CSI1_PIXCLK_EN 276 +#define VI_MIPI0_CSI0_PIXCLK_EN 277 +#define VI_MIPI0B_CFGCLK_EN 278 +#define VI_MIPI0A_CFGCLK_EN 279 +#define VI_MIPI0CSI1_PCLK_EN 280 +#define VI_MIPI0CSI0_PCLK_EN 281 +#define VI_REC_ACLK_EN 282 +#define VI_REC_PCLK_EN 283 +#define VI_FENCE_ACLK_EN 284 +#define VI_MIPI1CSI1_FPCLK_EN 285 +#define VI_MIPI1CSI0_FPCLK_EN 286 +#define VI_MIPI0CSI1_FPCLK_EN 287 +#define VI_MIPI0CSI0_FPCLK_EN 288 +#define VI_X2H2_CLK_EN 289 +#define VI_X2H1_CLK_EN 290 +#define VI_X2H0_CLK_EN 291 +#define VI_ARB_ACLK_EN 292 +#define VI_ARB_PCLK_EN 293 +#define VI_PTW_ACLK_EN 294 +#define VI_DFMU_ACLK_EN 295 +#define VI_DFMU_PCLK_EN 296 +#define VI_PRE_ISP_CORE_CLK_DIV_EN 297 +#define VI_PRE_ISP_IF_CLK_DIV_EN 298 +#define VI_PRE_MIPI1_PIXCLK_DIV_EN 299 +#define VI_PRE_MIPI0_PIXCLK_DIV_EN 300 +#define VI_ISP_IF_REF_SWITCH_SEL 301 +#define VI_MIPI1_PIX_REF_SWITCH_SEL 302 +#define VI_MIPI0_PIX_REF_SWITCH_SEL 303 +#define VI_PRE_ISP_CORE_CLK_DIV_NUM 304 +#define VI_PRE_ISP_IF_CLK_DIV_NUM 305 +#define VI_PRE_MIPI1_PIXCLK_DIV_NUM 306 +#define VI_PRE_MIPI0_PIXCLK_DIV_NUM 307 +#define VI_PRE_DECOMP_CLK_DIV_EN 308 +#define VI_PRE_COMP_CLK_DIV_EN 309 +#define VI_PRE_DWE_CLK_DIV_EN 310 +#define VI_PRE_VSE_CLK_DIV_EN 311 +#define VI_PRE_AXI_CLK_DIV_EN 312 +#define VI_PRE_DECOMP_CLK_DIV_NUM 313 +#define VI_PRE_COMP_CLK_DIV_NUM 314 +#define VI_PRE_DWE_CLK_DIV_NUM 315 +#define VI_PRE_VSE_CLK_DIV_NUM 316 +#define VI_PRE_AXI_CLK_DIV_NUM 317 +// VO_SYSREG +#define VO_X2H1_CLK_EN 318 +#define VO_X2H0_CLK_EN 319 +#define VO_PTW_ACLK_EN 320 +#define VO_DFMU_ACLK_EN 321 +#define VO_DFMU_PCLK_EN 322 +#define VO_ARB_ACLK_EN 323 +#define VO_ARB_PCLK_EN 324 +#define VO_DECOMP_ACLK_EN 325 +#define VO_DECOMP1_CLK_EN 326 +#define VO_DECOMP0_CLK_EN 327 +#define VO_DECOMP_PCLK_EN 328 +#define VO_MIPI_CFGCLK_EN 329 +#define VO_MIPI_PCLK_EN 330 +#define VO_HDMI_SFRCLK_EN 331 +#define VO_CEC_CLK_EN 332 +#define VO_I2S_CLK_EN 333 +#define VO_HDMI_PCLK_EN 334 +#define VO_AUXDISP_ACLK_EN 335 +#define VO_AUXDISP_PCLK_EN 336 +#define VO_CH2_PIXCLK_EN 337 +#define VO_DPU_ACLK_EN 338 +#define VO_DPUC_CLK_EN 339 +#define VO_DPU_HCLK_EN 340 +#define VO_CH1_PIXCLK_EN 341 +#define VO_CH0_PIXCLK_EN 342 +#define VO_PLL2_DIV_EN 343 +#define VO_PLL2_DIV_NUM 344 +#define VO_PLL1_DIV_EN 345 +#define VO_PLL1_DIV_NUM 346 +#define VO_PLL0_DIV_EN 347 +#define VO_PLL0_DIV_NUM 348 +#define VO_DECOMP_DIV_EN 349 +#define VO_DECOMP_DIV_NUM 350 +#define VO_DPUC_DIV_EN 351 +#define VO_DPUC_DIV_NUM 352 +#define VO_ACLK_DIV_EN 353 +#define VO_ACLK_DIV_NUM 354 +// VP_SYSREG +#define VP_DECOMP_EXTPCLK_EN 355 +#define VP_COMP_EXTPCLK_EN 356 +#define VP_VENC_RS_ACLK_EN 357 +#define VP_VDEC_RS_ACLK_EN 358 +#define VP_ARB_ACLK_EN 359 +#define VP_ARB_PCLK_EN 360 +#define VP_PTW_ACLK_EN 361 +#define VP_DFMU_ACLK_EN 362 +#define VP_DFMU_PCLK_EN 363 +#define VP_DECOMP_ACLK_EN 364 +#define VP_DECOMP_CCLK_EN 365 +#define VP_DECOMP_PCLK_EN 366 +#define VP_COMP_ACLK_EN 367 +#define VP_COMP_CCLK_EN 368 +#define VP_COMP_PCLK_EN 369 +#define VP_G2D_ACLK_EN 370 +#define VP_G2D_CCLK_EN 371 +#define VP_G2D_PCLK_EN 372 +#define VP_VENC_ACLK_EN 373 +#define VP_VENC_CCLK_EN 374 +#define VP_VENC_PCLK_EN 375 +#define VP_VDEC_ACLK_EN 376 +#define VP_VDEC_CCLK_EN 377 +#define VP_VDEC_PCLK_EN 378 +#define VP_DECOMP_DIV_EN 379 +#define VP_DECOMP_DIV_NUM 380 +#define VP_COMP_DIV_EN 381 +#define VP_COMP_DIV_NUM 382 +// PERI0_SYSREG +#define PERI0_MBOX1_PCLK_EN 383 +#define PERI0_MBOX0_PCLK_EN 384 +#define PERI0_WDT0_PCLK_EN 385 +#define PERI0_TIMER1_PCLK_EN 386 +#define PERI0_TIMER1_CCLK_EN 387 +#define PERI0_TIMER0_PCLK_EN 388 +#define PERI0_TIMER0_CCLK_EN 389 +// PERI1_SYSREG +#define PERI1_UART3_SCLK_EN 390 +#define PERI1_UART3_PCLK_EN 391 +#define PERI1_UART2_SCLK_EN 392 +#define PERI1_UART2_PCLK_EN 393 +#define PERI1_UART1_SCLK_EN 394 +#define PERI1_UART1_PCLK_EN 395 +#define PERI1_UART0_SCLK_EN 396 +#define PERI1_UART0_PCLK_EN 397 +#define PERI1_SPI0_SSI_CLK_EN 398 +#define PERI1_SPI0_PCLK_EN 399 +#define PERI1_QSPI0_SSI_CLK_EN 400 +#define PERI1_QSPI0_PCLK_EN 401 +#define PERI1_PWM0_PCLK_EN 402 +#define PERI1_PWM0_CCLK_EN 403 +#define PERI1_MST_BUS_PCLK_EN 404 +#define PERI1_MST_BUS_ACLK_EN 405 +#define PERI1_I2S0_SRC_CLK_EN 406 +#define PERI1_I2S0_PCLK_EN 407 +#define PERI1_I2C2_PCLK_EN 408 +#define PERI1_I2C2_IC_CLK_EN 409 +#define PERI1_I2C1_PCLK_EN 410 +#define PERI1_I2C1_IC_CLK_EN 411 +#define PERI1_I2C0_PCLK_EN 412 +#define PERI1_I2C0_IC_CLK_EN 413 +#define PERI1_GPIO1_PCLK_EN 414 +#define PERI1_GPIO1_DBCLK_EN 415 +#define PERI1_GPIO0_PCLK_EN 416 +#define PERI1_GPIO0_DBCLK_EN 417 +#define PERI1_GMAC1_HCLK_EN 418 +#define PERI1_GMAC1_ACLK_EN 419 +#define PERI1_GMAC0_HCLK_EN 420 +#define PERI1_GMAC0_ACLK_EN 421 +// PERI2_SYSREG +#define PERI2_I2S3_PCLK_EN 422 +#define PERI2_I2S3_SRC_CLK_EN 423 +#define PERI2_I2S2_PCLK_EN 424 +#define PERI2_I2S2_SRC_CLK_EN 425 +#define PERI2_I2S1_PCLK_EN 426 +#define PERI2_I2S1_SRC_CLK_EN 427 +#define PERI2_I2C7_IC_CLK_EN 428 +#define PERI2_I2C7_PCLK_EN 429 +#define PERI2_I2C6_IC_CLK_EN 430 +#define PERI2_I2C6_PCLK_EN 431 +#define PERI2_I2C5_IC_CLK_EN 432 +#define PERI2_I2C5_PCLK_EN 433 +#define PERI2_I2C4_IC_CLK_EN 434 +#define PERI2_I2C4_PCLK_EN 435 +#define PERI2_I2C3_IC_CLK_EN 436 +#define PERI2_I2C3_PCLK_EN 437 +#define PERI2_GPIO3_DBCLK_EN 438 +#define PERI2_GPIO3_PCLK_EN 439 +#define PERI2_PAD_CTRL_PCLK_EN 440 +#define PERI2_UART6_PCLK_EN 441 +#define PERI2_UART5_PCLK_EN 442 +#define PERI2_UART4_PCLK_EN 443 +#define PERI2_SPI1_PCLK_EN 444 +#define PERI2_GPIO2_PCLK_EN 445 +#define PERI2_CAN2_PCLK_EN 446 +#define PERI2_UART6_SCLK_EN 447 +#define PERI2_UART5_SCLK_EN 448 +#define PERI2_UART4_SCLK_EN 449 +#define PERI2_SPI1_SSI_CLK_EN 450 +#define PERI2_GPIO2_DBCLK_EN 451 +#define PERI2_CAN2_OSC_CLK_EN 452 +#define PERI2_CAN2_HIRES_CLK_EN 453 +#define PERI2_QSPI1_PCLK_EN 454 +#define PERI2_QSPI1_SSI_CLK_EN 455 +#define PERI2_UART9_PCLK_EN 456 +#define PERI2_UART9_SCLK_EN 457 +#define PERI2_UART8_PCLK_EN 458 +#define PERI2_UART8_SCLK_EN 459 +#define PERI2_UART7_PCLK_EN 460 +#define PERI2_UART7_SCLK_EN 461 +#define PERI2_PWM2_PCLK_EN 462 +#define PERI2_PWM2_CCLK_EN 463 +#define PERI2_PWM1_PCLK_EN 464 +#define PERI2_PWM1_CCLK_EN 465 +// PERI3_SYSREG +#define PERI3_PAD_CTRL_PCLK_EN 466 +#define PERI3_GPIO4_PCLK_EN 467 +#define PERI3_GPIO4_DBCLK_EN 468 +#define CLKCTRL_PERI3_TEE_H2H_SHCLKEN 469 +#define CLKCTRL_PERI3_TEE_H2H_MHCLKEN 470 +#define PERI3_TEE_X2X_ACLK_S_EN 471 +#define PERI3_ADC_PCLK_EN 472 +#define AXI_PERI3_MST_PCLK_EN 473 +#define AXI_PERI3_MST_ACLK_EN 474 +#define PERI3_SDIO_X2X_ACLK_S_EN 475 +#define PERI3_SDIO_X2X_ACLK_M_EN 476 +#define PERI3_SDIO_OSC_CLK_EN 477 +#define PERI3_SDIO_HCLK_EN 478 +#define PERI3_EMMC_X2X_ACLK_S_EN 479 +#define PERI3_EMMC_X2X_ACLK_M_EN 480 +#define PERI3_EMMC_OSC_CLK_EN 481 +#define PERI3_EMMC_HCLK_EN 482 +#define PERI3_EMMC_ACLK_EN 483 +#define PERI3_EMMC_SDIO_REF_CLK_CG_EN 484 +#define PERI3_DMAC_HCLK_EN 485 +#define PERI3_DMAC_ACLK_EN 486 +// TEE_CRG +#define TEE_PCLK_CDE_RATIO 487 +#define TEE_AHB2_TEESYS_CLKEN 488 +#define TEE_APB3_TEESYS_CLKEN 489 +#define TEE_AXI4_TEESYS_CLKEN 490 +#define TEE_X2P_TEESYS_CLKEN 491 +#define TEE_EIP120SI_CLKEN 492 +#define TEE_EIP120SII_CLKEN 493 +#define TEE_EIP120SIII_CLKEN 494 +#define TEE_EIP150B_CLKEN 495 +#define TEE_DMAC_CLKEN 496 +#define TEE_DS_CLKEN 497 +#define TEE_OCRAM_CLKEN 498 +#define TEE_EFUSE_CLKEN 499 +#define TEE_KEYRAM_CLKEN 500 + +#define CLK_DUMMY 501 +#define OSC_32K 502 +#define OSC_24M 503 +#define RC_24M 504 + +#define TOP_PLL_REF_CLK 509 +#define AON_OSC_CLK_PHY 510 +#define AON_OSC_CLK_LOGIC 511 +#define PLL_OSC_CLK 512 +#define D2D_PHY_REF_CLK_100M 513 +#define D2D_PHY_SCAN_CLK2 514 +#define TOP_PERI_TIMER_CLK_100M 515 +#define PERI1_UART_SCLK 516 +#define PERI2_UART_SCLK 517 +#define UART_SCLK_100M 518 +#define GPU_TOP_SYS_CLK 519 +#define GPU_PCLK_CDT 520 +#define PCIE_SS_APB_CLK 521 +#define USB_SS_GTC_CLK 522 +#define USB_SS_PAD_OSC_CLK_1M 523 +#define USB20_BUS_CLK 524 +#define USB20_CORE_CLK 525 +#define VI_PCLK 526 +#define VO_PCLK 527 +#define AON_RTC_CLK 528 +#define PERI1_PWM_CLK 529 +#define PERI2_PWM_CLK 530 +#define I2C_IC_CLK 531 +#define PERI3_SDIO_ACLK_EN 532 + +#define PERI1_ZGMAC_X2X_ACLK_EN 533 +#define PERI1_GMAC2_HCLK_EN 534 +#define PERI1_GMAC2_ACLK_EN 535 +#define PERI1_X2H_GMAC2_HCLK_EN 536 +#define PERI1_X2H_GMAC2_ACLK_EN 537 +#define PERI1_CHIP_DBG_PCLK_EN 538 +#define PERI1_CHIP_DBG_CCLK_EN 539 +#define PERI1_CHIP_DBG_ACLK_EN 540 +#define PERI1_TDM0_SCLK_EN 541 +#define PERI1_TDM0_PCLK_EN 542 +#define PERI1_PDM0_PCLK_EN 543 +#define PERI1_PDM0_MCLK_EN 544 +#define PERI1_CAN1_PCLK_EN 545 +#define PERI1_CAN1_OSC_CLK_EN 546 +#define PERI1_CAN1_HIRES_CLK_EN 547 +#define PERI1_CAN0_PCLK_EN 548 +#define PERI1_CAN0_OSC_CLK_EN 549 +#define PERI1_CAN0_HIRES_CLK_EN 550 +#define PERI1_PAD_CTRL_PCLK_EN 551 +#define PERI1_DFMU_PTW_ACLK_EN 552 +#define PERI1_DFMU_PCLK_EN 553 +#define PERI1_DFMU_ACLK_EN 554 +#define PERI1_X2H_GMAC1_HCLK_EN 555 +#define PERI1_X2H_GMAC1_ACLK_EN 556 +#define PERI1_X2H_GMAC0_HCLK_EN 557 +#define PERI1_X2H_GMAC0_ACLK_EN 558 +#define DPU0_PLL_FOUTVCO 559 + +#define PERI3_EMMC_SDIO_REF_CLK 560 + +#define VO_MIPI_PIXCLK 561 +#define VO_HDMI_PIXCLK 562 +#define VO_DPTX_PIXCLK 563 + +#define TOP_CPUSYS_CFG_ACLK_DIV 564 +#define TOP_CPUSYS_COM_APB_CLK_DIV 565 +#define TOP_CPUSYS_APB_CLK_DIV 566 + +#define VI_MISC_CTRL_H0CLK_CLK_EN 567 +#define VI_MISC_CTRL_H1CLK_CLK_EN 568 +#define VI_MISC_CTRL_ISP_ACLK_CLK_EN 569 +#define VI_MISC_CTRL_ISP_SCLK_CLK0_EN 570 +#define VI_MISC_CTRL_ISP_SCLK_CLK1_EN 571 +#define VI_MISC_CTRL_ISP_SCLK_CLK2_EN 572 +#define VI_MISC_CTRL_ISP_SCLK_CLK3_EN 573 +#define VI_MISC_CTRL_ISP_CORE_CLK_EN 574 +#define VI_MISC_CTRL_ISP_FLEXA_CLK_EN 575 +#define VI_MISC_CTRL_ISP_MCM_CLK_EN 576 +#define VI_MISC_CTRL_BUS_CLK_GT_DISABLE 577 + +#define CLK_END 578 + +#endif diff --git a/include/dt-bindings/iopmp/a210-iopmp.h b/include/dt-bindings/iopmp/a210-iopmp.h new file mode 100644 index 0000000000000..c963a5ad4c136 --- /dev/null +++ b/include/dt-bindings/iopmp/a210-iopmp.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * *** IMPORTANT *** + * This file is not only included from C-code but also from devicetree source + * files. As such this file MUST only contain comments and defines. + * + * Copyright (c) 2025 Xuliang Lin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef _ZH_DTS_IOPMP_H +#define _ZH_DTS_IOPMP_H + + +/* PERI1_SS */ +#define IOPMP_DEV_IOMMU_PTW 0x00 +#define IOPMP_DEV_PERI1_DFMU 0x01 +#define IOPMP_DEV_DMAC_AP 0x02 +#define IOPMP_DEV_GMAC_0 0x03 +#define IOPMP_DEV_GMAC_1 0x04 +#define IOPMP_DEV_GMAC_2 0x05 +#define IOPMP_DEV_SD 0x06 +#define IOPMP_DEV_EMMC 0x08 +#define IOPMP_DEVICE_AON 0x37 +#define IOPMP_DEVICE_CHIP_DBG 0x3e + +/* USB_SS */ +#define IOPMP_DEV_USB_DFMU 0x09 +#define IOPMP_DEV_USB3_0 0x0a +#define IOPMP_DEV_USB2_1 0x0b +#define IOPMP_DEV_USB2_2 0x0c + +/* PCIE_SS */ +#define IOPMP_DEV_PCIE_DFMU 0x10 +#define IOPMP_DEV_PCIE_0 0x11 +#define IOPMP_DEV_PCIE_1 0x12 +#define IOPMP_DEV_SATA_0 0x14 +#define IOPMP_DEV_TEE_EIP120SI 0x16 +#define IOPMP_DEV_TEE_EIP120SII 0x17 +#define IOPMP_DEV_TEE_EIP120SIII 0x18 +#define IOPMP_DEV_TEE_DMAC 0x19 + +//D2D RX DFMU device id lists +#define IOPMP_DEV_D2D_RX 0x1A + +/* VI_SS */ +#define IOPMP_DEV_VI_DFMU 0x20 +#define IOPMP_DEV_ISP 0x21 +#define IOPMP_DEV_VIPRE 0x22 +#define IOPMP_DEV_DW200 0x23 +#define IOPMP_DEV_VI_COMP_DECOMP 0x24 + +/* VP_SS */ +#define IOPMP_DEV_VP_DFMU 0x25 +#define IOPMP_DEV_VENC 0x26 +#define IOPMP_DEV_VDEC 0x27 +#define IOPMP_DEV_G2D 0x28 + +/* VO_SS */ +#define IOPMP_DEV_VO_DFMU 0x2b +#define IOPMP_DEV_DISPLAY_0 0x2c +#define IOPMP_DEV_DISPLAY_1 0x2d +#define IOPMP_DEV_AUXDISP 0x2e + +#define IOPMP_DEV_PIP_REC 0x2f + +//GPUSS DFMU device id lists +#define IOPMP_DEV_GPU_SS 0x33 +#define IOPMP_DEV_GPU 0x34 + +/* NPU_SS */ +#define IOPMP_DEV_NPU_DFMU 0x30 +#define IOPMP_DEV_NPU 0x31 + +//CPU SS DFMU device id lists +#define IOPMP_DEV_REMOTE_CPU 0x3A + +/* IOMMU IOPMP DEVCIE ID*/ +#define IOPMP_DEV_IOMMU_START 0x40 +#define IOPMP_DEV_VP_IOMMU (IOPMP_DEV_IOMMU_START + 0) +#define IOPMP_DEV_VI_IOMMU (IOPMP_DEV_IOMMU_START + 1) +#define IOPMP_DEV_NPU_IOMMU (IOPMP_DEV_IOMMU_START + 2) +#define IOPMP_DEV_VO_IOMMU (IOPMP_DEV_IOMMU_START + 3) +#define IOPMP_DEV_PERI1_IOMMU (IOPMP_DEV_IOMMU_START + 4) +#define IOPMP_DEV_PCIE_IOMMU (IOPMP_DEV_IOMMU_START + 5) +#define IOPMP_DEV_USB_IOMMU (IOPMP_DEV_IOMMU_START + 6) +#define IOPMP_DEV_GPU_IOMMU (IOPMP_DEV_IOMMU_START + 7) +#define IOPMP_DEV_D2D_RX_IOMMU (IOPMP_DEV_IOMMU_START + 8) +#define IOPMP_DEV_D2D_SS_IOMMU (IOPMP_DEV_IOMMU_START + 9) + +#endif diff --git a/include/dt-bindings/power/a210-power.h b/include/dt-bindings/power/a210-power.h new file mode 100644 index 0000000000000..1a5f432d22554 --- /dev/null +++ b/include/dt-bindings/power/a210-power.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#ifndef _DT_BINDINGS_POWER_A210_H_ +#define _DT_BINDINGS_POWER_A210_H_ + +#define A210_PD_GPU 0 +#define A210_PD_NPU_WRAPPER 1 +#define A210_PD_NPU_IP 2 +#define A210_PD_D2D 3 +#define A210_PD_PCIE0 4 +#define A210_PD_PCIE1 5 +#define A210_PD_SATA 6 +#define A210_PD_USB 7 +#define A210_PD_VI_WRAP 8 +#define A210_PD_VI_ISP 9 +#define A210_PD_VO 10 +#define A210_PD_VP_WRAP 11 +#define A210_PD_VENC 12 +#define A210_PD_VDEC 13 +#define A210_PD_TOP 14 +#define A210_PD_PERI0 15 +#define A210_PD_PERI1 16 +#define A210_PD_PERI2 17 +#define A210_PD_PERI3 18 +#define A210_PD_CAN 19 +#define A210_PD_SPI 20 +#define A210_PD_QSPI 21 +#define A210_PD_UART 22 +#define A210_PD_PWM 23 +#define A210_PD_EMMC 24 +#define A210_PD_SDIO 25 +#define A210_PD_DMAC 26 + +#define A210_POWER_DOMAINS_MAX 27 + +#define CCU_MODE_GATING 0 +#define CCU_MODE_SCALING 1 + +#endif /* _DT_BINDINGS_POWER_A210_H_ */ diff --git a/include/dt-bindings/reset/a210-reset.h b/include/dt-bindings/reset/a210-reset.h new file mode 100644 index 0000000000000..fad057d6072e0 --- /dev/null +++ b/include/dt-bindings/reset/a210-reset.h @@ -0,0 +1,352 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#ifndef DT_BINDING_RESET_A210_H +#define DT_BINDING_RESET_A210_H + +#define RST_SIGNAL_MASK 0xFF + +#define VP_VDEC_PRST 0x000 +#define VP_VDEC_CRST 0x001 +#define VP_VDEC_ARST 0x002 +#define VP_VENC_PRST 0x003 +#define VP_VENC_CRST 0x004 +#define VP_VENC_ARST 0x005 +#define VP_G2D_PRST 0x006 +#define VP_G2D_CRST 0x007 +#define VP_G2D_ARST 0x008 +#define VP_COMP_PRST 0x009 +#define VP_COMP_CRST 0x00A +#define VP_COMP_ARST 0x00B +#define VP_DECOMP_PRST 0x00C +#define VP_DECOMP_CRST 0x00D +#define VP_DECOMP_ARST 0x00E +#define VP_DFMU_PRST 0x00F +#define VP_DFMU_ARST 0x010 +#define VP_ARB_PRST 0x011 +#define VP_ARB_ARST 0x012 +#define VP_VDEC_RS_ARST 0x013 +#define VP_VENC_RS_ARST 0x014 +#define VP_COMP_EXTPRST 0x015 +#define VP_DECOMP_EXTPRST 0x016 + +#define VI_MIPI0_CSI0_PRST 0x100 +#define VI_MIPI0_CSI1_PRST 0x101 +#define VI_MIPI0_FIFO_RST 0x102 +#define VI_MIPI1_CSI0_PRST 0x103 +#define VI_MIPI1_CSI1_PRST 0x104 +#define VI_MIPI1_FIFO_RST 0x105 +#define VI_VIPRE_PRST 0x106 +#define VI_VIPRE_I0_PIX_RST 0x107 +#define VI_VIPRE_I1_PIX_RST 0x108 +#define VI_VIPRE_ISPIF_RST 0x109 +#define VI_VIPRE_ARST 0x10A +#define VI_ISP_RST 0x10B +#define VI_COMP_PRST 0x10C +#define VI_COMP_ARST 0x10D +#define VI_COMP_ISPOUT_RST 0x10E +#define VI_COMP_DECOUT_RST 0x10F +#define VI_COMP_VSEOUT_RST 0x110 +#define VI_COMP0_RST 0x111 +#define VI_COMP1_RST 0x112 +#define VI_DECOMP_RST 0x113 +#define VI_DW200_RST 0x114 +#define VI_DFMU_PRST 0x115 +#define VI_DFMU_ARST 0x116 +#define VI_ARB_PRST 0x117 +#define VI_ARB_ARST 0x118 +#define VI_X2H0_HRST 0x119 +#define VI_X2H1_HRST 0x11A +#define VI_X2H2_HRST 0x11B +#define VI_REC_PRST 0x11C +#define VI_REC_ARST 0x11D + +#define NPU_AAB_MST_RST 0x200 +#define NPU_AFENCE_RST 0x201 +#define NPU_AXI_CCU_PRST 0x202 +#define NPU_AXI_CCU_RST 0x203 +#define NPU_AXI_M2S1_RST 0x204 +#define NPU_AXI_RST 0x205 +#define NPU_CLK_CALC_RST 0x206 +#define NPU_DFMU_ARST 0x207 +#define NPU_DFMU_PRST 0x208 +#define NPU_LPC_C_RST 0x209 +#define NPU_LPE_C_PRST 0x20A +#define NPU_LPE_C_RST 0x20B +#define NPU_ARST 0x20C +#define NPU_CRST 0x20D +#define NPU_HRST 0x20E +#define NPU_PCTRL_PB_RST 0x20F +#define NPU_PCTRL_PRST 0x210 +#define NPU_PCTRL_RST 0x211 +#define NPU_PTW_CCU_PRST 0x212 +#define NPU_PTW_CCU_RST 0x213 +#define NPU_SEMA_ARST 0x214 +#define NPU_SEMA_PRST 0x215 +#define NPU_DROOP_CCTRL_PRST 0x216 +#define NPU_DROOP_CCTRL_RST 0x217 +#define NPU_X2H_RST 0x218 +#define NPU_X2P_RST 0x219 +#define NPU_LDIP_RST 0x21A +#define NPU_SRAM_RST 0x21B + +#define VO_X2H0_RST 0x300 +#define VO_X2H1_RST 0x301 +#define VO_DPU_HRST 0x302 +#define VO_DPU_CRST 0x303 +#define VO_DPU_ARST 0x304 +#define VO_AUXDISP_PRST 0x305 +#define VO_AUXDISP_PIX_RST 0x306 +#define VO_AUXDISP_ARST 0x307 +#define VO_HDMI_PRST 0x308 +#define VO_HDMI_MAIN_RST 0x309 +#define VO_MIPI_PRST 0x30A +#define VO_DECOMP_PRST 0x30B +#define VO_DECOMP0_CRST 0x30C +#define VO_DECOMP1_CRST 0x30D +#define VO_DECOMP_ARST 0x30E +#define VO_ARB_PRST 0x30F +#define VO_ARB_ARST 0x310 +#define VO_DFMU_PRST 0x311 +#define VO_DFMU_ARST 0x312 + +#define PERI0_TIMER0_CRST 0x400 +#define PERI0_TIMER0_PRST 0x401 +#define PERI0_TIMER1_CRST 0x402 +#define PERI0_TIMER1_PRST 0x403 +#define PERI0_WDT0_PRST 0x404 +#define PERI0_MBOX0_PRST 0x405 +#define PERI0_MBOX1_PRST 0x406 +#define PERI0_TIMER0_RST 0x407 +#define PERI0_TIMER1_RST 0x408 + +#define PERI1_GMAC0_ARST 0x500 +#define PERI1_GMAC0_HRST 0x501 +#define PERI1_GMAC1_ARST 0x502 +#define PERI1_GMAC1_HRST 0x503 +#define PERI1_GPIO0_DBRST 0x504 +#define PERI1_GPIO0_PRST 0x505 +#define PERI1_GPIO1_DBRST 0x506 +#define PERI1_GPIO1_PRST 0x507 +#define PERI1_I2C0_IC_RST 0x508 +#define PERI1_I2C0_PRST 0x509 +#define PERI1_I2C1_IC_RST 0x50A +#define PERI1_I2C1_PRST 0x50B +#define PERI1_I2C2_IC_RST 0x50C +#define PERI1_I2C2_PRST 0x50D +#define PERI1_I2S0_PRST 0x50E +#define PERI1_MST_BUS_ARST 0x50F +#define PERI1_MST_BUS_PRST 0x510 +#define PERI1_PWM0_CRST 0x511 +#define PERI1_PWM0_PRST 0x512 +#define PERI1_QSPI0_PRST 0x513 +#define PERI1_QSPI0_SSI_RST 0x514 +#define PERI1_SPI0_PRST 0x515 +#define PERI1_SPI0_SSI_RST 0x516 +#define PERI1_UART0_PRST 0x517 +#define PERI1_UART0_S_RST 0x518 +#define PERI1_UART1_PRST 0x519 +#define PERI1_UART1_S_RST 0x51A +#define PERI1_UART2_PRST 0x51B +#define PERI1_UART2_S_RST 0x51C +#define PERI1_UART3_PRST 0x51D +#define PERI1_UART3_S_RST 0x51E +#define PERI1_X2H_GMAC0_ARST 0x51F +#define PERI1_X2H_GMAC0_HRST 0x520 +#define PERI1_X2H_GMAC1_ARST 0x521 +#define PERI1_X2H_GMAC1_HRST 0x522 +#define PERI1_DFMU_ARESET 0x523 +#define PERI1_DFMU_PRESET 0x524 +#define PERI1_PAD_CTRL_PRST 0x525 +#define PERI1_PDM0_MRST 0x526 +#define PERI1_PDM0_PRST 0x527 +#define PERI1_TDM0_RST 0x528 +#define PERI1_CAN0_IPG_PE_RST 0x529 +#define PERI1_CAN0_IPG_RST 0x52A +#define PERI1_CAN0_IPG_SOFT_RST 0x52B +#define PERI1_CAN0_IPG_TS_RST 0x52C +#define PERI1_CAN0_PRST 0x52D +#define PERI1_CAN1_IPG_PE_RST 0x52E +#define PERI1_CAN1_IPG_RST 0x52F +#define PERI1_CAN1_IPG_SOFT_RST 0x530 +#define PERI1_CAN1_IPG_TS_RST 0x531 +#define PERI1_CAN1_PRST 0x532 +#define PERI1_CHIP_DBG_ARST 0x533 +#define PERI1_CHIP_DBG_CRST 0x534 +#define PERI1_CHIP_DBG_PRST 0x535 +#define PERI1_GMAC_CRST 0x536 +#define PERI1_X2H_GMAC2_ARST 0x537 +#define PERI1_X2H_GMAC2_HRST 0x538 +#define PERI1_ZGMAC_X2X_ARST 0x539 +#define PERI1_SPI0_RST 0x53A +#define PERI1_I2C0_RST 0x53B +#define PERI1_I2C1_RST 0x53C +#define PERI1_I2C2_RST 0x53D +#define PERI1_GMAC0_RST 0x53E +#define PERI1_GMAC0_X2H_RST 0x53F +#define PERI1_GMAC1_RST 0x540 +#define PERI1_GMAC1_X2H_RST 0x541 + +#define PERI2_CAN2_IPG_PE_RST 0x600 +#define PERI2_CAN2_IPG_RST 0x601 +#define PERI2_CAN2_IPG_SOFT_RST 0x602 +#define PERI2_CAN2_IPG_TS_RST 0x603 +#define PERI2_CAN2_PRST 0x604 +#define PERI2_GPIO2_DBRST 0x605 +#define PERI2_GPIO2_PRST 0x606 +#define PERI2_I2C4_IC_RST 0x607 +#define PERI2_I2C4_PRST 0x608 +#define PERI2_I2S2_PRST 0x609 +#define PERI2_SPI1_PRST 0x60A +#define PERI2_SPI1_SSI_RST 0x60B +#define PERI2_UART4_PRST 0x60C +#define PERI2_UART4_S_RST 0x60D +#define PERI2_UART5_PRST 0x60E +#define PERI2_UART5_S_RST 0x60F +#define PERI2_UART6_PRST 0x610 +#define PERI2_UART6_S_RST 0x611 +#define PERI2_PAD_CTRL_PRST 0x612 +#define PERI2_GPIO3_DBRST 0x613 +#define PERI2_GPIO3_PRST 0x614 +#define PERI2_I2C3_IC_RST 0x615 +#define PERI2_I2C3_PRST 0x616 +#define PERI2_I2C5_IC_RST 0x617 +#define PERI2_I2C5_PRST 0x618 +#define PERI2_I2C6_IC_RST 0x619 +#define PERI2_I2C6_PRST 0x61A +#define PERI2_I2C7_IC_RST 0x61B +#define PERI2_I2C7_PRST 0x61C +#define PERI2_I2S1_PRST 0x61D +#define PERI2_I2S3_PRST 0x61E +#define PERI2_UART7_PRST 0x61F +#define PERI2_UART7_S_RST 0x620 +#define PERI2_UART8_PRST 0x621 +#define PERI2_UART8_S_RST 0x622 +#define PERI2_UART9_PRST 0x623 +#define PERI2_UART9_S_RST 0x624 +#define PERI2_QSPI1_PRST 0x625 +#define PERI2_QSPI1_SSI_RST 0x626 +#define PERI2_PWM1_CRST 0x627 +#define PERI2_PWM1_PRST 0x628 +#define PERI2_PWM2_CRST 0x629 +#define PERI2_PWM2_PRST 0x62A +#define PERI2_I2C3_RST 0x62B +#define PERI2_I2C4_RST 0x62C +#define PERI2_I2C5_RST 0x62D +#define PERI2_I2C6_RST 0x62E +#define PERI2_I2C7_RST 0x62F +#define PERI2_SPI1_RST 0x630 + +#define PERI3_DMAC_ARST 0x700 +#define PERI3_DMAC_HRST 0x701 +#define PERI3_EMMC_SDIO_CLKGEN_RST 0x702 +#define PERI3_EMMC_RST 0x703 +#define PERI3_EMMC_X2X_ARST_M 0x704 +#define PERI3_EMMC_X2X_ARST_S 0x705 +#define PERI3_SDIO_RST 0x706 +#define PERI3_SDIO_X2X_ARST_M 0x707 +#define PERI3_SDIO_X2X_ARST_S 0x708 +#define PERI3_AXI_MST_ARST 0x709 +#define PERI3_AXI_MST_PRST 0x70A +#define PERI3_ADC_PRST 0x70B +#define PERI3_TEE_X2X_ARST_M 0x70C +#define PERI3_TEE_X2X_ARST_S 0x70D +#define PERI3_TEE_H2H_HRST 0x70E +#define PERI3_GPIO4_DBRST 0x70F +#define PERI3_GPIO4_PRST 0x710 +#define PERI3_PAD_CTRL_PRST 0x711 + +/* pcie common */ +#define PCIE_X2X_PERI_SLV_ARST 0x800 +#define PCIE_X2X_PERI_MST_ARST 0x801 +#define PCIE_AXI4_PCIE_MST_ARST 0x802 +#define PCIE_AXI4_PCIE_MST_PRST 0x803 +#define PCIE_DFMU_PRST 0x804 +#define PCIE_DFMU_ARST 0x805 +#define PCIE_E16PHY_PHY_RST 0x806 +#define PCIE_E16PHY_APBS_PRST 0x807 +#define PCIE_X2X_SATA_MST_ARST 0x808 +#define PCIE_X2X_SATA_SLV_ARST 0x809 +/* sata */ +#define PCIE_SATA_ARESET 0x80A +#define PCIE_SATA_RST_PMALIVE 0x80B +#define PCIE_SATA_SLV_AFENCE_ARST 0x80C +#define PCIE_SATA_MST_AFENCE_ARST 0x80D +#define PCIE_SATA_RST_ASIC0 0x80E +#define PCIE_SATA_RST_ASIC1 0x80F +#define PCIE_SATA_RST_RXOOB0 0x810 +#define PCIE_SATA_RST_RXOOB1 0x811 +/* pcie0 */ +#define PCIE_DM_GEN3X4_APBS_PRST 0x812 +#define PCIE_DM_GEN3X4_POWER_UP_RST 0x813 +#define PCIE_DM_SLV_AFENCE_ARST 0x814 +#define PCIE_DM_MST_AFENCE_ARST 0x815 +/* pcie1 */ +#define PCIE_RP_GEN3X1_APBS_PRST 0x816 +#define PCIE_RP_GEN3X1_POWER_UP_RST 0x817 +#define PCIE_RP_SLV_AFENCE_ARST 0x818 +#define PCIE_RP_MST_AFENCE_ARST 0x819 + +#define USB_DFMU_PRST 0x900 +#define USB_DFMU_ARST 0x901 +#define USB_AXI4_MST_ARST 0x902 +#define USB_AXI4_MST_PRST 0x903 +#define USB_DPTX_APBS_PRST 0x904 +#define USB_DPTX_VCC_RST 0x905 +#define USB_USB31_APBS_PRST 0x906 +#define USB_USB31_VCC_RST 0x907 +#define USB_USB31_PHY_RST 0x908 +#define USB_USB31_SLV_AFENCE_ARST 0x909 +#define USB_C10PHY_PHY_RST 0x90A +#define USB_C10PHY_APBS_PRST 0x90B +#define USB_USB20_BLK_X2H_HRST 0x90C +#define USB_USB20_BLK_X2H_ARST 0x90D +#define USB_USB20_SLV_AFENCE_ARST 0x90E +#define USB_USB20_BLK_H2P_HRST 0x90F +#define USB_USB20_BLK_AHB_SLV_HRST 0x910 +#define USB_USB20_BLK_AXI_MST_ARST 0x911 +#define USB_USB20_BLK_USB2_SYSREG_PRST 0x912 +#define USB_USB20_BLK_USB2_WRAP0_PRST 0x913 +#define USB_USB20_BLK_USB2_WRAP0_HRST 0x914 +#define USB_USB20_BLK_USB2_WRAP1_PRST 0x915 +#define USB_USB20_BLK_USB2_WRAP1_HRST 0x916 +#define USB_USB20_BLK_A2X0_HRST 0x917 +#define USB_USB20_BLK_A2X0_ARST 0x918 +#define USB_USB20_BLK_A2X1_HRST 0x919 +#define USB_USB20_BLK_A2X1_ARST 0x91A +#define USB_USB20_BLK_USB0_PHY_PON_RESET 0x91B +#define USB_USB20_BLK_USB1_PHY_PON_RESET 0x91C +#define USB_PERI2_SS_RST 0x91D +#define USB_PERI2_SLV_AFENCE_ARST 0x91E + +#define TEE_KEYRAM_PRST 0xA00 +#define TEE_DS_PRST 0xA01 +#define TEE_EFUSE_PRST 0xA02 +#define TEE_OCRAM_HRST 0xA03 +#define TEE_SYSREG_PRST 0xA04 +#define TEE_CCU_PRST 0xA05 +#define TEE_CCU_CRST 0xA06 +#define TEE_EIP150B_HRST 0xA07 +#define TEE_EIP120SIII_HRST 0xA08 +#define TEE_EIP120SIII_ARST 0xA09 +#define TEE_EIP120SII_HRST 0xA0A +#define TEE_EIP120SII_ARST 0xA0B +#define TEE_EIP120SI_HRST 0xA0C +#define TEE_EIP120SI_ARST 0xA0D +#define TEE_DMAC_HRST 0xA0E +#define TEE_DMAC_ARST 0xA0F +#define TEE_X2P_TEESYS_PRST 0xA10 +#define TEE_X2P_TEESYS_ARST 0xA11 +#define TEE_AXI4_TEESYS_ARST 0xA12 +#define TEE_APB3_TEESYS_PRST 0xA13 +#define TEE_APB3_TEESYS_HRST 0xA14 +#define TEE_AHB2_TEESYS_HRST 0xA15 + +#define GPU_PWR_WRAP_RGX_HOOD_RST 0xB00 +#define GPU_PWR_WRAP_DFMU_RST 0xB01 + +#define A210_RESETS_MAX 0xB02 + +#endif From c13662e7d2494ec1993b2dd1a4ca6a46cf6542c0 Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Apr 2026 20:28:50 +0800 Subject: [PATCH 04/17] clk: add ZhiHe A210 clock controller driver Add a clock controller driver for the ZhiHe A210 SoC that manages: - PLLs (integer and fractional) - Clock gates, dividers, and muxes for peripheral clocks The driver registers with the common clock framework and is referenced by device tree nodes through the clock binding IDs defined in dt-bindings/clock/a210-clock.h. Signed-off-by: Zhiguo Zhu --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/zhihe/Kconfig | 16 + drivers/clk/zhihe/Makefile | 7 + drivers/clk/zhihe/clk-a210.c | 1507 ++++++++++++++++++++++++++++++++ drivers/clk/zhihe/clk-helper.c | 429 +++++++++ drivers/clk/zhihe/clk-helper.h | 353 ++++++++ drivers/clk/zhihe/clk-pll.c | 377 ++++++++ 8 files changed, 2691 insertions(+) create mode 100644 drivers/clk/zhihe/Kconfig create mode 100644 drivers/clk/zhihe/Makefile create mode 100644 drivers/clk/zhihe/clk-a210.c create mode 100644 drivers/clk/zhihe/clk-helper.c create mode 100644 drivers/clk/zhihe/clk-helper.h create mode 100644 drivers/clk/zhihe/clk-pll.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 9bd521a2604af..87dda89263717 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -511,6 +511,7 @@ source "drivers/clk/visconti/Kconfig" source "drivers/clk/x86/Kconfig" source "drivers/clk/xilinx/Kconfig" source "drivers/clk/zynqmp/Kconfig" +source "drivers/clk/zhihe/Kconfig" # Kunit test cases config CLK_KUNIT_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 40ea0c28dbd2e..542b24b805098 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -139,3 +139,4 @@ obj-y += xilinx/ obj-$(CONFIG_ARCH_ZYNQ) += zynq/ obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/ obj-$(CONFIG_ARCH_XUANTIE) += thead/ +obj-$(CONFIG_ARCH_ZHIHE) += zhihe/ diff --git a/drivers/clk/zhihe/Kconfig b/drivers/clk/zhihe/Kconfig new file mode 100644 index 0000000000000..b6b172e423f98 --- /dev/null +++ b/drivers/clk/zhihe/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 + +config ZHIHE_CLK + bool + def_bool ARCH_ZHIHE + +config CLK_A210 + bool "ZhiHe A210 clock driver" + depends on ARCH_ZHIHE || COMPILE_TEST + default ARCH_ZHIHE + help + Build the clock controller driver for the ZhiHe A210 SoC. + + This driver provides clock tree management including PLLs, + dividers, gates, and muxes for the A210 platform. Say Y if + you are building a kernel for the ZhiHe A210. diff --git a/drivers/clk/zhihe/Makefile b/drivers/clk/zhihe/Makefile new file mode 100644 index 0000000000000..7b41724a2cc42 --- /dev/null +++ b/drivers/clk/zhihe/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_ZHIHE_CLK) += \ + clk-helper.o \ + clk-pll.o + +obj-$(CONFIG_CLK_A210) += clk-a210.o diff --git a/drivers/clk/zhihe/clk-a210.c b/drivers/clk/zhihe/clk-a210.c new file mode 100644 index 0000000000000..d9ae551c4d3be --- /dev/null +++ b/drivers/clk/zhihe/clk-a210.c @@ -0,0 +1,1507 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-helper.h" + +/* top reg idx */ +#define PLL_WRAP 0 +#define TOP_CRG 1 +#define CPU_SS_CLK_SYSREG 2 +#define CPU_SS_CPU_PLL 3 +#define DDR0_SYSREG 4 +#define DDR1_SYSREG 5 +#define SLC_DUAL_SYSREG 6 +#define TOP_CRG_T 7 +#define CPU_SS_CCU 8 +/* gpu reg idx */ +#define GPU_SS_PWRAP_CLK_EN 0 +#define GPU_SS_TOP_CLK_EN 1 +/* pcie reg idx */ +#define PCIE_CLK_EN 0 +/* usb reg idx */ +#define USB_CLK_EN 0 +/* vi reg idx */ +#define VI_CLK 0 +#define VI_MISC_CTRL 1 +/* vp reg idx */ +#define VP_CLK 0 +/* vo reg idx */ +#define VO_CLK 0 +#define VO_PATH_CTRL 1 +/* npu reg idx */ +#define NPU_CLK 0 +#define NPU_TOP_CLK 1 +/* peri reg idx */ +#define PERI0_SYSREG 0 +#define PERI1_SYSREG 1 +#define PERI2_SYSREG 2 +#define PERI3_SYSREG 3 +#define TEE_CRG 4 + +static u32 share_cnt_ddr_pll_clk_en; + +enum a210_pll_clktype { + AUDIO0_PLL, + AUDIO1_PLL, + VIDEO_PLL, + GMAC_PLL, + DVFS_PLL, + DPU0_PLL, + DPU1_PLL, + DPU2_PLL, + TEE_PLL, + DDR_PLL, + C920_PLL, + C908_PLL, +}; + +static const char *const noc_cclk_mux_parents[] = { + "dpu1_pll_foutvco", + "video_pll_foutvco", + "gmac_pll_foutvco", +}; +static const char *const top_cpu_ddr1_aclk_parents[] = { + "cbus2ddr_aclk1", + "gmac_pll_foutpostdiv", +}; +static const char *const top_cpu_ddr0_aclk_parents[] = { + "cbus2ddr_aclk0", + "gmac_pll_foutpostdiv", +}; +static const char *const ddr_pll_clkout_parents[] = { + "ddr_pll_foutpostdiv", + "ddr_pll_fout1ph0", + "ddr_pll_fout2", +}; +static const char *const top_cpu_bak_pll0_clk_mux0_parents[] = { + "audio0_pll_foutvco", + "dvfs_pll_foutvco", + "top_cpu_bak_pll0_clk_div0", + "top_cpu_bak_pll0_clk_div1", +}; +static const char *const top_cpu_bak_pll0_clk_mux_parents[] = { + "dpu1_pll_foutvco", + "top_cpu_bak_pll0_clk_mux0", + "dvfs_pll_foutvco", + "audio0_pll_foutvco", + "top_cpu_bak_pll0_clk_div0", + "top_cpu_bak_pll0_clk_div4", + "top_cpu_bak_pll0_clk_div3", + "top_cpu_bak_pll0_clk_div1", +}; +static const char *const top_cpu_bak_pll1_clk_mux0_parents[] = { + "audio0_pll_foutvco", + "dvfs_pll_foutvco", + "top_cpu_bak_pll1_clk_div0", + "top_cpu_bak_pll1_clk_div1", +}; +static const char *const top_cpu_bak_pll1_clk_mux_parents[] = { + "dpu1_pll_foutvco", + "top_cpu_bak_pll1_clk_mux0", + "dvfs_pll_foutvco", + "audio0_pll_foutvco", + "top_cpu_bak_pll1_clk_div0", + "top_cpu_bak_pll1_clk_div4", + "top_cpu_bak_pll1_clk_div3", + "top_cpu_bak_pll1_clk_div1", +}; +static const char *const top_cpusys_pic_clk_mux_parents[] = { + "gmac_pll_foutvco", + "video_pll_foutvco", +}; +static const char *const top_cpusys_bus_clk_mux_parents[] = { + "video_pll_foutvco", + "gmac_pll_foutvco", + "audio0_pll_foutvco", + "dpu2_pll_foutvco", +}; +static const char *const d2d_phy_ref_clk_parents[] = { + "d2d_phy_ref_clk_100M", + "aon_osc_clk_logic", +}; +static const char *const top_d2d_aclk_mux_parents[] = { + "dpu1_pll_foutvco", + "gmac_pll_foutvco", + "audio1_pll_foutvco", + "audio0_pll_foutvco", +}; +static const char *const top_gpu_core_clk_mux_parents[] = { + "dpu1_pll_foutvco", + "video_pll_foutvco", + "dvfs_pll_foutvco", + "audio0_pll_foutvco", +}; +static const char *const pcie_ss_axi_m_aclk_mux_parents[] = { + "audio0_pll_foutvco", + "video_pll_foutvco", +}; +static const char *const peri0_timer_clk_parents[] = { + "peri0_timer_clk_100M", + "aon_osc_clk_logic", +}; +static const char *const peri2_i2s3_src_clk_parents[] = { + "audio1_pll_fout2", + "audio0_pll_fout2", +}; +static const char *const peri1_i2s0_src_clk_parents[] = { + "audio1_pll_fout2", + "audio0_pll_fout2", +}; +static const char *const peri2_i2s1_src_clk_parents[] = { + "audio1_pll_fout2", + "audio0_pll_fout2", +}; +static const char *const peri2_i2s2_src_clk_parents[] = { + "audio1_pll_fout2", + "audio0_pll_fout2", +}; +static const char *const peri1_qspi_ssi_clk_parents[] = { + "peri1_qspi_ssi_clk_div1", + "peri1_qspi_ssi_clk_div0", +}; +static const char *const peri2_qspi_ssi_clk_parents[] = { + "peri2_qspi_ssi_clk_div1", + "peri2_qspi_ssi_clk_div0", +}; +static const char *const peri1_tdm_src_clk_parents[] = { + "audio1_pll_fout2", + "audio0_pll_fout2", +}; +static const char *const pdm_clk_mux_parents[] = { + "audio1_pll_fout2", + "audio0_pll_fout2", +}; +static const char *const emmc_ref_clk_mux_parents[] = { + "audio0_pll_foutvco", + "video_pll_foutvco", +}; +static const char *const pad_sensor_vclk0_mux_parents[] = { + "dpu0_pll_foutpostdiv", + "dpu1_pll_foutpostdiv", + "dpu2_pll_foutpostdiv", + "aon_osc_clk_logic", +}; +static const char *const pad_sensor_vclk1_mux_parents[] = { + "dpu0_pll_foutpostdiv", + "dpu1_pll_foutpostdiv", + "dpu2_pll_foutpostdiv", + "aon_osc_clk_logic", +}; +static const char *const vp_aclk_mux_parents[] = { + "video_pll_foutvco", + "audio0_pll_foutvco", +}; +static const char *const g2d_cclk_mux_parents[] = { + "audio0_pll_foutvco", + "gmac_pll_foutvco", + "video_pll_foutvco", +}; +static const char *const vdec_cclk_mux_parents[] = { + "audio0_pll_foutvco", + "video_pll_foutvco", + "gmac_pll_foutvco", + "audio1_pll_foutvco", +}; +static const char *const venc_cclk_mux_parents[] = { + "gmac_pll_foutvco", + "video_pll_foutvco", + "audio0_pll_foutvco", + "audio1_pll_foutvco", +}; +static const char *const npu_aclk_mux_parents[] = { + "gmac_pll_foutvco", + "video_pll_foutvco", + "audio0_pll_foutvco", + "audio1_pll_foutvco", +}; +static const char *const npu_cclk_mux_parents[] = { + "gmac_pll_foutvco", + "video_pll_foutvco", + "audio0_pll_foutvco", + "audio1_pll_foutvco", +}; +static const char *const c908_cpu_clk_parents[] = { + "c908_pll_foutvco", + "top_cpu_bak_pll0_clk", +}; +static const char *const c920_cpu_clk_parents[] = { + "c920_pll_foutvco", + "top_cpu_bak_pll1_clk", +}; +static const char *const tee_clk_mux_parents[] = { + "video_pll_foutvco", + "tee_pll_foutvco", +}; +static const char *const isp_if_ref_mux_parents[] = { + "audio0_pll_foutvco", + "video_pll_foutvco", +}; +static const char *const vi_preocc_mipi0_ifclk_mux_parents[] = { + "audio0_pll_foutvco", + "video_pll_foutvco", +}; +static const char *const vi_preocc_mipi1_ifclk_mux_parents[] = { + "audio0_pll_foutvco", + "video_pll_foutvco", +}; +static const char *const vo_mipi_pixclk_mux_parents[] = { + "dpu0_pixclk", + "dpu1_pixclk", + "dpu2_pixclk", +}; +static const char *const vo_hdmi_pixclk_mux_parents[] = { + "dpu0_pixclk", + "dpu1_pixclk", + "dpu2_pixclk", +}; +static const char *const vo_dptx_pixclk_mux_parents[] = { + "dpu0_pixclk", + "dpu1_pixclk", + "dpu2_pixclk", +}; + +static struct zhihe_pll_rate_table a210_teepll_tbl[] = { + PLL_RATE(2400000000, 800000000U, 1, 100, 0, 3, 1), +}; + +static struct zhihe_pll_rate_table a210_dpu2pll_tbl[] = { + PLL_RATE(2376000000, 1188000000U, 1, 99, 0, 2, 1), +}; + +static struct zhihe_pll_rate_table a210_dpu1pll_tbl[] = { + PLL_RATE(2376000000, 1188000000U, 1, 99, 0, 2, 1), +}; + +static struct zhihe_pll_rate_table a210_dpu0pll_tbl[] = { + PLL_RATE(2376000000, 1188000000U, 1, 99, 0, 2, 1), +}; + +static struct zhihe_pll_rate_table a210_dvfspll_tbl[] = { + PLL_RATE(1920000000, 960000000U, 1, 80, 0, 2, 1), +}; + +static struct zhihe_pll_rate_table a210_gmacpll_tbl[] = { + PLL_RATE(3000000000, 1000000000U, 1, 125, 0, 3, 1), +}; + +static struct zhihe_pll_rate_table a210_videopll_tbl[] = { + PLL_RATE(2640000000U, 1320000000U, 1, 110, 0, 2, 1), +}; + +static struct zhihe_pll_rate_table a210_audio0pll_tbl[] = { + PLL_RATE(2359296000U, 1179648000U, 1, 98, 5100274, 2, 1), +}; + +static struct zhihe_pll_rate_table a210_audio1pll_tbl[] = { + PLL_RATE(2528870400U, 1264435200U, 1, 105, 6200859, 2, 1), +}; + +static struct zhihe_pll_rate_table a210_c908pll_tbl[] = { + PLL_RATE(1200000000U, 1200000000U, 1, 50, 0, 1, 1), + PLL_RATE(1500000000U, 1500000000U, 2, 125, 0, 1, 1), + PLL_RATE(1698000000U, 1698000000U, 4, 283, 0, 1, 1), + PLL_RATE(1896000000U, 1896000000U, 1, 79, 0, 1, 1), +}; + +static struct zhihe_pll_rate_table a210_c920pll_tbl[] = { + PLL_RATE(1500000000U, 1500000000U, 2, 125, 0, 1, 1), + PLL_RATE(1698000000U, 1698000000U, 4, 283, 0, 1, 1), + PLL_RATE(1896000000U, 1896000000U, 1, 79, 0, 1, 1), + PLL_RATE(2298000000U, 2298000000U, 4, 383, 0, 1, 1), +}; + +static struct zhihe_clk_info_pll plls_top[] = { + PLL_PARAM(TEE_PLL, ZHIHE_PLL_VCO, a210_teepll_tbl, 0x160, 0x170, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, "tee_pll_foutvco_frequency"), + PLL_PARAM(DPU2_PLL, ZHIHE_PLL_VCO, a210_dpu2pll_tbl, 0x120, 0x130, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, "dpu2_pll_foutvco_frequency"), + PLL_PARAM(DPU1_PLL, ZHIHE_PLL_VCO, a210_dpu1pll_tbl, 0x100, 0x110, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, "dpu1_pll_foutvco_frequency"), + PLL_PARAM(DPU0_PLL, ZHIHE_PLL_VCO, a210_dpu0pll_tbl, 0x80, 0x90, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, "dpu0_pll_foutvco_frequency"), + PLL_PARAM(DVFS_PLL, ZHIHE_PLL_VCO, a210_dvfspll_tbl, 0x60, 0x70, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, "dvfs_pll_foutvco_frequency"), + PLL_PARAM(AUDIO0_PLL, ZHIHE_PLL_VCO, a210_audio0pll_tbl, 0x0, 0x10, + BIT(0), BIT(31), BIT(30), PLL_MODE_FRAC, "audio0_pll_foutvco_frequency"), + PLL_PARAM(AUDIO1_PLL, ZHIHE_PLL_VCO, a210_audio1pll_tbl, 0x20, 0x30, + BIT(0), BIT(31), BIT(30), PLL_MODE_FRAC, "audio1_pll_foutvco_frequency"), + PLL_PARAM(GMAC_PLL, ZHIHE_PLL_VCO, a210_gmacpll_tbl, 0x40, 0x50, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, "gmac_pll_foutvco_frequency"), + PLL_PARAM(VIDEO_PLL, ZHIHE_PLL_VCO, a210_videopll_tbl, 0x140, 0x150, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, "video_pll_foutvco_frequency"), + PLL_PARAM(C908_PLL, ZHIHE_PLL_VCO, a210_c908pll_tbl, 0x0, 0x10, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, ""), + PLL_PARAM(C920_PLL, ZHIHE_PLL_VCO, a210_c920pll_tbl, 0x40, 0x50, + BIT(0), BIT(31), BIT(30), PLL_MODE_INT, ""), +}; + +static struct zhihe_clk_reg regs_top[] = { + REG_NAMED(PLL_WRAP, "pll-wrap"), + REG_NAMED(TOP_CRG, "top-crg"), + REG_NAMED(CPU_SS_CLK_SYSREG, "cpu-ss-clk-sysreg"), + REG_NAMED(CPU_SS_CPU_PLL, "cpu-ss-cpu-pll"), + REG_NAMED(DDR0_SYSREG, "ddr0-sysreg"), + REG_NAMED(DDR1_SYSREG, "ddr1-sysreg"), + REG_NAMED(SLC_DUAL_SYSREG, "slc-dual-sysreg"), + REG_NAMED(TOP_CRG_T, "top-crg-t"), + REG_NAMED(CPU_SS_CCU, "cpu-ss-ccu"), +}; + +static struct zhihe_clk_reg regs_gpu[] = { + REG(GPU_SS_PWRAP_CLK_EN), + REG(GPU_SS_TOP_CLK_EN), +}; + +static struct zhihe_clk_reg regs_pcie[] = { + REG(PCIE_CLK_EN), +}; + +static struct zhihe_clk_reg regs_usb[] = { + REG(USB_CLK_EN), +}; + +static struct zhihe_clk_reg regs_vi[] = { + REG(VI_CLK), + REG(VI_MISC_CTRL), +}; + +static struct zhihe_clk_reg regs_vp[] = { + REG(VP_CLK), +}; + +static struct zhihe_clk_reg regs_vo[] = { + REG(VO_CLK), + REG(VO_PATH_CTRL), +}; + +static struct zhihe_clk_reg regs_npu[] = { + REG(NPU_CLK), + REG(NPU_TOP_CLK), +}; + +static struct zhihe_clk_reg regs_peri[] = { + REG_NAMED(PERI0_SYSREG, "peri0-sysreg"), + REG_NAMED(PERI1_SYSREG, "peri1-sysreg"), + REG_NAMED(PERI2_SYSREG, "peri2-sysreg"), + REG_NAMED(PERI3_SYSREG, "peri3-sysreg"), + REG_NAMED(TEE_CRG, "tee-crg"), +}; + +static struct zhihe_clk_info info_top[] = { + /* FIXED */ + FIXED(AON_OSC_CLK_PHY, "aon_osc_clk_phy", "osc-24m", 24000000), + FIXED(AON_OSC_CLK_LOGIC, "aon_osc_clk_logic", "osc-24m", 24000000), + FIXED(TOP_PLL_REF_CLK, "top_pll_ref_clk", "osc-24m", 24000000), + FIXED(PLL_OSC_CLK, "pll_osc_clk", "osc-24m", 24000000), + FIXED(AON_RTC_CLK, "aon_rtc_clk", "osc-24m", 32768), + /* PLL */ + PLL(AUDIO0_PLL_FOUTVCO, + "audio0_pll_foutvco", "osc-24m", PLL_WRAP, 0, &plls_top[AUDIO0_PLL]), + FIXED_FACTOR(AUDIO0_PLL_FOUTPOSTDIV, + "audio0_pll_foutpostdiv", "audio0_pll_foutvco", 1, 2), + FIXED_FACTOR(AUDIO0_PLL_FOUT2, + "audio0_pll_fout2", "audio0_pll_foutvco", 1, 8), + PLL(AUDIO1_PLL_FOUTVCO, + "audio1_pll_foutvco", "osc-24m", PLL_WRAP, 0, &plls_top[AUDIO1_PLL]), + FIXED_FACTOR(AUDIO1_PLL_FOUTPOSTDIV, + "audio1_pll_foutpostdiv", "audio1_pll_foutvco", 1, 2), + FIXED_FACTOR(AUDIO1_PLL_FOUT2, + "audio1_pll_fout2", "audio1_pll_foutvco", 1, 8), + PLL(C908_PLL_FOUTVCO, + "c908_pll_foutvco", "osc-24m", CPU_SS_CPU_PLL, 0, &plls_top[C908_PLL]), + PLL(C920_PLL_FOUTVCO, + "c920_pll_foutvco", "osc-24m", CPU_SS_CPU_PLL, 0, &plls_top[C920_PLL]), + PLL(VIDEO_PLL_FOUTVCO, + "video_pll_foutvco", "top_pll_ref_clk", PLL_WRAP, 0, &plls_top[VIDEO_PLL]), + FIXED_FACTOR(VIDEO_PLL_FOUTPOSTDIV, + "video_pll_foutpostdiv", "video_pll_foutvco", 1, 2), + FIXED_FACTOR(VIDEO_PLL_FOUT1PH0, + "video_pll_fout1ph0", "video_pll_foutvco", 1, 4), + FIXED_FACTOR(VIDEO_PLL_FOUT3, + "video_pll_fout3", "video_pll_foutvco", 1, 12), + PLL(GMAC_PLL_FOUTVCO, + "gmac_pll_foutvco", "top_pll_ref_clk", PLL_WRAP, 0, &plls_top[GMAC_PLL]), + FIXED_FACTOR(GMAC_PLL_FOUTPOSTDIV, + "gmac_pll_foutpostdiv", "gmac_pll_foutvco", 1, 3), + FIXED_FACTOR(GMAC_PLL_FOUT1PH0, + "gmac_pll_fout1ph0", "gmac_pll_foutvco", 1, 6), + PLL(DVFS_PLL_FOUTVCO, + "dvfs_pll_foutvco", "top_pll_ref_clk", PLL_WRAP, 0, &plls_top[DVFS_PLL]), + PLL(DPU0_PLL_FOUTVCO, + "dpu0_pll_foutvco", "top_pll_ref_clk", PLL_WRAP, 0, &plls_top[DPU0_PLL]), + FIXED_FACTOR(DPU0_PLL_FOUTPOSTDIV, + "dpu0_pll_foutpostdiv", "dpu0_pll_foutvco", 1, 2), + PLL(DPU1_PLL_FOUTVCO, + "dpu1_pll_foutvco", "top_pll_ref_clk", PLL_WRAP, 0, &plls_top[DPU1_PLL]), + FIXED_FACTOR(DPU1_PLL_FOUTPOSTDIV, + "dpu1_pll_foutpostdiv", "dpu1_pll_foutvco", 1, 2), + PLL(DPU2_PLL_FOUTVCO, + "dpu2_pll_foutvco", "top_pll_ref_clk", PLL_WRAP, 0, &plls_top[DPU2_PLL]), + FIXED_FACTOR(DPU2_PLL_FOUTPOSTDIV, + "dpu2_pll_foutpostdiv", "dpu2_pll_foutvco", 1, 2), + PLL(TEE_PLL_FOUTVCO, + "tee_pll_foutvco", "top_pll_ref_clk", PLL_WRAP, 0, &plls_top[TEE_PLL]), + /* TOP SS */ + DIV(TOP_CFG_ACLK_DIV, + "top_cfg_aclk", "video_pll_fout1ph0", TOP_CRG, 0, 8, 8, + NO_DIV_EN, MUX_TYPE_DIV, 2, 255), + DIV(TOP_PCLK_DIV, + "top_pclk", "video_pll_fout1ph0", TOP_CRG, 0, 0, 8, + NO_DIV_EN, MUX_TYPE_DIV, 4, 255), + DIV(AMUX_CLK_DIV, + "top_amux_clk_div", "video_pll_foutvco", TOP_CRG, 0x18, 8, 4, + NO_DIV_EN, MUX_TYPE_DIV, 4, 15), + GATE(SW_TOP_OSC_CLK_LOGIC_EN, + "top_osc_clk_logic", "aon_osc_clk_logic", TOP_CRG, 0x200, 2), + GATE(SW_AMUX_660_CLK_EN, + "top_amux_clk", "top_amux_clk_div", TOP_CRG, 0x200, 0), + /* TOP SS - IOMMU_PTW_ACLK */ + GATE(SW_IOMMU_PTW_330_ACLK_EN, + "iommu_ptw_aclk", "iommu_ptw_aclk_div", TOP_CRG, 0x200, 1), + DIV(IOMMU_PTW_ACLK_DIV, + "iommu_ptw_aclk_div", "video_pll_fout1ph0", TOP_CRG, 0, 24, 3, + NO_DIV_EN, MUX_TYPE_DIV, 2, 7), + /* TOP SS - CPU SS */ + DIV(TOP_CPUSYS_BUS_CLK_DIV, + "top_cpusys_bus_clk", "top_cpusys_bus_clk_mux", TOP_CRG, 0x8, 20, 4, + NO_DIV_EN, MUX_TYPE_DIV, 2, 15), + MUX(TOP_CPUSYS_BUS_CLK_MUX, + "top_cpusys_bus_clk_mux", TOP_CRG, 0x8, 16, 2, + top_cpusys_bus_clk_mux_parents, CLK_SET_RATE_PARENT), + DIV(TOP_CPUSYS_PIC_CLK_DIV, + "top_cpusys_pic_clk", "top_cpusys_pic_clk_mux", TOP_CRG, 0x4, 20, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_CPUSYS_PIC_CLK_MUX, + "top_cpusys_pic_clk_mux", TOP_CRG, 0x4, 3, 1, + top_cpusys_pic_clk_mux_parents, CLK_SET_RATE_PARENT), + MUX(TOP_CPU_BAK_PLL0_CLK_MUX, + "top_cpu_bak_pll0_clk", TOP_CRG, 0x4, 0, 3, + top_cpu_bak_pll0_clk_mux_parents, CLK_SET_RATE_PARENT), + MUX(TOP_CPU_BAK_PLL0_CLK_MUX0, + "top_cpu_bak_pll0_clk_mux0", TOP_CRG, 0x4, 16, 2, + top_cpu_bak_pll0_clk_mux0_parents, CLK_SET_RATE_PARENT), + DIV(TOP_CPU_BAK_PLL0_CLK_DIV0, + "top_cpu_bak_pll0_clk_div0", "gmac_pll_foutvco", TOP_CRG, 0x4, 12, 4, + NO_DIV_EN, MUX_TYPE_DIV, 2, 15), + DIV(TOP_CPU_BAK_PLL0_CLK_DIV1, + "top_cpu_bak_pll0_clk_div1", "gmac_pll_foutvco", TOP_CRG, 0x4, 8, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + DIV(TOP_CPU_BAK_PLL0_CLK_DIV3, + "top_cpu_bak_pll0_clk_div3", "audio1_pll_foutvco", TOP_CRG, 0x4, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 2, 15), + DIV(TOP_CPU_BAK_PLL0_CLK_DIV4, + "top_cpu_bak_pll0_clk_div4", "video_pll_foutvco", TOP_CRG, 0x4, 24, 8, + NO_DIV_EN, MUX_TYPE_DIV, 2, 255), + MUX(TOP_CPU_BAK_PLL1_CLK_MUX, + "top_cpu_bak_pll1_clk", TOP_CRG, 0x8, 0, 3, + top_cpu_bak_pll1_clk_mux_parents, CLK_SET_RATE_PARENT), + MUX(TOP_CPU_BAK_PLL1_CLK_MUX0, + "top_cpu_bak_pll1_clk_mux0", TOP_CRG, 0x8, 8, 2, + top_cpu_bak_pll1_clk_mux0_parents, CLK_SET_RATE_PARENT), + DIV(TOP_CPU_BAK_PLL1_CLK_DIV0, + "top_cpu_bak_pll1_clk_div0", "gmac_pll_foutvco", TOP_CRG, 0x8, 12, 4, + NO_DIV_EN, MUX_TYPE_DIV, 2, 15), + DIV(TOP_CPU_BAK_PLL1_CLK_DIV1, + "top_cpu_bak_pll1_clk_div1", "gmac_pll_foutvco", TOP_CRG, 0x8, 24, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + DIV(TOP_CPU_BAK_PLL1_CLK_DIV3, + "top_cpu_bak_pll1_clk_div3", "audio1_pll_foutvco", TOP_CRG, 0x8, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 2, 15), + DIV(TOP_CPU_BAK_PLL1_CLK_DIV4, + "top_cpu_bak_pll1_clk_div4", "video_pll_foutvco", TOP_CRG, 0x44, 0, 8, + NO_DIV_EN, MUX_TYPE_DIV, 2, 255), + DIV(TOP_CPUSYS_CFG_ACLK_DIV, + "top_cpusys_sys_cfg_axi_clk", "video_pll_fout1ph0", CPU_SS_CCU, 0x1c, 0, 16, + NO_DIV_EN, MUX_TYPE_CDE, 1, 5), + DIV(TOP_CPUSYS_COM_APB_CLK_DIV, + "top_cpusys_sys_com_apb_clk", "video_pll_fout1ph0", CPU_SS_CCU, 0x21c, 0, 16, + NO_DIV_EN, MUX_TYPE_CDE, 3, 7), + DIV(TOP_CPUSYS_APB_CLK_DIV, + "top_cpusys_cpu_apb_clk", "video_pll_fout1ph0", CPU_SS_CCU, 0x41c, 0, 16, + NO_DIV_EN, MUX_TYPE_CDE, 3, 7), + /* TOP SS - NOC_CCLK */ + GATE(SW_NOC_CCLK_EN, + "noc_cclk", "noc_cclk_div", TOP_CRG, 0x200, 3), + DIV(NOC_CCLK_DIV, + "noc_cclk_div", "noc_cclk_mux", TOP_CRG, 0, 20, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(NOC_CCLK_MUX, "noc_cclk_mux", TOP_CRG, 0, 16, 2, + noc_cclk_mux_parents, CLK_SET_RATE_PARENT), + /* TOP SS - DDR SS */ + MUX(TOP_CPU_DDR1_ACLK_MUX, + "top_ddr1_aclk", TOP_CRG, 0x4, 19, 1, + top_cpu_ddr1_aclk_parents, CLK_SET_RATE_PARENT), + MUX(TOP_CPU_DDR0_ACLK_MUX, + "top_ddr0_aclk", TOP_CRG, 0x4, 18, 1, + top_cpu_ddr0_aclk_parents, CLK_SET_RATE_PARENT), + FIXED_FACTOR(DDR_CBUS2DDR_ACLK0, + "cbus2ddr_aclk0", "ddr_pll_clk_en", 1, 1), + FIXED_FACTOR(DDR_CBUS2DDR_ACLK1, + "cbus2ddr_aclk1", "ddr_pll_clk_en", 1, 1), + FIXED(DDR_PLL_FOUTVCO, + "ddr_pll_foutvco", "pll_osc_clk", 3192000000), + FIXED_FACTOR(DDR_PLL_FOUTPOSTDIV, + "ddr_pll_foutpostdiv", "ddr_pll_foutvco", 1, 3), + FIXED_FACTOR(DDR_PLL_FOUT1PH0, + "ddr_pll_fout1ph0", "ddr_pll_foutvco", 1, 6), + FIXED_FACTOR(DDR_PLL_FOUT2, + "ddr_pll_fout2", "ddr_pll_foutvco", 1, 12), + FIXED_FACTOR(DDR_PLL_FOUT4, + "ddr_pll_fout4", "ddr_pll_foutvco", 1, 24), + /* TOP SS - D2D SS */ + FIXED_FACTOR(D2D_PHY_REF_CLK_100M, + "d2d_phy_ref_clk_100M", "gmac_pll_foutpostdiv", 1, 10), + MUX(TOP_D2D_REF_CLK_MUX, + "d2d_phy_ref_clk", TOP_CRG, 0x14, 15, 1, + d2d_phy_ref_clk_parents, CLK_SET_RATE_PARENT), + DIV(TOP_D2D_SCAN_CLK0_DIV, + "d2d_phy_scan_clk0", "dpu1_pll_foutvco", TOP_CRG, 0x14, 12, 3, + NO_DIV_EN, MUX_TYPE_DIV, 3, 7), + DIV(TOP_D2D_SCAN_CLK1_DIV, + "d2d_phy_scan_clk1", "dpu1_pll_foutvco", TOP_CRG, 0x14, 8, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + FIXED_FACTOR(D2D_PHY_SCAN_CLK2, + "d2d_phy_scan_clk2", "dpu2_pll_foutpostdiv", 1, 1), + DIV(TOP_D2D_ACLK_DIV, + "top_d2d_aclk", "top_d2d_aclk_mux", TOP_CRG, 0x14, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_D2D_ACLK_MUX, + "top_d2d_aclk_mux", TOP_CRG, 0x14, 0, 2, + top_d2d_aclk_mux_parents, CLK_SET_RATE_PARENT), + /* TOP SS - GPU SS */ + DIV(TOP_GPU_CORE_CLK_DIV, + "top_gpu_core_clk", "top_gpu_core_clk_mux", TOP_CRG, 0x18, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_GPU_CORE_CLK_MUX, + "top_gpu_core_clk_mux", TOP_CRG, 0x18, 0, 2, + top_gpu_core_clk_mux_parents, CLK_SET_RATE_PARENT), + /* TOP SS - PCIE SS */ + DIV(TOP_PCIE_SCAN_REF_CLK0_DIV, + "scan_ref_clk0", "dpu1_pll_foutvco", TOP_CRG, 0x1c, 8, 4, + NO_DIV_EN, MUX_TYPE_DIV, 6, 15), + DIV(TOP_PCIE_SCAN_REF_CLK1_DIV, + "scan_ref_clk1", "gmac_pll_foutvco", TOP_CRG, 0x1c, 12, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + DIV(TOP_PCIE_AXI_M_ACLK_DIV, + "pcie_ss_axi_m_aclk", "pcie_ss_axi_m_aclk_mux", TOP_CRG, 0x1c, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_PCIE_AXI_M_ACLK_MUX, + "pcie_ss_axi_m_aclk_mux", TOP_CRG, 0x1c, 0, 1, + pcie_ss_axi_m_aclk_mux_parents, CLK_SET_RATE_PARENT), + /* TOP SS - PERI SS */ + DIV(TOP_PERI_SPI_SSI_CLK0_DIV, + "peri1_spi_ssi_clk", "audio1_pll_foutvco", TOP_CRG, 0x20, 20, 8, + NO_DIV_EN, MUX_TYPE_DIV, 6, 255), + DIV(TOP_PERI_MST_ACLK0_DIV, + "peri1_mst_aclk", "video_pll_fout1ph0", TOP_CRG, 0x20, 16, 3, + NO_DIV_EN, MUX_TYPE_DIV, 2, 7), + FIXED_FACTOR(TOP_PERI_TIMER_CLK_100M, + "peri0_timer_clk_100M", "gmac_pll_foutpostdiv", 1, 10), + MUX(TOP_PERI_TIMER_CLK_MUX, + "peri0_timer_clk", TOP_CRG, 0x20, 15, 1, + peri0_timer_clk_parents, CLK_SET_RATE_PARENT), + MUX(TOP_PERI_I2S_8CH0_SRC_CLK_MUX, + "peri2_i2s3_src_clk", TOP_CRG, 0x28, 21, 1, + peri2_i2s3_src_clk_parents, CLK_SET_RATE_PARENT), + MUX(TOP_PERI_I2S_2CH0_SRC_CLK_MUX, + "peri1_i2s0_src_clk", TOP_CRG, 0x20, 13, 1, + peri1_i2s0_src_clk_parents, CLK_SET_RATE_PARENT), + MUX(TOP_PERI_I2S_2CH1_SRC_CLK_MUX, + "peri2_i2s1_src_clk", TOP_CRG, 0x20, 14, 1, + peri2_i2s1_src_clk_parents, CLK_SET_RATE_PARENT), + MUX(TOP_PERI_I2S_2CH2_SRC_CLK_MUX, + "peri2_i2s2_src_clk", TOP_CRG, 0x28, 23, 1, + peri2_i2s2_src_clk_parents, CLK_SET_RATE_PARENT), + DIV(TOP_PERI_QSPI0_SSI_CLK_DIV0, + "peri1_qspi_ssi_clk_div0", "video_pll_foutvco", TOP_CRG, 0x20, 8, 4, + NO_DIV_EN, MUX_TYPE_DIV, 2, 15), + DIV(TOP_PERI_QSPI0_SSI_CLK_DIV1, + "peri1_qspi_ssi_clk_div1", "audio1_pll_foutvco", TOP_CRG, 0x20, 0, 8, + NO_DIV_EN, MUX_TYPE_DIV, 6, 255), + MUX(TOP_PERI_QSPI_SSI_CLK_MUX0, + "peri1_qspi_ssi_clk", TOP_CRG, 0x20, 12, 1, + peri1_qspi_ssi_clk_parents, CLK_SET_RATE_PARENT), + DIV(TOP_PERI_SPI_SSI_CLK1_DIV, + "peri2_spi_ssi_clk", "audio1_pll_foutvco", TOP_CRG, 0x24, 24, 8, + NO_DIV_EN, MUX_TYPE_DIV, 6, 255), + DIV(TOP_PERI_HIRES_CLK0_DIV, + "peri1_hires_clk", "video_pll_foutvco", TOP_CRG, 0x24, 16, 6, + NO_DIV_EN, MUX_TYPE_DIV, 33, 63), + DIV(TOP_PERI_HIRES_CLK1_DIV, + "peri2_hires_clk", "video_pll_foutvco", TOP_CRG, 0x24, 0, 6, + NO_DIV_EN, MUX_TYPE_DIV, 33, 63), + MUX(TOP_PERI_TDM_SRC_CLK_MUX, + "peri1_tdm_src_clk", TOP_CRG, 0x28, 25, 1, + peri1_tdm_src_clk_parents, CLK_SET_RATE_PARENT), + FIXED_FACTOR(UART_SCLK_100M, + "uart_sclk", "gmac_pll_foutpostdiv", 1, 10), + FIXED_FACTOR(PERI1_UART_SCLK, + "peri1_uart_sclk", "uart_sclk", 1, 1), + FIXED_FACTOR(PERI2_UART_SCLK, + "peri2_uart_sclk", "uart_sclk", 1, 1), + DIV(TOP_PERI_PDM_MCLK_DIV, + "peri1_pdm_mclk", "pdm_clk_mux", TOP_CRG, 0x2c, 24, 8, + NO_DIV_EN, MUX_TYPE_DIV, 10, 255), + MUX(TOP_PERI_PDM_MCLK_MUX, + "pdm_clk_mux", TOP_CRG, 0x28, 22, 1, + pdm_clk_mux_parents, CLK_SET_RATE_PARENT), + DIV(TOP_PERI_QSPI1_SSI_CLK_DIV0, + "peri2_qspi_ssi_clk_div0", "video_pll_foutvco", TOP_CRG, 0x28, 16, 4, + NO_DIV_EN, MUX_TYPE_DIV, 2, 15), + DIV(TOP_PERI_QSPI1_SSI_CLK_DIV1, + "peri2_qspi_ssi_clk_div1", "audio1_pll_foutvco", TOP_CRG, 0x28, 8, 8, + NO_DIV_EN, MUX_TYPE_DIV, 6, 255), + MUX(TOP_PERI_QSPI_SSI_CLK_MUX1, + "peri2_qspi_ssi_clk", TOP_CRG, 0x28, 20, 1, + peri2_qspi_ssi_clk_parents, CLK_SET_RATE_PARENT), + DIV(TOP_PERI_MST_CLK1_DIV, + "peri3_mst_aclk", "video_pll_foutvco", TOP_CRG, 0x28, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 6, 15), + DIV(TOP_PERI_EMMC_REF_CLK_DIV, + "emmc_ref_clk", "emmc_ref_clk_mux", TOP_CRG, 0x28, 0, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_PERI_EMMC_REF_CLK_MUX, + "emmc_ref_clk_mux", TOP_CRG, 0x2c, 20, 1, + emmc_ref_clk_mux_parents, CLK_SET_RATE_PARENT), + FIXED_FACTOR(PERI1_PWM_CLK, + "peri1_pwm_clk", "gmac_pll_fout1ph0", 1, 10), + FIXED_FACTOR(PERI2_PWM_CLK, + "peri2_pwm_clk", "gmac_pll_fout1ph0", 1, 10), + FIXED_FACTOR(I2C_IC_CLK, + "i2c_ic_clk", "gmac_pll_foutpostdiv", 1, 10), + MUX(TOP_PAD_SENSOR_VCLK_MUX0, + "pad_sensor_vclk0_mux", TOP_CRG, 0x2c, 16, 2, + pad_sensor_vclk0_mux_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + DIV(TOP_PAD_SENSOR_VCLK0_DIV, + "top_pad_sensor_vclk0_div", "pad_sensor_vclk0_mux", TOP_CRG, 0x2c, 0, 8, + NO_DIV_EN, MUX_TYPE_DIV, 16, 255), + MUX(TOP_PAD_SENSOR_VCLK_MUX1, + "pad_sensor_vclk1_mux", TOP_CRG, 0x2c, 18, 2, + pad_sensor_vclk1_mux_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + DIV(TOP_PAD_SENSOR_VCLK1_DIV, + "top_pad_sensor_vclk1_div", "pad_sensor_vclk1_mux", TOP_CRG, 0x2c, 8, 8, + NO_DIV_EN, MUX_TYPE_DIV, 16, 255), + MUX(TOP_TEE_CLK_MUX, + "tee_clk_mux", TOP_CRG, 0x30, 0, 1, + tee_clk_mux_parents, CLK_SET_RATE_PARENT), + DIV_CLOSEST(TOP_TEE_CLK_DIV, + "tee_clk", "tee_clk_mux", TOP_CRG, 0x30, 4, 8, + NO_DIV_EN, MUX_TYPE_DIV, 7, 255), + DIV(TOP_USB_BUS_ACLK_DIV, + "clkgen_usb_ss_bus_clk", "video_pll_fout1ph0", TOP_CRG, 0x34, 8, 3, + NO_DIV_EN, MUX_TYPE_DIV, 2, 7), + DIV(TOP_USB_DP_AUX_CLK_DIV, + "clkgen_usb_ss_aux_clk", "video_pll_foutvco", TOP_CRG, 0x34, 0, 8, + NO_DIV_EN, MUX_TYPE_DIV, 165, 255), + DIV(TOP_VP_ACLK_DIV, + "vp_aclk", "vp_aclk_mux", TOP_CRG, 0x38, 24, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_VP_ACLK_MUX, + "vp_aclk_mux", TOP_CRG, 0x38, 28, 1, + vp_aclk_mux_parents, CLK_SET_RATE_PARENT), + DIV(TOP_VP_G2D_CCLK_DIV, + "g2d_cclk", "g2d_cclk_mux", TOP_CRG, 0x38, 20, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_VP_G2D_CCLK_MUX, + "g2d_cclk_mux", TOP_CRG, 0x38, 16, 2, + g2d_cclk_mux_parents, CLK_SET_RATE_PARENT), + DIV(TOP_VP_VDEC_CCLK_DIV, + "vdec_cclk", "vdec_cclk_mux", TOP_CRG, 0x38, 12, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_VP_VDEC_CCLK_MUX, + "vdec_cclk_mux", TOP_CRG, 0x38, 8, 2, + vdec_cclk_mux_parents, CLK_SET_RATE_PARENT), + DIV(TOP_VP_VENC_CCLK_DIV, + "venc_cclk", "venc_cclk_mux", TOP_CRG, 0x38, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 5, 15), + MUX(TOP_VP_VENC_CCLK_MUX, + "venc_cclk_mux", TOP_CRG, 0x38, 0, 2, + venc_cclk_mux_parents, CLK_SET_RATE_PARENT), + DIV(TOP_NPU_ACLK_DIV, + "npu_aclk", "npu_aclk_mux", TOP_CRG, 0x3c, 12, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_NPU_ACLK_MUX, + "npu_aclk_mux", TOP_CRG, 0x3c, 8, 2, + npu_aclk_mux_parents, CLK_SET_RATE_PARENT), + DIV(TOP_NPU_CCLK_DIV, + "npu_cclk", "npu_cclk_mux", TOP_CRG, 0x3c, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + MUX(TOP_NPU_CCLK_MUX, + "npu_cclk_mux", TOP_CRG, 0x3c, 0, 2, + npu_cclk_mux_parents, CLK_SET_RATE_PARENT), + DIV(TOP_USB_USB20_SCAN_REF_CLK_DIV, + "clkgen_usb20phy_scan_ref_clk", "dpu1_pll_foutvco", TOP_CRG, 0x40, 16, 4, + NO_DIV_EN, MUX_TYPE_DIV, 5, 15), + DIV(TOP_USB_SCAN_REF_CLK3_DIV, + "clkgen_c10phy_scan_ref_clk3", "dpu1_pll_foutvco", TOP_CRG, 0x40, 12, 4, + NO_DIV_EN, MUX_TYPE_DIV, 3, 15), + DIV(TOP_USB_SCAN_REF_CLK2_DIV, + "clkgen_c10phy_scan_ref_clk2", "gmac_pll_foutvco", TOP_CRG, 0x40, 8, 4, + NO_DIV_EN, MUX_TYPE_DIV, 5, 15), + DIV(TOP_USB_SCAN_REF_CLK1_DIV, + "clkgen_c10phy_scan_ref_clk1", "gmac_pll_foutvco", TOP_CRG, 0x40, 4, 4, + NO_DIV_EN, MUX_TYPE_DIV, 6, 15), + DIV(TOP_USB_SCAN_REF_CLK0_DIV, + "clkgen_c10phy_scan_ref_clk0", "dpu1_pll_foutvco", TOP_CRG, 0x40, 0, 4, + NO_DIV_EN, MUX_TYPE_DIV, 6, 15), + GATE(SW_TOP_PAD_SENSOR_VCLK0_EN, + "top_pad_sensor_vclk0", "top_pad_sensor_vclk0_div", TOP_CRG, 0x200, 4), + GATE(SW_TOP_PAD_SENSOR_VCLK1_EN, + "top_pad_sensor_vclk1", "top_pad_sensor_vclk1_div", TOP_CRG, 0x200, 5), + /* CPU SS */ + MUX(C908_CPU_TO_CDE_CLK_MUX, + "c908_cpu_clk", CPU_SS_CLK_SYSREG, 0x0, 0, 1, + c908_cpu_clk_parents, CLK_SET_RATE_PARENT), + MUX(C920_CPU_TO_CDE_CLK_MUX, + "c920_cpu_clk", CPU_SS_CLK_SYSREG, 0x4, 0, 1, + c920_cpu_clk_parents, CLK_SET_RATE_PARENT), + /* DDR SS */ + GATE(DDR0_PHY_DFICLK_EN, + "ddr0_phy_dficlk", "ddr_pll_foutpostdiv", DDR0_SYSREG, 0x8, 3), + GATE(DDR0_DDRC_ACLK_EN, + "ddr0_aclk", "ddr_pll_foutpostdiv", DDR0_SYSREG, 0x8, 2), + GATE(DDR0_DDRC_CCLK_EN, + "ddr0_cclk", "ddr_pll_foutpostdiv", DDR0_SYSREG, 0x8, 1), + GATE(DDR0_SBR_CLK_EN, + "ddr0_sbr_clk", "ddr_pll_foutpostdiv", DDR0_SYSREG, 0x8, 0), + GATE(DDR1_PHY_DFICLK_EN, + "ddr1_phy_dficlk", "ddr_pll_foutpostdiv", DDR1_SYSREG, 0x8, 3), + GATE(DDR1_DDRC_ACLK_EN, + "ddr1_aclk", "ddr_pll_foutpostdiv", DDR1_SYSREG, 0x8, 2), + GATE(DDR1_DDRC_CCLK_EN, + "ddr1_cclk", "ddr_pll_foutpostdiv", DDR1_SYSREG, 0x8, 1), + GATE(DDR1_SBR_CLK_EN, + "ddr1_sbr_clk", "ddr_pll_foutpostdiv", DDR1_SYSREG, 0x8, 0), + GATE_SHARED(DDR_PLL_CLK_EN, + "ddr_pll_clk_en", "ddr_pll_clkout", SLC_DUAL_SYSREG, 0x18, 16, + &share_cnt_ddr_pll_clk_en), + MUX(DDR_PLL_CLK_SEL, "ddr_pll_clkout", SLC_DUAL_SYSREG, 0x18, 17, 2, + ddr_pll_clkout_parents, CLK_SET_RATE_PARENT), +}; + +static struct zhihe_clk_info info_gpu[] = { + FIXED_FACTOR(GPU_TOP_SYS_CLK, + "gpu_top_sys_clk", "top_cfg_aclk", 1, 1), + FIXED_FACTOR(GPU_PCLK_CDT, + "gpu_pclk_cdt", "gpu_top_sys_clk", 1, 2), + GATE(SW_PWR_WRAP_DFMU_PCLK_EN, + "gpu_top_pclk", "gpu_pclk_cdt", GPU_SS_PWRAP_CLK_EN, 0, 7), + GATE(SW_PWR_WRAP_GPU_SYS_CLK_EN, + "gpu_top_aclk", "gpu_top_sys_clk", GPU_SS_PWRAP_CLK_EN, 0, 3), + GATE(SW_PWR_WRAP_DFMU_CORE_CLK_EN, + "gpu_dfmu_core_clk", "top_cfg_aclk", GPU_SS_PWRAP_CLK_EN, 0, 1), + GATE(SW_PWR_WRAP_GPU_CORE_CLK_EN, + "gpu_core_clk", "top_gpu_core_clk", GPU_SS_PWRAP_CLK_EN, 0, 0), +}; + +static struct zhihe_clk_info info_pcie[] = { + FIXED_FACTOR(PCIE_SS_APB_CLK, + "pcie_ss_apb_clk", "gmac_pll_foutpostdiv", 1, 10), + GATE(E16PHY_PCLK_EN, + "e16phy_apbs_pclk", "pcie_ss_apb_clk", PCIE_CLK_EN, 0x8, 0), + GATE(SATA_PMALIVE_CLK_EN, + "sata_pmalive_clk", "aon_osc_clk_logic", PCIE_CLK_EN, 0x14, 0), + GATE(SATA_RXOOB0_CLK_EN, + "sata_rxoob0_clk", "pcie_ss_apb_clk", PCIE_CLK_EN, 0x14, 16), + GATE(SATA_RXOOB1_CLK_EN, + "sata_rxoob1_clk", "pcie_ss_apb_clk", PCIE_CLK_EN, 0x14, 20), + GATE(SATA_GEN3X2_ACLK_EN, + "sata_gen3x2_aclk", "pcie_ss_axi_m_aclk", PCIE_CLK_EN, 0x10, 8), + GATE(PCIE_DM_GEN3X4_AUX_CLK_EN, + "pcie_dm_gen3x4_aux_clk", "aon_osc_clk_logic", PCIE_CLK_EN, 0x20, 12), + GATE(PCIE_DM_GEN3X4_SLV_ACLK_EN, + "pcie_dm_gen3x4_slv_aclk", "top_cfg_aclk", PCIE_CLK_EN, 0x20, 0), + GATE(PCIE_DM_GEN3X4_MST_ACLK_EN, + "pcie_dm_gen3x4_mst_aclk", "pcie_ss_axi_m_aclk", PCIE_CLK_EN, 0x20, 8), + GATE(PCIE_DM_GEN3X4_PCLK_EN, + "pcie_dm_gen3x4_pclk", "pcie_ss_apb_clk", PCIE_CLK_EN, 0x20, 4), + GATE(PCIE_RP_GEN3X1_AUX_CLK_EN, + "pcie_rp_gen3x1_aux_clk", "aon_osc_clk_logic", PCIE_CLK_EN, 0x24, 12), + GATE(PCIE_RP_GEN3X1_SLV_ACLK_EN, + "pcie_rp_gen3x1_slv_aclk", "top_cfg_aclk", PCIE_CLK_EN, 0x24, 0), + GATE(PCIE_RP_GEN3X1_MST_ACLK_EN, + "pcie_rp_gen3x1_mst_aclk", "pcie_ss_axi_m_aclk", PCIE_CLK_EN, 0x24, 8), + GATE(PCIE_RP_GEN3X1_PCLK_EN, + "pcie_rp_gen3x1_pclk", "pcie_ss_apb_clk", PCIE_CLK_EN, 0x24, 4), +}; + +static struct zhihe_clk_info info_usb[] = { + GATE(DPTX_I2S_CLK_EN, + "usb_dptx_i2s_clk", "audio0_pll_foutvco", USB_CLK_EN, 0x4, 16), + GATE(DPTX_IPI_CLK_EN, + "usb_dptx_ipi_clk", "usb_ss_gtc_clk", USB_CLK_EN, 0x4, 12), + GATE(DPTX_AUX_CLK_EN, + "usb_dptx_aux_clk", "clkgen_usb_ss_aux_clk", USB_CLK_EN, 0x4, 8), + FIXED_FACTOR(USB_SS_GTC_CLK, + "usb_ss_gtc_clk", "gmac_pll_foutpostdiv", 1, 10), + GATE(DPTX_GTC_CLK_EN, + "usb_dptx_gtc_clk", "usb_ss_gtc_clk", USB_CLK_EN, 0x4, 4), + GATE(DPTX_PCLK_EN, + "usb_dptx_pclk", "usb_ss_gtc_clk", USB_CLK_EN, 0x4, 0), + GATE(USB31_REF_CLK_EN, + "usb31_ref_clk", "aon_osc_clk_logic", USB_CLK_EN, 0x8, 16), + GATE(USB31_SLV_AFENCE_ACLK_EN, + "usb31_slv_afence_aclk", "aon_osc_clk_logic", USB_CLK_EN, 0x8, 20), + FIXED_FACTOR(USB_SS_PAD_OSC_CLK_1M, + "usb_ss_pad_osc_clk_1m", "aon_osc_clk_logic", 1, 24), + GATE(USB31_SUSPEND_CLK_EN, + "usb31_suspend_clk", "usb_ss_pad_osc_clk_1m", USB_CLK_EN, 0x8, 8), + GATE(USB31_BUS_CLK_EN, + "usb31_bus_clk", "clkgen_usb_ss_bus_clk", USB_CLK_EN, 0x8, 4), + GATE(USB31_PCLK_EN, + "usb31_pclk", "usb_ss_gtc_clk", USB_CLK_EN, 0x8, 0), + GATE(C10PHY_SUSPEND_CLK_EN, + "usb_c10phy_suspend_clk", "usb_ss_pad_osc_clk_1m", USB_CLK_EN, 0xc, 4), + GATE(C10PHY_PCLK_EN, + "usb_c10phy_pclk", "usb_ss_gtc_clk", USB_CLK_EN, 0xc, 0), + FIXED_FACTOR(USB20_CORE_CLK, + "usb20_core_clk", "aon_osc_clk_logic", 1, 1), + GATE(USB_SS_PERI2_CFG_ACLK_EN, + "usb_peri2_cfg_aclk", "aon_osc_clk_logic", USB_CLK_EN, 0x20, 4), + GATE(USB20_BUS_CLK, + "usb20_bus_clk", "clkgen_usb_ss_bus_clk", USB_CLK_EN, 0x10, 24), +}; + +static struct zhihe_clk_info info_vi[] = { + GATE(VI_VSE_CLK_EN, + "dw200_vseclk", "vi_pre_vse_clk_div", VI_CLK, 0, 29), + GATE(VI_VSEOUT_CLK_EN, + "dw200_vseout_clk", "vi_pre_vse_clk_div", VI_CLK, 0, 22), + DIV(VI_PRE_VSE_CLK_DIV_NUM, + "vi_pre_vse_clk_div", "gmac_pll_foutpostdiv", VI_CLK, 0xc, 4, 4, + 25, MUX_TYPE_DIV, 1, 15), + GATE(VI_DWE_CLK_EN, + "dw200_dweclk", "vi_pre_dwe_clk_div", VI_CLK, 0, 28), + GATE(VI_DW_SCLK_EN, + "dw_sclk", "vi_pre_dwe_clk_div", VI_CLK, 0, 30), + DIV(VI_PRE_DWE_CLK_DIV_NUM, + "vi_pre_dwe_clk_div", "video_pll_foutvco", VI_CLK, 0xc, 8, 4, + 26, MUX_TYPE_DIV, 3, 15), + DIV(VI_PRE_AXI_CLK_DIV_NUM, + "vi_preocc_aclk", "video_pll_foutvco", VI_CLK, 0xc, 0, 4, + 24, MUX_TYPE_DIV, 3, 15), + GATE(VI_DW200_ACLK_EN, + "dw200_aclk", "vi_preocc_aclk", VI_CLK, 0, 27), + GATE(VI_DW200_HCLK_EN, + "dw200_hclk", "top_cfg_aclk", VI_CLK, 0, 26), + DIV(VI_PRE_DECOMP_CLK_DIV_NUM, + "vi_pre_decomp_clk", "audio0_pll_foutvco", VI_CLK, 0xc, 20, 4, + 29, MUX_TYPE_DIV, 4, 15), + GATE(VI_DECOMP_CLK_EN, + "decomp_clk", "vi_pre_decomp_clk", VI_CLK, 0, 25), + GATE(VI_DECOUT_CLK_EN, + "decout_clk", "vi_pre_decomp_clk", VI_CLK, 0, 21), + DIV(VI_PRE_COMP_CLK_DIV_NUM, + "vi_pre_comp_clk", "audio0_pll_foutvco", VI_CLK, 0xc, 16, 4, + 28, MUX_TYPE_DIV, 4, 15), + GATE(VI_COMP0_CLK_EN, + "comp0_clk", "vi_pre_comp_clk", VI_CLK, 0, 23), + GATE(VI_COMP1_CLK_EN, + "comp1_clk", "vi_pre_comp_clk", VI_CLK, 0, 24), + GATE(VI_COMP_ACLK_EN, + "comp_aclk", "vi_preocc_aclk", VI_CLK, 0, 19), + GATE(VI_COMP_PCLK_EN, + "comp_pclk", "vi_pclk", VI_CLK, 0, 18), + GATE(VI_MIPI0CSI0_PCLK_EN, + "mipi0_csi0_pclk", "vi_pclk", VI_CLK, 0, 0), + GATE(VI_MIPI0CSI1_PCLK_EN, + "mipi0_csi1_pclk", "vi_pclk", VI_CLK, 0, 1), + GATE(VI_MIPI1CSI0_PCLK_EN, + "mipi1_csi0_pclk", "vi_pclk", VI_CLK, 0, 6), + GATE(VI_MIPI1CSI1_PCLK_EN, + "mipi1_csi1_pclk", "vi_pclk", VI_CLK, 0, 7), + GATE(VI_VIPRE_PCLK_EN, + "vipre_pclk", "vi_pclk", VI_CLK, 0, 12), + GATE(VI_MIPI0CSI0_FPCLK_EN, + "mipi0_csi0_fpclk", "vi_pclk", VI_CLK, 0x4, 8), + GATE(VI_MIPI0CSI1_FPCLK_EN, + "mipi0_csi1_fpclk", "vi_pclk", VI_CLK, 0x4, 9), + GATE(VI_MIPI1CSI0_FPCLK_EN, + "mipi1_csi0_fpclk", "vi_pclk", VI_CLK, 0x4, 10), + GATE(VI_MIPI1CSI1_FPCLK_EN, + "mipi1_csi1_fpclk", "vi_pclk", VI_CLK, 0x4, 11), + FIXED_FACTOR(VI_PCLK, + "vi_pclk", "top_cfg_aclk", 1, 2), + MUX(VI_ISP_IF_REF_SWITCH_SEL, + "isp_if_ref_mux", VI_CLK, 0x8, 22, 2, + isp_if_ref_mux_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + GATE(VI_VIPRE_SCLK_EN, + "vipre_sclk", "isp_if_ref_clk_div", VI_CLK, 0, 15), + DIV_CLOSEST(VI_PRE_ISP_IF_CLK_DIV_NUM, + "isp_if_ref_clk_div", "isp_if_ref_mux", VI_CLK, 0x8, 11, 4, + 26, MUX_TYPE_DIV, 3, 15), + GATE(VI_ISP_CLK_EN, + "isp_entire_clk", "video_pll_foutvco", VI_CLK, 0, 17), + DIV(VI_PRE_ISP_CORE_CLK_DIV_NUM, + "isp_core_clk", "video_pll_foutvco", VI_CLK, 0x8, 16, 4, + 27, MUX_TYPE_DIV, 4, 15), + GATE(VI_ISPOUT_CLK_EN, + "ispout_clk", "isp_core_clk", VI_CLK, 0, 20), + GATE(VI_VIPRE_ACLK_EN, + "vipre_aclk", "vi_preocc_aclk", VI_CLK, 0, 16), + GATE(VI_VIPRE_I0_PIXCLK_EN, + "vipre_m0if_clk", "vi_preocc_mipi0_ifclk", VI_CLK, 0, 13), + GATE(VI_MIPI0_CSI0_PIXCLK_EN, + "mipi0_csi0if_clk", "vi_preocc_mipi0_ifclk", VI_CLK, 0, 4), + GATE(VI_MIPI0_CSI1_PIXCLK_EN, + "mipi0_csi1if_clk", "vi_preocc_mipi0_ifclk", VI_CLK, 0, 5), + DIV_CLOSEST(VI_PRE_MIPI0_PIXCLK_DIV_NUM, + "vi_preocc_mipi0_ifclk", "vi_preocc_mipi0_ifclk_mux", VI_CLK, 0x8, 0, 4, + 24, MUX_TYPE_DIV, 3, 15), + MUX(VI_MIPI0_PIX_REF_SWITCH_SEL, + "vi_preocc_mipi0_ifclk_mux", VI_CLK, 0x8, 20, 1, + vi_preocc_mipi0_ifclk_mux_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + GATE(VI_VIPRE_I1_PIXCLK_EN, + "vipre_m1if_clk", "vi_preocc_mipi1_ifclk", VI_CLK, 0, 14), + GATE(VI_MIPI1_CSI0_PIXCLK_EN, + "mipi1_csi0if_clk", "vi_preocc_mipi1_ifclk", VI_CLK, 0, 10), + GATE(VI_MIPI1_CSI1_PIXCLK_EN, + "mipi1_csi1if_clk", "vi_preocc_mipi1_ifclk", VI_CLK, 0, 11), + DIV_CLOSEST(VI_PRE_MIPI1_PIXCLK_DIV_NUM, + "vi_preocc_mipi1_ifclk", "vi_preocc_mipi1_ifclk_mux", VI_CLK, 0x8, 4, 4, + 25, MUX_TYPE_DIV, 3, 15), + MUX(VI_MIPI1_PIX_REF_SWITCH_SEL, + "vi_preocc_mipi1_ifclk_mux", VI_CLK, 0x8, 21, 1, + vi_preocc_mipi1_ifclk_mux_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT), + GATE(VI_MIPI1B_CFGCLK_EN, + "mipi1_csi0_cfgclk", "aon_osc_clk_logic", VI_CLK, 0, 9), + GATE(VI_MIPI1A_CFGCLK_EN, + "mipi1_csi1_cfgclk", "aon_osc_clk_logic", VI_CLK, 0, 8), + GATE(VI_MIPI0B_CFGCLK_EN, + "mipi0_csi0_cfgclk", "aon_osc_clk_logic", VI_CLK, 0, 3), + GATE(VI_MIPI0A_CFGCLK_EN, + "mipi0_csi1_cfgclk", "aon_osc_clk_logic", VI_CLK, 0, 2), + GATE(VI_X2H0_CLK_EN, + "vi_x2h0_clk", "top_cfg_aclk", VI_CLK, 0x4, 5), + GATE(VI_X2H1_CLK_EN, + "vi_x2h1_clk", "top_cfg_aclk", VI_CLK, 0x4, 6), + GATE(VI_X2H2_CLK_EN, + "vi_x2h2_clk", "top_cfg_aclk", VI_CLK, 0x4, 7), + GATE(VI_REC_PCLK_EN, + "vi_rec_pclk", "top_cfg_aclk", VI_CLK, 0x4, 13), + GATE(VI_REC_ACLK_EN, + "vi_rec_aclk", "top_cfg_aclk", VI_CLK, 0x4, 14), + GATE(VI_MISC_CTRL_H0CLK_CLK_EN, + "vi_misc_ctrl_h0clk", "top_cfg_aclk", VI_MISC_CTRL, 0x0, 1), + GATE(VI_MISC_CTRL_H1CLK_CLK_EN, + "vi_misc_ctrl_h1clk", "top_cfg_aclk", VI_MISC_CTRL, 0x0, 2), + GATE(VI_MISC_CTRL_ISP_ACLK_CLK_EN, + "vi_misc_ctrl_isp_aclk", "top_cfg_aclk", VI_MISC_CTRL, 0x0, 3), + GATE(VI_MISC_CTRL_ISP_SCLK_CLK0_EN, + "vi_misc_ctrl_isp_sclk0", "top_cfg_aclk", VI_MISC_CTRL, 0x0, 4), + GATE(VI_MISC_CTRL_ISP_SCLK_CLK1_EN, + "vi_misc_ctrl_isp_sclk1", "top_cfg_aclk", VI_MISC_CTRL, 0x0, 5), + GATE(VI_MISC_CTRL_ISP_SCLK_CLK2_EN, + "vi_misc_ctrl_isp_sclk2", "top_cfg_aclk", VI_MISC_CTRL, 0x0, 6), + GATE(VI_MISC_CTRL_ISP_SCLK_CLK3_EN, + "vi_misc_ctrl_isp_sclk3", "top_cfg_aclk", VI_MISC_CTRL, 0x0, 7), + GATE(VI_MISC_CTRL_ISP_CORE_CLK_EN, + "vi_misc_ctrl_isp_core_clk", "isp_core_clk", VI_MISC_CTRL, 0x0, 8), + GATE(VI_MISC_CTRL_ISP_FLEXA_CLK_EN, + "vi_misc_ctrl_isp_flexa_clk", "isp_core_clk", VI_MISC_CTRL, 0x0, 9), + GATE(VI_MISC_CTRL_ISP_MCM_CLK_EN, + "vi_misc_ctrl_isp_mcm_clk", "isp_core_clk", VI_MISC_CTRL, 0x0, 10), + GATE(VI_MISC_CTRL_BUS_CLK_GT_DISABLE, + "vi_misc_ctrl_bus_clk", "isp_core_clk", VI_MISC_CTRL, 0x0, 11), +}; + +static struct zhihe_clk_info info_vp[] = { + GATE(VP_DECOMP_EXTPCLK_EN, "vp_decomp_extpclk", "top_cfg_aclk", VP_CLK, 0, 23), + GATE(VP_COMP_EXTPCLK_EN, "vp_comp_extpclk", "top_cfg_aclk", VP_CLK, 0, 22), + GATE(VP_DECOMP_ACLK_EN, "vp_decomp_aclk", "vp_aclk", VP_CLK, 0, 14), + GATE(VP_DECOMP_CCLK_EN, "vp_decomp_cclk", "vp_decomp_clk_div", VP_CLK, 0, 13), + GATE(VP_DECOMP_PCLK_EN, "vp_decomp_pclk", "top_cfg_aclk", VP_CLK, 0, 12), + GATE(VP_COMP_ACLK_EN, "vp_comp_aclk", "vp_aclk", VP_CLK, 0, 11), + GATE(VP_COMP_CCLK_EN, "vp_comp_cclk", "vp_comp_clk_div", VP_CLK, 0, 10), + GATE(VP_COMP_PCLK_EN, "vp_comp_pclk", "top_cfg_aclk", VP_CLK, 0, 9), + GATE(VP_G2D_ACLK_EN, "vp_g2d_aclk", "vp_aclk", VP_CLK, 0, 8), + GATE(VP_G2D_CCLK_EN, "vp_g2d_cclk", "g2d_cclk", VP_CLK, 0, 7), + GATE(VP_G2D_PCLK_EN, "vp_g2d_pclk", "top_cfg_aclk", VP_CLK, 0, 6), + GATE(VP_VENC_ACLK_EN, "vp_venc_aclk", "vp_aclk", VP_CLK, 0, 5), + GATE(VP_VENC_CCLK_EN, "vp_venc_cclk", "venc_cclk", VP_CLK, 0, 4), + GATE(VP_VENC_PCLK_EN, "vp_venc_pclk", "top_cfg_aclk", VP_CLK, 0, 3), + GATE(VP_VDEC_ACLK_EN, "vp_vdec_aclk", "vp_aclk", VP_CLK, 0, 2), + GATE(VP_VDEC_CCLK_EN, "vp_vdec_cclk", "vdec_cclk", VP_CLK, 0, 1), + GATE(VP_VDEC_PCLK_EN, "vp_vdec_pclk", "top_cfg_aclk", VP_CLK, 0, 0), + DIV(VP_DECOMP_DIV_NUM, "vp_decomp_clk_div", "vp_aclk", VP_CLK, 0x4, 16, 4, + 20, MUX_TYPE_DIV, 2, 15), + DIV(VP_COMP_DIV_NUM, "vp_comp_clk_div", "vp_aclk", VP_CLK, 0x4, 8, 4, + 12, MUX_TYPE_DIV, 2, 15), +}; + +static struct zhihe_clk_info info_vo[] = { + GATE(VO_X2H1_CLK_EN, "vo_x2h1_clk", "top_cfg_aclk", VO_CLK, 0, 24), + GATE(VO_X2H0_CLK_EN, "vo_x2h0_clk", "top_cfg_aclk", VO_CLK, 0, 23), + GATE(VO_ARB_ACLK_EN, "vo_arb_aclk", "vo_preocc_aclk", VO_CLK, 0, 19), + GATE(VO_DPU_ACLK_EN, "vo_dpu_aclk", "vo_preocc_aclk", VO_CLK, 0, 4), + GATE(VO_AUXDISP_ACLK_EN, "vo_disp_aclk", "vo_preocc_aclk", VO_CLK, 0, 7), + GATE(VO_DECOMP_ACLK_EN, "vo_decomp_aclk", "vo_preocc_aclk", VO_CLK, 0, 17), + DIV(VO_ACLK_DIV_NUM, "vo_preocc_aclk", "video_pll_foutvco", VO_CLK, 0x8, 0, 4, + 4, MUX_TYPE_DIV, 3, 15), + GATE(VO_DECOMP_PCLK_EN, "vo_decomp_pclk", "vo_pclk", VO_CLK, 0, 14), + GATE(VO_HDMI_PCLK_EN, "vo_hdmi_pclk", "vo_pclk", VO_CLK, 0, 8), + GATE(VO_MIPI_PCLK_EN, "vo_mipi_pclk", "vo_pclk", VO_CLK, 0, 12), + GATE(VO_AUXDISP_PCLK_EN, "vo_auxdisp_pclk", "vo_pclk", VO_CLK, 0, 6), + GATE(VO_ARB_PCLK_EN, "vo_arb_pclk", "vo_pclk", VO_CLK, 0, 18), + FIXED_FACTOR(VO_PCLK, "vo_pclk", "top_cfg_aclk", 1, 2), + GATE(VO_DECOMP0_CLK_EN, "vo_decomp0_clk", "vo_decomp_div", VO_CLK, 0, 15), + GATE(VO_DECOMP1_CLK_EN, "vo_decomp1_clk", "vo_decomp_div", VO_CLK, 0, 16), + DIV(VO_DECOMP_DIV_NUM, "vo_decomp_div", "video_pll_foutvco", VO_CLK, 0x8, 16, 4, + 20, MUX_TYPE_DIV, 12, 15), + GATE(VO_MIPI_CFGCLK_EN, "vo_mipi_cfgclk", "aon_osc_clk_logic", VO_CLK, 0, 13), + GATE(VO_HDMI_SFRCLK_EN, "vo_hdmi_sfrclk", "aon_osc_clk_logic", VO_CLK, 0, 11), + GATE(VO_CEC_CLK_EN, "vo_hdmi_cecclk", "aon_rtc_clk", VO_CLK, 0, 10), + GATE(VO_I2S_CLK_EN, "vo_hdmi_i2sclk", "audio0_pll_foutvco", VO_CLK, 0, 9), + GATE(VO_CH0_PIXCLK_EN, "dpu0_pixclk", "vo_pll0_div", VO_CLK, 0, 0), + DIV(VO_PLL0_DIV_NUM, "vo_pll0_div", "dpu0_pll_foutpostdiv", VO_CLK, 0x4, 0, 8, + 8, MUX_TYPE_DIV, 2, 255), + GATE(VO_CH1_PIXCLK_EN, "dpu1_pixclk", "vo_pll1_div", VO_CLK, 0, 1), + DIV(VO_PLL1_DIV_NUM, "vo_pll1_div", "dpu1_pll_foutpostdiv", VO_CLK, 0x4, 10, 8, + 18, MUX_TYPE_DIV, 2, 255), + GATE(VO_CH2_PIXCLK_EN, "dpu2_pixclk", "vo_pll2_div", VO_CLK, 0, 5), + DIV(VO_PLL2_DIV_NUM, "vo_pll2_div", "dpu2_pll_foutpostdiv", VO_CLK, 0x4, 20, 8, + 28, MUX_TYPE_DIV, 2, 255), + GATE(VO_DPU_HCLK_EN, "vo_dpuc_hclk", "top_cfg_aclk", VO_CLK, 0, 2), + GATE(VO_DPUC_CLK_EN, "vo_dpuc_clk", "vo_dpuc_div", VO_CLK, 0, 3), + DIV(VO_DPUC_DIV_NUM, "vo_dpuc_div", "video_pll_foutvco", VO_CLK, 0x8, 8, 4, + 12, MUX_TYPE_DIV, 3, 15), + MUX(VO_MIPI_PIXCLK, "vo_mipi_pixclk", VO_PATH_CTRL, 0x0, 0, 2, + vo_mipi_pixclk_mux_parents, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), + MUX(VO_HDMI_PIXCLK, "vo_hdmi_pixclk", VO_PATH_CTRL, 0x0, 2, 2, + vo_hdmi_pixclk_mux_parents, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), + MUX(VO_DPTX_PIXCLK, "vo_dptx_pixclk", VO_PATH_CTRL, 0x0, 4, 2, + vo_dptx_pixclk_mux_parents, CLK_SET_RATE_PARENT|CLK_SET_RATE_NO_REPARENT), +}; + +static struct zhihe_clk_info info_npu[] = { + GATE(SW_SEMA_PCLK_EN, "npu_clkgen_sema_pclk", "top_cfg_aclk", NPU_CLK, 0, 23), + GATE(SW_SEMA_ACLK_EN, "npu_clkgen_sema_aclk", "npu_aclk", NPU_CLK, 0, 22), + GATE(SW_NPU_X2P_ACLK_EN, "npu_x2p_aclk", "top_cfg_aclk", NPU_CLK, 0, 21), + GATE(SW_NPU_X2H_ACLK_EN, "npu_x2h_aclk", "top_cfg_aclk", NPU_CLK, 0, 20), + GATE(SW_NPU_IP_HCLK_EN, "npu_ip_hclk", "top_cfg_aclk", NPU_CLK, 0, 12), + GATE(SW_NPU_IP_CCLK_EN, "npu_ip_cclk", "npu_cclk", NPU_CLK, 0, 11), + GATE(SW_NPU_IP_ACLK_EN, "npu_ip_aclk", "npu_aclk", NPU_CLK, 0, 10), +}; + +static struct zhihe_clk_info info_peri[] = { + /* PERI0 SS */ + GATE(PERI0_MBOX1_PCLK_EN, + "peri0_mbox1_pclk", "top_cfg_aclk", PERI0_SYSREG, 0, 6), + GATE(PERI0_MBOX0_PCLK_EN, + "peri0_mbox0_pclk", "top_cfg_aclk", PERI0_SYSREG, 0, 5), + GATE(PERI0_WDT0_PCLK_EN, + "peri0_wdt0_pclk", "top_cfg_aclk", PERI0_SYSREG, 0, 4), + GATE(PERI0_TIMER1_PCLK_EN, + "peri0_timer1_pclk", "top_cfg_aclk", PERI0_SYSREG, 0, 3), + GATE(PERI0_TIMER1_CCLK_EN, + "peri0_timer1_cclk", "top_cfg_aclk", PERI0_SYSREG, 0, 2), + GATE(PERI0_TIMER0_PCLK_EN, + "peri0_timer0_pclk", "top_cfg_aclk", PERI0_SYSREG, 0, 1), + GATE(PERI0_TIMER0_CCLK_EN, + "peri0_timer0_cclk", "top_cfg_aclk", PERI0_SYSREG, 0, 0), + /* PERI1 SS */ + GATE(PERI1_UART3_SCLK_EN, + "peri1_clkgen_uart3_sclk", "uart_sclk", PERI1_SYSREG, 0, 31), + GATE(PERI1_UART3_PCLK_EN, + "peri1_clkgen_uart3_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 30), + GATE(PERI1_UART2_SCLK_EN, + "peri1_clkgen_uart2_sclk", "uart_sclk", PERI1_SYSREG, 0, 29), + GATE(PERI1_UART2_PCLK_EN, + "peri1_clkgen_uart2_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 28), + GATE(PERI1_UART1_SCLK_EN, + "peri1_clkgen_uart1_sclk", "uart_sclk", PERI1_SYSREG, 0, 27), + GATE(PERI1_UART1_PCLK_EN, + "peri1_clkgen_uart1_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 26), + GATE(PERI1_UART0_SCLK_EN, + "peri1_clkgen_uart0_sclk", "uart_sclk", PERI1_SYSREG, 0, 25), + GATE(PERI1_UART0_PCLK_EN, + "peri1_clkgen_uart0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 24), + GATE(PERI1_SPI0_SSI_CLK_EN, + "peri1_clkgen_spi0_ssi_clk", "peri1_spi_ssi_clk", PERI1_SYSREG, 0, 23), + GATE(PERI1_SPI0_PCLK_EN, + "peri1_clkgen_spi0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 22), + GATE(PERI1_QSPI0_SSI_CLK_EN, + "peri1_clkgen_qspi0_ssi_clk", "peri1_qspi_ssi_clk", PERI1_SYSREG, 0, 21), + GATE(PERI1_QSPI0_PCLK_EN, + "peri1_clkgen_qspi0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 20), + GATE(PERI1_PWM0_PCLK_EN, + "peri1_clkgen_pwm0_pclk", "peri1_pwm_clk", PERI1_SYSREG, 0, 19), + GATE(PERI1_PWM0_CCLK_EN, + "peri1_clkgen_pwm0_cclk", "peri1_clkgen_pwm0_pclk", PERI1_SYSREG, 0, 18), + GATE(PERI1_MST_BUS_PCLK_EN, + "peri1_clkgen_mst_bus_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 17), + GATE(PERI1_MST_BUS_ACLK_EN, + "peri1_clkgen_mst_bus_aclk", "peri1_mst_aclk", PERI1_SYSREG, 0, 16), + GATE(PERI1_I2S0_SRC_CLK_EN, + "peri1_clkgen_i2s0_src_clk", "peri1_i2s0_src_clk", PERI1_SYSREG, 0, 15), + GATE(PERI1_I2S0_PCLK_EN, + "peri1_clkgen_i2s0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 14), + GATE(PERI1_I2C2_PCLK_EN, + "peri1_clkgen_i2c2_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 13), + GATE(PERI1_I2C2_IC_CLK_EN, + "peri1_clkgen_i2c2_ic_clk", "i2c_ic_clk", PERI1_SYSREG, 0, 12), + GATE(PERI1_I2C1_PCLK_EN, + "peri1_clkgen_i2c1_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 11), + GATE(PERI1_I2C1_IC_CLK_EN, + "peri1_clkgen_i2c1_ic_clk", "i2c_ic_clk", PERI1_SYSREG, 0, 10), + GATE(PERI1_I2C0_PCLK_EN, + "peri1_clkgen_i2c0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 9), + GATE(PERI1_I2C0_IC_CLK_EN, + "peri1_clkgen_i2c0_ic_clk", "i2c_ic_clk", PERI1_SYSREG, 0, 8), + GATE(PERI1_GPIO1_PCLK_EN, + "peri1_clkgen_gpio1_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 7), + GATE(PERI1_GPIO1_DBCLK_EN, + "peri1_clkgen_gpio1_dbclk", "aon_rtc_clk", PERI1_SYSREG, 0, 6), + GATE(PERI1_GPIO0_PCLK_EN, + "peri1_clkgen_gpio0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0, 5), + GATE(PERI1_GPIO0_DBCLK_EN, + "peri1_clkgen_gpio0_dbclk", "aon_rtc_clk", PERI1_SYSREG, 0, 4), + GATE(PERI1_GMAC1_HCLK_EN, + "peri1_gmac1_hclk", "top_cfg_aclk", PERI1_SYSREG, 0, 3), + GATE(PERI1_GMAC1_ACLK_EN, + "peri1_gmac1_aclk", "peri1_mst_aclk", PERI1_SYSREG, 0, 2), + GATE(PERI1_GMAC0_HCLK_EN, + "peri1_gmac0_hclk", "top_cfg_aclk", PERI1_SYSREG, 0, 1), + GATE(PERI1_GMAC0_ACLK_EN, + "peri1_gmac0_aclk", "peri1_mst_aclk", PERI1_SYSREG, 0, 0), + GATE(PERI1_ZGMAC_X2X_ACLK_EN, + "peri1_zgmac0_x2x_aclk", "peri1_mst_aclk", PERI1_SYSREG, 0x4, 25), + GATE(PERI1_GMAC2_HCLK_EN, + "peri1_gmac2_hclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 24), + GATE(PERI1_GMAC2_ACLK_EN, + "peri1_gmac2_aclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 23), + GATE(PERI1_X2H_GMAC2_HCLK_EN, + "peri1_x2h_gmac2_hclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 22), + GATE(PERI1_X2H_GMAC2_ACLK_EN, + "peri1_x2h_gmac2_aclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 21), + GATE(PERI1_CHIP_DBG_PCLK_EN, + "peri1_chip_dbg_pclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 20), + GATE(PERI1_CHIP_DBG_CCLK_EN, + "peri1_chip_dbg_cclk", "aon_osc_clk_logic", PERI1_SYSREG, 0x4, 19), + GATE(PERI1_CHIP_DBG_ACLK_EN, + "peri1_chip_dbg_aclk", "peri1_mst_aclk", PERI1_SYSREG, 0x4, 18), + GATE(PERI1_TDM0_SCLK_EN, + "peri1_tdm0_sclk", "peri1_tdm_src_clk", PERI1_SYSREG, 0x4, 17), + GATE(PERI1_TDM0_PCLK_EN, + "peri1_tdm0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 16), + GATE(PERI1_PDM0_PCLK_EN, + "peri1_pdm0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 15), + GATE(PERI1_PDM0_MCLK_EN, + "peri1_pdm0_mclk", "peri1_pdm_mclk", PERI1_SYSREG, 0x4, 14), + GATE(PERI1_CAN1_PCLK_EN, + "peri1_can1_pclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 13), + GATE(PERI1_CAN1_OSC_CLK_EN, + "peri1_can1_osc_clk", "peri1_hires_clk", PERI1_SYSREG, 0x4, 12), + GATE(PERI1_CAN1_HIRES_CLK_EN, + "peri1_can1_hires_clk", "peri1_can1_osc_clk", PERI1_SYSREG, 0x4, 11), + GATE(PERI1_CAN0_PCLK_EN, + "peri1_can0_pclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 10), + GATE(PERI1_CAN0_OSC_CLK_EN, + "peri1_can0_osc_clk", "peri1_hires_clk", PERI1_SYSREG, 0x4, 9), + GATE(PERI1_CAN0_HIRES_CLK_EN, + "peri1_can0_hires_clk", "peri1_can0_osc_clk", PERI1_SYSREG, 0x4, 8), + GATE(PERI1_PAD_CTRL_PCLK_EN, + "peri1_pad_ctrl_pclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 7), + GATE(PERI1_X2H_GMAC1_HCLK_EN, + "peri1_x2h_gmac1_hclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 3), + GATE(PERI1_X2H_GMAC1_ACLK_EN, + "peri1_x2h_gmac1_aclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 2), + GATE(PERI1_X2H_GMAC0_HCLK_EN, + "peri1_x2h_gmac0_hclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 1), + GATE(PERI1_X2H_GMAC0_ACLK_EN, + "peri1_x2h_gmac0_aclk", "top_cfg_aclk", PERI1_SYSREG, 0x4, 0), + /* PERI2 SS */ + GATE(PERI2_I2S3_PCLK_EN, + "peri2_clkgen_i2s3_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 31), + GATE(PERI2_I2S3_SRC_CLK_EN, + "peri2_clkgen_i2s3_src_clk", "peri2_i2s3_src_clk", PERI2_SYSREG, 0, 30), + GATE(PERI2_I2S2_PCLK_EN, + "peri2_clkgen_i2s2_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 29), + GATE(PERI2_I2S2_SRC_CLK_EN, + "peri2_clkgen_i2s2_src_clk", "peri2_i2s2_src_clk", PERI2_SYSREG, 0, 28), + GATE(PERI2_I2S1_PCLK_EN, + "peri2_clkgen_i2s1_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 27), + GATE(PERI2_I2S1_SRC_CLK_EN, + "peri2_clkgen_i2s1_src_clk", "peri2_i2s1_src_clk", PERI2_SYSREG, 0, 26), + GATE(PERI2_I2C7_IC_CLK_EN, + "peri2_clkgen_i2c7_ic_clk", "i2c_ic_clk", PERI2_SYSREG, 0, 25), + GATE(PERI2_I2C7_PCLK_EN, + "peri2_clkgen_i2c7_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 24), + GATE(PERI2_I2C6_IC_CLK_EN, + "peri2_clkgen_i2c6_ic_clk", "i2c_ic_clk", PERI2_SYSREG, 0, 23), + GATE(PERI2_I2C6_PCLK_EN, + "peri2_clkgen_i2c6_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 22), + GATE(PERI2_I2C5_IC_CLK_EN, + "peri2_clkgen_i2c5_ic_clk", "i2c_ic_clk", PERI2_SYSREG, 0, 21), + GATE(PERI2_I2C5_PCLK_EN, + "peri2_clkgen_i2c5_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 20), + GATE(PERI2_I2C4_IC_CLK_EN, + "peri2_clkgen_i2c4_ic_clk", "i2c_ic_clk", PERI2_SYSREG, 0, 19), + GATE(PERI2_I2C4_PCLK_EN, + "peri2_clkgen_i2c4_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 18), + GATE(PERI2_I2C3_IC_CLK_EN, + "peri2_clkgen_i2c3_ic_clk", "i2c_ic_clk", PERI2_SYSREG, 0, 17), + GATE(PERI2_I2C3_PCLK_EN, + "peri2_clkgen_i2c3_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 16), + GATE(PERI2_GPIO3_DBCLK_EN, + "peri2_clkgen_gpio3_dbclk", "aon_rtc_clk", PERI2_SYSREG, 0, 15), + GATE(PERI2_GPIO3_PCLK_EN, + "peri2_clkgen_gpio3_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 14), + GATE(PERI2_PAD_CTRL_PCLK_EN, + "peri2_clkgen_pad_ctrl_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 13), + GATE(PERI2_UART6_PCLK_EN, + "peri2_clkgen_uart6_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 12), + GATE(PERI2_UART5_PCLK_EN, + "peri2_clkgen_uart5_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 11), + GATE(PERI2_UART4_PCLK_EN, + "peri2_clkgen_uart4_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 10), + GATE(PERI2_SPI1_PCLK_EN, + "peri2_clkgen_spi1_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 9), + GATE(PERI2_GPIO2_PCLK_EN, + "peri2_clkgen_gpio2_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 8), + GATE(PERI2_CAN2_PCLK_EN, + "peri2_clkgen_can2_pclk", "top_cfg_aclk", PERI2_SYSREG, 0, 7), + GATE(PERI2_UART6_SCLK_EN, + "peri2_clkgen_uart6_sclk", "uart_sclk", PERI2_SYSREG, 0, 6), + GATE(PERI2_UART5_SCLK_EN, + "peri2_clkgen_uart5_sclk", "uart_sclk", PERI2_SYSREG, 0, 5), + GATE(PERI2_UART4_SCLK_EN, + "peri2_clkgen_uart4_sclk", "uart_sclk", PERI2_SYSREG, 0, 4), + GATE(PERI2_SPI1_SSI_CLK_EN, + "peri2_clkgen_spi1_ssi_clk", "peri2_spi_ssi_clk", PERI2_SYSREG, 0, 3), + GATE(PERI2_GPIO2_DBCLK_EN, + "peri2_clkgen_gpio2_dbclk", "aon_rtc_clk", PERI2_SYSREG, 0, 2), + GATE(PERI2_CAN2_OSC_CLK_EN, + "peri2_clkgen_can2_osc_clk", "peri2_hires_clk", PERI2_SYSREG, 0, 1), + GATE(PERI2_CAN2_HIRES_CLK_EN, + "peri2_clkgen_can2_hires_clk", "peri2_clkgen_can2_osc_clk", PERI2_SYSREG, 0, 0), + GATE(PERI2_QSPI1_PCLK_EN, + "peri2_clkgen_qspi1_pclk", "top_cfg_aclk", PERI2_SYSREG, 0x4, 11), + GATE(PERI2_QSPI1_SSI_CLK_EN, + "peri2_clkgen_qspi1_ssi_clk", "peri2_qspi_ssi_clk", PERI2_SYSREG, 0x4, 10), + GATE(PERI2_UART9_PCLK_EN, + "peri2_clkgen_uart9_pclk", "top_cfg_aclk", PERI2_SYSREG, 0x4, 9), + GATE(PERI2_UART9_SCLK_EN, + "peri2_clkgen_uart9_sclk", "uart_sclk", PERI2_SYSREG, 0x4, 8), + GATE(PERI2_UART8_PCLK_EN, + "peri2_clkgen_uart8_pclk", "top_cfg_aclk", PERI2_SYSREG, 0x4, 7), + GATE(PERI2_UART8_SCLK_EN, + "peri2_clkgen_uart8_sclk", "uart_sclk", PERI2_SYSREG, 0x4, 6), + GATE(PERI2_UART7_PCLK_EN, + "peri2_clkgen_uart7_pclk", "top_cfg_aclk", PERI2_SYSREG, 0x4, 5), + GATE(PERI2_UART7_SCLK_EN, + "peri2_clkgen_uart7_sclk", "uart_sclk", PERI2_SYSREG, 0x4, 4), + GATE(PERI2_PWM2_PCLK_EN, + "peri2_clkgen_pwm2_pclk", "peri2_pwm_clk", PERI2_SYSREG, 0x4, 3), + GATE(PERI2_PWM2_CCLK_EN, + "peri2_clkgen_pwm2_cclk", "peri2_clkgen_pwm2_pclk", PERI2_SYSREG, 0x4, 2), + GATE(PERI2_PWM1_PCLK_EN, + "peri2_clkgen_pwm1_pclk", "peri2_pwm_clk", PERI2_SYSREG, 0x4, 1), + GATE(PERI2_PWM1_CCLK_EN, + "peri2_clkgen_pwm1_cclk", "peri2_clkgen_pwm1_pclk", PERI2_SYSREG, 0x4, 0), + /* PERI3 SS */ + GATE(PERI3_PAD_CTRL_PCLK_EN, + "peri3_clkgen_pad_ctrl_pclk", "top_cfg_aclk", PERI3_SYSREG, 0, 21), + GATE(PERI3_GPIO4_PCLK_EN, + "peri3_clkgen_gpio4_pclk", "top_cfg_aclk", PERI3_SYSREG, 0, 20), + GATE(PERI3_GPIO4_DBCLK_EN, + "peri3_clkgen_gpio4_dbclk", "aon_rtc_clk", PERI3_SYSREG, 0, 19), + GATE(CLKCTRL_PERI3_TEE_H2H_SHCLKEN, + "peri3_clkgen_tee_h2h_shclk", "top_cfg_aclk", PERI3_SYSREG, 0, 18), + GATE(CLKCTRL_PERI3_TEE_H2H_MHCLKEN, + "peri3_clkgen_tee_h2h_mhclk", "top_cfg_aclk", PERI3_SYSREG, 0, 17), + GATE(PERI3_TEE_X2X_ACLK_S_EN, + "peri3_clkgen_tee_x2x_aclk", "top_cfg_aclk", PERI3_SYSREG, 0, 16), + GATE(PERI3_ADC_PCLK_EN, + "peri3_clkgen_adc_pclk", "top_cfg_aclk", PERI3_SYSREG, 0, 15), + GATE(AXI_PERI3_MST_PCLK_EN, + "peri3_clkgen_axi_mst_pclk", "top_cfg_aclk", PERI3_SYSREG, 0, 14), + GATE(AXI_PERI3_MST_ACLK_EN, + "peri3_clkgen_axi_mst_aclk", "peri3_mst_aclk", PERI3_SYSREG, 0, 13), + GATE(PERI3_SDIO_X2X_ACLK_S_EN, + "peri3_clkgen_sdio_x2x_aclk_s", "peri3_mst_aclk", PERI3_SYSREG, 0, 12), + GATE(PERI3_SDIO_X2X_ACLK_M_EN, + "peri3_clkgen_sdio_x2x_aclk_m", "top_cfg_aclk", PERI3_SYSREG, 0, 11), + GATE(PERI3_SDIO_OSC_CLK_EN, + "peri3_clkgen_sdio_osc_clk", "aon_osc_clk_logic", PERI3_SYSREG, 0, 10), + GATE(PERI3_SDIO_HCLK_EN, + "peri3_clkgen_sdio_hclk", "top_cfg_aclk", PERI3_SYSREG, 0, 9), + GATE(PERI3_SDIO_ACLK_EN, + "peri3_clkgen_sdio_aclk", "top_cfg_aclk", PERI3_SYSREG, 0, 8), + GATE(PERI3_EMMC_X2X_ACLK_S_EN, + "peri3_clkgen_emmc_x2x_aclk_s", "peri3_mst_aclk", PERI3_SYSREG, 0, 7), + GATE(PERI3_EMMC_X2X_ACLK_M_EN, + "peri3_clkgen_emmc_x2x_aclk_m", "top_cfg_aclk", PERI3_SYSREG, 0, 6), + GATE(PERI3_EMMC_OSC_CLK_EN, + "peri3_clkgen_emmc_osc_clk", "aon_osc_clk_logic", PERI3_SYSREG, 0, 5), + GATE(PERI3_EMMC_HCLK_EN, + "peri3_clkgen_emmc_hclk", "top_cfg_aclk", PERI3_SYSREG, 0, 4), + GATE(PERI3_EMMC_ACLK_EN, + "peri3_clkgen_emmc_aclk", "top_cfg_aclk", PERI3_SYSREG, 0, 3), + FIXED_FACTOR(PERI3_EMMC_SDIO_REF_CLK, + "peri3_emmc_sdio_ref_clk", "emmc_ref_clk", 1, 4), + GATE(PERI3_EMMC_SDIO_REF_CLK_CG_EN, + "peri3_clkgen_sdio_ref_clk", "peri3_emmc_sdio_ref_clk", PERI3_SYSREG, 0, 2), + GATE(PERI3_DMAC_HCLK_EN, + "peri3_clkgen_dmac_hclk", "top_cfg_aclk", PERI3_SYSREG, 0, 1), + GATE(PERI3_DMAC_ACLK_EN, + "peri3_clkgen_dmac_aclk", "peri3_mst_aclk", PERI3_SYSREG, 0, 0), + /* TEE SS */ + GATE(TEE_AHB2_TEESYS_CLKEN, + "tee_ahb2_teesys_clk", "tee_clk", TEE_CRG, 0, 19), + GATE(TEE_APB3_TEESYS_CLKEN, + "tee_apb3_teesys_clk", "tee_clk", TEE_CRG, 0, 18), + GATE(TEE_AXI4_TEESYS_CLKEN, + "tee_axi4_teesys_clk", "tee_clk", TEE_CRG, 0, 17), + GATE(TEE_X2P_TEESYS_CLKEN, + "tee_x2p_teesys_clk", "tee_clk", TEE_CRG, 0, 16), + GATE(TEE_EIP120SI_CLKEN, + "tee_eip120si_clk", "tee_clk", TEE_CRG, 0, 12), + GATE(TEE_EIP120SII_CLKEN, + "tee_eip120sii_clk", "tee_clk", TEE_CRG, 0, 11), + GATE(TEE_EIP120SIII_CLKEN, + "tee_eip120siii_clk", "tee_clk", TEE_CRG, 0, 10), + GATE(TEE_EIP150B_CLKEN, + "tee_eip150b_clk", "tee_clk", TEE_CRG, 0, 9), + GATE(TEE_DMAC_CLKEN, + "tee_dmac_clk", "tee_clk", TEE_CRG, 0, 8), + FIXED_FACTOR(TEE_PCLK_CDE_RATIO, + "tee_pclk", "tee_clk", 1, 4), + GATE(TEE_DS_CLKEN, + "tee_ds_clk", "tee_pclk", TEE_CRG, 0, 3), + GATE(TEE_OCRAM_CLKEN, + "tee_ocram_clk", "tee_clk", TEE_CRG, 0, 2), + GATE(TEE_EFUSE_CLKEN, + "tee_efuse_clk", "tee_pclk", TEE_CRG, 0, 1), + GATE(TEE_KEYRAM_CLKEN, + "tee_keyram_clk", "tee_pclk", TEE_CRG, 0, 0), +}; + +static struct zhihe_clk_subsys top_clk = CLK_SUBSYS("top clk", regs_top, + info_top, plls_top, ARRAY_SIZE(plls_top), 0); +static struct zhihe_clk_subsys gpu_clk = CLK_SUBSYS("gpu clk", regs_gpu, + info_gpu, NULL, 0, 0); +static struct zhihe_clk_subsys pcie_clk = CLK_SUBSYS("pcie clk", regs_pcie, + info_pcie, NULL, 0, 0); +static struct zhihe_clk_subsys usb_clk = CLK_SUBSYS("usb clk", regs_usb, + info_usb, NULL, 0, 0); +static struct zhihe_clk_subsys vi_clk = CLK_SUBSYS("vi clk", regs_vi, + info_vi, NULL, 0, 0); +static struct zhihe_clk_subsys vp_clk = CLK_SUBSYS("vp clk", regs_vp, + info_vp, NULL, 0, 0); +static struct zhihe_clk_subsys vo_clk = CLK_SUBSYS("vo clk", regs_vo, + info_vo, NULL, 0, 0); +static struct zhihe_clk_subsys npu_clk = CLK_SUBSYS("npu clk", regs_npu, + info_npu, NULL, 0, 0); +static struct zhihe_clk_subsys peri_clk = CLK_SUBSYS("peri clk", regs_peri, + info_peri, NULL, 0, 0); + +static int a210_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct zhihe_clk_subsys *priv; + int ret; + + pm_runtime_enable(dev); + + struct clk_onecell_data *clk_data = + devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) { + ret = -ENOMEM; + goto fail; + } + + clk_data->clks = + devm_kcalloc(dev, CLK_END, sizeof(*clk_data->clks), GFP_KERNEL); + if (!clk_data->clks) { + ret = -ENOMEM; + goto fail; + } + clk_data->clk_num = CLK_END; + + for (int i = 0; i < CLK_END; i++) + clk_data->clks[i] = ERR_PTR(-ENOENT); + + priv = (struct zhihe_clk_subsys *)device_get_match_data(&pdev->dev); + priv->clk_data = clk_data; + + dev_set_drvdata(dev, priv); + + ret = zhihe_parse_regbase(pdev); + if (ret) { + dev_err(dev, "fail to parse reg base"); + ret = -EINVAL; + goto fail; + } + + zhihe_register_clock(pdev); + + ret = of_clk_add_provider(np, of_clk_src_onecell_get, priv->clk_data); + if (ret < 0) { + dev_err(dev, "failed to register clks for a210\n"); + goto unregister_clks; + } + + dev_info(dev, "succeed to register a210 %s driver on die%d\n", + priv->name, priv->die_num); + return 0; + +unregister_clks: + zhihe_unregister_clocks(priv->clk_data->clks, CLK_END); +fail: + return ret; +} + +static const struct of_device_id a210_clk_of_match[] = { + { .compatible = "zhihe,a210-clk", .data = (const void *)&top_clk }, + { .compatible = "zhihe,a210-gpu-clk", .data = (const void *)&gpu_clk }, + { .compatible = "zhihe,a210-pcie-clk", .data = (const void *)&pcie_clk }, + { .compatible = "zhihe,a210-usb-clk", .data = (const void *)&usb_clk }, + { .compatible = "zhihe,a210-vi-clk", .data = (const void *)&vi_clk }, + { .compatible = "zhihe,a210-vp-clk", .data = (const void *)&vp_clk }, + { .compatible = "zhihe,a210-vo-clk", .data = (const void *)&vo_clk }, + { .compatible = "zhihe,a210-npu-clk", .data = (const void *)&npu_clk }, + { .compatible = "zhihe,a210-peri-clk", .data = (const void *)&peri_clk }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, a210_clk_of_match); + +static struct platform_driver a210_clk_driver = { + .probe = a210_clocks_probe, + .driver = { + .name = "a210-clk", + .of_match_table = of_match_ptr(a210_clk_of_match), + }, +}; + +static int __init a210_clk_driver_init(void) +{ + return platform_driver_register(&a210_clk_driver); +} +core_initcall(a210_clk_driver_init); + +static void __exit a210_clk_driver_exit(void) +{ + platform_driver_unregister(&a210_clk_driver); +} +module_exit(a210_clk_driver_exit); + +MODULE_AUTHOR("dong.yan "); +MODULE_DESCRIPTION("Zhihe A210 clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/zhihe/clk-helper.c b/drivers/clk/zhihe/clk-helper.c new file mode 100644 index 0000000000000..e5838e51df4e3 --- /dev/null +++ b/drivers/clk/zhihe/clk-helper.c @@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-helper.h" + + +#define div_mask(d) ((1 << (d->width)) - 1) + +DEFINE_SPINLOCK(zhihe_clk_lock); + +void zhihe_unregister_clocks(struct clk *clks[], unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + clk_unregister(clks[i]); +} + +static inline struct clk_zhihediv *to_clk_zhihediv(struct clk_hw *hw) +{ + struct clk_divider *divider = to_clk_divider(hw); + + return container_of(divider, struct clk_zhihediv, divider); +} + +static unsigned long clk_zhihediv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_zhihediv *zhihe_div = to_clk_zhihediv(hw); + + return zhihe_div->ops->recalc_rate(&zhihe_div->divider.hw, parent_rate); +} + +static long clk_zhihediv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_zhihediv *zhihe_div = to_clk_zhihediv(hw); + + return zhihe_div->ops->round_rate(&zhihe_div->divider.hw, rate, prate); +} + +static int clk_zhihediv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_zhihediv *zhihe_div = to_clk_zhihediv(hw); + struct clk_divider *div = to_clk_divider(hw); + unsigned int divider, value; + unsigned long flags = 0; + u32 val; + + /** + * The clk-divider will calculate the node frequency by rounding up + * based on the parent frequency and the target divider. + * This calculation is to restore accurate frequency divider. + */ + divider = DIV64_U64_ROUND_CLOSEST(parent_rate, rate); + + /* DIV is zero based divider, but CDE is not */ + if (zhihe_div->div_type == MUX_TYPE_DIV) + value = divider; + else + value = divider - 1; + + /* handle the div valid range */ + if (value > zhihe_div->max_div) + value = zhihe_div->max_div; + if (value < zhihe_div->min_div) + value = zhihe_div->min_div; + + spin_lock_irqsave(div->lock, flags); + + val = readl(div->reg); + + if (zhihe_div->sync_en != NO_DIV_EN) { + val &= ~BIT(zhihe_div->sync_en); + writel(val, div->reg); + udelay(1); + } + + val &= ~(div_mask(div) << div->shift); + val |= value << div->shift; + writel(val, div->reg); + + if (zhihe_div->sync_en != NO_DIV_EN) { + udelay(1); + val |= BIT(zhihe_div->sync_en); + writel(val, div->reg); + } + + spin_unlock_irqrestore(div->lock, flags); + + return 0; +} + +static const struct clk_ops clk_zhihediv_ops = { + .recalc_rate = clk_zhihediv_recalc_rate, + .round_rate = clk_zhihediv_round_rate, + .set_rate = clk_zhihediv_set_rate, +}; + +static struct clk *zhihe_clk_divider_internal(struct device *dev, + const char *name, + const char *parent, + void __iomem *reg, u8 shift, + u8 width, u8 sync, + enum zhihe_div_type div_type, + u16 min, u16 max, bool closest) +{ + struct clk_zhihediv *zhihe_div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + zhihe_div = kzalloc(sizeof(*zhihe_div), GFP_KERNEL); + if (!zhihe_div) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_zhihediv_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = parent ? &parent : NULL; + init.num_parents = parent ? 1 : 0; + + zhihe_div->divider.reg = reg; + zhihe_div->divider.shift = shift; + zhihe_div->divider.width = width; + zhihe_div->divider.lock = &zhihe_clk_lock; + zhihe_div->divider.hw.init = &init; + zhihe_div->ops = &clk_divider_ops; + zhihe_div->sync_en = sync; + zhihe_div->div_type = div_type; + if (zhihe_div->div_type == MUX_TYPE_DIV) + zhihe_div->divider.flags = CLK_DIVIDER_ONE_BASED; + + if (closest) + zhihe_div->divider.flags |= CLK_DIVIDER_ROUND_CLOSEST; + + zhihe_div->min_div = min > ((1 << width) - 1) ? + ((1 << width) - 1) : min; + zhihe_div->max_div = max > ((1 << width) - 1) ? + ((1 << width) - 1) : max; + + hw = &zhihe_div->divider.hw; + + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(zhihe_div); + return ERR_PTR(ret); + } + + return hw->clk; +} + +static struct clk *zhihe_clk_divider(struct device *dev, const char *name, + const char *parent, void __iomem *reg, + u8 shift, u8 width, u8 sync, + enum zhihe_div_type div_type, + u16 min, u16 max) +{ + return zhihe_clk_divider_internal(dev, name, parent, reg, shift, + width, sync, div_type, min, + max, false); +} + +static struct clk *zhihe_clk_divider_closest(struct device *dev, const char *name, + const char *parent, void __iomem *reg, + u8 shift, u8 width, u8 sync, + enum zhihe_div_type div_type, + u16 min, u16 max) +{ + return zhihe_clk_divider_internal(dev, name, parent, reg, shift, + width, sync, div_type, min, + max, true); +} + +static inline struct clk_zhihegate *to_clk_zhihegate(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + + return container_of(gate, struct clk_zhihegate, gate); +} + +static int clk_zhihe_gate_share_is_enabled(struct clk_hw *hw) +{ + struct clk_zhihegate *zhihe_gate = to_clk_zhihegate(hw); + + return zhihe_gate->ops->is_enabled(hw); +} + +static int clk_zhihe_gate_share_enable(struct clk_hw *hw) +{ + struct clk_zhihegate *zhihe_gate = to_clk_zhihegate(hw); + + if (zhihe_gate->share_count && (*zhihe_gate->share_count)++ > 0) + return 0; + + return zhihe_gate->ops->enable(hw); +} + +static void clk_zhihe_gate_share_disable(struct clk_hw *hw) +{ + struct clk_zhihegate *zhihe_gate = to_clk_zhihegate(hw); + + if (zhihe_gate->share_count) { + if (WARN_ON(*zhihe_gate->share_count == 0)) + return; + else if (--(*zhihe_gate->share_count) > 0) + return; + } + + zhihe_gate->ops->disable(hw); +} + +static void clk_zhihe_gate_share_disable_unused(struct clk_hw *hw) +{ + struct clk_zhihegate *zhihe_gate = to_clk_zhihegate(hw); + + if (!zhihe_gate->share_count || *zhihe_gate->share_count == 0) + return zhihe_gate->ops->disable(hw); +} + +static const struct clk_ops clk_zhihegate_share_ops = { + .enable = clk_zhihe_gate_share_enable, + .disable = clk_zhihe_gate_share_disable, + .disable_unused = clk_zhihe_gate_share_disable_unused, + .is_enabled = clk_zhihe_gate_share_is_enabled, +}; + +struct clk *zhihe_clk_register_gate_shared(struct device *dev, const char *name, const char *parent, + unsigned long flags, void __iomem *reg, + u8 shift, spinlock_t *lock, + unsigned int *share_count) +{ + struct clk_zhihegate *zhihe_gate; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + zhihe_gate = kzalloc(sizeof(*zhihe_gate), GFP_KERNEL); + if (!zhihe_gate) + return ERR_PTR(-ENOMEM); + + zhihe_gate->gate.reg = reg; + zhihe_gate->gate.bit_idx = shift; + zhihe_gate->gate.flags = 0; + zhihe_gate->gate.lock = lock; + zhihe_gate->gate.hw.init = &init; + zhihe_gate->ops = &clk_gate_ops; + zhihe_gate->share_count = share_count; + + init.name = name; + init.ops = &clk_zhihegate_share_ops; + init.flags = flags; + init.parent_names = parent ? &parent : NULL; + init.num_parents = parent ? 1 : 0; + + hw = &zhihe_gate->gate.hw; + + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(zhihe_gate); + return ERR_PTR(ret); + } + + return hw->clk; +} + +int zhihe_parse_regbase(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zhihe_clk_subsys *priv = dev_get_drvdata(dev); + int ret = 0; + + for (int i = 0; i < priv->num_regs; i++) { + priv->regs[i].base = devm_platform_ioremap_resource_byname(pdev, + priv->regs[i].name); + if (WARN_ON(IS_ERR(priv->regs[i].base))) { + ret = PTR_ERR(priv->regs[i].base); + return ret; + } + } + + return ret; +} + +static char *str_die_suffix(struct device *dev, const char *name, int id) +{ + char *new_name = devm_kzalloc(dev, ZHIHE_CLK_NAME_SIZE, GFP_KERNEL); + + if (new_name) + snprintf(new_name, ZHIHE_CLK_NAME_SIZE, "%s_die%d", name, id); + return new_name; +} + +static const char *const *zhihe_add_mux_suffix(struct platform_device *pdev, int i) +{ + struct device *dev = &pdev->dev; + struct zhihe_clk_subsys *priv = dev_get_drvdata(dev); + const char *const *original_parents = priv->info[i].mux.parents; + u8 num_parents = priv->info[i].mux.num_parents; + const char **new_parents; + + if (priv->die_num == 0) + return original_parents; + + new_parents = devm_kzalloc(dev, sizeof(char *) * num_parents, GFP_KERNEL); + if (!new_parents) + return ERR_PTR(-ENOMEM); + + for (int j = 0; j < num_parents; j++) { + const char *original_name = original_parents[j]; + char *suffix_name; + + suffix_name = str_die_suffix(dev, original_name, priv->die_num); + if (!suffix_name) { + dev_err(dev, "Failed to allocate memory for suffix_name\n"); + return ERR_PTR(-ENOMEM); + } + + new_parents[j] = suffix_name; + } + return new_parents; +} + +void zhihe_register_clock(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zhihe_clk_subsys *priv = dev_get_drvdata(dev); + struct device_node *np = dev->of_node; + unsigned int freq; + char *name, *parent; + int ret; + + /* update pll freq if defined in dts */ + for (int i = 0; i < priv->num_plls; i++) { + ret = of_property_read_u32(np, priv->plls[i].name, &freq); + if (ret) + continue; + priv->plls[i].rate_table[0].vco_rate = freq; + priv->plls[i].rate_table[0].rate = freq / priv->plls[i].rate_table[0].postdiv1; + } + + for (int i = 0; i < priv->num_info; i++) { + u32 id = priv->info[i].id; + enum zhihe_clk_types type = priv->info[i].type; + void __iomem *base = priv->regs[priv->info[i].reg].base + + priv->info[i].shift; + u8 width = priv->info[i].width; + u8 bit_idx = priv->info[i].bit_idx; + + if (priv->die_num != 0) { + name = str_die_suffix(dev, priv->info[i].name, priv->die_num); + parent = str_die_suffix(dev, priv->info[i].parent, priv->die_num); + } else { + name = priv->info[i].name; + parent = priv->info[i].parent; + } + + switch (type) { + case CLK_TYPE_FIXED: + priv->clk_data->clks[id] = zhihe_clk_fixed(dev, + name, parent, priv->info[i].fixed.freq); + break; + case CLK_TYPE_FIXED_FACTOR: + priv->clk_data->clks[id] = zhihe_clk_fixed_factor( + dev, name, parent, + priv->info[i].fixed_factor.mult, + priv->info[i].fixed_factor.div); + break; + case CLK_TYPE_PLL: + priv->clk_data->clks[id] = zhihe_pll(dev, name, + parent, base, priv->info[i].pll); + break; + case CLK_TYPE_DIVIDER: + priv->clk_data->clks[id] = zhihe_clk_divider(dev, + name, parent, base, bit_idx, width, + priv->info[i].divider.sync, + priv->info[i].divider.div_type, + priv->info[i].divider.min, + priv->info[i].divider.max); + break; + case CLK_TYPE_DIVIDER_CLOSEST: + priv->clk_data->clks[id] = + zhihe_clk_divider_closest(dev, name, + parent, base, bit_idx, width, + priv->info[i].divider.sync, + priv->info[i].divider.div_type, + priv->info[i].divider.min, + priv->info[i].divider.max); + break; + case CLK_TYPE_GATE: + priv->clk_data->clks[id] = zhihe_clk_gate(dev, + name, parent, base, bit_idx); + break; + case CLK_TYPE_GATE_SHARED: + priv->clk_data->clks[id] = + zhihe_clk_gate_shared(dev, name, parent, + base, bit_idx, + priv->info[i].gate_shared.share_count); + break; + case CLK_TYPE_MUX: { + const char *const *parents; + + parents = zhihe_add_mux_suffix(pdev, i); + priv->clk_data->clks[id] = zhihe_clk_mux_flags( + dev, name, base, bit_idx, width, + parents, priv->info[i].mux.num_parents, + priv->info[i].mux.flags); + break; + } + default: + dev_err(dev, "clk register fail with wrong type=%d", + type); + break; + } + } +} diff --git a/drivers/clk/zhihe/clk-helper.h b/drivers/clk/zhihe/clk-helper.h new file mode 100644 index 0000000000000..192b584ab3343 --- /dev/null +++ b/drivers/clk/zhihe/clk-helper.h @@ -0,0 +1,353 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#ifndef __MACH_ZHIHE_CLK_H +#define __MACH_ZHIHE_CLK_H + +#include +#include +#include +#include + +extern spinlock_t zhihe_clk_lock; + +#define ZHIHE_CLK_NAME_SIZE 40 + +#define PLL_RATE(_vco, _rate, _r, _b, _f, _p, _k) \ + { \ + .vco_rate = (_vco), \ + .rate = (_rate), \ + .refdiv = (_r), \ + .fbdiv = (_b), \ + .frac = (_f), \ + .postdiv1 = (_p), \ + .postdiv2 = (_k), \ + } + +#define REG(n) \ + [(n)] = {.name = #n} + +#define REG_NAMED(n, _name) \ + [(n)] = {.name = (_name)} + +#define CLK(_type, _id, _name, _parent) \ + .type = (_type), \ + .id = (_id), \ + .name = (_name), \ + .parent = (_parent) + +#define FIXED(_id, _name, _parent, _freq) { \ + CLK(CLK_TYPE_FIXED, (_id), (_name), (_parent)), \ + .fixed = {.freq = (_freq),}, \ +} + +#define PLL(_id, _name, _parent, _reg, _shift, _pll) { \ + CLK(CLK_TYPE_PLL, (_id), (_name), (_parent)), \ + .reg = (_reg), \ + .shift = (_shift), \ + .pll = (_pll), \ +} + +#define FIXED_FACTOR(_id, _name, _parent, _mult, _div) { \ + CLK(CLK_TYPE_FIXED_FACTOR, (_id), (_name), (_parent)), \ + .fixed_factor = {.mult = (_mult), .div = (_div),}, \ +} + +#define DIV(_id, _name, _parent, _reg, _shift, _bit_idx, _width, _sync, _div_type, _min, _max) { \ + CLK(CLK_TYPE_DIVIDER, (_id), (_name), (_parent)), \ + .reg = (_reg), \ + .shift = (_shift), \ + .bit_idx = (_bit_idx), \ + .width = (_width), \ + .divider = { \ + .sync = (_sync), \ + .div_type = (_div_type), \ + .min = (_min), \ + .max = (_max) \ + } \ +} + +#define DIV_CLOSEST(_id, _name, _parent, _reg, _shift, _bit_idx, \ + _width, _sync, _div_type, _min, _max) { \ + CLK(CLK_TYPE_DIVIDER_CLOSEST, (_id), (_name), (_parent)),\ + .reg = (_reg), \ + .shift = (_shift), \ + .bit_idx = (_bit_idx), \ + .width = (_width), \ + .divider = { \ + .sync = (_sync), \ + .div_type = (_div_type), \ + .min = (_min), \ + .max = (_max) \ + } \ +} + +#define GATE(_id, _name, _parent, _reg, _shift, _bit_idx) { \ + CLK(CLK_TYPE_GATE, (_id), (_name), (_parent)), \ + .reg = (_reg), \ + .shift = (_shift), \ + .bit_idx = (_bit_idx), \ +} + +#define GATE_SHARED(_id, _name, _parent, _reg, _shift, _bit_idx, _count) { \ + CLK(CLK_TYPE_GATE_SHARED, (_id), (_name), (_parent)), \ + .reg = (_reg), \ + .shift = (_shift), \ + .bit_idx = (_bit_idx), \ + .gate_shared = { \ + .share_count = (_count) \ + }, \ +} + +#define MUX(_id, _name, _reg, _shift, _bit_idx, _width, _parents, _flags) { \ + CLK(CLK_TYPE_MUX, (_id), (_name), ""), \ + .reg = (_reg), \ + .shift = (_shift), \ + .bit_idx = (_bit_idx), \ + .width = (_width), \ + .mux = { \ + .parents = (_parents), \ + .num_parents = ARRAY_SIZE(_parents), \ + .flags = (_flags) \ + }, \ +} + +#define PLL_PARAM(_pll, _out, _table, _cfg0, _sts, _lock, _bypass, _rst, _mode, _name) \ + [(_pll)] = { \ + .out_type = (_out), \ + .clk_type = (_pll), \ + .rate_table = (_table), \ + .rate_count = ARRAY_SIZE(_table), \ + .cfg0_reg_off = (_cfg0), \ + .pll_sts_off = (_sts), \ + .pll_lock_bit = (_lock), \ + .pll_bypass_bit = (_bypass), \ + .pll_rst_bit = (_rst), \ + .pll_mode = (_mode), \ + .name = (_name), \ + } + +#define CLK_SUBSYS(_name, _regs, _info, _pll, _num_pll, _die_num) { \ + .name = (_name), \ + .regs = (_regs), \ + .num_regs = ARRAY_SIZE(_regs), \ + .info = (_info), \ + .num_info = ARRAY_SIZE(_info), \ + .plls = (_pll), \ + .num_plls = (_num_pll), \ + .die_num = (_die_num), \ +} + +enum zhihe_pll_outtype { + ZHIHE_PLL_VCO, + ZHIHE_PLL_DIV, +}; + +enum zhihe_div_type { + MUX_TYPE_DIV, + MUX_TYPE_CDE, +}; + +enum zhihe_div_sync_type { + NO_DIV_EN = 255, +}; + +enum zhihe_clk_types { + CLK_TYPE_FIXED, + CLK_TYPE_PLL, + CLK_TYPE_FIXED_FACTOR, + CLK_TYPE_DIVIDER, + CLK_TYPE_DIVIDER_CLOSEST, + CLK_TYPE_GATE, + CLK_TYPE_GATE_SHARED, + CLK_TYPE_MUX, +}; + +enum zhihe_pll_mode { + PLL_MODE_FRAC, + PLL_MODE_INT, +}; + +struct zhihe_clk_reg { + void __iomem *base; + char name[ZHIHE_CLK_NAME_SIZE]; +}; + +/* clk summary info at subsys level */ +struct zhihe_clk_subsys { + char name[ZHIHE_CLK_NAME_SIZE]; + struct zhihe_clk_reg *regs; + u32 num_regs; + struct zhihe_clk_info *info; + u32 num_info; + struct zhihe_clk_info_pll *plls; + u32 num_plls; + struct clk_onecell_data *clk_data; + char die_num; +}; + +struct clk_zhihepll { + struct clk_hw hw; + void __iomem *base; + unsigned int clk_type; + enum zhihe_pll_outtype out_type; + enum zhihe_pll_mode pll_mode; + const struct zhihe_pll_rate_table *rate_table; + int rate_count; + + u32 cfg0_reg_off; + u32 pll_sts_off; + int pll_lock_bit; + int pll_rst_bit; + int pll_bypass_bit; +}; + +struct clk_zhihediv { + struct clk_divider divider; + enum zhihe_div_type div_type; + u16 min_div; + u16 max_div; + u8 sync_en; + const struct clk_ops *ops; +}; + +struct clk_zhihegate { + struct clk_gate gate; + unsigned int *share_count; + const struct clk_ops *ops; +}; + +struct zhihe_pll_rate_table { + unsigned long vco_rate; + unsigned long rate; + unsigned int refdiv; + unsigned int fbdiv; + unsigned int frac; + unsigned int postdiv1; + unsigned int postdiv2; +}; + +/* detailed clk info for each clk */ + +struct zhihe_clk_info_pll { + enum zhihe_pll_outtype out_type; + unsigned int clk_type; + struct zhihe_pll_rate_table *rate_table; + int rate_count; + int flags; + char name[ZHIHE_CLK_NAME_SIZE]; + u32 cfg0_reg_off; + u32 pll_sts_off; + int pll_lock_bit; + int pll_rst_bit; + int pll_bypass_bit; + enum zhihe_pll_mode pll_mode; +}; + +struct zhihe_clk_info_fixed { + unsigned int freq; +}; + +struct zhihe_clk_info_fixed_factor { + unsigned int mult; + unsigned int div; +}; + +struct zhihe_clk_info_divider { + u8 sync; + enum zhihe_div_type div_type; + u16 min; + u16 max; +}; + +struct zhihe_clk_info_gate_shared { + unsigned int *share_count; +}; + +struct zhihe_clk_info_mux { + const char *const *parents; + int num_parents; + unsigned long flags; +}; + +struct zhihe_clk_info { + enum zhihe_clk_types type; + u32 id; + char name[ZHIHE_CLK_NAME_SIZE]; + char parent[ZHIHE_CLK_NAME_SIZE]; + u8 reg; + u32 shift; + u8 width; + u8 bit_idx; + union { + struct zhihe_clk_info_fixed fixed; + struct zhihe_clk_info_fixed_factor fixed_factor; + struct zhihe_clk_info_pll *pll; + struct zhihe_clk_info_divider divider; + struct zhihe_clk_info_gate_shared gate_shared; + struct zhihe_clk_info_mux mux; + }; +}; + +static inline struct clk *zhihe_clk_fixed_factor(struct device *dev, const char *name, + const char *parent, unsigned int mult, unsigned int div) +{ + return clk_register_fixed_factor(dev, name, parent, + CLK_SET_RATE_PARENT, mult, div); +} + +struct clk *zhihe_pll(struct device *dev, const char *name, const char *parent_name, + void __iomem *base, + const struct zhihe_clk_info_pll *pll_clk); + +static inline struct clk *zhihe_clk_gate(struct device *dev, + const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + return clk_register_gate(dev, name, parent, CLK_SET_RATE_PARENT, reg, + shift, 0, &zhihe_clk_lock); +} + +struct clk *zhihe_clk_register_gate_shared(struct device *dev, + const char *name, const char *parent, + unsigned long flags, void __iomem *reg, + u8 shift, spinlock_t *lock, + unsigned int *share_count); + +static inline struct clk *zhihe_clk_fixed(struct device *dev, const char *name, + const char *parent, + unsigned long rate) +{ + return clk_register_fixed_rate(dev, name, parent, 0, rate); +} + +static inline struct clk *zhihe_clk_gate_shared(struct device *dev, + const char *name, + const char *parent, + void __iomem *reg, u8 shift, + unsigned int *share_count) +{ + return zhihe_clk_register_gate_shared(dev, name, parent, + CLK_SET_RATE_PARENT, reg, + shift, &zhihe_clk_lock, + share_count); +} + +static inline struct clk *zhihe_clk_mux_flags(struct device *dev, const char *name, + void __iomem *reg, u8 shift, u8 width, + const char *const *parents, int num_parents, + unsigned long flags) +{ + return clk_register_mux(dev, name, parents, num_parents, + flags, reg, shift, width, 0, + &zhihe_clk_lock); +} + +int add_die_suffix(struct platform_device *pdev); +void zhihe_register_clock(struct platform_device *pdev); +void zhihe_unregister_clocks(struct clk *clks[], unsigned int count); +int zhihe_parse_regbase(struct platform_device *pdev); + +#endif diff --git a/drivers/clk/zhihe/clk-pll.c b/drivers/clk/zhihe/clk-pll.c new file mode 100644 index 0000000000000..d4b8ade9bdc83 --- /dev/null +++ b/drivers/clk/zhihe/clk-pll.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk-helper.h" + +#define ZHIHE_PLL_CFG0 0x0 +#define ZHIHE_PLL_CFG1 0x04 +#define ZHIHE_PLL_CFG2 0x8 +#define ZHIHE_POSTDIV2_SHIFT 24 +#define ZHIHE_POSTDIV2_MASK GENMASK(26, 24) +#define ZHIHE_POSTDIV1_SHIFT 20 +#define ZHIHE_POSTDIV1_MASK GENMASK(22, 20) +#define ZHIHE_FBDIV_SHIFT 8 +#define ZHIHE_FBDIV_MASK GENMASK(19, 8) +#define ZHIHE_REFDIV_SHIFT 0 +#define ZHIHE_REFDIV_MASK GENMASK(5, 0) +#define ZHIHE_BYPASS_MASK BIT(30) +#define ZHIHE_RST_MASK BIT(29) +#define ZHIHE_DSMPD_MASK BIT(24) +#define ZHIHE_DACPD_MASK BIT(25) +#define ZHIHE_FRAC_MASK GENMASK(23, 0) +#define ZHIHE_FRAC_SHIFT 0 +#define ZHIHE_FRAC_DIV BIT(24) + +#define LOCK_TIMEOUT_US 10000 + +#define to_clk_zhihepll(_hw) container_of(_hw, struct clk_zhihepll, hw) + +static int clk_zhihe_pll_wait_lock(struct clk_zhihepll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base + pll->pll_sts_off, val, + val & pll->pll_lock_bit, 0, + LOCK_TIMEOUT_US); +} + +static int clk_zhihe_pll_prepare(struct clk_hw *hw) +{ + struct clk_zhihepll *pll = to_clk_zhihepll(hw); + void __iomem *cfg1_off; + u32 val; + int ret; + + cfg1_off = pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1; + val = readl_relaxed(cfg1_off); + if (!(val & pll->pll_rst_bit)) + return 0; + + /* Enable RST */ + val |= pll->pll_rst_bit; + writel_relaxed(val, cfg1_off); + + udelay(3); + + /* Disable RST */ + val &= ~pll->pll_rst_bit; + writel_relaxed(val, cfg1_off); + + ret = clk_zhihe_pll_wait_lock(pll); + if (ret) + return ret; + + return 0; +} + +static int clk_zhihe_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_zhihepll *pll = to_clk_zhihepll(hw); + u32 val; + + val = readl_relaxed(pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1); + + return (val & pll->pll_rst_bit) ? 0 : 1; +} + +static void clk_zhihe_pll_unprepare(struct clk_hw *hw) +{ + struct clk_zhihepll *pll = to_clk_zhihepll(hw); + u32 val; + + val = readl_relaxed(pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1); + val |= pll->pll_rst_bit; + writel_relaxed(val, pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1); +} + +static unsigned long clk_zhihe_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_zhihepll *pll = to_clk_zhihepll(hw); + u32 refdiv, fbdiv, postdiv1, postdiv2, frac; + u32 pll_cfg0, pll_cfg1; + u64 fvco = 0; + + pll_cfg0 = readl_relaxed(pll->base + pll->cfg0_reg_off); + pll_cfg1 = readl_relaxed(pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1); + refdiv = (pll_cfg0 & ZHIHE_REFDIV_MASK) >> ZHIHE_REFDIV_SHIFT; + fbdiv = (pll_cfg0 & ZHIHE_FBDIV_MASK) >> ZHIHE_FBDIV_SHIFT; + postdiv1 = (pll_cfg0 & ZHIHE_POSTDIV1_MASK) >> ZHIHE_POSTDIV1_SHIFT; + postdiv2 = (pll_cfg0 & ZHIHE_POSTDIV2_MASK) >> ZHIHE_POSTDIV2_SHIFT; + frac = (pll_cfg1 & ZHIHE_FRAC_MASK) >> ZHIHE_FRAC_SHIFT; + + /* rate calculation: + * INT mode: FOUTVCO = FREE * FBDIV / REFDIV + * FRAC mode:FOUTVCO = (FREE * FBDIV + FREE * FRAC/BIT(24)) / REFDIV + */ + if (pll->pll_mode == PLL_MODE_FRAC) + fvco = (parent_rate * frac) / ZHIHE_FRAC_DIV; + + fvco += (parent_rate * fbdiv); + do_div(fvco, refdiv); + + if (pll->out_type == ZHIHE_PLL_DIV) + do_div(fvco, postdiv1 * postdiv2); + + return fvco; +} + +static const struct zhihe_pll_rate_table *zhihe_get_pll_div_settings( + struct clk_zhihepll *pll, unsigned long rate) +{ + const struct zhihe_pll_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) + if (rate == rate_table[i].rate) + return &rate_table[i]; + + return NULL; +} + +static const struct zhihe_pll_rate_table *zhihe_get_pll_vco_settings( + struct clk_zhihepll *pll, unsigned long rate) +{ + const struct zhihe_pll_rate_table *rate_table = pll->rate_table; + int i; + + for (i = 0; i < pll->rate_count; i++) + if (rate == rate_table[i].vco_rate) + return &rate_table[i]; + + return NULL; +} + +static inline bool clk_zhihe_pll_change(struct clk_zhihepll *pll, + const struct zhihe_pll_rate_table *rate) +{ + u32 refdiv_old, fbdiv_old, postdiv1_old, postdiv2_old, frac_old; + u32 cfg0, cfg1; + bool pll_changed; + + cfg0 = readl_relaxed(pll->base + pll->cfg0_reg_off); + cfg1 = readl_relaxed(pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1); + + refdiv_old = (cfg0 & ZHIHE_REFDIV_MASK) >> ZHIHE_REFDIV_SHIFT; + fbdiv_old = (cfg0 & ZHIHE_FBDIV_MASK) >> ZHIHE_FBDIV_SHIFT; + postdiv1_old = (cfg0 & ZHIHE_POSTDIV1_MASK) >> ZHIHE_POSTDIV1_SHIFT; + postdiv2_old = (cfg0 & ZHIHE_POSTDIV2_MASK) >> ZHIHE_POSTDIV2_SHIFT; + frac_old = (cfg1 & ZHIHE_FRAC_MASK) >> ZHIHE_FRAC_SHIFT; + + pll_changed = rate->refdiv != refdiv_old || rate->fbdiv != fbdiv_old || + rate->postdiv1 != postdiv1_old || rate->postdiv2 != postdiv2_old; + if (pll->pll_mode == PLL_MODE_FRAC) + pll_changed |= (rate->frac != frac_old); + + return pll_changed; +} + +static int clk_zhihe_pll_set_rate(struct clk_hw *hw, unsigned long drate, + unsigned long prate) +{ + struct clk_zhihepll *pll = to_clk_zhihepll(hw); + const struct zhihe_pll_rate_table *rate; + void __iomem *cfg1_off; + u32 tmp, div_val; + int ret; + + if (pll->out_type == ZHIHE_PLL_VCO) { + rate = zhihe_get_pll_vco_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + } else { + rate = zhihe_get_pll_div_settings(pll, drate); + if (!rate) { + pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__, + drate, clk_hw_get_name(hw)); + return -EINVAL; + } + } + + if (!clk_zhihe_pll_change(pll, rate)) + return 0; + + /* Enable RST */ + cfg1_off = pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1; + tmp = readl_relaxed(cfg1_off); + tmp |= pll->pll_rst_bit; + writel_relaxed(tmp, cfg1_off); + + div_val = (rate->refdiv << ZHIHE_REFDIV_SHIFT) | + (rate->fbdiv << ZHIHE_FBDIV_SHIFT) | + (rate->postdiv1 << ZHIHE_POSTDIV1_SHIFT) | + (rate->postdiv2 << ZHIHE_POSTDIV2_SHIFT); + writel_relaxed(div_val, pll->base + pll->cfg0_reg_off); + + if (pll->pll_mode == PLL_MODE_FRAC) { + tmp &= ~(ZHIHE_FRAC_MASK << ZHIHE_FRAC_SHIFT); + tmp |= rate->frac; + writel_relaxed(tmp, cfg1_off); + } + + udelay(3); + + /* Disable RST */ + tmp &= ~pll->pll_rst_bit; + writel_relaxed(tmp, cfg1_off); + + /* Wait Lock, ~20us cost */ + ret = clk_zhihe_pll_wait_lock(pll); + if (ret) + return ret; + + /* HW requires 30us for pll stable */ + udelay(30); + + return 0; +} + +static long clk_zhihe_pllvco_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_zhihepll *pll = to_clk_zhihepll(hw); + const struct zhihe_pll_rate_table *rate_table = pll->rate_table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; + + for (i = 0; i < pll->rate_count; i++) { + now = rate_table[i].vco_rate; + + if (rate == now) { + return rate_table[i].vco_rate; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + /* return minimum supported value */ + return rate_table[best_i].vco_rate; +} + +static long clk_zhihe_plldiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_zhihepll *pll = to_clk_zhihepll(hw); + const struct zhihe_pll_rate_table *rate_table = pll->rate_table; + unsigned long best = 0, now = 0; + unsigned int i, best_i = 0; + + for (i = 0; i < pll->rate_count; i++) { + now = rate_table[i].rate; + + if (rate == now) { + return rate_table[i].rate; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + /* return minimum supported value */ + return rate_table[best_i].rate; +} + +static const struct clk_ops clk_zhihe_pll_def_ops = { + .recalc_rate = clk_zhihe_pll_recalc_rate, +}; + +static const struct clk_ops clk_zhihe_pllvco_ops = { + .prepare = clk_zhihe_pll_prepare, + .unprepare = clk_zhihe_pll_unprepare, + .is_prepared = clk_zhihe_pll_is_prepared, + .recalc_rate = clk_zhihe_pll_recalc_rate, + .round_rate = clk_zhihe_pllvco_round_rate, + .set_rate = clk_zhihe_pll_set_rate, +}; + +static const struct clk_ops clk_zhihe_plldiv_ops = { + .prepare = clk_zhihe_pll_prepare, + .unprepare = clk_zhihe_pll_unprepare, + .is_prepared = clk_zhihe_pll_is_prepared, + .recalc_rate = clk_zhihe_pll_recalc_rate, + .round_rate = clk_zhihe_plldiv_round_rate, + .set_rate = clk_zhihe_pll_set_rate, +}; + +struct clk *zhihe_pll(struct device *dev, const char *name, const char *parent_name, + void __iomem *base, + const struct zhihe_clk_info_pll *pll_clk) +{ + struct clk_zhihepll *pll; + struct clk *clk; + struct clk_init_data init; + u32 val; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.flags = pll_clk->flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + switch (pll_clk->out_type) { + case ZHIHE_PLL_VCO: + if (pll_clk->rate_table) + init.ops = &clk_zhihe_pllvco_ops; + break; + case ZHIHE_PLL_DIV: + if (pll_clk->rate_table) + init.ops = &clk_zhihe_plldiv_ops; + break; + default: + pr_err("%s: Unknown pll out type for pll clk %s\n", + __func__, name); + }; + + if (!pll_clk->rate_table) + init.ops = &clk_zhihe_pll_def_ops; + + pll->base = base; + pll->hw.init = &init; + pll->out_type = pll_clk->out_type; + pll->clk_type = pll_clk->clk_type; + pll->rate_table = pll_clk->rate_table; + pll->rate_count = pll_clk->rate_count; + pll->cfg0_reg_off = pll_clk->cfg0_reg_off; + pll->pll_sts_off = pll_clk->pll_sts_off; + pll->pll_lock_bit = pll_clk->pll_lock_bit; + pll->pll_bypass_bit = pll_clk->pll_bypass_bit; + pll->pll_rst_bit = pll_clk->pll_rst_bit; + pll->pll_mode = pll_clk->pll_mode; + + val = readl_relaxed(pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1); + val &= ~pll->pll_bypass_bit; + val |= ZHIHE_DACPD_MASK; + val |= ZHIHE_DSMPD_MASK; + if (pll->pll_mode == PLL_MODE_FRAC) { + val &= ~ZHIHE_DSMPD_MASK; + val &= ~ZHIHE_DACPD_MASK; + } + writel_relaxed(val, pll->base + pll->cfg0_reg_off + ZHIHE_PLL_CFG1); + + clk = clk_register(dev, &pll->hw); + if (IS_ERR(clk)) { + pr_err("failed to register pll %s %ld\n", + name, PTR_ERR(clk)); + kfree(pll); + } + + return clk; +} From 4691a375c20b4df8d335a52c1df197b8e741277d Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Apr 2026 20:28:56 +0800 Subject: [PATCH 05/17] reset: add ZhiHe A210 reset controller driver Add a reset controller driver for the ZhiHe A210 SoC that manages hardware reset lines for various on-chip IP blocks. The driver uses reset line IDs defined in dt-bindings/reset/a210-reset.h. Signed-off-by: Zhiguo Zhu --- drivers/reset/Kconfig | 11 + drivers/reset/Makefile | 1 + drivers/reset/reset-a210.c | 1442 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1454 insertions(+) create mode 100644 drivers/reset/reset-a210.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index a662841c73ecc..431d4de3fa042 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -328,6 +328,17 @@ config RESET_ZYNQ help This enables the reset controller driver for Xilinx Zynq SoCs. +config RESET_A210 + bool "ZhiHe A210 reset controller" + depends on ARCH_ZHIHE || COMPILE_TEST + default ARCH_ZHIHE + help + Build the reset controller driver for the ZhiHe A210 SoC. + + This driver provides reset control for the various hardware + blocks in the A210 SoC. Say Y if you are building a kernel + for the ZhiHe A210 platform. + source "drivers/reset/spacemit/Kconfig" source "drivers/reset/starfive/Kconfig" source "drivers/reset/sti/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 82ad5421def3f..f415800e7348d 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o +obj-$(CONFIG_RESET_A210) += reset-a210.o diff --git a/drivers/reset/reset-a210.c b/drivers/reset/reset-a210.c new file mode 100644 index 0000000000000..8da2ff39af583 --- /dev/null +++ b/drivers/reset/reset-a210.c @@ -0,0 +1,1442 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define A210_RST_NAME_SIZE 40 + +/* reset subsys enumeration */ +enum { + VP_RST, + VI_RST, + NPU_RST, + VO_RST, + PERI0_RST, + PERI1_RST, + PERI2_RST, + PERI3_RST, + PCIE_RST, + USB_RST, + TEE_RST, + GPU_RST, + A210_RESET_SUBSYS_MAX, +}; + +/* + * Reset Signal + * + * nextid + * Next associated signal that needs to be processed together + * offset: + * Address offset of the register where the reset signal is located + * bit: + * Signal data, can be multiple bits + * subsys: + * The subsystem where this reset sinal is located. + */ +struct a210_rst_signal { + const char *name; + const unsigned short nextid; + const unsigned short offset; + const unsigned int bit; + const struct a210_rst_subsys *subsys; +}; + +/* reset info within a subsys */ +struct a210_rst_subsys { + void __iomem *base; + struct a210_rst_signal *signals; + u32 num_signals; + const char *name; +}; + +struct a210_rst_match_data { + u32 id; + const char *name; + struct a210_rst_signal *signals; + u32 num_signals; +}; + +#if defined(CONFIG_DEBUG_FS) +struct a210_rst_debugfs_node { + struct a210_rst_subsys *subsys; + struct a210_rst_signal *signal; +}; +#endif + +struct a210_reset { + struct device *dev; + struct reset_controller_dev reset; + struct a210_rst_subsys *subsys; + u32 num_subsys; + u32 subsys_id; + spinlock_t lock; +#if defined(CONFIG_DEBUG_FS) + struct a210_rst_debugfs_node *debugfs_node; +#endif +}; + +/* + * Reset node info + */ +static struct a210_rst_signal vp_rst_signals[] = { + [VP_VDEC_PRST & RST_SIGNAL_MASK] = { + "VP_VDEC_PRST", 0, 0, BIT(0), + }, + [VP_VDEC_CRST & RST_SIGNAL_MASK] = { + "VP_VDEC_CRST", 0, 0, BIT(1), + }, + [VP_VDEC_ARST & RST_SIGNAL_MASK] = { + "VP_VDEC_ARST", 0, 0, BIT(2), + }, + [VP_VENC_PRST & RST_SIGNAL_MASK] = { + "VP_VENC_PRST", 0, 0, BIT(3), + }, + [VP_VENC_CRST & RST_SIGNAL_MASK] = { + "VP_VENC_CRST", 0, 0, BIT(4), + }, + [VP_VENC_ARST & RST_SIGNAL_MASK] = { + "VP_VENC_ARST", 0, 0, BIT(5), + }, + [VP_G2D_PRST & RST_SIGNAL_MASK] = { + "VP_G2D_PRST", 0, 0, BIT(6), + }, + [VP_G2D_CRST & RST_SIGNAL_MASK] = { + "VP_G2D_CRST", 0, 0, BIT(7), + }, + [VP_G2D_ARST & RST_SIGNAL_MASK] = { + "VP_G2D_ARST", 0, 0, BIT(8), + }, + [VP_COMP_PRST & RST_SIGNAL_MASK] = { + "VP_COMP_PRST", 0, 0, BIT(9), + }, + [VP_COMP_CRST & RST_SIGNAL_MASK] = { + "VP_COMP_CRST", 0, 0, BIT(10), + }, + [VP_COMP_ARST & RST_SIGNAL_MASK] = { + "VP_COMP_ARST", 0, 0, BIT(11), + }, + [VP_DECOMP_PRST & RST_SIGNAL_MASK] = { + "VP_DECOMP_PRST", 0, 0, BIT(12), + }, + [VP_DECOMP_CRST & RST_SIGNAL_MASK] = { + "VP_DECOMP_CRST", 0, 0, BIT(13), + }, + [VP_DECOMP_ARST & RST_SIGNAL_MASK] = { + "VP_DECOMP_ARST", 0, 0, BIT(14), + }, + [VP_DFMU_PRST & RST_SIGNAL_MASK] = { + "VP_DFMU_PRST", 0, 0, BIT(15), + }, + [VP_DFMU_ARST & RST_SIGNAL_MASK] = { + "VP_DFMU_ARST", 0, 0, BIT(16), + }, + [VP_ARB_PRST & RST_SIGNAL_MASK] = { + "VP_ARB_PRST", 0, 0, BIT(18), + }, + [VP_ARB_ARST & RST_SIGNAL_MASK] = { + "VP_ARB_ARST", 0, 0, BIT(19), + }, + [VP_VDEC_RS_ARST & RST_SIGNAL_MASK] = { + "VP_VDEC_RS_ARST", 0, 0, BIT(20), + }, + [VP_VENC_RS_ARST & RST_SIGNAL_MASK] = { + "VP_VENC_RS_ARST", 0, 0, BIT(21), + }, + [VP_COMP_EXTPRST & RST_SIGNAL_MASK] = { + "VP_COMP_EXTPRST", 0, 0, BIT(22), + }, + [VP_DECOMP_EXTPRST & RST_SIGNAL_MASK] = { + "VP_DECOMP_EXTPRST", 0, 0, BIT(23), + }, +}; + +static struct a210_rst_signal vi_rst_signals[] = { + [VI_MIPI0_CSI0_PRST & RST_SIGNAL_MASK] = { + "VI_MIPI0_CSI0_PRST", 0, 0, BIT(0), + }, + [VI_MIPI0_CSI1_PRST & RST_SIGNAL_MASK] = { + "VI_MIPI0_CSI1_PRST", 0, 0, BIT(1), + }, + [VI_MIPI0_FIFO_RST & RST_SIGNAL_MASK] = { + "VI_MIPI0_FIFO_RST", 0, 0, BIT(2), + }, + [VI_MIPI1_CSI0_PRST & RST_SIGNAL_MASK] = { + "VI_MIPI1_CSI0_PRST", 0, 0, BIT(3), + }, + [VI_MIPI1_CSI1_PRST & RST_SIGNAL_MASK] = { + "VI_MIPI1_CSI1_PRST", 0, 0, BIT(4), + }, + [VI_MIPI1_FIFO_RST & RST_SIGNAL_MASK] = { + "VI_MIPI1_FIFO_RST", 0, 0, BIT(5), + }, + [VI_VIPRE_PRST & RST_SIGNAL_MASK] = { + "VI_VIPRE_PRST", 0, 0, BIT(6), + }, + [VI_VIPRE_I0_PIX_RST & RST_SIGNAL_MASK] = { + "VI_VIPRE_I0_PIX_RST", 0, 0, BIT(7), + }, + [VI_VIPRE_I1_PIX_RST & RST_SIGNAL_MASK] = { + "VI_VIPRE_I1_PIX_RST", 0, 0, BIT(8), + }, + [VI_VIPRE_ISPIF_RST & RST_SIGNAL_MASK] = { + "VI_VIPRE_ISPIF_RST", 0, 0, BIT(9), + }, + [VI_VIPRE_ARST & RST_SIGNAL_MASK] = { + "VI_VIPRE_ARST", 0, 0, BIT(10), + }, + [VI_ISP_RST & RST_SIGNAL_MASK] = { + "VI_ISP_RST", 0, 0, BIT(11), + }, + [VI_COMP_PRST & RST_SIGNAL_MASK] = { + "VI_COMP_PRST", 0, 0, BIT(12), + }, + [VI_COMP_ARST & RST_SIGNAL_MASK] = { + "VI_COMP_ARST", 0, 0, BIT(13), + }, + [VI_COMP_ISPOUT_RST & RST_SIGNAL_MASK] = { + "VI_COMP_ISPOUT_RST", 0, 0, BIT(14), + }, + [VI_COMP_DECOUT_RST & RST_SIGNAL_MASK] = { + "VI_COMP_DECOUT_RST", 0, 0, BIT(15), + }, + [VI_COMP_VSEOUT_RST & RST_SIGNAL_MASK] = { + "VI_COMP_VSEOUT_RST", 0, 0, BIT(16), + }, + [VI_COMP0_RST & RST_SIGNAL_MASK] = { + "VI_COMP0_RST", 0, 0, BIT(17), + }, + [VI_COMP1_RST & RST_SIGNAL_MASK] = { + "VI_COMP1_RST", 0, 0, BIT(18), + }, + [VI_DECOMP_RST & RST_SIGNAL_MASK] = { + "VI_DECOMP_RST", 0, 0, BIT(19), + }, + [VI_DW200_RST & RST_SIGNAL_MASK] = { + "VI_DW200_RST", 0, 0, BIT(20), + }, + [VI_DFMU_PRST & RST_SIGNAL_MASK] = { + "VI_DFMU_PRST", 0, 0, BIT(21), + }, + [VI_DFMU_ARST & RST_SIGNAL_MASK] = { + "VI_DFMU_ARST", 0, 0, BIT(22), + }, + [VI_ARB_PRST & RST_SIGNAL_MASK] = { + "VI_ARB_PRST", 0, 0, BIT(23), + }, + [VI_ARB_ARST & RST_SIGNAL_MASK] = { + "VI_ARB_ARST", 0, 0, BIT(24), + }, + [VI_X2H0_HRST & RST_SIGNAL_MASK] = { + "VI_X2H0_HRST", 0, 0, BIT(26), + }, + [VI_X2H1_HRST & RST_SIGNAL_MASK] = { + "VI_X2H1_HRST", 0, 0, BIT(27), + }, + [VI_X2H2_HRST & RST_SIGNAL_MASK] = { + "VI_X2H2_HRST", 0, 0, BIT(28), + }, + [VI_REC_PRST & RST_SIGNAL_MASK] = { + "VI_REC_PRST", 0, 0, BIT(29), + }, + [VI_REC_ARST & RST_SIGNAL_MASK] = { + "VI_REC_ARST", 0, 0, BIT(30), + }, +}; + +static struct a210_rst_signal npu_rst_signals[] = { + [NPU_AAB_MST_RST & RST_SIGNAL_MASK] = { + "NPU_AAB_MST_RST", 0, 0, BIT(0), + }, + [NPU_AFENCE_RST & RST_SIGNAL_MASK] = { + "NPU_AFENCE_RST", 0, 0, BIT(1), + }, + [NPU_AXI_CCU_PRST & RST_SIGNAL_MASK] = { + "NPU_AXI_CCU_PRST", 0, 0, BIT(2), + }, + [NPU_AXI_CCU_RST & RST_SIGNAL_MASK] = { + "NPU_AXI_CCU_RST", 0, 0, BIT(3), + }, + [NPU_AXI_M2S1_RST & RST_SIGNAL_MASK] = { + "NPU_AXI_M2S1_RST", 0, 0, BIT(4), + }, + [NPU_AXI_RST & RST_SIGNAL_MASK] = { + "NPU_AXI_RST", 0, 0, BIT(5), + }, + [NPU_CLK_CALC_RST & RST_SIGNAL_MASK] = { + "NPU_CLK_CALC_RST", 0, 0, BIT(6), + }, + [NPU_DFMU_ARST & RST_SIGNAL_MASK] = { + "NPU_DFMU_ARST", 0, 0, BIT(7), + }, + [NPU_DFMU_PRST & RST_SIGNAL_MASK] = { + "NPU_DFMU_PRST", 0, 0, BIT(8), + }, + [NPU_LPC_C_RST & RST_SIGNAL_MASK] = { + "NPU_LPC_C_RST", 0, 0, BIT(9), + }, + [NPU_LPE_C_PRST & RST_SIGNAL_MASK] = { + "NPU_LPE_C_PRST", 0, 0, BIT(10), + }, + [NPU_LPE_C_RST & RST_SIGNAL_MASK] = { + "NPU_LPE_C_RST", 0, 0, BIT(11), + }, + [NPU_ARST & RST_SIGNAL_MASK] = { + "NPU_ARST", 0, 0, BIT(12), + }, + [NPU_CRST & RST_SIGNAL_MASK] = { + "NPU_CRST", 0, 0, BIT(13), + }, + [NPU_HRST & RST_SIGNAL_MASK] = { + "NPU_HRST", 0, 0, BIT(14), + }, + [NPU_PCTRL_PB_RST & RST_SIGNAL_MASK] = { + "NPU_PCTRL_PB_RST", 0, 0, BIT(15), + }, + [NPU_PCTRL_PRST & RST_SIGNAL_MASK] = { + "NPU_PCTRL_PRST", 0, 0, BIT(16), + }, + [NPU_PCTRL_RST & RST_SIGNAL_MASK] = { + "NPU_PCTRL_RST", 0, 0, BIT(17), + }, + [NPU_PTW_CCU_PRST & RST_SIGNAL_MASK] = { + "NPU_PTW_CCU_PRST", 0, 0, BIT(18), + }, + [NPU_PTW_CCU_RST & RST_SIGNAL_MASK] = { + "NPU_PTW_CCU_RST", 0, 0, BIT(19), + }, + [NPU_SEMA_ARST & RST_SIGNAL_MASK] = { + "NPU_SEMA_ARST", 0, 0, BIT(20), + }, + [NPU_SEMA_PRST & RST_SIGNAL_MASK] = { + "NPU_SEMA_PRST", 0, 0, BIT(21), + }, + [NPU_DROOP_CCTRL_PRST & RST_SIGNAL_MASK] = { + "NPU_DROOP_CCTRL_PRST", 0, 0, BIT(22), + }, + [NPU_DROOP_CCTRL_RST & RST_SIGNAL_MASK] = { + "NPU_DROOP_CCTRL_RST", 0, 0, BIT(23), + }, + [NPU_X2H_RST & RST_SIGNAL_MASK] = { + "NPU_X2H_RST", 0, 0, BIT(24), + }, + [NPU_X2P_RST & RST_SIGNAL_MASK] = { + "NPU_X2P_RST", 0, 0, BIT(25), + }, + [NPU_LDIP_RST & RST_SIGNAL_MASK] = { + "NPU_LDIP_RST", 0, 0, BIT(26), + }, + [NPU_SRAM_RST & RST_SIGNAL_MASK] = { + "NPU_SRAM_RST", 0, 0, BIT(27), + }, +}; + +static struct a210_rst_signal vo_rst_signals[] = { + [VO_X2H0_RST & RST_SIGNAL_MASK] = { + "VO_X2H0_RST", 0, 0, BIT(0), + }, + [VO_X2H1_RST & RST_SIGNAL_MASK] = { + "VO_X2H1_RST", 0, 0, BIT(1), + }, + [VO_DPU_HRST & RST_SIGNAL_MASK] = { + "VO_DPU_HRST", 0, 0, BIT(2), + }, + [VO_DPU_CRST & RST_SIGNAL_MASK] = { + "VO_DPU_CRST", 0, 0, BIT(3), + }, + [VO_DPU_ARST & RST_SIGNAL_MASK] = { + "VO_DPU_ARST", 0, 0, BIT(4), + }, + [VO_AUXDISP_PRST & RST_SIGNAL_MASK] = { + "VO_AUXDISP_PRST", 0, 0, BIT(5), + }, + [VO_AUXDISP_PIX_RST & RST_SIGNAL_MASK] = { + "VO_AUXDISP_PIX_RST", 0, 0, BIT(6), + }, + [VO_AUXDISP_ARST & RST_SIGNAL_MASK] = { + "VO_AUXDISP_ARST", 0, 0, BIT(7), + }, + [VO_HDMI_PRST & RST_SIGNAL_MASK] = { + "VO_HDMI_PRST", 0, 0, BIT(8), + }, + [VO_HDMI_MAIN_RST & RST_SIGNAL_MASK] = { + "VO_HDMI_MAIN_RST", 0, 0, BIT(9), + }, + [VO_MIPI_PRST & RST_SIGNAL_MASK] = { + "VO_MIPI_PRST", 0, 0, BIT(10), + }, + [VO_DECOMP_PRST & RST_SIGNAL_MASK] = { + "VO_DECOMP_PRST", 0, 0, BIT(11), + }, + [VO_DECOMP0_CRST & RST_SIGNAL_MASK] = { + "VO_DECOMP0_CRST", 0, 0, BIT(12), + }, + [VO_DECOMP1_CRST & RST_SIGNAL_MASK] = { + "VO_DECOMP1_CRST", 0, 0, BIT(13), + }, + [VO_DECOMP_ARST & RST_SIGNAL_MASK] = { + "VO_DECOMP_ARST", 0, 0, BIT(14), + }, + [VO_ARB_PRST & RST_SIGNAL_MASK] = { + "VO_ARB_PRST", 0, 0, BIT(15), + }, + [VO_ARB_ARST & RST_SIGNAL_MASK] = { + "VO_ARB_ARST", 0, 0, BIT(16), + }, + [VO_DFMU_PRST & RST_SIGNAL_MASK] = { + "VO_DFMU_PRST", 0, 0, BIT(17), + }, + [VO_DFMU_ARST & RST_SIGNAL_MASK] = { + "VO_DFMU_ARST", 0, 0, BIT(18), + }, +}; + +static struct a210_rst_signal peri0_rst_signals[] = { + [PERI0_TIMER0_CRST & RST_SIGNAL_MASK] = { + "PERI0_TIMER0_CRST", 0, 0, BIT(0), + }, + [PERI0_TIMER0_PRST & RST_SIGNAL_MASK] = { + "PERI0_TIMER0_PRST", 0, 0, BIT(1), + }, + [PERI0_TIMER1_CRST & RST_SIGNAL_MASK] = { + "PERI0_TIMER1_CRST", 0, 0, BIT(2), + }, + [PERI0_TIMER1_PRST & RST_SIGNAL_MASK] = { + "PERI0_TIMER1_PRST", 0, 0, BIT(3), + }, + [PERI0_WDT0_PRST & RST_SIGNAL_MASK] = { + "PERI0_WDT0_PRST", 0, 0, BIT(4), + }, + [PERI0_MBOX0_PRST & RST_SIGNAL_MASK] = { + "PERI0_MBOX0_PRST", 0, 0, BIT(5), + }, + [PERI0_MBOX1_PRST & RST_SIGNAL_MASK] = { + "PERI0_MBOX1_PRST", 0, 0, BIT(6), + }, + [PERI0_TIMER0_RST & RST_SIGNAL_MASK] = { + "PERI0_TIMER0_RST", 0, 0, BIT(0) | BIT(1), + }, + [PERI0_TIMER1_RST & RST_SIGNAL_MASK] = { + "PERI0_TIMER1_RST", 0, 0, BIT(2) | BIT(3), + }, +}; + +static struct a210_rst_signal peri1_rst_signals[] = { + [PERI1_GMAC0_ARST & RST_SIGNAL_MASK] = { + "PERI1_GMAC0_ARST", 0, 0, BIT(0), + }, + [PERI1_GMAC0_HRST & RST_SIGNAL_MASK] = { + "PERI1_GMAC0_HRST", 0, 0, BIT(1), + }, + [PERI1_GMAC1_ARST & RST_SIGNAL_MASK] = { + "PERI1_GMAC1_ARST", 0, 0, BIT(2), + }, + [PERI1_GMAC1_HRST & RST_SIGNAL_MASK] = { + "PERI1_GMAC1_HRST", 0, 0, BIT(3), + }, + [PERI1_GPIO0_DBRST & RST_SIGNAL_MASK] = { + "PERI1_GPIO0_DBRST", 0, 0, BIT(4), + }, + [PERI1_GPIO0_PRST & RST_SIGNAL_MASK] = { + "PERI1_GPIO0_PRST", 0, 0, BIT(5), + }, + [PERI1_GPIO1_DBRST & RST_SIGNAL_MASK] = { + "PERI1_GPIO1_DBRST", 0, 0, BIT(6), + }, + [PERI1_GPIO1_PRST & RST_SIGNAL_MASK] = { + "PERI1_GPIO1_PRST", 0, 0, BIT(7), + }, + [PERI1_I2C0_IC_RST & RST_SIGNAL_MASK] = { + "PERI1_I2C0_IC_RST", 0, 0, BIT(8), + }, + [PERI1_I2C0_PRST & RST_SIGNAL_MASK] = { + "PERI1_I2C0_PRST", 0, 0, BIT(9), + }, + [PERI1_I2C1_IC_RST & RST_SIGNAL_MASK] = { + "PERI1_I2C1_IC_RST", 0, 0, BIT(10), + }, + [PERI1_I2C1_PRST & RST_SIGNAL_MASK] = { + "PERI1_I2C1_PRST", 0, 0, BIT(11), + }, + [PERI1_I2C2_IC_RST & RST_SIGNAL_MASK] = { + "PERI1_I2C2_IC_RST", 0, 0, BIT(12), + }, + [PERI1_I2C2_PRST & RST_SIGNAL_MASK] = { + "PERI1_I2C2_PRST", 0, 0, BIT(13), + }, + [PERI1_I2S0_PRST & RST_SIGNAL_MASK] = { + "PERI1_I2S0_PRST", 0, 0, BIT(14), + }, + [PERI1_MST_BUS_ARST & RST_SIGNAL_MASK] = { + "PERI1_MST_BUS_ARST", 0, 0, BIT(15), + }, + [PERI1_MST_BUS_PRST & RST_SIGNAL_MASK] = { + "PERI1_MST_BUS_PRST", 0, 0, BIT(16), + }, + [PERI1_PWM0_CRST & RST_SIGNAL_MASK] = { + "PERI1_PWM0_CRST", 0, 0, BIT(17), + }, + [PERI1_PWM0_PRST & RST_SIGNAL_MASK] = { + "PERI1_PWM0_PRST", 0, 0, BIT(18), + }, + [PERI1_QSPI0_PRST & RST_SIGNAL_MASK] = { + "PERI1_QSPI0_PRST", 0, 0, BIT(19), + }, + [PERI1_QSPI0_SSI_RST & RST_SIGNAL_MASK] = { + "PERI1_QSPI0_SSI_RST", 0, 0, BIT(20), + }, + [PERI1_SPI0_PRST & RST_SIGNAL_MASK] = { + "PERI1_SPI0_PRST", 0, 0, BIT(21), + }, + [PERI1_SPI0_SSI_RST & RST_SIGNAL_MASK] = { + "PERI1_SPI0_SSI_RST", 0, 0, BIT(22), + }, + [PERI1_UART0_PRST & RST_SIGNAL_MASK] = { + "PERI1_UART0_PRST", PERI1_UART0_S_RST, 0, BIT(23), + }, + [PERI1_UART0_S_RST & RST_SIGNAL_MASK] = { + "PERI1_UART0_S_RST", 0, 0, BIT(24), + }, + [PERI1_UART1_PRST & RST_SIGNAL_MASK] = { + "PERI1_UART1_PRST", PERI1_UART1_S_RST, 0, BIT(25), + }, + [PERI1_UART1_S_RST & RST_SIGNAL_MASK] = { + "PERI1_UART1_S_RST", 0, 0, BIT(26), + }, + [PERI1_UART2_PRST & RST_SIGNAL_MASK] = { + "PERI1_UART2_PRST", PERI1_UART2_S_RST, 0, BIT(27), + }, + [PERI1_UART2_S_RST & RST_SIGNAL_MASK] = { + "PERI1_UART2_S_RST", 0, 0, BIT(28), + }, + [PERI1_UART3_PRST & RST_SIGNAL_MASK] = { + "PERI1_UART3_PRST", PERI1_UART3_S_RST, 0, BIT(29), + }, + [PERI1_UART3_S_RST & RST_SIGNAL_MASK] = { + "PERI1_UART3_S_RST", 0, 0, BIT(30), + }, + [PERI1_X2H_GMAC0_ARST & RST_SIGNAL_MASK] = { + "PERI1_X2H_GMAC0_ARST", 0, 0, BIT(31), + }, + [PERI1_X2H_GMAC0_HRST & RST_SIGNAL_MASK] = { + "PERI1_X2H_GMAC0_HRST", 0, 0x4, BIT(0), + }, + [PERI1_X2H_GMAC1_ARST & RST_SIGNAL_MASK] = { + "PERI1_X2H_GMAC1_ARST", 0, 0x4, BIT(1), + }, + [PERI1_X2H_GMAC1_HRST & RST_SIGNAL_MASK] = { + "PERI1_X2H_GMAC1_HRST", 0, 0x4, BIT(2), + }, + [PERI1_DFMU_ARESET & RST_SIGNAL_MASK] = { + "PERI1_DFMU_ARESET", 0, 0x4, BIT(3), + }, + [PERI1_DFMU_PRESET & RST_SIGNAL_MASK] = { + "PERI1_DFMU_PRESET", 0, 0x4, BIT(4), + }, + [PERI1_PAD_CTRL_PRST & RST_SIGNAL_MASK] = { + "PERI1_PAD_CTRL_PRST", 0, 0x4, BIT(5), + }, + [PERI1_PDM0_MRST & RST_SIGNAL_MASK] = { + "PERI1_PDM0_MRST", 0, 0x4, BIT(6), + }, + [PERI1_PDM0_PRST & RST_SIGNAL_MASK] = { + "PERI1_PDM0_PRST", 0, 0x4, BIT(7), + }, + [PERI1_TDM0_RST & RST_SIGNAL_MASK] = { + "PERI1_TDM0_RST", 0, 0x4, BIT(8), + }, + [PERI1_CAN0_IPG_PE_RST & RST_SIGNAL_MASK] = { + "PERI1_CAN0_IPG_PE_RST", 0, 0x4, BIT(9), + }, + [PERI1_CAN0_IPG_RST & RST_SIGNAL_MASK] = { + "PERI1_CAN0_IPG_RST", 0, 0x4, BIT(10), + }, + [PERI1_CAN0_IPG_SOFT_RST & RST_SIGNAL_MASK] = { + "PERI1_CAN0_IPG_SOFT_RST", 0, 0x4, BIT(11), + }, + [PERI1_CAN0_IPG_TS_RST & RST_SIGNAL_MASK] = { + "PERI1_CAN0_IPG_TS_RST", 0, 0x4, BIT(12), + }, + [PERI1_CAN0_PRST & RST_SIGNAL_MASK] = { + "PERI1_CAN0_PRST", 0, 0x4, BIT(13), + }, + [PERI1_CAN1_IPG_PE_RST & RST_SIGNAL_MASK] = { + "PERI1_CAN1_IPG_PE_RST", 0, 0x4, BIT(14), + }, + [PERI1_CAN1_IPG_RST & RST_SIGNAL_MASK] = { + "PERI1_CAN1_IPG_RST", 0, 0x4, BIT(15), + }, + [PERI1_CAN1_IPG_SOFT_RST & RST_SIGNAL_MASK] = { + "PERI1_CAN1_IPG_SOFT_RST", 0, 0x4, BIT(16), + }, + [PERI1_CAN1_IPG_TS_RST & RST_SIGNAL_MASK] = { + "PERI1_CAN1_IPG_TS_RST", 0, 0x4, BIT(17), + }, + [PERI1_CAN1_PRST & RST_SIGNAL_MASK] = { + "PERI1_CAN1_PRST", 0, 0x4, BIT(18), + }, + [PERI1_CHIP_DBG_ARST & RST_SIGNAL_MASK] = { + "PERI1_CHIP_DBG_ARST", 0, 0x4, BIT(19), + }, + [PERI1_CHIP_DBG_CRST & RST_SIGNAL_MASK] = { + "PERI1_CHIP_DBG_CRST", 0, 0x4, BIT(20), + }, + [PERI1_CHIP_DBG_PRST & RST_SIGNAL_MASK] = { + "PERI1_CHIP_DBG_PRST", 0, 0x4, BIT(21), + }, + [PERI1_GMAC_CRST & RST_SIGNAL_MASK] = { + "PERI1_GMAC_CRST", 0, 0x4, BIT(22), + }, + [PERI1_X2H_GMAC2_ARST & RST_SIGNAL_MASK] = { + "PERI1_X2H_GMAC2_ARST", 0, 0x4, BIT(23), + }, + [PERI1_X2H_GMAC2_HRST & RST_SIGNAL_MASK] = { + "PERI1_X2H_GMAC2_HRST", 0, 0x4, BIT(24), + }, + [PERI1_ZGMAC_X2X_ARST & RST_SIGNAL_MASK] = { + "PERI1_ZGMAC_X2X_ARST", 0, 0x4, BIT(25), + }, + [PERI1_SPI0_RST & RST_SIGNAL_MASK] = { + "PERI1_SPI0_RST", 0, 0, BIT(21) | BIT(22), + }, + [PERI1_I2C0_RST & RST_SIGNAL_MASK] = { + "PERI1_I2C0_RST", 0, 0, BIT(8) | BIT(9), + }, + [PERI1_I2C1_RST & RST_SIGNAL_MASK] = { + "PERI1_I2C1_RST", 0, 0, BIT(10) | BIT(11), + }, + [PERI1_I2C2_RST & RST_SIGNAL_MASK] = { + "PERI1_I2C2_RST", 0, 0, BIT(12) | BIT(13), + }, + [PERI1_GMAC0_RST & RST_SIGNAL_MASK] = { + "PERI1_GMAC0_RST", 0, 0, BIT(0) | BIT(1) | BIT(31), + }, + [PERI1_GMAC0_X2H_RST & RST_SIGNAL_MASK] = { + "PERI1_GMAC0_X2H_RST", 0, 0x4, BIT(0), + }, + [PERI1_GMAC1_RST & RST_SIGNAL_MASK] = { + "PERI1_GMAC1_RST", 0, 0, BIT(2) | BIT(3), + }, + [PERI1_GMAC1_X2H_RST & RST_SIGNAL_MASK] = { + "PERI1_GMAC1_X2H_RST", 0, 0x4, BIT(1) | BIT(2), + }, +}; + +static struct a210_rst_signal peri2_rst_signals[] = { + [PERI2_CAN2_IPG_PE_RST & RST_SIGNAL_MASK] = { + "PERI2_CAN2_IPG_PE_RST", 0, 0, BIT(0), + }, + [PERI2_CAN2_IPG_RST & RST_SIGNAL_MASK] = { + "PERI2_CAN2_IPG_RST", 0, 0, BIT(1), + }, + [PERI2_CAN2_IPG_SOFT_RST & RST_SIGNAL_MASK] = { + "PERI2_CAN2_IPG_SOFT_RST", 0, 0, BIT(2), + }, + [PERI2_CAN2_IPG_TS_RST & RST_SIGNAL_MASK] = { + "PERI2_CAN2_IPG_TS_RST", 0, 0, BIT(3), + }, + [PERI2_CAN2_PRST & RST_SIGNAL_MASK] = { + "PERI2_CAN2_PRST", 0, 0, BIT(4), + }, + [PERI2_GPIO2_DBRST & RST_SIGNAL_MASK] = { + "PERI2_GPIO2_DBRST", 0, 0, BIT(5), + }, + [PERI2_GPIO2_PRST & RST_SIGNAL_MASK] = { + "PERI2_GPIO2_PRST", 0, 0, BIT(6), + }, + [PERI2_I2C4_IC_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C4_IC_RST", 0, 0, BIT(7), + }, + [PERI2_I2C4_PRST & RST_SIGNAL_MASK] = { + "PERI2_I2C4_PRST", 0, 0, BIT(8), + }, + [PERI2_I2S2_PRST & RST_SIGNAL_MASK] = { + "PERI2_I2S2_PRST", 0, 0, BIT(9), + }, + [PERI2_SPI1_PRST & RST_SIGNAL_MASK] = { + "PERI2_SPI1_PRST", 0, 0, BIT(10), + }, + [PERI2_SPI1_SSI_RST & RST_SIGNAL_MASK] = { + "PERI2_SPI1_SSI_RST", 0, 0, BIT(11), + }, + [PERI2_UART4_PRST & RST_SIGNAL_MASK] = { + "PERI2_UART4_PRST", PERI2_UART4_S_RST, 0, BIT(12), + }, + [PERI2_UART4_S_RST & RST_SIGNAL_MASK] = { + "PERI2_UART4_S_RST", 0, 0, BIT(13), + }, + [PERI2_UART5_PRST & RST_SIGNAL_MASK] = { + "PERI2_UART5_PRST", PERI2_UART5_S_RST, 0, BIT(14), + }, + [PERI2_UART5_S_RST & RST_SIGNAL_MASK] = { + "PERI2_UART5_S_RST", 0, 0, BIT(15), + }, + [PERI2_UART6_PRST & RST_SIGNAL_MASK] = { + "PERI2_UART6_PRST", PERI2_UART6_S_RST, 0, BIT(16), + }, + [PERI2_UART6_S_RST & RST_SIGNAL_MASK] = { + "PERI2_UART6_S_RST", 0, 0, BIT(17), + }, + [PERI2_PAD_CTRL_PRST & RST_SIGNAL_MASK] = { + "PERI2_PAD_CTRL_PRST", 0, 0, BIT(18), + }, + [PERI2_GPIO3_DBRST & RST_SIGNAL_MASK] = { + "PERI2_GPIO3_DBRST", 0, 0, BIT(19), + }, + [PERI2_GPIO3_PRST & RST_SIGNAL_MASK] = { + "PERI2_GPIO3_PRST", 0, 0, BIT(20), + }, + [PERI2_I2C3_IC_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C3_IC_RST", 0, 0, BIT(21), + }, + [PERI2_I2C3_PRST & RST_SIGNAL_MASK] = { + "PERI2_I2C3_PRST", 0, 0, BIT(22), + }, + [PERI2_I2C5_IC_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C5_IC_RST", 0, 0, BIT(23), + }, + [PERI2_I2C5_PRST & RST_SIGNAL_MASK] = { + "PERI2_I2C5_PRST", 0, 0, BIT(24), + }, + [PERI2_I2C6_IC_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C6_IC_RST", 0, 0, BIT(25), + }, + [PERI2_I2C6_PRST & RST_SIGNAL_MASK] = { + "PERI2_I2C6_PRST", 0, 0, BIT(26), + }, + [PERI2_I2C7_IC_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C7_IC_RST", 0, 0, BIT(27), + }, + [PERI2_I2C7_PRST & RST_SIGNAL_MASK] = { + "PERI2_I2C7_PRST", 0, 0, BIT(28), + }, + [PERI2_I2S1_PRST & RST_SIGNAL_MASK] = { + "PERI2_I2S1_PRST", 0, 0, BIT(29), + }, + [PERI2_I2S3_PRST & RST_SIGNAL_MASK] = { + "PERI2_I2S3_PRST", 0, 0, BIT(30), + }, + [PERI2_UART7_PRST & RST_SIGNAL_MASK] = { + "PERI2_UART7_PRST", PERI2_UART7_S_RST, 0, BIT(31), + }, + [PERI2_UART7_S_RST & RST_SIGNAL_MASK] = { + "PERI2_UART7_S_RST", 0, 0x4, BIT(0), + }, + [PERI2_UART8_PRST & RST_SIGNAL_MASK] = { + "PERI2_UART8_PRST", PERI2_UART8_S_RST, 0x4, BIT(1), + }, + [PERI2_UART8_S_RST & RST_SIGNAL_MASK] = { + "PERI2_UART8_S_RST", 0, 0x4, BIT(2), + }, + [PERI2_UART9_PRST & RST_SIGNAL_MASK] = { + "PERI2_UART9_PRST", PERI2_UART9_S_RST, 0x4, BIT(3), + }, + [PERI2_UART9_S_RST & RST_SIGNAL_MASK] = { + "PERI2_UART9_S_RST", 0, 0x4, BIT(4), + }, + [PERI2_QSPI1_PRST & RST_SIGNAL_MASK] = { + "PERI2_QSPI1_PRST", 0, 0x4, BIT(5), + }, + [PERI2_QSPI1_SSI_RST & RST_SIGNAL_MASK] = { + "PERI2_QSPI1_SSI_RST", 0, 0x4, BIT(6), + }, + [PERI2_PWM1_CRST & RST_SIGNAL_MASK] = { + "PERI2_PWM1_CRST", 0, 0x4, BIT(7), + }, + [PERI2_PWM1_PRST & RST_SIGNAL_MASK] = { + "PERI2_PWM1_PRST", 0, 0x4, BIT(8), + }, + [PERI2_PWM2_CRST & RST_SIGNAL_MASK] = { + "PERI2_PWM2_CRST", 0, 0x4, BIT(9), + }, + [PERI2_PWM2_PRST & RST_SIGNAL_MASK] = { + "PERI2_PWM2_PRST", 0, 0x4, BIT(10), + }, + [PERI2_I2C3_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C3_RST", 0, 0, BIT(21) | BIT(22), + }, + [PERI2_I2C4_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C4_RST", 0, 0, BIT(7) | BIT(8), + }, + [PERI2_I2C5_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C5_RST", 0, 0, BIT(23) | BIT(24), + }, + [PERI2_I2C6_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C6_RST", 0, 0, BIT(25) | BIT(26), + }, + [PERI2_I2C7_RST & RST_SIGNAL_MASK] = { + "PERI2_I2C7_RST", 0, 0, BIT(27) | BIT(28), + }, + [PERI2_SPI1_RST & RST_SIGNAL_MASK] = { + "PERI2_SPI1_RST", 0, 0, BIT(10) | BIT(11), + }, +}; + +static struct a210_rst_signal peri3_rst_signals[] = { + [PERI3_DMAC_ARST & RST_SIGNAL_MASK] = { + "PERI3_DMAC_ARST", 0, 0, BIT(0), + }, + [PERI3_DMAC_HRST & RST_SIGNAL_MASK] = { + "PERI3_DMAC_HRST", 0, 0, BIT(1), + }, + [PERI3_EMMC_SDIO_CLKGEN_RST & RST_SIGNAL_MASK] = { + "PERI3_EMMC_SDIO_CLKGEN_RST", 0, 0, BIT(2), + }, + [PERI3_EMMC_RST & RST_SIGNAL_MASK] = { + "PERI3_EMMC_RST", 0, 0, BIT(3), + }, + [PERI3_EMMC_X2X_ARST_M & RST_SIGNAL_MASK] = { + "PERI3_EMMC_X2X_ARST_M", 0, 0, BIT(4), + }, + [PERI3_EMMC_X2X_ARST_S & RST_SIGNAL_MASK] = { + "PERI3_EMMC_X2X_ARST_S", 0, 0, BIT(5), + }, + [PERI3_SDIO_RST & RST_SIGNAL_MASK] = { + "PERI3_SDIO_RST", 0, 0, BIT(6), + }, + [PERI3_SDIO_X2X_ARST_M & RST_SIGNAL_MASK] = { + "PERI3_SDIO_X2X_ARST_M", 0, 0, BIT(7), + }, + [PERI3_SDIO_X2X_ARST_S & RST_SIGNAL_MASK] = { + "PERI3_SDIO_X2X_ARST_S", 0, 0, BIT(8), + }, + [PERI3_AXI_MST_ARST & RST_SIGNAL_MASK] = { + "PERI3_AXI_MST_ARST", 0, 0, BIT(9), + }, + [PERI3_AXI_MST_PRST & RST_SIGNAL_MASK] = { + "PERI3_AXI_MST_PRST", 0, 0, BIT(10), + }, + [PERI3_ADC_PRST & RST_SIGNAL_MASK] = { + "PERI3_ADC_PRST", 0, 0, BIT(11), + }, + [PERI3_TEE_X2X_ARST_M & RST_SIGNAL_MASK] = { + "PERI3_TEE_X2X_ARST_M", 0, 0, BIT(12), + }, + [PERI3_TEE_X2X_ARST_S & RST_SIGNAL_MASK] = { + "PERI3_TEE_X2X_ARST_S", 0, 0, BIT(13), + }, + [PERI3_TEE_H2H_HRST & RST_SIGNAL_MASK] = { + "PERI3_TEE_H2H_HRST", 0, 0, BIT(14), + }, + [PERI3_GPIO4_DBRST & RST_SIGNAL_MASK] = { + "PERI3_GPIO4_DBRST", 0, 0, BIT(15), + }, + [PERI3_GPIO4_PRST & RST_SIGNAL_MASK] = { + "PERI3_GPIO4_PRST", 0, 0, BIT(16), + }, + [PERI3_PAD_CTRL_PRST & RST_SIGNAL_MASK] = { + "PERI3_PAD_CTRL_PRST", 0, 0, BIT(17), + }, +}; + +static struct a210_rst_signal pcie_rst_signals[] = { + [PCIE_X2X_PERI_SLV_ARST & RST_SIGNAL_MASK] = { + "PCIE_X2X_PERI_SLV_ARST", 0, 0, BIT(0), + }, + [PCIE_X2X_PERI_MST_ARST & RST_SIGNAL_MASK] = { + "PCIE_X2X_PERI_MST_ARST", 0, 0, BIT(4), + }, + [PCIE_AXI4_PCIE_MST_ARST & RST_SIGNAL_MASK] = { + "PCIE_AXI4_PCIE_MST_ARST", 0, 0, BIT(8), + }, + [PCIE_AXI4_PCIE_MST_PRST & RST_SIGNAL_MASK] = { + "PCIE_AXI4_PCIE_MST_PRST", 0, 0, BIT(12), + }, + [PCIE_DFMU_PRST & RST_SIGNAL_MASK] = { + "PCIE_DFMU_PRST", 0, 0x4, BIT(0), + }, + [PCIE_DFMU_ARST & RST_SIGNAL_MASK] = { + "PCIE_DFMU_ARST", 0, 0x4, BIT(4), + }, + [PCIE_E16PHY_PHY_RST & RST_SIGNAL_MASK] = { + "PCIE_E16PHY_PHY_RST", 0, 0x8, BIT(0), + }, + [PCIE_E16PHY_APBS_PRST & RST_SIGNAL_MASK] = { + "PCIE_E16PHY_APBS_PRST", 0, 0x8, BIT(4), + }, + [PCIE_X2X_SATA_MST_ARST & RST_SIGNAL_MASK] = { + "PCIE_X2X_SATA_MST_ARST", 0, 0x10, BIT(0), + }, + [PCIE_X2X_SATA_SLV_ARST & RST_SIGNAL_MASK] = { + "PCIE_X2X_SATA_SLV_ARST", 0, 0x10, BIT(4), + }, + [PCIE_SATA_ARESET & RST_SIGNAL_MASK] = { + "PCIE_SATA_ARESET", 0, 0x10, BIT(8), + }, + [PCIE_SATA_RST_PMALIVE & RST_SIGNAL_MASK] = { + "PCIE_SATA_RST_PMALIVE", 0, 0x10, BIT(12), + }, + [PCIE_SATA_SLV_AFENCE_ARST & RST_SIGNAL_MASK] = { + "PCIE_SATA_SLV_AFENCE_ARST", 0, 0x10, BIT(16), + }, + [PCIE_SATA_MST_AFENCE_ARST & RST_SIGNAL_MASK] = { + "PCIE_SATA_MST_AFENCE_ARST", 0, 0x10, BIT(20), + }, + [PCIE_SATA_RST_ASIC0 & RST_SIGNAL_MASK] = { + "PCIE_SATA_RST_ASIC0", 0, 0x14, BIT(0), + }, + [PCIE_SATA_RST_ASIC1 & RST_SIGNAL_MASK] = { + "PCIE_SATA_RST_ASIC1", 0, 0x14, BIT(4), + }, + [PCIE_SATA_RST_RXOOB0 & RST_SIGNAL_MASK] = { + "PCIE_SATA_RST_RXOOB0", 0, 0x14, BIT(8), + }, + [PCIE_SATA_RST_RXOOB1 & RST_SIGNAL_MASK] = { + "PCIE_SATA_RST_RXOOB1", 0, 0x14, BIT(12), + }, + [PCIE_DM_GEN3X4_APBS_PRST & RST_SIGNAL_MASK] = { + "PCIE_DM_GEN3X4_APBS_PRST", 0, 0x20, BIT(0), + }, + [PCIE_DM_GEN3X4_POWER_UP_RST & RST_SIGNAL_MASK] = { + "PCIE_DM_GEN3X4_POWER_UP_RST", 0, 0x20, BIT(4), + }, + [PCIE_DM_SLV_AFENCE_ARST & RST_SIGNAL_MASK] = { + "PCIE_DM_SLV_AFENCE_ARST", 0, 0x20, BIT(16), + }, + [PCIE_DM_MST_AFENCE_ARST & RST_SIGNAL_MASK] = { + "PCIE_DM_MST_AFENCE_ARST", 0, 0x20, BIT(20), + }, + [PCIE_RP_GEN3X1_APBS_PRST & RST_SIGNAL_MASK] = { + "PCIE_RP_GEN3X1_APBS_PRST", 0, 0x24, BIT(0), + }, + [PCIE_RP_GEN3X1_POWER_UP_RST & RST_SIGNAL_MASK] = { + "PCIE_RP_GEN3X1_POWER_UP_RST", 0, 0x24, BIT(4), + }, + [PCIE_RP_SLV_AFENCE_ARST & RST_SIGNAL_MASK] = { + "PCIE_RP_SLV_AFENCE_ARST", 0, 0x24, BIT(16), + }, + [PCIE_RP_MST_AFENCE_ARST & RST_SIGNAL_MASK] = { + "PCIE_RP_MST_AFENCE_ARST", 0, 0x24, BIT(20), + }, +}; + +static struct a210_rst_signal usb_rst_signals[] = { + [USB_DFMU_PRST & RST_SIGNAL_MASK] = { + "USB_DFMU_PRST", 0, 0, BIT(0), + }, + [USB_DFMU_ARST & RST_SIGNAL_MASK] = { + "USB_DFMU_ARST", 0, 0, BIT(4), + }, + [USB_AXI4_MST_ARST & RST_SIGNAL_MASK] = { + "USB_AXI4_MST_ARST", 0, 0, BIT(8), + }, + [USB_AXI4_MST_PRST & RST_SIGNAL_MASK] = { + "USB_AXI4_MST_PRST", 0, 0, BIT(12), + }, + [USB_DPTX_APBS_PRST & RST_SIGNAL_MASK] = { + "USB_DPTX_APBS_PRST", 0, 0x4, BIT(0), + }, + [USB_DPTX_VCC_RST & RST_SIGNAL_MASK] = { + "USB_DPTX_VCC_RST", 0, 0x4, BIT(4), + }, + [USB_USB31_APBS_PRST & RST_SIGNAL_MASK] = { + "USB_USB31_APBS_PRST", 0, 0x8, BIT(0), + }, + [USB_USB31_VCC_RST & RST_SIGNAL_MASK] = { + "USB_USB31_VCC_RST", 0, 0x8, BIT(4), + }, + [USB_USB31_PHY_RST & RST_SIGNAL_MASK] = { + "USB_USB31_PHY_RST", 0, 0x8, BIT(8), + }, + [USB_USB31_SLV_AFENCE_ARST & RST_SIGNAL_MASK] = { + "USB_USB31_SLV_AFENCE_ARST", 0, 0x8, BIT(12), + }, + [USB_C10PHY_PHY_RST & RST_SIGNAL_MASK] = { + "USB_C10PHY_PHY_RST", 0, 0xc, BIT(0), + }, + [USB_C10PHY_APBS_PRST & RST_SIGNAL_MASK] = { + "USB_C10PHY_APBS_PRST", 0, 0xc, BIT(4), + }, + [USB_USB20_BLK_X2H_HRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_X2H_HRST", 0, 0x10, BIT(0), + }, + [USB_USB20_BLK_X2H_ARST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_X2H_ARST", 0, 0x10, BIT(4), + }, + [USB_USB20_SLV_AFENCE_ARST & RST_SIGNAL_MASK] = { + "USB_USB20_SLV_AFENCE_ARST", 0, 0x10, BIT(8), + }, + [USB_USB20_BLK_H2P_HRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_H2P_HRST", 0, 0x10, BIT(16), + }, + [USB_USB20_BLK_AHB_SLV_HRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_AHB_SLV_HRST", 0, 0x10, BIT(20), + }, + [USB_USB20_BLK_AXI_MST_ARST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_AXI_MST_ARST", 0, 0x10, BIT(24), + }, + [USB_USB20_BLK_USB2_SYSREG_PRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_USB2_SYSREG_PRST", 0, 0x10, BIT(28), + }, + [USB_USB20_BLK_USB2_WRAP0_PRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_USB2_WRAP0_PRST", 0, 0x14, BIT(0), + }, + [USB_USB20_BLK_USB2_WRAP0_HRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_USB2_WRAP0_HRST", 0, 0x14, BIT(4), + }, + [USB_USB20_BLK_USB2_WRAP1_PRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_USB2_WRAP1_PRST", 0, 0x14, BIT(8), + }, + [USB_USB20_BLK_USB2_WRAP1_HRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_USB2_WRAP1_HRST", 0, 0x14, BIT(12), + }, + [USB_USB20_BLK_A2X0_HRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_A2X0_HRST", 0, 0x14, BIT(16), + }, + [USB_USB20_BLK_A2X0_ARST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_A2X0_ARST", 0, 0x14, BIT(20), + }, + [USB_USB20_BLK_A2X1_HRST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_A2X1_HRST", 0, 0x14, BIT(24), + }, + [USB_USB20_BLK_A2X1_ARST & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_A2X1_ARST", 0, 0x14, BIT(28), + }, + [USB_USB20_BLK_USB0_PHY_PON_RESET & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_USB0_PHY_PON_RESET", 0, 0x18, BIT(0), + }, + [USB_USB20_BLK_USB1_PHY_PON_RESET & RST_SIGNAL_MASK] = { + "USB_USB20_BLK_USB1_PHY_PON_RESET", 0, 0x18, BIT(4), + }, + [USB_PERI2_SS_RST & RST_SIGNAL_MASK] = { + "USB_PERI2_SS_RST", 0, 0x20, BIT(0), + }, + [USB_PERI2_SLV_AFENCE_ARST & RST_SIGNAL_MASK] = { + "USB_PERI2_SLV_AFENCE_ARST", 0, 0x20, BIT(4), + }, +}; + +static struct a210_rst_signal tee_rst_signals[] = { + [TEE_KEYRAM_PRST & RST_SIGNAL_MASK] = { + "TEE_KEYRAM_PRST", 0, 0, BIT(0), + }, + [TEE_DS_PRST & RST_SIGNAL_MASK] = { + "TEE_DS_PRST", 0, 0, BIT(1), + }, + [TEE_EFUSE_PRST & RST_SIGNAL_MASK] = { + "TEE_EFUSE_PRST", 0, 0, BIT(2), + }, + [TEE_OCRAM_HRST & RST_SIGNAL_MASK] = { + "TEE_OCRAM_HRST", 0, 0, BIT(3), + }, + [TEE_SYSREG_PRST & RST_SIGNAL_MASK] = { + "TEE_SYSREG_PRST", 0, 0, BIT(4), + }, + [TEE_CCU_PRST & RST_SIGNAL_MASK] = { + "TEE_CCU_PRST", 0, 0, BIT(5), + }, + [TEE_CCU_CRST & RST_SIGNAL_MASK] = { + "TEE_CCU_CRST", 0, 0, BIT(6), + }, + [TEE_EIP150B_HRST & RST_SIGNAL_MASK] = { + "TEE_EIP150B_HRST", 0, 0, BIT(8), + }, + [TEE_EIP120SIII_HRST & RST_SIGNAL_MASK] = { + "TEE_EIP120SIII_HRST", 0, 0, BIT(9), + }, + [TEE_EIP120SIII_ARST & RST_SIGNAL_MASK] = { + "TEE_EIP120SIII_ARST", 0, 0, BIT(10), + }, + [TEE_EIP120SII_HRST & RST_SIGNAL_MASK] = { + "TEE_EIP120SII_HRST", 0, 0, BIT(11), + }, + [TEE_EIP120SII_ARST & RST_SIGNAL_MASK] = { + "TEE_EIP120SII_ARST", 0, 0, BIT(12), + }, + [TEE_EIP120SI_HRST & RST_SIGNAL_MASK] = { + "TEE_EIP120SI_HRST", 0, 0, BIT(13), + }, + [TEE_EIP120SI_ARST & RST_SIGNAL_MASK] = { + "TEE_EIP120SI_ARST", 0, 0, BIT(14), + }, + [TEE_DMAC_HRST & RST_SIGNAL_MASK] = { + "TEE_DMAC_HRST", 0, 0, BIT(15), + }, + [TEE_DMAC_ARST & RST_SIGNAL_MASK] = { + "TEE_DMAC_ARST", 0, 0, BIT(16), + }, + [TEE_X2P_TEESYS_PRST & RST_SIGNAL_MASK] = { + "TEE_X2P_TEESYS_PRST", 0, 0, BIT(24), + }, + [TEE_X2P_TEESYS_ARST & RST_SIGNAL_MASK] = { + "TEE_X2P_TEESYS_ARST", 0, 0, BIT(25), + }, + [TEE_AXI4_TEESYS_ARST & RST_SIGNAL_MASK] = { + "TEE_AXI4_TEESYS_ARST", 0, 0, BIT(26), + }, + [TEE_APB3_TEESYS_PRST & RST_SIGNAL_MASK] = { + "TEE_APB3_TEESYS_PRST", 0, 0, BIT(27), + }, + [TEE_APB3_TEESYS_HRST & RST_SIGNAL_MASK] = { + "TEE_APB3_TEESYS_HRST", 0, 0, BIT(28), + }, + [TEE_AHB2_TEESYS_HRST & RST_SIGNAL_MASK] = { + "TEE_AHB2_TEESYS_HRST", 0, 0, BIT(29), + }, +}; + +static struct a210_rst_signal gpu_rst_signals[] = { + [GPU_PWR_WRAP_RGX_HOOD_RST & RST_SIGNAL_MASK] = { + "GPU_PWR_WRAP_RGX_HOOD_RST", 0, 0, BIT(0), + }, + [GPU_PWR_WRAP_DFMU_RST & RST_SIGNAL_MASK] = { + "GPU_PWR_WRAP_DFMU_RST", 0, 0, BIT(1), + }, +}; + +/* + * Reset ctrl functions + */ +#define RST_DEF(_id, _name, _signals) \ + [_id] = { \ + .id = _id, \ + .name = _name, \ + .signals = _signals, \ + .num_signals = ARRAY_SIZE(_signals), \ + } + +static const struct a210_rst_match_data a210_rst_match_data[] = { + RST_DEF(VP_RST, "vp-rst", vp_rst_signals), + RST_DEF(VI_RST, "vi-rst", vi_rst_signals), + RST_DEF(NPU_RST, "npu-rst", npu_rst_signals), + RST_DEF(VO_RST, "vo-rst", vo_rst_signals), + RST_DEF(PERI0_RST, "peri0-rst", peri0_rst_signals), + RST_DEF(PERI1_RST, "peri1-rst", peri1_rst_signals), + RST_DEF(PERI2_RST, "peri2-rst", peri2_rst_signals), + RST_DEF(PERI3_RST, "peri3-rst", peri3_rst_signals), + RST_DEF(PCIE_RST, "pcie-rst", pcie_rst_signals), + RST_DEF(USB_RST, "usb-rst", usb_rst_signals), + RST_DEF(TEE_RST, "tee-rst", tee_rst_signals), + RST_DEF(GPU_RST, "gpu-rst", gpu_rst_signals), +}; + +static int a210_reset_init_subsys(struct platform_device *pdev, + const struct a210_rst_match_data *data) +{ + struct device *dev = &pdev->dev; + struct a210_reset *priv = dev_get_drvdata(dev); + + if (!data) + return -EINVAL; + + priv->subsys = devm_kzalloc(dev, sizeof(*priv->subsys), GFP_KERNEL); + if (!priv->subsys) + return -ENOMEM; + + priv->subsys_id = data->id; + priv->num_subsys = 1; + priv->subsys[0].signals = data->signals; + priv->subsys[0].num_signals = data->num_signals; + priv->subsys[0].name = data->name; + priv->subsys[0].base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->subsys[0].base)) + return PTR_ERR(priv->subsys[0].base); + + for (int i = 0; i < priv->subsys[0].num_signals; i++) + priv->subsys[0].signals[i].subsys = &priv->subsys[0]; + + return 0; +} + +static inline struct a210_reset *to_a210_reset(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct a210_reset, reset); +} + +static int a210_reset_subsys_signal_lookup(struct a210_reset *priv, unsigned long id, + struct a210_rst_subsys **subsys, struct a210_rst_signal **signal) +{ + u32 subsys_id = id >> 8; + u32 signal_id = id & RST_SIGNAL_MASK; + + if (subsys_id != priv->subsys_id) + return -ENODEV; + + *subsys = &priv->subsys[0]; + + if (signal_id >= (*subsys)->num_signals) + return -ENODEV; + + *signal = &(*subsys)->signals[signal_id]; + + return 0; +} + +static int a210_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + u32 reg; + struct a210_reset *priv = to_a210_reset(rcdev); + struct a210_rst_subsys *subsys; + struct a210_rst_signal *signal; + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + do { + ret = a210_reset_subsys_signal_lookup(priv, id, &subsys, &signal); + if (ret) { + spin_unlock_irqrestore(&priv->lock, flags); + dev_err(rcdev->dev, "fail to find signal 0x%lx\n", id); + return ret; + } + + reg = readl(subsys->base + signal->offset); + if (assert == true) + reg &= ~signal->bit; + else + reg |= signal->bit; + writel(reg, subsys->base + signal->offset); + + id = signal->nextid; + } while (id > 0); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int a210_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return a210_reset_update(rcdev, id, true); +} + +static int a210_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return a210_reset_update(rcdev, id, false); +} + +static int a210_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct a210_reset *priv = to_a210_reset(rcdev); + struct a210_rst_subsys *subsys; + struct a210_rst_signal *signal; + int ret; + + ret = a210_reset_subsys_signal_lookup(priv, id, &subsys, &signal); + if (ret) + return ret; + + return !!(readl(subsys->base + signal->offset) & signal->bit); +} + +static const struct reset_control_ops a210_reset_ops = { + .assert = a210_reset_assert, + .deassert = a210_reset_deassert, + .status = a210_reset_status, +}; + +static int a210_register_reset(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct a210_reset *priv = dev_get_drvdata(dev); + + priv->reset.ops = &a210_reset_ops; + priv->reset.owner = THIS_MODULE; + priv->reset.of_node = dev->of_node; + priv->reset.of_reset_n_cells = 1; + priv->reset.nr_resets = A210_RESETS_MAX; + + spin_lock_init(&priv->lock); + + return reset_controller_register(&priv->reset); +} + +/* + * Debugfs + */ +#if defined(CONFIG_DEBUG_FS) +static void str_to_lower(char *str) +{ + while (*str) { + *str = tolower(*str); + str++; + } +} + +static struct a210_rst_debugfs_node *alloc_debugfs_nodes(struct platform_device *pdev) +{ + int i; + int signal_count = 0; + + struct a210_reset *priv = dev_get_drvdata(&pdev->dev); + + /* Get signal count */ + for (i = 0; i < priv->num_subsys; i++) + signal_count += priv->subsys[i].num_signals; + + return devm_kzalloc(&pdev->dev, + sizeof(struct a210_rst_debugfs_node) * signal_count, + GFP_KERNEL); +} + +static int a210_signal_status_show(struct seq_file *s, void *data) +{ + struct a210_rst_debugfs_node *node = (struct a210_rst_debugfs_node *)s->private; + struct a210_rst_subsys *subsys = node->subsys; + struct a210_rst_signal *signal = node->signal; + int status = !!(readl(subsys->base + signal->offset) & signal->bit); + + seq_printf(s, "%d\n", status); + + return 0; +} + +static int a210_subsys_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, a210_signal_status_show, inode->i_private); +} + +static const struct file_operations a210_subsys_status_fops = { + .open = a210_subsys_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void a210_reset_debugfs_init(struct a210_reset *priv) +{ + struct dentry *entry; + u32 i, j; + char name[A210_RST_NAME_SIZE]; + char debugfs_entry_name[32] = "a210-reset"; + struct dentry *debugfs_entry; + const char *addr_ptr; + + /* Multiple instance DTS node example + * rst1: reset-controller@1 + */ + addr_ptr = strchr(of_node_full_name(priv->dev->of_node), '@'); + if (addr_ptr) { + addr_ptr++; + strcat(debugfs_entry_name, addr_ptr); + } + + /* Create the main debugfs directory for a210 reset */ + debugfs_entry = debugfs_create_dir(debugfs_entry_name, NULL); + if (!debugfs_entry) { + dev_err(priv->dev, "Failed to create %s debugfs directory\n", debugfs_entry_name); + return; + } + + /* Iterate through all subsys */ + int signal_idx = 0; + + for (i = 0; i < priv->num_subsys; i++) { + /* Create signal files for each subsystem */ + for (j = 0; j < priv->subsys[i].num_signals; j++) { + struct a210_rst_debugfs_node *node = &priv->debugfs_node[signal_idx]; + + strscpy(name, priv->subsys[i].signals[j].name, sizeof(name)); + str_to_lower(name); + + node->signal = &priv->subsys[i].signals[j]; + node->subsys = &priv->subsys[i]; + entry = debugfs_create_file(name, 0444, + debugfs_entry, + (void *)node, + &a210_subsys_status_fops); + + signal_idx++; + if (!entry) { + dev_err(priv->dev, "Failed to create %s file in debugfs\n", name); + continue; + } + } + } +} +#endif + +/* + * Probe + */ +static int a210_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct a210_reset *priv; + int ret; + + /* Alloc priv data */ + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + dev_set_drvdata(dev, priv); + + ret = a210_reset_init_subsys(pdev, of_device_get_match_data(dev)); + if (ret) + goto fail; + + /* Alloc debugfs nodes */ + priv->debugfs_node = alloc_debugfs_nodes(pdev); + if (!priv->debugfs_node) { + ret = -ENOMEM; + goto fail; + } + + ret = a210_register_reset(pdev); + if (ret) + goto fail; + +#if defined(CONFIG_DEBUG_FS) + a210_reset_debugfs_init(priv); +#endif + dev_info(dev, "succeed to register a210 reset driver\n"); + + return ret; + +fail: + devm_kfree(dev, priv->debugfs_node); + devm_kfree(dev, priv->subsys); + devm_kfree(dev, priv); + return ret; +} + +static const struct of_device_id a210_reset_of_match[] = { + { .compatible = "zhihe,a210-vp-reset", .data = &a210_rst_match_data[VP_RST] }, + { .compatible = "zhihe,a210-vi-reset", .data = &a210_rst_match_data[VI_RST] }, + { .compatible = "zhihe,a210-npu-reset", .data = &a210_rst_match_data[NPU_RST] }, + { .compatible = "zhihe,a210-vo-reset", .data = &a210_rst_match_data[VO_RST] }, + { .compatible = "zhihe,a210-peri0-reset", .data = &a210_rst_match_data[PERI0_RST] }, + { .compatible = "zhihe,a210-peri1-reset", .data = &a210_rst_match_data[PERI1_RST] }, + { .compatible = "zhihe,a210-peri2-reset", .data = &a210_rst_match_data[PERI2_RST] }, + { .compatible = "zhihe,a210-peri3-reset", .data = &a210_rst_match_data[PERI3_RST] }, + { .compatible = "zhihe,a210-pcie-reset", .data = &a210_rst_match_data[PCIE_RST] }, + { .compatible = "zhihe,a210-usb-reset", .data = &a210_rst_match_data[USB_RST] }, + { .compatible = "zhihe,a210-tee-reset", .data = &a210_rst_match_data[TEE_RST] }, + { .compatible = "zhihe,a210-gpu-reset", .data = &a210_rst_match_data[GPU_RST] }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, a210_reset_of_match); + +struct platform_driver a210_reset_driver = { + .probe = a210_reset_probe, + .driver = { + .name = "a210-reset", + .of_match_table = of_match_ptr(a210_reset_of_match), + }, +}; + +static int a210_reset_init(void) +{ + return platform_driver_register(&a210_reset_driver); +} + +arch_initcall(a210_reset_init); + +MODULE_AUTHOR("dong.yan "); +MODULE_DESCRIPTION("Zhihe A210 reset controller driver"); +MODULE_LICENSE("GPL"); From 9f1199bc1811da6a203a94776c046dc205f620e7 Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Apr 2026 20:29:02 +0800 Subject: [PATCH 06/17] pinctrl: add ZhiHe A210 pin controller driver Add a pin controller driver for the ZhiHe A210 SoC supporting pin multiplexing and pin configuration (pull-up/down, drive strength, etc.). Signed-off-by: Zhiguo Zhu --- drivers/pinctrl/Kconfig | 14 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-a210.c | 1246 ++++++++++++++++++++++++++++++++ 3 files changed, 1261 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-a210.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index a943e120ac016..7a37ff6ddcca5 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -493,6 +493,20 @@ config PINCTRL_TH1520 help This selects the pinctrl driver for XuanTie TH1520 RISC-V SoC. +config PINCTRL_A210 + tristate "ZhiHe A210 pin controller" + depends on ARCH_ZHIHE || COMPILE_TEST + default ARCH_ZHIHE + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select PINMUX + help + This selects the pinctrl driver for the ZhiHe A210 RISC-V SoC. + + It provides pin multiplexing and configuration support for + the A210 pad controllers (AON, PADCTRL0-2). Say Y if you + are building a kernel for the ZhiHe A210 platform. + config PINCTRL_ZYNQ bool "Pinctrl driver for Xilinx Zynq" depends on ARCH_ZYNQ diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 555a120b0395f..429aa8ed27369 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o +obj-$(CONFIG_PINCTRL_A210) += pinctrl-a210.o obj-y += actions/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ diff --git a/drivers/pinctrl/pinctrl-a210.c b/drivers/pinctrl/pinctrl-a210.c new file mode 100644 index 0000000000000..0eb7a3b27fb34 --- /dev/null +++ b/drivers/pinctrl/pinctrl-a210.c @@ -0,0 +1,1246 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl driver for the ZhiHe A210 SoC + * + * Copyright (C) 2023 Emil Renner Berthing + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "core.h" +#include "pinmux.h" +#include "pinconf.h" + +#define A210_PADCFG_IE BIT(9) +#define A210_PADCFG_SL BIT(8) +#define A210_PADCFG_ST BIT(7) +#define A210_PADCFG_SPU BIT(6) +#define A210_PADCFG_PS BIT(5) +#define A210_PADCFG_PE BIT(4) +#define A210_PADCFG_BIAS (A210_PADCFG_SPU | A210_PADCFG_PS | A210_PADCFG_PE) +#define A210_PADCFG_DS GENMASK(3, 0) + +#define A210_PULL_DOWN_OHM 44000 /* typ. 44kOhm */ +#define A210_PULL_UP_OHM 48000 /* typ. 48kOhm */ +#define A210_PULL_STRONG_OHM 2100 /* typ. 2.1kOhm */ + +#define A210_PAD_NO_PADCFG BIT(63) +#define A210_PAD_MUXDATA GENMASK(55, 0) + +#ifdef CONFIG_PM_SLEEP +#define MAX_CFG_REG_NUMS 25 +#define MAX_MUX_REG_NUMS 7 +#define A210_AON_CFG_REG_NUMS 22 +#define A210_AON_MUX_REG_NUMS 6 +#define A210_PADCTRL0_CFG_REG_NUMS 25 +#define A210_PADCTRL0_MUX_REG_NUMS 7 +#define A210_PADCTRL1_CFG_REG_NUMS 22 +#define A210_PADCTRL1_MUX_REG_NUMS 6 +#define A210_PADCTRL2_CFG_REG_NUMS 6 +#define A210_PADCTRL2_MUX_REG_NUMS 1 +#define A210_PM_PAD_CFG(idx) (pp->base + pp->offset_cfg + idx * 4) +#define A210_PM_PAD_MUX(idx) (pp->base + pp->offset_mux + idx * 4) +#endif + +struct a210_pinctrl; + +enum a210_pinctrl_type { + A210_PADCTRL_AON, + A210_PADCTRL_0, + A210_PADCTRL_1, + A210_PADCTRL_2, +}; + +struct a210_pad_group { + const char *name; + const struct pinctrl_pin_desc *pins; + unsigned int npins; + unsigned int offset_mux; + unsigned int mask_mux; + unsigned int offset_cfg; + unsigned int mask_cfg; + enum a210_pinctrl_type type; +}; + +struct a210_pinctrl { + struct pinctrl_desc desc; + struct mutex mutex; /* serialize adding functions */ + raw_spinlock_t lock; /* serialize register access */ + void __iomem *base; + struct clk *clk; + unsigned int offset_mux; + unsigned int mask_mux; + unsigned int offset_cfg; + unsigned int mask_cfg; + enum a210_pinctrl_type type; + struct pinctrl_dev *pctl; +#ifdef CONFIG_PM_SLEEP + unsigned int cfg_bak[MAX_CFG_REG_NUMS]; + unsigned int mux_bak[MAX_MUX_REG_NUMS]; +#endif +}; + +static const unsigned int m1 = 0x55555555; // 01010101010101010101010101010101 +static const unsigned int m2 = 0x33333333; // 00110011001100110011001100110011 +static const unsigned int m4 = 0x0f0f0f0f; // 00001111000011110000111100001111 +static const unsigned int m8 = 0x00ff00ff; // 00000000111111110000000011111111 +static const unsigned int m16 = 0x0000ffff; // 00000000000000001111111111111111 + +static int __popcount(unsigned int x) +{ + x = (x & m1) + ((x >> 1) & m1); + x = (x & m2) + ((x >> 2) & m2); + x = (x & m4) + ((x >> 4) & m4); + x = (x & m8) + ((x >> 8) & m8); + x = (x & m16) + ((x >> 16) & m16); + return x; +} + +static void __iomem *a210_padcfg(struct a210_pinctrl *pp, + unsigned int pin) +{ + int width = __popcount(pp->mask_cfg); + + return pp->base + pp->offset_cfg + 4 * (pin * width / 32); +} + +static unsigned int a210_padcfg_shift(struct a210_pinctrl *pp, + unsigned int pin) +{ + int width = __popcount(pp->mask_cfg); + + return width * (pin & (32 / width - 1)); +} + +static void __iomem *a210_muxcfg(struct a210_pinctrl *pp, + unsigned int pin) +{ + int width = __popcount(pp->mask_mux); + + return pp->base + pp->offset_mux + 4 * (pin * width / 32); +} + +static unsigned int a210_muxcfg_shift(struct a210_pinctrl *pp, + unsigned int pin) +{ + int width = __popcount(pp->mask_mux); + + return width * (pin & (32 / width - 1)); +} + +enum a210_muxtype { + A210_MUX_____, + A210_MUX_AOUART, + A210_MUX_AOUART_IR, + A210_MUX_AOGPIO0, + A210_MUX_AOGPIO1, + A210_MUX_AOI2C0, + A210_MUX_AOI2C1, + A210_MUX_AOSPI, + A210_MUX_JTAG, + A210_MUX_RST, + A210_MUX_POR, + A210_MUX_PMIC, + A210_MUX_DVS, + A210_MUX_UART0, + A210_MUX_UART1, + A210_MUX_UART2, + A210_MUX_UART3, + A210_MUX_UART4, + A210_MUX_UART5, + A210_MUX_UART6, + A210_MUX_UART7, + A210_MUX_UART8, + A210_MUX_UART9, + A210_MUX_UART0_IR, + A210_MUX_UART1_IR, + A210_MUX_UART2_IR, + A210_MUX_UART3_IR, + A210_MUX_UART4_IR, + A210_MUX_UART5_IR, + A210_MUX_UART6_IR, + A210_MUX_UART7_IR, + A210_MUX_UART8_IR, + A210_MUX_UART9_IR, + A210_MUX_GPIO0, + A210_MUX_GPIO1, + A210_MUX_GPIO2, + A210_MUX_GPIO3, + A210_MUX_GPIO4, + A210_MUX_GMAC0, + A210_MUX_GMAC1, + A210_MUX_SPI0, + A210_MUX_SPI1, + A210_MUX_QSPI0, + A210_MUX_QSPI1, + A210_MUX_PWM0, + A210_MUX_PWM1, + A210_MUX_PWM2, + A210_MUX_CAN0, + A210_MUX_CAN1, + A210_MUX_CAN2, + A210_MUX_I2S0, + A210_MUX_I2S1, + A210_MUX_I2S2, + A210_MUX_I2S3, + A210_MUX_I2C0, + A210_MUX_I2C1, + A210_MUX_I2C2, + A210_MUX_I2C3, + A210_MUX_I2C4, + A210_MUX_I2C5, + A210_MUX_I2C6, + A210_MUX_I2C7, + A210_MUX_I2C7_SMB, + A210_MUX_SDIO, + A210_MUX_ISP0, + A210_MUX_DPTX, + A210_MUX_USB31, + A210_MUX_SATA_P0, + A210_MUX_SATA_P1, + A210_MUX_HDMI, + A210_MUX_ZMAC, + A210_MUX_BSEL, + A210_MUX_DBGM, + A210_MUX_CDBG, + A210_MUX_PDM, + A210_MUX_TDM, + A210_MUX_PCIE_X1, + A210_MUX_PCIE_X4, + A210_MUX_SEN_VCLK, + A210_MUX_MAX = 127, +}; + +static const char *const a210_muxtype_string[] = { + [A210_MUX_AOUART] = "aouart", + [A210_MUX_AOUART_IR] = "aouart_ir", + [A210_MUX_AOGPIO0] = "aogpio0", + [A210_MUX_AOGPIO1] = "aogpio1", + [A210_MUX_AOI2C0] = "aoi2c0", + [A210_MUX_AOI2C1] = "aoi2c1", + [A210_MUX_AOSPI] = "aospi", + [A210_MUX_JTAG] = "jtag", + [A210_MUX_RST] = "reset", + [A210_MUX_POR] = "por", + [A210_MUX_PMIC] = "pmic", + [A210_MUX_DVS] = "dvs", + [A210_MUX_UART0] = "uart0", + [A210_MUX_UART1] = "uart1", + [A210_MUX_UART2] = "uart2", + [A210_MUX_UART3] = "uart3", + [A210_MUX_UART4] = "uart4", + [A210_MUX_UART5] = "uart5", + [A210_MUX_UART6] = "uart6", + [A210_MUX_UART7] = "uart7", + [A210_MUX_UART8] = "uart8", + [A210_MUX_UART9] = "uart9", + [A210_MUX_UART0_IR] = "uart0_ir", + [A210_MUX_UART1_IR] = "uart1_ir", + [A210_MUX_UART2_IR] = "uart2_ir", + [A210_MUX_UART3_IR] = "uart3_ir", + [A210_MUX_UART4_IR] = "uart4_ir", + [A210_MUX_UART5_IR] = "uart5_ir", + [A210_MUX_UART6_IR] = "uart6_ir", + [A210_MUX_UART7_IR] = "uart7_ir", + [A210_MUX_UART8_IR] = "uart8_ir", + [A210_MUX_UART9_IR] = "uart9_ir", + [A210_MUX_GPIO0] = "gpio0", + [A210_MUX_GPIO1] = "gpio1", + [A210_MUX_GPIO2] = "gpio2", + [A210_MUX_GPIO3] = "gpio3", + [A210_MUX_GPIO4] = "gpio4", + [A210_MUX_GMAC0] = "gmac0", + [A210_MUX_GMAC1] = "gmac1", + [A210_MUX_SPI0] = "spi0", + [A210_MUX_SPI1] = "spi1", + [A210_MUX_QSPI0] = "qspi0", + [A210_MUX_QSPI1] = "qspi1", + [A210_MUX_PWM0] = "pwm0", + [A210_MUX_PWM1] = "pwm1", + [A210_MUX_PWM2] = "pwm2", + [A210_MUX_CAN0] = "can0", + [A210_MUX_CAN1] = "can1", + [A210_MUX_CAN2] = "can2", + [A210_MUX_I2S0] = "i2s0", + [A210_MUX_I2S1] = "i2s1", + [A210_MUX_I2S2] = "i2s2", + [A210_MUX_I2S3] = "i2s3", + [A210_MUX_I2C0] = "i2c0", + [A210_MUX_I2C1] = "i2c1", + [A210_MUX_I2C2] = "i2c2", + [A210_MUX_I2C3] = "i2c3", + [A210_MUX_I2C4] = "i2c4", + [A210_MUX_I2C5] = "i2c5", + [A210_MUX_I2C6] = "i2c6", + [A210_MUX_I2C7] = "i2c7", + [A210_MUX_I2C7_SMB] = "i2c7_smb", + [A210_MUX_SDIO] = "sdio", + [A210_MUX_ISP0] = "isp0", + [A210_MUX_DPTX] = "dptx", + [A210_MUX_USB31] = "usb31", + [A210_MUX_SATA_P0] = "sata_p0", + [A210_MUX_SATA_P1] = "sata_p1", + [A210_MUX_HDMI] = "hdmi", + [A210_MUX_ZMAC] = "zmac", + [A210_MUX_BSEL] = "bsel", + [A210_MUX_DBGM] = "dbgm", + [A210_MUX_CDBG] = "cdbg", + [A210_MUX_PDM] = "pdm", + [A210_MUX_TDM] = "tdm", + [A210_MUX_PCIE_X1] = "pcie_x1", + [A210_MUX_PCIE_X4] = "pcie_x4", + [A210_MUX_SEN_VCLK] = "sen_vclk", +}; + +static enum a210_muxtype a210_muxtype_get(const char *str) +{ + enum a210_muxtype mt; + + for (mt = A210_MUX_AOUART; mt < ARRAY_SIZE(a210_muxtype_string); mt++) { + if (!strcmp(str, a210_muxtype_string[mt])) + return mt; + } + return A210_MUX_____; +} + +#define A210_PAD(_nr, _name, m0, m1, m2, m3, m4, m5, m6, m7, _flags) \ + { .number = _nr, .name = #_name, .drv_data = (void *)((_flags) | \ + (A210_MUX_##m0 << 0) | (A210_MUX_##m1 << 7) | (A210_MUX_##m2 << 14) | \ + (A210_MUX_##m3 << 21) | ((uintptr_t)A210_MUX_##m4 << 28) | \ + ((uintptr_t)A210_MUX_##m5 << 35) | ((uintptr_t)A210_MUX_##m6 << 42) | \ + ((uintptr_t)A210_MUX_##m7 << 49)) } + +static const struct pinctrl_pin_desc a210_group0_pins[] = { + A210_PAD(0, OSC_CLK_IN, ____, ____, ____, ____, ____, ____, ____, ____, A210_PAD_NO_PADCFG), + A210_PAD(1, OSC_CLK_OUT, ____, ____, ____, ____, ____, ____, ____, ____, A210_PAD_NO_PADCFG), + A210_PAD(2, RST_N_IN, ____, ____, ____, ____, ____, ____, ____, ____, A210_PAD_NO_PADCFG), + A210_PAD(3, RTC_CLK_IN, ____, ____, ____, ____, ____, ____, ____, ____, A210_PAD_NO_PADCFG), + A210_PAD(4, RTC_CLK_OUT, ____, ____, ____, ____, ____, ____, ____, ____, A210_PAD_NO_PADCFG), + A210_PAD(6, TEST_MODE, ____, ____, ____, ____, ____, ____, ____, ____, A210_PAD_NO_PADCFG), + A210_PAD(7, POR_SEL, ____, ____, ____, ____, ____, ____, ____, ____, A210_PAD_NO_PADCFG), + /* skip number 7 so we can calculate register offsets and shifts from the pin number */ + A210_PAD(8, RST_N_OUT, RST, ____, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(9, BOOT_SEL0, BSEL, ____, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(10, BOOT_SEL1, BSEL, AOUART, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(11, DEBUG_MODE, DBGM, ____, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(12, AOUART_TXD, AOUART, AOUART_IR, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(13, AOUART_RXD, AOUART, AOUART_IR, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(14, AOI2C0_SCL, AOI2C0, AOSPI, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(15, AOI2C0_SDA, AOI2C0, AOSPI, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(16, AOI2C1_SCL, AOI2C1, AOSPI, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(17, AOI2C1_SDA, AOI2C1, AOSPI, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(18, CPU_JTG_TCLK, JTAG, ____, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(19, CPU_JTG_TMS, JTAG, ____, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(20, CPU_JTG_TDI, JTAG, ____, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(21, CPU_JTG_TDO, JTAG, POR, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(22, CPU_JTG_TRST, JTAG, ____, ____, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(23, AOGPIO0_21, AOGPIO0, AOSPI, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(24, AOGPIO0_22, AOGPIO0, AOSPI, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(25, AOGPIO0_23, BSEL, AOSPI, PMIC, AOGPIO0, ____, ____, ____, ____, 0), + A210_PAD(26, AOGPIO0_24, AOGPIO0, AOSPI, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(27, AOGPIO0_25, AOGPIO0, AOSPI, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(28, AOGPIO0_26, AOGPIO0, AOI2C1, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(29, AOGPIO0_27, AOGPIO0, AOI2C1, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(30, AOGPIO0_28, AOGPIO0, AOI2C1, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(31, AOGPIO0_29, AOGPIO0, AOI2C1, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(32, AOGPIO0_30, AOGPIO0, AOI2C1, PMIC, DVS, ____, ____, ____, ____, 0), + A210_PAD(33, AOGPIO0_31, AOGPIO0, AOUART, PMIC, DVS, ____, ____, ____, ____, 0), + A210_PAD(34, AOGPIO1_0, AOGPIO1, AOUART, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(35, AOGPIO1_1, AOGPIO1, ____, PMIC, ____, ____, ____, ____, ____, 0), + A210_PAD(36, AOGPIO1_2, AOGPIO1, ____, PMIC, DVS, ____, ____, ____, ____, 0), + A210_PAD(37, AOGPIO1_3, AOGPIO1, ____, PMIC, DVS, ____, ____, ____, ____, 0), + A210_PAD(38, AOGPIO1_4, AOGPIO1, ____, PMIC, DVS, ____, ____, ____, ____, 0), + A210_PAD(39, AOGPIO1_5, AOGPIO1, ____, PMIC, DVS, ____, ____, ____, ____, 0), + A210_PAD(40, AOGPIO1_6, AOGPIO1, ____, PMIC, DVS, ____, ____, ____, ____, 0), + A210_PAD(41, AOGPIO1_7, AOGPIO1, ____, PMIC, DVS, ____, ____, ____, ____, 0), + A210_PAD(42, AOGPIO1_8, PCIE_X4, ____, PMIC, AOGPIO1, ____, ____, ____, ____, 0), + A210_PAD(43, AOGPIO1_9, AOGPIO1, ____, PMIC, ____, ____, ____, ____, ____, 0), +}; + +static const struct pinctrl_pin_desc a210_group1_pins[] = { + A210_PAD(0, GPIO0_0, GPIO0, GMAC0, ____, ____, ____, ____, ZMAC, ____, 0), + A210_PAD(1, GPIO0_1, GPIO0, GMAC0, ____, ____, ____, ____, ZMAC, ____, 0), + A210_PAD(2, GPIO0_2, GPIO0, GMAC0, ____, ____, ____, ____, ZMAC, ____, 0), + A210_PAD(3, GPIO0_3, GPIO0, GMAC0, UART3, UART3_IR, ____, SATA_P0, ZMAC, ____, 0), + A210_PAD(4, GPIO0_4, GPIO0, GMAC0, UART3, UART3_IR, ____, SATA_P1, ZMAC, ____, 0), + A210_PAD(5, GPIO0_5, GPIO0, GMAC0, UART3, ____, ____, SATA_P1, ZMAC, ____, 0), + A210_PAD(6, GPIO0_6, GPIO0, GMAC0, UART3, ____, ____, SATA_P1, ZMAC, ____, 0), + A210_PAD(7, GPIO0_7, GPIO0, GMAC0, ____, ____, ____, SATA_P1, ZMAC, ____, 0), + A210_PAD(8, GPIO0_8, GPIO0, GMAC0, I2C0, ____, ____, SATA_P1, ZMAC, ____, 0), + A210_PAD(9, GPIO0_9, GPIO0, GMAC0, I2C0, ____, ____, PCIE_X4, ZMAC, ____, 0), + A210_PAD(10, GPIO0_10, GPIO0, GMAC0, I2C1, ____, ____, PCIE_X4, ZMAC, ____, 0), + A210_PAD(11, GPIO0_11, GPIO0, GMAC0, I2C1, ____, ____, PCIE_X4, ZMAC, ____, 0), + A210_PAD(12, GPIO0_12, GPIO0, GMAC0, ____, ____, ____, PCIE_X4, ZMAC, ____, 0), + A210_PAD(13, GPIO0_13, GPIO0, GMAC0, ____, ____, ____, PWM0, ZMAC, ____, 0), + A210_PAD(14, GPIO0_14, GPIO0, UART0, UART0_IR, ____, SATA_P1, I2S0, ____, ____, 0), + A210_PAD(15, GPIO0_15, GPIO0, UART0, UART0_IR, QSPI0, SATA_P1, I2S0, ____, ____, 0), + A210_PAD(16, GPIO0_16, GPIO0, UART0, UART1, UART1_IR, SATA_P1, I2S0, ZMAC, ____, 0), + A210_PAD(17, GPIO0_17, GPIO0, UART0, UART1, UART1_IR, SATA_P1, I2S0, ZMAC, ____, 0), + A210_PAD(18, GPIO0_18, GPIO0, QSPI0, GMAC0, SDIO, SATA_P1, I2S0, ____, PCIE_X1, 0), + A210_PAD(19, GPIO0_19, GPIO0, QSPI0, GMAC1, ____, TDM, SATA_P0, ____, PCIE_X1, 0), + A210_PAD(20, GPIO0_20, GPIO0, QSPI0, UART3, UART3_IR, TDM, SATA_P0, ZMAC, PCIE_X1, 0), + A210_PAD(21, GPIO0_21, GPIO0, QSPI0, UART3, UART3_IR, TDM, SATA_P0, ZMAC, PCIE_X1, 0), + A210_PAD(22, GPIO0_22, GPIO0, QSPI0, I2C2, ____, TDM, SATA_P0, ZMAC, PWM0, 0), + A210_PAD(23, GPIO0_23, GPIO0, QSPI0, I2C2, ____, ____, SATA_P0, ZMAC, PWM0, 0), + A210_PAD(24, GPIO0_24, GPIO0, QSPI0, I2C0, CAN0, CDBG, PCIE_X1, UART0, PWM0, 0), + A210_PAD(25, GPIO0_25, GPIO0, QSPI0, I2C0, CAN0, CDBG, PCIE_X1, UART0, PWM0, 0), + A210_PAD(26, GPIO0_26, GPIO0, QSPI0, I2C1, CAN1, CDBG, PCIE_X1, UART0, UART0_IR, 0), + A210_PAD(27, GPIO0_27, GPIO0, QSPI0, I2C1, CAN1, CDBG, PCIE_X1, UART0, UART0_IR, 0), + A210_PAD(28, GPIO0_28, GPIO0, PWM0, SPI0, UART1_IR, I2S0, PCIE_X4, UART1, ____, 0), + A210_PAD(29, GPIO0_29, GPIO0, PWM0, SPI0, UART1_IR, I2S0, PCIE_X4, UART1, ____, 0), + A210_PAD(30, GPIO0_30, GPIO0, PWM0, SPI0, ____, I2S0, PCIE_X4, UART1, ____, 0), + A210_PAD(31, GPIO0_31, GPIO0, PWM0, SPI0, QSPI0, I2S0, PCIE_X4, UART1, ____, 0), + A210_PAD(32, GPIO1_0, GPIO1, PWM0, UART2, UART2_IR, I2S0, SDIO, GMAC1, SATA_P0, 0), + A210_PAD(33, GPIO1_1, GPIO1, PWM0, UART2, UART2_IR, I2C2, SATA_P1, SPI0, SDIO, 0), + A210_PAD(34, GPIO1_2, GPIO1, GMAC1, TDM, PWM0, I2C2, SATA_P1, ____, ____, 0), + A210_PAD(35, GPIO1_3, GPIO1, GMAC1, TDM, PWM0, ____, SATA_P1, ____, ____, 0), + A210_PAD(36, GPIO1_4, GPIO1, GMAC1, TDM, UART2, ____, SATA_P1, ____, ____, 0), + A210_PAD(37, GPIO1_5, GPIO1, GMAC1, ____, UART2, ____, SATA_P1, ____, ____, 0), + A210_PAD(38, GPIO1_6, GPIO1, GMAC1, SPI0, PWM0, CDBG, SATA_P0, ____, ____, 0), + A210_PAD(39, GPIO1_7, GPIO1, GMAC1, SPI0, PWM0, CDBG, SATA_P0, ____, ____, 0), + A210_PAD(40, GPIO1_8, GPIO1, GMAC1, SPI0, PDM, CDBG, SATA_P0, ____, ____, 0), + A210_PAD(41, GPIO1_9, GPIO1, GMAC1, SPI0, PWM0, ____, SATA_P0, GMAC0, ____, 0), + A210_PAD(42, GPIO1_10, GPIO1, GMAC1, SPI0, PWM0, ____, SATA_P0, ____, ____, 0), + A210_PAD(43, GPIO1_11, GPIO1, GMAC1, QSPI0, PDM, I2S0, ISP0, PWM0, ____, 0), + A210_PAD(44, GPIO1_12, GPIO1, GMAC1, QSPI0, PDM, I2S0, ISP0, ____, ____, 0), + A210_PAD(45, GPIO1_13, GPIO1, GMAC1, QSPI0, PDM, I2S0, ISP0, ____, ____, 0), + A210_PAD(46, GPIO1_14, GPIO1, GMAC1, ____, PDM, I2S0, ISP0, ____, ____, 0), + A210_PAD(47, GPIO1_15, GPIO1, GMAC1, SDIO, PDM, I2S0, ISP0, ____, ____, 0), + A210_PAD(48, GPIO1_16, GPIO1, GMAC0, ____, ____, ____, SDIO, ____, ____, 0), + A210_PAD(49, MULTI_DIE_PACKAGE, GPIO1, ____, ____, ____, ____, ____, ____, ____, 0), +}; + +static const struct pinctrl_pin_desc a210_group2_pins[] = { + A210_PAD(0, GPIO2_0, GPIO2, UART4, UART4_IR, PWM2, ____, I2C3, ____, ____, 0), + A210_PAD(1, GPIO2_1, GPIO2, UART4, UART4_IR, PWM2, ____, I2C3, ____, ____, 0), + A210_PAD(2, GPIO2_2, GPIO2, UART5, UART5_IR, PWM2, ____, I2C5, I2S1, ____, 0), + A210_PAD(3, GPIO2_3, GPIO2, UART5, UART5_IR, PWM2, ____, I2C5, I2S1, ____, 0), + A210_PAD(4, GPIO2_4, GPIO2, UART6, UART6_IR, PWM2, ____, I2C6, I2S1, ____, 0), + A210_PAD(5, GPIO2_5, GPIO2, UART6, UART6_IR, PWM2, ____, I2C6, I2S1, ____, 0), + A210_PAD(6, GPIO2_6, GPIO2, UART7, UART7_IR, PWM2, SEN_VCLK, I2C4, I2S1, ____, 0), + A210_PAD(7, GPIO2_7, GPIO2, UART7, UART7_IR, PWM2, SEN_VCLK, I2C4, ____, ____, 0), + A210_PAD(8, GPIO2_8, GPIO2, I2S2, ____, SPI1, UART6, I2C6, PWM2, ____, 0), + A210_PAD(9, GPIO2_9, GPIO2, I2S2, ____, SPI1, UART6, I2C6, PWM2, ____, 0), + A210_PAD(10, GPIO2_10, GPIO2, I2S2, PWM1, SPI1, UART9, I2C7, ____, ____, 0), + A210_PAD(11, GPIO2_11, GPIO2, I2S2, PWM1, SPI1, UART9, I2C7, ____, ____, 0), + A210_PAD(12, GPIO2_12, GPIO2, I2S2, PWM1, SPI1, UART8, I2C7, ____, ____, 0), + A210_PAD(13, GPIO2_13, GPIO2, I2S3, PWM1, ____, ____, ____, ____, ____, 0), + A210_PAD(14, GPIO2_14, GPIO2, I2S3, PWM1, ____, ____, ____, ____, ____, 0), + A210_PAD(15, GPIO2_15, GPIO2, I2S3, ____, ____, ____, ____, ____, ____, 0), + A210_PAD(16, GPIO2_16, GPIO2, I2S3, ____, ____, ____, ____, ____, ____, 0), + A210_PAD(17, GPIO2_17, GPIO2, I2S3, SPI1, I2C4, UART8, I2C7, ____, ____, 0), + A210_PAD(18, GPIO2_18, GPIO2, I2S3, SPI1, I2C4, PWM2, UART5, UART5_IR, ____, 0), + A210_PAD(19, GPIO2_19, GPIO2, I2S3, SPI1, ____, PWM1, UART5, UART5_IR, ____, 0), + A210_PAD(20, GPIO2_20, GPIO2, I2S3, ____, ____, ____, ____, ____, ____, 0), + A210_PAD(21, GPIO2_21, GPIO2, I2S3, SPI1, I2C3, PWM1, UART8, ____, ____, 0), + A210_PAD(22, GPIO2_22, GPIO2, I2S3, SPI1, I2C3, PWM1, UART8, ____, ____, 0), + A210_PAD(23, GPIO2_23, GPIO2, I2S3, PWM1, ____, ____, ____, ____, ____, 0), + A210_PAD(24, GPIO2_24, GPIO2, I2C3, UART5, ____, ____, ____, ____, ____, 0), + A210_PAD(25, GPIO2_25, GPIO2, I2C3, UART5, ____, HDMI, QSPI1, PWM2, ____, 0), + A210_PAD(26, GPIO2_26, GPIO2, I2C4, UART6, ____, ____, ____, ____, ____, 0), + A210_PAD(27, GPIO2_27, GPIO2, I2C4, UART6, ____, ____, ____, ____, ____, 0), + A210_PAD(28, GPIO2_28, GPIO2, I2C5, UART7, PWM1, ____, QSPI1, ____, ____, 0), + A210_PAD(29, GPIO2_29, GPIO2, I2C5, UART7, PWM1, ____, QSPI1, ____, ____, 0), + A210_PAD(30, GPIO2_30, GPIO2, I2C6, UART8, PWM1, HDMI, QSPI1, I2S3, ____, 0), + A210_PAD(31, GPIO2_31, GPIO2, I2C6, UART8, PWM1, HDMI, QSPI1, I2S3, ____, 0), + A210_PAD(32, GPIO3_0, GPIO3, I2C7, UART9, PWM1, CAN2, QSPI1, I2S3, SEN_VCLK, 0), + A210_PAD(33, GPIO3_1, GPIO3, I2C7, UART9, PWM1, CAN2, QSPI1, I2S3, SEN_VCLK, 0), + A210_PAD(34, GPIO3_2, GPIO3, QSPI1, UART8, UART8_IR, ____, ____, I2S3, PWM1, 0), + A210_PAD(35, GPIO3_3, GPIO3, QSPI1, UART8, UART8_IR, ____, ____, I2S3, PWM1, 0), + A210_PAD(36, GPIO3_4, GPIO3, QSPI1, UART9, UART9_IR, ____, ____, I2S3, PWM2, 0), + A210_PAD(37, GPIO3_5, GPIO3, QSPI1, UART9, UART9_IR, ____, ____, I2S3, PWM2, 0), + A210_PAD(38, GPIO3_6, GPIO3, QSPI1, I2S1, I2C7_SMB, ____, DPTX, I2S3, PWM2, 0), + A210_PAD(39, GPIO3_7, GPIO3, QSPI1, I2S1, I2C7_SMB, UART7, I2C5, I2S3, PWM2, 0), + A210_PAD(40, GPIO3_8, GPIO3, QSPI1, I2S1, I2C7_SMB, UART7, I2C5, I2S3, PWM2, 0), + A210_PAD(41, GPIO3_9, GPIO3, UART4, I2S1, I2C7_SMB, UART5, DPTX, ____, PWM2, 0), + A210_PAD(42, GPIO3_10, GPIO3, UART4, I2S1, I2C7_SMB, UART5, USB31, ____, ____, 0), +}; + +static const struct pinctrl_pin_desc a210_group3_pins[] = { + A210_PAD(0, SDIO_CLK, SDIO, GPIO4, ____, ____, ____, ____, ____, ____, 0), + A210_PAD(1, SDIO_CMD, SDIO, GPIO4, ____, ____, ____, ____, ____, ____, 0), + A210_PAD(2, SDIO_DAT0, SDIO, GPIO4, ____, ____, ____, ____, ____, ____, 0), + A210_PAD(3, SDIO_DAT1, SDIO, GPIO4, ____, ____, ____, ____, ____, ____, 0), + A210_PAD(4, SDIO_DAT2, SDIO, GPIO4, ____, ____, ____, ____, ____, ____, 0), + A210_PAD(5, SDIO_DAT3, SDIO, GPIO4, ____, ____, ____, ____, ____, ____, 0), +}; + +static const struct a210_pad_group a210_group0 = { /* aon */ + .name = "a210-group0", + .pins = a210_group0_pins, + .npins = ARRAY_SIZE(a210_group0_pins), + .offset_mux = 0x400, + .mask_mux = 0xf, + .offset_cfg = 0x0, + .mask_cfg = 0xffff, + .type = A210_PADCTRL_AON, +}; + +static const struct a210_pad_group a210_group1 = { /* peri1 */ + .name = "a210-group1", + .pins = a210_group1_pins, + .npins = ARRAY_SIZE(a210_group1_pins), + .offset_mux = 0x400, + .mask_mux = 0xf, + .offset_cfg = 0x0, + .mask_cfg = 0xffff, + .type = A210_PADCTRL_0, +}; + +static const struct a210_pad_group a210_group2 = { /* peri2 */ + .name = "a210-group2", + .pins = a210_group2_pins, + .npins = ARRAY_SIZE(a210_group2_pins), + .offset_mux = 0x400, + .mask_mux = 0xf, + .offset_cfg = 0x0, + .mask_cfg = 0xffff, + .type = A210_PADCTRL_1, +}; + +static const struct a210_pad_group a210_group3 = { /* peri3 gpio special; zhihe need mod. */ + .name = "a210-group3", + .pins = a210_group3_pins, + .npins = ARRAY_SIZE(a210_group3_pins), + .offset_mux = 0x200, + .mask_mux = 0x1, + .offset_cfg = 0x0, + .mask_cfg = 0x1, + .type = A210_PADCTRL_2, +}; + +static int a210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + + return pp->desc.npins; +} + +static const char *a210_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int gsel) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + + return pp->desc.pins[gsel].name; +} + +static int a210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int gsel, + const unsigned int **pins, + unsigned int *npins) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pp->desc.pins[gsel].number; + *npins = 1; + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void a210_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + void __iomem *padcfg = a210_padcfg(pp, pin); + void __iomem *muxcfg = a210_muxcfg(pp, pin); + u32 pad; + u32 mux; + + scoped_guard(raw_spinlock_irqsave, &pp->lock) { + pad = readl_relaxed(padcfg); + mux = readl_relaxed(muxcfg); + } + + seq_printf(s, "[PADCFG_%03u:0x%x=0x%07x MUXCFG_%03u:0x%x=0x%08x]", + 1 + pin / 2, 0x000 + 4 * (pin / 2), pad, + 1 + pin / 8, 0x400 + 4 * (pin / 8), mux); +} +#else +#define a210_pin_dbg_show NULL +#endif + +static void a210_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned int nmaps) +{ + unsigned long *seen = NULL; + unsigned int i; + + for (i = 0; i < nmaps; i++) { + if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN && + map[i].data.configs.configs != seen) { + seen = map[i].data.configs.configs; + kfree(seen); + } + } + + kfree(map); +} + +static int a210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **maps, + unsigned int *num_maps) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + struct device_node *child; + struct pinctrl_map *map; + unsigned long *configs; + unsigned int nconfigs; + unsigned int nmaps; + int ret; + + nmaps = 0; + for_each_available_child_of_node(np, child) { + int npins = of_property_count_strings(child, "pins"); + + if (npins <= 0) { + of_node_put(child); + dev_err(pp->pctl->dev, "no pins selected for %pOFn.%pOFn\n", + np, child); + return -EINVAL; + } + nmaps += npins; + if (of_property_present(child, "function")) + nmaps += npins; + } + + map = kcalloc(nmaps, sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + nmaps = 0; + mutex_lock(&pp->mutex); + for_each_available_child_of_node(np, child) { + unsigned int rollback = nmaps; + enum a210_muxtype muxtype; + struct property *prop; + const char *funcname; + const char **pgnames; + const char *pinname; + int npins; + + ret = pinconf_generic_parse_dt_config(child, pctldev, &configs, &nconfigs); + if (ret) { + dev_err(pp->pctl->dev, "%pOFn.%pOFn: error parsing pin config\n", + np, child); + goto put_child; + } + + if (!of_property_read_string(child, "function", &funcname)) { + muxtype = a210_muxtype_get(funcname); + if (!muxtype) { + dev_err(pp->pctl->dev, "%pOFn.%pOFn: unknown function '%s'\n", + np, child, funcname); + ret = -EINVAL; + goto free_configs; + } + + funcname = devm_kasprintf(pp->pctl->dev, GFP_KERNEL, "%pOFn.%pOFn", + np, child); + if (!funcname) { + ret = -ENOMEM; + goto free_configs; + } + + npins = of_property_count_strings(child, "pins"); + pgnames = devm_kcalloc(pp->pctl->dev, npins, sizeof(*pgnames), GFP_KERNEL); + if (!pgnames) { + ret = -ENOMEM; + goto free_configs; + } + } else { + funcname = NULL; + } + + npins = 0; + of_property_for_each_string(child, "pins", prop, pinname) { + unsigned int i; + + for (i = 0; i < pp->desc.npins; i++) { + if (!strcmp(pinname, pp->desc.pins[i].name)) + break; + } + if (i == pp->desc.npins) { + nmaps = rollback; + dev_err(pp->pctl->dev, "%pOFn.%pOFn: unknown pin '%s'\n", + np, child, pinname); + goto free_configs; + } + + if (nconfigs) { + map[nmaps].type = PIN_MAP_TYPE_CONFIGS_PIN; + map[nmaps].data.configs.group_or_pin = pp->desc.pins[i].name; + map[nmaps].data.configs.configs = configs; + map[nmaps].data.configs.num_configs = nconfigs; + nmaps += 1; + } + if (funcname) { + pgnames[npins++] = pp->desc.pins[i].name; + map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + map[nmaps].data.mux.function = funcname; + map[nmaps].data.mux.group = pp->desc.pins[i].name; + nmaps += 1; + } + } + + if (funcname) { + ret = pinmux_generic_add_function(pctldev, funcname, pgnames, + npins, (void *)muxtype); + if (ret < 0) { + dev_err(pp->pctl->dev, "error adding function %s\n", funcname); + goto put_child; + } + } + } + + *maps = map; + *num_maps = nmaps; + mutex_unlock(&pp->mutex); + return 0; + +free_configs: + kfree(configs); +put_child: + of_node_put(child); + a210_pinctrl_dt_free_map(pctldev, map, nmaps); + mutex_unlock(&pp->mutex); + return ret; +} + +static const struct pinctrl_ops a210_pinctrl_ops = { + .get_groups_count = a210_pinctrl_get_groups_count, + .get_group_name = a210_pinctrl_get_group_name, + .get_group_pins = a210_pinctrl_get_group_pins, + .pin_dbg_show = a210_pin_dbg_show, + .dt_node_to_map = a210_pinctrl_dt_node_to_map, + .dt_free_map = a210_pinctrl_dt_free_map, +}; + +static const u8 a210_drive_strength_in_mA[16] = { + 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25, +}; + +static u16 a210_drive_strength_from_mA(u32 arg) +{ + u16 ds; + + for (ds = 0; ds < A210_PADCFG_DS; ds++) { + if (arg <= a210_drive_strength_in_mA[ds]) + return ds; + } + return A210_PADCFG_DS; +} + +static int a210_padcfg_rmw(struct a210_pinctrl *pp, unsigned int pin, + u32 mask, u32 value) +{ + void __iomem *padcfg = a210_padcfg(pp, pin); + unsigned int shift = a210_padcfg_shift(pp, pin); + u32 tmp; + + mask <<= shift; + value <<= shift; + + scoped_guard(raw_spinlock_irqsave, &pp->lock) { + tmp = readl_relaxed(padcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, padcfg); + } + return 0; +} + +static int a210_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + const struct pin_desc *desc = pin_desc_get(pctldev, pin); + bool enabled; + int param; + u32 value; + u32 arg; + + if ((uintptr_t)desc->drv_data & A210_PAD_NO_PADCFG) + return -EOPNOTSUPP; + + value = readl_relaxed(a210_padcfg(pp, pin)); + value = (value >> a210_padcfg_shift(pp, pin)) & GENMASK(9, 0); + + param = pinconf_to_config_param(*config); + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + enabled = !(value & (A210_PADCFG_SPU | A210_PADCFG_PE)); + arg = 0; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + enabled = (value & A210_PADCFG_BIAS) == A210_PADCFG_PE; + arg = enabled ? A210_PULL_DOWN_OHM : 0; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (value & A210_PADCFG_SPU) { + enabled = true; + arg = A210_PULL_STRONG_OHM; + } else if ((value & (A210_PADCFG_PE | A210_PADCFG_PS)) == + (A210_PADCFG_PE | A210_PADCFG_PS)) { + enabled = true; + arg = A210_PULL_UP_OHM; + } else { + enabled = false; + arg = 0; + } + break; + case PIN_CONFIG_DRIVE_STRENGTH: + enabled = true; + arg = a210_drive_strength_in_mA[value & A210_PADCFG_DS]; + break; + case PIN_CONFIG_INPUT_ENABLE: + enabled = value & A210_PADCFG_IE; + arg = enabled ? 1 : 0; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + enabled = value & A210_PADCFG_ST; + arg = enabled ? 1 : 0; + break; + case PIN_CONFIG_SLEW_RATE: + enabled = value & A210_PADCFG_SL; + arg = enabled ? 1 : 0; + break; + default: + return -EOPNOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return enabled ? 0 : -EINVAL; +} + +static int a210_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int gsel, unsigned long *config) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + unsigned int pin = pp->desc.pins[gsel].number; + + return a210_pinconf_get(pctldev, pin, config); +} + +static int a210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + const struct pin_desc *desc = pin_desc_get(pctldev, pin); + unsigned int i; + u16 mask, value; + + if ((uintptr_t)desc->drv_data & A210_PAD_NO_PADCFG) + return -EOPNOTSUPP; + + mask = 0; + value = 0; + for (i = 0; i < num_configs; i++) { + int param = pinconf_to_config_param(configs[i]); + u32 arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + mask |= A210_PADCFG_BIAS; + value &= ~A210_PADCFG_BIAS; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (arg == 0) + return -EOPNOTSUPP; + mask |= A210_PADCFG_BIAS; + value &= ~A210_PADCFG_BIAS; + value |= A210_PADCFG_PE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (arg == 0) + return -EOPNOTSUPP; + mask |= A210_PADCFG_BIAS; + value &= ~A210_PADCFG_BIAS; + if (arg == A210_PULL_STRONG_OHM) + value |= A210_PADCFG_SPU; + else + value |= A210_PADCFG_PE | A210_PADCFG_PS; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + mask |= A210_PADCFG_DS; + value &= ~A210_PADCFG_DS; + value |= a210_drive_strength_from_mA(arg); + break; + case PIN_CONFIG_INPUT_ENABLE: + mask |= A210_PADCFG_IE; + if (arg) + value |= A210_PADCFG_IE; + else + value &= ~A210_PADCFG_IE; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + mask |= A210_PADCFG_ST; + if (arg) + value |= A210_PADCFG_ST; + else + value &= ~A210_PADCFG_ST; + break; + case PIN_CONFIG_SLEW_RATE: + mask |= A210_PADCFG_SL; + if (arg) + value |= A210_PADCFG_SL; + else + value &= ~A210_PADCFG_SL; + break; + default: + return -EOPNOTSUPP; + } + } + + return a210_padcfg_rmw(pp, pin, mask, value); +} + +static int a210_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int gsel, + unsigned long *configs, + unsigned int num_configs) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + unsigned int pin = pp->desc.pins[gsel].number; + + return a210_pinconf_set(pctldev, pin, configs, num_configs); +} + +#ifdef CONFIG_DEBUG_FS +static void a210_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + u32 value = readl_relaxed(a210_padcfg(pp, pin)); + + value = (value >> a210_padcfg_shift(pp, pin)) & GENMASK(9, 0); + + seq_printf(s, " [0x%03x]", value); +} +#else +#define a210_pinconf_dbg_show NULL +#endif + +static const struct pinconf_ops a210_pinconf_ops = { + .pin_config_get = a210_pinconf_get, + .pin_config_group_get = a210_pinconf_group_get, + .pin_config_set = a210_pinconf_set, + .pin_config_group_set = a210_pinconf_group_set, + .pin_config_dbg_show = a210_pinconf_dbg_show, + .is_generic = true, +}; + +static int a210_pinmux_set(struct a210_pinctrl *pp, unsigned int pin, + unsigned long muxdata, enum a210_muxtype muxtype) +{ + void __iomem *muxcfg = a210_muxcfg(pp, pin); + unsigned int shift = a210_muxcfg_shift(pp, pin); + u32 mask, value, tmp; + + for (value = 0; muxdata; muxdata >>= 7, value++) { + if ((muxdata & GENMASK(6, 0)) == muxtype) + break; + } + if (!muxdata) { + dev_err(pp->pctl->dev, "invalid mux %s for pin %s\n", + a210_muxtype_string[muxtype], pin_get_name(pp->pctl, pin)); + return -EINVAL; + } + + mask = pp->mask_mux << shift; + value = value << shift; + + scoped_guard(raw_spinlock_irqsave, &pp->lock) { + tmp = readl_relaxed(muxcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, muxcfg); + } + + return 0; +} + +static int a210_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int fsel, unsigned int gsel) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + const struct function_desc *func = pinmux_generic_get_function(pctldev, fsel); + + return a210_pinmux_set(pp, pp->desc.pins[gsel].number, + (uintptr_t)pp->desc.pins[gsel].drv_data & A210_PAD_MUXDATA, + (uintptr_t)func->data); +} + +static int a210_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + unsigned int muxtype, value; + const struct pin_desc *desc = pin_desc_get(pctldev, offset); + unsigned long muxdata = (uintptr_t)desc->drv_data & A210_PAD_MUXDATA; + + for (value = 0; muxdata; muxdata >>= 7, value++) { + if (value <= 7) { // ALT0~ALT7 + switch (muxdata & GENMASK(6, 0)) { + case A210_MUX_AOGPIO0: + muxtype = A210_MUX_AOGPIO0; + break; + case A210_MUX_AOGPIO1: + muxtype = A210_MUX_AOGPIO1; + break; + case A210_MUX_GPIO0: + muxtype = A210_MUX_GPIO0; + break; + case A210_MUX_GPIO1: + muxtype = A210_MUX_GPIO1; + break; + case A210_MUX_GPIO2: + muxtype = A210_MUX_GPIO2; + break; + case A210_MUX_GPIO3: + muxtype = A210_MUX_GPIO3; + break; + case A210_MUX_GPIO4: + muxtype = A210_MUX_GPIO4; + break; + default: + continue; + } + } else { + dev_err(pp->pctl->dev, "invalid mux %#lx for pin %s\n", + (uintptr_t)desc->drv_data, desc->name); + return -EINVAL; + } + break; + } + + return a210_pinmux_set(pp, offset, + (uintptr_t)desc->drv_data & A210_PAD_MUXDATA, muxtype); +} + +static int a210_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct a210_pinctrl *pp = pinctrl_dev_get_drvdata(pctldev); + + return a210_padcfg_rmw(pp, offset, A210_PADCFG_IE, + input ? A210_PADCFG_IE : 0); +} + +static const struct pinmux_ops a210_pinmux_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = a210_pinmux_set_mux, + .gpio_request_enable = a210_gpio_request_enable, + .gpio_set_direction = a210_gpio_set_direction, + .strict = true, +}; + +static int a210_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct a210_pad_group *group; + struct a210_pinctrl *pp; + int ret; + + group = device_get_match_data(dev); + if (!group) + return dev_err_probe(dev, -EINVAL, "missing pad group data\n"); + + pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + + pp->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pp->base)) + return PTR_ERR(pp->base); + + pp->desc.name = group->name; + pp->desc.pins = group->pins; + pp->desc.npins = group->npins; + pp->offset_mux = group->offset_mux; + pp->mask_mux = group->mask_mux; + pp->offset_cfg = group->offset_cfg; + pp->mask_cfg = group->mask_cfg; + pp->type = group->type; + pp->desc.pctlops = &a210_pinctrl_ops; + pp->desc.pmxops = &a210_pinmux_ops; + pp->desc.confops = &a210_pinconf_ops; + pp->desc.owner = THIS_MODULE; + mutex_init(&pp->mutex); + raw_spin_lock_init(&pp->lock); + + if (pp->type > A210_PADCTRL_AON) { + pp->clk = devm_clk_get_enabled(dev, "pclk"); + if (IS_ERR(pp->clk)) + return dev_err_probe(dev, PTR_ERR(pp->clk), "error getting clock\n"); + } else { + pp->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(pp->clk)) + return dev_err_probe(dev, PTR_ERR(pp->clk), "error getting clock\n"); + } + + platform_set_drvdata(pdev, pp); + ret = devm_pinctrl_register_and_init(dev, &pp->desc, pp, &pp->pctl); + if (ret) + return dev_err_probe(dev, ret, "could not register pinctrl driver\n"); + + return pinctrl_enable(pp->pctl); +} + +#ifdef CONFIG_PM_SLEEP +static int a210_pinctrl_backup_regs(struct a210_pinctrl *pp, unsigned int cfg_reg_nums, + unsigned int mux_reg_nums) +{ + int i; + + for (i = 0; i < cfg_reg_nums; i++) + pp->cfg_bak[i] = readl(A210_PM_PAD_CFG(i)); + for (i = 0; i < mux_reg_nums; i++) + pp->mux_bak[i] = readl(A210_PM_PAD_MUX(i)); + + return 0; +} + +static int a210_pinctrl_restore_regs(struct a210_pinctrl *pp, unsigned int cfg_reg_nums, + unsigned int mux_reg_nums) +{ + int i; + + for (i = 0; i < cfg_reg_nums; i++) + writel(pp->cfg_bak[i], A210_PM_PAD_CFG(i)); + for (i = 0; i < mux_reg_nums; i++) + writel(pp->mux_bak[i], A210_PM_PAD_MUX(i)); + + return 0; +} + +static int a210_pinctrl_suspend(struct device *dev) +{ + dev_info(dev, "a210 pinctrl suspend\n"); + struct a210_pinctrl *pp = dev_get_drvdata(dev); + int ret = 0; + + switch (pp->type) { + case A210_PADCTRL_AON: + ret = a210_pinctrl_backup_regs(pp, A210_AON_CFG_REG_NUMS, + A210_AON_MUX_REG_NUMS); + break; + case A210_PADCTRL_0: + ret = a210_pinctrl_backup_regs(pp, + A210_PADCTRL0_CFG_REG_NUMS, + A210_PADCTRL0_MUX_REG_NUMS); + clk_disable_unprepare(pp->clk); + break; + case A210_PADCTRL_1: + ret = a210_pinctrl_backup_regs(pp, + A210_PADCTRL1_CFG_REG_NUMS, + A210_PADCTRL1_MUX_REG_NUMS); + clk_disable_unprepare(pp->clk); + break; + case A210_PADCTRL_2: + ret = a210_pinctrl_backup_regs(pp, + A210_PADCTRL2_CFG_REG_NUMS, + A210_PADCTRL2_MUX_REG_NUMS); + clk_disable_unprepare(pp->clk); + break; + default: + break; + } + + return ret; +} + +static int a210_pinctrl_resume(struct device *dev) +{ + dev_info(dev, "a210 pinctrl resume\n"); + struct a210_pinctrl *pp = dev_get_drvdata(dev); + int ret = 0; + + switch (pp->type) { + case A210_PADCTRL_AON: + ret = a210_pinctrl_restore_regs(pp, A210_AON_CFG_REG_NUMS, + A210_AON_MUX_REG_NUMS); + break; + case A210_PADCTRL_0: + ret = clk_prepare_enable(pp->clk); + if (ret) { + dev_err(dev, "could not enable padctrl clk\n"); + return -EINVAL; + } + ret = a210_pinctrl_restore_regs(pp, + A210_PADCTRL0_CFG_REG_NUMS, + A210_PADCTRL0_MUX_REG_NUMS); + break; + case A210_PADCTRL_1: + ret = clk_prepare_enable(pp->clk); + if (ret) { + dev_err(dev, "could not enable padctrl clk\n"); + return -EINVAL; + } + ret = a210_pinctrl_restore_regs(pp, + A210_PADCTRL1_CFG_REG_NUMS, + A210_PADCTRL1_MUX_REG_NUMS); + break; + case A210_PADCTRL_2: + ret = clk_prepare_enable(pp->clk); + if (ret) { + dev_err(dev, "could not enable padctrl clk\n"); + return -EINVAL; + } + ret = a210_pinctrl_restore_regs(pp, + A210_PADCTRL2_CFG_REG_NUMS, + A210_PADCTRL2_MUX_REG_NUMS); + break; + default: + break; + } + + return ret; +} +#endif //CONFIG_PM_SLEEP + +static const struct dev_pm_ops a210_pinctrl_dev_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(a210_pinctrl_suspend, a210_pinctrl_resume) +}; + +static const struct of_device_id a210_pinctrl_of_match[] = { + { .compatible = "zhihe,a210-aon-pinctrl", .data = &a210_group0 }, + { .compatible = "zhihe,a210-peri1-pinctrl", .data = &a210_group1 }, + { .compatible = "zhihe,a210-peri2-pinctrl", .data = &a210_group2 }, + { .compatible = "zhihe,a210-peri3-pinctrl", .data = &a210_group3 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, a210_pinctrl_of_match); + +static struct platform_driver a210_pinctrl_driver = { + .probe = a210_pinctrl_probe, + .driver = { + .name = "pinctrl-a210", + .of_match_table = a210_pinctrl_of_match, + .pm = &a210_pinctrl_dev_pm_ops, + }, +}; +module_platform_driver(a210_pinctrl_driver); + +MODULE_DESCRIPTION("Pinctrl driver for the ZhiHe A210 SoC"); +MODULE_AUTHOR("Emil Renner Berthing "); +MODULE_LICENSE("GPL"); From 57f04eb66a4c7b039a47d09adc99f20305f0dd6b Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Apr 2026 20:29:08 +0800 Subject: [PATCH 07/17] pmdomain: add ZhiHe A210 power domain driver Add a generic power domain driver for the ZhiHe A210 SoC to manage power gating of on-chip IP blocks. The driver uses power domain IDs defined in dt-bindings/power/a210-power.h. Signed-off-by: Zhiguo Zhu --- drivers/pmdomain/Kconfig | 1 + drivers/pmdomain/Makefile | 1 + drivers/pmdomain/zhihe/Kconfig | 12 + drivers/pmdomain/zhihe/Makefile | 2 + drivers/pmdomain/zhihe/a210-pd.c | 756 +++++++++++++++++++++++++++++++ drivers/pmdomain/zhihe/a210-pd.h | 115 +++++ 6 files changed, 887 insertions(+) create mode 100644 drivers/pmdomain/zhihe/Kconfig create mode 100644 drivers/pmdomain/zhihe/Makefile create mode 100644 drivers/pmdomain/zhihe/a210-pd.c create mode 100644 drivers/pmdomain/zhihe/a210-pd.h diff --git a/drivers/pmdomain/Kconfig b/drivers/pmdomain/Kconfig index ee6fec8f4acef..0308f213ad662 100644 --- a/drivers/pmdomain/Kconfig +++ b/drivers/pmdomain/Kconfig @@ -2,5 +2,6 @@ menu "PM Domains" source "drivers/pmdomain/thead/Kconfig" +source "drivers/pmdomain/zhihe/Kconfig" endmenu diff --git a/drivers/pmdomain/Makefile b/drivers/pmdomain/Makefile index 0c2d34c5d35b4..94996d6d53f92 100644 --- a/drivers/pmdomain/Makefile +++ b/drivers/pmdomain/Makefile @@ -16,3 +16,4 @@ obj-y += tegra/ obj-y += thead/ obj-y += ti/ obj-y += xilinx/ +obj-y += zhihe/ diff --git a/drivers/pmdomain/zhihe/Kconfig b/drivers/pmdomain/zhihe/Kconfig new file mode 100644 index 0000000000000..599e9068392f2 --- /dev/null +++ b/drivers/pmdomain/zhihe/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config A210_POWER_DOMAIN + bool "ZhiHe A210 power domain driver" + depends on PM && (ARCH_ZHIHE || COMPILE_TEST) + select PM_GENERIC_DOMAINS + default ARCH_ZHIHE + help + This is the power domain driver that controls PCU/PPU for + the A210 SoC. It manages power gating of various hardware + subsystems to reduce overall power consumption. + Say Y here if you are building a kernel for the ZhiHe A210. diff --git a/drivers/pmdomain/zhihe/Makefile b/drivers/pmdomain/zhihe/Makefile new file mode 100644 index 0000000000000..5feb2f628ed2c --- /dev/null +++ b/drivers/pmdomain/zhihe/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_A210_POWER_DOMAIN) += a210-pd.o diff --git a/drivers/pmdomain/zhihe/a210-pd.c b/drivers/pmdomain/zhihe/a210-pd.c new file mode 100644 index 0000000000000..ce3d98abdcef1 --- /dev/null +++ b/drivers/pmdomain/zhihe/a210-pd.c @@ -0,0 +1,756 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "a210-pd.h" + +static struct dentry *pd_debugfs_root; +static struct dentry *pd_pde; + +static inline struct a210_pm_domain *to_a210_pd(struct generic_pm_domain *domain) +{ + return container_of(domain, struct a210_pm_domain, pd); +} + +static void __iomem *a210_ioremap_by_index(struct device *dev, struct device_node *np, + int index) +{ + const __be32 *reg; + struct resource res; + u64 addr, size; + int na, ns, len; + int ret; + + ret = of_address_to_resource(np, index, &res); + if (!ret) + return devm_ioremap(dev, res.start, resource_size(&res)); + + /* + * Power-domain IDs are described in the parent node address space, while + * CCU subnodes still contain real SoC MMIO addresses. There is no useful + * address translation between those two spaces, so fall back to mapping the + * raw address from the CCU reg property. + */ + na = of_n_addr_cells(np); + ns = of_n_size_cells(np); + reg = of_get_property(np, "reg", &len); + if (!reg || len < (index + 1) * (na + ns) * sizeof(__be32)) { + dev_err(dev, "Failed to get resource from node %pOF at index %d\n", + np, index); + return ERR_PTR(ret); + } + + reg += index * (na + ns); + addr = of_read_number(reg, na); + size = of_read_number(reg + na, ns); + if (!size) + return ERR_PTR(-EINVAL); + + return devm_ioremap(dev, addr, size); +} + +static void __iomem *a210_ioremap_by_name(struct device *dev, struct device_node *np, + const char *name) +{ + int idx; + + idx = of_property_match_string(np, "reg-names", name); + if (idx < 0) + return ERR_PTR(-ENODEV); + + return a210_ioremap_by_index(dev, np, idx); +} + +static bool a210_child_is_available_ccu(struct device_node *np) +{ + if (of_device_is_compatible(np, "zhihe,a210-ccu") && of_device_is_available(np)) + return true; + + return false; +} + +static int a210_parse_ccu(struct device *dev, struct device_node *np, + struct a210_pm_domain *a210_pd) +{ + struct device_node *child; + int ret; + + INIT_LIST_HEAD(&a210_pd->ccu_grp); + for_each_child_of_node(np, child) { + if (!a210_child_is_available_ccu(child)) + continue; + + int count = of_address_count(child); + + if (count <= 0) + continue; + + struct a210_ccu_grp *ccu_grp = devm_kzalloc( + dev, struct_size(ccu_grp, ccu, count), GFP_KERNEL); + if (!ccu_grp) { + of_node_put(child); + return -ENOMEM; + } + + ccu_grp->num_ccus = count; + ccu_grp->mode = CCU_MODE_GATING; // gating as the default option + of_property_read_u32(child, "zhihe,ccu-mode", &ccu_grp->mode); + + for (int i = 0; i < ccu_grp->num_ccus; i++) { + ccu_grp->ccu[i].base = + a210_ioremap_by_index(dev, child, i); + + ret = of_property_read_u32_index(child, + "zhihe,ccu-dly-time", i, + &ccu_grp->ccu[i].delay); + if (ret) { + dev_err(dev, + "ccu failed to get dly-time for %pOF idx=%d\n", + child, i); + of_node_put(child); + return -EINVAL; + } + + ret = of_property_read_u32_index(child, + "zhihe,ccu-dly-time-step", + i, &ccu_grp->ccu[i].step); + if (ret) { + dev_err(dev, + "ccu failed to get dly-time-step for %pOF idx=%d\n", + child, i); + of_node_put(child); + return -EINVAL; + } + + if (ccu_grp->mode == CCU_MODE_SCALING) { + ret = of_property_read_u32_index(child, + "zhihe,ccu-ratio", i, + &ccu_grp->ccu[i].ratio); + if (ret) { + dev_err(dev, + "ccu failed to get ratio for %pOF idx=%d\n", + child, i); + of_node_put(child); + return -EINVAL; + } + } + } + list_add_tail(&ccu_grp->list, &a210_pd->ccu_grp); + } + + return 0; +} + +static void a210_config_ccu(struct a210_pm_domain *a210_pd) +{ + struct a210_ccu_grp *ccu_grp; + + list_for_each_entry(ccu_grp, &a210_pd->ccu_grp, list) { + for (int i = 0; i < ccu_grp->num_ccus; i++) { + u32 val = ccu_grp->ccu[i].delay | + (ccu_grp->ccu[i].step << 8); + + writel(val, ccu_grp->ccu[i].base); + if (ccu_grp->mode == CCU_MODE_GATING) + writel(0x4, ccu_grp->ccu[i].base + 0x4); + else { + writel(0x2, ccu_grp->ccu[i].base + 0x4); + writel(ccu_grp->ccu[i].ratio, + ccu_grp->ccu[i].base + 0x18); + } + } + } +} + +static void bpc_config(struct device *dev, const char *str, + void __iomem *base_addr, u32 bpc_ctrl) +{ + if ((bpc_ctrl & BIT(0)) != 0) { + dev_dbg(dev, "Enter %s sw model...\n", str); + writel(0x1, base_addr + 0x000); // 0x1 bypass + writel(0x18, base_addr + 0x13c); // bpc 9000 ocgen &rset + } else { + dev_dbg(dev, "Enter %s hw model...\n", str); + writel(0x0, base_addr + 0x000); + } + writel(0x10101, base_addr + 0x004); // pwr venc bpc 3000| fence +} + +static void pcu_intr(struct device *dev, const char *str, + void __iomem *base_addr) +{ + u32 data; + + udelay(1); + data = readl(base_addr + 0x2c); // read pcu intr + while (data == 0) { + udelay(1); + data = readl(base_addr + 0x2c); // read pcu intr + } + if (((data & BIT(0)) != 0) || ((data & BIT(3)) != 0)) + dev_dbg(dev, "%s accept\n", str); + if (((data & BIT(1)) != 0) || ((data & BIT(4)) != 0)) + dev_err(dev, "%s deny\n", str); + + if (((data & BIT(2)) != 0) || ((data & BIT(5)) != 0)) + dev_err(dev, "%s timeout\n", str); + writel(data, base_addr + 0x28); // clr cpu intr +} + +static void pcu_config(struct device *dev, const char *str, + void __iomem *base_addr, u32 pcu_ctrl, u32 state) +{ + writel(0x3f, base_addr + 0x24); // interrupt enable + if ((pcu_ctrl & BIT(0)) != 0) { + dev_dbg(dev, + "Enter %s: pcu reg trigger...state=0x%x\n", + str, state); + writel((state & 0x1f), base_addr + 0x0c); // lpstate = power on + writel(0x1, base_addr + 0x08); // lqreq + pcu_intr(dev, str, base_addr); // wait for accept + } else { + dev_dbg(dev, "Enter %s: wait r2p trigger...\n", str); + } +} + +static int a210_pd_power_switch(struct generic_pm_domain *domain, + enum power_mode mode) +{ + struct a210_pm_domain *a210_pd = to_a210_pd(domain); + struct a210_pd_soc *soc = a210_pd->soc; + + struct device *dev = soc->dev; + struct regulator *regulator = soc->regulators[a210_pd->index]; + const char *name = domain->name; + int ret; + + if (mode == ON && regulator != NULL) { + ret = regulator_enable(regulator); + if (ret) { + dev_err(dev, "failed to regulator_enable for %s", name); + return ret; + } + } + + /* config pca if needed */ + if (mode == ON && !IS_ERR(a210_pd->pca_base)) + writel(0x0, a210_pd->pca_base + 0x20); + + if (!IS_ERR(a210_pd->bpc_base)) + bpc_config(dev, name, a210_pd->bpc_base, BPC_HW_MODEL); + if (!IS_ERR(a210_pd->pcu_base)) + pcu_config(dev, name, a210_pd->pcu_base, PCU_REG_TRIGGER, mode); + + if (mode == OFF && regulator != NULL) { + ret = regulator_disable(regulator); + if (ret) { + dev_err(dev, "failed to regulator_disable for %s", name); + return ret; + } + } + + return 0; +} + +static int a210_pd_power_off(struct generic_pm_domain *domain) +{ + struct a210_pm_domain *a210_pd = to_a210_pd(domain); + int ret; + +#ifdef CONFIG_A210_IOPMP + if (a210_pd->device_ids_count > 0) + iopmp_disable(a210_pd->device_ids, a210_pd->device_ids_count); +#endif + + if (a210_pd->num_clks) + clk_bulk_disable(a210_pd->num_clks, a210_pd->clks); + + ret = reset_control_assert(a210_pd->reset); + if (ret) + return ret; + + return a210_pd_power_switch(domain, OFF); +} + +static int a210_pd_power_on(struct generic_pm_domain *domain) +{ + struct a210_pm_domain *a210_pd = to_a210_pd(domain); + int ret; + + ret = a210_pd_power_switch(domain, ON); + if (ret) + return ret; + + ret = reset_control_deassert(a210_pd->reset); + if (ret) + return ret; + + if (a210_pd->num_clks) { + ret = clk_bulk_enable(a210_pd->num_clks, a210_pd->clks); + if (ret) + return ret; + } + +#ifdef CONFIG_A210_IOPMP + if (a210_pd->device_ids_count > 0) + iopmp_enable(a210_pd->device_ids, a210_pd->device_ids_count); +#endif + + a210_config_ccu(a210_pd); + + return 0; +} + +static char *a210_pd_get_user_string(const char __user *userbuf, size_t userlen) +{ + char *buffer; + + buffer = vmalloc(userlen + 1); + if (!buffer) + return ERR_PTR(-ENOMEM); + + if (copy_from_user(buffer, userbuf, userlen) != 0) { + vfree(buffer); + return ERR_PTR(-EFAULT); + } + + pr_debug("buffer before strip linefeed = %s\n", buffer); + /* got the string, now strip linefeed. */ + if (buffer[userlen - 1] == '\n') + buffer[userlen - 1] = '\0'; + else + buffer[userlen] = '\0'; + + pr_debug("buffer after strip linefeed = %s\n", buffer); + + return buffer; +} + +static ssize_t a210_power_domain_write(struct file *file, + const char __user *userbuf, + size_t userlen, loff_t *ppos) +{ + char *buffer, *start, *end; + struct seq_file *m = (struct seq_file *)file->private_data; + struct a210_pd_soc *soc = m->private; + struct device *dev = soc->dev; + struct generic_pm_domain *domain; + char pd_name[A210_PD_NAME_SIZE]; + char pd_state[A210_PD_STATE_NAME_SIZE]; + int idx, ret; + + buffer = a210_pd_get_user_string(userbuf, userlen); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + start = skip_spaces(buffer); // skip leading space if any + end = start; + while (!isspace(*end) && *end != '\0') + end++; + + *end = '\0'; + strscpy(pd_name, start, sizeof(pd_name)); + + /* find the target power domain */ + for (idx = 0; idx < soc->num_domains; idx++) { + domain = &soc->domains[idx]->pd; + if (strcmp(pd_name, domain->name)) + continue; + break; + } + + if (idx == soc->num_domains) { + dev_err(dev, + "no taget power domain-%s found, idx = %d, total pd numbers = %d\n", + pd_name, idx, soc->num_domains); + userlen = -EINVAL; + goto out; + } + + end = end + 1; // end is the new start + start = skip_spaces(end); // skip leading space if any + end = start; + while (!isspace(*end) && *end != '\0') + end++; + + *end = '\0'; + strscpy(pd_state, start, sizeof(pd_state)); + + if (!strcmp(pd_state, "on")) { + ret = domain->power_on(domain); + if (ret) { + userlen = ret; + goto out; + } + } else if (!strcmp(pd_state, "off")) { + ret = domain->power_off(domain); + if (ret) { + userlen = ret; + goto out; + } + } else { + dev_err(dev, + "invalid power domain target state, not 'on' or 'off'\n"); + userlen = -EINVAL; + goto out; + } + +out: + vfree(buffer); + + return userlen; +} + +static int a210_power_domain_show(struct seq_file *m, void *v) +{ + struct a210_pd_soc *soc = m->private; + u32 count = soc->num_domains; + int idx; + + seq_puts(m, "[Power domain name list]: "); + for (idx = 0; idx < count; idx++) + seq_printf(m, "%s ", soc->domains[idx]->pd.name); + seq_puts(m, "\n"); + seq_puts(m, "[Power on domain usage]: echo power_name on > domain\n"); + seq_puts(m, "[Power off domain usage]: echo power_name off > domain\n"); + + return 0; +} + +static int a210_power_domain_open(struct inode *inode, struct file *file) +{ + struct a210_pd_soc *soc = inode->i_private; + + return single_open(file, a210_power_domain_show, soc); +} + +static const struct file_operations a210_power_domain_fops = { + .owner = THIS_MODULE, + .write = a210_power_domain_write, + .read = seq_read, + .open = a210_power_domain_open, + .llseek = generic_file_llseek, +}; + +static void pd_debugfs_init(struct a210_pd_soc *soc) +{ + pd_debugfs_root = debugfs_create_dir("power_domain", NULL); + if (IS_ERR_OR_NULL(pd_debugfs_root)) + return; + + pd_pde = debugfs_create_file("domain", 0600, pd_debugfs_root, soc, + &a210_power_domain_fops); +} + +static int a210_domain_lookup(struct device_node *np) +{ + u32 id; + + if (!of_property_read_u32_index(np, "reg", 1, &id)) + return id; + + if (!of_property_read_u32(np, "reg", &id)) + return id; + + if (!of_property_read_u32(np, "id", &id)) + return id; + + return -ENODEV; +} + +static int a210_add_one_domain(struct platform_device *pdev, + struct device_node *np) +{ + struct device *dev = &pdev->dev; + struct a210_pd_soc *pd_soc = dev_get_drvdata(dev); + struct a210_pm_domain *a210_pd; + const char *name; + int ret; + + a210_pd = devm_kzalloc(dev, sizeof(*a210_pd), GFP_KERNEL); + if (!a210_pd) + return -ENOMEM; + + int id = a210_domain_lookup(np); + + if (id < 0) + return -ENODEV; + + name = strrchr(of_node_full_name(np), '/'); + a210_pd->pd.name = devm_kstrdup(dev, name ? name + 1 : of_node_full_name(np), + GFP_KERNEL); + if (!a210_pd->pd.name) + return -ENOMEM; + + a210_pd->index = id; + a210_pd->pd.power_off = a210_pd_power_off; + a210_pd->pd.power_on = a210_pd_power_on; + a210_pd->soc = pd_soc; + + a210_pd->pca_base = a210_ioremap_by_name(dev, np, "pca"); + a210_pd->bpc_base = a210_ioremap_by_name(dev, np, "bpc"); + a210_pd->pcu_base = a210_ioremap_by_name(dev, np, "pcu"); + + ret = pm_genpd_init(&a210_pd->pd, NULL, true); + if (ret) { + dev_err(dev, "failed to init power domain %s index %d", + a210_pd->pd.name, a210_pd->index); + devm_kfree(dev, a210_pd); + return -ENODEV; + } + + ret = of_genpd_add_provider_simple(np, &a210_pd->pd); + if (ret) { + dev_err(dev, "failed to add PM domain provider for %pOFn: %d\n", + np, ret); + goto remove_genpd; + } + + a210_pd->reset = of_reset_control_array_get_optional_shared(np); + if (IS_ERR(a210_pd->reset)) { + ret = PTR_ERR(a210_pd->reset); + dev_err(dev, "failed to get device resets for domain:%s\n", np->name); + goto reset_fail; + } + + a210_pd->num_clks = of_clk_get_parent_count(np); + if (a210_pd->num_clks) { + a210_pd->clks = devm_kcalloc(dev, a210_pd->num_clks, + sizeof(*a210_pd->clks), GFP_KERNEL); + if (!a210_pd->clks) { + ret = -ENOMEM; + goto reset_fail; + } + + for (int i = 0; i < a210_pd->num_clks; i++) { + a210_pd->clks[i].clk = of_clk_get(np, i); + if (IS_ERR(a210_pd->clks[i].clk)) { + ret = PTR_ERR(a210_pd->clks[i].clk); + dev_err(dev, + "failed to get clk at index %d: err:%d for domain:%s\n", + i, ret, np->name); + goto clk_fail; + } + } + + ret = clk_bulk_prepare(a210_pd->num_clks, a210_pd->clks); + if (ret) { + clk_bulk_put(a210_pd->num_clks, a210_pd->clks); + goto clk_fail; + } + } + + ret = a210_parse_ccu(dev, np, a210_pd); + if (ret) + goto clk_fail; + + pd_soc->domains[pd_soc->num_domains++] = a210_pd; + + dev_dbg(dev, "added PM domain %s\n", a210_pd->pd.name); + +#ifdef CONFIG_A210_IOPMP + /* get iopmps config node */ + int device_id_count = 0; + int count = of_count_phandle_with_args(np, "iopmps", NULL); + + for (int i = 0; i < count; i++) { + struct device_node *iopmp_node; + + iopmp_node = of_parse_phandle(np, "iopmps", i); + if (!iopmp_node) { + dev_err(dev, + "failed to get iopmps at index %d for domain:%s\n", + i, np->name); + ret = -EINVAL; + goto clk_fail; + } + + u32 device_id; + + if (of_property_read_u32(iopmp_node, "device-id", + &device_id) == 0) { + a210_pd->device_ids[device_id_count] = device_id; + device_id_count++; + dev_dbg(dev, + "domain %pOFn iopmp %pOFn: device id: %d\n", + np, iopmp_node, device_id); + } + } + a210_pd->device_ids_count = device_id_count; +#endif + + return 0; + +clk_fail: + devm_kfree(dev, a210_pd->clks); +reset_fail: + reset_control_put(a210_pd->reset); +remove_genpd: + pm_genpd_remove(&a210_pd->pd); + devm_kfree(dev, a210_pd); + return ret; +} + +static int a210_init_pm_domains(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child; + struct of_phandle_args child_args, parent_args; + int ret; + + for_each_child_of_node(np, child) { + if (!of_device_is_available(child)) + continue; + + ret = a210_add_one_domain(pdev, child); + if (ret) { + dev_err(dev, "failed to handle node %pOFn: %d\n", + child, ret); + of_node_put(child); + return ret; + } + + if (of_parse_phandle_with_args(child, "power-domains", + "#power-domain-cells", 0, &parent_args)) + continue; + + child_args.np = child; + child_args.args_count = 0; + + ret = of_genpd_add_subdomain(&parent_args, &child_args); + of_node_put(parent_args.np); + if (ret) { + dev_err(dev, "failed to handle subdomain node %pOFn: %d\n", + child, ret); + of_node_put(child); + return ret; + } + } + + of_node_put(np); + + return ret; +} + +static int a210_pd_parse_regulators(struct device *dev) +{ + struct a210_pd_soc *pd_soc = dev_get_drvdata(dev); + struct device_node *np = dev->of_node; + struct device_node *child, *child_regulator; + + for_each_child_of_node(np, child) { + if (!of_device_is_available(child)) + continue; + + int id = a210_domain_lookup(child); + + if (id < 0) + return -ENODEV; + + if (of_property_present(child, "pmic-supply")) { + child_regulator = of_parse_phandle(child, + "pmic-supply", 0); + pd_soc->regulators[id] = regulator_get_optional( + dev, child_regulator->name); + if (IS_ERR(pd_soc->regulators[id])) { + dev_dbg(dev, "Regulator for %s deferred %ld\n", + child->name, + PTR_ERR(pd_soc->regulators[id])); + return -EPROBE_DEFER; + } + + u32 max_uV = 0; + + if (of_property_read_u32(child_regulator, + "regulator-max-microvolt", + &max_uV) == 0) { + regulator_set_voltage( + pd_soc->regulators[id], + max_uV, max_uV); + dev_info(dev, "Set %s voltage target %duV\n", + child->name, max_uV); + regulator_put(pd_soc->regulators[id]); + pd_soc->regulators[id] = + devm_regulator_get_optional( + dev, child_regulator->name); + } + } + } + of_node_put(np); + + return 0; +} + +static int a210_pd_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct a210_pd_soc *pd_soc; + int ret; + + pd_soc = devm_kzalloc(dev, sizeof(*pd_soc), GFP_KERNEL); + if (!pd_soc) + return -ENOMEM; + pd_soc->dev = dev; + + dev_set_drvdata(dev, pd_soc); + + ret = a210_pd_parse_regulators(dev); + if (ret) + return ret; + + ret = a210_init_pm_domains(pdev); + if (ret) + return ret; + + pd_debugfs_init(pd_soc); + + dev_info(dev, "Registered a210 power domain\n"); + + return ret; +} + +static const struct of_device_id a210_pd_of_match[] = { + { .compatible = "zhihe,a210-power-domain" }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, a210_pd_of_match); + +static struct platform_driver a210_pd_driver = { + .probe = a210_pd_probe, + .driver = { + .name = "a210-power-domain", + .of_match_table = of_match_ptr(a210_pd_of_match), + }, +}; + +builtin_platform_driver(a210_pd_driver); + +MODULE_AUTHOR("dong.yan "); +MODULE_DESCRIPTION("Zhihe A210 power domain driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pmdomain/zhihe/a210-pd.h b/drivers/pmdomain/zhihe/a210-pd.h new file mode 100644 index 0000000000000..63bd49668bf69 --- /dev/null +++ b/drivers/pmdomain/zhihe/a210-pd.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2025 Zhihe Computing Limited. + */ + +#ifndef __A210_PD_H +#define __A210_PD_H + +#include + +#define A210_PD_NAME_SIZE 20 +#define A210_PD_STATE_NAME_SIZE 10 + +#define BPC_SW_MODEL 1 +#define BPC_HW_MODEL 0 +#define PCU_REG_TRIGGER 1 +#define PCU_R2P_TRIGGER 0 + +#define IOPMP_DEVICES_MAX_COUNT 16 + +enum { + PMIC_CTRL, + VP_PCA, + VP_WRAP_BPC, + VP_WRAP_PCU, + VP_VENC_BPC, + VP_VENC_PCU, + VP_VDEC_BPC, + VP_VDEC_PCU, + VP_R2P, + GPU_PCA, + GPU_BPC, + GPU_PCU, + NPU_PCA, + NPU_WRAP_BPC, + NPU_WRAP_PCU, + NPU_IP_BPC, + NPU_IP_PCU, + PCIE0_BPC, + PCIE0_PCU, + PCIE1_BPC, + PCIE1_PCU, + SATA_BPC, + SATA_PCU, + USB_BPC, + USB_PCU, + VI_R2P, + VI_WRAP_BPC, + VI_WRAP_PCU, + VI_ISP_BPC, + VI_ISP_PCU, + VO_BPC, + VO_PCU, + A210_POWER_DOMAIN_REGS_MAX, +}; + +/* represent power domains info at soc level */ +struct a210_pd_soc { + struct device *dev; + struct a210_pm_domain *domains[A210_POWER_DOMAINS_MAX]; + u32 num_domains; + struct regulator *regulators[A210_POWER_DOMAINS_MAX]; +}; + +struct a210_ccu { + u32 delay; + u32 step; + u32 ratio; + void __iomem *base; +}; + +struct a210_ccu_grp { + bool enable; + u32 mode; + u32 num_ccus; + struct list_head list; + struct a210_ccu ccu[]; +}; + +/* represent a single power domain */ +struct a210_pm_domain { + struct generic_pm_domain pd; + u16 index; + struct a210_pd_soc *soc; + struct reset_control *reset; + struct clk_bulk_data *clks; + u32 num_clks; + u32 device_ids[IOPMP_DEVICES_MAX_COUNT]; + u32 device_ids_count; + void __iomem *pca_base; + void __iomem *bpc_base; + void __iomem *pcu_base; + struct list_head ccu_grp; +}; + +enum power_mode { + OFF = 0x0, + MEM_SD = 0x1, + MEM_RET = 0x2, + MEM_SD_ONLY = 0x9, + MEM_DSLP = 0xa, + MEM_SLP = 0xb, + CG = 0xf, + ON = 0x1f, + WAIT_OFF = 0x100, + WAIT_MEM_SD = 0x101, + WAIT_MEM_RET = 0x102, + WAIT_MEM_SD_ONLY = 0x109, + WAIT_MEM_DSLP = 0x10a, + WAIT_MEM_SLP = 0x10b, + WAIT_CG = 0x10f, + WAIT_ON = 0x11f +}; + +#endif From 5d529ebc49d2a9ecd2f5e27197da8e0cf495700c Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Thu, 9 Apr 2026 20:16:09 +0800 Subject: [PATCH 08/17] mailbox: add ZhiHe A210 mailbox controller driver Add a mailbox controller driver for the ZhiHe A210 SoC used for inter-processor communication between the application processor and the Always-On (AON) E902 core. The driver implements the standard mailbox controller API and supports interrupt-driven message passing. Signed-off-by: Zhiguo Zhu --- drivers/mailbox/Kconfig | 10 + drivers/mailbox/Makefile | 2 + drivers/mailbox/zhihe-mailbox.c | 743 ++++++++++++++++++++++++++++++++ 3 files changed, 755 insertions(+) create mode 100644 drivers/mailbox/zhihe-mailbox.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 3bab3fd53d540..8d7a82cb82670 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -314,4 +314,14 @@ config RISCV_SBI_MPXY_MBOX or HS-mode hypervisor). Say Y here if you want to have this support. If unsure say N. +config ZHIHE_MBOX + tristate "ZhiHe mailbox driver" + depends on ARCH_ZHIHE || COMPILE_TEST + default ARCH_ZHIHE + help + Mailbox implementation for ZhiHe SoCs. This driver provides + inter-processor communication channels between the application + processor and the AON (Always-On) subsystem. + Say Y here if you want to have this support. If unsure say N. + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 6604d6a21c85b..842e37f15eed1 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -66,3 +66,5 @@ obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o obj-$(CONFIG_TH1520_MBOX) += th1520-mailbox.o obj-$(CONFIG_RISCV_SBI_MPXY_MBOX) += riscv-sbi-mpxy-mbox.o + +obj-$(CONFIG_ZHIHE_MBOX) += zhihe-mailbox.o diff --git a/drivers/mailbox/zhihe-mailbox.c b/drivers/mailbox/zhihe-mailbox.c new file mode 100644 index 0000000000000..5341a5300889f --- /dev/null +++ b/drivers/mailbox/zhihe-mailbox.c @@ -0,0 +1,743 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * a210 MailBox support + * + * Copyright (C) 2024 ZHIHE Group Holding Limited. + * + * Author: xionglue.huang + * Author: hongkun.xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ZHIHE_MBOX_V1 0x0 +#define ZHIHE_MBOX_V2 0x1 + +/* Status Register */ +#define ZHIHE_MBOX_STA 0x0 +#define ZHIHE_MBOX_CLR 0x4 +#define ZHIHE_MBOX_MASK 0xc + +/* Transmit/receive data register: + * INFO0 ~ INFO6 + */ +#define ZHIHE_MBOX_INFO_NUM 8 +#define ZHIHE_MBOX_DATA_INFO_NUM 7 +#define ZHIHE_MBOX_INFO0 0x14 +/* Transmit ack register: INFO7 */ +#define ZHIHE_MBOX_INFO7 0x30 + +/* Generate remote icu IRQ Register */ +#define ZHIHE_MBOX_GEN 0x10 +#define ZHIHE_MBOX_GEN_RX_DATA BIT(6) +#define ZHIHE_MBOX_GEN_TX_ACK BIT(7) + +#define ZHIHE_MBOX_CHAN_RES_SIZE 0x1000 +#define ZHIHE_MBOX_CHANS 4 +#define ZHIHE_MBOX_CHAN_NAME_SIZE 20 + +#define ZHIHE_MBOX_ACK_MAGIC 0xdeadbeaf + +#ifdef CONFIG_PM_SLEEP +/* store MBOX context across system-wide suspend/resume transitions */ +struct zhihe_mbox_context { + u32 intr_mask[ZHIHE_MBOX_CHANS - 1]; +}; + +#endif +enum zhihe_mbox_chan_type { + ZHIHE_MBOX_TYPE_TXRX, /* Tx & Rx chan */ + ZHIHE_MBOX_TYPE_DB, /* Tx & Rx doorbell */ +}; + +enum zhihe_mbox_icu_cpu_id { + ZHIHE_MBOX_ICU_CPU0 = 0, /* A200:910T, A210:die0-908 */ + ZHIHE_MBOX_ICU_CPU1 = 1, /* A200:902 */ + ZHIHE_MBOX_ICU_CPU2 = 2, /* A200:906 */ + ZHIHE_MBOX_ICU_CPU3 = 3, /* A200:910R */ +}; + +enum zhihe_mbox_local_id { + ZHIHE_MBOX_INTERRUPT = 0, + ZHIHE_MBOX_DATA_CH0 = 1, /* A210:die0-908--die0-902 */ + ZHIHE_MBOX_DATA_CH1 = 2, + ZHIHE_MBOX_DATA_CH2 = 3, +}; +enum zhihe_mbox_remote_id { + ZHIHE_MBOX_REMOTE_CH0 = 0, /* A210:die0-908--die0-902 */ + ZHIHE_MBOX_REMOTE_CH1 = 1, + ZHIHE_MBOX_REMOTE_CH2 = 2, +}; + +struct zhihe_mbox_con_priv { + enum zhihe_mbox_icu_cpu_id icu_cpu_idx; + enum zhihe_mbox_local_id local_idx; + enum zhihe_mbox_chan_type type; + void __iomem *comm_local_base; + void __iomem *comm_remote_base; + char irq_desc[ZHIHE_MBOX_CHAN_NAME_SIZE]; + struct mbox_chan *chan; + struct tasklet_struct txdb_tasklet; +}; + +struct zhihe_mbox_priv { + struct device *dev; + void __iomem *local_icu[ZHIHE_MBOX_CHANS]; + void __iomem *remote_icu[ZHIHE_MBOX_CHANS - 1]; + void __iomem *cur_cpu_ch_base; + enum zhihe_mbox_icu_cpu_id cur_icu_cpu_id; + spinlock_t mbox_lock; /* control register lock */ + + struct mbox_controller mbox; + struct mbox_chan mbox_chans[ZHIHE_MBOX_CHANS]; + + struct zhihe_mbox_con_priv con_priv[ZHIHE_MBOX_CHANS]; + struct clk_bulk_data *clks; + u32 num_clks; + struct reset_control *reset; + int irq; + int version; +#ifdef CONFIG_PM_SLEEP + struct zhihe_mbox_context *ctx; +#endif +}; + +static struct zhihe_mbox_priv *to_zhihe_mbox_priv(struct mbox_controller *mbox) +{ + return container_of(mbox, struct zhihe_mbox_priv, mbox); +} + +static int zhihe_mbox_ioremap_byname(struct platform_device *pdev, + const char *name, void __iomem **base, + bool required) +{ + struct device *dev = &pdev->dev; + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (!res) { + if (required) + return dev_err_probe(dev, -EINVAL, "%s is missing\n", name); + + dev_dbg(dev, "%s is not present\n", name); + return 0; + } + + *base = devm_ioremap_resource(dev, res); + if (IS_ERR(*base)) + return PTR_ERR(*base); + + return 0; +} + +static void zhihe_mbox_write(struct zhihe_mbox_priv *priv, u32 val, u32 offs) +{ + iowrite32(val, priv->cur_cpu_ch_base + offs); +} + +static u32 zhihe_mbox_read(struct zhihe_mbox_priv *priv, u32 offs) +{ + return ioread32(priv->cur_cpu_ch_base + offs); +} + +static u32 zhihe_mbox_rmw(struct zhihe_mbox_priv *priv, + u32 off, u32 set, u32 clr) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&priv->mbox_lock, flags); + val = zhihe_mbox_read(priv, off); + val &= ~clr; + val |= set; + zhihe_mbox_write(priv, val, off); + spin_unlock_irqrestore(&priv->mbox_lock, flags); + + return val; +} + +static void zhihe_mbox_chan_write(struct zhihe_mbox_con_priv *cp, + u32 val, u32 offs, bool is_remote) +{ + if (is_remote) + iowrite32(val, cp->comm_remote_base + offs); + else + iowrite32(val, cp->comm_local_base + offs); +} + +static u32 zhihe_mbox_chan_read(struct zhihe_mbox_con_priv *cp, + u32 offs, bool is_remote) +{ + if (is_remote) + return ioread32(cp->comm_remote_base + offs); + else + return ioread32(cp->comm_local_base + offs); +} + +static void zhihe_mbox_chan_rmw(struct zhihe_mbox_con_priv *cp, + u32 off, u32 set, u32 clr, bool is_remote) +{ + u32 val; + unsigned long flags; + struct zhihe_mbox_priv *priv = to_zhihe_mbox_priv(cp->chan->mbox); + + spin_lock_irqsave(&priv->mbox_lock, flags); + val = zhihe_mbox_chan_read(cp, off, is_remote); + val &= ~clr; + val |= set; + zhihe_mbox_chan_write(cp, val, off, is_remote); + spin_unlock_irqrestore(&priv->mbox_lock, flags); +} + +static void zhihe_mbox_chan_rd_data(struct zhihe_mbox_con_priv *cp, + void *data, bool is_remote) +{ + u32 i; + u32 *arg = data; + u32 off = ZHIHE_MBOX_INFO0; + + /* read info0 ~ info6, totally 28 bytes + * requires data memory size is 28 bytes + */ + for (i = 0; i < ZHIHE_MBOX_DATA_INFO_NUM; i++) { + *arg = zhihe_mbox_chan_read(cp, off, is_remote); + off += 4; + arg++; + } +} + +static void zhihe_mbox_chan_wr_data(struct zhihe_mbox_con_priv *cp, + void *data, bool is_remote) +{ + u32 i; + u32 *arg = data; + u32 off = ZHIHE_MBOX_INFO0; + + /* write info0 ~ info6, totally 28 bytes + * requires data memory is 28 bytes valid data + */ + for (i = 0; i < ZHIHE_MBOX_DATA_INFO_NUM; i++) { + zhihe_mbox_chan_write(cp, *arg, off, is_remote); + off += 4; + arg++; + } +} + +static void zhihe_mbox_chan_wr_ack(struct zhihe_mbox_con_priv *cp, + void *data, bool is_remote) +{ + u32 *arg = data; + u32 off = ZHIHE_MBOX_INFO7; + + zhihe_mbox_chan_write(cp, *arg, off, is_remote); +} + +static int zhihe_mbox_chan_id_to_mapbit(struct zhihe_mbox_con_priv *cp) +{ + int i; + int mapbit = 0; + struct zhihe_mbox_priv *priv = to_zhihe_mbox_priv(cp->chan->mbox); + + if (priv->version == ZHIHE_MBOX_V1) { + for (i = 0; i < ZHIHE_MBOX_CHANS; i++) { + if (i == cp->icu_cpu_idx) + return mapbit; + + if (i != priv->cur_icu_cpu_id) + mapbit++; + } + } else if (priv->version == ZHIHE_MBOX_V2) { + for (i = 0; i < ZHIHE_MBOX_CHANS; i++) { + if (i == cp->local_idx) + return mapbit; + + if (i != ZHIHE_MBOX_INTERRUPT) + mapbit++; + } + } else { + dev_err(cp->chan->mbox->dev, "Unknown zhihe mailbox version\n"); + } + + if (i == ZHIHE_MBOX_CHANS) + dev_err(cp->chan->mbox->dev, "convert to mapbit failed\n"); + + return 0; +} + +static void zhihe_mbox_txdb_tasklet(unsigned long data) +{ + struct zhihe_mbox_con_priv *cp = (struct zhihe_mbox_con_priv *)data; + + mbox_chan_txdone(cp->chan, 0); +} + +static irqreturn_t zhihe_mbox_isr(int irq, void *p) +{ + u32 info0_data, info7_data; + u32 sta, dat[ZHIHE_MBOX_DATA_INFO_NUM]; + u32 ack_magic = ZHIHE_MBOX_ACK_MAGIC; + struct mbox_chan *chan = p; + struct zhihe_mbox_con_priv *cp = chan->con_priv; + int mapbit = zhihe_mbox_chan_id_to_mapbit(cp); + struct zhihe_mbox_priv *priv = to_zhihe_mbox_priv(chan->mbox); + + sta = zhihe_mbox_read(priv, ZHIHE_MBOX_STA); + if (!(sta & BIT(mapbit))) + return IRQ_NONE; + /* clear chan irq bit in STA register */ + zhihe_mbox_rmw(priv, ZHIHE_MBOX_CLR, BIT(mapbit), 0); + /* rx doorbell */ + if (cp->type == ZHIHE_MBOX_TYPE_DB) { + mbox_chan_received_data(cp->chan, NULL); + return IRQ_HANDLED; + } + /* info0 is the protocol word, should not be zero! */ + info0_data = zhihe_mbox_chan_read(cp, ZHIHE_MBOX_INFO0, false); + if (info0_data) { + /* read info0~info6 data */ + zhihe_mbox_chan_rd_data(cp, dat, false); + + /* clear local info0 */ + zhihe_mbox_chan_write(cp, 0x0, ZHIHE_MBOX_INFO0, false); + /* notify remote cpu */ + zhihe_mbox_chan_wr_ack(cp, &ack_magic, true); + + if (priv->version == ZHIHE_MBOX_V1) { + /* CPU1 902/906 use polling mode to monitor info7 */ + if (cp->icu_cpu_idx != ZHIHE_MBOX_ICU_CPU1 && + cp->icu_cpu_idx != ZHIHE_MBOX_ICU_CPU2) + zhihe_mbox_chan_rmw(cp, ZHIHE_MBOX_GEN, + ZHIHE_MBOX_GEN_TX_ACK, 0, true); + } + /* transfer the data to client */ + mbox_chan_received_data(chan, (void *)dat); + } + /* info7 magic value mean the real ack signal, not generate bit7 */ + info7_data = zhihe_mbox_chan_read(cp, ZHIHE_MBOX_INFO7, false); + if (info7_data == ZHIHE_MBOX_ACK_MAGIC) { + /* clear local info7 */ + zhihe_mbox_chan_write(cp, 0x0, ZHIHE_MBOX_INFO7, false); + + /* notify framework the last TX has completed */ + mbox_chan_txdone(chan, 0); + } + if (!info0_data && !info7_data) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int zhihe_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct zhihe_mbox_con_priv *cp = chan->con_priv; + + if (cp->type == ZHIHE_MBOX_TYPE_DB) + tasklet_schedule(&cp->txdb_tasklet); + else + zhihe_mbox_chan_wr_data(cp, data, true); + zhihe_mbox_chan_rmw(cp, ZHIHE_MBOX_GEN, ZHIHE_MBOX_GEN_RX_DATA, 0, + true); + + return 0; +} + +static int zhihe_mbox_startup(struct mbox_chan *chan) +{ + int ret; + int mask_bit; + u32 data[8] = {0}; + struct zhihe_mbox_con_priv *cp = chan->con_priv; + struct zhihe_mbox_priv *priv = to_zhihe_mbox_priv(chan->mbox); + + pm_runtime_get_sync(priv->dev); + + /* clear local and remote generate and info0~info7 */ + zhihe_mbox_chan_rmw(cp, ZHIHE_MBOX_GEN, 0x0, 0xff, true); + zhihe_mbox_chan_rmw(cp, ZHIHE_MBOX_GEN, 0x0, 0xff, false); + zhihe_mbox_chan_wr_ack(cp, &data[7], true); + zhihe_mbox_chan_wr_ack(cp, &data[7], false); + zhihe_mbox_chan_wr_data(cp, &data[0], true); + zhihe_mbox_chan_wr_data(cp, &data[0], false); + /* enable the chan mask */ + mask_bit = zhihe_mbox_chan_id_to_mapbit(cp); + zhihe_mbox_rmw(priv, ZHIHE_MBOX_MASK, BIT(mask_bit), 0); + + if (cp->type == ZHIHE_MBOX_TYPE_DB) + /* tx doorbell doesn't have ACK, rx doorbell requires isr */ + tasklet_init(&cp->txdb_tasklet, zhihe_mbox_txdb_tasklet, + (unsigned long)cp); + ret = request_irq(priv->irq, zhihe_mbox_isr, IRQF_SHARED | + IRQF_NO_SUSPEND, cp->irq_desc, chan); + if (ret) { + dev_err(priv->dev, + "Unable to acquire IRQ %d\n", priv->irq); + return ret; + } + return 0; +} + +static void zhihe_mbox_shutdown(struct mbox_chan *chan) +{ + int mask_bit; + struct zhihe_mbox_con_priv *cp = chan->con_priv; + struct zhihe_mbox_priv *priv = to_zhihe_mbox_priv(chan->mbox); + + /* clear the chan mask */ + mask_bit = zhihe_mbox_chan_id_to_mapbit(cp); + zhihe_mbox_rmw(priv, ZHIHE_MBOX_MASK, 0, BIT(mask_bit)); + + free_irq(priv->irq, chan); + + pm_runtime_put_sync(priv->dev); +} + +static const struct mbox_chan_ops zhihe_mbox_ops = { + .send_data = zhihe_mbox_send_data, + .startup = zhihe_mbox_startup, + .shutdown = zhihe_mbox_shutdown, +}; + +static int zhihe_mbox_init_generic(struct zhihe_mbox_priv *priv) +{ +#ifdef CONFIG_PM_SLEEP + priv->ctx = devm_kzalloc(priv->dev, sizeof(*priv->ctx), GFP_KERNEL); + if (!priv->ctx) + return -ENOMEM; +#endif + return 0; +} + +static struct mbox_chan *zhihe_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *sp) +{ + u32 chan, type; + struct zhihe_mbox_con_priv *cp; + struct zhihe_mbox_priv *priv = to_zhihe_mbox_priv(mbox); + + if (sp->args_count != 2) { + dev_err(mbox->dev, + "Invalid argument count %d\n", sp->args_count); + return ERR_PTR(-EINVAL); + } + + chan = sp->args[0]; /* comm remote channel */ + type = sp->args[1]; /* comm channel type */ + if (chan >= mbox->num_chans) { + dev_err(mbox->dev, "Not supported channel number: %d\n", chan); + return ERR_PTR(-EINVAL); + } + + if (priv->version == ZHIHE_MBOX_V1) { + if (chan == priv->cur_icu_cpu_id) { + dev_err(mbox->dev, "Cannot communicate with yourself\n"); + return ERR_PTR(-EINVAL); + } + } + + if (type > ZHIHE_MBOX_TYPE_DB) { + dev_err(mbox->dev, + "Not supported the type for channel[%d]\n", chan); + return ERR_PTR(-EINVAL); + } + + cp = mbox->chans[chan].con_priv; + cp->type = type; + + return &mbox->chans[chan]; +} + +static int zhihe_mbox_probe(struct platform_device *pdev) +{ + int ret; + unsigned int i; + unsigned int mbox_id; + struct zhihe_mbox_priv *priv; + unsigned int remote_idx = 0; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + pm_runtime_enable(dev); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + if (of_device_is_compatible(np, "zhihe,a210-mailbox-v2")) + priv->version = ZHIHE_MBOX_V2; + else + priv->version = ZHIHE_MBOX_V1; + + if (of_property_read_u32(np, "zhihe,icu-cpu-id", + &priv->cur_icu_cpu_id) && + of_property_read_u32(np, "icu_cpu_id", &priv->cur_icu_cpu_id)) { + dev_err(dev, "zhihe,icu-cpu-id is missing\n"); + return -EINVAL; + } + + priv->dev = dev; + + if (priv->version == ZHIHE_MBOX_V1) { + if (priv->cur_icu_cpu_id != ZHIHE_MBOX_ICU_CPU0 && + priv->cur_icu_cpu_id != ZHIHE_MBOX_ICU_CPU3) { + dev_err(dev, "icu_cpu_id is invalid\n"); + return -EINVAL; + } + + ret = zhihe_mbox_ioremap_byname(pdev, "local0", + &priv->local_icu[ZHIHE_MBOX_ICU_CPU0], + true); + if (ret) + return ret; + + ret = zhihe_mbox_ioremap_byname(pdev, "remote0", + &priv->remote_icu[ZHIHE_MBOX_REMOTE_CH0], + true); + if (ret) + return ret; + + ret = zhihe_mbox_ioremap_byname(pdev, "remote1", + &priv->remote_icu[ZHIHE_MBOX_REMOTE_CH1], + true); + if (ret) + return ret; + + ret = zhihe_mbox_ioremap_byname(pdev, "remote2", + &priv->remote_icu[ZHIHE_MBOX_REMOTE_CH2], + true); + if (ret) + return ret; + + priv->local_icu[ZHIHE_MBOX_ICU_CPU1] = + priv->local_icu[ZHIHE_MBOX_ICU_CPU0] + + ZHIHE_MBOX_CHAN_RES_SIZE; + + priv->local_icu[ZHIHE_MBOX_ICU_CPU2] = + priv->local_icu[ZHIHE_MBOX_ICU_CPU1] + + ZHIHE_MBOX_CHAN_RES_SIZE; + + priv->local_icu[ZHIHE_MBOX_ICU_CPU3] = + priv->local_icu[ZHIHE_MBOX_ICU_CPU2] + + ZHIHE_MBOX_CHAN_RES_SIZE; + + mbox_id = priv->cur_icu_cpu_id; + } else if (priv->version == ZHIHE_MBOX_V2) { + ret = zhihe_mbox_ioremap_byname(pdev, "interrupt", + &priv->local_icu[ZHIHE_MBOX_INTERRUPT], + true); + if (ret) + return ret; + + ret = zhihe_mbox_ioremap_byname(pdev, "local0", + &priv->local_icu[ZHIHE_MBOX_DATA_CH0], + true); + if (ret) + return ret; + + ret = zhihe_mbox_ioremap_byname(pdev, "local1", + &priv->local_icu[ZHIHE_MBOX_DATA_CH1], + false); + if (ret) + return ret; + + ret = zhihe_mbox_ioremap_byname(pdev, "remote0", + &priv->remote_icu[ZHIHE_MBOX_REMOTE_CH0], + true); + if (ret) + return ret; + + ret = zhihe_mbox_ioremap_byname(pdev, "remote1", + &priv->remote_icu[ZHIHE_MBOX_REMOTE_CH1], + false); + if (ret) + return ret; + + mbox_id = ZHIHE_MBOX_INTERRUPT; + } else { + dev_err(dev, "Unknown zhihe mailbox version\n"); + return -EINVAL; + } + + priv->cur_cpu_ch_base = priv->local_icu[mbox_id]; + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) + return priv->irq; + + priv->num_clks = of_clk_get_parent_count(np); + if (priv->num_clks) { + priv->clks = devm_kcalloc(dev, priv->num_clks, + sizeof(*priv->clks), GFP_KERNEL); + if (!priv->clks) + return -ENOMEM; + + for (int i = 0; i < priv->num_clks; i++) { + priv->clks[i].clk = of_clk_get(np, i); + if (IS_ERR(priv->clks[i].clk)) { + ret = PTR_ERR(priv->clks[i].clk); + dev_err(dev, + "failed to get clk at index %d: err:%d\n", i, ret); + return -EINVAL; + } + } + } + + priv->reset = of_reset_control_array_get_optional_exclusive(np); + if (IS_ERR(priv->reset)) { + dev_err(dev, "failed to get reset return %ld\n", PTR_ERR(priv->reset)); + return PTR_ERR(priv->reset); + } + + /* init the chans */ + if (priv->version == ZHIHE_MBOX_V1) { + for (i = 0; i < ZHIHE_MBOX_CHANS; i++) { + struct zhihe_mbox_con_priv *cp = &priv->con_priv[i]; + + cp->icu_cpu_idx = i; + cp->chan = &priv->mbox_chans[i]; + priv->mbox_chans[i].con_priv = cp; + snprintf(cp->irq_desc, sizeof(cp->irq_desc), + "zhihe_mbox_chan[%i]", cp->icu_cpu_idx); + cp->comm_local_base = priv->local_icu[i]; + if (i != priv->cur_icu_cpu_id) { + cp->comm_remote_base = priv->remote_icu[remote_idx]; + remote_idx++; + } + } + } else if (priv->version == ZHIHE_MBOX_V2) { + for (i = 0; i < ZHIHE_MBOX_CHANS; i++) { + struct zhihe_mbox_con_priv *cp = &priv->con_priv[i]; + + cp->local_idx = i; + cp->chan = &priv->mbox_chans[i]; + priv->mbox_chans[i].con_priv = cp; + snprintf(cp->irq_desc, sizeof(cp->irq_desc), + "zhihe_mbox_chan[%i]", cp->local_idx); + cp->comm_local_base = priv->local_icu[i]; + if (i != ZHIHE_MBOX_INTERRUPT) { + cp->comm_remote_base = priv->remote_icu[remote_idx]; + remote_idx++; + } + } + } else { + dev_err(dev, "Unknown zhihe mailbox version\n"); + } + + spin_lock_init(&priv->mbox_lock); + + priv->mbox.dev = dev; + priv->mbox.ops = &zhihe_mbox_ops; + priv->mbox.chans = priv->mbox_chans; + priv->mbox.num_chans = ZHIHE_MBOX_CHANS; + priv->mbox.of_xlate = zhihe_mbox_xlate; + priv->mbox.txdone_irq = true; + + ret = zhihe_mbox_init_generic(priv); + if (ret) { + dev_err(dev, "Failed to init mailbox context\n"); + return ret; + } + return devm_mbox_controller_register(dev, &priv->mbox); +} + +static int zhihe_mbox_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id zhihe_mbox_dt_ids[] = { + { .compatible = "zhihe,a210-mailbox" }, + { .compatible = "zhihe,a210-mailbox-v2" }, + { }, +}; +MODULE_DEVICE_TABLE(of, zhihe_mbox_dt_ids); + +#ifdef CONFIG_PM_SLEEP +static int __maybe_unused zhihe_mbox_suspend_noirq(struct device *dev) +{ + u32 i; + struct zhihe_mbox_priv *priv = dev_get_drvdata(dev); + struct zhihe_mbox_context *ctx = priv->ctx; + + /* + * ONLY interrupt mask bit should be stored and restores. + * INFO data all assumed to be lost. + */ + for (i = 0 ; i < ZHIHE_MBOX_CHANS; i++) + ctx->intr_mask[i] = ioread32(priv->local_icu[i] + + ZHIHE_MBOX_MASK); + + return 0; +} + +static int __maybe_unused zhihe_mbox_resume_noirq(struct device *dev) +{ + u32 i; + struct zhihe_mbox_priv *priv = dev_get_drvdata(dev); + struct zhihe_mbox_context *ctx = priv->ctx; + + for (i = 0 ; i < ZHIHE_MBOX_CHANS; i++) + iowrite32(ctx->intr_mask[i], + priv->local_icu[i] + ZHIHE_MBOX_MASK); + + return 0; +} + +#endif + +static int __maybe_unused zhihe_mbox_runtime_suspend(struct device *dev) +{ + struct zhihe_mbox_priv *priv = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + reset_control_assert(priv->reset); + + return 0; +} + +static int __maybe_unused zhihe_mbox_runtime_resume(struct device *dev) +{ + struct zhihe_mbox_priv *priv = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); + if (ret) + return ret; + reset_control_deassert(priv->reset); + + return 0; +} + +static const struct dev_pm_ops zhihe_mbox_pm_ops = { +#ifdef CONFIG_PM_SLEEP + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(zhihe_mbox_suspend_noirq, + zhihe_mbox_resume_noirq) +#endif + SET_RUNTIME_PM_OPS(zhihe_mbox_runtime_suspend, + zhihe_mbox_runtime_resume, NULL) +}; + +static struct platform_driver zhihe_mbox_driver = { + .probe = zhihe_mbox_probe, + .remove = zhihe_mbox_remove, + .driver = { + .name = "zhihe_mbox", + .of_match_table = zhihe_mbox_dt_ids, + .pm = &zhihe_mbox_pm_ops, + }, +}; +module_platform_driver(zhihe_mbox_driver); + +MODULE_AUTHOR("hongkun.xu "); +MODULE_AUTHOR("xionglue.huang "); +MODULE_DESCRIPTION("a210 Mailbox IPC driver"); +MODULE_LICENSE("GPL"); From 52b9f4baf5ce1c87f650b480675e6b5f54b8fdfa Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Thu, 9 Apr 2026 20:20:55 +0800 Subject: [PATCH 09/17] firmware: add ZhiHe A210 AON subsystem driver Add the Always-On (AON) subsystem driver for the ZhiHe A210 SoC. This driver manages IPC communication with the E902 AON core and provides: - Mailbox-based IPC message transport - Power, clock, and resource management requests to the AON firmware - Proc debug interface for runtime diagnostics Signed-off-by: Zhiguo Zhu --- drivers/firmware/Kconfig | 1 + drivers/firmware/Makefile | 1 + drivers/firmware/zhihe/Kconfig | 19 + drivers/firmware/zhihe/Makefile | 3 + drivers/firmware/zhihe/zhihe_aon.c | 433 ++++++++++++++++++++++ drivers/firmware/zhihe/zhihe_proc_debug.c | 164 ++++++++ include/linux/firmware/zhihe/a210-ipc.h | 20 + include/linux/zhihe_proc_debug.h | 13 + 8 files changed, 654 insertions(+) create mode 100644 drivers/firmware/zhihe/Kconfig create mode 100644 drivers/firmware/zhihe/Makefile create mode 100644 drivers/firmware/zhihe/zhihe_aon.c create mode 100644 drivers/firmware/zhihe/zhihe_proc_debug.c create mode 100644 include/linux/firmware/zhihe/a210-ipc.h create mode 100644 include/linux/zhihe_proc_debug.h diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index af9a782b9ec4b..0cbf501f453e8 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -324,5 +324,6 @@ source "drivers/firmware/riscv/Kconfig" source "drivers/firmware/smccc/Kconfig" source "drivers/firmware/tegra/Kconfig" source "drivers/firmware/xilinx/Kconfig" +source "drivers/firmware/zhihe/Kconfig" endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 35824aa600d75..a5a4d0f621989 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -40,3 +40,4 @@ obj-y += riscv/ obj-y += smccc/ obj-y += tegra/ obj-y += xilinx/ +obj-y += zhihe/ diff --git a/drivers/firmware/zhihe/Kconfig b/drivers/firmware/zhihe/Kconfig new file mode 100644 index 0000000000000..95e5f25c1428f --- /dev/null +++ b/drivers/firmware/zhihe/Kconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only +config ZHIHE_AON + bool "ZhiHe AON protocol driver" + depends on ZHIHE_MBOX=y + default ARCH_ZHIHE + help + ZhiHe AON is a low-level system function which runs a dedicated + ZhiHe RISC-V E902 core to provide power, clock and resource management. + + This driver manages the IPC interface between the host CPU and the + AON firmware running on the ZhiHe RISC-V E902 core. + +config ZHIHE_PROC_DEBUG + bool "ZhiHe AON debug" + help + Enable debug support for the ZhiHe AON subsystem via procfs. + This provides a /proc interface for reading AON firmware logs + and debugging the always-on subsystem. + Say Y here only if you need AON debugging support. diff --git a/drivers/firmware/zhihe/Makefile b/drivers/firmware/zhihe/Makefile new file mode 100644 index 0000000000000..7a91433ead78e --- /dev/null +++ b/drivers/firmware/zhihe/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_ZHIHE_AON) += zhihe_aon.o +obj-$(CONFIG_ZHIHE_PROC_DEBUG) += zhihe_proc_debug.o diff --git a/drivers/firmware/zhihe/zhihe_aon.c b/drivers/firmware/zhihe/zhihe_aon.c new file mode 100644 index 0000000000000..7ea531173bf05 --- /dev/null +++ b/drivers/firmware/zhihe/zhihe_aon.c @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 ZHIHE Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ZHIHE_AON_SYNC_VAL 0xfeabdeff +#define ZHIHE_AON_RESET_VAL 0x3 + +#define ZHIHE_AON_V1 0x0 +#define ZHIHE_AON_V2 0x1 + +/* wait for response for 3000ms instead of 300ms (fix me pls)*/ +#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000)) +#define MAX_TX_TIMEOUT (msecs_to_jiffies(500)) + +struct zhihe_aon_chan { + struct zhihe_aon_ipc *aon_ipc; + struct mbox_client cl; + struct mbox_chan *ch; + struct completion tx_done; + /*for log proc*/ + phys_addr_t log_phy; + size_t log_size; + void __iomem *log_mem; + void *log_ctrl; + struct proc_dir_entry *proc_dir; +}; + +struct zhihe_aon_ipc { + struct zhihe_aon_chan chans; + struct device *dev; + struct mutex lock; + struct completion done; + const char *mbox_name; + u32 *msg; +}; + +/* + * This type is used to indicate error response for most functions. + */ +enum zhihe_aon_error_codes { + ZHIHE_AON_ERR_NONE = 0, /* Success */ + ZHIHE_AON_ERR_VERSION = 1, /* Incompatible API version */ + ZHIHE_AON_ERR_CONFIG = 2, /* Configuration error */ + ZHIHE_AON_ERR_PARM = 3, /* Bad parameter */ + ZHIHE_AON_ERR_NOACCESS = 4, /* Permission error (no access) */ + ZHIHE_AON_ERR_LOCKED = 5, /* Permission error (locked) */ + ZHIHE_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */ + ZHIHE_AON_ERR_NOTFOUND = 7, /* Not found */ + ZHIHE_AON_ERR_NOPOWER = 8, /* No power */ + ZHIHE_AON_ERR_IPC = 9, /* Generic IPC error */ + ZHIHE_AON_ERR_BUSY = 10, /* Resource is currently busy/active */ + ZHIHE_AON_ERR_FAIL = 11, /* General I/O failure */ + ZHIHE_AON_ERR_LAST +}; + +static int zhihe_aon_linux_errmap[ZHIHE_AON_ERR_LAST] = { + 0, /* ZHIHE_AON_ERR_NONE */ + -EINVAL, /* ZHIHE_AON_ERR_VERSION */ + -EINVAL, /* ZHIHE_AON_ERR_CONFIG */ + -EINVAL, /* ZHIHE_AON_ERR_PARM */ + -EACCES, /* ZHIHE_AON_ERR_NOACCESS */ + -EACCES, /* ZHIHE_AON_ERR_LOCKED */ + -ERANGE, /* ZHIHE_AON_ERR_UNAVAILABLE */ + -EEXIST, /* ZHIHE_AON_ERR_NOTFOUND */ + -EPERM, /* ZHIHE_AON_ERR_NOPOWER */ + -EPIPE, /* ZHIHE_AON_ERR_IPC */ + -EBUSY, /* ZHIHE_AON_ERR_BUSY */ + -EIO, /* ZHIHE_AON_ERR_FAIL */ +}; +#define ZHIHE_AON_CHN_MAX (4) +static struct zhihe_aon_ipc *zhihe_aon_ipc_handle[ZHIHE_AON_CHN_MAX]; +static uint32_t g_aon_ipc_handle_num; + +static inline int zhihe_aon_to_linux_errno(int errno) +{ + if (errno >= ZHIHE_AON_ERR_NONE && errno < ZHIHE_AON_ERR_LAST) + return zhihe_aon_linux_errmap[errno]; + return -EIO; +} + +/* + * Get the default handle used by SCU + */ +int zhihe_aon_get_handle(struct zhihe_aon_ipc **ipc, char *name) +{ + uint32_t i = 0; + + if (!name) + return -1; + for (i = 0; i < g_aon_ipc_handle_num; i++) { + if (!zhihe_aon_ipc_handle[i]) + return -EPROBE_DEFER; + if (!strcmp(name, zhihe_aon_ipc_handle[i]->mbox_name)) { + *ipc = zhihe_aon_ipc_handle[i]; + return 0; + } + } + return -EPROBE_DEFER; +} +EXPORT_SYMBOL(zhihe_aon_get_handle); + +static void zhihe_aon_tx_done(struct mbox_client *cl, void *mssg, int r) +{ + struct zhihe_aon_chan *aon_chan = + container_of(cl, struct zhihe_aon_chan, cl); + + complete(&aon_chan->tx_done); +} + +static void zhihe_aon_rx_callback(struct mbox_client *c, void *msg) +{ + struct zhihe_aon_chan *aon_chan = container_of(c, struct zhihe_aon_chan, cl); + struct zhihe_aon_ipc *aon_ipc = aon_chan->aon_ipc; + struct th1520_aon_rpc_msg_hdr *hdr = (struct th1520_aon_rpc_msg_hdr *)msg; + uint8_t recv_size = sizeof(struct th1520_aon_rpc_msg_hdr) + hdr->size; + + memcpy(aon_ipc->msg, msg, recv_size); + dev_dbg(aon_ipc->dev, "msg head: 0x%x, size:%d\n", *((u32 *)msg), + recv_size); + complete(&aon_ipc->done); +} + +static int zhihe_aon_ipc_write(struct zhihe_aon_ipc *aon_ipc, void *msg) +{ + struct th1520_aon_rpc_msg_hdr *hdr = msg; + struct zhihe_aon_chan *aon_chan; + u32 *data = msg; + int ret; + /* check size, currently it requires 7 MSG in one transfer */ + if (hdr->size != TH1520_AON_RPC_MSG_NUM) + return -EINVAL; + + dev_dbg(aon_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr->svc, + hdr->func, hdr->size); + + aon_chan = &aon_ipc->chans; + + if (!wait_for_completion_timeout(&aon_chan->tx_done, MAX_TX_TIMEOUT)) { + dev_err(aon_ipc->dev, "tx_done timeout\n"); + return -ETIMEDOUT; + } + reinit_completion(&aon_chan->tx_done); + ret = mbox_send_message(aon_chan->ch, data); + if (ret < 0) + return ret; + + return 0; +} + +/* + * RPC command/response + */ +int zhihe_aon_call_rpc(struct zhihe_aon_ipc *aon_ipc, void *msg, + void *ack_msg, bool have_resp) +{ + struct th1520_aon_rpc_msg_hdr *hdr = msg; + int ret = 0; + + if (WARN_ON(!aon_ipc || !msg)) + return -EINVAL; + if (have_resp && WARN_ON(!ack_msg)) + return -EINVAL; + mutex_lock(&aon_ipc->lock); + reinit_completion(&aon_ipc->done); + RPC_SET_VER(hdr, TH1520_AON_RPC_VERSION); + /*svc id use 6bit for version 2*/ + RPC_SET_SVC_ID(hdr, hdr->svc); + RPC_SET_SVC_FLAG_MSG_TYPE(hdr, RPC_SVC_MSG_TYPE_DATA); + if (have_resp) { + aon_ipc->msg = ack_msg; + RPC_SET_SVC_FLAG_ACK_TYPE(hdr, RPC_SVC_MSG_NEED_ACK); + } else + RPC_SET_SVC_FLAG_ACK_TYPE(hdr, RPC_SVC_MSG_NO_NEED_ACK); + ret = zhihe_aon_ipc_write(aon_ipc, msg); + if (ret < 0) { + dev_err(aon_ipc->dev, "RPC send msg failed: %d\n", ret); + goto out; + } + if (have_resp) { + if (!wait_for_completion_timeout(&aon_ipc->done, MAX_RX_TIMEOUT)) { + dev_err(aon_ipc->dev, "RPC send msg timeout\n"); + mutex_unlock(&aon_ipc->lock); + return -ETIMEDOUT; + } + + /* response status is stored in msg data[0] field */ + struct th1520_aon_rpc_ack_common *ack = ack_msg; + + ret = ack->err_code; + } +out: + mutex_unlock(&aon_ipc->lock); + + dev_dbg(aon_ipc->dev, "RPC SVC done\n"); + + return zhihe_aon_to_linux_errno(ret); +} +EXPORT_SYMBOL(zhihe_aon_call_rpc); + +static int get_aon_log_mem(struct device *dev, phys_addr_t *mem, size_t *mem_size) +{ + struct resource r; + struct device_node *node; + int ret; + + *mem = 0; + *mem_size = 0; + + node = of_parse_phandle(dev->of_node, "log-memory-region", 0); + if (!node) { + dev_err(dev, "no memory-region specified\n"); + return -EINVAL; + } + + ret = of_address_to_resource(node, 0, &r); + if (ret) { + dev_err(dev, "memory-region get resource failed\n"); + return -EINVAL; + } + + *mem = r.start; + *mem_size = resource_size(&r); + return 0; +} + +static int zhihe_aon_boot_img_by_name(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; + const struct firmware *zhihe_aon_fw = NULL; + void __iomem *base_addr; + void __iomem *reset_reg; + void __iomem *sync_reg; + unsigned int reset_val = ZHIHE_AON_RESET_VAL; + unsigned int sync_val = ZHIHE_AON_SYNC_VAL; + unsigned int sync_read = 0; + const char *bin_name = NULL; + unsigned int timeout_ms = 50; + unsigned long timeout; + int ret; + + base_addr = devm_platform_ioremap_resource_byname(pdev, "aon-base"); + if (IS_ERR(base_addr)) { + dev_err(dev, "Failed to map base_addr\n"); + return PTR_ERR(base_addr); + } + + reset_reg = devm_platform_ioremap_resource_byname(pdev, "aon-reset"); + if (IS_ERR(reset_reg)) { + dev_err(dev, "Failed to map aon_reset_reg\n"); + return PTR_ERR(reset_reg); + } + + sync_reg = devm_platform_ioremap_resource_byname(pdev, "aon-sync"); + if (IS_ERR(sync_reg)) { + dev_err(dev, "Failed to map aon_sync_reg\n"); + return PTR_ERR(sync_reg); + } + + ret = of_property_read_string(node, "firmware-name", &bin_name); + if (ret) { + dev_err(dev, "Failed to get aon-bin-names property: %d\n", ret); + return ret; + } + + ret = request_firmware(&zhihe_aon_fw, bin_name, NULL); + if (ret) { + dev_err(dev, "Failed to load firmware: %s (ret=%d)\n", + bin_name, ret); + return ret; + } + + dev_info(dev, "firmware loaded, size = %zu bytes\n", zhihe_aon_fw->size); + + memset(base_addr, 0, zhihe_aon_fw->size); + memcpy(base_addr, zhihe_aon_fw->data, zhihe_aon_fw->size); + + iowrite32(reset_val, reset_reg); + + timeout = jiffies + msecs_to_jiffies(timeout_ms); + + while (ioread32(sync_reg) != sync_val) { + if (time_after(jiffies, timeout)) { + dev_err(dev, "AON bringup timeout! sync_reg=0x%x, expected=0x%x\n", + sync_read, sync_val); + release_firmware(zhihe_aon_fw); + return -ETIMEDOUT; + } + + usleep_range(1000, 2000); + } + + release_firmware(zhihe_aon_fw); + + return 0; +} + +static int zhihe_aon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zhihe_aon_ipc *aon_ipc; + struct zhihe_aon_chan *aon_chan; + struct mbox_client *cl; + struct device_node *np; + char dir_name[32] = { 0x0 }; + int ret; + + aon_ipc = devm_kzalloc(dev, sizeof(*aon_ipc), GFP_KERNEL); + if (!aon_ipc) + return -ENOMEM; + aon_chan = &aon_ipc->chans; + cl = &aon_chan->cl; + cl->dev = dev; + cl->tx_block = false; + cl->knows_txdone = true; + cl->rx_callback = zhihe_aon_rx_callback; + + /* Initial tx_done completion as "done" */ + cl->tx_done = zhihe_aon_tx_done; + init_completion(&aon_chan->tx_done); + complete(&aon_chan->tx_done); + + aon_chan->aon_ipc = aon_ipc; + np = cl->dev->of_node; + aon_ipc->mbox_name = of_get_property(np, "mbox-names", NULL); + aon_chan->ch = mbox_request_channel_byname(cl, aon_ipc->mbox_name); + if (IS_ERR(aon_chan->ch)) { + ret = PTR_ERR(aon_chan->ch); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to request aon mbox chan ret %d\n", + ret); + return ret; + } + dev_dbg(dev, "request zhihe mbox chan: %s\n", aon_ipc->mbox_name); + + aon_ipc->dev = dev; + mutex_init(&aon_ipc->lock); + init_completion(&aon_ipc->done); + aon_chan->log_ctrl = NULL; + if (g_aon_ipc_handle_num >= ZHIHE_AON_CHN_MAX) { + dev_err(dev, "aon_ipc:%s handle num overflow\n", aon_ipc->mbox_name); + return -1; + } + + ret = get_aon_log_mem(dev, &aon_chan->log_phy, &aon_chan->log_size); + if (!ret) { + aon_chan->log_mem = ioremap(aon_chan->log_phy, aon_chan->log_size); + if (IS_ERR(aon_chan->log_mem)) { + aon_chan->log_mem = NULL; + dev_err(dev, "%s:get aon log region fail\n", __func__); + return -1; + } + + sprintf(dir_name, "aon_proc"); + aon_chan->proc_dir = proc_mkdir(dir_name, NULL); + if (aon_chan->proc_dir != NULL) { +#ifdef CONFIG_ZHIHE_PROC_DEBUG + aon_chan->log_ctrl = zhihe_create_panic_log_proc( + aon_chan->log_phy, aon_chan->proc_dir, + aon_chan->log_mem, aon_chan->log_size); +#endif + } else { + dev_err(dev, "create %s fail\n", dir_name); + return ret; + } + } + + zhihe_aon_ipc_handle[g_aon_ipc_handle_num] = aon_ipc; + g_aon_ipc_handle_num++; + + ret = zhihe_aon_boot_img_by_name(pdev); + if (ret == -ETIMEDOUT) { + dev_warn(dev, "AON sync timeout, retrying...\n"); + ret = zhihe_aon_boot_img_by_name(pdev); + if (ret) { + dev_err(dev, "AON bringup failed after retry (ret=%d)\n", ret); + return ret; + } + } + + return devm_of_platform_populate(dev); +} + +static const struct of_device_id zhihe_aon_match[] = { + { + .compatible = "zhihe,a210-aon", + }, + { /* Sentinel */ } +}; + +static int __maybe_unused zhihe_aon_resume_noirq(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops zhihe_aon_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, zhihe_aon_resume_noirq) +}; +static struct platform_driver zhihe_aon_driver = { + .driver = { + .name = "zhihe-aon", + .of_match_table = zhihe_aon_match, + .pm = &zhihe_aon_pm_ops, + }, + .probe = zhihe_aon_probe, +}; +builtin_platform_driver(zhihe_aon_driver); + +MODULE_AUTHOR("hongkun.xu "); +MODULE_AUTHOR("xionglue.huang "); +MODULE_DESCRIPTION("ZHIHE firmware protocol driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/zhihe/zhihe_proc_debug.c b/drivers/firmware/zhihe/zhihe_proc_debug.c new file mode 100644 index 0000000000000..1edbd27cafcaa --- /dev/null +++ b/drivers/firmware/zhihe/zhihe_proc_debug.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * sys log sys for zhihe c908 and e902 + * Copyright (C) 2021 ZHIHE Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GET_PAGE_NUM(size, offset) \ + ((((size) + ((offset) & ~PAGE_MASK)) + PAGE_SIZE - 1) >> PAGE_SHIFT) + +struct zhihe_log_ring_buffer { + __u32 read; + __u32 write; + __u32 size; + __u32 reserved[1]; + __u8 data[]; +}; + +struct zhihe_hw_log { + __u32 panic; + __u32 reserved[2]; + struct zhihe_log_ring_buffer rb; +}; + +struct zhihe_proc_log_ctrl { + struct zhihe_hw_log __iomem *log; + struct proc_dir_entry *log_proc_file; + phys_addr_t log_phy; +}; + +static void dump_regs(const char *fn, void *hw_arg) +{ + struct zhihe_proc_log_ctrl *log_ctrl = hw_arg; + + if (!log_ctrl->log) + return; + + pr_debug("%s: panic = 0x%08x\n", fn, + __raw_readl(&log_ctrl->log->panic)); + pr_debug("%s: read = 0x%08x, write = 0x%08x, size = 0x%08x\n", fn, + __raw_readl(&log_ctrl->log->rb.read), + __raw_readl(&log_ctrl->log->rb.write), + __raw_readl(&log_ctrl->log->rb.size)); +} + +static int log_proc_show(struct seq_file *file, void *v) +{ + struct zhihe_proc_log_ctrl *log_ctrl = file->private; + char *buf; + size_t i; + /*dcache clean and invalid*/ + ALT_CMO_OP(flush, (phys_to_virt(log_ctrl->log_phy)), + sizeof(struct zhihe_hw_log), + riscv_cbom_block_size); + + uint32_t write = __raw_readl(&log_ctrl->log->rb.write); + uint32_t read = __raw_readl(&log_ctrl->log->rb.read); + uint32_t size = __raw_readl(&log_ctrl->log->rb.size); + size_t log_size = write >= read ? write - read : size + write - read; + + seq_puts(file, "****************** device log >>>>>>>>>>>>>>>>>\n"); + dump_regs(__func__, log_ctrl); + if (!log_size) { + seq_puts(file, "****************** end device log <<<<<<<<<<<<<<<<<\n"); + return 0; + } + + int page_num = GET_PAGE_NUM(log_size, 0); + + int log_patch_1 = -1, log_patch_2 = -1; + + buf = kmalloc(PAGE_SIZE * page_num, GFP_KERNEL); + if (buf) { + if (read + log_size >= size) { + log_patch_2 = read + log_size - size + 1; + log_patch_1 = log_size - log_patch_2; + } else + log_patch_1 = log_size; + + memcpy_fromio(buf, &log_ctrl->log->rb.data[read], log_patch_1); + if (log_patch_2 > 0) + memcpy_fromio(buf, &log_ctrl->log->rb.data[0], log_patch_2); + + uint8_t last_fame_size = log_size % 64; + + for (i = 0; i < log_size - last_fame_size; i += 64) + seq_printf(file, " %*pEp", 64, buf + i); + + if (last_fame_size) + seq_printf(file, " %*pEp", last_fame_size, buf + log_size - last_fame_size); + + __raw_writel(write, &log_ctrl->log->rb.read); + kfree(buf); + /*dcahce clean*/ + ALT_CMO_OP(clean, (phys_to_virt(log_ctrl->log_phy)), + sizeof(struct zhihe_hw_log), riscv_cbom_block_size); + //seq_printf(file, "%d %d %d %d %d\n", log_patch_1, + // log_patch_2, log_size, last_fame_size, read); + seq_puts(file, "\n****************** end device log <<<<<<<<<<<<<<<<<\n"); + return 0; + } + + pr_debug("Fail to alloc buf\n"); + return -1; + return 0; +} + +static bool zhihe_panic_init(struct zhihe_hw_log *hw_log, size_t size) +{ + if (size < sizeof(struct zhihe_hw_log)) + return false; + + hw_log->rb.read = 0; + hw_log->rb.size = size - sizeof(struct zhihe_hw_log); + return true; +} + +void *zhihe_create_panic_log_proc(phys_addr_t log_phy, void *dir, + void *log_info_addr, size_t size) +{ + struct zhihe_proc_log_ctrl *log_ctrl = + kmalloc(sizeof(struct zhihe_proc_log_ctrl), GFP_KERNEL); + + if (log_ctrl == NULL) + return NULL; + + log_ctrl->log = log_info_addr; + + zhihe_panic_init(log_ctrl->log, size); + + log_ctrl->log_proc_file = proc_create_single_data( + "proc_log", 0644, dir, &log_proc_show, log_ctrl); + if (log_ctrl->log_proc_file == NULL) { + pr_debug("Error: Could not initialize %s\n", "dsp_log"); + kfree(log_ctrl); + log_ctrl = NULL; + } else + pr_debug("%s create Success!\n", "dsp_log"); + + log_ctrl->log_phy = log_phy; + return log_ctrl; +} + +void zhihe_remove_panic_log_proc(void *arg) +{ + struct zhihe_proc_log_ctrl *log_ctrl = (struct zhihe_proc_log_ctrl *)arg; + + proc_remove(log_ctrl->log_proc_file); + kfree(log_ctrl); + pr_debug("zhihe proc log removed\n"); +} + diff --git a/include/linux/firmware/zhihe/a210-ipc.h b/include/linux/firmware/zhihe/a210-ipc.h new file mode 100644 index 0000000000000..107d0f3d11669 --- /dev/null +++ b/include/linux/firmware/zhihe/a210-ipc.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2021 ZHIHE Group Holding Limited. + */ + +#ifndef _ZHIHE_IPC_H +#define _ZHIHE_IPC_H + +#include +#include +#include + +struct zhihe_aon_ipc; + +int zhihe_aon_call_rpc(struct zhihe_aon_ipc *ipc, void *msg, void *ack_msg, bool have_resp); +int zhihe_aon_get_handle(struct zhihe_aon_ipc **ipc, char *name); +int zhihe_aon_misc_set_control(struct zhihe_aon_ipc *ipc, u16 resource, u32 ctrl, u32 val); +int zhihe_aon_misc_get_control(struct zhihe_aon_ipc *ipc, u16 resource, u32 ctrl, u32 *val); + +#endif /* _ZHIHE_IPC_H */ diff --git a/include/linux/zhihe_proc_debug.h b/include/linux/zhihe_proc_debug.h new file mode 100644 index 0000000000000..bac16904fbd25 --- /dev/null +++ b/include/linux/zhihe_proc_debug.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2021 ZHIHE Group Holding Limited. + */ + +#ifndef __ZHIHE_PROC_DEBUG_H_ +#define __ZHIHE_PROC_DEBUG_H_ + + +void *zhihe_create_panic_log_proc(phys_addr_t log_phy, void *dir, void *log_addr, size_t size); +void zhihe_remove_panic_log_proc(void *arg); + +#endif From b3d8e1b98ca3be65985dafae970c0ff431328634 Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Thu, 9 Apr 2026 20:22:27 +0800 Subject: [PATCH 10/17] regulator: add ZhiHe A210 AON regulator driver Add a virtual regulator driver for the ZhiHe A210 SoC that controls voltage regulators through the AON subsystem IPC interface. The driver translates standard regulator framework calls into IPC messages to the AON firmware which performs the actual hardware control. Signed-off-by: Zhiguo Zhu --- drivers/regulator/Kconfig | 11 + drivers/regulator/Makefile | 1 + drivers/regulator/zhihe-aon-regulator.c | 461 ++++++++++++++++++++++++ 3 files changed, 473 insertions(+) create mode 100644 drivers/regulator/zhihe-aon-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 91d66b56faca0..c44a3e3ad6624 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1670,4 +1670,15 @@ config REGULATOR_QCOM_LABIBB boost regulator and IBB can be used as a negative boost regulator for LCD display panel. +config REGULATOR_ZHIHE_AON + tristate "ZhiHe AON regulator" + depends on ZHIHE_AON + default ZHIHE_AON + help + This driver provides support for the ZhiHe virtual regulators + implemented on the ZhiHe AON subsystem. + + This driver relies on the IPC interface between the host CPU and + the AON firmware running on E902. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 54ac03d483499..bde262b5d67bc 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -196,5 +196,6 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o +obj-$(CONFIG_REGULATOR_ZHIHE_AON) += zhihe-aon-regulator.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/zhihe-aon-regulator.c b/drivers/regulator/zhihe-aon-regulator.c new file mode 100644 index 0000000000000..3b9ca0444d416 --- /dev/null +++ b/drivers/regulator/zhihe-aon-regulator.c @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Zhihe Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MBOX_MAX_MSG_LEN 28 + +/* + * struct rpc_msg_regu_vol_set - regulator voltage set request descriptor + * + * @regu_id: Virtual regulator id + * @is_daul_rail: Specify if this virtual id contains dual rails + * @dc1: Voltage uint in uv for single rail or the first rail + * @dc2: Voltage uint in uv for the second rail, ignore it if it's not daul rail + */ +struct rpc_msg_regu_vol_set { + u16 regu_id; + u16 is_dual_rail; + u32 dc1; + u32 dc2; + u16 reserved[6]; +} __packed __aligned(1); + +/* + * struct rpc_msg_regu_vol_get - regulator voltage get request descriptor + * + * @regu_id: Virtual regulator id + * @is_daul_rail: Specify if this virtual id contains dual rails + * @dc1: Voltage uint in uv for single rail or the first rail + * @dc2: Voltage uint in uv for the second rail, ignore it if it's not daul rail + */ +struct rpc_msg_regu_vol_get { + u16 regu_id; + u16 is_dual_rail; + u32 dc1; + u32 dc2; + u16 reserved[6]; +} __packed __aligned(1); + +/* + * struct rpc_msg_regu_vol_get_ack - regulator voltage get resp descriptor + * + * Dedicated for rpc rx message with transform status and regulator voltage. + * + * @th1520_aon_rpc_ack_common: RPC message ack descriptor + * @regu_id: Virtual regulator id + * @is_daul_rail: Specify if this virtual id contains dual rails + * @dc1: Voltage uint in uv for single rail or the first rail + * @dc2: Voltage uint in uv for the second rail, ignore it if it's not daul rail + */ +struct rpc_msg_regu_vol_get_ack { + struct th1520_aon_rpc_ack_common ack_hdr; + u16 regu_id; + u16 is_dual_rail; + u32 dc1; + u32 dc2; + u16 reserved[6]; +} __packed __aligned(1); + +/* + * struct rpc_msg_regu_pwr_set - regulator power status set request descriptor + * + * @regu_id: Virtual regulator id + * @status: Regulator on\off status + */ +struct rpc_msg_regu_pwr_set { + u16 regu_id; + u16 status; + u32 reserved[5]; +} __packed __aligned(1); + +/* + * struct rpc_msg_regu_pwr_get - regulator power status get request descriptor + * + * @regu_id: Virtual regulator id + */ +struct rpc_msg_regu_pwr_get { + u16 regu_id; + u32 reserved[5]; +} __packed __aligned(1); + +/* + * struct rpc_msg_regu_pwr_get_ack - regulator power status get resp descriptor + * + * @th1520_aon_rpc_ack_common: RPC message ack descriptor + * @regu_id: Virtual regulator id + * @status: Regulator on\off status + */ +struct rpc_msg_regu_pwr_get_ack { + struct th1520_aon_rpc_ack_common ack_hdr; + u16 regu_id; + u16 status; + u32 reserved[5]; +} __packed __aligned(1); + +struct zhihe_aon_msg_regulator_ctrl { + struct th1520_aon_rpc_msg_hdr hdr; + union rpc_func_t { + struct rpc_msg_regu_vol_set regu_vol_set; + struct rpc_msg_regu_vol_get regu_vol_get; + struct rpc_msg_regu_pwr_set regu_pwr_set; + struct rpc_msg_regu_pwr_get regu_pwr_get; + } __packed __aligned(1) rpc; +} __packed __aligned(1); + +enum a210_pm_resource { + A210_AVDD33_EMMC, /* sy70209: ldo1 */ + A210_AVDD33_USB2, /* sy70209: ldo2 */ + A210_DVDD08_AON, /* sy70209: ldo3 */ + A210_AVDD18_AON, /* sy70209: ldo4 */ + A210_AVDD18_EMMC_USB2, /* sy70209: ldo5 */ + A210_AVDD18_EMMC_PERI, /* sy70209: ldo7 */ + A210_AVDD18_TOP, /* sy70209: ldo8 */ + A210_AVDD18_PLL, /* sy70209: ldo9 */ + A210_AVDD18, /* sy70209: ldo10 */ + A210_DVDD18_DDR_VAA, /* sy70209: vout1 */ + A210_P3V3, /* sy70209: vout2 */ + A210_DVDD08_TOP, /* sy70209: vout3 */ + A210_DVDD06_DDR_VDDQLP, /* sy70209: vout4 */ + A210_DVDD08_DDR, /* sy70209: vout5 */ + A210_DVDD_CPU, /* sy70209: vout6 */ + A210_DVDDM_CPU, /* sy70209: vout7 */ + A210_DVDD_VP, /* sy70209: vout8 */ + A210_DVDD_NPU_VIP, /* sy70300: vout1 */ + A210_DVDD_CPU_P, /* sy70300: vout2 */ + A210_DVDD_GPU, /* sy70300: vout3 */ + A210_REGU_MAX +}; + +struct apcpu_vol_set { + u32 vdd; ///< cpu core voltage + u32 vddm; ///< cpu core-mem voltage +}; + +struct aon_regu_desc { + struct regulator_desc *regu_desc; + u32 regu_num; +}; + +struct aon_regu_info { + struct device *dev; + const struct apcpu_vol_set *cpu_vol; ///< signed-off voltage of cpu + u32 vddm; ///< cpu-mem voltage + uint8_t cpu_dual_rail_flag; ///< cpu dual rail flag + uint8_t vddm_dual_rail_flag; ///< cpu-mem dual rail flag + struct aon_regu_desc *regu_desc; ///< regu-desc set + struct zhihe_aon_ipc *ipc_handle; ///< handle of mail-box +}; + +static struct aon_regu_info zhihe_aon_pmic_info; + +/* dc2 is valid when is_dual_rail is true + * + * Dual-rail regulator means that a virtual regulator involves two hardware + * regulators. + */ +static int aon_set_regulator(struct zhihe_aon_ipc *ipc, u16 regu_id, u32 dc) +{ + struct zhihe_aon_msg_regulator_ctrl msg = { 0 }; + struct th1520_aon_rpc_ack_common ack_msg = { 0 }; + struct th1520_aon_rpc_msg_hdr *hdr = &msg.hdr; + + hdr->svc = (uint8_t)TH1520_AON_RPC_SVC_PM; + hdr->func = (uint8_t)TH1520_AON_PM_FUNC_SET_RESOURCE_REGULATOR; + hdr->size = TH1520_AON_RPC_MSG_NUM; + + RPC_SET_BE16(&msg.rpc.regu_vol_set.regu_id, 0, regu_id); + RPC_SET_BE32(&msg.rpc.regu_vol_set.regu_id, 4, dc); + + return zhihe_aon_call_rpc(ipc, &msg, &ack_msg, true); +} + +/* dc2 is valid when is_dual_rail is true + * + * Dual-rail regulator means that a virtual regulator involves two hardware + * regulators. + */ +static int aon_get_regulator(struct zhihe_aon_ipc *ipc, u16 regu_id, u32 *dc) +{ + struct zhihe_aon_msg_regulator_ctrl msg = { 0 }; + struct rpc_msg_regu_vol_get_ack ack_msg = { 0 }; + struct th1520_aon_rpc_msg_hdr *hdr = &msg.hdr; + int ret; + + hdr->svc = (uint8_t)TH1520_AON_RPC_SVC_PM; + hdr->func = (uint8_t)TH1520_AON_PM_FUNC_GET_RESOURCE_REGULATOR; + hdr->size = TH1520_AON_RPC_MSG_NUM; + + RPC_SET_BE16(&msg.rpc.regu_vol_get.regu_id, 0, regu_id); + + ret = zhihe_aon_call_rpc(ipc, &msg, &ack_msg, true); + if (ret) + return ret; + /*fix me:set local */ + ack_msg.regu_id = regu_id; + + RPC_GET_BE32(&ack_msg.regu_id, 4, &ack_msg.dc1); + + if (dc != NULL) + *dc = ack_msg.dc1; + + return 0; +} + +static int aon_regu_power_ctrl(struct zhihe_aon_ipc *ipc, u32 regu_id, u16 pwr_on) +{ + struct zhihe_aon_msg_regulator_ctrl msg = { 0 }; + struct th1520_aon_rpc_ack_common ack_msg = { 0 }; + struct th1520_aon_rpc_msg_hdr *hdr = &msg.hdr; + + hdr->svc = (uint8_t)TH1520_AON_RPC_SVC_PM; + hdr->func = (uint8_t)TH1520_AON_PM_FUNC_PWR_SET; + hdr->size = TH1520_AON_RPC_MSG_NUM; + + RPC_SET_BE16(&msg.rpc.regu_pwr_set.regu_id, 0, regu_id); + RPC_SET_BE16(&msg.rpc.regu_pwr_set.regu_id, 2, pwr_on); + + return zhihe_aon_call_rpc(ipc, &msg, &ack_msg, true); +} + +static int aon_regu_enable(struct regulator_dev *reg) +{ + u16 regu_id = (u16)rdev_get_id(reg); + + return aon_regu_power_ctrl(zhihe_aon_pmic_info.ipc_handle, regu_id, 1); +} + +static int aon_regu_disable(struct regulator_dev *reg) +{ + u16 regu_id = (u16)rdev_get_id(reg); + + return aon_regu_power_ctrl(zhihe_aon_pmic_info.ipc_handle, regu_id, 0); +} + +static int aon_regu_is_enabled(struct regulator_dev *reg) +{ + struct zhihe_aon_msg_regulator_ctrl msg = { 0 }; + struct rpc_msg_regu_pwr_get_ack ack_msg = { 0 }; + struct th1520_aon_rpc_msg_hdr *hdr = &msg.hdr; + u16 regu_id = (u16)rdev_get_id(reg); + int ret; + + hdr->svc = (uint8_t)TH1520_AON_RPC_SVC_PM; + hdr->func = (uint8_t)TH1520_AON_PM_FUNC_PWR_GET; + hdr->size = TH1520_AON_RPC_MSG_NUM; + + RPC_SET_BE16(&msg.rpc.regu_pwr_get.regu_id, 0, regu_id); + + ret = zhihe_aon_call_rpc(zhihe_aon_pmic_info.ipc_handle, &msg, &ack_msg, true); + if (ret < 0) + return ret; + + RPC_GET_BE16(&ack_msg.regu_id, 2, &ack_msg.status); + return (int)ack_msg.status; +} + +static int aon_regu_set_voltage(struct regulator_dev *reg, int minuV, + int max_uV, unsigned int *selector) +{ + const struct regulator_desc *desc = reg->desc; + u16 regu_id = (u16)rdev_get_id(reg); + + *selector = DIV_ROUND_UP(minuV - desc->min_uV, desc->uV_step); + + return aon_set_regulator(zhihe_aon_pmic_info.ipc_handle, regu_id, minuV); +} + +static int aon_regu_get_voltage(struct regulator_dev *reg) +{ + u16 regu_id = (u16)rdev_get_id(reg); + int voltage, ret; + + ret = aon_get_regulator(zhihe_aon_pmic_info.ipc_handle, regu_id, &voltage); + if (ret) { + pr_err("failed to get voltage\n"); + return -EINVAL; + } + + return voltage; +} + +static const struct regulator_ops regu_common_ops = { + .enable = aon_regu_enable, + .disable = aon_regu_disable, + .is_enabled = aon_regu_is_enabled, + .list_voltage = regulator_list_voltage_linear, + .set_voltage = aon_regu_set_voltage, + .get_voltage = aon_regu_get_voltage, +}; + +/* Macros for voltage DC/DC converters (BUCKs) for cpu */ +#define REGU_DSC_DEF(regu_id, of_math_name) \ + { .id = regu_id, \ + .name = of_match_ptr(of_math_name), \ + .of_match = of_match_ptr(of_math_name), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE } + +#define REGU_DYN_DSC_DEF(regu_id, of_math_name, min, step, max) \ + { .id = regu_id, \ + .name = of_match_ptr(of_math_name), \ + .of_match = of_match_ptr(of_math_name), \ + .min_uV = (min), \ + .uV_step = (step), \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE } + +static struct regulator_desc zhihe_a210_aon_regu_desc[] = { + /* Common regulators do not need dynamic voltage adjustment. */ + REGU_DSC_DEF(A210_AVDD33_EMMC, "avdd33_emmc"), + REGU_DSC_DEF(A210_AVDD33_USB2, "avdd33_usb2"), + REGU_DSC_DEF(A210_DVDD08_AON, "dvdd08_aon"), + REGU_DSC_DEF(A210_AVDD18_AON, "avdd18_aon"), + REGU_DSC_DEF(A210_AVDD18_EMMC_USB2, "avdd18_emmc_usb2"), + REGU_DSC_DEF(A210_AVDD18_EMMC_PERI, "avdd18_emmc_peri"), + REGU_DSC_DEF(A210_AVDD18_TOP, "avdd18_top"), + REGU_DSC_DEF(A210_AVDD18_PLL, "avdd18_pll"), + REGU_DSC_DEF(A210_AVDD18, "avdd18"), + REGU_DSC_DEF(A210_DVDD18_DDR_VAA, "dvdd18_ddr_vaa"), + REGU_DSC_DEF(A210_P3V3, "p3v3"), + REGU_DSC_DEF(A210_DVDD08_TOP, "dvdd08_top"), + REGU_DSC_DEF(A210_DVDD06_DDR_VDDQLP, "dvdd06_ddr_vddqlp"), + REGU_DYN_DSC_DEF(A210_DVDD08_DDR, "dvdd08_ddr", 750000, 5000, 800000), + REGU_DYN_DSC_DEF(A210_DVDD_CPU, "dvdd_cpu", 600000, 12500, 1000000), + REGU_DYN_DSC_DEF(A210_DVDDM_CPU, "dvddm_cpu", 800000, 12500, 1000000), + REGU_DYN_DSC_DEF(A210_DVDD_VP, "dvdd_vp", 750000, 12500, 800000), + REGU_DYN_DSC_DEF(A210_DVDD_NPU_VIP, "dvdd_npu_vip", 750000, 5000, 1000000), + REGU_DYN_DSC_DEF(A210_DVDD_CPU_P, "dvdd_cpu_p", 800000, 5000, 1000000), + REGU_DYN_DSC_DEF(A210_DVDD_GPU, "dvdd_gpu", 750000, 5000, 800000), +}; + +static const struct aon_regu_desc zhihe_a210_aon_regus = { + .regu_desc = (struct regulator_desc *)&zhihe_a210_aon_regu_desc, + .regu_num = ARRAY_SIZE(zhihe_a210_aon_regu_desc), +}; + +static int zhihe_match_regulator_id(struct aon_regu_desc *regus_set, u32 id) +{ + int index; + + for (index = 0; index < regus_set->regu_num; index++) { + if (regus_set->regu_desc[index].id == id) + return index; + } + + return -EINVAL; +} + +static int zhihe_aon_regulator_probe(struct platform_device *pdev) +{ + int ret; + int index; + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + struct regulator_config config = {}; + struct regulator_dev *rdev; + struct regulator_desc *desc; + struct aon_regu_desc *regus_set = NULL; + u32 regulator_id; + + if (!np) + return -ENODEV; + + regus_set = (struct aon_regu_desc *)of_device_get_match_data(&pdev->dev); + if (!regus_set) + return -ENODEV; + + /* Get IPC handle. */ + ret = zhihe_aon_get_handle(&(zhihe_aon_pmic_info.ipc_handle), "aon0"); + if (ret) { + dev_err(dev, "failed to get ipc_handle\n"); + return ret; + } + + /* Register regulators. */ + zhihe_aon_pmic_info.dev = dev; + config.dev = dev; + config.driver_data = &zhihe_aon_pmic_info; + + for_each_child_of_node(np, child) { + ret = of_property_read_u32(child, "zhihe,regulator-id", ®ulator_id); + if (ret) { + dev_err(dev, "failed to get zhihe,regulator-id for %pOFn\n", child); + goto put_child; + } + + index = zhihe_match_regulator_id(regus_set, regulator_id); + if (index < 0) { + dev_err(dev, "no regulator matches id %u\n", regulator_id); + ret = -EINVAL; + goto put_child; + } + + desc = ®us_set->regu_desc[index]; + desc->ops = ®u_common_ops; + + config.of_node = child; + rdev = devm_regulator_register(dev, desc, &config); + if (IS_ERR(rdev)) { + dev_err(dev, "Failed to register regulator %s\n", desc->name); + ret = PTR_ERR(rdev); + goto put_child; + } + } + + platform_set_drvdata(pdev, &zhihe_aon_pmic_info); + return 0; + +put_child: + of_node_put(child); + return ret; +} + +static const struct of_device_id zhihe_pmic_dev_id[] = { + { .compatible = "zhihe,a210-aon-regulator", .data = &zhihe_a210_aon_regus}, + {}, +}; +MODULE_DEVICE_TABLE(of, zhihe_pmic_dev_id); + +static struct platform_driver zhihe_aon_regulator_driver = { + .driver = { + .name = "zhihe-aon-reg", + .owner = THIS_MODULE, + .of_match_table = zhihe_pmic_dev_id, + }, + .probe = zhihe_aon_regulator_probe, +}; + +static int __init zhihe_aon_regulator_init(void) +{ + return platform_driver_register(&zhihe_aon_regulator_driver); +} +postcore_initcall(zhihe_aon_regulator_init); + +static void __exit zhihe_aon_regulator_exit(void) +{ + platform_driver_unregister(&zhihe_aon_regulator_driver); +} +module_exit(zhihe_aon_regulator_exit); + +MODULE_AUTHOR("hongkun.xu "); +MODULE_DESCRIPTION("Zhihe Aon regulator driver"); +MODULE_LICENSE("GPL"); From 152c216faa7258ccf468fb3b35b5a98393c3cc0d Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Apr 2026 20:29:34 +0800 Subject: [PATCH 11/17] dmaengine: dw-axi-dmac: add ZhiHe A210 compatible string Add "zhihe,a210-axi-dma" compatible string to the dw-axi-dmac driver with HAS_RESETS and USE_CFG2 chip flags matching the A210 DMA controller configuration. Signed-off-by: Zhiguo Zhu --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index f6a1fa7fadd17..1d23a689e6263 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -1675,6 +1675,9 @@ static const struct of_device_id dw_dma_of_id_table[] = { }, { .compatible = "xuantie,th1520-axi-dma", .data = (void *)(AXI_DMA_FLAG_USE_CFG2), + }, { + .compatible = "zhihe,a210-axi-dma", + .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2), }, {} }; From 3bb5d08fa198262be86fb7b84eabbab60ceb6d0a Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Apr 2026 20:29:39 +0800 Subject: [PATCH 12/17] mmc: sdhci-of-dwcmshc: add ZhiHe A210 compatible string Add "zhihe,a210-dwcmshc" compatible string to the sdhci-of-dwcmshc driver for the ZhiHe A210 SDHCI controller. The A210 SDHCI IP behaves identically to the TH1520 one, so the existing TH1520 platform data and callbacks are reused directly. Signed-off-by: Zhiguo Zhu --- drivers/mmc/host/sdhci-of-dwcmshc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 56646719017b1..0bb50e74a6e57 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -1037,6 +1037,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { .compatible = "thead,th1520-dwcmshc", .data = &sdhci_dwcmshc_th1520_pdata, }, + { + .compatible = "zhihe,a210-dwcmshc", + .data = &sdhci_dwcmshc_th1520_pdata, + }, {}, }; MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); From e9868c674f53c0165d1cb6471937ab0f9273592c Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Apr 2026 20:29:28 +0800 Subject: [PATCH 13/17] net: stmmac: add ZhiHe DWMAC glue layer Add a platform glue driver for the Synopsys DWMAC Ethernet controller integrated in ZhiHe SoCs. The driver handles SoC-specific clock and reset management and configures the MAC interface mode through a syscon register. Signed-off-by: Zhiguo Zhu --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 + drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + .../net/ethernet/stmicro/stmmac/dwmac-zhihe.c | 315 ++++++++++++++++++ 3 files changed, 327 insertions(+) create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-zhihe.c diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 35ff3c17c3849..bbda021b530ac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -236,6 +236,17 @@ config DWMAC_THEAD the stmmac device driver. This driver is used for XuanTie TH1520 ethernet controller. +config DWMAC_ZHIHE + tristate "ZhiHe A210 DWMAC support" + depends on OF && (ARCH_ZHIHE || COMPILE_TEST) + default STMMAC_ETH if ARCH_ZHIHE + help + Support for the Synopsys DesignWare MAC Ethernet controller + found on ZhiHe SoCs, through a platform glue layer for the + stmmac driver. It handles the clock and reset configuration + specific to the ZhiHe A210 platform. Say Y or M here if you + are building a kernel for a ZhiHe A210 based board. + config DWMAC_IMX8 tristate "NXP IMX8 DWMAC support" default ARCH_MXC diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 033ea262fd63e..9e760fc815d57 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o obj-$(CONFIG_DWMAC_THEAD) += dwmac-thead.o +obj-$(CONFIG_DWMAC_ZHIHE) += dwmac-zhihe.o obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-zhihe.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-zhihe.c new file mode 100644 index 0000000000000..f32bffc94a506 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-zhihe.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stmmac_platform.h" + +/* SYSCFG registers */ +#define GMAC_CLKCTRL (0x00) +#define GMAC_CTRL (0x04) +#define GMAC_ST (0x08) +#define GMAC_TMI (0x0C) +#define GMAC_PMI (0x10) +#define GMAC_SBDI (0x14) + +/* SYSCFG value */ +#define GMAC_CLKTRL_EN_ALL 0x1F +#define GMAC_CLKCTRL_SPEED_MASK (0x3 << 8) +#define GMAC_CLKCTRL_1G (0x0 << 8) +#define GMAC_CLKCTRL_10M (0x2 << 8) +#define GMAC_CLKCTRL_100M (0x3 << 8) + +#define GMAC_CTRL_INTF_MASK 0xF +#define GMAC_CTRL_RGMII 0x1 +#define GMAC_CTRL_RMII 0x4 + +struct zhihe_dwmac { + struct device *dev; + struct regmap *sys_regmap; + struct clk *gmac_aclk; + struct clk *gmac_pclk; + struct clk *gmac_x2h_aclk; + struct clk *gmac_x2h_hclk; + struct plat_stmmacenet_data *plat_dat; +}; + +/* zhihe a210 */ +static void zhihe_dwmac_set_speed(struct zhihe_dwmac *dwmac, unsigned int speed) +{ + phy_interface_t interface = dwmac->plat_dat->phy_interface; + struct device *dev = dwmac->dev; + unsigned int reg = 0; + + /* Configure mac speed */ + regmap_read(dwmac->sys_regmap, GMAC_CLKCTRL, ®); + switch (speed) { + case SPEED_10: + reg &= ~GMAC_CLKCTRL_SPEED_MASK; + reg |= GMAC_CLKCTRL_10M; + break; + case SPEED_100: + reg &= ~GMAC_CLKCTRL_SPEED_MASK; + reg |= GMAC_CLKCTRL_100M; + break; + case SPEED_1000: + reg &= ~GMAC_CLKCTRL_SPEED_MASK; + reg |= GMAC_CLKCTRL_1G; + break; + default: + dev_err(dev, "Invalid speed %u\n", speed); + return; + } + regmap_write(dwmac->sys_regmap, GMAC_CLKCTRL, reg); + + /* Configure phy interface */ + regmap_read(dwmac->sys_regmap, GMAC_CTRL, ®); + switch (interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + reg &= ~GMAC_CTRL_INTF_MASK; + reg |= GMAC_CTRL_RGMII; + break; + case PHY_INTERFACE_MODE_RMII: + reg &= ~GMAC_CTRL_INTF_MASK; + reg |= GMAC_CTRL_RMII; + break; + default: + dev_err(dev, "Invalid phy interface: %d\n", interface); + return; + } + regmap_write(dwmac->sys_regmap, GMAC_CTRL, reg); +} + +static void zhihe_dwmac_clkctrl_enable(struct zhihe_dwmac *dwmac, bool enable) +{ + unsigned int reg = 0; + + regmap_read(dwmac->sys_regmap, GMAC_CLKCTRL, ®); + reg &= ~GMAC_CLKTRL_EN_ALL; + if (enable) + reg |= GMAC_CLKTRL_EN_ALL; + regmap_write(dwmac->sys_regmap, GMAC_CLKCTRL, reg); +} + +static int zhihe_dwmac_peri_resource(struct zhihe_dwmac *dwmac) +{ + struct device *dev = dwmac->dev; + struct platform_device *pdev = to_platform_device(dev); + struct device_node *np = pdev->dev.of_node; + + /* clks resource */ + dwmac->gmac_aclk = devm_clk_get(dev, "stmmaceth"); + if (IS_ERR(dwmac->gmac_aclk)) { + return dev_err_probe(dev, PTR_ERR(dwmac->gmac_aclk), + "Error getting stmmaceth reference clock\n"); + } + + dwmac->gmac_pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(dwmac->gmac_pclk)) { + return dev_err_probe(dev, PTR_ERR(dwmac->gmac_pclk), + "Error getting pclk reference clock\n"); + } + + dwmac->gmac_x2h_aclk = devm_clk_get(dev, "x2h-aclk"); + if (IS_ERR(dwmac->gmac_x2h_aclk)) { + return dev_err_probe(dev, PTR_ERR(dwmac->gmac_x2h_aclk), + "Error getting x2h-aclk reference clock\n"); + } + + dwmac->gmac_x2h_hclk = devm_clk_get(dev, "x2h-hclk"); + if (IS_ERR(dwmac->gmac_x2h_hclk)) { + return dev_err_probe(dev, PTR_ERR(dwmac->gmac_x2h_hclk), + "Error getting x2h-hclk reference clock\n"); + } + + dwmac->sys_regmap = syscon_regmap_lookup_by_phandle(np, "zhihe,gmacsys"); + if (IS_ERR(dwmac->sys_regmap)) { + return dev_err_probe(dev, PTR_ERR(dwmac->sys_regmap), + "Error getting zhihe,gmacsys remap\n"); + } + return 0; +} + +static int zhihe_dwmac_peri_clk_enable(struct zhihe_dwmac *dwmac) +{ + int ret; + struct device *dev = dwmac->dev; + + ret = clk_prepare_enable(dwmac->gmac_aclk); + if (ret) { + dev_err(dev, "Failed to enable aclk clock\n"); + return ret; + } + + ret = clk_prepare_enable(dwmac->gmac_pclk); + if (ret) { + clk_disable_unprepare(dwmac->gmac_aclk); + dev_err(dev, "Failed to enable pclk clock\n"); + return ret; + } + + ret = clk_prepare_enable(dwmac->gmac_x2h_aclk); + if (ret) { + clk_disable_unprepare(dwmac->gmac_pclk); + clk_disable_unprepare(dwmac->gmac_aclk); + dev_err(dev, "Failed to enable x2h-aclk clock\n"); + return ret; + } + + ret = clk_prepare_enable(dwmac->gmac_x2h_hclk); + if (ret) { + clk_disable_unprepare(dwmac->gmac_x2h_aclk); + clk_disable_unprepare(dwmac->gmac_pclk); + clk_disable_unprepare(dwmac->gmac_aclk); + dev_err(dev, "Failed to enable x2h-hclk clock\n"); + return ret; + } + return ret; +} + +static void zhihe_dwmac_peri_clk_disable(struct zhihe_dwmac *dwmac) +{ + clk_disable_unprepare(dwmac->gmac_aclk); + clk_disable_unprepare(dwmac->gmac_pclk); + clk_disable_unprepare(dwmac->gmac_x2h_aclk); + clk_disable_unprepare(dwmac->gmac_x2h_hclk); +} + +/* STM platform Callback */ +static void plat_fix_mac_speed(void *priv, unsigned int speed, + unsigned int mode) +{ + struct zhihe_dwmac *dwmac = priv; + + zhihe_dwmac_set_speed(dwmac, speed); +} + +static int plat_clks_config(void *priv, bool enabled) +{ + struct zhihe_dwmac *dwmac = priv; + int ret; + + if (enabled) { + ret = zhihe_dwmac_peri_clk_enable(dwmac); + if (ret) + return ret; + + ret = reset_control_deassert(dwmac->plat_dat->stmmac_rst); + if (ret) + goto disable_clks; + + ret = reset_control_deassert(dwmac->plat_dat->stmmac_ahb_rst); + if (ret) + goto assert_stmmac_rst; + + zhihe_dwmac_clkctrl_enable(dwmac, true); + } else { + zhihe_dwmac_clkctrl_enable(dwmac, false); + reset_control_assert(dwmac->plat_dat->stmmac_ahb_rst); + reset_control_assert(dwmac->plat_dat->stmmac_rst); + zhihe_dwmac_peri_clk_disable(dwmac); + } + + return 0; + +assert_stmmac_rst: + reset_control_assert(dwmac->plat_dat->stmmac_rst); +disable_clks: + zhihe_dwmac_peri_clk_disable(dwmac); + + return ret; +} + +/* zhihe probe */ +static int zhihe_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct zhihe_dwmac *dwmac; + struct device *dev = &pdev->dev; + int ret; + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + return dev_err_probe(dev, ret, "Failed to set DMA mask\n"); + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get platform resources\n"); + + plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); + if (IS_ERR(plat_dat)) { + return dev_err_probe(dev, PTR_ERR(plat_dat), + "dt configuration failed\n"); + } + + dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) + return -ENOMEM; + + /* Init BSP priv data */ + dwmac->dev = &pdev->dev; + dwmac->plat_dat = plat_dat; + + /* Init Plat data */ + plat_dat->bsp_priv = dwmac; + plat_dat->fix_mac_speed = plat_fix_mac_speed; + plat_dat->clks_config = plat_clks_config; + + /* BSP clks & resets init */ + ret = zhihe_dwmac_peri_resource(dwmac); + if (ret) + goto err_remove_config_dt; + ret = zhihe_dwmac_peri_clk_enable(dwmac); + if (ret) + goto err_remove_config_dt; + + /* Plat probe + * "stmmaceth", "ahb" resets, hw init, caps config, pm init + */ + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) + goto err_clk_disable; + + return 0; + +err_clk_disable: + zhihe_dwmac_peri_clk_disable(dwmac); + +err_remove_config_dt: + stmmac_remove_config_dt(pdev, plat_dat); + + return ret; +} + +static const struct of_device_id zhihe_dwmac_match[] = { + { .compatible = "zhihe,a210-dwmac" }, + {} +}; +MODULE_DEVICE_TABLE(of, zhihe_dwmac_match); + +static struct platform_driver zhihe_dwmac_driver = { + .probe = zhihe_dwmac_probe, + .remove_new = stmmac_pltfr_remove, + .driver = { + .name = "zhihe-dwmac", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = of_match_ptr(zhihe_dwmac_match), + }, +}; +module_platform_driver(zhihe_dwmac_driver); + +MODULE_AUTHOR("ZHIHE"); +MODULE_DESCRIPTION("ZHIHE dwmac platform driver"); +MODULE_LICENSE("GPL"); From dffdc36c2f6662b8fba377f69bbb6c873f209b05 Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Fri, 3 Jul 2026 19:37:20 +0800 Subject: [PATCH 14/17] serial: 8250_dw: fix console hang on deferred probe re-registration When a UART port is deferred-probed (e.g. due to pinctrl dependencies), the re-registration path calls dw8250_set_termios() via register_console() -> console_call_setup() -> uart_set_options(). The original code unconditionally calls clk_disable_unprepare() which drops the enable count to zero, causing the clock framework to gate the UART hardware clock. Since the bootconsole (earlycon) is still actively writing to the same port, the MMIO access to the clock-gated peripheral causes a bus-level hang. Fix this by removing the disable/enable pair and only calling clk_set_rate() when the rate actually needs to change. For fixed-rate clock sources the rate never differs so clk_set_rate() is never called. Fixes: 4e26b134bd17 ("serial: 8250_dw: clock rate handling for all ACPI platforms") Signed-off-by: Zhiguo Zhu --- drivers/tty/serial/8250/8250_dw.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index a92432f8770d1..aac39dc22d104 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -385,9 +385,8 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, long rate; int ret; - clk_disable_unprepare(d->clk); rate = clk_round_rate(d->clk, newrate); - if (rate > 0) { + if (rate > 0 && rate != clk_get_rate(d->clk)) { /* * Note that any clock-notifer worker will block in * serial8250_update_uartclk() until we are done. @@ -396,7 +395,6 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, if (!ret) p->uartclk = rate; } - clk_prepare_enable(d->clk); dw8250_do_set_termios(p, termios, old); } From 423742b5ec90801c7f539e20d866bd483d2b3086 Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Jul 2026 10:39:13 +0800 Subject: [PATCH 15/17] soc: zhihe: add IOPMP driver Add the IO Physical Memory Protection (IOPMP) driver for the ZhiHe A210 SoC. The IOPMP controls peripheral DMA memory access permissions. The driver issues SBI extension calls (SBI_EXT_CONFIG_IOPMP) to configure protection rules from S-mode. Define the corresponding SBI extension ID and function IDs in asm/sbi.h. Signed-off-by: Zhiguo Zhu --- arch/riscv/include/asm/a210-iopmp.h | 21 +++++++++++ arch/riscv/include/asm/sbi.h | 6 +++ drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/zhihe/Kconfig | 15 ++++++++ drivers/soc/zhihe/Makefile | 2 + drivers/soc/zhihe/a210-iopmp.c | 57 +++++++++++++++++++++++++++++ 7 files changed, 103 insertions(+) create mode 100644 arch/riscv/include/asm/a210-iopmp.h create mode 100644 drivers/soc/zhihe/Kconfig create mode 100644 drivers/soc/zhihe/Makefile create mode 100644 drivers/soc/zhihe/a210-iopmp.c diff --git a/arch/riscv/include/asm/a210-iopmp.h b/arch/riscv/include/asm/a210-iopmp.h new file mode 100644 index 0000000000000..fee48194fd0e7 --- /dev/null +++ b/arch/riscv/include/asm/a210-iopmp.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * *** IMPORTANT *** + * This file is not only included from C-code but also from devicetree source + * files. As such this file MUST only contain comments and defines. + * + * Copyright (c) 2025 Xuliang Lin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef _A210_IOPMP_H +#define _A210_IOPMP_H + +long iopmp_enable(uint32_t *device_ids, uint32_t count); + +long iopmp_disable(uint32_t *device_ids, uint32_t count); + +#endif diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 6373d9f6ba5f4..eff08d19ac5d4 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -38,6 +38,7 @@ enum sbi_ext_id { SBI_EXT_SSE = 0x535345, SBI_EXT_FWFT = 0x46574654, SBI_EXT_MPXY = 0x4D505859, + SBI_EXT_CONFIG_IOPMP = 0x5A5A5A5A, /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START = 0x08000000, @@ -93,6 +94,11 @@ enum sbi_hsm_hart_state { SBI_HSM_STATE_RESUME_PENDING, }; +enum sbi_ext_config_iopmp_fid { + SBI_EXT_CONFIG_IOPMP_ADD_RULE = 0, + SBI_EXT_CONFIG_IOPMP_REMOVE_RULE, +}; + #define SBI_HSM_SUSP_BASE_MASK 0x7fffffff #define SBI_HSM_SUSP_NON_RET_BIT 0x80000000 #define SBI_HSM_SUSP_PLAT_BASE 0x10000000 diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 12d789a2e8c5a..b54e93944f7cb 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -33,5 +33,6 @@ source "drivers/soc/ux500/Kconfig" source "drivers/soc/versatile/Kconfig" source "drivers/soc/xilinx/Kconfig" source "drivers/soc/thead/Kconfig" +source "drivers/soc/zhihe/Kconfig" endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index f19f053b5404e..d757fcf26bd61 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -37,3 +37,4 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_PLAT_VERSATILE) += versatile/ obj-y += xilinx/ obj-y += thead/ +obj-y += zhihe/ diff --git a/drivers/soc/zhihe/Kconfig b/drivers/soc/zhihe/Kconfig new file mode 100644 index 0000000000000..1708ed3b3f25b --- /dev/null +++ b/drivers/soc/zhihe/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +menu "ZHIHE SoC drivers" + +config A210_IOPMP + tristate "ZhiHe A210 IOPMP support" + depends on ARCH_ZHIHE || COMPILE_TEST + default ARCH_ZHIHE + help + Say Y here to include support for zhihe iopmp found on + A210 fullmask devices. + To compile this driver as a module, choose M here: the module + will be called zh-iopmp. + +endmenu diff --git a/drivers/soc/zhihe/Makefile b/drivers/soc/zhihe/Makefile new file mode 100644 index 0000000000000..171b4fdc89d43 --- /dev/null +++ b/drivers/soc/zhihe/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_A210_IOPMP) += a210-iopmp.o diff --git a/drivers/soc/zhihe/a210-iopmp.c b/drivers/soc/zhihe/a210-iopmp.c new file mode 100644 index 0000000000000..05d5349cc9817 --- /dev/null +++ b/drivers/soc/zhihe/a210-iopmp.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +static long iopmp_ctrl(uint32_t *device_ids, uint32_t count, + int iopmp_ext_id, int fid) +{ + struct sbiret ret = {0}; + uint32_t *p_devices = device_ids; + + for (int i = 0; i < count; i += 5) { + uint32_t devices[5] = {0}; + uint32_t send_count = min((count - i), (uint32_t)5); + int j; + + for (j = 0; j < send_count; j++) + devices[j] = *(p_devices + j); + + ret = sbi_ecall(iopmp_ext_id, fid, send_count, + devices[0], devices[1], devices[2], + devices[3], devices[4]); + if (ret.error) + break; + + p_devices += send_count; + } + + return ret.error ? ret.error : ret.value; +} + +/** + * iopmp_enable - enable iopmp config for domain + * @device_ids: device id array + * @count: number of device ids + * + * Return: sbi_ecall result + */ +long iopmp_enable(uint32_t *device_ids, uint32_t count) +{ + return iopmp_ctrl(device_ids, count, SBI_EXT_CONFIG_IOPMP, + SBI_EXT_CONFIG_IOPMP_ADD_RULE); +} +EXPORT_SYMBOL(iopmp_enable); + +/** + * iopmp_disable - disable iopmp config for domain + * @device_ids: device id array + * @count: number of device ids + * + * Return: sbi_ecall result + */ +long iopmp_disable(uint32_t *device_ids, uint32_t count) +{ + return iopmp_ctrl(device_ids, count, SBI_EXT_CONFIG_IOPMP, + SBI_EXT_CONFIG_IOPMP_REMOVE_RULE); +} +EXPORT_SYMBOL(iopmp_disable); From 7b97db79b2074f3b5d01d6d00f737f4c55ba8089 Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Wed, 8 Apr 2026 20:29:47 +0800 Subject: [PATCH 16/17] riscv: dts: add ZhiHe A210 device tree support Add device tree files for the ZhiHe A210 SoC: - a210-soc-core.dtsi: CPU cluster, interrupt controller, memory, clocks, resets, and core bus infrastructure - a210-soc-peri.dtsi: peripheral devices (UART, SPI, I2C, etc.) - a210-evb.dts: A210 EVB (Evaluation Board) configuration - a210-dev.dts: A210 development board configuration The device tree describes the Always-On (AON) subsystem, power domains, pin controller, and all on-chip peripherals. Signed-off-by: Zhiguo Zhu --- arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/zhihe/Makefile | 3 + arch/riscv/boot/dts/zhihe/a210-dev.dts | 575 +++++++++ arch/riscv/boot/dts/zhihe/a210-evb.dts | 589 +++++++++ arch/riscv/boot/dts/zhihe/a210.dtsi | 1535 ++++++++++++++++++++++++ 5 files changed, 2703 insertions(+) create mode 100644 arch/riscv/boot/dts/zhihe/Makefile create mode 100644 arch/riscv/boot/dts/zhihe/a210-dev.dts create mode 100644 arch/riscv/boot/dts/zhihe/a210-evb.dts create mode 100644 arch/riscv/boot/dts/zhihe/a210.dtsi diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile index 8b16a3d7d6d58..fadcfe30d8bbb 100644 --- a/arch/riscv/boot/dts/Makefile +++ b/arch/riscv/boot/dts/Makefile @@ -9,5 +9,6 @@ subdir-y += spacemit subdir-y += starfive subdir-y += thead subdir-y += ultrarisc +subdir-y += zhihe obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y)) diff --git a/arch/riscv/boot/dts/zhihe/Makefile b/arch/riscv/boot/dts/zhihe/Makefile new file mode 100644 index 0000000000000..22f3b16152880 --- /dev/null +++ b/arch/riscv/boot/dts/zhihe/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +dtb-$(CONFIG_ARCH_ZHIHE) += a210-evb.dtb a210-dev.dtb diff --git a/arch/riscv/boot/dts/zhihe/a210-dev.dts b/arch/riscv/boot/dts/zhihe/a210-dev.dts new file mode 100644 index 0000000000000..f5e5ae3756862 --- /dev/null +++ b/arch/riscv/boot/dts/zhihe/a210-dev.dts @@ -0,0 +1,575 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/dts-v1/; + +#include "a210.dtsi" + +/ { + model = "Zhihe A210 Development Board"; + compatible = "zhihe,a210-dev", "zhihe,a210"; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + + gpio0 = &ao_gpio0; + gpio1 = &ao_gpio1; + gpio2 = &gpio0; + gpio3 = &gpio1; + gpio4 = &gpio2; + gpio5 = &gpio3; + gpio6 = &gpio4; + + mmc0 = &emmc; + mmc1 = &sdhci0; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; + serial8 = &uart8; + serial9 = &uart9; + }; +}; + +&peri1_padctrl { + gmac0_pins: gmac0-0 { + txclk-pins { + pins = "GPIO0_0", /* GMAC0_TX_CLK */ + "GPIO0_12"; /* GMAC0_MDC */ + function = "gmac0"; + bias-disable; + drive-strength = <13>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + tx-pins { + pins = "GPIO0_2", /* GMAC0_TXEN */ + "GPIO0_3", /* GMAC0_TXD0 */ + "GPIO0_4", /* GMAC0_TXD1 */ + "GPIO0_5", /* GMAC0_TXD2 */ + "GPIO0_6"; /* GMAC0_TXD3 */ + function = "gmac0"; + bias-disable; + drive-strength = <20>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO0_1", /* GMAC0_RX_CLK */ + "GPIO0_7", /* GMAC0_RXDV */ + "GPIO0_8", /* GMAC0_RXD0 */ + "GPIO0_9", /* GMAC0_RXD1 */ + "GPIO0_10", /* GMAC0_RXD2 */ + "GPIO0_11", /* GMAC0_RXD3 */ + "GPIO0_13"; /* GMAC0_MDIO */ + function = "gmac0"; + bias-disable; + drive-strength = <13>; + input-enable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + uart3_pins: uart3-0 { + tx-pins { + pins = "GPIO0_3", "GPIO0_6"; /* TXD, RTSN */ + function = "uart3"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO0_4", "GPIO0_5"; /* RXD, CTSN */ + function = "uart3"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart0_pins: uart0-0 { + tx-pins { + pins = "GPIO0_14", "GPIO0_17"; /* TXD, RTSN */ + function = "uart0"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO0_15", "GPIO0_16"; /* RXD, CTSN */ + function = "uart0"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart1_pins: uart1-1 { + tx-pins { + pins = "GPIO0_28", "GPIO0_31"; /* TXD, RTSN */ + function = "uart1"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO0_29", "GPIO0_30"; /* RXD, CTSN */ + function = "uart1"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + gmac1_pins: gmac1-0 { + txclk-pins { + pins = "GPIO1_2", /* GMAC1_TX_CLK */ + "GPIO1_14"; /* GMAC1_MDC */ + function = "gmac1"; + bias-disable; + drive-strength = <13>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + tx-pins { + pins = "GPIO1_4", /* GMAC1_TXEN */ + "GPIO1_5", /* GMAC1_TXD0 */ + "GPIO1_6", /* GMAC1_TXD1 */ + "GPIO1_7", /* GMAC1_TXD2 */ + "GPIO1_8"; /* GMAC1_TXD3 */ + function = "gmac1"; + bias-disable; + drive-strength = <20>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + rx-pins { + pins = "GPIO1_3", /* GMAC1_RX_CLK */ + "GPIO1_9", /* GMAC1_RXDV */ + "GPIO1_10", /* GMAC1_RXD0 */ + "GPIO1_11", /* GMAC1_RXD1 */ + "GPIO1_12", /* GMAC1_RXD2 */ + "GPIO1_13", /* GMAC1_RXD3 */ + "GPIO1_15"; /* GMAC1_MDIO */ + function = "gmac1"; + bias-disable; + drive-strength = <13>; + input-enable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + uart2_pins: uart2-0 { + tx-pins { + pins = "GPIO1_1"; + function = "uart2"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO1_0"; + function = "uart2"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + sdhci_pins: sdhci0-1 { + sd-pins { + pins = "GPIO1_1"; + function = "sdio"; + bias-disable; + drive-strength = <13>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; +}; + +&peri2_padctrl { + uart4_pins: uart4-0 { + tx-pins { + pins = "GPIO2_0"; + function = "uart4"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_1"; + function = "uart4"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart5_pins: uart5-0 { + tx-pins { + pins = "GPIO2_2"; + function = "uart5"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_3"; + function = "uart5"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart6_pins: uart6-0 { + tx-pins { + pins = "GPIO2_4", "GPIO2_9"; /* TXD, RTSN */ + function = "uart6"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_5", "GPIO2_8"; /* RXD, CTSN */ + function = "uart6"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart7_pins: uart7-0 { + tx-pins { + pins = "GPIO2_6"; + function = "uart7"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_7"; + function = "uart7"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart9_pins: uart9-0 { + tx-pins { + pins = "GPIO2_10"; + function = "uart9"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_11"; + function = "uart9"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + sen_vclk_pin0: sen-vclk0 { + sen-vclk0-pins { + pins = "GPIO3_0"; + function = "sen_vclk"; + bias-disable; + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + sen_vclk_pin1: sen-vclk1 { + sen-vclk1-pins { + pins = "GPIO3_1"; + function = "sen_vclk"; + bias-disable; + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart8_pins: uart8-1 { + tx-pins { + pins = "GPIO3_2"; + function = "uart8"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO3_3"; + function = "uart8"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; +}; + +&gmac0 { + phy-mode = "rgmii-id"; + pinctrl-names = "default"; + pinctrl-0 = <&gmac0_pins>; + rx-clk-delay = <0x00>; /* for RGMII */ + tx-clk-delay = <0x00>; /* for RGMII */ + phy-handle = <&phy0>; +}; + +&mdio0 { + phy0: ethernet-phy@0 { + reg = <0x0>; + }; +}; + +&gmac1 { + phy-mode = "rgmii-id"; + pinctrl-names = "default"; + pinctrl-0 = <&gmac1_pins>; + phy-handle = <&phy1>; +}; + +&mdio1 { + phy1: ethernet-phy@0 { + reg = <0x0>; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins>; +}; + +&uart7 { + pinctrl-names = "default"; + pinctrl-0 = <&uart7_pins>; +}; + +&uart8 { + pinctrl-names = "default"; + pinctrl-0 = <&uart8_pins>; +}; + +&emmc { + max-frequency = <196608000>; + non-removable; + mmc-hs400-enhanced-strobe; + mmc-hs400-1_8v; + mmc-hs200-1_8v; + no-sdio; + no-sd; + bus-width = <8>; + cap-mmc-highspeed; +}; + +&sdhci0 { + pinctrl-names = "default"; + pinctrl-0 = <&sdhci_pins>; + max-frequency = <196608000>; + cap-sd-highspeed; + bus-width = <4>; + sd-uhs-sdr104; + no-sdio; + disable-wp; +}; + +/* + * UART0 is the default EVB jumper configuration on this expansion header. + * It shares pins with I2S0/SATA P1; changing the jumpers to another + * function requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_05 -> 0 + * GPMUX_SEL_06 -> 0 + */ +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +}; + +/* + * UART1 is the default EVB jumper configuration on this expansion header. + * It shares pins with SPI0/PCIe x4; changing the jumpers to another + * function requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_07 -> 0 + * GPMUX_SEL_08 -> 0 + */ +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; +}; + +/* + * UART5 is the default EVB jumper configuration on this expansion header. + * It shares pins with I2C5/I2S1; changing the jumpers to another function + * requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_00 -> 0 + */ +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&uart5_pins>; +}; + +/* + * UART6 is the default EVB jumper configuration on this expansion header. + * It shares pins with I2C6/I2S1; changing the jumpers to another function + * requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_00 -> 0 + * GPMUX_SEL_03 -> 0 + */ +&uart6 { + pinctrl-names = "default"; + pinctrl-0 = <&uart6_pins>; +}; + +/* + * UART9 is the default EVB jumper configuration on this expansion header. + * It shares pins with I2C7/I2S2; changing the jumpers to another function + * requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_01 -> 0 + */ +&uart9 { + pinctrl-names = "default"; + pinctrl-0 = <&uart9_pins>; +}; + +&cluster0_opp { + opp0-500000000 { + opp-microvolt = <1000000>; + }; + opp0-1200000000 { + opp-microvolt = <1000000>; + }; + opp0-1500000000 { + opp-microvolt = <1000000>; + }; + opp0-1698000000 { + opp-microvolt = <1000000>; + }; + opp0-1896000000 { + opp-microvolt = <1000000>; + }; +}; + +&cluster1_opp { + opp1-500000000 { + opp-microvolt = <1000000>; + }; + opp1-1698000000 { + opp-microvolt = <1000000>; + }; + opp1-1896000000 { + opp-microvolt = <1000000>; + }; + opp1-2298000000 { + opp-microvolt = <1000000>; + }; +}; + +&uart0 { + status = "disabled"; +}; + +&uart1 { + status = "disabled"; +}; + +&uart2 { + status = "disabled"; +}; + +&uart3 { + status = "disabled"; +}; + +&uart6 { + status = "disabled"; +}; + +&uart7 { + status = "disabled"; +}; + +&uart9 { + status = "disabled"; +}; + +&dmac1 { + status = "disabled"; +}; diff --git a/arch/riscv/boot/dts/zhihe/a210-evb.dts b/arch/riscv/boot/dts/zhihe/a210-evb.dts new file mode 100644 index 0000000000000..3d4366d8c6d73 --- /dev/null +++ b/arch/riscv/boot/dts/zhihe/a210-evb.dts @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/dts-v1/; + +#include "a210.dtsi" + +/ { + model = "A210 EVB configuration"; + compatible = "zhihe,a210-evb", "zhihe,a210"; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + + mmc0 = &emmc; + mmc1 = &sdhci0; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; + serial8 = &uart8; + serial9 = &uart9; + }; +}; + +&peri1_padctrl { + gmac0_pins: gmac0-0 { + txclk-pins { + pins = "GPIO0_0", /* GMAC0_TX_CLK */ + "GPIO0_12"; /* GMAC0_MDC */ + function = "gmac0"; + bias-disable; + drive-strength = <13>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + tx-pins { + pins = "GPIO0_2", /* GMAC0_TXEN */ + "GPIO0_3", /* GMAC0_TXD0 */ + "GPIO0_4", /* GMAC0_TXD1 */ + "GPIO0_5", /* GMAC0_TXD2 */ + "GPIO0_6"; /* GMAC0_TXD3 */ + function = "gmac0"; + bias-disable; + drive-strength = <20>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO0_1", /* GMAC0_RX_CLK */ + "GPIO0_7", /* GMAC0_RXDV */ + "GPIO0_8", /* GMAC0_RXD0 */ + "GPIO0_9", /* GMAC0_RXD1 */ + "GPIO0_10", /* GMAC0_RXD2 */ + "GPIO0_11", /* GMAC0_RXD3 */ + "GPIO0_13"; /* GMAC0_MDIO */ + function = "gmac0"; + bias-disable; + drive-strength = <13>; + input-enable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + uart3_pins: uart3-0 { + tx-pins { + pins = "GPIO0_3", "GPIO0_6"; /* TXD, RTSN */ + function = "uart3"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO0_4", "GPIO0_5"; /* RXD, CTSN */ + function = "uart3"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart0_pins: uart0-0 { + tx-pins { + pins = "GPIO0_14", "GPIO0_17"; /* TXD, RTSN */ + function = "uart0"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO0_15", "GPIO0_16"; /* RXD, CTSN */ + function = "uart0"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart1_pins: uart1-1 { + tx-pins { + pins = "GPIO0_28", "GPIO0_31"; /* TXD, RTSN */ + function = "uart1"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO0_29", "GPIO0_30"; /* RXD, CTSN */ + function = "uart1"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + gmac1_pins: gmac1-0 { + txclk-pins { + pins = "GPIO1_2", /* GMAC1_TX_CLK */ + "GPIO1_14"; /* GMAC1_MDC */ + function = "gmac1"; + bias-disable; + drive-strength = <13>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + tx-pins { + pins = "GPIO1_4", /* GMAC1_TXEN */ + "GPIO1_5", /* GMAC1_TXD0 */ + "GPIO1_6", /* GMAC1_TXD1 */ + "GPIO1_7", /* GMAC1_TXD2 */ + "GPIO1_8"; /* GMAC1_TXD3 */ + function = "gmac1"; + bias-disable; + drive-strength = <20>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + rx-pins { + pins = "GPIO1_3", /* GMAC1_RX_CLK */ + "GPIO1_9", /* GMAC1_RXDV */ + "GPIO1_10", /* GMAC1_RXD0 */ + "GPIO1_11", /* GMAC1_RXD1 */ + "GPIO1_12", /* GMAC1_RXD2 */ + "GPIO1_13", /* GMAC1_RXD3 */ + "GPIO1_15"; /* GMAC1_MDIO */ + function = "gmac1"; + bias-disable; + drive-strength = <13>; + input-enable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + uart2_pins: uart2-0 { + tx-pins { + pins = "GPIO1_1"; + function = "uart2"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO1_0"; + function = "uart2"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + sdhci_pins: sdhci0-1 { + sd-pins { + pins = "GPIO1_1"; + function = "sdio"; + bias-disable; + drive-strength = <13>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; +}; + +&peri2_padctrl { + uart4_pins: uart4-0 { + tx-pins { + pins = "GPIO2_0"; + function = "uart4"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_1"; + function = "uart4"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart5_pins: uart5-0 { + tx-pins { + pins = "GPIO2_2"; + function = "uart5"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_3"; + function = "uart5"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart6_pins: uart6-0 { + tx-pins { + pins = "GPIO2_4", "GPIO2_9"; /* TXD, RTSN */ + function = "uart6"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_5", "GPIO2_8"; /* RXD, CTSN */ + function = "uart6"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart7_pins: uart7-0 { + tx-pins { + pins = "GPIO2_6"; + function = "uart7"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_7"; + function = "uart7"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart9_pins: uart9-0 { + tx-pins { + pins = "GPIO2_10"; + function = "uart9"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_11"; + function = "uart9"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + sen_vclk_pin0: sen-vclk0 { + sen-vclk0-pins { + pins = "GPIO3_0"; + function = "sen_vclk"; + bias-disable; + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + sen_vclk_pin1: sen-vclk1 { + sen-vclk1-pins { + pins = "GPIO3_1"; + function = "sen_vclk"; + bias-disable; + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + uart8_pins: uart8-1 { + tx-pins { + pins = "GPIO3_2"; + function = "uart8"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO3_3"; + function = "uart8"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; +}; + +&gmac0 { + phy-mode = "rgmii-id"; + pinctrl-names = "default"; + pinctrl-0 = <&gmac0_pins>; + rx-clk-delay = <0x00>; /* for RGMII */ + tx-clk-delay = <0x00>; /* for RGMII */ + phy-handle = <&phy0>; +}; + +&mdio0 { + phy0: ethernet-phy@0 { + reg = <0x0>; + }; +}; + +&gmac1 { + phy-mode = "rgmii-id"; + pinctrl-names = "default"; + pinctrl-0 = <&gmac1_pins>; + phy-handle = <&phy1>; +}; + +&mdio1 { + phy1: ethernet-phy@0 { + reg = <0x0>; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins>; +}; + +&uart7 { + pinctrl-names = "default"; + pinctrl-0 = <&uart7_pins>; +}; + +&uart8 { + pinctrl-names = "default"; + pinctrl-0 = <&uart8_pins>; +}; + +&emmc { + max-frequency = <196608000>; + non-removable; + mmc-hs400-enhanced-strobe; + mmc-hs400-1_8v; + mmc-hs200-1_8v; + no-sdio; + no-sd; + bus-width = <8>; + cap-mmc-highspeed; +}; + +&sdhci0 { + pinctrl-names = "default"; + pinctrl-0 = <&sdhci_pins>; + max-frequency = <196608000>; + cap-sd-highspeed; + bus-width = <4>; + sd-uhs-sdr104; + no-sdio; + disable-wp; +}; + +/* + * UART0 is the default EVB jumper configuration on this expansion header. + * It shares pins with I2S0/SATA P1; changing the jumpers to another + * function requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_05 -> 0 + * GPMUX_SEL_06 -> 0 + */ +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +}; + +/* + * UART1 is the default EVB jumper configuration on this expansion header. + * It shares pins with SPI0/PCIe x4; changing the jumpers to another + * function requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_07 -> 0 + * GPMUX_SEL_08 -> 0 + */ +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; +}; + +/* + * UART5 is the default EVB jumper configuration on this expansion header. + * It shares pins with I2C5/I2S1; changing the jumpers to another function + * requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_00 -> 0 + */ +&uart5 { + pinctrl-names = "default"; + pinctrl-0 = <&uart5_pins>; +}; + +/* + * UART6 is the default EVB jumper configuration on this expansion header. + * It shares pins with I2C6/I2S1; changing the jumpers to another function + * requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_00 -> 0 + * GPMUX_SEL_03 -> 0 + */ +&uart6 { + pinctrl-names = "default"; + pinctrl-0 = <&uart6_pins>; +}; + +/* + * UART9 is the default EVB jumper configuration on this expansion header. + * It shares pins with I2C7/I2S2; changing the jumpers to another function + * requires a board-specific DTS or local modification. + * + * Default jumper setting: + * GPMUX_SEL_01 -> 0 + */ +&uart9 { + pinctrl-names = "default"; + pinctrl-0 = <&uart9_pins>; +}; + +&cluster0_opp { + opp0-500000000 { + opp-microvolt = <1000000>; + }; + opp0-1200000000 { + opp-microvolt = <1000000>; + }; + opp0-1500000000 { + opp-microvolt = <1000000>; + }; + opp0-1698000000 { + opp-microvolt = <1000000>; + }; + opp0-1896000000 { + opp-microvolt = <1000000>; + }; +}; + +&cluster1_opp { + opp1-500000000 { + opp-microvolt = <1000000>; + }; + opp1-1698000000 { + opp-microvolt = <1000000>; + }; + opp1-1896000000 { + opp-microvolt = <1000000>; + }; + opp1-2298000000 { + opp-microvolt = <1000000>; + }; +}; + +&uart0 { + status = "disabled"; +}; + +&uart1 { + status = "disabled"; +}; + +&uart2 { + status = "disabled"; +}; + +&uart3 { + status = "disabled"; +}; + +&uart5 { + status = "disabled"; +}; + +&uart6 { + status = "disabled"; +}; + +&uart7 { + status = "disabled"; +}; + +&uart8 { + status = "disabled"; +}; + +&uart9 { + status = "disabled"; +}; + +&peri3_padctrl { + status = "disabled"; +}; + +&gpio4 { + status = "disabled"; +}; + +&dmac1 { + status = "disabled"; +}; diff --git a/arch/riscv/boot/dts/zhihe/a210.dtsi b/arch/riscv/boot/dts/zhihe/a210.dtsi new file mode 100644 index 0000000000000..5ddf3e05016f8 --- /dev/null +++ b/arch/riscv/boot/dts/zhihe/a210.dtsi @@ -0,0 +1,1535 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include + +/ { + compatible = "zhihe,a210"; + #address-cells = <2>; + #size-cells = <2>; + + /* The actual capacity will be adjusted through SPL */ + memory@0 { + device_type = "memory"; + reg = <0x00 0x80000000 0x01 0x00000000>; /* 4G */ + numa-node-id = <0>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x00 0x40000000>; + alloc-ranges = <0x00 0x90000000 0x00 0x40000000>; + linux,cma-default; + }; + + memory@1c000000 { + reg = <0x00 0x1c000000 0x00 0x2000000>; + no-map; + }; + + framebuffer: framebuffer@10000000 { + reg = <0x01 0x00 0x00 0x5000000>; + no-map; + }; + }; + + /* The bootargs in U-Boot will override the configuration set here. */ + chosen { + stdout-path = "serial4"; + }; + + reg_vref_1v8: regulator-adc-verf { + compatible = "regulator-fixed"; + regulator-name = "vref-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <24000000>; /*24M*/ + c908_0: cpu@0 { + device_type = "cpu"; + reg = <0>; + compatible = "riscv"; + riscv,isa = "rv64imac"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", + "zicntr", "zicsr", "zifencei", "zihpm", + "zba", "zbb", "zbc", "zbs", + "zicbom", "zicbop", "zicboz", + "svpbmt", "sscofpmf"; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + riscv,cbop-block-size = <64>; + mmu-type = "riscv,sv39"; + cpu-freq = "1.9Ghz"; + i-cache-block-size = <64>; + i-cache-size = <32768>; + i-cache-sets = <256>; + d-cache-block-size = <64>; + d-cache-size = <32768>; + d-cache-sets = <256>; + next-level-cache = <&c0_l2_cache>; + cpu-tlb = "1024 4-ways"; + cpu-vector = "1.0"; + capacity-dmips-mhz = <768>; + clocks = <&clk C908_CPU_TO_CDE_CLK_MUX>; + operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; + numa-node-id = <0>; + status = "okay"; + cpu0_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + c908_1: cpu@1 { + device_type = "cpu"; + reg = <1>; + compatible = "riscv"; + riscv,isa = "rv64imac"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", + "zicntr", "zicsr", "zifencei", "zihpm", + "zba", "zbb", "zbc", "zbs", + "zicbom", "zicbop", "zicboz", + "svpbmt", "sscofpmf"; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + riscv,cbop-block-size = <64>; + mmu-type = "riscv,sv39"; + cpu-freq = "1.9Ghz"; + i-cache-block-size = <64>; + i-cache-size = <32768>; + i-cache-sets = <256>; + d-cache-block-size = <64>; + d-cache-size = <32768>; + d-cache-sets = <256>; + next-level-cache = <&c0_l2_cache>; + cpu-tlb = "1024 4-ways"; + cpu-vector = "1.0"; + capacity-dmips-mhz = <768>; + operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; + numa-node-id = <0>; + status = "okay"; + cpu1_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + c908_2: cpu@2 { + device_type = "cpu"; + reg = <2>; + compatible = "riscv"; + riscv,isa = "rv64imac"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", + "zicntr", "zicsr", "zifencei", "zihpm", + "zba", "zbb", "zbc", "zbs", + "zicbom", "zicbop", "zicboz", + "svpbmt", "sscofpmf"; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + riscv,cbop-block-size = <64>; + mmu-type = "riscv,sv39"; + cpu-freq = "1.9Ghz"; + i-cache-block-size = <64>; + i-cache-size = <32768>; + i-cache-sets = <256>; + d-cache-block-size = <64>; + d-cache-size = <32768>; + d-cache-sets = <256>; + next-level-cache = <&c0_l2_cache>; + cpu-tlb = "1024 4-ways"; + cpu-vector = "1.0"; + capacity-dmips-mhz = <768>; + operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; + numa-node-id = <0>; + status = "okay"; + cpu2_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + c908_3: cpu@3 { + device_type = "cpu"; + reg = <3>; + compatible = "riscv"; + riscv,isa = "rv64imac"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", + "zicntr", "zicsr", "zifencei", "zihpm", + "zba", "zbb", "zbc", "zbs", + "zicbom", "zicbop", "zicboz", + "svpbmt", "sscofpmf"; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + riscv,cbop-block-size = <64>; + mmu-type = "riscv,sv39"; + cpu-freq = "1.9Ghz"; + i-cache-block-size = <64>; + i-cache-size = <32768>; + i-cache-sets = <256>; + d-cache-block-size = <64>; + d-cache-size = <32768>; + d-cache-sets = <256>; + next-level-cache = <&c0_l2_cache>; + cpu-tlb = "1024 4-ways"; + cpu-vector = "1.0"; + capacity-dmips-mhz = <768>; + operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; + numa-node-id = <0>; + status = "okay"; + cpu3_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + + c920_4: cpu@4 { + device_type = "cpu"; + reg = <4>; + compatible = "riscv"; + riscv,isa = "rv64imac"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", + "zicntr", "zicsr", "zifencei", "zihpm", + "zba", "zbb", "zbc", "zbs", + "zicbom", "zicbop", "zicboz", + "svpbmt", "sscofpmf"; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + riscv,cbop-block-size = <64>; + mmu-type = "riscv,sv39"; + cpu-freq = "2.3Ghz"; + i-cache-block-size = <64>; + i-cache-size = <65536>; + i-cache-sets = <512>; + d-cache-block-size = <64>; + d-cache-size = <65536>; + d-cache-sets = <512>; + next-level-cache = <&c1_l2_cache>; + cpu-tlb = "1024 4-ways"; + cpu-vector = "1.0"; + capacity-dmips-mhz = <1024>; + clocks = <&clk C920_CPU_TO_CDE_CLK_MUX>; + operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; + numa-node-id = <0>; + status = "okay"; + cpu4_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + c920_5: cpu@5 { + device_type = "cpu"; + reg = <5>; + compatible = "riscv"; + riscv,isa = "rv64imac"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", + "zicntr", "zicsr", "zifencei", "zihpm", + "zba", "zbb", "zbc", "zbs", + "zicbom", "zicbop", "zicboz", + "svpbmt", "sscofpmf"; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + riscv,cbop-block-size = <64>; + mmu-type = "riscv,sv39"; + cpu-freq = "2.3Ghz"; + i-cache-block-size = <64>; + i-cache-size = <65536>; + i-cache-sets = <512>; + d-cache-block-size = <64>; + d-cache-size = <65536>; + d-cache-sets = <512>; + next-level-cache = <&c1_l2_cache>; + cpu-tlb = "1024 4-ways"; + cpu-vector = "1.0"; + capacity-dmips-mhz = <1024>; + operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; + numa-node-id = <0>; + status = "okay"; + cpu5_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + c920_6: cpu@6 { + device_type = "cpu"; + reg = <6>; + compatible = "riscv"; + riscv,isa = "rv64imac"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", + "zicntr", "zicsr", "zifencei", "zihpm", + "zba", "zbb", "zbc", "zbs", + "zicbom", "zicbop", "zicboz", + "svpbmt", "sscofpmf"; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + riscv,cbop-block-size = <64>; + mmu-type = "riscv,sv39"; + cpu-freq = "2.3Ghz"; + i-cache-block-size = <64>; + i-cache-size = <65536>; + i-cache-sets = <512>; + d-cache-block-size = <64>; + d-cache-size = <65536>; + d-cache-sets = <512>; + next-level-cache = <&c1_l2_cache>; + cpu-tlb = "1024 4-ways"; + cpu-vector = "1.0"; + capacity-dmips-mhz = <1024>; + operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; + numa-node-id = <0>; + status = "okay"; + cpu6_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + c920_7: cpu@7 { + device_type = "cpu"; + reg = <7>; + compatible = "riscv"; + riscv,isa = "rv64imac"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", + "zicntr", "zicsr", "zifencei", "zihpm", + "zba", "zbb", "zbc", "zbs", + "zicbom", "zicbop", "zicboz", + "svpbmt", "sscofpmf"; + riscv,cbom-block-size = <64>; + riscv,cboz-block-size = <64>; + riscv,cbop-block-size = <64>; + mmu-type = "riscv,sv39"; + cpu-freq = "2.3Ghz"; + i-cache-block-size = <64>; + i-cache-size = <65536>; + i-cache-sets = <512>; + d-cache-block-size = <64>; + d-cache-size = <65536>; + d-cache-sets = <512>; + next-level-cache = <&c1_l2_cache>; + cpu-tlb = "1024 4-ways"; + cpu-vector = "1.0"; + capacity-dmips-mhz = <1024>; + operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; + numa-node-id = <0>; + status = "okay"; + cpu7_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + + c0_l2_cache: c0_l2-cache { + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <524288>; + cache-sets = <512>; + cache-unified; + }; + c1_l2_cache: c1_l2-cache { + compatible = "cache"; + cache-block-size = <64>; + cache-level = <2>; + cache-size = <1048576>; + cache-sets = <1024>; + cache-unified; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&c908_0>; + }; + + core1 { + cpu = <&c908_1>; + }; + + core2 { + cpu = <&c908_2>; + }; + + core3 { + cpu = <&c908_3>; + }; + }; + cluster1 { + core0 { + cpu = <&c920_4>; + }; + + core1 { + cpu = <&c920_5>; + }; + + core2 { + cpu = <&c920_6>; + }; + + core3 { + cpu = <&c920_7>; + }; + }; + }; + + idle_states: idle-states { + CPU_RET_0_0: cpu-retentive-0-0 { + compatible = "riscv,idle-state"; + riscv,sbi-suspend-param = <0x10000000>; + entry-latency-us = <20>; + exit-latency-us = <40>; + min-residency-us = <80>; + }; + + CPU_NONRET_0_0: cpu-nonretentive-0-0 { + compatible = "riscv,idle-state"; + riscv,sbi-suspend-param = <0x90000000>; + entry-latency-us = <250>; + exit-latency-us = <500>; + min-residency-us = <950>; + }; + + CLUSTER_RET_0: cluster-retentive-0 { + compatible = "riscv,idle-state"; + riscv,sbi-suspend-param = <0x11000000>; + local-timer-stop; + entry-latency-us = <50>; + exit-latency-us = <100>; + min-residency-us = <250>; + wakeup-latency-us = <130>; + }; + + CLUSTER_NONRET_0: cluster-nonretentive-0 { + compatible = "riscv,idle-state"; + riscv,sbi-suspend-param = <0x91000000>; + local-timer-stop; + entry-latency-us = <600>; + exit-latency-us = <1100>; + min-residency-us = <2700>; + wakeup-latency-us = <1500>; + }; + }; + }; + + cluster0_opp: opp-table-cluster0 { + compatible = "operating-points-v2"; + opp-shared; + opp0-500000000 { + opp-hz = /bits/ 64 <500000000>; + bus-clk-hz = /bits/ 64 <196608000>; + pic-clk-hz = /bits/ 64 <250000000>; + cfg-clk-hz = /bits/ 64 <110000000>; + com-clk-hz = /bits/ 64 <82500000>; + apb-clk-hz = /bits/ 64 <82500000>; + opp-microvolt = <700000 800000>; + }; + opp0-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + bus-clk-hz = /bits/ 64 <660000000>; + pic-clk-hz = /bits/ 64 <500000000>; + cfg-clk-hz = /bits/ 64 <220000000>; + com-clk-hz = /bits/ 64 <165000000>; + apb-clk-hz = /bits/ 64 <165000000>; + opp-microvolt = <700000 800000>; + }; + opp0-1500000000 { + opp-hz = /bits/ 64 <1500000000>; + bus-clk-hz = /bits/ 64 <1000000000>; + pic-clk-hz = /bits/ 64 <1000000000>; + cfg-clk-hz = /bits/ 64 <330000000>; + com-clk-hz = /bits/ 64 <165000000>; + apb-clk-hz = /bits/ 64 <165000000>; + opp-microvolt = <800000 800000>; + }; + opp0-1698000000 { + opp-hz = /bits/ 64 <1698000000>; + bus-clk-hz = /bits/ 64 <1100000000>; + pic-clk-hz = /bits/ 64 <1000000000>; + cfg-clk-hz = /bits/ 64 <330000000>; + com-clk-hz = /bits/ 64 <165000000>; + apb-clk-hz = /bits/ 64 <165000000>; + opp-microvolt = <900000 900000>; + }; + opp0-1896000000 { + opp-hz = /bits/ 64 <1896000000>; + bus-clk-hz = /bits/ 64 <1320000000>; + pic-clk-hz = /bits/ 64 <1000000000>; + cfg-clk-hz = /bits/ 64 <330000000>; + com-clk-hz = /bits/ 64 <165000000>; + apb-clk-hz = /bits/ 64 <165000000>; + opp-microvolt = <1000000 1000000>; + }; + }; + + cluster1_opp: opp-table-cluster1 { + compatible = "operating-points-v2"; + opp-shared; + opp1-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <800000>; + }; + opp1-1698000000 { + opp-hz = /bits/ 64 <1698000000>; + opp-microvolt = <900000>; + }; + opp1-1896000000 { + opp-hz = /bits/ 64 <1896000000>; + opp-microvolt = <1000000>; + }; + opp1-2298000000 { + opp-hz = /bits/ 64 <2298000000>; + opp-microvolt = <1000000>; + turbo-mode; + }; + }; + + pmu { + compatible = "riscv,pmu"; + riscv,event-to-mhpmevent = + /* PMU_HW_CPU_CYCLES:1 */ + <0x00001 0x00000000 0x00000000>, + /* PMU_HW_INSTRUCTIONS:2 */ + <0x00002 0x00000000 0x00000000>, + /* PMU_HW_CACHE_REFERENCES:3 */ + /* PMU_HW_CACHE_MISSES:4 */ + /* PMU_HW_BRANCH_INSTRUCTIONS:5 */ + <0x00005 0x00000000 0x00000007>, + /* PMU_HW_BRANCH_MISSES:6 */ + <0x00006 0x00000000 0x00000006>, + /* PMU_HW_BUS_CYCLES:7 */ + /* PMU_HW_STALLED_CYCLES_FRONTEND:8 */ + <0x00008 0x00000000 0x00000027>, + /* PMU_HW_STALLED_CYCLES_BACKEND:9 */ + <0x00009 0x00000000 0x00000028>, + /* PMU_HW_REF_CPU_CYCLES:10 */ + /* L1D_READ_ACCESS:0x10000 */ + <0x10000 0x00000000 0x0000000c>, + /* L1D_READ_MISS:0x10001 */ + <0x10001 0x00000000 0x0000000d>, + /* L1D_WRITE_ACCESS:0x10002 */ + <0x10002 0x00000000 0x0000000e>, + /* L1D_WRITE_MISS:0x10003 */ + <0x10003 0x00000000 0x0000000f>, + /* L1I_READ_ACCESS:0x10008 */ + <0x10008 0x00000000 0x00000001>, + /* L1I_READ_MISS:0x10009 */ + <0x10009 0x00000000 0x00000002>, + /* dTLB read miss :0x10019 */ + <0x10019 0x00000000 0x00000004>, + /* iTLB read miss :0x10021 */ + <0x10021 0x00000000 0x00000003>; + /* LL_READ_ACCESS:0x10010 */ + /* LL_READ_MISS:0x10011 */ + /* LL_WRITE_ACCESS:0x10012 */ + /* LL_WRITE_MISS:0x10013 */ + /* BPU_READ_ACCESS:0x10028 */ + /* BPU_READ_MISS:0x10029 */ + riscv,event-to-mhpmcounters = + /* 31 mhpmcounters, bitmap 0xfffffff8 */ + <0x00001 0x00001 0x00000001>, + <0x00002 0x00002 0x00000004>, + <0x00005 0x00005 0xfffffff8>, + <0x00006 0x00006 0xfffffff8>, + <0x00008 0x00008 0xfffffff8>, + <0x00009 0x00009 0xfffffff8>, + <0x10000 0x10000 0xfffffff8>, + <0x10001 0x10001 0xfffffff8>, + <0x10002 0x10002 0xfffffff8>, + <0x10003 0x10003 0xfffffff8>, + <0x10008 0x10008 0xfffffff8>, + <0x10009 0x10009 0xfffffff8>, + <0x10019 0x10019 0xfffffff8>, + <0x10021 0x10021 0xfffffff8>; + riscv,raw-event-to-mhpmcounters = + /* For raw event ID 0x0 - 0xff */ + <0x0 0x0 0xffffffff 0xffffff00 0xfffffff8>; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + dma-noncoherent; + + /* OPENSBI */ + reset: reset-sample { + compatible = "zhihe,a210-reset-sample"; + reg = <0x00 0x00 0x00 0x00>; + plic-delegate = <0x00 0x181ffffc>; /* PLIC_CTRL */ + /* SYSREG set rst boot address */ + entry-reg = <0x00 0x10148040 0x00 0x10148060>; + /* The number of CPUs in each cluster */ + entry-cnt = <4 4>; + control-reg = <0x00 0x10144004 0x00 0x10144008>;/* SWRST C908 C920*/ + control-val = <0x1f 0x1f>; /* bit0:clust, bit1~4:core0~core3 */ + }; + + clint0: clint@1c000000 { + compatible = "riscv,clint0"; + interrupts-extended = < + &cpu0_intc 3 &cpu0_intc 7 + &cpu1_intc 3 &cpu1_intc 7 + &cpu2_intc 3 &cpu2_intc 7 + &cpu3_intc 3 &cpu3_intc 7 + &cpu4_intc 3 &cpu4_intc 7 + &cpu5_intc 3 &cpu5_intc 7 + &cpu6_intc 3 &cpu6_intc 7 + &cpu7_intc 3 &cpu7_intc 7 + >; + reg = <0x00 0x1c000000 0x0 0x0000d000>; + clint,has-no-64bit-mmio; + }; + + clk: clock-controller@0 { + compatible = "zhihe,a210-clk"; + reg = <0x00 0x00260000 0x0 0x1000>,<0x00 0x00250000 0x0 0x1000>, + <0x00 0x10141600 0x0 0x100>,<0x00 0x10141400 0x0 0x100>, + <0x00 0x04810000 0x0 0x1000>,<0x00 0x05810000 0x0 0x1000>, + <0x00 0x04900000 0x0 0x1000>,<0x00 0x20250000 0x0 0x1000>, + <0x00 0x10140000 0x0 0xE00>; + reg-names = "pll-wrap","top-crg","cpu-ss-clk-sysreg","cpu-ss-cpu-pll", + "ddr0-sysreg","ddr1-sysreg","slc-dual-sysreg","top-crg-t","cpu-ss-ccu"; + #clock-cells = <1>; + clocks = <&osc_32k>, <&osc_24m>, <&rc_24m>; + clock-names = "osc-32k", "osc-24m", "rc-24m"; + assigned-clocks = <&clk AUDIO0_PLL_FOUTVCO>, <&clk AUDIO1_PLL_FOUTVCO>, + <&clk VIDEO_PLL_FOUTVCO>, <&clk GMAC_PLL_FOUTVCO>, + <&clk DVFS_PLL_FOUTVCO>, <&clk DPU0_PLL_FOUTVCO>, + <&clk DPU1_PLL_FOUTVCO>, <&clk DPU2_PLL_FOUTVCO>, + <&clk TOP_CFG_ACLK_DIV>, <&clk TOP_PCLK_DIV>, + <&clk SW_AMUX_660_CLK_EN>, + <&clk SW_IOMMU_PTW_330_ACLK_EN>, + <&clk SW_NOC_CCLK_EN>, <&clk TOP_CPUSYS_BUS_CLK_DIV>, + <&clk TOP_CPUSYS_PIC_CLK_DIV>; + assigned-clock-rates = <2359296000>, <2528870400>, + <2640000000>, <3000000000>, + <1920000000>, <2376000000>, + <2376000000>, <2376000000>, + <330000000>, <165000000>, + <660000000>, <330000000>, + <950000000>, <1320000000>, + <1000000000>; + status = "okay"; + }; + + + clk_peri: clock-controller@9 { + compatible = "zhihe,a210-peri-clk"; + reg = <0x00 0x00300200 0x0 0x4>, + <0x00 0x02010200 0x0 0x8>,<0x00 0x08400200 0x0 0x8>, + <0x00 0x00540200 0x0 0x4>,<0x00 0x27420200 0x0 0x200>; + reg-names = "peri0-sysreg","peri1-sysreg","peri2-sysreg", + "peri3-sysreg","tee-crg"; + #clock-cells = <1>; + assigned-clocks = <&clk TOP_PERI_TIMER_CLK_MUX>, + <&clk TOP_PERI_I2S_2CH0_SRC_CLK_MUX>, + <&clk TOP_PERI_I2S_2CH1_SRC_CLK_MUX>, + <&clk TOP_PERI_I2S_2CH2_SRC_CLK_MUX>, + <&clk TOP_PERI_I2S_8CH0_SRC_CLK_MUX>, + <&clk TOP_PERI_SPI_SSI_CLK0_DIV>, + <&clk TOP_PERI_SPI_SSI_CLK1_DIV>, + <&clk TOP_PERI_QSPI_SSI_CLK_MUX0>, + <&clk TOP_PERI_QSPI_SSI_CLK_MUX1>, + <&clk TOP_PERI_PDM_MCLK_DIV>, + <&clk TOP_PERI_TDM_SRC_CLK_MUX>, + <&clk TOP_PAD_SENSOR_VCLK0_DIV>, + <&clk TOP_PAD_SENSOR_VCLK1_DIV>, + <&clk TOP_PERI_HIRES_CLK0_DIV>, + <&clk TOP_PERI_HIRES_CLK1_DIV>, + <&clk TOP_PERI_EMMC_REF_CLK_DIV>, + <&clk TOP_PERI_MST_ACLK0_DIV>, + <&clk TOP_PERI_MST_CLK1_DIV>, + <&clk TOP_TEE_CLK_DIV>; + assigned-clock-rates = <24000000>, <316108800>, + <316108800>, <316108800>, + <316108800>, <421478400>, + <421478400>, <421478400>, + <421478400>, <8426058>, + <316108800>, <74250000>, + <148500000>, <80000000>, + <80000000>, <786432000>, + <330000000>, <440000000>, + <377142858>; + status = "okay"; + }; + + power: power-controller { + compatible = "zhihe,a210-power-domain"; + #address-cells = <1>; + #size-cells = <0>; + + power_top: power-domain@0 { + #power-domain-cells = <0>; + #address-cells = <2>; + #size-cells = <2>; + reg = ; + iopmps = <&device_aon_iopmp>, + <&device_gmac_0_iopmp>, + <&device_gmac_1_iopmp>, + <&device_gmac_2_iopmp>, + <&device_peri1_mt_iopmp>, + <&device_dmac_ap_iopmp>, + <&device_emmc_iopmp>, + <&device_sd_iopmp>; + ddr_ccu: clock-controller@5910000 { + compatible = "zhihe,a210-ccu"; + reg = <0x00 0x05910000 0x0 0x2C>, + <0x00 0x05920000 0x0 0x2C>; + zhihe,ccu-dly-time = <0x5E 0x5E>; + zhihe,ccu-dly-time-step = <0x3 0x3>; + }; + pcie_ccu: clock-controller@a007400 { + compatible = "zhihe,a210-ccu"; + reg = <0x00 0x0A007400 0x0 0x2C>, + <0x00 0x0A008000 0x0 0x2C>, + <0x00 0x0A008400 0x0 0x2C>; + zhihe,ccu-dly-time = <0x5E 0x5E 0x5E>; + zhihe,ccu-dly-time-step = <0x3 0x3 0x3>; + }; + tee_ccu: clock-controller@27430000 { + compatible = "zhihe,a210-ccu"; + reg = <0x00 0x27430000 0x0 0x2C>; + zhihe,ccu-dly-time = <0x5E>; + zhihe,ccu-dly-time-step = <0x3>; + }; + cpu_gating_ccu: clock-controller@10140000 { + compatible = "zhihe,a210-ccu"; + reg = <0x00 0x10140000 0x0 0x2C>, + <0x00 0x10140200 0x0 0x2C>, + <0x00 0x10140400 0x0 0x2C>, + <0x00 0x10140600 0x0 0x2C>, + <0x00 0x10140A00 0x0 0x2C>, + <0x00 0x10140C00 0x0 0x2C>, + <0x00 0x10204000 0x0 0x2C>, + <0x00 0x10204200 0x0 0x2C>, + <0x00 0x10204400 0x0 0x2C>, + <0x00 0x10204600 0x0 0x2C>, + <0x00 0x10204800 0x0 0x2C>, + <0x00 0x10204A00 0x0 0x2C>, + <0x00 0x10205400 0x0 0x2C>; + zhihe,ccu-dly-time = <0x34 0x34 0x34 + 0x34 0x34 0x34 + 0x34 0x34 0x34 + 0x34 0x34 0x34 + 0x34>; + zhihe,ccu-dly-time-step = <0x2 0x2 0x2 + 0x2 0x2 0x2 + 0x2 0x2 0x2 + 0x2 0x2 0x2 + 0x2>; + }; + cpu_scaling_ccu: clock-controller@10140800 { + compatible = "zhihe,a210-ccu"; + reg = <0x00 0x10140800 0x0 0x2C>; + zhihe,ccu-mode = ; + zhihe,ccu-dly-time = <0x34>; + zhihe,ccu-dly-time-step = <0x2>; + zhihe,ccu-ratio = <63>; + }; + }; + power_emmc: power-domain@1 { + power-domains = <&power_top>; + #power-domain-cells = <0>; + reg = ; + clocks = <&clk_peri PERI3_EMMC_ACLK_EN>, + <&clk_peri PERI3_EMMC_X2X_ACLK_S_EN>, + <&clk_peri PERI3_EMMC_X2X_ACLK_M_EN>, + <&clk_peri PERI3_EMMC_OSC_CLK_EN>; + }; + power_sdio: power-domain@2 { + power-domains = <&power_top>; + #power-domain-cells = <0>; + reg = ; + clocks = <&clk_peri PERI3_SDIO_ACLK_EN>, + <&clk_peri PERI3_SDIO_X2X_ACLK_S_EN>, + <&clk_peri PERI3_SDIO_X2X_ACLK_M_EN>, + <&clk_peri PERI3_SDIO_OSC_CLK_EN>; + }; + }; + + rst_vp: reset-controller@6b20400 { + compatible = "zhihe,a210-vp-reset"; + reg = <0x00 0x06b20400 0x0 0x200>; + #reset-cells = <1>; + }; + + rst_vi: reset-controller@63a0400 { + compatible = "zhihe,a210-vi-reset"; + reg = <0x00 0x063a0400 0x0 0x200>; + #reset-cells = <1>; + }; + + rst_npu: reset-controller@7112200 { + compatible = "zhihe,a210-npu-reset"; + reg = <0x00 0x07112200 0x0 0x10>; + #reset-cells = <1>; + }; + + rst_vo: reset-controller@6720400 { + compatible = "zhihe,a210-vo-reset"; + reg = <0x00 0x06720400 0x0 0x200>; + #reset-cells = <1>; + }; + + rst_peri0: reset-controller@300400 { + compatible = "zhihe,a210-peri0-reset"; + reg = <0x00 0x00300400 0x0 0x200>; + #reset-cells = <1>; + }; + + rst_peri1: reset-controller@2010400 { + compatible = "zhihe,a210-peri1-reset"; + reg = <0x00 0x02010400 0x0 0x200>; + #reset-cells = <1>; + }; + + rst_peri2: reset-controller@8400400 { + compatible = "zhihe,a210-peri2-reset"; + reg = <0x00 0x08400400 0x0 0x200>; + #reset-cells = <1>; + }; + + rst_peri3: reset-controller@540400 { + compatible = "zhihe,a210-peri3-reset"; + reg = <0x00 0x00540400 0x0 0x200>; + #reset-cells = <1>; + }; + + rst_pcie: reset-controller@a000100 { + compatible = "zhihe,a210-pcie-reset"; + reg = <0x00 0x0a000100 0x0 0x100>; + #reset-cells = <1>; + }; + + rst_usb: reset-controller@8000100 { + compatible = "zhihe,a210-usb-reset"; + reg = <0x00 0x08000100 0x0 0x100>; + #reset-cells = <1>; + }; + + rst_tee: reset-controller@27420400 { + compatible = "zhihe,a210-tee-reset"; + reg = <0x00 0x27420400 0x0 0x200>; + #reset-cells = <1>; + }; + + rst_gpu: reset-controller@6d02000 { + compatible = "zhihe,a210-gpu-reset"; + reg = <0x00 0x06d02000 0x0 0x200>; + #reset-cells = <1>; + }; + + intc: interrupt-controller@18000000 { + #interrupt-cells = <1>; + compatible = "riscv,plic0"; + interrupt-controller; + interrupts-extended = < + &cpu0_intc 0xffffffff &cpu0_intc 9 + &cpu1_intc 0xffffffff &cpu1_intc 9 + &cpu2_intc 0xffffffff &cpu2_intc 9 + &cpu3_intc 0xffffffff &cpu3_intc 9 + &cpu4_intc 0xffffffff &cpu4_intc 9 + &cpu5_intc 0xffffffff &cpu5_intc 9 + &cpu6_intc 0xffffffff &cpu6_intc 9 + &cpu7_intc 0xffffffff &cpu7_intc 9 + >; + reg = <0x00 0x18000000 0x0 0x04000000>; + reg-names = "control"; + riscv,max-priority = <7>; + riscv,ndev = <351>; + }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc_32k: clock-osc-32k { + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "osc-32k"; + #clock-cells = <0>; + }; + + osc_24m: clock-osc-24m { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "osc-24m"; + #clock-cells = <0>; + }; + + aon_110m: clock-osc-110m { + compatible = "fixed-clock"; + clock-frequency = <110000000>; + clock-output-names = "aon-110m"; + #clock-cells = <0>; + }; + + rc_24m: clock-rc-24m { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "rc-24m"; + #clock-cells = <0>; + }; + + apb_clk: apb-clk-clock { + compatible = "fixed-clock"; + clock-frequency = <62500000>; + clock-output-names = "apb-clk"; + #clock-cells = <0>; + }; + }; + + iopmp_regions: iopmp-regions { + #address-cells = <2>; + #size-cells = <2>; + + bypass_region: bypass-region { + reg = <0x00 0x00 0x80 0x00>; + permission = "rwx"; + mode = "TOR"; + }; + }; + + iopmp: iopmp-controller { + compatible = "zhihe,a210-iopmp"; + reg = <0x00 0x26B12000 0x00 0x1000>, + <0x00 0x26372000 0x00 0x1000>, + <0x00 0x27102000 0x00 0x1000>, + <0x00 0x26712000 0x00 0x1000>, + <0x00 0x22032000 0x00 0x1000>, + <0x00 0x2A012000 0x00 0x1000>, + <0x00 0x28022000 0x00 0x1000>, + <0x00 0x26D12000 0x00 0x1000>, + <0x00 0x29032000 0x00 0x1000>, + <0x00 0x30150000 0x00 0x1000>; + reg-names = "vp-iopmp", "vi-iopmp", "npu-iopmp", + "vo-iopmp", "peri1-iopmp", "pcie-iopmp", + "usb-iopmp", "gpu-iopmp", "d2d-rx-iopmp", + "d2d-ss-iopmp"; + }; + + iopmp-devices { + /* PCIE iopmp*/ + device_dmac_ap_iopmp: dmac-ap-iopmp { + iopmp-name = "pcie-iopmp"; + device-id = ; + iopmp-regions = <&bypass_region>; + }; + device_sd_iopmp: sd-iopmp { + iopmp-name = "pcie-iopmp"; + device-id = ; + iopmp-regions = <&bypass_region>; + }; + device_emmc_iopmp: emmc-iopmp { + iopmp-name = "pcie-iopmp"; + device-id = ; + iopmp-regions = <&bypass_region>; + }; + + /* PERI1 iopmp */ + device_peri1_mt_iopmp: peri1-mt-iopmp { + iopmp-name = "peri1-iopmp"; + device-id = ; + iopmp-regions = <&bypass_region>; + }; + device_gmac_0_iopmp: gmac-0-iopmp { + iopmp-name = "peri1-iopmp"; + device-id = ; + iopmp-regions = <&bypass_region>; + }; + device_gmac_1_iopmp: gmac-1-iopmp { + iopmp-name = "peri1-iopmp"; + device-id = ; + iopmp-regions = <&bypass_region>; + }; + device_gmac_2_iopmp: gmac-2-iopmp { + iopmp-name = "peri1-iopmp"; + device-id = ; + iopmp-regions = <&bypass_region>; + }; + device_aon_iopmp: aon-iopmp { + iopmp-name = "peri1-iopmp"; + device-id = ; + iopmp-regions = <&bypass_region>; + }; + }; + + pvt: pvt@3084C000 { + compatible = "moortec,mr75203"; + reg = <0x00 0x3084c000 0x0 0x80>, + <0x00 0x3084c080 0x0 0x180>, + <0x00 0x3084c200 0x0 0x200>, + <0x00 0x3084c400 0x0 0x200>; + reg-names = "common", "ts", "pd", "vm"; + clocks = <&aon_110m>; + #thermal-sensor-cells = <1>; + moortec,ts-coeff-h = <220000>; + moortec,ts-coeff-g = <42740>; + moortec,ts-coeff-j = <0xFFFFFF60>; /* -160 */ + moortec,ts-coeff-cal5 = <4094>; + }; + + + watchdog0: watchdog@305000 { + compatible = "snps,dw-wdt"; + reg = <0x00 0x00305000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <331>; + clocks = <&clk_peri PERI0_WDT0_PCLK_EN>; + power-domains = <&power_top>; + clock-names = "tclk"; + resets = <&rst_peri0 PERI0_WDT0_PRST>; + }; + + rtc: rtc@30840000 { + compatible = "snps,dw-apb-rtc"; + reg = <0x00 0x30840000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <18>; + clocks = <&osc_32k>; + clock-names = "osc-32k"; + wakeup-source; + prescaler = <0x8000>; + }; + + dmac0: dmac@520000 { + compatible = "zhihe,a210-axi-dma"; + reg = <0x00 0x00520000 0x0 0x4000>; + interrupt-parent = <&intc>; + interrupts = <264>; + clocks = <&clk_peri PERI3_DMAC_ACLK_EN>, <&clk_peri PERI3_DMAC_HCLK_EN>; + clock-names = "core-clk", "cfgr-clk"; + resets = <&rst_peri3 PERI3_DMAC_ARST>, <&rst_peri3 PERI3_DMAC_HRST>; + reset-names = "peri3-dmac-arst", "peri3-dmac-hrst"; + power-domains = <&power_top>; + #dma-cells = <1>; + dma-channels = <16>; + snps,block-size = <65536 65536 65536 65536 + 65536 65536 65536 65536 + 65536 65536 65536 65536 + 65536 65536 65536 65536>; + snps,priority = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>; + snps,dma-masters = <1>; + snps,data-width = <4>; + snps,axi-max-burst-len = <4>; + }; + + dmac1: tee-dmac@27540000 { + compatible = "zhihe,a210-axi-dma"; + reg = <0x00 0x27540000 0x0 0x4000>; + interrupt-parent = <&intc>; + interrupts = <259>; + clocks = <&clk_peri TEE_DMAC_CLKEN>, <&clk_peri TEE_DMAC_CLKEN>; + clock-names = "core-clk", "cfgr-clk"; + resets = <&rst_tee TEE_DMAC_ARST>, <&rst_tee TEE_DMAC_HRST>; + reset-names = "tee-dmac-arst", "tee-dmac-hrst"; + #dma-cells = <1>; + dma-channels = <4>; + snps,block-size = <65536 65536 65536 65536>; + snps,priority = <0 0 0 0>; + snps,dma-masters = <1>; + snps,data-width = <4>; + snps,axi-max-burst-len = <16>; + }; + + uart0: serial@2014000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x02014000 0x0 0x400>; + interrupt-parent = <&intc>; + interrupts = <321>; + clocks = <&clk_peri PERI1_UART0_PCLK_EN>, <&clk_peri PERI1_UART0_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri1 PERI1_UART0_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart1: serial@2015000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x02015000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <322>; + clocks = <&clk_peri PERI1_UART1_PCLK_EN>, <&clk_peri PERI1_UART1_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri1 PERI1_UART1_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart2: serial@2016000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x02016000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <323>; + clocks = <&clk_peri PERI1_UART2_PCLK_EN>, <&clk_peri PERI1_UART2_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri1 PERI1_UART2_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart3: serial@2017000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x02017000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <324>; + clocks = <&clk_peri PERI1_UART3_PCLK_EN>, <&clk_peri PERI1_UART3_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri1 PERI1_UART3_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart4: serial@8401000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x08401000 0x0 0x400>; + interrupt-parent = <&intc>; + interrupts = <325>; + clocks = <&clk_peri PERI2_UART4_PCLK_EN>, <&clk_peri PERI2_UART4_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri2 PERI2_UART4_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + current-speed = <115200>; /* OpenSBI */ + }; + + uart5: serial@8402000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x08402000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <326>; + clocks = <&clk_peri PERI2_UART5_PCLK_EN>, <&clk_peri PERI2_UART5_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri2 PERI2_UART5_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart6: serial@8403000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x08403000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <327>; + clocks = <&clk_peri PERI2_UART6_PCLK_EN>, <&clk_peri PERI2_UART6_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri2 PERI2_UART6_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart7: serial@8404000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x08404000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <328>; + clocks = <&clk_peri PERI2_UART7_PCLK_EN>, <&clk_peri PERI2_UART7_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri2 PERI2_UART7_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart8: serial@8405000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x08405000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <329>; + clocks = <&clk_peri PERI2_UART8_PCLK_EN>, <&clk_peri PERI2_UART8_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri2 PERI2_UART8_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + uart9: serial@8406000 { + compatible = "snps,dw-apb-uart"; + reg = <0x00 0x08406000 0x0 0x1000>; + interrupt-parent = <&intc>; + interrupts = <330>; + clocks = <&clk_peri PERI2_UART9_PCLK_EN>, <&clk_peri PERI2_UART9_SCLK_EN>; + clock-names = "apb_pclk", "baudclk"; + resets = <&rst_peri2 PERI2_UART9_PRST>; + power-domains = <&power_top>; + reg-shift = <2>; + reg-io-width = <4>; + }; + + emmc: emmc@500000 { + compatible = "zhihe,a210-dwcmshc"; + reg = <0x0 0x00500000 0x0 0x10000>; + interrupt-parent = <&intc>; + interrupts = <265>; + interrupt-names = "sdhciirq"; + clocks = <&clk_peri PERI3_EMMC_SDIO_REF_CLK_CG_EN>, + <&clk_peri PERI3_EMMC_HCLK_EN>; + clock-names = "core", "bus"; + power-domains = <&power_emmc>; + clk-delay-mmc-hs200 = <50>; + clk-delay-mmc-hs400 = <24>; + }; + + sdhci0: sd@510000 { + compatible = "zhihe,a210-dwcmshc"; + reg = <0x00 0x00510000 0x0 0x10000>; + interrupt-parent = <&intc>; + interrupts = <337>; + interrupt-names = "sdhci0irq"; + clocks = <&clk_peri PERI3_EMMC_SDIO_REF_CLK_CG_EN>, + <&clk_peri PERI3_SDIO_HCLK_EN>; + clock-names = "core", "bus"; + power-domains = <&power_sdio>; + clk-delay-default = <46>; + clk-delay-uhs-sdr104 = <46>; + }; + + stmmac_axi_setup: stmmac-axi-config { + snps,wr_osr_lmt = <7>; + snps,rd_osr_lmt = <7>; + snps,blen = <16 8 4 0 0 0 0>; + }; + + gmac0_sys: syscon@210f000 { + compatible = "syscon"; + reg = <0x00 0x0210f000 0x0 0x20>; + }; + + gmac1_sys: syscon@211f000 { + compatible = "syscon"; + reg = <0x00 0x0211f000 0x0 0x20>; + }; + + gmac0: ethernet@2100000 { + compatible = "zhihe,a210-dwmac", "snps,dwmac-5.20"; + reg = <0x00 0x02100000 0x0 0x10000>; + reg-names = "gmac"; + interrupt-parent = <&intc>; + interrupts = <277>; + interrupt-names = "macirq"; + clocks = <&clk_peri PERI1_GMAC0_ACLK_EN>, + <&clk_peri PERI1_GMAC0_HCLK_EN>, + <&clk_peri PERI1_X2H_GMAC0_ACLK_EN>, + <&clk_peri PERI1_X2H_GMAC0_HCLK_EN>; + clock-names = "stmmaceth", "pclk", "x2h-aclk", "x2h-hclk"; + resets = <&rst_peri1 PERI1_GMAC0_X2H_RST>, <&rst_peri1 PERI1_GMAC0_RST>; + reset-names = "stmmaceth", "ahb"; + power-domains = <&power_top>; + snps,pbl = <32>; + snps,fixed-burst; + snps,axi-config = <&stmmac_axi_setup>; + snps,tso; + zhihe,gmacsys = <&gmac0_sys>; + + mdio0: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + gmac1: ethernet@2110000 { + compatible = "zhihe,a210-dwmac", "snps,dwmac-5.20"; + reg = <0x00 0x02110000 0x0 0x10000>; + reg-names = "gmac"; + interrupt-parent = <&intc>; + interrupts = <288>; + interrupt-names = "macirq"; + clocks = <&clk_peri PERI1_GMAC1_ACLK_EN>, + <&clk_peri PERI1_GMAC1_HCLK_EN>, + <&clk_peri PERI1_X2H_GMAC1_ACLK_EN>, + <&clk_peri PERI1_X2H_GMAC1_HCLK_EN>; + clock-names = "stmmaceth", "pclk", "x2h-aclk", "x2h-hclk"; + resets = <&rst_peri1 PERI1_GMAC1_X2H_RST>, <&rst_peri1 PERI1_GMAC1_RST>; + reset-names = "stmmaceth", "ahb"; + power-domains = <&power_top>; + snps,pbl = <32>; + snps,fixed-burst; + snps,axi-config = <&stmmac_axi_setup>; + snps,tso; + zhihe,gmacsys = <&gmac1_sys>; + mdio1: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + aon_padctrl: aon-padctrl@30848000 { + compatible = "zhihe,a210-aon-pinctrl"; + reg = <0x00 0x30848000 0x0 0x2000>; + clocks = <&aon_110m>; + clock-names = "pclk"; + }; + + gpio@30841000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00 0x30841000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&aon_110m>, <&osc_32k>; + clock-names = "bus", "db"; + + ao_gpio0: ao-gpio0-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + gpio-ranges = <&aon_padctrl 0 8 15>, <&aon_padctrl 21 23 11>; + reg = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <17>; + }; + }; + + gpio@30897000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00 0x30897000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&aon_110m>, <&osc_32k>; + clock-names = "bus", "db"; + + ao_gpio1: ao-gpio1-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <10>; + gpio-ranges = <&aon_padctrl 0 34 10>; + reg = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <10>; + }; + }; + + peri1_padctrl: peri1-padctrl@2026000 { + compatible = "zhihe,a210-peri1-pinctrl"; + reg = <0x00 0x02026000 0x0 0x1000>; + clocks = <&clk_peri PERI1_PAD_CTRL_PCLK_EN>; + clock-names = "pclk"; + }; + + peri2_padctrl: peri2-padctrl@8411000 { + compatible = "zhihe,a210-peri2-pinctrl"; + reg = <0x00 0x08411000 0x0 0x1000>; + clocks = <&clk_peri PERI2_PAD_CTRL_PCLK_EN>; + clock-names = "pclk"; + }; + + peri3_padctrl: peri3-padctrl@542000 { + compatible = "zhihe,a210-peri3-pinctrl"; + reg = <0x00 0x00542000 0x0 0x1000>; + clocks = <&clk_peri PERI3_PAD_CTRL_PCLK_EN>; + clock-names = "pclk"; + }; + + gpio@2012000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00 0x02012000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk_peri PERI1_GPIO0_PCLK_EN>, + <&clk_peri PERI1_GPIO0_DBCLK_EN>; + clock-names = "bus", "db"; + power-domains = <&power_top>; + + gpio0: gpio0-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + gpio-ranges = <&peri1_padctrl 0 0 32>; + reg = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <289>; + }; + }; + + gpio@2013000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00 0x02013000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk_peri PERI1_GPIO1_PCLK_EN>, + <&clk_peri PERI1_GPIO1_DBCLK_EN>; + clock-names = "bus", "db"; + power-domains = <&power_top>; + + gpio1: gpio1-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <18>; + gpio-ranges = <&peri1_padctrl 0 32 18>; + reg = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <290>; + }; + }; + + gpio@8410000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00 0x08410000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk_peri PERI2_GPIO2_PCLK_EN>, + <&clk_peri PERI2_GPIO2_DBCLK_EN>; + clock-names = "bus", "db"; + power-domains = <&power_top>; + + gpio2: gpio2-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + gpio-ranges = <&peri2_padctrl 0 0 32>; + reg = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <291>; + }; + }; + + gpio@8412000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00 0x08412000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk_peri PERI2_GPIO3_PCLK_EN>, + <&clk_peri PERI2_GPIO3_DBCLK_EN>; + clock-names = "bus", "db"; + power-domains = <&power_top>; + + gpio3: gpio3-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <11>; + gpio-ranges = <&peri2_padctrl 0 32 11>; + reg = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <292>; + }; + }; + + gpio@550000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x00 0x00550000 0x0 0x10000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk_peri PERI3_GPIO4_PCLK_EN>, + <&clk_peri PERI3_GPIO4_DBCLK_EN>; + clock-names = "bus", "db"; + power-domains = <&power_top>; + + gpio4: gpio4-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <6>; + gpio-ranges = <&peri3_padctrl 0 0 6>; + reg = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <52>; + }; + }; + + mbox_920: mailbox@310000 { + compatible = "zhihe,a210-mailbox-v2"; + reg = <0x00 0x00321000 0x0 0x1000>, + <0x00 0x00320000 0x0 0x1000>, + <0x00 0x00311000 0x0 0x1000>; + reg-names = "interrupt", + "local0", + "remote0"; + clocks = <&clk_peri PERI0_MBOX0_PCLK_EN>, <&clk_peri PERI0_MBOX1_PCLK_EN>; + resets = <&rst_peri0 PERI0_MBOX0_PRST>, <&rst_peri0 PERI0_MBOX1_PRST>; + interrupt-parent = <&intc>; + interrupts = <336>; + zhihe,icu-cpu-id = <0>; + #mbox-cells = <2>; + }; + + aon: aon-subsys@308f8000 { + compatible = "zhihe,a210-aon"; + reg = <0x00 0x308f8000 0x0 0x10000>, + <0x00 0x30842018 0x0 0x4>, + <0x00 0x30846144 0x0 0x4>; + reg-names = "aon-base", + "aon-reset", + "aon-sync"; + firmware-name = "a210-aon.bin"; + mboxes = <&mbox_920 1 0>; + mbox-names = "aon0"; + #mbox-cells = <2>; + }; + }; +}; From 1f7e45b7e488b098ef39fc4cda9346d9b93c8cef Mon Sep 17 00:00:00 2001 From: Zhiguo Zhu Date: Tue, 14 Jul 2026 21:40:20 +0800 Subject: [PATCH 17/17] riscv: defconfig: enable ZhiHe A210 support Enable ARCH_ZHIHE in the generic RISC-V defconfig so the ZhiHe A210 platform can be built by default. A210 provides ten DesignWare 8250 UART controllers, so raise both the build-time and runtime 8250 UART limits to cover all of them. Signed-off-by: Zhiguo Zhu --- arch/riscv/configs/defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index d540b77f78fac..98ae0839737ab 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -49,6 +49,7 @@ CONFIG_SOC_STARFIVE=y CONFIG_ARCH_SUNXI=y CONFIG_ARCH_THEAD=y CONFIG_ARCH_XUANTIE=y +CONFIG_ARCH_ZHIHE=y CONFIG_ARCH_ULTRARISC=y CONFIG_SOC_VIRT=y CONFIG_SOC_SPACEMIT=y @@ -2757,3 +2758,5 @@ CONFIG_TEST_USER_COPY=m CONFIG_TEST_BPF=m CONFIG_TEST_FIRMWARE=m CONFIG_TEST_STATIC_KEYS=m +CONFIG_SERIAL_8250_NR_UARTS=10 +CONFIG_SERIAL_8250_RUNTIME_UARTS=10