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,.*": 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 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>; + }; + }; +}; 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 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/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; +} 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), }, {} }; 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/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"); 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); 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"); 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"); 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 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"); 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"); 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); 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); } 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 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