Projects
home:xmzzz:branches:openEuler:24.03
kernel
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 3
View file
_service:tar_scm:kernel.spec
Changed
@@ -87,10 +87,10 @@ Source9998: patches.tar.bz2 %endif +Patch0001: 0001-riscv-kernel.patch Patch0002: 0002-cpupower-clang-compile-support.patch Patch0003: 0003-x86_energy_perf_policy-clang-compile-support.patch Patch0004: 0004-turbostat-clang-compile-support.patch -Patch0005: 0005-riscv-kernel.patch #BuildRequires: BuildRequires: module-init-tools, patch >= 2.5.4, bash >= 2.03, tar @@ -329,6 +329,11 @@ Applypatches series.conf %{_builddir}/kernel-%{version}/linux-%{KernelVer} %endif +# riscv-kernel patch +%ifarch riscv64 +%patch0001 -p1 +%endif + %if "%toolchain" == "clang" %patch0002 -p1 %patch0003 -p1 @@ -406,11 +411,6 @@ fi %endif -# riscv-kernel patch -%ifarch riscv64 - %patch0005 -p1 -%endif - # aarch64 make dtbs %ifarch aarch64 riscv64 %{make} ARCH=%{Arch} dtbs
View file
_service:tar_scm:0001-riscv-kernel.patch
Added
@@ -0,0 +1,31141 @@ +From c0904638921da27a0daeebfaa55d0a32833723f0 Mon Sep 17 00:00:00 2001 +From: Mingzheng Xing <xingmingzheng@iscas.ac.cn> +Date: Thu, 21 Mar 2024 16:01:03 +0800 +Subject: PATCH riscv kernel + +Signed-off-by: Mingzheng Xing <xingmingzheng@iscas.ac.cn> +--- + .../bindings/gpio/snps,dw-apb-gpio.yaml | 2 + + .../sifive,plic-1.0.0.yaml | 1 + + .../thead,c900-aclint-mswi.yaml | 43 + + .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 1 + + .../devicetree/bindings/net/snps,dwmac.yaml | 2 + + .../devicetree/bindings/net/thead,dwmac.yaml | 77 + + .../pinctrl/thead,th1520-pinctrl.yaml | 372 +++ + .../bindings/pwm/thead,th1520-pwm.yaml | 44 + + .../bindings/reset/thead,th1520-reset.yaml | 44 + + .../devicetree/bindings/riscv/cpus.yaml | 1 + + .../devicetree/bindings/riscv/sophgo.yaml | 28 + + .../timer/thead,c900-aclint-mtimer.yaml | 50 + + .../bindings/usb/thead,th1520-usb.yaml | 73 + + .../devicetree/bindings/vendor-prefixes.yaml | 4 + + MAINTAINERS | 9 + + arch/riscv/Kconfig | 2 +- + arch/riscv/Kconfig.errata | 1 + + arch/riscv/Kconfig.socs | 6 + + arch/riscv/Makefile | 2 +- + arch/riscv/boot/dts/Makefile | 1 + + arch/riscv/boot/dts/sophgo/Makefile | 5 + + .../boot/dts/sophgo/mango-clock-socket0.dtsi | 124 + + .../boot/dts/sophgo/mango-cpus-socket0.dtsi | 1148 ++++++++++ + .../boot/dts/sophgo/mango-milkv-pioneer.dts | 163 ++ + .../riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi | 83 + + .../boot/dts/sophgo/mango-pcie-3rc-v2.dtsi | 118 + + .../riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi | 115 + + .../riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi | 151 ++ + arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi | 434 ++++ + .../boot/dts/sophgo/mango-sophgo-x4evb.dts | 137 ++ + .../boot/dts/sophgo/mango-sophgo-x8evb.dts | 165 ++ + .../boot/dts/sophgo/mango-top-intc2.dtsi | 62 + + arch/riscv/boot/dts/sophgo/mango.dtsi | 941 ++++++++ + arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi | 2000 +++++++++++++++++ + .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 19 + + arch/riscv/boot/dts/sophgo/sg2042.dtsi | 341 +++ + arch/riscv/boot/dts/thead/Makefile | 3 + + .../boot/dts/thead/th1520-beaglev-ahead.dts | 199 +- + .../thead/th1520-lichee-cluster-4a-16g.dts | 18 + + .../dts/thead/th1520-lichee-cluster-4a.dts | 45 + + .../dts/thead/th1520-lichee-module-4a.dtsi | 151 +- + .../dts/thead/th1520-lichee-pi-4a-16g.dts | 18 + + .../boot/dts/thead/th1520-lichee-pi-4a.dts | 712 ++++++ + .../boot/dts/thead/th1520-milkv-meles-4g.dts | 19 + + .../boot/dts/thead/th1520-milkv-meles.dts | 441 ++++ + arch/riscv/boot/dts/thead/th1520.dtsi | 573 ++++- + arch/riscv/configs/defconfig | 6 +- + arch/riscv/configs/openeuler_defconfig | 347 ++- + arch/riscv/errata/thead/errata.c | 69 +- + arch/riscv/include/asm/errata_list.h | 50 +- + arch/riscv/include/asm/pgtable-64.h | 14 +- + drivers/clk/Kconfig | 1 + + drivers/clk/Makefile | 2 + + drivers/clk/sophgo/Makefile | 3 + + drivers/clk/sophgo/clk-dummy.c | 600 +++++ + drivers/clk/sophgo/clk-mango.c | 977 ++++++++ + drivers/clk/sophgo/clk.c | 883 ++++++++ + drivers/clk/sophgo/clk.h | 152 ++ + drivers/clk/thead/Kconfig | 19 + + drivers/clk/thead/Makefile | 8 + + drivers/clk/thead/clk-light-fm.c | 646 ++++++ + drivers/clk/thead/clk-light-mpw.c | 492 ++++ + drivers/clk/thead/clk.c | 739 ++++++ + drivers/clk/thead/clk.h | 117 + + drivers/clk/thead/gate/Makefile | 3 + + drivers/clk/thead/gate/clk-gate.h | 35 + + drivers/clk/thead/gate/dspsys-gate.c | 109 + + drivers/clk/thead/gate/thead-gate.c | 114 + + drivers/clk/thead/gate/visys-gate.c | 144 ++ + drivers/clk/thead/gate/vosys-gate.c | 111 + + drivers/clk/thead/gate/vpsys-gate.c | 94 + + drivers/cpufreq/Kconfig | 10 + + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/light-mpw-cpufreq.c | 491 ++++ + drivers/firmware/Kconfig | 1 + + drivers/firmware/Makefile | 1 + + drivers/firmware/thead/Kconfig | 18 + + drivers/firmware/thead/Makefile | 3 + + drivers/firmware/thead/light_aon.c | 261 +++ + drivers/firmware/thead/light_aon_misc.c | 74 + + drivers/firmware/thead/light_aon_pd.c | 417 ++++ + drivers/firmware/thead/light_aon_test.c | 163 ++ + drivers/gpio/gpio-dwapb.c | 15 +- + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 + + drivers/gpu/drm/drm_gem_vram_helper.c | 2 +- + drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 + + drivers/gpu/drm/ttm/ttm_bo_util.c | 6 +- + drivers/gpu/drm/ttm/ttm_module.c | 3 +- + drivers/gpu/drm/ttm/ttm_resource.c | 7 +- + drivers/gpu/drm/ttm/ttm_tt.c | 2 +- + drivers/mailbox/Kconfig | 8 + + drivers/mailbox/Makefile | 3 + + drivers/mailbox/light-mailbox-client.c | 242 ++ + drivers/mailbox/light-mailbox.c | 507 +++++ + drivers/mmc/host/Kconfig | 14 + + drivers/mmc/host/Makefile | 1 + + drivers/mmc/host/sdhci-of-dwcmshc.c | 349 +++ + drivers/mmc/host/sdhci-sophgo.c | 619 +++++ + drivers/mmc/host/sdhci-sophgo.h | 121 + + drivers/mmc/host/sdhci.c | 12 +- + drivers/mmc/host/sdhci.h | 4 + + drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 + + drivers/net/ethernet/stmicro/stmmac/Makefile | 2 + + .../ethernet/stmicro/stmmac/dwmac-sophgo.c | 268 +++ + .../net/ethernet/stmicro/stmmac/dwmac-thead.c | 289 +++ + drivers/pci/controller/cadence/Kconfig | 11 + + drivers/pci/controller/cadence/Makefile | 1 + + .../controller/cadence/pcie-cadence-sophgo.c | 963 ++++++++ + .../controller/cadence/pcie-cadence-sophgo.h | 17 + + drivers/pci/pcie/portdrv.c | 2 +- + drivers/pinctrl/Kconfig | 11 +- + drivers/pinctrl/Makefile | 2 + + drivers/pinctrl/pinctrl-th1520.c | 860 +++++++ + drivers/pinctrl/sophgo/Makefile | 2 + + drivers/pinctrl/sophgo/pinctrl-mango.c | 453 ++++ + drivers/pinctrl/sophgo/pinctrl-sophgo.c | 292 +++ + drivers/pinctrl/sophgo/pinctrl-sophgo.h | 70 + + drivers/pwm/Kconfig | 11 + + drivers/pwm/Makefile | 2 + + drivers/pwm/pwm-sophgo.c | 276 +++ + drivers/pwm/pwm-thead.c | 269 +++ + drivers/regulator/Kconfig | 9 + + drivers/regulator/Makefile | 1 + + drivers/regulator/light-regulator-aon.c | 888 ++++++++ + drivers/reset/Kconfig | 10 + + drivers/reset/Makefile | 2 + + drivers/reset/reset-sophgo.c | 163 ++ + drivers/reset/reset-th1520.c | 109 + + drivers/rpmsg/Kconfig | 4 + + drivers/rpmsg/Makefile | 1 + + drivers/rpmsg/light_rpmsg.c | 864 +++++++ + drivers/soc/Kconfig | 1 + + drivers/soc/Makefile | 2 + + drivers/soc/sophgo/Makefile | 3 + + drivers/soc/sophgo/tach/sophgo-tach.c | 330 +++ + drivers/soc/sophgo/top/top_intc.c | 412 ++++ + drivers/soc/sophgo/umcu/mcu.c | 1144 ++++++++++ + drivers/soc/thead/Kconfig | 10 + + drivers/soc/thead/Makefile | 2 + + drivers/soc/thead/light_event.c | 279 +++ + drivers/usb/dwc3/Kconfig | 20 + + drivers/usb/dwc3/Makefile | 2 + + drivers/usb/dwc3/dwc3-thead.c | 112 + + drivers/watchdog/Kconfig | 14 + + drivers/watchdog/Makefile | 1 + + drivers/watchdog/light_wdt.c | 376 ++++ + include/dt-bindings/clock/light-dspsys.h | 25 + + include/dt-bindings/clock/light-fm-ap-clock.h | 513 +++++ + include/dt-bindings/clock/light-mpw-clock.h | 222 ++ + include/dt-bindings/clock/light-visys.h | 54 + + include/dt-bindings/clock/light-vosys.h | 41 + + include/dt-bindings/clock/light-vpsys.h | 24 + + .../dt-bindings/clock/sophgo-mango-clock.h | 165 ++ + include/dt-bindings/clock/sophgo.h | 15 + + include/dt-bindings/firmware/thead/rsrc.h | 17 + + .../dt-bindings/reset/sophgo-mango-resets.h | 96 + + .../dt-bindings/reset/thead,th1520-reset.h | 9 + + include/linux/firmware/thead/ipc.h | 74 + + include/linux/firmware/thead/light_event.h | 35 + + include/linux/light_rpmsg.h | 92 + + kernel/panic.c | 6 + + mm/memblock.c | 6 +- + scripts/package/builddeb | 2 +- + sound/pci/hda/hda_intel.c | 5 +- + tools/perf/pmu-events/arch/riscv/mapfile.csv | 1 + + .../arch/riscv/thead/c900-legacy/cache.json | 67 + + .../riscv/thead/c900-legacy/firmware.json | 68 + + .../riscv/thead/c900-legacy/instruction.json | 72 + + .../riscv/thead/c900-legacy/microarch.json | 80 + + 169 files changed, 28116 insertions(+), 186 deletions(-) + create mode 100644 Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml + create mode 100644 Documentation/devicetree/bindings/net/thead,dwmac.yaml + create mode 100644 Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml + create mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml + create mode 100644 Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml + create mode 100644 Documentation/devicetree/bindings/riscv/sophgo.yaml + create mode 100644 Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml + create mode 100644 Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml + create mode 100644 arch/riscv/boot/dts/sophgo/Makefile + create mode 100644 arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts + create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts + create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts + create mode 100644 arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/mango.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts + create mode 100644 arch/riscv/boot/dts/sophgo/sg2042.dtsi + create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts + create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts + create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts + create mode 100644 arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts + create mode 100644 arch/riscv/boot/dts/thead/th1520-milkv-meles.dts + create mode 100644 drivers/clk/sophgo/Makefile + create mode 100644 drivers/clk/sophgo/clk-dummy.c + create mode 100644 drivers/clk/sophgo/clk-mango.c + create mode 100644 drivers/clk/sophgo/clk.c + create mode 100644 drivers/clk/sophgo/clk.h + create mode 100644 drivers/clk/thead/Kconfig + create mode 100644 drivers/clk/thead/Makefile + create mode 100644 drivers/clk/thead/clk-light-fm.c + create mode 100644 drivers/clk/thead/clk-light-mpw.c + create mode 100644 drivers/clk/thead/clk.c + create mode 100644 drivers/clk/thead/clk.h + create mode 100644 drivers/clk/thead/gate/Makefile + create mode 100644 drivers/clk/thead/gate/clk-gate.h + create mode 100644 drivers/clk/thead/gate/dspsys-gate.c + create mode 100644 drivers/clk/thead/gate/thead-gate.c + create mode 100644 drivers/clk/thead/gate/visys-gate.c + create mode 100644 drivers/clk/thead/gate/vosys-gate.c + create mode 100644 drivers/clk/thead/gate/vpsys-gate.c + create mode 100644 drivers/cpufreq/light-mpw-cpufreq.c + create mode 100644 drivers/firmware/thead/Kconfig + create mode 100644 drivers/firmware/thead/Makefile + create mode 100644 drivers/firmware/thead/light_aon.c + create mode 100644 drivers/firmware/thead/light_aon_misc.c + create mode 100644 drivers/firmware/thead/light_aon_pd.c + create mode 100644 drivers/firmware/thead/light_aon_test.c + create mode 100644 drivers/mailbox/light-mailbox-client.c + create mode 100644 drivers/mailbox/light-mailbox.c + create mode 100644 drivers/mmc/host/sdhci-sophgo.c + create mode 100644 drivers/mmc/host/sdhci-sophgo.h + create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c + create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c + create mode 100644 drivers/pci/controller/cadence/pcie-cadence-sophgo.c + create mode 100644 drivers/pci/controller/cadence/pcie-cadence-sophgo.h + create mode 100644 drivers/pinctrl/pinctrl-th1520.c + create mode 100644 drivers/pinctrl/sophgo/Makefile + create mode 100644 drivers/pinctrl/sophgo/pinctrl-mango.c + create mode 100644 drivers/pinctrl/sophgo/pinctrl-sophgo.c + create mode 100644 drivers/pinctrl/sophgo/pinctrl-sophgo.h + create mode 100644 drivers/pwm/pwm-sophgo.c + create mode 100644 drivers/pwm/pwm-thead.c + create mode 100644 drivers/regulator/light-regulator-aon.c + create mode 100644 drivers/reset/reset-sophgo.c + create mode 100644 drivers/reset/reset-th1520.c + create mode 100644 drivers/rpmsg/light_rpmsg.c + create mode 100644 drivers/soc/sophgo/Makefile + create mode 100644 drivers/soc/sophgo/tach/sophgo-tach.c + create mode 100644 drivers/soc/sophgo/top/top_intc.c + create mode 100644 drivers/soc/sophgo/umcu/mcu.c + create mode 100644 drivers/soc/thead/Kconfig + create mode 100644 drivers/soc/thead/Makefile + create mode 100644 drivers/soc/thead/light_event.c + create mode 100644 drivers/usb/dwc3/dwc3-thead.c + create mode 100644 drivers/watchdog/light_wdt.c + create mode 100644 include/dt-bindings/clock/light-dspsys.h + create mode 100644 include/dt-bindings/clock/light-fm-ap-clock.h + create mode 100644 include/dt-bindings/clock/light-mpw-clock.h + create mode 100644 include/dt-bindings/clock/light-visys.h + create mode 100644 include/dt-bindings/clock/light-vosys.h + create mode 100644 include/dt-bindings/clock/light-vpsys.h + create mode 100644 include/dt-bindings/clock/sophgo-mango-clock.h + create mode 100644 include/dt-bindings/clock/sophgo.h + create mode 100644 include/dt-bindings/firmware/thead/rsrc.h + create mode 100644 include/dt-bindings/reset/sophgo-mango-resets.h + create mode 100644 include/dt-bindings/reset/thead,th1520-reset.h + create mode 100644 include/linux/firmware/thead/ipc.h + create mode 100644 include/linux/firmware/thead/light_event.h + create mode 100644 include/linux/light_rpmsg.h + create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json + create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json + create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json + create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json + +diff --git a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml +index eefe7b345286..ab2afc0e4153 100644 +--- a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml ++++ b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml +@@ -65,6 +65,8 @@ patternProperties: + minItems: 1 + maxItems: 32 + ++ gpio-ranges: true ++ + ngpios: + default: 32 + minimum: 1 +diff --git a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +index dc1f28e55266..16f9c4760c0f 100644 +--- a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml ++++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +@@ -65,6 +65,7 @@ properties: + - items: + - enum: + - allwinner,sun20i-d1-plic ++ - sophgo,sg2042-plic + - thead,th1520-plic + - const: thead,c900-plic + - items: +diff --git a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml +new file mode 100644 +index 000000000000..065f2544b63b +--- /dev/null ++++ b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml +@@ -0,0 +1,43 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-mswi.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sophgo sg2042 CLINT Machine-level Software Interrupt Device ++ ++maintainers: ++ - Inochi Amaoto <inochiama@outlook.com> ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - sophgo,sg2042-aclint-mswi ++ - const: thead,c900-aclint-mswi ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts-extended: ++ minItems: 1 ++ maxItems: 4095 ++ ++additionalProperties: false ++ ++required: ++ - compatible ++ - reg ++ - interrupts-extended ++ ++examples: ++ - | ++ interrupt-controller@94000000 { ++ compatible = "sophgo,sg2042-aclint-mswi", "thead,c900-aclint-mswi"; ++ interrupts-extended = <&cpu1intc 3>, ++ <&cpu2intc 3>, ++ <&cpu3intc 3>, ++ <&cpu4intc 3>; ++ reg = <0x94000000 0x00010000>; ++ }; ++... +diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +index a43eb837f8da..42804d955293 100644 +--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml ++++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +@@ -19,6 +19,7 @@ properties: + - rockchip,rk3568-dwcmshc + - rockchip,rk3588-dwcmshc + - snps,dwcmshc-sdhci ++ - thead,th1520-dwcmshc + + reg: + maxItems: 1 +diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml +index ddf9522a5dc2..73821f86a609 100644 +--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml ++++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml +@@ -96,6 +96,7 @@ properties: + - snps,dwxgmac + - snps,dwxgmac-2.10 + - starfive,jh7110-dwmac ++ - thead,th1520-dwmac + + reg: + minItems: 1 +@@ -586,6 +587,7 @@ allOf: + - qcom,sa8775p-ethqos + - qcom,sc8280xp-ethqos + - snps,dwmac-3.50a ++ - snps,dwmac-3.70a + - snps,dwmac-4.10a + - snps,dwmac-4.20a + - snps,dwmac-5.20 +diff --git a/Documentation/devicetree/bindings/net/thead,dwmac.yaml b/Documentation/devicetree/bindings/net/thead,dwmac.yaml +new file mode 100644 +index 000000000000..bf8ec8ca2753 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/thead,dwmac.yaml +@@ -0,0 +1,77 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/thead,dwmac.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: T-HEAD DWMAC Ethernet controller ++ ++maintainers: ++ - Jisheng Zhang <jszhang@kernel.org> ++ ++select: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - thead,th1520-dwmac ++ required: ++ - compatible ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - thead,th1520-dwmac ++ - const: snps,dwmac-3.70a ++ ++ reg: ++ maxItems: 1 ++ ++ thead,gmacapb: ++ $ref: /schemas/types.yaml#/definitions/phandle ++ description: ++ The phandle to the syscon node that control ethernet ++ interface and timing delay. ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - interrupts ++ - interrupt-names ++ - phy-mode ++ - thead,gmacapb ++ ++allOf: ++ - $ref: snps,dwmac.yaml# ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ gmac0: ethernet@e7070000 { ++ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; ++ reg = <0xe7070000 0x2000>; ++ clocks = <&clk 1>, <&clk 2>; ++ clock-names = "stmmaceth", "pclk"; ++ interrupts = <66>; ++ interrupt-names = "macirq"; ++ phy-mode = "rgmii-id"; ++ snps,fixed-burst; ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ thead,gmacapb = <&gmacapb_syscon>; ++ phy-handle = <&phy0>; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,dwmac-mdio"; ++ ++ phy0: ethernet-phy@0 { ++ reg = <0>; ++ }; ++ }; ++ }; +diff --git a/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml +new file mode 100644 +index 000000000000..b80d0f7b4697 +--- /dev/null ++++ b/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml +@@ -0,0 +1,372 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pinctrl/thead,th1520-pinctrl.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: T-Head TH1520 SoC pin controller ++ ++maintainers: ++ - Emil Renner Berthing <emil.renner.berthing@canonical.com> ++ ++description: | ++ Pinmux and pinconf controller in the T-Head TH1520 RISC-V SoC. ++ ++ The TH1520 has 3 groups of pads each controlled from different memory ranges. ++ Confusingly the memory ranges are named ++ PADCTRL_AOSYS -> PAD Group 1 ++ PADCTRL1_APSYS -> PAD Group 2 ++ PADCTRL0_APSYS -> PAD Group 3 ++ ++ Each pad can be muxed individually to up to 6 different functions. For most ++ pads only a few of those 6 configurations are valid though, and a few pads in ++ group 1 does not support muxing at all. ++ ++ Pinconf is fairly regular except for a few pads in group 1 that either can't ++ be configured or has some special functions. The rest have configurable drive ++ strength, input enable, schmitt trigger, slew rate, pull-up and pull-down in ++ addition to a special strong pull up. ++ ++ Certain pads in group 1 can be muxed to AUDIO_PA0 - AUDIO_PA30 functions and ++ are then meant to be used by the audio co-processor. Each such pad can then ++ be further muxed to either audio GPIO or one of 4 functions such as UART, I2C ++ and I2S. If the audio pad is muxed to one of the 4 functions then pinconf is ++ also configured in different registers. All of this is done from a different ++ AUDIO_IOCTRL memory range and is left to the audio co-processor for now. ++ ++properties: ++ compatible: ++ enum: ++ - thead,th1520-group1-pinctrl ++ - thead,th1520-group2-pinctrl ++ - thead,th1520-group3-pinctrl ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++patternProperties: ++ '-0-9+$': ++ type: object ++ ++ additionalProperties: false ++ ++ patternProperties: ++ '-pins$': ++ type: object ++ $ref: /schemas/pinctrl/pincfg-node.yaml ++ ++ additionalProperties: false ++ ++ description: ++ A pinctrl node should contain at least one subnode describing one ++ or more pads and their associated pinmux and pinconf settings. ++ ++ properties: ++ pins: ++ $ref: /schemas/pinctrl/pinmux-node.yaml#/properties/pins ++ description: List of pads that properties in the node apply to. ++ ++ function: ++ $ref: /schemas/pinctrl/pinmux-node.yaml#/properties/function ++ enum: gpio, pwm, uart, ir, i2c, spi, qspi, sdio, audio, i2s, ++ gmac0, gmac1, dpu0, dpu1, isp, hdmi, bootsel, debug, ++ clock, jtag, iso7816, efuse, reset ++ description: The mux function to select for the given pins. ++ ++ bias-disable: true ++ ++ bias-pull-up: ++ oneOf: ++ - type: boolean ++ description: Enable the regular 48kOhm pull-up ++ - enum: 2100, 48000 ++ description: Enable the strong 2.1kOhm pull-up or regular 48kOhm pull-up ++ ++ bias-pull-down: ++ oneOf: ++ - type: boolean ++ - const: 44000 ++ description: Enable the regular 44kOhm pull-down ++ ++ drive-strength: ++ description: Drive strength in mA ++ enum: 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25 ++ ++ input-enable: true ++ ++ input-disable: true ++ ++ input-schmitt-enable: true ++ ++ input-schmitt-disable: true ++ ++ slew-rate: ++ maximum: 1 ++ ++ required: ++ - pins ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ ++additionalProperties: false ++ ++allOf: ++ - $ref: pinctrl.yaml# ++ - if: ++ properties: ++ compatible: ++ const: thead,th1520-group1-pinctrl ++ then: ++ patternProperties: ++ '-0-9+$': ++ patternProperties: ++ '-pins$': ++ properties: ++ pins: ++ items: ++ enum: ++ - OSC_CLK_IN ++ - OSC_CLK_OUT ++ - SYS_RST_N ++ - RTC_CLK_IN ++ - RTC_CLK_OUT ++ - TEST_MODE ++ - DEBUG_MODE ++ - POR_SEL ++ - I2C_AON_SCL ++ - I2C_AON_SDA ++ - CPU_JTG_TCLK ++ - CPU_JTG_TMS ++ - CPU_JTG_TDI ++ - CPU_JTG_TDO ++ - CPU_JTG_TRST ++ - AOGPIO_7 ++ - AOGPIO_8 ++ - AOGPIO_9 ++ - AOGPIO_10 ++ - AOGPIO_11 ++ - AOGPIO_12 ++ - AOGPIO_13 ++ - AOGPIO_14 ++ - AOGPIO_15 ++ - AUDIO_PA0 ++ - AUDIO_PA1 ++ - AUDIO_PA2 ++ - AUDIO_PA3 ++ - AUDIO_PA4 ++ - AUDIO_PA5 ++ - AUDIO_PA6 ++ - AUDIO_PA7 ++ - AUDIO_PA8 ++ - AUDIO_PA9 ++ - AUDIO_PA10 ++ - AUDIO_PA11 ++ - AUDIO_PA12 ++ - AUDIO_PA13 ++ - AUDIO_PA14 ++ - AUDIO_PA15 ++ - AUDIO_PA16 ++ - AUDIO_PA17 ++ - AUDIO_PA27 ++ - AUDIO_PA28 ++ - AUDIO_PA29 ++ - AUDIO_PA30 ++ - if: ++ properties: ++ compatible: ++ const: thead,th1520-group2-pinctrl ++ then: ++ patternProperties: ++ '-0-9+$': ++ patternProperties: ++ '-pins$': ++ properties: ++ pins: ++ items: ++ enum: ++ - QSPI1_SCLK ++ - QSPI1_CSN0 ++ - QSPI1_D0_MOSI ++ - QSPI1_D1_MISO ++ - QSPI1_D2_WP ++ - QSPI1_D3_HOLD ++ - I2C0_SCL ++ - I2C0_SDA ++ - I2C1_SCL ++ - I2C1_SDA ++ - UART1_TXD ++ - UART1_RXD ++ - UART4_TXD ++ - UART4_RXD ++ - UART4_CTSN ++ - UART4_RTSN ++ - UART3_TXD ++ - UART3_RXD ++ - GPIO0_18 ++ - GPIO0_19 ++ - GPIO0_20 ++ - GPIO0_21 ++ - GPIO0_22 ++ - GPIO0_23 ++ - GPIO0_24 ++ - GPIO0_25 ++ - GPIO0_26 ++ - GPIO0_27 ++ - GPIO0_28 ++ - GPIO0_29 ++ - GPIO0_30 ++ - GPIO0_31 ++ - GPIO1_0 ++ - GPIO1_1 ++ - GPIO1_2 ++ - GPIO1_3 ++ - GPIO1_4 ++ - GPIO1_5 ++ - GPIO1_6 ++ - GPIO1_7 ++ - GPIO1_8 ++ - GPIO1_9 ++ - GPIO1_10 ++ - GPIO1_11 ++ - GPIO1_12 ++ - GPIO1_13 ++ - GPIO1_14 ++ - GPIO1_15 ++ - GPIO1_16 ++ - CLK_OUT_0 ++ - CLK_OUT_1 ++ - CLK_OUT_2 ++ - CLK_OUT_3 ++ - GPIO1_21 ++ - GPIO1_22 ++ - GPIO1_23 ++ - GPIO1_24 ++ - GPIO1_25 ++ - GPIO1_26 ++ - GPIO1_27 ++ - GPIO1_28 ++ - GPIO1_29 ++ - GPIO1_30 ++ - if: ++ properties: ++ compatible: ++ const: thead,th1520-group3-pinctrl ++ then: ++ patternProperties: ++ '-0-9+$': ++ patternProperties: ++ '-pins$': ++ properties: ++ pins: ++ items: ++ enum: ++ - UART0_TXD ++ - UART0_RXD ++ - QSPI0_SCLK ++ - QSPI0_CSN0 ++ - QSPI0_CSN1 ++ - QSPI0_D0_MOSI ++ - QSPI0_D1_MISO ++ - QSPI0_D2_WP ++ - QSPI1_D3_HOLD ++ - I2C2_SCL ++ - I2C2_SDA ++ - I2C3_SCL ++ - I2C3_SDA ++ - GPIO2_13 ++ - SPI_SCLK ++ - SPI_CSN ++ - SPI_MOSI ++ - SPI_MISO ++ - GPIO2_18 ++ - GPIO2_19 ++ - GPIO2_20 ++ - GPIO2_21 ++ - GPIO2_22 ++ - GPIO2_23 ++ - GPIO2_24 ++ - GPIO2_25 ++ - SDIO0_WPRTN ++ - SDIO0_DETN ++ - SDIO1_WPRTN ++ - SDIO1_DETN ++ - GPIO2_30 ++ - GPIO2_31 ++ - GPIO3_0 ++ - GPIO3_1 ++ - GPIO3_2 ++ - GPIO3_3 ++ - HDMI_SCL ++ - HDMI_SDA ++ - HDMI_CEC ++ - GMAC0_TX_CLK ++ - GMAC0_RX_CLK ++ - GMAC0_TXEN ++ - GMAC0_TXD0 ++ - GMAC0_TXD1 ++ - GMAC0_TXD2 ++ - GMAC0_TXD3 ++ - GMAC0_RXDV ++ - GMAC0_RXD0 ++ - GMAC0_RXD1 ++ - GMAC0_RXD2 ++ - GMAC0_RXD3 ++ - GMAC0_MDC ++ - GMAC0_MDIO ++ - GMAC0_COL ++ - GMAC0_CRS ++ ++examples: ++ - | ++ padctrl0_apsys: pinctrl@ec007000 { ++ compatible = "thead,th1520-group3-pinctrl"; ++ reg = <0xec007000 0x1000>; ++ clocks = <&apb_clk>; ++ ++ uart0_pins: uart0-0 { ++ tx-pins { ++ pins = "UART0_TXD"; ++ function = "uart"; ++ bias-disable; ++ drive-strength = <3>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pins = "UART0_RXD"; ++ function = "uart"; ++ bias-disable; ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ }; ++ ++ padctrl1_apsys: pinctrl@e7f3c000 { ++ compatible = "thead,th1520-group2-pinctrl"; ++ reg = <0xe7f3c000 0x1000>; ++ clocks = <&apb_clk>; ++ ++ i2c5_pins: i2c5-0 { ++ i2c-pins { ++ pins = "QSPI1_CSN0", /* I2C5_SCL */ ++ "QSPI1_D0_MOSI"; /* I2C5_SDA */ ++ function = "i2c"; ++ bias-pull-up = <2100>; ++ drive-strength = <7>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ }; +diff --git a/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml +new file mode 100644 +index 000000000000..e75d8e9f24c5 +--- /dev/null ++++ b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml +@@ -0,0 +1,44 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pwm/thead,th1520-pwm.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: T-HEAD TH1520 PWM ++ ++maintainers: ++ - Jisheng Zhang <jszhang@kernel.org> ++ ++allOf: ++ - $ref: pwm.yaml# ++ ++properties: ++ compatible: ++ enum: ++ - thead,th1520-pwm ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ "#pwm-cells": ++ const: 3 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ ++additionalProperties: false ++ ++examples: ++ - | ++ ++ pwm@ec01c000 { ++ compatible = "thead,th1520-pwm"; ++ reg = <0xec01c000 0x1000>; ++ clocks = <&clk 1>; ++ #pwm-cells = <3>; ++ }; +diff --git a/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml +new file mode 100644 +index 000000000000..49ea8c6a331f +--- /dev/null ++++ b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml +@@ -0,0 +1,44 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/reset/thead,th1520-reset.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: T-HEAD th1520 SoC Reset Controller ++ ++maintainers: ++ - Kwanghoon Son <k.son@samsung.com> ++ ++properties: ++ compatible: ++ items: ++ - const: thead,th1520-reset ++ - const: syscon ++ ++ reg: ++ maxItems: 1 ++ ++ '#reset-cells': ++ const: 1 ++ ++required: ++ - compatible ++ - reg ++ - '#reset-cells' ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include <dt-bindings/reset/thead,th1520-reset.h> ++ ++ soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ reset-controller@ffef014000 { ++ compatible = "thead,th1520-reset", "syscon"; ++ reg = <0xff 0xef014000 0x0 0x1000>; ++ #reset-cells = <1>; ++ }; ++ }; +diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml +index 97e8441eda1c..f392e367d673 100644 +--- a/Documentation/devicetree/bindings/riscv/cpus.yaml ++++ b/Documentation/devicetree/bindings/riscv/cpus.yaml +@@ -47,6 +47,7 @@ properties: + - sifive,u74-mc + - thead,c906 + - thead,c910 ++ - thead,c920 + - const: riscv + - items: + - enum: +diff --git a/Documentation/devicetree/bindings/riscv/sophgo.yaml b/Documentation/devicetree/bindings/riscv/sophgo.yaml +new file mode 100644 +index 000000000000..8adb5f39ca53 +--- /dev/null ++++ b/Documentation/devicetree/bindings/riscv/sophgo.yaml +@@ -0,0 +1,28 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/riscv/sophgo.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sophgo SoC-based boards ++ ++maintainers: ++ - Chao Wei <chao.wei@sophgo.com> ++ - Chen Wang <unicorn_wang@outlook.com> ++ ++description: ++ Sophgo SoC-based boards ++ ++properties: ++ $nodename: ++ const: '/' ++ compatible: ++ oneOf: ++ - items: ++ - enum: ++ - milkv,pioneer ++ - const: sophgo,sg2042 ++ ++additionalProperties: true ++ ++... +diff --git a/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml +new file mode 100644 +index 000000000000..2e92bcdeb423 +--- /dev/null ++++ b/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml +@@ -0,0 +1,50 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/timer/thead,c900-aclint-mtimer.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sophgo CLINT Timer ++ ++maintainers: ++ - Inochi Amaoto <inochiama@outlook.com> ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - sophgo,sg2042-aclint-mtimer ++ - const: thead,c900-aclint-mtimer ++ ++ reg: ++ items: ++ - description: MTIMECMP Registers ++ ++ reg-names: ++ items: ++ - const: mtimecmp ++ ++ interrupts-extended: ++ minItems: 1 ++ maxItems: 4095 ++ ++additionalProperties: false ++ ++required: ++ - compatible ++ - reg ++ - reg-names ++ - interrupts-extended ++ ++examples: ++ - | ++ timer@ac000000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ interrupts-extended = <&cpu1intc 7>, ++ <&cpu2intc 7>, ++ <&cpu3intc 7>, ++ <&cpu4intc 7>; ++ reg = <0xac000000 0x00010000>; ++ reg-names = "mtimecmp"; ++ }; ++... +diff --git a/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml b/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml +new file mode 100644 +index 000000000000..afb618eb5013 +--- /dev/null ++++ b/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml +@@ -0,0 +1,73 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/usb/thead,th1520-usb.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: T-HEAD TH1520 DWC3 USB Controller Glue ++ ++maintainers: ++ - Jisheng Zhang <jszhang@kernel.org> ++ ++properties: ++ compatible: ++ const: thead,th1520-usb ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 4 ++ ++ clock-names: ++ items: ++ - const: ref ++ - const: bus_early ++ - const: phy ++ - const: suspend ++ ++ ranges: true ++ ++ '#address-cells': ++ enum: 1, 2 ++ ++ '#size-cells': ++ enum: 1, 2 ++ ++# Required child node: ++ ++patternProperties: ++ "^usb@0-9a-f+$": ++ $ref: snps,dwc3.yaml# ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - ranges ++ ++additionalProperties: false ++ ++examples: ++ - | ++ ++ usb { ++ compatible = "thead,th1520-usb"; ++ reg = <0xec03f000 0x1000>; ++ clocks = <&clk 1>, ++ <&clk 2>, ++ <&clk 3>, ++ <&clk 4>; ++ clock-names = "ref", "bus_early", "phy", "suspend"; ++ ranges; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ usb@e7040000 { ++ compatible = "snps,dwc3"; ++ reg = <0xe7040000 0x10000>; ++ interrupts = <68>; ++ dr_mode = "host"; ++ }; ++ }; +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml +index 133cfb2bb05c..2a8938bfe447 100644 +--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml ++++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml +@@ -863,6 +863,8 @@ patternProperties: + description: MikroElektronika d.o.o. + "^mikrotik,.*": + description: MikroTik ++ "^milkv,.*": ++ description: MilkV Technology Co., Ltd + "^miniand,.*": + description: Miniand Tech + "^minix,.*": +@@ -1275,6 +1277,8 @@ patternProperties: + description: Solomon Systech Limited + "^sony,.*": + description: Sony Corporation ++ "^sophgo,.*": ++ description: Sophgo Technology Inc. + "^sourceparts,.*": + description: Source Parts Inc. + "^spansion,.*": +diff --git a/MAINTAINERS b/MAINTAINERS +index 33056b3b5b2c..832f3795de90 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -18499,6 +18499,8 @@ M: Fu Wei <wefu@redhat.com> + L: linux-riscv@lists.infradead.org + S: Maintained + F: arch/riscv/boot/dts/thead/ ++F: drivers/pinctrl/pinctrl-th1520.c ++F: drivers/usb/dwc3/dwc3-thead.c + + RNBD BLOCK DRIVERS + M: Md. Haris Iqbal <haris.iqbal@ionos.com> +@@ -20078,6 +20080,13 @@ F: drivers/char/sonypi.c + F: drivers/platform/x86/sony-laptop.c + F: include/linux/sony-laptop.h + ++SOPHGO DEVICETREES ++M: Chao Wei <chao.wei@sophgo.com> ++M: Chen Wang <unicorn_wang@outlook.com> ++S: Maintained ++F: arch/riscv/boot/dts/sophgo/ ++F: Documentation/devicetree/bindings/riscv/sophgo.yaml ++ + SOUND + M: Jaroslav Kysela <perex@perex.cz> + M: Takashi Iwai <tiwai@suse.com> +diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig +index 32aadf652681..16e6c9617f28 100644 +--- a/arch/riscv/Kconfig ++++ b/arch/riscv/Kconfig +@@ -501,7 +501,7 @@ config RISCV_ISA_V + depends on TOOLCHAIN_HAS_V + depends on FPU + select DYNAMIC_SIGFRAME +- default y ++ default n + help + Say N here if you want to disable all vector related procedure + in the kernel. +diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata +index e2c731cfed8c..dedb8b238e73 100644 +--- a/arch/riscv/Kconfig.errata ++++ b/arch/riscv/Kconfig.errata +@@ -79,6 +79,7 @@ config ERRATA_THEAD_CMO + depends on ERRATA_THEAD && MMU + select DMA_DIRECT_REMAP + select RISCV_DMA_NONCOHERENT ++ select RISCV_NONSTANDARD_CACHE_OPS + default y + help + This will apply the cache management errata to handle the +diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs +index 30fd6a512828..88ce9f0182be 100644 +--- a/arch/riscv/Kconfig.socs ++++ b/arch/riscv/Kconfig.socs +@@ -22,6 +22,12 @@ config SOC_SIFIVE + help + This enables support for SiFive SoC platform hardware. + ++config ARCH_SOPHGO ++ bool "Sophgo SoCs" ++ select DW_APB_TIMER_OF ++ help ++ This enables support for Sophgo SoC platform hardware. ++ + config ARCH_STARFIVE + def_bool SOC_STARFIVE + +diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile +index b43a6bb7e4dc..ecf81ab9bd9e 100644 +--- a/arch/riscv/Makefile ++++ b/arch/riscv/Makefile +@@ -152,7 +152,7 @@ ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy) + KBUILD_IMAGE := $(boot)/loader.bin + else + ifeq ($(CONFIG_EFI_ZBOOT),) +-KBUILD_IMAGE := $(boot)/Image.gz ++KBUILD_IMAGE := $(boot)/Image + else + KBUILD_IMAGE := $(boot)/vmlinuz.efi + endif +diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile +index f60a280abb15..72030fd727af 100644 +--- a/arch/riscv/boot/dts/Makefile ++++ b/arch/riscv/boot/dts/Makefile +@@ -4,6 +4,7 @@ subdir-y += canaan + subdir-y += microchip + subdir-y += renesas + subdir-y += sifive ++subdir-y += sophgo + subdir-y += starfive + subdir-y += thead + +diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile +new file mode 100644 +index 000000000000..37f481ea87bb +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0 ++dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb ++dtb-$(CONFIG_ARCH_SOPHGO) += mango-milkv-pioneer.dtb ++dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-x4evb.dtb ++dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-x8evb.dtb +diff --git a/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi b/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi +new file mode 100644 +index 000000000000..af3380412f1d +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi +@@ -0,0 +1,124 @@ ++/ { ++ socket0-clocks { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ cgi: ctrystal { ++ compatible = "fixed-clock"; ++ clock-frequency = <25000000>; ++ clock-output-names = "cgi"; ++ #clock-cells = <0>; ++ }; ++ ++ /* pll clock */ ++ mpll: mpll { ++ compatible = "mango, pll-clock"; ++ #clock-cells = <0>; ++ id = <MPLL_CLK>; ++ mode = <NORMAL_MODE>; ++ subctrl-syscon = <&top_misc>; ++ clocks = <&cgi>; ++ clock-output-names = "mpll_clock"; ++ }; ++ ++ fpll: fpll { ++ compatible = "mango, pll-clock"; ++ #clock-cells = <0>; ++ id = <FPLL_CLK>; ++ mode = <NORMAL_MODE>; ++ subctrl-syscon = <&top_misc>; ++ clocks = <&cgi>; ++ clock-output-names = "fpll_clock"; ++ }; ++ ++ dpll0: dpll0 { ++ compatible = "mango, pll-clock"; ++ #clock-cells = <0>; ++ id = <DPLL0_CLK>; ++ mode = <NORMAL_MODE>; ++ subctrl-syscon = <&top_misc>; ++ clocks = <&cgi>; ++ clock-output-names = "dpll0_clock"; ++ }; ++ ++ dpll1: dpll1 { ++ compatible = "mango, pll-clock"; ++ #clock-cells = <0>; ++ mode = <NORMAL_MODE>; ++ subctrl-syscon = <&top_misc>; ++ clocks = <&cgi>; ++ id = <DPLL1_CLK>; ++ clock-output-names = "dpll1_clock"; ++ }; ++ ++ div_clk: div_clk { ++ compatible = "mango, pll-child-clock"; ++ #clock-cells = <1>; ++ id = <S0_DIV_CLK_TABLE>; ++ subctrl-syscon = <&top_misc>; ++ }; ++ ++ mux_clk: mux_clk { ++ compatible = "mango, pll-mux-clock"; ++ #clock-cells = <1>; ++ id = <S0_MUX_CLK_TABLE>; ++ subctrl-syscon = <&top_misc>; ++ }; ++ ++ socket0_default_rates { ++ compatible = "mango, clk-default-rates"; ++ #clock-cells = <1>; ++ subctrl-syscon = <&top_misc>; ++ clocks = \ ++ <&mpll>, <&fpll>, ++ ++ <&div_clk DIV_CLK_FPLL_RP_CPU_NORMAL_1>, ++ <&div_clk DIV_CLK_FPLL_50M_A53>, ++ <&div_clk DIV_CLK_FPLL_TOP_RP_CMN_DIV2>, ++ <&div_clk DIV_CLK_FPLL_UART_500M>, ++ <&div_clk DIV_CLK_FPLL_AHB_LPC>, ++ <&div_clk DIV_CLK_FPLL_EFUSE>, ++ <&div_clk DIV_CLK_FPLL_TX_ETH0>, ++ <&div_clk DIV_CLK_FPLL_PTP_REF_I_ETH0>, ++ <&div_clk DIV_CLK_FPLL_REF_ETH0>, ++ <&div_clk DIV_CLK_FPLL_EMMC>, ++ <&div_clk DIV_CLK_FPLL_SD>, ++ <&div_clk DIV_CLK_FPLL_TOP_AXI0>, ++ <&div_clk DIV_CLK_FPLL_TOP_AXI_HSPERI>, ++ <&div_clk DIV_CLK_FPLL_AXI_DDR_1>, ++ <&div_clk DIV_CLK_FPLL_DIV_TIMER1>, ++ <&div_clk DIV_CLK_FPLL_DIV_TIMER2>, ++ <&div_clk DIV_CLK_FPLL_DIV_TIMER3>, ++ <&div_clk DIV_CLK_FPLL_DIV_TIMER4>, ++ <&div_clk DIV_CLK_FPLL_DIV_TIMER5>, ++ <&div_clk DIV_CLK_FPLL_DIV_TIMER6>, ++ <&div_clk DIV_CLK_FPLL_DIV_TIMER7>, ++ <&div_clk DIV_CLK_FPLL_DIV_TIMER8>, ++ <&div_clk DIV_CLK_FPLL_100K_EMMC>, ++ <&div_clk DIV_CLK_FPLL_100K_SD>, ++ <&div_clk DIV_CLK_FPLL_GPIO_DB>, ++ ++ <&div_clk DIV_CLK_MPLL_RP_CPU_NORMAL_0>, ++ <&div_clk DIV_CLK_MPLL_AXI_DDR_0>; ++ ++ clock-rates = \ ++ <2000000000>, <1000000000>, ++ ++ <2000000000>, <50000000>, ++ <1000000000>, <500000000>, ++ <200000000>, <25000000>, ++ <125000000>, <50000000>, ++ <25000000>, <100000000>, ++ <100000000>, <100000000>, ++ <250000000>, <1000000000>, ++ <50000000>, <50000000>, ++ <50000000>, <50000000>, ++ <50000000>, <50000000>, ++ <50000000>, <50000000>, ++ <100000>, <100000>, <100000>, ++ ++ <2000000001>, <1000000001>; ++ }; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi b/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi +new file mode 100644 +index 000000000000..9165f0a658b0 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi +@@ -0,0 +1,1148 @@ ++/ { ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ timebase-frequency = <50000000>; ++ ++ cpu-map { ++ socket0 { ++ cluster0 { ++ core0 { ++ cpu = <&cpu0>; ++ }; ++ core1 { ++ cpu = <&cpu1>; ++ }; ++ core2 { ++ cpu = <&cpu2>; ++ }; ++ core3 { ++ cpu = <&cpu3>; ++ }; ++ }; ++ ++ cluster1 { ++ core0 { ++ cpu = <&cpu4>; ++ }; ++ core1 { ++ cpu = <&cpu5>; ++ }; ++ core2 { ++ cpu = <&cpu6>; ++ }; ++ core3 { ++ cpu = <&cpu7>; ++ }; ++ }; ++ ++ cluster2 { ++ core0 { ++ cpu = <&cpu16>; ++ }; ++ core1 { ++ cpu = <&cpu17>; ++ }; ++ core2 { ++ cpu = <&cpu18>; ++ }; ++ core3 { ++ cpu = <&cpu19>; ++ }; ++ }; ++ ++ cluster3 { ++ core0 { ++ cpu = <&cpu20>; ++ }; ++ core1 { ++ cpu = <&cpu21>; ++ }; ++ core2 { ++ cpu = <&cpu22>; ++ }; ++ core3 { ++ cpu = <&cpu23>; ++ }; ++ }; ++ ++ cluster4 { ++ core0 { ++ cpu = <&cpu8>; ++ }; ++ core1 { ++ cpu = <&cpu9>; ++ }; ++ core2 { ++ cpu = <&cpu10>; ++ }; ++ core3 { ++ cpu = <&cpu11>; ++ }; ++ }; ++ ++ cluster5 { ++ core0 { ++ cpu = <&cpu12>; ++ }; ++ core1 { ++ cpu = <&cpu13>; ++ }; ++ core2 { ++ cpu = <&cpu14>; ++ }; ++ core3 { ++ cpu = <&cpu15>; ++ }; ++ }; ++ ++ cluster6 { ++ core0 { ++ cpu = <&cpu24>; ++ }; ++ core1 { ++ cpu = <&cpu25>; ++ }; ++ core2 { ++ cpu = <&cpu26>; ++ }; ++ core3 { ++ cpu = <&cpu27>; ++ }; ++ }; ++ ++ cluster7 { ++ core0 { ++ cpu = <&cpu28>; ++ }; ++ core1 { ++ cpu = <&cpu29>; ++ }; ++ core2 { ++ cpu = <&cpu30>; ++ }; ++ core3 { ++ cpu = <&cpu31>; ++ }; ++ }; ++ ++ cluster8 { ++ core0 { ++ cpu = <&cpu32>; ++ }; ++ core1 { ++ cpu = <&cpu33>; ++ }; ++ core2 { ++ cpu = <&cpu34>; ++ }; ++ core3 { ++ cpu = <&cpu35>; ++ }; ++ }; ++ ++ cluster9 { ++ core0 { ++ cpu = <&cpu36>; ++ }; ++ core1 { ++ cpu = <&cpu37>; ++ }; ++ core2 { ++ cpu = <&cpu38>; ++ }; ++ core3 { ++ cpu = <&cpu39>; ++ }; ++ }; ++ ++ cluster10 { ++ core0 { ++ cpu = <&cpu48>; ++ }; ++ core1 { ++ cpu = <&cpu49>; ++ }; ++ core2 { ++ cpu = <&cpu50>; ++ }; ++ core3 { ++ cpu = <&cpu51>; ++ }; ++ }; ++ ++ cluster11 { ++ core0 { ++ cpu = <&cpu52>; ++ }; ++ core1 { ++ cpu = <&cpu53>; ++ }; ++ core2 { ++ cpu = <&cpu54>; ++ }; ++ core3 { ++ cpu = <&cpu55>; ++ }; ++ }; ++ ++ cluster12 { ++ core0 { ++ cpu = <&cpu40>; ++ }; ++ core1 { ++ cpu = <&cpu41>; ++ }; ++ core2 { ++ cpu = <&cpu42>; ++ }; ++ core3 { ++ cpu = <&cpu43>; ++ }; ++ }; ++ ++ cluster13 { ++ core0 { ++ cpu = <&cpu44>; ++ }; ++ core1 { ++ cpu = <&cpu45>; ++ }; ++ core2 { ++ cpu = <&cpu46>; ++ }; ++ core3 { ++ cpu = <&cpu47>; ++ }; ++ }; ++ ++ cluster14 { ++ core0 { ++ cpu = <&cpu56>; ++ }; ++ core1 { ++ cpu = <&cpu57>; ++ }; ++ core2 { ++ cpu = <&cpu58>; ++ }; ++ core3 { ++ cpu = <&cpu59>; ++ }; ++ }; ++ ++ cluster15 { ++ core0 { ++ cpu = <&cpu60>; ++ }; ++ core1 { ++ cpu = <&cpu61>; ++ }; ++ core2 { ++ cpu = <&cpu62>; ++ }; ++ core3 { ++ cpu = <&cpu63>; ++ }; ++ }; ++ }; ++ }; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ reg = <0>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu0_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ reg = <1>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu1_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ reg = <2>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu2_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ reg = <3>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu3_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu4: cpu@4 { ++ device_type = "cpu"; ++ reg = <4>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu4_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu5: cpu@5 { ++ device_type = "cpu"; ++ reg = <5>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu5_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu6: cpu@6 { ++ device_type = "cpu"; ++ reg = <6>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu6_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu7: cpu@7 { ++ device_type = "cpu"; ++ reg = <7>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu7_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu8: cpu@8 { ++ device_type = "cpu"; ++ reg = <8>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu8_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu9: cpu@9 { ++ device_type = "cpu"; ++ reg = <9>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu9_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu10: cpu@10 { ++ device_type = "cpu"; ++ reg = <10>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu10_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu11: cpu@11 { ++ device_type = "cpu"; ++ reg = <11>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu11_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu12: cpu@12 { ++ device_type = "cpu"; ++ reg = <12>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu12_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu13: cpu@13 { ++ device_type = "cpu"; ++ reg = <13>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu13_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu14: cpu@14 { ++ device_type = "cpu"; ++ reg = <14>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu14_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu15: cpu@15 { ++ device_type = "cpu"; ++ reg = <15>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu15_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu16: cpu@16 { ++ device_type = "cpu"; ++ reg = <16>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu16_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu17: cpu@17 { ++ device_type = "cpu"; ++ reg = <17>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu17_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu18: cpu@18 { ++ device_type = "cpu"; ++ reg = <18>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu18_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu19: cpu@19 { ++ device_type = "cpu"; ++ reg = <19>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu19_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu20: cpu@20 { ++ device_type = "cpu"; ++ reg = <20>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu20_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu21: cpu@21 { ++ device_type = "cpu"; ++ reg = <21>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu21_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu22: cpu@22 { ++ device_type = "cpu"; ++ reg = <22>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu22_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu23: cpu@23 { ++ device_type = "cpu"; ++ reg = <23>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <0>; ++ cpu23_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu24: cpu@24 { ++ device_type = "cpu"; ++ reg = <24>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu24_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu25: cpu@25 { ++ device_type = "cpu"; ++ reg = <25>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu25_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu26: cpu@26 { ++ device_type = "cpu"; ++ reg = <26>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu26_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu27: cpu@27 { ++ device_type = "cpu"; ++ reg = <27>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu27_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu28: cpu@28 { ++ device_type = "cpu"; ++ reg = <28>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu28_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu29: cpu@29 { ++ device_type = "cpu"; ++ reg = <29>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu29_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu30: cpu@30 { ++ device_type = "cpu"; ++ reg = <30>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu30_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu31: cpu@31 { ++ device_type = "cpu"; ++ reg = <31>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <1>; ++ cpu31_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu32: cpu@32 { ++ device_type = "cpu"; ++ reg = <32>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu32_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu33: cpu@33 { ++ device_type = "cpu"; ++ reg = <33>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu33_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu34: cpu@34 { ++ device_type = "cpu"; ++ reg = <34>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu34_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu35: cpu@35 { ++ device_type = "cpu"; ++ reg = <35>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu35_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu36: cpu@36 { ++ device_type = "cpu"; ++ reg = <36>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu36_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu37: cpu@37 { ++ device_type = "cpu"; ++ reg = <37>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu37_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu38: cpu@38 { ++ device_type = "cpu"; ++ reg = <38>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu38_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu39: cpu@39 { ++ device_type = "cpu"; ++ reg = <39>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu39_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu40: cpu@40 { ++ device_type = "cpu"; ++ reg = <40>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu40_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu41: cpu@41 { ++ device_type = "cpu"; ++ reg = <41>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu41_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu42: cpu@42 { ++ device_type = "cpu"; ++ reg = <42>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu42_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu43: cpu@43 { ++ device_type = "cpu"; ++ reg = <43>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu43_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu44: cpu@44 { ++ device_type = "cpu"; ++ reg = <44>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu44_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu45: cpu@45 { ++ device_type = "cpu"; ++ reg = <45>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu45_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu46: cpu@46 { ++ device_type = "cpu"; ++ reg = <46>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu46_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu47: cpu@47 { ++ device_type = "cpu"; ++ reg = <47>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu47_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu48: cpu@48 { ++ device_type = "cpu"; ++ reg = <48>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu48_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu49: cpu@49 { ++ device_type = "cpu"; ++ reg = <49>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu49_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu50: cpu@50 { ++ device_type = "cpu"; ++ reg = <50>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu50_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu51: cpu@51 { ++ device_type = "cpu"; ++ reg = <51>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu51_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu52: cpu@52 { ++ device_type = "cpu"; ++ reg = <52>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu52_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu53: cpu@53 { ++ device_type = "cpu"; ++ reg = <53>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu53_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu54: cpu@54 { ++ device_type = "cpu"; ++ reg = <54>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu54_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu55: cpu@55 { ++ device_type = "cpu"; ++ reg = <55>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <2>; ++ cpu55_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu56: cpu@56 { ++ device_type = "cpu"; ++ reg = <56>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu56_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu57: cpu@57 { ++ device_type = "cpu"; ++ reg = <57>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu57_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu58: cpu@58 { ++ device_type = "cpu"; ++ reg = <58>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu58_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu59: cpu@59 { ++ device_type = "cpu"; ++ reg = <59>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu59_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu60: cpu@60 { ++ device_type = "cpu"; ++ reg = <60>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu60_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu61: cpu@61 { ++ device_type = "cpu"; ++ reg = <61>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu61_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu62: cpu@62 { ++ device_type = "cpu"; ++ reg = <62>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu62_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ cpu63: cpu@63 { ++ device_type = "cpu"; ++ reg = <63>; ++ status = "okay"; ++ compatible = "riscv"; ++ riscv,isa = "rv64imafdcv"; ++ mmu-type = "riscv,sv39"; ++ numa-node-id = <3>; ++ cpu63_intc: interrupt-controller { ++ #interrupt-cells = <1>; ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts +new file mode 100644 +index 000000000000..00f2d5e2c674 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts +@@ -0,0 +1,163 @@ ++#include "mango.dtsi" ++#include "mango-pcie-4rc.dtsi" ++ ++/ { ++ info { ++ file-name = "mango-milkv-pioneer.dts"; ++ }; ++}; ++ ++&i2c1 { ++ mcu: sg2042mcu@17 { ++ compatible = "sophgo,sg20xx-mcu"; ++ reg = <0x17>; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ mango_srst: mango-reset@17 { ++ compatible = "mango,reset"; ++ reg = <0x17>; ++ }; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_acquire>; ++}; ++ ++&soc { ++ /delete-node/ ethernet@7040026000; ++ gpio-poweroff { ++ compatible = "gpio-keys"; ++ input-name = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_key>; ++ ++ power { ++ label = "GPIO Key Power"; ++ linux,code = <KEY_POWER>; ++ gpios = <&port0a 22 GPIO_ACTIVE_HIGH>; ++ linux,input-type = <1>; ++ debounce-interval = <100>; ++ }; ++ }; ++ ++ gpio-restart { ++ compatible = "gpio-keys"; ++ input-name = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&restart_key>; ++ ++ restart { ++ label = "GPIO Key Restart"; ++ linux,code = <KEY_RESTART>; ++ gpios = <&port0a 23 GPIO_ACTIVE_HIGH>; ++ linux,input-type = <1>; ++ debounce-interval = <100>; ++ }; ++ }; ++}; ++ ++&tach0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&fan0_acquire>; ++}; ++ ++&tach1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&fan1_acquire>; ++}; ++ ++/ { ++ pwmfan: pwm-fan { ++ compatible = "pwm-fan"; ++ pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns ++ pwm-names = "pwm0","pwm1"; ++ pwm_inuse = "pwm0"; ++ #cooling-cells = <2>; ++ cooling-levels = <1 1 1 1 1>; //total 255 ++ }; ++ ++ thermal_zones: thermal-zones { ++ soc { ++ polling-delay-passive = <1000>; /* milliseconds */ ++ polling-delay = <1000>; /* milliseconds */ ++ thermal-sensors = <&mcu 0>; ++ ++ trips { ++ soc_pwmfan_trip1: soc_pwmfan_trip@1 { ++ temperature = <30000>; /* millicelsius */ ++ hysteresis = <8000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip2: soc_pwmfan_trip@2 { ++ temperature = <40000>; /* millicelsius */ ++ hysteresis = <12000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip3: soc_pwmfan_trip@3 { ++ temperature = <50000>; /* millicelsius */ ++ hysteresis = <10000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip4: soc_pwmfan_trip@4 { ++ temperature = <60000>; /* millicelsius */ ++ hysteresis = <5000>; /* millicelsius */ ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&soc_pwmfan_trip1>; ++ cooling-device = <&pwmfan 0 1>; ++ }; ++ ++ map1 { ++ trip = <&soc_pwmfan_trip2>; ++ cooling-device = <&pwmfan 1 2>; ++ }; ++ ++ map2 { ++ trip = <&soc_pwmfan_trip3>; ++ cooling-device = <&pwmfan 2 3>; ++ }; ++ ++ map3 { ++ trip = <&soc_pwmfan_trip4>; ++ cooling-device = <&pwmfan 3 4>; ++ }; ++ }; ++ ++ }; ++ ++ board { ++ polling-delay-passive = <1000>; /* milliseconds */ ++ polling-delay = <1000>; /* milliseconds */ ++ thermal-sensors = <&mcu 1>; ++ ++ trips { ++ board_pwmfan_trip1: board_pwmfan_trip@1 { ++ temperature = <75000>; /* millicelsius */ ++ hysteresis = <8000>; /* millicelsius */ ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ map4 { ++ trip = <&board_pwmfan_trip1>; ++ cooling-device = <&pwmfan 3 4>; ++ }; ++ }; ++ }; ++ }; ++ ++}; ++ ++&chosen { ++ bootargs = "console=ttyS0,115200 console=tty1 earlycon maxcpus=1"; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi +new file mode 100644 +index 000000000000..fb4eb57d82f0 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi +@@ -0,0 +1,83 @@ ++#include <dt-bindings/interrupt-controller/irq.h> ++ ++#define SOC_PERIPHERAL_IRQ(nr) (nr) ++ ++/ { ++ pcie@7062000000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x00 0x7f>; ++ linux,pci-domain = <0>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x1>; ++ link-id = /bits/ 16 <0x0>; ++ top-intc-used = <1>; ++ top-intc-id = <0>; ++ msix-supported = <0>; ++ interrupt-parent = <&intc1>; ++ //interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>; ++ //interrupt-names = "msi"; ++ reg = <0x70 0x62000000 0x0 0x02000000>, ++ <0x48 0x00000000 0x0 0x00001000>; ++ reg-names = "reg", "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00000000 0x48 0x10000000 0x0 0x00800000>, ++ <0x42000000 0x0 0x20000000 0x48 0x20000000 0x0 0x50000000>, ++ <0x02000000 0x0 0x70000000 0x48 0x70000000 0x0 0x20000000>, ++ <0x43000000 0x49 0x00000000 0x49 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x4b 0x00000000 0x4b 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++ ++ pcie@f060000000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x80 0xff>; ++ linux,pci-domain = <1>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x0>; ++ link-id = /bits/ 16 <0x0>; ++ top-intc-used = <1>; ++ top-intc-id = <1>; ++ msix-supported = <0>; ++ interrupt-parent = <&intc2>; ++ //interrupts = <SOC_PERIPHERAL_IRQ(346) IRQ_TYPE_LEVEL_HIGH>; ++ //interrupt-names = "msi"; ++ reg = <0xf0 0x60000000 0x0 0x02000000>, ++ <0xc0 0x00000000 0x0 0x00001000>; ++ reg-names = "reg", "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00800000 0xc0 0x10800000 0x0 0x00800000>, ++ <0x42000000 0x0 0x90000000 0xc0 0x90000000 0x0 0x50000000>, ++ <0x02000000 0x0 0xe0000000 0xc0 0xe0000000 0x0 0x20000000>, ++ <0x43000000 0xc1 0x00000000 0xc1 0x00000000 0x2 0x00000000>, ++ <0x03000000 0xc3 0x00000000 0xc3 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi +new file mode 100644 +index 000000000000..0414f892bfb7 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi +@@ -0,0 +1,118 @@ ++#include <dt-bindings/interrupt-controller/irq.h> ++ ++#define SOC_PERIPHERAL_IRQ(nr) (nr) ++ ++/ { ++ pcie@7060000000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x0 0x3f>; ++ linux,pci-domain = <0>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x0>; ++ link-id = /bits/ 16 <0x0>; ++ top-intc-used = <0>; ++ top-intc-id = <0>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi"; ++ reg = <0x70 0x60000000 0x0 0x02000000>, ++ <0x40 0x00000000 0x0 0x00001000>; ++ reg-names = "reg", "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00000000 0x40 0x10000000 0x0 0x00400000>, ++ <0x42000000 0x0 0xc0000000 0x40 0xc0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, ++ <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++ ++ pcie@7060800000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x40 0x7f>; ++ linux,pci-domain = <1>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x0>; ++ link-id = /bits/ 16 <0x1>; ++ top-intc-used = <1>; ++ top-intc-id = <0>; ++ msix-supported = <0>; ++ interrupt-parent = <&intc1>; ++ //interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>; ++ //interrupt-names = "msi"; ++ reg = <0x44 0x00000000 0x0 0x00001000>; ++ reg-names = "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00400000 0x44 0x10400000 0x0 0x00400000>, ++ <0x42000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xc0000000 0x44 0xc0000000 0x0 0x20000000>, ++ <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++ ++ pcie@7062000000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x80 0xff>; ++ linux,pci-domain = <2>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x1>; ++ link-id = /bits/ 16 <0x0>; ++ top-intc-used = <0>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi"; ++ reg = <0x70 0x62000000 0x0 0x02000000>, ++ <0x48 0x00000000 0x0 0x00001000>; ++ reg-names = "reg", "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00800000 0x48 0x10800000 0x0 0x00800000>, ++ <0x42000000 0x0 0xc0000000 0x48 0xc0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, ++ <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi +new file mode 100644 +index 000000000000..296d4207c9b2 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi +@@ -0,0 +1,115 @@ ++#include <dt-bindings/interrupt-controller/irq.h> ++ ++#define SOC_PERIPHERAL_IRQ(nr) (nr) ++ ++/ { ++ pcie@7060000000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x0 0x3f>; ++ linux,pci-domain = <0>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x0>; ++ link-id = /bits/ 16 <0x0>; ++ top-intc-used = <0>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi"; ++ reg = <0x70 0x60000000 0x0 0x02000000>, ++ <0x40 0x00000000 0x0 0x00001000>; ++ reg-names = "reg", "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00000000 0x40 0x10000000 0x0 0x00400000>, ++ <0x42000000 0x0 0xc0000000 0x40 0xc0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, ++ <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++ ++ pcie@7060800000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x40 0x7f>; ++ linux,pci-domain = <1>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x0>; ++ link-id = /bits/ 16 <0x1>; ++ top-intc-used = <1>; ++ top-intc-id = <0>; ++ msix-supported = <0>; ++ interrupt-parent = <&intc1>; ++ reg = <0x44 0x00000000 0x0 0x00001000>; ++ reg-names = "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00400000 0x44 0x10400000 0x0 0x00400000>, ++ <0x42000000 0x0 0xc0000000 0x44 0xc0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, ++ <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++ ++ pcie@7062000000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x80 0xff>; ++ linux,pci-domain = <2>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x1>; ++ link-id = /bits/ 16 <0x0>; ++ top-intc-used = <0>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi"; ++ reg = <0x70 0x62000000 0x0 0x02000000>, ++ <0x48 0x00000000 0x0 0x00001000>; ++ reg-names = "reg", "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00800000 0x48 0x10800000 0x0 0x00800000>, ++ <0x42000000 0x0 0xc0000000 0x48 0xc0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, ++ <0x43000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>, ++ <0x03000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi +new file mode 100644 +index 000000000000..4fe6bd3f52a0 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi +@@ -0,0 +1,151 @@ ++#include <dt-bindings/interrupt-controller/irq.h> ++ ++#define SOC_PERIPHERAL_IRQ(nr) (nr) ++ ++/ { ++ pcie@7060000000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x0 0x3f>; ++ linux,pci-domain = <0>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x0>; ++ link-id = /bits/ 16 <0x0>; ++ top-intc-used = <0>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi"; ++ reg = <0x70 0x60000000 0x0 0x02000000>, ++ <0x40 0x00000000 0x0 0x00001000>; ++ reg-names = "reg", "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00000000 0x40 0x10000000 0x0 0x00400000>, ++ <0x42000000 0x0 0xc0000000 0x40 0xc0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, ++ <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++ ++ pcie@7060800000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x40 0x7f>; ++ linux,pci-domain = <1>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x0>; ++ link-id = /bits/ 16 <0x1>; ++ top-intc-used = <1>; ++ top-intc-id = <0>; ++ msix-supported = <0>; ++ interrupt-parent = <&intc1>; ++ reg = <0x44 0x00000000 0x0 0x00001000>; ++ reg-names = "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00400000 0x44 0x10400000 0x0 0x00400000>, ++ <0x42000000 0x0 0xc0000000 0x44 0xc0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, ++ <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++ ++ pcie@7062000000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x80 0xbf>; ++ linux,pci-domain = <2>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x1>; ++ link-id = /bits/ 16 <0x0>; ++ top-intc-used = <0>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi"; ++ reg = <0x70 0x62000000 0x0 0x02000000>, ++ <0x48 0x00000000 0x0 0x00001000>; ++ reg-names = "reg", "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00800000 0x48 0x10800000 0x0 0x00400000>, ++ <0x42000000 0x0 0xc0000000 0x48 0xc0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, ++ <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>, ++ <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++ ++ pcie@7062800000 { ++ compatible = "sophgo,cdns-pcie-host"; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0xc0 0xff>; ++ linux,pci-domain = <3>; ++ cdns,max-outbound-regions = <16>; ++ cdns,no-bar-match-nbits = <48>; ++ vendor-id = /bits/ 16 <0x1E30>; ++ device-id = /bits/ 16 <0x2042>; ++ pcie-id = /bits/ 16 <0x1>; ++ link-id = /bits/ 16 <0x1>; ++ top-intc-used = <1>; ++ top-intc-id = <0>; ++ msix-supported = <0>; ++ interrupt-parent = <&intc1>; ++ reg = <0x4c 0x00000000 0x0 0x00001000>; ++ reg-names = "cfg"; ++ ++ // IO, check IO_SPACE_LIMIT ++ // 32bit prefetchable memory ++ // 32bit non-prefetchable memory ++ // 64bit prefetchable memory ++ // 64bit non-prefetchable memory ++ ranges = <0x01000000 0x0 0x00c00000 0x4c 0x10c00000 0x0 0x00400000>, ++ <0x42000000 0x0 0xd0000000 0x4c 0xd0000000 0x0 0x20000000>, ++ <0x02000000 0x0 0xf0000000 0x4c 0xf0000000 0x0 0x10000000>, ++ <0x43000000 0x4d 0x00000000 0x4d 0x00000000 0x2 0x00000000>, ++ <0x03000000 0x4f 0x00000000 0x4f 0x00000000 0x1 0x00000000>; ++ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ status = "okay"; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi b/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi +new file mode 100644 +index 000000000000..f3fb2e39af26 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi +@@ -0,0 +1,434 @@ ++/ { ++ bmpctrl: pinctrl@50010400 { ++ compatible = "sophgo, pinctrl-mango"; ++ subctrl-syscon = <&top_misc>; ++ top_pinctl_offset = <0x1000>; ++ ++ lpc_acquire: lpc_acquire { ++ mux { ++ groups = "lpc_grp"; ++ function = "lpc_a"; ++ }; ++ }; ++ ++ lpc_release: lpc_release{ ++ mux { ++ groups = "lpc_grp"; ++ function = "lpc_r"; ++ }; ++ }; ++ ++ pcie_acquire: pcie_acquire { ++ mux { ++ groups = "pcie_grp"; ++ function = "pcie_a"; ++ }; ++ }; ++ ++ pcie_release: pcie_release{ ++ mux { ++ groups = "pcie_grp"; ++ function = "pcie_r"; ++ }; ++ }; ++ ++ spif_acquire: spif_acquire { ++ mux { ++ groups = "spif_grp"; ++ function = "spif_a"; ++ }; ++ }; ++ ++ spif_release: spif_release{ ++ mux { ++ groups = "spif_grp"; ++ function = "spif_r"; ++ }; ++ }; ++ ++ emmc_acquire: emmc_acquire { ++ mux { ++ groups = "emmc_grp"; ++ function = "emmc_a"; ++ }; ++ }; ++ ++ emmc_release: emmc_release{ ++ mux { ++ groups = "emmc_grp"; ++ function = "emmc_r"; ++ }; ++ }; ++ ++ sdio_acquire: sdio_acquire { ++ mux { ++ groups = "sdio_grp"; ++ function = "sdio_a"; ++ }; ++ }; ++ ++ sdio_release: sdio_release{ ++ mux { ++ groups = "sdio_grp"; ++ function = "sdio_r"; ++ }; ++ }; ++ ++ eth0_acquire: eth0_acquire { ++ mux { ++ groups = "eth0_grp"; ++ function = "eth0_a"; ++ }; ++ }; ++ ++ eth0_release: eth0_release{ ++ mux { ++ groups = "eth0_grp"; ++ function = "eth0_r"; ++ }; ++ }; ++ ++ pwm0_acquire: pwm0_acquire { ++ mux { ++ groups = "pwm0_grp"; ++ function = "pwm0_a"; ++ }; ++ }; ++ ++ pwm0_release: pwm0_release{ ++ mux { ++ groups = "pwm0_grp"; ++ function = "pwm0_r"; ++ }; ++ }; ++ ++ pwm1_acquire: pwm1_acquire { ++ mux { ++ groups = "pwm1_grp"; ++ function = "pwm1_a"; ++ }; ++ }; ++ ++ pwm1_release: pwm1_release{ ++ mux { ++ groups = "pwm1_grp"; ++ function = "pwm1_r"; ++ }; ++ }; ++ ++ pwm2_acquire: pwm2_acquire { ++ mux { ++ groups = "pwm2_grp"; ++ function = "pwm2_a"; ++ }; ++ }; ++ ++ pwm2_release: pwm2_release{ ++ mux { ++ groups = "pwm2_grp"; ++ function = "pwm2_r"; ++ }; ++ }; ++ ++ pwm3_acquire: pwm3_acquire { ++ mux { ++ groups = "pwm3_grp"; ++ function = "pwm3_a"; ++ }; ++ }; ++ ++ pwm3_release: pwm3_release{ ++ mux { ++ groups = "pwm3_grp"; ++ function = "pwm3_r"; ++ }; ++ }; ++ ++ fan0_acquire: fan0_acquire { ++ mux { ++ groups = "fan0_grp"; ++ function = "fan0_a"; ++ }; ++ }; ++ ++ fan0_release: fan0_release{ ++ mux { ++ groups = "fan0_grp"; ++ function = "fan0_r"; ++ }; ++ }; ++ ++ fan1_acquire: fan1_acquire { ++ mux { ++ groups = "fan1_grp"; ++ function = "fan1_a"; ++ }; ++ }; ++ ++ fan1_release: fan1_release{ ++ mux { ++ groups = "fan1_grp"; ++ function = "fan1_r"; ++ }; ++ }; ++ ++ fan2_acquire: fan2_acquire { ++ mux { ++ groups = "fan2_grp"; ++ function = "fan2_a"; ++ }; ++ }; ++ ++ fan2_release: fan2_release{ ++ mux { ++ roups = "fan2_grp"; ++ function = "fan2_r"; ++ }; ++ }; ++ ++ fan3_acquire: fan3_acquire { ++ mux { ++ groups = "fan3_grp"; ++ function = "fan3_a"; ++ }; ++ }; ++ ++ fan3_release: fan3_release{ ++ mux { ++ groups = "fan3_grp"; ++ function = "fan3_r"; ++ }; ++ }; ++ ++ i2c0_acquire: i2c0_acquire { ++ mux { ++ groups = "i2c0_grp"; ++ function = "i2c0_a"; ++ }; ++ }; ++ ++ i2c0_release: i2c0_release{ ++ mux { ++ groups = "i2c0_grp"; ++ function = "i2c0_r"; ++ }; ++ }; ++ ++ i2c1_acquire: i2c1_acquire { ++ mux { ++ groups = "i2c1_grp"; ++ function = "i2c1_a"; ++ }; ++ }; ++ ++ i2c1_release: i2c1_release{ ++ mux { ++ groups = "i2c1_grp"; ++ function = "i2c1_r"; ++ }; ++ }; ++ ++ i2c2_acquire: i2c2_acquire { ++ mux { ++ groups = "i2c2_grp"; ++ function = "i2c2_a"; ++ }; ++ }; ++ ++ i2c2_release: i2c2_release{ ++ mux { ++ groups = "i2c2_grp"; ++ function = "i2c2_r"; ++ }; ++ }; ++ ++ i2c3_acquire: i2c3_acquire { ++ mux { ++ groups = "i2c3_grp"; ++ function = "i2c3_a"; ++ }; ++ }; ++ ++ i2c3_release: i2c3_release{ ++ mux { ++ groups = "i2c3_grp"; ++ function = "i2c3_r"; ++ }; ++ }; ++ ++ uart0_acquire: uart0_acquire { ++ mux { ++ groups = "uart0_grp"; ++ function = "uart0_a"; ++ }; ++ }; ++ ++ uart0_release: uart0_release{ ++ mux { ++ groups = "uart0_grp"; ++ function = "uart0_r"; ++ }; ++ }; ++ ++ uart1_acquire: uart1_acquire { ++ mux { ++ groups = "uart1_grp"; ++ function = "uart1_a"; ++ }; ++ }; ++ ++ uart1_release: uart1_release{ ++ mux { ++ groups = "uart1_grp"; ++ function = "uart1_r"; ++ }; ++ }; ++ ++ uart2_acquire: uart2_acquire { ++ mux { ++ groups = "uart2_grp"; ++ function = "uart2_a"; ++ }; ++ }; ++ ++ uart2_release: uart2_release{ ++ mux { ++ groups = "uart2_grp"; ++ function = "uart2_r"; ++ }; ++ }; ++ ++ uart3_acquire: uart3_acquire { ++ mux { ++ groups = "uart3_grp"; ++ function = "uart3_a"; ++ }; ++ }; ++ ++ uart3_release: uart3_release{ ++ mux { ++ groups = "uart3_grp"; ++ function = "uart3_r"; ++ }; ++ }; ++ ++ spi0_acquire: spi0_acquire { ++ mux { ++ groups = "spi0_grp"; ++ function = "spi0_a"; ++ }; ++ }; ++ ++ spi0_release: spi0_release{ ++ mux { ++ groups = "spi0_grp"; ++ function = "spi0_r"; ++ }; ++ }; ++ ++ spi1_acquire: spi1_acquire { ++ mux { ++ groups = "spi1_grp"; ++ function = "spi1_a"; ++ }; ++ }; ++ ++ spi1_release: spi1_release{ ++ mux { ++ groups = "spi1_grp"; ++ function = "spi1_r"; ++ }; ++ }; ++ ++ jtag0_acquire: jtag0_acquire { ++ mux { ++ groups = "jtag0_grp"; ++ function = "jtag0_a"; ++ }; ++ }; ++ ++ jtag0_release: jtag0_release{ ++ mux { ++ groups = "jtag0_grp"; ++ function = "jtag0_r"; ++ }; ++ }; ++ ++ jtag1_acquire: jtag1_acquire { ++ mux { ++ groups = "jtag1_grp"; ++ function = "jtag1_a"; ++ }; ++ }; ++ ++ jtag1_release: jtag1_release{ ++ mux { ++ groups = "jtag1_grp"; ++ function = "jtag1_r"; ++ }; ++ }; ++ ++ jtag2_acquire: jtag2_acquire { ++ mux { ++ groups = "jtag2_grp"; ++ function = "jtag2_a"; ++ }; ++ }; ++ ++ jtag2_release: jtag2_release{ ++ mux { ++ groups = "jtag2_grp"; ++ function = "jtag2_r"; ++ }; ++ }; ++ ++ gpio2_acquire: gpio2_acquire { ++ mux { ++ pins = <127>; ++ function = "gpio0_a"; ++ }; ++ }; ++ ++ gpio3_release: gpio3_release { ++ mux { ++ pins = <128>; ++ function = "gpio0_r"; ++ }; ++ }; ++ ++ gpio5_release: gpio5_release { ++ mux { ++ pins = <130>; ++ function = "gpio0_r"; ++ }; ++ }; ++ ++ pwr_key: pwr-key { ++ mux { ++ pins = <147>; ++ function = "gpio0_a"; ++ }; ++ }; ++ ++ restart_key: restart-key { ++ mux { ++ pins = <148>; ++ function = "gpio0_a"; ++ }; ++ }; ++ ++ dbgi2c_acquire: dbgi2c_acquire { ++ mux { ++ groups = "dbgi2c_grp"; ++ function = "dbgi2c_a"; ++ }; ++ }; ++ ++ dbgi2c_release: dbgi2c_release{ ++ mux { ++ groups = "dbgi2c_grp"; ++ function = "dbgi2c_r"; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts +new file mode 100644 +index 000000000000..78495159bbb4 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts +@@ -0,0 +1,137 @@ ++#include "mango.dtsi" ++#include "mango-pcie-3rc-v2.dtsi" ++ ++/ { ++ info { ++ file-name = "mango-sophgo-x4evb.dts"; ++ }; ++}; ++ ++&i2c1 { ++ mcu: sg2042mcu@17 { ++ compatible = "sophgo,sg20xx-mcu"; ++ reg = <0x17>; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ mango_srst: mango-reset@17 { ++ compatible = "mango,reset"; ++ reg = <0x17>; ++ }; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_acquire>; ++}; ++ ++&tach0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&fan0_acquire>; ++}; ++ ++&tach1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&fan1_acquire>; ++}; ++ ++ðernet0 { ++ max-speed = <1000>; ++ eth-sophgo-config { ++ autoneg = "enable"; ++ }; ++}; ++ ++&soc { ++ /delete-node/ flash-controller@7000180000; ++}; ++ ++/ { ++ pwmfan: pwm-fan { ++ compatible = "pwm-fan"; ++ pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns ++ pwm-names = "pwm0","pwm1"; ++ pwm_inuse = "pwm0"; ++ #cooling-cells = <2>; ++ cooling-levels = <102 127 178 229 254>; //total 255 ++ }; ++ ++ thermal_zones: thermal-zones { ++ soc { ++ polling-delay-passive = <1000>; /* milliseconds */ ++ polling-delay = <1000>; /* milliseconds */ ++ thermal-sensors = <&mcu 0>; ++ ++ trips { ++ soc_pwmfan_trip1: soc_pwmfan_trip@1 { ++ temperature = <40000>; /* millicelsius */ ++ hysteresis = <8000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip2: soc_pwmfan_trip@2 { ++ temperature = <58000>; /* millicelsius */ ++ hysteresis = <12000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip3: soc_pwmfan_trip@3 { ++ temperature = <70000>; /* millicelsius */ ++ hysteresis = <10000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip4: soc_pwmfan_trip@4 { ++ temperature = <85000>; /* millicelsius */ ++ hysteresis = <5000>; /* millicelsius */ ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&soc_pwmfan_trip1>; ++ cooling-device = <&pwmfan 0 1>; ++ }; ++ ++ map1 { ++ trip = <&soc_pwmfan_trip2>; ++ cooling-device = <&pwmfan 1 2>; ++ }; ++ ++ map2 { ++ trip = <&soc_pwmfan_trip3>; ++ cooling-device = <&pwmfan 2 3>; ++ }; ++ ++ map3 { ++ trip = <&soc_pwmfan_trip4>; ++ cooling-device = <&pwmfan 3 4>; ++ }; ++ }; ++ ++ }; ++ ++ board { ++ polling-delay-passive = <1000>; /* milliseconds */ ++ polling-delay = <1000>; /* milliseconds */ ++ thermal-sensors = <&mcu 1>; ++ ++ trips { ++ board_pwmfan_trip1: board_pwmfan_trip@1 { ++ temperature = <75000>; /* millicelsius */ ++ hysteresis = <8000>; /* millicelsius */ ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ map4 { ++ trip = <&board_pwmfan_trip1>; ++ cooling-device = <&pwmfan 3 4>; ++ }; ++ }; ++ }; ++ }; ++ ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts +new file mode 100644 +index 000000000000..83e4f1411f2e +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts +@@ -0,0 +1,165 @@ ++#include "mango.dtsi" ++#include "mango-pcie-3rc.dtsi" ++ ++/ { ++ info { ++ file-name = "mango-sophgo-x8evb.dts"; ++ }; ++}; ++ ++&i2c1 { ++ mcu: sg2042mcu@17 { ++ compatible = "sophgo,sg20xx-mcu"; ++ reg = <0x17>; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ mango_srst: mango-reset@17 { ++ compatible = "mango,reset"; ++ reg = <0x17>; ++ }; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_acquire>; ++}; ++ ++&soc { ++ gpio-poweroff { ++ compatible = "gpio-keys"; ++ input-name = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwr_key>; ++ ++ power { ++ label = "GPIO Key Power"; ++ linux,code = <KEY_POWER>; ++ gpios = <&port0a 22 GPIO_ACTIVE_HIGH>; ++ linux,input-type = <1>; ++ debounce-interval = <100>; ++ }; ++ }; ++ ++ gpio-restart { ++ compatible = "gpio-keys"; ++ input-name = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&restart_key>; ++ ++ restart { ++ label = "GPIO Key Restart"; ++ linux,code = <KEY_RESTART>; ++ gpios = <&port0a 23 GPIO_ACTIVE_HIGH>; ++ linux,input-type = <1>; ++ debounce-interval = <100>; ++ }; ++ }; ++}; ++ ++&tach0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&fan0_acquire>; ++}; ++ ++&tach1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&fan1_acquire>; ++}; ++ ++ðernet0 { ++ max-speed = <1000>; ++ eth-sophgo-config { ++ autoneg = "enable"; ++ }; ++}; ++ ++/ { ++ pwmfan: pwm-fan { ++ compatible = "pwm-fan"; ++ pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns ++ pwm-names = "pwm0","pwm1"; ++ pwm_inuse = "pwm0"; ++ #cooling-cells = <2>; ++ cooling-levels = <153 128 77 26 1>; //total 255 ++ }; ++ ++ thermal_zones: thermal-zones { ++ soc { ++ polling-delay-passive = <1000>; /* milliseconds */ ++ polling-delay = <1000>; /* milliseconds */ ++ thermal-sensors = <&mcu 0>; ++ ++ trips { ++ soc_pwmfan_trip1: soc_pwmfan_trip@1 { ++ temperature = <40000>; /* millicelsius */ ++ hysteresis = <8000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip2: soc_pwmfan_trip@2 { ++ temperature = <58000>; /* millicelsius */ ++ hysteresis = <12000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip3: soc_pwmfan_trip@3 { ++ temperature = <70000>; /* millicelsius */ ++ hysteresis = <10000>; /* millicelsius */ ++ type = "active"; ++ }; ++ ++ soc_pwmfan_trip4: soc_pwmfan_trip@4 { ++ temperature = <85000>; /* millicelsius */ ++ hysteresis = <5000>; /* millicelsius */ ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&soc_pwmfan_trip1>; ++ cooling-device = <&pwmfan 0 1>; ++ }; ++ ++ map1 { ++ trip = <&soc_pwmfan_trip2>; ++ cooling-device = <&pwmfan 1 2>; ++ }; ++ ++ map2 { ++ trip = <&soc_pwmfan_trip3>; ++ cooling-device = <&pwmfan 2 3>; ++ }; ++ ++ map3 { ++ trip = <&soc_pwmfan_trip4>; ++ cooling-device = <&pwmfan 3 4>; ++ }; ++ }; ++ ++ }; ++ ++ board { ++ polling-delay-passive = <1000>; /* milliseconds */ ++ polling-delay = <1000>; /* milliseconds */ ++ thermal-sensors = <&mcu 1>; ++ ++ trips { ++ board_pwmfan_trip1: board_pwmfan_trip@1 { ++ temperature = <75000>; /* millicelsius */ ++ hysteresis = <8000>; /* millicelsius */ ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ map4 { ++ trip = <&board_pwmfan_trip1>; ++ cooling-device = <&pwmfan 3 4>; ++ }; ++ }; ++ }; ++ }; ++ ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi b/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi +new file mode 100644 +index 000000000000..6d364cf6b3c5 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi +@@ -0,0 +1,62 @@ ++#include <dt-bindings/interrupt-controller/irq.h> ++ ++#define SOC_PERIPHERAL_IRQ(nr) (nr) ++ ++/ { ++ intc2: top_intc@f030010300 { ++ compatible = "sophgo,top-intc"; ++ reg = <0xf0 0x300102E0 0x0 0x4>, ++ <0xf0 0x30010300 0x0 0x4>, ++ <0xf0 0x30010304 0x0 0x4>; ++ reg-names = "sta", "set", "clr"; ++ reg-bitwidth = <32>; ++ top-intc-id = <1>; ++ interrupt-controller; ++ #interrupt-cells = <0x1>; // only applies to child node ++ for-msi; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(288) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(289) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(290) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(291) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(292) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(293) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(294) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(295) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(296) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(297) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(298) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(299) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(300) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(301) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(302) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(303) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(304) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(305) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(306) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(307) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(308) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(309) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(310) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(311) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(312) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(313) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(314) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(315) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(316) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(317) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(318) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(319) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi0", "msi1", "msi2", "msi3", ++ "msi4", "msi5", "msi6", "msi7", ++ "msi8", "msi9", "msi10", "msi11", ++ "msi12", "msi13", "msi14", "msi15", ++ "msi16", "msi17", "msi18", "msi19", ++ "msi20", "msi21", "msi22", "msi23", ++ "msi24", "msi25", "msi26", "msi27", ++ "msi28", "msi29", "msi30", "msi31"; ++ ++ }; ++ ++}; +diff --git a/arch/riscv/boot/dts/sophgo/mango.dtsi b/arch/riscv/boot/dts/sophgo/mango.dtsi +new file mode 100644 +index 000000000000..9ac0898b0906 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/mango.dtsi +@@ -0,0 +1,941 @@ ++/dts-v1/; ++#include <dt-bindings/clock/sophgo.h> ++#include <dt-bindings/clock/sophgo-mango-clock.h> ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/input/input.h> ++#include <dt-bindings/reset/sophgo-mango-resets.h> ++#include <dt-bindings/interrupt-controller/irq.h> ++ ++#include "mango-cpus-socket0.dtsi" ++#include "mango-clock-socket0.dtsi" ++#include "mango-pinctrl.dtsi" ++ ++#define SOC_PERIPHERAL_IRQ(nr) (nr) ++ ++/ { ++ model = "Sophgo Mango"; ++ compatible = "sophgo,mango"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ dma-noncoherent; ++ ++ distance-map { ++ compatible = "numa-distance-map-v1"; ++ distance-matrix = <0 0 10>, ++ <0 1 15>, ++ <0 2 25>, ++ <0 3 30>, ++ <1 0 15>, ++ <1 1 10>, ++ <1 2 30>, ++ <1 3 25>, ++ <2 0 25>, ++ <2 1 30>, ++ <2 2 10>, ++ <2 3 15>, ++ <3 0 30>, ++ <3 1 25>, ++ <3 2 15>, ++ <3 3 10>; ++ }; ++ ++ pmu { ++ compatible = "riscv,pmu"; ++ riscv,event-to-mhpmevent = ++ <0x00003 0x00000000 0x00000010>, ++ <0x00004 0x00000000 0x00000011>, ++ <0x00005 0x00000000 0x00000007>, ++ <0x00006 0x00000000 0x00000006>, ++ <0x00008 0x00000000 0x00000027>, ++ <0x00009 0x00000000 0x00000028>, ++ <0x10000 0x00000000 0x0000000c>, ++ <0x10001 0x00000000 0x0000000d>, ++ <0x10002 0x00000000 0x0000000e>, ++ <0x10003 0x00000000 0x0000000f>, ++ <0x10008 0x00000000 0x00000001>, ++ <0x10009 0x00000000 0x00000002>, ++ <0x10010 0x00000000 0x00000010>, ++ <0x10011 0x00000000 0x00000011>, ++ <0x10012 0x00000000 0x00000012>, ++ <0x10013 0x00000000 0x00000013>, ++ <0x10019 0x00000000 0x00000004>, ++ <0x10021 0x00000000 0x00000003>, ++ <0x10030 0x00000000 0x0000001c>, ++ <0x10031 0x00000000 0x0000001b>; ++ riscv,event-to-mhpmcounters = ++ <0x00003 0x00003 0xfffffff8>, ++ <0x00004 0x00004 0xfffffff8>, ++ <0x00005 0x00005 0xfffffff8>, ++ <0x00006 0x00006 0xfffffff8>, ++ <0x00007 0x00007 0xfffffff8>, ++ <0x00008 0x00008 0xfffffff8>, ++ <0x00009 0x00009 0xfffffff8>, ++ <0x0000a 0x0000a 0xfffffff8>, ++ <0x10000 0x10000 0xfffffff8>, ++ <0x10001 0x10001 0xfffffff8>, ++ <0x10002 0x10002 0xfffffff8>, ++ <0x10003 0x10003 0xfffffff8>, ++ <0x10008 0x10008 0xfffffff8>, ++ <0x10009 0x10009 0xfffffff8>, ++ <0x10010 0x10010 0xfffffff8>, ++ <0x10011 0x10011 0xfffffff8>, ++ <0x10012 0x10012 0xfffffff8>, ++ <0x10013 0x10013 0xfffffff8>, ++ <0x10019 0x10019 0xfffffff8>, ++ <0x10021 0x10021 0xfffffff8>, ++ <0x10030 0x10030 0xfffffff8>, ++ <0x10031 0x10031 0xfffffff8>; ++ riscv,raw-event-to-mhpmcounters = ++ <0x00000000 0x00000001 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000002 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000003 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000004 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000005 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000006 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000007 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000008 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000009 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000a 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000b 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000c 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000d 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000e 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000f 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000010 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000011 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000012 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000013 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000014 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000015 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000016 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000017 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000018 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000019 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001a 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001b 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001c 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001d 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001e 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001f 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000020 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000021 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000022 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000023 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000024 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000025 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000026 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000027 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000028 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000029 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000002a 0xffffffff 0xffffffff 0xfffffff8>; ++ }; ++ ++ soc: soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ compatible = "simple-bus"; ++ ranges; ++ dma-ranges = <0x0 0x0 0x0 0x0 0x1f 0x0>; ++ ++ clint_mswi: clint-mswi@7094000000 { ++ compatible = "thead,c900-clint-mswi"; ++ reg = <0x00000070 0x94000000 0x00000000 0x00004000>; ++ interrupts-extended = < ++ &cpu0_intc 3 ++ &cpu1_intc 3 ++ &cpu2_intc 3 ++ &cpu3_intc 3 ++ &cpu4_intc 3 ++ &cpu5_intc 3 ++ &cpu6_intc 3 ++ &cpu7_intc 3 ++ &cpu8_intc 3 ++ &cpu9_intc 3 ++ &cpu10_intc 3 ++ &cpu11_intc 3 ++ &cpu12_intc 3 ++ &cpu13_intc 3 ++ &cpu14_intc 3 ++ &cpu15_intc 3 ++ &cpu16_intc 3 ++ &cpu17_intc 3 ++ &cpu18_intc 3 ++ &cpu19_intc 3 ++ &cpu20_intc 3 ++ &cpu21_intc 3 ++ &cpu22_intc 3 ++ &cpu23_intc 3 ++ &cpu24_intc 3 ++ &cpu25_intc 3 ++ &cpu26_intc 3 ++ &cpu27_intc 3 ++ &cpu28_intc 3 ++ &cpu29_intc 3 ++ &cpu30_intc 3 ++ &cpu31_intc 3 ++ &cpu32_intc 3 ++ &cpu33_intc 3 ++ &cpu34_intc 3 ++ &cpu35_intc 3 ++ &cpu36_intc 3 ++ &cpu37_intc 3 ++ &cpu38_intc 3 ++ &cpu39_intc 3 ++ &cpu40_intc 3 ++ &cpu41_intc 3 ++ &cpu42_intc 3 ++ &cpu43_intc 3 ++ &cpu44_intc 3 ++ &cpu45_intc 3 ++ &cpu46_intc 3 ++ &cpu47_intc 3 ++ &cpu48_intc 3 ++ &cpu49_intc 3 ++ &cpu50_intc 3 ++ &cpu51_intc 3 ++ &cpu52_intc 3 ++ &cpu53_intc 3 ++ &cpu54_intc 3 ++ &cpu55_intc 3 ++ &cpu56_intc 3 ++ &cpu57_intc 3 ++ &cpu58_intc 3 ++ &cpu59_intc 3 ++ &cpu60_intc 3 ++ &cpu61_intc 3 ++ &cpu62_intc 3 ++ &cpu63_intc 3 ++ >; ++ }; ++ ++ clint_mtimer0: clint-mtimer@70ac000000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu0_intc 7 ++ &cpu1_intc 7 ++ &cpu2_intc 7 ++ &cpu3_intc 7 ++ >; ++ }; ++ ++ clint_mtimer1: clint-mtimer@70ac010000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu4_intc 7 ++ &cpu5_intc 7 ++ &cpu6_intc 7 ++ &cpu7_intc 7 ++ >; ++ }; ++ ++ clint_mtimer2: clint-mtimer@70ac020000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu8_intc 7 ++ &cpu9_intc 7 ++ &cpu10_intc 7 ++ &cpu11_intc 7 ++ >; ++ }; ++ ++ clint_mtimer3: clint-mtimer@70ac030000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu12_intc 7 ++ &cpu13_intc 7 ++ &cpu14_intc 7 ++ &cpu15_intc 7 ++ >; ++ }; ++ ++ clint_mtimer4: clint-mtimer@70ac040000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu16_intc 7 ++ &cpu17_intc 7 ++ &cpu18_intc 7 ++ &cpu19_intc 7 ++ >; ++ }; ++ ++ clint_mtimer5: clint-mtimer@70ac050000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu20_intc 7 ++ &cpu21_intc 7 ++ &cpu22_intc 7 ++ &cpu23_intc 7 ++ >; ++ }; ++ ++ clint_mtimer6: clint-mtimer@70ac060000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu24_intc 7 ++ &cpu25_intc 7 ++ &cpu26_intc 7 ++ &cpu27_intc 7 ++ >; ++ }; ++ ++ clint_mtimer7: clint-mtimer@70ac070000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu28_intc 7 ++ &cpu29_intc 7 ++ &cpu30_intc 7 ++ &cpu31_intc 7 ++ >; ++ }; ++ ++ clint_mtimer8: clint-mtimer@70ac080000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu32_intc 7 ++ &cpu33_intc 7 ++ &cpu34_intc 7 ++ &cpu35_intc 7 ++ >; ++ }; ++ ++ clint_mtimer9: clint-mtimer@70ac090000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu36_intc 7 ++ &cpu37_intc 7 ++ &cpu38_intc 7 ++ &cpu39_intc 7 ++ >; ++ }; ++ ++ clint_mtimer10: clint-mtimer@70ac0a0000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu40_intc 7 ++ &cpu41_intc 7 ++ &cpu42_intc 7 ++ &cpu43_intc 7 ++ >; ++ }; ++ ++ clint_mtimer11: clint-mtimer@70ac0b0000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu44_intc 7 ++ &cpu45_intc 7 ++ &cpu46_intc 7 ++ &cpu47_intc 7 ++ >; ++ }; ++ ++ clint_mtimer12: clint-mtimer@70ac0c0000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu48_intc 7 ++ &cpu49_intc 7 ++ &cpu50_intc 7 ++ &cpu51_intc 7 ++ >; ++ }; ++ ++ clint_mtimer13: clint-mtimer@70ac0d0000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu52_intc 7 ++ &cpu53_intc 7 ++ &cpu54_intc 7 ++ &cpu55_intc 7 ++ >; ++ }; ++ ++ clint_mtimer14: clint-mtimer@70ac0e0000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu56_intc 7 ++ &cpu57_intc 7 ++ &cpu58_intc 7 ++ &cpu59_intc 7 ++ >; ++ }; ++ ++ clint_mtimer15: clint-mtimer@70ac0f0000 { ++ compatible = "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>; ++ interrupts-extended = < ++ &cpu60_intc 7 ++ &cpu61_intc 7 ++ &cpu62_intc 7 ++ &cpu63_intc 7 ++ >; ++ }; ++ ++ intc: interrupt-controller@7090000000 { ++ #address-cells = <0>; ++ #interrupt-cells = <2>; ++ compatible = "thead,c900-plic"; ++ interrupt-controller; ++ interrupts-extended = < ++ &cpu0_intc 11 &cpu0_intc 9 ++ &cpu1_intc 11 &cpu1_intc 9 ++ &cpu2_intc 11 &cpu2_intc 9 ++ &cpu3_intc 11 &cpu3_intc 9 ++ &cpu4_intc 11 &cpu4_intc 9 ++ &cpu5_intc 11 &cpu5_intc 9 ++ &cpu6_intc 11 &cpu6_intc 9 ++ &cpu7_intc 11 &cpu7_intc 9 ++ &cpu8_intc 11 &cpu8_intc 9 ++ &cpu9_intc 11 &cpu9_intc 9 ++ &cpu10_intc 11 &cpu10_intc 9 ++ &cpu11_intc 11 &cpu11_intc 9 ++ &cpu12_intc 11 &cpu12_intc 9 ++ &cpu13_intc 11 &cpu13_intc 9 ++ &cpu14_intc 11 &cpu14_intc 9 ++ &cpu15_intc 11 &cpu15_intc 9 ++ &cpu16_intc 11 &cpu16_intc 9 ++ &cpu17_intc 11 &cpu17_intc 9 ++ &cpu18_intc 11 &cpu18_intc 9 ++ &cpu19_intc 11 &cpu19_intc 9 ++ &cpu20_intc 11 &cpu20_intc 9 ++ &cpu21_intc 11 &cpu21_intc 9 ++ &cpu22_intc 11 &cpu22_intc 9 ++ &cpu23_intc 11 &cpu23_intc 9 ++ &cpu24_intc 11 &cpu24_intc 9 ++ &cpu25_intc 11 &cpu25_intc 9 ++ &cpu26_intc 11 &cpu26_intc 9 ++ &cpu27_intc 11 &cpu27_intc 9 ++ &cpu28_intc 11 &cpu28_intc 9 ++ &cpu29_intc 11 &cpu29_intc 9 ++ &cpu30_intc 11 &cpu30_intc 9 ++ &cpu31_intc 11 &cpu31_intc 9 ++ &cpu32_intc 11 &cpu32_intc 9 ++ &cpu33_intc 11 &cpu33_intc 9 ++ &cpu34_intc 11 &cpu34_intc 9 ++ &cpu35_intc 11 &cpu35_intc 9 ++ &cpu36_intc 11 &cpu36_intc 9 ++ &cpu37_intc 11 &cpu37_intc 9 ++ &cpu38_intc 11 &cpu38_intc 9 ++ &cpu39_intc 11 &cpu39_intc 9 ++ &cpu40_intc 11 &cpu40_intc 9 ++ &cpu41_intc 11 &cpu41_intc 9 ++ &cpu42_intc 11 &cpu42_intc 9 ++ &cpu43_intc 11 &cpu43_intc 9 ++ &cpu44_intc 11 &cpu44_intc 9 ++ &cpu45_intc 11 &cpu45_intc 9 ++ &cpu46_intc 11 &cpu46_intc 9 ++ &cpu47_intc 11 &cpu47_intc 9 ++ &cpu48_intc 11 &cpu48_intc 9 ++ &cpu49_intc 11 &cpu49_intc 9 ++ &cpu50_intc 11 &cpu50_intc 9 ++ &cpu51_intc 11 &cpu51_intc 9 ++ &cpu52_intc 11 &cpu52_intc 9 ++ &cpu53_intc 11 &cpu53_intc 9 ++ &cpu54_intc 11 &cpu54_intc 9 ++ &cpu55_intc 11 &cpu55_intc 9 ++ &cpu56_intc 11 &cpu56_intc 9 ++ &cpu57_intc 11 &cpu57_intc 9 ++ &cpu58_intc 11 &cpu58_intc 9 ++ &cpu59_intc 11 &cpu59_intc 9 ++ &cpu60_intc 11 &cpu60_intc 9 ++ &cpu61_intc 11 &cpu61_intc 9 ++ &cpu62_intc 11 &cpu62_intc 9 ++ &cpu63_intc 11 &cpu63_intc 9 ++ >; ++ reg = <0x00000070 0x90000000 0x00000000 0x04000000>; ++ reg-names = "control"; ++ riscv,max-priority = <7>; ++ riscv,ndev = <224>; ++ }; ++ ++ timer0: dw-apb-timer0@7030003000 { ++ compatible = "snps,dw-apb-timer"; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_LEVEL_HIGH>; ++ reg = <0x70 0x30003000 0x0 0x14>; ++ clocks = <&div_clk GATE_CLK_TIMER1>, ++ <&div_clk GATE_CLK_APB_TIMER>; ++ clock-names = "timer", "pclk"; ++ clk-drv-rating = <300>; ++ }; ++ ++ timer1: dw-apb-timer1@7030003014 { ++ compatible = "snps,dw-apb-timer"; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_LEVEL_HIGH>; ++ reg = <0x70 0x30003014 0x0 0x10>; ++ clocks = <&div_clk GATE_CLK_TIMER2>, ++ <&div_clk GATE_CLK_APB_TIMER>; ++ clock-names = "timer", "pclk"; ++ clk-drv-rating = <300>; ++ }; ++ ++ top_misc: top_misc_ctrl@7030010000 { ++ compatible = "syscon"; ++ reg = <0x70 0x30010000 0x0 0x8000>; ++ }; ++ ++ rst: reset-controller { ++ #reset-cells = <1>; ++ compatible = "bitmain,reset"; ++ subctrl-syscon = <&top_misc>; ++ top_rst_offset = <0x3000>; ++ nr_resets = <RST_MAX_NUM>; ++ }; ++ ++ i2c0: i2c@7030005000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,designware-i2c"; ++ clocks = <&div_clk GATE_CLK_APB_I2C>; ++ clock-names = "clk_gate_apb_i2c"; ++ reg = <0x70 0x30005000 0x0 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(101) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <100000>; ++ resets = <&rst RST_I2C0>; ++ reset-names = "i2c0"; ++ }; ++ ++ i2c1: i2c@7030006000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,designware-i2c"; ++ clocks = <&div_clk GATE_CLK_APB_I2C>; ++ clock-names = "clk_gate_apb_i2c"; ++ reg = <0x70 0x30006000 0x0 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(102) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <100000>; ++ resets = <&rst RST_I2C1>; ++ reset-names = "i2c1"; ++ }; ++ ++ i2c2: i2c@7030007000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,designware-i2c"; ++ clocks = <&div_clk GATE_CLK_APB_I2C>; ++ clock-names = "clk_gate_apb_i2c"; ++ reg = <0x70 0x30007000 0x0 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(103) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <100000>; ++ resets = <&rst RST_I2C2>; ++ reset-names = "i2c2"; ++ }; ++ ++ i2c3: i2c@7030008000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,designware-i2c"; ++ clocks = <&div_clk GATE_CLK_APB_I2C>; ++ clock-names = "clk_gate_apb_i2c"; ++ reg = <0x70 0x30008000 0x0 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(104) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <100000>; ++ resets = <&rst RST_I2C3>; ++ reset-names = "i2c3"; ++ }; ++ ++ gpio0: gpio@7030009000 { ++ compatible = "snps,dw-apb-gpio"; ++ reg = <0x70 0x30009000 0x0 0x400>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&div_clk GATE_CLK_APB_GPIO>, ++ <&div_clk GATE_CLK_APB_GPIO_INTR>, ++ <&div_clk GATE_CLK_GPIO_DB>; ++ clock-names = "base_clk", "intr_clk", "db_clk"; ++ ++ port0a: gpio-controller@0 { ++ compatible = "snps,dw-apb-gpio-port"; ++ bank-name = "port0a"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ snps,nr-gpios = <32>; ++ reg = <0>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(96) IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ ++ gpio1: gpio@703000a000 { ++ compatible = "snps,dw-apb-gpio"; ++ reg = <0x70 0x3000a000 0x0 0x400>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&div_clk GATE_CLK_APB_GPIO>, ++ <&div_clk GATE_CLK_APB_GPIO_INTR>, ++ <&div_clk GATE_CLK_GPIO_DB>; ++ clock-names = "base_clk", "intr_clk", "db_clk"; ++ ++ port1a: gpio-controller@0 { ++ compatible = "snps,dw-apb-gpio-port"; ++ bank-name = "port0a"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ snps,nr-gpios = <32>; ++ reg = <0>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(97) IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ ++ gpio2: gpio@703000b000 { ++ compatible = "snps,dw-apb-gpio"; ++ reg = <0x70 0x3000b000 0x0 0x400>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&div_clk GATE_CLK_APB_GPIO>, ++ <&div_clk GATE_CLK_APB_GPIO_INTR>, ++ <&div_clk GATE_CLK_GPIO_DB>; ++ clock-names = "base_clk", "intr_clk", "db_clk"; ++ ++ port2a: gpio-controller@0 { ++ compatible = "snps,dw-apb-gpio-port"; ++ bank-name = "port0a"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ snps,nr-gpios = <32>; ++ reg = <0>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(98) IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ ++ pwm: pwm@703000C000 { ++ compatible = "sophgo,sophgo-pwm"; ++ reg = <0x70 0x3000C000 0x0 0x20>; ++ clocks = <&div_clk GATE_CLK_APB_PWM>; ++ clock-names = "clk_gate_apb_pwm"; ++ #pwm-cells = <2>; ++ pwm-num = <2>; ++ no-polarity; ++ }; ++ ++ tach0: tach@703000C020 { ++ compatible = "sophgo,sophgo-tach"; ++ reg = <0x70 0x3000C020 0x0 0x8>; ++ }; ++ ++ tach1: tach@703000C028 { ++ compatible = "sophgo,sophgo-tach"; ++ reg = <0x70 0x3000C028 0x0 0x8>; ++ }; ++ ++ uart0: serial@7040000000 { ++ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; ++ reg = <0x00000070 0x40000000 0x00000000 0x00001000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(112) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <500000000>; ++ clocks = <&div_clk GATE_CLK_UART_500M>, ++ <&div_clk GATE_CLK_APB_UART>; ++ clock-names = "baudclk", "apb_pclk"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ }; ++ ++ uart1: serial@7040001000 { ++ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; ++ reg = <0x00000070 0x40001000 0x00000000 0x00001000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(113) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <500000000>; ++ clocks = <&div_clk GATE_CLK_UART_500M>, ++ <&div_clk GATE_CLK_APB_UART>; ++ clock-names = "baudclk", "apb_pclk"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ }; ++ ++ uart2: serial@7040002000 { ++ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; ++ reg = <0x00000070 0x40002000 0x00000000 0x00001000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(114) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <500000000>; ++ clocks = <&div_clk GATE_CLK_UART_500M>, ++ <&div_clk GATE_CLK_APB_UART>; ++ clock-names = "baudclk", "apb_pclk"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ }; ++ ++ uart3: serial@7040003000 { ++ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; ++ reg = <0x00000070 0x40003000 0x00000000 0x00001000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(115) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <500000000>; ++ clocks = <&div_clk GATE_CLK_UART_500M>, ++ <&div_clk GATE_CLK_APB_UART>; ++ clock-names = "baudclk", "apb_pclk"; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ }; ++ ++ emmc: bm-emmc@704002A000 { ++ compatible = "bitmain,bm-emmc"; ++ reg = <0x70 0x4002A000 0x0 0x1000>; ++ reg-names = "core_mem"; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(134) IRQ_TYPE_LEVEL_HIGH>; ++ bus-width = <4>; ++ non-removable; ++ no-sdio; ++ no-sd; ++ resets = <&rst RST_EMMC>; ++ reset-names = "emmc"; ++ clocks = ++ <&div_clk GATE_CLK_EMMC_100M>, ++ <&div_clk GATE_CLK_AXI_EMMC>, ++ <&div_clk GATE_CLK_100K_EMMC>; ++ clock-names = ++ "clk_gate_emmc", ++ "clk_gate_axi_emmc", ++ "clk_gate_100k_emmc"; ++ }; ++ ++ sd: bm-sd@704002B000 { ++ compatible = "bitmain,bm-sd"; ++ reg = <0x70 0x4002B000 0x0 0x1000>; ++ reg-names = "core_mem"; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(136) IRQ_TYPE_LEVEL_HIGH>; ++ bus-width = <4>; ++ no-sdio; ++ no-mmc; ++ resets = <&rst RST_SD>; ++ reset-names = "sdio"; ++ clocks = ++ <&div_clk GATE_CLK_SD_100M>, ++ <&div_clk GATE_CLK_AXI_SD>, ++ <&div_clk GATE_CLK_100K_SD>; ++ clock-names = ++ "clk_gate_sd", ++ "clk_gate_axi_sd", ++ "clk_gate_100k_sd"; ++ }; ++ ++ spifmc0: flash-controller@7000180000 { ++ compatible = "sophgo,spifmc"; ++ reg = <0x70 0x00180000 0x0 0x1000000>; ++ reg-names = "memory"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(108) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <100000000>; ++ clocks = <&div_clk GATE_CLK_AHB_SF>; ++ flash@0 { ++ reg = <0>; ++ compatible = "jedec,spi-nor"; ++ }; ++ }; ++ ++ spifmc1: flash-controller@7002180000 { ++ compatible = "sophgo,spifmc"; ++ reg = <0x70 0x02180000 0x0 0x1000000>; ++ reg-names = "memory"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(109) IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <100000000>; ++ clocks = <&div_clk GATE_CLK_AHB_SF>; ++ flash@0 { ++ reg = <0>; ++ compatible = "jedec,spi-nor"; ++ }; ++ }; ++ ++ spi0: spi@7040004000 { ++ compatible = "snps,dw-apb-ssi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x70 0x40004000 0x0 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(110) IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&div_clk GATE_CLK_APB_SPI>, ++ <&div_clk GATE_CLK_SYSDMA_AXI>; ++ clock-frequency = <250000000>; ++ resets = <&rst RST_SPI0>; ++ reset-names = "spi0"; ++ num-cs = <2>; ++ status = "okay"; ++ }; ++ ++ spi1: spi@7040005000 { ++ compatible = "snps,dw-apb-ssi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x70 0x40005000 0x0 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(111) IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&div_clk GATE_CLK_APB_SPI>, ++ <&div_clk GATE_CLK_SYSDMA_AXI>; ++ clock-frequency = <250000000>; ++ resets = <&rst RST_SPI1>; ++ reset-names = "spi1"; ++ num-cs = <2>; ++ status = "okay"; ++ }; ++ ++ stmmac_axi_setup: stmmac-axi-config { ++ snps,wr_osr_lmt = <1>; ++ snps,rd_osr_lmt = <2>; ++ snps,blen = <4 8 16 0 0 0 0>; ++ }; ++ ++ mtl_rx_setup: rx-queues-config { ++ snps,rx-queues-to-use = <8>; ++ queue0 {}; ++ queue1 {}; ++ queue2 {}; ++ queue3 {}; ++ queue4 {}; ++ queue5 {}; ++ queue6 {}; ++ queue7 {}; ++ }; ++ ++ mtl_tx_setup: tx-queues-config { ++ snps,tx-queues-to-use = <8>; ++ queue0 {}; ++ queue1 {}; ++ queue2 {}; ++ queue3 {}; ++ queue4 {}; ++ queue5 {}; ++ queue6 {}; ++ queue7 {}; ++ }; ++ ++ ethernet0: ethernet@7040026000 { ++ compatible = "bitmain,ethernet"; ++ reg = <0x70 0x40026000 0x0 0x4000>; ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(132) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "macirq"; ++ clock-names = "clk_tx", "gate_clk_tx", "stmmaceth", "ptp_ref", "gate_clk_ref"; ++ clocks = <&div_clk DIV_CLK_FPLL_TX_ETH0>, ++ <&div_clk GATE_CLK_TX_ETH0>, ++ <&div_clk GATE_CLK_AXI_ETH0>, ++ <&div_clk GATE_CLK_PTP_REF_I_ETH0>, ++ <&div_clk GATE_CLK_REF_ETH0>; ++ ++ /* no hash filter and perfect filter support */ ++ snps,multicast-filter-bins = <0>; ++ snps,perfect-filter-entries = <1>; ++ ++ snps,txpbl = <32>; ++ snps,rxpbl = <32>; ++ snps,aal; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,mtl-rx-config = <&mtl_rx_setup>; ++ snps,mtl-tx-config = <&mtl_tx_setup>; ++ ++ phy-mode = "rgmii-txid"; ++ phy-reset-gpios = <&port0a 27 0>; ++ phy-handle = <&phy0>; ++ mdio { ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ compatible = "snps,dwmac-mdio"; ++ phy0: phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ device_type = "ethernet-phy"; ++ reg = <0x0>; ++ }; ++ }; ++ }; ++ }; ++ ++ intc1: top_intc@7030010300 { ++ compatible = "sophgo,top-intc"; ++ reg = <0x70 0x300102E0 0x0 0x4>, ++ <0x70 0x30010300 0x0 0x4>, ++ <0x70 0x30010304 0x0 0x4>; ++ reg-names = "sta", "set", "clr"; ++ reg-bitwidth = <32>; ++ top_intc_id = <0>; ++ interrupt-controller; ++ #interrupt-cells = <0x1>; // only applies to child node ++ for-msi; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <SOC_PERIPHERAL_IRQ(64) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(65) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(66) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(67) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(68) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(69) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(70) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(71) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(72) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(73) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(74) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(75) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(76) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(77) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(78) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(79) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(80) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(81) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(82) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(83) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(84) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(85) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(86) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(87) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(88) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(89) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(90) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(91) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(92) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(93) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(94) IRQ_TYPE_LEVEL_HIGH>, ++ <SOC_PERIPHERAL_IRQ(95) IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "msi0", "msi1", "msi2", "msi3", ++ "msi4", "msi5", "msi6", "msi7", ++ "msi8", "msi9", "msi10", "msi11", ++ "msi12", "msi13", "msi14", "msi15", ++ "msi16", "msi17", "msi18", "msi19", ++ "msi20", "msi21", "msi22", "msi23", ++ "msi24", "msi25", "msi26", "msi27", ++ "msi28", "msi29", "msi30", "msi31"; ++ ++ }; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ chosen: chosen { ++ bootargs = "console=ttyS0,115200 earlycon maxcpus=1"; ++ stdout-path = "serial0"; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi b/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi +new file mode 100644 +index 000000000000..b136b6c4128c +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi +@@ -0,0 +1,2000 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. ++ */ ++ ++/ { ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ timebase-frequency = <50000000>; ++ ++ cpu-map { ++ socket0 { ++ cluster0 { ++ core0 { ++ cpu = <&cpu0>; ++ }; ++ core1 { ++ cpu = <&cpu1>; ++ }; ++ core2 { ++ cpu = <&cpu2>; ++ }; ++ core3 { ++ cpu = <&cpu3>; ++ }; ++ }; ++ ++ cluster1 { ++ core0 { ++ cpu = <&cpu4>; ++ }; ++ core1 { ++ cpu = <&cpu5>; ++ }; ++ core2 { ++ cpu = <&cpu6>; ++ }; ++ core3 { ++ cpu = <&cpu7>; ++ }; ++ }; ++ ++ cluster2 { ++ core0 { ++ cpu = <&cpu16>; ++ }; ++ core1 { ++ cpu = <&cpu17>; ++ }; ++ core2 { ++ cpu = <&cpu18>; ++ }; ++ core3 { ++ cpu = <&cpu19>; ++ }; ++ }; ++ ++ cluster3 { ++ core0 { ++ cpu = <&cpu20>; ++ }; ++ core1 { ++ cpu = <&cpu21>; ++ }; ++ core2 { ++ cpu = <&cpu22>; ++ }; ++ core3 { ++ cpu = <&cpu23>; ++ }; ++ }; ++ ++ cluster4 { ++ core0 { ++ cpu = <&cpu8>; ++ }; ++ core1 { ++ cpu = <&cpu9>; ++ }; ++ core2 { ++ cpu = <&cpu10>; ++ }; ++ core3 { ++ cpu = <&cpu11>; ++ }; ++ }; ++ ++ cluster5 { ++ core0 { ++ cpu = <&cpu12>; ++ }; ++ core1 { ++ cpu = <&cpu13>; ++ }; ++ core2 { ++ cpu = <&cpu14>; ++ }; ++ core3 { ++ cpu = <&cpu15>; ++ }; ++ }; ++ ++ cluster6 { ++ core0 { ++ cpu = <&cpu24>; ++ }; ++ core1 { ++ cpu = <&cpu25>; ++ }; ++ core2 { ++ cpu = <&cpu26>; ++ }; ++ core3 { ++ cpu = <&cpu27>; ++ }; ++ }; ++ ++ cluster7 { ++ core0 { ++ cpu = <&cpu28>; ++ }; ++ core1 { ++ cpu = <&cpu29>; ++ }; ++ core2 { ++ cpu = <&cpu30>; ++ }; ++ core3 { ++ cpu = <&cpu31>; ++ }; ++ }; ++ ++ cluster8 { ++ core0 { ++ cpu = <&cpu32>; ++ }; ++ core1 { ++ cpu = <&cpu33>; ++ }; ++ core2 { ++ cpu = <&cpu34>; ++ }; ++ core3 { ++ cpu = <&cpu35>; ++ }; ++ }; ++ ++ cluster9 { ++ core0 { ++ cpu = <&cpu36>; ++ }; ++ core1 { ++ cpu = <&cpu37>; ++ }; ++ core2 { ++ cpu = <&cpu38>; ++ }; ++ core3 { ++ cpu = <&cpu39>; ++ }; ++ }; ++ ++ cluster10 { ++ core0 { ++ cpu = <&cpu48>; ++ }; ++ core1 { ++ cpu = <&cpu49>; ++ }; ++ core2 { ++ cpu = <&cpu50>; ++ }; ++ core3 { ++ cpu = <&cpu51>; ++ }; ++ }; ++ ++ cluster11 { ++ core0 { ++ cpu = <&cpu52>; ++ }; ++ core1 { ++ cpu = <&cpu53>; ++ }; ++ core2 { ++ cpu = <&cpu54>; ++ }; ++ core3 { ++ cpu = <&cpu55>; ++ }; ++ }; ++ ++ cluster12 { ++ core0 { ++ cpu = <&cpu40>; ++ }; ++ core1 { ++ cpu = <&cpu41>; ++ }; ++ core2 { ++ cpu = <&cpu42>; ++ }; ++ core3 { ++ cpu = <&cpu43>; ++ }; ++ }; ++ ++ cluster13 { ++ core0 { ++ cpu = <&cpu44>; ++ }; ++ core1 { ++ cpu = <&cpu45>; ++ }; ++ core2 { ++ cpu = <&cpu46>; ++ }; ++ core3 { ++ cpu = <&cpu47>; ++ }; ++ }; ++ ++ cluster14 { ++ core0 { ++ cpu = <&cpu56>; ++ }; ++ core1 { ++ cpu = <&cpu57>; ++ }; ++ core2 { ++ cpu = <&cpu58>; ++ }; ++ core3 { ++ cpu = <&cpu59>; ++ }; ++ }; ++ ++ cluster15 { ++ core0 { ++ cpu = <&cpu60>; ++ }; ++ core1 { ++ cpu = <&cpu61>; ++ }; ++ core2 { ++ cpu = <&cpu62>; ++ }; ++ core3 { ++ cpu = <&cpu63>; ++ }; ++ }; ++ }; ++ }; ++ ++ cpu0: cpu@0 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <0>; ++ 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 = <&l2_cache0>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu0_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu1: cpu@1 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <1>; ++ 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 = <&l2_cache0>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu1_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu2: cpu@2 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <2>; ++ 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 = <&l2_cache0>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu2_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu3: cpu@3 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <3>; ++ 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 = <&l2_cache0>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu3_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu4: cpu@4 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <4>; ++ 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 = <&l2_cache1>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu4_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu5: cpu@5 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <5>; ++ 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 = <&l2_cache1>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu5_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu6: cpu@6 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <6>; ++ 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 = <&l2_cache1>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu6_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu7: cpu@7 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <7>; ++ 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 = <&l2_cache1>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu7_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu8: cpu@8 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <8>; ++ 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 = <&l2_cache4>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu8_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu9: cpu@9 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <9>; ++ 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 = <&l2_cache4>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu9_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu10: cpu@10 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <10>; ++ 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 = <&l2_cache4>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu10_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu11: cpu@11 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <11>; ++ 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 = <&l2_cache4>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu11_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu12: cpu@12 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <12>; ++ 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 = <&l2_cache5>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu12_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu13: cpu@13 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <13>; ++ 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 = <&l2_cache5>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu13_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu14: cpu@14 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <14>; ++ 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 = <&l2_cache5>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu14_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu15: cpu@15 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <15>; ++ 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 = <&l2_cache5>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu15_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu16: cpu@16 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <16>; ++ 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 = <&l2_cache2>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu16_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu17: cpu@17 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <17>; ++ 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 = <&l2_cache2>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu17_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu18: cpu@18 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <18>; ++ 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 = <&l2_cache2>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu18_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu19: cpu@19 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <19>; ++ 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 = <&l2_cache2>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu19_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu20: cpu@20 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <20>; ++ 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 = <&l2_cache3>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu20_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu21: cpu@21 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <21>; ++ 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 = <&l2_cache3>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu21_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu22: cpu@22 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <22>; ++ 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 = <&l2_cache3>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu22_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu23: cpu@23 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <23>; ++ 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 = <&l2_cache3>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu23_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu24: cpu@24 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <24>; ++ 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 = <&l2_cache6>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu24_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu25: cpu@25 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <25>; ++ 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 = <&l2_cache6>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu25_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu26: cpu@26 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <26>; ++ 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 = <&l2_cache6>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu26_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu27: cpu@27 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <27>; ++ 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 = <&l2_cache6>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu27_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu28: cpu@28 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <28>; ++ 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 = <&l2_cache7>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu28_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu29: cpu@29 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <29>; ++ 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 = <&l2_cache7>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu29_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu30: cpu@30 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <30>; ++ 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 = <&l2_cache7>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu30_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu31: cpu@31 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <31>; ++ 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 = <&l2_cache7>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu31_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu32: cpu@32 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <32>; ++ 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 = <&l2_cache8>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu32_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu33: cpu@33 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <33>; ++ 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 = <&l2_cache8>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu33_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu34: cpu@34 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <34>; ++ 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 = <&l2_cache8>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu34_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu35: cpu@35 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <35>; ++ 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 = <&l2_cache8>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu35_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu36: cpu@36 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <36>; ++ 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 = <&l2_cache9>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu36_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu37: cpu@37 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <37>; ++ 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 = <&l2_cache9>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu37_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu38: cpu@38 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <38>; ++ 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 = <&l2_cache9>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu38_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu39: cpu@39 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <39>; ++ 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 = <&l2_cache9>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu39_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu40: cpu@40 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <40>; ++ 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 = <&l2_cache12>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu40_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu41: cpu@41 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <41>; ++ 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 = <&l2_cache12>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu41_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu42: cpu@42 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <42>; ++ 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 = <&l2_cache12>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu42_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu43: cpu@43 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <43>; ++ 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 = <&l2_cache12>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu43_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu44: cpu@44 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <44>; ++ 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 = <&l2_cache13>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu44_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu45: cpu@45 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <45>; ++ 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 = <&l2_cache13>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu45_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu46: cpu@46 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <46>; ++ 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 = <&l2_cache13>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu46_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu47: cpu@47 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <47>; ++ 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 = <&l2_cache13>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu47_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu48: cpu@48 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <48>; ++ 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 = <&l2_cache10>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu48_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu49: cpu@49 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <49>; ++ 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 = <&l2_cache10>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu49_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu50: cpu@50 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <50>; ++ 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 = <&l2_cache10>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu50_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu51: cpu@51 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <51>; ++ 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 = <&l2_cache10>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu51_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu52: cpu@52 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <52>; ++ 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 = <&l2_cache11>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu52_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu53: cpu@53 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <53>; ++ 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 = <&l2_cache11>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu53_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu54: cpu@54 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <54>; ++ 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 = <&l2_cache11>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu54_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu55: cpu@55 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <55>; ++ 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 = <&l2_cache11>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu55_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu56: cpu@56 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <56>; ++ 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 = <&l2_cache14>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu56_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu57: cpu@57 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <57>; ++ 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 = <&l2_cache14>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu57_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu58: cpu@58 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <58>; ++ 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 = <&l2_cache14>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu58_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu59: cpu@59 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <59>; ++ 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 = <&l2_cache14>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu59_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu60: cpu@60 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <60>; ++ 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 = <&l2_cache15>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu60_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu61: cpu@61 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <61>; ++ 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 = <&l2_cache15>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu61_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu62: cpu@62 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <62>; ++ 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 = <&l2_cache15>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu62_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu63: cpu@63 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", ++ "zicntr", "zicsr", "zifencei", ++ "zihpm"; ++ reg = <63>; ++ 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 = <&l2_cache15>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu63_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ l2_cache0: cache-controller-0 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache1: cache-controller-1 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache2: cache-controller-2 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache3: cache-controller-3 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache4: cache-controller-4 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache5: cache-controller-5 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache6: cache-controller-6 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache7: cache-controller-7 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache8: cache-controller-8 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache9: cache-controller-9 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache10: cache-controller-10 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache11: cache-controller-11 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache12: cache-controller-12 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache13: cache-controller-13 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache14: cache-controller-14 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache15: cache-controller-15 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +new file mode 100644 +index 000000000000..49b4b9c2c101 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. ++ */ ++ ++#include "sg2042.dtsi" ++ ++/ { ++ model = "Milk-V Pioneer"; ++ compatible = "milkv,pioneer", "sophgo,sg2042"; ++ ++ chosen { ++ stdout-path = "serial0"; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi +new file mode 100644 +index 000000000000..ead1cc35d88b +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi +@@ -0,0 +1,341 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. ++ */ ++ ++/dts-v1/; ++#include <dt-bindings/interrupt-controller/irq.h> ++ ++#include "sg2042-cpus.dtsi" ++ ++/ { ++ compatible = "sophgo,sg2042"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ dma-noncoherent; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ soc: soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ clint_mswi: interrupt-controller@7094000000 { ++ compatible = "sophgo,sg2042-aclint-mswi", "thead,c900-aclint-mswi"; ++ reg = <0x00000070 0x94000000 0x00000000 0x00004000>; ++ interrupts-extended = <&cpu0_intc 3>, ++ <&cpu1_intc 3>, ++ <&cpu2_intc 3>, ++ <&cpu3_intc 3>, ++ <&cpu4_intc 3>, ++ <&cpu5_intc 3>, ++ <&cpu6_intc 3>, ++ <&cpu7_intc 3>, ++ <&cpu8_intc 3>, ++ <&cpu9_intc 3>, ++ <&cpu10_intc 3>, ++ <&cpu11_intc 3>, ++ <&cpu12_intc 3>, ++ <&cpu13_intc 3>, ++ <&cpu14_intc 3>, ++ <&cpu15_intc 3>, ++ <&cpu16_intc 3>, ++ <&cpu17_intc 3>, ++ <&cpu18_intc 3>, ++ <&cpu19_intc 3>, ++ <&cpu20_intc 3>, ++ <&cpu21_intc 3>, ++ <&cpu22_intc 3>, ++ <&cpu23_intc 3>, ++ <&cpu24_intc 3>, ++ <&cpu25_intc 3>, ++ <&cpu26_intc 3>, ++ <&cpu27_intc 3>, ++ <&cpu28_intc 3>, ++ <&cpu29_intc 3>, ++ <&cpu30_intc 3>, ++ <&cpu31_intc 3>, ++ <&cpu32_intc 3>, ++ <&cpu33_intc 3>, ++ <&cpu34_intc 3>, ++ <&cpu35_intc 3>, ++ <&cpu36_intc 3>, ++ <&cpu37_intc 3>, ++ <&cpu38_intc 3>, ++ <&cpu39_intc 3>, ++ <&cpu40_intc 3>, ++ <&cpu41_intc 3>, ++ <&cpu42_intc 3>, ++ <&cpu43_intc 3>, ++ <&cpu44_intc 3>, ++ <&cpu45_intc 3>, ++ <&cpu46_intc 3>, ++ <&cpu47_intc 3>, ++ <&cpu48_intc 3>, ++ <&cpu49_intc 3>, ++ <&cpu50_intc 3>, ++ <&cpu51_intc 3>, ++ <&cpu52_intc 3>, ++ <&cpu53_intc 3>, ++ <&cpu54_intc 3>, ++ <&cpu55_intc 3>, ++ <&cpu56_intc 3>, ++ <&cpu57_intc 3>, ++ <&cpu58_intc 3>, ++ <&cpu59_intc 3>, ++ <&cpu60_intc 3>, ++ <&cpu61_intc 3>, ++ <&cpu62_intc 3>, ++ <&cpu63_intc 3>; ++ }; ++ ++ clint_mtimer0: timer@70ac004000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac004000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu0_intc 7>, ++ <&cpu1_intc 7>, ++ <&cpu2_intc 7>, ++ <&cpu3_intc 7>; ++ }; ++ ++ clint_mtimer1: timer@70ac014000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac014000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu4_intc 7>, ++ <&cpu5_intc 7>, ++ <&cpu6_intc 7>, ++ <&cpu7_intc 7>; ++ }; ++ ++ clint_mtimer2: timer@70ac024000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac024000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu8_intc 7>, ++ <&cpu9_intc 7>, ++ <&cpu10_intc 7>, ++ <&cpu11_intc 7>; ++ }; ++ ++ clint_mtimer3: timer@70ac034000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac034000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu12_intc 7>, ++ <&cpu13_intc 7>, ++ <&cpu14_intc 7>, ++ <&cpu15_intc 7>; ++ }; ++ ++ clint_mtimer4: timer@70ac044000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac044000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu16_intc 7>, ++ <&cpu17_intc 7>, ++ <&cpu18_intc 7>, ++ <&cpu19_intc 7>; ++ }; ++ ++ clint_mtimer5: timer@70ac054000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac054000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu20_intc 7>, ++ <&cpu21_intc 7>, ++ <&cpu22_intc 7>, ++ <&cpu23_intc 7>; ++ }; ++ ++ clint_mtimer6: timer@70ac064000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac064000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu24_intc 7>, ++ <&cpu25_intc 7>, ++ <&cpu26_intc 7>, ++ <&cpu27_intc 7>; ++ }; ++ ++ clint_mtimer7: timer@70ac074000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac074000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu28_intc 7>, ++ <&cpu29_intc 7>, ++ <&cpu30_intc 7>, ++ <&cpu31_intc 7>; ++ }; ++ ++ clint_mtimer8: timer@70ac084000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac084000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu32_intc 7>, ++ <&cpu33_intc 7>, ++ <&cpu34_intc 7>, ++ <&cpu35_intc 7>; ++ }; ++ ++ clint_mtimer9: timer@70ac094000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac094000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu36_intc 7>, ++ <&cpu37_intc 7>, ++ <&cpu38_intc 7>, ++ <&cpu39_intc 7>; ++ }; ++ ++ clint_mtimer10: timer@70ac0a4000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac0a4000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu40_intc 7>, ++ <&cpu41_intc 7>, ++ <&cpu42_intc 7>, ++ <&cpu43_intc 7>; ++ }; ++ ++ clint_mtimer11: timer@70ac0b4000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac0b4000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu44_intc 7>, ++ <&cpu45_intc 7>, ++ <&cpu46_intc 7>, ++ <&cpu47_intc 7>; ++ }; ++ ++ clint_mtimer12: timer@70ac0c4000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac0c4000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu48_intc 7>, ++ <&cpu49_intc 7>, ++ <&cpu50_intc 7>, ++ <&cpu51_intc 7>; ++ }; ++ ++ clint_mtimer13: timer@70ac0d4000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac0d4000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu52_intc 7>, ++ <&cpu53_intc 7>, ++ <&cpu54_intc 7>, ++ <&cpu55_intc 7>; ++ }; ++ ++ clint_mtimer14: timer@70ac0e4000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac0e4000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu56_intc 7>, ++ <&cpu57_intc 7>, ++ <&cpu58_intc 7>, ++ <&cpu59_intc 7>; ++ }; ++ ++ clint_mtimer15: timer@70ac0f4000 { ++ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; ++ reg = <0x00000070 0xac0f4000 0x00000000 0x0000c000>; ++ reg-names = "mtimecmp"; ++ interrupts-extended = <&cpu60_intc 7>, ++ <&cpu61_intc 7>, ++ <&cpu62_intc 7>, ++ <&cpu63_intc 7>; ++ }; ++ ++ intc: interrupt-controller@7090000000 { ++ compatible = "sophgo,sg2042-plic", "thead,c900-plic"; ++ #address-cells = <0>; ++ #interrupt-cells = <2>; ++ reg = <0x00000070 0x90000000 0x00000000 0x04000000>; ++ interrupt-controller; ++ interrupts-extended = ++ <&cpu0_intc 11>, <&cpu0_intc 9>, ++ <&cpu1_intc 11>, <&cpu1_intc 9>, ++ <&cpu2_intc 11>, <&cpu2_intc 9>, ++ <&cpu3_intc 11>, <&cpu3_intc 9>, ++ <&cpu4_intc 11>, <&cpu4_intc 9>, ++ <&cpu5_intc 11>, <&cpu5_intc 9>, ++ <&cpu6_intc 11>, <&cpu6_intc 9>, ++ <&cpu7_intc 11>, <&cpu7_intc 9>, ++ <&cpu8_intc 11>, <&cpu8_intc 9>, ++ <&cpu9_intc 11>, <&cpu9_intc 9>, ++ <&cpu10_intc 11>, <&cpu10_intc 9>, ++ <&cpu11_intc 11>, <&cpu11_intc 9>, ++ <&cpu12_intc 11>, <&cpu12_intc 9>, ++ <&cpu13_intc 11>, <&cpu13_intc 9>, ++ <&cpu14_intc 11>, <&cpu14_intc 9>, ++ <&cpu15_intc 11>, <&cpu15_intc 9>, ++ <&cpu16_intc 11>, <&cpu16_intc 9>, ++ <&cpu17_intc 11>, <&cpu17_intc 9>, ++ <&cpu18_intc 11>, <&cpu18_intc 9>, ++ <&cpu19_intc 11>, <&cpu19_intc 9>, ++ <&cpu20_intc 11>, <&cpu20_intc 9>, ++ <&cpu21_intc 11>, <&cpu21_intc 9>, ++ <&cpu22_intc 11>, <&cpu22_intc 9>, ++ <&cpu23_intc 11>, <&cpu23_intc 9>, ++ <&cpu24_intc 11>, <&cpu24_intc 9>, ++ <&cpu25_intc 11>, <&cpu25_intc 9>, ++ <&cpu26_intc 11>, <&cpu26_intc 9>, ++ <&cpu27_intc 11>, <&cpu27_intc 9>, ++ <&cpu28_intc 11>, <&cpu28_intc 9>, ++ <&cpu29_intc 11>, <&cpu29_intc 9>, ++ <&cpu30_intc 11>, <&cpu30_intc 9>, ++ <&cpu31_intc 11>, <&cpu31_intc 9>, ++ <&cpu32_intc 11>, <&cpu32_intc 9>, ++ <&cpu33_intc 11>, <&cpu33_intc 9>, ++ <&cpu34_intc 11>, <&cpu34_intc 9>, ++ <&cpu35_intc 11>, <&cpu35_intc 9>, ++ <&cpu36_intc 11>, <&cpu36_intc 9>, ++ <&cpu37_intc 11>, <&cpu37_intc 9>, ++ <&cpu38_intc 11>, <&cpu38_intc 9>, ++ <&cpu39_intc 11>, <&cpu39_intc 9>, ++ <&cpu40_intc 11>, <&cpu40_intc 9>, ++ <&cpu41_intc 11>, <&cpu41_intc 9>, ++ <&cpu42_intc 11>, <&cpu42_intc 9>, ++ <&cpu43_intc 11>, <&cpu43_intc 9>, ++ <&cpu44_intc 11>, <&cpu44_intc 9>, ++ <&cpu45_intc 11>, <&cpu45_intc 9>, ++ <&cpu46_intc 11>, <&cpu46_intc 9>, ++ <&cpu47_intc 11>, <&cpu47_intc 9>, ++ <&cpu48_intc 11>, <&cpu48_intc 9>, ++ <&cpu49_intc 11>, <&cpu49_intc 9>, ++ <&cpu50_intc 11>, <&cpu50_intc 9>, ++ <&cpu51_intc 11>, <&cpu51_intc 9>, ++ <&cpu52_intc 11>, <&cpu52_intc 9>, ++ <&cpu53_intc 11>, <&cpu53_intc 9>, ++ <&cpu54_intc 11>, <&cpu54_intc 9>, ++ <&cpu55_intc 11>, <&cpu55_intc 9>, ++ <&cpu56_intc 11>, <&cpu56_intc 9>, ++ <&cpu57_intc 11>, <&cpu57_intc 9>, ++ <&cpu58_intc 11>, <&cpu58_intc 9>, ++ <&cpu59_intc 11>, <&cpu59_intc 9>, ++ <&cpu60_intc 11>, <&cpu60_intc 9>, ++ <&cpu61_intc 11>, <&cpu61_intc 9>, ++ <&cpu62_intc 11>, <&cpu62_intc 9>, ++ <&cpu63_intc 11>, <&cpu63_intc 9>; ++ riscv,ndev = <224>; ++ }; ++ ++ uart0: serial@7040000000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x00000070 0x40000000 0x00000000 0x00001000>; ++ interrupt-parent = <&intc>; ++ interrupts = <112 IRQ_TYPE_LEVEL_HIGH>; ++ clock-frequency = <500000000>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/thead/Makefile b/arch/riscv/boot/dts/thead/Makefile +index b55a17127c2b..1f14fdaf6add 100644 +--- a/arch/riscv/boot/dts/thead/Makefile ++++ b/arch/riscv/boot/dts/thead/Makefile +@@ -1,2 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 + dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-pi-4a.dtb th1520-beaglev-ahead.dtb ++dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-pi-4a-16g.dtb ++dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-cluster-4a.dtb th1520-lichee-cluster-4a-16g.dtb ++dtb-$(CONFIG_ARCH_THEAD) += th1520-milkv-meles.dtb th1520-milkv-meles-4g.dtb +diff --git a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts +index 70e8042c8304..2c2d43433586 100644 +--- a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts ++++ b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts +@@ -7,22 +7,29 @@ + /dts-v1/; + + #include "th1520.dtsi" ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/leds/common.h> + + / { + model = "BeagleV Ahead"; + compatible = "beagle,beaglev-ahead", "thead,th1520"; + + aliases { ++ ethernet0 = &gmac0; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; ++ gpio4 = &gpio4; ++ gpio5 = &aogpio; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; ++ mmc0 = &emmc; ++ mmc1 = &sdio0; + }; + + chosen { +@@ -32,11 +39,46 @@ chosen { + memory@0 { + device_type = "memory"; + reg = <0x0 0x00000000 0x1 0x00000000>; ++ }; ++ ++ leds { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&led_pins>; ++ compatible = "gpio-leds"; ++ ++ led-1 { ++ gpios = <&gpio4 8 GPIO_ACTIVE_LOW>; ++ color = <LED_COLOR_ID_BLUE>; ++ label = "led1"; ++ }; ++ ++ led-2 { ++ gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; ++ color = <LED_COLOR_ID_BLUE>; ++ label = "led2"; ++ }; ++ ++ led-3 { ++ gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; ++ color = <LED_COLOR_ID_BLUE>; ++ label = "led3"; ++ }; + ++ led-4 { ++ gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; ++ color = <LED_COLOR_ID_BLUE>; ++ label = "led4"; ++ }; ++ ++ led-5 { ++ gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; ++ color = <LED_COLOR_ID_BLUE>; ++ label = "led5"; ++ }; + }; + }; + +-&osc { ++&osc_24m { + clock-frequency = <24000000>; + }; + +@@ -44,10 +86,18 @@ &osc_32k { + clock-frequency = <32768>; + }; + ++&aonsys_clk { ++ clock-frequency = <73728000>; ++}; ++ + &apb_clk { + clock-frequency = <62500000>; + }; + ++&sdhci_clk { ++ clock-frequency = <198000000>; ++}; ++ + &uart_sclk { + clock-frequency = <100000000>; + }; +@@ -56,6 +106,153 @@ &dmac0 { + status = "okay"; + }; + ++&gmac_clk { ++ clock-frequency = <500000000>; ++}; ++ ++&gmac_axi_clk { ++ clock-frequency = <100000000>; ++}; ++ ++&emmc { ++ bus-width = <8>; ++ max-frequency = <198000000>; ++ mmc-hs400-1_8v; ++ non-removable; ++ no-sdio; ++ no-sd; ++ status = "okay"; ++}; ++ ++&gmac0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac0_pins>; ++ phy-mode = "rgmii-id"; ++ status = "okay"; ++}; ++ ++&mdio0 { ++ phy0: ethernet-phy@1 { ++ reg = <1>; ++ }; ++}; ++ ++&padctrl_aosys { ++ led_pins: led-0 { ++ led-pins { ++ pins = "AUDIO_PA8", /* GPIO4_8 */ ++ "AUDIO_PA9", /* GPIO4_9 */ ++ "AUDIO_PA10", /* GPIO4_10 */ ++ "AUDIO_PA11", /* GPIO4_11 */ ++ "AUDIO_PA12"; /* GPIO4_12 */ ++ function = "gpio"; ++ bias-disable; ++ drive-strength = <3>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++}; ++ ++&padctrl0_apsys { ++ gmac0_pins: gmac0-0 { ++ tx-pins { ++ pins = "GMAC0_TX_CLK", ++ "GMAC0_TXEN", ++ "GMAC0_TXD0", ++ "GMAC0_TXD1", ++ "GMAC0_TXD2", ++ "GMAC0_TXD3"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <25>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pins = "GMAC0_RX_CLK", ++ "GMAC0_RXDV", ++ "GMAC0_RXD0", ++ "GMAC0_RXD1", ++ "GMAC0_RXD2", ++ "GMAC0_RXD3"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ mdc-pins { ++ pins = "GMAC0_MDC"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <13>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ mdio-pins { ++ pins = "GMAC0_MDIO"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <13>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ sdio0_pins: sdio0-0 { ++ detn-pins { ++ pins = "SDIO0_DETN"; ++ function = "sdio"; ++ bias-disable; /* external pull-up */ ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ uart0_pins: uart0-0 { ++ tx-pins { ++ pins = "UART0_TXD"; ++ function = "uart"; ++ bias-disable; ++ drive-strength = <3>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pins = "UART0_RXD"; ++ function = "uart"; ++ bias-disable; ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++}; ++ ++&sdio0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio0_pins>; ++ bus-width = <4>; ++ max-frequency = <198000000>; ++ status = "okay"; ++}; ++ + &uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins>; + status = "okay"; + }; +diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts +new file mode 100644 +index 000000000000..c65cd1c83101 +--- /dev/null ++++ b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2024 NekoRouter <nekorouter@outlook.com> ++ */ ++ ++/dts-v1/; ++ ++#include "th1520-lichee-cluster-4a.dts" ++ ++/ { ++ model = "Sipeed Lichee Cluster 4A 16G"; ++ compatible = "sipeed,lichee-cluster-4a", "sipeed,lichee-module-4a", "thead,th1520"; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x00000000 0x4 0x00000000>; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts +new file mode 100644 +index 000000000000..f1116426233f +--- /dev/null ++++ b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts +@@ -0,0 +1,45 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2024 NekoRouter <nekorouter@outlook.com> ++ */ ++ ++/dts-v1/; ++ ++#include "th1520-lichee-pi-4a.dts" ++ ++/ { ++ model = "Sipeed Lichee Cluster 4A"; ++ compatible = "sipeed,lichee-cluster-4a", "sipeed,lichee-module-4a", "thead,th1520"; ++ ++ /delete-node/ regulator-hub_5v; ++ ++ /delete-node/ regulator-vcc5v_usb; ++ ++ /delete-node/ regulator-hub_5v; ++ ++ /delete-node/ regulator-vcc5v_usb; ++ ++ /delete-node/ wireless-wlan; ++ ++ /delete-node/ wireless-bluetooth; ++ ++ /delete-node/ soc_wcn33_en; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ /delete-node/ gpio@18; ++}; ++ ++&i2c3 { ++ status = "okay"; ++ ++ /delete-node/ gpio@18; ++}; ++ ++&usb_dwc3 { ++ /delete-node/ hub@1; ++ ++ /delete-node/ hub@2; ++}; +diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +index a802ab110429..8e2d281c7dee 100644 +--- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi ++++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +@@ -15,9 +15,33 @@ memory@0 { + device_type = "memory"; + reg = <0x0 0x00000000 0x2 0x00000000>; + }; ++ ++ resmem: reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ //Note: with "no-map" reserv mem not saved in hibernation ++ rpmsgmem: memory@1E000000 { ++ reg = <0x0 0x1E000000 0x0 0x10000>; ++ }; ++ }; ++ ++ light_rpmsg: light_rpmsg { ++ compatible = "light,rpmsg-bus", "simple-bus"; ++ memory-region = <&rpmsgmem>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ rpmsg: rpmsg { ++ vdev-nums = <1>; ++ reg = <0x0 0x1E000000 0 0x10000>; ++ compatible = "light,light-rpmsg"; ++ status = "okay"; ++ }; ++ }; + }; + +-&osc { ++&osc_24m { + clock-frequency = <24000000>; + }; + +@@ -25,14 +49,139 @@ &osc_32k { + clock-frequency = <32768>; + }; + ++&aonsys_clk { ++ clock-frequency = <73728000>; ++}; ++ + &apb_clk { + clock-frequency = <62500000>; + }; + ++&sdhci_clk { ++ clock-frequency = <198000000>; ++}; ++ + &uart_sclk { + clock-frequency = <100000000>; + }; + ++&gmac_clk { ++ clock-frequency = <500000000>; ++}; ++ ++&gmac_axi_clk { ++ clock-frequency = <100000000>; ++}; ++ + &dmac0 { + status = "okay"; + }; ++ ++&emmc { ++ bus-width = <8>; ++ max-frequency = <198000000>; ++ mmc-hs400-1_8v; ++ non-removable; ++ no-sdio; ++ no-sd; ++ status = "okay"; ++}; ++ ++&padctrl0_apsys { ++ sdio0_pins: sdio0-0 { ++ detn-pins { ++ pins = "SDIO0_DETN"; ++ function = "sdio"; ++ bias-disable; /* external pull-up */ ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++}; ++ ++&sdio0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio0_pins>; ++ bus-width = <4>; ++ max-frequency = <198000000>; ++ status = "okay"; ++}; ++ ++&cpus { ++ c910_0: cpu@0 { ++ operating-points = < ++ /* kHz uV */ ++ 300000 650000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 800000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ dvdd-supply = <&dvdd_cpu_reg>; ++ dvddm-supply = <&dvddm_cpu_reg>; ++ }; ++ c910_1: cpu@1 { ++ operating-points = < ++ /* kHz uV */ ++ 300000 650000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 800000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ dvdd-supply = <&dvdd_cpu_reg>; ++ dvddm-supply = <&dvddm_cpu_reg>; ++ }; ++ c910_2: cpu@2 { ++ ++ operating-points = < ++ /* kHz uV */ ++ 300000 650000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 800000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ dvdd-supply = <&dvdd_cpu_reg>; ++ dvddm-supply = <&dvddm_cpu_reg>; ++ }; ++ c910_3: cpu@3 { ++ ++ operating-points = < ++ /* kHz uV */ ++ 300000 650000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 800000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ dvdd-supply = <&dvdd_cpu_reg>; ++ dvddm-supply = <&dvddm_cpu_reg>; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts +new file mode 100644 +index 000000000000..a3a991baf716 +--- /dev/null ++++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts +@@ -0,0 +1,18 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 Han Gao <gaohan@iscas.ac.cn> ++ */ ++ ++/dts-v1/; ++ ++#include "th1520-lichee-pi-4a.dts" ++ ++/ { ++ model = "Sipeed Lichee Pi 4A 16G"; ++ compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520"; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x00000000 0x4 0x00000000>; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +index 9a3884a73e13..6c0709e5193f 100644 +--- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts ++++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +@@ -4,29 +4,741 @@ + */ + + #include "th1520-lichee-module-4a.dtsi" ++#include <dt-bindings/gpio/gpio.h> + + / { + model = "Sipeed Lichee Pi 4A"; + compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520"; + + aliases { ++ ethernet0 = &gmac0; ++ ethernet1 = &gmac1; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; ++ gpio4 = &gpio4; ++ gpio5 = &aogpio; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ i2c4 = &i2c4; ++ i2c5 = &audio_i2c0; ++ i2c6 = &audio_i2c1; ++ mmc0 = &emmc; ++ mmc1 = &sdio0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; ++ ++ fan: pwm-fan { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&fan_pins>; ++ compatible = "pwm-fan"; ++ #cooling-cells = <2>; ++ pwms = <&pwm 1 10000000 0>; ++ cooling-levels = <0 66 196 255>; ++ }; ++ ++ hub_5v: regulator-hub_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "HUB_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ vcc5v_usb: regulator-vcc5v_usb { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC5V_USB"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ thermal-zones { ++ cpu-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <1000>; ++ thermal-sensors = <&pvt 0>; ++ ++ trips { ++ trip_active0: active-0 { ++ temperature = <39000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ trip_active1: active-1 { ++ temperature = <50000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ ++ trip_active2: active-2 { ++ temperature = <60000>; ++ hysteresis = <5000>; ++ type = "active"; ++ }; ++ }; ++ ++ cooling-maps { ++ map-active-0 { ++ cooling-device = <&fan 1 1>; ++ trip = <&trip_active0>; ++ }; ++ ++ map-active-1 { ++ cooling-device = <&fan 2 2>; ++ trip = <&trip_active1>; ++ }; ++ ++ map-active-2 { ++ cooling-device = <&fan 3 3>; ++ trip = <&trip_active2>; ++ }; ++ }; ++ }; ++ }; ++ ++ hub_5v: regulator-hub_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "HUB_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ vcc5v_usb: regulator-vcc5v_usb { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC5V_USB"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ wcn_wifi: wireless-wlan { ++ compatible = "wlan-platdata"; ++ clock-names = "clk_wifi"; ++ ref-clock-frequency = <24000000>; ++ keep_wifi_power_on; ++ pinctrl-names = "default"; ++ wifi_chip_type = "rtl8723ds"; ++ WIFI,poweren_gpio = <&ioexp2 5 0>; ++ status = "okay"; ++ }; ++ ++ wcn_bt: wireless-bluetooth { ++ compatible = "bluetooth-platdata"; ++ pinctrl-names = "default", "rts_gpio"; ++ BT,power_gpio = <&ioexp2 6 0>; ++ status = "okay"; ++ }; ++ ++ aon: aon { ++ compatible = "thead,light-aon"; ++ mbox-names = "aon"; ++ mboxes = <&mbox_910t 1 0>; ++ status = "okay"; ++ ++ pd: light-aon-pd { ++ compatible = "thead,light-aon-pd"; ++ #power-domain-cells = <1>; ++ }; ++ ++ soc_aud_3v3_en_reg: soc_aud_3v3_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_aud_3v3_en"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ soc_aud_1v8_en_reg: soc_aud_1v8_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_aud_1v8_en"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ soc_vdd_3v3_en_reg: soc_vdd_3v3_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_vdd_3v3_en"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio0 30 1>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ soc_vdd33_lcd0_en_reg: soc_lcd0_vdd33_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_lcd0_vdd33_en"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&ioexp2 5 1>; ++ enable-active-high; ++ }; ++ ++ soc_vdd18_lcd0_en_reg: soc_lcd0_vdd18_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_lcd0_vdd18_en"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ gpio = <&ioexp2 6 1>; ++ enable-active-high; ++ }; ++ ++ soc_vdd5v_se_en_reg: soc_vdd5v_se_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_vdd5v_se_en"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio2 14 1>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ soc_wcn33_en_reg: soc_wcn33_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_wcn33_en"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio2 29 1>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ soc_vbus_en_reg: soc_vbus_en { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_vbus_en"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio1 22 1>; ++ enable-active-high; ++ regulator-always-on; ++ }; ++ ++ ++ soc_avdd28_rgb_reg: soc_avdd28_rgb { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_avdd28_rgb"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ gpio = <&ioexp2 1 1>; ++ enable-active-high; ++ }; ++ ++ soc_dovdd18_rgb_reg: soc_dovdd18_rgb { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_dovdd18_rgb"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ gpio = <&ioexp2 2 1>; ++ enable-active-high; ++ }; ++ ++ soc_dvdd12_rgb_reg: soc_dvdd12_rgb { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_dvdd12_rgb"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ gpio = <&ioexp2 0 1>; ++ enable-active-high; ++ }; ++ ++ soc_avdd25_ir_reg: soc_avdd25_ir { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_avdd25_ir"; ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ gpio = <&ioexp2 5 1>; ++ enable-active-high; ++ }; ++ ++ soc_dovdd18_ir_reg: soc_dovdd18_ir { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_dovdd18_ir"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ gpio = <&ioexp2 3 1>; ++ enable-active-high; ++ }; ++ ++ soc_dvdd12_ir_reg: soc_dvdd12_ir { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_dvdd12_ir"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ gpio = <&ioexp2 4 1>; ++ enable-active-high; ++ }; ++ ++ soc_cam2_avdd25_ir_reg: soc_cam2_avdd25_ir { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_cam2_avdd25_ir"; ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ gpio = <&ioexp2 7 1>; ++ enable-active-high; ++ }; ++ ++ soc_cam2_dovdd18_ir_reg: soc_cam2_dovdd18_ir { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_cam2_dovdd18_ir"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ gpio = <&ioexp2 6 1>; ++ enable-active-high; ++ }; ++ ++ soc_cam2_dvdd12_ir_reg: soc_cam2_dvdd12_ir { ++ compatible = "regulator-fixed"; ++ regulator-name = "soc_cam2_dvdd12_ir"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ gpio = <&ioexp2 0 1>; ++ enable-active-high; ++ }; ++ ++ aon_reg_dialog: light-dialog-reg { ++ compatible = "thead,light-dialog-pmic-ant"; ++ status = "okay"; ++ ++ dvdd_cpu_reg: appcpu_dvdd { ++ regulator-name = "appcpu_dvdd"; ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1570000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ dvddm_cpu_reg: appcpu_dvddm { ++ regulator-name = "appcpu_dvddm"; ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1570000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dvdd18_aon_reg: soc_dvdd18_aon { ++ regulator-name = "soc_dvdd18_aon"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_avdd33_usb3_reg: soc_avdd33_usb3 { ++ regulator-name = "soc_avdd33_usb3"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dvdd08_aon_reg: soc_dvdd08_aon { ++ regulator-name = "soc_dvdd08_aon"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dvdd08_ddr_reg: soc_dvdd08_ddr { ++ regulator-name = "soc_dvdd08_ddr"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd_ddr_1v8_reg: soc_vdd_ddr_1v8 { ++ regulator-name = "soc_vdd_ddr_1v8"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd_ddr_1v1_reg: soc_vdd_ddr_1v1 { ++ regulator-name = "soc_vdd_ddr_1v1"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd_ddr_0v6_reg: soc_vdd_ddr_0v6 { ++ regulator-name = "soc_vdd_ddr_0v6"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dvdd18_ap_reg: soc_dvdd18_ap { ++ regulator-name = "soc_dvdd18_ap"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_avdd08_mipi_hdmi_reg: soc_avdd08_mipi_hdmi { ++ regulator-name = "soc_avdd08_mipi_hdmi"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_avdd18_mipi_hdmi_reg: soc_avdd18_mipi_hdmi { ++ regulator-name = "soc_avdd18_mipi_hdmi"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd33_emmc_reg: soc_vdd33_emmc { ++ regulator-name = "soc_vdd33_emmc"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd18_emmc_reg: soc_vdd18_emmc { ++ regulator-name = "soc_vdd18_emmc"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dovdd18_scan_reg: soc_dovdd18_scan { ++ regulator-name = "soc_dovdd18_scan"; ++ regulator-min-microvolt = <900000>; ++ regulator-max-microvolt = <3600000>; ++ }; ++ ++ soc_dvdd12_scan_reg: soc_dvdd12_scan { ++ regulator-name = "soc_dvdd12_scan"; ++ regulator-min-microvolt = <900000>; ++ regulator-max-microvolt = <3600000>; ++ }; ++ ++ soc_avdd28_scan_en_reg: soc_avdd28_scan_en { ++ regulator-name = "soc_avdd28_scan_en"; ++ regulator-min-microvolt = <900000>; ++ regulator-max-microvolt = <3600000>; ++ }; ++ ++ }; ++ ++ c910_cpufreq { ++ compatible = "thead,light-mpw-cpufreq"; ++ status = "okay"; ++ }; ++ ++ test: light-aon-test { ++ compatible = "thead,light-aon-test"; ++ }; ++ }; ++ ++}; ++ ++&aogpio { ++ sel-usb-hub-hog { ++ gpio-hog; ++ gpios = <4 GPIO_ACTIVE_HIGH>; ++ output-high; ++ }; ++}; ++ ++&gmac0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac0_pins>; ++ phy-handle = <&phy0>; ++ phy-mode = "rgmii-id"; ++ status = "okay"; ++}; ++ ++&gmac1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac1_pins>; ++ phy-handle = <&phy1>; ++ phy-mode = "rgmii-id"; ++ status = "okay"; ++}; ++ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <510>; ++ i2c-scl-falling-time-ns = <510>; ++ status = "okay"; ++ ++ ioexp1: gpio@18 { ++ compatible = "nxp,pca9557"; ++ reg = <0x18>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-line-names = "cam0_dvdd12", ++ "cam0_avdd28", ++ "cam0_dovdd18"; ++ }; ++}; ++ ++&i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1_pins>; ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <510>; ++ i2c-scl-falling-time-ns = <510>; ++ status = "okay"; ++ ++ ioexp2: gpio@18 { ++ compatible = "nxp,pca9557"; ++ reg = <0x18>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-line-names = "", ++ "cam0_reset", ++ "cam1_reset", ++ "cam2_reset", ++ "wl_host_wake", ++ "bt_resetn", ++ "", ++ "bt_host_wake"; ++ }; ++}; ++ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c3_pins>; ++ clock-frequency = <100000>; ++ i2c-sda-hold-time-ns = <300>; ++ i2c-sda-falling-time-ns = <510>; ++ i2c-scl-falling-time-ns = <510>; ++ status = "okay"; ++ ++ ioexp3: gpio@18 { ++ compatible = "nxp,pca9557"; ++ reg = <0x18>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-line-names = "tp0_rst", ++ "", ++ "", ++ "vcc5v_usb", ++ "vdd28_tp0", ++ "vdd33_lcd0", ++ "vdd18_lcd0", ++ "lcd0_reset"; ++ }; ++}; ++ ++&mdio0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mdio0_pins>; ++ ++ phy0: ethernet-phy@1 { ++ reg = <1>; ++ }; ++ ++ phy1: ethernet-phy@2 { ++ reg = <2>; ++ }; ++}; ++ ++&padctrl0_apsys { ++ fan_pins: fan-0 { ++ pwm1-pins { ++ pins = "GPIO3_3"; /* PWM1 */ ++ function = "pwm"; ++ bias-disable; ++ drive-strength = <25>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ gmac0_pins: gmac0-0 { ++ tx-pins { ++ pins = "GMAC0_TX_CLK", ++ "GMAC0_TXEN", ++ "GMAC0_TXD0", ++ "GMAC0_TXD1", ++ "GMAC0_TXD2", ++ "GMAC0_TXD3"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <25>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pins = "GMAC0_RX_CLK", ++ "GMAC0_RXDV", ++ "GMAC0_RXD0", ++ "GMAC0_RXD1", ++ "GMAC0_RXD2", ++ "GMAC0_RXD3"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ gmac1_pins: gmac1-0 { ++ tx-pins { ++ pins = "GPIO2_18", /* GMAC1_TX_CLK */ ++ "GPIO2_20", /* GMAC1_TXEN */ ++ "GPIO2_21", /* GMAC1_TXD0 */ ++ "GPIO2_22", /* GMAC1_TXD1 */ ++ "GPIO2_23", /* GMAC1_TXD2 */ ++ "GPIO2_24"; /* GMAC1_TXD3 */ ++ function = "gmac1"; ++ bias-disable; ++ drive-strength = <25>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pins = "GPIO2_19", /* GMAC1_RX_CLK */ ++ "GPIO2_25", /* GMAC1_RXDV */ ++ "GPIO2_30", /* GMAC1_RXD0 */ ++ "GPIO2_31", /* GMAC1_RXD1 */ ++ "GPIO3_0", /* GMAC1_RXD2 */ ++ "GPIO3_1"; /* GMAC1_RXD3 */ ++ function = "gmac1"; ++ bias-disable; ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ i2c3_pins: i2c3-0 { ++ i2c-pins { ++ pins = "I2C3_SCL", "I2C3_SDA"; ++ function = "i2c"; ++ bias-disable; ++ drive-strength = <7>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ mdio0_pins: mdio0-0 { ++ mdc-pins { ++ pins = "GMAC0_MDC"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <13>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ mdio-pins { ++ pins = "GMAC0_MDIO"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <13>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ uart0_pins: uart0-0 { ++ tx-pins { ++ pins = "UART0_TXD"; ++ function = "uart"; ++ bias-disable; ++ drive-strength = <3>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pins = "UART0_RXD"; ++ function = "uart"; ++ bias-disable; ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++}; ++ ++&padctrl1_apsys { ++ i2c0_pins: i2c0-0 { ++ i2c-pins { ++ pins = "I2C0_SCL", "I2C0_SDA"; ++ function = "i2c"; ++ bias-disable; ++ drive-strength = <7>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ i2c1_pins: i2c1-0 { ++ i2c-pins { ++ pins = "I2C1_SCL", "I2C1_SDA"; ++ function = "i2c"; ++ bias-disable; ++ drive-strength = <7>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; + }; + + &uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins>; ++ status = "okay"; ++}; ++ ++&usb { + status = "okay"; + }; ++ ++&usb_dwc3 { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ hub_2_0: hub@1 { ++ compatible = "usb2109,2817"; ++ reg = <1>; ++ peer-hub = <&hub_3_0>; ++ vdd-supply = <&hub_5v>; ++ vbus-supply = <&vcc5v_usb>; ++ }; ++ ++ hub_3_0: hub@2 { ++ compatible = "usb2109,817"; ++ reg = <2>; ++ peer-hub = <&hub_2_0>; ++ vbus-supply = <&vcc5v_usb>; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts b/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts +new file mode 100644 +index 000000000000..5a6baccd1684 +--- /dev/null ++++ b/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ * Copyright (C) 2024 Milk-V Limited. ++ */ ++ ++/dts-v1/; ++ ++#include "th1520-milkv-meles.dts" ++ ++/ { ++ model = "Milk-V Meles 4G"; ++ compatible = "milkv,meles", "thead,light"; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x00000000 0x1 0x00000000>; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts b/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts +new file mode 100644 +index 000000000000..394385afd53d +--- /dev/null ++++ b/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts +@@ -0,0 +1,441 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ * Copyright (C) 2024 Milk-V Limited. ++ */ ++ ++/dts-v1/; ++ ++#include "th1520.dtsi" ++#include <dt-bindings/gpio/gpio.h> ++ ++/ { ++ model = "Milk-V Meles"; ++ compatible = "milkv,meles", "thead,th1520"; ++ ++ aliases { ++ ethernet0 = &gmac0; ++ gpio0 = &gpio0; ++ gpio1 = &gpio1; ++ gpio2 = &gpio2; ++ gpio3 = &gpio3; ++ gpio4 = &gpio4; ++ gpio5 = &aogpio; ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ serial5 = &uart5; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x00000000 0x2 0x00000000>; ++ }; ++ ++ resmem: reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ //Note: with "no-map" reserv mem not saved in hibernation ++ rpmsgmem: memory@1E000000 { ++ reg = <0x0 0x1E000000 0x0 0x10000>; ++ }; ++ }; ++ ++ light_rpmsg: light_rpmsg { ++ compatible = "light,rpmsg-bus", "simple-bus"; ++ memory-region = <&rpmsgmem>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ rpmsg: rpmsg { ++ vdev-nums = <1>; ++ reg = <0x0 0x1E000000 0 0x10000>; ++ compatible = "light,light-rpmsg"; ++ status = "okay"; ++ }; ++ }; ++ ++ aon: aon { ++ compatible = "thead,light-aon"; ++ mbox-names = "aon"; ++ mboxes = <&mbox_910t 1 0>; ++ status = "okay"; ++ ++ pd: light-aon-pd { ++ compatible = "thead,light-aon-pd"; ++ #power-domain-cells = <1>; ++ }; ++ ++ aon_reg_dialog: light-dialog-reg { ++ compatible = "thead,light-dialog-pmic-ant"; ++ status = "okay"; ++ ++ dvdd_cpu_reg: appcpu_dvdd { ++ regulator-name = "appcpu_dvdd"; ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1570000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ dvddm_cpu_reg: appcpu_dvddm { ++ regulator-name = "appcpu_dvddm"; ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1570000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dvdd18_aon_reg: soc_dvdd18_aon { ++ regulator-name = "soc_dvdd18_aon"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_avdd33_usb3_reg: soc_avdd33_usb3 { ++ regulator-name = "soc_avdd33_usb3"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dvdd08_aon_reg: soc_dvdd08_aon { ++ regulator-name = "soc_dvdd08_aon"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dvdd08_ddr_reg: soc_dvdd08_ddr { ++ regulator-name = "soc_dvdd08_ddr"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd_ddr_1v8_reg: soc_vdd_ddr_1v8 { ++ regulator-name = "soc_vdd_ddr_1v8"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd_ddr_1v1_reg: soc_vdd_ddr_1v1 { ++ regulator-name = "soc_vdd_ddr_1v1"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd_ddr_0v6_reg: soc_vdd_ddr_0v6 { ++ regulator-name = "soc_vdd_ddr_0v6"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dvdd18_ap_reg: soc_dvdd18_ap { ++ regulator-name = "soc_dvdd18_ap"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_avdd08_mipi_hdmi_reg: soc_avdd08_mipi_hdmi { ++ regulator-name = "soc_avdd08_mipi_hdmi"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_avdd18_mipi_hdmi_reg: soc_avdd18_mipi_hdmi { ++ regulator-name = "soc_avdd18_mipi_hdmi"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd33_emmc_reg: soc_vdd33_emmc { ++ regulator-name = "soc_vdd33_emmc"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_vdd18_emmc_reg: soc_vdd18_emmc { ++ regulator-name = "soc_vdd18_emmc"; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ soc_dovdd18_scan_reg: soc_dovdd18_scan { ++ regulator-name = "soc_dovdd18_scan"; ++ regulator-min-microvolt = <900000>; ++ regulator-max-microvolt = <3600000>; ++ }; ++ ++ soc_dvdd12_scan_reg: soc_dvdd12_scan { ++ regulator-name = "soc_dvdd12_scan"; ++ regulator-min-microvolt = <900000>; ++ regulator-max-microvolt = <3600000>; ++ }; ++ ++ soc_avdd28_scan_en_reg: soc_avdd28_scan_en { ++ regulator-name = "soc_avdd28_scan_en"; ++ regulator-min-microvolt = <900000>; ++ regulator-max-microvolt = <3600000>; ++ }; ++ }; ++ ++ c910_cpufreq { ++ compatible = "thead,light-mpw-cpufreq"; ++ status = "okay"; ++ }; ++ ++ test: light-aon-test { ++ compatible = "thead,light-aon-test"; ++ }; ++ }; ++}; ++ ++&osc_24m { ++ clock-frequency = <24000000>; ++}; ++ ++&osc_32k { ++ clock-frequency = <32768>; ++}; ++ ++&aonsys_clk { ++ clock-frequency = <73728000>; ++}; ++ ++&apb_clk { ++ clock-frequency = <62500000>; ++}; ++ ++&sdhci_clk { ++ clock-frequency = <198000000>; ++}; ++ ++&uart_sclk { ++ clock-frequency = <100000000>; ++}; ++ ++&gmac_clk { ++ clock-frequency = <500000000>; ++}; ++ ++&gmac_axi_clk { ++ clock-frequency = <100000000>; ++}; ++ ++&dmac0 { ++ status = "okay"; ++}; ++ ++&emmc { ++ bus-width = <8>; ++ max-frequency = <198000000>; ++ mmc-hs400-1_8v; ++ non-removable; ++ no-sdio; ++ no-sd; ++ status = "okay"; ++}; ++ ++&gmac0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac0_pins>; ++ phy-handle = <&phy0>; ++ phy-mode = "rgmii-id"; ++ status = "okay"; ++}; ++ ++&mdio0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mdio0_pins>; ++ ++ phy0: ethernet-phy@1 { ++ reg = <1>; ++ }; ++}; ++ ++&sdio0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio0_pins>; ++ bus-width = <4>; ++ max-frequency = <198000000>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins>; ++ status = "okay"; ++}; ++ ++&cpus { ++ c910_0: cpu@0 { ++ operating-points = < ++ /* kHz uV */ ++ 300000 650000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 800000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ dvdd-supply = <&dvdd_cpu_reg>; ++ dvddm-supply = <&dvddm_cpu_reg>; ++ }; ++ ++ c910_1: cpu@1 { ++ operating-points = < ++ /* kHz uV */ ++ 300000 650000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 800000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ dvdd-supply = <&dvdd_cpu_reg>; ++ dvddm-supply = <&dvddm_cpu_reg>; ++ }; ++ ++ c910_2: cpu@2 { ++ operating-points = < ++ /* kHz uV */ ++ 300000 650000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 800000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ dvdd-supply = <&dvdd_cpu_reg>; ++ dvddm-supply = <&dvddm_cpu_reg>; ++ }; ++ ++ c910_3: cpu@3 { ++ operating-points = < ++ /* kHz uV */ ++ 300000 650000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 800000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ dvdd-supply = <&dvdd_cpu_reg>; ++ dvddm-supply = <&dvddm_cpu_reg>; ++ }; ++}; ++ ++&padctrl0_apsys { ++ gmac0_pins: gmac0-0 { ++ tx-pins { ++ pins = "GMAC0_TX_CLK", ++ "GMAC0_TXEN", ++ "GMAC0_TXD0", ++ "GMAC0_TXD1", ++ "GMAC0_TXD2", ++ "GMAC0_TXD3"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <25>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pins = "GMAC0_RX_CLK", ++ "GMAC0_RXDV", ++ "GMAC0_RXD0", ++ "GMAC0_RXD1", ++ "GMAC0_RXD2", ++ "GMAC0_RXD3"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ mdio0_pins: mdio0-0 { ++ mdc-pins { ++ pins = "GMAC0_MDC"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <13>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ mdio-pins { ++ pins = "GMAC0_MDIO"; ++ function = "gmac0"; ++ bias-disable; ++ drive-strength = <13>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ sdio0_pins: sdio0-0 { ++ detn-pins { ++ pins = "SDIO0_DETN"; ++ function = "sdio"; ++ bias-disable; /* external pull-up */ ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ uart0_pins: uart0-0 { ++ tx-pins { ++ pins = "UART0_TXD"; ++ function = "uart"; ++ bias-disable; ++ drive-strength = <3>; ++ input-disable; ++ input-schmitt-disable; ++ slew-rate = <0>; ++ }; ++ ++ rx-pins { ++ pins = "UART0_RXD"; ++ function = "uart"; ++ bias-disable; ++ drive-strength = <1>; ++ input-enable; ++ input-schmitt-enable; ++ slew-rate = <0>; ++ }; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi +index ff364709a6df..fab3b5f17f22 100644 +--- a/arch/riscv/boot/dts/thead/th1520.dtsi ++++ b/arch/riscv/boot/dts/thead/th1520.dtsi +@@ -5,6 +5,9 @@ + */ + + #include <dt-bindings/interrupt-controller/irq.h> ++#include <dt-bindings/clock/light-fm-ap-clock.h> ++#include <dt-bindings/gpio/gpio.h> ++#include <dt-bindings/reset/thead,th1520-reset.h> + + / { + compatible = "thead,th1520"; +@@ -29,6 +32,30 @@ c910_0: cpu@0 { + d-cache-sets = <512>; + next-level-cache = <&l2_cache>; + mmu-type = "riscv,sv39"; ++ cpu-freq = "1.848Ghz"; ++ cpu-cacheline = "64Bytes"; ++ ++ operating-points = < ++ /* kHz uV */ ++ 300000 600000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 750000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ clock-latency = <61036>; ++ clocks = <&clk C910_CCLK>, ++ <&clk C910_CCLK_I0>, ++ <&clk CPU_PLL1_FOUTPOSTDIV>, ++ <&clk CPU_PLL0_FOUTPOSTDIV>; ++ clock-names = "c910_cclk", "c910_cclk_i0", ++ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; +@@ -50,6 +77,30 @@ c910_1: cpu@1 { + d-cache-sets = <512>; + next-level-cache = <&l2_cache>; + mmu-type = "riscv,sv39"; ++ cpu-freq = "1.848Ghz"; ++ cpu-cacheline = "64Bytes"; ++ ++ operating-points = < ++ /* kHz uV */ ++ 300000 600000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 750000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ clock-latency = <61036>; ++ clocks = <&clk C910_CCLK>, ++ <&clk C910_CCLK_I0>, ++ <&clk CPU_PLL1_FOUTPOSTDIV>, ++ <&clk CPU_PLL0_FOUTPOSTDIV>; ++ clock-names = "c910_cclk", "c910_cclk_i0", ++ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; + + cpu1_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; +@@ -71,6 +122,30 @@ c910_2: cpu@2 { + d-cache-sets = <512>; + next-level-cache = <&l2_cache>; + mmu-type = "riscv,sv39"; ++ cpu-freq = "1.848Ghz"; ++ cpu-cacheline = "64Bytes"; ++ ++ operating-points = < ++ /* kHz uV */ ++ 300000 600000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 750000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ clock-latency = <61036>; ++ clocks = <&clk C910_CCLK>, ++ <&clk C910_CCLK_I0>, ++ <&clk CPU_PLL1_FOUTPOSTDIV>, ++ <&clk CPU_PLL0_FOUTPOSTDIV>; ++ clock-names = "c910_cclk", "c910_cclk_i0", ++ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; + + cpu2_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; +@@ -92,6 +167,30 @@ c910_3: cpu@3 { + d-cache-sets = <512>; + next-level-cache = <&l2_cache>; + mmu-type = "riscv,sv39"; ++ cpu-freq = "1.848Ghz"; ++ cpu-cacheline = "64Bytes"; ++ ++ operating-points = < ++ /* kHz uV */ ++ 300000 600000 ++ 800000 700000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ light,dvddm-operating-points = < ++ /* kHz uV */ ++ 300000 750000 ++ 800000 800000 ++ 1500000 800000 ++ 1848000 1000000 ++ >; ++ clock-latency = <61036>; ++ clocks = <&clk C910_CCLK>, ++ <&clk C910_CCLK_I0>, ++ <&clk CPU_PLL1_FOUTPOSTDIV>, ++ <&clk CPU_PLL0_FOUTPOSTDIV>; ++ clock-names = "c910_cclk", "c910_cclk_i0", ++ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; + + cpu3_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; +@@ -110,15 +209,111 @@ l2_cache: l2-cache { + }; + }; + +- osc: oscillator { ++ pmu { ++ compatible = "riscv,pmu"; ++ riscv,event-to-mhpmcounters = ++ <0x00003 0x00003 0x0007fff8>, ++ <0x00004 0x00004 0x0007fff8>, ++ <0x00005 0x00005 0x0007fff8>, ++ <0x00006 0x00006 0x0007fff8>, ++ <0x00007 0x00007 0x0007fff8>, ++ <0x00008 0x00008 0x0007fff8>, ++ <0x00009 0x00009 0x0007fff8>, ++ <0x0000a 0x0000a 0x0007fff8>, ++ <0x10000 0x10000 0x0007fff8>, ++ <0x10001 0x10001 0x0007fff8>, ++ <0x10002 0x10002 0x0007fff8>, ++ <0x10003 0x10003 0x0007fff8>, ++ <0x10010 0x10010 0x0007fff8>, ++ <0x10011 0x10011 0x0007fff8>, ++ <0x10012 0x10012 0x0007fff8>, ++ <0x10013 0x10013 0x0007fff8>; ++ riscv,event-to-mhpmevent = ++ <0x00003 0x00000000 0x00000001>, ++ <0x00004 0x00000000 0x00000002>, ++ <0x00006 0x00000000 0x00000006>, ++ <0x00005 0x00000000 0x00000007>, ++ <0x00007 0x00000000 0x00000008>, ++ <0x00008 0x00000000 0x00000009>, ++ <0x00009 0x00000000 0x0000000a>, ++ <0x0000a 0x00000000 0x0000000b>, ++ <0x10000 0x00000000 0x0000000c>, ++ <0x10001 0x00000000 0x0000000d>, ++ <0x10002 0x00000000 0x0000000e>, ++ <0x10003 0x00000000 0x0000000f>, ++ <0x10010 0x00000000 0x00000010>, ++ <0x10011 0x00000000 0x00000011>, ++ <0x10012 0x00000000 0x00000012>, ++ <0x10013 0x00000000 0x00000013>; ++ riscv,raw-event-to-mhpmcounters = ++ <0x00000000 0x00000001 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000002 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000003 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000004 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000005 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000006 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000007 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000008 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000009 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000000a 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000000b 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000000c 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000000d 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000000e 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000000f 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000010 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000011 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000012 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000013 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000014 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000015 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000016 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000017 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000018 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000019 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000001a 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000001b 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000001c 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000001d 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000001e 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000001f 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000020 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000021 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000022 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000023 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000024 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000025 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000026 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000027 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000028 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x00000029 0xffffffff 0xffffffff 0x0007fff8>, ++ <0x00000000 0x0000002a 0xffffffff 0xffffffff 0x0007fff8>; ++ }; ++ ++ osc_32k: clock-osc-32k { + compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ clock-output-names = "osc_32k"; ++ }; ++ ++ osc_24m: clock-osc-24m { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; + clock-output-names = "osc_24m"; ++ }; ++ ++ rc_24m: clock-rc-24m { ++ compatible = "fixed-clock"; + #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ clock-output-names = "rc_24m"; + }; + +- osc_32k: 32k-oscillator { ++ aonsys_clk: aonsys-clk { + compatible = "fixed-clock"; +- clock-output-names = "osc_32k"; ++ clock-output-names = "aonsys_clk"; + #clock-cells = <0>; + }; + +@@ -134,6 +329,36 @@ uart_sclk: uart-sclk-clock { + #clock-cells = <0>; + }; + ++ sdhci_clk: sdhci-clock { ++ compatible = "fixed-clock"; ++ clock-frequency = <198000000>; ++ clock-output-names = "sdhci_clk"; ++ #clock-cells = <0>; ++ }; ++ ++ gmac_axi_clk: gmac-axi-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "gmac_axi_clk"; ++ #clock-cells = <0>; ++ }; ++ ++ gmac_clk: gmac-clock { ++ compatible = "fixed-clock"; ++ clock-output-names = "gmac_clk"; ++ #clock-cells = <0>; ++ }; ++ ++ stmmac_axi_config: stmmac-axi-config { ++ snps,wr_osr_lmt = <15>; ++ snps,rd_osr_lmt = <15>; ++ snps,blen = <0 0 64 32 0 0 0>; ++ }; ++ ++ aon_iram: aon-iram@ffffef8000 { ++ compatible = "syscon"; ++ reg = <0xff 0xffef8000 0x0 0x10000>; ++ }; ++ + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; +@@ -142,6 +367,41 @@ soc { + dma-noncoherent; + ranges; + ++ cpurst: cpurst { ++ compatible = "thead,reset-sample"; ++ entry-reg = <0xff 0xff019050>; ++ entry-cnt = <4>; ++ control-reg = <0xff 0xff015004>; ++ control-val = <0x1c>; ++ csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>; ++ }; ++ ++ light_event: light-event { ++ compatible = "thead,light-event"; ++ aon-iram-regmap = <&aon_iram>; ++ status = "okay"; ++ }; ++ ++ audio_i2c0: i2c@ffcb01a000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0xff 0xcb01a000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ interrupts = <182 IRQ_TYPE_LEVEL_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ audio_i2c1: i2c@ffcb01b000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0xff 0xcb01b000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ interrupts = <183 IRQ_TYPE_LEVEL_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + plic: interrupt-controller@ffd8000000 { + compatible = "thead,th1520-plic", "thead,c900-plic"; + reg = <0xff 0xd8000000 0x0 0x01000000>; +@@ -164,6 +424,50 @@ clint: timer@ffdc000000 { + <&cpu3_intc 3>, <&cpu3_intc 7>; + }; + ++ gmac0: ethernet@ffe7070000 { ++ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; ++ reg = <0xff 0xe7070000 0x0 0x2000>; ++ interrupts = <66 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "macirq"; ++ clocks = <&gmac_clk>, <&gmac_axi_clk>; ++ clock-names = "stmmaceth", "pclk"; ++ snps,pbl = <32>; ++ snps,fixed-burst; ++ snps,multicast-filter-bins = <64>; ++ snps,perfect-filter-entries = <32>; ++ snps,axi-config = <&stmmac_axi_config>; ++ thead,gmacapb = <&gmac0_apb>; ++ status = "disabled"; ++ ++ mdio0: mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ }; ++ ++ gmac1: ethernet@ffe7060000 { ++ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; ++ reg = <0xff 0xe7060000 0x0 0x2000>; ++ interrupts = <67 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "macirq"; ++ clocks = <&gmac_clk>, <&gmac_axi_clk>; ++ clock-names = "stmmaceth", "pclk"; ++ snps,pbl = <32>; ++ snps,fixed-burst; ++ snps,multicast-filter-bins = <64>; ++ snps,perfect-filter-entries = <32>; ++ snps,axi-config = <&stmmac_axi_config>; ++ thead,gmacapb = <&gmac1_apb>; ++ status = "disabled"; ++ ++ mdio1: mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ }; ++ + uart0: serial@ffe7014000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff 0xe7014000 0x0 0x100>; +@@ -194,17 +498,48 @@ uart3: serial@ffe7f04000 { + status = "disabled"; + }; + +- gpio2: gpio@ffe7f34000 { ++ i2c0: i2c@ffe7f20000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0xff 0xe7f20000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@ffe7f24000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0xff 0xe7f24000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@ffe7f28000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0xff 0xe7f28000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ gpio@ffe7f34000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xe7f34000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + +- portc: gpio-controller@0 { ++ gpio2: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; ++ gpio-ranges = <&padctrl0_apsys 0 0 32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; +@@ -212,17 +547,18 @@ portc: gpio-controller@0 { + }; + }; + +- gpio3: gpio@ffe7f38000 { ++ gpio@ffe7f38000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xe7f38000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + +- portd: gpio-controller@0 { ++ gpio3: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; +- ngpios = <32>; ++ ngpios = <23>; ++ gpio-ranges = <&padctrl0_apsys 0 32 23>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; +@@ -230,17 +566,34 @@ portd: gpio-controller@0 { + }; + }; + +- gpio0: gpio@ffec005000 { ++ padctrl1_apsys: pinctrl@ffe7f3c000 { ++ compatible = "thead,th1520-group2-pinctrl"; ++ reg = <0xff 0xe7f3c000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ }; ++ ++ gmac0_apb: syscon@ffec003000 { ++ compatible = "thead,th1520-gmac-apb", "syscon"; ++ reg = <0xff 0xec003000 0x0 0x1000>; ++ }; ++ ++ gmac1_apb: syscon@ffec004000 { ++ compatible = "thead,th1520-gmac-apb", "syscon"; ++ reg = <0xff 0xec004000 0x0 0x1000>; ++ }; ++ ++ gpio@ffec005000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xec005000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + +- porta: gpio-controller@0 { ++ gpio0: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; ++ gpio-ranges = <&padctrl1_apsys 0 0 32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; +@@ -248,17 +601,18 @@ porta: gpio-controller@0 { + }; + }; + +- gpio1: gpio@ffec006000 { ++ gpio@ffec006000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xec006000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + +- portb: gpio-controller@0 { ++ gpio1: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; +- ngpios = <32>; ++ ngpios = <31>; ++ gpio-ranges = <&padctrl1_apsys 0 32 31>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; +@@ -266,6 +620,22 @@ portb: gpio-controller@0 { + }; + }; + ++ padctrl0_apsys: pinctrl@ffec007000 { ++ compatible = "thead,th1520-group3-pinctrl"; ++ reg = <0xff 0xec007000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ }; ++ ++ i2c2: i2c@ffec00c000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0xff 0xec00c000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + uart2: serial@ffec010000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff 0xec010000 0x0 0x4000>; +@@ -276,6 +646,88 @@ uart2: serial@ffec010000 { + status = "disabled"; + }; + ++ i2c3: i2c@ffec014000 { ++ compatible = "snps,designware-i2c"; ++ reg = <0xff 0xec014000 0x0 0x1000>; ++ clocks = <&apb_clk>; ++ interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ pwm: pwm@ffec01c000 { ++ compatible = "thead,th1520-pwm"; ++ reg = <0xff 0xec01c000 0x0 0x4000>; ++ #pwm-cells = <3>; ++ clocks = <&osc_24m>; ++ }; ++ ++ audio_mbox: audio_mbox@0xffefc48000 { ++ compatible = "thead,light-audio-mbox-reg", "syscon"; ++ reg = <0xff 0xefc48000 0x0 0x1000>; ++ status = "okay"; ++ }; ++ ++ mbox_910t_client1: mbox_910t_client1 { ++ compatible = "thead,light-mbox-client"; ++ mbox-names = "902"; ++ mboxes = <&mbox_910t 1 0>; ++ status = "disabled"; ++ }; ++ ++ mbox_910t_client2: mbox_910t_client2 { ++ compatible = "thead,light-mbox-client"; ++ mbox-names = "906"; ++ mboxes = <&mbox_910t 2 0>; ++ audio-mbox-regmap = <&audio_mbox>; ++ status = "okay"; ++ }; ++ ++ clk: clock-controller@ffef010000 { ++ compatible = "thead,light-fm-ree-clk"; ++ reg = <0xff 0xef010000 0x0 0x1000>; ++ #clock-cells = <1>; ++ clocks = <&osc_32k>, <&osc_24m>, <&rc_24m>; ++ clock-names = "osc_32k", "osc_24m", "rc_24m"; ++ status = "okay"; ++ }; ++ ++ rst: reset-controller@ffef014000 { ++ compatible = "thead,th1520-reset", "syscon"; ++ reg = <0xff 0xef014000 0x0 0x1000>; ++ #reset-cells = <1>; ++ }; ++ ++ sys_reg: sys_reg@ffef010100 { ++ compatible = "thead,light_sys_reg"; ++ reg = <0xff 0xef010100 0x0 0x100>; ++ status = "okay"; ++ }; ++ ++ misc_sysreg: misc_sysreg@ffec02c000 { ++ compatible = "thead,th1520-misc-sysreg", "syscon"; ++ reg = <0xff 0xec02c000 0x0 0x1000>; ++ }; ++ ++ usb: usb@ffec03f000 { ++ compatible = "thead,th1520-usb"; ++ reg = <0xff 0xec03f000 0x0 0x1000>; ++ thead,misc-sysreg = <&misc_sysreg>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ usb_dwc3: usb@ffe7040000 { ++ compatible = "snps,dwc3"; ++ reg = <0xff 0xe7040000 0x0 0x10000>; ++ interrupts = <68 IRQ_TYPE_LEVEL_HIGH>; ++ dr_mode = "host"; ++ snps,usb3_lpm_capable; ++ status = "disabled"; ++ }; ++ }; ++ + dmac0: dma-controller@ffefc00000 { + compatible = "snps,axi-dma-1.01a"; + reg = <0xff 0xefc00000 0x0 0x1000>; +@@ -292,6 +744,33 @@ dmac0: dma-controller@ffefc00000 { + status = "disabled"; + }; + ++ emmc: mmc@ffe7080000 { ++ compatible = "thead,th1520-dwcmshc"; ++ reg = <0xff 0xe7080000 0x0 0x10000>; ++ interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&sdhci_clk>; ++ clock-names = "core"; ++ status = "disabled"; ++ }; ++ ++ sdio0: mmc@ffe7090000 { ++ compatible = "thead,th1520-dwcmshc"; ++ reg = <0xff 0xe7090000 0x0 0x10000>; ++ interrupts = <64 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&sdhci_clk>; ++ clock-names = "core"; ++ status = "disabled"; ++ }; ++ ++ sdio1: mmc@ffe70a0000 { ++ compatible = "thead,th1520-dwcmshc"; ++ reg = <0xff 0xe70a0000 0x0 0x10000>; ++ interrupts = <71 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&sdhci_clk>; ++ clock-names = "core"; ++ status = "disabled"; ++ }; ++ + timer0: timer@ffefc32000 { + compatible = "snps,dw-apb-timer"; + reg = <0xff 0xefc32000 0x0 0x14>; +@@ -384,17 +863,18 @@ timer7: timer@ffffc3303c { + status = "disabled"; + }; + +- ao_gpio0: gpio@fffff41000 { ++ gpio@fffff41000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xfff41000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + +- porte: gpio-controller@0 { ++ aogpio: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; +- ngpios = <32>; ++ ngpios = <16>; ++ gpio-ranges = <&padctrl_aosys 0 9 16>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; +@@ -402,22 +882,77 @@ porte: gpio-controller@0 { + }; + }; + +- ao_gpio1: gpio@fffff52000 { ++ padctrl_aosys: pinctrl@fffff4a000 { ++ compatible = "thead,th1520-group1-pinctrl"; ++ reg = <0xff 0xfff4a000 0x0 0x2000>; ++ clocks = <&aonsys_clk>; ++ }; ++ ++ pvt: pvt@fffff4e000 { ++ compatible = "moortec,mr75203"; ++ reg = <0xff 0xfff4e000 0x0 0x80>, ++ <0xff 0xfff4e080 0x0 0x100>, ++ <0xff 0xfff4e180 0x0 0x680>, ++ <0xff 0xfff4e800 0x0 0x600>; ++ reg-names = "common", "ts", "pd", "vm"; ++ clocks = <&aonsys_clk>; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ gpio@fffff52000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xff 0xfff52000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + +- portf: gpio-controller@0 { ++ gpio4: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; +- ngpios = <32>; ++ ngpios = <23>; ++ gpio-ranges = <&padctrl_aosys 0 25 22>, <&padctrl_aosys 22 7 1>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <55 IRQ_TYPE_LEVEL_HIGH>; + }; + }; ++ ++ mbox_910t: mbox@ffffc38000 { ++ compatible = "thead,light-mbox"; ++ reg = <0xff 0xffc38000 0x0 0x4000>, ++ <0xff 0xffc44000 0x0 0x1000>, ++ <0xff 0xffc4c000 0x0 0x1000>, ++ <0xff 0xffc54000 0x0 0x1000>; ++ reg-names = "local_base", "remote_icu0", "remote_icu1", "remote_icu2"; ++ #interrupt-cells = <2>; ++ interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&apb_clk>; ++ clock-names = "ipg"; ++ icu_cpu_id = <0>; ++ #mbox-cells = <2>; ++ }; ++ ++ watchdog0: watchdog@ffefc30000 { ++ compatible = "snps,dw-wdt"; ++ reg = <0xff 0xefc30000 0x0 0x1000>; ++ interrupt-parent = <&plic>; ++ interrupts = <24>; ++ clocks = <&clk CLKGEN_WDT0_PCLK>; ++ clock-names = "tclk"; ++ resets = <&rst TH1520_RESET_WDT0>; ++ status = "okay"; ++ }; ++ ++ watchdog1: watchdog@ffefc31000 { ++ compatible = "snps,dw-wdt"; ++ reg = <0xff 0xefc31000 0x0 0x1000>; ++ interrupt-parent = <&plic>; ++ interrupts = <25>; ++ clocks = <&clk CLKGEN_WDT1_PCLK>; ++ clock-names = "tclk"; ++ resets = <&rst TH1520_RESET_WDT1>; ++ status = "okay"; ++ }; + }; + }; +diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig +index ab86ec3b9eab..3de25be550fd 100644 +--- a/arch/riscv/configs/defconfig ++++ b/arch/riscv/configs/defconfig +@@ -27,10 +27,11 @@ CONFIG_EXPERT=y + CONFIG_PROFILING=y + CONFIG_SOC_MICROCHIP_POLARFIRE=y + CONFIG_ARCH_RENESAS=y +-CONFIG_ARCH_THEAD=y + CONFIG_SOC_SIFIVE=y ++CONFIG_ARCH_SOPHGO=y + CONFIG_SOC_STARFIVE=y + CONFIG_ARCH_SUNXI=y ++CONFIG_ARCH_THEAD=y + CONFIG_SOC_VIRT=y + CONFIG_SMP=y + CONFIG_HOTPLUG_CPU=y +@@ -168,12 +169,15 @@ CONFIG_MMC=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SDHCI_CADENCE=y ++CONFIG_MMC_SDHCI_OF_DWCMSHC=y + CONFIG_MMC_SPI=y + CONFIG_MMC_SUNXI=y + CONFIG_RTC_CLASS=y + CONFIG_RTC_DRV_SUN6I=y + CONFIG_DMADEVICES=y + CONFIG_DMA_SUN6I=m ++CONFIG_DW_AXI_DMAC=y ++CONFIG_RZ_DMAC=y + CONFIG_VIRTIO_PCI=y + CONFIG_VIRTIO_BALLOON=y + CONFIG_VIRTIO_INPUT=y +diff --git a/arch/riscv/configs/openeuler_defconfig b/arch/riscv/configs/openeuler_defconfig +index 24a04cd8c1c0..514aee201d9b 100644 +--- a/arch/riscv/configs/openeuler_defconfig ++++ b/arch/riscv/configs/openeuler_defconfig +@@ -2,6 +2,7 @@ + # Automatically generated file; DO NOT EDIT. + # Linux/riscv 6.6.0 Kernel Configuration + # ++CONFIG_TOOLS_SUPPORT_RELR=y + CONFIG_IRQ_WORK=y + CONFIG_BUILDTIME_TABLE_SORT=y + CONFIG_THREAD_INFO_IN_TASK=y +@@ -12,6 +13,7 @@ CONFIG_THREAD_INFO_IN_TASK=y + CONFIG_INIT_ENV_ARG_LIMIT=32 + # CONFIG_COMPILE_TEST is not set + # CONFIG_WERROR is not set ++# CONFIG_UAPI_HEADER_TEST is not set + CONFIG_LOCALVERSION="" + # CONFIG_LOCALVERSION_AUTO is not set + CONFIG_BUILD_SALT="" +@@ -70,6 +72,7 @@ CONFIG_CONTEXT_TRACKING_USER=y + # CONFIG_CONTEXT_TRACKING_USER_FORCE is not set + CONFIG_NO_HZ=y + CONFIG_HIGH_RES_TIMERS=y ++# CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE is not set + # end of Timers subsystem + + CONFIG_BPF=y +@@ -85,6 +88,7 @@ CONFIG_BPF_JIT_DEFAULT_ON=y + # CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set + # CONFIG_BPF_PRELOAD is not set + # CONFIG_BPF_LSM is not set ++# CONFIG_BPF_SCHED is not set + # end of BPF subsystem + + CONFIG_PREEMPT_VOLUNTARY_BUILD=y +@@ -110,6 +114,8 @@ CONFIG_TASK_XACCT=y + CONFIG_TASK_IO_ACCOUNTING=y + CONFIG_PSI=y + CONFIG_PSI_DEFAULT_DISABLED=y ++# CONFIG_PSI_CGROUP_V1 is not set ++# CONFIG_PSI_FINE_GRAINED is not set + # end of CPU/Task time and stats accounting + + CONFIG_CPU_ISOLATION=y +@@ -163,6 +169,7 @@ CONFIG_CGROUP_SCHED=y + CONFIG_FAIR_GROUP_SCHED=y + CONFIG_CFS_BANDWIDTH=y + CONFIG_RT_GROUP_SCHED=y ++# CONFIG_QOS_SCHED_DYNAMIC_AFFINITY is not set + CONFIG_SCHED_MM_CID=y + CONFIG_CGROUP_PIDS=y + CONFIG_CGROUP_RDMA=y +@@ -178,6 +185,8 @@ CONFIG_CGROUP_BPF=y + # CONFIG_CGROUP_DEBUG is not set + CONFIG_SOCK_CGROUP_DATA=y + # CONFIG_CGROUP_V1_KILL is not set ++# CONFIG_CGROUP_V1_STAT is not set ++# CONFIG_CGROUP_FILES is not set + CONFIG_NAMESPACES=y + CONFIG_UTS_NS=y + CONFIG_TIME_NS=y +@@ -185,6 +194,7 @@ CONFIG_IPC_NS=y + CONFIG_USER_NS=y + CONFIG_PID_NS=y + CONFIG_NET_NS=y ++# CONFIG_SCHED_STEAL is not set + CONFIG_CHECKPOINT_RESTORE=y + CONFIG_SCHED_AUTOGROUP=y + CONFIG_RELAY=y +@@ -197,6 +207,7 @@ CONFIG_RD_XZ=y + CONFIG_RD_LZO=y + CONFIG_RD_LZ4=y + CONFIG_RD_ZSTD=y ++CONFIG_INITRAMFS_FILE_METADATA="" + CONFIG_BOOT_CONFIG=y + # CONFIG_BOOT_CONFIG_FORCE is not set + # CONFIG_BOOT_CONFIG_EMBED is not set +@@ -291,19 +302,20 @@ CONFIG_FIX_EARLYCON_MEM=y + CONFIG_PGTABLE_LEVELS=5 + CONFIG_LOCKDEP_SUPPORT=y + CONFIG_RISCV_DMA_NONCOHERENT=y ++CONFIG_RISCV_NONSTANDARD_CACHE_OPS=y + + # + # SoC selection + # +-CONFIG_ARCH_MICROCHIP_POLARFIRE=y +-CONFIG_SOC_MICROCHIP_POLARFIRE=y ++# CONFIG_SOC_MICROCHIP_POLARFIRE is not set + # CONFIG_ARCH_RENESAS is not set + CONFIG_ARCH_SIFIVE=y + CONFIG_SOC_SIFIVE=y ++CONFIG_ARCH_SOPHGO=y + CONFIG_ARCH_STARFIVE=y + CONFIG_SOC_STARFIVE=y + # CONFIG_ARCH_SUNXI is not set +-# CONFIG_ARCH_THEAD is not set ++CONFIG_ARCH_THEAD=y + CONFIG_ARCH_VIRT=y + CONFIG_SOC_VIRT=y + # end of SoC selection +@@ -315,7 +327,10 @@ CONFIG_SOC_VIRT=y + CONFIG_ERRATA_SIFIVE=y + CONFIG_ERRATA_SIFIVE_CIP_453=y + CONFIG_ERRATA_SIFIVE_CIP_1200=y +-# CONFIG_ERRATA_THEAD is not set ++CONFIG_ERRATA_THEAD=y ++CONFIG_ERRATA_THEAD_PBMT=y ++CONFIG_ERRATA_THEAD_CMO=y ++CONFIG_ERRATA_THEAD_PMU=y + # end of CPU errata selection + + # +@@ -334,15 +349,12 @@ CONFIG_TUNE_GENERIC=y + CONFIG_NUMA=y + CONFIG_NODES_SHIFT=7 + CONFIG_RISCV_ALTERNATIVE=y ++CONFIG_RISCV_ALTERNATIVE_EARLY=y + CONFIG_RISCV_ISA_C=y + CONFIG_RISCV_ISA_SVNAPOT=y + CONFIG_RISCV_ISA_SVPBMT=y +-CONFIG_TOOLCHAIN_HAS_V=y +-CONFIG_RISCV_ISA_V=y +-CONFIG_RISCV_ISA_V_DEFAULT_ENABLE=y + CONFIG_RISCV_ISA_ZICBOM=y + CONFIG_RISCV_ISA_ZICBOZ=y +-CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE=y + CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y + CONFIG_FPU=y + CONFIG_IRQ_STACKS=y +@@ -374,14 +386,9 @@ CONFIG_COMPAT=y + # + # Boot options + # +-CONFIG_CMDLINE="console=ttyAMA0" +-CONFIG_CMDLINE_FALLBACK=y +-# CONFIG_CMDLINE_EXTEND is not set +-# CONFIG_CMDLINE_FORCE is not set ++CONFIG_CMDLINE="" + CONFIG_EFI_STUB=y + CONFIG_EFI=y +-CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y +-CONFIG_STACKPROTECTOR_PER_TASK=y + CONFIG_RISCV_ISA_FALLBACK=y + # end of Boot options + +@@ -461,6 +468,7 @@ CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + # + CONFIG_CPUFREQ_DT=y + CONFIG_CPUFREQ_DT_PLATDEV=y ++CONFIG_RISCV_THEAD_LIGHT_CPUFREQ=y + # end of CPU Frequency scaling + # end of CPU Power Management + +@@ -566,7 +574,6 @@ CONFIG_HAVE_PREEMPT_DYNAMIC_KEY=y + CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y + CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y + CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y +-CONFIG_DYNAMIC_SIGFRAME=y + + # + # GCOV-based kernel profiling +@@ -622,6 +629,7 @@ CONFIG_BLK_DEV_WRITE_MOUNTED=y + CONFIG_BLK_DEV_ZONED=y + CONFIG_BLK_DEV_THROTTLING=y + # CONFIG_BLK_DEV_THROTTLING_LOW is not set ++# CONFIG_BLK_DEV_SUPPORT_LEGACY_GLOBAL_LIMIT is not set + CONFIG_BLK_WBT=y + CONFIG_BLK_WBT_MQ=y + # CONFIG_BLK_CGROUP_IOLATENCY is not set +@@ -631,7 +639,10 @@ CONFIG_BLK_WBT_MQ=y + CONFIG_BLK_DEBUG_FS=y + CONFIG_BLK_DEBUG_FS_ZONED=y + # CONFIG_BLK_SED_OPAL is not set +-# CONFIG_BLK_INLINE_ENCRYPTION is not set ++CONFIG_BLK_INLINE_ENCRYPTION=y ++CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y ++# CONFIG_BLK_DEV_DETECT_WRITING_PART0 is not set ++# CONFIG_BLK_DEV_WRITE_MOUNTED_DUMP is not set + + # + # Partition Types +@@ -692,13 +703,13 @@ CONFIG_ARCH_HAS_MMIOWB=y + CONFIG_MMIOWB=y + CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y + CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y ++# CONFIG_PID_MAX_PER_NAMESPACE is not set + CONFIG_FREEZER=y + + # + # Executable file formats + # + CONFIG_BINFMT_ELF=y +-CONFIG_COMPAT_BINFMT_ELF=y + CONFIG_ELFCORE=y + CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y + CONFIG_BINFMT_SCRIPT=y +@@ -785,8 +796,8 @@ CONFIG_USE_PERCPU_NUMA_NODE_ID=y + CONFIG_CMA=y + # CONFIG_CMA_DEBUG is not set + # CONFIG_CMA_DEBUGFS is not set +-# CONFIG_CMA_SYSFS is not set +-CONFIG_CMA_AREAS=7 ++CONFIG_CMA_SYSFS=y ++CONFIG_CMA_AREAS=19 + CONFIG_GENERIC_EARLY_IOREMAP=y + # CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set + CONFIG_PAGE_IDLE_FLAG=y +@@ -810,7 +821,6 @@ CONFIG_LRU_GEN_ENABLED=y + CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y + CONFIG_PER_VMA_LOCK=y + CONFIG_LOCK_MM_AND_FIND_VMA=y +-# CONFIG_ASCEND_OOM is not set + # CONFIG_PAGE_CACHE_LIMIT is not set + + # +@@ -917,6 +927,7 @@ CONFIG_DEFAULT_CUBIC=y + # CONFIG_DEFAULT_RENO is not set + CONFIG_DEFAULT_TCP_CONG="cubic" + CONFIG_TCP_MD5SIG=y ++# CONFIG_TCP_COMP is not set + CONFIG_IPV6=y + CONFIG_IPV6_ROUTER_PREF=y + CONFIG_IPV6_ROUTE_INFO=y +@@ -1556,10 +1567,12 @@ CONFIG_PAGE_POOL_STATS=y + CONFIG_FAILOVER=y + CONFIG_ETHTOOL_NETLINK=y + CONFIG_NETACC_BPF=y ++CONFIG_NETACC_TERRACE=y + + # + # Device Drivers + # ++CONFIG_ARM_AMBA=y + CONFIG_HAVE_PCI=y + CONFIG_PCI=y + CONFIG_PCI_DOMAINS=y +@@ -1606,14 +1619,22 @@ CONFIG_HOTPLUG_PCI_SHPC=y + # CONFIG_PCI_FTPCI100 is not set + CONFIG_PCI_HOST_COMMON=y + CONFIG_PCI_HOST_GENERIC=y +-# CONFIG_PCIE_MICROCHIP_HOST is not set ++CONFIG_PCIE_MICROCHIP_HOST=y + CONFIG_PCIE_XILINX=y + + # + # Cadence-based PCIe controllers + # +-# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +-# CONFIG_PCI_J721E_HOST is not set ++CONFIG_PCIE_CADENCE=y ++CONFIG_PCIE_CADENCE_HOST=y ++CONFIG_PCIE_CADENCE_EP=y ++CONFIG_PCIE_CADENCE_PLAT=y ++CONFIG_PCIE_CADENCE_PLAT_HOST=y ++CONFIG_PCIE_CADENCE_PLAT_EP=y ++CONFIG_PCIE_CADENCE_SOPHGO=y ++CONFIG_PCI_J721E=y ++CONFIG_PCI_J721E_HOST=y ++# CONFIG_PCI_J721E_EP is not set + # end of Cadence-based PCIe controllers + + # +@@ -1621,8 +1642,11 @@ CONFIG_PCIE_XILINX=y + # + CONFIG_PCIE_DW=y + CONFIG_PCIE_DW_HOST=y ++CONFIG_PCIE_DW_EP=y + # CONFIG_PCI_MESON is not set +-# CONFIG_PCIE_DW_PLAT_HOST is not set ++CONFIG_PCIE_DW_PLAT=y ++CONFIG_PCIE_DW_PLAT_HOST=y ++CONFIG_PCIE_DW_PLAT_EP=y + CONFIG_PCIE_FU740=y + # end of DesignWare-based PCIe controllers + +@@ -1635,7 +1659,10 @@ CONFIG_PCIE_FU740=y + # + # PCI Endpoint + # +-# CONFIG_PCI_ENDPOINT is not set ++CONFIG_PCI_ENDPOINT=y ++CONFIG_PCI_ENDPOINT_CONFIGFS=y ++# CONFIG_PCI_EPF_TEST is not set ++# CONFIG_PCI_EPF_NTB is not set + # end of PCI Endpoint + + # +@@ -1677,8 +1704,9 @@ CONFIG_WANT_DEV_COREDUMP=y + # CONFIG_DEBUG_DEVRES is not set + # CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set + # CONFIG_TEST_ASYNC_DRIVER_PROBE is not set ++CONFIG_GENERIC_CPU_DEVICES=y + CONFIG_REGMAP=y +-CONFIG_REGMAP_I2C=m ++CONFIG_REGMAP_I2C=y + CONFIG_REGMAP_SPI=m + CONFIG_REGMAP_MMIO=y + CONFIG_DMA_SHARED_BUFFER=y +@@ -1716,7 +1744,7 @@ CONFIG_PROC_EVENTS=y + + # CONFIG_FIRMWARE_MEMMAP is not set + CONFIG_SYSFB=y +-# CONFIG_SYSFB_SIMPLEFB is not set ++CONFIG_SYSFB_SIMPLEFB=y + # CONFIG_GOOGLE_FIRMWARE is not set + + # +@@ -1743,6 +1771,9 @@ CONFIG_EFI_EARLYCON=y + # Tegra firmware driver + # + # end of Tegra firmware driver ++ ++CONFIG_LIGHT_AON=y ++CONFIG_LIGHT_AON_PD=y + # end of Firmware Drivers + + # CONFIG_GNSS is not set +@@ -1922,8 +1953,8 @@ CONFIG_BLK_DEV_RBD=m + # + # NVME Support + # +-CONFIG_NVME_CORE=m +-CONFIG_BLK_DEV_NVME=m ++CONFIG_NVME_CORE=y ++CONFIG_BLK_DEV_NVME=y + CONFIG_NVME_MULTIPATH=y + # CONFIG_NVME_VERBOSE_ERRORS is not set + # CONFIG_NVME_HWMON is not set +@@ -1963,7 +1994,7 @@ CONFIG_SENSORS_APDS990X=m + # CONFIG_HMC6352 is not set + # CONFIG_DS1682 is not set + # CONFIG_LATTICE_ECP3_CONFIG is not set +-# CONFIG_SRAM is not set ++CONFIG_SRAM=y + # CONFIG_DW_XDATA_PCIE is not set + # CONFIG_PCI_ENDPOINT_TEST is not set + # CONFIG_XILINX_SDFEC is not set +@@ -2163,6 +2194,7 @@ CONFIG_ATA_PIIX=m + # CONFIG_SATA_ULI is not set + # CONFIG_SATA_VIA is not set + # CONFIG_SATA_VITESSE is not set ++# CONFIG_SATA_ZHAOXIN is not set + + # + # PATA SFF controllers with BMDMA +@@ -2431,6 +2463,8 @@ CONFIG_ICE=m + CONFIG_ICE_SWITCHDEV=y + CONFIG_FM10K=m + # CONFIG_IGC is not set ++CONFIG_NET_VENDOR_MUCSE=y ++# CONFIG_MXGBE is not set + # CONFIG_JME is not set + CONFIG_NET_VENDOR_ADI=y + # CONFIG_ADIN1110 is not set +@@ -2535,7 +2569,17 @@ CONFIG_EPIC100=m + CONFIG_SMSC911X=m + CONFIG_SMSC9420=m + # CONFIG_NET_VENDOR_SOCIONEXT is not set +-# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_NET_VENDOR_STMICRO=y ++CONFIG_STMMAC_ETH=m ++# CONFIG_STMMAC_SELFTESTS is not set ++CONFIG_STMMAC_PLATFORM=m ++# CONFIG_DWMAC_DWC_QOS_ETH is not set ++CONFIG_DWMAC_GENERIC=m ++CONFIG_DWMAC_STARFIVE=m ++CONFIG_DWMAC_THEAD=m ++# CONFIG_DWMAC_INTEL_PLAT is not set ++# CONFIG_DWMAC_LOONGSON is not set ++# CONFIG_STMMAC_PCI is not set + # CONFIG_NET_VENDOR_SUN is not set + # CONFIG_NET_VENDOR_SYNOPSYS is not set + # CONFIG_NET_VENDOR_TEHUTI is not set +@@ -2903,7 +2947,7 @@ CONFIG_KEYBOARD_ATKBD=y + # CONFIG_KEYBOARD_QT2160 is not set + # CONFIG_KEYBOARD_DLINK_DIR685 is not set + # CONFIG_KEYBOARD_LKKBD is not set +-# CONFIG_KEYBOARD_GPIO is not set ++CONFIG_KEYBOARD_GPIO=y + # CONFIG_KEYBOARD_GPIO_POLLED is not set + # CONFIG_KEYBOARD_TCA6416 is not set + # CONFIG_KEYBOARD_TCA8418 is not set +@@ -3005,6 +3049,7 @@ CONFIG_RMI4_F30=y + # + CONFIG_SERIO=y + CONFIG_SERIO_SERPORT=y ++# CONFIG_SERIO_AMBAKMI is not set + # CONFIG_SERIO_PCIPS2 is not set + CONFIG_SERIO_LIBPS2=y + CONFIG_SERIO_RAW=m +@@ -3063,6 +3108,8 @@ CONFIG_SERIAL_OF_PLATFORM=y + # + # Non-8250 serial port support + # ++# CONFIG_SERIAL_AMBA_PL010 is not set ++# CONFIG_SERIAL_AMBA_PL011 is not set + # CONFIG_SERIAL_EARLYCON_SEMIHOST is not set + # CONFIG_SERIAL_KGDB_NMI is not set + # CONFIG_SERIAL_MAX3100 is not set +@@ -3148,7 +3195,7 @@ CONFIG_TCG_TIS_ST33ZP24_SPI=m + CONFIG_I2C=y + CONFIG_I2C_BOARDINFO=y + CONFIG_I2C_COMPAT=y +-CONFIG_I2C_CHARDEV=m ++CONFIG_I2C_CHARDEV=y + CONFIG_I2C_MUX=m + + # +@@ -3166,16 +3213,9 @@ CONFIG_I2C_MUX_PINCTRL=m + CONFIG_I2C_MUX_MLXCPLD=m + # end of Multiplexer I2C Chip support + +-# CONFIG_I2C_HELPER_AUTO is not set +-CONFIG_I2C_SMBUS=m +- +-# +-# I2C Algorithms +-# ++CONFIG_I2C_HELPER_AUTO=y + CONFIG_I2C_ALGOBIT=y +-# CONFIG_I2C_ALGOPCF is not set + CONFIG_I2C_ALGOPCA=m +-# end of I2C Algorithms + + # + # I2C Hardware Bus support +@@ -3184,6 +3224,7 @@ CONFIG_I2C_ALGOPCA=m + # + # PC SMBus host controller drivers + # ++CONFIG_I2C_CCGX_UCSI=m + # CONFIG_I2C_ALI1535 is not set + # CONFIG_I2C_ALI1563 is not set + # CONFIG_I2C_ALI15X3 is not set +@@ -3204,14 +3245,14 @@ CONFIG_I2C_NFORCE2=m + # I2C system bus drivers (mostly embedded / system-on-chip) + # + # CONFIG_I2C_CBUS_GPIO is not set +-CONFIG_I2C_DESIGNWARE_CORE=m +-# CONFIG_I2C_DESIGNWARE_SLAVE is not set +-CONFIG_I2C_DESIGNWARE_PLATFORM=m +-# CONFIG_I2C_DESIGNWARE_PCI is not set ++CONFIG_I2C_DESIGNWARE_CORE=y ++CONFIG_I2C_DESIGNWARE_SLAVE=y ++CONFIG_I2C_DESIGNWARE_PLATFORM=y ++CONFIG_I2C_DESIGNWARE_PCI=m + # CONFIG_I2C_EMEV2 is not set + CONFIG_I2C_GPIO=m + # CONFIG_I2C_GPIO_FAULT_INJECTOR is not set +-# CONFIG_I2C_MICROCHIP_CORE is not set ++# CONFIG_I2C_NOMADIK is not set + # CONFIG_I2C_OCORES is not set + CONFIG_I2C_PCA_PLATFORM=m + # CONFIG_I2C_RK3X is not set +@@ -3268,6 +3309,7 @@ CONFIG_SPI_DW_MMIO=y + # CONFIG_SPI_MICROCHIP_CORE_QSPI is not set + # CONFIG_SPI_OC_TINY is not set + # CONFIG_SPI_PCI1XXXX is not set ++# CONFIG_SPI_PL022 is not set + # CONFIG_SPI_PXA2XX is not set + # CONFIG_SPI_SC18IS602 is not set + CONFIG_SPI_SIFIVE=y +@@ -3334,6 +3376,7 @@ CONFIG_GENERIC_PINCONF=y + # CONFIG_PINCTRL_SINGLE is not set + # CONFIG_PINCTRL_STMFX is not set + # CONFIG_PINCTRL_SX150X is not set ++CONFIG_PINCTRL_TH1520=y + + # + # Renesas pinctrl drivers +@@ -3359,7 +3402,7 @@ CONFIG_GPIO_GENERIC=y + # + # CONFIG_GPIO_74XX_MMIO is not set + # CONFIG_GPIO_ALTERA is not set +-# CONFIG_GPIO_CADENCE is not set ++CONFIG_GPIO_CADENCE=m + CONFIG_GPIO_DWAPB=y + # CONFIG_GPIO_EXAR is not set + # CONFIG_GPIO_FTGPIO010 is not set +@@ -3368,6 +3411,7 @@ CONFIG_GPIO_GENERIC_PLATFORM=m + # CONFIG_GPIO_HLWD is not set + # CONFIG_GPIO_LOGICVC is not set + # CONFIG_GPIO_MB86S7X is not set ++# CONFIG_GPIO_PL061 is not set + CONFIG_GPIO_SIFIVE=y + # CONFIG_GPIO_SYSCON is not set + # CONFIG_GPIO_XILINX is not set +@@ -3383,7 +3427,8 @@ CONFIG_GPIO_SIFIVE=y + # CONFIG_GPIO_GW_PLD is not set + # CONFIG_GPIO_MAX7300 is not set + # CONFIG_GPIO_MAX732X is not set +-# CONFIG_GPIO_PCA953X is not set ++CONFIG_GPIO_PCA953X=y ++CONFIG_GPIO_PCA953X_IRQ=y + # CONFIG_GPIO_PCA9570 is not set + # CONFIG_GPIO_PCF857X is not set + # CONFIG_GPIO_TPIC2810 is not set +@@ -3566,7 +3611,7 @@ CONFIG_SENSORS_MAX31790=m + CONFIG_SENSORS_MCP3021=m + # CONFIG_SENSORS_TC654 is not set + # CONFIG_SENSORS_TPS23861 is not set +-# CONFIG_SENSORS_MR75203 is not set ++CONFIG_SENSORS_MR75203=m + CONFIG_SENSORS_ADCXX=m + CONFIG_SENSORS_LM63=m + CONFIG_SENSORS_LM70=m +@@ -3646,7 +3691,7 @@ CONFIG_SENSORS_UCD9200=m + # CONFIG_SENSORS_XDPE152 is not set + # CONFIG_SENSORS_XDPE122 is not set + CONFIG_SENSORS_ZL6100=m +-CONFIG_SENSORS_PWM_FAN=m ++CONFIG_SENSORS_PWM_FAN=y + # CONFIG_SENSORS_SBTSI is not set + # CONFIG_SENSORS_SBRMI is not set + CONFIG_SENSORS_SHT15=m +@@ -3744,6 +3789,7 @@ CONFIG_ALIM7101_WDT=m + CONFIG_I6300ESB_WDT=m + # CONFIG_MEN_A21_WDT is not set + CONFIG_STARFIVE_WATCHDOG=y ++CONFIG_LIGHT_PMIC_WATCHDOG=y + + # + # PCI-based Watchdog Cards +@@ -3894,7 +3940,7 @@ CONFIG_MFD_SYSCON=y + + CONFIG_REGULATOR=y + # CONFIG_REGULATOR_DEBUG is not set +-# CONFIG_REGULATOR_FIXED_VOLTAGE is not set ++CONFIG_REGULATOR_FIXED_VOLTAGE=y + # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set + # CONFIG_REGULATOR_USERSPACE_CONSUMER is not set + # CONFIG_REGULATOR_88PG86X is not set +@@ -3937,7 +3983,7 @@ CONFIG_REGULATOR=y + # CONFIG_REGULATOR_PV88060 is not set + # CONFIG_REGULATOR_PV88080 is not set + # CONFIG_REGULATOR_PV88090 is not set +-# CONFIG_REGULATOR_PWM is not set ++CONFIG_REGULATOR_PWM=y + # CONFIG_REGULATOR_RAA215300 is not set + # CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set + # CONFIG_REGULATOR_RT4801 is not set +@@ -3965,6 +4011,7 @@ CONFIG_REGULATOR=y + # CONFIG_REGULATOR_TPS65132 is not set + # CONFIG_REGULATOR_TPS6524X is not set + # CONFIG_REGULATOR_VCTRL is not set ++CONFIG_REGULATOR_LIGHT_AON=y + # CONFIG_RC_CORE is not set + + # +@@ -4644,8 +4691,9 @@ CONFIG_AUXDISPLAY=y + # CONFIG_CHARLCD_BL_OFF is not set + # CONFIG_CHARLCD_BL_ON is not set + CONFIG_CHARLCD_BL_FLASH=y +-CONFIG_DRM=m +-CONFIG_DRM_KMS_HELPER=m ++CONFIG_DRM=y ++# CONFIG_DRM_DEBUG_MM is not set ++CONFIG_DRM_KMS_HELPER=y + # CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set + # CONFIG_DRM_DEBUG_MODESET_LOCK is not set + CONFIG_DRM_FBDEV_EMULATION=y +@@ -4841,7 +4889,10 @@ CONFIG_FB_EFI=y + # CONFIG_FB_RIVA is not set + # CONFIG_FB_I740 is not set + # CONFIG_FB_MATROX is not set +-# CONFIG_FB_RADEON is not set ++CONFIG_FB_RADEON=y ++CONFIG_FB_RADEON_I2C=y ++CONFIG_FB_RADEON_BACKLIGHT=y ++# CONFIG_FB_RADEON_DEBUG is not set + # CONFIG_FB_ATY128 is not set + # CONFIG_FB_ATY is not set + # CONFIG_FB_S3 is not set +@@ -4871,6 +4922,7 @@ CONFIG_FB_CORE=y + CONFIG_FB_NOTIFY=y + # CONFIG_FIRMWARE_EDID is not set + CONFIG_FB_DEVICE=y ++CONFIG_FB_DDC=y + CONFIG_FB_CFB_FILLRECT=y + CONFIG_FB_CFB_COPYAREA=y + CONFIG_FB_CFB_IMAGEBLIT=y +@@ -4883,7 +4935,7 @@ CONFIG_FB_DEFERRED_IO=y + CONFIG_FB_IOMEM_HELPERS=y + CONFIG_FB_SYSMEM_HELPERS=y + CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y +-CONFIG_FB_BACKLIGHT=m ++CONFIG_FB_BACKLIGHT=y + CONFIG_FB_MODE_HELPERS=y + CONFIG_FB_TILEBLITTING=y + # end of Frame buffer Devices +@@ -4931,10 +4983,10 @@ CONFIG_DUMMY_CONSOLE=y + CONFIG_DUMMY_CONSOLE_COLUMNS=80 + CONFIG_DUMMY_CONSOLE_ROWS=25 + CONFIG_FRAMEBUFFER_CONSOLE=y +-# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set ++CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION=y + CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y + CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +-# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set ++CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y + # end of Console display driver support + + CONFIG_LOGO=y +@@ -5319,8 +5371,29 @@ CONFIG_USB_MICROTEK=m + # USB dual-mode controller drivers + # + # CONFIG_USB_CDNS_SUPPORT is not set +-# CONFIG_USB_MUSB_HDRC is not set +-# CONFIG_USB_DWC3 is not set ++CONFIG_USB_MUSB_HDRC=y ++CONFIG_USB_MUSB_HOST=y ++ ++# ++# Platform Glue Layer ++# ++ ++# ++# MUSB DMA mode ++# ++# CONFIG_MUSB_PIO_ONLY is not set ++CONFIG_USB_DWC3=m ++# CONFIG_USB_DWC3_ULPI is not set ++# CONFIG_USB_DWC3_HOST is not set ++# CONFIG_USB_DWC3_GADGET is not set ++CONFIG_USB_DWC3_DUAL_ROLE=y ++ ++# ++# Platform Glue Driver Support ++# ++CONFIG_USB_DWC3_HAPS=m ++CONFIG_USB_DWC3_OF_SIMPLE=m ++CONFIG_USB_DWC3_THEAD=m + # CONFIG_USB_DWC2 is not set + # CONFIG_USB_CHIPIDEA is not set + # CONFIG_USB_ISP1760 is not set +@@ -5412,7 +5485,7 @@ CONFIG_USB_HSIC_USB3503=m + # CONFIG_USB_HSIC_USB4604 is not set + # CONFIG_USB_LINK_LAYER_TEST is not set + CONFIG_USB_CHAOSKEY=m +-# CONFIG_USB_ONBOARD_HUB is not set ++CONFIG_USB_ONBOARD_HUB=m + CONFIG_USB_ATM=m + # CONFIG_USB_SPEEDTOUCH is not set + CONFIG_USB_CXACRU=m +@@ -5427,7 +5500,59 @@ CONFIG_USB_XUSBATM=m + # CONFIG_USB_ISP1301 is not set + # end of USB Physical Layer drivers + +-# CONFIG_USB_GADGET is not set ++CONFIG_USB_GADGET=m ++# CONFIG_USB_GADGET_DEBUG is not set ++# CONFIG_USB_GADGET_DEBUG_FILES is not set ++# CONFIG_USB_GADGET_DEBUG_FS is not set ++CONFIG_USB_GADGET_VBUS_DRAW=2 ++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 ++ ++# ++# USB Peripheral Controller ++# ++# CONFIG_USB_GR_UDC is not set ++# CONFIG_USB_R8A66597 is not set ++# CONFIG_USB_PXA27X is not set ++# CONFIG_USB_MV_UDC is not set ++# CONFIG_USB_MV_U3D is not set ++# CONFIG_USB_SNP_UDC_PLAT is not set ++# CONFIG_USB_M66592 is not set ++# CONFIG_USB_BDC_UDC is not set ++# CONFIG_USB_AMD5536UDC is not set ++# CONFIG_USB_NET2272 is not set ++# CONFIG_USB_NET2280 is not set ++# CONFIG_USB_GOKU is not set ++# CONFIG_USB_EG20T is not set ++# CONFIG_USB_GADGET_XILINX is not set ++# CONFIG_USB_MAX3420_UDC is not set ++# CONFIG_USB_DUMMY_HCD is not set ++# end of USB Peripheral Controller ++ ++# CONFIG_USB_CONFIGFS is not set ++ ++# ++# USB Gadget precomposed configurations ++# ++# CONFIG_USB_ZERO is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_ETH is not set ++# CONFIG_USB_G_NCM is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_FUNCTIONFS is not set ++# CONFIG_USB_MASS_STORAGE is not set ++# CONFIG_USB_GADGET_TARGET is not set ++# CONFIG_USB_G_SERIAL is not set ++# CONFIG_USB_MIDI_GADGET is not set ++# CONFIG_USB_G_PRINTER is not set ++# CONFIG_USB_CDC_COMPOSITE is not set ++# CONFIG_USB_G_ACM_MS is not set ++# CONFIG_USB_G_MULTI is not set ++# CONFIG_USB_G_HID is not set ++# CONFIG_USB_G_DBGP is not set ++# CONFIG_USB_G_WEBCAM is not set ++# CONFIG_USB_RAW_GADGET is not set ++# end of USB Gadget precomposed configurations ++ + CONFIG_TYPEC=m + CONFIG_TYPEC_TCPM=m + CONFIG_TYPEC_TCPCI=m +@@ -5464,15 +5589,17 @@ CONFIG_USB_ROLE_SWITCH=y + CONFIG_MMC=y + CONFIG_PWRSEQ_EMMC=m + CONFIG_PWRSEQ_SIMPLE=m +-CONFIG_MMC_BLOCK=m ++CONFIG_MMC_BLOCK=y + CONFIG_MMC_BLOCK_MINORS=8 + CONFIG_SDIO_UART=m + # CONFIG_MMC_TEST is not set ++CONFIG_MMC_CRYPTO=y + + # + # MMC/SD/SDIO Host Controller Drivers + # + # CONFIG_MMC_DEBUG is not set ++# CONFIG_MMC_ARMMMCI is not set + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_IO_ACCESSORS=y + CONFIG_MMC_SDHCI_PCI=m +@@ -5480,12 +5607,13 @@ CONFIG_MMC_RICOH_MMC=y + CONFIG_MMC_SDHCI_PLTFM=y + # CONFIG_MMC_SDHCI_OF_ARASAN is not set + # CONFIG_MMC_SDHCI_OF_AT91 is not set +-# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set ++CONFIG_MMC_SDHCI_OF_DWCMSHC=y + CONFIG_MMC_SDHCI_CADENCE=y + # CONFIG_MMC_SDHCI_F_SDH30 is not set + # CONFIG_MMC_SDHCI_MILBEAUT is not set + CONFIG_MMC_TIFM_SD=m + CONFIG_MMC_SPI=y ++CONFIG_MMC_SDHCI_SOPHGO=y + CONFIG_MMC_CB710=m + CONFIG_MMC_VIA_SDMMC=m + CONFIG_MMC_DW=m +@@ -5494,15 +5622,15 @@ CONFIG_MMC_DW_BLUEFIELD=m + # CONFIG_MMC_DW_EXYNOS is not set + # CONFIG_MMC_DW_HI3798CV200 is not set + # CONFIG_MMC_DW_K3 is not set +-# CONFIG_MMC_DW_PCI is not set ++CONFIG_MMC_DW_PCI=m + # CONFIG_MMC_DW_STARFIVE is not set + CONFIG_MMC_VUB300=m + CONFIG_MMC_USHC=m + # CONFIG_MMC_USDHI6ROL0 is not set +-# CONFIG_MMC_REALTEK_PCI is not set +-# CONFIG_MMC_REALTEK_USB is not set +-CONFIG_MMC_CQHCI=m +-# CONFIG_MMC_HSQ is not set ++CONFIG_MMC_REALTEK_PCI=m ++CONFIG_MMC_REALTEK_USB=m ++CONFIG_MMC_CQHCI=y ++CONFIG_MMC_HSQ=m + CONFIG_MMC_TOSHIBA_PCI=m + CONFIG_MMC_MTK=m + CONFIG_MMC_SDHCI_XENON=m +@@ -5656,6 +5784,7 @@ CONFIG_EDAC_SUPPORT=y + CONFIG_EDAC=y + CONFIG_EDAC_LEGACY_SYSFS=y + # CONFIG_EDAC_DEBUG is not set ++# CONFIG_EDAC_SIFIVE is not set + CONFIG_RTC_LIB=y + CONFIG_RTC_CLASS=y + CONFIG_RTC_HCTOSYS=y +@@ -5766,6 +5895,8 @@ CONFIG_RTC_DRV_RP5C01=m + # + # on-CPU RTC drivers + # ++# CONFIG_RTC_DRV_PL030 is not set ++# CONFIG_RTC_DRV_PL031 is not set + # CONFIG_RTC_DRV_CADENCE is not set + # CONFIG_RTC_DRV_FTRTC010 is not set + # CONFIG_RTC_DRV_R7301 is not set +@@ -5774,7 +5905,6 @@ CONFIG_RTC_DRV_RP5C01=m + # HID Sensor RTC drivers + # + CONFIG_RTC_DRV_GOLDFISH=y +-# CONFIG_RTC_DRV_POLARFIRE_SOC is not set + CONFIG_DMADEVICES=y + # CONFIG_DMADEVICES_DEBUG is not set + +@@ -5782,11 +5912,14 @@ CONFIG_DMADEVICES=y + # DMA Devices + # + CONFIG_DMA_ENGINE=y ++CONFIG_DMA_VIRTUAL_CHANNELS=y + CONFIG_DMA_OF=y + # CONFIG_ALTERA_MSGDMA is not set +-# CONFIG_DW_AXI_DMAC is not set ++# CONFIG_AMBA_PL08X is not set ++CONFIG_DW_AXI_DMAC=y + # CONFIG_FSL_EDMA is not set + # CONFIG_INTEL_IDMA64 is not set ++# CONFIG_PL330_DMA is not set + # CONFIG_PLX_DMA is not set + # CONFIG_XILINX_DMA is not set + # CONFIG_XILINX_XDMA is not set +@@ -5867,6 +6000,7 @@ CONFIG_VHOST_MENU=y + CONFIG_VHOST_NET=m + CONFIG_VHOST_SCSI=m + CONFIG_VHOST_VSOCK=m ++# CONFIG_VHOST_VDPA_MIGRATION is not set + # CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + + # +@@ -5901,7 +6035,6 @@ CONFIG_COMMON_CLK=y + # CONFIG_COMMON_CLK_VC7 is not set + # CONFIG_COMMON_CLK_FIXED_MMIO is not set + CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC=y +-CONFIG_MCHP_CLK_MPFS=y + CONFIG_CLK_SIFIVE=y + CONFIG_CLK_SIFIVE_PRCI=y + CONFIG_CLK_STARFIVE_JH71X0=y +@@ -5915,6 +6048,9 @@ CONFIG_CLK_STARFIVE_JH7110_ISP=m + CONFIG_CLK_STARFIVE_JH7110_VOUT=m + # CONFIG_XILINX_VCU is not set + # CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set ++CONFIG_THEAD_CLK=y ++# CONFIG_CLK_LIGHT_MPW is not set ++CONFIG_CLK_LIGHT_FM=y + CONFIG_HWSPINLOCK=y + + # +@@ -5922,14 +6058,19 @@ CONFIG_HWSPINLOCK=y + # + CONFIG_TIMER_OF=y + CONFIG_TIMER_PROBE=y ++CONFIG_DW_APB_TIMER=y ++CONFIG_DW_APB_TIMER_OF=y + CONFIG_RISCV_TIMER=y + # end of Clock Source drivers + + CONFIG_MAILBOX=y ++# CONFIG_ARM_MHU is not set ++# CONFIG_ARM_MHU_V2 is not set + # CONFIG_PLATFORM_MHU is not set ++# CONFIG_PL320_MBOX is not set + # CONFIG_ALTERA_MBOX is not set + # CONFIG_MAILBOX_TEST is not set +-# CONFIG_POLARFIRE_SOC_MAILBOX is not set ++CONFIG_THEAD_LIGHT_MBOX=y + CONFIG_IOMMU_API=y + CONFIG_IOMMU_SUPPORT=y + +@@ -5939,8 +6080,8 @@ CONFIG_IOMMU_SUPPORT=y + # end of Generic IOMMU Pagetable Support + + # CONFIG_IOMMU_DEBUGFS is not set +-CONFIG_IOMMU_DEFAULT_DMA_STRICT=y +-# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set ++# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set ++CONFIG_IOMMU_DEFAULT_DMA_LAZY=y + # CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set + CONFIG_OF_IOMMU=y + # CONFIG_IOMMUFD is not set +@@ -5959,6 +6100,7 @@ CONFIG_RPMSG_CHAR=y + CONFIG_RPMSG_CTRL=y + CONFIG_RPMSG_NS=y + # CONFIG_RPMSG_QCOM_GLINK_RPM is not set ++CONFIG_RPMSG_THEAD_LIGHT=y + CONFIG_RPMSG_VIRTIO=y + # end of Rpmsg drivers + +@@ -6007,7 +6149,7 @@ CONFIG_RPMSG_VIRTIO=y + # CONFIG_QCOM_PMIC_GLINK is not set + # end of Qualcomm SoC drivers + +-# CONFIG_SIFIVE_CCACHE is not set ++CONFIG_SIFIVE_CCACHE=y + CONFIG_JH71XX_PMU=y + # CONFIG_SOC_TI is not set + +@@ -6015,6 +6157,12 @@ CONFIG_JH71XX_PMU=y + # Xilinx SoC drivers + # + # end of Xilinx SoC drivers ++ ++# ++# Thead SoC drivers ++# ++CONFIG_LIGHT_REBOOTMODE=y ++# end of Thead SoC drivers + # end of SOC (System On Chip) specific Drivers + + # CONFIG_PM_DEVFREQ is not set +@@ -6041,9 +6189,9 @@ CONFIG_PWM_SYSFS=y + # CONFIG_PWM_CLK is not set + # CONFIG_PWM_DWC is not set + # CONFIG_PWM_FSL_FTM is not set +-# CONFIG_PWM_MICROCHIP_CORE is not set + # CONFIG_PWM_PCA9685 is not set +-# CONFIG_PWM_SIFIVE is not set ++CONFIG_PWM_SIFIVE=m ++CONFIG_PWM_THEAD=m + # CONFIG_PWM_XILINX is not set + + # +@@ -6058,8 +6206,8 @@ CONFIG_SIFIVE_PLIC=y + + # CONFIG_IPACK_BUS is not set + CONFIG_RESET_CONTROLLER=y +-CONFIG_RESET_POLARFIRE_SOC=y + CONFIG_RESET_SIMPLE=y ++CONFIG_RESET_TH1520=y + # CONFIG_RESET_TI_SYSCON is not set + # CONFIG_RESET_TI_TPS380X is not set + CONFIG_RESET_STARFIVE_JH71X0=y +@@ -6118,6 +6266,12 @@ CONFIG_USB4=m + # CONFIG_ANDROID_BINDER_IPC is not set + # end of Android + ++# ++# Vendor Hooks ++# ++# CONFIG_VENDOR_HOOKS is not set ++# end of Vendor Hooks ++ + CONFIG_LIBNVDIMM=m + CONFIG_BLK_DEV_PMEM=m + CONFIG_ND_CLAIM=y +@@ -6153,17 +6307,23 @@ CONFIG_NVMEM_SYSFS=y + CONFIG_PM_OPP=y + # CONFIG_SIOX is not set + # CONFIG_SLIMBUS is not set +-# CONFIG_INTERCONNECT is not set ++CONFIG_INTERCONNECT=y + # CONFIG_COUNTER is not set + # CONFIG_MOST is not set + # CONFIG_PECI is not set + # CONFIG_HTE is not set ++ ++# ++# CPU Inspect ++# ++# CONFIG_CPU_INSPECT is not set ++# end of CPU Inspect + # end of Device Drivers + + # + # File systems + # +-# CONFIG_VALIDATE_FS_PARSER is not set ++CONFIG_VALIDATE_FS_PARSER=y + CONFIG_FS_IOMAP=y + CONFIG_BUFFER_HEAD=y + CONFIG_LEGACY_DIRECT_IO=y +@@ -6176,6 +6336,7 @@ CONFIG_EXT4_USE_FOR_EXT2=y + CONFIG_EXT4_FS_POSIX_ACL=y + CONFIG_EXT4_FS_SECURITY=y + # CONFIG_EXT4_DEBUG is not set ++# CONFIG_EXT4_ERROR_REPORT is not set + CONFIG_JBD2=y + # CONFIG_JBD2_DEBUG is not set + CONFIG_FS_MBCACHE=y +@@ -6296,6 +6457,7 @@ CONFIG_PROC_PAGE_MONITOR=y + CONFIG_PROC_CHILDREN=y + CONFIG_KERNFS=y + CONFIG_SYSFS=y ++CONFIG_DIRTY_PAGES=y + CONFIG_TMPFS=y + CONFIG_TMPFS_POSIX_ACL=y + CONFIG_TMPFS_XATTR=y +@@ -6306,6 +6468,7 @@ CONFIG_HUGETLBFS=y + CONFIG_HUGETLB_PAGE=y + CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y + # CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set ++# CONFIG_HUGETLB_ALLOC_LIMIT is not set + CONFIG_ARCH_HAS_GIGANTIC_PAGE=y + CONFIG_CONFIGFS_FS=y + CONFIG_EFIVAR_FS=y +@@ -6570,7 +6733,12 @@ CONFIG_IMA_X509_PATH="/etc/keys/x509_ima.der" + CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS=y + CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS=y + # CONFIG_IMA_DISABLE_HTABLE is not set ++# CONFIG_IMA_DIGEST_LIST is not set + CONFIG_EVM=y ++# CONFIG_EVM_DEFAULT_HASH_SHA1 is not set ++CONFIG_EVM_DEFAULT_HASH_SHA256=y ++# CONFIG_EVM_DEFAULT_HASH_SHA512 is not set ++CONFIG_EVM_DEFAULT_HASH="sha256" + CONFIG_EVM_ATTR_FSUUID=y + # CONFIG_EVM_ADD_XATTRS is not set + CONFIG_EVM_LOAD_X509=y +@@ -6819,6 +6987,9 @@ CONFIG_PKCS7_MESSAGE_PARSER=y + # CONFIG_PKCS7_TEST_KEY is not set + CONFIG_SIGNED_PE_FILE_VERIFICATION=y + # CONFIG_FIPS_SIGNATURE_SELFTEST is not set ++# CONFIG_PGP_LIBRARY is not set ++# CONFIG_PGP_KEY_PARSER is not set ++# CONFIG_PGP_PRELOAD is not set + + # + # Certificates for signature checking +@@ -6835,6 +7006,7 @@ CONFIG_SYSTEM_BLACKLIST_HASH_LIST="" + CONFIG_SYSTEM_REVOCATION_LIST=y + CONFIG_SYSTEM_REVOCATION_KEYS="" + # CONFIG_SYSTEM_BLACKLIST_AUTH_UPDATE is not set ++# CONFIG_PGP_PRELOAD_PUBLIC_KEYS is not set + # end of Certificates for signature checking + + CONFIG_BINARY_PRINTF=y +@@ -7034,8 +7206,8 @@ CONFIG_DEBUG_MISC=y + # + CONFIG_DEBUG_INFO=y + # CONFIG_DEBUG_INFO_NONE is not set +-# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set +-CONFIG_DEBUG_INFO_DWARF4=y ++CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y ++# CONFIG_DEBUG_INFO_DWARF4 is not set + # CONFIG_DEBUG_INFO_DWARF5 is not set + # CONFIG_DEBUG_INFO_REDUCED is not set + CONFIG_DEBUG_INFO_COMPRESSED_NONE=y +@@ -7049,7 +7221,8 @@ CONFIG_DEBUG_INFO_BTF_MODULES=y + CONFIG_FRAME_WARN=2048 + CONFIG_STRIP_ASM_SYMS=y + # CONFIG_READABLE_ASM is not set +-# CONFIG_HEADERS_INSTALL is not set ++CONFIG_HEADERS_INSTALL=y ++# CONFIG_OPTIMIZE_INLINING is not set + CONFIG_DEBUG_SECTION_MISMATCH=y + CONFIG_SECTION_MISMATCH_WARN_ONLY=y + # CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set +@@ -7204,8 +7377,6 @@ CONFIG_DEBUG_LIST=y + # CONFIG_DEBUG_MAPLE_TREE is not set + # end of Debug kernel data structures + +-# CONFIG_DEBUG_CREDENTIALS is not set +- + # + # RCU Debugging + # +@@ -7271,7 +7442,7 @@ CONFIG_DYNAMIC_EVENTS=y + CONFIG_PROBE_EVENTS=y + # CONFIG_BPF_KPROBE_OVERRIDE is not set + CONFIG_FTRACE_MCOUNT_RECORD=y +-CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT=y ++CONFIG_FTRACE_MCOUNT_USE_CC=y + CONFIG_SYNTH_EVENTS=y + # CONFIG_USER_EVENTS is not set + # CONFIG_TRACE_EVENT_INJECT is not set +@@ -7314,3 +7485,5 @@ CONFIG_ARCH_USE_MEMTEST=y + # + # end of Rust hacking + # end of Kernel hacking ++ ++# CONFIG_KWORKER_NUMA_AFFINITY is not set +diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c +index 0554ed4bf087..07c7ab6bcb4a 100644 +--- a/arch/riscv/errata/thead/errata.c ++++ b/arch/riscv/errata/thead/errata.c +@@ -12,8 +12,10 @@ + #include <asm/alternative.h> + #include <asm/cacheflush.h> + #include <asm/cpufeature.h> ++#include <asm/dma-noncoherent.h> + #include <asm/errata_list.h> + #include <asm/hwprobe.h> ++#include <asm/io.h> + #include <asm/patch.h> + #include <asm/vendorid_list.h> + +@@ -33,6 +35,69 @@ static bool errata_probe_pbmt(unsigned int stage, + return false; + } + ++/* ++ * th.dcache.ipa rs1 (invalidate, physical address) ++ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | ++ * 0000001 01010 rs1 000 00000 0001011 ++ * th.dcache.iva rs1 (invalidate, virtual address) ++ * 0000001 00110 rs1 000 00000 0001011 ++ * ++ * th.dcache.cpa rs1 (clean, physical address) ++ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | ++ * 0000001 01001 rs1 000 00000 0001011 ++ * th.dcache.cva rs1 (clean, virtual address) ++ * 0000001 00101 rs1 000 00000 0001011 ++ * ++ * th.dcache.cipa rs1 (clean then invalidate, physical address) ++ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | ++ * 0000001 01011 rs1 000 00000 0001011 ++ * th.dcache.civa rs1 (clean then invalidate, virtual address) ++ * 0000001 00111 rs1 000 00000 0001011 ++ * ++ * th.sync.s (make sure all cache operations finished) ++ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | ++ * 0000000 11001 00000 000 00000 0001011 ++ */ ++#define THEAD_INVAL_A0 ".long 0x02a5000b" ++#define THEAD_CLEAN_A0 ".long 0x0295000b" ++#define THEAD_FLUSH_A0 ".long 0x02b5000b" ++#define THEAD_SYNC_S ".long 0x0190000b" ++ ++#define THEAD_CMO_OP(_op, _start, _size, _cachesize) \ ++asm volatile("mv a0, %1\n\t" \ ++ "j 2f\n\t" \ ++ "3:\n\t" \ ++ THEAD_##_op##_A0 "\n\t" \ ++ "add a0, a0, %0\n\t" \ ++ "2:\n\t" \ ++ "bltu a0, %2, 3b\n\t" \ ++ THEAD_SYNC_S \ ++ : : "r"(_cachesize), \ ++ "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ ++ "r"((unsigned long)(_start) + (_size)) \ ++ : "a0") ++ ++static void thead_errata_cache_inv(phys_addr_t paddr, size_t size) ++{ ++ THEAD_CMO_OP(INVAL, paddr, size, riscv_cbom_block_size); ++} ++ ++static void thead_errata_cache_wback(phys_addr_t paddr, size_t size) ++{ ++ THEAD_CMO_OP(CLEAN, paddr, size, riscv_cbom_block_size); ++} ++ ++static void thead_errata_cache_wback_inv(phys_addr_t paddr, size_t size) ++{ ++ THEAD_CMO_OP(FLUSH, paddr, size, riscv_cbom_block_size); ++} ++ ++static const struct riscv_nonstd_cache_ops thead_errata_cmo_ops = { ++ .wback = &thead_errata_cache_wback_inv, ++ .inv = &thead_errata_cache_inv, ++ .wback_inv = &thead_errata_cache_wback_inv, ++}; ++ + static bool errata_probe_cmo(unsigned int stage, + unsigned long arch_id, unsigned long impid) + { +@@ -48,6 +113,7 @@ static bool errata_probe_cmo(unsigned int stage, + if (stage == RISCV_ALTERNATIVES_BOOT) { + riscv_cbom_block_size = L1_CACHE_BYTES; + riscv_noncoherent_supported(); ++ riscv_noncoherent_register_cache_ops(&thead_errata_cmo_ops); + } + + return true; +@@ -77,8 +143,7 @@ static u32 thead_errata_probe(unsigned int stage, + if (errata_probe_pbmt(stage, archid, impid)) + cpu_req_errata |= BIT(ERRATA_THEAD_PBMT); + +- if (errata_probe_cmo(stage, archid, impid)) +- cpu_req_errata |= BIT(ERRATA_THEAD_CMO); ++ errata_probe_cmo(stage, archid, impid); + + if (errata_probe_pmu(stage, archid, impid)) + cpu_req_errata |= BIT(ERRATA_THEAD_PMU); +diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h +index b55b434f0059..ea33288f8a25 100644 +--- a/arch/riscv/include/asm/errata_list.h ++++ b/arch/riscv/include/asm/errata_list.h +@@ -24,9 +24,8 @@ + + #ifdef CONFIG_ERRATA_THEAD + #define ERRATA_THEAD_PBMT 0 +-#define ERRATA_THEAD_CMO 1 +-#define ERRATA_THEAD_PMU 2 +-#define ERRATA_THEAD_NUMBER 3 ++#define ERRATA_THEAD_PMU 1 ++#define ERRATA_THEAD_NUMBER 2 + #endif + + #ifdef __ASSEMBLY__ +@@ -94,54 +93,17 @@ asm volatile(ALTERNATIVE( \ + #define ALT_THEAD_PMA(_val) + #endif + +-/* +- * dcache.ipa rs1 (invalidate, physical address) +- * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | +- * 0000001 01010 rs1 000 00000 0001011 +- * dache.iva rs1 (invalida, virtual address) +- * 0000001 00110 rs1 000 00000 0001011 +- * +- * dcache.cpa rs1 (clean, physical address) +- * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | +- * 0000001 01001 rs1 000 00000 0001011 +- * dcache.cva rs1 (clean, virtual address) +- * 0000001 00101 rs1 000 00000 0001011 +- * +- * dcache.cipa rs1 (clean then invalidate, physical address) +- * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | +- * 0000001 01011 rs1 000 00000 0001011 +- * dcache.civa rs1 (... virtual address) +- * 0000001 00111 rs1 000 00000 0001011 +- * +- * sync.s (make sure all cache operations finished) +- * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | +- * 0000000 11001 00000 000 00000 0001011 +- */ +-#define THEAD_inval_A0 ".long 0x0265000b" +-#define THEAD_clean_A0 ".long 0x0255000b" +-#define THEAD_flush_A0 ".long 0x0275000b" +-#define THEAD_SYNC_S ".long 0x0190000b" +- + #define ALT_CMO_OP(_op, _start, _size, _cachesize) \ +-asm volatile(ALTERNATIVE_2( \ +- __nops(6), \ ++asm volatile(ALTERNATIVE( \ ++ __nops(5), \ + "mv a0, %1\n\t" \ + "j 2f\n\t" \ + "3:\n\t" \ + CBO_##_op(a0) \ + "add a0, a0, %0\n\t" \ + "2:\n\t" \ +- "bltu a0, %2, 3b\n\t" \ +- "nop", 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ +- "mv a0, %1\n\t" \ +- "j 2f\n\t" \ +- "3:\n\t" \ +- THEAD_##_op##_A0 "\n\t" \ +- "add a0, a0, %0\n\t" \ +- "2:\n\t" \ +- "bltu a0, %2, 3b\n\t" \ +- THEAD_SYNC_S, THEAD_VENDOR_ID, \ +- ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO) \ ++ "bltu a0, %2, 3b\n\t", \ ++ 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM) \ + : : "r"(_cachesize), \ + "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ + "r"((unsigned long)(_start) + (_size)) \ +diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h +index 7a5097202e15..783837bbd878 100644 +--- a/arch/riscv/include/asm/pgtable-64.h ++++ b/arch/riscv/include/asm/pgtable-64.h +@@ -126,14 +126,18 @@ enum napot_cont_order { + + /* + * 63:59 T-Head Memory Type definitions: +- * +- * 00000 - NC Weakly-ordered, Non-cacheable, Non-bufferable, Non-shareable, Non-trustable ++ * bit63 SO - Strong Order ++ * bit62 C - Cacheable ++ * bit61 B - Bufferable ++ * bit60 SH - Shareable ++ * bit59 Sec - Trustable ++ * 00110 - NC Weakly-ordered, Non-cacheable, Bufferable, Shareable, Non-trustable + * 01110 - PMA Weakly-ordered, Cacheable, Bufferable, Shareable, Non-trustable +- * 10000 - IO Strongly-ordered, Non-cacheable, Non-bufferable, Non-shareable, Non-trustable ++ * 10010 - IO Strongly-ordered, Non-cacheable, Non-bufferable, Shareable, Non-trustable + */ + #define _PAGE_PMA_THEAD ((1UL << 62) | (1UL << 61) | (1UL << 60)) +-#define _PAGE_NOCACHE_THEAD 0UL +-#define _PAGE_IO_THEAD (1UL << 63) ++#define _PAGE_NOCACHE_THEAD ((1UL << 61) | (1UL << 60)) ++#define _PAGE_IO_THEAD ((1UL << 63) | (1UL << 60)) + #define _PAGE_MTMASK_THEAD (_PAGE_PMA_THEAD | _PAGE_IO_THEAD | (1UL << 59)) + + static inline u64 riscv_page_mtmask(void) +diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig +index c30099866174..1578cc32432d 100644 +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -501,6 +501,7 @@ source "drivers/clk/visconti/Kconfig" + source "drivers/clk/x86/Kconfig" + source "drivers/clk/xilinx/Kconfig" + source "drivers/clk/zynqmp/Kconfig" ++source "drivers/clk/thead/Kconfig" + + # Kunit test cases + config CLK_KUNIT_TEST +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index 18969cbd4bb1..ebecef837e58 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -124,6 +124,7 @@ obj-$(CONFIG_ARCH_STM32) += stm32/ + obj-y += starfive/ + obj-$(CONFIG_ARCH_SUNXI) += sunxi/ + obj-y += sunxi-ng/ ++obj-$(CONFIG_ARCH_SOPHGO) += sophgo/ + obj-$(CONFIG_ARCH_TEGRA) += tegra/ + obj-y += ti/ + obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ +@@ -136,3 +137,4 @@ endif + obj-y += xilinx/ + obj-$(CONFIG_ARCH_ZYNQ) += zynq/ + obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/ ++obj-$(CONFIG_ARCH_THEAD) += thead/ +diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile +new file mode 100644 +index 000000000000..55997fc07b5b +--- /dev/null ++++ b/drivers/clk/sophgo/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_ARCH_SOPHGO) += clk-dummy.o ++obj-$(CONFIG_ARCH_SOPHGO) += clk.o ++obj-$(CONFIG_ARCH_SOPHGO) += clk-mango.o +diff --git a/drivers/clk/sophgo/clk-dummy.c b/drivers/clk/sophgo/clk-dummy.c +new file mode 100644 +index 000000000000..99af0e6dae6a +--- /dev/null ++++ b/drivers/clk/sophgo/clk-dummy.c +@@ -0,0 +1,600 @@ ++/* ++ * Copyright (c) 2022 SOPHGO ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++#include <linux/mfd/syscon.h> ++#include <linux/io.h> ++#include <linux/of_address.h> ++#include <linux/string.h> ++#include <linux/log2.h> ++ ++#include "clk.h" ++ ++/* ++ * @hw: handle between common and hardware-specific interfaces ++ * @reg: register containing divider ++ * @shift: shift to the divider bit field ++ * @width: width of the divider bit field ++ * @initial_val:initial value of the divider ++ * @table: the div table that the divider supports ++ * @lock: register lock ++ */ ++struct mango_clk_divider { ++ struct clk_hw hw; ++ void __iomem *reg; ++ u8 shift; ++ u8 width; ++ u8 flags; ++ u32 initial_val; ++ const struct clk_div_table *table; ++ spinlock_t *lock; ++}; ++ ++static unsigned long mango_clk_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct device_node *node; ++ struct of_phandle_args clkspec; ++ int rc, index = 0; ++ u32 rate; ++ struct property *prop; ++ const __be32 *cur; ++ struct clk *clk; ++ ++ node = of_find_node_by_name(NULL, "default_rates"); ++ ++ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) { ++ if (rate) { ++ rc = of_parse_phandle_with_args(node, "clocks", ++ "#clock-cells", index, &clkspec); ++ if (rc < 0) { ++ /* skip empty (null) phandles */ ++ if (rc == -ENOENT) ++ continue; ++ else ++ return rc; ++ } ++ ++ clk = of_clk_get_from_provider(&clkspec); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ if (!strcmp(clk_hw_get_name(hw), __clk_get_name(clk))) ++ return rate; ++ } ++ index++; ++ } ++ return 0; ++} ++ ++static long mango_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ return rate; ++} ++ ++static int mango_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ return 0; ++} ++ ++/* ++ * @hw: ccf use to hook get mango_pll_clock ++ * @parent_rate: parent rate ++ * ++ * The is function will be called through clk_get_rate ++ * and return current rate after decoding reg value ++ */ ++static unsigned long mango_clk_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct device_node *node; ++ struct of_phandle_args clkspec; ++ int rc, index = 0; ++ u32 rate; ++ struct property *prop; ++ const __be32 *cur; ++ ++ node = of_find_node_by_name(NULL, "default_rates"); ++ ++ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) { ++ if (rate) { ++ rc = of_parse_phandle_with_args(node, "clocks", ++ "#clock-cells", index, &clkspec); ++ if (rc < 0) { ++ /* skip empty (null) phandles */ ++ if (rc == -ENOENT) ++ continue; ++ else ++ return rc; ++ } ++ ++ if (!strncmp(clk_hw_get_name(hw), clkspec.np->name, 4)) ++ return rate; ++ } ++ index++; ++ } ++ return 0; ++} ++ ++static long mango_clk_pll_round_rate(struct clk_hw *hw, ++ unsigned long req_rate, unsigned long *prate) ++{ ++ return req_rate; ++} ++ ++static int mango_clk_pll_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ req->rate = mango_clk_pll_round_rate(hw, min(req->rate, req->max_rate), ++ &req->best_parent_rate); ++ return 0; ++} ++ ++static int mango_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ return 0; ++} ++ ++const struct clk_ops dm_mango_clk_divider_ops = { ++ .recalc_rate = mango_clk_divider_recalc_rate, ++ .round_rate = mango_clk_divider_round_rate, ++ .set_rate = mango_clk_divider_set_rate, ++}; ++ ++const struct clk_ops dm_mango_clk_divider_ro_ops = { ++ .recalc_rate = mango_clk_divider_recalc_rate, ++ .round_rate = mango_clk_divider_round_rate, ++}; ++ ++const struct clk_ops dm_mango_clk_pll_ops = { ++ .recalc_rate = mango_clk_pll_recalc_rate, ++ .round_rate = mango_clk_pll_round_rate, ++ .determine_rate = mango_clk_pll_determine_rate, ++ .set_rate = mango_clk_pll_set_rate, ++}; ++ ++const struct clk_ops dm_mango_clk_pll_ro_ops = { ++ .recalc_rate = mango_clk_pll_recalc_rate, ++ .round_rate = mango_clk_pll_round_rate, ++}; ++ ++struct mux_cb_clk_name { ++ const char *name; ++ struct list_head node; ++}; ++ ++static struct list_head mux_cb_clk_name_list = ++ LIST_HEAD_INIT(mux_cb_clk_name_list); ++static int mux_notifier_cb(struct notifier_block *nb, ++ unsigned long event, void *data) ++{ ++ int ret = 0; ++ static unsigned char mux_id = 1; ++ struct clk_notifier_data *ndata = data; ++ struct clk_hw *hw = __clk_get_hw(ndata->clk); ++ const struct clk_ops *ops = &clk_mux_ops; ++ struct mux_cb_clk_name *cb_lsit; ++ ++ if (event == PRE_RATE_CHANGE) { ++ struct clk_hw *hw_p = clk_hw_get_parent(hw); ++ ++ cb_lsit = kmalloc(sizeof(*cb_lsit), GFP_KERNEL); ++ if (cb_lsit) { ++ INIT_LIST_HEAD(&cb_lsit->node); ++ list_add_tail(&cb_lsit->node, &mux_cb_clk_name_list); ++ } else { ++ pr_err("mux cb kmalloc mem fail\n"); ++ goto out; ++ } ++ ++ cb_lsit->name = clk_hw_get_name(hw_p); ++ mux_id = ops->get_parent(hw); ++ if (mux_id > 1) { ++ ret = 1; ++ goto out; ++ } ++ ops->set_parent(hw, !mux_id); ++ } else if (event == POST_RATE_CHANGE) { ++ struct clk_hw *hw_p = clk_hw_get_parent(hw); ++ ++ cb_lsit = list_first_entry_or_null(&mux_cb_clk_name_list, ++ typeof(*cb_lsit), node); ++ if (cb_lsit) { ++ const char *pre_name = cb_lsit->name; ++ ++ list_del_init(&cb_lsit->node); ++ kfree(cb_lsit); ++ if (strcmp(clk_hw_get_name(hw_p), pre_name)) ++ goto out; ++ } ++ ++ ops->set_parent(hw, mux_id); ++ } ++ ++out: ++ return notifier_from_errno(ret); ++} ++ ++int dm_set_default_clk_rates(struct device_node *node) ++{ ++ struct of_phandle_args clkspec; ++ struct property *prop; ++ const __be32 *cur; ++ int rc, index = 0; ++ struct clk *clk; ++ u32 rate; ++ ++ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) { ++ if (rate) { ++ rc = of_parse_phandle_with_args(node, "clocks", ++ "#clock-cells", index, &clkspec); ++ if (rc < 0) { ++ /* skip empty (null) phandles */ ++ if (rc == -ENOENT) ++ continue; ++ else ++ return rc; ++ } ++ ++ clk = of_clk_get_from_provider(&clkspec); ++ if (IS_ERR(clk)) { ++ pr_warn("clk: couldn't get clock %d for %s\n", ++ index, node->full_name); ++ return PTR_ERR(clk); ++ } ++ ++ rc = clk_set_rate(clk, rate); ++ if (rc < 0) ++ pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n", ++ __clk_get_name(clk), rate, rc, ++ clk_get_rate(clk)); ++ clk_put(clk); ++ } ++ index++; ++ } ++ ++ return 0; ++} ++ ++static struct clk *__register_divider_clks(struct device *dev, const char *name, ++ const char *parent_name, ++ unsigned long flags, ++ void __iomem *reg, u8 shift, ++ u8 width, u32 initial_val, ++ u8 clk_divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ struct mango_clk_divider *div; ++ struct clk_hw *hw; ++ struct clk_init_data init; ++ int ret; ++ ++ if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { ++ if (width + shift > 16) { ++ pr_warn("divider value exceeds LOWORD field\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ } ++ ++ /* allocate the divider */ ++ div = kzalloc(sizeof(*div), GFP_KERNEL); ++ if (!div) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) ++ init.ops = &dm_mango_clk_divider_ro_ops; ++ else ++ init.ops = &dm_mango_clk_divider_ops; ++ init.flags = flags; ++ init.parent_names = (parent_name ? &parent_name : NULL); ++ init.num_parents = (parent_name ? 1 : 0); ++ ++ /* struct mango_clk_divider assignments */ ++ div->reg = reg; ++ div->shift = shift; ++ div->width = width; ++ div->flags = clk_divider_flags; ++ div->lock = lock; ++ div->hw.init = &init; ++ div->table = table; ++ div->initial_val = initial_val; ++ ++ /* register the clock */ ++ hw = &div->hw; ++ ret = clk_hw_register(dev, hw); ++ if (ret) { ++ kfree(div); ++ hw = ERR_PTR(ret); ++ return ERR_PTR(-EBUSY); ++ } ++ ++ return hw->clk; ++} ++ ++static inline int register_provider_clks ++(struct device_node *node, struct mango_clk_data *clk_data, int clk_num) ++{ ++ return of_clk_add_provider(node, of_clk_src_onecell_get, ++ &clk_data->clk_data); ++} ++ ++static int register_gate_clks(struct device *dev, struct mango_clk_data *clk_data) ++{ ++ struct clk *clk; ++ const struct mango_clk_table *table = clk_data->table; ++ const struct mango_gate_clock *gate_clks = table->gate_clks; ++ void __iomem *base = clk_data->base; ++ int clk_num = table->gate_clks_num; ++ int i; ++ ++ for (i = 0; i < clk_num; i++) { ++ clk = clk_register_gate( ++ dev, gate_clksi.name, gate_clksi.parent_name, ++ gate_clksi.flags | CLK_IS_CRITICAL, base + gate_clksi.offset, ++ gate_clksi.bit_idx, gate_clksi.gate_flags, ++ &clk_data->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ gate_clksi.name); ++ goto err; ++ } ++ ++ if (gate_clksi.alias) ++ clk_register_clkdev(clk, gate_clksi.alias, NULL); ++ ++ clk_data->clk_data.clksgate_clksi.id = clk; ++ } ++ ++ return 0; ++ ++err: ++ while (i--) ++ clk_unregister_gate(clk_data->clk_data.clksgate_clksi.id); ++ ++ return PTR_ERR(clk); ++} ++ ++static int register_divider_clks(struct device *dev, ++ struct mango_clk_data *clk_data) ++{ ++ struct clk *clk; ++ const struct mango_clk_table *table = clk_data->table; ++ const struct mango_divider_clock *div_clks = table->div_clks; ++ void __iomem *base = clk_data->base; ++ int clk_num = table->div_clks_num; ++ int i, val; ++ ++ for (i = 0; i < clk_num; i++) { ++ clk = __register_divider_clks( ++ NULL, div_clksi.name, div_clksi.parent_name, ++ div_clksi.flags, base + div_clksi.offset, ++ div_clksi.shift, div_clksi.width, ++ div_clksi.initial_val, ++ (div_clksi.initial_sel & MANGO_CLK_USE_INIT_VAL) ? ++ div_clksi.div_flags | CLK_DIVIDER_READ_ONLY : ++ div_clksi.div_flags, ++ div_clksi.table, &clk_data->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ div_clksi.name); ++ goto err; ++ } ++ ++ clk_data->clk_data.clksdiv_clksi.id = clk; ++ ++ if (div_clksi.initial_sel == MANGO_CLK_USE_REG_VAL) { ++ regmap_read(clk_data->syscon_top, div_clksi.offset, ++ &val); ++ ++ /* ++ * set a default divider factor, ++ * clk driver should not select divider clock as the ++ * clock source, before set the divider by right process ++ * (assert div, set div factor, de assert div). ++ */ ++ if (div_clksi.initial_val > 0) ++ val |= (div_clksi.initial_val << 16 | 1 << 3); ++ else { ++ /* ++ * the div register is config to use divider factor, don't change divider ++ */ ++ if (!(val >> 3 & 0x1)) ++ val |= 1 << 16; ++ } ++ ++ regmap_write(clk_data->syscon_top, div_clksi.offset, ++ val); ++ } ++ } ++ ++ return 0; ++ ++err: ++ while (i--) ++ clk_unregister_divider(clk_data->clk_data.clksdiv_clksi.id); ++ ++ return PTR_ERR(clk); ++} ++ ++static int register_mux_clks(struct device *dev, struct mango_clk_data *clk_data) ++{ ++ struct clk *clk; ++ const struct mango_clk_table *table = clk_data->table; ++ const struct mango_mux_clock *mux_clks = table->mux_clks; ++ void __iomem *base = clk_data->base; ++ int clk_num = table->mux_clks_num; ++ int i; ++ ++ for (i = 0; i < clk_num; i++) { ++ u32 mask = BIT(mux_clksi.width) - 1; ++ ++ clk = clk_register_mux_table( ++ dev, mux_clksi.name, mux_clksi.parent_names, ++ mux_clksi.num_parents, mux_clksi.flags, ++ base + mux_clksi.offset, mux_clksi.shift, mask, ++ mux_clksi.mux_flags, mux_clksi.table, ++ &clk_data->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ mux_clksi.name); ++ goto err; ++ } ++ ++ clk_data->clk_data.clksmux_clksi.id = clk; ++ ++ if (!(mux_clksi.flags & CLK_MUX_READ_ONLY)) { ++ struct clk *parent; ++ struct notifier_block *clk_nb; ++ ++ /* set mux clock default parent here, it's parent index ++ * value is read from the mux clock reg. dts can override ++ * setting the mux clock parent later. ++ */ ++ parent = clk_get_parent(clk); ++ clk_set_parent(clk, parent); ++ ++ /* add a notify callback function */ ++ clk_nb = kzalloc(sizeof(*clk_nb), GFP_KERNEL); ++ if (!clk_nb) ++ goto err; ++ clk_nb->notifier_call = mux_notifier_cb; ++ if (clk_notifier_register(clk, clk_nb)) ++ pr_err("%s: failed to register clock notifier for %s\n", ++ __func__, mux_clksi.name); ++ } ++ } ++ ++ return 0; ++ ++err: ++ while (i--) ++ clk_unregister_mux(clk_data->clk_data.clksmux_clksi.id); ++ ++ return PTR_ERR(clk); ++} ++ ++/* pll clock init */ ++int dm_mango_register_pll_clks(struct device_node *node, ++ struct mango_clk_data *clk_data, const char *clk_name) ++{ ++ struct clk *clk = NULL; ++ struct mango_pll_clock *pll_clks; ++ int i, ret = 0; ++ const struct clk_ops *local_ops; ++ ++ pll_clks = (struct mango_pll_clock *)clk_data->table->pll_clks; ++ for (i = 0; i < clk_data->table->pll_clks_num; i++) { ++ if (!strcmp(clk_name, pll_clksi.name)) { ++ /* have to assigne pll_clks.syscon_top first ++ * since clk_register_composite will need it ++ * to calculate current rate. ++ */ ++ pll_clksi.syscon_top = clk_data->syscon_top; ++ pll_clksi.lock = &clk_data->lock; ++ if (pll_clksi.ini_flags & MANGO_CLK_RO) ++ local_ops = &dm_mango_clk_pll_ro_ops; ++ else ++ local_ops = &dm_mango_clk_pll_ops; ++ clk = clk_register_composite( ++ NULL, pll_clksi.name, &pll_clksi.parent_name, ++ 1, NULL, NULL, &pll_clksi.hw, local_ops, ++ NULL, NULL, pll_clksi.flags); ++ ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ pll_clksi.name); ++ ret = -EINVAL; ++ goto out; ++ } ++ ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); ++ if (ret) ++ clk_unregister(clk); ++ } else { ++ continue; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++/* mux clk init */ ++int dm_mango_register_mux_clks(struct device_node *node, struct mango_clk_data *clk_data) ++{ ++ int ret; ++ int count; ++ struct clk **clk_table; ++ ++ count = clk_data->table->mux_clks_num + clk_data->table->gate_clks_num; ++ clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL); ++ if (!clk_table) ++ return -ENOMEM; ++ ++ clk_data->clk_data.clks = clk_table; ++ clk_data->clk_data.clk_num = count; ++ ++ ret = register_mux_clks(NULL, clk_data); ++ if (ret) ++ goto err; ++ ++ ret = register_gate_clks(NULL, clk_data); ++ if (ret) ++ goto err; ++ ++ ret = register_provider_clks(node, clk_data, count); ++ if (ret) ++ goto err; ++ ++ return 0; ++err: ++ kfree(clk_table); ++ return ret; ++} ++ ++/* pll divider init */ ++int dm_mango_register_div_clks(struct device_node *node, struct mango_clk_data *clk_data) ++{ ++ int ret; ++ int count; ++ ++ struct clk **clk_table; ++ ++ count = clk_data->table->div_clks_num + clk_data->table->gate_clks_num; ++ clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL); ++ if (!clk_table) ++ return -ENOMEM; ++ ++ clk_data->clk_data.clks = clk_table; ++ clk_data->clk_data.clk_num = count; ++ ++ ret = register_divider_clks(NULL, clk_data); ++ if (ret) ++ goto err; ++ ++ ret = register_gate_clks(NULL, clk_data); ++ if (ret) ++ goto err; ++ ++ ret = register_provider_clks(node, clk_data, count); ++ if (ret) ++ goto err; ++ ++ ++ return 0; ++err: ++ kfree(clk_table); ++ pr_err("%s error %d\n", __func__, ret); ++ return ret; ++} +diff --git a/drivers/clk/sophgo/clk-mango.c b/drivers/clk/sophgo/clk-mango.c +new file mode 100644 +index 000000000000..70e17f65c6fb +--- /dev/null ++++ b/drivers/clk/sophgo/clk-mango.c +@@ -0,0 +1,977 @@ ++/* ++ * Copyright (c) 2022 SOPHGO ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/of_address.h> ++#include <linux/mfd/syscon.h> ++#include <dt-bindings/clock/sophgo-mango-clock.h> ++ ++#include "clk.h" ++ ++/* fixed clocks */ ++struct mango_pll_clock mango_root_pll_clks = { ++ { ++ .id = FPLL_CLK, ++ .name = "fpll_clock", ++ .parent_name = "cgi", ++ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, ++ .ini_flags = MANGO_CLK_RO, ++ }, { ++ .id = DPLL0_CLK, ++ .name = "dpll0_clock", ++ .parent_name = "cgi", ++ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, ++ .ini_flags = MANGO_CLK_RO, ++ .status_offset = 0xc0, ++ .enable_offset = 0xc4, ++ }, { ++ .id = DPLL1_CLK, ++ .name = "dpll1_clock", ++ .parent_name = "cgi", ++ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, ++ .ini_flags = MANGO_CLK_RO, ++ .status_offset = 0xc0, ++ .enable_offset = 0xc4, ++ }, { ++ .id = MPLL_CLK, ++ .name = "mpll_clock", ++ .parent_name = "cgi", ++ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, ++ .status_offset = 0xc0, ++ .enable_offset = 0xc4, ++ },{ ++ .id = FPLL_CLK, ++ .name = "s1_fpll_clock", ++ .parent_name = "s1_cgi", ++ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, ++ .ini_flags = MANGO_CLK_RO, ++ }, { ++ .id = DPLL0_CLK, ++ .name = "s1_dpll0_clock", ++ .parent_name = "s1_cgi", ++ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, ++ .ini_flags = MANGO_CLK_RO, ++ .status_offset = 0xc0, ++ .enable_offset = 0xc4, ++ }, { ++ .id = DPLL1_CLK, ++ .name = "s1_dpll1_clock", ++ .parent_name = "s1_cgi", ++ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, ++ .ini_flags = MANGO_CLK_RO, ++ .status_offset = 0xc0, ++ .enable_offset = 0xc4, ++ }, { ++ .id = MPLL_CLK, ++ .name = "s1_mpll_clock", ++ .parent_name = "s1_cgi", ++ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, ++ .status_offset = 0xc0, ++ .enable_offset = 0xc4, ++ } ++}; ++ ++/* divider clocks */ ++static const struct mango_divider_clock s0_div_clks = { ++ { DIV_CLK_MPLL_RP_CPU_NORMAL_0, "clk_div_rp_cpu_normal_0", "clk_gate_rp_cpu_normal_div0", ++ 0, 0x2044, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_MPLL_AXI_DDR_0, "clk_div_axi_ddr_0", "clk_gate_axi_ddr_div0", ++ 0, 0x20a8, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5}, ++ { DIV_CLK_FPLL_DDR01_1, "clk_div_ddr01_1", "clk_gate_ddr01_div1", ++ 0, 0x20b0, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, ++ { DIV_CLK_FPLL_DDR23_1, "clk_div_ddr23_1", "clk_gate_ddr23_div1", ++ 0, 0x20b8, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, ++ { DIV_CLK_FPLL_RP_CPU_NORMAL_1, "clk_div_rp_cpu_normal_1", "clk_gate_rp_cpu_normal_div1", ++ 0, 0x2040, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_50M_A53, "clk_div_50m_a53", "fpll_clock", ++ 0, 0x2048, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_TOP_RP_CMN_DIV2, "clk_div_top_rp_cmn_div2", "clk_mux_rp_cpu_normal", ++ 0, 0x204c, 16, 16, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_UART_500M, "clk_div_uart_500m", "fpll_clock", ++ 0, 0x2050, 16, 7, CLK_DIVIDER_READ_ONLY, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_AHB_LPC, "clk_div_ahb_lpc", "fpll_clock", ++ 0, 0x2054, 16, 16, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_EFUSE, "clk_div_efuse", "fpll_clock", ++ 0, 0x2078, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_TX_ETH0, "clk_div_tx_eth0", "fpll_clock", ++ 0, 0x2080, 16, 11, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_PTP_REF_I_ETH0, "clk_div_ptp_ref_i_eth0", "fpll_clock", ++ 0, 0x2084, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_REF_ETH0, "clk_div_ref_eth0", "fpll_clock", ++ 0, 0x2088, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_EMMC, "clk_div_emmc", "fpll_clock", ++ 0, 0x208c, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_SD, "clk_div_sd", "fpll_clock", ++ 0, 0x2094, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_TOP_AXI0, "clk_div_top_axi0", "fpll_clock", ++ 0, 0x209c, 16, 5, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_TOP_AXI_HSPERI, "clk_div_top_axi_hsperi", "fpll_clock", ++ 0, 0x20a0, 16, 5, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_AXI_DDR_1, "clk_div_axi_ddr_1", "clk_gate_axi_ddr_div1", ++ 0, 0x20a4, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5}, ++ { DIV_CLK_FPLL_DIV_TIMER1, "clk_div_timer1", "clk_div_50m_a53", ++ 0, 0x2058, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER2, "clk_div_timer2", "clk_div_50m_a53", ++ 0, 0x205c, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER3, "clk_div_timer3", "clk_div_50m_a53", ++ 0, 0x2060, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER4, "clk_div_timer4", "clk_div_50m_a53", ++ 0, 0x2064, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER5, "clk_div_timer5", "clk_div_50m_a53", ++ 0, 0x2068, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER6, "clk_div_timer6", "clk_div_50m_a53", ++ 0, 0x206c, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER7, "clk_div_timer7", "clk_div_50m_a53", ++ 0, 0x2070, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER8, "clk_div_timer8", "clk_div_50m_a53", ++ 0, 0x2074, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_100K_EMMC, "clk_div_100k_emmc", "clk_div_top_axi0", ++ 0, 0x2090, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_100K_SD, "clk_div_100k_sd", "clk_div_top_axi0", ++ 0, 0x2098, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_GPIO_DB, "clk_div_gpio_db", "clk_div_top_axi0", ++ 0, 0x207c, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_DPLL0_DDR01_0, "clk_div_ddr01_0", "clk_gate_ddr01_div0", ++ 0, 0x20ac, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, ++ { DIV_CLK_DPLL1_DDR23_0, "clk_div_ddr23_0", "clk_gate_ddr23_div0", ++ 0, 0x20b4, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, ++}; ++ ++/* gate clocks */ ++static const struct mango_gate_clock s0_gate_clks = { ++ { GATE_CLK_RP_CPU_NORMAL_DIV0, "clk_gate_rp_cpu_normal_div1", "mpll_clock", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, ++ { GATE_CLK_AXI_DDR_DIV0, "clk_gate_axi_ddr_div1", "mpll_clock", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, ++ { GATE_CLK_DDR01_DIV0, "clk_gate_ddr01_div0", "fpll_clock", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 }, ++ { GATE_CLK_DDR23_DIV0, "clk_gate_ddr23_div0", "fpll_clock", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 }, ++ { GATE_CLK_RP_CPU_NORMAL_DIV1, "clk_gate_rp_cpu_normal_div0", "fpll_clock", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, ++ { GATE_CLK_AXI_DDR_DIV1, "clk_gate_axi_ddr_div0", "fpll_clock", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, ++ { GATE_CLK_DDR01_DIV1, "clk_gate_ddr01_div1", "dpll0_clock", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 14, 0 }, ++ { GATE_CLK_DDR23_DIV1, "clk_gate_ddr23_div1", "dpll1_clock", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 15, 0 }, ++ { GATE_CLK_A53_50M, "clk_gate_a53_50m", "clk_div_50m_a53", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 1, 0 }, ++ { GATE_CLK_TOP_RP_CMN_DIV2, "clk_gate_top_rp_cmn_div2", "clk_gate_rp_cpu_normal", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 2, 0 }, ++ { GATE_CLK_AXI_PCIE0, "clk_gate_axi_pcie0", "clk_gate_rp_cpu_normal", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 8, 0 }, ++ { GATE_CLK_AXI_PCIE1, "clk_gate_axi_pcie1", "clk_gate_rp_cpu_normal", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 9, 0 }, ++ { GATE_CLK_HSDMA, "clk_gate_hsdma", "clk_gate_top_rp_cmn_div2", ++ CLK_SET_RATE_PARENT, 0x2004, 10, 0 }, ++ { GATE_CLK_EMMC_100M, "clk_gate_emmc", "clk_div_emmc", ++ CLK_SET_RATE_PARENT, 0x2004, 3, 0 }, ++ { GATE_CLK_SD_100M, "clk_gate_sd", "clk_div_sd", ++ CLK_SET_RATE_PARENT, 0x2004, 6, 0 }, ++ { GATE_CLK_TX_ETH0, "clk_gate_tx_eth0", "clk_div_tx_eth0", ++ CLK_SET_RATE_PARENT, 0x2000, 30, 0 }, ++ { GATE_CLK_PTP_REF_I_ETH0, "clk_gate_ptp_ref_i_eth0", "clk_div_ptp_ref_i_eth0", ++ CLK_SET_RATE_PARENT, 0x2004, 0, 0 }, ++ { GATE_CLK_REF_ETH0, "clk_gate_ref_eth0", "clk_div_ref_eth0", ++ CLK_SET_RATE_PARENT, 0x2004, 1, 0 }, ++ { GATE_CLK_UART_500M, "clk_gate_uart_500m", "clk_div_uart_500m", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 4, 0 }, ++ { GATE_CLK_AHB_LPC, "clk_gate_ahb_lpc", "clk_div_ahb_lpc", ++ CLK_SET_RATE_PARENT, 0x2000, 7, 0 }, ++ { GATE_CLK_EFUSE, "clk_gate_efuse", "clk_div_efuse", ++ CLK_SET_RATE_PARENT, 0x2000, 20, 0}, ++ { GATE_CLK_TOP_AXI0, "clk_gate_top_axi0", "clk_div_top_axi0", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 11, 0 }, ++ { GATE_CLK_TOP_AXI_HSPERI, "clk_gate_top_axi_hsperi", "clk_div_top_axi_hsperi", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 12, 0 }, ++ { GATE_CLK_AHB_ROM, "clk_gate_ahb_rom", "clk_gate_top_axi0", ++ 0, 0x2000, 8, 0 }, ++ { GATE_CLK_AHB_SF, "clk_gate_ahb_sf", "clk_gate_top_axi0", ++ 0, 0x2000, 9, 0 }, ++ { GATE_CLK_AXI_SRAM, "clk_gate_axi_sram", "clk_gate_top_axi0", ++ CLK_IGNORE_UNUSED, 0x2000, 10, 0 }, ++ { GATE_CLK_APB_TIMER, "clk_gate_apb_timer", "clk_gate_top_axi0", ++ CLK_IGNORE_UNUSED, 0x2000, 11, 0 }, ++ { GATE_CLK_APB_EFUSE, "clk_gate_apb_efuse", "clk_gate_top_axi0", ++ 0, 0x2000, 21, 0 }, ++ { GATE_CLK_APB_GPIO, "clk_gate_apb_gpio", "clk_gate_top_axi0", ++ 0, 0x2000, 22, 0 }, ++ { GATE_CLK_APB_GPIO_INTR, "clk_gate_apb_gpio_intr", "clk_gate_top_axi0", ++ 0, 0x2000, 23, 0 }, ++ { GATE_CLK_APB_I2C, "clk_gate_apb_i2c", "clk_gate_top_axi0", ++ 0, 0x2000, 26, 0 }, ++ { GATE_CLK_APB_WDT, "clk_gate_apb_wdt", "clk_gate_top_axi0", ++ 0, 0x2000, 27, 0 }, ++ { GATE_CLK_APB_PWM, "clk_gate_apb_pwm", "clk_gate_top_axi0", ++ 0, 0x2000, 28, 0 }, ++ { GATE_CLK_APB_RTC, "clk_gate_apb_rtc", "clk_gate_top_axi0", ++ 0, 0x2000, 29, 0 }, ++ { GATE_CLK_SYSDMA_AXI, "clk_gate_sysdma_axi", "clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 3, 0 }, ++ { GATE_CLK_APB_UART, "clk_gate_apb_uart", "clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 5, 0 }, ++ { GATE_CLK_AXI_DBG_I2C, "clk_gate_axi_dbg_i2c", "clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 6, 0 }, ++ { GATE_CLK_APB_SPI, "clk_gate_apb_spi", "clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 25, 0 }, ++ { GATE_CLK_AXI_ETH0, "clk_gate_axi_eth0", "clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 31, 0 }, ++ { GATE_CLK_AXI_EMMC, "clk_gate_axi_emmc", "clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2004, 2, 0 }, ++ { GATE_CLK_AXI_SD, "clk_gate_axi_sd", "clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2004, 5, 0 }, ++ { GATE_CLK_TIMER1, "clk_gate_timer1", "clk_div_timer1", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 12, 0 }, ++ { GATE_CLK_TIMER2, "clk_gate_timer2", "clk_div_timer2", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 13, 0 }, ++ { GATE_CLK_TIMER3, "clk_gate_timer3", "clk_div_timer3", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 14, 0 }, ++ { GATE_CLK_TIMER4, "clk_gate_timer4", "clk_div_timer4", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 15, 0 }, ++ { GATE_CLK_TIMER5, "clk_gate_timer5", "clk_div_timer5", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 16, 0 }, ++ { GATE_CLK_TIMER6, "clk_gate_timer6", "clk_div_timer6", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 17, 0 }, ++ { GATE_CLK_TIMER7, "clk_gate_timer7", "clk_div_timer7", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 18, 0 }, ++ { GATE_CLK_TIMER8, "clk_gate_timer8", "clk_div_timer8", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 19, 0 }, ++ { GATE_CLK_100K_EMMC, "clk_gate_100k_emmc", "clk_div_100k_emmc", ++ CLK_SET_RATE_PARENT, 0x2004, 4, 0 }, ++ { GATE_CLK_100K_SD, "clk_gate_100k_sd", "clk_div_100k_sd", ++ CLK_SET_RATE_PARENT, 0x2004, 7, 0 }, ++ { GATE_CLK_GPIO_DB, "clk_gate_gpio_db", "clk_div_gpio_db", ++ CLK_SET_RATE_PARENT, 0x2000, 24, 0 }, ++ { GATE_CLK_DDR01, "clk_gate_ddr01", "clk_mux_ddr01", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 }, ++ { GATE_CLK_DDR23, "clk_gate_ddr23", "clk_mux_ddr23", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 }, ++ { GATE_CLK_RP_CPU_NORMAL, "clk_gate_rp_cpu_normal", "clk_mux_rp_cpu_normal", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, ++ { GATE_CLK_AXI_DDR, "clk_gate_axi_ddr", "clk_mux_axi_ddr", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, ++ { GATE_CLK_RXU0, "clk_gate_rxu0", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 0, 0 }, ++ { GATE_CLK_RXU1, "clk_gate_rxu1", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 1, 0 }, ++ { GATE_CLK_RXU2, "clk_gate_rxu2", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 2, 0 }, ++ { GATE_CLK_RXU3, "clk_gate_rxu3", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 3, 0 }, ++ { GATE_CLK_RXU4, "clk_gate_rxu4", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 4, 0 }, ++ { GATE_CLK_RXU5, "clk_gate_rxu5", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 5, 0 }, ++ { GATE_CLK_RXU6, "clk_gate_rxu6", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 6, 0 }, ++ { GATE_CLK_RXU7, "clk_gate_rxu7", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 7, 0 }, ++ { GATE_CLK_RXU8, "clk_gate_rxu8", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 8, 0 }, ++ { GATE_CLK_RXU9, "clk_gate_rxu9", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 9, 0 }, ++ { GATE_CLK_RXU10, "clk_gate_rxu10", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 10, 0 }, ++ { GATE_CLK_RXU11, "clk_gate_rxu11", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 11, 0 }, ++ { GATE_CLK_RXU12, "clk_gate_rxu12", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 12, 0 }, ++ { GATE_CLK_RXU13, "clk_gate_rxu13", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 13, 0 }, ++ { GATE_CLK_RXU14, "clk_gate_rxu14", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 14, 0 }, ++ { GATE_CLK_RXU15, "clk_gate_rxu15", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 15, 0 }, ++ { GATE_CLK_RXU16, "clk_gate_rxu16", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 16, 0 }, ++ { GATE_CLK_RXU17, "clk_gate_rxu17", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 17, 0 }, ++ { GATE_CLK_RXU18, "clk_gate_rxu18", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 18, 0 }, ++ { GATE_CLK_RXU19, "clk_gate_rxu19", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 19, 0 }, ++ { GATE_CLK_RXU20, "clk_gate_rxu20", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 20, 0 }, ++ { GATE_CLK_RXU21, "clk_gate_rxu21", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 21, 0 }, ++ { GATE_CLK_RXU22, "clk_gate_rxu22", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 22, 0 }, ++ { GATE_CLK_RXU23, "clk_gate_rxu23", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 23, 0 }, ++ { GATE_CLK_RXU24, "clk_gate_rxu24", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 24, 0 }, ++ { GATE_CLK_RXU25, "clk_gate_rxu25", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 25, 0 }, ++ { GATE_CLK_RXU26, "clk_gate_rxu26", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 26, 0 }, ++ { GATE_CLK_RXU27, "clk_gate_rxu27", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 27, 0 }, ++ { GATE_CLK_RXU28, "clk_gate_rxu28", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 28, 0 }, ++ { GATE_CLK_RXU29, "clk_gate_rxu29", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 29, 0 }, ++ { GATE_CLK_RXU30, "clk_gate_rxu30", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 30, 0 }, ++ { GATE_CLK_RXU31, "clk_gate_rxu31", "clk_gate_rp_cpu_normal", ++ 0, 0x368, 31, 0 }, ++ { GATE_CLK_MP0, "clk_gate_mp0", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x384, 0, 0 }, ++ { GATE_CLK_MP1, "clk_gate_mp1", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x38c, 0, 0 }, ++ { GATE_CLK_MP2, "clk_gate_mp2", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x394, 0, 0 }, ++ { GATE_CLK_MP3, "clk_gate_mp3", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x39c, 0, 0 }, ++ { GATE_CLK_MP4, "clk_gate_mp4", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3a4, 0, 0 }, ++ { GATE_CLK_MP5, "clk_gate_mp5", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ac, 0, 0 }, ++ { GATE_CLK_MP6, "clk_gate_mp6", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3b4, 0, 0 }, ++ { GATE_CLK_MP7, "clk_gate_mp7", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3bc, 0, 0 }, ++ { GATE_CLK_MP8, "clk_gate_mp8", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3c4, 0, 0 }, ++ { GATE_CLK_MP9, "clk_gate_mp9", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3cc, 0, 0 }, ++ { GATE_CLK_MP10, "clk_gate_mp10", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3d4, 0, 0 }, ++ { GATE_CLK_MP11, "clk_gate_mp11", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3dc, 0, 0 }, ++ { GATE_CLK_MP12, "clk_gate_mp12", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3e4, 0, 0 }, ++ { GATE_CLK_MP13, "clk_gate_mp13", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ec, 0, 0 }, ++ { GATE_CLK_MP14, "clk_gate_mp14", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3f4, 0, 0 }, ++ { GATE_CLK_MP15, "clk_gate_mp15", "clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3fc, 0, 0 }, ++}; ++ ++static const struct mango_divider_clock s1_div_clks = { ++ { DIV_CLK_MPLL_RP_CPU_NORMAL_0, "s1_clk_div_rp_cpu_normal_0", "s1_clk_gate_rp_cpu_normal_div0", ++ 0, 0x2044, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_MPLL_AXI_DDR_0, "s1_clk_div_axi_ddr_0", "s1_clk_gate_axi_ddr_div0", ++ 0, 0x20a8, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5}, ++ { DIV_CLK_FPLL_DDR01_1, "s1_clk_div_ddr01_1", "s1_clk_gate_ddr01_div1", ++ 0, 0x20b0, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, ++ { DIV_CLK_FPLL_DDR23_1, "s1_clk_div_ddr23_1", "s1_clk_gate_ddr23_div1", ++ 0, 0x20b8, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, ++ { DIV_CLK_FPLL_RP_CPU_NORMAL_1, "s1_clk_div_rp_cpu_normal_1", "s1_clk_gate_rp_cpu_normal_div1", ++ 0, 0x2040, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_50M_A53, "s1_clk_div_50m_a53", "s1_fpll_clock", ++ 0, 0x2048, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_TOP_RP_CMN_DIV2, "s1_clk_div_top_rp_cmn_div2", "s1_clk_mux_rp_cpu_normal", ++ 0, 0x204c, 16, 16, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_UART_500M, "s1_clk_div_uart_500m", "s1_fpll_clock", ++ 0, 0x2050, 16, 7, CLK_DIVIDER_READ_ONLY, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_AHB_LPC, "s1_clk_div_ahb_lpc", "s1_fpll_clock", ++ 0, 0x2054, 16, 16, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_EFUSE, "s1_clk_div_efuse", "s1_fpll_clock", ++ 0, 0x2078, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_TX_ETH0, "s1_clk_div_tx_eth0", "s1_fpll_clock", ++ 0, 0x2080, 16, 11, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_PTP_REF_I_ETH0, "s1_clk_div_ptp_ref_i_eth0", "s1_fpll_clock", ++ 0, 0x2084, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_REF_ETH0, "s1_clk_div_ref_eth0", "s1_fpll_clock", ++ 0, 0x2088, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_EMMC, "s1_clk_div_emmc", "s1_fpll_clock", ++ 0, 0x208c, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_SD, "s1_clk_div_sd", "s1_fpll_clock", ++ 0, 0x2094, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_TOP_AXI0, "s1_clk_div_top_axi0", "s1_fpll_clock", ++ 0, 0x209c, 16, 5, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_TOP_AXI_HSPERI, "s1_clk_div_top_axi_hsperi", "s1_fpll_clock", ++ 0, 0x20a0, 16, 5, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_AXI_DDR_1, "s1_clk_div_axi_ddr_1", "s1_clk_gate_axi_ddr_div1", ++ 0, 0x20a4, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5}, ++ { DIV_CLK_FPLL_DIV_TIMER1, "s1_clk_div_timer1", "s1_clk_div_50m_a53", ++ 0, 0x2058, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER2, "s1_clk_div_timer2", "s1_clk_div_50m_a53", ++ 0, 0x205c, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER3, "s1_clk_div_timer3", "s1_clk_div_50m_a53", ++ 0, 0x2060, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER4, "s1_clk_div_timer4", "s1_clk_div_50m_a53", ++ 0, 0x2064, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER5, "s1_clk_div_timer5", "s1_clk_div_50m_a53", ++ 0, 0x2068, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER6, "s1_clk_div_timer6", "s1_clk_div_50m_a53", ++ 0, 0x206c, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER7, "s1_clk_div_timer7", "s1_clk_div_50m_a53", ++ 0, 0x2070, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_DIV_TIMER8, "s1_clk_div_timer8", "s1_clk_div_50m_a53", ++ 0, 0x2074, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_100K_EMMC, "s1_clk_div_100k_emmc", "s1_clk_div_top_axi0", ++ 0, 0x2090, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_100K_SD, "s1_clk_div_100k_sd", "s1_clk_div_top_axi0", ++ 0, 0x2098, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_FPLL_GPIO_DB, "s1_clk_div_gpio_db", "s1_clk_div_top_axi0", ++ 0, 0x207c, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, ++ { DIV_CLK_DPLL0_DDR01_0, "s1_clk_div_ddr01_0", "s1_clk_gate_ddr01_div0", ++ 0, 0x20ac, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, ++ { DIV_CLK_DPLL1_DDR23_0, "s1_clk_div_ddr23_0", "s1_clk_gate_ddr23_div0", ++ 0, 0x20b4, 16, 8, CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, ++}; ++ ++static const struct mango_gate_clock s1_gate_clks = { ++ { GATE_CLK_RP_CPU_NORMAL_DIV0, "s1_clk_gate_rp_cpu_normal_div1", "s1_mpll_clock", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, ++ { GATE_CLK_AXI_DDR_DIV0, "s1_clk_gate_axi_ddr_div1", "s1_mpll_clock", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, ++ { GATE_CLK_DDR01_DIV0, "s1_clk_gate_ddr01_div0", "s1_fpll_clock", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 }, ++ { GATE_CLK_DDR23_DIV0, "s1_clk_gate_ddr23_div0", "s1_fpll_clock", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 }, ++ { GATE_CLK_RP_CPU_NORMAL_DIV1, "s1_clk_gate_rp_cpu_normal_div0", "s1_fpll_clock", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, ++ { GATE_CLK_AXI_DDR_DIV1, "s1_clk_gate_axi_ddr_div0", "s1_fpll_clock", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, ++ { GATE_CLK_DDR01_DIV1, "s1_clk_gate_ddr01_div1", "s1_dpll0_clock", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 14, 0 }, ++ { GATE_CLK_DDR23_DIV1, "s1_clk_gate_ddr23_div1", "s1_dpll1_clock", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 15, 0 }, ++ { GATE_CLK_A53_50M, "s1_clk_gate_a53_50m", "s1_clk_div_50m_a53", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 1, 0 }, ++ { GATE_CLK_TOP_RP_CMN_DIV2, "s1_clk_gate_top_rp_cmn_div2", "s1_clk_gate_rp_cpu_normal", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 2, 0 }, ++ { GATE_CLK_AXI_PCIE0, "s1_clk_gate_axi_pcie0", "s1_clk_gate_rp_cpu_normal", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 8, 0 }, ++ { GATE_CLK_AXI_PCIE1, "s1_clk_gate_axi_pcie1", "s1_clk_gate_rp_cpu_normal", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 9, 0 }, ++ { GATE_CLK_HSDMA, "s1_clk_gate_hsdma", "s1_clk_gate_top_rp_cmn_div2", ++ CLK_SET_RATE_PARENT, 0x2004, 10, 0 }, ++ { GATE_CLK_EMMC_100M, "s1_clk_gate_emmc", "s1_clk_div_emmc", ++ CLK_SET_RATE_PARENT, 0x2004, 3, 0 }, ++ { GATE_CLK_SD_100M, "s1_clk_gate_sd", "s1_clk_div_sd", ++ CLK_SET_RATE_PARENT, 0x2004, 6, 0 }, ++ { GATE_CLK_TX_ETH0, "s1_clk_gate_tx_eth0", "s1_clk_div_tx_eth0", ++ CLK_SET_RATE_PARENT, 0x2000, 30, 0 }, ++ { GATE_CLK_PTP_REF_I_ETH0, "s1_clk_gate_ptp_ref_i_eth0", "s1_clk_div_ptp_ref_i_eth0", ++ CLK_SET_RATE_PARENT, 0x2004, 0, 0 }, ++ { GATE_CLK_REF_ETH0, "s1_clk_gate_ref_eth0", "s1_clk_div_ref_eth0", ++ CLK_SET_RATE_PARENT, 0x2004, 1, 0 }, ++ { GATE_CLK_UART_500M, "s1_clk_gate_uart_500m", "s1_clk_div_uart_500m", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 4, 0 }, ++ { GATE_CLK_AHB_LPC, "s1_clk_gate_ahb_lpc", "s1_clk_div_ahb_lpc", ++ CLK_SET_RATE_PARENT, 0x2000, 7, 0 }, ++ { GATE_CLK_EFUSE, "s1_clk_gate_efuse", "s1_clk_div_efuse", ++ CLK_SET_RATE_PARENT, 0x2000, 20, 0}, ++ { GATE_CLK_TOP_AXI0, "s1_clk_gate_top_axi0", "s1_clk_div_top_axi0", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 11, 0 }, ++ { GATE_CLK_TOP_AXI_HSPERI, "s1_clk_gate_top_axi_hsperi", "s1_clk_div_top_axi_hsperi", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 12, 0 }, ++ { GATE_CLK_AHB_ROM, "s1_clk_gate_ahb_rom", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 8, 0 }, ++ { GATE_CLK_AHB_SF, "s1_clk_gate_ahb_sf", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 9, 0 }, ++ { GATE_CLK_AXI_SRAM, "s1_clk_gate_axi_sram", "s1_clk_gate_top_axi0", ++ CLK_IGNORE_UNUSED, 0x2000, 10, 0 }, ++ { GATE_CLK_APB_TIMER, "s1_clk_gate_apb_timer", "s1_clk_gate_top_axi0", ++ CLK_IGNORE_UNUSED, 0x2000, 11, 0 }, ++ { GATE_CLK_APB_EFUSE, "s1_clk_gate_apb_efuse", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 21, 0 }, ++ { GATE_CLK_APB_GPIO, "s1_clk_gate_apb_gpio", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 22, 0 }, ++ { GATE_CLK_APB_GPIO_INTR, "s1_clk_gate_apb_gpio_intr", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 23, 0 }, ++ { GATE_CLK_APB_I2C, "s1_clk_gate_apb_i2c", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 26, 0 }, ++ { GATE_CLK_APB_WDT, "s1_clk_gate_apb_wdt", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 27, 0 }, ++ { GATE_CLK_APB_PWM, "s1_clk_gate_apb_pwm", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 28, 0 }, ++ { GATE_CLK_APB_RTC, "s1_clk_gate_apb_rtc", "s1_clk_gate_top_axi0", ++ 0, 0x2000, 29, 0 }, ++ { GATE_CLK_SYSDMA_AXI, "s1_clk_gate_sysdma_axi", "s1_clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 3, 0 }, ++ { GATE_CLK_APB_UART, "s1_clk_gate_apb_uart", "s1_clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 5, 0 }, ++ { GATE_CLK_AXI_DBG_I2C, "s1_clk_gate_axi_dbg_i2c", "s1_clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 6, 0 }, ++ { GATE_CLK_APB_SPI, "s1_clk_gate_apb_spi", "s1_clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 25, 0 }, ++ { GATE_CLK_AXI_ETH0, "s1_clk_gate_axi_eth0", "s1_clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2000, 31, 0 }, ++ { GATE_CLK_AXI_EMMC, "s1_clk_gate_axi_emmc", "s1_clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2004, 2, 0 }, ++ { GATE_CLK_AXI_SD, "s1_clk_gate_axi_sd", "s1_clk_gate_top_axi_hsperi", ++ CLK_SET_RATE_PARENT, 0x2004, 5, 0 }, ++ { GATE_CLK_TIMER1, "s1_clk_gate_timer1", "s1_clk_div_timer1", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 12, 0 }, ++ { GATE_CLK_TIMER2, "s1_clk_gate_timer2", "s1_clk_div_timer2", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 13, 0 }, ++ { GATE_CLK_TIMER3, "s1_clk_gate_timer3", "s1_clk_div_timer3", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 14, 0 }, ++ { GATE_CLK_TIMER4, "s1_clk_gate_timer4", "s1_clk_div_timer4", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 15, 0 }, ++ { GATE_CLK_TIMER5, "s1_clk_gate_timer5", "s1_clk_div_timer5", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 16, 0 }, ++ { GATE_CLK_TIMER6, "s1_clk_gate_timer6", "s1_clk_div_timer6", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 17, 0 }, ++ { GATE_CLK_TIMER7, "s1_clk_gate_timer7", "s1_clk_div_timer7", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 18, 0 }, ++ { GATE_CLK_TIMER8, "s1_clk_gate_timer8", "s1_clk_div_timer8", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 19, 0 }, ++ { GATE_CLK_100K_EMMC, "s1_clk_gate_100k_emmc", "s1_clk_div_100k_emmc", ++ CLK_SET_RATE_PARENT, 0x2004, 4, 0 }, ++ { GATE_CLK_100K_SD, "s1_clk_gate_100k_sd", "s1_clk_div_100k_sd", ++ CLK_SET_RATE_PARENT, 0x2004, 7, 0 }, ++ { GATE_CLK_GPIO_DB, "s1_clk_gate_gpio_db", "s1_clk_div_gpio_db", ++ CLK_SET_RATE_PARENT, 0x2000, 24, 0 }, ++ { GATE_CLK_DDR01, "s1_clk_gate_ddr01", "s1_clk_mux_ddr01", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 }, ++ { GATE_CLK_DDR23, "s1_clk_gate_ddr23", "s1_clk_mux_ddr23", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 }, ++ { GATE_CLK_RP_CPU_NORMAL, "s1_clk_gate_rp_cpu_normal", "s1_clk_mux_rp_cpu_normal", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, ++ { GATE_CLK_AXI_DDR, "s1_clk_gate_axi_ddr", "s1_clk_mux_axi_ddr", ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, ++ { GATE_CLK_RXU0, "s1_clk_gate_rxu0", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 0, 0 }, ++ { GATE_CLK_RXU1, "s1_clk_gate_rxu1", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 1, 0 }, ++ { GATE_CLK_RXU2, "s1_clk_gate_rxu2", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 2, 0 }, ++ { GATE_CLK_RXU3, "s1_clk_gate_rxu3", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 3, 0 }, ++ { GATE_CLK_RXU4, "s1_clk_gate_rxu4", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 4, 0 }, ++ { GATE_CLK_RXU5, "s1_clk_gate_rxu5", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 5, 0 }, ++ { GATE_CLK_RXU6, "s1_clk_gate_rxu6", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 6, 0 }, ++ { GATE_CLK_RXU7, "s1_clk_gate_rxu7", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 7, 0 }, ++ { GATE_CLK_RXU8, "s1_clk_gate_rxu8", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 8, 0 }, ++ { GATE_CLK_RXU9, "s1_clk_gate_rxu9", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 9, 0 }, ++ { GATE_CLK_RXU10, "s1_clk_gate_rxu10", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 10, 0 }, ++ { GATE_CLK_RXU11, "s1_clk_gate_rxu11", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 11, 0 }, ++ { GATE_CLK_RXU12, "s1_clk_gate_rxu12", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 12, 0 }, ++ { GATE_CLK_RXU13, "s1_clk_gate_rxu13", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 13, 0 }, ++ { GATE_CLK_RXU14, "s1_clk_gate_rxu14", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 14, 0 }, ++ { GATE_CLK_RXU15, "s1_clk_gate_rxu15", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 15, 0 }, ++ { GATE_CLK_RXU16, "s1_clk_gate_rxu16", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 16, 0 }, ++ { GATE_CLK_RXU17, "s1_clk_gate_rxu17", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 17, 0 }, ++ { GATE_CLK_RXU18, "s1_clk_gate_rxu18", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 18, 0 }, ++ { GATE_CLK_RXU19, "s1_clk_gate_rxu19", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 19, 0 }, ++ { GATE_CLK_RXU20, "s1_clk_gate_rxu20", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 20, 0 }, ++ { GATE_CLK_RXU21, "s1_clk_gate_rxu21", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 21, 0 }, ++ { GATE_CLK_RXU22, "s1_clk_gate_rxu22", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 22, 0 }, ++ { GATE_CLK_RXU23, "s1_clk_gate_rxu23", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 23, 0 }, ++ { GATE_CLK_RXU24, "s1_clk_gate_rxu24", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 24, 0 }, ++ { GATE_CLK_RXU25, "s1_clk_gate_rxu25", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 25, 0 }, ++ { GATE_CLK_RXU26, "s1_clk_gate_rxu26", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 26, 0 }, ++ { GATE_CLK_RXU27, "s1_clk_gate_rxu27", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 27, 0 }, ++ { GATE_CLK_RXU28, "s1_clk_gate_rxu28", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 28, 0 }, ++ { GATE_CLK_RXU29, "s1_clk_gate_rxu29", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 29, 0 }, ++ { GATE_CLK_RXU30, "s1_clk_gate_rxu30", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 30, 0 }, ++ { GATE_CLK_RXU31, "s1_clk_gate_rxu31", "s1_clk_gate_rp_cpu_normal", ++ 0, 0x368, 31, 0 }, ++ { GATE_CLK_MP0, "s1_clk_gate_mp0", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x384, 0, 0 }, ++ { GATE_CLK_MP1, "s1_clk_gate_mp1", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x38c, 0, 0 }, ++ { GATE_CLK_MP2, "s1_clk_gate_mp2", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x394, 0, 0 }, ++ { GATE_CLK_MP3, "s1_clk_gate_mp3", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x39c, 0, 0 }, ++ { GATE_CLK_MP4, "s1_clk_gate_mp4", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3a4, 0, 0 }, ++ { GATE_CLK_MP5, "s1_clk_gate_mp5", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ac, 0, 0 }, ++ { GATE_CLK_MP6, "s1_clk_gate_mp6", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3b4, 0, 0 }, ++ { GATE_CLK_MP7, "s1_clk_gate_mp7", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3bc, 0, 0 }, ++ { GATE_CLK_MP8, "s1_clk_gate_mp8", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3c4, 0, 0 }, ++ { GATE_CLK_MP9, "s1_clk_gate_mp9", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3cc, 0, 0 }, ++ { GATE_CLK_MP10, "s1_clk_gate_mp10", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3d4, 0, 0 }, ++ { GATE_CLK_MP11, "s1_clk_gate_mp11", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3dc, 0, 0 }, ++ { GATE_CLK_MP12, "s1_clk_gate_mp12", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3e4, 0, 0 }, ++ { GATE_CLK_MP13, "s1_clk_gate_mp13", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ec, 0, 0 }, ++ { GATE_CLK_MP14, "s1_clk_gate_mp14", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3f4, 0, 0 }, ++ { GATE_CLK_MP15, "s1_clk_gate_mp15", "s1_clk_gate_rp_cpu_normal", ++ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3fc, 0, 0 }, ++}; ++ ++/* socket0 mux clocks */ ++static const char *const clk_mux_ddr01_p = { ++ "clk_div_ddr01_0", "clk_div_ddr01_1"}; ++static const char *const clk_mux_ddr23_p = { ++ "clk_div_ddr23_0", "clk_div_ddr23_1"}; ++static const char *const clk_mux_rp_cpu_normal_p = { ++ "clk_div_rp_cpu_normal_0", "clk_div_rp_cpu_normal_1"}; ++static const char *const clk_mux_axi_ddr_p = { ++ "clk_div_axi_ddr_0", "clk_div_axi_ddr_1"}; ++ ++struct mango_mux_clock s0_mux_clks = { ++ { ++ MUX_CLK_DDR01, "clk_mux_ddr01", clk_mux_ddr01_p, ++ ARRAY_SIZE(clk_mux_ddr01_p), ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | ++ CLK_MUX_READ_ONLY, ++ 0x2020, 2, 1, 0, ++ }, ++ { ++ MUX_CLK_DDR23, "clk_mux_ddr23", clk_mux_ddr23_p, ++ ARRAY_SIZE(clk_mux_ddr23_p), ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | ++ CLK_MUX_READ_ONLY, ++ 0x2020, 3, 1, 0, ++ }, ++ { ++ MUX_CLK_RP_CPU_NORMAL, "clk_mux_rp_cpu_normal", clk_mux_rp_cpu_normal_p, ++ ARRAY_SIZE(clk_mux_rp_cpu_normal_p), ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, ++ 0x2020, 0, 1, 0, ++ }, ++ { ++ MUX_CLK_AXI_DDR, "clk_mux_axi_ddr", clk_mux_axi_ddr_p, ++ ARRAY_SIZE(clk_mux_axi_ddr_p), ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, ++ 0x2020, 1, 1, 0, ++ }, ++}; ++ ++/* socket1 mux clocks */ ++static const char *const s1_clk_mux_ddr01_p = { ++ "s1_clk_div_ddr01_0", "s1_clk_div_ddr01_1"}; ++static const char *const s1_clk_mux_ddr23_p = { ++ "s1_clk_div_ddr23_0", "s1_clk_div_ddr23_1"}; ++static const char *const s1_clk_mux_rp_cpu_normal_p = { ++ "s1_clk_div_rp_cpu_normal_0", "s1_clk_div_rp_cpu_normal_1"}; ++static const char *const s1_clk_mux_axi_ddr_p = { ++ "s1_clk_div_axi_ddr_0", "s1_clk_div_axi_ddr_1"}; ++ ++struct mango_mux_clock s1_mux_clks = { ++ { ++ MUX_CLK_DDR01, "s1_clk_mux_ddr01", s1_clk_mux_ddr01_p, ++ ARRAY_SIZE(s1_clk_mux_ddr01_p), ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | ++ CLK_MUX_READ_ONLY, ++ 0x2020, 2, 1, 0, ++ }, ++ { ++ MUX_CLK_DDR23, "s1_clk_mux_ddr23", s1_clk_mux_ddr23_p, ++ ARRAY_SIZE(s1_clk_mux_ddr23_p), ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | ++ CLK_MUX_READ_ONLY, ++ 0x2020, 3, 1, 0, ++ }, ++ { ++ MUX_CLK_RP_CPU_NORMAL, "s1_clk_mux_rp_cpu_normal", s1_clk_mux_rp_cpu_normal_p, ++ ARRAY_SIZE(s1_clk_mux_rp_cpu_normal_p), ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, ++ 0x2020, 0, 1, 0, ++ }, ++ { ++ MUX_CLK_AXI_DDR, "s1_clk_mux_axi_ddr", s1_clk_mux_axi_ddr_p, ++ ARRAY_SIZE(s1_clk_mux_axi_ddr_p), ++ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, ++ 0x2020, 1, 1, 0, ++ }, ++}; ++ ++struct mango_clk_table pll_clk_tables = { ++ .pll_clks_num = ARRAY_SIZE(mango_root_pll_clks), ++ .pll_clks = mango_root_pll_clks, ++}; ++ ++struct mango_clk_table div_clk_tables = { ++ { ++ .id = S0_DIV_CLK_TABLE, ++ .div_clks_num = ARRAY_SIZE(s0_div_clks), ++ .div_clks = s0_div_clks, ++ .gate_clks_num = ARRAY_SIZE(s0_gate_clks), ++ .gate_clks = s0_gate_clks, ++ },{ ++ .id = S1_DIV_CLK_TABLE, ++ .div_clks_num = ARRAY_SIZE(s1_div_clks), ++ .div_clks = s1_div_clks, ++ .gate_clks_num = ARRAY_SIZE(s1_gate_clks), ++ .gate_clks = s1_gate_clks, ++ }, ++}; ++ ++struct mango_clk_table mux_clk_tables = { ++ { ++ .id = S0_MUX_CLK_TABLE, ++ .mux_clks_num = ARRAY_SIZE(s0_mux_clks), ++ .mux_clks = s0_mux_clks, ++ },{ ++ .id = S1_MUX_CLK_TABLE, ++ .mux_clks_num = ARRAY_SIZE(s1_mux_clks), ++ .mux_clks = s1_mux_clks, ++ }, ++}; ++ ++static const struct of_device_id mango_clk_match_ids_tables = { ++ { ++ .compatible = "mango, pll-clock", ++ .data = &pll_clk_tables, ++ }, ++ { ++ .compatible = "mango, pll-child-clock", ++ .data = div_clk_tables, ++ }, ++ { ++ .compatible = "mango, pll-mux-clock", ++ .data = mux_clk_tables, ++ }, ++ { ++ .compatible = "mango, clk-default-rates", ++ }, ++ { ++ .compatible = "mango, dm-pll-clock", ++ .data = &pll_clk_tables, ++ }, ++ { ++ .compatible = "mango, dm-pll-child-clock", ++ .data = div_clk_tables, ++ }, ++ { ++ .compatible = "mango, dm-pll-mux-clock", ++ .data = mux_clk_tables, ++ }, ++ { ++ .compatible = "mango, dm-clk-default-rates", ++ }, ++ {} ++}; ++ ++static void __init mango_clk_init(struct device_node *node) ++{ ++ struct device_node *np_top; ++ struct mango_clk_data *clk_data = NULL; ++ const struct mango_clk_table *dev_data; ++ struct regmap *syscon; ++ void __iomem *base; ++ int i, ret = 0; ++ unsigned int id; ++ const char *clk_name; ++ const struct of_device_id *match = NULL; ++ ++ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); ++ if (!clk_data) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ match = of_match_node(mango_clk_match_ids_tables, node); ++ if (match) { ++ dev_data = (struct mango_clk_table *)match->data; ++ } else { ++ pr_err("%s did't match node data\n", __func__); ++ ret = -ENODEV; ++ goto no_match_data; ++ } ++ ++ np_top = of_parse_phandle(node, "subctrl-syscon", 0); ++ if (!np_top) { ++ pr_err("%s can't get subctrl-syscon node\n", ++ __func__); ++ ret = -EINVAL; ++ goto no_match_data; ++ } ++ ++ syscon = device_node_to_regmap(np_top); ++ if (IS_ERR_OR_NULL(syscon)) { ++ pr_err("%s cannot get regmap %ld\n", __func__, PTR_ERR(syscon)); ++ ret = -ENODEV; ++ goto no_match_data; ++ } ++ base = of_iomap(np_top, 0); ++ ++ spin_lock_init(&clk_data->lock); ++ if (of_device_is_compatible(node, "mango, pll-clock") || ++ of_device_is_compatible(node, "mango, dm-pll-clock")) { ++ if (!dev_data->pll_clks_num) { ++ ret = -EINVAL; ++ goto no_match_data; ++ } ++ ++ clk_data->table = dev_data; ++ clk_data->base = base; ++ clk_data->syscon_top = syscon; ++ ++ if (of_property_read_string(node, "clock-output-names", &clk_name)) { ++ pr_err("%s cannot get pll name for %s\n", ++ __func__, node->full_name); ++ ret = -ENODEV; ++ goto no_match_data; ++ } ++ if (of_device_is_compatible(node, "mango, pll-clock")) ++ ret = mango_register_pll_clks(node, clk_data, clk_name); ++ else ++ ret = dm_mango_register_pll_clks(node, clk_data, clk_name); ++ } ++ ++ if (of_device_is_compatible(node, "mango, pll-child-clock") || ++ of_device_is_compatible(node, "mango, dm-pll-child-clock")) { ++ ret = of_property_read_u32(node, "id", &id); ++ if (ret) { ++ pr_err("not assigned id for %s\n", node->full_name); ++ ret = -ENODEV; ++ goto no_match_data; ++ } ++ ++ /* Below brute-force to check dts property "id" ++ * whether match id of array ++ */ ++ for (i = 0; i < ARRAY_SIZE(div_clk_tables); i++) { ++ if (id == dev_datai.id) ++ break; /* found */ ++ } ++ clk_data->table = &dev_datai; ++ clk_data->base = base; ++ clk_data->syscon_top = syscon; ++ if (of_device_is_compatible(node, "mango, pll-child-clock")) ++ ret = mango_register_div_clks(node, clk_data); ++ else ++ ret = dm_mango_register_div_clks(node, clk_data); ++ } ++ ++ if (of_device_is_compatible(node, "mango, pll-mux-clock") || ++ of_device_is_compatible(node, "mango, dm-pll-mux-clock")) { ++ ret = of_property_read_u32(node, "id", &id); ++ if (ret) { ++ pr_err("not assigned id for %s\n", node->full_name); ++ ret = -ENODEV; ++ goto no_match_data; ++ } ++ ++ /* Below brute-force to check dts property "id" ++ * whether match id of array ++ */ ++ for (i = 0; i < ARRAY_SIZE(mux_clk_tables); i++) { ++ if (id == dev_datai.id) ++ break; /* found */ ++ } ++ clk_data->table = &dev_datai; ++ clk_data->base = base; ++ clk_data->syscon_top = syscon; ++ if (of_device_is_compatible(node, "mango, pll-mux-clock")) ++ ret = mango_register_mux_clks(node, clk_data); ++ else ++ ret = dm_mango_register_mux_clks(node, clk_data); ++ } ++ ++ if (of_device_is_compatible(node, "mango, clk-default-rates")) ++ ret = set_default_clk_rates(node); ++ ++ if (of_device_is_compatible(node, "mango, dm-clk-default-rates")) ++ ret = dm_set_default_clk_rates(node); ++ ++ if (!ret) ++ return; ++ ++no_match_data: ++ kfree(clk_data); ++ ++out: ++ pr_err("%s failed error number %d\n", __func__, ret); ++} ++ ++CLK_OF_DECLARE(mango_clk_pll, "mango, pll-clock", mango_clk_init); ++CLK_OF_DECLARE(mango_clk_pll_child, "mango, pll-child-clock", mango_clk_init); ++CLK_OF_DECLARE(mango_clk_pll_mux, "mango, pll-mux-clock", mango_clk_init); ++CLK_OF_DECLARE(mango_clk_default_rate, "mango, clk-default-rates", mango_clk_init); ++CLK_OF_DECLARE(dm_mango_clk_pll, "mango, dm-pll-clock", mango_clk_init); ++CLK_OF_DECLARE(dm_mango_clk_pll_child, "mango, dm-pll-child-clock", mango_clk_init); ++CLK_OF_DECLARE(dm_mango_clk_pll_mux, "mango, dm-pll-mux-clock", mango_clk_init); ++CLK_OF_DECLARE(dm_mango_clk_default_rate, "mango, dm-clk-default-rates", mango_clk_init); +diff --git a/drivers/clk/sophgo/clk.c b/drivers/clk/sophgo/clk.c +new file mode 100644 +index 000000000000..4d3893ace2b9 +--- /dev/null ++++ b/drivers/clk/sophgo/clk.c +@@ -0,0 +1,883 @@ ++/* ++ * Copyright (c) 2022 SOPHGO ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++#include <linux/mfd/syscon.h> ++#include <linux/io.h> ++#include <linux/of_address.h> ++#include <linux/string.h> ++#include <linux/log2.h> ++ ++#include "clk.h" ++ ++/* ++ * @hw: handle between common and hardware-specific interfaces ++ * @reg: register containing divider ++ * @shift: shift to the divider bit field ++ * @width: width of the divider bit field ++ * @initial_val:initial value of the divider ++ * @table: the div table that the divider supports ++ * @lock: register lock ++ */ ++struct mango_clk_divider { ++ struct clk_hw hw; ++ void __iomem *reg; ++ u8 shift; ++ u8 width; ++ u8 flags; ++ u32 initial_val; ++ const struct clk_div_table *table; ++ spinlock_t *lock; ++}; ++ ++static inline int mango_pll_enable(struct regmap *map, ++ struct mango_pll_clock *pll, bool en) ++{ ++ unsigned int value; ++ unsigned long enter; ++ unsigned int id = pll->id; ++ ++ if (en) { ++ /* wait pll lock */ ++ enter = jiffies; ++ regmap_read(map, pll->status_offset, &value); ++ while (!((value >> (PLL_STAT_LOCK_OFFSET + id)) & 0x1)) { ++ regmap_read(map, pll->status_offset, &value); ++ if (time_after(jiffies, enter + HZ / 10)) ++ pr_warn("%s not locked\n", pll->name); ++ } ++ /* wait pll updating */ ++ enter = jiffies; ++ regmap_read(map, pll->status_offset, &value); ++ while (((value >> id) & 0x1)) { ++ regmap_read(map, pll->status_offset, &value); ++ if (time_after(jiffies, enter + HZ / 10)) ++ pr_warn("%s still updating\n", pll->name); ++ } ++ /* enable pll */ ++ regmap_read(map, pll->enable_offset, &value); ++ regmap_write(map, pll->enable_offset, value | (1 << id)); ++ } else { ++ /* disable pll */ ++ regmap_read(map, pll->enable_offset, &value); ++ regmap_write(map, pll->enable_offset, value & (~(1 << id))); ++ } ++ ++ return 0; ++} ++ ++static inline int mango_pll_write(struct regmap *map, int id, int value) ++{ ++ return regmap_write(map, PLL_CTRL_OFFSET + (id << 2), value); ++} ++ ++static inline int mango_pll_read(struct regmap *map, int id, unsigned int *pvalue) ++{ ++ return regmap_read(map, PLL_CTRL_OFFSET + (id << 2), pvalue); ++} ++ ++static unsigned int _get_table_div(const struct clk_div_table *table, ++ unsigned int val) ++{ ++ const struct clk_div_table *clkt; ++ ++ for (clkt = table; clkt->div; clkt++) ++ if (clkt->val == val) ++ return clkt->div; ++ return 0; ++} ++ ++static unsigned int _get_div(const struct clk_div_table *table, ++ unsigned int val, unsigned long flags, u8 width) ++{ ++ if (flags & CLK_DIVIDER_ONE_BASED) ++ return val; ++ if (flags & CLK_DIVIDER_POWER_OF_TWO) ++ return 1 << val; ++ if (flags & CLK_DIVIDER_MAX_AT_ZERO) ++ return val ? val : div_mask(width) + 1; ++ if (table) ++ return _get_table_div(table, val); ++ return val + 1; ++} ++ ++static unsigned long mango_clk_divider_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct mango_clk_divider *divider = to_mango_clk_divider(hw); ++ unsigned int val; ++ ++ val = readl(divider->reg) >> divider->shift; ++ val &= div_mask(divider->width); ++ ++#ifdef CONFIG_ARCH_BM1880 ++ /* if select divide factor from initial value */ ++ if (!(readl(divider->reg) & BIT(3))) ++ val = divider->initial_val; ++#endif ++ ++ return divider_recalc_rate(hw, parent_rate, val, divider->table, ++ divider->flags, divider->width); ++} ++ ++static long mango_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ int bestdiv; ++ struct mango_clk_divider *divider = to_mango_clk_divider(hw); ++ ++ /* if read only, just return current value */ ++ if (divider->flags & CLK_DIVIDER_READ_ONLY) { ++ bestdiv = readl(divider->reg) >> divider->shift; ++ bestdiv &= div_mask(divider->width); ++ bestdiv = _get_div(divider->table, bestdiv, divider->flags, ++ divider->width); ++ return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); ++ } ++ ++ return divider_round_rate(hw, rate, prate, divider->table, ++ divider->width, divider->flags); ++} ++ ++static int mango_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ unsigned int value; ++ unsigned int val; ++ unsigned long flags = 0; ++ struct mango_clk_divider *divider = to_mango_clk_divider(hw); ++ ++ value = divider_get_val(rate, parent_rate, divider->table, ++ divider->width, divider->flags); ++ ++ if (divider->lock) ++ spin_lock_irqsave(divider->lock, flags); ++ else ++ __acquire(divider->lock); ++ ++ /* div assert */ ++ val = readl(divider->reg); ++ val &= ~0x1; ++ writel(val, divider->reg); ++ ++ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { ++ val = div_mask(divider->width) << (divider->shift + 16); ++ } else { ++ val = readl(divider->reg); ++ val &= ~(div_mask(divider->width) << divider->shift); ++ } ++ ++ val |= value << divider->shift; ++ writel(val, divider->reg); ++ ++ if (!(divider->flags & CLK_DIVIDER_READ_ONLY)) ++ val |= 1 << 3; ++ ++ /* de-assert */ ++ val |= 1; ++ writel(val, divider->reg); ++ if (divider->lock) ++ spin_unlock_irqrestore(divider->lock, flags); ++ else ++ __release(divider->lock); ++ ++ return 0; ++} ++ ++/* Below array is the total combination lists of POSTDIV1 and POSTDIV2 ++ * for example: ++ * postdiv1_20 = {1, 1, 1} ++ * ==> div1 = 1, div2 = 1 , div1 * div2 = 1 ++ * postdiv1_222 = {6, 7, 42} ++ * ==> div1 = 6, div2 = 7 , div1 * div2 = 42 ++ * ++ * And POSTDIV_RESULT_INDEX point to 3rd element in the array ++ */ ++#define POSTDIV_RESULT_INDEX 2 ++int postdiv1_23 = { ++ {2, 4, 8}, {3, 3, 9}, {2, 5, 10}, {2, 6, 12}, ++ {2, 7, 14}, {3, 5, 15}, {4, 4, 16}, {3, 6, 18}, ++ {4, 5, 20}, {3, 7, 21}, {4, 6, 24}, {5, 5, 25}, ++ {4, 7, 28}, {5, 6, 30}, {5, 7, 35}, {6, 6, 36}, ++ {6, 7, 42}, {7, 7, 49} ++}; ++ ++/* ++ * @reg_value: current register value ++ * @parent_rate: parent frequency ++ * ++ * This function is used to calculate below "rate" in equation ++ * rate = (parent_rate/REFDIV) x FBDIV/POSTDIV1/POSTDIV2 ++ * = (parent_rate x FBDIV) / (REFDIV x POSTDIV1 x POSTDIV2) ++ */ ++static unsigned long __pll_recalc_rate(unsigned int reg_value, ++ unsigned long parent_rate) ++{ ++ unsigned int fbdiv, refdiv; ++ unsigned int postdiv1, postdiv2; ++ u64 rate, numerator, denominator; ++ ++ fbdiv = (reg_value >> 16) & 0xfff; ++ refdiv = reg_value & 0x3f; ++ postdiv1 = (reg_value >> 8) & 0x7; ++ postdiv2 = (reg_value >> 12) & 0x7; ++ ++ numerator = parent_rate * fbdiv; ++ denominator = refdiv * postdiv1 * postdiv2; ++ do_div(numerator, denominator); ++ rate = numerator; ++ ++ return rate; ++} ++ ++/* ++ * @reg_value: current register value ++ * @rate: request rate ++ * @prate: parent rate ++ * @pctrl_table: use to save div1/div2/fbdiv/refdiv ++ * ++ * We use below equation to get POSTDIV1 and POSTDIV2 ++ * POSTDIV = (parent_rate/REFDIV) x FBDIV/input_rate ++ * above POSTDIV = POSTDIV1*POSTDIV2 ++ */ ++static int __pll_get_postdiv_1_2(unsigned long rate, unsigned long prate, ++ unsigned int fbdiv, unsigned int refdiv, unsigned int *postdiv1, ++ unsigned int *postdiv2) ++{ ++ int index = 0; ++ int ret = 0; ++ u64 tmp0; ++ ++ /* calculate (parent_rate/refdiv) ++ * and result save to prate ++ */ ++ tmp0 = prate; ++ do_div(tmp0, refdiv); ++ ++ /* calcuate ((parent_rate/REFDIV) x FBDIV) ++ * and result save to prate ++ */ ++ tmp0 *= fbdiv; ++ ++ /* calcuate (((parent_rate/REFDIV) x FBDIV)/input_rate) ++ * and result save to prate ++ * here *prate is (POSTDIV1*POSTDIV2) ++ */ ++ do_div(tmp0, rate); ++ ++ /* calculate div1 and div2 value */ ++ if (tmp0 <= 7) { ++ /* (div1 * div2) <= 7, no need to use array search */ ++ *postdiv1 = tmp0; ++ *postdiv2 = 1; ++ } else { ++ /* (div1 * div2) > 7, use array search */ ++ for (index = 0; index < ARRAY_SIZE(postdiv1_2); index++) { ++ if (tmp0 > postdiv1_2indexPOSTDIV_RESULT_INDEX) { ++ continue; ++ } else { ++ /* found it */ ++ break; ++ } ++ } ++ if (index < ARRAY_SIZE(postdiv1_2)) { ++ *postdiv1 = postdiv1_2index1; ++ *postdiv2 = postdiv1_2index0; ++ } else { ++ pr_debug("%s out of postdiv array range!\n", __func__); ++ ret = -ESPIPE; ++ } ++ } ++ ++ return ret; ++} ++ ++static int __get_pll_ctl_setting(struct mango_pll_ctrl *best, ++ unsigned long req_rate, unsigned long parent_rate) ++{ ++ int ret; ++ unsigned int fbdiv, refdiv, fref, postdiv1, postdiv2; ++ unsigned long tmp = 0, foutvco; ++ ++ fref = parent_rate; ++ ++ for (refdiv = REFDIV_MIN; refdiv < REFDIV_MAX + 1; refdiv++) { ++ for (fbdiv = FBDIV_MIN; fbdiv < FBDIV_MAX + 1; fbdiv++) { ++ foutvco = fref * fbdiv / refdiv; ++ /* check fpostdiv pfd */ ++ if (foutvco < PLL_FREQ_MIN || foutvco > PLL_FREQ_MAX ++ || (fref / refdiv) < 10) ++ continue; ++ ++ ret = __pll_get_postdiv_1_2(req_rate, fref, fbdiv, ++ refdiv, &postdiv1, &postdiv2); ++ if (ret) ++ continue; ++ ++ tmp = foutvco / (postdiv1 * postdiv2); ++ if (abs_diff(tmp, req_rate) < abs_diff(best->freq, req_rate)) { ++ best->freq = tmp; ++ best->refdiv = refdiv; ++ best->fbdiv = fbdiv; ++ best->postdiv1 = postdiv1; ++ best->postdiv2 = postdiv2; ++ if (tmp == req_rate) ++ return 0; ++ } ++ continue; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * @hw: ccf use to hook get mango_pll_clock ++ * @parent_rate: parent rate ++ * ++ * The is function will be called through clk_get_rate ++ * and return current rate after decoding reg value ++ */ ++static unsigned long mango_clk_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ unsigned int value; ++ unsigned long rate; ++ struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw); ++ ++ mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value); ++ rate = __pll_recalc_rate(value, parent_rate); ++ return rate; ++} ++ ++static long mango_clk_pll_round_rate(struct clk_hw *hw, ++ unsigned long req_rate, unsigned long *prate) ++{ ++ unsigned int value; ++ struct mango_pll_ctrl pctrl_table; ++ struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw); ++ long proper_rate; ++ ++ memset(&pctrl_table, 0, sizeof(struct mango_pll_ctrl)); ++ ++ /* use current setting to get fbdiv, refdiv ++ * then combine with prate, and req_rate to ++ * get postdiv1 and postdiv2 ++ */ ++ mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value); ++ __get_pll_ctl_setting(&pctrl_table, req_rate, *prate); ++ if (!pctrl_table.freq) { ++ proper_rate = 0; ++ goto out; ++ } ++ ++ value = TOP_PLL_CTRL(pctrl_table.fbdiv, pctrl_table.postdiv1, ++ pctrl_table.postdiv2, pctrl_table.refdiv); ++ proper_rate = (long)__pll_recalc_rate(value, *prate); ++ ++out: ++ return proper_rate; ++} ++ ++static int mango_clk_pll_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ req->rate = mango_clk_pll_round_rate(hw, min(req->rate, req->max_rate), ++ &req->best_parent_rate); ++ return 0; ++} ++ ++static int mango_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ unsigned long flags; ++ unsigned int value; ++ int ret = 0; ++ struct mango_pll_ctrl pctrl_table; ++ struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw); ++ ++ memset(&pctrl_table, 0, sizeof(struct mango_pll_ctrl)); ++ spin_lock_irqsave(mango_pll->lock, flags); ++ if (mango_pll_enable(mango_pll->syscon_top, mango_pll, 0)) { ++ pr_warn("Can't disable pll(%s), status error\n", mango_pll->name); ++ goto out; ++ } ++ mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value); ++ __get_pll_ctl_setting(&pctrl_table, rate, parent_rate); ++ if (!pctrl_table.freq) { ++ pr_warn("%s: Can't find a proper pll setting\n", mango_pll->name); ++ goto out; ++ } ++ ++ value = TOP_PLL_CTRL(pctrl_table.fbdiv, pctrl_table.postdiv1, ++ pctrl_table.postdiv2, pctrl_table.refdiv); ++ ++ /* write the value to top register */ ++ mango_pll_write(mango_pll->syscon_top, mango_pll->id, value); ++ mango_pll_enable(mango_pll->syscon_top, mango_pll, 1); ++out: ++ spin_unlock_irqrestore(mango_pll->lock, flags); ++ return ret; ++} ++ ++const struct clk_ops mango_clk_divider_ops = { ++ .recalc_rate = mango_clk_divider_recalc_rate, ++ .round_rate = mango_clk_divider_round_rate, ++ .set_rate = mango_clk_divider_set_rate, ++}; ++ ++const struct clk_ops mango_clk_divider_ro_ops = { ++ .recalc_rate = mango_clk_divider_recalc_rate, ++ .round_rate = mango_clk_divider_round_rate, ++}; ++ ++const struct clk_ops mango_clk_pll_ops = { ++ .recalc_rate = mango_clk_pll_recalc_rate, ++ .round_rate = mango_clk_pll_round_rate, ++ .determine_rate = mango_clk_pll_determine_rate, ++ .set_rate = mango_clk_pll_set_rate, ++}; ++ ++const struct clk_ops mango_clk_pll_ro_ops = { ++ .recalc_rate = mango_clk_pll_recalc_rate, ++ .round_rate = mango_clk_pll_round_rate, ++}; ++ ++struct mux_cb_clk_name { ++ const char *name; ++ struct list_head node; ++}; ++ ++static struct list_head mux_cb_clk_name_list = ++ LIST_HEAD_INIT(mux_cb_clk_name_list); ++static int mux_notifier_cb(struct notifier_block *nb, ++ unsigned long event, void *data) ++{ ++ int ret = 0; ++ static unsigned char mux_id = 1; ++ struct clk_notifier_data *ndata = data; ++ struct clk_hw *hw = __clk_get_hw(ndata->clk); ++ const struct clk_ops *ops = &clk_mux_ops; ++ struct mux_cb_clk_name *cb_lsit; ++ ++ if (event == PRE_RATE_CHANGE) { ++ struct clk_hw *hw_p = clk_hw_get_parent(hw); ++ ++ cb_lsit = kmalloc(sizeof(*cb_lsit), GFP_KERNEL); ++ if (cb_lsit) { ++ INIT_LIST_HEAD(&cb_lsit->node); ++ list_add_tail(&cb_lsit->node, &mux_cb_clk_name_list); ++ } else { ++ pr_err("mux cb kmalloc mem fail\n"); ++ goto out; ++ } ++ ++ cb_lsit->name = clk_hw_get_name(hw_p); ++ mux_id = ops->get_parent(hw); ++ if (mux_id > 1) { ++ ret = 1; ++ goto out; ++ } ++ ops->set_parent(hw, !mux_id); ++ } else if (event == POST_RATE_CHANGE) { ++ struct clk_hw *hw_p = clk_hw_get_parent(hw); ++ ++ cb_lsit = list_first_entry_or_null(&mux_cb_clk_name_list, ++ typeof(*cb_lsit), node); ++ if (cb_lsit) { ++ const char *pre_name = cb_lsit->name; ++ ++ list_del_init(&cb_lsit->node); ++ kfree(cb_lsit); ++ if (strcmp(clk_hw_get_name(hw_p), pre_name)) ++ goto out; ++ } ++ ++ ops->set_parent(hw, mux_id); ++ } ++ ++out: ++ return notifier_from_errno(ret); ++} ++ ++int set_default_clk_rates(struct device_node *node) ++{ ++ struct of_phandle_args clkspec; ++ struct property *prop; ++ const __be32 *cur; ++ int rc, index = 0; ++ struct clk *clk; ++ u32 rate; ++ ++ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) { ++ if (rate) { ++ rc = of_parse_phandle_with_args(node, "clocks", ++ "#clock-cells", index, &clkspec); ++ if (rc < 0) { ++ /* skip empty (null) phandles */ ++ if (rc == -ENOENT) ++ continue; ++ else ++ return rc; ++ } ++ ++ clk = of_clk_get_from_provider(&clkspec); ++ if (IS_ERR(clk)) { ++ pr_warn("clk: couldn't get clock %d for %s\n", ++ index, node->full_name); ++ return PTR_ERR(clk); ++ } ++ ++ rc = clk_set_rate(clk, rate); ++ if (rc < 0) ++ pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n", ++ __clk_get_name(clk), rate, rc, ++ clk_get_rate(clk)); ++ clk_put(clk); ++ } ++ index++; ++ } ++ ++ return 0; ++} ++ ++static struct clk *__register_divider_clks(struct device *dev, const char *name, ++ const char *parent_name, ++ unsigned long flags, ++ void __iomem *reg, u8 shift, ++ u8 width, u32 initial_val, ++ u8 clk_divider_flags, ++ const struct clk_div_table *table, ++ spinlock_t *lock) ++{ ++ struct mango_clk_divider *div; ++ struct clk_hw *hw; ++ struct clk_init_data init; ++ int ret; ++ ++ if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { ++ if (width + shift > 16) { ++ pr_warn("divider value exceeds LOWORD field\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ } ++ ++ /* allocate the divider */ ++ div = kzalloc(sizeof(*div), GFP_KERNEL); ++ if (!div) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) ++ init.ops = &mango_clk_divider_ro_ops; ++ else ++ init.ops = &mango_clk_divider_ops; ++ init.flags = flags; ++ init.parent_names = (parent_name ? &parent_name : NULL); ++ init.num_parents = (parent_name ? 1 : 0); ++ ++ /* struct mango_clk_divider assignments */ ++ div->reg = reg; ++ div->shift = shift; ++ div->width = width; ++ div->flags = clk_divider_flags; ++ div->lock = lock; ++ div->hw.init = &init; ++ div->table = table; ++ div->initial_val = initial_val; ++ ++ /* register the clock */ ++ hw = &div->hw; ++ ret = clk_hw_register(dev, hw); ++ if (ret) { ++ kfree(div); ++ hw = ERR_PTR(ret); ++ return ERR_PTR(-EBUSY); ++ } ++ ++ return hw->clk; ++} ++ ++static inline int register_provider_clks ++(struct device_node *node, struct mango_clk_data *clk_data, int clk_num) ++{ ++ return of_clk_add_provider(node, of_clk_src_onecell_get, ++ &clk_data->clk_data); ++} ++ ++static int register_gate_clks(struct device *dev, struct mango_clk_data *clk_data) ++{ ++ struct clk *clk; ++ const struct mango_clk_table *table = clk_data->table; ++ const struct mango_gate_clock *gate_clks = table->gate_clks; ++ void __iomem *base = clk_data->base; ++ int clk_num = table->gate_clks_num; ++ int i; ++ ++ for (i = 0; i < clk_num; i++) { ++ clk = clk_register_gate( ++ dev, gate_clksi.name, gate_clksi.parent_name, ++ gate_clksi.flags, base + gate_clksi.offset, ++ gate_clksi.bit_idx, gate_clksi.gate_flags, ++ &clk_data->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ gate_clksi.name); ++ goto err; ++ } ++ ++ if (gate_clksi.alias) ++ clk_register_clkdev(clk, gate_clksi.alias, NULL); ++ ++ clk_data->clk_data.clksgate_clksi.id = clk; ++ } ++ ++ return 0; ++ ++err: ++ while (i--) ++ clk_unregister_gate(clk_data->clk_data.clksgate_clksi.id); ++ ++ return PTR_ERR(clk); ++} ++ ++static int register_divider_clks(struct device *dev, ++ struct mango_clk_data *clk_data) ++{ ++ struct clk *clk; ++ const struct mango_clk_table *table = clk_data->table; ++ const struct mango_divider_clock *div_clks = table->div_clks; ++ void __iomem *base = clk_data->base; ++ int clk_num = table->div_clks_num; ++ int i, val; ++ ++ for (i = 0; i < clk_num; i++) { ++ clk = __register_divider_clks( ++ NULL, div_clksi.name, div_clksi.parent_name, ++ div_clksi.flags, base + div_clksi.offset, ++ div_clksi.shift, div_clksi.width, ++ div_clksi.initial_val, ++ (div_clksi.initial_sel & MANGO_CLK_USE_INIT_VAL) ? ++ div_clksi.div_flags | CLK_DIVIDER_READ_ONLY : ++ div_clksi.div_flags, ++ div_clksi.table, &clk_data->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ div_clksi.name); ++ goto err; ++ } ++ ++ clk_data->clk_data.clksdiv_clksi.id = clk; ++ ++ if (div_clksi.initial_sel == MANGO_CLK_USE_REG_VAL) { ++ regmap_read(clk_data->syscon_top, div_clksi.offset, ++ &val); ++ ++ /* ++ * set a default divider factor, ++ * clk driver should not select divider clock as the ++ * clock source, before set the divider by right process ++ * (assert div, set div factor, de assert div). ++ */ ++ if (div_clksi.initial_val > 0) ++ val |= (div_clksi.initial_val << 16 | 1 << 3); ++ else { ++ /* ++ * the div register is config to use divider factor, don't change divider ++ */ ++ if (!(val >> 3 & 0x1)) ++ val |= 1 << 16; ++ } ++ ++ regmap_write(clk_data->syscon_top, div_clksi.offset, ++ val); ++ } ++ } ++ ++ return 0; ++ ++err: ++ while (i--) ++ clk_unregister_divider(clk_data->clk_data.clksdiv_clksi.id); ++ ++ return PTR_ERR(clk); ++} ++ ++static int register_mux_clks(struct device *dev, struct mango_clk_data *clk_data) ++{ ++ struct clk *clk; ++ const struct mango_clk_table *table = clk_data->table; ++ const struct mango_mux_clock *mux_clks = table->mux_clks; ++ void __iomem *base = clk_data->base; ++ int clk_num = table->mux_clks_num; ++ int i; ++ ++ for (i = 0; i < clk_num; i++) { ++ u32 mask = BIT(mux_clksi.width) - 1; ++ ++ clk = clk_register_mux_table( ++ dev, mux_clksi.name, mux_clksi.parent_names, ++ mux_clksi.num_parents, mux_clksi.flags, ++ base + mux_clksi.offset, mux_clksi.shift, mask, ++ mux_clksi.mux_flags, mux_clksi.table, ++ &clk_data->lock); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ mux_clksi.name); ++ goto err; ++ } ++ ++ clk_data->clk_data.clksmux_clksi.id = clk; ++ ++ if (!(mux_clksi.flags & CLK_MUX_READ_ONLY)) { ++ struct clk *parent; ++ struct notifier_block *clk_nb; ++ ++ /* set mux clock default parent here, it's parent index ++ * value is read from the mux clock reg. dts can override ++ * setting the mux clock parent later. ++ */ ++ parent = clk_get_parent(clk); ++ clk_set_parent(clk, parent); ++ ++ /* add a notify callback function */ ++ clk_nb = kzalloc(sizeof(*clk_nb), GFP_KERNEL); ++ if (!clk_nb) ++ goto err; ++ clk_nb->notifier_call = mux_notifier_cb; ++ if (clk_notifier_register(clk, clk_nb)) ++ pr_err("%s: failed to register clock notifier for %s\n", ++ __func__, mux_clksi.name); ++ } ++ } ++ ++ return 0; ++ ++err: ++ while (i--) ++ clk_unregister_mux(clk_data->clk_data.clksmux_clksi.id); ++ ++ return PTR_ERR(clk); ++} ++ ++/* pll clock init */ ++int mango_register_pll_clks(struct device_node *node, ++ struct mango_clk_data *clk_data, const char *clk_name) ++{ ++ struct clk *clk = NULL; ++ struct mango_pll_clock *pll_clks; ++ int i, ret = 0; ++ const struct clk_ops *local_ops; ++ ++ pll_clks = (struct mango_pll_clock *)clk_data->table->pll_clks; ++ for (i = 0; i < clk_data->table->pll_clks_num; i++) { ++ if (!strcmp(clk_name, pll_clksi.name)) { ++ /* have to assigne pll_clks.syscon_top first ++ * since clk_register_composite will need it ++ * to calculate current rate. ++ */ ++ pll_clksi.syscon_top = clk_data->syscon_top; ++ pll_clksi.lock = &clk_data->lock; ++ if (pll_clksi.ini_flags & MANGO_CLK_RO) ++ local_ops = &mango_clk_pll_ro_ops; ++ else ++ local_ops = &mango_clk_pll_ops; ++ clk = clk_register_composite( ++ NULL, pll_clksi.name, &pll_clksi.parent_name, ++ 1, NULL, NULL, &pll_clksi.hw, local_ops, ++ NULL, NULL, pll_clksi.flags); ++ ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register clock %s\n", __func__, ++ pll_clksi.name); ++ ret = -EINVAL; ++ goto out; ++ } ++ ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); ++ if (ret) ++ clk_unregister(clk); ++ } else { ++ continue; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++/* mux clk init */ ++int mango_register_mux_clks(struct device_node *node, struct mango_clk_data *clk_data) ++{ ++ int ret; ++ int count; ++ struct clk **clk_table; ++ ++ count = clk_data->table->mux_clks_num + clk_data->table->gate_clks_num; ++ clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL); ++ if (!clk_table) ++ return -ENOMEM; ++ ++ clk_data->clk_data.clks = clk_table; ++ clk_data->clk_data.clk_num = count; ++ ++ ret = register_mux_clks(NULL, clk_data); ++ if (ret) ++ goto err; ++ ++ ret = register_gate_clks(NULL, clk_data); ++ if (ret) ++ goto err; ++ ++ ret = register_provider_clks(node, clk_data, count); ++ if (ret) ++ goto err; ++ ++ return 0; ++err: ++ kfree(clk_table); ++ return ret; ++} ++ ++/* pll divider init */ ++int mango_register_div_clks(struct device_node *node, struct mango_clk_data *clk_data) ++{ ++ int ret; ++ int count; ++ ++ struct clk **clk_table; ++ ++ count = clk_data->table->div_clks_num + clk_data->table->gate_clks_num; ++ clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL); ++ if (!clk_table) ++ return -ENOMEM; ++ ++ clk_data->clk_data.clks = clk_table; ++ clk_data->clk_data.clk_num = count; ++ ++ ret = register_divider_clks(NULL, clk_data); ++ if (ret) ++ goto err; ++ ++ ret = register_gate_clks(NULL, clk_data); ++ if (ret) ++ goto err; ++ ++ ret = register_provider_clks(node, clk_data, count); ++ if (ret) ++ goto err; ++ ++ ++ return 0; ++err: ++ kfree(clk_table); ++ pr_err("%s error %d\n", __func__, ret); ++ return ret; ++} +diff --git a/drivers/clk/sophgo/clk.h b/drivers/clk/sophgo/clk.h +new file mode 100644 +index 000000000000..81e9f9eb1b20 +--- /dev/null ++++ b/drivers/clk/sophgo/clk.h +@@ -0,0 +1,152 @@ ++#ifndef __SOPHGO_CLOCK__ ++#define __SOPHGO_CLOCK__ ++ ++#include <linux/regmap.h> ++#include <linux/slab.h> ++#include <linux/clk.h> ++#include <linux/clk-provider.h> ++#include <linux/device.h> ++#include <linux/clkdev.h> ++ ++#include <dt-bindings/clock/sophgo.h> ++ ++#define KHZ 1000L ++#define MHZ (KHZ * KHZ) ++ ++#define MANGO_CLK_USE_INIT_VAL BIT(0) /* use default value */ ++#define MANGO_CLK_USE_REG_VAL BIT(1) /* use reg divider value */ ++#define MANGO_CLK_RO BIT(2) /* use reg divider value */ ++ ++#define CLK_PLL BIT(0) ++#define CLK_MUX BIT(1) ++ ++#define PLL_CTRL_OFFSET 0xE8 ++#define PLL_STAT_LOCK_OFFSET 0x8 ++#define CLK_MODE 0x4 ++#define CLK_MODE_MASK 0x3 ++ ++#define REFDIV_MIN 1 ++#define REFDIV_MAX 64 ++#define FBDIV_MIN 16 ++#define FBDIV_MAX 321 ++ ++#define PLL_FREQ_MIN (16 * MHZ) ++#define PLL_FREQ_MAX (3200 * MHZ) ++ ++#define div_mask(width) ((1 << (width)) - 1) ++#define TOP_PLL_CTRL(fbdiv, p1, p2, refdiv) \ ++ (((fbdiv & 0xfff) << 16) | ((p2 & 0x7) << 12) | ((p1 & 0x7) << 8) | (refdiv & 0x3f)) ++ ++struct mango_pll_ctrl { ++ unsigned int mode; ++ unsigned long freq; ++ ++ unsigned int fbdiv; ++ unsigned int postdiv1; ++ unsigned int postdiv2; ++ unsigned int refdiv; ++}; ++ ++struct mango_pll_clock { ++ unsigned int id; ++ char *name; ++ const char *parent_name; ++ unsigned long flags; ++ struct clk_hw hw; ++ struct regmap *syscon_top; ++ ++ /* Below lock used to protect PLL top register during write */ ++ spinlock_t *lock; ++ u32 ini_flags; ++ ++ u32 status_offset; ++ u32 enable_offset; ++ ++ struct mango_pll_ctrl pctrl_table4; ++}; ++ ++#define to_mango_pll_clk(_hw) container_of(_hw, struct mango_pll_clock, hw) ++ ++#define to_mango_clk_divider(_hw) \ ++ container_of(_hw, struct mango_clk_divider, hw) ++ ++#define to_mango_clk_mux(nb) \ ++ container_of(nb, struct mango_mux_clock, clk_nb) ++ ++struct mango_divider_clock { ++ unsigned int id; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ unsigned long offset; ++ u8 shift; ++ u8 width; ++ u8 div_flags; ++ u32 initial_sel; ++ u32 initial_val; ++ struct clk_div_table *table; ++}; ++ ++struct mango_mux_clock { ++ unsigned int id; ++ const char *name; ++ const char *const *parent_names; ++ u8 num_parents; ++ unsigned long flags; ++ unsigned long offset; ++ u8 shift; ++ u8 width; ++ u8 mux_flags; ++ u32 *table; ++ ++ struct notifier_block clk_nb; ++}; ++ ++struct mango_gate_clock { ++ unsigned int id; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ unsigned long offset; ++ u8 bit_idx; ++ u8 gate_flags; ++ const char *alias; ++}; ++ ++struct mango_clk_table { ++ u32 id; ++ u32 pll_clks_num; ++ u32 div_clks_num; ++ u32 gate_clks_num; ++ u32 mux_clks_num; ++ ++ const struct mango_pll_clock *pll_clks; ++ const struct mango_divider_clock *div_clks; ++ const struct mango_gate_clock *gate_clks; ++ const struct mango_mux_clock *mux_clks; ++}; ++ ++struct mango_clk_data { ++ void __iomem *base; ++ spinlock_t lock; ++ struct regmap *syscon_top; ++ struct clk_onecell_data clk_data; ++ const struct mango_clk_table *table; ++}; ++ ++int mango_register_mux_clks ++(struct device_node *node, struct mango_clk_data *clk_data); ++int mango_register_div_clks ++(struct device_node *node, struct mango_clk_data *clk_data); ++int mango_register_pll_clks ++(struct device_node *node, struct mango_clk_data *clk_data, const char *clk_name); ++int set_default_clk_rates(struct device_node *node); ++ ++int dm_mango_register_mux_clks ++(struct device_node *node, struct mango_clk_data *clk_data); ++int dm_mango_register_div_clks ++(struct device_node *node, struct mango_clk_data *clk_data); ++int dm_mango_register_pll_clks ++(struct device_node *node, struct mango_clk_data *clk_data, const char *name); ++int dm_set_default_clk_rates(struct device_node *node); ++#endif +diff --git a/drivers/clk/thead/Kconfig b/drivers/clk/thead/Kconfig +new file mode 100644 +index 000000000000..4fa0021a195d +--- /dev/null ++++ b/drivers/clk/thead/Kconfig +@@ -0,0 +1,19 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++config THEAD_CLK ++ bool ++ def_bool ARCH_THEAD ++ ++config CLK_LIGHT_MPW ++ bool "Thead Light MPW Clock Driver" ++ depends on ARCH_THEAD ++ default n ++ help ++ Build the driver for light mpw Clock Driver ++ ++config CLK_LIGHT_FM ++ bool "Thead Light Fullmask Clock Driver" ++ depends on ARCH_THEAD ++ default n ++ help ++ Build the driver for light fullmask Clock Driver +diff --git a/drivers/clk/thead/Makefile b/drivers/clk/thead/Makefile +new file mode 100644 +index 000000000000..24a349f91989 +--- /dev/null ++++ b/drivers/clk/thead/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++obj-$(CONFIG_THEAD_CLK) += \ ++ clk.o ++ ++obj-$(CONFIG_CLK_LIGHT_MPW) += clk-light-mpw.o ++obj-$(CONFIG_CLK_LIGHT_FM) += clk-light-fm.o ++obj-$(CONFIG_CLK_LIGHT_FM) += gate/ +diff --git a/drivers/clk/thead/clk-light-fm.c b/drivers/clk/thead/clk-light-fm.c +new file mode 100644 +index 000000000000..2fe47c063a53 +--- /dev/null ++++ b/drivers/clk/thead/clk-light-fm.c +@@ -0,0 +1,646 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <dt-bindings/clock/light-fm-ap-clock.h> ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/types.h> ++ ++#include "clk.h" ++ ++static struct clk *clksCLK_END; ++static struct clk_onecell_data clk_data; ++ ++/* Light Fullmask */ ++static u32 share_cnt_x2h_cpusys_clk_en; ++static u32 share_cnt_dmac_cpusys_clk_en; ++static u32 share_cnt_timer0_clk_en; ++static u32 share_cnt_timer1_clk_en; ++static u32 share_cnt_axi4_cpusys2_clk_en; ++static u32 share_cnt_bmu_c910_clk_en; ++static u32 share_cnt_aon2cpu_a2x_clk_en; ++static u32 share_cnt_chip_dbg_clk_en; ++static u32 share_cnt_x2x_cpusys_clk_en; ++static u32 share_cnt_cfg2tee_x2h_clk_en; ++static u32 share_cnt_cpu2aon_x2h_clk_en; ++static u32 share_cnt_cpu2vp_x2p_clk_en; ++static u32 share_cnt_npu_core_clk_en; ++static u32 share_cnt_cpu2peri_x2h_clk_en; ++static u32 share_cnt_cpu2vi_x2h_clk_en; ++static u32 share_cnt_vpsys_axi_aclk_en; ++static u32 share_cnt_gmac1_clk_en; ++static u32 share_cnt_gmac0_clk_en; ++static u32 share_cnt_perisys_apb3_hclk_en; ++static u32 share_cnt_qspi0_clk_en; ++static u32 share_cnt_gmac_axi_clk_en; ++static u32 share_cnt_gpio0_clk_en; ++static u32 share_cnt_gpio1_clk_en; ++static u32 share_cnt_pwm_clk_en; ++static u32 share_cnt_spi_clk_en; ++static u32 share_cnt_uart0_clk_en; ++static u32 share_cnt_uart2_clk_en; ++static u32 share_cnt_i2c2_clk_en; ++static u32 share_cnt_peri_i2s_clk_en; ++static u32 share_cnt_qspi1_clk_en; ++static u32 share_cnt_uart1_clk_en; ++static u32 share_cnt_uart3_clk_en; ++static u32 share_cnt_uart4_clk_en; ++static u32 share_cnt_uart5_clk_en; ++static u32 share_cnt_i2c0_clk_en; ++static u32 share_cnt_i2c1_clk_en; ++static u32 share_cnt_i2c4_clk_en; ++static u32 share_cnt_i2c5_clk_en; ++static u32 share_cnt_gpio2_clk_en; ++static u32 share_cnt_gpio3_clk_en; ++static u32 share_cnt_vosys_axi_aclk_en; ++ ++/* Light Fullmask PLL Bypass */ ++static const char * const cpu_pll0_bypass_sels = {"cpu_pll0_foutpostdiv", "osc_24m", }; ++static const char * const cpu_pll1_bypass_sels = {"cpu_pll1_foutpostdiv", "osc_24m", }; ++static const char * const gmac_pll_bypass_sels = {"gmac_pll_foutpostdiv", "osc_24m", }; ++static const char * const video_pll_bypass_sels = {"video_pll_foutpostdiv", "osc_24m", }; ++static const char * const tee_pll_bypass_sels = {"tee_pll_foutpostdiv", "osc_24m"}; ++static const char * const dpu0_pll_bypass_sels = {"dpu0_pll_foutpostdiv", "osc_24m"}; ++static const char * const dpu1_pll_bypass_sels = {"dpu1_pll_foutpostdiv", "osc_24m"}; ++ ++/* light fullmask mux */ ++static const char * const ahb2_cpusys_hclk_sels = {"ahb2_cpusys_hclk_out_div", "osc_24m"}; ++static const char * const c910_cclk_i0_sels = {"cpu_pll0_foutpostdiv", "osc_24m"}; ++static const char * const c910_cclk_sels = {"c910_cclk_i0", "cpu_pll1_foutpostdiv"}; ++static const char * const cfg_axi_aclk_sels = {"cfg_axi_aclk_out_div", "osc_24m"}; ++static const char * const teesys_hclk_sels = {"teesys_i1_hclk", "teesys_i0_hclk"}; ++static const char * const perisys_ahb_hclk_sels = {"perisys_ahb_hclk_out_div", "osc_24m"}; ++static const char * const clk_out_1_sels = {"osc_24m", "clk_out_1_out_div"}; ++static const char * const clk_out_2_sels = {"osc_24m", "clk_out_2_out_div"}; ++static const char * const clk_out_3_sels = {"osc_24m", "clk_out_3_out_div"}; ++static const char * const clk_out_4_sels = {"osc_24m", "clk_out_4_out_div"}; ++static const char * const peri_i2s_src_clk_sels = {"clkgen_peri_i2s_src_clk_0", "clkgen_peri_i2s_src_clk_1"}; ++static const char * const npu_cclk_sels = {"gmac_pll_foutpostdiv", "npu_cclk_out_div"}; ++static const char * const cfg_apb_pclk_sels = {"cfg_apb_pclk_out_div", "osc_24m"}; ++static const char * const uart_sclk_sels = {"clk_100m", "osc_24m"}; ++ ++static const struct light_pll_rate_table light_cpupll_tbl = { ++ LIGHT_PLL_RATE(2616000000U, 2616000000U, 1, 109, 0, 1, 1), ++ LIGHT_PLL_RATE(2592000000U, 2592000000U, 1, 108, 0, 1, 1), ++ LIGHT_PLL_RATE(2568000000U, 2568000000U, 1, 107, 0, 1, 1), ++ LIGHT_PLL_RATE(2544000000U, 2544000000U, 1, 106, 0, 1, 1), ++ LIGHT_PLL_RATE(2520000000U, 2520000000U, 1, 105, 0, 1, 1), ++ LIGHT_PLL_RATE(2496000000U, 2496000000U, 1, 104, 0, 1, 1), ++ LIGHT_PLL_RATE(2472000000U, 2472000000U, 1, 103, 0, 1, 1), ++ LIGHT_PLL_RATE(2448000000U, 2448000000U, 1, 102, 0, 1, 1), ++ LIGHT_PLL_RATE(2424000000U, 2424000000U, 1, 101, 0, 1, 1), ++ LIGHT_PLL_RATE(2400000000U, 2400000000U, 1, 100, 0, 1, 1), ++ LIGHT_PLL_RATE(2376000000U, 2376000000U, 1, 99, 0, 1, 1), ++ LIGHT_PLL_RATE(2352000000U, 2352000000U, 1, 98, 0, 1, 1), ++ LIGHT_PLL_RATE(2328000000U, 2328000000U, 1, 97, 0, 1, 1), ++ LIGHT_PLL_RATE(2304000000U, 2304000000U, 1, 96, 0, 1, 1), ++ LIGHT_PLL_RATE(2280000000U, 2280000000U, 1, 95, 0, 1, 1), ++ LIGHT_PLL_RATE(2256000000U, 2256000000U, 1, 94, 0, 1, 1), ++ LIGHT_PLL_RATE(2232000000U, 2232000000U, 1, 93, 0, 1, 1), ++ LIGHT_PLL_RATE(2208000000U, 2208000000U, 1, 92, 0, 1, 1), ++ LIGHT_PLL_RATE(2184000000U, 2184000000U, 1, 91, 0, 1, 1), ++ LIGHT_PLL_RATE(2160000000U, 2160000000U, 1, 90, 0, 1, 1), ++ LIGHT_PLL_RATE(2136000000U, 2136000000U, 1, 89, 0, 1, 1), ++ LIGHT_PLL_RATE(2112000000U, 2112000000U, 1, 88, 0, 1, 1), ++ LIGHT_PLL_RATE(2088000000U, 2088000000U, 1, 87, 0, 1, 1), ++ LIGHT_PLL_RATE(2064000000U, 2064000000U, 1, 86, 0, 1, 1), ++ LIGHT_PLL_RATE(2040000000U, 2040000000U, 1, 85, 0, 1, 1), ++ LIGHT_PLL_RATE(2016000000U, 2016000000U, 1, 84, 0, 1, 1), ++ LIGHT_PLL_RATE(1992000000U, 1992000000U, 1, 83, 0, 1, 1), ++ LIGHT_PLL_RATE(1968000000U, 1968000000U, 1, 82, 0, 1, 1), ++ LIGHT_PLL_RATE(1944000000U, 1944000000U, 1, 81, 0, 1, 1), ++ LIGHT_PLL_RATE(1920000000U, 1920000000U, 1, 80, 0, 1, 1), ++ LIGHT_PLL_RATE(1896000000U, 1896000000U, 1, 79, 0, 1, 1), ++ LIGHT_PLL_RATE(1872000000U, 1872000000U, 1, 78, 0, 1, 1), ++ LIGHT_PLL_RATE(1848000000U, 1848000000U, 1, 77, 0, 1, 1), ++ LIGHT_PLL_RATE(1824000000U, 1824000000U, 1, 76, 0, 1, 1), ++ LIGHT_PLL_RATE(1800000000U, 1800000000U, 1, 75, 0, 1, 1), ++ LIGHT_PLL_RATE(1776000000U, 1776000000U, 1, 74, 0, 1, 1), ++ LIGHT_PLL_RATE(1752000000U, 1752000000U, 1, 73, 0, 1, 1), ++ LIGHT_PLL_RATE(1728000000U, 1728000000U, 1, 72, 0, 1, 1), ++ LIGHT_PLL_RATE(1704000000U, 1704000000U, 1, 71, 0, 1, 1), ++ LIGHT_PLL_RATE(1680000000U, 1680000000U, 1, 70, 0, 1, 1), ++ LIGHT_PLL_RATE(1656000000U, 1656000000U, 1, 69, 0, 1, 1), ++ LIGHT_PLL_RATE(1632000000U, 1632000000U, 1, 68, 0, 1, 1), ++ LIGHT_PLL_RATE(1608000000U, 1608000000U, 1, 67, 0, 1, 1), ++ LIGHT_PLL_RATE(1584000000U, 1584000000U, 1, 66, 0, 1, 1), ++ LIGHT_PLL_RATE(1560000000U, 1560000000U, 1, 65, 0, 1, 1), ++ LIGHT_PLL_RATE(1536000000U, 1536000000U, 1, 64, 0, 1, 1), ++ LIGHT_PLL_RATE(1512000000U, 1512000000U, 1, 63, 0, 1, 1), ++ LIGHT_PLL_RATE(3000000000U, 1500000000U, 1, 125, 0, 2, 1), ++ LIGHT_PLL_RATE(2976000000U, 1488000000U, 1, 124, 0, 2, 1), ++ LIGHT_PLL_RATE(2952000000U, 1476000000U, 1, 123, 0, 2, 1), ++ LIGHT_PLL_RATE(2928000000U, 1464000000U, 1, 122, 0, 2, 1), ++ LIGHT_PLL_RATE(2904000000U, 1452000000U, 1, 121, 0, 2, 1), ++ LIGHT_PLL_RATE(2880000000U, 1440000000U, 1, 120, 0, 2, 1), ++ LIGHT_PLL_RATE(2856000000U, 1428000000U, 1, 119, 0, 2, 1), ++ LIGHT_PLL_RATE(2832000000U, 1416000000U, 1, 118, 0, 2, 1), ++ LIGHT_PLL_RATE(2808000000U, 1404000000U, 1, 117, 0, 2, 1), ++ LIGHT_PLL_RATE(2784000000U, 1392000000U, 1, 116, 0, 2, 1), ++ LIGHT_PLL_RATE(2760000000U, 1380000000U, 1, 115, 0, 2, 1), ++ LIGHT_PLL_RATE(2736000000U, 1368000000U, 1, 114, 0, 2, 1), ++ LIGHT_PLL_RATE(2712000000U, 1356000000U, 1, 113, 0, 2, 1), ++ LIGHT_PLL_RATE(2688000000U, 1344000000U, 1, 112, 0, 2, 1), ++ LIGHT_PLL_RATE(2664000000U, 1332000000U, 1, 111, 0, 2, 1), ++ LIGHT_PLL_RATE(2640000000U, 1320000000U, 1, 110, 0, 2, 1), ++ LIGHT_PLL_RATE(2616000000U, 1308000000U, 1, 109, 0, 2, 1), ++ LIGHT_PLL_RATE(2592000000U, 1296000000U, 1, 108, 0, 2, 1), ++ LIGHT_PLL_RATE(2568000000U, 1284000000U, 1, 107, 0, 2, 1), ++ LIGHT_PLL_RATE(2544000000U, 1272000000U, 1, 106, 0, 2, 1), ++ LIGHT_PLL_RATE(2520000000U, 1260000000U, 1, 105, 0, 2, 1), ++ LIGHT_PLL_RATE(2496000000U, 1248000000U, 1, 104, 0, 2, 1), ++ LIGHT_PLL_RATE(2472000000U, 1236000000U, 1, 103, 0, 2, 1), ++ LIGHT_PLL_RATE(2448000000U, 1224000000U, 1, 102, 0, 2, 1), ++ LIGHT_PLL_RATE(2424000000U, 1212000000U, 1, 101, 0, 2, 1), ++ LIGHT_PLL_RATE(2400000000U, 1200000000U, 1, 100, 0, 2, 1), ++ LIGHT_PLL_RATE(2376000000U, 1188000000U, 1, 99, 0, 2, 1), ++ LIGHT_PLL_RATE(2352000000U, 1176000000U, 1, 98, 0, 2, 1), ++ LIGHT_PLL_RATE(2328000000U, 1164000000U, 1, 97, 0, 2, 1), ++ LIGHT_PLL_RATE(2304000000U, 1152000000U, 1, 96, 0, 2, 1), ++ LIGHT_PLL_RATE(2280000000U, 1140000000U, 1, 95, 0, 2, 1), ++ LIGHT_PLL_RATE(2256000000U, 1128000000U, 1, 94, 0, 2, 1), ++ LIGHT_PLL_RATE(2232000000U, 1116000000U, 1, 93, 0, 2, 1), ++ LIGHT_PLL_RATE(2208000000U, 1104000000U, 1, 92, 0, 2, 1), ++ LIGHT_PLL_RATE(2184000000U, 1092000000U, 1, 91, 0, 2, 1), ++ LIGHT_PLL_RATE(2160000000U, 1080000000U, 1, 90, 0, 2, 1), ++ LIGHT_PLL_RATE(2136000000U, 1068000000U, 1, 89, 0, 2, 1), ++ LIGHT_PLL_RATE(2112000000U, 1056000000U, 1, 88, 0, 2, 1), ++ LIGHT_PLL_RATE(2088000000U, 1044000000U, 1, 87, 0, 2, 1), ++ LIGHT_PLL_RATE(2064000000U, 1032000000U, 1, 86, 0, 2, 1), ++ LIGHT_PLL_RATE(2040000000U, 1020000000U, 1, 85, 0, 2, 1), ++ LIGHT_PLL_RATE(2016000000U, 1008000000U, 1, 84, 0, 2, 1), ++ LIGHT_PLL_RATE(3000000000U, 1000000000U, 1, 125, 0, 3, 1), ++ LIGHT_PLL_RATE(2976000000U, 992000000U, 1, 124, 0, 3, 1), ++ LIGHT_PLL_RATE(2952000000U, 984000000U, 1, 123, 0, 3, 1), ++ LIGHT_PLL_RATE(2928000000U, 976000000U, 1, 122, 0, 3, 1), ++ LIGHT_PLL_RATE(2904000000U, 968000000U, 1, 121, 0, 3, 1), ++ LIGHT_PLL_RATE(2880000000U, 960000000U, 1, 120, 0, 3, 1), ++ LIGHT_PLL_RATE(2856000000U, 952000000U, 1, 119, 0, 3, 1), ++ LIGHT_PLL_RATE(2832000000U, 944000000U, 1, 118, 0, 3, 1), ++ LIGHT_PLL_RATE(2808000000U, 936000000U, 1, 117, 0, 3, 1), ++ LIGHT_PLL_RATE(2784000000U, 928000000U, 1, 116, 0, 3, 1), ++ LIGHT_PLL_RATE(2760000000U, 920000000U, 1, 115, 0, 3, 1), ++ LIGHT_PLL_RATE(2736000000U, 912000000U, 1, 114, 0, 3, 1), ++ LIGHT_PLL_RATE(2712000000U, 904000000U, 1, 113, 0, 3, 1), ++ LIGHT_PLL_RATE(1800000000U, 900000000U, 1, 75, 0, 2, 1), ++ LIGHT_PLL_RATE(2688000000U, 896000000U, 1, 112, 0, 3, 1), ++ LIGHT_PLL_RATE(2664000000U, 888000000U, 1, 111, 0, 3, 1), ++ LIGHT_PLL_RATE(2640000000U, 880000000U, 1, 110, 0, 3, 1), ++ LIGHT_PLL_RATE(2616000000U, 872000000U, 1, 109, 0, 3, 1), ++ LIGHT_PLL_RATE(2592000000U, 864000000U, 1, 108, 0, 3, 1), ++ LIGHT_PLL_RATE(2568000000U, 856000000U, 1, 107, 0, 3, 1), ++ LIGHT_PLL_RATE(2544000000U, 848000000U, 1, 106, 0, 3, 1), ++ LIGHT_PLL_RATE(2520000000U, 840000000U, 1, 105, 0, 3, 1), ++ LIGHT_PLL_RATE(2496000000U, 832000000U, 1, 104, 0, 3, 1), ++ LIGHT_PLL_RATE(2472000000U, 824000000U, 1, 103, 0, 3, 1), ++ LIGHT_PLL_RATE(2448000000U, 816000000U, 1, 102, 0, 3, 1), ++ LIGHT_PLL_RATE(2424000000U, 808000000U, 1, 101, 0, 3, 1), ++ LIGHT_PLL_RATE(2400000000U, 800000000U, 1, 100, 0, 3, 1), ++ LIGHT_PLL_RATE(2376000000U, 792000000U, 1, 99, 0, 3, 1), ++ LIGHT_PLL_RATE(2352000000U, 784000000U, 1, 98, 0, 3, 1), ++ LIGHT_PLL_RATE(2328000000U, 776000000U, 1, 97, 0, 3, 1), ++ LIGHT_PLL_RATE(2304000000U, 768000000U, 1, 96, 0, 3, 1), ++ LIGHT_PLL_RATE(2280000000U, 760000000U, 1, 95, 0, 3, 1), ++ LIGHT_PLL_RATE(2256000000U, 752000000U, 1, 94, 0, 3, 1), ++ LIGHT_PLL_RATE(2232000000U, 744000000U, 1, 93, 0, 3, 1), ++ LIGHT_PLL_RATE(2208000000U, 736000000U, 1, 92, 0, 3, 1), ++ LIGHT_PLL_RATE(2184000000U, 728000000U, 1, 91, 0, 3, 1), ++ LIGHT_PLL_RATE(2160000000U, 720000000U, 1, 90, 0, 3, 1), ++ LIGHT_PLL_RATE(2136000000U, 712000000U, 1, 89, 0, 3, 1), ++ LIGHT_PLL_RATE(2808000000U, 702000000U, 1, 117, 0, 4, 1), ++ LIGHT_PLL_RATE(2760000000U, 690000000U, 1, 115, 0, 4, 1), ++ LIGHT_PLL_RATE(2712000000U, 678000000U, 1, 113, 0, 4, 1), ++ LIGHT_PLL_RATE(2664000000U, 666000000U, 1, 111, 0, 4, 1), ++ LIGHT_PLL_RATE(2616000000U, 654000000U, 1, 109, 0, 4, 1), ++ LIGHT_PLL_RATE(2568000000U, 642000000U, 1, 107, 0, 4, 1), ++ LIGHT_PLL_RATE(2520000000U, 630000000U, 1, 105, 0, 4, 1), ++ LIGHT_PLL_RATE(2472000000U, 618000000U, 1, 103, 0, 4, 1), ++ LIGHT_PLL_RATE(2424000000U, 606000000U, 1, 101, 0, 4, 1), ++ LIGHT_PLL_RATE(3000000000U, 600000000U, 1, 125, 0, 5, 1), ++ LIGHT_PLL_RATE(2952000000U, 590400000U, 1, 123, 0, 5, 1), ++ LIGHT_PLL_RATE(2904000000U, 580800000U, 1, 121, 0, 5, 1), ++ LIGHT_PLL_RATE(2856000000U, 571200000U, 1, 119, 0, 5, 1), ++ LIGHT_PLL_RATE(2808000000U, 561600000U, 1, 117, 0, 5, 1), ++ LIGHT_PLL_RATE(2760000000U, 552000000U, 1, 115, 0, 5, 1), ++ LIGHT_PLL_RATE(2712000000U, 542400000U, 1, 113, 0, 5, 1), ++ LIGHT_PLL_RATE(2664000000U, 532800000U, 1, 111, 0, 5, 1), ++ LIGHT_PLL_RATE(2616000000U, 523200000U, 1, 109, 0, 5, 1), ++ LIGHT_PLL_RATE(2568000000U, 513600000U, 1, 107, 0, 5, 1), ++ LIGHT_PLL_RATE(2520000000U, 504000000U, 1, 105, 0, 5, 1), ++ LIGHT_PLL_RATE(3000000000U, 500000000U, 1, 125, 0, 6, 1), ++ LIGHT_PLL_RATE(2952000000U, 492000000U, 1, 123, 0, 6, 1), ++ LIGHT_PLL_RATE(2904000000U, 484000000U, 1, 121, 0, 6, 1), ++ LIGHT_PLL_RATE(2856000000U, 476000000U, 1, 119, 0, 6, 1), ++ LIGHT_PLL_RATE(2808000000U, 468000000U, 1, 117, 0, 6, 1), ++ LIGHT_PLL_RATE(2760000000U, 460000000U, 1, 115, 0, 6, 1), ++ LIGHT_PLL_RATE(2712000000U, 452000000U, 1, 113, 0, 6, 1), ++ LIGHT_PLL_RATE(2664000000U, 444000000U, 1, 111, 0, 6, 1), ++ LIGHT_PLL_RATE(2616000000U, 436000000U, 1, 109, 0, 6, 1), ++ LIGHT_PLL_RATE(2568000000U, 428000000U, 1, 107, 0, 6, 1), ++ LIGHT_PLL_RATE(2520000000U, 420000000U, 1, 105, 0, 6, 1), ++ LIGHT_PLL_RATE(2472000000U, 412000000U, 1, 103, 0, 6, 1), ++ LIGHT_PLL_RATE(2400000000U, 400000000U, 1, 100, 0, 3, 2), ++ LIGHT_PLL_RATE(2352000000U, 392000000U, 1, 98, 0, 3, 2), ++ LIGHT_PLL_RATE(2304000000U, 384000000U, 1, 96, 0, 3, 2), ++ LIGHT_PLL_RATE(2256000000U, 376000000U, 1, 94, 0, 3, 2), ++ LIGHT_PLL_RATE(2208000000U, 368000000U, 1, 92, 0, 3, 2), ++ LIGHT_PLL_RATE(2160000000U, 360000000U, 1, 90, 0, 3, 2), ++ LIGHT_PLL_RATE(2112000000U, 352000000U, 1, 88, 0, 3, 2), ++ LIGHT_PLL_RATE(2064000000U, 344000000U, 1, 86, 0, 3, 2), ++ LIGHT_PLL_RATE(2016000000U, 336000000U, 1, 84, 0, 3, 2), ++ LIGHT_PLL_RATE(1968000000U, 328000000U, 1, 82, 0, 3, 2), ++ LIGHT_PLL_RATE(1920000000U, 320000000U, 1, 80, 0, 3, 2), ++ LIGHT_PLL_RATE(1872000000U, 312000000U, 1, 78, 0, 3, 2), ++ LIGHT_PLL_RATE(1824000000U, 304000000U, 1, 76, 0, 3, 2), ++ LIGHT_PLL_RATE(3000000000U, 300000000U, 1, 125, 0, 5, 2), ++ LIGHT_PLL_RATE(2880000000U, 288000000U, 1, 120, 0, 5, 2), ++ LIGHT_PLL_RATE(2760000000U, 276000000U, 1, 115, 0, 5, 2), ++ LIGHT_PLL_RATE(2640000000U, 264000000U, 1, 110, 0, 5, 2), ++ LIGHT_PLL_RATE(2520000000U, 252000000U, 1, 105, 0, 5, 2), ++ LIGHT_PLL_RATE(2400000000U, 240000000U, 1, 100, 0, 5, 2), ++ LIGHT_PLL_RATE(2280000000U, 228000000U, 1, 95, 0, 5, 2), ++ LIGHT_PLL_RATE(2160000000U, 216000000U, 1, 90, 0, 5, 2), ++ LIGHT_PLL_RATE(2040000000U, 204000000U, 1, 85, 0, 5, 2), ++ LIGHT_PLL_RATE(3000000000U, 200000000U, 1, 125, 0, 5, 3), ++ LIGHT_PLL_RATE(2880000000U, 192000000U, 1, 120, 0, 5, 3), ++ LIGHT_PLL_RATE(2760000000U, 184000000U, 1, 115, 0, 5, 3), ++ LIGHT_PLL_RATE(2640000000U, 176000000U, 1, 110, 0, 5, 3), ++ LIGHT_PLL_RATE(2520000000U, 168000000U, 1, 105, 0, 5, 3), ++ LIGHT_PLL_RATE(2400000000U, 160000000U, 1, 100, 0, 5, 3), ++ LIGHT_PLL_RATE(2280000000U, 152000000U, 1, 95, 0, 5, 3), ++ LIGHT_PLL_RATE(2160000000U, 144000000U, 1, 90, 0, 5, 3), ++ LIGHT_PLL_RATE(2040000000U, 136000000U, 1, 85, 0, 5, 3), ++ LIGHT_PLL_RATE(1920000000U, 128000000U, 1, 80, 0, 5, 3), ++ LIGHT_PLL_RATE(3000000000U, 125000000U, 1, 125, 0, 6, 4), ++ LIGHT_PLL_RATE(2760000000U, 115000000U, 1, 115, 0, 6, 4), ++ LIGHT_PLL_RATE(2520000000U, 105000000U, 1, 105, 0, 6, 4), ++ LIGHT_PLL_RATE(2280000000U, 95000000U, 1, 95, 0, 6, 4), ++ LIGHT_PLL_RATE(2040000000U, 85000000U, 1, 85, 0, 6, 4), ++ LIGHT_PLL_RATE(1800000000U, 75000000U, 1, 75, 0, 6, 4), ++ LIGHT_PLL_RATE(1560000000U, 65000000U, 1, 65, 0, 6, 4), ++ LIGHT_PLL_RATE(1320000000U, 55000000U, 1, 55, 0, 6, 4), ++}; ++ ++static const struct light_pll_rate_table light_dpupll_tbl = { ++ LIGHT_PLL_RATE(2376000000U, 1188000000U, 1, 99, 0, 2, 1), ++ LIGHT_PLL_RATE(1980000000U, 990000000U, 2, 165, 0, 2, 1), ++ LIGHT_PLL_RATE(2970000000U, 742500000U, 4, 495, 0, 4, 1), ++ LIGHT_PLL_RATE(2304000000U, 1152000000U, 1, 96, 0, 2, 1), ++ LIGHT_PLL_RATE(1512000000U, 504000000U, 1, 63, 0, 3, 1), ++ LIGHT_PLL_RATE(1512000000U, 503500000U, 1, 63, 0, 3, 1), ++ LIGHT_PLL_RATE(2898000000U, 483000000U, 4, 483, 0, 6, 1), ++ LIGHT_PLL_RATE(2592000000U, 648000000U, 1, 108, 0, 4, 1), ++ LIGHT_PLL_RATE(2772000000U, 924000000U, 2, 231, 0, 3, 1), ++ LIGHT_PLL_RATE(2856000000U, 476000000U, 1, 119, 0, 6, 1), ++ LIGHT_PLL_RATE(2130000000U, 355000000U, 4, 355, 0, 6, 1), ++ LIGHT_PLL_RATE(3192000000U, 456000000U, 1, 133, 0, 7, 1), ++ LIGHT_PLL_RATE(2730000000U, 390000000U, 4, 455, 0, 7, 1), ++ LIGHT_PLL_RATE(1680000000U, 240000000U, 1, 70, 0, 7, 1), ++ LIGHT_PLL_RATE(2832000000U, 708000000U, 1, 118, 0, 4, 1), ++ LIGHT_PLL_RATE(1026000000U, 342000000U, 4, 171, 0, 3, 1), ++ LIGHT_PLL_RATE(1260000000U, 630000000U, 4, 210, 0, 2, 1), ++}; ++ ++static struct light_pll_clk light_cpu_pll0div = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_CPU_PLL0, ++ .rate_table = light_cpupll_tbl, ++ .rate_count = ARRAY_SIZE(light_cpupll_tbl), ++}; ++ ++static struct light_pll_clk light_cpu_pll1div = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_CPU_PLL1, ++ .rate_table = light_cpupll_tbl, ++ .rate_count = ARRAY_SIZE(light_cpupll_tbl), ++}; ++ ++static struct light_pll_clk light_dpu0_plldiv = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_DPU0_PLL, ++ .rate_table = light_dpupll_tbl, ++ .rate_count = ARRAY_SIZE(light_dpupll_tbl), ++}; ++ ++static struct light_pll_clk light_dpu1_plldiv = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_DPU1_PLL, ++ .rate_table = light_dpupll_tbl, ++ .rate_count = ARRAY_SIZE(light_dpupll_tbl), ++}; ++ ++static int light_clocks_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ void __iomem *ap_base; ++ int ret; ++ const bool *teesys = of_device_get_match_data(dev); ++ ++ /* Clock source */ ++ clksCLK_DUMMY = thead_clk_fixed("dummy", 0); ++ clksOSC_32K = of_clk_get_by_name(np, "osc_32k"); ++ clksOSC_24M = of_clk_get_by_name(np, "osc_24m"); ++ clksRC_24M = of_clk_get_by_name(np, "rc_24m"); ++ ++ np = dev->of_node; ++ ap_base = devm_platform_ioremap_resource(pdev, 0); ++ if (WARN_ON(IS_ERR(ap_base))) { ++ ret = PTR_ERR(ap_base); ++ goto unregister_clks; ++ } ++ ++ /* Light Fullmask AP PLL clocks */ ++ clksCPU_PLL0_FOUTPOSTDIV = thead_light_pll("cpu_pll0_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll0div); ++ clksCPU_PLL1_FOUTPOSTDIV = thead_light_pll("cpu_pll1_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll1div); ++ ++ clksDPU0_PLL_FOUTPOSTDIV = thead_light_pll("dpu0_pll_foutpostdiv", "osc_24m", ap_base, &light_dpu0_plldiv); ++ clksDPU1_PLL_FOUTPOSTDIV = thead_light_pll("dpu1_pll_foutpostdiv", "osc_24m", ap_base, &light_dpu1_plldiv); ++ ++ /* Light Fullmask AP Fixed PLL */ ++ clksGMAC_PLL_FOUTPOSTDIV = thead_clk_fixed("gmac_pll_foutpostdiv", 1000000000); ++ clksVIDEO_PLL_FOUTPOSTDIV = thead_clk_fixed("video_pll_foutpostdiv", 792000000); ++ clksVIDEO_PLL_FOUTVCO = thead_clk_fixed("video_pll_foutvco", 2376000000); ++ clksTEE_PLL_FOUTPOSTDIV = thead_clk_fixed("tee_pll_foutpostdiv", 792000000); ++ clksCLKGEN_PERI_I2S_SRC_CLK_0 = thead_clk_fixed("clkgen_peri_i2s_src_clk_0", 294912000); //from audio_pll_foutpostdiv ++ clksCLKGEN_PERI_I2S_SRC_CLK_1 = thead_clk_fixed("clkgen_peri_i2s_src_clk_1", 135475200); //from sys_pll_foutpostdiv ++ clksCLKGEN_C910_BUS_CLK_NO_ICG = thead_clk_fixed("clkgen_c910_bus_clk_no_icg", 750000000); ++ clksAONSYS_BUS_CLK = thead_clk_fixed("aonsys_hclk", 101606400); //from sys_pll, maybe change ? ++ ++ /* Light Fullmask AP MUX */ ++ clksCPU_PLL0_BYPASS = thead_light_clk_mux_flags("cpu_pll0_bypass", ap_base + 0x4, 30, 1, cpu_pll0_bypass_sels, ARRAY_SIZE(cpu_pll0_bypass_sels), CLK_SET_RATE_PARENT); ++ clksCPU_PLL1_BYPASS = thead_light_clk_mux_flags("cpu_pll1_bypass", ap_base + 0x14, 30, 1, cpu_pll1_bypass_sels, ARRAY_SIZE(cpu_pll1_bypass_sels), CLK_SET_RATE_PARENT); ++ clksGMAC_PLL_BYPASS = thead_light_clk_mux_flags("gmac_pll_bypass", ap_base + 0x24, 30, 1, gmac_pll_bypass_sels, ARRAY_SIZE(gmac_pll_bypass_sels), CLK_SET_RATE_PARENT); ++ clksVIDEO_PLL_BYPASS = thead_light_clk_mux_flags("video_pll_bypass", ap_base + 0x34, 30, 1, video_pll_bypass_sels, ARRAY_SIZE(video_pll_bypass_sels), CLK_SET_RATE_PARENT); ++ clksTEE_PLL_BYPASS = thead_light_clk_mux_flags("tee_pll_bypass", ap_base + 0x64, 30, 1, tee_pll_bypass_sels, ARRAY_SIZE(tee_pll_bypass_sels), CLK_SET_RATE_PARENT); ++ clksDPU0_PLL_BYPASS = thead_light_clk_mux_flags("dpu0_pll_bypass", ap_base + 0x44, 30, 1, dpu0_pll_bypass_sels, ARRAY_SIZE(dpu0_pll_bypass_sels), CLK_SET_RATE_PARENT); ++ clksDPU1_PLL_BYPASS = thead_light_clk_mux_flags("dpu1_pll_bypass", ap_base + 0x54, 30, 1, dpu1_pll_bypass_sels, ARRAY_SIZE(dpu1_pll_bypass_sels), CLK_SET_RATE_PARENT); ++ ++ clksAHB2_CPUSYS_HCLK = thead_light_clk_mux_flags("ahb2_cpusys_hclk", ap_base + 0x120, 5, 1, ahb2_cpusys_hclk_sels, ARRAY_SIZE(ahb2_cpusys_hclk_sels), CLK_SET_RATE_PARENT); ++ clksC910_CCLK_I0 = thead_light_clk_mux_flags("c910_cclk_i0", ap_base + 0x100, 1, 1, c910_cclk_i0_sels, ARRAY_SIZE(c910_cclk_i0_sels), CLK_SET_RATE_PARENT); ++ clksC910_CCLK = thead_light_clk_mux_flags("c910_cclk", ap_base + 0x100, 0, 1, c910_cclk_sels, ARRAY_SIZE(c910_cclk_sels), CLK_SET_RATE_PARENT); ++ clksCFG_AXI_ACLK = thead_light_clk_mux_flags("cfg_axi_aclk", ap_base + 0x138, 5, 1, cfg_axi_aclk_sels, ARRAY_SIZE(cfg_axi_aclk_sels), CLK_SET_RATE_PARENT); ++ ++ if (teesys) ++ clksTEESYS_HCLK = thead_light_clk_mux_flags("teesys_hclk", ap_base + 0x1cc, 13, 1, teesys_hclk_sels, ARRAY_SIZE(teesys_hclk_sels), CLK_SET_RATE_PARENT); //just for teesys!!! ++ ++ clksPERISYS_AHB_HCLK = thead_light_clk_mux_flags("perisys_ahb_hclk", ap_base + 0x140, 5, 1, perisys_ahb_hclk_sels, ARRAY_SIZE(perisys_ahb_hclk_sels), CLK_SET_RATE_PARENT); ++ clksCLK_OUT_1 = thead_light_clk_mux_flags("clk_out_1", ap_base + 0x1b4, 4, 1, clk_out_1_sels, ARRAY_SIZE(clk_out_1_sels), CLK_SET_RATE_PARENT); ++ clksCLK_OUT_2 = thead_light_clk_mux_flags("clk_out_2", ap_base + 0x1b8, 4, 1, clk_out_2_sels, ARRAY_SIZE(clk_out_2_sels), CLK_SET_RATE_PARENT); ++ clksCLK_OUT_3 = thead_light_clk_mux_flags("clk_out_3", ap_base + 0x1bc, 4, 1, clk_out_3_sels, ARRAY_SIZE(clk_out_3_sels), CLK_SET_RATE_PARENT); ++ clksCLK_OUT_4 = thead_light_clk_mux_flags("clk_out_4", ap_base + 0x1c0, 4, 1, clk_out_4_sels, ARRAY_SIZE(clk_out_4_sels), CLK_SET_RATE_PARENT); ++ clksPERI_I2S_SRC_CLK = thead_light_clk_mux_flags("peri_i2s_src_clk", ap_base + 0x1f0, 0, 1, peri_i2s_src_clk_sels, ARRAY_SIZE(peri_i2s_src_clk_sels), CLK_SET_RATE_PARENT); ++ clksNPU_CCLK = thead_light_clk_mux_flags("npu_cclk", ap_base + 0x1c8, 6, 1, npu_cclk_sels, ARRAY_SIZE(npu_cclk_sels), CLK_SET_RATE_PARENT); ++ clksCFG_APB_PCLK = thead_light_clk_mux_flags("cfg_apb_pclk", ap_base + 0x1c4, 7, 1, cfg_apb_pclk_sels, ARRAY_SIZE(cfg_apb_pclk_sels), CLK_SET_RATE_PARENT); ++ clksUART_SCLK = thead_light_clk_mux_flags("uart_sclk", ap_base + 0x210, 0, 1, uart_sclk_sels, ARRAY_SIZE(uart_sclk_sels), CLK_SET_RATE_PARENT); ++ ++ /* Light Fullmask AP Divider */ ++ clksAHB2_CPUSYS_HCLK_OUT_DIV = thead_clk_light_divider("ahb2_cpusys_hclk_out_div", "gmac_pll_fout1ph0", ap_base + 0x120, 0, 3, 4, MUX_TYPE_DIV, 2, 7); ++ clksAPB3_CPUSYS_PCLK = thead_clk_light_divider("apb3_cpusys_pclk", "ahb2_cpusys_hclk", ap_base + 0x130, 0, 3, 3, MUX_TYPE_CDE, 1, 7); ++ clksAXI4_CPUSYS2_ACLK = thead_clk_light_divider("axi4_cpusys2_aclk", "gmac_pll_foutpostdiv", ap_base + 0x134, 0, 3, 4, MUX_TYPE_DIV, 2, 7); ++ clksCFG_AXI_ACLK_OUT_DIV = thead_clk_light_divider("cfg_axi_aclk_out_div", "video_pll_foutpostdiv", ap_base + 0x138, 0, 4, 4, MUX_TYPE_DIV, 2, 15); ++ ++ if (teesys) { ++ clksTEESYS_I0_HCLK = thead_clk_light_divider("teesys_i0_hclk", "tee_pll_foutpostdiv", ap_base + 0x1cc, 0, 4, 4, MUX_TYPE_DIV, 2, 15); //just for teesys!!! ++ clksTEESYS_I1_HCLK = thead_clk_light_divider("teesys_i1_hclk", "video_pll_foutpostdiv", ap_base + 0x1cc, 8, 4, 12, MUX_TYPE_DIV, 2, 15); //just for teesys!!! ++ } ++ ++ clksPERISYS_AHB_HCLK_OUT_DIV = thead_clk_light_divider("perisys_ahb_hclk_out_div", "gmac_pll_fout1ph0", ap_base + 0x140, 0, 4, 4, MUX_TYPE_DIV, 2, 7); ++ clksPERISYS_APB_PCLK = thead_clk_light_divider("perisys_apb_pclk", "perisys_ahb_hclk", ap_base + 0x150, 0, 3, 3, MUX_TYPE_CDE, 3, 7); ++ clksPERI2SYS_APB_PCLK = thead_clk_light_divider("peri2sys_apb_pclk", "gmac_pll_fout4", ap_base + 0x150, 4, 3, 8, MUX_TYPE_DIV, 2, 7); ++ clksCLK_OUT_1_OUT_DIV = thead_clk_light_divider("clk_out_1_out_div", "osc_24m", ap_base + 0x1b4, 0, 3, 3, MUX_TYPE_DIV, 2, 4); ++ clksCLK_OUT_2_OUT_DIV = thead_clk_light_divider("clk_out_2_out_div", "osc_24m", ap_base + 0x1b8, 0, 3, 3, MUX_TYPE_DIV, 2, 4); ++ clksCLK_OUT_3_OUT_DIV = thead_clk_light_divider("clk_out_3_out_div", "osc_24m", ap_base + 0x1bc, 0, 3, 3, MUX_TYPE_DIV, 2, 4); ++ clksCLK_OUT_4_OUT_DIV = thead_clk_light_divider("clk_out_4_out_div", "osc_24m", ap_base + 0x1c0, 0, 3, 3, MUX_TYPE_DIV, 2, 4); ++ clksVOSYS_ACLK_M = thead_clk_light_divider("vosys_aclk_m", "video_pll_foutvco", ap_base + 0x1dc, 0, 4, 4, MUX_TYPE_DIV, 3, 15); ++ clksNPU_CCLK_OUT_DIV = thead_clk_light_divider("npu_cclk_out_div", "video_pll_foutvco", ap_base + 0x1c8, 0, 3, 3, MUX_TYPE_DIV, 3, 7); ++ clksCFG_APB_PCLK_OUT_DIV = thead_clk_light_divider("cfg_apb_pclk_out_div", "gmac_pll_foutpostdiv", ap_base + 0x1c4, 0, 4, 4, MUX_TYPE_DIV, 4, 15); ++ clksVISYS_ACLK_M = thead_clk_light_divider("visys_aclk_m", "video_pll_foutvco", ap_base + 0x1d0, 16, 4, 20, MUX_TYPE_DIV, 3, 15); ++ clksVISYS_AHB_HCLK = thead_clk_light_divider("visys_ahb_hclk", "video_pll_foutvco", ap_base + 0x1d0, 0, 4, 4, MUX_TYPE_DIV, 6, 15); ++ clksVPSYS_APB_PCLK = thead_clk_light_divider("vpsys_apb_pclk", "gmac_pll_fout1ph0", ap_base + 0x1e0, 0, 3, 4, MUX_TYPE_DIV, 2, 7); ++ clksVPSYS_AXI_ACLK = thead_clk_light_divider("vpsys_axi_aclk", "video_pll_foutvco", ap_base + 0x1e0, 8, 4, 12, MUX_TYPE_DIV, 3, 15); ++ clksVENC_CCLK = thead_clk_light_divider("venc_cclk", "gmac_pll_foutpostdiv", ap_base + 0x1e4, 0, 3, 4, MUX_TYPE_DIV, 2, 7); ++ clksDPU0_PLL_DIV_CLK = thead_clk_light_divider("dpu0_pll_div_clk", "dpu0_pll_foutpostdiv", ap_base + 0x1e8, 0, 8, 8, MUX_TYPE_DIV, 2, 214); ++ clksDPU1_PLL_DIV_CLK = thead_clk_light_divider("dpu1_pll_div_clk", "dpu1_pll_foutpostdiv", ap_base + 0x1ec, 0, 8, 8, MUX_TYPE_DIV, 2, 214); ++ ++ /* Light Fullmask PLL FOUT */ ++ clksGMAC_PLL_FOUT1PH0 = thead_light_clk_fixed_factor("gmac_pll_fout1ph0", "gmac_pll_bypass", 1, 2); ++ clksGMAC_PLL_FOUT4 = thead_light_clk_fixed_factor("gmac_pll_fout4", "gmac_pll_bypass", 1, 8); ++ clksVIDEO_PLL_FOUT1PH0 = thead_light_clk_fixed_factor("video_pll_fout1ph0", "video_pll_bybass", 1, 2); ++ clksVIDEO_PLL_FOUT4 = thead_light_clk_fixed_factor("video_pll_fout4", "video_pll_bypass", 1, 8); ++ clksTEE_PLL_FOUT4 = thead_light_clk_fixed_factor("tee_pll_fout4", "tee_pll_bypass", 1, 8); ++ clksCPU_PLL0_FOUT4 = thead_light_clk_fixed_factor("cpu_pll0_fout4", "cpu_pll0_bypass", 1, 8); ++ clksCPU_PLL1_FOUT4 = thead_light_clk_fixed_factor("cpu_pll1_fout4", "cpu_pll1_bypass", 1, 8); ++ clksDPU0_PLL_FOUT4 = thead_light_clk_fixed_factor("dpu0_pll_fout4", "dpu0_pll_bypass", 1, 8); ++ clksDPU1_PLL_FOUT4 = thead_light_clk_fixed_factor("dpu1_pll_fout4", "dpu1_pll_bypass", 1, 8); ++ ++ /* Light Fullmask Fixed Factor */ ++ clksC910_OSC_CLK = thead_light_clk_fixed_factor("c910_osc_clk", "osc_24m", 1, 1); ++ clksQSPI_SSI_CLK = thead_light_clk_fixed_factor("qspi_ssi_clk", "video_pll_foutpostdiv", 1, 1); /* Note: no mux to select, use default value */ ++ clksQSPI0_SSI_CLK = thead_light_clk_fixed_factor("qspi0_ssi_clk", "qspi_ssi_clk", 1, 1); ++ clksQSPI1_SSI_CLK = thead_light_clk_fixed_factor("qspi1_ssi_clk", "video_pll_fout1ph0", 1, 1); ++ clksSPI_SSI_CLK = thead_light_clk_fixed_factor("spi_ssi_clk", "video_pll_fout1ph0", 1, 1); ++ clksEMMC_SDIO_REF_CLK = thead_light_clk_fixed_factor("emmc_sdio_ref_clk", "video_pll_foutpostdiv", 1, 1); /* Note: no mux to select, use default value */ ++ clksPWM_CCLK = thead_light_clk_fixed_factor("pwm_cclk", "osc_24m", 1, 1); ++ clksCHIP_DBG_CCLK = thead_light_clk_fixed_factor("chip_dbg_cclk", "osc_24m", 1, 1); ++ clksGMAC_CCLK = thead_light_clk_fixed_factor("gmac_cclk", "gmac_pll_fout1ph0", 1, 1); ++ clksGPIO0_DBCLK = thead_light_clk_fixed_factor("gpio0_dbclk", "pad_rtc_clk", 1, 1); ++ clksGPIO1_DBCLK = thead_light_clk_fixed_factor("gpio1_dbclk", "pad_rtc_clk", 1, 1); ++ clksGPIO2_DBCLK = thead_light_clk_fixed_factor("gpio2_dbclk", "pad_rtc_clk", 1, 1); ++ clksGPIO3_DBCLK = thead_light_clk_fixed_factor("gpio3_dbclk", "pad_rtc_clk", 1, 1); ++ clksCLK_100M = thead_light_clk_fixed_factor("clk_100m", "gmac_pll_foutpostdiv", 1, 10); ++ clksI2C_IC_CLK = thead_light_clk_fixed_factor("i2c_ic_clk", "clk_100m", 1, 2); ++ clksTIMER_CCLK = thead_light_clk_fixed_factor("timer_cclk", "osc_24m", 1, 1); ++ clksAXI4_CPUSYS1_ACLK = thead_light_clk_fixed_factor("axi4_cpusys1_aclk", "clkgen_c910_bus_clk_no_icg", 1, 1); ++ clksCPU_BUS_DFTCLK = thead_light_clk_fixed_factor("cpu_bus_dftclk", "cpu_pll0_foutpostdiv", 1, 2); ++ clksCPU_PLL0_TEST_CLK = thead_light_clk_fixed_factor("cpu_pll0_test_clk", "cpu_pll0_fout4", 1, 8); ++ clksCPU_PLL1_TEST_CLK = thead_light_clk_fixed_factor("cpu_pll1_test_clk", "cpu_pll1_fout4", 1, 8); ++ clksDPU0_PLL_TEST_CLK = thead_light_clk_fixed_factor("dpu0_pll_test_clk", "dpu0_pll_fout4", 1, 8); ++ clksDPU1_PLL_TEST_CLK = thead_light_clk_fixed_factor("dpu1_pll_test_clk", "dpu1_pll_fout4", 1, 8); ++ clksGMAC_PLL_TEST_CLK = thead_light_clk_fixed_factor("gmac_pll_test_clk", "gmac_pll_fout4", 1, 8); ++ clksVIDEO_PLL_TEST_CLK = thead_light_clk_fixed_factor("video_pll_test_clk", "video_pll_fout4", 1, 8); ++ clksTEE_PLL_TEST_CLK = thead_light_clk_fixed_factor("tee_pll_test_clk", "tee_pll_fout4", 1, 8); ++ clksAONSYS_BUS_CLK = thead_light_clk_fixed_factor("aonsys_bus_clk", "aonsys_hclk", 1, 1); ++ ++ /* Light Fullmask Clock Gate */ ++ clksCLKGEN_AHB2_CPUSYS_HCLK = thead_clk_light_gate("clkgen_ahb2_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x120, 6); ++ clksCLKGEN_APB3_CPUSYS_HCLK = thead_clk_light_gate("clkgen_apb3_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x130, 4); ++ clksCLKGEN_C910_BROM_HCLK = thead_clk_light_gate("clkgen_c910_brom_hclk", "ahb2_cpusys_hclk", ap_base + 0x100, 4); ++ clksCLKGEN_SPINLOCK_HCLK = thead_clk_light_gate("clkgen_spinlock_hclk", "ahb2_cpusys_hclk", ap_base + 0x208, 10); ++ clksCLKGEN_MBOX0_PCLK = thead_clk_light_gate("clkgen_mbox0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 7); ++ clksCLKGEN_MBOX1_PCLK = thead_clk_light_gate("clkgen_mbox1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 6); ++ clksCLKGEN_MBOX2_PCLK = thead_clk_light_gate("clkgen_mbox2_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 5); ++ clksCLKGEN_MBOX3_PCLK = thead_clk_light_gate("clkgen_mbox3_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 4); ++ clksCLKGEN_WDT0_PCLK = thead_clk_light_gate("clkgen_wdt0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 3); ++ clksCLKGEN_WDT1_PCLK = thead_clk_light_gate("clkgen_wdt1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 2); ++ ++ if (teesys) ++ clksCLKGEN_MISCSYS_TEE_CCLK = thead_clk_light_gate("clkgen_miscsys_tee_cclk", "teesys_hclk", ap_base + 0x1cc, 25); //just for teesys!!! ++ ++ clksCLKGEN_SRAM_AXI_ACLK_2 = thead_clk_light_gate("clkgen_sram_axi_aclk_2", "axi4_cpusys1_aclk", ap_base + 0x20c, 2); ++ clksCLKGEN_PERISYS_AHB_HCLK = thead_clk_light_gate("clkgen_perisys_ahb_hclk", "perisys_ahb_hclk", ap_base + 0x140, 6); ++ clksCLKGEN_PERISYS_APB1_HCLK = thead_clk_light_gate("clkgen_perisys_apb1_hclk", "perisys_ahb_hclk", ap_base + 0x150, 9); ++ clksCLKGEN_PERISYS_APB2_HCLK = thead_clk_light_gate("clkgen_perisys_apb2_hclk", "perisys_ahb_hclk", ap_base + 0x150, 10); ++ clksCLKGEN_PERISYS_APB4_HCLK = thead_clk_light_gate("clkgen_perisys_apb4_hclk", "perisys_ahb_hclk", ap_base + 0x150, 12); ++ clksCLKGEN_PADCTRL0_APSYS_PCLK = thead_clk_light_gate("clkgen_padctrl0_apsys_pclk", "perisys_ahb_hclk", ap_base + 0x204, 22); ++ clksCLKGEN_DSMART_PCLK = thead_clk_light_gate("clkgen_dsmart_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 23); ++ clksCLKGEN_PADCTRL1_APSYS_PCLK = thead_clk_light_gate("clkgen_padctrl1_apsys_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 24); ++ clksCLKGEN_CLK_OUT_1_CLK = thead_clk_light_gate("clkgen_clk_out_1_clk", "clk_out_1", ap_base + 0x1b4, 5); ++ clksCLKGEN_CLK_OUT_2_CLK = thead_clk_light_gate("clkgen_clk_out_2_clk", "clk_out_2", ap_base + 0x1b8, 5); ++ clksCLKGEN_CLK_OUT_3_CLK = thead_clk_light_gate("clkgen_clk_out_3_clk", "clk_out_3", ap_base + 0x1bc, 5); ++ clksCLKGEN_CLK_OUT_4_CLK = thead_clk_light_gate("clkgen_clk_out_4_clk", "clk_out_4", ap_base + 0x1c0, 5); ++ clksCLKGEN_NPUSYS_AXI_ACLK = thead_clk_light_gate("clkgen_npusys_axi_aclk", "npu_cclk", ap_base + 0x1c8, 5); ++ clksCLKGEN_SRAM_AXI_ACLK_0 = thead_clk_light_gate("clkgen_sram_axi_aclk_0", "npu_cclk", ap_base + 0x20c, 4); ++ clksCLKGEN_APB_CPU2CFG_HCLK = thead_clk_light_gate("clkgen_apb_cpu2cfg_hclk", "cfg_apb_pclk", ap_base + 0x1c4, 5); ++ clksCLKGEN_SRAM_AXI_ACLK_1 = thead_clk_light_gate("clkgen_sram_axi_aclk_1", "visys_aclk_m", ap_base + 0x20c, 3); ++ clksCLKGEN_SRAM_AXI_ACLK_3 = thead_clk_light_gate("clkgen_sram_axi_aclk_3", "vpsys_axi_aclk", ap_base + 0x20c, 1); ++ clksCLKGEN_VPSYS_VENC_CCLK = thead_clk_light_gate("clkgen_vpsys_venc_cclk", "venc_cclk", ap_base + 0x1e4, 5); ++ clksCLKGEN_EMMC_SDIO_REF_CLK = thead_clk_light_gate("clkgen_emmc_sdio_ref_clk", "emmc_sdio_ref_clk", ap_base + 0x204, 30); ++ ++ clksCLKGEN_X2H_CPUSYS_MHCLK = thead_clk_light_gate_shared("clkgen_x2h_cpusys_mhclk", "ahb2_cpusys_hclk", ap_base + 0x120, 7, &share_cnt_x2h_cpusys_clk_en); ++ clksCLKGEN_X2H_CPUSYS_ACLK = thead_clk_light_gate_shared("clkgen_x2h_cpusys_aclk", "cfg_axi_aclk", ap_base + 0x120, 7, &share_cnt_x2h_cpusys_clk_en); ++ clksCLKGEN_DMAC_CPUSYS_HCLK = thead_clk_light_gate_shared("clkgen_dmac_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); ++ clksCLKGEN_IOPMP_DMAC_CPUSYS_PCLK = thead_clk_light_gate_shared("clkgen_iopmp_dmac_cpusys_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); ++ clksCLKGEN_DMAC_CPUSYS_ACLK = thead_clk_light_gate_shared("clkgen_dmac_cpusys_aclk", "axi4_cpusys2_aclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); ++ clksCLKGEN_TIMER0_PCLK = thead_clk_light_gate_shared("clkgen_timer0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 1, &share_cnt_timer0_clk_en); ++ clksCLKGEN_TIMER0_CCLK = thead_clk_light_gate_shared("clkgen_timer0_cclk", "timer_cclk", ap_base + 0x208, 1, &share_cnt_timer0_clk_en); ++ clksCLKGEN_TIMER1_PCLK = thead_clk_light_gate_shared("clkgen_timer1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 0, &share_cnt_timer1_clk_en); ++ clksCLKGEN_TIMER1_CCLK = thead_clk_light_gate_shared("clkgen_timer1_cclk", "timer_cclk", ap_base + 0x208, 0, &share_cnt_timer1_clk_en); ++ clksCLKGEN_AXI4_CPUSYS2_PCLK = thead_clk_light_gate_shared("clkgen_axi4_cpusys2_pclk", "apb3_cpusys_pclk", ap_base + 0x134, 5, &share_cnt_axi4_cpusys2_clk_en); ++ clksCLKGEN_AXI4_CPUSYS2_ACLK = thead_clk_light_gate_shared("clkgen_axi4_cpusys2_aclk", "axi4_cpusys2_aclk", ap_base + 0x134, 5, &share_cnt_axi4_cpusys2_clk_en); ++ clksCLKGEN_BMU_C910_PCLK = thead_clk_light_gate_shared("clkgen_bmu_c910_pclk", "apb3_cpusys_pclk", ap_base + 0x100, 5, &share_cnt_bmu_c910_clk_en); ++ clksCLKGEN_BMU_C910_ACLK = thead_clk_light_gate_shared("clkgen_bmu_c910_aclk", "axi4_cpusys1_aclk", ap_base + 0x100, 5, &share_cnt_bmu_c910_clk_en); ++ clksCLKGEN_IOPMP_AON_PCLK = thead_clk_light_gate_shared("clkgen_iopmp_aon_pclk", "apb3_cpusys_pclk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); ++ clksCLKGEN_AON2CPU_A2X_ACLK = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_aclk", "axi4_cpusys2_aclk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); ++ clksCLKGEN_AON2CPU_A2X_HCLK = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_hclk", "aonsys_bus_clk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); ++ clksCLKGEN_IOPMP_CHIP_DBG_PCLK = thead_clk_light_gate_shared("clkgen_iopmp_chip_dbg_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); ++ clksCLKGEN_CHIP_DBG_ACLK = thead_clk_light_gate_shared("clkgen_chip_dbg_aclk", "axi4_cpusys2_aclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); ++ clksCLKGEN_CHIP_DBG_CCLK = thead_clk_light_gate_shared("clkgen_chip_dbg_cclk", "chip_dbg_cclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); ++ clksCLKGEN_X2X_CPUSYS_ACLK_M = thead_clk_light_gate_shared("clkgen_x2x_cpusys_aclk_m", "axi4_cpusys2_aclk", ap_base + 0x134, 7, &share_cnt_x2x_cpusys_clk_en); ++ clksCLKGEN_X2X_CPUSYS_ACLK_S = thead_clk_light_gate_shared("clkgen_x2x_cpusys_aclk_s", "axi4_cpusys1_aclk", ap_base + 0x134, 7, &share_cnt_x2x_cpusys_clk_en); ++ clksCLKGEN_CPU2PERI_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_aclk", "axi4_cpusys1_aclk", ap_base + 0x140, 9, &share_cnt_cpu2peri_x2h_clk_en); ++ clksCLKGEN_CPU2PERI_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_mhclk", "perisys_ahb_hclk", ap_base + 0x140, 9, &share_cnt_cpu2peri_x2h_clk_en); ++ clksCLKGEN_CPU2VI_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2vi_x2h_aclk", "axi4_cpusys1_aclk", ap_base + 0x1d0, 21, &share_cnt_cpu2vi_x2h_clk_en); ++ clksCLKGEN_CPU2VI_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2vi_x2h_mhclk", "visys_ahb_hclk", ap_base + 0x1d0, 21, &share_cnt_cpu2vi_x2h_clk_en); ++ clksCLKGEN_CFG2TEE_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cfg2tee_x2h_aclk", "cfg_axi_aclk", ap_base + 0x1cc, 24, &share_cnt_cfg2tee_x2h_clk_en); // just for teesys!!! ++ clksCLKGEN_CFG2TEE_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cfg2tee_x2h_mhclk", "teesys_hclk", ap_base + 0x1cc, 24, &share_cnt_cfg2tee_x2h_clk_en); // just for teesys!!! ++ clksCLKGEN_CPU2AON_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_aclk", "cfg_axi_aclk", ap_base + 0x138, 8, &share_cnt_cpu2aon_x2h_clk_en); ++ clksCLKGEN_CPU2AON_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_mhclk", "aonsys_bus_clk", ap_base + 0x138, 8, &share_cnt_cpu2aon_x2h_clk_en); ++ clksCLKGEN_CPU2VP_X2P_ACLK = thead_clk_light_gate_shared("clkgen_cpu2vp_x2p_aclk", "cfg_axi_aclk", ap_base + 0x1e0, 13, &share_cnt_cpu2vp_x2p_clk_en); ++ clksCLKGEN_CPU2VP_X2P_PCLK = thead_clk_light_gate_shared("clkgen_cpu2vp_x2p_pclk", "vpsys_apb_pclk", ap_base + 0x1e0, 13, &share_cnt_cpu2vp_x2p_clk_en); ++ clksCLKGEN_TOP_AXI4S_ACLK = thead_clk_light_gate_shared("clkgen_top_axi4s_aclk", "cfg_axi_aclk", ap_base + 0x1c8, 4, &share_cnt_npu_core_clk_en); ++ clksCLKGEN_TOP_APB_SX_PCLK = thead_clk_light_gate_shared("clkgen_top_apb_sx_pclk", "cfg_apb_pclk", ap_base + 0x1c8, 4, &share_cnt_npu_core_clk_en); ++ clksCLKGEN_MISC2VP_X2X_ACLK_M = thead_clk_light_gate_shared("clkgen_misc2vp_x2x_aclk_m", "perisys_ahb_hclk", ap_base + 0x1e0, 15, &share_cnt_vpsys_axi_aclk_en); ++ clksCLKGEN_VPSYS_ACLK = thead_clk_light_gate_shared("clkgen_vpsys_aclk", "vpsys_axi_aclk", ap_base + 0x1e0, 15, &share_cnt_vpsys_axi_aclk_en); ++ clksCLKGEN_GMAC1_HCLK = thead_clk_light_gate_shared("clkgen_gmac1_hclk", "perisys_ahb_hclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); ++ clksCLKGEN_GMAC1_PCLK = thead_clk_light_gate_shared("clkgen_gmac1_pclk", "perisys_ahb_hclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); ++ clksCLKGEN_GMAC1_CCLK = thead_clk_light_gate_shared("clkgen_gmac1_cclk", "gmac_cclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); ++ clksCLKGEN_GMAC0_HCLK = thead_clk_light_gate_shared("clkgen_gmac0_hclk", "perisys_ahb_hclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); ++ clksCLKGEN_GMAC0_PCLK = thead_clk_light_gate_shared("clkgen_gmac0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); ++ clksCLKGEN_GMAC0_CCLK = thead_clk_light_gate_shared("clkgen_gmac0_cclk", "gmac_cclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); ++ clksCLKGEN_PERI2PERI1_APB_HCLK = thead_clk_light_gate_shared("clkgen_peri2peri1_apb_hclk", "perisys_ahb_hclk", ap_base + 0x150, 11, &share_cnt_perisys_apb3_hclk_en); ++ clksCLKGEN_PERI2PERI1_APB_PCLK = thead_clk_light_gate_shared("clkgen_peri2peri1_apb_pclk", "peri2sys_apb_pclk", ap_base + 0x150, 11, &share_cnt_perisys_apb3_hclk_en); ++ clksCLKGEN_QSPI0_PCLK = thead_clk_light_gate_shared("clkgen_qspi0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 17, &share_cnt_qspi0_clk_en); ++ clksCLKGEN_QSPI0_SSI_CLK = thead_clk_light_gate_shared("clkgen_qspi0_ssi_clk", "qspi0_ssi_clk", ap_base + 0x204, 17, &share_cnt_qspi0_clk_en); ++ clksCLKGEN_GMAC_AXI_ACLK = thead_clk_light_gate_shared("clkgen_gmac_axi_aclk", "perisys_ahb_hclk", ap_base + 0x204, 21, &share_cnt_gmac_axi_clk_en); ++ clksCLKGEN_GMAC_AXI_PCLK = thead_clk_light_gate_shared("clkgen_gmac_axi_pclk", "perisys_ahb_hclk", ap_base + 0x204, 21, &share_cnt_gmac_axi_clk_en); ++ clksCLKGEN_GPIO0_PCLK = thead_clk_light_gate_shared("clkgen_gpio0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 8, &share_cnt_gpio0_clk_en); ++ clksCLKGEN_GPIO0_DBCLK = thead_clk_light_gate_shared("clkgen_gpio0_dbclk", "gpio0_dbclk", ap_base + 0x204, 8, &share_cnt_gpio0_clk_en); ++ clksCLKGEN_GPIO1_PCLK = thead_clk_light_gate_shared("clkgen_gpio1_pclk", "perisys_ahb_hclk", ap_base + 0x204, 7, &share_cnt_gpio0_clk_en); ++ clksCLKGEN_GPIO1_DBCLK = thead_clk_light_gate_shared("clkgen_gpio1_dbclk", "gpio1_dbclk", ap_base + 0x204, 7, &share_cnt_gpio1_clk_en); ++ clksCLKGEN_PWM_PCLK = thead_clk_light_gate_shared("clkgen_pwm_pclk", "perisys_apb_pclk", ap_base + 0x204, 18, &share_cnt_pwm_clk_en); ++ clksCLKGEN_PWM_CCLK = thead_clk_light_gate_shared("clkgen_pwm_cclk", "pwm_cclk", ap_base + 0x204, 18, &share_cnt_pwm_clk_en); ++ clksCLKGEN_SPI_PCLK = thead_clk_light_gate_shared("clkgen_spi_pclk", "perisys_apb_pclk", ap_base + 0x204, 15, &share_cnt_spi_clk_en); ++ clksCLKGEN_SPI_SSI_CLK = thead_clk_light_gate_shared("clkgen_spi_ssi_clk", "spi_ssi_clk", ap_base + 0x204, 15, &share_cnt_spi_clk_en); ++ clksCLKGEN_UART0_PCLK = thead_clk_light_gate_shared("clkgen_uart0_pclk", "perisys_apb_pclk", ap_base + 0x204, 14, &share_cnt_uart0_clk_en); ++ clksCLKGEN_UART0_SCLK = thead_clk_light_gate_shared("clkgen_uart0_sclk", "uart_sclk", ap_base + 0x204, 14, &share_cnt_uart0_clk_en); ++ clksCLKGEN_UART2_PCLK = thead_clk_light_gate_shared("clkgen_uart2_pclk", "perisys_apb_pclk", ap_base + 0x204, 12, &share_cnt_uart2_clk_en); ++ clksCLKGEN_UART2_SCLK = thead_clk_light_gate_shared("clkgen_uart2_sclk", "uart_sclk", ap_base + 0x204, 12, &share_cnt_uart2_clk_en); ++ clksCLKGEN_I2C2_PCLK = thead_clk_light_gate_shared("clkgen_i2c2_pclk", "perisys_apb_pclk", ap_base + 0x204, 3, &share_cnt_i2c2_clk_en); ++ clksCLKGEN_I2C2_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c2_ic_clk", "i2c_ic_clk", ap_base + 0x204, 3, &share_cnt_i2c2_clk_en); ++ clksCLKGEN_I2C3_PCLK = thead_clk_light_gate_shared("clkgen_i2c3_pclk", "perisys_apb_pclk", ap_base + 0x204, 2, &share_cnt_i2c2_clk_en); ++ clksCLKGEN_I2C3_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c3_ic_clk", "i2c_ic_clk", ap_base + 0x204, 2, &share_cnt_i2c2_clk_en); ++ clksCLKGEN_I2S_PCLK = thead_clk_light_gate_shared("clkgen_i2s_pclk", "perisys_apb_pclk", ap_base + 0x1f0, 1, &share_cnt_peri_i2s_clk_en); ++ clksCLKGEN_I2S_SRC_CLK = thead_clk_light_gate_shared("clkgen_i2s_src_clk", "peri_i2s_src_clk", ap_base + 0x1f0, 1, &share_cnt_peri_i2s_clk_en); ++ clksCLKGEN_QSPI1_PCLK = thead_clk_light_gate_shared("clkgen_qspi1_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 16, &share_cnt_qspi1_clk_en); ++ clksCLKGEN_QSPI1_SSI_CLK = thead_clk_light_gate_shared("clkgen_qspi1_ssi_clk", "qspi1_ssi_clk", ap_base + 0x204, 16, &share_cnt_qspi1_clk_en); ++ clksCLKGEN_UART1_PCLK = thead_clk_light_gate_shared("clkgen_uart1_pclk", "per2sys_apb_pclk", ap_base + 0x204, 13, &share_cnt_uart1_clk_en); ++ clksCLKGEN_UART1_SCLK = thead_clk_light_gate_shared("clkgen_uart1_sclk", "uart_sclk", ap_base + 0x204, 13, &share_cnt_uart1_clk_en); ++ clksCLKGEN_UART3_PCLK = thead_clk_light_gate_shared("clkgen_uart3_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 11, &share_cnt_uart3_clk_en); ++ clksCLKGEN_UART3_SCLK = thead_clk_light_gate_shared("clkgen_uart3_sclk", "uart_sclk", ap_base + 0x204, 11, &share_cnt_uart3_clk_en); ++ clksCLKGEN_UART4_PCLK = thead_clk_light_gate_shared("clkgen_uart4_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 10, &share_cnt_uart4_clk_en); ++ clksCLKGEN_UART4_SCLK = thead_clk_light_gate_shared("clkgen_uart4_sclk", "uart_sclk", ap_base + 0x204, 10, &share_cnt_uart4_clk_en); ++ clksCLKGEN_UART5_PCLK = thead_clk_light_gate_shared("clkgen_uart5_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 9, &share_cnt_uart5_clk_en); ++ clksCLKGEN_UART5_SCLK = thead_clk_light_gate_shared("clkgen_uart5_sclk", "uart_sclk", ap_base + 0x204, 9, &share_cnt_uart5_clk_en); ++ clksCLKGEN_I2C0_PCLK = thead_clk_light_gate_shared("clkgen_i2c0_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 5, &share_cnt_i2c0_clk_en); ++ clksCLKGEN_I2C0_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c0_ic_clk", "i2c_ic_clk", ap_base + 0x204, 5, &share_cnt_i2c0_clk_en); ++ clksCLKGEN_I2C1_PCLK = thead_clk_light_gate_shared("clkgen_i2c1_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 4, &share_cnt_i2c1_clk_en); ++ clksCLKGEN_I2C1_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c1_ic_clk", "i2c_ic_clk", ap_base + 0x204, 4, &share_cnt_i2c1_clk_en); ++ clksCLKGEN_I2C4_PCLK = thead_clk_light_gate_shared("clkgen_i2c4_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 1, &share_cnt_i2c4_clk_en); ++ clksCLKGEN_I2C4_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c4_ic_clk", "i2c_ic_clk", ap_base + 0x204, 1, &share_cnt_i2c4_clk_en); ++ clksCLKGEN_I2C5_PCLK = thead_clk_light_gate_shared("clkgen_i2c5_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 0, &share_cnt_i2c5_clk_en); ++ clksCLKGEN_I2C5_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c5_ic_clk", "i2c_ic_clk", ap_base + 0x204, 0, &share_cnt_i2c5_clk_en); ++ clksCLKGEN_GPIO2_PCLK = thead_clk_light_gate_shared("clkgen_gpio2_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); ++ clksCLKGEN_GPIO2_DBCLK = thead_clk_light_gate_shared("clkgen_gpio2_dbclk", "gpio2_dbclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); ++ clksCLKGEN_GPIO3_PCLK = thead_clk_light_gate_shared("clkgen_gpio3_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); //!!! gpio3 pclk is controlled by gpio2_clk_en ++ clksCLKGEN_GPIO3_DBCLK = thead_clk_light_gate_shared("clkgen_gpio3_dbclk", "gpio3_dbclk", ap_base + 0x204, 20, &share_cnt_gpio3_clk_en); ++ clksCLKGEN_VOSYS_AXI_ACLK = thead_clk_light_gate_shared("clkgen_vosys_axi_aclk", "vosys_aclk_m", ap_base + 0x1dc, 5, &share_cnt_vosys_axi_aclk_en); ++ clksCLKGEN_VOSYS_X2X_ACLK_S = thead_clk_light_gate_shared("clkgen_vosys_x2x_aclk_s", "npu_cclk", ap_base + 0x1dc, 5, &share_cnt_vosys_axi_aclk_en); ++ ++ clk_data.clks = clks; ++ clk_data.clk_num = ARRAY_SIZE(clks); ++ ++ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); ++ if (ret < 0) { ++ dev_err(dev, "failed to register clks for light\n"); ++ goto unregister_clks; ++ } ++ ++#ifndef FPGA_EMU ++ /* HW defalut */ ++ clk_set_parent(clksC910_CCLK, clksCPU_PLL1_FOUTPOSTDIV); ++#else ++ clk_set_parent(clksC910_CCLK_I0, clksOSC_24M); ++ clk_set_parent(clksC910_CCLK, clksC910_CCLK_I0); ++#endif ++ dev_info(dev, "succeed to register light fullmask clock driver\n"); ++ ++ return 0; ++ ++unregister_clks: ++ thead_unregister_clocks(clks, ARRAY_SIZE(clks)); ++ return ret; ++} ++ ++ ++const bool tee_sys_flag; ++ ++static const struct of_device_id light_clk_of_match = { ++ { .compatible = "thead,light-fm-ree-clk" }, ++ { .compatible = "thead,light-fm-tee-clk", .data = &tee_sys_flag,}, ++ { /* Sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, light_clk_of_match); ++ ++static struct platform_driver light_clk_driver = { ++ .probe = light_clocks_probe, ++ .driver = { ++ .name = "light-fm-clk", ++ .of_match_table = of_match_ptr(light_clk_of_match), ++ }, ++}; ++ ++module_platform_driver(light_clk_driver); ++MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light Fullmask clock driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/clk/thead/clk-light-mpw.c b/drivers/clk/thead/clk-light-mpw.c +new file mode 100644 +index 000000000000..f7356ddf4684 +--- /dev/null ++++ b/drivers/clk/thead/clk-light-mpw.c +@@ -0,0 +1,492 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <dt-bindings/clock/light-mpw-clock.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/types.h> ++ ++#include "clk.h" ++ ++static struct clk *clksLIGHT_CLK_END; ++static struct clk_onecell_data clk_data; ++ ++static u32 share_cnt_cpu2cfg_x2x_clk_en; ++static u32 share_cnt_cpu2peri_x2h_clk_en; ++static u32 share_cnt_aon2cpu_a2x_clk_en; ++static u32 share_cnt_dmac_clk_en; ++static u32 share_cnt_x2h_cpusys_clk_en; ++static u32 share_cnt_cpu2tee_x2h_clk_en; ++static u32 share_cnt_cpu2aon_x2h_clk_en; ++static u32 share_cnt_cpu2cfg_x2h_clk_en; ++static u32 share_cnt_timer0_clk_en; ++static u32 share_cnt_timer1_clk_en; ++static u32 share_cnt_peri2ddr_x2x_clk_en; ++static u32 share_cnt_usb3_drd_clk_en; ++static u32 share_cnt_gmac_clk_en; ++static u32 share_cnt_emmc0_clk_en; ++static u32 share_cnt_emmc1_clk_en; ++static u32 share_cnt_pwm_clk_en; ++static u32 share_cnt_qspi0_clk_en; ++static u32 share_cnt_qspi1_clk_en; ++static u32 share_cnt_spi_clk_en; ++static u32 share_cnt_gpio0_clk_en; ++static u32 share_cnt_gpio1_clk_en; ++static u32 share_cnt_gpio2_clk_en; ++static u32 share_cnt_dmac_1_clk_en; ++static u32 share_cnt_dmac_2_clk_en; ++static u32 share_cnt_dmac_3_clk_en; ++ ++#ifdef THEAD_LIGHT_AON_CLK ++static const char * const audio_pll_bypass_sels = {"audio_pll_foutpostdiv", "osc_24m", }; ++static const char * const sys_pll_bypass_sels = {"sys_pll_foutpostdiv", "osc_24m", }; ++#endif ++#ifdef THEAD_LIGHT_DDR_CLK ++static const char * const ddr_pll_bypass_sels = {"ddr_pll_foutpostdiv", "osc_24m", }; ++#endif ++static const char * const cpu_pll0_bypass_sels = {"cpu_pll0_foutpostdiv", "osc_24m", }; ++static const char * const cpu_pll1_bypass_sels = {"cpu_pll1_foutpostdiv", "osc_24m", }; ++static const char * const gmac_pll_bypass_sels = {"gmac_pll_foutpostdiv", "osc_24m", }; ++static const char * const video_pll_bypass_sels = {"video_pll_foutpostdiv", "osc_24m", }; ++ ++#ifdef THEAD_LIGHT_AON_CLK ++static const char * const aonsys_clk_switch_0_sels = {"audio_pll_fout3", "osc_24m", }; ++static const char * const aonsys_clk_switch_1_sels = {"aonsys_clk_switch_0", "rc_24m", }; ++#endif ++ ++static const char * const c910_cclk_i0_sels = {"cpu_pll0_bypass", "osc_24m", }; ++static const char * const c910_cclk_sels = {"c910_cclk_i0", "cpu_pll1_foutpostdiv", }; ++static const char * const cpusys_ahb_hclk_sel = {"cpusys_ahb_hclk_div", "osc_24m"}; ++static const char * const cpusys_cfg_axi_aclk_sel = {"cpusys_cfg_axi_aclk_div", "osc_24m"}; ++static const char * const perisys_ahb_hclk_sel = {"perisys_ahb_hclk_div", "osc_24m"}; ++static const char * const clk_out_1_sel = {"clk_out_1_div", "osc_24m"}; ++static const char * const clk_out_2_sel = {"clk_out_2_div", "osc_24m"}; ++static const char * const clk_out_3_sel = {"clk_out_3_div", "osc_24m"}; ++static const char * const clk_out_4_sel = {"clk_out_4_div", "osc_24m"}; ++ ++static const struct light_pll_rate_table light_audiopll_tbl = { ++ LIGHT_PLL_RATE(2654208000U, 147456000U, 1, 110, 9932112, 6, 3), ++ LIGHT_PLL_RATE(884736000U, 294912000U, 1, 36, 14495600, 3, 1), ++}; ++ ++static const struct light_pll_rate_table light_syspll_tbl = { ++ LIGHT_PLL_RATE(2438553600U, 812851200U, 1, 101, 10173704, 3, 1), ++ LIGHT_PLL_RATE(884736000U, 294912000U, 1, 36, 14495600, 3, 1), ++}; ++ ++static const struct light_pll_rate_table light_cpupll_tbl = { ++ LIGHT_PLL_RATE(1800000000U, 1800000000U, 1, 75, 0, 1, 1), ++ LIGHT_PLL_RATE(3000000000U, 1500000000U, 1, 125, 0, 2, 1), ++ LIGHT_PLL_RATE(3000000000U, 1000000000U, 1, 125, 0, 3, 1), ++ LIGHT_PLL_RATE(3000000000U, 125000000U, 1, 125, 0, 6, 4), ++}; ++ ++#ifdef THEAD_LIGHT_DDR_CLK ++static const struct light_pll_rate_table light_ddrpll_tbl = { ++ LIGHT_PLL_RATE(3192000000U, 798000000U, 1, 133, 0, 4, 1), ++ LIGHT_PLL_RATE(3192000000U, 532000000U, 1, 133, 0, 6, 1), ++ LIGHT_PLL_RATE(2112000000U, 1056000000U, 1, 88, 0, 2, 1), ++}; ++#endif ++ ++#ifdef THEAD_LIGHT_AON_CLK ++static struct light_pll_clk light_audio_pllvco = { ++ .out_type = LIGHT_PLL_VCO, ++ .clk_type = LIGHT_AUDIO_PLL, ++ .rate_table = light_audiopll_tbl, ++ .rate_count = ARRAY_SIZE(light_audiopll_tbl), ++}; ++ ++static struct light_pll_clk light_audio_plldiv = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_AUDIO_PLL, ++ .rate_table = light_audiopll_tbl, ++ .rate_count = ARRAY_SIZE(light_audiopll_tbl), ++}; ++ ++static struct light_pll_clk light_sys_pllvco = { ++ .out_type = LIGHT_PLL_VCO, ++ .clk_type = LIGHT_SYS_PLL, ++ .rate_table = light_syspll_tbl, ++ .rate_count = ARRAY_SIZE(light_syspll_tbl), ++}; ++ ++static struct light_pll_clk light_sys_plldiv = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_SYS_PLL, ++ .rate_table = light_syspll_tbl, ++ .rate_count = ARRAY_SIZE(light_syspll_tbl), ++}; ++#endif ++ ++static struct light_pll_clk light_cpu_pll0vco = { ++ .out_type = LIGHT_PLL_VCO, ++ .clk_type = LIGHT_CPU_PLL0, ++ .rate_table = light_cpupll_tbl, ++ .rate_count = ARRAY_SIZE(light_cpupll_tbl), ++}; ++ ++static struct light_pll_clk light_cpu_pll0div = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_CPU_PLL0, ++ .rate_table = light_cpupll_tbl, ++ .rate_count = ARRAY_SIZE(light_cpupll_tbl), ++}; ++ ++static struct light_pll_clk light_cpu_pll1vco = { ++ .out_type = LIGHT_PLL_VCO, ++ .clk_type = LIGHT_CPU_PLL1, ++ .rate_table = light_cpupll_tbl, ++ .rate_count = ARRAY_SIZE(light_cpupll_tbl), ++}; ++ ++static struct light_pll_clk light_cpu_pll1div = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_CPU_PLL1, ++ .rate_table = light_cpupll_tbl, ++ .rate_count = ARRAY_SIZE(light_cpupll_tbl), ++}; ++ ++#ifdef THEAD_LIGHT_DDR_CLK ++static struct light_pll_clk light_ddr_pllvco = { ++ .out_type = LIGHT_PLL_VCO, ++ .clk_type = LIGHT_DDR_PLL, ++ .rate_table = light_ddrpll_tbl, ++ .rate_count = ARRAY_SIZE(light_ddrpll_tbl), ++}; ++ ++static struct light_pll_clk light_ddr_plldiv = { ++ .out_type = LIGHT_PLL_DIV, ++ .clk_type = LIGHT_DDR_PLL, ++ .rate_table = light_ddrpll_tbl, ++ .rate_count = ARRAY_SIZE(light_ddrpll_tbl), ++}; ++#endif ++ ++static int light_clocks_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ void __iomem *ap_base; ++#ifdef THEAD_LIGHT_DDR_CLK ++ void __iomem *ddr_base; ++#endif ++#ifdef THEAD_LIGHT_AON_CLK ++ void __iomem *aon_base; ++#endif ++ int ret; ++ ++#ifdef THEAD_LIGHT_AON_CLK ++ np = of_find_compatible_node(NULL, NULL, "thead,light-aon-clk"); ++ aon_base = of_iomap(np, 0); ++ if (WARN_ON(!aon_base)) { ++ ret = -ENOMEM; ++ goto unregister_clks; ++ } ++ of_node_put(np); ++#endif ++ ++ /* Clock source */ ++ clksLIGHT_CLK_DUMMY = thead_clk_fixed("dummy", 0); ++ clksLIGHT_CLK_32K = of_clk_get_by_name(np, "osc_32k"); ++ clksLIGHT_CLK_24M = of_clk_get_by_name(np, "osc_24m"); ++ clksLIGHT_RC_24M = of_clk_get_by_name(np, "rc_24m"); ++ ++ /* AP Fixed PLL */ ++ clksLIGHT_VIDEO_PLL_FOUTVCO = thead_clk_fixed("video_pll_foutvco", 2376000000); ++ clksLIGHT_VIDEO_PLL_FOUTPOSTDIV = thead_clk_fixed("video_pll_foutpostdiv", 796000000); ++ clksLIGHT_GMAC_PLL_FOUTVCO = thead_clk_fixed("gmac_pll_foutvco", 2000000000); ++ clksLIGHT_GMAC_PLL_FOUTPOSTDIV = thead_clk_fixed("gmac_pll_foutpostdiv", 1000000000); ++ ++#ifdef THEAD_LIGHT_AON_CLK ++ /* Aon PLL clocks */ ++ clksLIGHT_AUDIO_PLL_FOUTVCO = thead_light_pll("audio_pll_foutvco", "osc_24m", aon_base, &light_audio_pllvco); ++ clksLIGHT_AUDIO_PLL_FOUTPOSTDIV = thead_light_pll("audio_pll_foutpostdiv", "osc_24m", aon_base, &light_audio_plldiv); ++ clksLIGHT_SYS_PLL_FOUTVCO = thead_light_pll("sys_pll_foutvco", "osc_24m", aon_base, &light_sys_pllvco); ++ clksLIGHT_SYS_PLL_FOUTPOSTDIV = thead_light_pll("sys_pll_foutpostdiv", "osc_24m", aon_base, &light_sys_plldiv); ++#endif ++ ++#ifdef THEAD_LIGHT_DDR_CLK ++ np = of_find_compatible_node(NULL, NULL, "thead,light-ddr-clk"); ++ ddr_base = of_iomap(np, 0); ++ if (WARN_ON(!ddr_base)) { ++ ret = -ENOMEM; ++ goto unregister_clks; ++ } ++ of_node_put(np); ++ ++ /* DDR PLL */ ++ clksLIGHT_DDR_PLL_FOUTVCO = thead_light_pll("ddr_pll_foutvco", "osc_24m", ddr_base, &light_ddr_pllvco); ++ clksLIGHT_DDR_PLL_FOUTPOSTDIV = thead_light_pll("ddr_pll_foutpostdiv", "osc_24m", ddr_base, &light_ddr_plldiv); ++#endif ++ ++ np = dev->of_node; ++ ap_base = devm_platform_ioremap_resource(pdev, 0); ++ if (WARN_ON(IS_ERR(ap_base))) { ++ ret = PTR_ERR(ap_base); ++ goto unregister_clks; ++ } ++ ++ /* AP PLL clocks */ ++ clksLIGHT_CPU_PLL0_FOUTVCO = thead_light_pll("cpu_pll0_foutvco", "osc_24m", ap_base, &light_cpu_pll0vco); ++ clksLIGHT_CPU_PLL0_FOUTPOSTDIV = thead_light_pll("cpu_pll0_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll0div); ++ clksLIGHT_CPU_PLL1_FOUTVCO = thead_light_pll("cpu_pll1_foutvco", "osc_24m", ap_base, &light_cpu_pll1vco); ++ clksLIGHT_CPU_PLL1_FOUTPOSTDIV = thead_light_pll("cpu_pll1_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll1div); ++ ++ /* PLL bypass */ ++#ifdef THEAD_LIGHT_AON_CLK ++ clksLIGHT_AUDIO_PLL_BYPASS = thead_light_clk_mux_flags("audio_pll_bypass", aon_base + 0x4, 31, 1, audio_pll_bypass_sels, ARRAY_SIZE(audio_pll_bypass_sels), CLK_SET_RATE_PARENT); ++ clksLIGHT_SYS_PLL_BYPASS = thead_light_clk_mux_flags("sys_pll_bypass", aon_base + 0x14, 31, 1, sys_pll_bypass_sels, ARRAY_SIZE(sys_pll_bypass_sels), CLK_SET_RATE_PARENT); ++#endif ++#ifdef THEAD_LIGHT_DDR_CLK ++ clksLIGHT_DDR_PLL_BYPASS = thead_light_clk_mux_flags("ddr_pll_bypass", ddr_base + 0xc, 31, 1, ddr_pll_bypass_sels, ARRAY_SIZE(ddr_pll_bypass_sels), CLK_SET_RATE_PARENT); ++#endif ++ clksLIGHT_CPU_PLL0_BYPASS = thead_light_clk_mux_flags("cpu_pll0_bypass", ap_base + 0x4, 31, 1, cpu_pll0_bypass_sels, ARRAY_SIZE(cpu_pll0_bypass_sels), CLK_SET_RATE_PARENT); ++ clksLIGHT_CPU_PLL1_BYPASS = thead_light_clk_mux_flags("cpu_pll1_bypass", ap_base + 0x14, 31, 1, cpu_pll1_bypass_sels, ARRAY_SIZE(cpu_pll1_bypass_sels), CLK_SET_RATE_PARENT); ++ clksLIGHT_GMAC_PLL_BYPASS = thead_light_clk_mux_flags("gmac_pll_bypass", ap_base + 0x24, 31, 1, gmac_pll_bypass_sels, ARRAY_SIZE(gmac_pll_bypass_sels), CLK_SET_RATE_PARENT); ++ clksLIGHT_VIDEO_PLL_BYPASS = thead_light_clk_mux_flags("video_pll_bypass", ap_base + 0x34, 31, 1, video_pll_bypass_sels, ARRAY_SIZE(video_pll_bypass_sels), CLK_SET_RATE_PARENT); ++ ++ /* PLL FOUT */ ++#ifdef THEAD_LIGHT_AON_CLK ++ clksLIGHT_AUDIO_PLL_FOUT3 = thead_light_clk_fixed_factor("audio_pll_fout3", "audio_pll_bypass", 1, 6); ++ clksLIGHT_SYS_PLL_FOUT4 = thead_light_clk_fixed_factor("sys_pll_fout4", "sys_pll_bypass", 1, 8); ++#endif ++#ifdef THEAD_LIGHT_DDR_CLK ++ clksLIGHT_DDR_PLL_FOUT4 = thead_light_clk_fixed_factor("ddr_pll_fout4", "ddr_pll_bypass", 1, 8); ++#endif ++ clksLIGHT_CPU_PLL0_FOUT4 = thead_light_clk_fixed_factor("cpu_pll0_fout4", "cpu_pll0_bypass", 1, 8); ++ clksLIGHT_CPU_PLL1_FOUT4 = thead_light_clk_fixed_factor("cpu_pll1_fout4", "cpu_pll1_bypass", 1, 8); ++ clksLIGHT_GMAC_PLL_FOUT1PH0 = thead_light_clk_fixed_factor("gmac_pll_fout1ph0", "gmac_pll_bypass", 1, 2); ++ clksLIGHT_GMAC_CORECLK = thead_light_clk_fixed_factor("gmac_coreclk", "gmac_pll_fout1ph0", 1, 1); ++ clksLIGHT_GMAC_PLL_FOUT4 = thead_light_clk_fixed_factor("gmac_pll_fout4", "gmac_pll_bypass", 1, 8); ++ clksLIGHT_VIDEO_PLL_FOUT4 = thead_light_clk_fixed_factor("video_pll_fout4", "video_pll_bypass", 1, 8); ++ clksLIGHT_GMAC_PLL_FOUTVCO_DIV5 = thead_light_clk_fixed_factor("gmac_pll_foutvco_div5", "gmac_pll_foutvco", 1, 5); ++ clksLIGHT_OSC_CLK_DIV24 = thead_light_clk_fixed_factor("osc_clk_div24", "osc_24m", 1, 24); ++ clksLIGHT_CHIP_DBG_CCLK = thead_light_clk_fixed_factor("chip_dbg_cclk", "osc_24m", 1, 1); ++ clksLIGHT_AXI_ACLK = thead_light_clk_fixed_factor("cpusys_axi_aclk", "cpu_pll0_bypass", 1, 2); ++ clksLIGHT_X2H_HCLK = thead_light_clk_fixed_factor("aonsys_x2h_hclk", "osc_24m", 1, 1); ++ clksLIGHT_EMMC_CLK_DIV = thead_light_clk_fixed_factor("emmc_clk_div", "video_pll_bypass", 1, 4); ++ clksLIGHT_EMMC0_OSC_CLK = thead_light_clk_fixed_factor("emmc0_osc_clk", "osc_24m", 1, 1); ++ clksLIGHT_EMMC1_OSC_CLK = thead_light_clk_fixed_factor("emmc1_osc_clk", "osc_24m", 1, 1); ++ clksLIGHT_PWM_CCLK = thead_light_clk_fixed_factor("pwm_cclk", "osc_24m", 1, 1); ++ clksLIGHT_USB3_PHY_REF_CLK = thead_light_clk_fixed_factor("usb3_phy_ref_clk", "osc_24m", 1, 1); ++ clksLIGHT_SPI_CLK = thead_light_clk_fixed_factor("spi_clk", "gmac_pll_foutvco_div5", 1, 1); ++ clksLIGHT_GPIO_DBCLK = thead_light_clk_fixed_factor("gpio_dbclk", "osc_32k", 1, 1); ++ ++#ifdef THEAD_LIGHT_AON_CLK ++ /* Aon sys mux tree */ ++ clksLIGHT_AONSYS_CLK_SWITCH_0 = thead_light_clk_mux_flags("aonsys_clk_switch_0", aon_base + 0x100, 4, 1, aonsys_clk_switch_0_sels, ARRAY_SIZE(aonsys_clk_switch_0_sels), CLK_SET_RATE_PARENT); ++ clksLIGHT_AONSYS_CLK_SWITCH_1 = thead_light_clk_mux_flags("aonsys_clk_switch_1", aon_base + 0x100, 5, 1, aonsys_clk_switch_1_sels, ARRAY_SIZE(aonsys_clk_switch_1_sels), CLK_SET_RATE_PARENT); ++ ++ /* Aon sys div tree */ ++ clksLIGHT_AONSYS_CLK = thead_clk_light_divider("aonsys_clk", "aonsys_clk_switch_1", aon_base + 0x100, 0, 3, 3, MUX_TYPE_CDE, 0, 7); ++ clksLIGHT_SHARE_SRAM_CLK = thead_clk_light_divider("share_sram_clk", "sys_pll_foutvco", aon_base + 0x104, 0, 4, 4, MUX_TYPE_DIV, 3, 12); ++ ++ /* Aon sys gate tree */ ++ clksLIGHT_CLKGEN_RTC_PCLK = thead_clk_light_gate("rtc_pclk_en", "aonsys_clk", aon_base + 0x120, 0); ++ clksLIGHT_CLKGEN_AOGPIO_PCLK = thead_clk_light_gate("aogpio_pclk_en", "aonsys_clk", aon_base + 0x120, 1); ++ clksLIGHT_CLKGEN_AOI2C_PCLK = thead_clk_light_gate("aoi2c_pclk_en", "aonsys_clk", aon_base + 0x120, 2); ++ clksLIGHT_CLKGEN_PVTC_PCLK = thead_clk_light_gate("pvtc_pclk_en", "aonsys_clk", aon_base + 0x120, 3); ++ clksLIGHT_CLKGEN_SRAM_AXI_ACLK = thead_clk_light_gate("share_sram_clk_en", "aonsys_clk", aon_base + 0x120, 4); ++ clksLIGHT_CLKGEN_AOPAD_PCLK = thead_clk_light_gate("aopad_pclk_en", "aonsys_clk", aon_base + 0x120, 5); ++ clksLIGHT_CLKGEN_AOAPB_HCLK = thead_clk_light_gate("aoapb_hclk_en", "aonsys_clk", aon_base + 0x120, 6); ++ clksLIGHT_CLKGEN_AOSRAM_HCLK = thead_clk_light_gate("aosram_hclk_en", "aonsys_clk", aon_base + 0x120, 7); ++ clksLIGHT_CLKGEN_AOAHB_HCLK = thead_clk_light_gate("aoahb_hclk_en", "aonsys_clk", aon_base + 0x120, 8); ++ clksLIGHT_CLKGEN_AOGPIO_DBCLK = thead_clk_light_gate("aogpio_dbclk_en", "aonsys_clk", aon_base + 0x120, 9); ++ clksLIGHT_CLKGEN_AOTIMER_PCLK = thead_clk_light_gate("aotimer_pclk_en", "aonsys_clk", aon_base + 0x120, 10); ++ clksLIGHT_CLKGEN_AOTIMER_CCLK = thead_clk_light_gate("aotimer_cclk_en", "aonsys_clk", aon_base + 0x120, 11); ++ clksLIGHT_CLKGEN_CPU2RAM_X2X_ACLK_S = thead_clk_light_gate("apsys_clk_en", "aonsys_clk", aon_base + 0x130, 0); ++#endif ++ ++ /* AP sys mux tree */ ++ clksLIGHT_C910_CCLK_I0 = thead_light_clk_mux_flags("c910_cclk_i0", ap_base + 0x100, 1, 1, c910_cclk_i0_sels, ARRAY_SIZE(c910_cclk_i0_sels), CLK_SET_RATE_PARENT); ++ clksLIGHT_C910_CCLK = thead_light_clk_mux_flags("c910_cclk", ap_base + 0x100, 0, 1, c910_cclk_sels, ARRAY_SIZE(c910_cclk_sels), CLK_SET_RATE_PARENT); ++ clksLIGHT_CPUSYS_AHB_HCLK = thead_light_clk_mux_flags("cpusys_ahb_hclk", ap_base + 0x120, 5, 1, cpusys_ahb_hclk_sel, ARRAY_SIZE(cpusys_ahb_hclk_sel), CLK_SET_RATE_PARENT); ++ clksLIGHT_CPUSYS_CFG_AXI_ACLK = thead_light_clk_mux_flags("cpusys_cfg_axi_aclk", ap_base + 0x138, 5, 1, cpusys_cfg_axi_aclk_sel, ARRAY_SIZE(cpusys_cfg_axi_aclk_sel), CLK_SET_RATE_PARENT); ++ clksLIGHT_PERISYS_AHB_HCLK = thead_light_clk_mux_flags("perisys_ahb_hclk", ap_base + 0x40, 5, 1, perisys_ahb_hclk_sel, ARRAY_SIZE(perisys_ahb_hclk_sel), CLK_SET_RATE_PARENT); ++ clksLIGHT_CLK_OUT_1 = thead_light_clk_mux_flags("clk_out_1", ap_base + 0x1b4, 4, 1, clk_out_1_sel, ARRAY_SIZE(clk_out_1_sel), CLK_SET_RATE_PARENT); ++ clksLIGHT_CLK_OUT_2 = thead_light_clk_mux_flags("clk_out_2", ap_base + 0x1b8, 4, 1, clk_out_2_sel, ARRAY_SIZE(clk_out_2_sel), CLK_SET_RATE_PARENT); ++ clksLIGHT_CLK_OUT_3 = thead_light_clk_mux_flags("clk_out_3", ap_base + 0x1bc, 4, 1, clk_out_3_sel, ARRAY_SIZE(clk_out_3_sel), CLK_SET_RATE_PARENT); ++ clksLIGHT_CLK_OUT_4 = thead_light_clk_mux_flags("clk_out_4", ap_base + 0x1c0, 4, 1, clk_out_4_sel, ARRAY_SIZE(clk_out_4_sel), CLK_SET_RATE_PARENT); ++ ++ /* AP sys div tree */ ++ clksLIGHT_CPUSYS_AHB_HCLK_DIV = thead_clk_light_divider("cpusys_ahb_hclk_div", "gmac_pll_fout1ph0", ap_base + 0x120, 0, 4, 4, MUX_TYPE_DIV, 2, 8); ++ clksLIGHT_APB3_CPUSYS_PCLK = thead_clk_light_divider("apb3_cpusys_pclk", "cpusys_ahb_hclk", ap_base + 0x130, 0, 3, 3, MUX_TYPE_CDE, 1, 7); ++ clksLIGHT_CPUSYS_SUB_AXI_ACLK = thead_clk_light_divider("cpusys_sub_axi_aclk", "gmac_pll_bypass", ap_base + 0x134, 0, 4, 4, MUX_TYPE_DIV, 2, 8); ++ clksLIGHT_CPUSYS_CFG_AXI_ACLK_DIV = thead_clk_light_divider("cpusys_cfg_axi_aclk_div", "gmac_pll_bypass", ap_base + 0x138, 0, 4, 4, MUX_TYPE_DIV, 8, 15); ++ clksLIGHT_TEESYS_HCLK = thead_clk_light_divider("teesys_hclk", "gmac_pll_fout1ph0", ap_base + 0x154, 0, 2, 2, MUX_TYPE_DIV, 2, 3); ++ clksLIGHT_DMAC_1_CLK = thead_clk_light_divider("dmac_1_clk", "video_pll_bypass", ap_base + 0x158, 0, 2, 2, MUX_TYPE_CDE, 0, 7); ++ clksLIGHT_DMAC_2_CLK = thead_clk_light_divider("dmac_2_clk", "video_pll_bypass", ap_base + 0x16c, 0, 2, 2, MUX_TYPE_CDE, 0, 7); ++ clksLIGHT_DMAC_3_CLK = thead_clk_light_divider("dmac_3_clk", "gmac_pll_bypass", ap_base + 0x160, 0, 2, 2, MUX_TYPE_CDE, 0, 7); ++ clksLIGHT_AXI_PORT4_CLK = thead_clk_light_divider("axi_port4_clk", "video_pll_bypass", ap_base + 0x164, 0, 2, 2, MUX_TYPE_CDE, 0, 7); ++ clksLIGHT_PERISYS_AHB_HCLK_DIV = thead_clk_light_divider("perisys_ahb_hclk_div", "gmac_pll_fout1ph0", ap_base + 0x140, 0, 4, 4, MUX_TYPE_DIV, 2, 8); ++ clksLIGHT_PERISYS_APB_PCLK = thead_clk_light_divider("perisys_apb_pclk", "perisys_ahb_hclk", ap_base + 0x150, 0, 3, 3, MUX_TYPE_CDE, 3, 7); ++ clksLIGHT_CLK_OUT_1_DIV = thead_clk_light_divider("clk_out_1_div", "osc_24m", ap_base + 0x1b4, 0, 3, 3, MUX_TYPE_DIV, 2, 7); ++ clksLIGHT_CLK_OUT_2_DIV = thead_clk_light_divider("clk_out_2_div", "osc_24m", ap_base + 0x1b8, 0, 3, 3, MUX_TYPE_DIV, 2, 7); ++ clksLIGHT_CLK_OUT_3_DIV = thead_clk_light_divider("clk_out_3_div", "osc_24m", ap_base + 0x1bc, 0, 3, 3, MUX_TYPE_DIV, 2, 7); ++ clksLIGHT_CLK_OUT_4_DIV = thead_clk_light_divider("clk_out_4_div", "osc_24m", ap_base + 0x1c0, 0, 3, 3, MUX_TYPE_DIV, 2, 7); ++ ++ /* AP sys gate tree */ ++ clksLIGHT_CLKGEN_PERISYS_AXI_ACLK = thead_clk_light_gate("clkgen_perisys_axi_aclk", "perisys_ahb_hclk", ap_base + 0x200, 31); ++ clksLIGHT_CLKGEN_PERISYS_AHB_HCLK = thead_clk_light_gate("clkgen_perisys_ahb_hclk", "perisys_ahb_hclk", ap_base + 0x200, 30); ++ clksLIGHT_CLKGEN_PERISYS_APB1_HCLK = thead_clk_light_gate("clkgen_perisys_apb1_hclk", "perisys_ahb_hclk", ap_base + 0x200, 29); ++ clksLIGHT_CLKGEN_PERISYS_APB2_HCLK = thead_clk_light_gate("clkgen_perisys_apb2_hclk", "perisys_ahb_hclk", ap_base + 0x200, 28); ++ clksLIGHT_CLKGEN_USB3_DRD_PHY_REF_CLK = thead_clk_light_gate("clkgen_usb3_drd_phy_ref_clk", "usb3_phy_ref_clk", ap_base + 0x200, 27); ++ clksLIGHT_CLKGEN_USB3_DRD_CTRL_REF_CLK = thead_clk_light_gate("clkgen_usb3_drd_ctrl_ref_clk", "usb3_ctrl_ref_clk", ap_base + 0x200, 26); ++ clksLIGHT_CLKGEN_USB3_DRD_SPDCLK = thead_clk_light_gate("clkgen_usb3_drd_spdclk", "osc_clk_div24", ap_base + 0x200, 25); ++ clksLIGHT_CLKGEN_EMMC1_X2X_ACLK = thead_clk_light_gate("clkgen_emmc1_x2x_aclk", "perisys_ahb_hclk", ap_base + 0x200, 23); ++ clksLIGHT_CLKGEN_EMMC0_X2X_ACLK = thead_clk_light_gate("clkgen_emmc0_x2x_aclk", "perisys_ahb_hclk", ap_base + 0x200, 22); ++ clksLIGHT_CLKGEN_UART0_PCLK = thead_clk_light_gate("clkgen_uart0_pclk", "perisys_apb_pclk", ap_base + 0x200, 14); ++ clksLIGHT_CLKGEN_UART1_PCLK = thead_clk_light_gate("clkgen_uart1_pclk", "perisys_apb_pclk", ap_base + 0x200, 13); ++ clksLIGHT_CLKGEN_UART2_PCLK = thead_clk_light_gate("clkgen_uart2_pclk", "perisys_apb_pclk", ap_base + 0x200, 12); ++ clksLIGHT_CLKGEN_UART3_PCLK = thead_clk_light_gate("clkgen_uart3_pclk", "perisys_apb_pclk", ap_base + 0x200, 11); ++ clksLIGHT_CLKGEN_UART4_PCLK = thead_clk_light_gate("clkgen_uart4_pclk", "perisys_apb_pclk", ap_base + 0x200, 10); ++ clksLIGHT_CLKGEN_UART5_PCLK = thead_clk_light_gate("clkgen_uart5_pclk", "perisys_apb_pclk", ap_base + 0x200, 9); ++ clksLIGHT_CLKGEN_I2C0_IC_CLK = thead_clk_light_gate("clkgen_i2c0_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 5); ++ clksLIGHT_CLKGEN_I2C1_IC_CLK = thead_clk_light_gate("clkgen_i2c1_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 4); ++ clksLIGHT_CLKGEN_I2C2_IC_CLK = thead_clk_light_gate("clkgen_i2c2_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 3); ++ clksLIGHT_CLKGEN_I2C3_IC_CLK = thead_clk_light_gate("clkgen_i2c3_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 2); ++ clksLIGHT_CLKGEN_I2C4_IC_CLK = thead_clk_light_gate("clkgen_i2c4_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 1); ++ clksLIGHT_CLKGEN_I2C5_IC_CLK = thead_clk_light_gate("clkgen_i2c5_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 0); ++ ++ clksLIGHT_CLKGEN_AXI_DUMMY_SLV_4_ACLK = thead_clk_light_gate("clkgen_axi_dummy_slv_4_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 28); ++ clksLIGHT_CLKGEN_AXI_DUMMY_SLV_3_ACLK = thead_clk_light_gate("clkgen_axi_dummy_slv_3_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 27); ++ clksLIGHT_CLKGEN_AXI_DUMMY_SLV_2_ACLK = thead_clk_light_gate("clkgen_axi_dummy_slv_2_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 26); ++ clksLIGHT_CLKGEN_AXI_DUMMY_SLV_1_ACLK = thead_clk_light_gate("clkgen_axi_dummy_slv_1_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 25); ++ clksLIGHT_CLKGEN_APB_CPU2FG_HCLK = thead_clk_light_gate("clkgen_apb_cpu2cfg_hclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 24); ++ clksLIGHT_CLKGEN_CPU2RAM_X2X_ACLK_M = thead_clk_light_gate("clkgen_cpu2ram_x2x_aclk_m", "cpusys_axi_aclk", ap_base + 0x204, 21); ++ clksLIGHT_CLKGEN_AXI4_CPUSYS2_ACLK = thead_clk_light_gate("clkgen_axi4_cpusys2_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 20); ++ clksLIGHT_CLKGEN_X2X_CPUSYS_ACLK_M = thead_clk_light_gate("clkgen_x2x_cpusys_aclk_m", "cpusys_sub_axi_aclk", ap_base + 0x204, 19); ++ clksLIGHT_CLKGEN_CHIP_DBG_ACLK = thead_clk_light_gate("clkgen_chip_dbg_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 18); ++ clksLIGHT_CLKGEN_AXI4_CFG_BUS_ACLK = thead_clk_light_gate("clkgen_axi4_cfg_bus_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 17); ++ clksLIGHT_CLKGEN_AHB2_CPUSYS_HCLK = thead_clk_light_gate("clkgen_ahb2_cpusys_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 11); ++ clksLIGHT_CLKGEN_APB3_CPUSYS_HCLK = thead_clk_light_gate("clkgen_apb3_cpusys_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 10); ++ clksLIGHT_CLKGEN_C910_BROM_HCLK = thead_clk_light_gate("clkgen_c910_brom_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 9); ++ clksLIGHT_CLKGEN_MBOX0_PCLK = thead_clk_light_gate("clkgen_mbox0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 7); ++ clksLIGHT_CLKGEN_MBOX1_PCLK = thead_clk_light_gate("clkgen_mbox1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 6); ++ clksLIGHT_CLKGEN_MBOX2_PCLK = thead_clk_light_gate("clkgen_mbox2_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 5); ++ clksLIGHT_CLKGEN_MBOX3_PCLK = thead_clk_light_gate("clkgen_mbox3_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 4); ++ clksLIGHT_CLKGEN_WDT0_PCLK = thead_clk_light_gate("clkgen_wdt0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 3); ++ clksLIGHT_CLKGEN_WDT1_PCLK = thead_clk_light_gate("clkgen_wdt1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 2); ++ ++ clksLIGHT_CLKGEN_TRNG_RB_HCLK = thead_clk_light_gate("clkgen_trng_rb_hclk", "teesys_hclk", ap_base + 0x208, 19); ++ clksLIGHT_CLKGEN_ADC_PCLK = thead_clk_light_gate("clkgen_adc_pclk", "perisys_apb_pclk", ap_base + 0x208, 18); ++ clksLIGHT_CLKGEN_AXI_ACLK_4 = thead_clk_light_gate("axi_aclk_4", "axi_port4_clk", ap_base + 0x208, 17); ++ clksLIGHT_CLKGEN_AXI_ACLK_3 = thead_clk_light_gate("axi_aclk_3", "dmac_3_clk", ap_base + 0x208, 16); ++ clksLIGHT_CLKGEN_AXI_ACLK_2 = thead_clk_light_gate("axi_aclk_2", "dmac_2_clk", ap_base + 0x208, 15); ++ clksLIGHT_CLKGEN_AXI_ACLK_1 = thead_clk_light_gate("axi_aclk_1", "dmac_1_clk", ap_base + 0x208, 14); ++ clksLIGHT_CLKGEN_AXI_ACLK_0 = thead_clk_light_gate("axi_aclk_0", "cpusys_axi_aclk", ap_base + 0x208, 13); ++ clksLIGHT_CLKGEN_SRAM_AXI_PCLK = thead_clk_light_gate("clkgen_sram_axi_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 9); ++ clksLIGHT_CLKGEN_AHB2_TEESYS_HCLK = thead_clk_light_gate("clkgen_ahb2_teesys_hclk", "teesys_hclk", ap_base + 0x208, 8); ++ clksLIGHT_CLKGEN_EFUSE_MPW_PCLK = thead_clk_light_gate("clkgen_efuse_mpw_pclk", "perisys_apb_pclk", ap_base + 0x208, 7); ++ clksLIGHT_CLKGEN_CLK_OUT_4_CLK = thead_clk_light_gate("clkgen_clk_out_4_clk", "clk_out_4", ap_base + 0x208, 6); ++ clksLIGHT_CLKGEN_CLK_OUT_3_CLK = thead_clk_light_gate("clkgen_clk_out_3_clk", "clk_out_3", ap_base + 0x208, 5); ++ clksLIGHT_CLKGEN_CLK_OUT_2_CLK = thead_clk_light_gate("clkgen_clk_out_2_clk", "clk_out_2", ap_base + 0x208, 4); ++ clksLIGHT_CLKGEN_CLK_OUT_1_CLK = thead_clk_light_gate("clkgen_clk_out_1_clk", "clk_out_1", ap_base + 0x208, 3); ++ clksLIGHT_CLKGEN_DDR_APB_PCLK = thead_clk_light_gate("clkgen_ddr_apb_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 2); ++ clksLIGHT_CLKGEN_PADCTRL_APSYS_PCLK = thead_clk_light_gate("clkgen_padctrl_apsys_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 1); ++ clksLIGHT_CLKGEN_CHIP_DBG_CCLK = thead_clk_light_gate("clkgen_chip_dbg_cclk", "chip_dbg_cclk", ap_base + 0x208, 0); ++ ++ /* register AP shared gate */ ++ clksLIGHT_CLKGEN_CPU2CFG_X2X_ACLK_M = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2x_aclk_m", "cpusys_axi_aclk", ap_base + 0x204, 22, &share_cnt_cpu2cfg_x2x_clk_en); ++ clksLIGHT_CLKGEN_CPU2CFG_X2X_ACLK_S = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2x_aclk_s", "cpusys_cfg_axi_aclk", ap_base + 0x204, 22, &share_cnt_cpu2cfg_x2x_clk_en); ++ clksLIGHT_CLKGEN_CPU2PERI_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_mhclk", "perisys_ahb_hclk", ap_base + 0x204, 12, &share_cnt_cpu2peri_x2h_clk_en); ++ clksLIGHT_CLKGEN_CPU2CFG_X2H_ACLK_S = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_aclk", "cpusys_axi_aclk", ap_base + 0x204, 12, &share_cnt_cpu2peri_x2h_clk_en); ++ clksLIGHT_CLKGEN_AON2CPU_A2X_ACLK = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 23, &share_cnt_aon2cpu_a2x_clk_en); ++ clksLIGHT_CLKGEN_AON2CPU_A2X_HCLK = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_hclk", "aonsys_x2h_hclk", ap_base + 0x204, 23, &share_cnt_aon2cpu_a2x_clk_en); ++ clksLIGHT_CLKGEN_DMAC_ACLK = thead_clk_light_gate_shared("clkgen_dmac_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 8, &share_cnt_dmac_clk_en); ++ clksLIGHT_CLKGEN_DMAC_HCLK = thead_clk_light_gate_shared("clkgen_dmac_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 8, &share_cnt_dmac_clk_en); ++ clksLIGHT_CLKGEN_X2H_CPUSYS_ACLK = thead_clk_light_gate_shared("clkgen_x2h_cpusys_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 16, &share_cnt_x2h_cpusys_clk_en); ++ clksLIGHT_CLKGEN_X2H_CPUSYS_MHCLK = thead_clk_light_gate_shared("clkgen_x2h_cpusys_mhclk", "cpusys_ahb_hclk", ap_base + 0x204, 16, &share_cnt_x2h_cpusys_clk_en); ++ clksLIGHT_CLKGEN_CPU2TEE_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2tee_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 15, &share_cnt_cpu2tee_x2h_clk_en); ++ clksLIGHT_CLKGEN_CPU2TEE_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2tee_x2h_mhclk", "teesys_hclk", ap_base + 0x204, 15, &share_cnt_cpu2tee_x2h_clk_en); ++ clksLIGHT_CLKGEN_CPU2AON_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 14, &share_cnt_cpu2aon_x2h_clk_en); ++ clksLIGHT_CLKGEN_CPU2AON_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_mhclk", "aonsys_x2h_hclk", ap_base + 0x204, 14, &share_cnt_cpu2aon_x2h_clk_en); ++ clksLIGHT_CLKGEN_CPU2CFG_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 13, &share_cnt_cpu2cfg_x2h_clk_en); ++ clksLIGHT_CLKGEN_CPU2CFG_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2h_mhclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 13, &share_cnt_cpu2cfg_x2h_clk_en); ++ clksLIGHT_CLKGEN_TIMER0_CCLK = thead_clk_light_gate_shared("clkgen_timer0_cclk", "apb3_cpusys_pclk", ap_base + 0x204, 1, &share_cnt_timer0_clk_en); ++ clksLIGHT_CLKGEN_TIMER0_PCLK = thead_clk_light_gate_shared("clkgen_timer0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 1, &share_cnt_timer0_clk_en); ++ clksLIGHT_CLKGEN_TIMER1_CCLK = thead_clk_light_gate_shared("clkgen_timer1_cclk", "apb3_cpusys_pclk", ap_base + 0x204, 0, &share_cnt_timer1_clk_en); ++ clksLIGHT_CLKGEN_TIMER1_PCLK = thead_clk_light_gate_shared("clkgen_timer1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 0, &share_cnt_timer1_clk_en); ++ clksLIGHT_CLKGEN_PERI2DDR_X2X_ACLK_M = thead_clk_light_gate_shared("clkgen_peri2ddr_x2x_aclk_m", "perisys_ahb_hclk", ap_base + 0x204, 29, &share_cnt_peri2ddr_x2x_clk_en); ++ clksLIGHT_CLKGEN_PERI2DDR_X2X_ACLK_S = thead_clk_light_gate_shared("clkgen_peri2ddr_x2x_aclk_s", "axi_port4_clk", ap_base + 0x204, 29, &share_cnt_peri2ddr_x2x_clk_en); ++ clksLIGHT_CLKGEN_USB3_DRD_ACLK = thead_clk_light_gate_shared("clkgen_usb3_drd_aclk", "perisys_ahb_hclk", ap_base + 0x200, 24, &share_cnt_usb3_drd_clk_en); ++ clksLIGHT_CLKGEN_USB3_DRD_PCLK = thead_clk_light_gate_shared("clkgen_usb3_drd_pclk", "perisys_apb_pclk", ap_base + 0x200, 24, &share_cnt_usb3_drd_clk_en); ++ clksLIGHT_CLKGEN_GMAC_HCLK = thead_clk_light_gate_shared("clkgen_gmac_hclk", "perisys_ahb_hclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); ++ clksLIGHT_CLKGEN_GMAC_ACLK = thead_clk_light_gate_shared("clkgen_gmac_aclk", "perisys_ahb_hclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); ++ clksLIGHT_CLKGEN_GMAC_PCLK = thead_clk_light_gate_shared("clkgen_gmac_pclk", "perisys_apb_pclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); ++ clksLIGHT_CLKGEN_GMAC_CCLK = thead_clk_light_gate_shared("clkgen_gmac_cclk", "gmac_coreclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); ++ clksLIGHT_CLKGEN_EMMC0_HCLK = thead_clk_light_gate_shared("clkgen_emmc0_hclk", "perisys_ahb_hclk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); ++ clksLIGHT_CLKGEN_EMMC0_ACLK = thead_clk_light_gate_shared("clkgen_emmc0_aclk", "perisys_ahb_hclk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); ++ clksLIGHT_CLKGEN_EMMC0_REF_CLK = thead_clk_light_gate_shared("clkgen_emmc0_ref_clk", "emmc_clk_div", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); ++ clksLIGHT_CLKGEN_EMMC0_OSC_CLK = thead_clk_light_gate_shared("clkgen_emmc0_osc_clk", "emmc0_osc_clk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); ++ clksLIGHT_CLKGEN_EMMC1_HCLK = thead_clk_light_gate_shared("clkgen_emmc1_hclk", "perisys_ahb_hclk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); ++ clksLIGHT_CLKGEN_EMMC1_ACLK = thead_clk_light_gate_shared("clkgen_emmc1_aclk", "perisys_ahb_hclk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); ++ clksLIGHT_CLKGEN_EMMC1_REF_CLK = thead_clk_light_gate_shared("clkgen_emmc1_ref_clk", "emmc_clk_div", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); ++ clksLIGHT_CLKGEN_EMMC1_OSC_CLK = thead_clk_light_gate_shared("clkgen_emmc1_osc_clk", "emmc1_osc_clk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); ++ clksLIGHT_CLKGEN_PWM_PCLK = thead_clk_light_gate_shared("clkgen_pwm_pclk", "perisys_ahb_hclk", ap_base + 0x200, 18, &share_cnt_pwm_clk_en); ++ clksLIGHT_CLKGEN_PWM_CCLK = thead_clk_light_gate_shared("clkgen_pwm_cclk", "pwm_cclk", ap_base + 0x200, 18, &share_cnt_pwm_clk_en); ++ clksLIGHT_CLKGEN_QSPI0_PCLK = thead_clk_light_gate_shared("clkgen_qspi0_pclk", "perisys_apb_pclk", ap_base + 0x200, 17, &share_cnt_qspi0_clk_en); ++ clksLIGHT_CLKGEN_QSPI0_SSI_CLK = thead_clk_light_gate_shared("clkgen_qspi0_ssi_clk", "spi_clk", ap_base + 0x200, 17, &share_cnt_qspi0_clk_en); ++ clksLIGHT_CLKGEN_QSPI1_PCLK = thead_clk_light_gate_shared("clkgen_qspi1_pclk", "perisys_apb_pclk", ap_base + 0x200, 16, &share_cnt_qspi1_clk_en); ++ clksLIGHT_CLKGEN_QSPI1_SSI_CLK = thead_clk_light_gate_shared("clkgen_qspi1_ssi_clk", "spi_clk", ap_base + 0x200, 16, &share_cnt_qspi0_clk_en); ++ clksLIGHT_CLKGEN_SPI_PCLK = thead_clk_light_gate_shared("clkgen_spi_pclk", "perisys_apb_pclk", ap_base + 0x200, 15, &share_cnt_spi_clk_en); ++ clksLIGHT_CLKGEN_SPI_SSI_CLK = thead_clk_light_gate_shared("clkgen_spi_ssi_clk", "spi_clk", ap_base + 0x200, 15, &share_cnt_spi_clk_en); ++ clksLIGHT_CLKGEN_GPIO0_PCLK = thead_clk_light_gate_shared("clkgen_gpio0_pclk", "perisys_apb_pclk", ap_base + 0x200, 8, &share_cnt_gpio0_clk_en); ++ clksLIGHT_CLKGEN_GPIO0_DBCLK = thead_clk_light_gate_shared("clkgen_gpio0_dbclk", "gpio_dbclk", ap_base + 0x200, 8, &share_cnt_gpio0_clk_en); ++ clksLIGHT_CLKGEN_GPIO1_PCLK = thead_clk_light_gate_shared("clkgen_gpio1_pclk", "perisys_apb_pclk", ap_base + 0x200, 7, &share_cnt_gpio1_clk_en); ++ clksLIGHT_CLKGEN_GPIO1_DBCLK = thead_clk_light_gate_shared("clkgen_gpio1_dbclk", "gpio_dbclk", ap_base + 0x200, 7, &share_cnt_gpio1_clk_en); ++ clksLIGHT_CLKGEN_GPIO2_PCLK = thead_clk_light_gate_shared("clkgen_gpio2_pclk", "perisys_apb_pclk", ap_base + 0x200, 6, &share_cnt_gpio2_clk_en); ++ clksLIGHT_CLKGEN_GPIO2_DBCLK = thead_clk_light_gate_shared("clkgen_gpio2_dbclk", "gpio_dbclk", ap_base + 0x200, 6, &share_cnt_gpio2_clk_en); ++ clksLIGHT_CLKGEN_DMAC_1_ACLK = thead_clk_light_gate_shared("clkgen_dmac_1_aclk", "dmac_1_clk", ap_base + 0x208, 12, &share_cnt_dmac_1_clk_en); ++ clksLIGHT_CLKGEN_DMAC_1_HCLK = thead_clk_light_gate_shared("clkgen_dmac_1_hclk", "teesys_hclk", ap_base + 0x208, 12, &share_cnt_dmac_1_clk_en); ++ clksLIGHT_CLKGEN_DMAC_2_ACLK = thead_clk_light_gate_shared("clkgen_dmac_2_aclk", "dmac_2_clk", ap_base + 0x208, 11, &share_cnt_dmac_2_clk_en); ++ clksLIGHT_CLKGEN_DMAC_2_HCLK = thead_clk_light_gate_shared("clkgen_dmac_2_hclk", "teesys_hclk", ap_base + 0x208, 11, &share_cnt_dmac_2_clk_en); ++ clksLIGHT_CLKGEN_DMAC_3_ACLK = thead_clk_light_gate_shared("clkgen_dmac_3_aclk", "dmac_3_clk", ap_base + 0x208, 10, &share_cnt_dmac_3_clk_en); ++ clksLIGHT_CLKGEN_DMAC_3_HCLK = thead_clk_light_gate_shared("clkgen_dmac_3_hclk", "teesys_hclk", ap_base + 0x208, 10, &share_cnt_dmac_3_clk_en); ++ ++ clk_data.clks = clks; ++ clk_data.clk_num = ARRAY_SIZE(clks); ++ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); ++ ++ if (ret < 0) { ++ dev_err(dev, "failed to register clks for light\n"); ++ goto unregister_clks; ++ } ++ ++ /* HW defalut */ ++ clk_set_parent(clksLIGHT_C910_CCLK, clksLIGHT_CPU_PLL1_FOUTPOSTDIV); ++ ++ return 0; ++ ++unregister_clks: ++ thead_unregister_clocks(clks, ARRAY_SIZE(clks)); ++ return ret; ++} ++ ++static const struct of_device_id light_clk_of_match = { ++ { .compatible = "thead,light-mpw-clk" }, ++ { /* Sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, light_clk_of_match); ++ ++static struct platform_driver light_clk_driver = { ++ .probe = light_clocks_probe, ++ .driver = { ++ .name = "light-mpw-clk", ++ .of_match_table = of_match_ptr(light_clk_of_match), ++ }, ++}; ++ ++module_platform_driver(light_clk_driver); ++MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light MPW clock driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/clk/thead/clk.c b/drivers/clk/thead/clk.c +new file mode 100644 +index 000000000000..2e181a9fd180 +--- /dev/null ++++ b/drivers/clk/thead/clk.c +@@ -0,0 +1,739 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++#include <linux/clk.h> ++#include <linux/clk-provider.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/iopoll.h> ++#include <linux/of.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++ ++#include "clk.h" ++ ++#define LIGHT_PLL_CFG0 0x0 ++#define LIGHT_PLL_CFG1 0x04 ++#define LIGHT_PLL_CFG2 0x8 ++#define LIGHT_POSTDIV2_SHIFT 24 ++#define LIGHT_POSTDIV2_MASK GENMASK(26, 24) ++#define LIGHT_POSTDIV1_SHIFT 20 ++#define LIGHT_POSTDIV1_MASK GENMASK(22, 20) ++#define LIGHT_FBDIV_SHIFT 8 ++#define LIGHT_FBDIV_MASK GENMASK(19, 8) ++#define LIGHT_REFDIV_SHIFT 0 ++#define LIGHT_REFDIV_MASK GENMASK(5, 0) ++#define LIGHT_BYPASS_MASK BIT(30) ++#define LIGHT_RST_MASK BIT(29) ++#define LIGHT_DSMPD_MASK BIT(24) ++#define LIGHT_DACPD_MASK BIT(25) ++#define LIGHT_FRAC_MASK GENMASK(23, 0) ++#define LIGHT_FRAC_SHIFT 0 ++#define LIGHT_FRAC_DIV BIT(24) ++ ++#define LOCK_TIMEOUT_US 10000 ++ ++#define div_mask(d) ((1 << (d->width)) - 1) ++ ++DEFINE_SPINLOCK(thead_light_clk_lock); ++ ++enum light_pll_mode { ++ PLL_MODE_FRAC, ++ PLL_MODE_INT, ++}; ++ ++struct clk_lightpll { ++ struct clk_hw hw; ++ void __iomem *base; ++ enum light_pll_clktype clk_type; ++ enum light_pll_outtype out_type; ++ enum light_pll_mode pll_mode; ++ const struct light_pll_rate_table *rate_table; ++ int rate_count; ++ ++ u32 cfg0_reg_off; ++ u32 pll_sts_off; ++ int pll_lock_bit; ++ ++ /* Light MPW Aon/ddr pll define bypass:rst bits as: 31:30 ++ * but AP pll define bypass:rst bits as: 30:29 ++ * ++ * Light Fullmask align these register field define, all pll ++ * define bypss:rst bits as: 30:29 ++ */ ++ int pll_rst_bit; ++ int pll_bypass_bit; ++}; ++ ++struct clk_lightdiv { ++ struct clk_divider divider; ++ enum light_div_type div_type; ++ u16 min_div; ++ u16 max_div; ++ u8 sync_en; ++ const struct clk_ops *ops; ++}; ++ ++struct clk_lightgate { ++ struct clk_gate gate; ++ unsigned int *share_count; ++ const struct clk_ops *ops; ++}; ++ ++#define to_clk_lightpll(_hw) container_of(_hw, struct clk_lightpll, hw) ++ ++void thead_unregister_clocks(struct clk *clks, unsigned int count) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < count; i++) ++ clk_unregister(clksi); ++} ++ ++static void clk_light_pll_cfg_init(struct clk_lightpll *pll) ++{ ++ switch (pll->clk_type) { ++ case LIGHT_AUDIO_PLL: ++ pll->cfg0_reg_off = 0x0; ++ pll->pll_sts_off = 0x90; ++ pll->pll_lock_bit = BIT(0); ++ pll->pll_bypass_bit = BIT(31); ++ pll->pll_rst_bit = BIT(30); ++ pll->pll_mode = PLL_MODE_FRAC; ++ break; ++ case LIGHT_SYS_PLL: ++ pll->cfg0_reg_off = 0x10; ++ pll->pll_sts_off = 0x90; ++ pll->pll_lock_bit = BIT(1); ++ pll->pll_bypass_bit = BIT(31); ++ pll->pll_rst_bit = BIT(30); ++ pll->pll_mode = PLL_MODE_FRAC; ++ break; ++ case LIGHT_CPU_PLL0: ++ pll->cfg0_reg_off = 0x0; ++ pll->pll_sts_off = 0x80; ++ pll->pll_lock_bit = BIT(1); ++ pll->pll_bypass_bit = BIT(30); ++ pll->pll_rst_bit = BIT(29); ++ pll->pll_mode = PLL_MODE_INT; ++ break; ++ case LIGHT_CPU_PLL1: ++ pll->cfg0_reg_off = 0x10; ++ pll->pll_sts_off = 0x80; ++ pll->pll_lock_bit = BIT(4); ++ pll->pll_bypass_bit = BIT(30); ++ pll->pll_rst_bit = BIT(29); ++ pll->pll_mode = PLL_MODE_INT; ++ break; ++ case LIGHT_GMAC_PLL: ++ pll->cfg0_reg_off = 0x20; ++ pll->pll_sts_off = 0x80; ++ pll->pll_lock_bit = BIT(3); ++ pll->pll_bypass_bit = BIT(30); ++ pll->pll_rst_bit = BIT(29); ++ pll->pll_mode = PLL_MODE_INT; ++ break; ++ case LIGHT_VIDEO_PLL: ++ pll->cfg0_reg_off = 0x30; ++ pll->pll_sts_off = 0x80; ++ pll->pll_lock_bit = BIT(7); ++ pll->pll_bypass_bit = BIT(30); ++ pll->pll_rst_bit = BIT(29); ++ pll->pll_mode = PLL_MODE_INT; ++ break; ++ case LIGHT_DDR_PLL: ++ pll->cfg0_reg_off = 0x8; ++ pll->pll_sts_off = 0x18; ++ pll->pll_lock_bit = BIT(0); ++ pll->pll_bypass_bit = BIT(31); ++ pll->pll_rst_bit = BIT(30); ++ pll->pll_mode = PLL_MODE_INT; ++ break; ++ case LIGHT_DPU0_PLL: ++ pll->cfg0_reg_off = 0x40; ++ pll->pll_sts_off = 0x80; ++ pll->pll_lock_bit = BIT(8); ++ pll->pll_bypass_bit = BIT(30); ++ pll->pll_rst_bit = BIT(29); ++ pll->pll_mode = PLL_MODE_INT; ++ break; ++ case LIGHT_DPU1_PLL: ++ pll->cfg0_reg_off = 0x50; ++ pll->pll_sts_off = 0x80; ++ pll->pll_lock_bit = BIT(9); ++ pll->pll_bypass_bit = BIT(30); ++ pll->pll_rst_bit = BIT(29); ++ pll->pll_mode = PLL_MODE_INT; ++ break; ++ default: ++ pr_err("%s: Unknown pll type\n", __func__); ++ }; ++} ++ ++static int clk_light_pll_wait_lock(struct clk_lightpll *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_light_pll_prepare(struct clk_hw *hw) ++{ ++ struct clk_lightpll *pll = to_clk_lightpll(hw); ++ void __iomem *cfg1_off; ++ u32 val; ++ int ret; ++ ++ cfg1_off = pll->base + pll->cfg0_reg_off + LIGHT_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_light_pll_wait_lock(pll); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int clk_light_pll_is_prepared(struct clk_hw *hw) ++{ ++ struct clk_lightpll *pll = to_clk_lightpll(hw); ++ u32 val; ++ ++ val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); ++ ++ return (val & pll->pll_rst_bit) ? 0 : 1; ++} ++ ++static void clk_light_pll_unprepare(struct clk_hw *hw) ++{ ++ struct clk_lightpll *pll = to_clk_lightpll(hw); ++ u32 val; ++ ++ val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); ++ val |= pll->pll_rst_bit; ++ writel_relaxed(val, pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); ++} ++ ++static unsigned long clk_light_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++#ifndef CONFIG_LIGHT_CLK_EMU ++ struct clk_lightpll *pll = to_clk_lightpll(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 + LIGHT_PLL_CFG1); ++ refdiv = (pll_cfg0 & LIGHT_REFDIV_MASK) >> LIGHT_REFDIV_SHIFT; ++ fbdiv = (pll_cfg0 & LIGHT_FBDIV_MASK) >> LIGHT_FBDIV_SHIFT; ++ postdiv1 = (pll_cfg0 & LIGHT_POSTDIV1_MASK) >> LIGHT_POSTDIV1_SHIFT; ++ postdiv2 = (pll_cfg0 & LIGHT_POSTDIV2_MASK) >> LIGHT_POSTDIV2_SHIFT; ++ frac = (pll_cfg1 & LIGHT_FRAC_MASK) >> LIGHT_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) / LIGHT_FRAC_DIV; ++ ++ fvco += (parent_rate * fbdiv); ++ do_div(fvco, refdiv); ++ ++ if (pll->out_type == LIGHT_PLL_DIV) ++ do_div(fvco, postdiv1 * postdiv2); ++ ++ return fvco; ++#else ++ ++ struct clk_lightpll *pll = to_clk_lightpll(hw); ++ const struct light_pll_rate_table *rate_table = pll->rate_table; ++ ++ /* return minimum supported value */ ++ if (pll->out_type == LIGHT_PLL_DIV) ++ return rate_table0.rate; ++ ++ return rate_table0.vco_rate; ++#endif ++} ++ ++static const struct light_pll_rate_table *light_get_pll_div_settings( ++ struct clk_lightpll *pll, unsigned long rate) ++{ ++ const struct light_pll_rate_table *rate_table = pll->rate_table; ++ int i; ++ ++ for (i = 0; i < pll->rate_count; i++) ++ if (rate == rate_tablei.rate) ++ return &rate_tablei; ++ ++ return NULL; ++} ++ ++static const struct light_pll_rate_table *light_get_pll_vco_settings( ++ struct clk_lightpll *pll, unsigned long rate) ++{ ++ const struct light_pll_rate_table *rate_table = pll->rate_table; ++ int i; ++ ++ for (i = 0; i < pll->rate_count; i++) ++ if (rate == rate_tablei.vco_rate) ++ return &rate_tablei; ++ ++ return NULL; ++} ++ ++static inline bool clk_light_pll_change(struct clk_lightpll *pll, ++ const struct light_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 + LIGHT_PLL_CFG1); ++ ++ refdiv_old = (cfg0 & LIGHT_REFDIV_MASK) >> LIGHT_REFDIV_SHIFT; ++ fbdiv_old = (cfg0 & LIGHT_FBDIV_MASK) >> LIGHT_FBDIV_SHIFT; ++ postdiv1_old = (cfg0 & LIGHT_POSTDIV1_MASK) >> LIGHT_POSTDIV1_SHIFT; ++ postdiv2_old = (cfg0 & LIGHT_POSTDIV2_MASK) >> LIGHT_POSTDIV2_SHIFT; ++ frac_old = (cfg1 & LIGHT_FRAC_MASK) >> LIGHT_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_light_pll_set_rate(struct clk_hw *hw, unsigned long drate, ++ unsigned long prate) ++{ ++ struct clk_lightpll *pll = to_clk_lightpll(hw); ++ const struct light_pll_rate_table *rate; ++ void __iomem *cfg1_off; ++ u32 tmp, div_val; ++ int ret; ++ ++ if (pll->out_type == LIGHT_PLL_VCO) { ++ rate = light_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 = light_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_light_pll_change(pll, rate)) ++ return 0; ++ ++ /* Enable RST */ ++ cfg1_off = pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1; ++ tmp = readl_relaxed(cfg1_off); ++ tmp |= pll->pll_rst_bit; ++ writel_relaxed(tmp, cfg1_off); ++ ++ div_val = (rate->refdiv << LIGHT_REFDIV_SHIFT) | ++ (rate->fbdiv << LIGHT_FBDIV_SHIFT) | ++ (rate->postdiv1 << LIGHT_POSTDIV1_SHIFT) | ++ (rate->postdiv2 << LIGHT_POSTDIV2_SHIFT); ++ writel_relaxed(div_val, pll->base + pll->cfg0_reg_off); ++ ++ if (pll->pll_mode == PLL_MODE_FRAC) { ++ tmp &= ~(LIGHT_FRAC_MASK << LIGHT_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_light_pll_wait_lock(pll); ++ if (ret) ++ return ret; ++ ++ /* HW requires 30us for pll stable */ ++ udelay(30); ++ ++ return 0; ++} ++ ++static long clk_light_pllvco_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_lightpll *pll = to_clk_lightpll(hw); ++ const struct light_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_tablei.vco_rate; ++ ++ if (rate == now) { ++ return rate_tablei.vco_rate; ++ } else if (abs(now - rate) < abs(best - rate)) { ++ best = now; ++ best_i = i; ++ } ++ } ++ ++ /* return minimum supported value */ ++ return rate_tablebest_i.vco_rate; ++} ++ ++static long clk_light_plldiv_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_lightpll *pll = to_clk_lightpll(hw); ++ const struct light_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_tablei.rate; ++ ++ if (rate == now) { ++ return rate_tablei.rate; ++ } else if (abs(now - rate) < abs(best - rate)) { ++ best = now; ++ best_i = i; ++ } ++ } ++ ++ /* return minimum supported value */ ++ return rate_tablebest_i.rate; ++} ++ ++static const struct clk_ops clk_light_pll_def_ops = { ++ .recalc_rate = clk_light_pll_recalc_rate, ++}; ++ ++static const struct clk_ops clk_light_pllvco_ops = { ++ .prepare = clk_light_pll_prepare, ++ .unprepare = clk_light_pll_unprepare, ++ .is_prepared = clk_light_pll_is_prepared, ++ .recalc_rate = clk_light_pll_recalc_rate, ++ .round_rate = clk_light_pllvco_round_rate, ++ .set_rate = clk_light_pll_set_rate, ++}; ++ ++static const struct clk_ops clk_light_plldiv_ops = { ++ .prepare = clk_light_pll_prepare, ++ .unprepare = clk_light_pll_unprepare, ++ .is_prepared = clk_light_pll_is_prepared, ++ .recalc_rate = clk_light_pll_recalc_rate, ++ .round_rate = clk_light_plldiv_round_rate, ++ .set_rate = clk_light_pll_set_rate, ++}; ++ ++struct clk *thead_light_pll(const char *name, const char *parent_name, ++ void __iomem *base, ++ const struct light_pll_clk *pll_clk) ++{ ++ struct clk_lightpll *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 LIGHT_PLL_VCO: ++ if (pll_clk->rate_table) ++ init.ops = &clk_light_pllvco_ops; ++ break; ++ case LIGHT_PLL_DIV: ++ if (pll_clk->rate_table) ++ init.ops = &clk_light_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_light_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; ++ ++ clk_light_pll_cfg_init(pll); ++ ++ val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); ++ val &= ~pll->pll_bypass_bit; ++ val |= LIGHT_DACPD_MASK; ++ val |= LIGHT_DSMPD_MASK; ++ if (pll->pll_mode == PLL_MODE_FRAC) { ++ val &= ~LIGHT_DSMPD_MASK; ++ val &= ~LIGHT_DACPD_MASK; ++ } ++ writel_relaxed(val, pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); ++ ++ clk = clk_register(NULL, &pll->hw); ++ if (IS_ERR(clk)) { ++ pr_err("%s: failed to register pll %s %lu\n", ++ __func__, name, PTR_ERR(clk)); ++ kfree(pll); ++ } ++ ++ return clk; ++} ++ ++static inline struct clk_lightdiv *to_clk_lightdiv(struct clk_hw *hw) ++{ ++ struct clk_divider *divider = to_clk_divider(hw); ++ ++ return container_of(divider, struct clk_lightdiv, divider); ++} ++ ++static unsigned long clk_lightdiv_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_lightdiv *light_div = to_clk_lightdiv(hw); ++ ++ return light_div->ops->recalc_rate(&light_div->divider.hw, parent_rate); ++} ++ ++static long clk_lightdiv_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_lightdiv *light_div = to_clk_lightdiv(hw); ++ ++ return light_div->ops->round_rate(&light_div->divider.hw, rate, prate); ++} ++ ++static int clk_lightdiv_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_lightdiv *light_div = to_clk_lightdiv(hw); ++ struct clk_divider *div = to_clk_divider(hw); ++ unsigned int divider, value; ++ unsigned long flags = 0; ++ u32 val; ++ ++ divider = parent_rate / rate; ++ ++ /* DIV is zero based divider, but CDE is not */ ++ if (light_div->div_type == MUX_TYPE_DIV) ++ value = divider; ++ else ++ value = divider - 1; ++ ++ /* handle the div valid range */ ++ if (value > light_div->max_div) ++ value = light_div->max_div; ++ if (value < light_div->min_div) ++ value = light_div->min_div; ++ ++ spin_lock_irqsave(div->lock, flags); ++ ++ val = readl(div->reg); ++ val &= ~BIT(light_div->sync_en); ++ writel(val, div->reg); ++ ++ udelay(1); ++ ++ val &= ~(div_mask(div) << div->shift); ++ val |= value << div->shift; ++ writel(val, div->reg); ++ ++ udelay(1); ++ ++ val |= BIT(light_div->sync_en); ++ writel(val, div->reg); ++ ++ spin_unlock_irqrestore(div->lock, flags); ++ ++ return 0; ++} ++ ++static const struct clk_ops clk_lightdiv_ops = { ++ .recalc_rate = clk_lightdiv_recalc_rate, ++ .round_rate = clk_lightdiv_round_rate, ++ .set_rate = clk_lightdiv_set_rate, ++}; ++ ++struct clk *thead_clk_light_divider(const char *name, const char *parent, ++ void __iomem *reg, u8 shift, u8 width, ++ u8 sync, enum light_div_type div_type, ++ u16 min, u16 max) ++{ ++ struct clk_lightdiv *light_div; ++ struct clk_hw *hw; ++ struct clk_init_data init; ++ int ret; ++ ++ light_div = kzalloc(sizeof(*light_div), GFP_KERNEL); ++ if (!light_div) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &clk_lightdiv_ops; ++ init.flags = CLK_SET_RATE_PARENT; ++ init.parent_names = parent ? &parent : NULL; ++ init.num_parents = parent ? 1 : 0; ++ ++ light_div->divider.reg = reg; ++ light_div->divider.shift = shift; ++ light_div->divider.width = width; ++ light_div->divider.lock = &thead_light_clk_lock; ++ light_div->divider.hw.init = &init; ++ light_div->ops = &clk_divider_ops; ++ light_div->sync_en = sync; ++ light_div->div_type = div_type; ++ if (light_div->div_type == MUX_TYPE_DIV) ++ light_div->divider.flags = CLK_DIVIDER_ONE_BASED; ++ light_div->min_div = min > ((1 << width) - 1) ? ++ ((1 << width) - 1) : min; ++ light_div->max_div = max > ((1 << width) - 1) ? ++ ((1 << width) - 1) : max; ++ ++ hw = &light_div->divider.hw; ++ ++ ret = clk_hw_register(NULL, hw); ++ if (ret) { ++ kfree(light_div); ++ return ERR_PTR(ret); ++ } ++ ++ return hw->clk; ++} ++ ++static inline struct clk_lightgate *to_clk_lightgate(struct clk_hw *hw) ++{ ++ struct clk_gate *gate = to_clk_gate(hw); ++ ++ return container_of(gate, struct clk_lightgate, gate); ++} ++ ++static int clk_light_gate_share_is_enabled(struct clk_hw *hw) ++{ ++ struct clk_lightgate *light_gate = to_clk_lightgate(hw); ++ ++ return light_gate->ops->is_enabled(hw); ++} ++ ++static int clk_light_gate_share_enable(struct clk_hw *hw) ++{ ++ struct clk_lightgate *light_gate = to_clk_lightgate(hw); ++ ++ if (light_gate->share_count && (*light_gate->share_count)++ > 0) { ++ pr_debug("%s,%dshare_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); ++ return 0; ++ } ++ ++ pr_debug("%s,%dshare_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); ++ ++ return light_gate->ops->enable(hw); ++} ++ ++static void clk_light_gate_share_disable(struct clk_hw *hw) ++{ ++ struct clk_lightgate *light_gate = to_clk_lightgate(hw); ++ ++ if (light_gate->share_count) { ++ if (WARN_ON(*light_gate->share_count == 0)) ++ return; ++ else if (--(*light_gate->share_count) > 0) { ++ pr_debug("%s,%dshare_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); ++ return; ++ } ++ } ++ ++ pr_debug("%s,%dshare_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); ++ ++ light_gate->ops->disable(hw); ++} ++ ++static void clk_light_gate_share_disable_unused(struct clk_hw *hw) ++{ ++ struct clk_lightgate *light_gate = to_clk_lightgate(hw); ++ ++ if (!light_gate->share_count || *light_gate->share_count == 0) ++ return light_gate->ops->disable(hw); ++} ++ ++static const struct clk_ops clk_lightgate_share_ops = { ++ .enable = clk_light_gate_share_enable, ++ .disable = clk_light_gate_share_disable, ++ .disable_unused = clk_light_gate_share_disable_unused, ++ .is_enabled = clk_light_gate_share_is_enabled, ++}; ++ ++struct clk *thead_clk_light_register_gate_shared(const char *name, const char *parent, ++ unsigned long flags, void __iomem *reg, ++ u8 shift, spinlock_t *lock, ++ unsigned int *share_count) ++{ ++ struct clk_lightgate *light_gate; ++ struct clk_hw *hw; ++ struct clk_init_data init; ++ int ret; ++ ++ light_gate = kzalloc(sizeof(*light_gate), GFP_KERNEL); ++ if (!light_gate) ++ return ERR_PTR(-ENOMEM); ++ ++ light_gate->gate.reg = reg; ++ light_gate->gate.bit_idx = shift; ++ light_gate->gate.flags = 0; ++ light_gate->gate.lock = lock; ++ light_gate->gate.hw.init = &init; ++ light_gate->ops = &clk_gate_ops; ++ light_gate->share_count = share_count; ++ ++ init.name = name; ++ init.ops = &clk_lightgate_share_ops; ++ init.flags = flags; ++ init.parent_names = parent ? &parent : NULL; ++ init.num_parents = parent ? 1 : 0; ++ ++ hw = &light_gate->gate.hw; ++ ++ ret = clk_hw_register(NULL, hw); ++ if (ret) { ++ kfree(light_gate); ++ return ERR_PTR(ret); ++ } ++ ++ return hw->clk; ++} +diff --git a/drivers/clk/thead/clk.h b/drivers/clk/thead/clk.h +new file mode 100644 +index 000000000000..cad975e8ede4 +--- /dev/null ++++ b/drivers/clk/thead/clk.h +@@ -0,0 +1,117 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef __MACH_THEAD_CLK_H ++#define __MACH_THEAD_CLK_H ++ ++#include <linux/spinlock.h> ++#include <linux/clk-provider.h> ++ ++extern spinlock_t thead_light_clk_lock; ++ ++#define LIGHT_PLL_RATE(_vco, _rate, _r, _b, _f, _p, _k) \ ++ { \ ++ .vco_rate = (_vco), \ ++ .rate = (_rate), \ ++ .refdiv = (_r), \ ++ .fbdiv = (_b), \ ++ .frac = (_f), \ ++ .postdiv1 = (_p), \ ++ .postdiv2 = (_k), \ ++ } ++ ++enum light_pll_outtype { ++ LIGHT_PLL_VCO, ++ LIGHT_PLL_DIV, ++}; ++ ++enum light_div_type { ++ MUX_TYPE_DIV, ++ MUX_TYPE_CDE, ++}; ++ ++enum light_pll_clktype { ++ LIGHT_AUDIO_PLL, ++ LIGHT_SYS_PLL, ++ LIGHT_CPU_PLL0, ++ LIGHT_CPU_PLL1, ++ LIGHT_GMAC_PLL, ++ LIGHT_VIDEO_PLL, ++ LIGHT_DDR_PLL, ++ LIGHT_DPU0_PLL, ++ LIGHT_DPU1_PLL, ++}; ++ ++struct light_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; ++}; ++ ++struct light_pll_clk { ++ enum light_pll_outtype out_type; ++ enum light_pll_clktype clk_type; ++ const struct light_pll_rate_table *rate_table; ++ int rate_count; ++ int flags; ++}; ++ ++static inline struct clk *thead_light_clk_fixed_factor(const char *name, ++ const char *parent, unsigned int mult, unsigned int div) ++{ ++ return clk_register_fixed_factor(NULL, name, parent, ++ CLK_SET_RATE_PARENT, mult, div); ++} ++ ++struct clk *thead_light_pll(const char *name, const char *parent_name, ++ void __iomem *base, ++ const struct light_pll_clk *pll_clk); ++ ++static inline struct clk *thead_clk_light_gate(const char *name, const char *parent, ++ void __iomem *reg, u8 shift) ++{ ++ return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg, ++ shift, 0, &thead_light_clk_lock); ++} ++ ++struct clk *thead_clk_light_register_gate_shared(const char *name, const char *parent, ++ unsigned long flags, void __iomem *reg, ++ u8 shift, spinlock_t *lock, ++ unsigned int *share_count); ++ ++struct clk *thead_clk_light_divider(const char *name, const char *parent, ++ void __iomem *reg, u8 shift, u8 width, ++ u8 sync, enum light_div_type div_type, ++ u16 min, u16 max); ++ ++void thead_unregister_clocks(struct clk *clks, unsigned int count); ++ ++static inline struct clk *thead_clk_fixed(const char *name, unsigned long rate) ++{ ++ return clk_register_fixed_rate(NULL, name, NULL, 0, rate); ++} ++ ++static inline struct clk *thead_clk_light_gate_shared(const char *name, const char *parent, ++ void __iomem *reg, u8 shift, ++ unsigned int *share_count) ++{ ++ return thead_clk_light_register_gate_shared(name, parent, CLK_SET_RATE_PARENT, reg, ++ shift, &thead_light_clk_lock, share_count); ++} ++ ++static inline struct clk *thead_light_clk_mux_flags(const char *name, ++ void __iomem *reg, u8 shift, u8 width, ++ const char * const *parents, int num_parents, ++ unsigned long flags) ++{ ++ return clk_register_mux(NULL, name, parents, num_parents, ++ flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0, ++ &thead_light_clk_lock); ++} ++#endif +diff --git a/drivers/clk/thead/gate/Makefile b/drivers/clk/thead/gate/Makefile +new file mode 100644 +index 000000000000..b0ad8b2011c0 +--- /dev/null ++++ b/drivers/clk/thead/gate/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++obj-$(CONFIG_CLK_LIGHT_FM) += thead-gate.o visys-gate.o vpsys-gate.o vosys-gate.o dspsys-gate.o +diff --git a/drivers/clk/thead/gate/clk-gate.h b/drivers/clk/thead/gate/clk-gate.h +new file mode 100644 +index 000000000000..ebb190374a0e +--- /dev/null ++++ b/drivers/clk/thead/gate/clk-gate.h +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef CLK_GATE_H ++#define CLK_GATE_H ++ ++#include <linux/clk-provider.h> ++#include <linux/mfd/syscon.h> ++ ++enum clk_gate_type { ++ GATE_NOT_SHARED, ++ GATE_SHARED, ++}; ++ ++struct thead_clk_gate { ++ struct clk_hw hw; ++ struct regmap *regmap; ++ u32 offset; ++ u8 bit; ++ bool shared; ++ u32 *share_count; ++}; ++ ++struct clk *thead_gate_clk_register(const char *name, ++ const char *parent_name, ++ struct regmap *regmap, ++ int offset, ++ u8 bit, ++ bool shared, ++ u32 *share_count, ++ struct device *dev); ++ ++#endif +diff --git a/drivers/clk/thead/gate/dspsys-gate.c b/drivers/clk/thead/gate/dspsys-gate.c +new file mode 100644 +index 000000000000..e68a5d4e6151 +--- /dev/null ++++ b/drivers/clk/thead/gate/dspsys-gate.c +@@ -0,0 +1,109 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#include <dt-bindings/clock/light-dspsys.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/mfd/syscon.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/types.h> ++#include "clk-gate.h" ++#include "../clk.h" ++ ++static struct clk *gatesLIGHT_CLKGEN_DSPSYS_CLK_END; ++static struct clk_onecell_data clk_gate_data; ++ ++static int light_dspsys_clk_probe(struct platform_device *pdev) ++{ ++ struct regmap *dspsys_regmap, *tee_dspsys_regmap; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ int ret; ++ ++ dspsys_regmap = syscon_regmap_lookup_by_phandle(np, "dspsys-regmap"); ++ if (IS_ERR(dspsys_regmap)) { ++ dev_err(&pdev->dev, "cannot find regmap for dsp system register\n"); ++ return PTR_ERR(dspsys_regmap); ++ } ++ ++ tee_dspsys_regmap = syscon_regmap_lookup_by_phandle(np, "tee-dspsys-regmap"); ++ if (IS_ERR(tee_dspsys_regmap)) { ++ dev_warn(&pdev->dev, "cannot find regmap for tee dsp system register\n"); ++ tee_dspsys_regmap = NULL; ++ } ++ ++ gatesCLKGEN_DSP0_PCLK = thead_gate_clk_register("clkgen_dsp0_pclk", NULL, dspsys_regmap, ++ 0x24, 0, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_DSP1_PCLK = thead_gate_clk_register("clkgen_dsp1_pclk", NULL, dspsys_regmap, ++ 0x24, 1, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_DSP1_CCLK = thead_gate_clk_register("clkgen_dsp1_cclk", NULL, dspsys_regmap, ++ 0x24, 2, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_DSP0_CCLK = thead_gate_clk_register("clkgen_dsp0_cclk", NULL, dspsys_regmap, ++ 0x24, 3, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_X2X_DSP2_ACLK_S = thead_gate_clk_register("clkgen_x2x_dsp2_aclk_s", NULL, dspsys_regmap, ++ 0x24, 4, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_X2X_DSP0_ACLK_S = thead_gate_clk_register("clkgen_x2x_dsp0_aclk_s", NULL, dspsys_regmap, ++ 0x24, 5, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_X2X_X4_DSPSLV_DSP1_ACLK_M = thead_gate_clk_register("clkgen_x2x_x4_dspslv_dsp1_aclk_m", ++ NULL, dspsys_regmap, 0x24, 6, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_X2X_X4_DSPSLV_DSP0_ACLK_M = thead_gate_clk_register("clkgen_x2x_x4_dspslv_dsp0_aclk_m", ++ NULL, dspsys_regmap, 0x24, 7, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_AXI4_DSPSYS_SLV_ACLK = thead_gate_clk_register("clkgen_axi4_dspsys_slv_aclk", NULL, dspsys_regmap, ++ 0x24, 20, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_AXI4_DSPSYS_SLV_PCLK = thead_gate_clk_register("clkgen_axi4_dspsys_slv_pclk", NULL, dspsys_regmap, ++ 0x24, 21, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_AXI4_DSPSYS_ACLK = thead_gate_clk_register("clkgen_axi4_dspsys_aclk", NULL, dspsys_regmap, ++ 0x24, 23, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_AXI4_DSPSYS_PCLK = thead_gate_clk_register("clkgen_axi4_dspsys_pclk", NULL, dspsys_regmap, ++ 0x24, 24, GATE_NOT_SHARED, NULL, dev); ++ if (tee_dspsys_regmap) { ++ gatesCLKGEN_IOPMP_DSP1_PCLK = thead_gate_clk_register("clkgen_iopmp_dsp1_pclk", NULL, tee_dspsys_regmap, ++ 0x24, 25, GATE_NOT_SHARED, NULL, dev); ++ gatesCLKGEN_IOPMP_DSP0_PCLK = thead_gate_clk_register("clkgen_iopmp_dsp0_pclk", NULL, tee_dspsys_regmap, ++ 0x24, 26, GATE_NOT_SHARED, NULL, dev); ++ } ++ ++ clk_gate_data.clks = gates; ++ clk_gate_data.clk_num = ARRAY_SIZE(gates); ++ ++ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); ++ if (ret < 0) { ++ dev_err(dev, "failed to register gate clks for light dspsys\n"); ++ goto unregister_clks; ++ } ++ ++ dev_info(dev, "succeed to register dspsys gate clock provider\n"); ++ ++ return 0; ++ ++unregister_clks: ++ thead_unregister_clocks(gates, ARRAY_SIZE(gates)); ++ return ret; ++} ++ ++static const struct of_device_id dspsys_clk_gate_of_match = { ++ { .compatible = "thead,dspsys-gate-controller" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, dspsys_clk_gate_of_match); ++ ++static struct platform_driver light_dspsys_clk_driver = { ++ .probe = light_dspsys_clk_probe, ++ .driver = { ++ .name = "dspsys-clk-gate-provider", ++ .of_match_table = of_match_ptr(dspsys_clk_gate_of_match), ++ }, ++}; ++ ++module_platform_driver(light_dspsys_clk_driver); ++MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light Fullmask dspsys clock gate provider"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/clk/thead/gate/thead-gate.c b/drivers/clk/thead/gate/thead-gate.c +new file mode 100644 +index 000000000000..372c11dee1b9 +--- /dev/null ++++ b/drivers/clk/thead/gate/thead-gate.c +@@ -0,0 +1,114 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/regmap.h> ++#include "clk-gate.h" ++ ++#define to_thead_clk_gate(_hw) container_of(_hw, struct thead_clk_gate, hw) ++ ++static int thead_clk_gate_is_enabled(struct clk_hw *hw) ++{ ++ struct thead_clk_gate *tcg = to_thead_clk_gate(hw); ++ u32 val; ++ ++ regmap_read(tcg->regmap, tcg->offset, &val); ++ ++ val &= BIT(tcg->bit); ++ ++ return val != 0; ++} ++ ++static void thead_clk_gate_disable(struct clk_hw *hw) ++{ ++ struct thead_clk_gate *tcg = to_thead_clk_gate(hw); ++ ++ if (!tcg->shared) ++ goto out; ++ ++ if (tcg->share_count) { ++ if (WARN_ON(*tcg->share_count == 0)) ++ return; ++ else if (--(*tcg->share_count) > 0) { ++ pr_info("%s,%dshare_count = %d\n", __func__, __LINE__, ++ (*tcg->share_count)); ++ return; ++ } ++ } ++ ++out: ++ regmap_update_bits(tcg->regmap, tcg->offset, ++ BIT(tcg->bit), 0); ++} ++ ++static int thead_clk_gate_enable(struct clk_hw *hw) ++{ ++ struct thead_clk_gate *tcg = to_thead_clk_gate(hw); ++ ++ if (!tcg->shared) ++ goto out; ++ ++ if (tcg->share_count && (*tcg->share_count)++ > 0) { ++ pr_info("%s,%dshare_count = %d\n", __func__, __LINE__, (*tcg->share_count)); ++ return 0; ++ } ++ ++out: ++ return regmap_update_bits(tcg->regmap, tcg->offset, ++ BIT(tcg->bit), BIT(tcg->bit)); ++} ++ ++const struct clk_ops thead_gate_clk_ops = { ++ .enable = thead_clk_gate_enable, ++ .disable = thead_clk_gate_disable, ++ .is_enabled = thead_clk_gate_is_enabled, ++}; ++ ++struct clk *thead_gate_clk_register(const char *name, ++ const char *parent_name, ++ struct regmap *regmap, ++ int offset, ++ u8 bit, ++ bool shared, ++ u32 *share_count, ++ struct device *dev) ++{ ++ struct thead_clk_gate *tcg; ++ struct clk *clk; ++ struct clk_init_data init = {}; ++ ++ tcg = kzalloc(sizeof(*tcg), GFP_KERNEL); ++ if (!tcg) ++ return ERR_PTR(-ENOMEM); ++ ++ tcg->regmap = regmap; ++ tcg->offset = offset; ++ tcg->bit = bit; ++ tcg->shared = shared; ++ tcg->share_count = share_count; ++ ++ init.name = name; ++ init.flags = CLK_SET_RATE_PARENT; ++ init.parent_names = parent_name ? &parent_name : NULL; ++ init.num_parents = parent_name ? 1 : 0; ++ init.ops = &thead_gate_clk_ops; ++ ++ tcg->hw.init = &init; ++ ++ clk = clk_register(dev, &tcg->hw); ++ if (IS_ERR(clk)) ++ kfree(tcg); ++ ++ return clk; ++} +diff --git a/drivers/clk/thead/gate/visys-gate.c b/drivers/clk/thead/gate/visys-gate.c +new file mode 100644 +index 000000000000..b023e42b8269 +--- /dev/null ++++ b/drivers/clk/thead/gate/visys-gate.c +@@ -0,0 +1,144 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#include <dt-bindings/clock/light-fm-ap-clock.h> ++#include <dt-bindings/clock/light-visys.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/types.h> ++#include "clk-gate.h" ++#include "../clk.h" ++ ++static struct clk *gatesLIGHT_CLKGEN_VISYS_CLK_END; ++static struct clk_onecell_data clk_gate_data; ++ ++static u32 share_cnt_isp0_hclk_en; ++static u32 share_cnt_isp0_aclk_en; ++ ++static int light_visys_clk_probe(struct platform_device *pdev) ++{ ++ struct regmap *visys_regmap; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ int ret; ++ ++ visys_regmap = syscon_regmap_lookup_by_phandle(np, "visys-regmap"); ++ if (IS_ERR(visys_regmap)) { ++ dev_err(&pdev->dev, "cannot find regmap for vi system register\n"); ++ return PTR_ERR(visys_regmap); ++ } ++ ++ /* we assume that the gate clock is a root clock */ ++ gatesLIGHT_CLKGEN_DW200_ACLK = thead_gate_clk_register("clkgen_dw200_aclk", NULL, ++ visys_regmap, 0xa0, 27, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_AXI4_VISYS1_ACLK = thead_gate_clk_register("clkgen_axi4_visys1_aclk", NULL, ++ visys_regmap, 0xa0, 26, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_AXI4_VISYS2_ACLK = thead_gate_clk_register("clkgen_axi4_visys2_aclk", NULL, ++ visys_regmap, 0xa0, 25, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_AXI4_VISYS3_ACLK = thead_gate_clk_register("clkgen_axi4_visys3_aclk", NULL, ++ visys_regmap, 0xa0, 24, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP_RY_ACLK = thead_gate_clk_register("clkgen_isp_ry_aclk", NULL, ++ visys_regmap, 0xa0, 22, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP_VENC_SHAKE_ACLK = thead_gate_clk_register("clkgen_isp_venc_shake_aclk", NULL, ++ visys_regmap, 0xa0, 30, GATE_NOT_SHARED, NULL, dev); ++ ++ gatesLIGHT_CLKGEN_VIPRE_ACLK = thead_gate_clk_register("clkgen_vipre_aclk", NULL, ++ visys_regmap, 0xa0, 31, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_DW200_HCLK = thead_gate_clk_register("clkgen_dw200_hclk", NULL, ++ visys_regmap, 0xa0, 13, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP_RY_HCLK = thead_gate_clk_register("clkgen_isp_ry_hclk", NULL, ++ visys_regmap, 0xa0, 12, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_MIPI_CSI0_PCLK = thead_gate_clk_register("clkgen_mipi_csi0_pclk", NULL, ++ visys_regmap, 0xa0, 18, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_MIPI_CSI1_PCLK = thead_gate_clk_register("clkgen_mipi_csi1_pclk", NULL, ++ visys_regmap, 0xa0, 17, GATE_NOT_SHARED, NULL, dev); ++ ++ gatesLIGHT_CLKGEN_MIPI_CSI2_PCLK = thead_gate_clk_register("clkgen_mipi_csi2_pclk", NULL, ++ visys_regmap, 0xa0, 16, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_VIPRE_PCLK = thead_gate_clk_register("clkgen_vipre_pclk", NULL, ++ visys_regmap, 0xa0, 15, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP_VENC_SHAKE_PCLK = thead_gate_clk_register("clkgen_isp_venc_shake_pclk", NULL, ++ visys_regmap, 0xa0, 29, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_MIPI_CSI0_PIXCLK = thead_gate_clk_register("clkgen_mipi_csi0_pixclk", NULL, ++ visys_regmap, 0xa0, 11, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_MIPI_CSI1_PIXCLK = thead_gate_clk_register("clkgen_mipi_csi1_pixclk", NULL, ++ visys_regmap, 0xa0, 10, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_MIPI_CSI2_PIXCLK = thead_gate_clk_register("clkgen_mipi_csi2_pixclk", NULL, ++ visys_regmap, 0xa0, 9, GATE_NOT_SHARED, NULL, dev); ++ ++ gatesLIGHT_CLKGEN_VIPRE_PIXELCLK = thead_gate_clk_register("clkgen_vipre_pixelclk", NULL, ++ visys_regmap, 0xa4, 23, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_MIPI_CSI0_CFG_CLK = thead_gate_clk_register("clkgen_mipi_csi0_cfg_clk", NULL, ++ visys_regmap, 0xa0, 8, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_MIPI_CSI1_CFG_CLK = thead_gate_clk_register("clkgen_mipi_csi1_cfg_clk", NULL, ++ visys_regmap, 0xa0, 6, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_MIPI_CSI2_CFG_CLK = thead_gate_clk_register("clkgen_mipi_csi2_cfg_clk", NULL, ++ visys_regmap, 0xa0, 7, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_DW200_CLK_VSE = thead_gate_clk_register("clkgen_dw200_clk_vse", NULL, ++ visys_regmap, 0xa0, 5, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_DW200_CLK_DWE = thead_gate_clk_register("clkgen_dw200_clk_dwe", NULL, ++ visys_regmap, 0xa0, 4, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP0_CLK = thead_gate_clk_register("clkgen_isp_clk_0", NULL, ++ visys_regmap, 0xa4, 31, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP1_CLK = thead_gate_clk_register("clkgen_isp_clk_1", NULL, ++ visys_regmap, 0xa4, 30, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP_RY_CCLK = thead_gate_clk_register("clkgen_isp_ry_cclk", NULL, ++ visys_regmap, 0xa0, 21, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP1_PIXELCLK = thead_gate_clk_register("clkgen_isp1_pixelclk", NULL, ++ visys_regmap, 0xa4, 28, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP0_PIXELCLK = thead_gate_clk_register("clkgen_isp0_pixelclk", NULL, ++ visys_regmap, 0xa4, 29, GATE_NOT_SHARED, NULL, dev); ++ gatesLIGHT_CLKGEN_ISP1_HCLK = thead_gate_clk_register("clkgen_isp1_hclk", NULL, ++ visys_regmap, 0xa0, 1, GATE_SHARED, &share_cnt_isp0_hclk_en, dev); ++ gatesLIGHT_CLKGEN_ISP0_HCLK = thead_gate_clk_register("clkgen_isp0_hclk", NULL, ++ visys_regmap, 0xa0, 1, GATE_SHARED, &share_cnt_isp0_hclk_en, dev); ++ gatesLIGHT_CLKGEN_ISP1_ACLK = thead_gate_clk_register("clkgen_isp1_aclk", NULL, ++ visys_regmap, 0xa0, 3, GATE_SHARED, &share_cnt_isp0_aclk_en, dev); ++ gatesLIGHT_CLKGEN_ISP0_ACLK = thead_gate_clk_register("clkgen_isp0_aclk", NULL, ++ visys_regmap, 0xa0, 3, GATE_SHARED, &share_cnt_isp0_aclk_en, dev); ++ ++ clk_gate_data.clks = gates; ++ clk_gate_data.clk_num = ARRAY_SIZE(gates); ++ ++ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); ++ if (ret < 0) { ++ dev_err(dev, "failed to register gate clks for light visys\n"); ++ goto unregister_clks; ++ } ++ ++ dev_info(dev, "succeed to register visys gate clock provider\n"); ++ ++ return 0; ++ ++unregister_clks: ++ thead_unregister_clocks(gates, ARRAY_SIZE(gates)); ++ return ret; ++} ++ ++static const struct of_device_id visys_clk_gate_of_match = { ++ { .compatible = "thead,visys-gate-controller" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, visys_clk_gate_of_match); ++ ++static struct platform_driver light_visys_clk_driver = { ++ .probe = light_visys_clk_probe, ++ .driver = { ++ .name = "visys-clk-gate-provider", ++ .of_match_table = of_match_ptr(visys_clk_gate_of_match), ++ }, ++}; ++ ++module_platform_driver(light_visys_clk_driver); ++MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light Fullmask visys clock gate provider"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/clk/thead/gate/vosys-gate.c b/drivers/clk/thead/gate/vosys-gate.c +new file mode 100644 +index 000000000000..e53ba1a3e763 +--- /dev/null ++++ b/drivers/clk/thead/gate/vosys-gate.c +@@ -0,0 +1,111 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#include <dt-bindings/clock/light-fm-ap-clock.h> ++#include <dt-bindings/clock/light-vosys.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/types.h> ++#include "../clk.h" ++ ++static struct clk *gatesLIGHT_CLKGEN_VOSYS_CLK_END; ++static struct clk_onecell_data clk_gate_data; ++ ++static int light_vosys_clk_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ void __iomem *gate_base; ++ int ret; ++ ++ gate_base = devm_platform_ioremap_resource(pdev, 0); ++ if (WARN_ON(IS_ERR(gate_base))) ++ return PTR_ERR(gate_base); ++ ++ /* we assume that the gate clock is a root clock */ ++ gatesLIGHT_CLKGEN_AXI4_VO_PCLK = thead_clk_light_gate("clkgen_axi4_vo_pclk", NULL, ++ gate_base + 0x50, 22); ++ gatesLIGHT_CLKGEN_IOPMP_VOSYS_DPU_PCLK = thead_clk_light_gate("clkgen_iopmp_dpu_pclk", NULL, ++ gate_base + 0x50, 23); ++ gatesLIGHT_CLKGEN_IOPMP_VOSYS_DPU1_PCLK = thead_clk_light_gate("clkgen_iopmp_dpu1_pclk", NULL, ++ gate_base + 0x50, 24); ++ gatesLIGHT_CLKGEN_IOPMP_VOSYS_GPU_PCLK = thead_clk_light_gate("clkgen_iopmp_gpu_pclk", NULL, ++ gate_base + 0x50, 25); ++ gatesLIGHT_CLKGEN_HDMI_PCLK = thead_clk_light_gate("clkgen_hdmi_pclk", NULL, gate_base + 0x50, 11); ++ gatesLIGHT_CLKGEN_MIPIDSI0_PCLK = thead_clk_light_gate("clkgen_mipidsi0_pclk", NULL, ++ gate_base + 0x50, 13); ++ gatesLIGHT_CLKGEN_MIPIDSI1_PCLK = thead_clk_light_gate("clkgen_mipidsi1_pclk", NULL, ++ gate_base + 0x50, 14); ++ gatesLIGHT_CLKGEN_AXI4_VO_ACLK = thead_clk_light_gate("clkgen_axi4_vo_aclk", NULL, ++ gate_base + 0x50, 0); ++ gatesLIGHT_CLKGEN_IOPMP_GPU_ACLK = thead_clk_light_gate("clkgen_iopmp_gpu_aclk", NULL, ++ gate_base + 0x50, 29); ++ gatesLIGHT_CLKGEN_IOPMP_DPU_ACLK = thead_clk_light_gate("clkgen_iopmp_dpu_aclk", NULL, ++ gate_base + 0x50, 28); ++ gatesLIGHT_CLKGEN_IOPMP_DPU1_ACLK = thead_clk_light_gate("clkgen_iopmp_dpu1_aclk", NULL, ++ gate_base + 0x50, 27); ++ gatesLIGHT_CLKGEN_X2H_DPU_ACLK = thead_clk_light_gate("clkgen_x2h_dpu_aclk", NULL, gate_base + 0x50, 21); ++ gatesLIGHT_CLKGEN_X2H_DPU1_ACLK = thead_clk_light_gate("clkgen_x2h_dpu1_aclk", NULL, gate_base + 0x50, 20); ++ gatesLIGHT_CLKGEN_MIPIDSI0_PIXCLK = thead_clk_light_gate("clkgen_mipidsi0_pixclk", NULL, gate_base + 0x50, 30); ++ gatesLIGHT_CLKGEN_HDMI_PIXCLK = thead_clk_light_gate("clkgen_hdmi_pixclk", NULL, gate_base + 0x54, 0); ++ gatesLIGHT_CLKGEN_MIPIDSI1_PIXCLK = thead_clk_light_gate("clkgen_mipidsi1_pixclk", NULL, gate_base + 0x50, 31); ++ gatesLIGHT_CLKGEN_HDMI_SFR_CLK = thead_clk_light_gate("clkgen_hdmi_sfr_clk", NULL, gate_base + 0x50, 10); ++ gatesLIGHT_CLKGEN_HDMI_CEC_CLK = thead_clk_light_gate("clkgen_hdmi_cec_cclk", NULL, gate_base + 0x50, 12); ++ gatesLIGHT_CLKGEN_HDMI_I2S_CLK = thead_clk_light_gate("clkgen_hdmi_i2s_clk", NULL, gate_base + 0x50, 19); ++ gatesLIGHT_CLKGEN_MIPIDSI0_CFG_CLK = thead_clk_light_gate("clkgen_mipidsi0_cfg_clk", NULL, gate_base + 0x50, 15); ++ gatesLIGHT_CLKGEN_MIPIDSI1_CFG_CLK = thead_clk_light_gate("clkgen_mipidsi1_cfg_clk", NULL, gate_base + 0x50, 16); ++ gatesLIGHT_CLKGEN_MIPIDSI0_REFCLK = thead_clk_light_gate("clkgen_mipidsi0_refclk", NULL, gate_base + 0x50, 17); ++ gatesLIGHT_CLKGEN_MIPIDSI1_REFCLK = thead_clk_light_gate("clkgen_mipidsi1_refclk", NULL, gate_base + 0x50, 18); ++ gatesLIGHT_CLKGEN_GPU_CORE_CLK = thead_clk_light_gate("clkgen_gpu_core_clk", NULL, gate_base + 0x50, 3); ++ gatesLIGHT_CLKGEN_GPU_CFG_ACLK = thead_clk_light_gate("clkgen_gpu_cfg_aclk", NULL, gate_base + 0x50, 4); ++ gatesLIGHT_CLKGEN_DPU_HCLK = thead_clk_light_gate("clkgen_dpu_hclk", NULL, gate_base + 0x50, 7); ++ gatesLIGHT_CLKGEN_DPU_ACLK = thead_clk_light_gate("clkgen_dpu_aclk", NULL, gate_base + 0x50, 8); ++ gatesLIGHT_CLKGEN_DPU_CCLK = thead_clk_light_gate("clkgen_dpu_cclk", NULL, gate_base + 0x50, 9); ++ gatesLIGHT_CLKGEN_DPU_PIXCLK0 = thead_clk_light_gate("clkgen_dpu_pixclk0", NULL, gate_base + 0x50, 5); ++ gatesLIGHT_CLKGEN_DPU_PIXCLK1 = thead_clk_light_gate("clkgen_dpu_pixclk1", NULL, gate_base + 0x50, 6); ++ ++ clk_gate_data.clks = gates; ++ clk_gate_data.clk_num = ARRAY_SIZE(gates); ++ ++ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); ++ if (ret < 0) { ++ dev_err(dev, "failed to register gate clks for light vosys\n"); ++ goto unregister_clks; ++ } ++ ++ dev_info(dev, "succeed to register vosys gate clock provider\n"); ++ ++ return 0; ++ ++unregister_clks: ++ thead_unregister_clocks(gates, ARRAY_SIZE(gates)); ++ return ret; ++} ++ ++static const struct of_device_id vosys_clk_gate_of_match = { ++ { .compatible = "thead,vosys-gate-controller" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, vosys_clk_gate_of_match); ++ ++static struct platform_driver light_vosys_clk_driver = { ++ .probe = light_vosys_clk_probe, ++ .driver = { ++ .name = "vosys-clk-gate-provider", ++ .of_match_table = of_match_ptr(vosys_clk_gate_of_match), ++ }, ++}; ++ ++module_platform_driver(light_vosys_clk_driver); ++MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light Fullmask vosys clock gate provider"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/clk/thead/gate/vpsys-gate.c b/drivers/clk/thead/gate/vpsys-gate.c +new file mode 100644 +index 000000000000..78613188da70 +--- /dev/null ++++ b/drivers/clk/thead/gate/vpsys-gate.c +@@ -0,0 +1,94 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#include <dt-bindings/clock/light-fm-ap-clock.h> ++#include <dt-bindings/clock/light-vpsys.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/types.h> ++#include "../clk.h" ++ ++static struct clk *gatesLIGHT_VPSYS_CLK_END; ++static struct clk_onecell_data clk_gate_data; ++ ++static u32 share_cnt_g2d_clk_en; ++static u32 share_cnt_fce_clk_en; ++ ++static int light_vpsys_clk_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ void __iomem *gate_base; ++ int ret; ++ ++ gate_base = devm_platform_ioremap_resource(pdev, 0); ++ if (WARN_ON(IS_ERR(gate_base))) ++ return PTR_ERR(gate_base); ++ ++ /* we assume that the gate clock is a root clock */ ++ gatesLIGHT_VPSYS_G2D_PCLK = thead_clk_light_gate_shared("clkgen_vpsys_g2d_pclk", NULL, ++ gate_base + 0x20, 3, &share_cnt_g2d_clk_en); ++ gatesLIGHT_VPSYS_G2D_ACLK = thead_clk_light_gate_shared("clkgen_vpsys_g2d_aclk", NULL, ++ gate_base + 0x20, 3, &share_cnt_g2d_clk_en); ++ gatesLIGHT_VPSYS_G2D_CCLK = thead_clk_light_gate_shared("clkgen_vpsys_g2d_cclk", NULL, ++ gate_base + 0x20, 3, &share_cnt_g2d_clk_en); ++ ++ ++ gatesLIGHT_VPSYS_FCE_PCLK = thead_clk_light_gate_shared("clkgen_vpsys_fce_pclk", NULL, ++ gate_base + 0x20, 2, &share_cnt_fce_clk_en); ++ gatesLIGHT_VPSYS_FCE_ACLK = thead_clk_light_gate_shared("clkgen_vpsys_fce_aclk", NULL, ++ gate_base + 0x20, 2, &share_cnt_fce_clk_en); ++ ++ gatesLIGHT_VPSYS_VDEC_ACLK = thead_clk_light_gate("clkgen_vdec_aclk", NULL, gate_base + 0x20, 4); ++ gatesLIGHT_VPSYS_VDEC_CCLK = thead_clk_light_gate("clkgen_vdec_cclk", NULL, gate_base + 0x20, 5); ++ gatesLIGHT_VPSYS_VDEC_PCLK = thead_clk_light_gate("clkgen_vdec_pclk", NULL, gate_base + 0x20, 6); ++ ++ gatesLIGHT_VPSYS_VENC_CCLK = thead_clk_light_gate("clkgen_venc_cclk", NULL, gate_base + 0x20, 8); ++ gatesLIGHT_VPSYS_VENC_PCLK = thead_clk_light_gate("clkgen_venc_pclk", NULL, gate_base + 0x20, 9); ++ gatesLIGHT_VPSYS_VENC_ACLK = thead_clk_light_gate("clkgen_venc_aclk", NULL, gate_base + 0x20, 7); ++ ++ clk_gate_data.clks = gates; ++ clk_gate_data.clk_num = ARRAY_SIZE(gates); ++ ++ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); ++ if (ret < 0) { ++ dev_err(dev, "failed to register gate clks for light vpsys\n"); ++ goto unregister_clks; ++ } ++ ++ dev_info(dev, "succeed to register vpsys gate clock provider\n"); ++ ++ return 0; ++ ++unregister_clks: ++ thead_unregister_clocks(gates, ARRAY_SIZE(gates)); ++ return ret; ++} ++ ++static const struct of_device_id vpsys_clk_gate_of_match = { ++ { .compatible = "thead,vpsys-gate-controller" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, vpsys_clk_gate_of_match); ++ ++static struct platform_driver light_vpsys_clk_driver = { ++ .probe = light_vpsys_clk_probe, ++ .driver = { ++ .name = "vpsys-clk-gate-provider", ++ .of_match_table = of_match_ptr(vpsys_clk_gate_of_match), ++ }, ++}; ++ ++module_platform_driver(light_vpsys_clk_driver); ++MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light Fullmask vpsys clock gate provider"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig +index d1fdea27eb0d..4c67dd5991d1 100644 +--- a/drivers/cpufreq/Kconfig ++++ b/drivers/cpufreq/Kconfig +@@ -346,5 +346,15 @@ config QORIQ_CPUFREQ + This adds the CPUFreq driver support for Freescale QorIQ SoCs + which are capable of changing the CPU's frequency dynamically. + ++config RISCV_THEAD_LIGHT_CPUFREQ ++ tristate "CPU frequency scaling driver for Thead light SoCs" ++ depends on OF && COMMON_CLK ++ select CLK_LIGHT ++ select PM_OPP ++ help ++ This adds the CPUFreq driver support for Thead light SoCs ++ which are capable of changing the CPU's frequency dynamically. ++ ++ + endif + endmenu +diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile +index f9c1c9012ce7..4c87824d45eb 100644 +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -110,3 +110,4 @@ obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o + obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o + obj-$(CONFIG_SW64_CPUFREQ) += sw64_cpufreq.o + obj-$(CONFIG_SW64_CPUFREQ_DEBUGFS) += sw64_cpufreq_debugfs.o ++obj-$(CONFIG_RISCV_THEAD_LIGHT_CPUFREQ) += light-mpw-cpufreq.o +diff --git a/drivers/cpufreq/light-mpw-cpufreq.c b/drivers/cpufreq/light-mpw-cpufreq.c +new file mode 100644 +index 000000000000..72f8b348778c +--- /dev/null ++++ b/drivers/cpufreq/light-mpw-cpufreq.c +@@ -0,0 +1,491 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/cpu.h> ++#include <linux/cpufreq.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/pm_opp.h> ++#include <linux/platform_device.h> ++#include <linux/reboot.h> ++#include <linux/regulator/consumer.h> ++#include <linux/suspend.h> ++#include <linux/clk-provider.h> ++#include <linux/smp.h> ++#include <linux/kernel.h> ++#include <linux/notifier.h> ++ ++extern struct atomic_notifier_head panic_notifier_list; ++ ++static DEFINE_MUTEX(cpufreq_lock); ++ ++bool cpufreq_denied = false; ++ ++struct regulator *dvdd_cpu_reg; ++struct regulator *dvddm_cpu_reg; ++ ++enum LIGHT_MPW_CPUFREQ_CLKS { ++ LIGHT_C910_CCLK, ++ LIGHT_C910_CCLK_I0, ++ LIGHT_CPU_PLL1_FOUTPOSTDIV, ++ LIGHT_CPU_PLL0_FOUTPOSTDIV, ++}; ++ ++#define LIGHT_MPW_CPUFREQ_CLK_NUM 4 ++#define LIGHT_CPUFREQ_THRE 2000000 ++#define LIGHT_C910_BUS_CLK_SYNC BIT(11) ++#define LIGHT_C910_BUS_CLK_RATIO_MASK 0x700 ++#define LIGHT_C910_BUS_CLK_DIV_RATIO_2 0x100 ++#define LIGHT_C910_BUS_CLK_DIV_RATIO_3 0x200 ++ ++static int num_clks; ++static struct clk_bulk_data clks = { ++ { .id = "c910_cclk" }, ++ { .id = "c910_cclk_i0" }, ++ { .id = "cpu_pll1_foutpostdiv" }, ++ { .id = "cpu_pll0_foutpostdiv" }, ++}; ++ ++static struct device *cpu_dev; ++static struct cpufreq_frequency_table *freq_table; ++static unsigned int max_freq; ++static unsigned int transition_latency; ++static void __iomem *ap_sys_reg; ++static bool light_dvfs_sv = false; ++ ++static u32 *light_dvddm_volt; ++static u32 soc_opp_count = 0; ++ ++static int light_set_target(struct cpufreq_policy *policy, unsigned int index) ++{ ++ struct dev_pm_opp *opp; ++ unsigned long freq_hz; ++ int volt, volt_old; ++ unsigned int old_freq, new_freq; ++ int ret; ++ u32 val; ++ u32 re_modify_bus_freq = 0; ++ ++ mutex_lock(&cpufreq_lock); ++ ++ if (cpufreq_denied) { ++ dev_emerg(cpu_dev, "Denied to set cpu frequency temporarily on reboot\n"); ++ mutex_unlock(&cpufreq_lock); ++ return 0; ++ } ++ new_freq = freq_tableindex.frequency; ++ freq_hz = new_freq * 1000; ++ old_freq = policy->cur; ++ ++ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); ++ if (IS_ERR(opp)) { ++ dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); ++ mutex_unlock(&cpufreq_lock); ++ return PTR_ERR(opp); ++ } ++ ++ volt = dev_pm_opp_get_voltage(opp); ++ dev_pm_opp_put(opp); ++ ++ volt_old = regulator_get_voltage(dvdd_cpu_reg); ++ if (volt_old < 0) { ++ dev_err(cpu_dev, "failed to get cpu voltage\n"); ++ mutex_unlock(&cpufreq_lock); ++ return volt_old; ++ } ++ ++ dev_dbg(cpu_dev, "%u MHz, %d mV --> %u MHz, %d mV\n", ++ old_freq / 1000, volt_old / 1000, ++ new_freq / 1000, volt / 1000); ++ ++ /* change AXI bus clock ratio to match: BUS_CLK = CPU_CCLK/ratio <= 750MHz */ ++ val = readl(ap_sys_reg); ++ if (new_freq > LIGHT_CPUFREQ_THRE) { ++ val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; ++ val |= LIGHT_C910_BUS_CLK_DIV_RATIO_3; ++ } else { ++ val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; ++ ++ if (old_freq > LIGHT_CPUFREQ_THRE) { ++ re_modify_bus_freq = 1; ++ val |= LIGHT_C910_BUS_CLK_DIV_RATIO_3; ++ }else ++ val |= LIGHT_C910_BUS_CLK_DIV_RATIO_2; ++ } ++ ++ writel(val, ap_sys_reg); ++ val &= ~LIGHT_C910_BUS_CLK_SYNC; ++ writel(val, ap_sys_reg); ++ udelay(1); ++ val |= LIGHT_C910_BUS_CLK_SYNC; ++ writel(val, ap_sys_reg); ++ udelay(1); ++ ++ /* scaling up? scale voltage before frequency */ ++ if (new_freq > old_freq && !light_dvfs_sv) { ++ ret = regulator_set_voltage_tol(dvddm_cpu_reg, light_dvddm_voltindex, 0); ++ if (ret) { ++ dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); ++ mutex_unlock(&cpufreq_lock); ++ return ret; ++ } ++ ret = regulator_set_voltage_tol(dvdd_cpu_reg, volt, 0); ++ if (ret) { ++ dev_err(cpu_dev, ++ "failed to scale vddarm up: %d\n", ret); ++ mutex_unlock(&cpufreq_lock); ++ return ret; ++ } ++ } ++ ++ if (!strcmp(__clk_get_name(clk_get_parent(clksLIGHT_C910_CCLK.clk)), ++ __clk_get_name(clksLIGHT_C910_CCLK_I0.clk))) { ++ clk_prepare_enable(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk); ++ clk_set_rate(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk, new_freq * 1000); ++ ret = clk_set_parent(clksLIGHT_C910_CCLK.clk, clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk); ++ udelay(1); ++ if (ret) ++ clk_disable_unprepare(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk); ++ } else { ++ clk_prepare_enable(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk); ++ clk_set_rate(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk, new_freq * 1000); ++ ret = clk_set_parent(clksLIGHT_C910_CCLK.clk, clksLIGHT_C910_CCLK_I0.clk); ++ udelay(1); ++ if (ret) ++ clk_disable_unprepare(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk); ++ } ++ ++ /*add delay for clk-switch*/ ++ udelay(1); ++ ++ /* Ensure the c910_cclk clock divider is what we expect */ ++ ret = clk_set_rate(clksLIGHT_C910_CCLK.clk, new_freq * 1000); ++ if (ret) { ++ int ret1; ++ ++ dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); ++ ret1 = regulator_set_voltage_tol(dvdd_cpu_reg, volt_old, 0); ++ if (ret1) ++ dev_err(cpu_dev, "failed to restore dvdd_cpu voltage: %d\n", ret1); ++ mutex_unlock(&cpufreq_lock); ++ return ret; ++ } ++ ++ /* scaling down? scale voltage after frequency */ ++ if (new_freq < old_freq && !light_dvfs_sv) { ++ ret = regulator_set_voltage_tol(dvddm_cpu_reg, light_dvddm_voltindex, 0); ++ if (ret) ++ dev_err(cpu_dev, "failed to scale dvddm down: %d\n", ret); ++ ret = regulator_set_voltage_tol(dvdd_cpu_reg, volt, 0); ++ if (ret) ++ dev_err(cpu_dev, "failed to scale dvdd_cpu down: %d\n", ret); ++ } ++ ++ val = readl(ap_sys_reg); ++ if (re_modify_bus_freq) { ++ val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; ++ val |= LIGHT_C910_BUS_CLK_DIV_RATIO_2; ++ ++ writel(val, ap_sys_reg); ++ val &= ~LIGHT_C910_BUS_CLK_SYNC; ++ writel(val, ap_sys_reg); ++ udelay(1); ++ val |= LIGHT_C910_BUS_CLK_SYNC; ++ writel(val, ap_sys_reg); ++ udelay(1); ++ } ++ ++ mutex_unlock(&cpufreq_lock); ++ ++ return 0; ++} ++ ++static int light_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ policy->clk = clksLIGHT_C910_CCLK.clk; ++ policy->cur = clk_get_rate(policy->clk) / 1000; ++ cpufreq_generic_init(policy, freq_table, transition_latency); ++ policy->suspend_freq = max_freq; ++ dev_pm_opp_of_register_em(cpu_dev, policy->cpus); ++ ++ return 0; ++} ++ ++static int light_cpufreq_reboot_notifier(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ mutex_lock(&cpufreq_lock); ++ cpufreq_denied = true; ++ mutex_unlock(&cpufreq_lock); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block cpufreq_reboot_notifier = { ++ .notifier_call = light_cpufreq_reboot_notifier, ++}; ++ ++static struct cpufreq_driver light_cpufreq_driver = { ++ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK | ++ CPUFREQ_IS_COOLING_DEV, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = light_set_target, ++ .get = cpufreq_generic_get, ++ .init = light_cpufreq_init, ++ .name = "light-cpufreq", ++ .attr = cpufreq_generic_attr, ++ .suspend = cpufreq_generic_suspend, ++}; ++ ++static int light_cpufreq_pm_notify(struct notifier_block *nb, ++ unsigned long event, void *dummy) ++{ ++ switch (event) { ++ case PM_SUSPEND_PREPARE: ++ /* TBD */ ++ break; ++ case PM_POST_SUSPEND: ++ /* TBD */ ++ break; ++ default: ++ break; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block light_cpufreq_pm_notifier = { ++ .notifier_call = light_cpufreq_pm_notify, ++}; ++ ++/* ++ * Set CPU PLL1's frequency as minimum on panic ++ */ ++static int panic_cpufreq_notifier_call(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ int cpu = smp_processor_id(); ++ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); ++ ++ pr_info("enter panic_cpufreq_notifier_call\n"); ++ ++ /* ++ * set CPU PLL1's frequency as minimum to compatible voltage ++ * becarefull if the PLL1 is serving the cpu core, swith to PLL0 first ++ */ ++ if (strcmp(__clk_get_name(clk_get_parent(clksLIGHT_C910_CCLK.clk)), ++ __clk_get_name(clksLIGHT_C910_CCLK_I0.clk))) { ++ pr_debug("%s,%d\n", __func__, __LINE__); ++ clk_prepare_enable(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk); ++ clk_set_rate(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk, policy->min * 1000); ++ udelay(1); ++ clk_set_parent(clksLIGHT_C910_CCLK.clk, clksLIGHT_C910_CCLK_I0.clk); ++ ++ pr_debug("%s,%d\n", __func__, __LINE__); ++ } ++ ++ pr_debug("%s,%d\n", __func__, __LINE__); ++ /* ++ * since the clk driver will use PLL1 as the default clock source, ++ * in order to compatible voltage which is unpredictable we should ++ * set the CPU PLL1's frequency as minimum in advance, otherwise the ++ * system may crash in crash kernel stage. ++ */ ++ clk_prepare_enable(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk); ++ clk_set_rate(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk, policy->min * 1000); ++ udelay(1); ++ ++ pr_info("finish to execute cpufreq notifier callback on panic\n"); ++ ++ return 0; ++} ++ ++static struct notifier_block panic_cpufreq_notifier = { ++ .notifier_call = panic_cpufreq_notifier_call, ++}; ++ ++static int light_cpufreq_probe(struct platform_device *pdev) ++{ ++ struct device_node *np; ++ int num, ret; ++ const struct property *prop; ++ const __be32 *val; ++ u32 nr, i, j; ++ ++ np = of_find_compatible_node(NULL, NULL, "thead,light_sys_reg"); ++ if (!np) ++ return -ENOENT; ++ ap_sys_reg = of_iomap(np, 0); ++ WARN_ON(!ap_sys_reg); ++ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ np = of_node_get(cpu_dev->of_node); ++ if (!np) { ++ dev_err(cpu_dev, "failed to find cpu0 node\n"); ++ return -ENOENT; ++ } ++ ++ num_clks = LIGHT_MPW_CPUFREQ_CLK_NUM; ++ ret = clk_bulk_get(cpu_dev, num_clks, clks); ++ if (ret) ++ goto put_node; ++ ++ dvdd_cpu_reg = regulator_get(cpu_dev, "dvdd"); ++ dvddm_cpu_reg = regulator_get(cpu_dev, "dvddm"); ++ if (PTR_ERR(dvdd_cpu_reg) == -EPROBE_DEFER || ++ PTR_ERR(dvddm_cpu_reg) == -EPROBE_DEFER) { ++ ret = -EPROBE_DEFER; ++ dev_dbg(cpu_dev, "regulators not ready, defer\n"); ++ goto put_reg; ++ } ++ ++ if (IS_ERR(dvdd_cpu_reg) || IS_ERR(dvddm_cpu_reg)) { ++ dev_err(cpu_dev, "failed to get regulators\n"); ++ ret = -ENOENT; ++ goto put_reg; ++ } ++ ++ ret = dev_pm_opp_of_add_table(cpu_dev); ++ if (ret < 0) { ++ dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); ++ goto put_reg; ++ } ++ ++ num = dev_pm_opp_get_opp_count(cpu_dev); ++ if (num < 0) { ++ ret = num; ++ dev_err(cpu_dev, "no OPP table is found: %d\n", ret); ++ goto out_free_opp; ++ } ++ ++ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ++ if (ret) { ++ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); ++ goto out_free_opp; ++ } ++ ++ /* Make light_dvddm_volt array's size same as dvdd opp number */ ++ light_dvddm_volt = devm_kcalloc(cpu_dev, num, sizeof(*light_dvddm_volt), ++ GFP_KERNEL); ++ if (light_dvddm_volt == NULL) { ++ ret = -ENOMEM; ++ goto free_freq_table; ++ } ++ ++ if (of_get_property(np, "dvfs_sv", NULL)) ++ light_dvfs_sv = true; ++ else ++ light_dvfs_sv = false; ++ ++ prop = of_find_property(np, "light,dvddm-operating-points", NULL); ++ if (!prop || !prop->value) ++ goto soc_opp_out; ++ ++ nr = prop->length / sizeof(u32); ++ if (nr % 2 || (nr / 2) < num) ++ goto soc_opp_out; ++ ++ for (j = 0; j < num; j++) { ++ val = prop->value; ++ for (i = 0; i < nr / 2; i++) { ++ unsigned long freq = be32_to_cpup(val++); ++ unsigned long volt = be32_to_cpup(val++); ++ if (freq_tablej.frequency == freq) { ++ light_dvddm_voltsoc_opp_count++ = volt; ++ break; ++ } ++ } ++ } ++ ++soc_opp_out: ++ if (soc_opp_count != num) ++ dev_warn(cpu_dev, "Not find valid light,dvddm-operating-points property\n"); ++ ++ if (of_property_read_u32(np, "clock-latency", &transition_latency)) ++ transition_latency = CPUFREQ_ETERNAL; ++ ++ max_freq = freq_table--num.frequency; ++ ++ ret = cpufreq_register_driver(&light_cpufreq_driver); ++ if (ret) { ++ dev_err(cpu_dev, "failed register driver: %d\n", ret); ++ goto free_freq_table; ++ } ++ ++ register_pm_notifier(&light_cpufreq_pm_notifier); ++ ++ of_node_put(np); ++ ++ ret = atomic_notifier_chain_register(&panic_notifier_list, ++ &panic_cpufreq_notifier); ++ if (ret) { ++ pr_err("unable to register notifier(%d)\n", ret); ++ goto free_freq_table; ++ } ++ ++ register_reboot_notifier(&cpufreq_reboot_notifier); ++ ++ dev_info(cpu_dev, "finish to register cpufreq driver\n"); ++ ++ return 0; ++ ++free_freq_table: ++ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); ++out_free_opp: ++ dev_pm_opp_of_remove_table(cpu_dev); ++put_reg: ++ if (!IS_ERR(dvdd_cpu_reg)) ++ regulator_put(dvdd_cpu_reg); ++ if (!IS_ERR(dvddm_cpu_reg)) ++ regulator_put(dvddm_cpu_reg); ++ ++ clk_bulk_put(num_clks, clks); ++put_node: ++ of_node_put(np); ++ ++ return ret; ++} ++ ++static int light_cpufreq_remove(struct platform_device *pdev) ++{ ++ cpufreq_unregister_driver(&light_cpufreq_driver); ++ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); ++ dev_pm_opp_of_remove_table(cpu_dev); ++ regulator_put(dvdd_cpu_reg); ++ regulator_put(dvddm_cpu_reg); ++ ++ clk_bulk_put(num_clks, clks); ++ ++ return 0; ++} ++ ++static const struct of_device_id light_cpufreq_match = { ++ { .compatible = "thead,light-mpw-cpufreq" }, ++ {}, ++}; ++ ++static struct platform_driver light_cpufreq_platdrv = { ++ .driver = { ++ .name = "thead,light-mpw-cpufreq", ++ .of_match_table = light_cpufreq_match, ++ }, ++ .probe = light_cpufreq_probe, ++ .remove = light_cpufreq_remove, ++}; ++module_platform_driver(light_cpufreq_platdrv); ++ ++MODULE_ALIAS("platform:light-cpufreq"); ++MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light cpufreq driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig +index 9cb284a6e7a1..52f07f9c5db7 100644 +--- a/drivers/firmware/Kconfig ++++ b/drivers/firmware/Kconfig +@@ -314,5 +314,6 @@ source "drivers/firmware/psci/Kconfig" + source "drivers/firmware/smccc/Kconfig" + source "drivers/firmware/tegra/Kconfig" + source "drivers/firmware/xilinx/Kconfig" ++source "drivers/firmware/thead/Kconfig" + + endmenu +diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile +index 28fcddcd688f..a817fe549c9f 100644 +--- a/drivers/firmware/Makefile ++++ b/drivers/firmware/Makefile +@@ -38,3 +38,4 @@ obj-y += psci/ + obj-y += smccc/ + obj-y += tegra/ + obj-y += xilinx/ ++obj-y += thead/ +diff --git a/drivers/firmware/thead/Kconfig b/drivers/firmware/thead/Kconfig +new file mode 100644 +index 000000000000..ad5b82dd51e8 +--- /dev/null ++++ b/drivers/firmware/thead/Kconfig +@@ -0,0 +1,18 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config LIGHT_AON ++ bool "Thead Light Aon Protocol driver" ++ depends on THEAD_LIGHT_MBOX ++ default y ++ help ++ Thead light Aon is a low-level system function which runs a dedicated ++ thead riscv E902 core to provide power, clock and resource management. ++ ++ This driver manages the IPC interface between host cpu liks thead ++ and the Aon firmware running on thead riscv E902 core. ++ ++config LIGHT_AON_PD ++ bool "Thead Light Aon Power Domain driver" ++ depends on LIGHT_AON ++ select PM_GENERIC_DOMAINS if PM ++ help ++ The Aon power domain virtual driver. +diff --git a/drivers/firmware/thead/Makefile b/drivers/firmware/thead/Makefile +new file mode 100644 +index 000000000000..6bd2afe817ef +--- /dev/null ++++ b/drivers/firmware/thead/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_LIGHT_AON) += light_aon.o light_aon_misc.o light_aon_test.o ++obj-$(CONFIG_LIGHT_AON_PD) += light_aon_pd.o +diff --git a/drivers/firmware/thead/light_aon.c b/drivers/firmware/thead/light_aon.c +new file mode 100644 +index 000000000000..5af7de821e76 +--- /dev/null ++++ b/drivers/firmware/thead/light_aon.c +@@ -0,0 +1,261 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/err.h> ++#include <linux/firmware/thead/ipc.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++#include <linux/kernel.h> ++#include <linux/mailbox_client.h> ++#include <linux/module.h> ++#include <linux/mutex.h> ++#include <linux/of_platform.h> ++#include <linux/platform_device.h> ++ ++/* 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 light_aon_chan { ++ struct light_aon_ipc *aon_ipc; ++ ++ struct mbox_client cl; ++ struct mbox_chan *ch; ++ struct completion tx_done; ++}; ++ ++struct light_aon_ipc { ++ struct light_aon_chan chans; ++ struct device *dev; ++ struct mutex lock; ++ struct completion done; ++ u32 *msg; ++}; ++ ++/* ++ * This type is used to indicate error response for most functions. ++ */ ++enum light_aon_error_codes { ++ LIGHT_AON_ERR_NONE = 0, /* Success */ ++ LIGHT_AON_ERR_VERSION = 1, /* Incompatible API version */ ++ LIGHT_AON_ERR_CONFIG = 2, /* Configuration error */ ++ LIGHT_AON_ERR_PARM = 3, /* Bad parameter */ ++ LIGHT_AON_ERR_NOACCESS = 4, /* Permission error (no access) */ ++ LIGHT_AON_ERR_LOCKED = 5, /* Permission error (locked) */ ++ LIGHT_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */ ++ LIGHT_AON_ERR_NOTFOUND = 7, /* Not found */ ++ LIGHT_AON_ERR_NOPOWER = 8, /* No power */ ++ LIGHT_AON_ERR_IPC = 9, /* Generic IPC error */ ++ LIGHT_AON_ERR_BUSY = 10, /* Resource is currently busy/active */ ++ LIGHT_AON_ERR_FAIL = 11, /* General I/O failure */ ++ LIGHT_AON_ERR_LAST ++}; ++ ++static int light_aon_linux_errmapLIGHT_AON_ERR_LAST = { ++ 0, /* LIGHT_AON_ERR_NONE */ ++ -EINVAL, /* LIGHT_AON_ERR_VERSION */ ++ -EINVAL, /* LIGHT_AON_ERR_CONFIG */ ++ -EINVAL, /* LIGHT_AON_ERR_PARM */ ++ -EACCES, /* LIGHT_AON_ERR_NOACCESS */ ++ -EACCES, /* LIGHT_AON_ERR_LOCKED */ ++ -ERANGE, /* LIGHT_AON_ERR_UNAVAILABLE */ ++ -EEXIST, /* LIGHT_AON_ERR_NOTFOUND */ ++ -EPERM, /* LIGHT_AON_ERR_NOPOWER */ ++ -EPIPE, /* LIGHT_AON_ERR_IPC */ ++ -EBUSY, /* LIGHT_AON_ERR_BUSY */ ++ -EIO, /* LIGHT_AON_ERR_FAIL */ ++}; ++ ++static struct light_aon_ipc *light_aon_ipc_handle; ++ ++static inline int light_aon_to_linux_errno(int errno) ++{ ++ if (errno >= LIGHT_AON_ERR_NONE && errno < LIGHT_AON_ERR_LAST) ++ return light_aon_linux_errmaperrno; ++ return -EIO; ++} ++ ++/* ++ * Get the default handle used by SCU ++ */ ++int light_aon_get_handle(struct light_aon_ipc **ipc) ++{ ++ if (!light_aon_ipc_handle) ++ return -EPROBE_DEFER; ++ ++ *ipc = light_aon_ipc_handle; ++ return 0; ++} ++EXPORT_SYMBOL(light_aon_get_handle); ++ ++static void light_aon_tx_done(struct mbox_client *cl, void *mssg, int r) ++{ ++ struct light_aon_chan *aon_chan = container_of(cl, struct light_aon_chan, cl); ++ ++ complete(&aon_chan->tx_done); ++} ++ ++static void light_aon_rx_callback(struct mbox_client *c, void *msg) ++{ ++ struct light_aon_chan *aon_chan = container_of(c, struct light_aon_chan, cl); ++ struct light_aon_ipc *aon_ipc = aon_chan->aon_ipc; ++ ++ memcpy(aon_ipc->msg, msg, LIGHT_AON_RPC_MSG_NUM * sizeof(u32)); ++ dev_dbg(aon_ipc->dev, "msg head: 0x%x\n", *((u32 *)msg)); ++ complete(&aon_ipc->done); ++} ++ ++static int light_aon_ipc_write(struct light_aon_ipc *aon_ipc, void *msg) ++{ ++ struct light_aon_rpc_msg_hdr *hdr = msg; ++ struct light_aon_chan *aon_chan; ++ u32 *data = msg; ++ int ret; ++ ++ /* check size, currently it requires 7 MSG in one transfer */ ++ if (hdr->size != LIGHT_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 light_aon_call_rpc(struct light_aon_ipc *aon_ipc, void *msg, bool have_resp) ++{ ++ struct light_aon_rpc_msg_hdr *hdr; ++ int ret; ++ ++ if (WARN_ON(!aon_ipc || !msg)) ++ return -EINVAL; ++ ++ mutex_lock(&aon_ipc->lock); ++ reinit_completion(&aon_ipc->done); ++ ++ if (have_resp) ++ aon_ipc->msg = msg; ++ ++ ret = light_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 hdr->func field */ ++ hdr = msg; ++ ret = hdr->func; ++ } ++ ++out: ++ mutex_unlock(&aon_ipc->lock); ++ ++ dev_dbg(aon_ipc->dev, "RPC SVC done\n"); ++ ++ return light_aon_to_linux_errno(ret); ++} ++EXPORT_SYMBOL(light_aon_call_rpc); ++ ++static int light_aon_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct light_aon_ipc *aon_ipc; ++ struct light_aon_chan *aon_chan; ++ struct mbox_client *cl; ++ 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 = light_aon_rx_callback; ++ ++ /* Initial tx_done completion as "done" */ ++ cl->tx_done = light_aon_tx_done; ++ init_completion(&aon_chan->tx_done); ++ complete(&aon_chan->tx_done); ++ ++ aon_chan->aon_ipc = aon_ipc; ++ aon_chan->ch = mbox_request_channel_byname(cl, "aon"); ++ 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 thead mbox chan: aon\n"); ++ ++ aon_ipc->dev = dev; ++ mutex_init(&aon_ipc->lock); ++ init_completion(&aon_ipc->done); ++ ++ light_aon_ipc_handle = aon_ipc; ++ ++ return devm_of_platform_populate(dev); ++} ++ ++static const struct of_device_id light_aon_match = { ++ { .compatible = "thead,light-aon", }, ++ { /* Sentinel */ } ++}; ++ ++static int __maybe_unused light_aon_resume_noirq(struct device *dev) ++{ ++ struct light_aon_chan *aon_chan; ++ int ret; ++ ++ aon_chan = &light_aon_ipc_handle->chans; ++ ++ complete(&aon_chan->tx_done); ++ return 0; ++} ++ ++static const struct dev_pm_ops light_aon_pm_ops = { ++ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, ++ light_aon_resume_noirq) ++}; ++static struct platform_driver light_aon_driver = { ++ .driver = { ++ .name = "light-aon", ++ .of_match_table = light_aon_match, ++ .pm = &light_aon_pm_ops, ++ }, ++ .probe = light_aon_probe, ++}; ++builtin_platform_driver(light_aon_driver); ++ ++MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light firmware protocol driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/firmware/thead/light_aon_misc.c b/drivers/firmware/thead/light_aon_misc.c +new file mode 100644 +index 000000000000..3fb689f4b261 +--- /dev/null ++++ b/drivers/firmware/thead/light_aon_misc.c +@@ -0,0 +1,74 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/firmware/thead/ipc.h> ++ ++struct light_aon_msg_req_misc_set_ctrl { ++ struct light_aon_rpc_msg_hdr hdr; ++ u32 ctrl; ++ u32 val; ++ u16 resource; ++ u16 reserved7; ++} __packed __aligned(4); ++ ++struct light_aon_msg_req_misc_get_ctrl { ++ struct light_aon_rpc_msg_hdr hdr; ++ u32 ctrl; ++ u16 resource; ++ u16 reserved9; ++} __packed __aligned(4); ++ ++struct light_aon_msg_resp_misc_get_ctrl { ++ struct light_aon_rpc_msg_hdr hdr; ++ u32 val; ++ u32 reserved5; ++} __packed __aligned(4); ++ ++int light_aon_misc_set_control(struct light_aon_ipc *ipc, u16 resource, ++ u32 ctrl, u32 val) ++{ ++ struct light_aon_msg_req_misc_set_ctrl msg; ++ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; ++ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; ++ hdr->func = (uint8_t)LIGHT_AON_MISC_FUNC_SET_CONTROL; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++ ++ msg.ctrl = ctrl; ++ msg.val = val; ++ msg.resource = resource; ++ ++ return light_aon_call_rpc(ipc, &msg, true); ++} ++EXPORT_SYMBOL(light_aon_misc_set_control); ++ ++int light_aon_misc_get_control(struct light_aon_ipc *ipc, u16 resource, ++ u32 ctrl, u32 *val) ++{ ++ struct light_aon_msg_req_misc_get_ctrl msg; ++ struct light_aon_msg_resp_misc_get_ctrl *resp; ++ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; ++ int ret; ++ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; ++ hdr->func = (uint8_t)LIGHT_AON_MISC_FUNC_GET_CONTROL; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++ ++ msg.ctrl = ctrl; ++ msg.resource = resource; ++ ++ ret = light_aon_call_rpc(ipc, &msg, true); ++ if (ret) ++ return ret; ++ ++ resp = (struct light_aon_msg_resp_misc_get_ctrl *)&msg; ++ if (val != NULL) ++ *val = resp->val; ++ ++ return 0; ++} ++EXPORT_SYMBOL(light_aon_misc_get_control); +diff --git a/drivers/firmware/thead/light_aon_pd.c b/drivers/firmware/thead/light_aon_pd.c +new file mode 100644 +index 000000000000..3bef67df5a0a +--- /dev/null ++++ b/drivers/firmware/thead/light_aon_pd.c +@@ -0,0 +1,417 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <dt-bindings/firmware/thead/rsrc.h> ++#include <linux/ctype.h> ++#include <linux/debugfs.h> ++#include <linux/firmware/thead/ipc.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_platform.h> ++#include <linux/platform_device.h> ++#include <linux/pm.h> ++#include <linux/pm_domain.h> ++#include <linux/seq_file.h> ++#include <linux/slab.h> ++ ++struct light_aon_msg_req_set_resource_power_mode { ++ struct light_aon_rpc_msg_hdr hdr; ++ u16 resource; ++ u16 mode; ++ u16 reserved10; ++} __packed __aligned(4); ++ ++#define LIGHT_AONU_PD_NAME_SIZE 20 ++#define LIGHT_AONU_PD_STATE_NAME_SIZE 10 ++ ++struct light_aon_pm_domain { ++ struct generic_pm_domain pd; ++ char nameLIGHT_AONU_PD_NAME_SIZE; ++ u16 rsrc; ++}; ++ ++struct light_aon_pd_range { ++ char *name; ++ u32 rsrc; ++ u8 num; ++ ++ /* add domain index */ ++ bool postfix; ++ u8 start_from; ++}; ++ ++struct light_aon_pd_soc { ++ const struct light_aon_pd_range *pd_ranges; ++ u8 num_ranges; ++}; ++ ++static const struct light_aon_pd_range light_aon_pd_ranges = { ++ /* AUDIO SS */ ++ { "audio", LIGHT_AON_AUDIO_PD, 1, false, 0 }, ++ { "vdec", LIGHT_AON_VDEC_PD, 1, false, 0}, ++ { "npu", LIGHT_AON_NPU_PD, 1, false, 0}, ++ { "venc", LIGHT_AON_VENC_PD, 1, false, 0}, ++ { "gpu", LIGHT_AON_GPU_PD, 1, false, 0}, ++ { "dsp0", LIGHT_AON_DSP0_PD, 1, false, 0}, ++ { "dsp1", LIGHT_AON_DSP1_PD, 1, false, 0}, ++ {}, ++}; ++ ++static const struct light_aon_pd_soc light_aon_pd = { ++ .pd_ranges = light_aon_pd_ranges, ++ .num_ranges = ARRAY_SIZE(light_aon_pd_ranges), ++}; ++ ++static struct light_aon_ipc *pm_ipc_handle; ++static struct dentry *pd_debugfs_root; ++struct dentry *pd_pde; ++struct genpd_onecell_data *genpd_data; ++ ++static inline struct light_aon_pm_domain *to_light_aon_pd(struct generic_pm_domain *genpd) ++{ ++ return container_of(genpd, struct light_aon_pm_domain, pd); ++} ++ ++static int light_aon_pd_power(struct generic_pm_domain *domain, bool power_on) ++{ ++ struct light_aon_msg_req_set_resource_power_mode msg; ++ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; ++ struct light_aon_pm_domain *pd; ++ int ret; ++ ++ pd = to_light_aon_pd(domain); ++ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = LIGHT_AON_RPC_SVC_PM; ++ hdr->func = LIGHT_AON_PM_FUNC_SET_RESOURCE_POWER_MODE; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++ ++ msg.resource = pd->rsrc; ++ msg.mode = power_on ? LIGHT_AON_PM_PW_MODE_ON : LIGHT_AON_PM_PW_MODE_OFF; ++ ++ ret = light_aon_call_rpc(pm_ipc_handle, &msg, true); ++ if (ret) ++ dev_err(&domain->dev, "failed to power %s resource %d ret %d\n", ++ power_on ? "up" : "off", pd->rsrc, ret); ++ ++ return ret; ++} ++ ++static int light_aon_pd_power_on(struct generic_pm_domain *domain) ++{ ++ return light_aon_pd_power(domain, true); ++} ++ ++static int light_aon_pd_power_off(struct generic_pm_domain *domain) ++{ ++ return light_aon_pd_power(domain, false); ++} ++ ++static struct generic_pm_domain *light_aon_pd_xlate(struct of_phandle_args *spec, ++ void *data) ++{ ++ struct generic_pm_domain *domain = ERR_PTR(-ENOENT); ++ struct genpd_onecell_data *pd_data = data; ++ unsigned int i; ++ ++ for (i = 0; i < pd_data->num_domains; i++) { ++ struct light_aon_pm_domain *aon_pd; ++ ++ aon_pd = to_light_aon_pd(pd_data->domainsi); ++ if (aon_pd->rsrc == spec->args0) { ++ domain = &aon_pd->pd; ++ break; ++ } ++ } ++ ++ return domain; ++} ++ ++static struct light_aon_pm_domain * ++light_aon_add_pm_domain(struct device *dev, int idx, ++ const struct light_aon_pd_range *pd_ranges) ++{ ++ struct light_aon_pm_domain *aon_pd; ++ int ret; ++ ++ aon_pd = devm_kzalloc(dev, sizeof(*aon_pd), GFP_KERNEL); ++ if (!aon_pd) ++ return ERR_PTR(-ENOMEM); ++ ++ aon_pd->rsrc = pd_ranges->rsrc + idx; ++ aon_pd->pd.power_off = light_aon_pd_power_off; ++ aon_pd->pd.power_on = light_aon_pd_power_on; ++ ++ if (pd_ranges->postfix) ++ snprintf(aon_pd->name, sizeof(aon_pd->name), ++ "%s%i", pd_ranges->name, pd_ranges->start_from + idx); ++ else ++ snprintf(aon_pd->name, sizeof(aon_pd->name), ++ "%s", pd_ranges->name); ++ ++ aon_pd->pd.name = aon_pd->name; ++ ++#if 0 ++ if (aon_pd->rsrc >= LIGHT_AON_R_LAST) { ++ dev_warn(dev, "invalid pd %s rsrc id %d found", ++ aon_pd->name, aon_pd->rsrc); ++ ++ devm_kfree(dev, aon_pd); ++ return NULL; ++ } ++#endif ++ ++ ret = pm_genpd_init(&aon_pd->pd, NULL, true); ++ if (ret) { ++ dev_warn(dev, "failed to init pd %s rsrc id %d", ++ aon_pd->name, aon_pd->rsrc); ++ devm_kfree(dev, aon_pd); ++ return NULL; ++ } ++ ++ return aon_pd; ++} ++ ++static int light_aon_init_pm_domains(struct device *dev, ++ const struct light_aon_pd_soc *pd_soc) ++{ ++ const struct light_aon_pd_range *pd_ranges = pd_soc->pd_ranges; ++ struct generic_pm_domain **domains; ++ struct genpd_onecell_data *pd_data; ++ struct light_aon_pm_domain *aon_pd; ++ u32 count = 0; ++ int i, j; ++ ++ for (i = 0; i < pd_soc->num_ranges; i++) ++ count += pd_rangesi.num; ++ ++ domains = devm_kcalloc(dev, count, sizeof(*domains), GFP_KERNEL); ++ if (!domains) ++ return -ENOMEM; ++ ++ pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL); ++ if (!pd_data) ++ return -ENOMEM; ++ ++ count = 0; ++ for (i = 0; i < pd_soc->num_ranges; i++) { ++ for (j = 0; j < pd_rangesi.num; j++) { ++ aon_pd = light_aon_add_pm_domain(dev, j, &pd_rangesi); ++ if (IS_ERR_OR_NULL(aon_pd)) ++ continue; ++ ++ domainscount++ = &aon_pd->pd; ++ dev_dbg(dev, "added power domain %s\n", aon_pd->pd.name); ++ } ++ } ++ ++ pd_data->domains = domains; ++ pd_data->num_domains = count; ++ pd_data->xlate = light_aon_pd_xlate; ++ genpd_data = pd_data; ++ ++ of_genpd_add_provider_onecell(dev->of_node, pd_data); ++ ++ return 0; ++} ++ ++static char *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); ++ } ++ ++ /* got the string, now strip linefeed. */ ++ if (bufferuserlen - 1 == '\n') ++ bufferuserlen -1 = '\0'; ++ else ++ bufferuserlen = '\0'; ++ ++ pr_debug("buffer = %s\n", buffer); ++ ++ return buffer; ++} ++ ++static ssize_t light_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 genpd_onecell_data *aon_pds_data = m->private; ++ struct generic_pm_domain *hitted_pm_genpd; ++ char pd_nameLIGHT_AONU_PD_NAME_SIZE; ++ char pd_stateLIGHT_AONU_PD_STATE_NAME_SIZE; ++ int idx, ret; ++ size_t origin_len = userlen; ++ ++ buffer = pd_get_user_string(userbuf, userlen); ++ if (IS_ERR(buffer)) ++ return PTR_ERR(buffer); ++ ++ start = skip_spaces(buffer); ++ end = start; ++ while(!isspace(*end) && *end != '\0') ++ end++; ++ ++ *end = '\0'; ++ strcpy(pd_name, start); ++ pr_debug("power domain name: %s\n", pd_name); ++ ++ /* find the target power domain */ ++ for (idx = 0; idx < aon_pds_data->num_domains; idx++) { ++ struct generic_pm_domain *domain = aon_pds_data->domainsidx; ++ pr_debug("generic pm domain name: %s, pd_name: %s, ret = %d\n", ++ domain->name, pd_name, strcmp(pd_name, domain->name)); ++ if (strcmp(pd_name, domain->name)) ++ continue; ++ else { ++ hitted_pm_genpd = aon_pds_data->domainsidx; ++ pr_debug("target pm power domain-%s found, index: %d\n", ++ hitted_pm_genpd->name, idx); ++ break; ++ } ++ } ++ ++ if (idx >= aon_pds_data->num_domains) { ++ pr_err("no taget power domain-%s found, idx = %d, total pd numbers = %d\n", ++ pd_name, idx, aon_pds_data->num_domains); ++ userlen = -EINVAL; ++ goto out; ++ } ++ ++ if (!hitted_pm_genpd->power_on && !hitted_pm_genpd->power_off) { ++ pr_err("no power operations registered for power domain-%s\n", pd_name); ++ userlen = -EINVAL; ++ goto out; ++ } ++ ++ end = end + 1; ++ start = skip_spaces(end); ++ end = start; ++ while(!isspace(*end) && *end != '\0') ++ end++; ++ ++ *end = '\0'; ++ strcpy(pd_state, start); ++ pr_debug("power domain target state: %s\n", pd_state); ++ ++ if (!strcmp(pd_state, "on")) { ++ ret = hitted_pm_genpd->power_on(hitted_pm_genpd); ++ if (ret) { ++ userlen = ret; ++ goto out; ++ } ++ } else if (!strcmp(pd_state, "off")) { ++ ret = hitted_pm_genpd->power_off(hitted_pm_genpd); ++ if (ret) { ++ userlen = ret; ++ goto out; ++ } ++ } else { ++ pr_err("invalid power domain target state, not 'on' or 'off'\n"); ++ userlen = -EINVAL; ++ goto out; ++ } ++ ++out: ++ memset(buffer, 0, origin_len); ++ vfree(buffer); ++ ++ return userlen; ++} ++ ++static int light_power_domain_show(struct seq_file *m, void *v) ++{ ++ struct genpd_onecell_data *pd_data = m->private; ++ u32 count = pd_data->num_domains; ++ int idx; ++ ++ seq_puts(m, "Power domain name list: "); ++ for(idx = 0; idx < count; idx++) ++ seq_printf(m, "%s ", pd_data->domainsidx->name); ++ seq_printf(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 light_power_domain_open(struct inode *inode, struct file *file) ++{ ++ struct genpd_onecell_data *pd_data = inode->i_private; ++ ++ return single_open(file, light_power_domain_show, pd_data); ++} ++ ++static const struct file_operations light_power_domain_fops = { ++ .owner = THIS_MODULE, ++ .write = light_power_domain_write, ++ .read = seq_read, ++ .open = light_power_domain_open, ++ .llseek = generic_file_llseek, ++}; ++ ++static void pd_debugfs_init(struct genpd_onecell_data *aon_pds_data) ++{ ++ umode_t mode = S_IRUSR | S_IWUSR | S_IFREG; ++ ++ pd_debugfs_root = debugfs_create_dir("power_domain", NULL); ++ if (!pd_debugfs_root || IS_ERR(pd_debugfs_root)) ++ return; ++ ++ pd_pde = debugfs_create_file("domain", mode, pd_debugfs_root, (void *)aon_pds_data, &light_power_domain_fops); ++ ++ pr_info("succeed to create power domain debugfs direntry\n"); ++} ++ ++static int light_aon_pd_probe(struct platform_device *pdev) ++{ ++ const struct light_aon_pd_soc *pd_soc; ++ int ret; ++ ++ ret = light_aon_get_handle(&pm_ipc_handle); ++ if (ret) ++ return ret; ++ ++ pd_soc = of_device_get_match_data(&pdev->dev); ++ if (!pd_soc) ++ return -ENODEV; ++ ++ ret = light_aon_init_pm_domains(&pdev->dev, pd_soc); ++ if (ret) ++ return ret; ++ ++ pd_debugfs_init(genpd_data); ++ ++ return 0; ++} ++ ++static const struct of_device_id light_aon_pd_match = { ++ { .compatible = "thead,light-aon-pd", &light_aon_pd}, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver light_aon_pd_driver = { ++ .driver = { ++ .name = "light-aon-pd", ++ .of_match_table = light_aon_pd_match, ++ }, ++ .probe = light_aon_pd_probe, ++}; ++builtin_platform_driver(light_aon_pd_driver); ++ ++MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light firmware protocol driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/firmware/thead/light_aon_test.c b/drivers/firmware/thead/light_aon_test.c +new file mode 100644 +index 000000000000..172025430853 +--- /dev/null ++++ b/drivers/firmware/thead/light_aon_test.c +@@ -0,0 +1,163 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/debugfs.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++#include <linux/firmware/thead/ipc.h> ++ ++#define MBOX_MAX_MSG_LEN 28 ++ ++static struct dentry *root_debugfs_dir; ++ ++struct light_aon_msg_req_misc_set_ctrl { ++ struct light_aon_rpc_msg_hdr hdr; ++ u32 ctrl; ++ u32 val; ++ u16 resource; ++ u16 reserved7; ++} __packed __aligned(4); ++ ++struct light_aon_msg_req_misc_get_ctrl { ++ struct light_aon_rpc_msg_hdr hdr; ++ u32 ctrl; ++ u16 resource; ++ u16 reserved9; ++} __packed __aligned(4); ++ ++struct light_aon_msg_resp_misc_get_ctrl { ++ struct light_aon_rpc_msg_hdr hdr; ++ u32 val; ++ u32 reserved5; ++} __packed __aligned(4); ++ ++struct light_aon_device { ++ struct device *dev; ++ char *test_buf; ++ struct light_aon_ipc *ipc_handle; ++}; ++ ++static ssize_t light_aon_test_buf_write(struct file *filp, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct light_aon_device *tdev = filp->private_data; ++ int ret; ++ ++ if (count > MBOX_MAX_MSG_LEN) ++ count = MBOX_MAX_MSG_LEN; ++ ++ ret = copy_from_user(tdev->test_buf, userbuf, count); ++ if (ret) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ret = light_aon_misc_set_control(tdev->ipc_handle, 0x1, 0x2, 0x3); ++ ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x11, 0x12, 0x13); ++ ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x21, 0x22, 0x23); ++ ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x31, 0x32, 0x33); ++ if (ret) ++ dev_err(tdev->dev, "failed to set control\n"); ++ ++ //print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->test_buf, MBOX_MAX_MSG_LEN, true); ++ ++out: ++ return ret < 0 ? ret : count; ++} ++ ++static ssize_t light_aon_test_buf_read(struct file *filp, ++ char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct light_aon_device *tdev = filp->private_data; ++ ++ //print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->test_buf, MBOX_MAX_MSG_LEN, true); ++ memset(tdev->test_buf, 0, MBOX_MAX_MSG_LEN); ++ ++ return MBOX_MAX_MSG_LEN; ++} ++ ++static const struct file_operations light_aon_test_buf_ops = { ++ .write = light_aon_test_buf_write, ++ .read = light_aon_test_buf_read, ++ .open = simple_open, ++ .llseek = generic_file_llseek, ++}; ++ ++static int light_aon_add_debugfs(struct platform_device *pdev, struct light_aon_device *tdev) ++{ ++ root_debugfs_dir = debugfs_create_dir("light_aon",NULL); ++ if (!root_debugfs_dir) { ++ dev_err(&pdev->dev, "Failed to create light_aon_test debugfs\n"); ++ return -EINVAL; ++ } ++ ++ debugfs_create_file("test", 0600, root_debugfs_dir, tdev, &light_aon_test_buf_ops); ++ return 0; ++} ++ ++static int light_aon_probe(struct platform_device *pdev) ++{ ++ struct light_aon_device *tdev; ++ int ret; ++ ++ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); ++ if (!tdev) ++ return -ENOMEM; ++ ++ tdev->dev = &pdev->dev; ++ platform_set_drvdata(pdev, tdev); ++ ++ tdev->test_buf = devm_kzalloc(&pdev->dev, MBOX_MAX_MSG_LEN, GFP_KERNEL); ++ if (!tdev->test_buf) ++ return -ENOMEM; ++ ++ ret = light_aon_get_handle(&(tdev->ipc_handle)); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to get ipc_handle\n"); ++ return ret; ++ } ++ ++ ret = light_aon_add_debugfs(pdev, tdev); ++ if (ret) ++ return ret; ++ ++ dev_info(&pdev->dev, "Successfully registered\n"); ++ ++ return 0; ++} ++ ++static int light_aon_remove(struct platform_device *pdev) ++{ ++ debugfs_remove_recursive(root_debugfs_dir); ++ return 0; ++} ++ ++static const struct of_device_id light_aon_match = { ++ { .compatible = "thead,light-aon-test" }, ++ {}, ++}; ++ ++static struct platform_driver light_aon_driver = { ++ .driver = { ++ .name = "thead,light-aon-test", ++ .of_match_table = light_aon_match, ++ }, ++ .probe = light_aon_probe, ++ .remove = light_aon_remove, ++}; ++module_platform_driver(light_aon_driver); ++ ++MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light firmware protocol test driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c +index c22fcaa44a61..47f550689d53 100644 +--- a/drivers/gpio/gpio-dwapb.c ++++ b/drivers/gpio/gpio-dwapb.c +@@ -411,13 +411,12 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc, + static int dwapb_gpio_set_config(struct gpio_chip *gc, unsigned offset, + unsigned long config) + { +- u32 debounce; +- +- if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) +- return -ENOTSUPP; ++ if (pinconf_to_config_param(config) == PIN_CONFIG_INPUT_DEBOUNCE) { ++ u32 debounce = pinconf_to_config_argument(config); ++ return dwapb_gpio_set_debounce(gc, offset, debounce); ++ } + +- debounce = pinconf_to_config_argument(config); +- return dwapb_gpio_set_debounce(gc, offset, debounce); ++ return gpiochip_generic_config(gc, offset, config); + } + + static int dwapb_convert_irqs(struct dwapb_gpio_port_irqchip *pirq, +@@ -527,10 +526,14 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, + port->gc.fwnode = pp->fwnode; + port->gc.ngpio = pp->ngpio; + port->gc.base = pp->gpio_base; ++ port->gc.request = gpiochip_generic_request; ++ port->gc.free = gpiochip_generic_free; + + /* Only port A support debounce */ + if (pp->idx == 0) + port->gc.set_config = dwapb_gpio_set_config; ++ else ++ port->gc.set_config = gpiochip_generic_config; + + /* Only port A can provide interrupts in all configurations of the IP */ + if (pp->idx == 0) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 94e91516952c..628ae4b95b67 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -1109,6 +1109,8 @@ int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev) + u16 cmd; + int r; + ++ return 0; ++ + if (!IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT)) + return 0; + +diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c +index b67eafa55715..5ebe418bd383 100644 +--- a/drivers/gpu/drm/drm_gem_vram_helper.c ++++ b/drivers/gpu/drm/drm_gem_vram_helper.c +@@ -870,7 +870,7 @@ static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo, + if (!tt) + return NULL; + +- ret = ttm_tt_init(tt, bo, page_flags, ttm_cached, 0); ++ ret = ttm_tt_init(tt, bo, page_flags, ttm_write_combined, 0); + if (ret < 0) + goto err_ttm_tt_init; + +diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c +index c4dda908666c..33b56ca7af6f 100644 +--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c ++++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c +@@ -250,10 +250,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev) + * of address for "64-bit" MSIs which breaks on some platforms, notably + * IBM POWER servers, so we limit them + */ ++#if 0 + if (rdev->family < CHIP_BONAIRE) { + dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n"); + rdev->pdev->no_64bit_msi = 1; + } ++#endif + + /* force MSI on */ + if (radeon_msi == 1) +diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c +index fd9fd3d15101..0c29e322cb60 100644 +--- a/drivers/gpu/drm/ttm/ttm_bo_util.c ++++ b/drivers/gpu/drm/ttm/ttm_bo_util.c +@@ -345,7 +345,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, + ret = ttm_tt_populate(bo->bdev, ttm, &ctx); + if (ret) + return ret; +- ++#if 0 + if (num_pages == 1 && ttm->caching == ttm_cached) { + /* + * We're mapping a single page, and the desired +@@ -355,7 +355,9 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, + map->bo_kmap_type = ttm_bo_map_kmap; + map->page = ttm->pagesstart_page; + map->virtual = kmap(map->page); +- } else { ++ } else ++#endif ++ { + /* + * We need to use vmap to get the desired page protection + * or to make the buffer object look contiguous. +diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c +index b3fffe7b5062..aa137ead5cc5 100644 +--- a/drivers/gpu/drm/ttm/ttm_module.c ++++ b/drivers/gpu/drm/ttm/ttm_module.c +@@ -74,7 +74,8 @@ pgprot_t ttm_prot_from_caching(enum ttm_caching caching, pgprot_t tmp) + #endif /* CONFIG_UML */ + #endif /* __i386__ || __x86_64__ */ + #if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \ +- defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) ++ defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) || \ ++ defined(__riscv) + if (caching == ttm_write_combined) + tmp = pgprot_writecombine(tmp); + else +diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c +index 46ff9c75bb12..63a9b8d41b94 100644 +--- a/drivers/gpu/drm/ttm/ttm_resource.c ++++ b/drivers/gpu/drm/ttm/ttm_resource.c +@@ -187,7 +187,7 @@ void ttm_resource_init(struct ttm_buffer_object *bo, + res->bus.addr = NULL; + res->bus.offset = 0; + res->bus.is_iomem = false; +- res->bus.caching = ttm_cached; ++ res->bus.caching = ttm_write_combined; + res->bo = bo; + + man = ttm_manager_type(bo->bdev, place->mem_type); +@@ -670,17 +670,18 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io, + } else { + iter_io->needs_unmap = true; + memset(&iter_io->dmap, 0, sizeof(iter_io->dmap)); +- if (mem->bus.caching == ttm_write_combined) ++ if (mem->bus.caching == ttm_write_combined || mem->bus.caching == ttm_cached) + iosys_map_set_vaddr_iomem(&iter_io->dmap, + ioremap_wc(mem->bus.offset, + mem->size)); ++#if 0 + else if (mem->bus.caching == ttm_cached) + iosys_map_set_vaddr(&iter_io->dmap, + memremap(mem->bus.offset, mem->size, + MEMREMAP_WB | + MEMREMAP_WT | + MEMREMAP_WC)); +- ++#endif + /* If uncached requested or if mapping cached or wc failed */ + if (iosys_map_is_null(&iter_io->dmap)) + iosys_map_set_vaddr_iomem(&iter_io->dmap, +diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c +index e0a77671edd6..8ed5f661d536 100644 +--- a/drivers/gpu/drm/ttm/ttm_tt.c ++++ b/drivers/gpu/drm/ttm/ttm_tt.c +@@ -141,7 +141,7 @@ static void ttm_tt_init_fields(struct ttm_tt *ttm, + ttm->dma_address = NULL; + ttm->swap_storage = NULL; + ttm->sg = bo->sg; +- ttm->caching = caching; ++ ttm->caching = ttm_write_combined; + } + + int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo, +diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig +index bc2e265cb02d..ca9cfa3ac9f7 100644 +--- a/drivers/mailbox/Kconfig ++++ b/drivers/mailbox/Kconfig +@@ -295,4 +295,12 @@ config QCOM_IPCC + acts as an interrupt controller for receiving interrupts from clients. + Say Y here if you want to build this driver. + ++config THEAD_LIGHT_MBOX ++ bool "Thead light Mailbox" ++ depends on ARCH_THEAD || COMPILE_TEST ++ default y ++ help ++ Mailbox implementation for Thead light SoCs. ++ ++ + endif +diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile +index fc9376117111..7e82b9edccd4 100644 +--- a/drivers/mailbox/Makefile ++++ b/drivers/mailbox/Makefile +@@ -62,3 +62,6 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o + obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o + + obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o ++ ++obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox.o ++#obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox-client.o +diff --git a/drivers/mailbox/light-mailbox-client.c b/drivers/mailbox/light-mailbox-client.c +new file mode 100644 +index 000000000000..10cf7ae15cbc +--- /dev/null ++++ b/drivers/mailbox/light-mailbox-client.c +@@ -0,0 +1,242 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/debugfs.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/mailbox_client.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++ ++#define MBOX_MAX_MSG_LEN 28 ++#define WJ_MBOX_SEND_MAX_MESSAGE_LENGTH 28 ++#define HEXDUMP_BYTES_PER_LINE 28 ++#define HEXDUMP_LINE_LEN ((HEXDUMP_BYTES_PER_LINE * 4) + 2) ++#define HEXDUMP_MAX_LEN (HEXDUMP_LINE_LEN * \ ++ (MBOX_MAX_MSG_LEN / HEXDUMP_BYTES_PER_LINE)) ++ ++static struct dentry *root_debugfs_dir; ++ ++struct mbox_client_light_device { ++ struct device *dev; ++ void __iomem *tx_mmio; ++ void __iomem *rx_mmio; ++ struct mbox_chan *tx_channel; ++ struct mbox_chan *rx_channel; ++ char *rx_buffer; ++ char *message; ++ spinlock_t lock; ++}; ++ ++static ssize_t mbox_client_light_message_write(struct file *filp, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mbox_client_light_device *tdev = filp->private_data; ++ void *data; ++ int ret; ++ ++ if (!tdev->tx_channel) { ++ dev_err(tdev->dev, "Channel cannot do Tx\n"); ++ return -EINVAL; ++ } ++ ++ if (count > WJ_MBOX_SEND_MAX_MESSAGE_LENGTH) ++ count = WJ_MBOX_SEND_MAX_MESSAGE_LENGTH; ++ ++ tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); ++ if (!tdev->message) ++ return -ENOMEM; ++ ++ ret = copy_from_user(tdev->message, userbuf, count); ++ if (ret) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ data = tdev->message; ++ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->message, MBOX_MAX_MSG_LEN, true); ++ ++ ret = mbox_send_message(tdev->tx_channel, data); ++ if (ret < 0) ++ dev_err(tdev->dev, "Failed to send message via mailbox\n"); ++ ++out: ++ kfree(tdev->message); ++ return ret < 0 ? ret : count; ++} ++ ++static ssize_t mbox_client_light_message_read(struct file *filp, ++ char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mbox_client_light_device *tdev = filp->private_data; ++ unsigned long flags; ++ ++ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); ++ spin_lock_irqsave(&tdev->lock, flags); ++ memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); ++ spin_unlock_irqrestore(&tdev->lock, flags); ++ ++ return MBOX_MAX_MSG_LEN; ++} ++ ++static const struct file_operations mbox_client_light_message_ops = { ++ .write = mbox_client_light_message_write, ++ .read = mbox_client_light_message_read, ++ .open = simple_open, ++ .llseek = generic_file_llseek, ++}; ++ ++static int index_names = 0; ++static bool debugfs_dir_created = false; ++static const char* file_names = {"mbox-client0", "mbox-client1"}; ++ ++static int mbox_client_light_add_debugfs(struct platform_device *pdev, ++ struct mbox_client_light_device *tdev) ++{ ++ if (!debugfs_initialized()) ++ return 0; ++ ++ if (index_names > 2) { ++ dev_err(&pdev->dev, "Max device index is 2\n"); ++ return 0; ++ } ++ ++ if (!debugfs_dir_created) { ++ root_debugfs_dir = debugfs_create_dir("mailbox",NULL); ++ if (!root_debugfs_dir) { ++ dev_err(&pdev->dev, ++ "Failed to create mailbox debugfs\n"); ++ return -EINVAL; ++ } ++ debugfs_dir_created = true; ++ } ++ ++ debugfs_create_file(file_namesindex_names, 0600, root_debugfs_dir, ++ tdev, &mbox_client_light_message_ops); ++ ++ index_names++; ++ return 0; ++} ++ ++static void mbox_client_light_receive_message(struct mbox_client *client, ++ void *message) ++{ ++ struct mbox_client_light_device *tdev = dev_get_drvdata(client->dev); ++ char *data = message; ++ ++ spin_lock(&tdev->lock); ++ memcpy(tdev->rx_buffer, data, MBOX_MAX_MSG_LEN); ++ spin_unlock(&tdev->lock); ++ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); ++} ++ ++static struct mbox_chan * ++mbox_client_light_request_channel(struct platform_device *pdev, ++ const char *name) ++{ ++ struct mbox_client *client; ++ struct mbox_chan *channel; ++ ++ client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); ++ if (!client) ++ return ERR_PTR(-ENOMEM); ++ ++ client->dev = &pdev->dev; ++ client->tx_block = true; ++ client->knows_txdone = false; ++ client->tx_tout = 500; ++ client->rx_callback = mbox_client_light_receive_message; ++ ++ channel = mbox_request_channel_byname(client, name); ++ if (IS_ERR(channel)) { ++ devm_kfree(&pdev->dev, client); ++ dev_warn(&pdev->dev, "Failed to request %s channel\n", name); ++ return NULL; ++ } ++ ++ return channel; ++} ++ ++static int mbox_client_light_probe(struct platform_device *pdev) ++{ ++ struct mbox_client_light_device *tdev; ++ int ret; ++ static int chan_idx = 0; ++ ++ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); ++ if (!tdev) ++ return -ENOMEM; ++ ++ if (!chan_idx) ++ tdev->tx_channel = mbox_client_light_request_channel(pdev, "902"); ++ else ++ tdev->tx_channel = mbox_client_light_request_channel(pdev, "906"); ++ if (!tdev->tx_channel) { ++ dev_err(&pdev->dev, "Request channel failed\n"); ++ return -EPROBE_DEFER; ++ } ++ chan_idx++; ++ /* In fact, rx_channel is same with tx_channel in C-SKY's mailbox */ ++ tdev->rx_channel = tdev->tx_channel; ++ ++ tdev->dev = &pdev->dev; ++ platform_set_drvdata(pdev, tdev); ++ ++ spin_lock_init(&tdev->lock); ++ ++ tdev->rx_buffer = devm_kzalloc(&pdev->dev, ++ MBOX_MAX_MSG_LEN, GFP_KERNEL); ++ if (!tdev->rx_buffer) ++ return -ENOMEM; ++ ++ ret = mbox_client_light_add_debugfs(pdev, tdev); ++ if (ret) ++ return ret; ++ ++ dev_info(&pdev->dev, "Successfully registered\n"); ++ ++ return 0; ++} ++ ++static int mbox_client_light_remove(struct platform_device *pdev) ++{ ++ struct mbox_client_light_device *tdev = platform_get_drvdata(pdev); ++ ++ debugfs_remove_recursive(root_debugfs_dir); ++ ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ ++ return 0; ++} ++ ++static const struct of_device_id mbox_client_light_match = { ++ { .compatible = "thead,light-mbox-client" }, ++ {}, ++}; ++ ++static struct platform_driver mbox_client_light_driver = { ++ .driver = { ++ .name = "thead,light-mbox-client", ++ .of_match_table = mbox_client_light_match, ++ }, ++ .probe = mbox_client_light_probe, ++ .remove = mbox_client_light_remove, ++}; ++module_platform_driver(mbox_client_light_driver); ++ ++MODULE_AUTHOR("Alibaba Group Holding Limited"); ++MODULE_DESCRIPTION("Thead Light mailbox IPC client driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/mailbox/light-mailbox.c b/drivers/mailbox/light-mailbox.c +new file mode 100644 +index 000000000000..f3d34d947ec4 +--- /dev/null ++++ b/drivers/mailbox/light-mailbox.c +@@ -0,0 +1,507 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/mailbox_controller.h> ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/slab.h> ++ ++/* Status Register */ ++#define LIGHT_MBOX_STA 0x0 ++#define LIGHT_MBOX_CLR 0x4 ++#define LIGHT_MBOX_MASK 0xc ++ ++/* Transmit/receive data register: ++ * INFO0 ~ INFO6 ++ */ ++#define LIGHT_MBOX_INFO_NUM 8 ++#define LIGHT_MBOX_DATA_INFO_NUM 7 ++#define LIGHT_MBOX_INFO0 0x14 ++/* Transmit ack register: INFO7 */ ++#define LIGHT_MBOX_INFO7 0x30 ++ ++/* Generate remote icu IRQ Register */ ++#define LIGHT_MBOX_GEN 0x10 ++#define LIGHT_MBOX_GEN_RX_DATA BIT(6) ++#define LIGHT_MBOX_GEN_TX_ACK BIT(7) ++ ++#define LIGHT_MBOX_CHAN_RES_SIZE 0x1000 ++#define LIGHT_MBOX_CHANS 4 ++#define LIGHT_MBOX_CHAN_NAME_SIZE 20 ++ ++#define LIGHT_MBOX_ACK_MAGIC 0xdeadbeaf ++ ++enum light_mbox_chan_type { ++ LIGHT_MBOX_TYPE_TXRX, /* Tx & Rx chan */ ++ LIGHT_MBOX_TYPE_DB, /* Tx & Rx doorbell */ ++}; ++ ++enum light_mbox_icu_cpu_id { ++ LIGHT_MBOX_ICU_CPU0, /* 910T */ ++ LIGHT_MBOX_ICU_CPU1, /* 902 */ ++ LIGHT_MBOX_ICU_CPU2, /* 906 */ ++ LIGHT_MBOX_ICU_CPU3, /* 910R */ ++}; ++ ++struct light_mbox_con_priv { ++ enum light_mbox_icu_cpu_id idx; ++ enum light_mbox_chan_type type; ++ void __iomem *comm_local_base; ++ void __iomem *comm_remote_base; ++ char irq_descLIGHT_MBOX_CHAN_NAME_SIZE; ++ struct mbox_chan *chan; ++ struct tasklet_struct txdb_tasklet; ++}; ++ ++struct light_mbox_priv { ++ struct device *dev; ++ void __iomem *local_icuLIGHT_MBOX_CHANS; ++ void __iomem *remote_icuLIGHT_MBOX_CHANS - 1; ++ void __iomem *cur_cpu_ch_base; ++ enum light_mbox_icu_cpu_id cur_icu_cpu_id; ++ spinlock_t mbox_lock; /* control register lock */ ++ ++ struct mbox_controller mbox; ++ struct mbox_chan mbox_chansLIGHT_MBOX_CHANS; ++ ++ struct light_mbox_con_priv con_privLIGHT_MBOX_CHANS; ++ struct clk *clk; ++ int irq; ++}; ++ ++static struct light_mbox_priv *to_light_mbox_priv(struct mbox_controller *mbox) ++{ ++ return container_of(mbox, struct light_mbox_priv, mbox); ++} ++ ++static void light_mbox_write(struct light_mbox_priv *priv, u32 val, u32 offs) ++{ ++ iowrite32(val, priv->cur_cpu_ch_base + offs); ++} ++ ++static u32 light_mbox_read(struct light_mbox_priv *priv, u32 offs) ++{ ++ return ioread32(priv->cur_cpu_ch_base + offs); ++} ++ ++static u32 light_mbox_rmw(struct light_mbox_priv *priv, u32 off, u32 set, u32 clr) ++{ ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&priv->mbox_lock, flags); ++ val = light_mbox_read(priv, off); ++ val &= ~clr; ++ val |= set; ++ light_mbox_write(priv, val, off); ++ spin_unlock_irqrestore(&priv->mbox_lock, flags); ++ ++ return val; ++} ++ ++static void light_mbox_chan_write(struct light_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 light_mbox_chan_read(struct light_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 light_mbox_chan_rmw(struct light_mbox_con_priv *cp, u32 off, u32 set, u32 clr, bool is_remote) ++{ ++ struct light_mbox_priv *priv = to_light_mbox_priv(cp->chan->mbox); ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(&priv->mbox_lock, flags); ++ val = light_mbox_chan_read(cp, off, is_remote); ++ val &= ~clr; ++ val |= set; ++ light_mbox_chan_write(cp, val, off, is_remote); ++ spin_unlock_irqrestore(&priv->mbox_lock, flags); ++} ++ ++static void light_mbox_chan_rd_data(struct light_mbox_con_priv *cp, void *data, bool is_remote) ++{ ++ u32 off = LIGHT_MBOX_INFO0; ++ u32 *arg = data; ++ u32 i; ++ ++ /* read info0 ~ info6, totally 28 bytes ++ * requires data memory size is 28 bytes ++ */ ++ for (i = 0; i < LIGHT_MBOX_DATA_INFO_NUM; i++) { ++ *arg = light_mbox_chan_read(cp, off, is_remote); ++ off += 4; ++ arg++; ++ } ++} ++ ++static void light_mbox_chan_wr_data(struct light_mbox_con_priv *cp, void *data, bool is_remote) ++{ ++ u32 off = LIGHT_MBOX_INFO0; ++ u32 *arg = data; ++ u32 i; ++ ++ /* write info0 ~ info6, totally 28 bytes ++ * requires data memory is 28 bytes valid data ++ */ ++ for (i = 0; i < LIGHT_MBOX_DATA_INFO_NUM; i++) { ++ light_mbox_chan_write(cp, *arg, off, is_remote); ++ off += 4; ++ arg++; ++ } ++} ++ ++static void light_mbox_chan_wr_ack(struct light_mbox_con_priv *cp, void *data, bool is_remote) ++{ ++ u32 off = LIGHT_MBOX_INFO7; ++ u32 *arg = data; ++ ++ light_mbox_chan_write(cp, *arg, off, is_remote); ++} ++ ++static int light_mbox_chan_id_to_mapbit(struct light_mbox_con_priv *cp) ++{ ++ struct light_mbox_priv *priv = to_light_mbox_priv(cp->chan->mbox); ++ int mapbit = 0; ++ int i; ++ ++ for (i = 0; i < LIGHT_MBOX_CHANS; i++) { ++ if (i == cp->idx) ++ return mapbit; ++ ++ if (i != priv->cur_icu_cpu_id) ++ mapbit++; ++ } ++ ++ if (i == LIGHT_MBOX_CHANS) ++ dev_err(cp->chan->mbox->dev, "convert to mapbit failed\n"); ++ ++ return 0; ++} ++ ++static void light_mbox_txdb_tasklet(unsigned long data) ++{ ++ struct light_mbox_con_priv *cp = (struct light_mbox_con_priv *)data; ++ ++ mbox_chan_txdone(cp->chan, 0); ++} ++ ++static irqreturn_t light_mbox_isr(int irq, void *p) ++{ ++ struct mbox_chan *chan = p; ++ struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); ++ struct light_mbox_con_priv *cp = chan->con_priv; ++ int mapbit = light_mbox_chan_id_to_mapbit(cp); ++ u32 sta, datLIGHT_MBOX_DATA_INFO_NUM; ++ u32 ack_magic = LIGHT_MBOX_ACK_MAGIC; ++ u32 info0_data, info7_data; ++ ++ sta = light_mbox_read(priv, LIGHT_MBOX_STA); ++ if (!(sta & BIT(mapbit))) ++ return IRQ_NONE; ++ ++ /* clear chan irq bit in STA register */ ++ light_mbox_rmw(priv, LIGHT_MBOX_CLR, BIT(mapbit), 0); ++ ++ /* rx doorbell */ ++ if (cp->type == LIGHT_MBOX_TYPE_DB) { ++ mbox_chan_received_data(cp->chan, NULL); ++ return IRQ_HANDLED; ++ } ++ ++ /* info0 is the protocol word, shoud not be zero! */ ++ info0_data = light_mbox_chan_read(cp, LIGHT_MBOX_INFO0, false); ++ if (info0_data) { ++ /* read info0~info6 data */ ++ light_mbox_chan_rd_data(cp, dat, false); ++ ++ /* clear local info0 */ ++ light_mbox_chan_write(cp, 0x0, LIGHT_MBOX_INFO0, false); ++ ++ /* notify remote cpu */ ++ light_mbox_chan_wr_ack(cp, &ack_magic, true); ++ /* CPU1 902/906 use polling mode to monitor info7 */ ++ if (cp->idx != LIGHT_MBOX_ICU_CPU1 && cp->idx != LIGHT_MBOX_ICU_CPU2) ++ light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, LIGHT_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 = light_mbox_chan_read(cp, LIGHT_MBOX_INFO7, false); ++ if (info7_data == LIGHT_MBOX_ACK_MAGIC) { ++ /* clear local info7 */ ++ light_mbox_chan_write(cp, 0x0, LIGHT_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 light_mbox_send_data(struct mbox_chan *chan, void *data) ++{ ++ struct light_mbox_con_priv *cp = chan->con_priv; ++ ++ if (cp->type == LIGHT_MBOX_TYPE_DB) ++ tasklet_schedule(&cp->txdb_tasklet); ++ else ++ light_mbox_chan_wr_data(cp, data, true); ++ light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, LIGHT_MBOX_GEN_RX_DATA, 0, true); ++ return 0; ++} ++ ++static int light_mbox_startup(struct mbox_chan *chan) ++{ ++ struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); ++ struct light_mbox_con_priv *cp = chan->con_priv; ++ u32 data8 = {0}; ++ int mask_bit; ++ int ret; ++ ++ /* clear local and remote generate and info0~info7 */ ++ light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, 0x0, 0xff, true); ++ light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, 0x0, 0xff, false); ++ light_mbox_chan_wr_ack(cp, &data7, true); ++ light_mbox_chan_wr_ack(cp, &data7, false); ++ light_mbox_chan_wr_data(cp, &data0, true); ++ light_mbox_chan_wr_data(cp, &data0, false); ++ ++ /* enable the chan mask */ ++ mask_bit = light_mbox_chan_id_to_mapbit(cp); ++ light_mbox_rmw(priv, LIGHT_MBOX_MASK, BIT(mask_bit), 0); ++ ++ if (cp->type == LIGHT_MBOX_TYPE_DB) ++ /* tx doorbell doesn't have ACK, rx doorbell requires isr */ ++ tasklet_init(&cp->txdb_tasklet, light_mbox_txdb_tasklet, ++ (unsigned long)cp); ++ ++ ret = request_irq(priv->irq, light_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 light_mbox_shutdown(struct mbox_chan *chan) ++{ ++ struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); ++ struct light_mbox_con_priv *cp = chan->con_priv; ++ int mask_bit; ++ ++ /* clear the chan mask */ ++ mask_bit = light_mbox_chan_id_to_mapbit(cp); ++ light_mbox_rmw(priv, LIGHT_MBOX_MASK, 0, BIT(mask_bit)); ++ ++ free_irq(priv->irq, chan); ++} ++ ++static const struct mbox_chan_ops light_mbox_ops = { ++ .send_data = light_mbox_send_data, ++ .startup = light_mbox_startup, ++ .shutdown = light_mbox_shutdown, ++}; ++ ++static void light_mbox_init_generic(struct light_mbox_priv *priv) ++{ ++ /* Set default configuration */ ++ light_mbox_write(priv, 0xff, LIGHT_MBOX_CLR); ++ light_mbox_write(priv, 0x0, LIGHT_MBOX_MASK); ++} ++ ++static struct mbox_chan *light_mbox_xlate(struct mbox_controller *mbox, ++ const struct of_phandle_args *sp) ++{ ++ struct light_mbox_priv *priv = to_light_mbox_priv(mbox); ++ struct light_mbox_con_priv *cp; ++ u32 chan, type; ++ ++ if (sp->args_count != 2) { ++ dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ chan = sp->args0; /* comm remote channel */ ++ type = sp->args1; /* comm channel type */ ++ ++ if (chan >= mbox->num_chans) { ++ dev_err(mbox->dev, "Not supported channel number: %d\n", chan); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (chan == priv->cur_icu_cpu_id) { ++ dev_err(mbox->dev, "Cannot communicate with yourself\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (type > LIGHT_MBOX_TYPE_DB) { ++ dev_err(mbox->dev, "Not supported the type for channel%d\n", chan); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ cp = mbox->chanschan.con_priv; ++ cp->type = type; ++ ++ return &mbox->chanschan; ++} ++ ++static int light_mbox_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct light_mbox_priv *priv; ++ struct resource *res; ++ unsigned int remote_idx = 0; ++ unsigned int i; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ if (of_property_read_u32(np, "icu_cpu_id", &priv->cur_icu_cpu_id)) { ++ dev_err(dev, "icu_cpu_id is missing\n"); ++ return -EINVAL; ++ } ++ ++ if (priv->cur_icu_cpu_id != LIGHT_MBOX_ICU_CPU0 && ++ priv->cur_icu_cpu_id != LIGHT_MBOX_ICU_CPU3) { ++ dev_err(dev, "icu_cpu_id is invalid\n"); ++ return -EINVAL; ++ } ++ ++ priv->dev = dev; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "local_base"); ++ priv->local_icuLIGHT_MBOX_ICU_CPU0 = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->local_icuLIGHT_MBOX_ICU_CPU0)) ++ return PTR_ERR(priv->local_icuLIGHT_MBOX_ICU_CPU0); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu0"); ++ priv->remote_icu0 = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->remote_icu0)) ++ return PTR_ERR(priv->remote_icu0); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu1"); ++ priv->remote_icu1 = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->remote_icu1)) ++ return PTR_ERR(priv->remote_icu1); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu2"); ++ priv->remote_icu2 = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->remote_icu2)) ++ return PTR_ERR(priv->remote_icu2); ++ ++ priv->local_icuLIGHT_MBOX_ICU_CPU1 = priv->local_icuLIGHT_MBOX_ICU_CPU0 + ++ LIGHT_MBOX_CHAN_RES_SIZE; ++ priv->local_icuLIGHT_MBOX_ICU_CPU2 = priv->local_icuLIGHT_MBOX_ICU_CPU1 + ++ LIGHT_MBOX_CHAN_RES_SIZE; ++ priv->local_icuLIGHT_MBOX_ICU_CPU3 = priv->local_icuLIGHT_MBOX_ICU_CPU2 + ++ LIGHT_MBOX_CHAN_RES_SIZE; ++ ++ priv->cur_cpu_ch_base = priv->local_icupriv->cur_icu_cpu_id; ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (priv->irq < 0) ++ return priv->irq; ++ ++ priv->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ if (PTR_ERR(priv->clk) != -ENOENT) ++ return PTR_ERR(priv->clk); ++ ++ priv->clk = NULL; ++ } ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(dev, "Failed to enable clock\n"); ++ return ret; ++ } ++ ++ /* init the chans */ ++ for (i = 0; i < LIGHT_MBOX_CHANS; i++) { ++ struct light_mbox_con_priv *cp = &priv->con_privi; ++ ++ cp->idx = i; ++ cp->chan = &priv->mbox_chansi; ++ priv->mbox_chansi.con_priv = cp; ++ snprintf(cp->irq_desc, sizeof(cp->irq_desc), ++ "light_mbox_chan%i", cp->idx); ++ ++ cp->comm_local_base = priv->local_icui; ++ if (i != priv->cur_icu_cpu_id) { ++ cp->comm_remote_base = priv->remote_icuremote_idx; ++ remote_idx++; ++ } ++ } ++ ++ spin_lock_init(&priv->mbox_lock); ++ ++ priv->mbox.dev = dev; ++ priv->mbox.ops = &light_mbox_ops; ++ priv->mbox.chans = priv->mbox_chans; ++ priv->mbox.num_chans = LIGHT_MBOX_CHANS; ++ priv->mbox.of_xlate = light_mbox_xlate; ++ priv->mbox.txdone_irq = true; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ light_mbox_init_generic(priv); ++ ++ return devm_mbox_controller_register(dev, &priv->mbox); ++} ++ ++static int light_mbox_remove(struct platform_device *pdev) ++{ ++ struct light_mbox_priv *priv = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id light_mbox_dt_ids = { ++ { .compatible = "thead,light-mbox" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, light_mbox_dt_ids); ++ ++static struct platform_driver light_mbox_driver = { ++ .probe = light_mbox_probe, ++ .remove = light_mbox_remove, ++ .driver = { ++ .name = "light_mbox", ++ .of_match_table = light_mbox_dt_ids, ++ }, ++}; ++module_platform_driver(light_mbox_driver); ++ ++MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light mailbox IPC driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 554e67103c1a..97dd14701193 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -654,6 +654,20 @@ config MMC_SDHCI_SPRD + + If unsure, say N. + ++config MMC_SDHCI_SOPHGO ++ tristate "Sophgo/BitMain SDIO host Controller" ++ depends on MMC_SDHCI_PLTFM ++ help ++ This selects the SDIO Host Controller in Sophgo/BitMain ++ SoCs. ++ ++ If you have a controller with this interface, say Y or M here. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called sdhci-sophgo. ++ + config MMC_TMIO_CORE + tristate + +diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile +index a693fa3d3f1c..36976786afe2 100644 +--- a/drivers/mmc/host/Makefile ++++ b/drivers/mmc/host/Makefile +@@ -95,6 +95,7 @@ obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o + obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o + obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o + obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o ++obj-$(CONFIG_MMC_SDHCI_SOPHGO) += sdhci-sophgo.o + obj-$(CONFIG_MMC_SUNPLUS) += sunplus-mmc.o + obj-$(CONFIG_MMC_CQHCI) += cqhci.o + cqhci-y += cqhci-core.o +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index 3a3bae6948a8..0eb72544c09e 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -8,6 +8,7 @@ + */ + + #include <linux/acpi.h> ++#include <linux/bitfield.h> + #include <linux/clk.h> + #include <linux/dma-mapping.h> + #include <linux/iopoll.h> +@@ -35,6 +36,21 @@ + #define DWCMSHC_CARD_IS_EMMC BIT(0) + #define DWCMSHC_ENHANCED_STROBE BIT(8) + #define DWCMSHC_EMMC_ATCTRL 0x40 ++/* Tuning and auto-tuning fields in AT_CTRL_R control register */ ++#define AT_CTRL_AT_EN BIT(0) /* autotuning is enabled */ ++#define AT_CTRL_CI_SEL BIT(1) /* interval to drive center phase select */ ++#define AT_CTRL_SWIN_TH_EN BIT(2) /* sampling window threshold enable */ ++#define AT_CTRL_RPT_TUNE_ERR BIT(3) /* enable reporting framing errors */ ++#define AT_CTRL_SW_TUNE_EN BIT(4) /* enable software managed tuning */ ++#define AT_CTRL_WIN_EDGE_SEL_MASK GENMASK(11, 8) /* bits 11:8 */ ++#define AT_CTRL_WIN_EDGE_SEL 0xf /* sampling window edge select */ ++#define AT_CTRL_TUNE_CLK_STOP_EN BIT(16) /* clocks stopped during phase code change */ ++#define AT_CTRL_PRE_CHANGE_DLY_MASK GENMASK(18, 17) /* bits 18:17 */ ++#define AT_CTRL_PRE_CHANGE_DLY 0x1 /* 2-cycle latency */ ++#define AT_CTRL_POST_CHANGE_DLY_MASK GENMASK(20, 19) /* bits 20:19 */ ++#define AT_CTRL_POST_CHANGE_DLY 0x3 /* 4-cycle latency */ ++#define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits 31:24 */ ++#define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */ + + /* Rockchip specific Registers */ + #define DWCMSHC_EMMC_DLL_CTRL 0x800 +@@ -72,6 +88,82 @@ + (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) + #define RK35xx_MAX_CLKS 3 + ++/* PHY register area pointer */ ++#define DWC_MSHC_PTR_PHY_R 0x300 ++ ++/* PHY general configuration */ ++#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) ++#define PHY_CNFG_RSTN_DEASSERT 0x1 /* Deassert PHY reset */ ++#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16) /* bits 19:16 */ ++#define PHY_CNFG_PAD_SP 0x0c /* PMOS TX drive strength */ ++#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20) /* bits 23:20 */ ++#define PHY_CNFG_PAD_SN 0x0c /* NMOS TX drive strength */ ++ ++/* PHY command/response pad settings */ ++#define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04) ++ ++/* PHY data pad settings */ ++#define PHY_DATAPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x06) ++ ++/* PHY clock pad settings */ ++#define PHY_CLKPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x08) ++ ++/* PHY strobe pad settings */ ++#define PHY_STBPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0a) ++ ++/* PHY reset pad settings */ ++#define PHY_RSTNPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0c) ++ ++/* Bitfields are common for all pad settings */ ++#define PHY_PAD_RXSEL_1V8 0x1 /* Receiver type select for 1.8V */ ++#define PHY_PAD_RXSEL_3V3 0x2 /* Receiver type select for 3.3V */ ++ ++#define PHY_PAD_WEAKPULL_MASK GENMASK(4, 3) /* bits 4:3 */ ++#define PHY_PAD_WEAKPULL_PULLUP 0x1 /* Weak pull up enabled */ ++#define PHY_PAD_WEAKPULL_PULLDOWN 0x2 /* Weak pull down enabled */ ++ ++#define PHY_PAD_TXSLEW_CTRL_P_MASK GENMASK(8, 5) /* bits 8:5 */ ++#define PHY_PAD_TXSLEW_CTRL_P 0x3 /* Slew control for P-Type pad TX */ ++#define PHY_PAD_TXSLEW_CTRL_N_MASK GENMASK(12, 9) /* bits 12:9 */ ++#define PHY_PAD_TXSLEW_CTRL_N 0x3 /* Slew control for N-Type pad TX */ ++ ++/* PHY CLK delay line settings */ ++#define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d) ++#define PHY_SDCLKDL_CNFG_UPDATE BIT(4) /* set before writing to SDCLKDL_DC */ ++ ++/* PHY CLK delay line delay code */ ++#define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e) ++#define PHY_SDCLKDL_DC_INITIAL 0x40 /* initial delay code */ ++#define PHY_SDCLKDL_DC_DEFAULT 0x32 /* default delay code */ ++#define PHY_SDCLKDL_DC_HS400 0x18 /* delay code for HS400 mode */ ++ ++/* PHY drift_cclk_rx delay line configuration setting */ ++#define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21) ++#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2) /* bits 3:2 */ ++#define PHY_ATDL_CNFG_INPSEL 0x3 /* delay line input source */ ++ ++/* PHY DLL control settings */ ++#define PHY_DLL_CTRL_R (DWC_MSHC_PTR_PHY_R + 0x24) ++#define PHY_DLL_CTRL_DISABLE 0x0 /* PHY DLL is enabled */ ++#define PHY_DLL_CTRL_ENABLE 0x1 /* PHY DLL is disabled */ ++ ++/* PHY DLL configuration register 1 */ ++#define PHY_DLL_CNFG1_R (DWC_MSHC_PTR_PHY_R + 0x25) ++#define PHY_DLL_CNFG1_SLVDLY_MASK GENMASK(5, 4) /* bits 5:4 */ ++#define PHY_DLL_CNFG1_SLVDLY 0x2 /* DLL slave update delay input */ ++#define PHY_DLL_CNFG1_WAITCYCLE 0x5 /* DLL wait cycle input */ ++ ++/* PHY DLL configuration register 2 */ ++#define PHY_DLL_CNFG2_R (DWC_MSHC_PTR_PHY_R + 0x26) ++#define PHY_DLL_CNFG2_JUMPSTEP 0xa /* DLL jump step input */ ++ ++/* PHY DLL master and slave delay line configuration settings */ ++#define PHY_DLLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x28) ++#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5) /* bits 6:5 */ ++#define PHY_DLLDL_CNFG_SLV_INPSEL 0x3 /* clock source select for slave DL */ ++ ++#define FLAG_IO_FIXED_1V8 BIT(0) ++ + #define BOUNDARY_OK(addr, len) \ + ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) + +@@ -92,6 +184,8 @@ struct dwcmshc_priv { + struct clk *bus_clk; + int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ + void *priv; /* pointer to SoC private stuff */ ++ u16 delay_line; ++ u16 flags; + }; + + /* +@@ -157,6 +251,127 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq) + sdhci_request(mmc, mrq); + } + ++static void dwcmshc_phy_1_8v_init(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ u32 val; ++ ++ /* deassert phy reset & set tx drive strength */ ++ val = PHY_CNFG_RSTN_DEASSERT; ++ val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP); ++ val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN); ++ sdhci_writel(host, val, PHY_CNFG_R); ++ ++ /* disable delay line */ ++ sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R); ++ ++ /* set delay line */ ++ sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R); ++ sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R); ++ ++ /* enable delay lane */ ++ val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); ++ val &= ~(PHY_SDCLKDL_CNFG_UPDATE); ++ sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); ++ ++ /* configure phy pads */ ++ val = PHY_PAD_RXSEL_1V8; ++ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); ++ sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); ++ sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); ++ sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); ++ ++ val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); ++ sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); ++ ++ val = PHY_PAD_RXSEL_1V8; ++ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); ++ sdhci_writew(host, val, PHY_STBPAD_CNFG_R); ++ ++ /* enable data strobe mode */ ++ sdhci_writeb(host, FIELD_PREP(PHY_DLLDL_CNFG_SLV_INPSEL_MASK, PHY_DLLDL_CNFG_SLV_INPSEL), ++ PHY_DLLDL_CNFG_R); ++ ++ /* enable phy dll */ ++ sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); ++} ++ ++static void dwcmshc_phy_3_3v_init(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ u32 val; ++ ++ /* deassert phy reset & set tx drive strength */ ++ val = PHY_CNFG_RSTN_DEASSERT; ++ val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP); ++ val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN); ++ sdhci_writel(host, val, PHY_CNFG_R); ++ ++ /* disable delay line */ ++ sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R); ++ ++ /* set delay line */ ++ sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R); ++ sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R); ++ ++ /* enable delay lane */ ++ val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); ++ val &= ~(PHY_SDCLKDL_CNFG_UPDATE); ++ sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); ++ ++ /* configure phy pads */ ++ val = PHY_PAD_RXSEL_3V3; ++ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); ++ sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); ++ sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); ++ sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); ++ ++ val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); ++ sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); ++ ++ val = PHY_PAD_RXSEL_3V3; ++ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); ++ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); ++ sdhci_writew(host, val, PHY_STBPAD_CNFG_R); ++ ++ /* enable phy dll */ ++ sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); ++} ++ ++static void th1520_sdhci_set_phy(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; ++ u16 emmc_ctrl; ++ ++ /* Before power on, set PHY configs */ ++ if (priv->flags & FLAG_IO_FIXED_1V8) ++ dwcmshc_phy_1_8v_init(host); ++ else ++ dwcmshc_phy_3_3v_init(host); ++ ++ if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { ++ emmc_ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); ++ emmc_ctrl |= DWCMSHC_CARD_IS_EMMC; ++ sdhci_writew(host, emmc_ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); ++ } ++ ++ sdhci_writeb(host, FIELD_PREP(PHY_DLL_CNFG1_SLVDLY_MASK, PHY_DLL_CNFG1_SLVDLY) | ++ PHY_DLL_CNFG1_WAITCYCLE, PHY_DLL_CNFG1_R); ++} ++ + static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) + { +@@ -189,9 +404,25 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, + ctrl_2 |= DWCMSHC_CTRL_HS400; + } + ++ if (priv->flags & FLAG_IO_FIXED_1V8) ++ ctrl_2 |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + } + ++static void th1520_set_uhs_signaling(struct sdhci_host *host, ++ unsigned int timing) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ ++ dwcmshc_set_uhs_signaling(host, timing); ++ if (timing == MMC_TIMING_MMC_HS400) ++ priv->delay_line = PHY_SDCLKDL_DC_HS400; ++ else ++ sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R); ++ th1520_sdhci_set_phy(host); ++} ++ + static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, + struct mmc_ios *ios) + { +@@ -338,6 +569,79 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) + sdhci_reset(host, mask); + } + ++static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ u32 val = 0; ++ ++ if (host->flags & SDHCI_HS400_TUNING) ++ return 0; ++ ++ sdhci_writeb(host, FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL), ++ PHY_ATDL_CNFG_R); ++ val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); ++ ++ /* ++ * configure tuning settings: ++ * - center phase select code driven in block gap interval ++ * - disable reporting of framing errors ++ * - disable software managed tuning ++ * - disable user selection of sampling window edges, ++ * instead tuning calculated edges are used ++ */ ++ val &= ~(AT_CTRL_CI_SEL | AT_CTRL_RPT_TUNE_ERR | AT_CTRL_SW_TUNE_EN | ++ FIELD_PREP(AT_CTRL_WIN_EDGE_SEL_MASK, AT_CTRL_WIN_EDGE_SEL)); ++ ++ /* ++ * configure tuning settings: ++ * - enable auto-tuning ++ * - enable sampling window threshold ++ * - stop clocks during phase code change ++ * - set max latency in cycles between tx and rx clocks ++ * - set max latency in cycles to switch output phase ++ * - set max sampling window threshold value ++ */ ++ val |= AT_CTRL_AT_EN | AT_CTRL_SWIN_TH_EN | AT_CTRL_TUNE_CLK_STOP_EN; ++ val |= FIELD_PREP(AT_CTRL_PRE_CHANGE_DLY_MASK, AT_CTRL_PRE_CHANGE_DLY); ++ val |= FIELD_PREP(AT_CTRL_POST_CHANGE_DLY_MASK, AT_CTRL_POST_CHANGE_DLY); ++ val |= FIELD_PREP(AT_CTRL_SWIN_TH_VAL_MASK, AT_CTRL_SWIN_TH_VAL); ++ ++ sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); ++ val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); ++ ++ /* perform tuning */ ++ sdhci_start_tuning(host); ++ host->tuning_err = __sdhci_execute_tuning(host, opcode); ++ if (host->tuning_err) { ++ /* disable auto-tuning upon tuning error */ ++ val &= ~AT_CTRL_AT_EN; ++ sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); ++ dev_err(mmc_dev(host->mmc), "tuning failed: %d\n", host->tuning_err); ++ return -EIO; ++ } ++ sdhci_end_tuning(host); ++ ++ return 0; ++} ++ ++static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ u16 ctrl_2; ++ ++ sdhci_reset(host, mask); ++ ++ if (priv->flags & FLAG_IO_FIXED_1V8) { ++ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ if (!(ctrl_2 & SDHCI_CTRL_VDD_180)) { ++ ctrl_2 |= SDHCI_CTRL_VDD_180; ++ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); ++ } ++ } ++} ++ + static const struct sdhci_ops sdhci_dwcmshc_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, +@@ -356,6 +660,17 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { + .adma_write_desc = dwcmshc_adma_write_desc, + }; + ++static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = { ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .set_uhs_signaling = th1520_set_uhs_signaling, ++ .get_max_clock = dwcmshc_get_max_clock, ++ .reset = th1520_sdhci_reset, ++ .adma_write_desc = dwcmshc_adma_write_desc, ++ .voltage_switch = dwcmshc_phy_1_8v_init, ++ .platform_execute_tuning = &th1520_execute_tuning, ++}; ++ + static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +@@ -379,6 +694,12 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, + }; + ++static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = { ++ .ops = &sdhci_dwcmshc_th1520_ops, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, ++}; ++ + static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) + { + int err; +@@ -447,6 +768,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids = { + .compatible = "snps,dwcmshc-sdhci", + .data = &sdhci_dwcmshc_pdata, + }, ++ { ++ .compatible = "thead,th1520-dwcmshc", ++ .data = &sdhci_dwcmshc_th1520_pdata, ++ }, + {}, + }; + MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); +@@ -542,6 +867,30 @@ static int dwcmshc_probe(struct platform_device *pdev) + goto err_clk; + } + ++ if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) { ++ priv->delay_line = PHY_SDCLKDL_DC_DEFAULT; ++ ++ if ((device_property_read_bool(dev, "mmc-ddr-1_8v")) | ++ (device_property_read_bool(dev, "mmc-hs200-1_8v")) | ++ (device_property_read_bool(dev, "mmc-hs400-1_8v"))) ++ priv->flags |= FLAG_IO_FIXED_1V8; ++ else ++ priv->flags &= ~FLAG_IO_FIXED_1V8; ++ ++ /* ++ * start_signal_voltage_switch() will try 3.3V first ++ * then 1.8V. Use SDHCI_SIGNALING_180 rather than ++ * SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V ++ * in sdhci_start_signal_voltage_switch(). ++ */ ++ if (priv->flags & FLAG_IO_FIXED_1V8) { ++ host->flags &= ~SDHCI_SIGNALING_330; ++ host->flags |= SDHCI_SIGNALING_180; ++ } ++ ++ sdhci_enable_v4_mode(host); ++ } ++ + #ifdef CONFIG_ACPI + if (pltfm_data == &sdhci_dwcmshc_bf3_pdata) + sdhci_enable_v4_mode(host); +diff --git a/drivers/mmc/host/sdhci-sophgo.c b/drivers/mmc/host/sdhci-sophgo.c +new file mode 100644 +index 000000000000..8200ccaa68f6 +--- /dev/null ++++ b/drivers/mmc/host/sdhci-sophgo.c +@@ -0,0 +1,619 @@ ++/* ++ * Sophgo SDHCI Platform driver ++ * ++ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/delay.h> ++#include <linux/mmc/mmc.h> ++#include <linux/slab.h> ++#include <linux/reset.h> ++#include "sdhci-pltfm.h" ++#include "sdhci-sophgo.h" ++ ++#define DRIVER_NAME "bm" ++ ++#define BM_SDHCI_VENDOR_OFFSET 0x500 ++#define BM_SDHCI_VENDOR_MSHC_CTRL_R (BM_SDHCI_VENDOR_OFFSET + 0x8) ++#define BM_SDHCI_VENDOR_A_CTRL_R (BM_SDHCI_VENDOR_OFFSET + 0x40) ++#define BM_SDHCI_VENDOR_A_STAT_R (BM_SDHCI_VENDOR_OFFSET + 0x44) ++ ++static void bm_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) ++{ ++ sdhci_writel(host, 0x0, BM_SDHCI_VENDOR_MSHC_CTRL_R); ++ sdhci_writel(host, 0x18, BM_SDHCI_VENDOR_A_CTRL_R); ++ sdhci_writel(host, tap, BM_SDHCI_VENDOR_A_STAT_R); ++} ++ ++static int sdhci_bm_execute_software_tuning(struct sdhci_host *host, u32 opcode) ++{ ++ unsigned int maxwidth = 0; ++ unsigned int tuntap; ++ struct { ++ unsigned int start; ++ unsigned int end; ++ unsigned int width; ++ } tunlist4; ++ unsigned int listcount; ++ unsigned int listsel; ++ ++ unsigned int tun = 0; ++ unsigned int max = 256; ++ int i; ++ ++ listcount = 0; ++ for (i = 0; i < ARRAY_SIZE(tunlist); i++) { ++ while (tun < max) { ++ bm_sdhci_set_tap(host, tun); ++ if (!mmc_send_tuning(host->mmc, opcode, NULL)) ++ break; ++ tun++; ++ } ++ tunlisti.start = tun; ++ tun++; ++ while (tun < max) { ++ bm_sdhci_set_tap(host, tun); ++ if (mmc_send_tuning(host->mmc, opcode, NULL)) ++ break; ++ tun++; ++ } ++ tunlisti.end = tun-1; ++ tunlisti.width = tunlisti.end - tunlisti.start; ++ listcount++; ++ tun++; ++ pr_info("%s id:%d start:%d end:%d width:%d\n", mmc_hostname(host->mmc), ++ i, tunlisti.start, tunlisti.end, tunlisti.width); ++ if (tun >= max) ++ break; ++ } ++ ++ //find maxwidth ++ listsel = 0; ++ for (i = 0; i < listcount; i++) { ++ if (tunlisti.width > maxwidth) { ++ maxwidth = tunlisti.width; ++ listsel = i; ++ } ++ } ++ tuntap = tunlistlistsel.start + (tunlistlistsel.width/2); ++ ++ /* The TRM states the ideal tap value is at 75% in the passing range. */ ++ bm_sdhci_set_tap(host, tuntap); ++ pr_info("%s listsel:%d tuntap:%d\n", ++ mmc_hostname(host->mmc), listsel, tuntap); ++ ++ return mmc_send_tuning(host->mmc, opcode, NULL); ++} ++ ++static int sdhci_bm_select_drive_strength(struct mmc_card *card, ++ unsigned int max_dtr, int host_drv, ++ int card_drv, int *drv_type) ++{ ++ struct sdhci_host *host = mmc_priv(card->host); ++ struct mmc_host *mmc = host->mmc; ++ uint32_t reg; ++ int driver_type; ++ ++ pr_info("%s max_dtr %d, host_drv %d, card_drv %d, drv_type %d\n", ++ mmc_hostname(mmc), ++ max_dtr, host_drv, card_drv, *drv_type); ++ ++ driver_type = MMC_SET_DRIVER_TYPE_C; ++ *drv_type = MMC_SET_DRIVER_TYPE_C; ++ ++ reg = (1 << PHY_CNFG_PHY_PWRGOOD) | (0xe << PHY_CNFG_PAD_SP) | ++ (0xe << PHY_CNFG_PAD_SN) | (1 << PHY_CNFG_PHY_RSTN); ++ sdhci_writel(host, reg, SDHCI_P_PHY_CNFG); ++ ++ return driver_type; ++} ++ ++static void sdhci_bm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) ++{ ++ struct mmc_host *mmc = host->mmc; ++ u16 ctrl_2; ++ ++ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ /* Select Bus Speed Mode for host */ ++ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; ++ switch (uhs) { ++ case MMC_TIMING_UHS_SDR12: ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR12; ++ break; ++ case MMC_TIMING_UHS_SDR25: ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR25; ++ break; ++ case MMC_TIMING_UHS_SDR50: ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR50; ++ break; ++ case MMC_TIMING_MMC_HS200: ++ case MMC_TIMING_UHS_SDR104: ++ ctrl_2 |= SDHCI_CTRL_UHS_SDR104; ++ break; ++ case MMC_TIMING_UHS_DDR50: ++ case MMC_TIMING_MMC_DDR52: ++ ctrl_2 |= SDHCI_CTRL_UHS_DDR50; ++ break; ++ } ++ ++ /* ++ * When clock frequency is less than 100MHz, the feedback clock must be ++ * provided and DLL must not be used so that tuning can be skipped. To ++ * provide feedback clock, the mode selection can be any value less ++ * than 3'b011 in bits 2:0 of HOST CONTROL2 register. ++ */ ++ if (host->clock <= 100000000 && ++ (uhs == MMC_TIMING_MMC_HS400 || ++ uhs == MMC_TIMING_MMC_HS200 || ++ uhs == MMC_TIMING_UHS_SDR104)) ++ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; ++ ++ dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n", ++ mmc_hostname(host->mmc), host->clock, uhs, ctrl_2); ++ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); ++} ++ ++static unsigned int bm_sdhci_get_min_clock(struct sdhci_host *host) ++{ ++ return 200 * 1000; ++} ++ ++static unsigned int bm_sdhci_get_max_clock(struct sdhci_host *host) ++{ ++ return 50 * 1000 * 1000; ++} ++ ++#if 0 // FIXME, SD card not working after this. ++static void bm_sdhci_hw_reset(struct sdhci_host *host) ++{ ++ struct sdhci_pltfm_host *pltfm_host; ++ struct sdhci_bm_host *bm_host; ++ struct mmc_host *mmc = host->mmc; ++ ++ pltfm_host = sdhci_priv(host); ++ bm_host = sdhci_pltfm_priv(pltfm_host); ++ ++ pr_info("%s hardware reset\n", mmc_hostname(mmc)); ++ reset_control_assert(bm_host->reset); ++ udelay(10); ++ reset_control_deassert(bm_host->reset); ++} ++#endif ++ ++void bm_sdhci_reset(struct sdhci_host *host, u8 mask) ++{ ++#if 0 // FIXME, SD card not working after this. ++ bm_sdhci_hw_reset(host); ++#endif ++ sdhci_reset(host, mask); ++ ++ if (mask & SDHCI_RESET_ALL) ++ bm_sdhci_phy_init(host); ++} ++ ++int bm_sdhci_phy_init(struct sdhci_host *host) ++{ ++ // Asset reset of phy ++ sdhci_writel(host, sdhci_readl(host, SDHCI_P_PHY_CNFG) & ~(1 << PHY_CNFG_PHY_RSTN), SDHCI_P_PHY_CNFG); ++ ++ // Set PAD_SN PAD_SP ++ sdhci_writel(host, ++ (1 << PHY_CNFG_PHY_PWRGOOD) | (0x9 << PHY_CNFG_PAD_SP) | (0x8 << PHY_CNFG_PAD_SN), ++ SDHCI_P_PHY_CNFG); ++ ++ // Set CMDPAD ++ sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | ++ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_CMDPAD_CNFG); ++ ++ // Set DATAPAD ++ sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | ++ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_DATPAD_CNFG); ++ ++ // Set CLKPAD ++ sdhci_writew(host, ++ (0x2 << PAD_CNFG_RXSEL) | (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), ++ SDHCI_P_CLKPAD_CNFG); ++ ++ // Set STB_PAD ++ sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (0x2 << PAD_CNFG_WEAKPULL_EN) | ++ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_STBPAD_CNFG); ++ ++ // Set RSTPAD ++ sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | ++ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_RSTNPAD_CNFG); ++ ++ // Set SDCLKDL_CNFG, EXTDLY_EN = 1, fix delay ++ sdhci_writeb(host, (1 << SDCLKDL_CNFG_EXTDLY_EN), SDHCI_P_SDCLKDL_CNFG); ++ ++ // Add 10 * 70ps = 0.7ns for output delay ++ sdhci_writeb(host, 10, SDHCI_P_SDCLKDL_DC); ++ ++ //if (host->index == 1) { ++ // Set SMPLDL_CNFG, Bypass ++ sdhci_writeb(host, (1 << SMPLDL_CNFG_BYPASS_EN), SDHCI_P_SMPLDL_CNFG); ++ //} ++ //else { ++ // Set SMPLDL_CNFG, INPSEL_CNFG = 0x2 ++ //sdhci_writeb(host, (0x2 << SMPLDL_CNFG_INPSEL_CNFG), SDHCI_P_SMPLDL_CNFG); ++ //} ++ ++ // Set ATDL_CNFG, tuning clk not use for init ++ sdhci_writeb(host, (2 << ATDL_CNFG_INPSEL_CNFG), SDHCI_P_ATDL_CNFG); ++ ++ // deasset reset of phy ++ sdhci_writel(host, sdhci_readl(host, SDHCI_P_PHY_CNFG) | (1 << PHY_CNFG_PHY_RSTN), SDHCI_P_PHY_CNFG); ++ ++ return 0; ++} ++ ++void bm_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) ++{ ++ sdhci_set_clock(host, clock); ++ ++ if (clock == 0) ++ // forward tx ++ sdhci_writeb(host, 0x0, SDHCI_P_SDCLKDL_DC); ++ else ++ // revert tx ++ sdhci_writeb(host, 0x10, SDHCI_P_SDCLKDL_DC); ++} ++ ++/* ++ * If DMA addr spans 128MB boundary, we split the DMA transfer into two ++ * so that each DMA transfer doesn't exceed the boundary. ++ */ ++#define BOUNDARY_OK(addr, len) \ ++ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) ++ ++static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, ++ dma_addr_t addr, int len, unsigned int cmd) ++{ ++ int tmplen, offset; ++ ++ if (likely(!len || BOUNDARY_OK(addr, len))) { ++ sdhci_adma_write_desc(host, desc, addr, len, cmd); ++ return; ++ } ++ ++ offset = addr & (SZ_128M - 1); ++ tmplen = SZ_128M - offset; ++ sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); ++ ++ addr += tmplen; ++ len -= tmplen; ++ sdhci_adma_write_desc(host, desc, addr, len, cmd); ++} ++ ++ ++/* ------------- bm palludium sdcard --------------- */ ++static const struct sdhci_ops sdhci_bm_pldm_sd_ops = { ++ .reset = bm_sdhci_reset, ++ .set_clock = bm_sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .set_uhs_signaling = sdhci_bm_set_uhs_signaling, ++ .get_max_clock = bm_sdhci_get_max_clock, ++ .get_min_clock = bm_sdhci_get_min_clock, ++ .adma_write_desc = dwcmshc_adma_write_desc, ++}; ++ ++static const struct sdhci_pltfm_data sdhci_bm_pldm_sd_pdata = { ++ .ops = &sdhci_bm_pldm_sd_ops, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_INVERTED_WRITE_PROTECT, ++ .quirks2 = SDHCI_QUIRK2_NO_1_8_V, ++}; ++ ++static inline bool sdhci_data_line_cmd(struct mmc_command *cmd) ++{ ++ return cmd->data || cmd->flags & MMC_RSP_BUSY; ++} ++ ++static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) ++{ ++ if (sdhci_data_line_cmd(mrq->cmd)) ++ del_timer(&host->data_timer); ++ else ++ del_timer(&host->timer); ++} ++ ++int bm_platform_execute_tuning(struct sdhci_host *host, u32 opcode) ++{ ++ u16 ctrl; ++ int tuning_loop_counter = 0; ++ int err = 0; ++ unsigned long flags; ++ unsigned int tuning_count = 0; ++ bool hs400_tuning; ++ int hit = 0; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ hs400_tuning = host->flags & SDHCI_HS400_TUNING; ++ host->flags &= ~SDHCI_HS400_TUNING; ++ ++ if (host->tuning_mode == SDHCI_TUNING_MODE_1) ++ tuning_count = host->tuning_count; ++ ++ switch (host->timing) { ++ /* HS400 tuning is done in HS200 mode */ ++ case MMC_TIMING_MMC_HS400: ++ err = -EINVAL; ++ goto out_unlock; ++ ++ case MMC_TIMING_MMC_HS200: ++ /* ++ * Periodic re-tuning for HS400 is not expected to be needed, so ++ * disable it here. ++ */ ++ if (hs400_tuning) ++ tuning_count = 0; ++ break; ++ ++ case MMC_TIMING_UHS_SDR104: ++ case MMC_TIMING_UHS_DDR50: ++ break; ++ ++ case MMC_TIMING_UHS_SDR50: ++ if (host->flags & SDHCI_SDR50_NEEDS_TUNING) ++ break; ++ ++ default: ++ goto out_unlock; ++ } ++ ++ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ++ ctrl |= SDHCI_CTRL_EXEC_TUNING; ++ ++ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); ++ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); ++ ++ sdhci_writew(host, 0x704b | (0x3<<4) | (0x1<<3), SDHCI_HOST_CONTROL2);/*drv_strength | 1.8v*/ ++ ++ sdhci_writel(host, 0, SDHCI_DMA_ADDRESS);/*sdmasa*/ ++ sdhci_writel(host, 0, SDHCI_MSHC_CTRL); ++ ++ sdhci_writel(host, 0x18, SDHCI_AT_CTRL); ++ ++ sdhci_writew(host, 0x0, SDHCI_BLOCK_COUNT); ++ sdhci_writew(host, 0x1040, SDHCI_BLOCK_SIZE); ++ sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); ++ ++ do { ++ struct mmc_command cmd = {0}; ++ struct mmc_request mrq = {NULL}; ++ ++ cmd.opcode = opcode; ++ cmd.arg = 0; ++ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; ++ cmd.retries = 0; ++ cmd.data = NULL; ++ cmd.mrq = &mrq; ++ cmd.error = 0; ++ ++ sdhci_writel(host, tuning_loop_counter, SDHCI_AT_STAT); ++ mrq.cmd = &cmd; ++ sdhci_send_command(host, &cmd); ++ ++ host->cmd = NULL; ++ sdhci_del_timer(host, &mrq); ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ /* Wait for Buffer Read Ready interrupt */ ++ wait_event_timeout(host->buf_ready_int, ++ (host->tuning_done == 1), ++ msecs_to_jiffies(10)); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ if (host->tuning_done == 1) { ++ u16 stat; ++ ++ stat = sdhci_readw(host, SDHCI_ERR_INT_STATUS) & 0x3F; ++ if (stat == 0) ++ hit = tuning_loop_counter; ++ } ++ ++ host->tuning_done = 0; ++ tuning_loop_counter++; ++ sdhci_writeb(host, 0xFF, SDHCI_INT_STATUS); ++ sdhci_writeb(host, 0xFF, SDHCI_ERR_INT_STATUS); ++ sdhci_writeb(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA, SDHCI_SOFTWARE_RESET); ++ } while (tuning_loop_counter < MAX_TUNING_STEP); ++ ++ if (tuning_loop_counter >= MAX_TUNING_STEP) { ++ ctrl &= ~(SDHCI_CTRL_TUNED_CLK | SDHCI_CTRL_EXEC_TUNING); ++ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); ++ } ++ ++ sdhci_writel(host, 0, SDHCI_AT_CTRL); ++ sdhci_writeb(host, 0xFF, SDHCI_INT_STATUS);/*clear normal int*/ ++ sdhci_writeb(host, 0xFF, SDHCI_ERR_INT_STATUS);/*clear error int*/ ++ sdhci_writel(host, sdhci_readl(host, SDHCI_AT_CTRL) | (0x1<<4), SDHCI_AT_CTRL);/*en sw_tuning_en bit*/ ++ sdhci_writel(host, (sdhci_readl(host, SDHCI_AT_STAT) & (~0xFF)) | hit, SDHCI_AT_STAT);/*center_ph_code*/ ++ sdhci_writel(host, sdhci_readl(host, SDHCI_AT_CTRL) & (~(0x1<<4)), SDHCI_AT_CTRL);/*dis sw_tuning_en bit*/ ++ sdhci_writeb(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA, SDHCI_SOFTWARE_RESET); ++ ++ if (tuning_count) ++ err = 0; ++ ++ host->mmc->retune_period = err ? 0 : tuning_count; ++ ++ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); ++ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); ++out_unlock: ++ spin_unlock_irqrestore(&host->lock, flags); ++ return err; ++} ++ ++/* ------------- bm palludium emmc --------------- */ ++static const struct sdhci_ops sdhci_bm_pldm_emmc_ops = { ++ .reset = sdhci_reset, ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .set_uhs_signaling = sdhci_bm_set_uhs_signaling, ++ .get_max_clock = bm_sdhci_get_max_clock, ++ .get_min_clock = bm_sdhci_get_min_clock, ++ .platform_execute_tuning = bm_platform_execute_tuning, ++ .adma_write_desc = dwcmshc_adma_write_desc, ++}; ++ ++static const struct sdhci_pltfm_data sdhci_bm_pldm_emmc_pdata = { ++ .ops = &sdhci_bm_pldm_emmc_ops, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, ++}; ++ ++/* ------------ bm asic ------------ */ ++static const struct sdhci_ops sdhci_bm_ops = { ++ .reset = bm_sdhci_reset, ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .set_uhs_signaling = sdhci_bm_set_uhs_signaling, ++ .platform_execute_tuning = sdhci_bm_execute_software_tuning, ++ .adma_write_desc = dwcmshc_adma_write_desc, ++}; ++ ++static const struct sdhci_pltfm_data sdhci_bm_emmc_pdata = { ++ .ops = &sdhci_bm_ops, ++ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT, ++ .quirks2 = 0, ++}; ++ ++static const struct sdhci_pltfm_data sdhci_bm_sd_pdata = { ++ .ops = &sdhci_bm_ops, ++ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT, ++ .quirks2 = 0, ++}; ++ ++static const struct of_device_id sdhci_bm_dt_match = { ++ {.compatible = "bitmain,bm-pldm-sdcard", .data = &sdhci_bm_pldm_sd_pdata}, ++ {.compatible = "bitmain,bm-pldm-emmc", .data = &sdhci_bm_pldm_emmc_pdata}, ++ {.compatible = "bitmain,bm-emmc", .data = &sdhci_bm_emmc_pdata}, ++ {.compatible = "bitmain,bm-sd", .data = &sdhci_bm_sd_pdata}, ++ { /* sentinel */ } ++}; ++ ++MODULE_DEVICE_TABLE(of, sdhci_bm_dt_match); ++ ++static int sdhci_bm_probe(struct platform_device *pdev) ++{ ++ struct sdhci_host *host; ++ struct sdhci_pltfm_host *pltfm_host; ++ struct sdhci_bm_host *bm_host; ++ const struct of_device_id *match; ++ const struct sdhci_pltfm_data *pdata; ++ int ret; ++ ++ match = of_match_device(sdhci_bm_dt_match, &pdev->dev); ++ if (!match) ++ return -EINVAL; ++ ++ pdata = match->data; ++ ++ host = sdhci_pltfm_init(pdev, pdata, sizeof(*bm_host)); ++ if (IS_ERR(host)) ++ return PTR_ERR(host); ++ ++ pltfm_host = sdhci_priv(host); ++ bm_host = sdhci_pltfm_priv(pltfm_host); ++ bm_host->mmc = host->mmc; ++ bm_host->pdev = pdev; ++ bm_host->core_mem = host->ioaddr; ++ ++ ret = mmc_of_parse(host->mmc); ++ if (ret) ++ goto pltfm_free; ++ ++ sdhci_get_of_property(pdev); ++ ++ if (host->mmc->caps2 & MMC_CAP2_NO_SD) { ++ bm_host->reset = devm_reset_control_get(&pdev->dev, "emmc"); ++ if (IS_ERR(bm_host->reset)) { ++ ret = PTR_ERR(bm_host->reset); ++ goto pltfm_free; ++ } ++ ++ bm_host->clkaxi = devm_clk_get(&pdev->dev, "clk_gate_axi_emmc"); ++ if (IS_ERR(bm_host->clkaxi)) ++ dev_err(&pdev->dev, "get emmc clk axi failed\n"); ++ else ++ clk_prepare_enable(bm_host->clkaxi); ++ bm_host->clk = devm_clk_get(&pdev->dev, "clk_gate_emmc"); ++ if (IS_ERR(bm_host->clk)) ++ dev_err(&pdev->dev, "get emmc clk failed\n"); ++ else ++ clk_prepare_enable(bm_host->clk); ++ bm_host->clk100k = devm_clk_get(&pdev->dev, "clk_gate_100k_emmc"); ++ if (IS_ERR(bm_host->clk100k)) ++ dev_err(&pdev->dev, "get emmc clk 100k failed\n"); ++ else ++ clk_prepare_enable(bm_host->clk100k); ++ } else if (host->mmc->caps2 & MMC_CAP2_NO_MMC) { ++ bm_host->reset = devm_reset_control_get(&pdev->dev, "sdio"); ++ if (IS_ERR(bm_host->reset)) { ++ ret = PTR_ERR(bm_host->reset); ++ goto pltfm_free; ++ } ++ ++ bm_host->clkaxi = devm_clk_get(&pdev->dev, "clk_gate_axi_sd"); ++ if (IS_ERR(bm_host->clkaxi)) ++ dev_err(&pdev->dev, "get sd clk axi failed\n"); ++ else ++ clk_prepare_enable(bm_host->clkaxi); ++ bm_host->clk = devm_clk_get(&pdev->dev, "clk_gate_sd"); ++ if (IS_ERR(bm_host->clk)) ++ dev_err(&pdev->dev, "get sd clk failed\n"); ++ else ++ clk_prepare_enable(bm_host->clk); ++ bm_host->clk100k = devm_clk_get(&pdev->dev, "clk_gate_100k_sd"); ++ if (IS_ERR(bm_host->clk100k)) ++ dev_err(&pdev->dev, "get sd clk 100k failed\n"); ++ else ++ clk_prepare_enable(bm_host->clk100k); ++ } ++ ++ host->mmc_host_ops.select_drive_strength = sdhci_bm_select_drive_strength; ++ ++ ret = sdhci_add_host(host); ++ if (ret) ++ goto err_add_host; ++ ++ return 0; ++ ++err_add_host: ++pltfm_free: ++ sdhci_pltfm_free(pdev); ++ return ret; ++} ++ ++static int sdhci_bm_remove(struct platform_device *pdev) ++{ ++ struct sdhci_host *host = platform_get_drvdata(pdev); ++ int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); ++ ++ sdhci_remove_host(host, dead); ++ sdhci_pltfm_free(pdev); ++ return 0; ++} ++ ++static struct platform_driver sdhci_bm_driver = { ++ .probe = sdhci_bm_probe, ++ .remove = sdhci_bm_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .of_match_table = sdhci_bm_dt_match, ++ }, ++}; ++ ++module_platform_driver(sdhci_bm_driver); ++MODULE_DESCRIPTION("BitMain Secure Digital Host Controller Interface driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/mmc/host/sdhci-sophgo.h b/drivers/mmc/host/sdhci-sophgo.h +new file mode 100644 +index 000000000000..508d0a16d71e +--- /dev/null ++++ b/drivers/mmc/host/sdhci-sophgo.h +@@ -0,0 +1,121 @@ ++/* ++ * drivers/mmc/host/sdhci-bm.c - BitMain SDHCI Platform driver ++ * ++ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#ifndef __SDHCI_BM_H ++#define __SDHCI_BM_H ++ ++#include <linux/module.h> ++#include <linux/of_device.h> ++#include <linux/delay.h> ++#include <linux/mmc/mmc.h> ++#include <linux/slab.h> ++ ++/*register macro */ ++#define P_VENDOR_SPECIFIC_AREA 0xE8 ++#define P_VENDOR2_SPECIFIC_AREA 0xEA ++#define VENDOR_EMMC_CTRL 0x2C ++#define SW_RST_R 0x2F ++#define SDHCI_NORMAL_INT_STATUS 0x30 ++#define SDHCI_ERR_INT_STATUS 0x32 ++#define SDHCI_ERR_INT_STATUS_EN 0x36 ++#define SDHCI_HOST_CTRL2_R 0x3E ++#define SDHCI_MSHC_CTRL 0x508 ++#define SDHCI_AT_CTRL 0x540 ++#define SDHCI_AT_STAT 0x544 ++ ++/* PHY register */ ++#define SDHCI_PHY_R_OFFSET 0x300 ++ ++#define SDHCI_P_PHY_CNFG (SDHCI_PHY_R_OFFSET + 0x00) ++#define SDHCI_P_CMDPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x04) ++#define SDHCI_P_DATPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x06) ++#define SDHCI_P_CLKPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x08) ++#define SDHCI_P_STBPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0A) ++#define SDHCI_P_RSTNPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0C) ++#define SDHCI_P_PADTEST_CNFG (SDHCI_PHY_R_OFFSET + 0x0E) ++#define SDHCI_P_PADTEST_OUT (SDHCI_PHY_R_OFFSET + 0x10) ++#define SDHCI_P_PADTEST_IN (SDHCI_PHY_R_OFFSET + 0x12) ++#define SDHCI_P_COMMDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1C) ++#define SDHCI_P_SDCLKDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1D) ++#define SDHCI_P_SDCLKDL_DC (SDHCI_PHY_R_OFFSET + 0x1E) ++#define SDHCI_P_SMPLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x20) ++#define SDHCI_P_ATDL_CNFG (SDHCI_PHY_R_OFFSET + 0x21) ++#define SDHCI_P_DLL_CTRL (SDHCI_PHY_R_OFFSET + 0x24) ++#define SDHCI_P_DLL_CNFG1 (SDHCI_PHY_R_OFFSET + 0x25) ++#define SDHCI_P_DLL_CNFG2 (SDHCI_PHY_R_OFFSET + 0x26) ++#define SDHCI_P_DLLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x28) ++#define SDHCI_P_DLL_OFFST (SDHCI_PHY_R_OFFSET + 0x29) ++#define SDHCI_P_DLLMST_TSTDC (SDHCI_PHY_R_OFFSET + 0x2A) ++#define SDHCI_P_DLLLBT_CNFG (SDHCI_PHY_R_OFFSET + 0x2C) ++#define SDHCI_P_DLL_STATUS (SDHCI_PHY_R_OFFSET + 0x2E) ++#define SDHCI_P_DLLDBG_MLKDC (SDHCI_PHY_R_OFFSET + 0x30) ++#define SDHCI_P_DLLDBG_SLKDC (SDHCI_PHY_R_OFFSET + 0x32) ++ ++#define PHY_CNFG_PHY_RSTN 0 ++#define PHY_CNFG_PHY_PWRGOOD 1 ++#define PHY_CNFG_PAD_SP 16 ++#define PHY_CNFG_PAD_SP_MSK 0xf ++#define PHY_CNFG_PAD_SN 20 ++#define PHY_CNFG_PAD_SN_MSK 0xf ++ ++#define PAD_CNFG_RXSEL 0 ++#define PAD_CNFG_RXSEL_MSK 0x7 ++#define PAD_CNFG_WEAKPULL_EN 3 ++#define PAD_CNFG_WEAKPULL_EN_MSK 0x3 ++#define PAD_CNFG_TXSLEW_CTRL_P 5 ++#define PAD_CNFG_TXSLEW_CTRL_P_MSK 0xf ++#define PAD_CNFG_TXSLEW_CTRL_N 9 ++#define PAD_CNFG_TXSLEW_CTRL_N_MSK 0xf ++ ++#define COMMDL_CNFG_DLSTEP_SEL 0 ++#define COMMDL_CNFG_DLOUT_EN 1 ++ ++#define SDCLKDL_CNFG_EXTDLY_EN 0 ++#define SDCLKDL_CNFG_BYPASS_EN 1 ++#define SDCLKDL_CNFG_INPSEL_CNFG 2 ++#define SDCLKDL_CNFG_INPSEL_CNFG_MSK 0x3 ++#define SDCLKDL_CNFG_UPDATE_DC 4 ++ ++#define SMPLDL_CNFG_EXTDLY_EN 0 ++#define SMPLDL_CNFG_BYPASS_EN 1 ++#define SMPLDL_CNFG_INPSEL_CNFG 2 ++#define SMPLDL_CNFG_INPSEL_CNFG_MSK 0x3 ++#define SMPLDL_CNFG_INPSEL_OVERRIDE 4 ++ ++#define ATDL_CNFG_EXTDLY_EN 0 ++#define ATDL_CNFG_BYPASS_EN 1 ++#define ATDL_CNFG_INPSEL_CNFG 2 ++#define ATDL_CNFG_INPSEL_CNFG_MSK 0x3 ++ ++#define MAX_TUNING_STEP 128 ++ ++struct sdhci_bm_host { ++ struct platform_device *pdev; ++ void __iomem *core_mem; /* bm SDCC mapped address */ ++ struct clk *clk; /* main SD/MMC bus clock */ ++ struct clk *clk100k; ++ struct clk *clkaxi; ++ struct mmc_host *mmc; ++ struct reset_control *reset; ++ ++ struct reset_control *clk_rst_axi_emmc_ctrl; ++ struct reset_control *clk_rst_emmc_ctrl; ++ struct reset_control *clk_rst_100k_emmc_ctrl; ++}; ++ ++int bm_sdhci_phy_init(struct sdhci_host *host); ++bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); ++#endif +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index ff41aa56564e..526df8063579 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -49,7 +49,9 @@ static unsigned int debug_quirks2; + + static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); + ++#ifndef CONFIG_ARCH_SOPHGO + static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); ++#endif + + void sdhci_dumpregs(struct sdhci_host *host) + { +@@ -1627,7 +1629,11 @@ static void sdhci_finish_data(struct sdhci_host *host) + __sdhci_finish_data(host, false); + } + ++#ifndef CONFIG_ARCH_SOPHGO + static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) ++#else ++bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) ++#endif + { + int flags; + u32 mask; +@@ -1717,6 +1723,9 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) + + return true; + } ++#ifdef CONFIG_ARCH_SOPHGO ++EXPORT_SYMBOL_GPL(sdhci_send_command); ++#endif + + static bool sdhci_present_error(struct sdhci_host *host, + struct mmc_command *cmd, bool present) +@@ -2841,7 +2850,7 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode) + } + EXPORT_SYMBOL_GPL(sdhci_send_tuning); + +-static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) ++int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) + { + int i; + +@@ -2879,6 +2888,7 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) + sdhci_reset_tuning(host); + return -EAGAIN; + } ++EXPORT_SYMBOL_GPL(__sdhci_execute_tuning); + + int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + { +diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h +index f219bdea8f28..149e699aac92 100644 +--- a/drivers/mmc/host/sdhci.h ++++ b/drivers/mmc/host/sdhci.h +@@ -793,6 +793,7 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width); + void sdhci_reset(struct sdhci_host *host, u8 mask); + void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); + int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); ++int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode); + void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); + int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios); +@@ -823,5 +824,8 @@ void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode); + void sdhci_switch_external_dma(struct sdhci_host *host, bool en); + void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable); + void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd); ++#ifdef CONFIG_ARCH_SOPHGO ++bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); ++#endif + + #endif /* __SDHCI_HW_H */ +diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig +index 25f2d42de406..f70de0533599 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig ++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig +@@ -216,6 +216,17 @@ config DWMAC_SUN8I + stmmac device driver. This driver is used for H3/A83T/A64 + EMAC ethernet controller. + ++config DWMAC_THEAD ++ tristate "T-HEAD dwmac support" ++ depends on OF && (ARCH_THEAD || COMPILE_TEST) ++ select MFD_SYSCON ++ help ++ Support for ethernet controllers on T-HEAD RISC-V SoCs ++ ++ This selects the T-HEAD platform specific glue layer support for ++ the stmmac device driver. This driver is used for T-HEAD TH1520 ++ ethernet controller. ++ + 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 5b57aee19267..3d8221783e57 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/Makefile ++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile +@@ -27,6 +27,8 @@ obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o + obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o + obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o + obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o ++obj-$(CONFIG_ARCH_SOPHGO) += dwmac-sophgo.o ++obj-$(CONFIG_DWMAC_THEAD) += dwmac-thead.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-sophgo.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c +new file mode 100644 +index 000000000000..50a76c8f0df6 +--- /dev/null ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c +@@ -0,0 +1,268 @@ ++/* ++ * DWMAC specific glue layer ++ * ++ * Copyright (c) 2018 Bitmain Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/stmmac.h> ++#include <linux/module.h> ++#include <linux/phy.h> ++#include <linux/platform_device.h> ++#include <linux/of_net.h> ++#include <linux/of_gpio.h> ++#include <linux/io.h> ++ ++#include "stmmac_platform.h" ++ ++struct bm_mac { ++ struct device *dev; ++ struct reset_control *rst; ++ struct clk *clk_tx; ++ struct clk *gate_clk_tx; ++ struct clk *gate_clk_ref; ++ struct gpio_desc *reset; ++}; ++ ++static u64 bm_dma_mask = DMA_BIT_MASK(40); ++ ++static int bm_eth_reset_phy(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ int phy_reset_gpio; ++ ++ if (!np) ++ return 0; ++ ++ phy_reset_gpio = of_get_named_gpio(np, "phy-reset-gpios", 0); ++ ++ if (phy_reset_gpio < 0) ++ return 0; ++ ++ if (gpio_request(phy_reset_gpio, "eth-phy-reset")) ++ return 0; ++ ++ /* RESET_PU */ ++ gpio_direction_output(phy_reset_gpio, 0); ++ mdelay(100); ++ ++ gpio_direction_output(phy_reset_gpio, 1); ++ /* RC charging time */ ++ mdelay(100); ++ ++ return 0; ++} ++ ++static void bm_mac_fix_speed(void *priv, unsigned int speed, unsigned int mode) ++{ ++ struct bm_mac *bsp_priv = priv; ++ unsigned long rate = 125000000; ++ bool needs_calibration = false; ++ int err; ++ ++ switch (speed) { ++ case SPEED_1000: ++ needs_calibration = true; ++ rate = 125000000; ++ break; ++ ++ case SPEED_100: ++ needs_calibration = true; ++ rate = 25000000; ++ break; ++ ++ case SPEED_10: ++ needs_calibration = true; ++ rate = 2500000; ++ break; ++ ++ default: ++ dev_err(bsp_priv->dev, "invalid speed %u\n", speed); ++ break; ++ } ++ ++ if (needs_calibration) { ++ err = clk_set_rate(bsp_priv->clk_tx, rate); ++ if (err < 0) ++ dev_err(bsp_priv->dev, "failed to set TX rate: %d\n" ++ , err); ++ } ++} ++ ++void bm_dwmac_exit(struct platform_device *pdev, void *priv) ++{ ++ struct bm_mac *bsp_priv = priv; ++ ++ clk_disable_unprepare(bsp_priv->gate_clk_tx); ++ clk_disable_unprepare(bsp_priv->gate_clk_ref); ++} ++ ++static int bm_validate_ucast_entries(struct device *dev, int ucast_entries) ++{ ++ int x = ucast_entries; ++ ++ switch (x) { ++ case 1 ... 32: ++ case 64: ++ case 128: ++ break; ++ default: ++ x = 1; ++ dev_info(dev, "Unicast table entries set to unexpected value %d\n", ++ ucast_entries); ++ break; ++ } ++ return x; ++} ++ ++static int bm_validate_mcast_bins(struct device *dev, int mcast_bins) ++{ ++ int x = mcast_bins; ++ ++ switch (x) { ++ case HASH_TABLE_SIZE: ++ case 128: ++ case 256: ++ break; ++ default: ++ x = 0; ++ dev_info(dev, "Hash table entries set to unexpected value %d\n", ++ mcast_bins); ++ break; ++ } ++ return x; ++} ++ ++static void bm_dwmac_probe_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ ++ of_property_read_u32(np, "snps,multicast-filter-bins", &plat->multicast_filter_bins); ++ of_property_read_u32(np, "snps,perfect-filter-entries", &plat->unicast_filter_entries); ++ plat->unicast_filter_entries = bm_validate_ucast_entries(&pdev->dev, ++ plat->unicast_filter_entries); ++ plat->multicast_filter_bins = bm_validate_mcast_bins(&pdev->dev, ++ plat->multicast_filter_bins); ++ plat->flags |= (STMMAC_FLAG_TSO_EN); ++ plat->has_gmac4 = 1; ++ plat->has_gmac = 0; ++ plat->pmt = 0; ++} ++ ++static int bm_dwmac_probe(struct platform_device *pdev) ++{ ++ struct plat_stmmacenet_data *plat_dat; ++ struct stmmac_resources stmmac_res; ++ struct bm_mac *bsp_priv = NULL; ++ struct phy_device *phydev = NULL; ++ struct stmmac_priv *priv = NULL; ++ struct net_device *ndev = NULL; ++ int ret; ++ ++ pdev->dev.dma_mask = &bm_dma_mask; ++ pdev->dev.coherent_dma_mask = bm_dma_mask; ++ ++ bm_eth_reset_phy(pdev); ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return ret; ++ ++ plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return PTR_ERR(plat_dat); ++ ++ bm_dwmac_probe_config_dt(pdev, plat_dat); ++ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ++ if (ret) ++ goto err_remove_config_dt; ++ ++ bsp_priv = devm_kzalloc(&pdev->dev, sizeof(*bsp_priv), GFP_KERNEL); ++ if (!bsp_priv) ++ return PTR_ERR(bsp_priv); ++ ++ bsp_priv->dev = &pdev->dev; ++ ++ /* clock setup */ ++ bsp_priv->clk_tx = devm_clk_get(&pdev->dev, ++ "clk_tx"); ++ if (IS_ERR(bsp_priv->clk_tx)) ++ dev_warn(&pdev->dev, "Cannot get mac tx clock!\n"); ++ else ++ plat_dat->fix_mac_speed = bm_mac_fix_speed; ++ ++ bsp_priv->gate_clk_tx = devm_clk_get(&pdev->dev, "gate_clk_tx"); ++ if (IS_ERR(bsp_priv->gate_clk_tx)) ++ dev_warn(&pdev->dev, "Cannot get mac tx gating clock!\n"); ++ else ++ clk_prepare_enable(bsp_priv->gate_clk_tx); ++ ++ bsp_priv->gate_clk_ref = devm_clk_get(&pdev->dev, "gate_clk_ref"); ++ if (IS_ERR(bsp_priv->gate_clk_ref)) ++ dev_warn(&pdev->dev, "Cannot get mac ref gating clock!\n"); ++ else ++ clk_prepare_enable(bsp_priv->gate_clk_ref); ++ ++ plat_dat->bsp_priv = bsp_priv; ++ plat_dat->exit = bm_dwmac_exit; ++ ++ ndev = dev_get_drvdata(&pdev->dev); ++ priv = netdev_priv(ndev); ++ phydev = mdiobus_get_phy(priv->mii, 0); ++ if (phydev == NULL) { ++ dev_err(&pdev->dev, "Can not get phy in addr 0\n"); ++ goto err_remove_config_dt; ++ } ++ ++ /* set green LED0 active for transmit, yellow LED1 for link*/ ++ ret = phy_write_paged(phydev, 0, 0x1f, 0xd04); ++ if (ret < 0) ++ dev_err(&pdev->dev, "Can not select page 0xd04\n"); ++ ret = phy_write_paged(phydev, 0xd04, 0x10, 0x617f); ++ if (ret < 0) ++ dev_err(&pdev->dev, "Can not alter LED Configuration\n"); ++ /* disable eee LED function */ ++ ret = phy_write_paged(phydev, 0xd04, 0x11, 0x0); ++ if (ret < 0) ++ dev_err(&pdev->dev, "Can not disable EEE Configuration\n"); ++ ret = phy_write_paged(phydev, 0, 0x1f, 0); ++ if (ret < 0) ++ dev_err(&pdev->dev, "Can not select page 0\n"); ++ ++ return 0; ++ ++err_remove_config_dt: ++ stmmac_remove_config_dt(pdev, plat_dat); ++ ++ return ret; ++} ++ ++static const struct of_device_id bm_dwmac_match = { ++ { .compatible = "bitmain,ethernet" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, bm_dwmac_match); ++ ++static struct platform_driver bm_dwmac_driver = { ++ .probe = bm_dwmac_probe, ++ .remove_new = stmmac_pltfr_remove, ++ .driver = { ++ .name = "bm-dwmac", ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = bm_dwmac_match, ++ }, ++}; ++module_platform_driver(bm_dwmac_driver); ++ ++MODULE_AUTHOR("Wei Huang<wei.huang01@bitmain.com>"); ++MODULE_DESCRIPTION("Bitmain DWMAC specific glue layer"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c +new file mode 100644 +index 000000000000..fec27f78a417 +--- /dev/null ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c +@@ -0,0 +1,289 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * T-HEAD DWMAC platform driver ++ * ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org> ++ * ++ */ ++ ++#include <linux/bitfield.h> ++#include <linux/mfd/syscon.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/of_net.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++ ++#include "stmmac_platform.h" ++ ++#define GMAC_CLK_EN 0x00 ++#define GMAC_TX_CLK_EN BIT(1) ++#define GMAC_TX_CLK_N_EN BIT(2) ++#define GMAC_TX_CLK_OUT_EN BIT(3) ++#define GMAC_RX_CLK_EN BIT(4) ++#define GMAC_RX_CLK_N_EN BIT(5) ++#define GMAC_EPHY_REF_CLK_EN BIT(6) ++#define GMAC_RXCLK_DELAY_CTRL 0x04 ++#define GMAC_RXCLK_BYPASS BIT(15) ++#define GMAC_RXCLK_INVERT BIT(14) ++#define GMAC_RXCLK_DELAY_MASK GENMASK(4, 0) ++#define GMAC_RXCLK_DELAY_VAL(x) FIELD_PREP(GMAC_RXCLK_DELAY_MASK, (x)) ++#define GMAC_TXCLK_DELAY_CTRL 0x08 ++#define GMAC_TXCLK_BYPASS BIT(15) ++#define GMAC_TXCLK_INVERT BIT(14) ++#define GMAC_TXCLK_DELAY_MASK GENMASK(4, 0) ++#define GMAC_TXCLK_DELAY_VAL(x) FIELD_PREP(GMAC_RXCLK_DELAY_MASK, (x)) ++#define GMAC_PLLCLK_DIV 0x0c ++#define GMAC_PLLCLK_DIV_EN BIT(31) ++#define GMAC_PLLCLK_DIV_MASK GENMASK(7, 0) ++#define GMAC_PLLCLK_DIV_NUM(x) FIELD_PREP(GMAC_PLLCLK_DIV_MASK, (x)) ++#define GMAC_GTXCLK_SEL 0x18 ++#define GMAC_GTXCLK_SEL_PLL BIT(0) ++#define GMAC_INTF_CTRL 0x1c ++#define PHY_INTF_MASK BIT(0) ++#define PHY_INTF_RGMII FIELD_PREP(PHY_INTF_MASK, 1) ++#define PHY_INTF_MII_GMII FIELD_PREP(PHY_INTF_MASK, 0) ++#define GMAC_TXCLK_OEN 0x20 ++#define TXCLK_DIR_MASK BIT(0) ++#define TXCLK_DIR_OUTPUT FIELD_PREP(TXCLK_DIR_MASK, 0) ++#define TXCLK_DIR_INPUT FIELD_PREP(TXCLK_DIR_MASK, 1) ++ ++#define GMAC_GMII_RGMII_RATE 125000000 ++#define GMAC_MII_RATE 25000000 ++ ++struct thead_dwmac { ++ struct plat_stmmacenet_data *plat; ++ struct regmap *apb_regmap; ++ struct device *dev; ++ u32 rx_delay; ++ u32 tx_delay; ++}; ++ ++static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat) ++{ ++ struct thead_dwmac *dwmac = plat->bsp_priv; ++ u32 phyif; ++ ++ switch (plat->mac_interface) { ++ case PHY_INTERFACE_MODE_MII: ++ phyif = PHY_INTF_MII_GMII; ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ phyif = PHY_INTF_RGMII; ++ break; ++ default: ++ dev_err(dwmac->dev, "unsupported phy interface %d\n", ++ plat->mac_interface); ++ return -EINVAL; ++ }; ++ ++ regmap_write(dwmac->apb_regmap, GMAC_INTF_CTRL, phyif); ++ ++ return 0; ++} ++ ++static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) ++{ ++ struct thead_dwmac *dwmac = plat->bsp_priv; ++ u32 txclk_dir; ++ ++ switch (plat->mac_interface) { ++ case PHY_INTERFACE_MODE_MII: ++ txclk_dir = TXCLK_DIR_INPUT; ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ txclk_dir = TXCLK_DIR_OUTPUT; ++ break; ++ default: ++ dev_err(dwmac->dev, "unsupported phy interface %d\n", ++ plat->mac_interface); ++ return -EINVAL; ++ }; ++ ++ regmap_write(dwmac->apb_regmap, GMAC_TXCLK_OEN, txclk_dir); ++ ++ return 0; ++} ++ ++static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode) ++{ ++ struct thead_dwmac *dwmac = priv; ++ struct plat_stmmacenet_data *plat = dwmac->plat; ++ unsigned long rate; ++ u32 div; ++ ++ switch (plat->mac_interface) { ++ /* For MII, rxc/txc is provided by phy */ ++ case PHY_INTERFACE_MODE_MII: ++ return; ++ ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ rate = clk_get_rate(plat->stmmac_clk); ++ if (!rate || rate % GMAC_GMII_RGMII_RATE != 0 || ++ rate % GMAC_MII_RATE != 0) { ++ dev_err(dwmac->dev, "invalid gmac rate %ld\n", rate); ++ return; ++ } ++ ++ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, GMAC_PLLCLK_DIV_EN, 0); ++ ++ switch (speed) { ++ case SPEED_1000: ++ div = rate / GMAC_GMII_RGMII_RATE; ++ break; ++ case SPEED_100: ++ div = rate / GMAC_MII_RATE; ++ break; ++ case SPEED_10: ++ div = rate * 10 / GMAC_MII_RATE; ++ break; ++ default: ++ dev_err(dwmac->dev, "invalid speed %u\n", speed); ++ return; ++ } ++ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, ++ GMAC_PLLCLK_DIV_MASK, GMAC_PLLCLK_DIV_NUM(div)); ++ ++ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, ++ GMAC_PLLCLK_DIV_EN, GMAC_PLLCLK_DIV_EN); ++ break; ++ default: ++ dev_err(dwmac->dev, "unsupported phy interface %d\n", ++ plat->mac_interface); ++ return; ++ } ++} ++ ++static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) ++{ ++ struct thead_dwmac *dwmac = plat->bsp_priv; ++ u32 reg; ++ ++ switch (plat->mac_interface) { ++ case PHY_INTERFACE_MODE_MII: ++ reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN; ++ break; ++ ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ /* use pll */ ++ regmap_write(dwmac->apb_regmap, GMAC_GTXCLK_SEL, GMAC_GTXCLK_SEL_PLL); ++ ++ reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN | ++ GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN; ++ break; ++ ++ default: ++ dev_err(dwmac->dev, "unsupported phy interface %d\n", ++ plat->mac_interface); ++ return -EINVAL; ++ } ++ ++ regmap_write(dwmac->apb_regmap, GMAC_CLK_EN, reg); ++ ++ return 0; ++} ++ ++static int thead_dwmac_init(struct platform_device *pdev, ++ struct plat_stmmacenet_data *plat) ++{ ++ struct thead_dwmac *dwmac = plat->bsp_priv; ++ int ret; ++ ++ ret = thead_dwmac_set_phy_if(plat); ++ if (ret) ++ return ret; ++ ++ ret = thead_dwmac_set_txclk_dir(plat); ++ if (ret) ++ return ret; ++ ++ regmap_write(dwmac->apb_regmap, GMAC_RXCLK_DELAY_CTRL, ++ GMAC_RXCLK_DELAY_VAL(dwmac->rx_delay)); ++ regmap_write(dwmac->apb_regmap, GMAC_TXCLK_DELAY_CTRL, ++ GMAC_TXCLK_DELAY_VAL(dwmac->tx_delay)); ++ ++ thead_dwmac_fix_speed(dwmac, SPEED_1000, 0); ++ ++ return thead_dwmac_enable_clk(plat); ++} ++ ++static int thead_dwmac_probe(struct platform_device *pdev) ++{ ++ struct plat_stmmacenet_data *plat; ++ struct stmmac_resources stmmac_res; ++ struct thead_dwmac *dwmac; ++ struct device_node *np = pdev->dev.of_node; ++ u32 delay_ps; ++ int ret; ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "failed to get resources\n"); ++ ++ plat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); ++ if (IS_ERR(plat)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(plat), ++ "dt configuration failed\n"); ++ ++ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); ++ if (!dwmac) ++ return -ENOMEM; ++ ++ if (!of_property_read_u32(np, "rx-internal-delay-ps", &delay_ps)) ++ dwmac->rx_delay = delay_ps; ++ if (!of_property_read_u32(np, "tx-internal-delay-ps", &delay_ps)) ++ dwmac->tx_delay = delay_ps; ++ ++ dwmac->apb_regmap = syscon_regmap_lookup_by_phandle(np, "thead,gmacapb"); ++ if (IS_ERR(dwmac->apb_regmap)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->apb_regmap), ++ "Failed to get gmac apb syscon\n"); ++ ++ dwmac->dev = &pdev->dev; ++ dwmac->plat = plat; ++ plat->bsp_priv = dwmac; ++ plat->fix_mac_speed = thead_dwmac_fix_speed; ++ ++ ret = thead_dwmac_init(pdev, plat); ++ if (ret) ++ return ret; ++ ++ return stmmac_dvr_probe(&pdev->dev, plat, &stmmac_res); ++} ++ ++static const struct of_device_id thead_dwmac_match = { ++ { .compatible = "thead,th1520-dwmac" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, thead_dwmac_match); ++ ++static struct platform_driver thead_dwmac_driver = { ++ .probe = thead_dwmac_probe, ++ .remove_new = stmmac_pltfr_remove, ++ .driver = { ++ .name = "thead-dwmac", ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = thead_dwmac_match, ++ }, ++}; ++module_platform_driver(thead_dwmac_driver); ++ ++MODULE_AUTHOR("T-HEAD"); ++MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); ++MODULE_DESCRIPTION("T-HEAD dwmac platform driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig +index 291d12711363..25c768d5afb4 100644 +--- a/drivers/pci/controller/cadence/Kconfig ++++ b/drivers/pci/controller/cadence/Kconfig +@@ -42,6 +42,17 @@ config PCIE_CADENCE_PLAT_EP + endpoint mode. This PCIe controller may be embedded into many + different vendors SoCs. + ++config PCIE_CADENCE_SOPHGO ++ bool "Cadence Sophgo PCIe Host controller" ++ depends on OF ++ select IRQ_DOMAIN ++ select PCIE_CADENCE ++ help ++ Say Y here if you want to support the Cadence PCIe controller in host mode ++ for Sophgo SoCs. this PCIe controller is from cadence, integrated into the ++ Sophgo SoCs. PCIe is one of subsystems, it is choisable, Don't be ++ care of this if it is not used in your systems. ++ + config PCI_J721E + bool + +diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile +index 9bac5fb2f13d..edac7c5e94a3 100644 +--- a/drivers/pci/controller/cadence/Makefile ++++ b/drivers/pci/controller/cadence/Makefile +@@ -4,3 +4,4 @@ obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o + obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o + obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o + obj-$(CONFIG_PCI_J721E) += pci-j721e.o ++obj-$(CONFIG_PCIE_CADENCE_SOPHGO) += pcie-cadence-sophgo.o +diff --git a/drivers/pci/controller/cadence/pcie-cadence-sophgo.c b/drivers/pci/controller/cadence/pcie-cadence-sophgo.c +new file mode 100644 +index 000000000000..feb9bfdc7e75 +--- /dev/null ++++ b/drivers/pci/controller/cadence/pcie-cadence-sophgo.c +@@ -0,0 +1,963 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2017 Cadence ++// Cadence PCIe host controller driver. ++// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> ++ ++#include <linux/kernel.h> ++#include <linux/of_address.h> ++#include <linux/of_pci.h> ++#include <linux/msi.h> ++#include <linux/irq.h> ++#include <linux/irqdomain.h> ++#include <linux/irqchip/chained_irq.h> ++#include <linux/platform_device.h> ++#include <linux/pm_runtime.h> ++ ++#include "pcie-cadence.h" ++#include "pcie-cadence-sophgo.h" ++ ++#define MAX_MSI_IRQS 512 ++#define MAX_MSI_IRQS_PER_CTRL 1 ++#define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL) ++#define MSI_DEF_NUM_VECTORS 512 ++#define BYTE_NUM_PER_MSI_VEC 4 ++ ++// mango sideband signals ++#define CDNS_PCIE_CFG_MANGO_APB 0x1800000 ++#define CDNS_PCIE_IRS_REG0400 0x0400 ++#define CDNS_PCIE_IRS_REG0404 0x0404 ++#define CDNS_PCIE_IRS_REG0418 0x0418 ++#define CDNS_PCIE_IRS_REG041C 0x041C ++#define CDNS_PCIE_IRS_REG0804 0x0804 ++#define CDNS_PCIE_IRS_REG080C 0x080C ++#define CDNS_PCIE_IRS_REG0810 0x0810 ++#define CDNS_PCIE_IRS_REG085C 0x085C ++#define CDNS_PCIE_IRS_REG0860 0x0860 ++#define CDNS_PCIE_IRS_REG0864 0x0864 ++#define CDNS_PCIE_IRS_REG0868 0x0868 ++#define CDNS_PCIE_IRS_REG086C 0x086C ++ ++#define CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT 2 ++#define CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT 3 ++#define CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT 2 ++#define CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT 3 ++ ++#define CDNS_PLAT_CPU_TO_BUS_ADDR 0xCFFFFFFFFF ++ ++struct cdns_pcie_database { ++ void __iomem *pcie_reg_base; ++}; ++ ++static struct cdns_pcie_database cdns_pcie_db; ++ ++static inline void cdns_pcie_rp_writel(struct cdns_pcie *pcie, ++ u32 reg, u32 value) ++{ ++ writel(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); ++} ++ ++static inline u32 cdns_pcie_rp_readl(struct cdns_pcie *pcie, ++ u32 reg) ++{ ++ return readl(pcie->reg_base + CDNS_PCIE_RP_BASE + reg); ++} ++ ++/** ++ * struct cdns_mango_pcie_rc - private data for this PCIe Root Complex driver ++ * @pcie: Cadence PCIe controller ++ * @dev: pointer to PCIe device ++ * @cfg_res: start/end offsets in the physical system memory to map PCI ++ * configuration space accesses ++ * @bus_range: first/last buses behind the PCIe host controller ++ * @cfg_base: IO mapped window to access the PCI configuration space of a ++ * single function at a time ++ * @max_regions: maximum number of regions supported by the hardware ++ * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address ++ * translation (nbits sets into the "no BAR match" register) ++ * @vendor_id: PCI vendor ID ++ * @device_id: PCI device ID ++ */ ++struct cdns_mango_pcie_rc { ++ struct cdns_pcie pcie; ++ struct device *dev; ++ struct resource *cfg_res; ++ struct resource *bus_range; ++ void __iomem *cfg_base; ++ u32 max_regions; ++ u32 no_bar_nbits; ++ u16 vendor_id; ++ u16 device_id; ++ u16 pcie_id; ++ u16 link_id; ++ u32 top_intc_used; ++ u32 msix_supported; ++ struct irq_domain *msi_domain; ++ int msi_irq; ++ struct irq_domain *irq_domain; ++ dma_addr_t msi_data; ++ void *msi_page; ++ struct irq_chip *msi_irq_chip; ++ u32 num_vectors; ++ u32 num_applied_vecs; ++ u32 irq_maskMAX_MSI_CTRLS; ++ struct pci_bus *root_bus; ++ raw_spinlock_t lock; ++ DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); ++}; ++ ++static u64 cdns_mango_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr) ++{ ++ return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR; ++} ++ ++static const struct cdns_pcie_ops cdns_mango_ops = { ++ .cpu_addr_fixup = cdns_mango_cpu_addr_fixup, ++}; ++ ++static void __iomem *cdns_mango_pci_map_bus(struct pci_bus *bus, unsigned int devfn, ++ int where) ++{ ++ struct pci_host_bridge *bridge = pci_find_host_bridge(bus); ++ struct cdns_mango_pcie_rc *rc = pci_host_bridge_priv(bridge); ++ struct cdns_pcie *pcie = &rc->pcie; ++ unsigned int busn = bus->number; ++ u32 addr0, desc0; ++ ++ if (pci_is_root_bus(bus)) { ++ /* ++ * Only the root port (devfn == 0) is connected to this bus. ++ * All other PCI devices are behind some bridge hence on another ++ * bus. ++ */ ++ if (devfn) ++ return NULL; ++ ++ return pcie->reg_base + CDNS_PCIE_RP_BASE + (where & 0xfff); ++ } ++ /* Check that the link is up */ ++ if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1)) ++ return NULL; ++ /* Clear AXI link-down status */ ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_LINKDOWN, 0x0); ++ ++ /* Update Output registers for AXI region 0. */ ++ addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | ++ CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) | ++ CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn); ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0); ++ ++ /* Configuration Type 0 or Type 1 access. */ ++ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | ++ CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); ++ /* ++ * The bus number was already set once for all in desc1 by ++ * cdns_pcie_host_init_address_translation(). ++ */ ++ if (busn == bridge->busnr + 1) ++ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0; ++ else ++ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1; ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0); ++ ++ return rc->cfg_base + (where & 0xfff); ++} ++ ++int cdns_pcie_config_read(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 *val) ++{ ++ unsigned long addr; ++ unsigned int value, offset; ++ void __iomem *aligned_addr; ++ ++ if ((bus->number != 0) && (bus->number != 0x40) && ++ (bus->number != 0x80) && (bus->number != 0xc0)) ++ return pci_generic_config_read(bus, devfn, where, size, val); ++ ++ addr = (unsigned long)bus->ops->map_bus(bus, devfn, where); ++ if (!addr) { ++ *val = ~0; ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ } ++ ++ if (size == 1) { ++ offset = addr & 0x3; ++ aligned_addr = (void __iomem *)(addr & ~0x3UL); ++ value = readl(aligned_addr); ++ *val = (value >> (8 * offset)) & 0xff; ++ } else if (size == 2) { ++ WARN_ON((addr & 0x1) != 0); // address should be aligned to 2 bytes ++ offset = addr & 0x3; ++ aligned_addr = (void __iomem *)(addr & ~0x3UL); ++ value = readl(aligned_addr); ++ *val = (value >> (8 * offset)) & 0xffff; ++ } else { ++ WARN_ON((addr & 0x3) != 0); // address should be aligned to 4 bytes ++ *val = readl((void __iomem *)(addr)); ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++int cdns_pcie_config_write(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ unsigned long addr; ++ unsigned int value, offset; ++ void __iomem *aligned_addr; ++ ++ if ((bus->number != 0) && (bus->number != 0x40) && ++ (bus->number != 0x80) && (bus->number != 0xc0)) ++ return pci_generic_config_write(bus, devfn, where, size, val); ++ ++ addr = (unsigned long)bus->ops->map_bus(bus, devfn, where); ++ if (!addr) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ if (size == 1) { ++ offset = addr & 0x3; ++ aligned_addr = (void __iomem *)(addr & ~0x3UL); ++ value = readl(aligned_addr); ++ value &= ~(0xFF << (8 * offset)); ++ value |= ((val << (8 * offset)) & (0xFF << (8 * offset))); ++ writel(value, aligned_addr); ++ } else if (size == 2) { ++ WARN_ON((addr & 0x1) != 0); ++ offset = addr & 0x3; ++ aligned_addr = (void __iomem *)(addr & ~0x3UL); ++ value = readl(aligned_addr); ++ value &= ~(0xFFFF << (8 * offset)); ++ value |= ((val << (8 * offset)) & (0xFFFF << (8 * offset))); ++ writel(value, aligned_addr); ++ } else { ++ WARN_ON((addr & 0x3) != 0); ++ writel(val, (void __iomem *)(addr)); ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++ ++static struct pci_ops cdns_pcie_host_ops = { ++ .map_bus = cdns_mango_pci_map_bus, ++ .read = cdns_pcie_config_read, ++ .write = cdns_pcie_config_write, ++}; ++ ++static const struct of_device_id cdns_pcie_host_of_match = { ++ { .compatible = "sophgo,cdns-pcie-host" }, ++ ++ { }, ++}; ++ ++static int cdns_pcie_host_init_root_port(struct cdns_mango_pcie_rc *rc) ++{ ++ struct cdns_pcie *pcie = &rc->pcie; ++ u32 value, ctrl; ++ u32 id; ++ ++ /* ++ * Set the root complex BAR configuration register: ++ * - disable both BAR0 and BAR1. ++ * - enable Prefetchable Memory Base and Limit registers in type 1 ++ * config space (64 bits). ++ * - enable IO Base and Limit registers in type 1 config ++ * space (32 bits). ++ */ ++ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; ++ value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) | ++ CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) | ++ CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE | ++ CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS | ++ CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE | ++ CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS; ++ cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); ++ ++ /* Set root port configuration space */ ++ if (rc->vendor_id != 0xffff) { ++ id = CDNS_PCIE_LM_ID_VENDOR(rc->vendor_id) | ++ CDNS_PCIE_LM_ID_SUBSYS(rc->vendor_id); ++ cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id); ++ } ++ ++ if (rc->device_id != 0xffff) { ++ value = cdns_pcie_rp_readl(pcie, PCI_VENDOR_ID); ++ value &= 0x0000FFFF; ++ value |= (rc->device_id << 16); ++ cdns_pcie_rp_writel(pcie, PCI_VENDOR_ID, value); ++ } ++ ++ cdns_pcie_rp_writel(pcie, PCI_CLASS_REVISION, PCI_CLASS_BRIDGE_PCI << 16); ++ ++ return 0; ++} ++ ++static int cdns_pcie_host_init_address_translation(struct cdns_mango_pcie_rc *rc) ++{ ++ struct cdns_pcie *pcie = &rc->pcie; ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc); ++ struct resource *cfg_res = rc->cfg_res; ++ struct resource_entry *entry = NULL; ++ u32 addr0, addr1, desc1; ++ u64 cpu_addr; ++ int r, busnr = 0; ++ ++ entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS); ++ if (entry) ++ busnr = entry->res->start; ++ ++ /* ++ * Reserve region 0 for PCI configure space accesses: ++ * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by ++ * cdns_pci_map_bus(), other region registers are set here once for all. ++ */ ++ addr1 = 0; /* Should be programmed to zero. */ ++ desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr); ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1); ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1); ++ ++ cpu_addr = cfg_res->start; ++ addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) | ++ (lower_32_bits(cpu_addr) & GENMASK(31, 8)); ++ addr1 = upper_32_bits(cpu_addr); ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0); ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1); ++ ++ r = 1; ++ resource_list_for_each_entry(entry, &bridge->windows) { ++ struct resource *res = entry->res; ++ u64 pci_addr = res->start - entry->offset; ++ ++ if (resource_type(res) == IORESOURCE_IO) ++ cdns_pcie_set_outbound_region(pcie, busnr, 0, r, ++ true, ++ pci_pio_to_address(res->start), ++ pci_addr, ++ resource_size(res)); ++ else ++ cdns_pcie_set_outbound_region(pcie, busnr, 0, r, ++ false, ++ res->start, ++ pci_addr, ++ resource_size(res)); ++ ++ r++; ++ } ++ ++ /* ++ * Set Root Port no BAR match Inbound Translation registers: ++ * needed for MSI and DMA. ++ * Root Port BAR0 and BAR1 are disabled, hence no need to set their ++ * inbound translation registers. ++ */ ++ addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits); ++ addr1 = 0; ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0); ++ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1); ++ ++ return 0; ++} ++ ++static int cdns_pcie_msi_init(struct cdns_mango_pcie_rc *rc) ++{ ++ struct device *dev = rc->dev; ++ struct cdns_pcie *pcie = &rc->pcie; ++ u32 apb_base = CDNS_PCIE_CFG_MANGO_APB; ++ u64 msi_target = 0; ++ u32 value = 0; ++ ++ // support 512 msi vectors ++ rc->msi_page = dma_alloc_coherent(dev, 2048, &rc->msi_data, ++ (GFP_KERNEL|GFP_DMA32|__GFP_ZERO)); ++ if (rc->msi_page == NULL) ++ return -1; ++ ++ dev_info(dev, "msi_data is 0x%llx\n", rc->msi_data); ++ msi_target = (u64)rc->msi_data; ++ ++ if (rc->link_id == 1) { ++ apb_base -= 0x800000; ++ /* Program the msi_data */ ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0868), ++ lower_32_bits(msi_target)); ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG086C), ++ upper_32_bits(msi_target)); ++ ++ value = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG080C)); ++ value = (value & 0xffff0000) | MAX_MSI_IRQS; ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG080C), value); ++ } else { ++ /* Program the msi_data */ ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0860), ++ lower_32_bits(msi_target)); ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0864), ++ upper_32_bits(msi_target)); ++ ++ value = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG085C)); ++ value = (value & 0x0000ffff) | (MAX_MSI_IRQS << 16); ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG085C), value); ++ } ++ ++ return 0; ++} ++ ++static int cdns_pcie_host_init(struct device *dev, struct cdns_mango_pcie_rc *rc) ++{ ++ int err; ++ ++ err = cdns_pcie_host_init_root_port(rc); ++ if (err) ++ return err; ++ ++ err = cdns_pcie_host_init_address_translation(rc); ++ if (err) ++ return err; ++ ++ if (rc->top_intc_used == 0) { ++ rc->num_vectors = MSI_DEF_NUM_VECTORS; ++ rc->num_applied_vecs = 0; ++ if (IS_ENABLED(CONFIG_PCI_MSI)) { ++ err = cdns_pcie_msi_init(rc); ++ if (err) ++ return err; ++ } ++ } ++ return 0; ++} ++ ++ ++static void cdns_pcie_msi_ack_irq(struct irq_data *d) ++{ ++ irq_chip_ack_parent(d); ++} ++ ++static void cdns_pcie_msi_mask_irq(struct irq_data *d) ++{ ++ pci_msi_mask_irq(d); ++ irq_chip_mask_parent(d); ++} ++ ++static void cdns_pcie_msi_unmask_irq(struct irq_data *d) ++{ ++ pci_msi_unmask_irq(d); ++ irq_chip_unmask_parent(d); ++} ++ ++static struct irq_chip cdns_pcie_msi_irq_chip = { ++ .name = "cdns-msi", ++ .irq_ack = cdns_pcie_msi_ack_irq, ++ .irq_mask = cdns_pcie_msi_mask_irq, ++ .irq_unmask = cdns_pcie_msi_unmask_irq, ++}; ++ ++static struct msi_domain_info cdns_pcie_msi_domain_info = { ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), ++ .chip = &cdns_pcie_msi_irq_chip, ++}; ++ ++static struct msi_domain_info cdns_pcie_top_intr_msi_domain_info = { ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS ++ | MSI_FLAG_PCI_MSIX), ++ .chip = &cdns_pcie_msi_irq_chip, ++}; ++ ++struct vendor_id_list vendor_id_list = { ++ {"Inter X520", 0x8086, 0x10fb}, ++ //{"WangXun RP1000", 0x8088}, ++ {"Switchtec", 0x11f8,4052}, ++}; ++ ++size_t vendor_id_list_num = ARRAY_SIZE(vendor_id_list); ++ ++int check_vendor_id(struct pci_dev *dev, struct vendor_id_list vendor_id_list, ++ size_t vendor_id_list_num) ++{ ++ uint16_t device_vendor_id; ++ uint16_t device_id; ++ ++ if (pci_read_config_word(dev, PCI_VENDOR_ID, &device_vendor_id) != 0) { ++ pr_err("Failed to read device vendor ID\n"); ++ return 0; ++ } ++ ++ if (pci_read_config_word(dev, PCI_DEVICE_ID, &device_id) != 0) { ++ pr_err("Failed to read device vendor ID\n"); ++ return 0; ++ } ++ ++ for (int i = 0; i < vendor_id_list_num; ++i) { ++ if (device_vendor_id == vendor_id_listi.vendor_id && device_id == vendor_id_listi.device_id) { ++ pr_info("dev: %s vendor ID: 0x%04x device ID: 0x%04x Enable MSI-X IRQ\n", ++ vendor_id_listi.name, device_vendor_id, device_id); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++ ++static int cdns_pcie_msi_setup_for_top_intc(struct cdns_mango_pcie_rc *rc, int intc_id) ++{ ++ struct irq_domain *irq_parent = cdns_pcie_get_parent_irq_domain(intc_id); ++ struct fwnode_handle *fwnode = of_node_to_fwnode(rc->dev->of_node); ++ ++ if (rc->msix_supported == 1) { ++ rc->msi_domain = pci_msi_create_irq_domain(fwnode, ++ &cdns_pcie_top_intr_msi_domain_info, ++ irq_parent); ++ } else { ++ rc->msi_domain = pci_msi_create_irq_domain(fwnode, ++ &cdns_pcie_msi_domain_info, ++ irq_parent); ++ } ++ ++ if (!rc->msi_domain) { ++ dev_err(rc->dev, "create msi irq domain failed\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++/* MSI int handler */ ++irqreturn_t cdns_handle_msi_irq(struct cdns_mango_pcie_rc *rc) ++{ ++ u32 i, pos, irq; ++ unsigned long val; ++ u32 status, num_vectors; ++ irqreturn_t ret = IRQ_NONE; ++ ++ num_vectors = rc->num_applied_vecs; ++ for (i = 0; i <= num_vectors; i++) { ++ status = readl((void *)(rc->msi_page + i * BYTE_NUM_PER_MSI_VEC)); ++ if (!status) ++ continue; ++ ++ ret = IRQ_HANDLED; ++ val = status; ++ pos = 0; ++ while ((pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL, ++ pos)) != MAX_MSI_IRQS_PER_CTRL) { ++ irq = irq_find_mapping(rc->irq_domain, ++ (i * MAX_MSI_IRQS_PER_CTRL) + ++ pos); ++ generic_handle_irq(irq); ++ pos++; ++ } ++ writel(0, ((void *)(rc->msi_page) + i * BYTE_NUM_PER_MSI_VEC)); ++ } ++ if (ret == IRQ_NONE) { ++ ret = IRQ_HANDLED; ++ for (i = 0; i <= num_vectors; i++) { ++ for (pos = 0; pos < MAX_MSI_IRQS_PER_CTRL; pos++) { ++ irq = irq_find_mapping(rc->irq_domain, ++ (i * MAX_MSI_IRQS_PER_CTRL) + ++ pos); ++ if (!irq) ++ continue; ++ generic_handle_irq(irq); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++static irqreturn_t cdns_pcie_irq_handler(int irq, void *arg) ++{ ++ struct cdns_mango_pcie_rc *rc = arg; ++ struct cdns_pcie *pcie = &rc->pcie; ++ u32 apb_base = CDNS_PCIE_CFG_MANGO_APB; ++ u32 status = 0; ++ u32 st_msi_in_bit = 0; ++ u32 clr_msi_in_bit = 0; ++ ++ if (rc->link_id == 1) { ++ apb_base -= 0x800000; ++ st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT; ++ clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT; ++ } else { ++ st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT; ++ clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT; ++ } ++ ++ status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0810)); ++ if ((status >> st_msi_in_bit) & 0x1) { ++ WARN_ON(!IS_ENABLED(CONFIG_PCI_MSI)); ++ ++ //clear msi interrupt bit reg08102 ++ status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0804)); ++ status |= ((u32)0x1 << clr_msi_in_bit); ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status); ++ ++ status &= ~((u32)0x1 << clr_msi_in_bit); ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status); ++ ++ cdns_handle_msi_irq(rc); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* Chained MSI interrupt service routine */ ++static void cdns_chained_msi_isr(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ struct cdns_mango_pcie_rc *rc; ++ struct cdns_pcie *pcie; ++ u32 apb_base = CDNS_PCIE_CFG_MANGO_APB; ++ u32 status = 0; ++ u32 st_msi_in_bit = 0; ++ u32 clr_msi_in_bit = 0; ++ ++ chained_irq_enter(chip, desc); ++ ++ rc = irq_desc_get_handler_data(desc); ++ pcie = &rc->pcie; ++ if (rc->link_id == 1) { ++ apb_base -= 0x800000; ++ st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT; ++ clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT; ++ } else { ++ st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT; ++ clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT; ++ } ++ ++ status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0810)); ++ if ((status >> st_msi_in_bit) & 0x1) { ++ WARN_ON(!IS_ENABLED(CONFIG_PCI_MSI)); ++ ++ //clear msi interrupt bit reg08102 ++ status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0804)); ++ status |= ((u32)0x1 << clr_msi_in_bit); ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status); ++ ++ status &= ~((u32)0x1 << clr_msi_in_bit); ++ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status); ++ ++ cdns_handle_msi_irq(rc); ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static int cdns_pci_msi_set_affinity(struct irq_data *d, ++ const struct cpumask *mask, bool force) ++{ ++ return -EINVAL; ++} ++ ++static void cdns_pci_bottom_mask(struct irq_data *d) ++{ ++} ++ ++static void cdns_pci_bottom_unmask(struct irq_data *d) ++{ ++} ++ ++static void cdns_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg) ++{ ++ struct cdns_mango_pcie_rc *rc = irq_data_get_irq_chip_data(d); ++ u64 msi_target; ++ ++ msi_target = (u64)rc->msi_data; ++ ++ msg->address_lo = lower_32_bits(msi_target) + BYTE_NUM_PER_MSI_VEC * d->hwirq; ++ msg->address_hi = upper_32_bits(msi_target); ++ msg->data = 1; ++ ++ rc->num_applied_vecs = d->hwirq; ++ ++ dev_err(rc->dev, "msi#%d address_hi %#x address_lo %#x\n", ++ (int)d->hwirq, msg->address_hi, msg->address_lo); ++} ++ ++static void cdns_pci_bottom_ack(struct irq_data *d) ++{ ++} ++ ++static struct irq_chip cdns_pci_msi_bottom_irq_chip = { ++ .name = "CDNS-PCI-MSI", ++ .irq_ack = cdns_pci_bottom_ack, ++ .irq_compose_msi_msg = cdns_pci_setup_msi_msg, ++ .irq_set_affinity = cdns_pci_msi_set_affinity, ++ .irq_mask = cdns_pci_bottom_mask, ++ .irq_unmask = cdns_pci_bottom_unmask, ++}; ++ ++static int cdns_pcie_irq_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs, ++ void *args) ++{ ++ struct cdns_mango_pcie_rc *rc = domain->host_data; ++ unsigned long flags; ++ u32 i; ++ int bit; ++ ++ raw_spin_lock_irqsave(&rc->lock, flags); ++ ++ bit = bitmap_find_free_region(rc->msi_irq_in_use, rc->num_vectors, ++ order_base_2(nr_irqs)); ++ ++ raw_spin_unlock_irqrestore(&rc->lock, flags); ++ ++ if (bit < 0) ++ return -ENOSPC; ++ ++ for (i = 0; i < nr_irqs; i++) ++ irq_domain_set_info(domain, virq + i, bit + i, ++ rc->msi_irq_chip, ++ rc, handle_edge_irq, ++ NULL, NULL); ++ ++ return 0; ++} ++ ++static void cdns_pcie_irq_domain_free(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs) ++{ ++ struct irq_data *d = irq_domain_get_irq_data(domain, virq); ++ struct cdns_mango_pcie_rc *rc = irq_data_get_irq_chip_data(d); ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&rc->lock, flags); ++ ++ bitmap_release_region(rc->msi_irq_in_use, d->hwirq, ++ order_base_2(nr_irqs)); ++ ++ raw_spin_unlock_irqrestore(&rc->lock, flags); ++} ++ ++static const struct irq_domain_ops cdns_pcie_msi_domain_ops = { ++ .alloc = cdns_pcie_irq_domain_alloc, ++ .free = cdns_pcie_irq_domain_free, ++}; ++ ++int cdns_pcie_allocate_domains(struct cdns_mango_pcie_rc *rc) ++{ ++ struct fwnode_handle *fwnode = of_node_to_fwnode(rc->dev->of_node); ++ ++ rc->irq_domain = irq_domain_create_linear(fwnode, rc->num_vectors, ++ &cdns_pcie_msi_domain_ops, rc); ++ if (!rc->irq_domain) { ++ dev_err(rc->dev, "Failed to create IRQ domain\n"); ++ return -ENOMEM; ++ } ++ ++ irq_domain_update_bus_token(rc->irq_domain, DOMAIN_BUS_NEXUS); ++ ++ rc->msi_domain = pci_msi_create_irq_domain(fwnode, ++ &cdns_pcie_msi_domain_info, ++ rc->irq_domain); ++ if (!rc->msi_domain) { ++ dev_err(rc->dev, "Failed to create MSI domain\n"); ++ irq_domain_remove(rc->irq_domain); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++void cdns_pcie_free_msi(struct cdns_mango_pcie_rc *rc) ++{ ++ if (rc->msi_irq) { ++ irq_set_chained_handler(rc->msi_irq, NULL); ++ irq_set_handler_data(rc->msi_irq, NULL); ++ } ++ ++ irq_domain_remove(rc->msi_domain); ++ irq_domain_remove(rc->irq_domain); ++ ++ if (rc->msi_page) ++ dma_free_coherent(rc->dev, 1024, rc->msi_page, rc->msi_data); ++ ++} ++ ++static int cdns_pcie_msi_setup(struct cdns_mango_pcie_rc *rc) ++{ ++ int ret = 0; ++ ++ raw_spin_lock_init(&rc->lock); ++ ++ if (IS_ENABLED(CONFIG_PCI_MSI)) { ++ rc->msi_irq_chip = &cdns_pci_msi_bottom_irq_chip; ++ ++ ret = cdns_pcie_allocate_domains(rc); ++ if (ret) ++ return ret; ++ ++ if (rc->msi_irq) ++ irq_set_chained_handler_and_data(rc->msi_irq, cdns_chained_msi_isr, rc); ++ } ++ ++ return ret; ++} ++ ++static int cdns_pcie_host_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct pci_host_bridge *bridge; ++ struct cdns_mango_pcie_rc *rc; ++ struct cdns_pcie *pcie; ++ struct resource *res; ++ int ret; ++ int phy_count; ++ int top_intc_id = -1; ++ ++ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); ++ if (!bridge) ++ return -ENOMEM; ++ ++ rc = pci_host_bridge_priv(bridge); ++ rc->dev = dev; ++ ++ pcie = &rc->pcie; ++ pcie->is_rc = true; ++ pcie->ops = &cdns_mango_ops; ++ ++ rc->max_regions = 32; ++ of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions); ++ ++ rc->no_bar_nbits = 32; ++ of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits); ++ ++ rc->vendor_id = 0xffff; ++ of_property_read_u16(np, "vendor-id", &rc->vendor_id); ++ ++ rc->device_id = 0xffff; ++ of_property_read_u16(np, "device-id", &rc->device_id); ++ ++ rc->pcie_id = 0xffff; ++ of_property_read_u16(np, "pcie-id", &rc->pcie_id); ++ ++ rc->link_id = 0xffff; ++ of_property_read_u16(np, "link-id", &rc->link_id); ++ ++ rc->msix_supported = 0; ++ of_property_read_u32(np, "msix-supported", &rc->msix_supported); ++ ++ rc->top_intc_used = 0; ++ of_property_read_u32(np, "top-intc-used", &rc->top_intc_used); ++ if (rc->top_intc_used == 1) ++ of_property_read_u32(np, "top-intc-id", &top_intc_id); ++ ++ if (rc->link_id == 0) { ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); ++ pcie->reg_base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pcie->reg_base)) { ++ dev_err(dev, "missing \"reg\"\n"); ++ return PTR_ERR(pcie->reg_base); ++ } ++ cdns_pcie_db.pcie_reg_base = pcie->reg_base; ++ } else if (rc->link_id == 1) { ++ pcie->reg_base = cdns_pcie_db.pcie_reg_base + 0x800000; ++ } ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); ++ rc->cfg_base = devm_pci_remap_cfg_resource(dev, res); ++ if (IS_ERR(rc->cfg_base)) { ++ dev_err(dev, "missing \"cfg\"\n"); ++ return PTR_ERR(rc->cfg_base); ++ } ++ rc->cfg_res = res; ++ ++ ret = cdns_pcie_init_phy(dev, pcie); ++ if (ret) { ++ dev_err(dev, "failed to init phy\n"); ++ return ret; ++ } ++ platform_set_drvdata(pdev, pcie); ++ ++ pm_runtime_enable(dev); ++ ret = pm_runtime_get_sync(dev); ++ if (ret < 0) { ++ dev_err(dev, "pm_runtime_get_sync() failed\n"); ++ goto err_get_sync; ++ } ++ ++ ret = cdns_pcie_host_init(dev, rc); ++ if (ret) ++ goto err_init; ++ ++ if ((rc->top_intc_used == 0) && (IS_ENABLED(CONFIG_PCI_MSI))) { ++ rc->msi_irq = platform_get_irq_byname(pdev, "msi"); ++ if (rc->msi_irq <= 0) { ++ dev_err(dev, "failed to get MSI irq\n"); ++ goto err_init_irq; ++ } ++ ++ ret = devm_request_irq(dev, rc->msi_irq, cdns_pcie_irq_handler, ++ IRQF_SHARED | IRQF_NO_THREAD, ++ "cdns-pcie-irq", rc); ++ ++ if (ret) { ++ dev_err(dev, "failed to request MSI irq\n"); ++ goto err_init_irq; ++ } ++ } ++ ++ bridge->dev.parent = dev; ++ bridge->ops = &cdns_pcie_host_ops; ++ bridge->map_irq = of_irq_parse_and_map_pci; ++ bridge->swizzle_irq = pci_common_swizzle; ++ if (rc->top_intc_used == 0) ++ bridge->sysdata = rc; ++ ++ if (rc->top_intc_used == 0) { ++ ret = cdns_pcie_msi_setup(rc); ++ if (ret < 0) ++ goto err_host_probe; ++ } else if (rc->top_intc_used == 1) { ++ ret = cdns_pcie_msi_setup_for_top_intc(rc, top_intc_id); ++ if (ret < 0) ++ goto err_host_probe; ++ } ++ ++ ret = pci_host_probe(bridge); ++ if (ret < 0) ++ goto err_host_probe; ++ ++ return 0; ++ ++ err_host_probe: ++ err_init_irq: ++ if ((rc->top_intc_used == 0) && pci_msi_enabled()) ++ cdns_pcie_free_msi(rc); ++ ++ err_init: ++ pm_runtime_put_sync(dev); ++ ++ err_get_sync: ++ pm_runtime_disable(dev); ++ cdns_pcie_disable_phy(pcie); ++ phy_count = pcie->phy_count; ++ while (phy_count--) ++ device_link_del(pcie->linkphy_count); ++ ++ return ret; ++} ++ ++static void cdns_pcie_shutdown(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct cdns_pcie *pcie = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = pm_runtime_put_sync(dev); ++ if (ret < 0) ++ dev_dbg(dev, "pm_runtime_put_sync failed\n"); ++ ++ pm_runtime_disable(dev); ++ cdns_pcie_disable_phy(pcie); ++} ++ ++static struct platform_driver cdns_pcie_host_driver = { ++ .driver = { ++ .name = "cdns-pcie-host", ++ .of_match_table = cdns_pcie_host_of_match, ++ .pm = &cdns_pcie_pm_ops, ++ }, ++ .probe = cdns_pcie_host_probe, ++ .shutdown = cdns_pcie_shutdown, ++}; ++builtin_platform_driver(cdns_pcie_host_driver); +diff --git a/drivers/pci/controller/cadence/pcie-cadence-sophgo.h b/drivers/pci/controller/cadence/pcie-cadence-sophgo.h +new file mode 100644 +index 000000000000..ef46c46678ed +--- /dev/null ++++ b/drivers/pci/controller/cadence/pcie-cadence-sophgo.h +@@ -0,0 +1,17 @@ ++#ifndef PCIE_CADENCE_SOPHGO ++#define PCIE_CADENCE_SOPHGO ++ ++ ++struct vendor_id_list { ++ const char *name; ++ uint16_t vendor_id; ++ uint16_t device_id; ++}; ++ ++extern struct vendor_id_list vendor_id_list; ++extern size_t vendor_id_list_num; ++ ++extern struct irq_domain *cdns_pcie_get_parent_irq_domain(int intc_id); ++int check_vendor_id(struct pci_dev *dev, struct vendor_id_list vendor_id_list, ++ size_t vendor_id_list_num); ++#endif +diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c +index 46fad0d813b2..560b3a236d84 100644 +--- a/drivers/pci/pcie/portdrv.c ++++ b/drivers/pci/pcie/portdrv.c +@@ -598,7 +598,7 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *drv) + } + + /* If this switch is set, PCIe port native services should not be enabled. */ +-bool pcie_ports_disabled; ++bool pcie_ports_disabled = true; + + /* + * If the user specified "pcie_ports=native", use the PCIe services regardless +diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig +index 79753411b778..15ad8ada527d 100644 +--- a/drivers/pinctrl/Kconfig ++++ b/drivers/pinctrl/Kconfig +@@ -22,7 +22,7 @@ config PINCONF + bool "Support pin configuration controllers" if COMPILE_TEST + + config GENERIC_PINCONF +- bool ++ bool "GENERIC_PINCONF" + select PINCONF + + config DEBUG_PINCTRL +@@ -469,6 +469,15 @@ config PINCTRL_TB10X + depends on OF && ARC_PLAT_TB10X + select GPIOLIB + ++config PINCTRL_TH1520 ++ tristate "Pinctrl driver for the T-Head TH1520 SoC" ++ depends on ARCH_THEAD || COMPILE_TEST ++ select GENERIC_PINMUX_FUNCTIONS ++ select GENERIC_PINCONF ++ select PINMUX ++ help ++ This selects the pinctrl driver for T-Head TH1520 RISC-V SoC. ++ + config PINCTRL_ZYNQ + bool "Pinctrl driver for Xilinx Zynq" + depends on ARCH_ZYNQ +diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile +index 4275eca92488..f07a2ee92197 100644 +--- a/drivers/pinctrl/Makefile ++++ b/drivers/pinctrl/Makefile +@@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o + obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o + obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o + 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 + +@@ -75,6 +76,7 @@ obj-$(CONFIG_SOC_STARFIVE) += starfive/ + obj-$(CONFIG_PINCTRL_STM32) += stm32/ + obj-y += sunplus/ + obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/ ++obj-$(CONFIG_ARCH_SOPHGO) += sophgo/ + obj-$(CONFIG_ARCH_TEGRA) += tegra/ + obj-y += ti/ + obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ +diff --git a/drivers/pinctrl/pinctrl-th1520.c b/drivers/pinctrl/pinctrl-th1520.c +new file mode 100644 +index 000000000000..6af46d59d0fa +--- /dev/null ++++ b/drivers/pinctrl/pinctrl-th1520.c +@@ -0,0 +1,860 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Pinctrl driver for the T-Head TH1520 SoC ++ * ++ * Copyright (C) 2023 Emil Renner Berthing <emil.renner.berthing@canonical.com> ++ */ ++ ++#include <linux/bits.h> ++#include <linux/cleanup.h> ++#include <linux/clk.h> ++#include <linux/device.h> ++#include <linux/io.h> ++#include <linux/mod_devicetable.h> ++#include <linux/module.h> ++#include <linux/mutex.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/seq_file.h> ++#include <linux/spinlock.h> ++ ++#include <linux/pinctrl/pinconf.h> ++#include <linux/pinctrl/pinconf-generic.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++ ++#include "core.h" ++#include "pinmux.h" ++#include "pinconf.h" ++ ++#define TH1520_PADCFG_IE BIT(9) ++#define TH1520_PADCFG_SL BIT(8) ++#define TH1520_PADCFG_ST BIT(7) ++#define TH1520_PADCFG_SPU BIT(6) ++#define TH1520_PADCFG_PS BIT(5) ++#define TH1520_PADCFG_PE BIT(4) ++#define TH1520_PADCFG_BIAS (TH1520_PADCFG_SPU | TH1520_PADCFG_PS | TH1520_PADCFG_PE) ++#define TH1520_PADCFG_DS GENMASK(3, 0) ++ ++#define TH1520_PULL_DOWN_OHM 44000 /* typ. 44kOhm */ ++#define TH1520_PULL_UP_OHM 48000 /* typ. 48kOhm */ ++#define TH1520_PULL_STRONG_OHM 2100 /* typ. 2.1kOhm */ ++ ++#define TH1520_PAD_NO_PADCFG BIT(30) ++#define TH1520_PAD_MUXDATA GENMASK(29, 0) ++ ++struct th1520_pad_group { ++ const char *name; ++ const struct pinctrl_pin_desc *pins; ++ unsigned int npins; ++}; ++ ++struct th1520_pinctrl { ++ struct pinctrl_desc desc; ++ struct mutex mutex; /* serialize adding functions */ ++ raw_spinlock_t lock; /* serialize register access */ ++ void __iomem *base; ++ struct pinctrl_dev *pctl; ++}; ++ ++static void __iomem *th1520_padcfg(struct th1520_pinctrl *thp, ++ unsigned int pin) ++{ ++ return thp->base + 4 * (pin / 2); ++} ++ ++static unsigned int th1520_padcfg_shift(unsigned int pin) ++{ ++ return 16 * (pin & BIT(0)); ++} ++ ++static void __iomem *th1520_muxcfg(struct th1520_pinctrl *thp, ++ unsigned int pin) ++{ ++ return thp->base + 0x400 + 4 * (pin / 8); ++} ++ ++static unsigned int th1520_muxcfg_shift(unsigned int pin) ++{ ++ return 4 * (pin & GENMASK(2, 0)); ++} ++ ++enum th1520_muxtype { ++ TH1520_MUX_____, ++ TH1520_MUX_GPIO, ++ TH1520_MUX_PWM, ++ TH1520_MUX_UART, ++ TH1520_MUX_IR, ++ TH1520_MUX_I2C, ++ TH1520_MUX_SPI, ++ TH1520_MUX_QSPI, ++ TH1520_MUX_SDIO, ++ TH1520_MUX_AUD, ++ TH1520_MUX_I2S, ++ TH1520_MUX_MAC0, ++ TH1520_MUX_MAC1, ++ TH1520_MUX_DPU0, ++ TH1520_MUX_DPU1, ++ TH1520_MUX_ISP, ++ TH1520_MUX_HDMI, ++ TH1520_MUX_BSEL, ++ TH1520_MUX_DBG, ++ TH1520_MUX_CLK, ++ TH1520_MUX_JTAG, ++ TH1520_MUX_ISO, ++ TH1520_MUX_FUSE, ++ TH1520_MUX_RST, ++}; ++ ++static const char *const th1520_muxtype_string = { ++ TH1520_MUX_GPIO = "gpio", ++ TH1520_MUX_PWM = "pwm", ++ TH1520_MUX_UART = "uart", ++ TH1520_MUX_IR = "ir", ++ TH1520_MUX_I2C = "i2c", ++ TH1520_MUX_SPI = "spi", ++ TH1520_MUX_QSPI = "qspi", ++ TH1520_MUX_SDIO = "sdio", ++ TH1520_MUX_AUD = "audio", ++ TH1520_MUX_I2S = "i2s", ++ TH1520_MUX_MAC0 = "gmac0", ++ TH1520_MUX_MAC1 = "gmac1", ++ TH1520_MUX_DPU0 = "dpu0", ++ TH1520_MUX_DPU1 = "dpu1", ++ TH1520_MUX_ISP = "isp", ++ TH1520_MUX_HDMI = "hdmi", ++ TH1520_MUX_BSEL = "bootsel", ++ TH1520_MUX_DBG = "debug", ++ TH1520_MUX_CLK = "clock", ++ TH1520_MUX_JTAG = "jtag", ++ TH1520_MUX_ISO = "iso7816", ++ TH1520_MUX_FUSE = "efuse", ++ TH1520_MUX_RST = "reset", ++}; ++ ++static enum th1520_muxtype th1520_muxtype_get(const char *str) ++{ ++ enum th1520_muxtype mt; ++ ++ for (mt = TH1520_MUX_GPIO; mt < ARRAY_SIZE(th1520_muxtype_string); mt++) { ++ if (!strcmp(str, th1520_muxtype_stringmt)) ++ return mt; ++ } ++ return TH1520_MUX_____; ++} ++ ++#define TH1520_PAD(_nr, _name, m0, m1, m2, m3, m4, m5, _flags) \ ++ { .number = _nr, .name = #_name, .drv_data = (void *)((_flags) | \ ++ (TH1520_MUX_##m0 << 0) | (TH1520_MUX_##m1 << 5) | (TH1520_MUX_##m2 << 10) | \ ++ (TH1520_MUX_##m3 << 15) | (TH1520_MUX_##m4 << 20) | (TH1520_MUX_##m5 << 25)) } ++ ++static const struct pinctrl_pin_desc th1520_group1_pins = { ++ TH1520_PAD(0, OSC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), ++ TH1520_PAD(1, OSC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), ++ TH1520_PAD(2, SYS_RST_N, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), ++ TH1520_PAD(3, RTC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), ++ TH1520_PAD(4, RTC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), ++ /* skip number 5 so we can calculate register offsets and shifts from the pin number */ ++ TH1520_PAD(6, TEST_MODE, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), ++ TH1520_PAD(7, DEBUG_MODE, DBG, ____, ____, GPIO, ____, ____, TH1520_PAD_NO_PADCFG), ++ TH1520_PAD(8, POR_SEL, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), ++ TH1520_PAD(9, I2C_AON_SCL, I2C, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(10, I2C_AON_SDA, I2C, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(11, CPU_JTG_TCLK, JTAG, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(12, CPU_JTG_TMS, JTAG, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(13, CPU_JTG_TDI, JTAG, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(14, CPU_JTG_TDO, JTAG, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(15, CPU_JTG_TRST, JTAG, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(16, AOGPIO_7, CLK, AUD, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(17, AOGPIO_8, UART, AUD, IR, GPIO, ____, ____, 0), ++ TH1520_PAD(18, AOGPIO_9, UART, AUD, IR, GPIO, ____, ____, 0), ++ TH1520_PAD(19, AOGPIO_10, CLK, AUD, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(20, AOGPIO_11, GPIO, AUD, ____, ____, ____, ____, 0), ++ TH1520_PAD(21, AOGPIO_12, GPIO, AUD, ____, ____, ____, ____, 0), ++ TH1520_PAD(22, AOGPIO_13, GPIO, AUD, ____, ____, ____, ____, 0), ++ TH1520_PAD(23, AOGPIO_14, GPIO, AUD, ____, ____, ____, ____, 0), ++ TH1520_PAD(24, AOGPIO_15, GPIO, AUD, ____, ____, ____, ____, 0), ++ TH1520_PAD(25, AUDIO_PA0, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(26, AUDIO_PA1, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(27, AUDIO_PA2, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(28, AUDIO_PA3, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(29, AUDIO_PA4, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(30, AUDIO_PA5, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(31, AUDIO_PA6, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(32, AUDIO_PA7, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(33, AUDIO_PA8, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(34, AUDIO_PA9, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(35, AUDIO_PA10, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(36, AUDIO_PA11, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(37, AUDIO_PA12, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(38, AUDIO_PA13, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(39, AUDIO_PA14, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(40, AUDIO_PA15, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(41, AUDIO_PA16, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(42, AUDIO_PA17, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(43, AUDIO_PA27, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(44, AUDIO_PA28, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(45, AUDIO_PA29, AUD, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(46, AUDIO_PA30, AUD, RST, ____, GPIO, ____, ____, 0), ++}; ++ ++static const struct pinctrl_pin_desc th1520_group2_pins = { ++ TH1520_PAD(0, QSPI1_SCLK, QSPI, ISO, ____, GPIO, FUSE, ____, 0), ++ TH1520_PAD(1, QSPI1_CSN0, QSPI, ____, I2C, GPIO, FUSE, ____, 0), ++ TH1520_PAD(2, QSPI1_D0_MOSI, QSPI, ISO, I2C, GPIO, FUSE, ____, 0), ++ TH1520_PAD(3, QSPI1_D1_MISO, QSPI, ISO, ____, GPIO, FUSE, ____, 0), ++ TH1520_PAD(4, QSPI1_D2_WP, QSPI, ISO, UART, GPIO, FUSE, ____, 0), ++ TH1520_PAD(5, QSPI1_D3_HOLD, QSPI, ISO, UART, GPIO, ____, ____, 0), ++ TH1520_PAD(6, I2C0_SCL, I2C, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(7, I2C0_SDA, I2C, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(8, I2C1_SCL, I2C, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(9, I2C1_SDA, I2C, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(10, UART1_TXD, UART, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(11, UART1_RXD, UART, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(12, UART4_TXD, UART, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(13, UART4_RXD, UART, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(14, UART4_CTSN, UART, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(15, UART4_RTSN, UART, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(16, UART3_TXD, DBG, UART, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(17, UART3_RXD, DBG, UART, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(18, GPIO0_18, GPIO, I2C, ____, ____, ____, ____, 0), ++ TH1520_PAD(19, GPIO0_19, GPIO, I2C, ____, ____, ____, ____, 0), ++ TH1520_PAD(20, GPIO0_20, GPIO, UART, IR, ____, ____, ____, 0), ++ TH1520_PAD(21, GPIO0_21, GPIO, UART, IR, ____, DPU0, DPU1, 0), ++ TH1520_PAD(22, GPIO0_22, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), ++ TH1520_PAD(23, GPIO0_23, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), ++ TH1520_PAD(24, GPIO0_24, GPIO, JTAG, QSPI, ____, DPU0, DPU1, 0), ++ TH1520_PAD(25, GPIO0_25, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(26, GPIO0_26, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(27, GPIO0_27, GPIO, ____, I2C, ____, DPU0, DPU1, 0), ++ TH1520_PAD(28, GPIO0_28, GPIO, ____, I2C, ____, DPU0, DPU1, 0), ++ TH1520_PAD(29, GPIO0_29, GPIO, ____, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(30, GPIO0_30, GPIO, ____, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(31, GPIO0_31, GPIO, ____, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(32, GPIO1_0, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(33, GPIO1_1, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(34, GPIO1_2, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(35, GPIO1_3, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(36, GPIO1_4, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(37, GPIO1_5, GPIO, ____, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(38, GPIO1_6, GPIO, ____, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(39, GPIO1_7, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(40, GPIO1_8, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(41, GPIO1_9, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(42, GPIO1_10, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(43, GPIO1_11, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(44, GPIO1_12, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(45, GPIO1_13, GPIO, UART, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(46, GPIO1_14, GPIO, UART, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(47, GPIO1_15, GPIO, UART, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(48, GPIO1_16, GPIO, UART, ____, ____, DPU0, DPU1, 0), ++ TH1520_PAD(49, CLK_OUT_0, BSEL, CLK, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(50, CLK_OUT_1, BSEL, CLK, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(51, CLK_OUT_2, BSEL, CLK, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(52, CLK_OUT_3, BSEL, CLK, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(53, GPIO1_21, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(54, GPIO1_22, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(55, GPIO1_23, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(56, GPIO1_24, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(57, GPIO1_25, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(58, GPIO1_26, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(59, GPIO1_27, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(60, GPIO1_28, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(61, GPIO1_29, GPIO, ____, ISP, ____, ____, ____, 0), ++ TH1520_PAD(62, GPIO1_30, GPIO, ____, ISP, ____, ____, ____, 0), ++}; ++ ++static const struct pinctrl_pin_desc th1520_group3_pins = { ++ TH1520_PAD(0, UART0_TXD, UART, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(1, UART0_RXD, UART, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(2, QSPI0_SCLK, QSPI, PWM, I2S, GPIO, ____, ____, 0), ++ TH1520_PAD(3, QSPI0_CSN0, QSPI, PWM, I2S, GPIO, ____, ____, 0), ++ TH1520_PAD(4, QSPI0_CSN1, QSPI, PWM, I2S, GPIO, ____, ____, 0), ++ TH1520_PAD(5, QSPI0_D0_MOSI, QSPI, PWM, I2S, GPIO, ____, ____, 0), ++ TH1520_PAD(6, QSPI0_D1_MISO, QSPI, PWM, I2S, GPIO, ____, ____, 0), ++ TH1520_PAD(7, QSPI0_D2_WP, QSPI, PWM, I2S, GPIO, ____, ____, 0), ++ TH1520_PAD(8, QSPI1_D3_HOLD, QSPI, ____, I2S, GPIO, ____, ____, 0), ++ TH1520_PAD(9, I2C2_SCL, I2C, UART, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(10, I2C2_SDA, I2C, UART, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(11, I2C3_SCL, I2C, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(12, I2C3_SDA, I2C, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(13, GPIO2_13, GPIO, SPI, ____, ____, ____, ____, 0), ++ TH1520_PAD(14, SPI_SCLK, SPI, UART, IR, GPIO, ____, ____, 0), ++ TH1520_PAD(15, SPI_CSN, SPI, UART, IR, GPIO, ____, ____, 0), ++ TH1520_PAD(16, SPI_MOSI, SPI, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(17, SPI_MISO, SPI, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(18, GPIO2_18, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(19, GPIO2_19, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(20, GPIO2_20, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(21, GPIO2_21, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(22, GPIO2_22, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(23, GPIO2_23, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(24, GPIO2_24, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(25, GPIO2_25, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(26, SDIO0_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(27, SDIO0_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(28, SDIO1_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(29, SDIO1_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(30, GPIO2_30, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(31, GPIO2_31, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(32, GPIO3_0, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(33, GPIO3_1, GPIO, MAC1, ____, ____, ____, ____, 0), ++ TH1520_PAD(34, GPIO3_2, GPIO, PWM, ____, ____, ____, ____, 0), ++ TH1520_PAD(35, GPIO3_3, GPIO, PWM, ____, ____, ____, ____, 0), ++ TH1520_PAD(36, HDMI_SCL, HDMI, PWM, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(37, HDMI_SDA, HDMI, PWM, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(38, HDMI_CEC, HDMI, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(39, GMAC0_TX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(40, GMAC0_RX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(41, GMAC0_TXEN, MAC0, UART, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(42, GMAC0_TXD0, MAC0, UART, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(43, GMAC0_TXD1, MAC0, UART, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(44, GMAC0_TXD2, MAC0, UART, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(45, GMAC0_TXD3, MAC0, I2C, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(46, GMAC0_RXDV, MAC0, I2C, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(47, GMAC0_RXD0, MAC0, I2C, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(48, GMAC0_RXD1, MAC0, I2C, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(49, GMAC0_RXD2, MAC0, SPI, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(50, GMAC0_RXD3, MAC0, SPI, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(51, GMAC0_MDC, MAC0, SPI, MAC1, GPIO, ____, ____, 0), ++ TH1520_PAD(52, GMAC0_MDIO, MAC0, SPI, MAC1, GPIO, ____, ____, 0), ++ TH1520_PAD(53, GMAC0_COL, MAC0, PWM, ____, GPIO, ____, ____, 0), ++ TH1520_PAD(54, GMAC0_CRS, MAC0, PWM, ____, GPIO, ____, ____, 0), ++}; ++ ++static const struct th1520_pad_group th1520_group1 = { ++ .name = "th1520-group1", ++ .pins = th1520_group1_pins, ++ .npins = ARRAY_SIZE(th1520_group1_pins), ++}; ++ ++static const struct th1520_pad_group th1520_group2 = { ++ .name = "th1520-group2", ++ .pins = th1520_group2_pins, ++ .npins = ARRAY_SIZE(th1520_group2_pins), ++}; ++ ++static const struct th1520_pad_group th1520_group3 = { ++ .name = "th1520-group3", ++ .pins = th1520_group3_pins, ++ .npins = ARRAY_SIZE(th1520_group3_pins), ++}; ++ ++static int th1520_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) ++{ ++ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); ++ ++ return thp->desc.npins; ++} ++ ++static const char *th1520_pinctrl_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned int gsel) ++{ ++ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); ++ ++ return thp->desc.pinsgsel.name; ++} ++ ++static int th1520_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, ++ unsigned int gsel, ++ const unsigned int **pins, ++ unsigned int *npins) ++{ ++ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); ++ ++ *pins = &thp->desc.pinsgsel.number; ++ *npins = 1; ++ return 0; ++} ++ ++#ifdef CONFIG_DEBUG_FS ++static void th1520_pin_dbg_show(struct pinctrl_dev *pctldev, ++ struct seq_file *s, unsigned int pin) ++{ ++ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); ++ void __iomem *padcfg = th1520_padcfg(thp, pin); ++ void __iomem *muxcfg = th1520_muxcfg(thp, pin); ++ u32 pad; ++ u32 mux; ++ ++ scoped_guard(raw_spinlock_irqsave, &thp->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 th1520_pin_dbg_show NULL ++#endif ++ ++static void th1520_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 (mapi.type == PIN_MAP_TYPE_CONFIGS_PIN && ++ mapi.data.configs.configs != seen) { ++ seen = mapi.data.configs.configs; ++ kfree(seen); ++ } ++ } ++ ++ kfree(map); ++} ++ ++static int th1520_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, ++ struct device_node *np, ++ struct pinctrl_map **maps, ++ unsigned int *num_maps) ++{ ++ struct th1520_pinctrl *thp = 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(thp->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(&thp->mutex); ++ for_each_available_child_of_node(np, child) { ++ unsigned int rollback = nmaps; ++ enum th1520_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(thp->pctl->dev, "%pOFn.%pOFn: error parsing pin config\n", ++ np, child); ++ goto put_child; ++ } ++ ++ if (!of_property_read_string(child, "function", &funcname)) { ++ muxtype = th1520_muxtype_get(funcname); ++ if (!muxtype) { ++ dev_err(thp->pctl->dev, "%pOFn.%pOFn: unknown function '%s'\n", ++ np, child, funcname); ++ ret = -EINVAL; ++ goto free_configs; ++ } ++ ++ funcname = devm_kasprintf(thp->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(thp->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 < thp->desc.npins; i++) { ++ if (!strcmp(pinname, thp->desc.pinsi.name)) ++ break; ++ } ++ if (i == thp->desc.npins) { ++ nmaps = rollback; ++ dev_err(thp->pctl->dev, "%pOFn.%pOFn: unknown pin '%s'\n", ++ np, child, pinname); ++ goto free_configs; ++ } ++ ++ if (nconfigs) { ++ mapnmaps.type = PIN_MAP_TYPE_CONFIGS_PIN; ++ mapnmaps.data.configs.group_or_pin = thp->desc.pinsi.name; ++ mapnmaps.data.configs.configs = configs; ++ mapnmaps.data.configs.num_configs = nconfigs; ++ nmaps += 1; ++ } ++ if (funcname) { ++ pgnamesnpins++ = thp->desc.pinsi.name; ++ mapnmaps.type = PIN_MAP_TYPE_MUX_GROUP; ++ mapnmaps.data.mux.function = funcname; ++ mapnmaps.data.mux.group = thp->desc.pinsi.name; ++ nmaps += 1; ++ } ++ } ++ ++ if (funcname) { ++ ret = pinmux_generic_add_function(pctldev, funcname, pgnames, ++ npins, (void *)muxtype); ++ if (ret < 0) { ++ dev_err(thp->pctl->dev, "error adding function %s\n", funcname); ++ goto put_child; ++ } ++ } ++ } ++ ++ *maps = map; ++ *num_maps = nmaps; ++ mutex_unlock(&thp->mutex); ++ return 0; ++ ++free_configs: ++ kfree(configs); ++put_child: ++ of_node_put(child); ++ th1520_pinctrl_dt_free_map(pctldev, map, nmaps); ++ mutex_unlock(&thp->mutex); ++ return ret; ++} ++ ++static const struct pinctrl_ops th1520_pinctrl_ops = { ++ .get_groups_count = th1520_pinctrl_get_groups_count, ++ .get_group_name = th1520_pinctrl_get_group_name, ++ .get_group_pins = th1520_pinctrl_get_group_pins, ++ .pin_dbg_show = th1520_pin_dbg_show, ++ .dt_node_to_map = th1520_pinctrl_dt_node_to_map, ++ .dt_free_map = th1520_pinctrl_dt_free_map, ++}; ++ ++static int th1520_pinmux_set_mux(struct pinctrl_dev *pctldev, ++ unsigned int fsel, unsigned int gsel) ++{ ++ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); ++ const struct function_desc *func = pinmux_generic_get_function(pctldev, fsel); ++ uintptr_t muxdata = (uintptr_t)thp->desc.pinsgsel.drv_data & TH1520_PAD_MUXDATA; ++ uintptr_t muxtype = (uintptr_t)func->data; ++ unsigned int pin = thp->desc.pinsgsel.number; ++ void __iomem *muxcfg = th1520_muxcfg(thp, pin); ++ unsigned int shift = th1520_muxcfg_shift(pin); ++ u32 mask, value, tmp; ++ ++ for (value = 0; muxdata; muxdata >>= 5, value++) { ++ if ((muxdata & GENMASK(4, 0)) == muxtype) ++ break; ++ } ++ if (!muxdata) { ++ dev_err(thp->pctl->dev, "%s: invalid mux %s for pin %s\n", ++ func->name, th1520_muxtype_stringmuxtype, thp->desc.pinsgsel.name); ++ return -EINVAL; ++ } ++ ++ mask = GENMASK(3, 0) << shift; ++ value = value << shift; ++ ++ scoped_guard(raw_spinlock_irqsave, &thp->lock) { ++ tmp = readl_relaxed(muxcfg); ++ tmp = (tmp & ~mask) | value; ++ writel_relaxed(tmp, muxcfg); ++ } ++ return 0; ++} ++ ++static const struct pinmux_ops th1520_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 = th1520_pinmux_set_mux, ++ .strict = true, ++}; ++ ++static const u8 th1520_drive_strength_in_mA16 = { ++ 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25, ++}; ++ ++static u16 th1520_drive_strength_from_mA(u32 arg) ++{ ++ u16 ds; ++ ++ for (ds = 0; ds < TH1520_PADCFG_DS; ds++) { ++ if (arg <= th1520_drive_strength_in_mAds) ++ return ds; ++ } ++ return TH1520_PADCFG_DS; ++} ++ ++static int th1520_padcfg_rmw(struct th1520_pinctrl *thp, unsigned int pin, ++ u32 mask, u32 value) ++{ ++ void __iomem *padcfg = th1520_padcfg(thp, pin); ++ unsigned int shift = th1520_padcfg_shift(pin); ++ u32 tmp; ++ ++ mask <<= shift; ++ value <<= shift; ++ ++ scoped_guard(raw_spinlock_irqsave, &thp->lock) { ++ tmp = readl_relaxed(padcfg); ++ tmp = (tmp & ~mask) | value; ++ writel_relaxed(tmp, padcfg); ++ } ++ return 0; ++} ++ ++static int th1520_pinconf_get(struct pinctrl_dev *pctldev, ++ unsigned int pin, unsigned long *config) ++{ ++ struct th1520_pinctrl *thp = 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 & TH1520_PAD_NO_PADCFG) ++ return -ENOTSUPP; ++ ++ value = readl_relaxed(th1520_padcfg(thp, pin)); ++ value = (value >> th1520_padcfg_shift(pin)) & GENMASK(9, 0); ++ ++ param = pinconf_to_config_param(*config); ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ enabled = !(value & (TH1520_PADCFG_SPU | TH1520_PADCFG_PE)); ++ arg = 0; ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ enabled = (value & TH1520_PADCFG_BIAS) == TH1520_PADCFG_PE; ++ arg = enabled ? TH1520_PULL_DOWN_OHM : 0; ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ if (value & TH1520_PADCFG_SPU) { ++ enabled = true; ++ arg = TH1520_PULL_STRONG_OHM; ++ } else if ((value & (TH1520_PADCFG_PE | TH1520_PADCFG_PS)) == ++ (TH1520_PADCFG_PE | TH1520_PADCFG_PS)) { ++ enabled = true; ++ arg = TH1520_PULL_UP_OHM; ++ } else { ++ enabled = false; ++ arg = 0; ++ } ++ break; ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ enabled = true; ++ arg = th1520_drive_strength_in_mAvalue & TH1520_PADCFG_DS; ++ break; ++ case PIN_CONFIG_INPUT_ENABLE: ++ enabled = value & TH1520_PADCFG_IE; ++ arg = enabled ? 1 : 0; ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ enabled = value & TH1520_PADCFG_ST; ++ arg = enabled ? 1 : 0; ++ break; ++ case PIN_CONFIG_SLEW_RATE: ++ enabled = value & TH1520_PADCFG_SL; ++ arg = enabled ? 1 : 0; ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ ++ *config = pinconf_to_config_packed(param, arg); ++ return enabled ? 0 : -EINVAL; ++} ++ ++static int th1520_pinconf_group_get(struct pinctrl_dev *pctldev, ++ unsigned int gsel, unsigned long *config) ++{ ++ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); ++ unsigned int pin = thp->desc.pinsgsel.number; ++ ++ return th1520_pinconf_get(pctldev, pin, config); ++} ++ ++static int th1520_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, ++ unsigned long *configs, unsigned int num_configs) ++{ ++ struct th1520_pinctrl *thp = 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 & TH1520_PAD_NO_PADCFG) ++ return -ENOTSUPP; ++ ++ mask = 0; ++ value = 0; ++ for (i = 0; i < num_configs; i++) { ++ int param = pinconf_to_config_param(configsi); ++ u32 arg = pinconf_to_config_argument(configsi); ++ ++ switch (param) { ++ case PIN_CONFIG_BIAS_DISABLE: ++ mask |= TH1520_PADCFG_BIAS; ++ value &= ~TH1520_PADCFG_BIAS; ++ break; ++ case PIN_CONFIG_BIAS_PULL_DOWN: ++ if (arg == 0) ++ return -ENOTSUPP; ++ mask |= TH1520_PADCFG_BIAS; ++ value &= ~TH1520_PADCFG_BIAS; ++ value |= TH1520_PADCFG_PE; ++ break; ++ case PIN_CONFIG_BIAS_PULL_UP: ++ if (arg == 0) ++ return -ENOTSUPP; ++ mask |= TH1520_PADCFG_BIAS; ++ value &= ~TH1520_PADCFG_BIAS; ++ if (arg == TH1520_PULL_STRONG_OHM) ++ value |= TH1520_PADCFG_SPU; ++ else ++ value |= TH1520_PADCFG_PE | TH1520_PADCFG_PS; ++ break; ++ case PIN_CONFIG_DRIVE_STRENGTH: ++ mask |= TH1520_PADCFG_DS; ++ value &= ~TH1520_PADCFG_DS; ++ value |= th1520_drive_strength_from_mA(arg); ++ break; ++ case PIN_CONFIG_INPUT_ENABLE: ++ mask |= TH1520_PADCFG_IE; ++ if (arg) ++ value |= TH1520_PADCFG_IE; ++ else ++ value &= ~TH1520_PADCFG_IE; ++ break; ++ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ++ mask |= TH1520_PADCFG_ST; ++ if (arg) ++ value |= TH1520_PADCFG_ST; ++ else ++ value &= ~TH1520_PADCFG_ST; ++ break; ++ case PIN_CONFIG_SLEW_RATE: ++ mask |= TH1520_PADCFG_SL; ++ if (arg) ++ value |= TH1520_PADCFG_SL; ++ else ++ value &= ~TH1520_PADCFG_SL; ++ break; ++ default: ++ return -ENOTSUPP; ++ } ++ } ++ ++ return th1520_padcfg_rmw(thp, pin, mask, value); ++} ++ ++static int th1520_pinconf_group_set(struct pinctrl_dev *pctldev, ++ unsigned int gsel, ++ unsigned long *configs, ++ unsigned int num_configs) ++{ ++ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); ++ unsigned int pin = thp->desc.pinsgsel.number; ++ ++ return th1520_pinconf_set(pctldev, pin, configs, num_configs); ++} ++ ++#ifdef CONFIG_DEBUG_FS ++static void th1520_pinconf_dbg_show(struct pinctrl_dev *pctldev, ++ struct seq_file *s, unsigned int pin) ++{ ++ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); ++ u32 value = readl_relaxed(th1520_padcfg(thp, pin)); ++ ++ value = (value >> th1520_padcfg_shift(pin)) & GENMASK(9, 0); ++ ++ seq_printf(s, " 0x%03x", value); ++} ++#else ++#define th1520_pinconf_dbg_show NULL ++#endif ++ ++static const struct pinconf_ops th1520_pinconf_ops = { ++ .pin_config_get = th1520_pinconf_get, ++ .pin_config_group_get = th1520_pinconf_group_get, ++ .pin_config_set = th1520_pinconf_set, ++ .pin_config_group_set = th1520_pinconf_group_set, ++ .pin_config_dbg_show = th1520_pinconf_dbg_show, ++ .is_generic = true, ++}; ++ ++static int th1520_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ const struct th1520_pad_group *group = device_get_match_data(dev); ++ struct th1520_pinctrl *thp; ++ struct clk *clk; ++ int ret; ++ ++ thp = devm_kzalloc(dev, sizeof(*thp), GFP_KERNEL); ++ if (!thp) ++ return -ENOMEM; ++ ++ thp->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(thp->base)) ++ return PTR_ERR(thp->base); ++ ++ clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(clk)) ++ return dev_err_probe(dev, PTR_ERR(clk), "error getting clock\n"); ++ ++ thp->desc.name = group->name; ++ thp->desc.pins = group->pins; ++ thp->desc.npins = group->npins; ++ thp->desc.pctlops = &th1520_pinctrl_ops; ++ thp->desc.pmxops = &th1520_pinmux_ops; ++ thp->desc.confops = &th1520_pinconf_ops; ++ thp->desc.owner = THIS_MODULE; ++ mutex_init(&thp->mutex); ++ raw_spin_lock_init(&thp->lock); ++ ++ ret = devm_pinctrl_register_and_init(dev, &thp->desc, thp, &thp->pctl); ++ if (ret) ++ return dev_err_probe(dev, ret, "could not register pinctrl driver\n"); ++ ++ return pinctrl_enable(thp->pctl); ++} ++ ++static const struct of_device_id th1520_pinctrl_of_match = { ++ { .compatible = "thead,th1520-group1-pinctrl", .data = &th1520_group1 }, ++ { .compatible = "thead,th1520-group2-pinctrl", .data = &th1520_group2 }, ++ { .compatible = "thead,th1520-group3-pinctrl", .data = &th1520_group3 }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, th1520_pinctrl_of_match); ++ ++static struct platform_driver th1520_pinctrl_driver = { ++ .probe = th1520_pinctrl_probe, ++ .driver = { ++ .name = "pinctrl-th1520", ++ .of_match_table = th1520_pinctrl_of_match, ++ }, ++}; ++module_platform_driver(th1520_pinctrl_driver); ++ ++MODULE_DESCRIPTION("Pinctrl driver for the T-Head TH1520 SoC"); ++MODULE_AUTHOR("Emil Renner Berthing <emil.renner.berthing@canonical.com>"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/pinctrl/sophgo/Makefile b/drivers/pinctrl/sophgo/Makefile +new file mode 100644 +index 000000000000..2f2cd0d5a99d +--- /dev/null ++++ b/drivers/pinctrl/sophgo/Makefile +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_ARCH_SOPHGO) += pinctrl-sophgo.o ++obj-$(CONFIG_ARCH_SOPHGO) += pinctrl-mango.o +diff --git a/drivers/pinctrl/sophgo/pinctrl-mango.c b/drivers/pinctrl/sophgo/pinctrl-mango.c +new file mode 100644 +index 000000000000..8e7bd08a73db +--- /dev/null ++++ b/drivers/pinctrl/sophgo/pinctrl-mango.c +@@ -0,0 +1,453 @@ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/pinctrl/pinconf.h> ++#include <linux/pinctrl/pinconf-generic.h> ++#include <linux/device.h> ++#include <linux/of.h> ++ ++#include "../pinctrl-utils.h" ++#include "pinctrl-sophgo.h" ++ ++#define DRV_PINCTRL_NAME "mango_pinctrl" ++#define DRV_PINMUX_NAME "mango_pinmux" ++ ++#define FUNCTION(fname, gname, fmode) \ ++ { \ ++ .name = #fname, \ ++ .groups = gname##_group, \ ++ .num_groups = ARRAY_SIZE(gname##_group), \ ++ .mode = fmode, \ ++ } ++ ++#define PIN_GROUP(gname) \ ++ { \ ++ .name = #gname "_grp", \ ++ .pins = gname##_pins, \ ++ .num_pins = ARRAY_SIZE(gname##_pins), \ ++ } ++ ++static const struct pinctrl_pin_desc mango_pins = { ++ PINCTRL_PIN(0, "MIO0"), ++ PINCTRL_PIN(1, "MIO1"), ++ PINCTRL_PIN(2, "MIO2"), ++ PINCTRL_PIN(3, "MIO3"), ++ PINCTRL_PIN(4, "MIO4"), ++ PINCTRL_PIN(5, "MIO5"), ++ PINCTRL_PIN(6, "MIO6"), ++ PINCTRL_PIN(7, "MIO7"), ++ PINCTRL_PIN(8, "MIO8"), ++ PINCTRL_PIN(9, "MIO9"), ++ PINCTRL_PIN(10, "MIO10"), ++ PINCTRL_PIN(11, "MIO11"), ++ PINCTRL_PIN(12, "MIO12"), ++ PINCTRL_PIN(13, "MIO13"), ++ PINCTRL_PIN(14, "MIO14"), ++ PINCTRL_PIN(15, "MIO15"), ++ PINCTRL_PIN(16, "MIO16"), ++ PINCTRL_PIN(17, "MIO17"), ++ PINCTRL_PIN(18, "MIO18"), ++ PINCTRL_PIN(19, "MIO19"), ++ PINCTRL_PIN(20, "MIO20"), ++ PINCTRL_PIN(21, "MIO21"), ++ PINCTRL_PIN(22, "MIO22"), ++ PINCTRL_PIN(23, "MIO23"), ++ PINCTRL_PIN(24, "MIO24"), ++ PINCTRL_PIN(25, "MIO25"), ++ PINCTRL_PIN(26, "MIO26"), ++ PINCTRL_PIN(27, "MIO27"), ++ PINCTRL_PIN(28, "MIO28"), ++ PINCTRL_PIN(29, "MIO29"), ++ PINCTRL_PIN(30, "MIO30"), ++ PINCTRL_PIN(31, "MIO31"), ++ PINCTRL_PIN(32, "MIO32"), ++ PINCTRL_PIN(33, "MIO33"), ++ PINCTRL_PIN(34, "MIO34"), ++ PINCTRL_PIN(35, "MIO35"), ++ PINCTRL_PIN(36, "MIO36"), ++ PINCTRL_PIN(37, "MIO37"), ++ PINCTRL_PIN(38, "MIO38"), ++ PINCTRL_PIN(39, "MIO39"), ++ PINCTRL_PIN(40, "MIO40"), ++ PINCTRL_PIN(41, "MIO41"), ++ PINCTRL_PIN(42, "MIO42"), ++ PINCTRL_PIN(43, "MIO43"), ++ PINCTRL_PIN(44, "MIO44"), ++ PINCTRL_PIN(45, "MIO45"), ++ PINCTRL_PIN(46, "MIO46"), ++ PINCTRL_PIN(47, "MIO47"), ++ PINCTRL_PIN(48, "MIO48"), ++ PINCTRL_PIN(49, "MIO49"), ++ PINCTRL_PIN(50, "MIO50"), ++ PINCTRL_PIN(51, "MIO51"), ++ PINCTRL_PIN(52, "MIO52"), ++ PINCTRL_PIN(53, "MIO53"), ++ PINCTRL_PIN(54, "MIO54"), ++ PINCTRL_PIN(55, "MIO55"), ++ PINCTRL_PIN(56, "MIO56"), ++ PINCTRL_PIN(57, "MIO57"), ++ PINCTRL_PIN(58, "MIO58"), ++ PINCTRL_PIN(59, "MIO59"), ++ PINCTRL_PIN(60, "MIO60"), ++ PINCTRL_PIN(61, "MIO61"), ++ PINCTRL_PIN(62, "MIO62"), ++ PINCTRL_PIN(63, "MIO63"), ++ PINCTRL_PIN(64, "MIO64"), ++ PINCTRL_PIN(65, "MIO65"), ++ PINCTRL_PIN(66, "MIO66"), ++ PINCTRL_PIN(67, "MIO67"), ++ PINCTRL_PIN(68, "MIO68"), ++ PINCTRL_PIN(69, "MIO69"), ++ PINCTRL_PIN(70, "MIO70"), ++ PINCTRL_PIN(71, "MIO71"), ++ PINCTRL_PIN(72, "MIO72"), ++ PINCTRL_PIN(73, "MIO73"), ++ PINCTRL_PIN(74, "MIO74"), ++ PINCTRL_PIN(75, "MIO75"), ++ PINCTRL_PIN(76, "MIO76"), ++ PINCTRL_PIN(77, "MIO77"), ++ PINCTRL_PIN(78, "MIO78"), ++ PINCTRL_PIN(79, "MIO79"), ++ PINCTRL_PIN(80, "MIO80"), ++ PINCTRL_PIN(81, "MIO81"), ++ PINCTRL_PIN(82, "MIO82"), ++ PINCTRL_PIN(83, "MIO83"), ++ PINCTRL_PIN(84, "MIO84"), ++ PINCTRL_PIN(85, "MIO85"), ++ PINCTRL_PIN(86, "MIO86"), ++ PINCTRL_PIN(87, "MIO87"), ++ PINCTRL_PIN(88, "MIO88"), ++ PINCTRL_PIN(89, "MIO89"), ++ PINCTRL_PIN(90, "MIO90"), ++ PINCTRL_PIN(91, "MIO91"), ++ PINCTRL_PIN(92, "MIO92"), ++ PINCTRL_PIN(93, "MIO93"), ++ PINCTRL_PIN(94, "MIO94"), ++ PINCTRL_PIN(95, "MIO95"), ++ PINCTRL_PIN(96, "MIO96"), ++ PINCTRL_PIN(97, "MIO97"), ++ PINCTRL_PIN(98, "MIO98"), ++ PINCTRL_PIN(99, "MIO99"), ++ PINCTRL_PIN(100, "MIO100"), ++ PINCTRL_PIN(101, "MIO101"), ++ PINCTRL_PIN(102, "MIO102"), ++ PINCTRL_PIN(103, "MIO103"), ++ PINCTRL_PIN(104, "MIO104"), ++ PINCTRL_PIN(105, "MIO105"), ++ PINCTRL_PIN(106, "MIO106"), ++ PINCTRL_PIN(107, "MIO107"), ++ PINCTRL_PIN(108, "MIO108"), ++ PINCTRL_PIN(109, "MIO109"), ++ PINCTRL_PIN(110, "MIO110"), ++ PINCTRL_PIN(111, "MIO111"), ++ PINCTRL_PIN(112, "MIO112"), ++ PINCTRL_PIN(113, "MIO113"), ++ PINCTRL_PIN(114, "MIO114"), ++ PINCTRL_PIN(115, "MIO115"), ++ PINCTRL_PIN(116, "MIO116"), ++ PINCTRL_PIN(117, "MIO117"), ++ PINCTRL_PIN(118, "MIO118"), ++ PINCTRL_PIN(119, "MIO119"), ++ PINCTRL_PIN(120, "MIO120"), ++ PINCTRL_PIN(121, "MIO121"), ++ PINCTRL_PIN(122, "MIO122"), ++ PINCTRL_PIN(123, "MIO123"), ++ PINCTRL_PIN(124, "MIO124"), ++ PINCTRL_PIN(125, "MIO125"), ++ PINCTRL_PIN(126, "MIO126"), ++ PINCTRL_PIN(127, "MIO127"), ++ PINCTRL_PIN(128, "MIO128"), ++ PINCTRL_PIN(129, "MIO129"), ++ PINCTRL_PIN(130, "MIO130"), ++ PINCTRL_PIN(131, "MIO131"), ++ PINCTRL_PIN(132, "MIO132"), ++ PINCTRL_PIN(133, "MIO133"), ++ PINCTRL_PIN(134, "MIO134"), ++ PINCTRL_PIN(135, "MIO135"), ++ PINCTRL_PIN(136, "MIO136"), ++ PINCTRL_PIN(137, "MIO137"), ++ PINCTRL_PIN(138, "MIO138"), ++ PINCTRL_PIN(139, "MIO139"), ++ PINCTRL_PIN(140, "MIO140"), ++ PINCTRL_PIN(141, "MIO141"), ++ PINCTRL_PIN(142, "MIO142"), ++ PINCTRL_PIN(143, "MIO143"), ++ PINCTRL_PIN(144, "MIO144"), ++ PINCTRL_PIN(145, "MIO145"), ++ PINCTRL_PIN(146, "MIO146"), ++ PINCTRL_PIN(147, "MIO147"), ++ PINCTRL_PIN(148, "MIO148"), ++ PINCTRL_PIN(149, "MIO149"), ++ PINCTRL_PIN(150, "MIO150"), ++ PINCTRL_PIN(151, "MIO151"), ++ PINCTRL_PIN(152, "MIO152"), ++ PINCTRL_PIN(153, "MIO153"), ++ PINCTRL_PIN(154, "MIO154"), ++ PINCTRL_PIN(155, "MIO155"), ++ PINCTRL_PIN(156, "MIO156"), ++}; ++ ++static const unsigned int lpc_pins = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; ++static const unsigned int pcie_pins = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; ++static const unsigned int spif_pins = {25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40}; ++static const unsigned int emmc_pins = {41, 42, 43, 44}; ++static const unsigned int sdio_pins = {45, 46, 47, 48}; ++static const unsigned int eth0_pins = {49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}; ++static const unsigned int pwm0_pins = {65}; ++static const unsigned int pwm1_pins = {66}; ++static const unsigned int pwm2_pins = {67}; ++static const unsigned int pwm3_pins = {68}; ++static const unsigned int fan0_pins = {69}; ++static const unsigned int fan1_pins = {70}; ++static const unsigned int fan2_pins = {71}; ++static const unsigned int fan3_pins = {72}; ++static const unsigned int i2c0_pins = {73, 74}; ++static const unsigned int i2c1_pins = {75, 76}; ++static const unsigned int i2c2_pins = {77, 78}; ++static const unsigned int i2c3_pins = {79, 80}; ++static const unsigned int uart0_pins = {81, 82, 83, 84}; ++static const unsigned int uart1_pins = {85, 86, 87, 88}; ++static const unsigned int uart2_pins = {89, 90, 91, 92}; ++static const unsigned int uart3_pins = {93, 94, 95, 96}; ++static const unsigned int spi0_pins = {97, 98, 99, 100, 101}; ++static const unsigned int spi1_pins = {102, 103, 104, 105, 106}; ++static const unsigned int jtag0_pins = {107, 108, 109, 110, 111, 112}; ++static const unsigned int jtag1_pins = {113, 114, 115, 116, 117, 118}; ++static const unsigned int jtag2_pins = {119, 120, 121, 122, 123, 124}; ++static const unsigned int gpio0_pins = {125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,\ ++ 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,\ ++ 151, 152, 153}; ++static const unsigned int dbgi2c_pins = {154, 155, 156}; ++ ++static const char * const lpc_group = {"lpc_grp"}; ++static const char * const pcie_group = {"pcie_grp"}; ++static const char * const spif_group = {"spif_grp"}; ++static const char * const emmc_group = {"emmc_grp"}; ++static const char * const sdio_group = {"sdio_grp"}; ++static const char * const eth0_group = {"eth0_grp"}; ++static const char * const pwm0_group = {"pwm0_grp"}; ++static const char * const pwm1_group = {"pwm1_grp"}; ++static const char * const pwm2_group = {"pwm2_grp"}; ++static const char * const pwm3_group = {"pwm3_grp"}; ++static const char * const fan0_group = {"fan0_grp"}; ++static const char * const fan1_group = {"fan1_grp"}; ++static const char * const fan2_group = {"fan2_grp"}; ++static const char * const fan3_group = {"fan3_grp"}; ++static const char * const i2c0_group = {"i2c0_grp"}; ++static const char * const i2c1_group = {"i2c1_grp"}; ++static const char * const i2c2_group = {"i2c2_grp"}; ++static const char * const i2c3_group = {"i2c3_grp"}; ++static const char * const uart0_group = {"uart0_grp"}; ++static const char * const uart1_group = {"uart1_grp"}; ++static const char * const uart2_group = {"uart2_grp"}; ++static const char * const uart3_group = {"uart3_grp"}; ++static const char * const spi0_group = {"spi0_grp"}; ++static const char * const spi1_group = {"spi1_grp"}; ++static const char * const jtag0_group = {"jtag0_grp"}; ++static const char * const jtag1_group = {"jtag1_grp"}; ++static const char * const jtag2_group = {"jtag2_grp"}; ++static const char * const gpio0_group = {"gpio0_grp"}; ++static const char * const dbgi2c_group = {"dbgi2c_grp"}; ++ ++static struct mango_group mango_groups = { ++ PIN_GROUP(lpc), ++ PIN_GROUP(pcie), ++ PIN_GROUP(spif), ++ PIN_GROUP(emmc), ++ PIN_GROUP(sdio), ++ PIN_GROUP(eth0), ++ PIN_GROUP(pwm0), ++ PIN_GROUP(pwm1), ++ PIN_GROUP(pwm2), ++ PIN_GROUP(pwm3), ++ PIN_GROUP(fan0), ++ PIN_GROUP(fan1), ++ PIN_GROUP(fan2), ++ PIN_GROUP(fan3), ++ PIN_GROUP(i2c0), ++ PIN_GROUP(i2c1), ++ PIN_GROUP(i2c2), ++ PIN_GROUP(i2c3), ++ PIN_GROUP(uart0), ++ PIN_GROUP(uart1), ++ PIN_GROUP(uart2), ++ PIN_GROUP(uart3), ++ PIN_GROUP(spi0), ++ PIN_GROUP(spi1), ++ PIN_GROUP(jtag0), ++ PIN_GROUP(jtag1), ++ PIN_GROUP(jtag2), ++ PIN_GROUP(gpio0), ++ PIN_GROUP(dbgi2c), ++}; ++ ++static const struct mango_pmx_func mango_funcs = { ++ FUNCTION(lpc_a, lpc, FUNC_MODE0), ++ FUNCTION(lpc_r, lpc, FUNC_MODE1), ++ FUNCTION(pcie_a, pcie, FUNC_MODE0), ++ FUNCTION(pcie_r, pcie, FUNC_MODE1), ++ FUNCTION(spif_a, spif, FUNC_MODE0), ++ FUNCTION(spif_r, spif, FUNC_MODE1), ++ FUNCTION(emmc_a, emmc, FUNC_MODE0), ++ FUNCTION(emmc_r, emmc, FUNC_MODE1), ++ FUNCTION(sdio_a, sdio, FUNC_MODE0), ++ FUNCTION(sdio_r, sdio, FUNC_MODE1), ++ FUNCTION(eth0_a, eth0, FUNC_MODE1), ++ FUNCTION(eth0_r, eth0, FUNC_MODE0), ++ FUNCTION(pwm0_a, pwm0, FUNC_MODE0), ++ FUNCTION(pwm0_r, pwm0, FUNC_MODE1), ++ FUNCTION(pwm1_a, pwm1, FUNC_MODE0), ++ FUNCTION(pwm1_r, pwm1, FUNC_MODE1), ++ FUNCTION(pwm2_a, pwm2, FUNC_MODE0), ++ FUNCTION(pwm2_r, pwm2, FUNC_MODE1), ++ FUNCTION(pwm3_a, pwm3, FUNC_MODE0), ++ FUNCTION(pwm3_r, pwm3, FUNC_MODE1), ++ FUNCTION(fan0_a, fan0, FUNC_MODE1), ++ FUNCTION(fan0_r, fan0, FUNC_MODE0), ++ FUNCTION(fan1_a, fan1, FUNC_MODE1), ++ FUNCTION(fan1_r, fan1, FUNC_MODE0), ++ FUNCTION(fan2_a, fan2, FUNC_MODE1), ++ FUNCTION(fan2_r, fan2, FUNC_MODE0), ++ FUNCTION(fan3_a, fan3, FUNC_MODE1), ++ FUNCTION(fan3_r, fan3, FUNC_MODE0), ++ FUNCTION(i2c0_a, i2c0, FUNC_MODE0), ++ FUNCTION(i2c0_r, i2c0, FUNC_MODE1), ++ FUNCTION(i2c1_a, i2c1, FUNC_MODE0), ++ FUNCTION(i2c1_r, i2c1, FUNC_MODE1), ++ FUNCTION(i2c2_a, i2c2, FUNC_MODE1), ++ FUNCTION(i2c2_r, i2c2, FUNC_MODE0), ++ FUNCTION(i2c3_a, i2c3, FUNC_MODE1), ++ FUNCTION(i2c3_r, i2c3, FUNC_MODE0), ++ FUNCTION(uart0_a, uart0, FUNC_MODE0), ++ FUNCTION(uart0_r, uart0, FUNC_MODE1), ++ FUNCTION(uart1_a, uart1, FUNC_MODE0), ++ FUNCTION(uart1_r, uart1, FUNC_MODE1), ++ FUNCTION(uart2_a, uart2, FUNC_MODE1), ++ FUNCTION(uart2_r, uart2, FUNC_MODE0), ++ FUNCTION(uart3_a, uart3, FUNC_MODE1), ++ FUNCTION(uart3_r, uart3, FUNC_MODE0), ++ FUNCTION(spi0_a, spi0, FUNC_MODE1), ++ FUNCTION(spi0_r, spi0, FUNC_MODE0), ++ FUNCTION(spi1_a, spi1, FUNC_MODE0), ++ FUNCTION(spi1_r, spi1, FUNC_MODE1), ++ FUNCTION(jtag0_a, jtag0, FUNC_MODE0), ++ FUNCTION(jtag0_r, jtag0, FUNC_MODE1), ++ FUNCTION(jtag1_a, jtag1, FUNC_MODE1), ++ FUNCTION(jtag1_r, jtag1, FUNC_MODE0), ++ FUNCTION(jtag2_a, jtag2, FUNC_MODE1), ++ FUNCTION(jtag2_r, jtag2, FUNC_MODE0), ++ FUNCTION(gpio0_a, gpio0, FUNC_MODE1), ++ FUNCTION(gpio0_r, gpio0, FUNC_MODE0), ++ FUNCTION(dbgi2c_a, dbgi2c, FUNC_MODE0), ++ FUNCTION(dbgi2c_r, dbgi2c, FUNC_MODE1), ++}; ++ ++static struct device_attribute lpc_attr = __ATTR(lpc, 0664, pinmux_show, pinmux_store); ++static struct device_attribute pcie_attr = __ATTR(pcie, 0664, pinmux_show, pinmux_store); ++static struct device_attribute spif_attr = __ATTR(spif, 0664, pinmux_show, pinmux_store); ++static struct device_attribute emmc_attr = __ATTR(emmc, 0664, pinmux_show, pinmux_store); ++static struct device_attribute sdio_attr = __ATTR(sdio, 0664, pinmux_show, pinmux_store); ++static struct device_attribute eth0_attr = __ATTR(eth0, 0664, pinmux_show, pinmux_store); ++static struct device_attribute pwm0_attr = __ATTR(pwm0, 0664, pinmux_show, pinmux_store); ++static struct device_attribute pwm1_attr = __ATTR(pwm1, 0664, pinmux_show, pinmux_store); ++static struct device_attribute pwm2_attr = __ATTR(pwm2, 0664, pinmux_show, pinmux_store); ++static struct device_attribute pwm3_attr = __ATTR(pwm3, 0664, pinmux_show, pinmux_store); ++static struct device_attribute fan0_attr = __ATTR(fan0, 0664, pinmux_show, pinmux_store); ++static struct device_attribute fan1_attr = __ATTR(fan1, 0664, pinmux_show, pinmux_store); ++static struct device_attribute fan2_attr = __ATTR(fan2, 0664, pinmux_show, pinmux_store); ++static struct device_attribute fan3_attr = __ATTR(fan3, 0664, pinmux_show, pinmux_store); ++static struct device_attribute i2c0_attr = __ATTR(i2c0, 0664, pinmux_show, pinmux_store); ++static struct device_attribute i2c1_attr = __ATTR(i2c1, 0664, pinmux_show, pinmux_store); ++static struct device_attribute i2c2_attr = __ATTR(i2c2, 0664, pinmux_show, pinmux_store); ++static struct device_attribute i2c3_attr = __ATTR(i2c3, 0664, pinmux_show, pinmux_store); ++static struct device_attribute uart0_attr = __ATTR(uart0, 0664, pinmux_show, pinmux_store); ++static struct device_attribute uart1_attr = __ATTR(uart1, 0664, pinmux_show, pinmux_store); ++static struct device_attribute uart2_attr = __ATTR(uart2, 0664, pinmux_show, pinmux_store); ++static struct device_attribute uart3_attr = __ATTR(uart3, 0664, pinmux_show, pinmux_store); ++static struct device_attribute spi0_attr = __ATTR(spi0, 0664, pinmux_show, pinmux_store); ++static struct device_attribute spi1_attr = __ATTR(spi1, 0664, pinmux_show, pinmux_store); ++static struct device_attribute jtag0_attr = __ATTR(jtag0, 0664, pinmux_show, pinmux_store); ++static struct device_attribute jtag1_attr = __ATTR(jtag1, 0664, pinmux_show, pinmux_store); ++static struct device_attribute jtag2_attr = __ATTR(jtag2, 0664, pinmux_show, pinmux_store); ++static struct device_attribute gpio0_attr = __ATTR(gpio0, 0664, pinmux_show, pinmux_store); ++static struct device_attribute dbgi2c_attr = __ATTR(dbgi2c, 0664, pinmux_show, pinmux_store); ++ ++ ++static struct attribute *pinmux_attrs = { ++ &lpc_attr.attr, ++ &pcie_attr.attr, ++ &spif_attr.attr, ++ &emmc_attr.attr, ++ &sdio_attr.attr, ++ ð0_attr.attr, ++ &pwm0_attr.attr, ++ &pwm1_attr.attr, ++ &pwm2_attr.attr, ++ &pwm3_attr.attr, ++ &fan0_attr.attr, ++ &fan1_attr.attr, ++ &fan2_attr.attr, ++ &fan3_attr.attr, ++ &i2c0_attr.attr, ++ &i2c1_attr.attr, ++ &i2c2_attr.attr, ++ &i2c3_attr.attr, ++ &uart0_attr.attr, ++ &uart1_attr.attr, ++ &uart2_attr.attr, ++ &uart3_attr.attr, ++ &spi0_attr.attr, ++ &spi1_attr.attr, ++ &jtag0_attr.attr, ++ &jtag1_attr.attr, ++ &jtag2_attr.attr, ++ &gpio0_attr.attr, ++ &dbgi2c_attr.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(pinmux); ++ ++static struct class pinmux_class = { ++ .name = "pinmux", ++ .dev_groups = pinmux_groups, ++}; ++ ++static struct mango_soc_pinctrl_data mango_pinctrl_data = { ++ .pins = mango_pins, ++ .npins = ARRAY_SIZE(mango_pins), ++ .groups = mango_groups, ++ .groups_count = ARRAY_SIZE(mango_groups), ++ .functions = mango_funcs, ++ .functions_count = ARRAY_SIZE(mango_funcs), ++ .p_class = &pinmux_class, ++}; ++ ++static const struct of_device_id mango_pinctrl_of_table = { ++ { ++ .compatible = "sophgo, pinctrl-mango", ++ .data = &mango_pinctrl_data, ++ }, ++ {} ++}; ++ ++static int mango_pinctrl_probe(struct platform_device *pdev) ++{ ++ return sophgo_pinctrl_probe(pdev); ++} ++ ++static struct platform_driver mango_pinctrl_driver = { ++ .probe = mango_pinctrl_probe, ++ .driver = { ++ .name = DRV_PINCTRL_NAME, ++ .of_match_table = of_match_ptr(mango_pinctrl_of_table), ++ }, ++}; ++ ++static int __init mango_pinctrl_init(void) ++{ ++ return platform_driver_register(&mango_pinctrl_driver); ++} ++postcore_initcall(mango_pinctrl_init); +diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.c b/drivers/pinctrl/sophgo/pinctrl-sophgo.c +new file mode 100644 +index 000000000000..0862177d4144 +--- /dev/null ++++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.c +@@ -0,0 +1,292 @@ ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/of_device.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> ++ ++#include "pinctrl-sophgo.h" ++ ++ ++static int mango_get_groups(struct pinctrl_dev *pctldev, unsigned int selector, ++ const char * const **groups, ++ unsigned int * const num_groups); ++ ++static struct mango_soc_pinctrl_data *get_pinmux_data(struct pinctrl_dev *pctldev) ++{ ++ struct mango_pinctrl *mangopctrl = pinctrl_dev_get_drvdata(pctldev); ++ ++ return mangopctrl->data; ++} ++ ++static int mango_get_functions_count(struct pinctrl_dev *pctldev) ++{ ++ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); ++ ++ return data->functions_count; ++} ++ ++static const char *mango_get_fname(struct pinctrl_dev *pctldev, ++ unsigned int selector) ++{ ++ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); ++ ++ return data->functionsselector.name; ++} ++ ++static int mango_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, ++ unsigned int group) ++{ ++ int p; ++ unsigned int pidx; ++ u32 offset, regval, mux_offset; ++ struct mango_pinctrl *ctrl = pinctrl_dev_get_drvdata(pctldev); ++ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); ++ ++ data->groupsgroup.cur_func_idx = data->functionsselector.mode; ++ for (p = 0; p < data->groupsgroup.num_pins; p++) { ++ pidx = data->groupsgroup.pinsp; ++ offset = (pidx >> 1) << 2; ++ regmap_read(ctrl->syscon_pinctl, ++ ctrl->top_pinctl_offset + offset, ®val); ++ mux_offset = ((!((pidx + 1) & 1) << 4) + 4); ++ ++ regval = regval & ~(3 << mux_offset); ++ regval |= data->functionsselector.mode << mux_offset; ++ regmap_write(ctrl->syscon_pinctl, ++ ctrl->top_pinctl_offset + offset, regval); ++ regmap_read(ctrl->syscon_pinctl, ++ ctrl->top_pinctl_offset + offset, ®val); ++ dev_dbg(ctrl->dev, "%s : check new reg=0x%x val=0x%x\n", ++ data->groupsgroup.name, ++ ctrl->top_pinctl_offset + offset, regval); ++ } ++ ++ return 0; ++} ++ ++static const struct pinmux_ops mango_pinmux_ops = { ++ .get_functions_count = mango_get_functions_count, ++ .get_function_name = mango_get_fname, ++ .get_function_groups = mango_get_groups, ++ .set_mux = mango_set_mux, ++ .strict = true, ++}; ++ ++static int mango_pinconf_cfg_get(struct pinctrl_dev *pctldev, unsigned int pin, ++ unsigned long *config) ++{ ++ return 0; ++} ++ ++static int mango_pinconf_cfg_set(struct pinctrl_dev *pctldev, unsigned int pin, ++ unsigned long *configs, unsigned int num_configs) ++{ ++ return 0; ++} ++ ++static int mango_pinconf_group_set(struct pinctrl_dev *pctldev, ++ unsigned int selector, unsigned long *configs, unsigned int num_configs) ++{ ++ return 0; ++} ++ ++static const struct pinconf_ops mango_pinconf_ops = { ++ .is_generic = true, ++ .pin_config_get = mango_pinconf_cfg_get, ++ .pin_config_set = mango_pinconf_cfg_set, ++ .pin_config_group_set = mango_pinconf_group_set, ++}; ++ ++static int mango_get_groups(struct pinctrl_dev *pctldev, unsigned int selector, ++ const char * const **groups, ++ unsigned int * const num_groups) ++{ ++ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); ++ ++ *groups = data->functionsselector.groups; ++ *num_groups = data->functionsselector.num_groups; ++ ++ return 0; ++} ++ ++static int mango_get_groups_count(struct pinctrl_dev *pctldev) ++{ ++ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); ++ ++ return data->groups_count; ++} ++ ++static const char *mango_get_group_name(struct pinctrl_dev *pctldev, ++ unsigned int selector) ++{ ++ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); ++ ++ return data->groupsselector.name; ++} ++ ++static int mango_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, ++ const unsigned int **pins, ++ unsigned int *num_pins) ++{ ++ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); ++ ++ *pins = data->groupsselector.pins; ++ *num_pins = data->groupsselector.num_pins; ++ ++ return 0; ++} ++ ++static void mango_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, ++ unsigned int offset) ++{ ++} ++ ++static const struct pinctrl_ops mango_pctrl_ops = { ++ .get_groups_count = mango_get_groups_count, ++ .get_group_name = mango_get_group_name, ++ .get_group_pins = mango_get_group_pins, ++ .pin_dbg_show = mango_pin_dbg_show, ++ .dt_node_to_map = pinconf_generic_dt_node_to_map_all, ++ .dt_free_map = pinctrl_utils_free_map, ++}; ++ ++static struct pinctrl_desc mango_desc = { ++ .name = "mango_pinctrl", ++ .pctlops = &mango_pctrl_ops, ++ .pmxops = &mango_pinmux_ops, ++ .confops = &mango_pinconf_ops, ++ .owner = THIS_MODULE, ++}; ++ ++ssize_t pinmux_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mango_pinctrl *mangopctrl; ++ int p, ret, group, selector = -1; ++ struct mango_soc_pinctrl_data *data; ++ ++ mangopctrl = dev_get_drvdata(dev); ++ data = (struct mango_soc_pinctrl_data *)mangopctrl->data; ++ ++ for (p = 0; p < data->functions_count; p++) { ++ if (!strncmp(attr->attr.name, data->functionsp.name, ++ strlen(attr->attr.name))) { ++ selector = p; ++ break; ++ } ++ } ++ if (selector < 0) ++ return -ENXIO; ++ ++ group = selector/2; ++ ret = snprintf(buf, 128, "%d\n", data->groupsgroup.cur_func_idx); ++ if (ret <= 0 || ret > 128) { ++ dev_err(dev, "snprintf failed %d\n", ret); ++ return -EFAULT; ++ } ++ return ret; ++} ++ ++ssize_t pinmux_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct mango_pinctrl *mangopctrl; ++ int p, ret, group, selector = -1; ++ unsigned long user_data; ++ struct mango_soc_pinctrl_data *data; ++ ++ ret = kstrtoul(buf, 0, &user_data); ++ if (ret) ++ return -EINVAL; ++ ++ if (user_data != 0 && user_data != 1) ++ return -EINVAL; ++ ++ mangopctrl = dev_get_drvdata(dev); ++ data = (struct mango_soc_pinctrl_data *)mangopctrl->data; ++ ++ for (p = 0; p < data->functions_count; p++) { ++ if (!strncmp(attr->attr.name, data->functionsp.name, ++ strlen(attr->attr.name)) && ++ (user_data == data->functionsp.mode)) { ++ selector = p; ++ break; ++ } ++ } ++ if (selector < 0) ++ return -ENXIO; ++ ++ group = selector/2; ++ mango_set_mux(mangopctrl->pctl, selector, group); ++ ++ dev_info(dev, "pinmux store set %s to func %d\n", ++ attr->attr.name, data->functionsselector.mode); ++ return size; ++} ++ ++ ++int sophgo_pinctrl_probe(struct platform_device *pdev) ++{ ++ struct mango_pinctrl *mangopctrl; ++ struct pinctrl_desc *desc; ++ struct mango_soc_pinctrl_data *data; ++ struct device *dev = &pdev->dev; ++ struct device *pin_dev = NULL; ++ struct device_node *np = dev->of_node, *np_top; ++ static struct regmap *syscon; ++ int ret; ++ ++ data = (struct mango_soc_pinctrl_data *)of_device_get_match_data(&pdev->dev); ++ if (!data) ++ return -EINVAL; ++ mangopctrl = devm_kzalloc(&pdev->dev, sizeof(*mangopctrl), GFP_KERNEL); ++ if (!mangopctrl) ++ return -ENOMEM; ++ ++ mangopctrl->dev = &pdev->dev; ++ ++ np_top = of_parse_phandle(np, "subctrl-syscon", 0); ++ if (!np_top) { ++ dev_err(dev, "%s can't get subctrl-syscon node\n", __func__); ++ return -EINVAL; ++ } ++ syscon = syscon_node_to_regmap(np_top); ++ if (IS_ERR(syscon)) { ++ dev_err(dev, "cannot get regmap\n"); ++ return PTR_ERR(syscon); ++ } ++ mangopctrl->syscon_pinctl = syscon; ++ ++ ret = device_property_read_u32(&pdev->dev, ++ "top_pinctl_offset", &mangopctrl->top_pinctl_offset); ++ if (ret < 0) { ++ dev_err(dev, "cannot get top_pinctl_offset\n"); ++ return ret; ++ } ++ ++ desc = &mango_desc; ++ desc->pins = data->pins; ++ desc->npins = data->npins; ++ ++ mangopctrl->data = (void *)data; ++ mangopctrl->pctl = devm_pinctrl_register(&pdev->dev, desc, mangopctrl); ++ if (IS_ERR(mangopctrl->pctl)) { ++ dev_err(&pdev->dev, "could not register Sophgo pin ctrl driver\n"); ++ return PTR_ERR(mangopctrl->pctl); ++ } ++ ++ platform_set_drvdata(pdev, mangopctrl); ++ ++ ret = class_register(data->p_class); ++ if (ret < 0) { ++ dev_err(dev, "cannot register pinmux class\n"); ++ return ret; ++ } ++ pin_dev = device_create(data->p_class, &pdev->dev, MKDEV(0, 0), mangopctrl, "mango_pinmux"); ++ if (IS_ERR(pin_dev)) ++ return PTR_ERR(pin_dev); ++ ++ return 0; ++} +diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.h b/drivers/pinctrl/sophgo/pinctrl-sophgo.h +new file mode 100644 +index 000000000000..f3a30f0275b1 +--- /dev/null ++++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.h +@@ -0,0 +1,70 @@ ++#ifndef __mango_PINCTRL_CORE_H__ ++#define __mango_PINCTRL_CORE_H__ ++ ++#include <linux/pinctrl/pinctrl.h> ++#include <linux/pinctrl/pinmux.h> ++#include <linux/pinctrl/pinconf.h> ++#include <linux/pinctrl/pinconf-generic.h> ++#include "../pinctrl-utils.h" ++#include "../core.h" ++ ++enum FUNC_MODE { ++ FUNC_MODE0, ++ FUNC_MODE1, ++ FUNC_MODE2, ++ FUNC_MODE3, ++ FUNC_MASK, ++}; ++ ++struct mango_pinctrl { ++ struct device *dev; ++ struct pinctrl_dev *pctl; ++ u32 top_pinctl_offset; ++ struct regmap *syscon_pinctl; ++ void *data; ++}; ++ ++struct mango_group { ++ const char *name; ++ const unsigned int *pins; ++ const unsigned int num_pins; ++ int cur_func_idx; ++ struct mango_pmx_func *funcs; ++}; ++ ++struct mango_pmx_func { ++ const char *name; ++ const char * const *groups; ++ unsigned int num_groups; ++ enum FUNC_MODE mode; ++}; ++ ++struct mango_soc_pinmux_info { ++ const char name16; ++ const char name_a16; ++ const char name_r16; ++ struct pinctrl_state *pinctrl_a; ++ struct pinctrl_state *pinctrl_r; ++ const unsigned int def_state; /* default state */ ++ int (*set)(struct device *dev, unsigned int data); ++}; ++ ++struct mango_soc_pinctrl_data { ++ const struct pinctrl_pin_desc *pins; ++ unsigned int npins; ++ struct mango_group *groups; ++ int groups_count; ++ const struct mango_pmx_func *functions; ++ int functions_count; ++ struct class *p_class; ++}; ++ ++int sophgo_pinctrl_probe(struct platform_device *pdev); ++int mango_pmux_probe(struct platform_device *pdev); ++ ++ssize_t pinmux_show(struct device *dev, ++ struct device_attribute *attr, char *buf); ++ ++ssize_t pinmux_store(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t size); ++#endif +diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig +index 8ebcddf91f7b..428fa365a19a 100644 +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -637,6 +637,17 @@ config PWM_TEGRA + To compile this driver as a module, choose M here: the module + will be called pwm-tegra. + ++config PWM_THEAD ++ tristate "T-HEAD PWM support" ++ depends on ARCH_THEAD || COMPILE_TEST ++ depends on HAS_IOMEM ++ help ++ Generic PWM framework driver for the PWFM controller found on THEAD ++ SoCs. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-thead. ++ + config PWM_TIECAP + tristate "ECAP PWM support" + depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST +diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile +index c822389c2a24..4847ffd6997d 100644 +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -50,6 +50,7 @@ obj-$(CONFIG_PWM_RZ_MTU3) += pwm-rz-mtu3.o + obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o + obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o + obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o ++obj-$(CONFIG_ARCH_SOPHGO) += pwm-sophgo.o + obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o + obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o + obj-$(CONFIG_PWM_STI) += pwm-sti.o +@@ -59,6 +60,7 @@ obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o + obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o + obj-$(CONFIG_PWM_SUNPLUS) += pwm-sunplus.o + obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o ++obj-$(CONFIG_PWM_THEAD) += pwm-thead.o + obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o + obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o + obj-$(CONFIG_PWM_TWL) += pwm-twl.o +diff --git a/drivers/pwm/pwm-sophgo.c b/drivers/pwm/pwm-sophgo.c +new file mode 100644 +index 000000000000..b6297175a5b7 +--- /dev/null ++++ b/drivers/pwm/pwm-sophgo.c +@@ -0,0 +1,276 @@ ++/* ++ * Copyright (c) 2007 Ben Dooks ++ * Copyright (c) 2008 Simtec Electronics ++ * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org> ++ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com> ++ * ++ * PWM driver for Samsung SoCs ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License. ++ */ ++ ++#include <linux/bitops.h> ++#include <linux/clk.h> ++#include <linux/export.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++#include <linux/pwm.h> ++#include <linux/slab.h> ++ ++ ++ ++#define REG_HLPERIOD 0x0 ++#define REG_PERIOD 0x4 ++#define REG_GROUP 0x8 ++#define REG_POLARITY 0x20 ++ ++ ++/** ++ * struct sophgo_pwm_channel - private data of PWM channel ++ * @period_ns: current period in nanoseconds programmed to the hardware ++ * @duty_ns: current duty time in nanoseconds programmed to the hardware ++ * @tin_ns: time of one timer tick in nanoseconds with current timer rate ++ */ ++struct sophgo_pwm_channel { ++ u32 period; ++ u32 hlperiod; ++}; ++ ++/** ++ * struct sophgo_pwm_chip - private data of PWM chip ++ * @chip: generic PWM chip ++ * @variant: local copy of hardware variant data ++ * @inverter_mask: inverter status for all channels - one bit per channel ++ * @base: base address of mapped PWM registers ++ * @base_clk: base clock used to drive the timers ++ * @tclk0: external clock 0 (can be ERR_PTR if not present) ++ * @tclk1: external clock 1 (can be ERR_PTR if not present) ++ */ ++struct sophgo_pwm_chip { ++ struct pwm_chip chip; ++ void __iomem *base; ++ struct clk *base_clk; ++ u8 polarity_mask; ++ bool no_polarity; ++}; ++ ++ ++static inline ++struct sophgo_pwm_chip *to_sophgo_pwm_chip(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct sophgo_pwm_chip, chip); ++} ++ ++static int pwm_sophgo_request(struct pwm_chip *chip, struct pwm_device *pwm_dev) ++{ ++ struct sophgo_pwm_channel *channel; ++ ++ channel = kzalloc(sizeof(*channel), GFP_KERNEL); ++ if (!channel) ++ return -ENOMEM; ++ ++ return pwm_set_chip_data(pwm_dev, channel); ++} ++ ++static void pwm_sophgo_free(struct pwm_chip *chip, struct pwm_device *pwm_dev) ++{ ++ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev); ++ ++ pwm_set_chip_data(pwm_dev, NULL); ++ kfree(channel); ++} ++ ++static int pwm_sophgo_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, ++ int duty_ns, int period_ns) ++{ ++ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip); ++ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev); ++ u64 cycles; ++ ++ cycles = clk_get_rate(our_chip->base_clk); ++ cycles *= period_ns; ++ do_div(cycles, NSEC_PER_SEC); ++ ++ channel->period = cycles; ++ cycles = cycles * duty_ns; ++ do_div(cycles, period_ns); ++ channel->hlperiod = channel->period - cycles; ++ ++ return 0; ++} ++ ++static int pwm_sophgo_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev) ++{ ++ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip); ++ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev); ++ ++ writel(channel->period, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_PERIOD); ++ writel(channel->hlperiod, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_HLPERIOD); ++ ++ return 0; ++} ++ ++static void pwm_sophgo_disable(struct pwm_chip *chip, ++ struct pwm_device *pwm_dev) ++{ ++ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip); ++ ++ writel(0, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_PERIOD); ++ writel(0, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_HLPERIOD); ++} ++ ++static int pwm_sophgo_apply(struct pwm_chip *chip, struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ int ret; ++ ++ bool enabled = pwm->state.enabled; ++ ++ if (state->polarity != pwm->state.polarity && pwm->state.enabled) { ++ pwm_sophgo_disable(chip, pwm); ++ enabled = false; ++ } ++ ++ if (!state->enabled) { ++ if (enabled) ++ pwm_sophgo_disable(chip, pwm); ++ return 0; ++ } ++ ++ ret = pwm_sophgo_config(chip, pwm, state->duty_cycle, state->period); ++ if (ret) { ++ dev_err(chip->dev, "pwm apply err\n"); ++ return ret; ++ } ++ dev_dbg(chip->dev, "%s tate->enabled =%d\n", __func__, state->enabled); ++ if (state->enabled) ++ ret = pwm_sophgo_enable(chip, pwm); ++ else ++ pwm_sophgo_disable(chip, pwm); ++ ++ if (ret) { ++ dev_err(chip->dev, "pwm apply failed\n"); ++ return ret; ++ } ++ return ret; ++} ++ ++static const struct pwm_ops pwm_sophgo_ops = { ++ .request = pwm_sophgo_request, ++ .free = pwm_sophgo_free, ++ .apply = pwm_sophgo_apply, ++ .owner = THIS_MODULE, ++}; ++ ++static const struct of_device_id sophgo_pwm_match = { ++ { .compatible = "sophgo,sophgo-pwm" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sophgo_pwm_match); ++ ++static int pwm_sophgo_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct sophgo_pwm_chip *chip; ++ struct resource *res; ++ int ret; ++ ++ pr_info("%s\n", __func__); ++ ++ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); ++ if (chip == NULL) ++ return -ENOMEM; ++ ++ chip->chip.dev = &pdev->dev; ++ chip->chip.ops = &pwm_sophgo_ops; ++ chip->chip.base = -1; ++ chip->polarity_mask = 0; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ chip->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(chip->base)) ++ return PTR_ERR(chip->base); ++ ++ chip->base_clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(chip->base_clk)) { ++ dev_err(dev, "failed to get pwm source clk\n"); ++ return PTR_ERR(chip->base_clk); ++ } ++ ++ ret = clk_prepare_enable(chip->base_clk); ++ if (ret < 0) { ++ dev_err(dev, "failed to enable base clock\n"); ++ return ret; ++ } ++ ++ //pwm-num default is 4, compatible with sg2042 ++ if (of_property_read_bool(pdev->dev.of_node, "pwm-num")) ++ device_property_read_u32(&pdev->dev, "pwm-num", &chip->chip.npwm); ++ else ++ chip->chip.npwm = 4; ++ ++ //no_polarity default is false(have polarity) , compatible with sg2042 ++ if (of_property_read_bool(pdev->dev.of_node, "no-polarity")) ++ chip->no_polarity = true; ++ else ++ chip->no_polarity = false; ++ pr_debug("chip->chip.npwm =%d chip->no_polarity=%d\n", chip->chip.npwm, chip->no_polarity); ++ ++ platform_set_drvdata(pdev, chip); ++ ++ ret = pwmchip_add(&chip->chip); ++ if (ret < 0) { ++ dev_err(dev, "failed to register PWM chip\n"); ++ clk_disable_unprepare(chip->base_clk); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int pwm_sophgo_remove(struct platform_device *pdev) ++{ ++ struct sophgo_pwm_chip *chip = platform_get_drvdata(pdev); ++ ++ pwmchip_remove(&chip->chip); ++ ++ clk_disable_unprepare(chip->base_clk); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int pwm_sophgo_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int pwm_sophgo_resume(struct device *dev) ++{ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(pwm_sophgo_pm_ops, pwm_sophgo_suspend, ++ pwm_sophgo_resume); ++ ++static struct platform_driver pwm_sophgo_driver = { ++ .driver = { ++ .name = "sophgo-pwm", ++ .pm = &pwm_sophgo_pm_ops, ++ .of_match_table = of_match_ptr(sophgo_pwm_match), ++ }, ++ .probe = pwm_sophgo_probe, ++ .remove = pwm_sophgo_remove, ++}; ++module_platform_driver(pwm_sophgo_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("chunzhi.lin"); ++MODULE_DESCRIPTION("Sophgo PWM driver"); +diff --git a/drivers/pwm/pwm-thead.c b/drivers/pwm/pwm-thead.c +new file mode 100644 +index 000000000000..3b4772c3b8ca +--- /dev/null ++++ b/drivers/pwm/pwm-thead.c +@@ -0,0 +1,269 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * T-HEAD PWM driver ++ * ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org> ++ * ++ * Limitations: ++ * - The THEAD_PWM_CTRL_START bit is only effective when 0 -> 1, which is used ++ * to start the channel, 1 -> 0 doesn't change anything. so 0 % duty cycle ++ * is used to "disable" the channel. ++ * - The THEAD_PWM_CTRL_START bit is automatically cleared once PWM channel is ++ * started. ++ * - The THEAD_PWM_CFG_UPDATE atomically updates and only updates period and duty. ++ * - To update period and duty, THEAD_PWM_CFG_UPDATE needs to go through 0 -> 1 ++ * step, I.E if THEAD_PWM_CFG_UPDATE is already 1, it's necessary to clear it ++ * to 0 beforehand. ++ * - Polarity can only be changed if never started before. ++ */ ++ ++#include <linux/bitfield.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/mod_devicetable.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/pm_runtime.h> ++#include <linux/pwm.h> ++#include <linux/slab.h> ++ ++#define THEAD_PWM_MAX_NUM 6 ++#define THEAD_PWM_MAX_PERIOD GENMASK(31, 0) ++#define THEAD_PWM_MAX_DUTY GENMASK(31, 0) ++ ++#define THEAD_PWM_CHN_BASE(n) ((n) * 0x20) ++#define THEAD_PWM_CTRL(n) (THEAD_PWM_CHN_BASE(n) + 0x00) ++#define THEAD_PWM_CTRL_START BIT(0) ++#define THEAD_PWM_CTRL_SOFT_RST BIT(1) ++#define THEAD_PWM_CTRL_CFG_UPDATE BIT(2) ++#define THEAD_PWM_CTRL_INTEN BIT(3) ++#define THEAD_PWM_CTRL_MODE GENMASK(5, 4) ++#define THEAD_PWM_CTRL_MODE_CONTINUOUS FIELD_PREP(THEAD_PWM_CTRL_MODE, 2) ++#define THEAD_PWM_CTRL_EVTRIG GENMASK(7, 6) ++#define THEAD_PWM_CTRL_FPOUT BIT(8) ++#define THEAD_PWM_CTRL_INFACTOUT BIT(9) ++#define THEAD_PWM_RPT(n) (THEAD_PWM_CHN_BASE(n) + 0x04) ++#define THEAD_PWM_PER(n) (THEAD_PWM_CHN_BASE(n) + 0x08) ++#define THEAD_PWM_FP(n) (THEAD_PWM_CHN_BASE(n) + 0x0c) ++#define THEAD_PWM_STATUS(n) (THEAD_PWM_CHN_BASE(n) + 0x10) ++#define THEAD_PWM_STATUS_CYCLE GENMASK(7, 0) ++ ++struct thead_pwm_chip { ++ struct pwm_chip chip; ++ void __iomem *mmio_base; ++ struct clk *clk; ++ u8 channel_ever_started; ++}; ++ ++static inline struct thead_pwm_chip *thead_pwm_from_chip(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct thead_pwm_chip, chip); ++} ++ ++static int thead_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ struct thead_pwm_chip *priv = thead_pwm_from_chip(chip); ++ u32 val = THEAD_PWM_CTRL_INFACTOUT | THEAD_PWM_CTRL_FPOUT | THEAD_PWM_CTRL_MODE_CONTINUOUS; ++ u64 period_cycle, duty_cycle, rate; ++ int ret; ++ ++ /* if ever started, can't change the polarity */ ++ if ((priv->channel_ever_started & (1 << pwm->hwpwm)) && ++ state->polarity != pwm->state.polarity) ++ return -EINVAL; ++ ++ if (!state->enabled) { ++ if (pwm->state.enabled) { ++ val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); ++ val &= ~THEAD_PWM_CTRL_CFG_UPDATE; ++ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); ++ ++ writel(0, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); ++ ++ val |= THEAD_PWM_CTRL_CFG_UPDATE; ++ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); ++ pm_runtime_put_sync(chip->dev); ++ } ++ return 0; ++ } ++ ++ if (!pwm->state.enabled) { ++ ret = pm_runtime_resume_and_get(chip->dev); ++ if (ret < 0) ++ return ret; ++ } ++ ++ if (state->polarity == PWM_POLARITY_INVERSED) ++ val &= ~THEAD_PWM_CTRL_FPOUT; ++ ++ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); ++ ++ rate = clk_get_rate(priv->clk); ++ /* ++ * The following calculations might overflow if clk is bigger ++ * than 1 GHz. In practise it's 24MHz, so this limitation ++ * is only theoretic. ++ */ ++ if (rate > NSEC_PER_SEC) ++ return -EINVAL; ++ ++ period_cycle = mul_u64_u64_div_u64(rate, state->period, NSEC_PER_SEC); ++ if (period_cycle > THEAD_PWM_MAX_PERIOD) ++ period_cycle = THEAD_PWM_MAX_PERIOD; ++ /* ++ * With limitation above we have period_cycle <= THEAD_PWM_MAX_PERIOD, ++ * so this cannot overflow. ++ */ ++ writel(period_cycle, priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm)); ++ ++ duty_cycle = mul_u64_u64_div_u64(rate, state->duty_cycle, NSEC_PER_SEC); ++ if (duty_cycle > THEAD_PWM_MAX_DUTY) ++ duty_cycle = THEAD_PWM_MAX_DUTY; ++ /* ++ * With limitation above we have duty_cycle <= THEAD_PWM_MAX_DUTY, ++ * so this cannot overflow. ++ */ ++ writel(duty_cycle, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); ++ ++ val |= THEAD_PWM_CTRL_CFG_UPDATE; ++ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); ++ ++ if (!pwm->state.enabled) { ++ val |= THEAD_PWM_CTRL_START; ++ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); ++ priv->channel_ever_started |= 1 << pwm->hwpwm; ++ } ++ ++ return 0; ++} ++ ++static int thead_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ++ struct pwm_state *state) ++{ ++ struct thead_pwm_chip *priv = thead_pwm_from_chip(chip); ++ u64 rate = clk_get_rate(priv->clk); ++ u32 val; ++ int ret; ++ ++ ret = pm_runtime_resume_and_get(chip->dev); ++ if (ret < 0) ++ return ret; ++ ++ val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); ++ if (val & THEAD_PWM_CTRL_FPOUT) ++ state->polarity = PWM_POLARITY_NORMAL; ++ else ++ state->polarity = PWM_POLARITY_INVERSED; ++ ++ val = readl(priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm)); ++ /* ++ * val 32 bits, multiply NSEC_PER_SEC, won't overflow. ++ */ ++ state->period = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); ++ ++ val = readl(priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); ++ state->enabled = !!val; ++ /* ++ * val 32 bits, multiply NSEC_PER_SEC, won't overflow. ++ */ ++ state->duty_cycle = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); ++ ++ pm_runtime_put_sync(chip->dev); ++ ++ return 0; ++} ++ ++static const struct pwm_ops thead_pwm_ops = { ++ .apply = thead_pwm_apply, ++ .get_state = thead_pwm_get_state, ++}; ++ ++static int __maybe_unused thead_pwm_runtime_suspend(struct device *dev) ++{ ++ struct thead_pwm_chip *priv = dev_get_drvdata(dev); ++ ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused thead_pwm_runtime_resume(struct device *dev) ++{ ++ struct thead_pwm_chip *priv = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) ++ dev_err(dev, "failed to enable pwm clock(%pe)\n", ERR_PTR(ret)); ++ ++ return ret; ++} ++ ++static int thead_pwm_probe(struct platform_device *pdev) ++{ ++ struct thead_pwm_chip *priv; ++ int ret, i; ++ u32 val; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ priv->mmio_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->mmio_base)) ++ return PTR_ERR(priv->mmio_base); ++ ++ priv->clk = devm_clk_get_enabled(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk)) ++ return PTR_ERR(priv->clk); ++ ++ priv->chip.ops = &thead_pwm_ops; ++ priv->chip.dev = &pdev->dev; ++ priv->chip.npwm = THEAD_PWM_MAX_NUM; ++ ++ /* check whether PWM is ever started or not */ ++ for (i = 0; i < priv->chip.npwm; i++) { ++ val = readl(priv->mmio_base + THEAD_PWM_FP(i)); ++ if (val) ++ priv->channel_ever_started |= 1 << i; ++ } ++ ++ ret = devm_pwmchip_add(&pdev->dev, &priv->chip); ++ if (ret) ++ return ret; ++ ++ devm_pm_runtime_enable(&pdev->dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id thead_pwm_dt_ids = { ++ {.compatible = "thead,th1520-pwm",}, ++ {/* sentinel */} ++}; ++MODULE_DEVICE_TABLE(of, thead_pwm_dt_ids); ++ ++static const struct dev_pm_ops thead_pwm_pm_ops = { ++ SET_RUNTIME_PM_OPS(thead_pwm_runtime_suspend, thead_pwm_runtime_resume, NULL) ++}; ++ ++static struct platform_driver thead_pwm_driver = { ++ .driver = { ++ .name = "thead-pwm", ++ .of_match_table = thead_pwm_dt_ids, ++ .pm = &thead_pwm_pm_ops, ++ }, ++ .probe = thead_pwm_probe, ++}; ++module_platform_driver(thead_pwm_driver); ++ ++MODULE_AUTHOR("Wei Liu <lw312886@linux.alibaba.com>"); ++MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); ++MODULE_DESCRIPTION("T-HEAD pwm driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig +index 965d4f0c18a6..8a2c579c783c 100644 +--- a/drivers/regulator/Kconfig ++++ b/drivers/regulator/Kconfig +@@ -1663,4 +1663,13 @@ config REGULATOR_QCOM_LABIBB + boost regulator and IBB can be used as a negative boost regulator + for LCD display panel. + ++config REGULATOR_LIGHT_AON ++ tristate "Thead Light Aon regulator" ++ depends on LIGHT_AON ++ default y ++ help ++ This driver provides support for the thead light virtal regulators that ++ inmplemented on Light Aon system. ++ ++ + endif +diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile +index 23074714a81a..aa1d8ca59499 100644 +--- a/drivers/regulator/Makefile ++++ b/drivers/regulator/Makefile +@@ -195,5 +195,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_LIGHT_AON) += light-regulator-aon.o + + ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG +diff --git a/drivers/regulator/light-regulator-aon.c b/drivers/regulator/light-regulator-aon.c +new file mode 100644 +index 000000000000..d30cb956145b +--- /dev/null ++++ b/drivers/regulator/light-regulator-aon.c +@@ -0,0 +1,888 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/debugfs.h> ++#include <linux/err.h> ++#include <linux/slab.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/regulator/driver.h> ++#include <linux/regulator/machine.h> ++#include <linux/regulator/of_regulator.h> ++#include <linux/regulator/machine.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++#include <linux/firmware/thead/ipc.h> ++ ++#define MBOX_MAX_MSG_LEN 28 ++ ++#define CONFIG_AON_REG_DEBUG 1 ++ ++struct rpc_msg_regu_vol_set { ++ u16 regu_id; ///< virtual regu id ++ u16 is_dual_rail; ///< whether this regu has dual rails ++ u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail ++ u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false ++ u16 reserved6; ++} __packed __aligned(4); ++ ++struct rpc_msg_regu_vol_get { ++ u16 regu_id; ///< virtual regu id ++ u16 is_dual_rail; ///< whether this regu has dual rails ++ u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail ++ u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false ++ u16 reserved6; ++ ++} __packed __aligned(4); ++ ++struct rpc_msg_regu_pwr_set { ++ u16 regu_id; ///< virtual regu id ++ u16 status; ///< 0: power off; 1: powr on ++ u32 reserved5; ++} __packed __aligned(4); ++ ++struct rpc_msg_regu_pwr_get { ++ u16 regu_id; ///< virtual regu id ++ u16 status; ///< 0: power off; 1: powr on ++ u32 reserved5; ++ ++} __packed __aligned(4); ++ ++struct light_aon_msg_regulator_ctrl { ++ struct light_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(4) rpc; ++} __packed __aligned(4); ++ ++enum pm_resource { ++ SOC_DVDD18_AON, /*da9063: ldo-3 */ ++ SOC_AVDD33_USB3, /*da9063: ldo-9 */ ++ SOC_DVDD08_AON, /*da9063: ldo-2 */ ++ SOC_APCPU_DVDD_DVDDM,/*da9063: vbcore1 & vbcore2*/ ++ SOC_DVDD08_DDR, /*da9063: buckperi */ ++ SOC_VDD_DDR_1V8, /*da9063: ldo-4 */ ++ SOC_VDD_DDR_1V1, /*da9063: buckmem & buckio */ ++ SOC_VDD_DDR_0V6, /*da9063: buckpro */ ++ SOC_DVDD18_AP, /*da9063: ldo-11 */ ++ SOC_DVDD08_AP, /*da9121: da9121_ex */ ++ SOC_AVDD08_MIPI_HDMI,/*da9063: ldo-1 */ ++ SOC_AVDD18_MIPI_HDMI,/*da9063: ldo-5 */ ++ SOC_DVDD33_EMMC, /*da9063: ldo-10 */ ++ SOC_DVDD18_EMMC, /*slg51000:ldo-3 */ ++ SOC_DOVDD18_SCAN, /*da9063: ldo-6 */ ++ SOC_VEXT_2V8, /*da9063: ldo-7 */ ++ SOC_DVDD12_SCAN, /*da9063: ld0-8 */ ++ SOC_AVDD28_SCAN_EN, /*da9063: gpio4 */ ++ SOC_AVDD28_RGB, /*slg51000:ldo-1 */ ++ SOC_DOVDD18_RGB, /*slg51000:ldo-4 */ ++ SOC_DVDD12_RGB, /*slg51000:ldo-5 */ ++ SOC_AVDD25_IR, /*slg51000:ldo-2 */ ++ SOC_DOVDD18_IR, /*slg51000:ldo-7 */ ++ SOC_DVDD12_IR, /*slg51000:ldo-6 */ ++ SOC_ADC_VREF, ++ SOC_LCD0_EN, ++ SOC_VEXT_1V8, ++ ++ ++ SOC_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; ///< discription of regulator ++ u32 regu_num; ///< element number of regulators,which point to regu-dsc-array ++}; ++ ++struct aon_regu_info { ++ struct device *dev; ++ const struct apcpu_vol_set *cpu_vol; ///< signed-off voltage of cpu ++ u32 vddm; ///< cpu-mem voltage ++ struct aon_regu_desc *regu_desc; ///< regu-desc set ++ struct light_aon_ipc *ipc_handle; ///< handle of mail-box ++}; ++ ++static struct aon_regu_info light_aon_pmic_info; ++ ++#define APCPU_VOL_DEF(_vdd, _vddm) \ ++ { \ ++ .vdd = _vdd, \ ++ .vddm = _vddm, \ ++ } ++ ++static const struct apcpu_vol_set apcpu_volts = { ++ /*300Mhz*/ ++ APCPU_VOL_DEF(600000U, 750000U), ++ APCPU_VOL_DEF(600000U, 800000U), ++ APCPU_VOL_DEF(650000U, 800000U), ++ APCPU_VOL_DEF(720000U, 770000U), ++ /*800Mhz*/ ++ APCPU_VOL_DEF(700000U,800000U), ++ APCPU_VOL_DEF(720000U,820000U), ++ /*1500Mhz*/ ++ APCPU_VOL_DEF(800000U,800000U), ++ APCPU_VOL_DEF(820000U,820000U), ++ /*1850Mhz*/ ++ APCPU_VOL_DEF(1000000U,1000000U), ++}; ++ ++/* dc2 is valid when is_dual_rail is true ++ * ++ * dual-rail regulator means that a virtual regulator involes two hw-regulators ++ */ ++static int aon_set_regulator(struct light_aon_ipc *ipc, u16 regu_id, ++ u32 dc1, u32 dc2, u16 is_dual_rail) ++{ ++ struct light_aon_msg_regulator_ctrl msg = {0}; ++ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; ++ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; ++ hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_SET_RESOURCE_REGULATOR; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++ ++ msg.rpc.regu_vol_set.regu_id = regu_id; ++ msg.rpc.regu_vol_set.is_dual_rail = is_dual_rail; ++ msg.rpc.regu_vol_set.dc1 = dc1; ++ msg.rpc.regu_vol_set.dc2 = dc2; ++ ++ return light_aon_call_rpc(ipc, &msg, true); ++} ++ ++/* dc2 is valid when is_dual_rail is true ++ * ++ * dual-rail regulator means that a virtual regulator involes two hw-regulators ++ */ ++static int aon_get_regulator(struct light_aon_ipc *ipc, u16 regu_id, ++ u32 *dc1, u32 *dc2, u16 is_dual_rail) ++{ ++ struct light_aon_msg_regulator_ctrl msg = {0}; ++ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; ++ int ret; ++ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; ++ hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_GET_RESOURCE_REGULATOR; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++ msg.rpc.regu_vol_get.regu_id = regu_id; ++ msg.rpc.regu_vol_get.is_dual_rail = is_dual_rail; ++ ++ ret = light_aon_call_rpc(ipc, &msg, true); ++ if (ret) ++ return ret; ++ ++ if (dc1 != NULL) ++ *dc1 = msg.rpc.regu_vol_get.dc1; ++ ++ if (dc2 != NULL) ++ *dc2 = msg.rpc.regu_vol_get.dc2; ++ ++ return 0; ++} ++ ++static int aon_regu_power_ctrl(struct light_aon_ipc *ipc,u32 regu_id,u16 pwr_on) ++{ ++ struct light_aon_msg_regulator_ctrl msg = {0}; ++ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; ++ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; ++ hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_PWR_SET; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++ ++ msg.rpc.regu_pwr_set.regu_id = regu_id; ++ msg.rpc.regu_pwr_set.status = pwr_on; ++ return light_aon_call_rpc(ipc, &msg, true); ++} ++static int aon_regu_dummy_enable(struct regulator_dev *reg) ++{ ++ return 0; ++} ++static int aon_regu_dummy_disable(struct regulator_dev *reg) ++{ ++ return 0; ++} ++static int aon_regu_dummy_is_enabled(struct regulator_dev *reg) ++{ ++ return 0; ++} ++static int aon_regu_enable(struct regulator_dev *reg) ++{ ++ u16 regu_id =(u16) rdev_get_id(reg); ++ return aon_regu_power_ctrl(light_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(light_aon_pmic_info.ipc_handle, regu_id, 0); ++} ++ ++static int aon_regu_is_enabled(struct regulator_dev *reg) ++{ ++ struct light_aon_msg_regulator_ctrl msg = {0}; ++ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; ++ int ret; ++ u16 regu_id =(u16) rdev_get_id(reg); ++ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; ++ hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_PWR_GET; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++ ++ msg.rpc.regu_pwr_get.regu_id = regu_id; ++ ret = light_aon_call_rpc(light_aon_pmic_info.ipc_handle, &msg, true); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ return (int) msg.rpc.regu_pwr_get.status; ++} ++ ++static int aon_regu_set_voltage(struct regulator_dev *reg, ++ int minuV, int uV, unsigned *selector) ++{ ++ u16 regu_id =(u16) rdev_get_id(reg); ++ u32 voltage = minuV; /* uV */ ++ int err; ++ ++ pr_debug("%s,%dminuV = %d, uV = %d\n", __func__, __LINE__, minuV, uV); ++ ++ err = aon_set_regulator(light_aon_pmic_info.ipc_handle, regu_id, ++ voltage, 0, 0); ++ if (err) { ++ pr_err("failed to set Voltages to %d!\n", minuV); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++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(light_aon_pmic_info.ipc_handle, regu_id, ++ &voltage, NULL, 0); ++ if (ret) { ++ pr_err("failed to get voltage\n"); ++ return -EINVAL; ++ } ++ ++ pr_debug("%s,%dvoltage = %d\n", __func__, __LINE__, voltage); ++ ++ return voltage; ++} ++ ++static const struct apcpu_vol_set *apcpu_get_matched_signed_off_voltage(u32 vdd, u32 vddm) ++{ ++ int vol_count = ARRAY_SIZE(apcpu_volts); ++ int i; ++ ++ for (i = 0; i < vol_count; i++) ++ if ((vdd == apcpu_voltsi.vdd) && ++ (vddm == apcpu_voltsi.vddm)) ++ return &apcpu_voltsi; ++ ++#ifdef CONFIG_AON_REG_DEBUG ++ return &apcpu_volts2; ++#else ++ return NULL; ++#endif ++} ++ ++static int apcpu_set_vdd_vddm_voltage(struct regulator_dev *reg, ++ int minuV, int uV, unsigned *selector) ++{ ++ struct aon_regu_info *info = rdev_get_drvdata(reg); ++ const struct apcpu_vol_set *cpu_vol; ++ u32 vol = minuV; /* uV */ ++ u32 dc1, dc2; ++ int err; ++ ++ cpu_vol = apcpu_get_matched_signed_off_voltage(vol, light_aon_pmic_info.vddm); ++ if (!cpu_vol) { ++ dev_err(info->dev, "failed to find bcore1/bcore2 matching table\n"); ++#ifndef CONFIG_AON_REG_DEBUG ++ return -EINVAL; ++#endif ++ } ++ ++ dc1 = cpu_vol->vdd; ++ dc2 = cpu_vol->vddm; ++ info->cpu_vol = cpu_vol; ++ info->vddm = cpu_vol->vddm; ++ ++ err = aon_set_regulator(light_aon_pmic_info.ipc_handle, (u16)SOC_APCPU_DVDD_DVDDM, ++ dc1, dc2, 1); ++ if (err) { ++ dev_err(info->dev, "failed to set Voltages to %d!\n", uV); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int apcpu_set_vddm_voltage(struct regulator_dev *reg, ++ int minuV, int uV, unsigned *selector) ++{ ++ struct aon_regu_info *info = rdev_get_drvdata(reg); ++ int bcore_table_count = ARRAY_SIZE(apcpu_volts); ++ u32 vol = minuV; /* uV */ ++ int i; ++ ++ for (i = 0; i < bcore_table_count; i++) ++ if (vol == apcpu_voltsi.vddm) ++ break; ++ ++ if (i >= bcore_table_count) { ++ dev_err(info->dev, "The vol is not existed in matching table\n"); ++#ifndef CONFIG_AON_REG_DEBUG ++ return -EINVAL; ++#endif ++ } ++ ++ /* update the vddm */ ++ info->vddm = vol; ++ return 0; ++} ++ ++static int apcpu_get_voltage(struct regulator_dev *reg, bool is_vdd) ++{ ++ struct aon_regu_info *info = rdev_get_drvdata(reg); ++ const struct apcpu_vol_set *cpu_vol; ++ u32 dc1, dc2; ++ int err; ++ ++ err = aon_get_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, ++ &dc1, &dc2, 1); ++ if (err) { ++ dev_err(info->dev, "failed to get Voltages!\n"); ++ return -EINVAL; ++ } ++ cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); ++ if (!cpu_vol) { ++ dev_err(info->dev, "Voltage %d:%d is not existing in matching table\n", dc1, dc2); ++ return -EINVAL; ++ } ++ ++ info->cpu_vol = cpu_vol; ++ ++ return is_vdd ? cpu_vol->vdd : cpu_vol->vddm; ++} ++ ++static int apcpu_get_vdd_voltage(struct regulator_dev *reg) ++{ ++ return apcpu_get_voltage(reg, true); ++} ++ ++static int apcpu_get_vddm_voltage(struct regulator_dev *reg) ++{ ++ return apcpu_get_voltage(reg, false); ++} ++ ++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, ++}; ++static const struct regulator_ops apcpu_dvdd_ops = { ++ .enable = aon_regu_dummy_enable, ++ .disable = aon_regu_dummy_disable, ++ .is_enabled = aon_regu_dummy_is_enabled, ++ .list_voltage = regulator_list_voltage_linear, ++ .set_voltage = apcpu_set_vdd_vddm_voltage, ++ .get_voltage = apcpu_get_vdd_voltage, ++}; ++ ++static const struct regulator_ops apcpu_dvddm_ops = { ++ .enable = aon_regu_dummy_enable, ++ .disable = aon_regu_dummy_disable, ++ .is_enabled = aon_regu_dummy_is_enabled, ++ .list_voltage = regulator_list_voltage_linear, ++ .set_voltage = apcpu_set_vddm_voltage, ++ .get_voltage = apcpu_get_vddm_voltage, ++}; ++ ++/* Macros for voltage DC/DC converters (BUCKs) for cpu */ ++#define REGU_DSC_DEF(regu_id, of_math_name) \ ++ .id = regu_id, \ ++ .name = #regu_id, \ ++ .of_match = of_match_ptr(__stringify(of_math_name)), \ ++ .ops = ®u_common_ops, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE ++ ++#define BUCK_APCPU_DVDD(regu_id,min_mV, step_mV, max_mV) \ ++ .id = regu_id, \ ++ .name = "APCPU_DVDD", \ ++ .of_match = of_match_ptr("appcpu_dvdd"), \ ++ .ops = &apcpu_dvdd_ops, \ ++ .min_uV = (min_mV), \ ++ .uV_step = (step_mV), \ ++ .n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE ++ ++#define BUCK_APCPU_DVDDM(regu_id, min_mV, step_mV, max_mV) \ ++ .id = regu_id, \ ++ .name = "APCPU_DVDDM", \ ++ .of_match = of_match_ptr("appcpu_dvddm"), \ ++ .ops = &apcpu_dvddm_ops, \ ++ .min_uV = (min_mV) , \ ++ .uV_step = (step_mV), \ ++ .n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE ++ ++/* regulator desc for dialog */ ++static struct regulator_desc light_dialog_ant_regu_desc = { ++ /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ ++ { ++ BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), ++ }, ++ { ++ BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), ++ }, ++ ++ /*common regu ,no need to adjust vol dynamicaly */ ++ { ++ REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DOVDD18_SCAN,soc_dovdd18_scan), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD12_SCAN,soc_dvdd12_scan), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD28_SCAN_EN,soc_avdd28_scan_en), ++ }, ++}; ++ ++static struct regulator_desc light_dialog_regu_desc = { ++ /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ ++ { ++ BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), ++ }, ++ { ++ BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), ++ }, ++ ++ /*common regu ,no need to adjust vol dynamicaly */ ++ { ++ REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DOVDD18_SCAN,soc_dovdd18_scan), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VEXT_2V8,soc_vext_2v8), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD12_SCAN,soc_dvdd12_scan), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD28_SCAN_EN,soc_avdd28_scan_en), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD28_RGB,soc_avdd28_rgb), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DOVDD18_RGB,soc_dovdd18_rgb), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD12_RGB,soc_dvdd12_rgb), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD25_IR,soc_avdd25_ir), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DOVDD18_IR,soc_dovdd18_ir), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD12_IR,soc_dvdd12_ir), ++ }, ++}; ++ ++/* regulator desc for ricoh */ ++static struct regulator_desc light_ricoh_regu_desc = { ++ /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ ++ { ++ BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 600000, 12500, 1500000), ++ }, ++ { ++ BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 600000, 12500, 1500000), ++ }, ++ ++ /*common regu ,no need to adjust vol dynamicaly */ ++ { ++ REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), ++ }, ++ { ++ REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), ++ }, ++ { ++ REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), ++ }, ++ { ++ REGU_DSC_DEF(SOC_LCD0_EN,soc_lcd0_en), ++ }, ++ { ++ REGU_DSC_DEF(SOC_VEXT_1V8,soc_vext_1v8), ++ }, ++}; ++ ++#define GEN_REGISTER_SHOW(x, y) \ ++static ssize_t x##_registers_show(struct device *dev, \ ++ struct device_attribute *attr, \ ++ char *buf) \ ++{ \ ++ struct platform_device *pdev = to_platform_device(dev); \ ++ struct aon_regu_info *info = platform_get_drvdata(pdev); \ ++ u32 dc1, dc2; \ ++ ssize_t ret; \ ++ \ ++ ret = aon_get_regulator(light_aon_pmic_info.ipc_handle, y, \ ++ &dc1, &dc2, 0); \ ++ if (ret) { \ ++ dev_err(info->dev, "failed to get Voltages!\n"); \ ++ return -EINVAL; \ ++ } \ ++ \ ++ ret = sprintf(buf, "%u\n", dc1); \ ++ return ret; \ ++} ++ ++#define GEN_REGISTER_STORE(x, y) \ ++static ssize_t x##_register_store(struct device *dev, \ ++ struct device_attribute *attr, \ ++ const char *buf, size_t count) \ ++{ \ ++ struct platform_device *pdev = to_platform_device(dev); \ ++ struct aon_regu_info *info = platform_get_drvdata(pdev); \ ++ unsigned long dc1, dc2 = 0; \ ++ int err; \ ++ \ ++ if (kstrtoul(buf, 0, &dc1)) \ ++ return -EINVAL; \ ++ \ ++ err = aon_set_regulator(light_aon_pmic_info.ipc_handle, y, \ ++ dc1, dc2, 0); \ ++ if (err) { \ ++ dev_err(info->dev, "failed to set Voltages to %lu!\n", dc1); \ ++ return -EINVAL; \ ++ } \ ++ \ ++ return count; \ ++} ++ ++static ssize_t soc_apcpu_dvdd_dvddm_registers_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct aon_regu_info *info = platform_get_drvdata(pdev); ++ size_t bufpos = 0, count = 26; ++ const struct apcpu_vol_set *cpu_vol; ++ u32 dc1, dc2; ++ int i = 0; ++ int err; ++ err = aon_get_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, ++ &dc1, &dc2, 1); ++ if (err) { ++ dev_err(info->dev, "failed to get Voltages!\n"); ++ return -EINVAL; ++ } ++ cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); ++ if (!cpu_vol) ++ dev_err(info->dev, "Read %d:%d is not existing in matching table\n", dc1, dc2); ++ snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i); ++ bufpos += 4; ++ snprintf(buf + bufpos, count - bufpos, "%u", dc1); ++ bufpos += 8; ++ bufbufpos++ = '\n'; ++ i++; ++ snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i); ++ bufpos += 4; ++ snprintf(buf + bufpos, count - bufpos, "%u", dc2); ++ bufpos += 8; ++ bufbufpos++ = '\n'; ++ return bufpos; ++} ++static ssize_t soc_apcpu_dvdd_dvddm_register_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct aon_regu_info *info = platform_get_drvdata(pdev); ++ const struct apcpu_vol_set *cpu_vol; ++ char *start = (char *)buf; ++ unsigned long dc1, dc2; ++ int err; ++ while (*start == ' ') ++ start++; ++ dc1 = simple_strtoul(start, &start, 0); ++ while (*start == ' ') ++ start++; ++ if (kstrtoul(start, 0, &dc2)) ++ return -EINVAL; ++ cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); ++ if (!cpu_vol) { ++ dev_err(info->dev, "failed to find bcore1/bcore2 matching table\n"); ++#ifndef CONFIG_AON_REG_DEBUG ++ return -EINVAL; ++#endif ++ } ++ info->cpu_vol = cpu_vol; ++ info->vddm = cpu_vol->vddm; ++ err = aon_set_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, ++ dc1, dc2, 1); ++ if (err) { ++ dev_err(info->dev, "failed to set Voltages to %lu,%lu!\n", dc1, dc2); ++#ifndef CONFIG_AON_REG_DEBUG ++ return -EINVAL; ++#endif ++ } ++ return size; ++} ++ ++GEN_REGISTER_SHOW(soc_dvdd18_aon, SOC_DVDD18_AON) ++GEN_REGISTER_STORE(soc_dvdd18_aon, SOC_DVDD18_AON) ++GEN_REGISTER_SHOW(soc_dvdd08_ap, SOC_DVDD08_AP) ++GEN_REGISTER_STORE(soc_dvdd08_ap, SOC_DVDD08_AP) ++GEN_REGISTER_SHOW(soc_dvdd18_emmc, SOC_DVDD18_EMMC) ++GEN_REGISTER_STORE(soc_dvdd18_emmc, SOC_DVDD18_EMMC) ++GEN_REGISTER_SHOW(soc_dvdd33_emmc, SOC_DVDD33_EMMC) ++GEN_REGISTER_STORE(soc_dvdd33_emmc, SOC_DVDD33_EMMC) ++ ++static DEVICE_ATTR(soc_dvdd18_aon_regs, 0644, soc_dvdd18_aon_registers_show, soc_dvdd18_aon_register_store); ++static DEVICE_ATTR(soc_dvdd08_ap_regs, 0644, soc_dvdd08_ap_registers_show, soc_dvdd08_ap_register_store); ++static DEVICE_ATTR(soc_dvdd33_emmc_regs, 0644, soc_dvdd33_emmc_registers_show, soc_dvdd33_emmc_register_store); ++static DEVICE_ATTR(soc_dvdd18_emmc_regs, 0644, soc_dvdd18_emmc_registers_show, soc_dvdd18_emmc_register_store); ++static DEVICE_ATTR(soc_apcpu_dvdd_dvddm_regs, 0644, soc_apcpu_dvdd_dvddm_registers_show, soc_apcpu_dvdd_dvddm_register_store); ++ ++static struct attribute *aon_regs_sysfs_entries = { ++ &dev_attr_soc_dvdd18_aon_regs.attr, ++ &dev_attr_soc_dvdd08_ap_regs.attr, ++ &dev_attr_soc_dvdd33_emmc_regs.attr, ++ &dev_attr_soc_dvdd18_emmc_regs.attr, ++ &dev_attr_soc_apcpu_dvdd_dvddm_regs.attr, ++ NULL ++}; ++static const struct attribute_group dev_attr_aon_regs_group = { ++ .attrs = aon_regs_sysfs_entries, ++}; ++ ++ ++static const struct aon_regu_desc light_dialog_regus = { ++ .regu_desc = (struct regulator_desc*) &light_dialog_regu_desc, ++ .regu_num = ARRAY_SIZE(light_dialog_regu_desc), ++}; ++ ++static const struct aon_regu_desc light_dialog_ant_regus = { ++ .regu_desc = (struct regulator_desc*) &light_dialog_ant_regu_desc, ++ .regu_num = ARRAY_SIZE(light_dialog_ant_regu_desc), ++}; ++ ++static const struct aon_regu_desc light_ricoh_regus = { ++ .regu_desc = (struct regulator_desc*)&light_ricoh_regu_desc, ++ .regu_num = ARRAY_SIZE(light_ricoh_regu_desc), ++}; ++ ++static int light_aon_regulator_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct regulator_config config = { }; ++ int i; ++ int ret; ++ struct aon_regu_desc *regus_set = NULL; ++ ++ 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 = light_aon_get_handle(&(light_aon_pmic_info.ipc_handle)); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to get ipc_handle\n"); ++ return ret; ++ } ++ ++ /*init private drv data */ ++ light_aon_pmic_info.dev = &pdev->dev; ++ light_aon_pmic_info.regu_desc = regus_set; ++ light_aon_pmic_info.cpu_vol = &apcpu_volts2; /* pmic default voltages */ ++ light_aon_pmic_info.vddm = light_aon_pmic_info.cpu_vol->vddm; ++ ++ /*register all regulators*/ ++ config.dev = &pdev->dev; ++ config.driver_data = &light_aon_pmic_info; ++ for (i = 0; i < regus_set->regu_num; i++) { ++ struct regulator_dev *rdev; ++ struct regulator_desc *desc; ++ ++ desc = ®us_set->regu_desci; ++ rdev = devm_regulator_register(&pdev->dev, desc, &config); ++ if (IS_ERR(rdev)) { ++ dev_err(&pdev->dev, ++ "Failed to initialize regulator-%d\n", i); ++ return PTR_ERR(rdev); ++ } ++ } ++ ++ i = sysfs_create_group(&config.dev->kobj, &dev_attr_aon_regs_group); ++ if (i) { ++ dev_err(&pdev->dev, "Failed to create aon regs debug sysfs.\n"); ++ return i; ++ } ++ ++ platform_set_drvdata(pdev, &light_aon_pmic_info); ++ ++ return 0; ++} ++ ++static const struct of_device_id light_pmic_dev_id = { ++ { .compatible = "thead,light-dialog-pmic-ant", .data = &light_dialog_ant_regus}, ++ { .compatible = "thead,light-dialog-pmic", .data = &light_dialog_regus}, ++ { .compatible = "thead,light-ricoh-pmic", .data = &light_ricoh_regus}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, light_pmic_dev_id); ++ ++static struct platform_driver light_aon_regulator_driver = { ++ .driver = { ++ .name = "light-aon-reg", ++ .owner = THIS_MODULE, ++ .of_match_table = light_pmic_dev_id, ++ }, ++ .probe = light_aon_regulator_probe, ++}; ++ ++module_platform_driver(light_aon_regulator_driver); ++ ++MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); ++MODULE_AUTHOR("linghui.zlh <linghui.zlh@linux.alibaba.com>"); ++MODULE_DESCRIPTION("Thead Light Aon regulator virtual driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +index ccd59ddd7610..ec69e6bbba6e 100644 +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -253,6 +253,16 @@ config RESET_SUNXI + help + This enables the reset driver for Allwinner SoCs. + ++config RESET_TH1520 ++ bool "TH1520 Reset Driver" ++ depends on (ARCH_THEAD || COMPILE_TEST) && OF ++ select MFD_SYSCON ++ default ARCH_THEAD ++ help ++ Support for the T-HEAD 1520 RISC-V SoC reset controller. ++ Say Y if you want to control reset signals provided by this ++ controller. ++ + config RESET_TI_SCI + tristate "TI System Control Interface (TI-SCI) reset driver" + depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) +diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile +index 8270da8a4baa..ca0abdce468d 100644 +--- a/drivers/reset/Makefile ++++ b/drivers/reset/Makefile +@@ -33,6 +33,8 @@ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o + obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o + obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o + obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o ++obj-$(CONFIG_ARCH_SOPHGO) += reset-sophgo.o ++obj-$(CONFIG_RESET_TH1520) += reset-th1520.o + obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o + obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o + obj-$(CONFIG_RESET_TI_TPS380X) += reset-tps380x.o +diff --git a/drivers/reset/reset-sophgo.c b/drivers/reset/reset-sophgo.c +new file mode 100644 +index 000000000000..3c46a43e24ba +--- /dev/null ++++ b/drivers/reset/reset-sophgo.c +@@ -0,0 +1,163 @@ ++/* ++ * Sophgo SoCs Reset Controller driver ++ * ++ * Copyright (c) 2018 Bitmain Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/reset-controller.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/types.h> ++#include <linux/of_device.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> ++ ++#define BITS_PER_REG 32 ++ ++struct bm_reset_data { ++ spinlock_t lock; ++ void __iomem *membase; ++ struct reset_controller_dev rcdev; ++ struct regmap *syscon_rst; ++ u32 top_rst_offset; ++}; ++ ++static int bm_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct bm_reset_data *data = container_of(rcdev, ++ struct bm_reset_data, ++ rcdev); ++ int bank = id / BITS_PER_REG; ++ int offset = id % BITS_PER_REG; ++ unsigned long flags; ++ u32 reg; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ regmap_read(data->syscon_rst, data->top_rst_offset + (bank * 4), ++ ®); ++ regmap_write(data->syscon_rst, data->top_rst_offset + (bank * 4), ++ reg & ~BIT(offset)); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ return 0; ++} ++ ++static int bm_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct bm_reset_data *data = container_of(rcdev, ++ struct bm_reset_data, ++ rcdev); ++ int bank = id / BITS_PER_REG; ++ int offset = id % BITS_PER_REG; ++ unsigned long flags; ++ u32 reg; ++ ++ spin_lock_irqsave(&data->lock, flags); ++ ++ regmap_read(data->syscon_rst, data->top_rst_offset + (bank * 4), ++ ®); ++ regmap_write(data->syscon_rst, data->top_rst_offset + (bank * 4), ++ reg | BIT(offset)); ++ ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ return 0; ++} ++ ++static const struct reset_control_ops bm_reset_ops = { ++ .assert = bm_reset_assert, ++ .deassert = bm_reset_deassert, ++}; ++ ++static const struct of_device_id bm_reset_dt_ids = { ++ { .compatible = "bitmain,reset", }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, bm_reset_dt_ids); ++ ++static int bm_reset_probe(struct platform_device *pdev) ++{ ++ struct bm_reset_data *data; ++ int ret = 0; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node, *np_top; ++ static struct regmap *syscon; ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ np_top = of_parse_phandle(np, "subctrl-syscon", 0); ++ if (!np_top) { ++ dev_err(dev, "%s can't get subctrl-syscon node\n", __func__); ++ goto out_free_devm; ++ } ++ ++ syscon = syscon_node_to_regmap(np_top); ++ if (IS_ERR(syscon)) { ++ dev_err(dev, "cannot get regmap\n"); ++ goto out_free_devm; ++ } ++ ++ data->syscon_rst = syscon; ++ ret = device_property_read_u32(&pdev->dev, "top_rst_offset", ++ &data->top_rst_offset); ++ if (ret < 0) { ++ dev_err(dev, "cannot get top_rst_offset\n"); ++ goto out_free_devm; ++ } ++ ++ ret = device_property_read_u32(&pdev->dev, "nr_resets", ++ &data->rcdev.nr_resets); ++ if (ret < 0) { ++ dev_err(dev, "cannot get nr_resets\n"); ++ goto out_free_devm; ++ } ++ ++ spin_lock_init(&data->lock); ++ ++ data->rcdev.owner = THIS_MODULE; ++ data->rcdev.ops = &bm_reset_ops; ++ data->rcdev.of_node = pdev->dev.of_node; ++ ++ ret = devm_reset_controller_register(&pdev->dev, &data->rcdev); ++ if (!ret) ++ return 0; ++ ++out_free_devm: ++ devm_kfree(&pdev->dev, data); ++ return ret; ++} ++ ++static struct platform_driver bm_reset_driver = { ++ .probe = bm_reset_probe, ++ .driver = { ++ .name = "bm-reset", ++ .of_match_table = bm_reset_dt_ids, ++ }, ++}; ++ ++static int __init bm_reset_init(void) ++{ ++ return platform_driver_register(&bm_reset_driver); ++} ++postcore_initcall(bm_reset_init); ++ ++MODULE_AUTHOR("Wei Huang<wei.huang01@bitmain.com>"); ++MODULE_DESCRIPTION("Bitmain SoC Reset Controoler Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/reset/reset-th1520.c b/drivers/reset/reset-th1520.c +new file mode 100644 +index 000000000000..5a89d201fc0c +--- /dev/null ++++ b/drivers/reset/reset-th1520.c +@@ -0,0 +1,109 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include <linux/mfd/syscon.h> ++#include <linux/of_device.h> ++#include <linux/platform_device.h> ++#include <linux/reset-controller.h> ++#include <linux/regmap.h> ++#include <dt-bindings/reset/thead,th1520-reset.h> ++ ++struct th1520_rst_signal { ++ unsigned int offset, bit; ++}; ++ ++struct th1520_rst { ++ struct reset_controller_dev rcdev; ++ struct regmap *regmap; ++ const struct th1520_rst_signal *signals; ++}; ++ ++enum th1520_rst_registers { ++ RST_WDT0 = 0x0034, ++ RST_WDT1 = 0x0038, ++}; ++ ++static int th1520_reset_update(struct th1520_rst *rst, unsigned long id, ++ unsigned int value) ++{ ++ const struct th1520_rst_signal *signal = &rst->signalsid; ++ ++ return regmap_update_bits(rst->regmap, signal->offset, signal->bit, ++ value); ++} ++ ++static const struct th1520_rst_signal th1520_rst_signals = { ++ TH1520_RESET_WDT0 = { RST_WDT0, BIT(0) }, ++ TH1520_RESET_WDT1 = { RST_WDT1, BIT(0) }, ++}; ++ ++static struct th1520_rst *to_th1520_rst(struct reset_controller_dev *rcdev) ++{ ++ return container_of(rcdev, struct th1520_rst, rcdev); ++} ++ ++static int th1520_reset_set(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) ++{ ++ struct th1520_rst *rst = to_th1520_rst(rcdev); ++ const unsigned int bit = rst->signalsid.bit; ++ unsigned int value = assert ? bit : 0; ++ ++ return th1520_reset_update(rst, id, value); ++} ++ ++static int th1520_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return th1520_reset_set(rcdev, id, false); ++} ++ ++static int th1520_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return th1520_reset_set(rcdev, id, true); ++} ++ ++static const struct reset_control_ops th1520_rst_ops = { ++ .assert = th1520_reset_assert, ++ .deassert = th1520_reset_deassert, ++}; ++ ++static int th1520_reset_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct th1520_rst *rst; ++ struct regmap_config config = { .name = "rst" }; ++ ++ rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL); ++ if (!rst) ++ return -ENOMEM; ++ ++ rst->signals = th1520_rst_signals; ++ rst->regmap = syscon_node_to_regmap(dev->of_node); ++ if (IS_ERR(rst->regmap)) ++ return PTR_ERR(rst->regmap); ++ ++ regmap_attach_dev(dev, rst->regmap, &config); ++ ++ rst->rcdev.owner = THIS_MODULE; ++ rst->rcdev.dev = dev; ++ rst->rcdev.of_node = dev->of_node; ++ rst->rcdev.ops = &th1520_rst_ops; ++ rst->rcdev.nr_resets = ARRAY_SIZE(th1520_rst_signals); ++ ++ return devm_reset_controller_register(dev, &rst->rcdev); ++} ++ ++static const struct of_device_id th1520_reset_dt_ids = { ++ { .compatible = "thead,th1520-reset" }, ++ { /* sentinel */ }, ++}; ++ ++static struct platform_driver th1520_reset_driver = { ++ .probe = th1520_reset_probe, ++ .driver = { ++ .name = "th1520-reset", ++ .of_match_table = th1520_reset_dt_ids, ++ }, ++}; ++builtin_platform_driver(th1520_reset_driver); +diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig +index d3795860f5c0..34e4d97766c3 100644 +--- a/drivers/rpmsg/Kconfig ++++ b/drivers/rpmsg/Kconfig +@@ -74,6 +74,10 @@ config RPMSG_QCOM_SMD + providing communication channels to remote processors in Qualcomm + platforms. + ++config RPMSG_THEAD_LIGHT ++ tristate "THEAD Light RPM Driver" ++ depends on RPMSG ++ + config RPMSG_VIRTIO + tristate "Virtio RPMSG bus driver" + depends on HAS_DMA +diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile +index 58e3b382e316..35c46c704a7c 100644 +--- a/drivers/rpmsg/Makefile ++++ b/drivers/rpmsg/Makefile +@@ -10,3 +10,4 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o + obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o + obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o + obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o ++obj-$(CONFIG_RPMSG_THEAD_LIGHT) += light_rpmsg.o +diff --git a/drivers/rpmsg/light_rpmsg.c b/drivers/rpmsg/light_rpmsg.c +new file mode 100644 +index 000000000000..cecda6e251a9 +--- /dev/null ++++ b/drivers/rpmsg/light_rpmsg.c +@@ -0,0 +1,864 @@ ++/* ++ * Copyright (C) 2023 Alibaba Group Holding Limited. ++ * ++ * derived from the omap-rpmsg implementation. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/notifier.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_device.h> ++#include <linux/of_irq.h> ++#include <linux/platform_device.h> ++#include <linux/rpmsg.h> ++#include <linux/slab.h> ++#include <linux/virtio.h> ++#include <linux/virtio_config.h> ++#include <linux/virtio_ids.h> ++#include <linux/virtio_ring.h> ++#include <linux/light_rpmsg.h> ++#include <linux/delay.h> ++#include <linux/regmap.h> ++#include <linux/mfd/syscon.h> ++#include <linux/debugfs.h> ++#include <linux/err.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/mailbox_client.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++#include <linux/workqueue.h> ++#include <linux/light_rpmsg.h> ++ ++#define MBOX_MAX_MSG_LEN 28 ++#define WJ_MBOX_SEND_MAX_MESSAGE_LENGTH 28 ++#define HEXDUMP_BYTES_PER_LINE 28 ++#define HEXDUMP_LINE_LEN ((HEXDUMP_BYTES_PER_LINE * 4) + 2) ++#define HEXDUMP_MAX_LEN (HEXDUMP_LINE_LEN * \ ++ (MBOX_MAX_MSG_LEN / HEXDUMP_BYTES_PER_LINE)) ++ ++//extern struct light_rpmsg_vproc *pri_rpdev; ++static struct dentry *root_debugfs_dir; ++ ++struct mbox_client_light_device { ++ struct device *dev; ++ void __iomem *tx_mmio; ++ void __iomem *rx_mmio; ++ struct mbox_chan *tx_channel; ++ struct mbox_chan *rx_channel; ++ char *rx_buffer; ++ struct regmap *audio_mbox_regmap; ++ char *message; ++ spinlock_t lock; ++}; ++ ++struct mbox_client_light_device *tdev_priv; ++ ++static volatile uint32_t *p_mbox_reg; ++static volatile uint32_t *p_mbox_reg1; ++static volatile uint32_t *p_mbox_reg2; ++ ++/* ++ * For now, allocate 256 buffers of 512 bytes for each side. each buffer ++ * will then have 16B for the msg header and 496B for the payload. ++ * This will require a total space of 256KB for the buffers themselves, and ++ * 3 pages for every vring (the size of the vring depends on the number of ++ * buffers it supports). ++ */ ++#define RPMSG_NUM_BUFS (512) ++//#define RPMSG_BUF_SIZE (512) ++//#define RPMSG_BUFS_SPACE (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE) ++ ++/* ++ * The alignment between the consumer and producer parts of the vring. ++ * Note: this is part of the "wire" protocol. If you change this, you need ++ * to update your BIOS image as well ++ */ ++#define RPMSG_VRING_ALIGN (4096) ++ ++/* With 256 buffers, our vring will occupy 3 pages */ ++#define RPMSG_RING_SIZE ((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \ ++ RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE) ++ ++#define to_light_virdev(vd) container_of(vd, struct light_virdev, vdev) ++#define to_light_rpdev(vd, id) container_of(vd, struct light_rpmsg_vproc, ivdevid) ++ ++struct light_rpmsg_vq_info { ++ __u16 num; /* number of entries in the virtio_ring */ ++ __u16 vq_id; /* a globaly unique index of this virtqueue */ ++ void *addr; /* address where we mapped the virtio ring */ ++ struct light_rpmsg_vproc *rpdev; ++}; ++ ++static u64 light_rpmsg_get_features(struct virtio_device *vdev) ++{ ++ /* VIRTIO_RPMSG_F_NS has been made private */ ++ return 1 << 0; ++} ++ ++static int light_rpmsg_finalize_features(struct virtio_device *vdev) ++{ ++ /* Give virtio_ring a chance to accept features */ ++ vring_transport_features(vdev); ++ return 0; ++} ++ ++/* kick the remote processor, and let it know which virtqueue to poke at */ ++static bool light_rpmsg_notify(struct virtqueue *vq) ++{ ++ unsigned int mu_rpmsg = 0; ++ int ret; ++ struct light_rpmsg_vq_info *rpvq = vq->priv; ++ ++#ifdef CONFIG_PM_SLEEP ++ if(rpvq->rpdev->sleep_flag) { ++ dev_err(tdev_priv->dev, "dev in deep sleep, Channel cannot do Tx+++\n"); ++ return -EINVAL; ++ } ++#endif ++ ++ mu_rpmsg = rpvq->vq_id << 16; ++ mutex_lock(&rpvq->rpdev->lock); ++ ++ //pr_info("light rpmsg: notify %d\n", rpvq->rpdev->first_notify); ++ if (unlikely(rpvq->rpdev->first_notify > 0)) { ++ rpvq->rpdev->first_notify--; ++ if (!tdev_priv->tx_channel) { ++ dev_err(tdev_priv->dev, "Channel cannot do Tx+++\n"); ++ return -EINVAL; ++ } ++ ++ ret = mbox_send_message(tdev_priv->tx_channel, "Hello, Queue!"); ++ } else { ++ *p_mbox_reg1 |= 1 << 0; ++ *p_mbox_reg2 |= 1 << 0; ++ } ++ mutex_unlock(&rpvq->rpdev->lock); ++ ++ return true; ++} ++ ++static int light_mu_rpmsg_callback(struct notifier_block *this, ++ unsigned long index, void *data) ++{ ++ u32 mu_msg = (phys_addr_t) data; ++ struct light_virdev *virdev; ++ ++ virdev = container_of(this, struct light_virdev, nb); ++ ++ pr_debug("light rpmsg: %s notifier_call mu_msg: 0x%x\n", __func__, mu_msg); ++ /* ignore vq indices which are clearly not for us */ ++ mu_msg = mu_msg >> 16; ++ if (mu_msg < virdev->base_vq_id || mu_msg > virdev->base_vq_id + 1) { ++ pr_debug("light rpmsg: mu_msg 0x%x is invalid\n", mu_msg); ++ //return NOTIFY_DONE; ++ } ++ ++ mu_msg -= virdev->base_vq_id; ++ pr_debug("%smu_msg 0x%xbase_vq_id 0x%xvirdev num_of_vqs0x%x\n", __func__, mu_msg, virdev->base_vq_id, virdev->num_of_vqs); ++ ++ /* ++ * Currently both PENDING_MSG and explicit-virtqueue-index ++ * messaging are supported. ++ * Whatever approach is taken, at this point 'mu_msg' contains ++ * the index of the vring which was just triggered. ++ */ ++ //if (mu_msg < virdev->num_of_vqs) ++ vring_interrupt(mu_msg, virdev->vqmu_msg); ++ ++ return NOTIFY_DONE; ++} ++ ++static int light_mu_rpmsg_register_nb(struct light_rpmsg_vproc *rpdev, ++ struct notifier_block *nb) ++{ ++ if ((rpdev == NULL) || (nb == NULL)) ++ return -EINVAL; ++ ++ blocking_notifier_chain_register(&(rpdev->notifier), nb); ++ ++ return 0; ++} ++ ++static int light_mu_rpmsg_unregister_nb(struct light_rpmsg_vproc *rpdev, ++ struct notifier_block *nb) ++{ ++ if ((rpdev == NULL) || (nb == NULL)) ++ return -EINVAL; ++ ++ blocking_notifier_chain_unregister(&(rpdev->notifier), nb); ++ ++ return 0; ++} ++ ++static struct virtqueue *rp_find_vq(struct virtio_device *vdev, ++ unsigned int index, ++ void (*callback)(struct virtqueue *vq), ++ const char *name, ++ bool ctx) ++{ ++ struct light_virdev *virdev = to_light_virdev(vdev); ++ struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev, ++ virdev->base_vq_id / 2); ++ struct light_rpmsg_vq_info *rpvq; ++ struct virtqueue *vq; ++ int err; ++ //static void __iomem *brd_io; ++ ++ rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL); ++ if (!rpvq) ++ return ERR_PTR(-ENOMEM); ++ ++ /* ioremap'ing normal memory, so we cast away sparse's complaints */ ++ //rpvq->addr = (__force void *) ioremap_nocache(virdev->vringindex, ++ // RPMSG_RING_SIZE); ++ rpvq->addr = (__force void *) ioremap(virdev->vringindex, ++ RPMSG_RING_SIZE); ++ if (!rpvq->addr) { ++ err = -ENOMEM; ++ goto free_rpvq; ++ } ++ ++ p_mbox_reg = ioremap(0xffefc48000,25); ++ p_mbox_reg1 = p_mbox_reg + 4; ++ p_mbox_reg2 = p_mbox_reg + 5; ++ ++ memset_io(rpvq->addr, 0, RPMSG_RING_SIZE); ++ ++ pr_debug("vring%d: phys 0x%x, virt 0x%p\n", index, virdev->vringindex, ++ rpvq->addr); ++ ++ vq = vring_new_virtqueue(index, RPMSG_NUM_BUFS / 2, RPMSG_VRING_ALIGN, ++ vdev, true, ctx, ++ rpvq->addr, ++ light_rpmsg_notify, callback, ++ name); ++ if (!vq) { ++ pr_err("light rpmsg: vring_new_virtqueue failed\n"); ++ err = -ENOMEM; ++ goto unmap_vring; ++ } ++ ++ virdev->vqindex = vq; ++ vq->priv = rpvq; ++ /* system-wide unique id for this virtqueue */ ++ rpvq->vq_id = virdev->base_vq_id + index; ++ rpvq->rpdev = rpdev; ++ mutex_init(&rpdev->lock); ++ ++ return vq; ++ ++unmap_vring: ++ /* iounmap normal memory, so make sparse happy */ ++ iounmap((__force void __iomem *) rpvq->addr); ++free_rpvq: ++ kfree(rpvq); ++ return ERR_PTR(err); ++} ++ ++static void light_rpmsg_del_vqs(struct virtio_device *vdev) ++{ ++ struct virtqueue *vq, *n; ++ struct light_virdev *virdev = to_light_virdev(vdev); ++ struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev, ++ virdev->base_vq_id / 2); ++ ++ list_for_each_entry_safe(vq, n, &vdev->vqs, list) { ++ struct light_rpmsg_vq_info *rpvq = vq->priv; ++ ++ iounmap(rpvq->addr); ++ vring_del_virtqueue(vq); ++ kfree(rpvq); ++ } ++ ++ if (&virdev->nb) ++ light_mu_rpmsg_unregister_nb(rpdev, &virdev->nb); ++} ++ ++static int light_rpmsg_find_vqs(struct virtio_device *vdev, unsigned int nvqs, ++ struct virtqueue *vqs, ++ vq_callback_t *callbacks, ++ const char * const names, ++ const bool *ctx, ++ struct irq_affinity *desc) ++{ ++ struct light_virdev *virdev = to_light_virdev(vdev); ++ struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev, ++ virdev->base_vq_id / 2); ++ int i, err; ++ ++ /* we maintain two virtqueues per remote processor (for RX and TX) */ ++ if (nvqs != 2) ++ return -EINVAL; ++ ++ for (i = 0; i < nvqs; ++i) { ++ vqsi = rp_find_vq(vdev, i, callbacksi, namesi, ++ ctx ? ctxi : false); ++ if (IS_ERR(vqsi)) { ++ err = PTR_ERR(vqsi); ++ goto error; ++ } ++ } ++ ++ virdev->num_of_vqs = nvqs; ++ ++ virdev->nb.notifier_call = light_mu_rpmsg_callback; ++ light_mu_rpmsg_register_nb(rpdev, &virdev->nb); ++ ++ return 0; ++ ++error: ++ light_rpmsg_del_vqs(vdev); ++ return err; ++} ++ ++static void light_rpmsg_reset(struct virtio_device *vdev) ++{ ++ dev_dbg(&vdev->dev, "reset!\n"); ++} ++ ++static u8 light_rpmsg_get_status(struct virtio_device *vdev) ++{ ++ return 0; ++} ++ ++static void light_rpmsg_set_status(struct virtio_device *vdev, u8 status) ++{ ++ dev_dbg(&vdev->dev, "%s new status: %d\n", __func__, status); ++} ++ ++static void light_rpmsg_vproc_release(struct device *dev) ++{ ++ /* this handler is provided so driver core doesn't yell at us */ ++} ++ ++static struct virtio_config_ops light_rpmsg_config_ops = { ++ .get_features = light_rpmsg_get_features, ++ .finalize_features = light_rpmsg_finalize_features, ++ .find_vqs = light_rpmsg_find_vqs, ++ .del_vqs = light_rpmsg_del_vqs, ++ .reset = light_rpmsg_reset, ++ .set_status = light_rpmsg_set_status, ++ .get_status = light_rpmsg_get_status, ++}; ++ ++static struct light_rpmsg_vproc light_rpmsg_vprocs = { ++ { ++ .rproc_name = "m4", ++ }, ++ { ++ .rproc_name = "m4", ++ }, ++}; ++ ++static const struct of_device_id light_rpmsg_dt_ids = { ++ { .compatible = "light,light-rpmsg", .data = (void *)LIGHT_RPMSG, }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, light_rpmsg_dt_ids); ++ ++static int set_vring_phy_buf(struct platform_device *pdev, ++ struct light_rpmsg_vproc *rpdev, int vdev_nums) ++{ ++ struct resource *res; ++ resource_size_t size; ++ unsigned int start, end; ++ int i, ret = 0; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (res) { ++ size = resource_size(res); ++ start = res->start; ++ end = res->start + size; ++ for (i = 0; i < vdev_nums; i++) { ++ rpdev->ivdevi.vring0 = start; ++ rpdev->ivdevi.vring1 = start + ++ 0x8000; ++ start += 0x10000; ++ if (start > end) { ++ pr_err("Too small memory size %x!\n", ++ (u32)size); ++ ret = -EINVAL; ++ break; ++ } ++ } ++ } else { ++ return -ENOMEM; ++ } ++ ++ return ret; ++} ++ ++static void rpmsg_work_handler(struct work_struct *work) ++{ ++ u32 message = 0; ++ struct delayed_work *dwork = to_delayed_work(work); ++ struct light_rpmsg_vproc *rpdev = container_of(dwork, ++ struct light_rpmsg_vproc, rpmsg_work); ++ ++ //spin_lock_irqsave(&rpdev->mu_lock, flags); ++ blocking_notifier_call_chain(&(rpdev->notifier), 4, ++ (void *)(phys_addr_t)message); ++ //spin_unlock_irqrestore(&rpdev->mu_lock, flags); ++} ++ ++struct light_rpmsg_vproc *pri_rpdev; ++EXPORT_SYMBOL_GPL(pri_rpdev); ++ ++static int light_rpmsg_probe(struct platform_device *pdev) ++{ ++ int core_id, j, ret = 0; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = pdev->dev.of_node; ++ struct light_rpmsg_vproc *rpdev; ++ ++ if (of_property_read_u32(np, "multi-core-id", &core_id)) ++ core_id = 0; ++ rpdev = &light_rpmsg_vprocscore_id; ++ rpdev->core_id = core_id; ++ rpdev->variant = (enum light_rpmsg_variants)of_device_get_match_data(dev); ++ ++ spin_lock_init(&rpdev->mu_lock); ++ ++ pri_rpdev = rpdev; ++ ++ INIT_DELAYED_WORK(&(rpdev->rpmsg_work), rpmsg_work_handler); ++ BLOCKING_INIT_NOTIFIER_HEAD(&(rpdev->notifier)); ++#ifdef CONFIG_PM_SLEEP ++ sema_init(&rpdev->pm_sem, 0); ++#endif ++ pr_info("light rpmsg: Ready for cross core communication!\n"); ++ ++ ret = of_property_read_u32(np, "vdev-nums", &rpdev->vdev_nums); ++ if (ret) { ++ rpdev->vdev_nums = 1; ++ } ++ ++ if (rpdev->vdev_nums > MAX_VDEV_NUMS) { ++ pr_err("light rpmsg: vdev-nums exceed the max %d\n", MAX_VDEV_NUMS); ++ return -EINVAL; ++ } ++ ++ rpdev->first_notify = rpdev->vdev_nums; ++ ++ pr_info("light rpmsg: rproc_name = %s",rpdev->rproc_name); ++ if (!strcmp(rpdev->rproc_name, "m4")) { ++ ret = set_vring_phy_buf(pdev, rpdev, ++ rpdev->vdev_nums); ++ if (ret) { ++ pr_err("light rpmsg: No vring buffer.\n"); ++ return -ENOMEM; ++ } ++ } else { ++ pr_err("light rpmsg: No remote processor.\n"); ++ return -ENODEV; ++ } ++ ++ for (j = 0; j < rpdev->vdev_nums; j++) { ++ pr_debug("%s rpdev%d vdev%d: vring0 0x%x, vring1 0x%x\n", ++ __func__, rpdev->core_id, rpdev->vdev_nums, ++ rpdev->ivdevj.vring0, ++ rpdev->ivdevj.vring1); ++ rpdev->ivdevj.vdev.id.device = VIRTIO_ID_RPMSG; ++ rpdev->ivdevj.vdev.config = &light_rpmsg_config_ops; ++ rpdev->ivdevj.vdev.dev.parent = &pdev->dev; ++ rpdev->ivdevj.vdev.dev.release = light_rpmsg_vproc_release; ++ rpdev->ivdevj.base_vq_id = j * 2; ++ ++ ret = register_virtio_device(&rpdev->ivdevj.vdev); ++ if (ret) { ++ pr_err("light rpmsg: %s failed to register rpdev: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ } ++ platform_set_drvdata(pdev, rpdev); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++ ++typedef enum { ++ RPMSG_MAILBOX_TYPE_PM = 0xA0, ++ RPMSG_MAILBOX_TYPE_MAX ++} rpmsg_mailbox_message_type_en; ++ ++typedef enum { ++ RPMSG_PM_CTRL = 0x50, ++ RPMSG_PM_GET, ++ RPMSG_PM_STATUS, ++ RPMSG_PM_MAX ++} rpmsg_pm_message_type_en; ++ ++typedef enum { ++ LIGHT_PM_DISABLE = 0xA0, ++ LIGHT_PM_OFF, ++ LIGHT_PM_HW_VAD, ++ LIGHT_PM_TYPE_MAX ++} light_pm_type_en; ++ ++typedef enum { ++ LIGHT_PM_WAKEUP = 0x50, ++ LIGHT_PM_SLEEP, ++ LIGHT_PM_STATUS_MAX ++} light_pm_status_en; ++ ++#define MAX_PM_NOTIFY_TIME 10 ++#define MAX_PM_ASK_TIME 10 ++ ++static int light_rpmsg_sleep_notify(struct virtqueue *vq, light_pm_type_en type) ++{ ++ int ret; ++ struct light_rpmsg_vq_info *rpvq = vq->priv; ++ uint8_t sleep_ctrl4 = {RPMSG_MAILBOX_TYPE_PM, RPMSG_PM_CTRL, type, '\n'}; ++ mutex_lock(&rpvq->rpdev->lock); ++ ret = mbox_send_message(tdev_priv->tx_channel, sleep_ctrl); ++ if(ret < 0) { ++ pr_err("sleep notify faild %d", ret); ++ mutex_unlock(&rpvq->rpdev->lock); ++ return ret; ++ } ++ mutex_unlock(&rpvq->rpdev->lock); ++ return 0; ++} ++ ++static int light_rpmsg_sleep_ask(struct virtqueue *vq) ++{ ++ int ret; ++ struct light_rpmsg_vq_info *rpvq = vq->priv; ++ uint8_t sleep_get3 = {RPMSG_MAILBOX_TYPE_PM, RPMSG_PM_GET, '\n'}; ++ mutex_lock(&rpvq->rpdev->lock); ++ ret = mbox_send_message(tdev_priv->tx_channel, sleep_get); ++ if(ret < 0) { ++ pr_err("sleep ask send faild %d", ret); ++ mutex_unlock(&rpvq->rpdev->lock); ++ return ret; ++ } ++ mutex_unlock(&rpvq->rpdev->lock); ++ return 0; ++} ++ ++static int light_rpmsg_suspend(struct device *dev) ++ ++{ ++ int ret; ++ int try_num = 0; ++ struct light_rpmsg_vproc *rpdev = dev_get_drvdata(dev); ++ ++ //clk_disable_unprepare(rpdev->mu_clk); ++ printk("%s,%d,enter",__func__,__LINE__); ++ light_rpmsg_sleep_notify(rpdev->ivdev0.vq0, LIGHT_PM_OFF); ++ try_num++; ++ down_timeout(&rpdev->pm_sem, msecs_to_jiffies(200)); ++ while(!rpdev->sleep_flag) { ++ light_rpmsg_sleep_notify(rpdev->ivdev0.vq0, LIGHT_PM_OFF); ++ down_timeout(&rpdev->pm_sem, msecs_to_jiffies(200)); ++ if(try_num++ > MAX_PM_NOTIFY_TIME) { ++ pr_err("sleep notify faild after try %d time", MAX_PM_NOTIFY_TIME); ++ printk("%s,%d,try %d times, exist",__func__,__LINE__, try_num); ++ return -1; ++ } ++ } ++ printk("%s,%d,try %d times, exist",__func__,__LINE__, try_num); ++ return 0; ++} ++ ++static int light_rpmsg_resume(struct device *dev) ++{ ++ struct light_rpmsg_vproc *rpdev = dev_get_drvdata(dev); ++ int ret; ++ int try_num = 0; ++ printk("%s,%d,enter",__func__,__LINE__); ++ while(rpdev->sleep_flag) { ++ ret = light_rpmsg_sleep_ask(rpdev->ivdev0.vq0); ++ down_timeout(&rpdev->pm_sem, msecs_to_jiffies(200)); ++ if(try_num++ > MAX_PM_ASK_TIME) { ++ pr_err("sleep status check faild after try %d time", MAX_PM_ASK_TIME); ++ printk("%s,%d,try %d times, exist",__func__,__LINE__, try_num); ++ return -1; ++ } ++ } ++ printk("%s,%d,try %d times, exist",__func__,__LINE__, try_num); ++ return ret; ++} ++ ++#endif ++ ++static SIMPLE_DEV_PM_OPS(light_rpmsg_pm_ops, light_rpmsg_suspend, light_rpmsg_resume); ++ ++static struct platform_driver light_rpmsg_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "light-rpmsg", ++ .of_match_table = light_rpmsg_dt_ids, ++ .pm = &light_rpmsg_pm_ops, ++ }, ++ .probe = light_rpmsg_probe, ++}; ++ ++static int __init light_rpmsg_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&light_rpmsg_driver); ++ if (ret) ++ pr_err("light rpmsg: Unable to initialize\n"); ++ else ++ pr_info("light rpmsg: driver is registered.\n"); ++ ++ return ret; ++} ++ ++late_initcall(light_rpmsg_init); ++ ++static ssize_t mbox_client_light_message_write(struct file *filp, ++ const char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mbox_client_light_device *tdev = filp->private_data; ++ void *data; ++ int ret; ++ ++ if (!tdev->tx_channel) { ++ dev_err(tdev->dev, "Channel cannot do Tx\n"); ++ return -EINVAL; ++ } ++ ++ if (count > WJ_MBOX_SEND_MAX_MESSAGE_LENGTH) ++ count = WJ_MBOX_SEND_MAX_MESSAGE_LENGTH; ++ ++ tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); ++ if (!tdev->message) ++ return -ENOMEM; ++ ++ ret = copy_from_user(tdev->message, userbuf, count); ++ if (ret) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ data = tdev->message; ++ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->message, MBOX_MAX_MSG_LEN, true); ++ ++ ret = mbox_send_message(tdev->tx_channel, data); ++ if (ret < 0) ++ dev_err(tdev->dev, "Failed to send message via mailbox\n"); ++ ++out: ++ kfree(tdev->message); ++ return ret < 0 ? ret : count; ++} ++ ++static ssize_t mbox_client_light_message_read(struct file *filp, ++ char __user *userbuf, ++ size_t count, loff_t *ppos) ++{ ++ struct mbox_client_light_device *tdev = filp->private_data; ++ unsigned long flags; ++ ++ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); ++ spin_lock_irqsave(&tdev->lock, flags); ++ memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); ++ spin_unlock_irqrestore(&tdev->lock, flags); ++ ++ return MBOX_MAX_MSG_LEN; ++} ++ ++static const struct file_operations mbox_client_light_message_ops = { ++ .write = mbox_client_light_message_write, ++ .read = mbox_client_light_message_read, ++ .open = simple_open, ++ .llseek = generic_file_llseek, ++}; ++ ++static int index_names = 0; ++static bool debugfs_dir_created = false; ++static const char* file_names = {"mbox-client0", "mbox-client1"}; ++ ++static int mbox_client_light_add_debugfs(struct platform_device *pdev, ++ struct mbox_client_light_device *tdev) ++{ ++ if (!debugfs_initialized()) ++ return 0; ++ ++ if (index_names > 2) { ++ dev_err(&pdev->dev, "Max device index is 2\n"); ++ return 0; ++ } ++ ++ if (!debugfs_dir_created) { ++ root_debugfs_dir = debugfs_create_dir("mailbox",NULL); ++ if (!root_debugfs_dir) { ++ dev_err(&pdev->dev, ++ "Failed to create mailbox debugfs\n"); ++ return -EINVAL; ++ } ++ debugfs_dir_created = true; ++ } ++ ++ debugfs_create_file(file_namesindex_names, 0600, root_debugfs_dir, ++ tdev, &mbox_client_light_message_ops); ++ ++ index_names++; ++ return 0; ++} ++ ++static void mbox_client_light_receive_message(struct mbox_client *client, ++ void *message) ++{ ++ struct mbox_client_light_device *tdev = dev_get_drvdata(client->dev); ++ char *data = message; ++ ++ spin_lock(&tdev->lock); ++ memcpy(tdev->rx_buffer, data, MBOX_MAX_MSG_LEN); ++ spin_unlock(&tdev->lock); ++ ++ //printk("mbox_client receive rpmsg_work\n"); ++ schedule_delayed_work(&(pri_rpdev->rpmsg_work), 0); ++#ifdef CONFIG_PM_SLEEP ++ if(data0 == RPMSG_MAILBOX_TYPE_PM && data1 == RPMSG_PM_STATUS) { ++ if(data2 == LIGHT_PM_WAKEUP) { ++ pri_rpdev->sleep_flag = 0; ++ up(&pri_rpdev->pm_sem); ++ printk("audio wakeup"); ++ } else if(data2 == LIGHT_PM_SLEEP) { ++ pri_rpdev->sleep_flag = 1; ++ up(&pri_rpdev->pm_sem); ++ printk("audio sleep"); ++ } ++ } ++#endif ++ //print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); ++} ++ ++static struct mbox_chan * ++mbox_client_light_request_channel(struct platform_device *pdev, ++ const char *name) ++{ ++ struct mbox_client *client; ++ struct mbox_chan *channel; ++ ++ client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); ++ if (!client) ++ return ERR_PTR(-ENOMEM); ++ ++ client->dev = &pdev->dev; ++ client->tx_block = true; ++ client->knows_txdone = false; ++ client->tx_tout = 500; ++ client->rx_callback = mbox_client_light_receive_message; ++ ++ channel = mbox_request_channel_byname(client, name); ++ if (IS_ERR(channel)) { ++ devm_kfree(&pdev->dev, client); ++ dev_warn(&pdev->dev, "Failed to request %s channel\n", name); ++ return NULL; ++ } ++ ++ return channel; ++} ++ ++static int mbox_client_light_probe(struct platform_device *pdev) ++{ ++ struct mbox_client_light_device *tdev; ++ struct device_node *np = pdev->dev.of_node; ++ int ret; ++ ++ static int chan_idx = 1; ++ ++ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); ++ if (!tdev) ++ return -ENOMEM; ++ ++ tdev_priv = tdev; ++ ++ if (!chan_idx) ++ tdev->tx_channel = mbox_client_light_request_channel(pdev, "902"); ++ else ++ tdev->tx_channel = mbox_client_light_request_channel(pdev, "906"); ++ ++ if (!tdev->tx_channel) { ++ dev_err(&pdev->dev, "Request channel failed\n"); ++ return -EPROBE_DEFER; ++ } ++ chan_idx++; ++ ++ /* In fact, rx_channel is same with tx_channel in C-SKY's mailbox */ ++ tdev->rx_channel = tdev->tx_channel; ++ ++ tdev->dev = &pdev->dev; ++ platform_set_drvdata(pdev, tdev); ++ ++ tdev->audio_mbox_regmap = syscon_regmap_lookup_by_phandle(np, "audio-mbox-regmap"); ++ if (IS_ERR(tdev->audio_mbox_regmap)) { ++ dev_err(&pdev->dev, "cannot find regmap for audio mbox register\n"); ++ } else { ++ dev_dbg(&pdev->dev, "audio_mbox_regmap ok\n"); ++ } ++ ++ spin_lock_init(&tdev->lock); ++ ++ tdev->rx_buffer = devm_kzalloc(&pdev->dev, ++ MBOX_MAX_MSG_LEN, GFP_KERNEL); ++ if (!tdev->rx_buffer) ++ return -ENOMEM; ++ ++ ret = mbox_client_light_add_debugfs(pdev, tdev); ++ if (ret) ++ return ret; ++ ++ dev_err(&pdev->dev, "Successfully registered\n"); ++ ++ return 0; ++} ++ ++static int mbox_client_light_remove(struct platform_device *pdev) ++{ ++ struct mbox_client_light_device *tdev = platform_get_drvdata(pdev); ++ ++ debugfs_remove_recursive(root_debugfs_dir); ++ ++ if (tdev->tx_channel) ++ mbox_free_channel(tdev->tx_channel); ++ ++ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) ++ mbox_free_channel(tdev->rx_channel); ++ ++ return 0; ++} ++ ++static const struct of_device_id mbox_client_light_match = { ++ { .compatible = "thead,light-mbox-client" }, ++ {}, ++}; ++ ++static struct platform_driver mbox_client_light_driver = { ++ .driver = { ++ .name = "thead,light-mbox-client", ++ .of_match_table = mbox_client_light_match, ++ }, ++ .probe = mbox_client_light_probe, ++ .remove = mbox_client_light_remove, ++}; ++module_platform_driver(mbox_client_light_driver); ++ ++MODULE_AUTHOR("Alibaba Group Holding Limited"); ++MODULE_DESCRIPTION("Thead Light mailbox IPC client driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig +index d21e75d69294..6ce6f6300055 100644 +--- a/drivers/soc/Kconfig ++++ b/drivers/soc/Kconfig +@@ -31,5 +31,6 @@ source "drivers/soc/ti/Kconfig" + source "drivers/soc/ux500/Kconfig" + source "drivers/soc/versatile/Kconfig" + source "drivers/soc/xilinx/Kconfig" ++source "drivers/soc/thead/Kconfig" + + endmenu +diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile +index 0706a27d13be..f34415578e9e 100644 +--- a/drivers/soc/Makefile ++++ b/drivers/soc/Makefile +@@ -30,8 +30,10 @@ obj-y += rockchip/ + obj-$(CONFIG_SOC_SAMSUNG) += samsung/ + obj-y += sifive/ + obj-y += sunxi/ ++obj-$(CONFIG_ARCH_SOPHGO) += sophgo/ + obj-$(CONFIG_ARCH_TEGRA) += tegra/ + obj-y += ti/ + obj-$(CONFIG_ARCH_U8500) += ux500/ + obj-$(CONFIG_PLAT_VERSATILE) += versatile/ + obj-y += xilinx/ ++obj-y += thead/ +diff --git a/drivers/soc/sophgo/Makefile b/drivers/soc/sophgo/Makefile +new file mode 100644 +index 000000000000..1e143d85aa17 +--- /dev/null ++++ b/drivers/soc/sophgo/Makefile +@@ -0,0 +1,3 @@ ++obj-$(CONFIG_ARCH_SOPHGO) += top/top_intc.o ++obj-$(CONFIG_ARCH_SOPHGO) += umcu/mcu.o ++obj-$(CONFIG_ARCH_SOPHGO) += tach/sophgo-tach.o +diff --git a/drivers/soc/sophgo/tach/sophgo-tach.c b/drivers/soc/sophgo/tach/sophgo-tach.c +new file mode 100644 +index 000000000000..77884d80eace +--- /dev/null ++++ b/drivers/soc/sophgo/tach/sophgo-tach.c +@@ -0,0 +1,330 @@ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/workqueue.h> ++#include <linux/delay.h> ++#include <linux/of.h> ++#include <linux/netlink.h> ++#include <net/sock.h> ++ ++#define DEV_NAME "sophgo-tach" ++#define MHZ 1000000 ++#define USER_PORT 100 ++#define USER_MSG 30 ++ ++struct fan_state { ++ unsigned int freq_num; ++ bool enable; ++}; ++ ++struct sophgo_fan_speed_device { ++ struct device *dev; ++ struct device *parent; ++ struct class *class; ++ dev_t devno; ++ u32 __iomem *regs; ++ struct delayed_work poll_queue; ++ struct fan_state fan_state; ++ struct mutex enable_lock; ++ struct mutex freqnum_lock; ++}; ++ ++static int fan_index; ++static struct class *sophgo_fan_speed_class; ++static struct sock *nl_fd; ++ ++static int send_msg(char *pbuf, uint16_t len) ++{ ++ struct sk_buff *nl_skb; ++ struct nlmsghdr *nlh; ++ int ret = 0; ++ ++ //alloc a new netlink message ++ nl_skb = nlmsg_new(len, GFP_ATOMIC); ++ if (!nl_skb) { ++ pr_err("sophgo_fan_speed, netlink alloc skb error!\n"); ++ return -ENOMEM; ++ } ++ ++ //add a new netlink message to skb ++ nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0); ++ if (nlh == NULL) { ++ pr_err("sophgo_fan_speed, nlmsg_put error!\n"); ++ nlmsg_free(nl_skb); ++ return -EFAULT; ++ } ++ ++ memcpy(nlmsg_data(nlh), pbuf, len); ++ ret = netlink_unicast(nl_fd, nl_skb, USER_PORT, MSG_DONTWAIT); ++ ++ return ret; ++} ++ ++static void recv_cb(struct sk_buff *skb) ++{ ++ struct nlmsghdr *nlh = NULL; ++ void *data = NULL; ++ ++ if (skb->len >= nlmsg_total_size(0)) { ++ nlh = nlmsg_hdr(skb); ++ data = nlmsg_data(nlh); ++ if (data) { ++ pr_info("sophgo_fan_speed, kernel receive data: %s\n", (int8_t *)data); ++ send_msg(data, nlmsg_len(nlh)); ++ } ++ } ++} ++ ++struct netlink_kernel_cfg cfg = { ++ .input = recv_cb, ++}; ++ ++static void fan_speed_check(struct work_struct *work) ++{ ++ struct sophgo_fan_speed_device *sophgo_fan = container_of(work, ++ struct sophgo_fan_speed_device, poll_queue.work); ++ int speed, ret = 0; ++ char buf64; ++ ++ speed = readl(sophgo_fan->regs + 1); ++ if (speed == 0) { ++ dev_dbg(sophgo_fan->dev, "fan stop!"); ++ ret = snprintf(buf, 32, "%s fan stop!\n", dev_name(sophgo_fan->dev)); ++ if (ret <= 0 || ret > 32) { ++ dev_err(sophgo_fan->dev, "%s snprintf failed\n", __func__); ++ return; ++ } ++ ret = send_msg(buf, sizeof(buf)); ++ if (ret < 0) ++ dev_dbg(sophgo_fan->dev, "%s send msg failed, ret=%d\n", __func__, ret); ++ } ++ mod_delayed_work(system_freezable_wq, &sophgo_fan->poll_queue, ++ round_jiffies(msecs_to_jiffies(5000))); ++} ++ ++static void fan_speed_enable(bool enalbe, struct sophgo_fan_speed_device *sophgo_fan) ++{ ++ if (enalbe) { ++ cancel_delayed_work(&sophgo_fan->poll_queue); ++ writel(sophgo_fan->fan_state.freq_num, sophgo_fan->regs); ++ mod_delayed_work(system_freezable_wq, &sophgo_fan->poll_queue, ++ round_jiffies(msecs_to_jiffies(5000))); ++ sophgo_fan->fan_state.enable = true; ++ } else { ++ cancel_delayed_work(&sophgo_fan->poll_queue); ++ writel(0, sophgo_fan->regs); ++ sophgo_fan->fan_state.enable = false; ++ } ++} ++ ++static ssize_t freq_num_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct sophgo_fan_speed_device *sophgo_fan; ++ ++ sophgo_fan = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", sophgo_fan->fan_state.freq_num); ++} ++ ++static ssize_t freq_num_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ int val, ret = 0; ++ struct sophgo_fan_speed_device *sophgo_fan; ++ ++ sophgo_fan = dev_get_drvdata(dev); ++ ++ ret = kstrtoint(buf, 0, &val); ++ if (ret) ++ return ret; ++ ++ if (val < (MHZ/10) || val > (1000*MHZ)) ++ ret = -EINVAL; ++ ++ mutex_lock(&sophgo_fan->freqnum_lock); ++ sophgo_fan->fan_state.freq_num = val; ++ mutex_unlock(&sophgo_fan->freqnum_lock); ++ ++ return ret ? : size; ++} ++ ++static ssize_t enable_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct sophgo_fan_speed_device *sophgo_fan; ++ ++ sophgo_fan = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%d\n", sophgo_fan->fan_state.enable); ++} ++ ++static ssize_t enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ int val, ret = 0; ++ struct sophgo_fan_speed_device *sophgo_fan; ++ ++ sophgo_fan = dev_get_drvdata(dev); ++ ++ ret = kstrtoint(buf, 0, &val); ++ if (ret) ++ return ret; ++ ++ mutex_lock(&sophgo_fan->enable_lock); ++ switch (val) { ++ case 0: ++ fan_speed_enable(false, sophgo_fan); ++ break; ++ case 1: ++ fan_speed_enable(true, sophgo_fan); ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ mutex_unlock(&sophgo_fan->enable_lock); ++ ++ return ret ? : size; ++} ++ ++static ssize_t fan_speed_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int ret = -1; ++ struct sophgo_fan_speed_device *sophgo_fan; ++ ++ sophgo_fan = dev_get_drvdata(dev); ++ ret = snprintf(buf, 32, "fan_speed:%d\n", readl(sophgo_fan->regs + 1)); ++ if (ret <= 0 || ret > 32) { ++ dev_err(sophgo_fan->dev, "%s snprintf failed %d\n", __func__, ret); ++ return -EFAULT; ++ } ++ dev_dbg(sophgo_fan->dev, "%s\n", buf); ++ return ret; ++} ++ ++static DEVICE_ATTR_RW(enable); ++static DEVICE_ATTR_RW(freq_num); ++static DEVICE_ATTR_RO(fan_speed); ++ ++static struct attribute *fan_speed_attrs = { ++ &dev_attr_enable.attr, ++ &dev_attr_freq_num.attr, ++ &dev_attr_fan_speed.attr, ++ NULL, ++}; ++ATTRIBUTE_GROUPS(fan_speed); ++ ++static int sophgo_fan_speed_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ struct sophgo_fan_speed_device *sophgo_fan; ++ char dev_name32; ++ int ret; ++ ++ sophgo_fan = devm_kzalloc(&pdev->dev, sizeof(*sophgo_fan), GFP_KERNEL); ++ if (sophgo_fan == NULL) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ sophgo_fan->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(sophgo_fan->regs)) ++ return PTR_ERR(sophgo_fan->regs); ++ ++ ret = snprintf(dev_name, 15, "%s-%d", DEV_NAME, fan_index++); ++ if (ret <= 0 || ret > 15) { ++ dev_err(&pdev->dev, "%s snprintf failed\n", __func__); ++ return -EINVAL; ++ } ++ ret = alloc_chrdev_region(&sophgo_fan->devno, 0, 1, dev_name); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "register chrdev error\n"); ++ return ret; ++ } ++ sophgo_fan->class = sophgo_fan_speed_class; ++ sophgo_fan->dev = device_create(sophgo_fan->class, sophgo_fan->parent, ++ sophgo_fan->devno, sophgo_fan, dev_name); ++ if (IS_ERR(sophgo_fan->dev)) { ++ ret = PTR_ERR(sophgo_fan->dev); ++ dev_err(&pdev->dev, "create device failed\n"); ++ unregister_chrdev_region(sophgo_fan->devno, 1); ++ return ret; ++ } ++ ++ //as fan source clk 100M, we advise to set freq num 100M ++ sophgo_fan->fan_state.freq_num = 100*MHZ; ++ mutex_init(&sophgo_fan->freqnum_lock); ++ mutex_init(&sophgo_fan->enable_lock); ++ ++ platform_set_drvdata(pdev, sophgo_fan); ++ INIT_DELAYED_WORK(&sophgo_fan->poll_queue, fan_speed_check); ++ ++ return 0; ++} ++ ++static int sophgo_fan_speed_remove(struct platform_device *pdev) ++{ ++ struct sophgo_fan_speed_device *sophgo_fan = platform_get_drvdata(pdev); ++ ++ cancel_delayed_work(&sophgo_fan->poll_queue); ++ device_destroy(sophgo_fan->class, sophgo_fan->devno); ++ unregister_chrdev_region(sophgo_fan->devno, 1); ++ kfree(sophgo_fan); ++ sophgo_fan = NULL; ++ return 0; ++} ++ ++static const struct of_device_id sophgo_fan_speed_of_match = { ++ { ++ .compatible = "sophgo,sophgo-tach", ++ }, ++ {} ++}; ++ ++static struct platform_driver sophgo_fan_speed_driver = { ++ .probe = sophgo_fan_speed_probe, ++ .remove = sophgo_fan_speed_remove, ++ .driver = { ++ .name = "sophgo,sophgo-tach", ++ .of_match_table = sophgo_fan_speed_of_match, ++ }, ++}; ++ ++static int __init sophgo_fan_speed_init(void) ++{ ++ sophgo_fan_speed_class = class_create(DEV_NAME); ++ if (IS_ERR(sophgo_fan_speed_class)) { ++ pr_err("class create failed\n"); ++ return PTR_ERR(sophgo_fan_speed_class); ++ } ++ sophgo_fan_speed_class->dev_groups = fan_speed_groups; ++ ++ nl_fd = netlink_kernel_create(&init_net, USER_MSG, &cfg); ++ if (!nl_fd) { ++ pr_err("sophgo_fan_speed, cannot create netlink socket!\n"); ++ return -1; ++ } ++ fan_index = 0; ++ return platform_driver_register(&sophgo_fan_speed_driver); ++} ++ ++static void __exit sophgo_fan_speed_exit(void) ++{ ++ class_destroy(sophgo_fan_speed_class); ++ if (nl_fd) { ++ netlink_kernel_release(nl_fd); ++ nl_fd = NULL; ++ } ++} ++ ++module_init(sophgo_fan_speed_init); ++module_exit(sophgo_fan_speed_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Xiao Wang"); ++MODULE_DESCRIPTION("minimal module"); ++MODULE_VERSION("ALPHA"); +diff --git a/drivers/soc/sophgo/top/top_intc.c b/drivers/soc/sophgo/top/top_intc.c +new file mode 100644 +index 000000000000..2577137fbc4f +--- /dev/null ++++ b/drivers/soc/sophgo/top/top_intc.c +@@ -0,0 +1,412 @@ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/of.h> ++#include <linux/of_platform.h> ++#include <linux/of_pci.h> ++#include <linux/msi.h> ++#include <linux/irq.h> ++#include <linux/irqdomain.h> ++#include <linux/irqchip/chained_irq.h> ++ ++#define MAX_IRQ_NUMBER 32 ++#define TOP_INTC_NUM 2 ++/* ++ * here we assume all plic hwirq and tic hwirq should ++ * be contiguous. ++ * topc_intc hwirq is index of bitmap (both software and ++ * hardware), and starts from 0. ++ * so we use tic hwirq as index to get plic hwirq and its ++ * irq data. ++ * when used as a msi parent, tic hwirq is written to Top ++ * reg for triggering irq by a PCIe device. ++ * ++ * now we pre-requested plic interrupt, but may try request ++ * plic interrupt when needed, like gicp_irq_domain_alloc. ++ */ ++struct top_intc_data { ++ struct platform_device *pdev; ++ int irq_num; ++ struct irq_domain *domain; ++ struct irq_chip *chip; ++ int for_msi; ++ int reg_bitwidth; ++ ++ DECLARE_BITMAP(irq_bitmap, MAX_IRQ_NUMBER); ++ spinlock_t lock; ++ ++ void __iomem *reg_sta; ++ void __iomem *reg_set; ++ void __iomem *reg_clr; ++ ++ phys_addr_t reg_set_phys; ++ ++ irq_hw_number_t plic_hwirqsMAX_IRQ_NUMBER; ++ int plic_irqsMAX_IRQ_NUMBER; ++ struct irq_data *plic_irq_datasMAX_IRQ_NUMBER; ++ int tic_to_plicMAX_IRQ_NUMBER; // mapping from tic hwirq to plic hwirq ++}; ++ ++// workaround for using in other modules ++struct top_intc_data *tic_dataTOP_INTC_NUM; ++ ++struct irq_domain *cdns_pcie_get_parent_irq_domain(int intc_id) ++{ ++ if (intc_id >= TOP_INTC_NUM) ++ return NULL; ++ ++ if (tic_dataintc_id) ++ return tic_dataintc_id->domain; ++ else ++ return NULL; ++} ++ ++static int top_intc_domain_translate(struct irq_domain *d, ++ struct irq_fwspec *fwspec, ++ unsigned long *hwirq, ++ unsigned int *type) ++{ ++ struct top_intc_data *data = d->host_data; ++ ++ if (fwspec->param_count != 2) ++ return -EINVAL; ++ if (fwspec->param1 >= data->irq_num) ++ return -EINVAL; ++ ++ *hwirq = fwspec->param0; ++ *type = fwspec->param1 & IRQ_TYPE_SENSE_MASK; ++ pr_debug("%s hwirq %d, flag %d\n", __func__, fwspec->param0, fwspec->param1); ++ return 0; ++} ++ ++static int top_intc_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs, ++ void *args) ++{ ++ unsigned long flags; ++ irq_hw_number_t hwirq; ++ int i, type, ret = -1; ++ struct top_intc_data *data = domain->host_data; ++ ++ if (data->for_msi) { ++ // dynamically alloc hwirq ++ spin_lock_irqsave(&data->lock, flags); ++ ret = bitmap_find_free_region(data->irq_bitmap, data->irq_num, ++ order_base_2(nr_irqs)); ++ spin_unlock_irqrestore(&data->lock, flags); ++ ++ if (ret < 0) { ++ pr_err("%s failed to alloc irq %d, total %d\n", __func__, virq, nr_irqs); ++ return -ENOSPC; ++ } ++ ++ hwirq = ret; ++ for (i = 0; i < nr_irqs; i++) { ++ irq_domain_set_info(domain, virq + i, hwirq + i, ++ data->chip, ++ data, handle_edge_irq, ++ NULL, NULL); ++ data->tic_to_plichwirq + i = data->plic_hwirqshwirq + i; ++ } ++ } else { ++ // try use hwirq specified in parameter ++ ret = top_intc_domain_translate(domain, args, &hwirq, &type); ++ if (ret) { ++ pr_err("%s failed to translate virq %d, %d\n", __func__, virq, ret); ++ return ret; ++ } ++ ++ // try to occupy bitmap for the given hwirq ++ spin_lock_irqsave(&data->lock, flags); ++ ret = bitmap_allocate_region(data->irq_bitmap, hwirq, order_base_2(1)); ++ spin_unlock_irqrestore(&data->lock, flags); ++ if (ret < 0) { ++ pr_err("%s virq %d found hwirq %ld occupied\n", __func__, virq, hwirq); ++ return -EBUSY; ++ } ++ ++ irq_domain_set_info(domain, virq, hwirq, ++ data->chip, ++ data, handle_edge_irq, ++ NULL, NULL); ++ ++ // explicitly set parent ++ data->tic_to_plichwirq = data->plic_hwirqshwirq; ++ } ++ ++ pr_debug("%s hwirq %ld, irq %d, plic irq %d, total %d\n", __func__, ++ hwirq, virq, data->plic_irqshwirq, nr_irqs); ++ return 0; ++} ++ ++static void top_intc_domain_free(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs) ++{ ++ struct irq_data *d = irq_domain_get_irq_data(domain, virq); ++ struct top_intc_data *data = irq_data_get_irq_chip_data(d); ++ unsigned long flags; ++ ++ pr_debug("%s hwirq %ld, irq %d, total %d\n", __func__, d->hwirq, virq, nr_irqs); ++ ++ spin_lock_irqsave(&data->lock, flags); ++ bitmap_release_region(data->irq_bitmap, d->hwirq, ++ order_base_2(nr_irqs)); ++ spin_unlock_irqrestore(&data->lock, flags); ++} ++ ++static const struct irq_domain_ops top_intc_domain_ops = { ++ .translate = top_intc_domain_translate, ++ .alloc = top_intc_domain_alloc, ++ .free = top_intc_domain_free, ++}; ++ ++static void top_intc_ack_irq(struct irq_data *d) ++{ ++ struct top_intc_data *data = irq_data_get_irq_chip_data(d); ++ int reg_off, bit_off; ++ struct irq_data *plic_irq_data = data->plic_irq_datasd->hwirq; ++ ++ reg_off = d->hwirq / data->reg_bitwidth; ++ bit_off = d->hwirq - data->reg_bitwidth * reg_off; ++ writel(1 << bit_off, (unsigned int *)data->reg_clr + reg_off); ++ ++ pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq, ++ plic_irq_data->domain->name, plic_irq_data->hwirq); ++ if (plic_irq_data->chip->irq_ack) ++ plic_irq_data->chip->irq_ack(plic_irq_data); ++} ++ ++static void top_intc_mask_irq(struct irq_data *d) ++{ ++ struct top_intc_data *data = irq_data_get_irq_chip_data(d); ++ struct irq_data *plic_irq_data = data->plic_irq_datasd->hwirq; ++ ++ pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq, ++ plic_irq_data->domain->name, plic_irq_data->hwirq); ++ plic_irq_data->chip->irq_mask(plic_irq_data); ++} ++ ++static void top_intc_unmask_irq(struct irq_data *d) ++{ ++ struct top_intc_data *data = irq_data_get_irq_chip_data(d); ++ struct irq_data *plic_irq_data = data->plic_irq_datasd->hwirq; ++ ++ pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq, ++ plic_irq_data->domain->name, plic_irq_data->hwirq); ++ plic_irq_data->chip->irq_unmask(plic_irq_data); ++} ++ ++static void top_intc_setup_msi_msg(struct irq_data *d, struct msi_msg *msg) ++{ ++ struct top_intc_data *data = irq_data_get_irq_chip_data(d); ++ ++ msg->address_lo = lower_32_bits(data->reg_set_phys); ++ msg->address_hi = upper_32_bits(data->reg_set_phys); ++ msg->data = 1 << d->hwirq; ++ ++ pr_debug("%s msi#%d: address_hi %#x, address_lo %#x, data %#x\n", __func__, ++ (int)d->hwirq, msg->address_hi, msg->address_lo, msg->data); ++} ++ ++static int top_intc_set_affinity(struct irq_data *d, ++ const struct cpumask *mask, bool force) ++{ ++ struct top_intc_data *data = irq_data_get_irq_chip_data(d); ++ struct irq_data *plic_irq_data = data->plic_irq_datasd->hwirq; ++ ++ irq_data_update_effective_affinity(d, mask); ++ if (plic_irq_data->chip->irq_set_affinity) ++ return plic_irq_data->chip->irq_set_affinity(plic_irq_data, mask, force); ++ else ++ return -EINVAL; ++} ++ ++static int top_intc_set_type(struct irq_data *d, u32 type) ++{ ++ /* ++ * dummy function, so __irq_set_trigger can continue to set ++ * correct trigger type. ++ */ ++ return 0; ++} ++ ++static struct irq_chip top_intc_irq_chip = { ++ .name = "top-intc", ++ .irq_ack = top_intc_ack_irq, ++ .irq_mask = top_intc_mask_irq, ++ .irq_unmask = top_intc_unmask_irq, ++ .irq_compose_msi_msg = top_intc_setup_msi_msg, ++ .irq_set_affinity = top_intc_set_affinity, ++ .irq_set_type = top_intc_set_type, ++}; ++ ++static void top_intc_irq_handler(struct irq_desc *plic_desc) ++{ ++ struct irq_chip *plic_chip = irq_desc_get_chip(plic_desc); ++ struct top_intc_data *data = irq_desc_get_handler_data(plic_desc); ++ irq_hw_number_t plic_hwirq = irq_desc_get_irq_data(plic_desc)->hwirq; ++ irq_hw_number_t top_intc_hwirq; ++ int top_intc_irq, i, ret; ++ ++ chained_irq_enter(plic_chip, plic_desc); ++ ++ for (i = 0; i < data->irq_num; i++) { ++ if (data->tic_to_plici == plic_hwirq) ++ break; ++ } ++ if (i < data->irq_num) { ++ top_intc_hwirq = i; ++ top_intc_irq = irq_find_mapping(data->domain, top_intc_hwirq); ++ pr_debug("%s plic hwirq %ld, tic hwirq %ld, tic irq %d\n", __func__, ++ plic_hwirq, top_intc_hwirq, top_intc_irq); ++ if (top_intc_irq) ++ ret = generic_handle_irq(top_intc_irq); ++ pr_debug("%s handled tic irq %d, %d\n", __func__, top_intc_irq, ret); ++ } else { ++ pr_debug("%s not found tic hwirq for plic hwirq %ld\n", __func__, plic_hwirq); ++ // workaround, ack unexpected(unregistered) interrupt ++ writel(1 << (plic_hwirq - data->plic_hwirqs0), data->reg_clr); ++ } ++ ++ chained_irq_exit(plic_chip, plic_desc); ++} ++ ++static int top_intc_probe(struct platform_device *pdev) ++{ ++ struct top_intc_data *data; ++ struct resource *res; ++ struct fwnode_handle *fwnode = of_node_to_fwnode(pdev->dev.of_node); ++ int ret = 0, i; ++ int intc_id = 0; ++ ++ device_property_read_u32(&pdev->dev, "top-intc-id", &intc_id); ++ if (intc_id >= TOP_INTC_NUM) ++ return -EINVAL; ++ ++ // alloc private data ++ data = kzalloc(sizeof(struct top_intc_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, data); ++ data->pdev = pdev; ++ spin_lock_init(&data->lock); ++ ++ if (device_property_read_bool(&pdev->dev, "for-msi")) { ++ dev_info(&pdev->dev, "is a msi parent\n"); ++ data->for_msi = 1; ++ } ++ if (device_property_read_u32(&pdev->dev, "reg-bitwidth", &data->reg_bitwidth)) ++ data->reg_bitwidth = 32; ++ ++ // get register address ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sta"); ++ data->reg_sta = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(data->reg_sta)) { ++ dev_err(&pdev->dev, "failed map status register\n"); ++ ret = PTR_ERR(data->reg_sta); ++ goto out; ++ } ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set"); ++ data->reg_set = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(data->reg_set)) { ++ dev_err(&pdev->dev, "failed map set register\n"); ++ ret = PTR_ERR(data->reg_set); ++ goto out; ++ } ++ data->reg_set_phys = res->start; ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr"); ++ data->reg_clr = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(data->reg_clr)) { ++ dev_err(&pdev->dev, "failed map clear register\n"); ++ ret = PTR_ERR(data->reg_clr); ++ goto out; ++ } ++ ++ // get irq numbers ++ for (i = 0; i < ARRAY_SIZE(data->plic_hwirqs); i++) { ++ char name8; ++ int irq; ++ ++ snprintf(name, ARRAY_SIZE(name), "msi%d", i); ++ irq = platform_get_irq_byname(pdev, name); ++ if (irq < 0) ++ break; ++ ++ data->plic_irqsi = irq; ++ data->plic_irq_datasi = irq_get_irq_data(irq); ++ data->plic_hwirqsi = data->plic_irq_datasi->hwirq; ++ dev_dbg(&pdev->dev, "%s: plic hwirq %ld, plic irq %d\n", name, ++ data->plic_hwirqsi, data->plic_irqsi); ++ } ++ data->irq_num = i; ++ dev_dbg(&pdev->dev, "got %d plic irqs\n", data->irq_num); ++ ++ // create IRQ domain ++ data->domain = irq_domain_create_linear(fwnode, data->irq_num, ++ &top_intc_domain_ops, data); ++ if (!data->domain) { ++ dev_err(&pdev->dev, "create linear irq doamin failed\n"); ++ ret = -ENODEV; ++ goto out; ++ } ++ data->chip = &top_intc_irq_chip; ++ ++ /* ++ * workaround to deal with IRQ conflict with TPU driver, ++ * skip the firt IRQ and mark it as used. ++ */ ++ //bitmap_allocate_region(data->irq_bitmap, 0, order_base_2(1)); ++ for (i = 0; i < data->irq_num; i++) ++ irq_set_chained_handler_and_data(data->plic_irqsi, ++ top_intc_irq_handler, data); ++ ++ if (data->for_msi) { ++ irq_domain_update_bus_token(data->domain, DOMAIN_BUS_NEXUS); ++ if (tic_dataintc_id) ++ dev_err(&pdev->dev, "tic_data is not empty, %s\n", ++ dev_name(&tic_dataintc_id->pdev->dev)); ++ tic_dataintc_id = data; ++ } else { ++ /* ++ * populate child nodes. when test device node is a child, it will not be ++ * automatically enumerated as a platform device. ++ */ ++ of_platform_populate(pdev->dev.of_node, NULL, NULL, NULL); ++ } ++ return ret; ++ ++out: ++ if (data->reg_sta) ++ iounmap(data->reg_sta); ++ if (data->reg_set) ++ iounmap(data->reg_set); ++ if (data->reg_clr) ++ iounmap(data->reg_clr); ++ kfree(data); ++ return ret; ++} ++ ++static const struct of_device_id top_intc_of_match = { ++ { ++ .compatible = "sophgo,top-intc", ++ }, ++ {}, ++}; ++ ++static struct platform_driver top_intc_driver = { ++ .driver = { ++ .name = "sophgo,top-intc", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(top_intc_of_match), ++ }, ++ .probe = top_intc_probe, ++}; ++ ++static int __init top_intc_init(void) ++{ ++ return platform_driver_register(&top_intc_driver); ++} ++ ++arch_initcall(top_intc_init); +diff --git a/drivers/soc/sophgo/umcu/mcu.c b/drivers/soc/sophgo/umcu/mcu.c +new file mode 100644 +index 000000000000..bf419f1821ef +--- /dev/null ++++ b/drivers/soc/sophgo/umcu/mcu.c +@@ -0,0 +1,1144 @@ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/nvmem-consumer.h> ++#include <linux/i2c.h> ++#include <linux/err.h> ++#include <linux/hwmon.h> ++#include <linux/mutex.h> ++#include <linux/slab.h> ++ ++/* fixed MCU registers */ ++#define MCU_REG_BOARD_TYPE 0x00 ++#define MCU_REG_VERSION 0x01 ++#define MCU_REG_SOC_TEMP 0x04 ++#define MCU_REG_BOARD_TEMP 0x05 ++#define MCU_REG_PWROFF_REASON1 0x06 ++#define MCU_REG_PWROFF_REASON2 0x07 ++ ++#define MCU_REG_CRITICAL_ACTIONS 0x65 ++#define MCU_REG_CRITICAL_TEMP 0x66 ++#define MCU_REG_REPOWERON_TEMP 0x67 ++#define MCU_REG_KEEP_DDR_POWERON 0x68 ++ ++#define MCU_CRITICAL_ACTION_POWEROFF 0x2 ++#define MCU_CRITICAL_ACTION_REBOOT 0X1 ++ ++#define MANGO_BOARD_TYPE_MASK 1 << 7 ++ ++#ifndef assert ++#define assert(exp) WARN_ON(!(exp)) ++#endif ++ ++struct mcu_features { ++ u8 id; ++ char *proj; ++ char *soc; ++ char *chip; ++ ++ int board_type; ++ int mcu_ver; ++ int pcb_ver; ++ int soc_tmp; ++ int board_tmp; ++ int alert_status; ++ int alert_mask; ++ int rst_cnt; ++ int uptime; ++ int lock; ++ int power; ++ int power_tpu; ++ int brd_id; ++ int brd_ip; ++ ++ int critical_action; ++ int critical_temp; ++ int repoweron_temp; ++ int keep_ddr_poweron; ++ ++ char *alert_table16; ++}; ++ ++struct mcu_info { ++ u8 board_type; ++ u8 mcu_ver; ++ u8 pcb_ver; ++ u8 rst_cnt; ++ int updated; ++}; ++ ++struct mcu_ctx { ++ const struct mcu_features *features; ++ struct i2c_client *i2c; ++ struct mcu_info info; ++ u32 channel_config4; ++ struct hwmon_channel_info temp_info; ++ const struct hwmon_channel_info *channel_info3; ++ struct hwmon_chip_info chip; ++ struct mutex update_lock; ++ unsigned int hwmon_update_interval; /* in milliseconds */ ++}; ++ ++const struct mcu_features mcu_list = { ++ { ++ 0x80, "SG2042 EVB", "SG2042", "GD32", ++ 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1, ++ -1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS, ++ MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP, ++ MCU_REG_KEEP_DDR_POWERON, ++ { ++ "SoC overheat", ++ "Power supply overheat", ++ "Board overheat", ++ "Board overheat and shutdown", ++ "SoC overheat and shutdown", ++ "Power supply failure", ++ "12V power supply failure", ++ "SoC required reboot", ++ }, ++ }, ++ ++ { ++ 0x83, "SG2042 X4", "SG2042", "GD32", ++ 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1, ++ -1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS, ++ MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP, ++ MCU_REG_KEEP_DDR_POWERON, ++ { ++ "SoC overheat", ++ "Power supply overheat", ++ "Board overheat", ++ "Board overheat and shutdown", ++ "SoC overheat and shutdown", ++ "Power supply failure", ++ "12V power supply failure", ++ "SoC required reboot", ++ }, ++ }, ++ ++ { ++ 0x90, "MILKV PIONEER", "SG2042", "GD32", ++ 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1, ++ -1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS, ++ MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP, ++ MCU_REG_KEEP_DDR_POWERON, ++ { ++ "SoC overheat", ++ "Power supply overheat", ++ "Board overheat", ++ "Board overheat and shutdown", ++ "SoC overheat and shutdown", ++ "Power supply failure", ++ "12V power supply failure", ++ "SoC required reboot", ++ }, ++ }, ++}; ++ ++static const char help = ++"\n" ++"sys files description\n" ++"======================\n" ++"Bitmain unified mcu device driver\n" ++"You can get/set MCU though read/write operation\n" ++"eg. You can get fixed information though command\n" ++"$cat /sys/bus/i2c/0-0017/information\n" ++"You can set alert mask though command\n" ++"$echo 0xffff /sys/bus/i2c/0-0017/alert\n" ++"\n" ++"information\n" ++"-----------\n" ++"Fixed information during SoC uptime\n" ++"Read this file will return such information\n" ++"Write this file to force SoC re-get such information from MCU\n" ++"No matter what data you write to or just invoke write with a length of 0\n" ++"File pointer will move forward after read,\n" ++"write has no effect on file pointer\n" ++"\n" ++"temperature\n" ++"-----------\n" ++"Temperature value, sensors located on SoC and on board\n" ++"Read this file will return temperature of both in celsius\n" ++"Write is forbidden\n" ++"\n" ++"uptime\n" ++"------\n" ++"Uptime (from SoC poweron) in seconds\n" ++"Read will get this value, write is forbidden\n" ++"\n" ++"alert\n" ++"-----\n" ++"Alert control and status\n" ++"Read will get current alert status\n" ++"Write corresponding bit to 1 will mask this alert\n" ++"You can use 0x/0X for hex, 0 for octal\n" ++"other leading characters will be considered as decimal\n" ++"Values larger than 0xffff is forbidden\n" ++"\n"; ++ ++enum { ++ MCU_I2C_TYPE_U = 0, ++ MCU_I2C_TYPE_U8, ++ MCU_I2C_TYPE_U16, ++ MCU_I2C_TYPE_U32, ++ MCU_I2C_TYPE_U64, ++ MCU_I2C_TYPE_D, ++ MCU_I2C_TYPE_S8, ++ MCU_I2C_TYPE_S16, ++ MCU_I2C_TYPE_S32, ++ MCU_I2C_TYPE_S64, ++ MCU_I2C_TYPE_MAX, ++}; ++ ++static const char *mcu_i2c_type_listMCU_I2C_TYPE_MAX = { ++ MCU_I2C_TYPE_U = "u", ++ MCU_I2C_TYPE_U8 = "u8", ++ MCU_I2C_TYPE_U16 = "u16", ++ MCU_I2C_TYPE_U32 = "u32", ++ MCU_I2C_TYPE_U64 = "u64", ++ MCU_I2C_TYPE_D = "d", ++ MCU_I2C_TYPE_S8 = "s8", ++ MCU_I2C_TYPE_S16 = "s16", ++ MCU_I2C_TYPE_S32 = "s32", ++ MCU_I2C_TYPE_S64 = "s64", ++}; ++ ++static int check_token(char *token) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(mcu_i2c_type_list); ++i) { ++ if (strcmp(token, mcu_i2c_type_listi) == 0) ++ return i; ++ } ++ return -EINVAL; ++} ++ ++static inline struct device *i2c2dev(struct i2c_client *i2c) ++{ ++ return &i2c->dev; ++} ++ ++static int mcu_i2c_write_byte(struct i2c_client *i2c, int reg, u8 data) ++{ ++ int err; ++ ++ if (reg == -1) ++ return 0; ++ err = i2c_smbus_write_byte_data(i2c, reg, data); ++ dev_dbg(i2c2dev(i2c), "%d : %u\n", reg, data); ++ return err; ++} ++ ++static int mcu_i2c_read_byte(struct i2c_client *i2c, int reg) ++{ ++ int err; ++ ++ if (reg == -1) ++ return 0; ++ err = i2c_smbus_read_byte_data(i2c, reg); ++ dev_dbg(i2c2dev(i2c), "%d : %d\n", reg, err); ++ return err; ++} ++ ++static int mcu_i2c_write_block(struct i2c_client *i2c, int reg, ++ int len, void *data) ++{ ++ int err, i; ++ ++ if (reg == -1) ++ return 0; ++ ++ err = i2c_smbus_write_i2c_block_data(i2c, reg, len, data); ++ for (i = 0; i < len; ++i) ++ dev_dbg(i2c2dev(i2c), "%d : %u\n", reg + i, ((u8 *)data)i); ++ return err; ++} ++ ++static int mcu_i2c_read_block(struct i2c_client *i2c, int reg, ++ int len, void *data) ++{ ++ int err, i; ++ ++ if (reg == -1) ++ return 0; ++ ++ err = i2c_smbus_read_i2c_block_data(i2c, reg, len, data); ++ for (i = 0; i < len; ++i) ++ dev_dbg(i2c2dev(i2c), "%d : %u\n", reg + i, ((u8 *)data)i); ++ ++ return err; ++} ++ ++static int mcu_i2c_sreadf(struct i2c_client *i2c, const char *fmt, ...) ++{ ++ va_list arg; ++ const char *p = fmt; ++ const char *start, *end; ++ char token16; ++ int tokenlen; ++ int ret = -EINVAL; ++ int idx; ++ ++ if (fmt == NULL) ++ return -EINVAL; ++ ++ va_start(arg, fmt); ++ ++ while (*p) { ++ /* skip all % */ ++ while (*p == '%') ++ ++p; ++ start = p; ++ while (*p && *p != '%') ++ ++p; ++ /* now *p is ether \0 or % */ ++ end = p; ++ tokenlen = end - start; ++ if (tokenlen > sizeof(token) - 1) { ++ ret = -EINVAL; ++ goto end; ++ } ++ if (tokenlen == 0) ++ continue; ++ /* get this token */ ++ memcpy(token, start, tokenlen); ++ tokentokenlen = 0; /* terminat this string */ ++ idx = check_token(token); ++ if (idx < 0) { ++ ret = idx; ++ goto end; ++ } ++ ++ ret = mcu_i2c_read_byte(i2c, va_arg(arg, int)); ++ if (ret < 0) ++ goto end; ++ ++ switch (idx) { ++ case MCU_I2C_TYPE_U: ++ *va_arg(arg, unsigned int *) = ret; ++ break; ++ case MCU_I2C_TYPE_U8: ++ *va_arg(arg, u8 *) = ret; ++ break; ++ case MCU_I2C_TYPE_U16: ++ *va_arg(arg, u16 *) = ret; ++ break; ++ case MCU_I2C_TYPE_U32: ++ *va_arg(arg, u32 *) = ret; ++ break; ++ case MCU_I2C_TYPE_U64: ++ *va_arg(arg, u64 *) = ret; ++ break; ++ case MCU_I2C_TYPE_D: ++ *va_arg(arg, int *) = ret; ++ break; ++ case MCU_I2C_TYPE_S8: ++ *va_arg(arg, s8 *) = ret; ++ break; ++ case MCU_I2C_TYPE_S16: ++ *va_arg(arg, s16 *) = ret; ++ break; ++ case MCU_I2C_TYPE_S32: ++ *va_arg(arg, s32 *) = ret; ++ break; ++ case MCU_I2C_TYPE_S64: ++ *va_arg(arg, s64 *) = ret; ++ break; ++ default: ++ assert(false); ++ break; ++ } ++ } ++ ++ ret = 0; ++end: ++ va_end(arg); ++ return ret; ++} ++ ++/* sysfs callbacks */ ++ ++static inline struct i2c_client *dev2i2c(struct device *dev) ++{ ++ return container_of(dev, struct i2c_client, dev); ++} ++ ++static const inline struct mcu_features *dev2features(struct device *dev) ++{ ++ struct i2c_client *i2c = dev2i2c(dev); ++ struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c); ++ ++ return ctx->features; ++} ++ ++static ssize_t help_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ buf0 = 0; ++ strncpy(buf, help, PAGE_SIZE); ++ return strlen(buf); ++} ++ ++static int mcu_msg_append(char *base, unsigned long limit, ++ const char *fmt, ...) ++{ ++ int len = strlen(base); ++ va_list arg; ++ ++ va_start(arg, fmt); ++ len += vsnprintf(base + len, limit - len, fmt, arg); ++ va_end(arg); ++ return len; ++} ++ ++ssize_t info_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *i2c = dev2i2c(dev); ++ struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c); ++ struct mcu_info *info = &ctx->info; ++ const struct mcu_features *features = ctx->features; ++ int err; ++ ++ if (info->updated == 0) { ++ /* get information from mcu through i2c */ ++ err = mcu_i2c_sreadf(i2c, "%u8%u8%u8%u8", ++ features->board_type, &info->board_type, ++ features->mcu_ver, &info->mcu_ver, ++ features->pcb_ver, &info->pcb_ver, ++ features->rst_cnt, &info->rst_cnt); ++ if (err) ++ return err; ++ info->updated = 1; ++ } ++ ++ /* convert to json text */ ++ mcu_msg_append(buf, PAGE_SIZE, "{\n"); ++ mcu_msg_append(buf, PAGE_SIZE, "\t\"model\": \"%s\",\n", features->proj); ++ mcu_msg_append(buf, PAGE_SIZE, "\t\"chip\": \"%s\",\n", features->soc); ++ mcu_msg_append(buf, PAGE_SIZE, "\t\"mcu\": \"%s\",\n", features->chip); ++ mcu_msg_append(buf, PAGE_SIZE, "\t\"board type\": \"0x%02X\",\n", info->board_type); ++ mcu_msg_append(buf, PAGE_SIZE, "\t\"mcu version\": \"0x%02X\",\n", info->mcu_ver); ++ mcu_msg_append(buf, PAGE_SIZE, "\t\"pcb version\": \"0x%02X\",\n", info->pcb_ver); ++ mcu_msg_append(buf, PAGE_SIZE, "\t\"reset count\": %u\n", info->rst_cnt); ++ err = mcu_msg_append(buf, PAGE_SIZE, "}\n"); ++ ++ return err; ++} ++ ++static ssize_t info_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *i2c = dev2i2c(dev); ++ struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c); ++ struct mcu_info *info = &ctx->info; ++ ++ info->updated = 0; ++ return count; ++} ++ ++ssize_t brdid_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ int err = 0; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->brd_id == -1) ++ return -ENODEV; ++ ++ err = mcu_i2c_read_byte(dev2i2c(dev), features->brd_id); ++ if (err < 0) ++ return err; ++ ++ return sprintf(buf, "brdid:%u\n", err); ++} ++ ++ssize_t brdip_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ u8 ip4; ++ int err; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->brd_ip == -1) ++ return -ENODEV; ++ ++ memset(ip, 0, sizeof(ip)); ++ err = mcu_i2c_read_block(dev2i2c(dev), features->brd_ip, ++ sizeof(ip), ip); ++ if (err < 0) ++ return err; ++ ++ return mcu_msg_append(buf, PAGE_SIZE, "brdip:%u.%u.%u.%u\n", ++ ip0, ip1, ip2, ip3); ++} ++ ++static ssize_t brdip_store(struct device *dev, struct device_attribute *attr, ++ const char *ubuf, size_t len) ++{ ++ u8 ip4; ++ char buf32; ++ char *s, *p, *n; ++ unsigned long res; ++ int i, err; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->brd_ip == -1) ++ return -ENODEV; ++ ++ memset(buf, 0, sizeof(buf)); ++ len = min(sizeof(buf), len); ++ memcpy(buf, ubuf, len); ++ s = buf; ++ for (i = 0; i < 4; i++) { ++ if (i != 3) { ++ p = strchr(s, '.'); ++ n = p+1; ++ *p = '\0'; ++ } ++ err = kstrtoul(s, 10, &res); ++ if (err) ++ return err; ++ ipi = (u8)res; ++ dev_dbg(dev, "ip%d = %d\n", i, ipi); ++ s = n; ++ } ++ err = mcu_i2c_write_block(dev2i2c(dev), features->brd_ip, ++ sizeof(ip), ip); ++ if (err < 0) ++ return err; ++ ++ return len; ++} ++ssize_t uptime_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ u8 t2; ++ int err; ++ const struct mcu_features *features = dev2features(dev); ++ ++ err = mcu_i2c_read_block(dev2i2c(dev), features->uptime, ++ sizeof(t), t); ++ if (err < 0) ++ return err; ++ ++ return mcu_msg_append(buf, PAGE_SIZE, ++ "%u Seconds\n", t0 | (t1 << 8)); ++} ++ ++ssize_t temp_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ s8 t2; ++ int err; ++ const struct mcu_features *features = dev2features(dev); ++ ++ /* get information from mcu through i2c */ ++ err = mcu_i2c_sreadf(dev2i2c(dev), "%s8%s8", ++ features->soc_tmp, t, ++ features->board_tmp, t + 1); ++ if (err) ++ return err; ++ ++ mcu_msg_append(buf, PAGE_SIZE, ++ "SoC temperature: %d Cel\n", t0); ++ return mcu_msg_append(buf, PAGE_SIZE, ++ "Board temperature: %d Cel\n", t1); ++} ++ ++ ++static const char *alert_id2name(const struct mcu_features *features, int id) ++{ ++ if (features->alert_tableid) ++ return features->alert_tableid; ++ return "Unknown alert"; ++} ++ ++ssize_t alert_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ int cnt = 0; ++ int i, err; ++ u8 t4; ++ u16 mask, status; ++ const struct mcu_features *features = dev2features(dev); ++ const char *alt_msg; ++ ++ if (features->alert_status == -1) ++ return 0; ++ ++ err = mcu_i2c_read_block(dev2i2c(dev), features->alert_mask, ++ sizeof(t), t); ++ /* get information from mcu through i2c */ ++ if (err < 0) ++ return err; ++ ++ status = t0 | (t1 << 8); ++ mask = t2 | (t3 << 8); ++ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, ++ "Mask 0x%02x, Status 0x%02x\n", ++ mask, status); ++ ++ if (status == 0) { ++ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, ++ "Working fine\n"); ++ } else { ++ for (i = 0; i < sizeof(status) * 8; ++i) { ++ if ((status >> i) & 1) { ++ alt_msg = alert_id2name(features, i); ++ cnt += snprintf(buf + cnt, ++ PAGE_SIZE - cnt, ++ "%d: %s\n", ++ i, alt_msg); ++ } ++ } ++ } ++ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, ++ "**************************************************\n"); ++ ++ for (i = 0; i < 16; ++i) { ++ if (features->alert_tablei == NULL) ++ continue; ++ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, ++ "%d: %s\n", i, alert_id2name(features, i)); ++ } ++ ++ return cnt; ++} ++ ++static ssize_t alert_store(struct device *dev, struct device_attribute *attr, ++ const char *ubuf, size_t len) ++{ ++ char buf32; ++ u8 t2; ++ unsigned long res; ++ int err; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->alert_mask == -1) ++ return -ENODEV; ++ ++ len = min(sizeof(buf) - 1, len); ++ memcpy(buf, ubuf, len); ++ ++ buflen = 0; // zero terminated ++ err = kstrtoul(buf, 0, &res); ++ if (err) ++ return err; ++ if (res > 0xffff) ++ return -EINVAL; ++ ++ t0 = res & 0xff; ++ t1 = (res >> 8) & 0xff; ++ err = mcu_i2c_write_block(dev2i2c(dev), features->alert_mask, ++ sizeof(t), t); ++ if (err < 0) ++ return err; ++ ++ return len; ++} ++ ++ssize_t lock_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ int err; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->lock == -1) ++ return -ENODEV; ++ ++ err = mcu_i2c_read_byte(dev2i2c(dev), features->lock); ++ ++ if (err < 0) ++ return err; ++ ++ return mcu_msg_append(buf, PAGE_SIZE, ++ "%d", err ? 1 : 0); ++} ++ ++static ssize_t lock_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int err; ++ unsigned long res; ++ const u8 *code = { "CK", "LO", }; ++ const u8 *p; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->lock == -1) ++ return -ENODEV; ++ ++ err = kstrtoul(buf, 0, &res); ++ if (err) ++ return err; ++ ++ res = res ? 1 : 0; ++ ++ for (p = coderes; *p; ++p) { ++ err = mcu_i2c_write_byte(dev2i2c(dev), features->lock, *p); ++ if (err < 0) ++ return err; ++ } ++ ++ return len; ++} ++ ++ssize_t power_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ u8 t2; ++ int err; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->power < 0) ++ return -EOPNOTSUPP; ++ ++ err = mcu_i2c_read_block(dev2i2c(dev), features->power, sizeof(t), t); ++ if (err < 0) ++ return err; ++ ++ err = sprintf(buf, "%umW\n", ((u16)t0) | (t1 << 8)); ++ ++ return err; ++} ++ ++static ssize_t power_tpu_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int err; ++ unsigned long res; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->power_tpu < 0) ++ return -EOPNOTSUPP; ++ ++ err = kstrtoul(buf, 0, &res); ++ if (err) ++ return err; ++ ++ data = res ? 1 : 0; ++ ++ err = mcu_i2c_write_block(dev2i2c(dev), features->power_tpu, ++ sizeof(data), &data); ++ return len; ++} ++ ++static ssize_t power_tpu_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ int err; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (features->power_tpu < 0) ++ return -EOPNOTSUPP; ++ ++ err = mcu_i2c_read_block(dev2i2c(dev), features->power_tpu, sizeof(data), &data); ++ if (err < 0) ++ return err; ++ ++ err = sprintf(buf, "%u\n", data); ++ ++ return err; ++} ++ ++static ssize_t mcu_critical_action_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int err; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ ++ if (!strcmp(buf, "reboot\n")) ++ data = MCU_CRITICAL_ACTION_REBOOT; ++ else if (!strcmp(buf, "poweroff\n")) ++ data = MCU_CRITICAL_ACTION_POWEROFF; ++ else ++ data = 0; ++ ++ if (data) { ++ err = mcu_i2c_write_block(dev2i2c(dev), ++ features->critical_action, sizeof(data), &data); ++ } ++ return len; ++} ++ ++static ssize_t mcu_critical_action_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ int err; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ err = mcu_i2c_read_block(dev2i2c(dev), features->critical_action, ++ sizeof(data), &data); ++ if (err < 0) ++ return err; ++ ++ if (data == MCU_CRITICAL_ACTION_REBOOT) ++ err = sprintf(buf, "reboot\n"); ++ else if (data == MCU_CRITICAL_ACTION_POWEROFF) ++ err = sprintf(buf, "poweroff\n"); ++ else ++ err = sprintf(buf, "unknown critical action\n"); ++ ++ return err; ++} ++ ++ ++static ssize_t mcu_critical_temp_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int err; ++ unsigned long res; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ err = kstrtoul(buf, 0, &res); ++ if (err) ++ return err; ++ ++ data = res; ++ ++ err = mcu_i2c_write_block(dev2i2c(dev), features->critical_temp, ++ sizeof(data), &data); ++ return len; ++} ++ ++static ssize_t mcu_critical_temp_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int err; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ err = mcu_i2c_read_block(dev2i2c(dev), features->critical_temp, ++ sizeof(data), &data); ++ if (err < 0) ++ return err; ++ ++ err = sprintf(buf, "%u Cel\n", data); ++ ++ return err; ++} ++ ++ ++static ssize_t mcu_repoweron_temp_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int err; ++ unsigned long res; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ err = kstrtoul(buf, 0, &res); ++ if (err) ++ return err; ++ ++ data = res; ++ ++ err = mcu_i2c_write_block(dev2i2c(dev), features->repoweron_temp, ++ sizeof(data), &data); ++ return len; ++} ++ ++static ssize_t mcu_repoweron_temp_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int err; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ err = mcu_i2c_read_block(dev2i2c(dev), features->repoweron_temp, ++ sizeof(data), &data); ++ if (err < 0) ++ return err; ++ ++ err = sprintf(buf, "%u Cel\n", data); ++ ++ return err; ++} ++ ++ ++static ssize_t mcu_keep_ddr_poweron_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int err; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ if (!strcmp(buf, "disable\n")) ++ data = 1; ++ else if (!strcmp(buf, "enable\n")) ++ data = 0; ++ else ++ return 0; ++ ++ err = mcu_i2c_write_block(dev2i2c(dev), features->keep_ddr_poweron, ++ sizeof(data), &data); ++ return len; ++} ++ ++static ssize_t mcu_keep_ddr_poweron_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int err; ++ unsigned char data; ++ const struct mcu_features *features = dev2features(dev); ++ ++ err = mcu_i2c_read_block(dev2i2c(dev), features->keep_ddr_poweron, ++ sizeof(data), &data); ++ if (err < 0) ++ return err; ++ ++ if (data == 1) ++ err = sprintf(buf, "disable\n"); ++ else if (data == 0) ++ err = sprintf(buf, "enable\n"); ++ else ++ err = sprintf(buf, "unknown states\n"); ++ ++ return err; ++} ++ ++/* end of sysfs callbacks */ ++ ++const struct device_attribute mcu_attrs = { ++ {{"help", 0444}, help_show, NULL}, ++ {{"information", 0644}, info_show, info_store}, ++ {{"temperature", 0444}, temp_show, NULL}, ++ {{"uptime", 0444}, uptime_show, NULL}, ++ {{"alert", 0644}, alert_show, alert_store}, ++ {{"lock", 0644}, lock_show, lock_store}, ++ {{"power-now", 0444}, power_show, NULL}, ++ {{"power-tpu", 0644}, power_tpu_show, power_tpu_store}, ++ {{"board-id", 0444}, brdid_show, NULL}, ++ {{"board-ip", 0644}, brdip_show, brdip_store}, ++ {{"critical-action", 0644}, mcu_critical_action_show, ++ mcu_critical_action_store}, ++ {{"critical-temp", 0644}, mcu_critical_temp_show, ++ mcu_critical_temp_store}, ++ {{"repoweron-temp", 0664}, mcu_repoweron_temp_show, ++ mcu_repoweron_temp_store}, ++ {{"keep-ddr-poweron", 0664}, mcu_keep_ddr_poweron_show, ++ mcu_keep_ddr_poweron_store}, ++}; ++ ++static umode_t mcu_chip_is_visible(const void *data, enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_chip: ++ return 0444; ++ case hwmon_temp: ++ return 0444; ++ default: ++ return 0; ++ } ++} ++ ++static int mcu_hwmon_chip_read(struct device *dev, u32 attr, int channel, long *val) ++{ ++ struct mcu_ctx *ctx = dev_get_drvdata(dev); ++ ++ switch (attr) { ++ case hwmon_chip_update_interval: ++ *val = ctx->hwmon_update_interval; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int mcu_hwmon_temp_read(struct device *dev, u32 attr, int channel, long *val) ++{ ++ int soc_temp, board_temp; ++ ++ struct mcu_ctx *ctx = dev_get_drvdata(dev); ++ struct i2c_client *i2c = ctx->i2c; ++ mutex_lock(&ctx->update_lock); ++ soc_temp = mcu_i2c_read_byte(i2c, MCU_REG_SOC_TEMP); ++ mutex_unlock(&ctx->update_lock); ++ ++ mutex_lock(&ctx->update_lock); ++ board_temp = mcu_i2c_read_byte(i2c, MCU_REG_BOARD_TEMP); ++ mutex_unlock(&ctx->update_lock); ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ if (channel == 0) ++ *val = soc_temp * 1000; ++ else if (channel == 1) ++ *val = board_temp * 1000; ++ else ++ *val = 0; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++ ++static int mcu_hwmon_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ ++ switch (type) { ++ case hwmon_chip: ++ return mcu_hwmon_chip_read(dev, attr, channel, val); ++ case hwmon_temp: ++ return mcu_hwmon_temp_read(dev, attr, channel, val); ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static const struct hwmon_ops mcu_ops = { ++ .is_visible = mcu_chip_is_visible, ++ .read = mcu_hwmon_read, ++ .read_string = NULL, ++ .write = NULL, ++}; ++ ++static int register_hwmon_temp_sensor(struct i2c_client *i2c, ++ struct mcu_ctx *ctx) ++{ ++ struct device *dev = &i2c->dev; ++ struct hwmon_channel_info *info; ++ struct device *hwmon_dev; ++ ++ mutex_init(&ctx->update_lock); ++ ++ ctx->i2c = i2c; ++ ctx->hwmon_update_interval = 1000; ++ ++ ctx->chip.ops = &mcu_ops; ++ ctx->chip.info = ctx->channel_info; ++ ctx->channel_info0 = HWMON_CHANNEL_INFO(chip, ++ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL); ++ ctx->channel_info1 = &ctx->temp_info; ++ ++ info = &ctx->temp_info; ++ info->type = hwmon_temp; ++ info->config = ctx->channel_config; ++ ++ ctx->channel_config0 = HWMON_T_INPUT; ++ ctx->channel_config1 = HWMON_T_INPUT; ++ hwmon_dev = devm_hwmon_device_register_with_info( ++ dev, ++ dev->driver->name, ++ ctx, ++ &ctx->chip, ++ NULL); ++ ++ if (IS_ERR(hwmon_dev)) ++ return PTR_ERR(hwmon_dev); ++ ++ return 0; ++} ++ ++static int sub_probe(struct i2c_client *i2c, ++ const struct mcu_features *features) ++{ ++ struct mcu_ctx *ctx; ++ int i, err; ++ ++ ctx = devm_kzalloc(i2c2dev(i2c), sizeof(*ctx), GFP_KERNEL); ++ if (ctx == NULL) ++ return -ENOMEM; ++ ++ for (i = 0; i < ARRAY_SIZE(mcu_attrs); ++i) { ++ err = device_create_file(i2c2dev(i2c), mcu_attrs + i); ++ if (err) ++ return err; ++ } ++ ++ ctx->features = features; ++ ++ assert(features->alert_status + 2 == features->alert_mask); ++ ++ if ((features->id & MANGO_BOARD_TYPE_MASK) == 0x80 ) { ++ err = register_hwmon_temp_sensor(i2c, ctx); ++ if (err) ++ dev_warn(i2c2dev(i2c), "mcu board id %u register hwmon failed\n", features->id); ++ } ++ ++ i2c_set_clientdata(i2c, ctx); ++ return 0; ++} ++ ++static int mcu_i2c_probe(struct i2c_client *i2c) ++{ ++ int id; ++ int err; ++ int i; ++ uint8_t regs3; ++ ++ /* get information from mcu through i2c */ ++ err = mcu_i2c_sreadf(i2c, "%u8%u8%u8", ++ MCU_REG_VERSION, regs, ++ MCU_REG_PWROFF_REASON1, regs + 1, ++ MCU_REG_PWROFF_REASON2, regs + 2); ++ if (err) ++ return err; ++ ++ dev_info(i2c2dev(i2c), "MCU: version 0x%x, reason 0x%x/0x%x\n", ++ regs0, regs1, regs2); ++ ++ id = mcu_i2c_read_byte(i2c, MCU_REG_BOARD_TYPE); ++ if (id < 0) ++ return id; ++ ++ for (i = 0; i < ARRAY_SIZE(mcu_list); ++i) { ++ if (mcu_listi.id == id) ++ return sub_probe(i2c, mcu_list + i); ++ } ++ ++ dev_warn(i2c2dev(i2c), "not registered mcu id %u\n", id); ++ return -ENODEV; ++} ++ ++static void mcu_i2c_remove(struct i2c_client *i2c) ++{ ++ return; ++} ++ ++static const struct of_device_id mcu_i2c_dt_table = { ++ { .compatible = "sophgo,sg20xx-mcu" }, ++ {}, ++}; ++ ++static const struct i2c_device_id mcu_i2c_id_table = { ++ { "sg20xx-mcu", 0 }, ++ {}, ++}; ++ ++static struct i2c_driver mcu_i2c_drv = { ++ .driver = { ++ .name = "sg20xx-mcu", ++ .of_match_table = mcu_i2c_dt_table, ++ }, ++ .probe = mcu_i2c_probe, ++ .remove = mcu_i2c_remove, ++ .id_table = mcu_i2c_id_table, ++}; ++ ++module_i2c_driver(mcu_i2c_drv); ++ ++MODULE_DESCRIPTION("MCU I2C driver for bm16xx soc platform"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Chao.Wei@bitmain.com>"); +diff --git a/drivers/soc/thead/Kconfig b/drivers/soc/thead/Kconfig +new file mode 100644 +index 000000000000..7948bbb61568 +--- /dev/null ++++ b/drivers/soc/thead/Kconfig +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++menu "Thead SoC drivers" ++ ++config LIGHT_REBOOTMODE ++ bool "Thead light rebootmode support" ++ default y ++ help ++ This driver supports check rebootmode feature in Light FM platform ++ ++endmenu +diff --git a/drivers/soc/thead/Makefile b/drivers/soc/thead/Makefile +new file mode 100644 +index 000000000000..1af5bb20810e +--- /dev/null ++++ b/drivers/soc/thead/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++obj-$(CONFIG_LIGHT_REBOOTMODE) += light_event.o +diff --git a/drivers/soc/thead/light_event.c b/drivers/soc/thead/light_event.c +new file mode 100644 +index 000000000000..f8f6292bac6e +--- /dev/null ++++ b/drivers/soc/thead/light_event.c +@@ -0,0 +1,279 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++#include <linux/kernel.h> ++#include <linux/of.h> ++#include <linux/miscdevice.h> ++#include <linux/module.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> ++#include <linux/platform_device.h> ++#include <linux/firmware/thead/ipc.h> ++#include <linux/firmware/thead/light_event.h> ++ ++/* ++ * AON SRAM total size is 0x10000, reserve 0x100 for event. ++ * Notice: c902 *.ld also need resize. ++ * -------------- 0xff_ffef8000 ++ * | | ++ * | | ++ * | | ++ * | c902 | ++ * | | ++ * | | ++ * | | ++ * -------------- 0xff_fff07f00 ++ * | reserve | ++ * | | ++ * -------------- ++ */ ++#define LIGHT_AON_SRAM_LEN 0x10000 ++#define LIGHT_AON_SRAM_RESERV (LIGHT_AON_SRAM_LEN - 0x100) ++#define LIGHT_EVENT_OFFSET (LIGHT_AON_SRAM_RESERV + 0x10) ++#define LIGHT_EVENT_CHECK (LIGHT_EVENT_OFFSET + 0x4) ++ ++#define LIGHT_EVENT_MAGIC 0x5A5A5A5A ++ ++struct light_aon_msg_event_ctrl { ++ struct light_aon_rpc_msg_hdr hdr; ++ u32 reserve_offset; ++ u32 reserved5; ++} __packed __aligned(4); ++ ++struct light_event { ++ struct device *dev; ++ ++ struct light_aon_ipc *ipc_handle; ++ struct light_aon_msg_event_ctrl msg; ++ ++ struct regmap *aon_iram; ++ bool init; ++}; ++ ++struct light_event *light_event; ++ ++static void light_event_msg_hdr_fill(struct light_aon_rpc_msg_hdr *hdr, enum light_aon_misc_func func) ++{ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; ++ hdr->func = (uint8_t)func; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++} ++ ++static int light_event_aon_reservemem(struct light_event *event) ++{ ++ struct light_aon_ipc *ipc = event->ipc_handle; ++ int ret = 0; ++ ++ dev_dbg(event->dev, "aon reservemem...\n"); ++ ++ light_event_msg_hdr_fill(&event->msg.hdr, LIGHT_AON_MISC_FUNC_AON_RESERVE_MEM); ++ event->msg.reserve_offset = LIGHT_EVENT_OFFSET; ++ ++ ret = light_aon_call_rpc(ipc, &event->msg, true); ++ if (ret) ++ dev_err(event->dev, "failed to set aon reservemem\n"); ++ ++ return ret; ++} ++ ++int light_event_set_rebootmode(enum light_rebootmode_index mode) ++{ ++ int ret; ++ ++ if (!light_event || !light_event->init) ++ return -EINVAL; ++ ++ ret = regmap_write(light_event->aon_iram, LIGHT_EVENT_OFFSET, mode); ++ if (ret) { ++ dev_err(light_event->dev, "set rebootmode failed,ret:%d\n", ret); ++ return ret; ++ } ++ ++ dev_info(light_event->dev, "set rebootmode:0x%x\n", mode); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(light_event_set_rebootmode); ++ ++int light_event_get_rebootmode(enum light_rebootmode_index *mode) ++{ ++ int ret; ++ ++ if (!light_event || !light_event->init) ++ return -EINVAL; ++ ++ ret = regmap_read(light_event->aon_iram, LIGHT_EVENT_OFFSET, mode); ++ if (ret) { ++ dev_err(light_event->dev, "get rebootmode failed,ret:%d\n", ret); ++ return ret; ++ } ++ dev_dbg(light_event->dev, "%s get rebootmode:0x%x\n", __func__, *mode); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(light_event_get_rebootmode); ++ ++static int light_event_check_powerup(void) ++{ ++ enum light_rebootmode_index mode; ++ unsigned int val; ++ int ret; ++ ++ if (!light_event->init) ++ return -EINVAL; ++ ++ ret = regmap_read(light_event->aon_iram, LIGHT_EVENT_CHECK, &val); ++ if (ret) { ++ dev_err(light_event->dev, "get magicnum failed,ret:%d\n", ret); ++ return ret; ++ } ++ ret = regmap_read(light_event->aon_iram, LIGHT_EVENT_OFFSET, &mode); ++ if (ret) { ++ dev_err(light_event->dev, "get rebootmode failed,ret:%d\n", ret); ++ return ret; ++ } ++ dev_info(light_event->dev, "magicnum:0x%x mode:0x%x\n", val, mode); ++ ++ /* powerup means SRAM data is randam */ ++ if (val != LIGHT_EVENT_MAGIC && mode != LIGHT_EVENT_PMIC_ONKEY) ++ light_event_set_rebootmode(LIGHT_EVENT_PMIC_POWERUP); ++ ++ ret = regmap_write(light_event->aon_iram, LIGHT_EVENT_CHECK, LIGHT_EVENT_MAGIC); ++ if (ret) { ++ dev_err(light_event->dev, "set magicnum failed,ret:%d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static ssize_t rebootmode_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ enum light_rebootmode_index mode; ++ ++ if (kstrtouint(buf, 0, &mode) < 0) ++ return -EINVAL; ++ light_event_set_rebootmode(mode); ++ ++ return count; ++} ++ ++static ssize_t ++rebootmode_show(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ enum light_rebootmode_index mode; ++ ++ light_event_get_rebootmode(&mode); ++ ++ return sprintf(buf, "0x%x\n", mode); ++} ++static DEVICE_ATTR_RW(rebootmode); ++ ++static struct attribute *event_attrs = { ++ &dev_attr_rebootmode.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(event); ++ ++static int light_event_open(struct inode *inode, struct file *f) ++{ ++ return 0; ++} ++ ++static int light_event_release(struct inode *inode, struct file *f) ++{ ++ return 0; ++} ++ ++static long light_event_ioctl(struct file *f, unsigned int ioctl, ++ unsigned long arg) ++{ ++ return 0; ++} ++ ++static const struct file_operations light_event_fops = { ++ .owner = THIS_MODULE, ++ .release = light_event_release, ++ .open = light_event_open, ++ .unlocked_ioctl = light_event_ioctl, ++}; ++ ++static struct miscdevice light_event_misc = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "light-event", ++ .fops = &light_event_fops, ++}; ++ ++static int light_event_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct light_event *thead; ++ int ret; ++ ++ thead = devm_kzalloc(&pdev->dev, sizeof(*thead), GFP_KERNEL); ++ if (!thead) ++ return -ENOMEM; ++ ++ ret = light_aon_get_handle(&(thead->ipc_handle)); ++ if (ret == -EPROBE_DEFER) ++ return ret; ++ ++ platform_set_drvdata(pdev, thead); ++ thead->dev = &pdev->dev; ++ ++ thead->aon_iram = syscon_regmap_lookup_by_phandle(np, "aon-iram-regmap"); ++ if (IS_ERR(thead->aon_iram)) ++ return PTR_ERR(thead->aon_iram); ++ ++ ret = misc_register(&light_event_misc); ++ if (ret < 0) ++ return ret; ++ ++ ret = light_event_aon_reservemem(thead); ++ if (ret) { ++ dev_err(dev, "set aon reservemem failed!\n"); ++ return -EPERM; ++ } ++ thead->init = true; ++ light_event = thead; ++ ++ ret = light_event_check_powerup(); ++ if (ret) { ++ dev_err(dev, "check powerup failed!\n"); ++ light_event = NULL; ++ return -EPERM; ++ } ++ dev_info(dev, "light-event driver init successfully\n"); ++ ++ return 0; ++} ++ ++static int light_event_remove(struct platform_device *pdev) ++{ ++ misc_deregister(&light_event_misc); ++ ++ return 0; ++} ++ ++static const struct of_device_id light_event_of_match = { ++ { .compatible = "thead,light-event" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, light_event_of_match); ++ ++static struct platform_driver light_event_driver = { ++ .probe = light_event_probe, ++ .remove = light_event_remove, ++ .driver = { ++ .name = "light-event", ++ .dev_groups = event_groups, ++ .of_match_table = light_event_of_match, ++ }, ++}; ++ ++module_platform_driver(light_event_driver); ++ ++MODULE_DESCRIPTION("light-event driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig +index 98efcbb76c88..a2183b8e7772 100644 +--- a/drivers/usb/dwc3/Kconfig ++++ b/drivers/usb/dwc3/Kconfig +@@ -178,4 +178,24 @@ config USB_DWC3_OCTEON + Only the host mode is currently supported. + Say 'Y' or 'M' here if you have one such device. + ++config USB_DWC3_RTK ++ tristate "Realtek DWC3 Platform Driver" ++ depends on OF && ARCH_REALTEK ++ default USB_DWC3 ++ select USB_ROLE_SWITCH ++ help ++ RTK DHC RTD SoCs with DesignWare Core USB3 IP inside, ++ and IP Core configured for USB 2.0 and USB 3.0 in host ++ or dual-role mode. ++ Say 'Y' or 'M' if you have such device. ++ ++config USB_DWC3_THEAD ++ tristate "T-HEAD Platform" ++ depends on ARCH_THEAD || COMPILE_TEST ++ default USB_DWC3 ++ help ++ Support T-HEAD platform with DesignWare Core USB3 IP. ++ Only the host mode is currently supported. ++ Say 'Y' or 'M' here if you have one such device. ++ + endif +diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile +index fe1493d4bbe5..79afa5c03c10 100644 +--- a/drivers/usb/dwc3/Makefile ++++ b/drivers/usb/dwc3/Makefile +@@ -55,3 +55,5 @@ obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o + obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o + obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o + obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o ++obj-$(CONFIG_USB_DWC3_RTK) += dwc3-rtk.o ++obj-$(CONFIG_USB_DWC3_THEAD) += dwc3-thead.o +diff --git a/drivers/usb/dwc3/dwc3-thead.c b/drivers/usb/dwc3/dwc3-thead.c +new file mode 100644 +index 000000000000..987ac70a5afc +--- /dev/null ++++ b/drivers/usb/dwc3/dwc3-thead.c +@@ -0,0 +1,112 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * dwc3-thead.c - T-HEAD platform specific glue layer ++ * ++ * Inspired by dwc3-of-simple.c ++ * ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org> ++ * Copyright (c) 2018, The Linux Foundation. All rights reserved. ++ */ ++ ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/mfd/syscon.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_platform.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++ ++#include "core.h" ++ ++#define USB_SSP_EN 0x34 ++#define REF_SSP_EN BIT(0) ++#define USB_SYS 0x3c ++#define COMMONONN BIT(0) ++ ++#define USB3_DRD_SWRST 0x14 ++#define USB3_DRD_PRST BIT(0) ++#define USB3_DRD_PHYRST BIT(1) ++#define USB3_DRD_VCCRST BIT(2) ++#define USB3_DRD_RSTMASK (USB3_DRD_PRST | USB3_DRD_PHYRST | USB3_DRD_VCCRST) ++ ++struct dwc3_thead { ++ void __iomem *base; ++ struct regmap *misc_sysreg; ++ struct regulator *vbus; ++}; ++ ++static void dwc3_thead_optimize_power(struct dwc3_thead *thead) ++{ ++ u32 val; ++ ++ /* config usb top within USB ctrl & PHY reset */ ++ regmap_update_bits(thead->misc_sysreg, USB3_DRD_SWRST, ++ USB3_DRD_RSTMASK, USB3_DRD_PRST); ++ ++ /* ++ * dwc reg also need to be configed to save power ++ * 1. set USB_SYSCOMMONONN ++ * 2. set DWC3_GCTLSOFITPSYNC(done by core.c) ++ * 3. set GUSB3PIPECTLSUSPENDEN (done by core.c) ++ */ ++ val = readl(thead->base + USB_SYS); ++ val |= COMMONONN; ++ writel(val, thead->base + USB_SYS); ++ val = readl(thead->base + USB_SSP_EN); ++ val |= REF_SSP_EN; ++ writel(val, thead->base + USB_SSP_EN); ++ ++ regmap_update_bits(thead->misc_sysreg, USB3_DRD_SWRST, ++ USB3_DRD_RSTMASK, USB3_DRD_RSTMASK); ++} ++ ++static int dwc3_thead_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct dwc3_thead *thead; ++ int ret; ++ ++ thead = devm_kzalloc(&pdev->dev, sizeof(*thead), GFP_KERNEL); ++ if (!thead) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, thead); ++ ++ ret = devm_regulator_get_enable_optional(dev, "vbus"); ++ if (ret < 0 && ret != -ENODEV) ++ return ret; ++ ++ thead->misc_sysreg = syscon_regmap_lookup_by_phandle(np, "thead,misc-sysreg"); ++ if (IS_ERR(thead->misc_sysreg)) ++ return PTR_ERR(thead->misc_sysreg); ++ ++ thead->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(thead->base)) ++ return PTR_ERR(thead->base); ++ ++ dwc3_thead_optimize_power(thead); ++ ++ return devm_of_platform_populate(dev); ++} ++ ++static const struct of_device_id dwc3_thead_of_match = { ++ { .compatible = "thead,th1520-usb" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, dwc3_thead_of_match); ++ ++static struct platform_driver dwc3_thead_driver = { ++ .probe = dwc3_thead_probe, ++ .driver = { ++ .name = "dwc3-thead", ++ .of_match_table = dwc3_thead_of_match, ++ }, ++}; ++module_platform_driver(dwc3_thead_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("DesignWare DWC3 T-HEAD Glue Driver"); ++MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); +diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig +index 751458959411..b26aac73333a 100644 +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -2044,6 +2044,20 @@ config STARFIVE_WATCHDOG + Say Y here to support the watchdog of StarFive JH7100 and JH7110 + SoC. This driver can also be built as a module if choose M. + ++config LIGHT_PMIC_WATCHDOG ++ tristate "THEAD Light pmic watchdog" ++ depends on THEAD_LIGHT_MBOX ++ select WATCHDOG_CORE ++ help ++ This is the driver for the hardware watchdog on Light Board. This watchdog ++ simply watches your kernel to make sure it doesn't freeze, and if ++ it does, it reboots your computer after a certain amount of time. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called acquirewdt. ++ ++ Most people will say N. ++ + # S390 Architecture + + config DIAG288_WATCHDOG +diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile +index 7eab9de311cb..5c36e33f8b6e 100644 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -196,6 +196,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o + + # RISC-V Architecture + obj-$(CONFIG_STARFIVE_WATCHDOG) += starfive-wdt.o ++obj-$(CONFIG_LIGHT_PMIC_WATCHDOG) += light_wdt.o + + # S390 Architecture + obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o +diff --git a/drivers/watchdog/light_wdt.c b/drivers/watchdog/light_wdt.c +new file mode 100644 +index 000000000000..d5fa5f77cec1 +--- /dev/null ++++ b/drivers/watchdog/light_wdt.c +@@ -0,0 +1,376 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/device.h> ++#include <linux/watchdog.h> ++#include <linux/firmware/thead/ipc.h> ++#include <linux/firmware/thead/light_event.h> ++ ++#define DRV_NAME "light-wdt" ++ ++/* ++ * Watchdog selector to timeout in seconds. ++ * 0: WDT disabled; ++ * others: timeout = 2048 ms * 2^(TWDSCALE-1). ++ */ ++static const unsigned int wdt_timeout = {8, 16, 32,128}; ++#define LIGHT_TWDSCALE_DISABLE 0 ++#define LIGHT_TWDSCALE_MIN 1 ++#define LIGHT_TWDSCALE_MAX (ARRAY_SIZE(wdt_timeout) - 1) ++#define LIGHT_WDT_MIN_TIMEOUT wdt_timeoutLIGHT_TWDSCALE_MIN ++#define LIGHT_WDT_MAX_TIMEOUT wdt_timeoutLIGHT_TWDSCALE_MAX ++#define LIGHT_WDT_TIMEOUT wdt_timeout3 ++#define LIGHT_RESET_PROTECTION_MS 256 ++ ++struct light_aon_msg_wdg_ctrl { ++ struct light_aon_rpc_msg_hdr hdr; ++ u32 timeout; ++ u32 running_state; ++ u32 reserved4; ++}_packed __aligned(4); ++ ++struct light_wdt_device { ++ struct device *dev; ++ struct light_aon_ipc *ipc_handle; ++ struct light_aon_msg_wdg_ctrl msg; ++ unsigned int is_aon_wdt_ena; ++}; ++ ++struct light_wdt_device *light_power_off_wdt; ++ ++static unsigned int light_wdt_timeout_to_sel(unsigned secs) ++{ ++ unsigned int i; ++ ++ for (i = LIGHT_TWDSCALE_MIN; i <= LIGHT_TWDSCALE_MAX; i++) { ++ if (wdt_timeouti >= secs) ++ return i; ++ } ++ ++ return LIGHT_TWDSCALE_MAX; ++} ++ ++static void light_wdt_msg_hdr_fill(struct light_aon_rpc_msg_hdr *hdr, enum light_aon_misc_func func) ++{ ++ hdr->ver = LIGHT_AON_RPC_VERSION; ++ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; ++ hdr->func = (uint8_t)func; ++ hdr->size = LIGHT_AON_RPC_MSG_NUM; ++} ++ ++static int light_wdt_is_running(struct light_wdt_device *wdt_dev) ++{ ++ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; ++ int ret; ++ ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_GET_STATE); ++ wdt_dev->msg.running_state = -1; ++ ++ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); ++ if (ret) ++ return ret; ++ ++ pr_debug("ret = %d, timeout = %d, running_state = %d\n", ret, wdt_dev->msg.timeout, ++ wdt_dev->msg.running_state); ++ ++ return wdt_dev->msg.running_state; ++} ++ ++static int light_wdt_update_timeout(struct light_wdt_device *wdt_dev, unsigned int timeout) ++{ ++ /* ++ * The watchdog triggers a reboot if a timeout value is already ++ * programmed because the timeout value combines two functions ++ * in one: indicating the counter limit and starting the watchdog. ++ * The watchdog must be disabled to be able to change the timeout ++ * value if the watchdog is already running. Then we can set the ++ * new timeout value which enables the watchdog again. ++ */ ++ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; ++ int ret; ++ ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_TIMEOUTSET); ++ wdt_dev->msg.timeout = timeout; ++ ++ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int light_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout) ++{ ++ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); ++ int ret = 0; ++ ++ /* ++ * There are two cases when a set_timeout() will be called: ++ * 1. The watchdog is off and someone wants to set the timeout for the ++ * further use. ++ * 2. The watchdog is already running and a new timeout value should be ++ * set. ++ * ++ * The watchdog can't store a timeout value not equal zero without ++ * enabling the watchdog, so the timeout must be buffered by the driver. ++ */ ++ if (watchdog_active(wdd)) ++ ret = light_wdt_update_timeout(wdt_dev, timeout); ++ else ++ wdd->timeout = wdt_timeoutlight_wdt_timeout_to_sel(timeout); ++ ++ return ret; ++} ++ ++static int light_wdt_start(struct watchdog_device *wdd) ++{ ++ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); ++ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; ++ int ret; ++ ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_START); ++ ++ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int light_wdt_stop(struct watchdog_device *wdd) ++{ ++ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); ++ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; ++ int ret; ++ ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_STOP); ++ ++ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int light_wdt_ping(struct watchdog_device *wdd) ++{ ++ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); ++ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; ++ int ret; ++ ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_PING); ++ ++ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int light_wdt_restart(struct watchdog_device *wdd, unsigned long action, void *data) ++{ ++ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); ++ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; ++ int ret; ++ ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_RESTART); ++ ++ pr_debug("%s,%d: Inform aon to restart the whole system....\n", __func__, __LINE__); ++ ++ light_event_set_rebootmode(LIGHT_EVENT_SW_REBOOT); ++ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, false); ++ if (ret) ++ return ret; ++ pr_debug("%s,%d: Finish to inform aon to restart the whole system....\n", __func__, __LINE__); ++ ++ return 0; ++} ++ ++static const struct watchdog_info light_watchdog_info = { ++ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, ++ .identity = "Light Watchdog", ++}; ++ ++ ++static const struct watchdog_ops light_watchdog_ops = { ++ .owner = THIS_MODULE, ++ .start = light_wdt_start, ++ .stop = light_wdt_stop, ++ .ping = light_wdt_ping, ++ .set_timeout = light_wdt_set_timeout, ++ .restart = light_wdt_restart, ++}; ++ ++static ssize_t aon_sys_wdt_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct light_wdt_device *wdt_dev = platform_get_drvdata(pdev); ++ return sprintf(buf,"%u\n",wdt_dev->is_aon_wdt_ena); ++} ++ ++static ssize_t aon_sys_wdt_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct light_wdt_device *wdt_dev = platform_get_drvdata(pdev); ++ struct light_aon_ipc *ipc; ++ int ret; ++ char *start = (char *)buf; ++ unsigned long val; ++ ++ ipc = wdt_dev->ipc_handle; ++ val = simple_strtoul(start, &start, 0); ++ wdt_dev->is_aon_wdt_ena = val; ++ if (val) ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_AON_WDT_ON); ++ else ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_AON_WDT_OFF); ++ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); ++ if (ret){ ++ pr_err("%s: err:%d \n",__func__,ret); ++ return -EINVAL; ++ } ++ return size; ++} ++ ++void light_pm_power_off(void) ++{ ++ struct light_wdt_device *wdt_dev = light_power_off_wdt; ++ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; ++ int ret; ++ ++ pr_info("%s,%dpoweroff system...\n", __func__, __LINE__); ++ ++ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_POWER_OFF); ++ ++ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); ++ ++ if (ret) ++ pr_err("failed to power off the system\n"); ++} ++ ++ ++static DEVICE_ATTR(aon_sys_wdt, 0644, aon_sys_wdt_show, aon_sys_wdt_store); ++ ++static struct attribute *aon_sys_wdt_sysfs_entries = { ++ &dev_attr_aon_sys_wdt.attr, ++ NULL ++}; ++static const struct attribute_group dev_attr_aon_sys_wdt_group = { ++ .attrs = aon_sys_wdt_sysfs_entries, ++}; ++ ++static int light_wdt_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct light_wdt_device *wdt_dev; ++ int ret; ++ struct watchdog_device *wdd; ++ ++ wdt_dev = devm_kzalloc(dev, sizeof(*wdt_dev), GFP_KERNEL); ++ if (!wdt_dev) ++ return -ENOMEM; ++ wdt_dev->is_aon_wdt_ena = 0; ++ ++ ret = light_aon_get_handle(&(wdt_dev->ipc_handle)); ++ if (ret == -EPROBE_DEFER) ++ return ret; ++ ++ wdd = devm_kzalloc(dev, sizeof(*wdd), GFP_KERNEL); ++ if (!wdd) ++ return -ENOMEM; ++ ++ wdd->info = &light_watchdog_info; ++ wdd->ops = &light_watchdog_ops; ++ wdd->min_timeout = LIGHT_WDT_MIN_TIMEOUT; ++ wdd->max_timeout = LIGHT_WDT_MAX_TIMEOUT; ++ wdd->min_hw_heartbeat_ms = LIGHT_RESET_PROTECTION_MS; ++ wdd->status = WATCHDOG_NOWAYOUT_INIT_STATUS; ++ ++ watchdog_set_restart_priority(wdd, 128); ++ watchdog_set_drvdata(wdd, wdt_dev); ++ ++ /* Set default timeout, maybe default value if the watchdog is running */ ++ wdd->timeout = LIGHT_WDT_TIMEOUT; ++ watchdog_init_timeout(wdd, 0, dev); ++ light_wdt_set_timeout(wdd, wdd->timeout); ++ ++ platform_set_drvdata(pdev, wdt_dev); ++ ret = light_wdt_is_running(wdt_dev); ++ if (ret < 0) { ++ pr_err("failed to get pmic wdt running state\n"); ++ return ret; ++ } ++ ++ if (ret) { ++ light_wdt_update_timeout(wdt_dev, wdd->timeout); ++ set_bit(WDOG_HW_RUNNING, &wdd->status); ++ } ++ ++ ret = devm_watchdog_register_device(dev, wdd); ++ if (ret) ++ return ret; ++ ++ pr_info("%s,%d register power off callback\n", __func__, __LINE__); ++ ++ pm_power_off = light_pm_power_off; ++ ++ light_power_off_wdt = wdt_dev; ++ ++ ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_aon_sys_wdt_group); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to create aon_sys_wdt sysfs.\n"); ++ return ret; ++ } ++ ++ pr_info("succeed to register light pmic watchdog\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver light_wdt_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ }, ++ .probe = light_wdt_probe, ++}; ++ ++static int __init light_wdt_init(void) ++{ ++ static struct platform_device *pdev; ++ int ret; ++ ++ pdev = platform_device_register_simple(DRV_NAME, -1, NULL, 0); ++ if (IS_ERR(pdev)) ++ return PTR_ERR(pdev); ++ ++ ret = platform_driver_register(&light_wdt_driver); ++ if (ret) { ++ platform_device_unregister(pdev); ++ return PTR_ERR(pdev); ++ } ++ ++ pr_info("Watchdog module: %s loaded\n", DRV_NAME); ++ ++ return 0; ++} ++device_initcall(light_wdt_init); ++ ++MODULE_AUTHOR("Wei.Liu <lw312886@linux.alibaba.com>"); ++MODULE_DESCRIPTION("PMIC Watchdog Driver for Light"); ++MODULE_LICENSE("GPL"); +diff --git a/include/dt-bindings/clock/light-dspsys.h b/include/dt-bindings/clock/light-dspsys.h +new file mode 100644 +index 000000000000..6473e12623c6 +--- /dev/null ++++ b/include/dt-bindings/clock/light-dspsys.h +@@ -0,0 +1,25 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef _LIGHT_DSPSYS_H ++#define _LIGHT_DSPSYS_H ++ ++#define CLKGEN_DSP0_PCLK 0 ++#define CLKGEN_DSP0_CCLK 1 ++#define CLKGEN_DSP1_PCLK 2 ++#define CLKGEN_DSP1_CCLK 3 ++#define CLKGEN_X2X_X4_DSPSLV_DSP0_ACLK_M 4 ++#define CLKGEN_X2X_X4_DSPSLV_DSP1_ACLK_M 5 ++#define CLKGEN_AXI4_DSPSYS_SLV_ACLK 6 ++#define CLKGEN_AXI4_DSPSYS_ACLK 7 ++#define CLKGEN_IOPMP_DSP0_PCLK 8 ++#define CLKGEN_IOPMP_DSP1_PCLK 9 ++#define CLKGEN_AXI4_DSPSYS_SLV_PCLK 10 ++#define CLKGEN_AXI4_DSPSYS_PCLK 11 ++#define CLKGEN_X2X_DSP0_ACLK_S 12 ++#define CLKGEN_X2X_DSP2_ACLK_S 13 ++#define LIGHT_CLKGEN_DSPSYS_CLK_END 14 ++ ++#endif +diff --git a/include/dt-bindings/clock/light-fm-ap-clock.h b/include/dt-bindings/clock/light-fm-ap-clock.h +new file mode 100644 +index 000000000000..8bb23b690f98 +--- /dev/null ++++ b/include/dt-bindings/clock/light-fm-ap-clock.h +@@ -0,0 +1,513 @@ ++#ifndef _APSYS_CLKGEN_H ++#define _APSYS_CLKGEN_H ++ ++#define C910_CCLK_I0 0 ++#define AXI4_CPUSYS1_ACLK 1 ++#define CLKGEN_GPIO2_DBCLK 2 ++#define CLKGEN_MBOX0_PCLK 3 ++#define CLKGEN_GMAC0_CCLK 4 ++#define CLKGEN_SPI_PCLK 5 ++#define CLKGEN_CLK_OUT_1_CLK 6 ++#define PAD_RTC_CLK 7 ++#define CLKGEN_SPINLOCK_HCLK 8 ++#define CLKGEN_QSPI1_PCLK 9 ++#define CLKGEN_HDMI_ISCAN_CK_REF_CLK 10 ++#define CLKGEN_IOPMP_AON_PCLK 11 ++#define CLKGEN_ISP_RY_ACLK 12 ++#define CLKGEN_MIPIDSI0_SCANRXCLKESC 13 ++#define CLKGEN_EIP120SII_HCLK 14 ++#define CLKGEN_MIPI_CSI0_PIXCLK 15 ++#define CLKGEN_SRAM_AXI_ACLK_3 16 ++#define CLKGEN_PERISYS_AHB_HCLK 17 ++#define VOSYS_HDMI_ISCAN_RX_WORD_CLK0_CLK 18 ++#define CLKGEN_QSPI0_SSI_CLK 19 ++#define CLKGEN_DW200_ACLK 20 ++#define CLKGEN_IOPMP_EIP120SIII_PCLK 21 ++#define VISYS_MIPI_CSI2_CFGCLK 22 ++#define CLKGEN_APB3_CPUSYS_HCLK 23 ++#define CLKGEN_PERISYS_APB1_HCLK 24 ++#define CLKGEN_GPU_CORE_CLK 25 ++#define CLKGEN_USB3_DRD_ACLK 26 ++#define CLKGEN_VISYS_ACLK 27 ++#define CLKGEN_USB3_DRD_CTRL_REF_CLK 28 ++#define CLKGEN_TEE_DMAC_ACLK 29 ++#define CLKGEN_AUDIO_SUBSYS_ACLK_CP2AP 30 ++#define CLKGEN_SRAM_AXI_ACLK_2 31 ++#define CLKGEN_IOPMP_VOSYS_GPU_PCLK 32 ++#define CLKGEN_CFG2TEE_X2H_ACLK 33 ++#define CLKGEN_SRAM_AXI_ACLK_1 34 ++#define MISC_SDIO0_OSC_CLK 35 ++#define CLKGEN_SDIO0_ACLK 36 ++#define CLKGEN_MIPI_DSI1_CFGCLK 37 ++#define APB3_CPUSYS_PCLK 38 ++#define CLKGEN_TEE_DMAC_HCLK 39 ++#define VOSYS_DPU0_PIXELCLK 40 ++#define CLKGEN_CPU2CFG_X2H_MHCLK 41 ++#define CLKGEN_VPSYS_ACLK 42 ++#define CLKGEN_MIPIDSI1_SCANRXCLKESC 43 ++#define CLKGEN_MISC2VP_X2X_ACLK_S 44 ++#define CLKGEN_MIPI_CSI_SCANBYTECLK 45 ++#define CLKGEN_APB3_TEESYS_HCLK 46 ++#define VENC_CCLK 47 ++#define VPSYS_VDEC_CCLK 48 ++#define CLKGEN_MIPI_CSI0_CFG_CLK 49 ++#define CLKGEN_MISCSYS_BUS_CLK 50 ++#define CLKGEN_DPU_HCLK 51 ++#define CLKGEN_UART1_SCLK 52 ++#define GMAC_PLL_FOUTPOSTDIV 53 ++#define MISC_BUS_CLK 54 ++#define CLKGEN_USB3_DRD_SPDCLK 55 ++#define CLKGEN_MIPI_CSI2_CFG_CLK 56 ++#define CLKGEN_TOP_AXI4S_ACLK 57 ++#define CLKGEN_IOPMP_EIP120SII_ACLK 58 ++#define CORE_CLK 59 ++#define CLKGEN_VPSYS_FCE_ACLK 60 ++#define CLKGEN_I2C3_PCLK 61 ++#define DPU1_PLL_DIV_CLK 62 ++#define CLKGEN_USB3_DRD_PHY_REF_CLK 63 ++#define CLKGEN_AON2CPU_A2X_ACLK 64 ++#define CLKGEN_QSPI1_SSI_CLK 65 ++#define CLKGEN_DPU_CCLK 66 ++#define VISYS_MASTER_BUS_ACLK 67 ++#define CLKGEN_PERI_I2S_SRC_CLK_0 68 ++#define VOSYS_ACLK_M 69 ++#define TEESYS_I0_HCLK 70 ++#define CLKGEN_MIPI_DSI1_REFCLK 71 ++#define CLKGEN_MIPI_DSI0_PCLK 72 ++#define CLKGEN_VOSYS_ACLK_S 73 ++#define CLKGEN_CPU2VP_X2P_PCLK 74 ++#define CLKGEN_X2X_CPUSYS_ACLK_S 75 ++#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK1_CLK 76 ++#define CLKGEN_IOPMP_VOSYS_DPU1_PCLK 77 ++#define CLKGEN_MISC2VP_X2X_ACLK_M 78 ++#define CLKGEN_WDT0_PCLK 79 ++#define VOSYS_MIPIDSI0_SCANTXCLKESC 80 ++#define VISYS_MIPI_CSI1_CFGCLK 81 ++#define AHB2_CPUSYS_HCLK 82 ++#define CLKGEN_SDIO1_HCLK 83 ++#define CLKGEN_SDIO0_HCLK 84 ++#define CLKGEN_CLK_OUT_3_CLK 85 ++#define CLKGEN_GMAC_AXI_ACLK 86 ++#define GMAC_CCLK 87 ++#define CLKGEN_VIPRE_PCLK 88 ++#define CLKGEN_HDMI_ISCAN_TX_CK_OUT2_CLK 89 ++#define CLKGEN_MIPIDSI1_SCANTXCLKESC 90 ++#define CLKGEN_VISYS_SLAVE_HCLK 91 ++#define VOSYS_HDMI_ISCAN_TX_CK_OUT1_CLK 92 ++#define CLKGEN_X2X_CPUSYS_ACLK_M 93 ++#define CLKGEN_CPU2CFG_X2X_ACLK_S 94 ++#define C910_OSC_CLK 95 ++#define CLKGEN_X2H_DPU1_ACLK 96 ++#define CLKGEN_I2C4_PCLK 97 ++#define CLKGEN_GMAC0_ACLK 98 ++#define MISC_USB3_PHY_REF_CLK 99 ++#define VOSYS_MIPIDSI0_CFG_CLK 100 ++#define CLKGEN_VPSYS_VDEC_CCLK 101 ++#define VOSYS_MIPIDSI1_CFG_CLK 102 ++#define CLKGEN_I2S_PCLK 103 ++#define CLKGEN_DMAC_CPUSYS_ACLK 104 ++#define VISYS_DW200_CLK_DWE 105 ++#define CLKGEN_OCRAM_HCLK 106 ++#define CLKGEN_EFUSE_PCLK 107 ++#define CLKGEN_X2H_DPU_ACLK 108 ++#define CLKGEN_IOPMP_SDIO0_ACLK 109 ++#define VOSYS_DPU1_PIXELCLK 110 ++#define CPU_PLL1_FOUT4 111 ++#define CLKGEN_GPIO2_PCLK 112 ++#define CLKGEN_GMAC1_CCLK 113 ++#define CPU_PLL1_FOUTPOSTDIV 114 ++#define VOSYS_HDMI_ISCAN_40M_CLK 115 ++#define CLKGEN_VOSYS_X2X_ACLK_S 116 ++#define CLKGEN_PERISYS_APB2_HCLK 117 ++#define VOSYS_OSC_CLK_MUX_I2S_CLK_OCCBUF 118 ++#define CLKGEN_HDMI_CEC_CLK 119 ++#define CLKGEN_X2P_X4_VOSYS_PCLK 120 ++#define CLKGEN_VOSYS_ACLK_M 121 ++#define CLKGEN_EMMC_SDIO_REF_CLK 122 ++#define CLKGEN_IOPMP_EMMC_ACLK 123 ++#define VIDEO_PLL_FOUTVCO 124 ++#define CLKGEN_HDMI_ISCAN_CKO_WORD_CLK 125 ++#define CLKGEN_IOPMP_VOSYS_DPU_PCLK 126 ++#define CLKGEN_AXI4_VISYS3_ACLK 127 ++#define CLKGEN_VISYS_SYSREG_PCLK 128 ++#define CLKGEN_MIPIDSI0_SCANTXCLKESC 129 ++#define CLKGEN_HDMI_ISCAN_TX_CK_OUT1_CLK 130 ++#define CLKGEN_IOPMP_EIP120SIII_ACLK 131 ++#define CLKGEN_EIP120SII_ACLK 132 ++#define CLKGEN_MBOX2_PCLK 133 ++#define CLKGEN_AXI4_VISYS1_ACLK 134 ++#define CLKGEN_UART1_PCLK 135 ++#define CLK_OUT_3 136 ++#define CLKGEN_UART5_SCLK 137 ++#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK2_CLK 138 ++#define CLKGEN_MBOX3_PCLK 139 ++#define QSPI1_SSI_CLK 140 ++#define CLKGEN_I2C1_PCLK 141 ++#define CLKGEN_HDMI_I2S_CLK 142 ++#define CLKGEN_AXI4_CPUSYS2_PCLK 143 ++#define CLKGEN_CFG2TEE_X2H_MHCLK 144 ++#define CLKGEN_C910_CPU_CLK 145 ++#define VOSYS_HDMI_ISCAN_TX_CK_OUT2_CLK 146 ++#define CLKGEN_HDMI_PCLK 147 ++#define CLKGEN_IOPMP_EIP120SII_PCLK 148 ++#define CLKGEN_MISCSYS_AXI_PCLK 149 ++#define CLKGEN_EIP120SI_ACLK 150 ++#define TEESYS_I1_HCLK 151 ++#define PERISYS_APB_PCLK 152 ++#define VOSYS_HDMI_ISCAN_RX_WORD_CLK0_DIV2_CLK 153 ++#define CLKGEN_TIMER0_CCLK 154 ++#define CLKGEN_IOPMP_USB3_ACLK 155 ++#define CLKGEN_UART2_PCLK 156 ++#define CLK_OUT_4 157 ++#define AXI4_CPUSYS2_ACLK 158 ++#define CLKGEN_AUDIO_SUBSYS_ACLK_AP2CP 159 ++#define CLKGEN_I2C3_IC_CLK 160 ++#define CLKGEN_IOPMP_GPU_ACLK 161 ++#define CLKGEN_TIMER1_CCLK 162 ++#define VOSYS_I2S_CLK 163 ++#define CLKGEN_I2C5_IC_CLK 164 ++#define VOSYS_OSC_CLK_MUX_I2S_CLK 165 ++#define CLKGEN_DDR_SUBSYS_ACLK_0 166 ++#define CLKGEN_TIMER1_PCLK 167 ++#define CLKGEN_I2C1_IC_CLK 168 ++#define CLKGEN_I2S_SRC_CLK 169 ++#define VISYS_DW200_CLK_VSE 170 ++#define CLKGEN_MIPIDSI1_PIXCLK 171 ++#define VOSYS_RTC_CLK 172 ++#define CLK_OUT_1 173 ++#define CLKGEN_PERISYS_APB4_HCLK 174 ++#define MISC_USB3_CTRL_REF_CLK 175 ++#define CLKGEN_TEE_SYSREG_PCLK 176 ++#define CLKGEN_MISCSYS_AXI_ACLK 177 ++#define CLKGEN_MIPIDSI1_SCANCLK 178 ++#define CLKGEN_GPIO3_DBCLK 179 ++#define CLKGEN_HDMI_ISCAN_40M_CLK 180 ++#define CLKGEN_PERI2PERI1_APB_HCLK 181 ++#define CLKGEN_GMAC0_HCLK 182 ++#define CLKGEN_DDR_SUBSYS_PCLK 183 ++#define VOSYS_PCLK 184 ++#define CLKGEN_MIPIDSI1_SCANBYTECLK 185 ++#define CLKGEN_VPSYS_G2D_ACLK 186 ++#define CLKGEN_EIP150B_HCLK 187 ++#define CLKGEN_UART4_SCLK 188 ++#define DPU1_PLL_TEST_CLK 189 ++#define CLKGEN_VOSYS_X2X_ACLK_M 190 ++#define CLKGEN_IOPMP_EIP120SI_ACLK 191 ++#define CLKGEN_CLK_OUT_4_CLK 192 ++#define CLKGEN_GPIO0_FPCLK 193 ++#define PAD_OSC_CLK 194 ++#define CLKGEN_C910_BUS_CLK_NO_ICG 195 ++#define CLKGEN_TIMER0_PCLK 196 ++#define CLKGEN_AHB2_CPUSYS_HCLK 197 ++#define EMMC_SDIO_REF_CLK 198 ++#define CLKGEN_IOPMP_CHIP_DBG_PCLK 199 ++#define CLKGEN_BMU_C910_PCLK 200 ++#define CLKGEN_IOPMP_DPU1_ACLK 201 ++#define CLKGEN_PADCTRL0_APSYS_PCLK 202 ++#define MISC_SDIO1_OSC_CLK 203 ++#define CLKGEN_C910_OSC_CLK 204 ++#define VISYS_ISP_RY_CCLK 205 ++#define CLKGEN_VPSYS_PCLK 206 ++#define VISYS_MIPI_CSI0_PIXELCLK 207 ++#define NPU_CCLK 208 ++#define CLKGEN_AXI4_TEESYS_ACLK 209 ++#define PERI2SYS_APB_PCLK 210 ++#define CLKGEN_IOPMP_GMAC0_PCLK 211 ++#define CLKGEN_VPSYS_G2D_PCLK 212 ++#define CLKGEN_EMMC_ACLK 213 ++#define CLKGEN_UART3_SCLK 214 ++#define AONSYS_BUS_CLK 215 ++#define DPU0_PLL_FOUT4 216 ++#define VOSYS_MIPIDSI1_SCANCLK 217 ++#define CLKGEN_UART4_PCLK 218 ++#define CLKGEN_HDMI_ISCAN_SCL 219 ++#define CLKGEN_MIPI_CSI1_PIXCLK 220 ++#define CLKGEN_APSYS_CLKGEN_PCLK 221 ++#define CLKGEN_GPU_TIMER_REFCLK 222 ++#define GMAC_PLL_FOUT1PH0 223 ++#define VOSYS_MIPIDSI1_SCANBYTECLK 224 ++#define CLKGEN_GPIO3_FPCLK 225 ++#define CLKGEN_SDIO1_OSC_CLK 226 ++#define CLKGEN_GPIO3_PCLK 227 ++#define CLKGEN_VPSYS_AXI_ACLK 228 ++#define CLKGEN_HDMI_ISCAN_TX_CK_20B_CLK 229 ++#define CLKGEN_VOSYSREG_PCLK 230 ++#define VIDEO_PLL_TEST_CLK 231 ++#define CLKGEN_MBOX1_PCLK 232 ++#define CLKGEN_I2C2_IC_CLK 233 ++#define VOSYS_MIPIDSI0_PLL_SCANCLK 234 ++#define VOSYS_MIPIDSI1_SCANTXCLKESC 235 ++#define VOSYS_HDMI_ISCAN_RX_WORD_CLK1_DIV2_CLK 236 ++#define CLKGEN_UART2_SCLK 237 ++#define MISC_TEESYS_PCLK 238 ++#define AUDIO_PLL_TEST_CLK 239 ++#define CLKGEN_DPU_PIXELCLK1 240 ++#define CLKGEN_IOPMP_TEEDMAC_PCLK 241 ++#define CLKGEN_TOP_APB_SX_PCLK 242 ++#define CLKGEN_I2C4_IC_CLK 243 ++#define GMAC_PLL_TEST_CLK 244 ++#define CLKGEN_HDMI_JTAG_TCLK 245 ++#define VISYS_MIPI_CSI0_CFGCLK 246 ++#define CLKGEN_CPU2AON_X2H_ACLK 247 ++#define VOSYS_HDMI_ISCAN_TX_CK_OUT0_CLK 248 ++#define QSPI_SSI_CLK 249 ++#define VOSYS_DPU_CCLK 250 ++#define CLKGEN_CPU2VI_X2H_MHCLK 251 ++#define CLKGEN_MIPI_DSI0_REFCLK 252 ++#define CLKGEN_DSPSYS_HCLK 253 ++#define CLKGEN_IOPMP_AUD_PCLK 254 ++#define CLKGEN_PERI2PERI1_APB_PCLK 255 ++#define CFG_AXI_ACLK 256 ++#define VPSYS_FCE_CCLK 257 ++#define CLKGEN_HDMI_ISCAN_CLK 258 ++#define CPU_PLL0_TEST_CLK 259 ++#define CLKGEN_CPU2PERI_X2H_MHCLK 260 ++#define VISYS_ACLK_M 261 ++#define VOSYS_HDMI_JTAG_TCLK 262 ++#define CLKGEN_IOPMP_AUD_ACLK 263 ++#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK1_DIV2_CLK 264 ++#define VOSYS_HDMI_ISCAN_RX_WORD_CLK1_CLK 265 ++#define VOSYS_MIPIDSI0_REFCLK 266 ++#define CLKGEN_VISYS_ACLK_M 267 ++#define VOSYS_MIPIDSI0_SCANRXCLKESC 268 ++#define CLKGEN_SDIO1_ACLK 269 ++#define CFG_APB_PCLK 270 ++#define CLKGEN_PADCTRL1_APSYS_PCLK 271 ++#define VOSYS_MIPIDSI0_SCANCLK 272 ++#define CLKGEN_I2C0_IC_CLK 273 ++#define CLKGEN_VPSYS_APB_PCLK 274 ++#define CLKGEN_VPSYS_VENC_CCLK 275 ++#define CLKGEN_AXI4_CFG_BUS_ACLK 276 ++#define CLKGEN_MIPIDSI0_SCANBYTECLK 277 ++#define GPIO3_DBCLK 278 ++#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK0_CLK 279 ++#define CLKGEN_UART5_PCLK 280 ++#define DPU0_PLL_FOUTPOSTDIV_ICG 281 ++#define CPU_PLL0_FOUT4 282 ++#define CLKGEN_GPIO2_FPCLK 283 ++#define CLKGEN_DPU_ACLK 284 ++#define CLKGEN_AXI4_CPUSYS2_ACLK 285 ++#define CLKGEN_DSPSYS_PCLK 286 ++#define TEE_PLL_FOUTPOSTDIV 287 ++#define TIMER_CCLK 288 ++#define VOSYS_MIPIDSI1_PLL_SCANCLK 289 ++#define CLKGEN_GMAC_AXI_PCLK 290 ++#define CLKGEN_USB3_DRD_PCLK 291 ++#define CLKGEN_AXI4_CPUSYS1_PCLK 292 ++#define VOSYS_ACLK 293 ++#define CLKGEN_IOPMP_EIP120SI_PCLK 294 ++#define VOSYS_HDMI_ISCAN_TMDSCLKIN_CLK 295 ++#define VOSYS_HDMI_ISCAN_CKO_WORD_CLK 296 ++#define CLKGEN_NPUSYS_AXI_ACLK 297 ++#define CLKGEN_IOPMP_SDIO0_PCLK 298 ++#define CLKGEN_DW200_HCLK 299 ++#define VOSYS_HDMI_ISCAN_RX_WORD_CLK2_CLK 300 ++#define CLKGEN_UART0_PCLK 301 ++#define CLKGEN_CLK_OUT_2_CLK 302 ++#define CLKGEN_GPIO0_PCLK 303 ++#define CLKGEN_EMMC_OSC_CLK 304 ++#define VPSYS_APB_PCLK 305 ++#define CLKGEN_HDMI_PIXCLK 306 ++#define CLKGEN_IOPMP_TEEDMAC_ACLK 307 ++#define AUDIO_PLL_FOUT4 308 ++#define CLKGEN_MIPI_CSI2_PCLK 309 ++#define CLKGEN_MIPI_DSI1_PCLK 310 ++#define CLKGEN_MIPI_DSI0_CFGCLK 311 ++#define VISYS_ISP0_CLK 312 ++#define VISYS_ISP1_CLK 313 ++#define MISC_EMMC_OSC_CLK 314 ++#define DPU0_PLL_FOUTPOSTDIV 315 ++#define VISYS_AHB_HCLK 316 ++#define CLKGEN_IOPMP_SDIO1_ACLK 317 ++#define CLKGEN_EMMC_HCLK 318 ++#define I2S_CLK 319 ++#define CLKGEN_CPU2PERI_X2H_ACLK 320 ++#define VPSYS_AXI_ACLK 321 ++#define CLKGEN_IOPMP_SDIO1_PCLK 322 ++#define CLKGEN_EIP120SIII_HCLK 323 ++#define CLKGEN_BMU_C910_ACLK 324 ++#define CLKGEN_IOPMP_DMAC_CPUSYS_PCLK 325 ++#define GPIO2_DBCLK 326 ++#define CHIP_DBG_CCLK 327 ++#define CLKGEN_MISCSYS_TEE_CCLK 328 ++#define CLKGEN_I2C5_PCLK 329 ++#define CLKGEN_X2H_CPUSYS_MHCLK 330 ++#define CLKGEN_PWM_CCLK 331 ++#define DPU0_PLL_TEST_CLK 332 ++#define CLKGEN_VISYS_PCLK 333 ++#define MISC_TEESYS_HCLK 334 ++#define SPI_SSI_CLK 335 ++#define CLKGEN_PWM_PCLK 336 ++#define VOSYS_MIPIDSI1_SCANRXCLKESC 337 ++#define QSPI0_SSI_CLK 338 ++#define CLKGEN_HDMI_ISCAN_TMDSCLKIN_CLK 339 ++#define CLKGEN_SPI_SSI_CLK 340 ++#define VIDEO_PLL_FOUT4 341 ++#define CLKGEN_IOPMP_GMAC0_ACLK 342 ++#define CLKGEN_VIPRE_ACLK 343 ++#define MISC_OSC_CLK_DIV24 344 ++#define CLKGEN_ISP_VENC_SHAKE_PCLK 345 ++#define CLKGEN_HDMI_ISCAN_TX_CK_OUT0_CLK 346 ++#define CLKGEN_VPSYS_G2D_CCLK 347 ++#define CLKGEN_CPU2CFG_X2X_ACLK_M 348 ++#define CLKGEN_GMAC1_PCLK 349 ++#define CLKGEN_MIPIDSI0_PLL_SCANCLK 350 ++#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK0_DIV2_CLK 351 ++#define TEE_PLL_FOUT4 352 ++#define PERISYS_AHB_HCLK 353 ++#define VIDEO_PLL_FOUT1PH0 354 ++#define CLKGEN_MIPIDSI0_PIXCLK 355 ++#define CLKGEN_PERI_I2S_SRC_CLK_1 356 ++#define CLKGEN_MIPI_CSI0_PCLK 357 ++#define CLKGEN_DDR_SUBSYS_ACLK_1 358 ++#define CLKGEN_GMAC0_PCLK 359 ++#define CLK_OUT_2 360 ++#define CLKGEN_EIP120SIII_ACLK 361 ++#define AONSYS_HCLK 362 ++#define CLKGEN_ISP0_CLK 363 ++#define CLKGEN_C910_BROM_HCLK 364 ++#define DPU1_PLL_FOUT4 365 ++#define PERI_I2S_SRC_CLK 366 ++#define CPU_PLL1_TEST_CLK 367 ++#define CLKGEN_DDR_SUBSYS_ACLK_2 368 ++#define CLKGEN_MIPIDSI0_SCANCLK 369 ++#define I2C_IC_CLK 370 ++#define CLKGEN_DPU_PIXELCLK0 371 ++#define CLKGEN_GPIO1_DBCLK 372 ++#define CLKGEN_C910_TOP_DS_PCLK 373 ++#define CLKGEN_DSPSYS_ACLK_M 374 ++#define CLKGEN_AON2CPU_A2X_HCLK 375 ++#define VOSYS_HDMI_ISCAN_CK_REF_CLK 376 ++#define CLKGEN_IOPMP_EMMC_PCLK 377 ++#define NPU_CORE_CLK 378 ++#define CLKGEN_IOPMP_USB3_PCLK 379 ++#define VPSYS_PCLK 380 ++#define VIDEO_PLL_FOUTPOSTDIV 381 ++#define CLKGEN_CPU2VP_X2P_ACLK 382 ++#define CLKGEN_APB_CPU2CFG_HCLK 383 ++#define VOSYS_OSC_CLK_MUX_CEC_CLK_OCCBUF 384 ++#define CLKGEN_GPIO1_PCLK 385 ++#define CLKGEN_APSYS_SYSREG_PCLK 386 ++#define CLKGEN_VISYS_HCLK 387 ++#define CLKGEN_MIPI_CSI1_PCLK 388 ++#define CLKGEN_AHB2_TEESYS_HCLK 389 ++#define CLKGEN_DDR_SUBSYS_ACLK_4 390 ++#define SYS_PLL_TEST_CLK 391 ++#define VISYS_MIPI_CSI_SCANCLK 392 ++#define CPU_PLL0_FOUTPOSTDIV 393 ++#define CLKGEN_UART3_PCLK 394 ++#define CLKGEN_X2H_CPUSYS_ACLK 395 ++#define CLKGEN_MIPI_CSI1_CFG_CLK 396 ++#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK2_DIV2_CLK 397 ++#define CLKGEN_MISCSYS_APB_HCLK 398 ++#define CLKGEN_CPU2CFG_X2H_ACLK 399 ++#define CLKGEN_MIPI_CSI2_FPCLK 400 ++#define CLKGEN_ISP_RY_CCLK 401 ++#define CLKGEN_X2P_VOSYS_ACLK 402 ++#define CLKGEN_VIPRE_PIXELCLK 403 ++#define VOSYS_GPU_TIMER_REFCLK 404 ++#define VOSYS_OSC_CLK_MUX_CEC_CLK 405 ++#define CLKGEN_APSYS_RSTGEN_PCLK 406 ++#define VOSYS_HDMI_ISCAN_SCL 407 ++#define CLKGEN_ISP_RY_HCLK 408 ++#define VOSYS_OSC_CLK 409 ++#define VISYS_PCLK 410 ++#define CLKGEN_AXI4_VO_ACLK 411 ++#define CLKGEN_MIPIDSI1_PLL_SCANCLK 412 ++#define GPIO1_DBCLK 413 ++#define CLKGEN_AXI4_VISYS2_ACLK 414 ++#define CLKGEN_EIP120SI_HCLK 415 ++#define CLKGEN_IOPMP_CHIP_DBG_ACLK 416 ++#define VOSYS_HDMI_ISCAN_TX_CK_20B_CLK 417 ++#define VOSYS_MIPIDSI1_REFCLK 418 ++#define CLKGEN_CHIP_DBG_ACLK 419 ++#define VOSYS_CFG_ACLK 420 ++#define CLKGEN_VOSYS_AXI_ACLK 421 ++#define CPU_BUS_DFTCLK 422 ++#define VOSYS_HDMI_ISCAN_CLK 423 ++#define VISYS_SLAVE_BUS_HCLK 424 ++#define CLKGEN_VPSYS_VDEC_PCLK 425 ++#define GMAC_PLL_FOUT4 426 ++#define CLKGEN_QSPI0_PCLK 427 ++#define CLKGEN_ISP1_CLK 428 ++#define CLKGEN_MIPI_CSI0_FPCLK 429 ++#define CLKGEN_ISP0_ACLK 430 ++#define CLKGEN_CPU2VI_X2H_ACLK 431 ++#define C910_CCLK 432 ++#define CLKGEN_DW200_CLK_VSE 433 ++#define CLKGEN_AXI4_CPUSYS1_ACLK 434 ++#define CLKGEN_GPU_CFG_ACLK 435 ++#define CLKGEN_GPIO1_FPCLK 436 ++#define CLKGEN_SRAM_AXI_ACLK_0 437 ++#define CLKGEN_I2C2_PCLK 438 ++#define CLKGEN_IOPMP_GMAC1_PCLK 439 ++#define CLKGEN_ISP0_S_HCLK 440 ++#define GPIO0_DBCLK 441 ++#define CLKGEN_AXI4_VO_CFG_ACLK 442 ++#define CLKGEN_NPU_CORE_CLK 443 ++#define DPU0_PLL_DIV_CLK 444 ++#define VOSYS_MIPIDSI0_SCANBYTECLK 445 ++#define CLKGEN_CHIP_DBG_CCLK 446 ++#define CLKGEN_DMAC_CPUSYS_HCLK 447 ++#define CLKGEN_IOPMP_DPU_ACLK 448 ++#define CLKGEN_DDR_SUBSYS_ACLK_3 449 ++#define CLK_100M 450 ++#define CLKGEN_DSMART_PCLK 451 ++#define CLKGEN_DW200_CLK_DWE 452 ++#define VPSYS_G2D_CCLK 453 ++#define CLKGEN_WDT1_PCLK 454 ++#define DPU1_PLL_FOUTPOSTDIV 455 ++#define CLKGEN_IOPMP_GMAC1_ACLK 456 ++#define CLKGEN_VPSYS_FCE_PCLK 457 ++#define CLKGEN_MIPI_CSI_SCANCLK 458 ++#define CLKGEN_MIPI_CSI2_PIXCLK 459 ++#define CLKGEN_I2C0_PCLK 460 ++#define VOSYS_HDMI_ISCAN_RX_WORD_CLK2_DIV2_CLK 461 ++#define CLKGEN_HDMI_SFR_CLK 462 ++#define TEE_PLL_TEST_CLK 463 ++#define CLKGEN_IOPMP_DMAC_CPUSYS_ACLK 464 ++#define CLKGEN_ISP_PIXELCLK 465 ++#define CLKGEN_MIPI_CSI1_FPCLK 466 ++#define SYS_PLL_FOUT4 467 ++#define CLKGEN_AXI4_VO_PCLK 468 ++#define CLKGEN_UART0_SCLK 469 ++#define CLKGEN_CPU2AON_X2H_MHCLK 470 ++#define VISYS_MIPI_CSI_SCANBYTECLK 471 ++#define UART_SCLK 472 ++#define CLKGEN_IOPMP_AON_ACLK 473 ++#define CLKGEN_VPSYS_VDEC_ACLK 474 ++#define CLKGEN_GMAC1_HCLK 475 ++#define CLKGEN_ISP_VENC_SHAKE_ACLK 476 ++#define TEESYS_HCLK 477 ++#define PWM_CCLK 478 ++#define CLKGEN_GPIO0_DBCLK 479 ++#define CLKGEN_SDIO0_OSC_CLK 480 ++#define CLKGEN_GMAC1_ACLK 481 ++#define VPSYS_ACLK 482 ++ ++#define AHB2_CPUSYS_HCLK_OUT_DIV 483 ++#define APB3_CPUSYS_PCLK_DIV 484 ++#define CFG_AXI_ACLK_OUT_DIV 485 ++#define PERISYS_AHB_HCLK_OUT_DIV 486 ++#define CLK_OUT_1_OUT_DIV 487 ++#define CLK_OUT_2_OUT_DIV 488 ++#define CLK_OUT_3_OUT_DIV 489 ++#define CLK_OUT_4_OUT_DIV 490 ++#define NPU_CCLK_OUT_DIV 491 ++#define CFG_APB_PCLK_OUT_DIV 492 ++#define CPU_PLL0_BYPASS 493 ++#define CPU_PLL1_BYPASS 494 ++#define GMAC_PLL_BYPASS 495 ++#define VIDEO_PLL_BYPASS 496 ++#define TEE_PLL_BYPASS 497 ++#define DPU0_PLL_BYPASS 498 ++#define DPU1_PLL_BYPASS 499 ++ ++#define CLK_DUMMY 500 ++#define OSC_32K 501 ++#define OSC_24M 502 ++#define RC_24M 503 ++ ++#define CLK_END 504 ++ ++#endif +diff --git a/include/dt-bindings/clock/light-mpw-clock.h b/include/dt-bindings/clock/light-mpw-clock.h +new file mode 100644 +index 000000000000..46c2a052a9d2 +--- /dev/null ++++ b/include/dt-bindings/clock/light-mpw-clock.h +@@ -0,0 +1,222 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef __DT_BINDINGS_CLOCK_LIGHT_H ++#define __DT_BINDINGS_CLOCK_LIGHT_H ++ ++#define LIGHT_CLK_DUMMY 0 ++#define LIGHT_CLK_32K 1 ++#define LIGHT_CLK_24M 2 ++#define LIGHT_RC_24M 3 ++ ++#define LIGHT_VIDEO_PLL_FOUTVCO 4 ++#define LIGHT_VIDEO_PLL_FOUTPOSTDIV 5 ++#define LIGHT_VIDEO_PLL_FOUT4 6 ++#define LIGHT_VIDEO_PLL_BYPASS 7 ++ ++#define LIGHT_GMAC_PLL_FOUTVCO 8 ++#define LIGHT_GMAC_PLL_FOUTPOSTDIV 9 ++#define LIGHT_GMAC_PLL_FOUT1PH0 10 ++#define LIGHT_GMAC_PLL_FOUT4 11 ++#define LIGHT_GMAC_PLL_BYPASS 12 ++ ++#define LIGHT_AUDIO_PLL_FOUTVCO 13 ++#define LIGHT_AUDIO_PLL_FOUTPOSTDIV 14 ++#define LIGHT_AUDIO_PLL_FOUT3 15 ++#define LIGHT_AUDIO_PLL_BYPASS 16 ++ ++#define LIGHT_SYS_PLL_FOUTVCO 17 ++#define LIGHT_SYS_PLL_FOUTPOSTDIV 18 ++#define LIGHT_SYS_PLL_FOUT4 19 ++#define LIGHT_SYS_PLL_BYPASS 20 ++ ++#define LIGHT_CPU_PLL0_FOUTVCO 21 ++#define LIGHT_CPU_PLL0_FOUTPOSTDIV 22 ++#define LIGHT_CPU_PLL0_FOUT4 23 ++#define LIGHT_CPU_PLL0_BYPASS 24 ++ ++#define LIGHT_CPU_PLL1_FOUTVCO 25 ++#define LIGHT_CPU_PLL1_FOUTPOSTDIV 26 ++#define LIGHT_CPU_PLL1_FOUT4 27 ++#define LIGHT_CPU_PLL1_BYPASS 28 ++ ++#define LIGHT_DDR_PLL_FOUTVCO 29 ++#define LIGHT_DDR_PLL_FOUTPOSTDIV 30 ++#define LIGHT_DDR_PLL_FOUT4 31 ++#define LIGHT_DDR_PLL_BYPASS 32 ++ ++#define LIGHT_AONSYS_CLK_SWITCH_0 33 ++#define LIGHT_AONSYS_CLK_SWITCH_1 34 ++#define LIGHT_AONSYS_CLK 35 ++#define LIGHT_SHARE_SRAM_CLK 36 ++#define LIGHT_CLKGEN_RTC_PCLK 37 ++#define LIGHT_CLKGEN_AOGPIO_PCLK 38 ++#define LIGHT_CLKGEN_AOI2C_PCLK 39 ++#define LIGHT_CLKGEN_PVTC_PCLK 40 ++#define LIGHT_CLKGEN_AOAHB_HCLK 41 ++#define LIGHT_CLKGEN_AOSRAM_HCLK 42 ++#define LIGHT_CLKGEN_AOAPB_HCLK 43 ++#define LIGHT_CLKGEN_AOPAD_PCLK 44 ++#define LIGHT_CLKGEN_AOTIMER_PCLK 45 ++#define LIGHT_CLKGEN_AOTIMER_CCLK 46 ++#define LIGHT_CLKGEN_SRAM_AXI_ACLK 47 ++#define LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_S 48 ++#define LIGHT_CLKGEN_AOGPIO_DBCLK 49 ++ ++#define LIGHT_GMAC_CORECLK 50 ++#define LIGHT_OSC_CLK_DIV24 51 ++#define LIGHT_GMAC_PLL_FOUTVCO_DIV5 52 ++#define LIGHT_C910_CCLK_I0 53 ++#define LIGHT_C910_CCLK 54 ++#define LIGHT_CPUSYS_AHB_HCLK 55 ++#define LIGHT_CPUSYS_CFG_AXI_ACLK 56 ++#define LIGHT_PERISYS_AHB_HCLK 57 ++#define LIGHT_CLK_OUT_1 58 ++#define LIGHT_CLK_OUT_2 59 ++#define LIGHT_CLK_OUT_3 60 ++#define LIGHT_CLK_OUT_4 61 ++#define LIGHT_CPUSYS_AHB_HCLK_DIV 62 ++#define LIGHT_APB3_CPUSYS_PCLK 63 ++#define LIGHT_CPUSYS_SUB_AXI_ACLK 64 ++#define LIGHT_CPUSYS_CFG_AXI_ACLK_DIV 65 ++#define LIGHT_TEESYS_HCLK 66 ++#define LIGHT_DMAC_1_CLK 67 ++#define LIGHT_DMAC_2_CLK 68 ++#define LIGHT_DMAC_3_CLK 69 ++#define LIGHT_AXI_PORT4_CLK 70 ++#define LIGHT_PERISYS_AHB_HCLK_DIV 71 ++#define LIGHT_PERISYS_APB_PCLK 72 ++#define LIGHT_CLK_OUT_1_DIV 73 ++#define LIGHT_CLK_OUT_2_DIV 74 ++#define LIGHT_CLK_OUT_3_DIV 75 ++#define LIGHT_CLK_OUT_4_DIV 76 ++#define LIGHT_CLKGEN_PERISYS_AXI_ACLK 77 ++#define LIGHT_CLKGEN_PERISYS_AHB_HCLK 78 ++#define LIGHT_CLKGEN_PERISYS_APB1_HCLK 79 ++#define LIGHT_CLKGEN_PERISYS_APB2_HCLK 80 ++#define LIGHT_CLKGEN_USB3_DRD_PHY_REF_CLK 81 ++#define LIGHT_CLKGEN_USB3_DRD_CTRL_REF_CLK 82 ++#define LIGHT_CLKGEN_USB3_DRD_SPDCLK 83 ++#define LIGHT_CLKGEN_USB3_DRD_ACLK 84 ++#define LIGHT_CLKGEN_EMMC1_X2X_ACLK 85 ++#define LIGHT_CLKGEN_EMMC0_X2X_ACLK 86 ++#define LIGHT_CLKGEN_EMMC0_HCLK 87 ++#define LIGHT_CLKGEN_EMMC1_HCLK 88 ++#define LIGHT_CLKGEN_GMAC_ACLK 89 ++#define LIGHT_CLKGEN_PWM_PCLK 90 ++#define LIGHT_CLKGEN_QSPI0_PCLK 91 ++#define LIGHT_CLKGEN_QSPI1_PCLK 92 ++#define LIGHT_CLKGEN_SPI_PCLK 93 ++#define LIGHT_CLKGEN_UART0_PCLK 94 ++#define LIGHT_CLKGEN_UART1_PCLK 95 ++#define LIGHT_CLKGEN_UART2_PCLK 96 ++#define LIGHT_CLKGEN_UART3_PCLK 97 ++#define LIGHT_CLKGEN_UART4_PCLK 98 ++#define LIGHT_CLKGEN_UART5_PCLK 99 ++#define LIGHT_CLKGEN_GPIO0_PCLK 100 ++#define LIGHT_CLKGEN_GPIO1_PCLK 101 ++#define LIGHT_CLKGEN_GPIO2_PCLK 102 ++#define LIGHT_CLKGEN_I2C0_IC_CLK 103 ++#define LIGHT_CLKGEN_I2C1_IC_CLK 104 ++#define LIGHT_CLKGEN_I2C2_IC_CLK 105 ++#define LIGHT_CLKGEN_I2C3_IC_CLK 106 ++#define LIGHT_CLKGEN_I2C4_IC_CLK 107 ++#define LIGHT_CLKGEN_I2C5_IC_CLK 108 ++#define LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_M 109 ++#define LIGHT_CLKGEN_AXI_DUMMY_SLV_4_ACLK 110 ++#define LIGHT_CLKGEN_AXI_DUMMY_SLV_3_ACLK 111 ++#define LIGHT_CLKGEN_AXI_DUMMY_SLV_2_ACLK 112 ++#define LIGHT_CLKGEN_AXI_DUMMY_SLV_1_ACLK 113 ++#define LIGHT_CLKGEN_APB_CPU2FG_HCLK 114 ++#define LIGHT_CLKGEN_AON2CPU_A2X_ACLK 115 ++#define LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_M 116 ++#define LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_M 117 ++#define LIGHT_CLKGEN_AXI4_CPUSYS2_ACLK 118 ++#define LIGHT_CLKGEN_X2X_CPUSYS_ACLK_M 119 ++#define LIGHT_CLKGEN_CHIP_DBG_ACLK 120 ++#define LIGHT_CLKGEN_AXI4_CFG_BUS_ACLK 121 ++#define LIGHT_CLKGEN_X2H_CPUSYS_ACLK 122 ++#define LIGHT_CLKGEN_CPU2TEE_X2H_ACLK 123 ++#define LIGHT_CLKGEN_CPU2AON_X2H_ACLK 124 ++#define LIGHT_CLKGEN_CPU2CFG_X2H_ACLK 125 ++#define LIGHT_CLKGEN_CPU2PERI_X2H_MHCLK 126 ++#define LIGHT_CLKGEN_AHB2_CPUSYS_HCLK 127 ++#define LIGHT_CLKGEN_APB3_CPUSYS_HCLK 128 ++#define LIGHT_CLKGEN_C910_BROM_HCLK 129 ++#define LIGHT_CLKGEN_DMAC_ACLK 130 ++#define LIGHT_CLKGEN_MBOX0_PCLK 131 ++#define LIGHT_CLKGEN_MBOX1_PCLK 132 ++#define LIGHT_CLKGEN_MBOX2_PCLK 133 ++#define LIGHT_CLKGEN_MBOX3_PCLK 134 ++#define LIGHT_CLKGEN_WDT0_PCLK 135 ++#define LIGHT_CLKGEN_WDT1_PCLK 136 ++#define LIGHT_CLKGEN_TIMER0_CCLK 137 ++#define LIGHT_CLKGEN_TIMER1_CCLK 138 ++#define LIGHT_CLKGEN_TRNG_RB_HCLK 139 ++#define LIGHT_CLKGEN_ADC_PCLK 140 ++#define LIGHT_CLKGEN_AXI_ACLK_4 141 ++#define LIGHT_CLKGEN_AXI_ACLK_3 142 ++#define LIGHT_CLKGEN_AXI_ACLK_2 143 ++#define LIGHT_CLKGEN_AXI_ACLK_1 145 ++#define LIGHT_CLKGEN_AXI_ACLK_0 146 ++#define LIGHT_CLKGEN_DMAC_1_ACLK 147 ++#define LIGHT_CLKGEN_DMAC_2_ACLK 148 ++#define LIGHT_CLKGEN_DMAC_3_ACLK 149 ++#define LIGHT_CLKGEN_SRAM_AXI_PCLK 150 ++#define LIGHT_CLKGEN_AHB2_TEESYS_HCLK 151 ++#define LIGHT_CLKGEN_EFUSE_MPW_PCLK 152 ++#define LIGHT_CLKGEN_CLK_OUT_4_CLK 153 ++#define LIGHT_CLKGEN_CLK_OUT_3_CLK 154 ++#define LIGHT_CLKGEN_CLK_OUT_2_CLK 155 ++#define LIGHT_CLKGEN_CLK_OUT_1_CLK 156 ++#define LIGHT_CLKGEN_DDR_APB_PCLK 157 ++#define LIGHT_CLKGEN_PADCTRL_APSYS_PCLK 158 ++#define LIGHT_CLKGEN_CHIP_DBG_CCLK 159 ++#define LIGHT_CHIP_DBG_CCLK 160 ++#define LIGHT_AXI_ACLK 161 ++ ++#define LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_S 162 ++#define LIGHT_CLKGEN_CPU2CFG_X2H_ACLK_S 163 ++#define LIGHT_CLKGEN_AON2CPU_A2X_HCLK 164 ++#define LIGHT_CLKGEN_DMAC_HCLK 165 ++#define LIGHT_CLKGEN_X2H_CPUSYS_MHCLK 166 ++#define LIGHT_CLKGEN_CPU2TEE_X2H_MHCLK 167 ++#define LIGHT_CLKGEN_CPU2AON_X2H_MHCLK 168 ++#define LIGHT_AXI_HCLK 169 ++#define LIGHT_CLKGEN_CPU2CFG_X2H_MHCLK 170 ++#define LIGHT_CLKGEN_TIMER0_PCLK 171 ++#define LIGHT_CLKGEN_TIMER1_PCLK 172 ++#define LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_S 173 ++#define LIGHT_CLKGEN_USB3_DRD_PCLK 174 ++#define LIGHT_CLKGEN_GMAC_HCLK 175 ++#define LIGHT_CLKGEN_GMAC_PCLK 176 ++#define LIGHT_CLKGEN_GMAC_CCLK 177 ++#define LIGHT_CLKGEN_EMMC0_ACLK 178 ++#define LIGHT_CLKGEN_EMMC0_REF_CLK 179 ++#define LIGHT_CLKGEN_EMMC0_OSC_CLK 180 ++#define LIGHT_CLKGEN_EMMC1_ACLK 181 ++#define LIGHT_CLKGEN_EMMC1_REF_CLK 182 ++#define LIGHT_CLKGEN_EMMC1_OSC_CLK 183 ++#define LIGHT_CLKGEN_PWM_CCLK 184 ++#define LIGHT_CLKGEN_QSPI0_SSI_CLK 185 ++#define LIGHT_CLKGEN_QSPI1_SSI_CLK 186 ++#define LIGHT_CLKGEN_SPI_SSI_CLK 187 ++#define LIGHT_CLKGEN_GPIO0_DBCLK 188 ++#define LIGHT_CLKGEN_GPIO1_DBCLK 189 ++#define LIGHT_CLKGEN_GPIO2_DBCLK 190 ++#define LIGHT_CLKGEN_DMAC_1_HCLK 191 ++#define LIGHT_CLKGEN_DMAC_2_HCLK 192 ++#define LIGHT_CLKGEN_DMAC_3_HCLK 193 ++#define LIGHT_EMMC_CLK_DIV 194 ++#define LIGHT_EMMC0_OSC_CLK 195 ++#define LIGHT_EMMC1_OSC_CLK 196 ++#define LIGHT_PWM_CCLK 197 ++#define LIGHT_USB3_PHY_REF_CLK 198 ++#define LIGHT_SPI_CLK 199 ++#define LIGHT_GPIO_DBCLK 200 ++#define LIGHT_X2H_HCLK 201 ++ ++#define LIGHT_CLK_END 202 ++#endif +diff --git a/include/dt-bindings/clock/light-visys.h b/include/dt-bindings/clock/light-visys.h +new file mode 100644 +index 000000000000..53fed0bfb624 +--- /dev/null ++++ b/include/dt-bindings/clock/light-visys.h +@@ -0,0 +1,54 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef _LIGHT_VISYS_H ++#define _LIGHT_VISYS_H ++ ++#define LIGHT_CLKGEN_VISYS_ACLK 0 ++#define LIGHT_CLKGEN_DW200_ACLK 1 ++#define LIGHT_CLKGEN_AXI4_VISYS1_ACLK 2 ++#define LIGHT_CLKGEN_AXI4_VISYS2_ACLK 3 ++#define LIGHT_CLKGEN_AXI4_VISYS3_ACLK 4 ++#define LIGHT_CLKGEN_ISP0_ACLK 5 ++#define LIGHT_CLKGEN_ISP_RY_ACLK 6 ++#define LIGHT_CLKGEN_ISP_VENC_SHAKE_ACLK 7 ++#define LIGHT_CLKGEN_VIPRE_ACLK 8 ++#define LIGHT_CLKGEN_VISYS_SLAVE_HCLK 9 ++#define LIGHT_CLKGEN_ISP0_S_HCLK 10 ++#define LIGHT_CLKGEN_DW200_HCLK 11 ++#define LIGHT_CLKGEN_ISP_RY_HCLK 12 ++#define LIGHT_CLKGEN_MIPI_CSI0_PCLK 13 ++#define LIGHT_CLKGEN_MIPI_CSI0_FPCLK 14 ++#define LIGHT_CLKGEN_MIPI_CSI1_PCLK 15 ++#define LIGHT_CLKGEN_MIPI_CSI1_FPCLK 16 ++#define LIGHT_CLKGEN_MIPI_CSI2_PCLK 17 ++#define LIGHT_CLKGEN_MIPI_CSI2_FPCLK 18 ++#define LIGHT_CLKGEN_VIPRE_PCLK 19 ++#define LIGHT_CLKGEN_VISYS_PCLK 20 ++#define LIGHT_CLKGEN_VISYS_SYSREG_PCLK 21 ++#define LIGHT_CLKGEN_ISP_VENC_SHAKE_PCLK 22 ++#define LIGHT_CLKGEN_MIPI_CSI0_PIXCLK 23 ++#define LIGHT_CLKGEN_MIPI_CSI1_PIXCLK 24 ++#define LIGHT_CLKGEN_MIPI_CSI2_PIXCLK 25 ++#define LIGHT_CLKGEN_VIPRE_PIXELCLK 26 ++#define LIGHT_CLKGEN_ISP_PIXELCLK 27 ++#define LIGHT_CLKGEN_MIPI_CSI0_CFG_CLK 28 ++#define LIGHT_CLKGEN_MIPI_CSI1_CFG_CLK 29 ++#define LIGHT_CLKGEN_MIPI_CSI2_CFG_CLK 30 ++#define LIGHT_CLKGEN_DW200_CLK_VSE 31 ++#define LIGHT_CLKGEN_DW200_CLK_DWE 32 ++#define LIGHT_CLKGEN_ISP0_CLK 33 ++#define LIGHT_CLKGEN_ISP1_CLK 34 ++#define LIGHT_CLKGEN_ISP_RY_CCLK 35 ++#define LIGHT_CLKGEN_MIPI_CSI_SCANBYTECLK 36 ++#define LIGHT_CLKGEN_MIPI_CSI_SCANCLK 37 ++#define LIGHT_CLKGEN_ISP1_PIXELCLK 38 ++#define LIGHT_CLKGEN_ISP0_PIXELCLK 39 ++#define LIGHT_CLKGEN_ISP1_HCLK 40 ++#define LIGHT_CLKGEN_ISP0_HCLK 41 ++#define LIGHT_CLKGEN_ISP1_ACLK 42 ++#define LIGHT_CLKGEN_VISYS_CLK_END 43 ++ ++#endif +diff --git a/include/dt-bindings/clock/light-vosys.h b/include/dt-bindings/clock/light-vosys.h +new file mode 100644 +index 000000000000..dbdd7fa7016b +--- /dev/null ++++ b/include/dt-bindings/clock/light-vosys.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef LIGHT_VOSYS_H ++#define LIGHT_VOSYS_H ++ ++#define LIGHT_CLKGEN_AXI4_VO_PCLK 0 ++#define LIGHT_CLKGEN_IOPMP_VOSYS_DPU_PCLK 1 ++#define LIGHT_CLKGEN_IOPMP_VOSYS_DPU1_PCLK 2 ++#define LIGHT_CLKGEN_IOPMP_VOSYS_GPU_PCLK 3 ++#define LIGHT_CLKGEN_HDMI_PCLK 4 ++#define LIGHT_CLKGEN_MIPIDSI0_PCLK 5 ++#define LIGHT_CLKGEN_MIPIDSI1_PCLK 6 ++#define LIGHT_CLKGEN_AXI4_VO_ACLK 7 ++#define LIGHT_CLKGEN_IOPMP_GPU_ACLK 8 ++#define LIGHT_CLKGEN_IOPMP_DPU_ACLK 9 ++#define LIGHT_CLKGEN_IOPMP_DPU1_ACLK 10 ++#define LIGHT_CLKGEN_X2H_DPU_ACLK 11 ++#define LIGHT_CLKGEN_X2H_DPU1_ACLK 12 ++#define LIGHT_CLKGEN_MIPIDSI0_PIXCLK 13 ++#define LIGHT_CLKGEN_HDMI_PIXCLK 14 ++#define LIGHT_CLKGEN_MIPIDSI1_PIXCLK 15 ++#define LIGHT_CLKGEN_HDMI_SFR_CLK 16 ++#define LIGHT_CLKGEN_HDMI_CEC_CLK 17 ++#define LIGHT_CLKGEN_HDMI_I2S_CLK 18 ++#define LIGHT_CLKGEN_MIPIDSI0_CFG_CLK 19 ++#define LIGHT_CLKGEN_MIPIDSI1_CFG_CLK 20 ++#define LIGHT_CLKGEN_MIPIDSI0_REFCLK 21 ++#define LIGHT_CLKGEN_MIPIDSI1_REFCLK 22 ++#define LIGHT_CLKGEN_GPU_CORE_CLK 23 ++#define LIGHT_CLKGEN_GPU_CFG_ACLK 24 ++#define LIGHT_CLKGEN_DPU_HCLK 25 ++#define LIGHT_CLKGEN_DPU_ACLK 26 ++#define LIGHT_CLKGEN_DPU_CCLK 27 ++#define LIGHT_CLKGEN_DPU_PIXCLK0 28 ++#define LIGHT_CLKGEN_DPU_PIXCLK1 29 ++#define LIGHT_CLKGEN_VOSYS_CLK_END 30 ++ ++#endif +diff --git a/include/dt-bindings/clock/light-vpsys.h b/include/dt-bindings/clock/light-vpsys.h +new file mode 100644 +index 000000000000..188aaa6cc435 +--- /dev/null ++++ b/include/dt-bindings/clock/light-vpsys.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef _LIGHT_VPSYS_H ++#define _LIGHT_VPSYS_H ++ ++#define LIGHT_VPSYS_G2D_PCLK 0 ++#define LIGHT_VPSYS_G2D_ACLK 1 ++#define LIGHT_VPSYS_G2D_CCLK 2 ++#define LIGHT_VPSYS_FCE_PCLK 3 ++#define LIGHT_VPSYS_FCE_ACLK 4 ++#define LIGHT_VPSYS_VDEC_PCLK 5 ++#define LIGHT_VPSYS_VDEC_ACLK 6 ++#define LIGHT_VPSYS_VDEC_CCLK 7 ++#define LIGHT_VPSYS_AXI_ACLK 8 ++#define LIGHT_VPSYS_VENC_CCLK 9 ++#define LIGHT_VPSYS_VENC_PCLK 10 ++#define LIGHT_VPSYS_VENC_ACLK 11 ++#define LIGHT_VPSYS_CLK_END 12 ++ ++#endif ++ +diff --git a/include/dt-bindings/clock/sophgo-mango-clock.h b/include/dt-bindings/clock/sophgo-mango-clock.h +new file mode 100644 +index 000000000000..aaed4ad27dc1 +--- /dev/null ++++ b/include/dt-bindings/clock/sophgo-mango-clock.h +@@ -0,0 +1,165 @@ ++#ifndef __SOPHGO_MANGO_CLOCK__ ++#define __SOPHGO_MANGO_CLOCK__ ++ ++#include <dt-bindings/clock/sophgo.h> ++ ++/*div clock*/ ++#define DIV_CLK_MPLL_RP_CPU_NORMAL_0 0 ++#define DIV_CLK_MPLL_AXI_DDR_0 1 ++#define DIV_CLK_FPLL_DDR01_1 2 ++#define DIV_CLK_FPLL_DDR23_1 3 ++#define DIV_CLK_FPLL_RP_CPU_NORMAL_1 4 ++#define DIV_CLK_FPLL_50M_A53 5 ++#define DIV_CLK_FPLL_TOP_RP_CMN_DIV2 6 ++#define DIV_CLK_FPLL_UART_500M 7 ++#define DIV_CLK_FPLL_AHB_LPC 8 ++#define DIV_CLK_FPLL_EFUSE 9 ++#define DIV_CLK_FPLL_TX_ETH0 10 ++#define DIV_CLK_FPLL_PTP_REF_I_ETH0 11 ++#define DIV_CLK_FPLL_REF_ETH0 12 ++#define DIV_CLK_FPLL_EMMC 13 ++#define DIV_CLK_FPLL_SD 14 ++#define DIV_CLK_FPLL_TOP_AXI0 15 ++#define DIV_CLK_FPLL_TOP_AXI_HSPERI 16 ++#define DIV_CLK_FPLL_AXI_DDR_1 17 ++#define DIV_CLK_FPLL_DIV_TIMER1 18 ++#define DIV_CLK_FPLL_DIV_TIMER2 19 ++#define DIV_CLK_FPLL_DIV_TIMER3 20 ++#define DIV_CLK_FPLL_DIV_TIMER4 21 ++#define DIV_CLK_FPLL_DIV_TIMER5 22 ++#define DIV_CLK_FPLL_DIV_TIMER6 23 ++#define DIV_CLK_FPLL_DIV_TIMER7 24 ++#define DIV_CLK_FPLL_DIV_TIMER8 25 ++#define DIV_CLK_FPLL_100K_EMMC 26 ++#define DIV_CLK_FPLL_100K_SD 27 ++#define DIV_CLK_FPLL_GPIO_DB 28 ++#define DIV_CLK_DPLL0_DDR01_0 29 ++#define DIV_CLK_DPLL1_DDR23_0 30 ++ ++/* MPLL */ ++#define GATE_CLK_RP_CPU_NORMAL_DIV0 31 ++#define GATE_CLK_AXI_DDR_DIV0 32 ++ ++/* FPLL */ ++#define GATE_CLK_RP_CPU_NORMAL_DIV1 33 ++#define GATE_CLK_A53_50M 34 ++#define GATE_CLK_TOP_RP_CMN_DIV2 35 ++#define GATE_CLK_HSDMA 36 ++#define GATE_CLK_EMMC_100M 37 ++#define GATE_CLK_SD_100M 38 ++#define GATE_CLK_TX_ETH0 39 ++#define GATE_CLK_PTP_REF_I_ETH0 40 ++#define GATE_CLK_REF_ETH0 41 ++#define GATE_CLK_UART_500M 42 ++#define GATE_CLK_EFUSE 43 ++ ++#define GATE_CLK_AHB_LPC 44 ++#define GATE_CLK_AHB_ROM 45 ++#define GATE_CLK_AHB_SF 46 ++ ++#define GATE_CLK_APB_UART 47 ++#define GATE_CLK_APB_TIMER 48 ++#define GATE_CLK_APB_EFUSE 49 ++#define GATE_CLK_APB_GPIO 50 ++#define GATE_CLK_APB_GPIO_INTR 51 ++#define GATE_CLK_APB_SPI 52 ++#define GATE_CLK_APB_I2C 53 ++#define GATE_CLK_APB_WDT 54 ++#define GATE_CLK_APB_PWM 55 ++#define GATE_CLK_APB_RTC 56 ++ ++#define GATE_CLK_AXI_PCIE0 57 ++#define GATE_CLK_AXI_PCIE1 58 ++#define GATE_CLK_SYSDMA_AXI 59 ++#define GATE_CLK_AXI_DBG_I2C 60 ++#define GATE_CLK_AXI_SRAM 61 ++#define GATE_CLK_AXI_ETH0 62 ++#define GATE_CLK_AXI_EMMC 63 ++#define GATE_CLK_AXI_SD 64 ++#define GATE_CLK_TOP_AXI0 65 ++#define GATE_CLK_TOP_AXI_HSPERI 66 ++ ++#define GATE_CLK_TIMER1 67 ++#define GATE_CLK_TIMER2 68 ++#define GATE_CLK_TIMER3 69 ++#define GATE_CLK_TIMER4 70 ++#define GATE_CLK_TIMER5 71 ++#define GATE_CLK_TIMER6 72 ++#define GATE_CLK_TIMER7 73 ++#define GATE_CLK_TIMER8 74 ++#define GATE_CLK_100K_EMMC 75 ++#define GATE_CLK_100K_SD 76 ++#define GATE_CLK_GPIO_DB 77 ++ ++#define GATE_CLK_AXI_DDR_DIV1 78 ++#define GATE_CLK_DDR01_DIV1 79 ++#define GATE_CLK_DDR23_DIV1 80 ++/* DPLL0 */ ++#define GATE_CLK_DDR01_DIV0 81 ++/* DPLL1 */ ++#define GATE_CLK_DDR23_DIV0 82 ++ ++#define GATE_CLK_DDR01 83 ++#define GATE_CLK_DDR23 84 ++#define GATE_CLK_RP_CPU_NORMAL 85 ++#define GATE_CLK_AXI_DDR 86 ++#define GATE_CLK_RXU0 87 ++#define GATE_CLK_RXU1 88 ++#define GATE_CLK_RXU2 89 ++#define GATE_CLK_RXU3 90 ++#define GATE_CLK_RXU4 91 ++#define GATE_CLK_RXU5 92 ++#define GATE_CLK_RXU6 93 ++#define GATE_CLK_RXU7 94 ++#define GATE_CLK_RXU8 95 ++#define GATE_CLK_RXU9 96 ++#define GATE_CLK_RXU10 97 ++#define GATE_CLK_RXU11 98 ++#define GATE_CLK_RXU12 99 ++#define GATE_CLK_RXU13 100 ++#define GATE_CLK_RXU14 101 ++#define GATE_CLK_RXU15 102 ++#define GATE_CLK_RXU16 103 ++#define GATE_CLK_RXU17 104 ++#define GATE_CLK_RXU18 105 ++#define GATE_CLK_RXU19 106 ++#define GATE_CLK_RXU20 107 ++#define GATE_CLK_RXU21 108 ++#define GATE_CLK_RXU22 109 ++#define GATE_CLK_RXU23 110 ++#define GATE_CLK_RXU24 111 ++#define GATE_CLK_RXU25 112 ++#define GATE_CLK_RXU26 113 ++#define GATE_CLK_RXU27 114 ++#define GATE_CLK_RXU28 115 ++#define GATE_CLK_RXU29 116 ++#define GATE_CLK_RXU30 117 ++#define GATE_CLK_RXU31 118 ++#define GATE_CLK_MP0 119 ++#define GATE_CLK_MP1 120 ++#define GATE_CLK_MP2 121 ++#define GATE_CLK_MP3 122 ++#define GATE_CLK_MP4 123 ++#define GATE_CLK_MP5 124 ++#define GATE_CLK_MP6 125 ++#define GATE_CLK_MP7 126 ++#define GATE_CLK_MP8 127 ++#define GATE_CLK_MP9 128 ++#define GATE_CLK_MP10 129 ++#define GATE_CLK_MP11 130 ++#define GATE_CLK_MP12 131 ++#define GATE_CLK_MP13 132 ++#define GATE_CLK_MP14 133 ++#define GATE_CLK_MP15 134 ++ ++/* MUX */ ++#define MUX_CLK_DDR01 0 ++#define MUX_CLK_DDR23 1 ++#define MUX_CLK_RP_CPU_NORMAL 2 ++#define MUX_CLK_AXI_DDR 3 ++ ++#define S0_DIV_CLK_TABLE 0 ++#define S1_DIV_CLK_TABLE 1 ++#define S0_MUX_CLK_TABLE 2 ++#define S1_MUX_CLK_TABLE 3 ++#endif +diff --git a/include/dt-bindings/clock/sophgo.h b/include/dt-bindings/clock/sophgo.h +new file mode 100644 +index 000000000000..5584243f9135 +--- /dev/null ++++ b/include/dt-bindings/clock/sophgo.h +@@ -0,0 +1,15 @@ ++#ifndef __SOPHGO_CLK__ ++#define __SOPHGO_CLK__ ++ ++//PLL ID ++#define MPLL_CLK 0 ++#define FPLL_CLK 3 ++#define DPLL0_CLK 4 ++#define DPLL1_CLK 5 ++ ++//clock mode ++#define NORMAL_MODE 0 ++#define FAST_MODE 1 ++#define SAFE_MODE 2 ++#define BYPASS_MODE 3 ++#endif +diff --git a/include/dt-bindings/firmware/thead/rsrc.h b/include/dt-bindings/firmware/thead/rsrc.h +new file mode 100644 +index 000000000000..8cee0fcaeb74 +--- /dev/null ++++ b/include/dt-bindings/firmware/thead/rsrc.h +@@ -0,0 +1,17 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2022 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef __DT_BINDINGS_RSCRC_LIGHT_H ++#define __DT_BINDINGS_RSCRC_LIGHT_H ++ ++#define LIGHT_AON_AUDIO_PD 0 ++#define LIGHT_AON_VDEC_PD 1 ++#define LIGHT_AON_NPU_PD 2 ++#define LIGHT_AON_VENC_PD 3 ++#define LIGHT_AON_GPU_PD 4 ++#define LIGHT_AON_DSP0_PD 5 ++#define LIGHT_AON_DSP1_PD 6 ++ ++#endif +diff --git a/include/dt-bindings/reset/sophgo-mango-resets.h b/include/dt-bindings/reset/sophgo-mango-resets.h +new file mode 100644 +index 000000000000..9ff8ca4c3d67 +--- /dev/null ++++ b/include/dt-bindings/reset/sophgo-mango-resets.h +@@ -0,0 +1,96 @@ ++/* ++ * Sophgo SoCs Reset definitions ++ * ++ * Copyright (c) 2018 Bitmain Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef _DT_BINDINGS_RST_MANGO_H_ ++#define _DT_BINDINGS_RST_MANGO_H_ ++ ++#define RST_MAIN_AP 0 ++#define RST_RISCV_CPU 1 ++#define RST_RISCV_LOW_SPEED_LOGIC 2 ++#define RST_RISCV_CMN 3 ++#define RST_HSDMA 4 ++#define RST_SYSDMA 5 ++#define RST_EFUSE0 6 ++#define RST_EFUSE1 7 ++#define RST_RTC 8 ++#define RST_TIMER 9 ++#define RST_WDT 10 ++#define RST_AHB_ROM0 11 ++#define RST_AHB_ROM1 12 ++#define RST_I2C0 13 ++#define RST_I2C1 14 ++#define RST_I2C2 15 ++#define RST_I2C3 16 ++#define RST_GPIO0 17 ++#define RST_GPIO1 18 ++#define RST_GPIO2 19 ++#define RST_PWM 20 ++#define RST_AXI_SRAM0 21 ++#define RST_AXI_SRAM1 22 ++#define RST_SF0 23 ++#define RST_SF1 24 ++#define RST_LPC 25 ++#define RST_ETH0 26 ++#define RST_EMMC 27 ++#define RST_SD 28 ++#define RST_UART0 29 ++#define RST_UART1 30 ++#define RST_UART2 31 ++ ++#define RST_UART3 32 ++#define RST_SPI0 33 ++#define RST_SPI1 34 ++#define RST_DBG_I2C 35 ++#define RST_PCIE0 36 ++#define RST_PCIE1 37 ++#define RST_DDR0 38 ++#define RST_DDR1 39 ++#define RST_DDR2 40 ++#define RST_DDR3 41 ++#define RST_FAU0 42 ++#define RST_FAU1 43 ++#define RST_FAU2 44 ++#define RST_RXU0 45 ++#define RST_RXU1 46 ++#define RST_RXU2 47 ++#define RST_RXU3 48 ++#define RST_RXU4 49 ++#define RST_RXU5 50 ++#define RST_RXU6 51 ++#define RST_RXU7 52 ++#define RST_RXU8 53 ++#define RST_RXU9 54 ++#define RST_RXU10 55 ++#define RST_RXU11 56 ++#define RST_RXU12 57 ++#define RST_RXU13 58 ++#define RST_RXU14 59 ++#define RST_RXU15 60 ++#define RST_RXU16 61 ++#define RST_RXU17 62 ++#define RST_RXU18 63 ++#define RST_RXU19 64 ++#define RST_RXU20 65 ++#define RST_RXU21 66 ++#define RST_RXU22 67 ++#define RST_RXU23 68 ++#define RST_RXU24 69 ++#define RST_RXU25 70 ++#define RST_RXU26 71 ++#define RST_RXU27 72 ++#define RST_RXU28 73 ++#define RST_RXU29 74 ++#define RST_RXU30 75 ++#define RST_RXU31 76 ++ ++#define RST_MAX_NUM (RST_RXU31+1) ++ ++#endif +diff --git a/include/dt-bindings/reset/thead,th1520-reset.h b/include/dt-bindings/reset/thead,th1520-reset.h +new file mode 100644 +index 000000000000..ec10751814e5 +--- /dev/null ++++ b/include/dt-bindings/reset/thead,th1520-reset.h +@@ -0,0 +1,9 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ ++ ++#ifndef DT_BINDING_RESET_TH1520_H ++#define DT_BINDING_RESET_TH1520_H ++ ++#define TH1520_RESET_WDT0 0 ++#define TH1520_RESET_WDT1 1 ++ ++#endif +diff --git a/include/linux/firmware/thead/ipc.h b/include/linux/firmware/thead/ipc.h +new file mode 100644 +index 000000000000..dfda60e76725 +--- /dev/null ++++ b/include/linux/firmware/thead/ipc.h +@@ -0,0 +1,74 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2021 Alibaba Group Holding Limited. ++ */ ++ ++#ifndef _SC_IPC_H ++#define _SC_IPC_H ++ ++#include <linux/device.h> ++#include <linux/types.h> ++ ++#define AON_RPC_MSG_MAGIC (0xef) ++#define LIGHT_AON_RPC_VERSION 1 ++#define LIGHT_AON_RPC_MSG_NUM 7 ++ ++struct light_aon_ipc; ++ ++enum light_aon_rpc_svc { ++ LIGHT_AON_RPC_SVC_UNKNOWN = 0, ++ LIGHT_AON_RPC_SVC_RETURN = 1, ++ LIGHT_AON_RPC_SVC_PM = 2, ++ LIGHT_AON_RPC_SVC_MISC = 3, ++ LIGHT_AON_RPC_SVC_AVFS = 4, ++}; ++ ++enum light_aon_misc_func { ++ LIGHT_AON_MISC_FUNC_UNKNOWN = 0, ++ LIGHT_AON_MISC_FUNC_SET_CONTROL = 1, ++ LIGHT_AON_MISC_FUNC_GET_CONTROL = 2, ++ LIGHT_AON_MISC_FUNC_WDG_START = 3, ++ LIGHT_AON_MISC_FUNC_WDG_STOP = 4, ++ LIGHT_AON_MISC_FUNC_WDG_PING = 5, ++ LIGHT_AON_MISC_FUNC_WDG_TIMEOUTSET = 6, ++ LIGHT_AON_MISC_FUNC_WDG_RESTART = 7, ++ LIGHT_AON_MISC_FUNC_WDG_GET_STATE = 8, ++ LIGHT_AON_MISC_FUNC_WDG_POWER_OFF = 9, ++ LIGHT_AON_MISC_FUNC_AON_WDT_ON = 10, ++ LIGHT_AON_MISC_FUNC_AON_WDT_OFF = 11, ++ LIGHT_AON_MISC_FUNC_AON_RESERVE_MEM = 12, ++ LIGHT_AON_MISC_FUNC_REQUIRE_STR = 13, ++ LIGHT_AON_MISC_FUNC_RESUME_STR = 14, ++ LIGHT_AON_MISC_FUNC_REQUIRE_STD = 15, ++ LIGHT_AON_MISC_FUNC_CPUHP = 16, ++}; ++ ++enum light_aon_pm_func { ++ LIGHT_AON_PM_FUNC_UNKNOWN = 0, ++ LIGHT_AON_PM_FUNC_SET_RESOURCE_REGULATOR = 1, ++ LIGHT_AON_PM_FUNC_GET_RESOURCE_REGULATOR = 2, ++ LIGHT_AON_PM_FUNC_SET_RESOURCE_POWER_MODE = 3, ++ LIGHT_AON_PM_FUNC_PWR_SET = 4, ++ LIGHT_AON_PM_FUNC_PWR_GET = 5, ++}; ++ ++struct light_aon_rpc_msg_hdr { ++ uint8_t ver; ///< version of msg hdr ++ uint8_t size; ///< msg size ,uinit in bytes,the size includes rpc msg header self. ++ uint8_t svc; ///< rpc main service id ++ uint8_t func; ///< rpc sub func id of specific service, sent by caller ++} __packed __aligned(4); ++ ++/* ++ * Defines for SC PM Power Mode ++ */ ++#define LIGHT_AON_PM_PW_MODE_OFF 0 /* Power off */ ++#define LIGHT_AON_PM_PW_MODE_STBY 1 /* Power in standby */ ++#define LIGHT_AON_PM_PW_MODE_LP 2 /* Power in low-power */ ++#define LIGHT_AON_PM_PW_MODE_ON 3 /* Power on */ ++ ++int light_aon_call_rpc(struct light_aon_ipc *ipc, void *msg, bool have_resp); ++int light_aon_get_handle(struct light_aon_ipc **ipc); ++int light_aon_misc_set_control(struct light_aon_ipc *ipc, u16 resource, u32 ctrl, u32 val); ++int light_aon_misc_get_control(struct light_aon_ipc *ipc, u16 resource, u32 ctrl, u32 *val); ++#endif /* _SC_IPC_H */ +diff --git a/include/linux/firmware/thead/light_event.h b/include/linux/firmware/thead/light_event.h +new file mode 100644 +index 000000000000..a4f99d41c2d1 +--- /dev/null ++++ b/include/linux/firmware/thead/light_event.h +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#ifndef _LIGHT_EVENT_H ++#define _LIGHT_EVENT_H ++ ++enum light_rebootmode_index { ++ /* C902 event rebootmode */ ++ LIGHT_EVENT_PMIC_RESET = 0x0, ++ LIGHT_EVENT_PMIC_ONKEY, ++ LIGHT_EVENT_PMIC_POWERUP, ++ ++ /* C910 event rebootmode */ ++ LIGHT_EVENT_SW_REBOOT = 0x20, ++ LIGHT_EVENT_SW_WATCHDOG, ++ LIGHT_EVENT_SW_PANIC, ++ LIGHT_EVENT_SW_HANG, ++ LIGHT_EVENT_MAX, ++}; ++ ++#if IS_ENABLED(CONFIG_LIGHT_REBOOTMODE) ++extern int light_event_set_rebootmode(enum light_rebootmode_index mode); ++extern int light_event_get_rebootmode(enum light_rebootmode_index *mode); ++#else ++static int light_event_set_rebootmode(enum light_rebootmode_index mode) ++{ ++ return 0; ++} ++static int light_event_get_rebootmode(enum light_rebootmode_index *mode) ++{ ++ *mode = LIGHT_EVENT_MAX; ++ ++ return 0; ++} ++#endif ++ ++#endif +diff --git a/include/linux/light_rpmsg.h b/include/linux/light_rpmsg.h +new file mode 100644 +index 000000000000..8930845604a0 +--- /dev/null ++++ b/include/linux/light_rpmsg.h +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (C) 2023 Alibaba Group Holding Limited. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU Lesser General ++ * Public License. You may obtain a copy of the GNU Lesser General ++ * Public License Version 2.1 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/lgpl-license.html ++ * http://www.gnu.org/copyleft/lgpl.html ++ */ ++ ++/* ++ * @file linux/light_rpmsg.h ++ * ++ * @brief Global header file for imx RPMSG ++ * ++ * @ingroup RPMSG ++ */ ++#ifndef __LINUX_LIGHT_RPMSG_H__ ++#define __LINUX_LIGHT_RPMSG_H__ ++ ++#include <linux/rpmsg.h> ++#include <linux/slab.h> ++#include <linux/virtio.h> ++#include <linux/virtio_config.h> ++#include <linux/virtio_ids.h> ++#include <linux/virtio_ring.h> ++ ++/* Category define */ ++#define LIGHT_RMPSG_LIFECYCLE 1 ++#define LIGHT_RPMSG_PMIC 2 ++#define LIGHT_RPMSG_AUDIO 3 ++#define LIGHT_RPMSG_KEY 4 ++#define LIGHT_RPMSG_GPIO 5 ++#define LIGHT_RPMSG_RTC 6 ++#define LIGHT_RPMSG_SENSOR 7 ++/* rpmsg version */ ++#define LIGHT_RMPSG_MAJOR 1 ++#define LIGHT_RMPSG_MINOR 0 ++ ++enum light_rpmsg_variants { ++ LIGHTA, ++ LIGHTB, ++ LIGHT_RPMSG, ++}; ++ ++struct light_virdev { ++ struct virtio_device vdev; ++ unsigned int vring2; ++ struct virtqueue *vq2; ++ int base_vq_id; ++ int num_of_vqs; ++ struct notifier_block nb; ++}; ++ ++struct light_rpmsg_vproc { ++ char *rproc_name; ++ struct mutex lock; ++ struct clk *mu_clk; ++ enum light_rpmsg_variants variant; ++ int vdev_nums; ++ int first_notify; ++#define MAX_VDEV_NUMS 8 ++ struct light_virdev ivdevMAX_VDEV_NUMS; ++ void __iomem *mu_base; ++ struct delayed_work rpmsg_work; ++ struct blocking_notifier_head notifier; ++#define MAX_NUM 10 /* enlarge it if overflow happen */ ++ u32 m4_messageMAX_NUM; ++ u32 in_idx; ++ u32 out_idx; ++ u32 core_id; ++ spinlock_t mu_lock; ++#ifdef CONFIG_PM_SLEEP ++ struct semaphore pm_sem; ++ int sleep_flag; ++#endif ++}; ++ ++struct light_rpmsg_head { ++ u8 cate; ++ u8 major; ++ u8 minor; ++ u8 type; ++ u8 cmd; ++ u8 reserved5; ++} __attribute__ ((packed)); ++ ++#endif /* __LINUX_LIGHT_RPMSG_H__*/ ++ +diff --git a/kernel/panic.c b/kernel/panic.c +index ffa037fa777d..d054d02133f9 100644 +--- a/kernel/panic.c ++++ b/kernel/panic.c +@@ -37,6 +37,7 @@ + #include <linux/context_tracking.h> + #include <trace/events/error_report.h> + #include <asm/sections.h> ++#include <linux/firmware/thead/light_event.h> + + #define PANIC_TIMER_STEP 100 + #define PANIC_BLINK_SPD 18 +@@ -281,6 +282,11 @@ void panic(const char *fmt, ...) + int state = 0; + int old_cpu, this_cpu; + bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers; ++ enum light_rebootmode_index mode; ++ ++ if (!light_event_get_rebootmode(&mode) && ++ mode != LIGHT_EVENT_SW_WATCHDOG) ++ light_event_set_rebootmode(LIGHT_EVENT_SW_PANIC); + + if (panic_on_warn) { + /* +diff --git a/mm/memblock.c b/mm/memblock.c +index e18a25f6ce04..047b45ade06f 100644 +--- a/mm/memblock.c ++++ b/mm/memblock.c +@@ -1779,6 +1779,7 @@ phys_addr_t __init_memblock memblock_end_of_DRAM(void) + + static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit) + { ++ phys_addr_t phys_ram_base = memblock_start_of_DRAM(); + phys_addr_t max_addr = PHYS_ADDR_MAX; + struct memblock_region *r; + +@@ -1788,11 +1789,10 @@ static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit) + * of those regions, max_addr will keep original value PHYS_ADDR_MAX + */ + for_each_mem_region(r) { +- if (limit <= r->size) { +- max_addr = r->base + limit; ++ if ((r->base + r->size) >= (phys_ram_base + limit)) { ++ max_addr = phys_ram_base + limit; + break; + } +- limit -= r->size; + } + + return max_addr; +diff --git a/scripts/package/builddeb b/scripts/package/builddeb +index d7dd0d04c70c..259668daea63 100755 +--- a/scripts/package/builddeb ++++ b/scripts/package/builddeb +@@ -85,7 +85,7 @@ install_linux_image () { + case "${SRCARCH}" in + um) + installed_image_path="usr/bin/linux-${KERNELRELEASE}";; +- parisc|mips|powerpc) ++ parisc|mips|powerpc|riscv*) + installed_image_path="boot/vmlinux-${KERNELRELEASE}";; + *) + installed_image_path="boot/vmlinuz-${KERNELRELEASE}";; +diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c +index af2b2bb9a8ff..d825d925f641 100644 +--- a/sound/pci/hda/hda_intel.c ++++ b/sound/pci/hda/hda_intel.c +@@ -298,8 +298,7 @@ enum { + + /* quirks for ATI/AMD HDMI */ + #define AZX_DCAPS_PRESET_ATI_HDMI \ +- (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB|\ +- AZX_DCAPS_NO_MSI64) ++ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB) + + /* quirks for ATI HDMI with snoop off */ + #define AZX_DCAPS_PRESET_ATI_HDMI_NS \ +@@ -313,7 +312,7 @@ enum { + + /* quirks for Nvidia */ + #define AZX_DCAPS_PRESET_NVIDIA \ +- (AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\ ++ (AZX_DCAPS_CORBRP_SELF_CLEAR |\ + AZX_DCAPS_SNOOP_TYPE(NVIDIA)) + + #define AZX_DCAPS_PRESET_CTHDA \ +diff --git a/tools/perf/pmu-events/arch/riscv/mapfile.csv b/tools/perf/pmu-events/arch/riscv/mapfile.csv +index c61b3d6ef616..b42b65d09c36 100644 +--- a/tools/perf/pmu-events/arch/riscv/mapfile.csv ++++ b/tools/perf/pmu-events/arch/riscv/mapfile.csv +@@ -15,3 +15,4 @@ + # + #MVENDORID-MARCHID-MIMPID,Version,Filename,EventType + 0x489-0x8000000000000007-0x:xdigit:+,v1,sifive/u74,core ++0x5b7-0x0-0x0,v1,thead/c900-legacy,core +diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json +new file mode 100644 +index 000000000000..2b142348d635 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json +@@ -0,0 +1,67 @@ ++ ++ { ++ "EventName": "L1_ICACHE_ACCESS", ++ "EventCode": "0x00000001", ++ "BriefDescription": "L1 instruction cache access" ++ }, ++ { ++ "EventName": "L1_ICACHE_MISS", ++ "EventCode": "0x00000002", ++ "BriefDescription": "L1 instruction cache miss" ++ }, ++ { ++ "EventName": "ITLB_MISS", ++ "EventCode": "0x00000003", ++ "BriefDescription": "I-UTLB miss" ++ }, ++ { ++ "EventName": "DTLB_MISS", ++ "EventCode": "0x00000004", ++ "BriefDescription": "D-UTLB miss" ++ }, ++ { ++ "EventName": "JTLB_MISS", ++ "EventCode": "0x00000005", ++ "BriefDescription": "JTLB miss" ++ }, ++ { ++ "EventName": "L1_DCACHE_READ_ACCESS", ++ "EventCode": "0x0000000c", ++ "BriefDescription": "L1 data cache read access" ++ }, ++ { ++ "EventName": "L1_DCACHE_READ_MISS", ++ "EventCode": "0x0000000d", ++ "BriefDescription": "L1 data cache read miss" ++ }, ++ { ++ "EventName": "L1_DCACHE_WRITE_ACCESS", ++ "EventCode": "0x0000000e", ++ "BriefDescription": "L1 data cache write access" ++ }, ++ { ++ "EventName": "L1_DCACHE_WRITE_MISS", ++ "EventCode": "0x0000000f", ++ "BriefDescription": "L1 data cache write miss" ++ }, ++ { ++ "EventName": "LL_CACHE_READ_ACCESS", ++ "EventCode": "0x00000010", ++ "BriefDescription": "LL Cache read access" ++ }, ++ { ++ "EventName": "LL_CACHE_READ_MISS", ++ "EventCode": "0x00000011", ++ "BriefDescription": "LL Cache read miss" ++ }, ++ { ++ "EventName": "LL_CACHE_WRITE_ACCESS", ++ "EventCode": "0x00000012", ++ "BriefDescription": "LL Cache write access" ++ }, ++ { ++ "EventName": "LL_CACHE_WRITE_MISS", ++ "EventCode": "0x00000013", ++ "BriefDescription": "LL Cache write miss" ++ } ++ +diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json +new file mode 100644 +index 000000000000..9b4a032186a7 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json +@@ -0,0 +1,68 @@ ++ ++ { ++ "ArchStdEvent": "FW_MISALIGNED_LOAD" ++ }, ++ { ++ "ArchStdEvent": "FW_MISALIGNED_STORE" ++ }, ++ { ++ "ArchStdEvent": "FW_ACCESS_LOAD" ++ }, ++ { ++ "ArchStdEvent": "FW_ACCESS_STORE" ++ }, ++ { ++ "ArchStdEvent": "FW_ILLEGAL_INSN" ++ }, ++ { ++ "ArchStdEvent": "FW_SET_TIMER" ++ }, ++ { ++ "ArchStdEvent": "FW_IPI_SENT" ++ }, ++ { ++ "ArchStdEvent": "FW_IPI_RECEIVED" ++ }, ++ { ++ "ArchStdEvent": "FW_FENCE_I_SENT" ++ }, ++ { ++ "ArchStdEvent": "FW_FENCE_I_RECEIVED" ++ }, ++ { ++ "ArchStdEvent": "FW_SFENCE_VMA_SENT" ++ }, ++ { ++ "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED" ++ }, ++ { ++ "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED" ++ }, ++ { ++ "ArchStdEvent": "FW_SFENCE_VMA_ASID_RECEIVED" ++ }, ++ { ++ "ArchStdEvent": "FW_HFENCE_GVMA_SENT" ++ }, ++ { ++ "ArchStdEvent": "FW_HFENCE_GVMA_RECEIVED" ++ }, ++ { ++ "ArchStdEvent": "FW_HFENCE_GVMA_VMID_SENT" ++ }, ++ { ++ "ArchStdEvent": "FW_HFENCE_GVMA_VMID_RECEIVED" ++ }, ++ { ++ "ArchStdEvent": "FW_HFENCE_VVMA_SENT" ++ }, ++ { ++ "ArchStdEvent": "FW_HFENCE_VVMA_RECEIVED" ++ }, ++ { ++ "ArchStdEvent": "FW_HFENCE_VVMA_ASID_SENT" ++ }, ++ { ++ "ArchStdEvent": "FW_HFENCE_VVMA_ASID_RECEIVED" ++ } ++ +diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json +new file mode 100644 +index 000000000000..c822b5373333 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json +@@ -0,0 +1,72 @@ ++ ++ { ++ "EventName": "INST_BRANCH_MISPREDICT", ++ "EventCode": "0x00000006", ++ "BriefDescription": "Mispredicted branch instructions" ++ }, ++ { ++ "EventName": "INST_BRANCH", ++ "EventCode": "0x00000007", ++ "BriefDescription": "Retired branch instructions" ++ }, ++ { ++ "EventName": "INST_JMP_MISPREDICT", ++ "EventCode": "0x00000008", ++ "BriefDescription": "Indirect branch mispredict" ++ }, ++ { ++ "EventName": "INST_JMP", ++ "EventCode": "0x00000009", ++ "BriefDescription": "Retired jmp instructions" ++ }, ++ { ++ "EventName": "INST_STORE", ++ "EventCode": "0x0000000b", ++ "BriefDescription": "Retired store instructions" ++ }, ++ { ++ "EventName": "INST_ALU", ++ "EventCode": "0x0000001d", ++ "BriefDescription": "Retired ALU instructions" ++ }, ++ { ++ "EventName": "INST_LDST", ++ "EventCode": "0x0000001e", ++ "BriefDescription": "Retired Load/Store instructions" ++ }, ++ { ++ "EventName": "INST_VECTOR", ++ "EventCode": "0x0000001f", ++ "BriefDescription": "Retired Vector instructions" ++ }, ++ { ++ "EventName": "INST_CSR", ++ "EventCode": "0x00000020", ++ "BriefDescription": "Retired CSR instructions" ++ }, ++ { ++ "EventName": "INST_SYNC", ++ "EventCode": "0x00000021", ++ "BriefDescription": "Retired sync instructions (AMO/LR/SC instructions)" ++ }, ++ { ++ "EventName": "INST_UNALIGNED_ACCESS", ++ "EventCode": "0x00000022", ++ "BriefDescription": "Retired Store/Load instructions with unaligned memory access" ++ }, ++ { ++ "EventName": "INST_ECALL", ++ "EventCode": "0x00000025", ++ "BriefDescription": "Retired ecall instructions" ++ }, ++ { ++ "EventName": "INST_LONG_JP", ++ "EventCode": "0x00000026", ++ "BriefDescription": "Retired long jump instructions" ++ }, ++ { ++ "EventName": "INST_FP", ++ "EventCode": "0x0000002a", ++ "BriefDescription": "Retired FPU instructions" ++ } ++ +diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json +new file mode 100644 +index 000000000000..0ab6f288af91 +--- /dev/null ++++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json +@@ -0,0 +1,80 @@ ++ ++ { ++ "EventName": "LSU_SPEC_FAIL", ++ "EventCode": "0x0000000a", ++ "BriefDescription": "LSU speculation fail" ++ }, ++ { ++ "EventName": "IDU_RF_PIPE_FAIL", ++ "EventCode": "0x00000014", ++ "BriefDescription": "Instruction decode unit launch pipeline failed in RF state" ++ }, ++ { ++ "EventName": "IDU_RF_REG_FAIL", ++ "EventCode": "0x00000015", ++ "BriefDescription": "Instruction decode unit launch register file fail in RF state" ++ }, ++ { ++ "EventName": "IDU_RF_INSTRUCTION", ++ "EventCode": "0x00000016", ++ "BriefDescription": "retired instruction count of Instruction decode unit in RF (Register File) stage" ++ }, ++ { ++ "EventName": "LSU_4K_STALL", ++ "EventCode": "0x00000017", ++ "BriefDescription": "LSU stall times for long distance data access (Over 4K)", ++ "PublicDescription": "This stall occurs when translate virtual address with page offset over 4k" ++ }, ++ { ++ "EventName": "LSU_OTHER_STALL", ++ "EventCode": "0x00000018", ++ "BriefDescription": "LSU stall times for other reasons (except the 4k stall)" ++ }, ++ { ++ "EventName": "LSU_SQ_OTHER_DIS", ++ "EventCode": "0x00000019", ++ "BriefDescription": "LSU store queue discard others" ++ }, ++ { ++ "EventName": "LSU_SQ_DATA_DISCARD", ++ "EventCode": "0x0000001a", ++ "BriefDescription": "LSU store queue discard data (uops)" ++ }, ++ { ++ "EventName": "BRANCH_DIRECTION_MISPREDICTION", ++ "EventCode": "0x0000001b", ++ "BriefDescription": "Branch misprediction in BTB" ++ }, ++ { ++ "EventName": "BRANCH_DIRECTION_PREDICTION", ++ "EventCode": "0x0000001c", ++ "BriefDescription": "All branch prediction in BTB", ++ "PublicDescription": "This event including both successful prediction and failed prediction in BTB" ++ }, ++ { ++ "EventName": "INTERRUPT_ACK_COUNT", ++ "EventCode": "0x00000023", ++ "BriefDescription": "acknowledged interrupt count" ++ }, ++ { ++ "EventName": "INTERRUPT_OFF_CYCLE", ++ "EventCode": "0x00000024", ++ "BriefDescription": "PLIC arbitration time when the interrupt is not responded", ++ "PublicDescription": "The arbitration time is recorded while meeting any of the following:\n- CPU is M-mode and MIE == 0\n- CPU is S-mode and delegation and SIE == 0\n" ++ }, ++ { ++ "EventName": "IFU_STALLED_CYCLE", ++ "EventCode": "0x00000027", ++ "BriefDescription": "Number of stall cycles of the instruction fetch unit (IFU)." ++ }, ++ { ++ "EventName": "IDU_STALLED_CYCLE", ++ "EventCode": "0x00000028", ++ "BriefDescription": "hpcp_backend_stall Number of stall cycles of the instruction decoding unit (IDU) and next-level pipeline unit." ++ }, ++ { ++ "EventName": "SYNC_STALL", ++ "EventCode": "0x00000029", ++ "BriefDescription": "Sync instruction stall cycle fence/fence.i/sync/sfence" ++ } ++ +-- +2.34.1 +
View file
_service:tar_scm:0005-riscv-kernel.patch
Deleted
@@ -1,31141 +0,0 @@ -From c0904638921da27a0daeebfaa55d0a32833723f0 Mon Sep 17 00:00:00 2001 -From: Mingzheng Xing <xingmingzheng@iscas.ac.cn> -Date: Thu, 21 Mar 2024 16:01:03 +0800 -Subject: PATCH riscv kernel - -Signed-off-by: Mingzheng Xing <xingmingzheng@iscas.ac.cn> ---- - .../bindings/gpio/snps,dw-apb-gpio.yaml | 2 + - .../sifive,plic-1.0.0.yaml | 1 + - .../thead,c900-aclint-mswi.yaml | 43 + - .../bindings/mmc/snps,dwcmshc-sdhci.yaml | 1 + - .../devicetree/bindings/net/snps,dwmac.yaml | 2 + - .../devicetree/bindings/net/thead,dwmac.yaml | 77 + - .../pinctrl/thead,th1520-pinctrl.yaml | 372 +++ - .../bindings/pwm/thead,th1520-pwm.yaml | 44 + - .../bindings/reset/thead,th1520-reset.yaml | 44 + - .../devicetree/bindings/riscv/cpus.yaml | 1 + - .../devicetree/bindings/riscv/sophgo.yaml | 28 + - .../timer/thead,c900-aclint-mtimer.yaml | 50 + - .../bindings/usb/thead,th1520-usb.yaml | 73 + - .../devicetree/bindings/vendor-prefixes.yaml | 4 + - MAINTAINERS | 9 + - arch/riscv/Kconfig | 2 +- - arch/riscv/Kconfig.errata | 1 + - arch/riscv/Kconfig.socs | 6 + - arch/riscv/Makefile | 2 +- - arch/riscv/boot/dts/Makefile | 1 + - arch/riscv/boot/dts/sophgo/Makefile | 5 + - .../boot/dts/sophgo/mango-clock-socket0.dtsi | 124 + - .../boot/dts/sophgo/mango-cpus-socket0.dtsi | 1148 ++++++++++ - .../boot/dts/sophgo/mango-milkv-pioneer.dts | 163 ++ - .../riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi | 83 + - .../boot/dts/sophgo/mango-pcie-3rc-v2.dtsi | 118 + - .../riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi | 115 + - .../riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi | 151 ++ - arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi | 434 ++++ - .../boot/dts/sophgo/mango-sophgo-x4evb.dts | 137 ++ - .../boot/dts/sophgo/mango-sophgo-x8evb.dts | 165 ++ - .../boot/dts/sophgo/mango-top-intc2.dtsi | 62 + - arch/riscv/boot/dts/sophgo/mango.dtsi | 941 ++++++++ - arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi | 2000 +++++++++++++++++ - .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 19 + - arch/riscv/boot/dts/sophgo/sg2042.dtsi | 341 +++ - arch/riscv/boot/dts/thead/Makefile | 3 + - .../boot/dts/thead/th1520-beaglev-ahead.dts | 199 +- - .../thead/th1520-lichee-cluster-4a-16g.dts | 18 + - .../dts/thead/th1520-lichee-cluster-4a.dts | 45 + - .../dts/thead/th1520-lichee-module-4a.dtsi | 151 +- - .../dts/thead/th1520-lichee-pi-4a-16g.dts | 18 + - .../boot/dts/thead/th1520-lichee-pi-4a.dts | 712 ++++++ - .../boot/dts/thead/th1520-milkv-meles-4g.dts | 19 + - .../boot/dts/thead/th1520-milkv-meles.dts | 441 ++++ - arch/riscv/boot/dts/thead/th1520.dtsi | 573 ++++- - arch/riscv/configs/defconfig | 6 +- - arch/riscv/configs/openeuler_defconfig | 347 ++- - arch/riscv/errata/thead/errata.c | 69 +- - arch/riscv/include/asm/errata_list.h | 50 +- - arch/riscv/include/asm/pgtable-64.h | 14 +- - drivers/clk/Kconfig | 1 + - drivers/clk/Makefile | 2 + - drivers/clk/sophgo/Makefile | 3 + - drivers/clk/sophgo/clk-dummy.c | 600 +++++ - drivers/clk/sophgo/clk-mango.c | 977 ++++++++ - drivers/clk/sophgo/clk.c | 883 ++++++++ - drivers/clk/sophgo/clk.h | 152 ++ - drivers/clk/thead/Kconfig | 19 + - drivers/clk/thead/Makefile | 8 + - drivers/clk/thead/clk-light-fm.c | 646 ++++++ - drivers/clk/thead/clk-light-mpw.c | 492 ++++ - drivers/clk/thead/clk.c | 739 ++++++ - drivers/clk/thead/clk.h | 117 + - drivers/clk/thead/gate/Makefile | 3 + - drivers/clk/thead/gate/clk-gate.h | 35 + - drivers/clk/thead/gate/dspsys-gate.c | 109 + - drivers/clk/thead/gate/thead-gate.c | 114 + - drivers/clk/thead/gate/visys-gate.c | 144 ++ - drivers/clk/thead/gate/vosys-gate.c | 111 + - drivers/clk/thead/gate/vpsys-gate.c | 94 + - drivers/cpufreq/Kconfig | 10 + - drivers/cpufreq/Makefile | 1 + - drivers/cpufreq/light-mpw-cpufreq.c | 491 ++++ - drivers/firmware/Kconfig | 1 + - drivers/firmware/Makefile | 1 + - drivers/firmware/thead/Kconfig | 18 + - drivers/firmware/thead/Makefile | 3 + - drivers/firmware/thead/light_aon.c | 261 +++ - drivers/firmware/thead/light_aon_misc.c | 74 + - drivers/firmware/thead/light_aon_pd.c | 417 ++++ - drivers/firmware/thead/light_aon_test.c | 163 ++ - drivers/gpio/gpio-dwapb.c | 15 +- - drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 + - drivers/gpu/drm/drm_gem_vram_helper.c | 2 +- - drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 + - drivers/gpu/drm/ttm/ttm_bo_util.c | 6 +- - drivers/gpu/drm/ttm/ttm_module.c | 3 +- - drivers/gpu/drm/ttm/ttm_resource.c | 7 +- - drivers/gpu/drm/ttm/ttm_tt.c | 2 +- - drivers/mailbox/Kconfig | 8 + - drivers/mailbox/Makefile | 3 + - drivers/mailbox/light-mailbox-client.c | 242 ++ - drivers/mailbox/light-mailbox.c | 507 +++++ - drivers/mmc/host/Kconfig | 14 + - drivers/mmc/host/Makefile | 1 + - drivers/mmc/host/sdhci-of-dwcmshc.c | 349 +++ - drivers/mmc/host/sdhci-sophgo.c | 619 +++++ - drivers/mmc/host/sdhci-sophgo.h | 121 + - drivers/mmc/host/sdhci.c | 12 +- - drivers/mmc/host/sdhci.h | 4 + - drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 + - drivers/net/ethernet/stmicro/stmmac/Makefile | 2 + - .../ethernet/stmicro/stmmac/dwmac-sophgo.c | 268 +++ - .../net/ethernet/stmicro/stmmac/dwmac-thead.c | 289 +++ - drivers/pci/controller/cadence/Kconfig | 11 + - drivers/pci/controller/cadence/Makefile | 1 + - .../controller/cadence/pcie-cadence-sophgo.c | 963 ++++++++ - .../controller/cadence/pcie-cadence-sophgo.h | 17 + - drivers/pci/pcie/portdrv.c | 2 +- - drivers/pinctrl/Kconfig | 11 +- - drivers/pinctrl/Makefile | 2 + - drivers/pinctrl/pinctrl-th1520.c | 860 +++++++ - drivers/pinctrl/sophgo/Makefile | 2 + - drivers/pinctrl/sophgo/pinctrl-mango.c | 453 ++++ - drivers/pinctrl/sophgo/pinctrl-sophgo.c | 292 +++ - drivers/pinctrl/sophgo/pinctrl-sophgo.h | 70 + - drivers/pwm/Kconfig | 11 + - drivers/pwm/Makefile | 2 + - drivers/pwm/pwm-sophgo.c | 276 +++ - drivers/pwm/pwm-thead.c | 269 +++ - drivers/regulator/Kconfig | 9 + - drivers/regulator/Makefile | 1 + - drivers/regulator/light-regulator-aon.c | 888 ++++++++ - drivers/reset/Kconfig | 10 + - drivers/reset/Makefile | 2 + - drivers/reset/reset-sophgo.c | 163 ++ - drivers/reset/reset-th1520.c | 109 + - drivers/rpmsg/Kconfig | 4 + - drivers/rpmsg/Makefile | 1 + - drivers/rpmsg/light_rpmsg.c | 864 +++++++ - drivers/soc/Kconfig | 1 + - drivers/soc/Makefile | 2 + - drivers/soc/sophgo/Makefile | 3 + - drivers/soc/sophgo/tach/sophgo-tach.c | 330 +++ - drivers/soc/sophgo/top/top_intc.c | 412 ++++ - drivers/soc/sophgo/umcu/mcu.c | 1144 ++++++++++ - drivers/soc/thead/Kconfig | 10 + - drivers/soc/thead/Makefile | 2 + - drivers/soc/thead/light_event.c | 279 +++ - drivers/usb/dwc3/Kconfig | 20 + - drivers/usb/dwc3/Makefile | 2 + - drivers/usb/dwc3/dwc3-thead.c | 112 + - drivers/watchdog/Kconfig | 14 + - drivers/watchdog/Makefile | 1 + - drivers/watchdog/light_wdt.c | 376 ++++ - include/dt-bindings/clock/light-dspsys.h | 25 + - include/dt-bindings/clock/light-fm-ap-clock.h | 513 +++++ - include/dt-bindings/clock/light-mpw-clock.h | 222 ++ - include/dt-bindings/clock/light-visys.h | 54 + - include/dt-bindings/clock/light-vosys.h | 41 + - include/dt-bindings/clock/light-vpsys.h | 24 + - .../dt-bindings/clock/sophgo-mango-clock.h | 165 ++ - include/dt-bindings/clock/sophgo.h | 15 + - include/dt-bindings/firmware/thead/rsrc.h | 17 + - .../dt-bindings/reset/sophgo-mango-resets.h | 96 + - .../dt-bindings/reset/thead,th1520-reset.h | 9 + - include/linux/firmware/thead/ipc.h | 74 + - include/linux/firmware/thead/light_event.h | 35 + - include/linux/light_rpmsg.h | 92 + - kernel/panic.c | 6 + - mm/memblock.c | 6 +- - scripts/package/builddeb | 2 +- - sound/pci/hda/hda_intel.c | 5 +- - tools/perf/pmu-events/arch/riscv/mapfile.csv | 1 + - .../arch/riscv/thead/c900-legacy/cache.json | 67 + - .../riscv/thead/c900-legacy/firmware.json | 68 + - .../riscv/thead/c900-legacy/instruction.json | 72 + - .../riscv/thead/c900-legacy/microarch.json | 80 + - 169 files changed, 28116 insertions(+), 186 deletions(-) - create mode 100644 Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml - create mode 100644 Documentation/devicetree/bindings/net/thead,dwmac.yaml - create mode 100644 Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml - create mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml - create mode 100644 Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml - create mode 100644 Documentation/devicetree/bindings/riscv/sophgo.yaml - create mode 100644 Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml - create mode 100644 Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml - create mode 100644 arch/riscv/boot/dts/sophgo/Makefile - create mode 100644 arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts - create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts - create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts - create mode 100644 arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/mango.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi - create mode 100644 arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts - create mode 100644 arch/riscv/boot/dts/sophgo/sg2042.dtsi - create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts - create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts - create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts - create mode 100644 arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts - create mode 100644 arch/riscv/boot/dts/thead/th1520-milkv-meles.dts - create mode 100644 drivers/clk/sophgo/Makefile - create mode 100644 drivers/clk/sophgo/clk-dummy.c - create mode 100644 drivers/clk/sophgo/clk-mango.c - create mode 100644 drivers/clk/sophgo/clk.c - create mode 100644 drivers/clk/sophgo/clk.h - create mode 100644 drivers/clk/thead/Kconfig - create mode 100644 drivers/clk/thead/Makefile - create mode 100644 drivers/clk/thead/clk-light-fm.c - create mode 100644 drivers/clk/thead/clk-light-mpw.c - create mode 100644 drivers/clk/thead/clk.c - create mode 100644 drivers/clk/thead/clk.h - create mode 100644 drivers/clk/thead/gate/Makefile - create mode 100644 drivers/clk/thead/gate/clk-gate.h - create mode 100644 drivers/clk/thead/gate/dspsys-gate.c - create mode 100644 drivers/clk/thead/gate/thead-gate.c - create mode 100644 drivers/clk/thead/gate/visys-gate.c - create mode 100644 drivers/clk/thead/gate/vosys-gate.c - create mode 100644 drivers/clk/thead/gate/vpsys-gate.c - create mode 100644 drivers/cpufreq/light-mpw-cpufreq.c - create mode 100644 drivers/firmware/thead/Kconfig - create mode 100644 drivers/firmware/thead/Makefile - create mode 100644 drivers/firmware/thead/light_aon.c - create mode 100644 drivers/firmware/thead/light_aon_misc.c - create mode 100644 drivers/firmware/thead/light_aon_pd.c - create mode 100644 drivers/firmware/thead/light_aon_test.c - create mode 100644 drivers/mailbox/light-mailbox-client.c - create mode 100644 drivers/mailbox/light-mailbox.c - create mode 100644 drivers/mmc/host/sdhci-sophgo.c - create mode 100644 drivers/mmc/host/sdhci-sophgo.h - create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c - create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c - create mode 100644 drivers/pci/controller/cadence/pcie-cadence-sophgo.c - create mode 100644 drivers/pci/controller/cadence/pcie-cadence-sophgo.h - create mode 100644 drivers/pinctrl/pinctrl-th1520.c - create mode 100644 drivers/pinctrl/sophgo/Makefile - create mode 100644 drivers/pinctrl/sophgo/pinctrl-mango.c - create mode 100644 drivers/pinctrl/sophgo/pinctrl-sophgo.c - create mode 100644 drivers/pinctrl/sophgo/pinctrl-sophgo.h - create mode 100644 drivers/pwm/pwm-sophgo.c - create mode 100644 drivers/pwm/pwm-thead.c - create mode 100644 drivers/regulator/light-regulator-aon.c - create mode 100644 drivers/reset/reset-sophgo.c - create mode 100644 drivers/reset/reset-th1520.c - create mode 100644 drivers/rpmsg/light_rpmsg.c - create mode 100644 drivers/soc/sophgo/Makefile - create mode 100644 drivers/soc/sophgo/tach/sophgo-tach.c - create mode 100644 drivers/soc/sophgo/top/top_intc.c - create mode 100644 drivers/soc/sophgo/umcu/mcu.c - create mode 100644 drivers/soc/thead/Kconfig - create mode 100644 drivers/soc/thead/Makefile - create mode 100644 drivers/soc/thead/light_event.c - create mode 100644 drivers/usb/dwc3/dwc3-thead.c - create mode 100644 drivers/watchdog/light_wdt.c - create mode 100644 include/dt-bindings/clock/light-dspsys.h - create mode 100644 include/dt-bindings/clock/light-fm-ap-clock.h - create mode 100644 include/dt-bindings/clock/light-mpw-clock.h - create mode 100644 include/dt-bindings/clock/light-visys.h - create mode 100644 include/dt-bindings/clock/light-vosys.h - create mode 100644 include/dt-bindings/clock/light-vpsys.h - create mode 100644 include/dt-bindings/clock/sophgo-mango-clock.h - create mode 100644 include/dt-bindings/clock/sophgo.h - create mode 100644 include/dt-bindings/firmware/thead/rsrc.h - create mode 100644 include/dt-bindings/reset/sophgo-mango-resets.h - create mode 100644 include/dt-bindings/reset/thead,th1520-reset.h - create mode 100644 include/linux/firmware/thead/ipc.h - create mode 100644 include/linux/firmware/thead/light_event.h - create mode 100644 include/linux/light_rpmsg.h - create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json - create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json - create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json - create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json - -diff --git a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml -index eefe7b345286..ab2afc0e4153 100644 ---- a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml -+++ b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml -@@ -65,6 +65,8 @@ patternProperties: - minItems: 1 - maxItems: 32 - -+ gpio-ranges: true -+ - ngpios: - default: 32 - minimum: 1 -diff --git a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml -index dc1f28e55266..16f9c4760c0f 100644 ---- a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml -+++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml -@@ -65,6 +65,7 @@ properties: - - items: - - enum: - - allwinner,sun20i-d1-plic -+ - sophgo,sg2042-plic - - thead,th1520-plic - - const: thead,c900-plic - - items: -diff --git a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml -new file mode 100644 -index 000000000000..065f2544b63b ---- /dev/null -+++ b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml -@@ -0,0 +1,43 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-mswi.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Sophgo sg2042 CLINT Machine-level Software Interrupt Device -+ -+maintainers: -+ - Inochi Amaoto <inochiama@outlook.com> -+ -+properties: -+ compatible: -+ items: -+ - enum: -+ - sophgo,sg2042-aclint-mswi -+ - const: thead,c900-aclint-mswi -+ -+ reg: -+ maxItems: 1 -+ -+ interrupts-extended: -+ minItems: 1 -+ maxItems: 4095 -+ -+additionalProperties: false -+ -+required: -+ - compatible -+ - reg -+ - interrupts-extended -+ -+examples: -+ - | -+ interrupt-controller@94000000 { -+ compatible = "sophgo,sg2042-aclint-mswi", "thead,c900-aclint-mswi"; -+ interrupts-extended = <&cpu1intc 3>, -+ <&cpu2intc 3>, -+ <&cpu3intc 3>, -+ <&cpu4intc 3>; -+ reg = <0x94000000 0x00010000>; -+ }; -+... -diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml -index a43eb837f8da..42804d955293 100644 ---- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml -+++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml -@@ -19,6 +19,7 @@ properties: - - rockchip,rk3568-dwcmshc - - rockchip,rk3588-dwcmshc - - snps,dwcmshc-sdhci -+ - thead,th1520-dwcmshc - - reg: - maxItems: 1 -diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml -index ddf9522a5dc2..73821f86a609 100644 ---- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml -+++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml -@@ -96,6 +96,7 @@ properties: - - snps,dwxgmac - - snps,dwxgmac-2.10 - - starfive,jh7110-dwmac -+ - thead,th1520-dwmac - - reg: - minItems: 1 -@@ -586,6 +587,7 @@ allOf: - - qcom,sa8775p-ethqos - - qcom,sc8280xp-ethqos - - snps,dwmac-3.50a -+ - snps,dwmac-3.70a - - snps,dwmac-4.10a - - snps,dwmac-4.20a - - snps,dwmac-5.20 -diff --git a/Documentation/devicetree/bindings/net/thead,dwmac.yaml b/Documentation/devicetree/bindings/net/thead,dwmac.yaml -new file mode 100644 -index 000000000000..bf8ec8ca2753 ---- /dev/null -+++ b/Documentation/devicetree/bindings/net/thead,dwmac.yaml -@@ -0,0 +1,77 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/net/thead,dwmac.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: T-HEAD DWMAC Ethernet controller -+ -+maintainers: -+ - Jisheng Zhang <jszhang@kernel.org> -+ -+select: -+ properties: -+ compatible: -+ contains: -+ enum: -+ - thead,th1520-dwmac -+ required: -+ - compatible -+ -+properties: -+ compatible: -+ items: -+ - enum: -+ - thead,th1520-dwmac -+ - const: snps,dwmac-3.70a -+ -+ reg: -+ maxItems: 1 -+ -+ thead,gmacapb: -+ $ref: /schemas/types.yaml#/definitions/phandle -+ description: -+ The phandle to the syscon node that control ethernet -+ interface and timing delay. -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ - clock-names -+ - interrupts -+ - interrupt-names -+ - phy-mode -+ - thead,gmacapb -+ -+allOf: -+ - $ref: snps,dwmac.yaml# -+ -+unevaluatedProperties: false -+ -+examples: -+ - | -+ gmac0: ethernet@e7070000 { -+ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; -+ reg = <0xe7070000 0x2000>; -+ clocks = <&clk 1>, <&clk 2>; -+ clock-names = "stmmaceth", "pclk"; -+ interrupts = <66>; -+ interrupt-names = "macirq"; -+ phy-mode = "rgmii-id"; -+ snps,fixed-burst; -+ snps,axi-config = <&stmmac_axi_setup>; -+ snps,pbl = <32>; -+ thead,gmacapb = <&gmacapb_syscon>; -+ phy-handle = <&phy0>; -+ -+ mdio { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "snps,dwmac-mdio"; -+ -+ phy0: ethernet-phy@0 { -+ reg = <0>; -+ }; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml -new file mode 100644 -index 000000000000..b80d0f7b4697 ---- /dev/null -+++ b/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml -@@ -0,0 +1,372 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/pinctrl/thead,th1520-pinctrl.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: T-Head TH1520 SoC pin controller -+ -+maintainers: -+ - Emil Renner Berthing <emil.renner.berthing@canonical.com> -+ -+description: | -+ Pinmux and pinconf controller in the T-Head TH1520 RISC-V SoC. -+ -+ The TH1520 has 3 groups of pads each controlled from different memory ranges. -+ Confusingly the memory ranges are named -+ PADCTRL_AOSYS -> PAD Group 1 -+ PADCTRL1_APSYS -> PAD Group 2 -+ PADCTRL0_APSYS -> PAD Group 3 -+ -+ Each pad can be muxed individually to up to 6 different functions. For most -+ pads only a few of those 6 configurations are valid though, and a few pads in -+ group 1 does not support muxing at all. -+ -+ Pinconf is fairly regular except for a few pads in group 1 that either can't -+ be configured or has some special functions. The rest have configurable drive -+ strength, input enable, schmitt trigger, slew rate, pull-up and pull-down in -+ addition to a special strong pull up. -+ -+ Certain pads in group 1 can be muxed to AUDIO_PA0 - AUDIO_PA30 functions and -+ are then meant to be used by the audio co-processor. Each such pad can then -+ be further muxed to either audio GPIO or one of 4 functions such as UART, I2C -+ and I2S. If the audio pad is muxed to one of the 4 functions then pinconf is -+ also configured in different registers. All of this is done from a different -+ AUDIO_IOCTRL memory range and is left to the audio co-processor for now. -+ -+properties: -+ compatible: -+ enum: -+ - thead,th1520-group1-pinctrl -+ - thead,th1520-group2-pinctrl -+ - thead,th1520-group3-pinctrl -+ -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ maxItems: 1 -+ -+patternProperties: -+ '-0-9+$': -+ type: object -+ -+ additionalProperties: false -+ -+ patternProperties: -+ '-pins$': -+ type: object -+ $ref: /schemas/pinctrl/pincfg-node.yaml -+ -+ additionalProperties: false -+ -+ description: -+ A pinctrl node should contain at least one subnode describing one -+ or more pads and their associated pinmux and pinconf settings. -+ -+ properties: -+ pins: -+ $ref: /schemas/pinctrl/pinmux-node.yaml#/properties/pins -+ description: List of pads that properties in the node apply to. -+ -+ function: -+ $ref: /schemas/pinctrl/pinmux-node.yaml#/properties/function -+ enum: gpio, pwm, uart, ir, i2c, spi, qspi, sdio, audio, i2s, -+ gmac0, gmac1, dpu0, dpu1, isp, hdmi, bootsel, debug, -+ clock, jtag, iso7816, efuse, reset -+ description: The mux function to select for the given pins. -+ -+ bias-disable: true -+ -+ bias-pull-up: -+ oneOf: -+ - type: boolean -+ description: Enable the regular 48kOhm pull-up -+ - enum: 2100, 48000 -+ description: Enable the strong 2.1kOhm pull-up or regular 48kOhm pull-up -+ -+ bias-pull-down: -+ oneOf: -+ - type: boolean -+ - const: 44000 -+ description: Enable the regular 44kOhm pull-down -+ -+ drive-strength: -+ description: Drive strength in mA -+ enum: 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25 -+ -+ input-enable: true -+ -+ input-disable: true -+ -+ input-schmitt-enable: true -+ -+ input-schmitt-disable: true -+ -+ slew-rate: -+ maximum: 1 -+ -+ required: -+ - pins -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ -+additionalProperties: false -+ -+allOf: -+ - $ref: pinctrl.yaml# -+ - if: -+ properties: -+ compatible: -+ const: thead,th1520-group1-pinctrl -+ then: -+ patternProperties: -+ '-0-9+$': -+ patternProperties: -+ '-pins$': -+ properties: -+ pins: -+ items: -+ enum: -+ - OSC_CLK_IN -+ - OSC_CLK_OUT -+ - SYS_RST_N -+ - RTC_CLK_IN -+ - RTC_CLK_OUT -+ - TEST_MODE -+ - DEBUG_MODE -+ - POR_SEL -+ - I2C_AON_SCL -+ - I2C_AON_SDA -+ - CPU_JTG_TCLK -+ - CPU_JTG_TMS -+ - CPU_JTG_TDI -+ - CPU_JTG_TDO -+ - CPU_JTG_TRST -+ - AOGPIO_7 -+ - AOGPIO_8 -+ - AOGPIO_9 -+ - AOGPIO_10 -+ - AOGPIO_11 -+ - AOGPIO_12 -+ - AOGPIO_13 -+ - AOGPIO_14 -+ - AOGPIO_15 -+ - AUDIO_PA0 -+ - AUDIO_PA1 -+ - AUDIO_PA2 -+ - AUDIO_PA3 -+ - AUDIO_PA4 -+ - AUDIO_PA5 -+ - AUDIO_PA6 -+ - AUDIO_PA7 -+ - AUDIO_PA8 -+ - AUDIO_PA9 -+ - AUDIO_PA10 -+ - AUDIO_PA11 -+ - AUDIO_PA12 -+ - AUDIO_PA13 -+ - AUDIO_PA14 -+ - AUDIO_PA15 -+ - AUDIO_PA16 -+ - AUDIO_PA17 -+ - AUDIO_PA27 -+ - AUDIO_PA28 -+ - AUDIO_PA29 -+ - AUDIO_PA30 -+ - if: -+ properties: -+ compatible: -+ const: thead,th1520-group2-pinctrl -+ then: -+ patternProperties: -+ '-0-9+$': -+ patternProperties: -+ '-pins$': -+ properties: -+ pins: -+ items: -+ enum: -+ - QSPI1_SCLK -+ - QSPI1_CSN0 -+ - QSPI1_D0_MOSI -+ - QSPI1_D1_MISO -+ - QSPI1_D2_WP -+ - QSPI1_D3_HOLD -+ - I2C0_SCL -+ - I2C0_SDA -+ - I2C1_SCL -+ - I2C1_SDA -+ - UART1_TXD -+ - UART1_RXD -+ - UART4_TXD -+ - UART4_RXD -+ - UART4_CTSN -+ - UART4_RTSN -+ - UART3_TXD -+ - UART3_RXD -+ - GPIO0_18 -+ - GPIO0_19 -+ - GPIO0_20 -+ - GPIO0_21 -+ - GPIO0_22 -+ - GPIO0_23 -+ - GPIO0_24 -+ - GPIO0_25 -+ - GPIO0_26 -+ - GPIO0_27 -+ - GPIO0_28 -+ - GPIO0_29 -+ - GPIO0_30 -+ - GPIO0_31 -+ - GPIO1_0 -+ - GPIO1_1 -+ - GPIO1_2 -+ - GPIO1_3 -+ - GPIO1_4 -+ - GPIO1_5 -+ - GPIO1_6 -+ - GPIO1_7 -+ - GPIO1_8 -+ - GPIO1_9 -+ - GPIO1_10 -+ - GPIO1_11 -+ - GPIO1_12 -+ - GPIO1_13 -+ - GPIO1_14 -+ - GPIO1_15 -+ - GPIO1_16 -+ - CLK_OUT_0 -+ - CLK_OUT_1 -+ - CLK_OUT_2 -+ - CLK_OUT_3 -+ - GPIO1_21 -+ - GPIO1_22 -+ - GPIO1_23 -+ - GPIO1_24 -+ - GPIO1_25 -+ - GPIO1_26 -+ - GPIO1_27 -+ - GPIO1_28 -+ - GPIO1_29 -+ - GPIO1_30 -+ - if: -+ properties: -+ compatible: -+ const: thead,th1520-group3-pinctrl -+ then: -+ patternProperties: -+ '-0-9+$': -+ patternProperties: -+ '-pins$': -+ properties: -+ pins: -+ items: -+ enum: -+ - UART0_TXD -+ - UART0_RXD -+ - QSPI0_SCLK -+ - QSPI0_CSN0 -+ - QSPI0_CSN1 -+ - QSPI0_D0_MOSI -+ - QSPI0_D1_MISO -+ - QSPI0_D2_WP -+ - QSPI1_D3_HOLD -+ - I2C2_SCL -+ - I2C2_SDA -+ - I2C3_SCL -+ - I2C3_SDA -+ - GPIO2_13 -+ - SPI_SCLK -+ - SPI_CSN -+ - SPI_MOSI -+ - SPI_MISO -+ - GPIO2_18 -+ - GPIO2_19 -+ - GPIO2_20 -+ - GPIO2_21 -+ - GPIO2_22 -+ - GPIO2_23 -+ - GPIO2_24 -+ - GPIO2_25 -+ - SDIO0_WPRTN -+ - SDIO0_DETN -+ - SDIO1_WPRTN -+ - SDIO1_DETN -+ - GPIO2_30 -+ - GPIO2_31 -+ - GPIO3_0 -+ - GPIO3_1 -+ - GPIO3_2 -+ - GPIO3_3 -+ - HDMI_SCL -+ - HDMI_SDA -+ - HDMI_CEC -+ - GMAC0_TX_CLK -+ - GMAC0_RX_CLK -+ - GMAC0_TXEN -+ - GMAC0_TXD0 -+ - GMAC0_TXD1 -+ - GMAC0_TXD2 -+ - GMAC0_TXD3 -+ - GMAC0_RXDV -+ - GMAC0_RXD0 -+ - GMAC0_RXD1 -+ - GMAC0_RXD2 -+ - GMAC0_RXD3 -+ - GMAC0_MDC -+ - GMAC0_MDIO -+ - GMAC0_COL -+ - GMAC0_CRS -+ -+examples: -+ - | -+ padctrl0_apsys: pinctrl@ec007000 { -+ compatible = "thead,th1520-group3-pinctrl"; -+ reg = <0xec007000 0x1000>; -+ clocks = <&apb_clk>; -+ -+ uart0_pins: uart0-0 { -+ tx-pins { -+ pins = "UART0_TXD"; -+ function = "uart"; -+ bias-disable; -+ drive-strength = <3>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ rx-pins { -+ pins = "UART0_RXD"; -+ function = "uart"; -+ bias-disable; -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ }; -+ -+ padctrl1_apsys: pinctrl@e7f3c000 { -+ compatible = "thead,th1520-group2-pinctrl"; -+ reg = <0xe7f3c000 0x1000>; -+ clocks = <&apb_clk>; -+ -+ i2c5_pins: i2c5-0 { -+ i2c-pins { -+ pins = "QSPI1_CSN0", /* I2C5_SCL */ -+ "QSPI1_D0_MOSI"; /* I2C5_SDA */ -+ function = "i2c"; -+ bias-pull-up = <2100>; -+ drive-strength = <7>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml -new file mode 100644 -index 000000000000..e75d8e9f24c5 ---- /dev/null -+++ b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml -@@ -0,0 +1,44 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/pwm/thead,th1520-pwm.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: T-HEAD TH1520 PWM -+ -+maintainers: -+ - Jisheng Zhang <jszhang@kernel.org> -+ -+allOf: -+ - $ref: pwm.yaml# -+ -+properties: -+ compatible: -+ enum: -+ - thead,th1520-pwm -+ -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ maxItems: 1 -+ -+ "#pwm-cells": -+ const: 3 -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ -+additionalProperties: false -+ -+examples: -+ - | -+ -+ pwm@ec01c000 { -+ compatible = "thead,th1520-pwm"; -+ reg = <0xec01c000 0x1000>; -+ clocks = <&clk 1>; -+ #pwm-cells = <3>; -+ }; -diff --git a/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml -new file mode 100644 -index 000000000000..49ea8c6a331f ---- /dev/null -+++ b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml -@@ -0,0 +1,44 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/reset/thead,th1520-reset.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: T-HEAD th1520 SoC Reset Controller -+ -+maintainers: -+ - Kwanghoon Son <k.son@samsung.com> -+ -+properties: -+ compatible: -+ items: -+ - const: thead,th1520-reset -+ - const: syscon -+ -+ reg: -+ maxItems: 1 -+ -+ '#reset-cells': -+ const: 1 -+ -+required: -+ - compatible -+ - reg -+ - '#reset-cells' -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include <dt-bindings/reset/thead,th1520-reset.h> -+ -+ soc { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ -+ reset-controller@ffef014000 { -+ compatible = "thead,th1520-reset", "syscon"; -+ reg = <0xff 0xef014000 0x0 0x1000>; -+ #reset-cells = <1>; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml -index 97e8441eda1c..f392e367d673 100644 ---- a/Documentation/devicetree/bindings/riscv/cpus.yaml -+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml -@@ -47,6 +47,7 @@ properties: - - sifive,u74-mc - - thead,c906 - - thead,c910 -+ - thead,c920 - - const: riscv - - items: - - enum: -diff --git a/Documentation/devicetree/bindings/riscv/sophgo.yaml b/Documentation/devicetree/bindings/riscv/sophgo.yaml -new file mode 100644 -index 000000000000..8adb5f39ca53 ---- /dev/null -+++ b/Documentation/devicetree/bindings/riscv/sophgo.yaml -@@ -0,0 +1,28 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/riscv/sophgo.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Sophgo SoC-based boards -+ -+maintainers: -+ - Chao Wei <chao.wei@sophgo.com> -+ - Chen Wang <unicorn_wang@outlook.com> -+ -+description: -+ Sophgo SoC-based boards -+ -+properties: -+ $nodename: -+ const: '/' -+ compatible: -+ oneOf: -+ - items: -+ - enum: -+ - milkv,pioneer -+ - const: sophgo,sg2042 -+ -+additionalProperties: true -+ -+... -diff --git a/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml -new file mode 100644 -index 000000000000..2e92bcdeb423 ---- /dev/null -+++ b/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml -@@ -0,0 +1,50 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/timer/thead,c900-aclint-mtimer.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Sophgo CLINT Timer -+ -+maintainers: -+ - Inochi Amaoto <inochiama@outlook.com> -+ -+properties: -+ compatible: -+ items: -+ - enum: -+ - sophgo,sg2042-aclint-mtimer -+ - const: thead,c900-aclint-mtimer -+ -+ reg: -+ items: -+ - description: MTIMECMP Registers -+ -+ reg-names: -+ items: -+ - const: mtimecmp -+ -+ interrupts-extended: -+ minItems: 1 -+ maxItems: 4095 -+ -+additionalProperties: false -+ -+required: -+ - compatible -+ - reg -+ - reg-names -+ - interrupts-extended -+ -+examples: -+ - | -+ timer@ac000000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ interrupts-extended = <&cpu1intc 7>, -+ <&cpu2intc 7>, -+ <&cpu3intc 7>, -+ <&cpu4intc 7>; -+ reg = <0xac000000 0x00010000>; -+ reg-names = "mtimecmp"; -+ }; -+... -diff --git a/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml b/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml -new file mode 100644 -index 000000000000..afb618eb5013 ---- /dev/null -+++ b/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml -@@ -0,0 +1,73 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/usb/thead,th1520-usb.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: T-HEAD TH1520 DWC3 USB Controller Glue -+ -+maintainers: -+ - Jisheng Zhang <jszhang@kernel.org> -+ -+properties: -+ compatible: -+ const: thead,th1520-usb -+ -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ maxItems: 4 -+ -+ clock-names: -+ items: -+ - const: ref -+ - const: bus_early -+ - const: phy -+ - const: suspend -+ -+ ranges: true -+ -+ '#address-cells': -+ enum: 1, 2 -+ -+ '#size-cells': -+ enum: 1, 2 -+ -+# Required child node: -+ -+patternProperties: -+ "^usb@0-9a-f+$": -+ $ref: snps,dwc3.yaml# -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ - clock-names -+ - ranges -+ -+additionalProperties: false -+ -+examples: -+ - | -+ -+ usb { -+ compatible = "thead,th1520-usb"; -+ reg = <0xec03f000 0x1000>; -+ clocks = <&clk 1>, -+ <&clk 2>, -+ <&clk 3>, -+ <&clk 4>; -+ clock-names = "ref", "bus_early", "phy", "suspend"; -+ ranges; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ usb@e7040000 { -+ compatible = "snps,dwc3"; -+ reg = <0xe7040000 0x10000>; -+ interrupts = <68>; -+ dr_mode = "host"; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml -index 133cfb2bb05c..2a8938bfe447 100644 ---- a/Documentation/devicetree/bindings/vendor-prefixes.yaml -+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml -@@ -863,6 +863,8 @@ patternProperties: - description: MikroElektronika d.o.o. - "^mikrotik,.*": - description: MikroTik -+ "^milkv,.*": -+ description: MilkV Technology Co., Ltd - "^miniand,.*": - description: Miniand Tech - "^minix,.*": -@@ -1275,6 +1277,8 @@ patternProperties: - description: Solomon Systech Limited - "^sony,.*": - description: Sony Corporation -+ "^sophgo,.*": -+ description: Sophgo Technology Inc. - "^sourceparts,.*": - description: Source Parts Inc. - "^spansion,.*": -diff --git a/MAINTAINERS b/MAINTAINERS -index 33056b3b5b2c..832f3795de90 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -18499,6 +18499,8 @@ M: Fu Wei <wefu@redhat.com> - L: linux-riscv@lists.infradead.org - S: Maintained - F: arch/riscv/boot/dts/thead/ -+F: drivers/pinctrl/pinctrl-th1520.c -+F: drivers/usb/dwc3/dwc3-thead.c - - RNBD BLOCK DRIVERS - M: Md. Haris Iqbal <haris.iqbal@ionos.com> -@@ -20078,6 +20080,13 @@ F: drivers/char/sonypi.c - F: drivers/platform/x86/sony-laptop.c - F: include/linux/sony-laptop.h - -+SOPHGO DEVICETREES -+M: Chao Wei <chao.wei@sophgo.com> -+M: Chen Wang <unicorn_wang@outlook.com> -+S: Maintained -+F: arch/riscv/boot/dts/sophgo/ -+F: Documentation/devicetree/bindings/riscv/sophgo.yaml -+ - SOUND - M: Jaroslav Kysela <perex@perex.cz> - M: Takashi Iwai <tiwai@suse.com> -diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig -index 32aadf652681..16e6c9617f28 100644 ---- a/arch/riscv/Kconfig -+++ b/arch/riscv/Kconfig -@@ -501,7 +501,7 @@ config RISCV_ISA_V - depends on TOOLCHAIN_HAS_V - depends on FPU - select DYNAMIC_SIGFRAME -- default y -+ default n - help - Say N here if you want to disable all vector related procedure - in the kernel. -diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata -index e2c731cfed8c..dedb8b238e73 100644 ---- a/arch/riscv/Kconfig.errata -+++ b/arch/riscv/Kconfig.errata -@@ -79,6 +79,7 @@ config ERRATA_THEAD_CMO - depends on ERRATA_THEAD && MMU - select DMA_DIRECT_REMAP - select RISCV_DMA_NONCOHERENT -+ select RISCV_NONSTANDARD_CACHE_OPS - default y - help - This will apply the cache management errata to handle the -diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs -index 30fd6a512828..88ce9f0182be 100644 ---- a/arch/riscv/Kconfig.socs -+++ b/arch/riscv/Kconfig.socs -@@ -22,6 +22,12 @@ config SOC_SIFIVE - help - This enables support for SiFive SoC platform hardware. - -+config ARCH_SOPHGO -+ bool "Sophgo SoCs" -+ select DW_APB_TIMER_OF -+ help -+ This enables support for Sophgo SoC platform hardware. -+ - config ARCH_STARFIVE - def_bool SOC_STARFIVE - -diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile -index b43a6bb7e4dc..ecf81ab9bd9e 100644 ---- a/arch/riscv/Makefile -+++ b/arch/riscv/Makefile -@@ -152,7 +152,7 @@ ifeq ($(CONFIG_RISCV_M_MODE)$(CONFIG_ARCH_CANAAN),yy) - KBUILD_IMAGE := $(boot)/loader.bin - else - ifeq ($(CONFIG_EFI_ZBOOT),) --KBUILD_IMAGE := $(boot)/Image.gz -+KBUILD_IMAGE := $(boot)/Image - else - KBUILD_IMAGE := $(boot)/vmlinuz.efi - endif -diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile -index f60a280abb15..72030fd727af 100644 ---- a/arch/riscv/boot/dts/Makefile -+++ b/arch/riscv/boot/dts/Makefile -@@ -4,6 +4,7 @@ subdir-y += canaan - subdir-y += microchip - subdir-y += renesas - subdir-y += sifive -+subdir-y += sophgo - subdir-y += starfive - subdir-y += thead - -diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile -new file mode 100644 -index 000000000000..37f481ea87bb ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/Makefile -@@ -0,0 +1,5 @@ -+# SPDX-License-Identifier: GPL-2.0 -+dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb -+dtb-$(CONFIG_ARCH_SOPHGO) += mango-milkv-pioneer.dtb -+dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-x4evb.dtb -+dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-x8evb.dtb -diff --git a/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi b/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi -new file mode 100644 -index 000000000000..af3380412f1d ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi -@@ -0,0 +1,124 @@ -+/ { -+ socket0-clocks { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ cgi: ctrystal { -+ compatible = "fixed-clock"; -+ clock-frequency = <25000000>; -+ clock-output-names = "cgi"; -+ #clock-cells = <0>; -+ }; -+ -+ /* pll clock */ -+ mpll: mpll { -+ compatible = "mango, pll-clock"; -+ #clock-cells = <0>; -+ id = <MPLL_CLK>; -+ mode = <NORMAL_MODE>; -+ subctrl-syscon = <&top_misc>; -+ clocks = <&cgi>; -+ clock-output-names = "mpll_clock"; -+ }; -+ -+ fpll: fpll { -+ compatible = "mango, pll-clock"; -+ #clock-cells = <0>; -+ id = <FPLL_CLK>; -+ mode = <NORMAL_MODE>; -+ subctrl-syscon = <&top_misc>; -+ clocks = <&cgi>; -+ clock-output-names = "fpll_clock"; -+ }; -+ -+ dpll0: dpll0 { -+ compatible = "mango, pll-clock"; -+ #clock-cells = <0>; -+ id = <DPLL0_CLK>; -+ mode = <NORMAL_MODE>; -+ subctrl-syscon = <&top_misc>; -+ clocks = <&cgi>; -+ clock-output-names = "dpll0_clock"; -+ }; -+ -+ dpll1: dpll1 { -+ compatible = "mango, pll-clock"; -+ #clock-cells = <0>; -+ mode = <NORMAL_MODE>; -+ subctrl-syscon = <&top_misc>; -+ clocks = <&cgi>; -+ id = <DPLL1_CLK>; -+ clock-output-names = "dpll1_clock"; -+ }; -+ -+ div_clk: div_clk { -+ compatible = "mango, pll-child-clock"; -+ #clock-cells = <1>; -+ id = <S0_DIV_CLK_TABLE>; -+ subctrl-syscon = <&top_misc>; -+ }; -+ -+ mux_clk: mux_clk { -+ compatible = "mango, pll-mux-clock"; -+ #clock-cells = <1>; -+ id = <S0_MUX_CLK_TABLE>; -+ subctrl-syscon = <&top_misc>; -+ }; -+ -+ socket0_default_rates { -+ compatible = "mango, clk-default-rates"; -+ #clock-cells = <1>; -+ subctrl-syscon = <&top_misc>; -+ clocks = \ -+ <&mpll>, <&fpll>, -+ -+ <&div_clk DIV_CLK_FPLL_RP_CPU_NORMAL_1>, -+ <&div_clk DIV_CLK_FPLL_50M_A53>, -+ <&div_clk DIV_CLK_FPLL_TOP_RP_CMN_DIV2>, -+ <&div_clk DIV_CLK_FPLL_UART_500M>, -+ <&div_clk DIV_CLK_FPLL_AHB_LPC>, -+ <&div_clk DIV_CLK_FPLL_EFUSE>, -+ <&div_clk DIV_CLK_FPLL_TX_ETH0>, -+ <&div_clk DIV_CLK_FPLL_PTP_REF_I_ETH0>, -+ <&div_clk DIV_CLK_FPLL_REF_ETH0>, -+ <&div_clk DIV_CLK_FPLL_EMMC>, -+ <&div_clk DIV_CLK_FPLL_SD>, -+ <&div_clk DIV_CLK_FPLL_TOP_AXI0>, -+ <&div_clk DIV_CLK_FPLL_TOP_AXI_HSPERI>, -+ <&div_clk DIV_CLK_FPLL_AXI_DDR_1>, -+ <&div_clk DIV_CLK_FPLL_DIV_TIMER1>, -+ <&div_clk DIV_CLK_FPLL_DIV_TIMER2>, -+ <&div_clk DIV_CLK_FPLL_DIV_TIMER3>, -+ <&div_clk DIV_CLK_FPLL_DIV_TIMER4>, -+ <&div_clk DIV_CLK_FPLL_DIV_TIMER5>, -+ <&div_clk DIV_CLK_FPLL_DIV_TIMER6>, -+ <&div_clk DIV_CLK_FPLL_DIV_TIMER7>, -+ <&div_clk DIV_CLK_FPLL_DIV_TIMER8>, -+ <&div_clk DIV_CLK_FPLL_100K_EMMC>, -+ <&div_clk DIV_CLK_FPLL_100K_SD>, -+ <&div_clk DIV_CLK_FPLL_GPIO_DB>, -+ -+ <&div_clk DIV_CLK_MPLL_RP_CPU_NORMAL_0>, -+ <&div_clk DIV_CLK_MPLL_AXI_DDR_0>; -+ -+ clock-rates = \ -+ <2000000000>, <1000000000>, -+ -+ <2000000000>, <50000000>, -+ <1000000000>, <500000000>, -+ <200000000>, <25000000>, -+ <125000000>, <50000000>, -+ <25000000>, <100000000>, -+ <100000000>, <100000000>, -+ <250000000>, <1000000000>, -+ <50000000>, <50000000>, -+ <50000000>, <50000000>, -+ <50000000>, <50000000>, -+ <50000000>, <50000000>, -+ <100000>, <100000>, <100000>, -+ -+ <2000000001>, <1000000001>; -+ }; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi b/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi -new file mode 100644 -index 000000000000..9165f0a658b0 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi -@@ -0,0 +1,1148 @@ -+/ { -+ cpus { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ timebase-frequency = <50000000>; -+ -+ cpu-map { -+ socket0 { -+ cluster0 { -+ core0 { -+ cpu = <&cpu0>; -+ }; -+ core1 { -+ cpu = <&cpu1>; -+ }; -+ core2 { -+ cpu = <&cpu2>; -+ }; -+ core3 { -+ cpu = <&cpu3>; -+ }; -+ }; -+ -+ cluster1 { -+ core0 { -+ cpu = <&cpu4>; -+ }; -+ core1 { -+ cpu = <&cpu5>; -+ }; -+ core2 { -+ cpu = <&cpu6>; -+ }; -+ core3 { -+ cpu = <&cpu7>; -+ }; -+ }; -+ -+ cluster2 { -+ core0 { -+ cpu = <&cpu16>; -+ }; -+ core1 { -+ cpu = <&cpu17>; -+ }; -+ core2 { -+ cpu = <&cpu18>; -+ }; -+ core3 { -+ cpu = <&cpu19>; -+ }; -+ }; -+ -+ cluster3 { -+ core0 { -+ cpu = <&cpu20>; -+ }; -+ core1 { -+ cpu = <&cpu21>; -+ }; -+ core2 { -+ cpu = <&cpu22>; -+ }; -+ core3 { -+ cpu = <&cpu23>; -+ }; -+ }; -+ -+ cluster4 { -+ core0 { -+ cpu = <&cpu8>; -+ }; -+ core1 { -+ cpu = <&cpu9>; -+ }; -+ core2 { -+ cpu = <&cpu10>; -+ }; -+ core3 { -+ cpu = <&cpu11>; -+ }; -+ }; -+ -+ cluster5 { -+ core0 { -+ cpu = <&cpu12>; -+ }; -+ core1 { -+ cpu = <&cpu13>; -+ }; -+ core2 { -+ cpu = <&cpu14>; -+ }; -+ core3 { -+ cpu = <&cpu15>; -+ }; -+ }; -+ -+ cluster6 { -+ core0 { -+ cpu = <&cpu24>; -+ }; -+ core1 { -+ cpu = <&cpu25>; -+ }; -+ core2 { -+ cpu = <&cpu26>; -+ }; -+ core3 { -+ cpu = <&cpu27>; -+ }; -+ }; -+ -+ cluster7 { -+ core0 { -+ cpu = <&cpu28>; -+ }; -+ core1 { -+ cpu = <&cpu29>; -+ }; -+ core2 { -+ cpu = <&cpu30>; -+ }; -+ core3 { -+ cpu = <&cpu31>; -+ }; -+ }; -+ -+ cluster8 { -+ core0 { -+ cpu = <&cpu32>; -+ }; -+ core1 { -+ cpu = <&cpu33>; -+ }; -+ core2 { -+ cpu = <&cpu34>; -+ }; -+ core3 { -+ cpu = <&cpu35>; -+ }; -+ }; -+ -+ cluster9 { -+ core0 { -+ cpu = <&cpu36>; -+ }; -+ core1 { -+ cpu = <&cpu37>; -+ }; -+ core2 { -+ cpu = <&cpu38>; -+ }; -+ core3 { -+ cpu = <&cpu39>; -+ }; -+ }; -+ -+ cluster10 { -+ core0 { -+ cpu = <&cpu48>; -+ }; -+ core1 { -+ cpu = <&cpu49>; -+ }; -+ core2 { -+ cpu = <&cpu50>; -+ }; -+ core3 { -+ cpu = <&cpu51>; -+ }; -+ }; -+ -+ cluster11 { -+ core0 { -+ cpu = <&cpu52>; -+ }; -+ core1 { -+ cpu = <&cpu53>; -+ }; -+ core2 { -+ cpu = <&cpu54>; -+ }; -+ core3 { -+ cpu = <&cpu55>; -+ }; -+ }; -+ -+ cluster12 { -+ core0 { -+ cpu = <&cpu40>; -+ }; -+ core1 { -+ cpu = <&cpu41>; -+ }; -+ core2 { -+ cpu = <&cpu42>; -+ }; -+ core3 { -+ cpu = <&cpu43>; -+ }; -+ }; -+ -+ cluster13 { -+ core0 { -+ cpu = <&cpu44>; -+ }; -+ core1 { -+ cpu = <&cpu45>; -+ }; -+ core2 { -+ cpu = <&cpu46>; -+ }; -+ core3 { -+ cpu = <&cpu47>; -+ }; -+ }; -+ -+ cluster14 { -+ core0 { -+ cpu = <&cpu56>; -+ }; -+ core1 { -+ cpu = <&cpu57>; -+ }; -+ core2 { -+ cpu = <&cpu58>; -+ }; -+ core3 { -+ cpu = <&cpu59>; -+ }; -+ }; -+ -+ cluster15 { -+ core0 { -+ cpu = <&cpu60>; -+ }; -+ core1 { -+ cpu = <&cpu61>; -+ }; -+ core2 { -+ cpu = <&cpu62>; -+ }; -+ core3 { -+ cpu = <&cpu63>; -+ }; -+ }; -+ }; -+ }; -+ -+ cpu0: cpu@0 { -+ device_type = "cpu"; -+ reg = <0>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu0_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu1: cpu@1 { -+ device_type = "cpu"; -+ reg = <1>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu1_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu2: cpu@2 { -+ device_type = "cpu"; -+ reg = <2>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu2_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu3: cpu@3 { -+ device_type = "cpu"; -+ reg = <3>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu3_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu4: cpu@4 { -+ device_type = "cpu"; -+ reg = <4>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu4_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu5: cpu@5 { -+ device_type = "cpu"; -+ reg = <5>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu5_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu6: cpu@6 { -+ device_type = "cpu"; -+ reg = <6>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu6_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu7: cpu@7 { -+ device_type = "cpu"; -+ reg = <7>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu7_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu8: cpu@8 { -+ device_type = "cpu"; -+ reg = <8>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu8_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu9: cpu@9 { -+ device_type = "cpu"; -+ reg = <9>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu9_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu10: cpu@10 { -+ device_type = "cpu"; -+ reg = <10>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu10_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu11: cpu@11 { -+ device_type = "cpu"; -+ reg = <11>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu11_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu12: cpu@12 { -+ device_type = "cpu"; -+ reg = <12>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu12_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu13: cpu@13 { -+ device_type = "cpu"; -+ reg = <13>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu13_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu14: cpu@14 { -+ device_type = "cpu"; -+ reg = <14>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu14_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu15: cpu@15 { -+ device_type = "cpu"; -+ reg = <15>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu15_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu16: cpu@16 { -+ device_type = "cpu"; -+ reg = <16>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu16_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu17: cpu@17 { -+ device_type = "cpu"; -+ reg = <17>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu17_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu18: cpu@18 { -+ device_type = "cpu"; -+ reg = <18>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu18_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu19: cpu@19 { -+ device_type = "cpu"; -+ reg = <19>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu19_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu20: cpu@20 { -+ device_type = "cpu"; -+ reg = <20>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu20_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu21: cpu@21 { -+ device_type = "cpu"; -+ reg = <21>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu21_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu22: cpu@22 { -+ device_type = "cpu"; -+ reg = <22>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu22_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu23: cpu@23 { -+ device_type = "cpu"; -+ reg = <23>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <0>; -+ cpu23_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu24: cpu@24 { -+ device_type = "cpu"; -+ reg = <24>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu24_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu25: cpu@25 { -+ device_type = "cpu"; -+ reg = <25>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu25_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu26: cpu@26 { -+ device_type = "cpu"; -+ reg = <26>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu26_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu27: cpu@27 { -+ device_type = "cpu"; -+ reg = <27>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu27_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu28: cpu@28 { -+ device_type = "cpu"; -+ reg = <28>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu28_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu29: cpu@29 { -+ device_type = "cpu"; -+ reg = <29>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu29_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu30: cpu@30 { -+ device_type = "cpu"; -+ reg = <30>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu30_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu31: cpu@31 { -+ device_type = "cpu"; -+ reg = <31>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <1>; -+ cpu31_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu32: cpu@32 { -+ device_type = "cpu"; -+ reg = <32>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu32_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu33: cpu@33 { -+ device_type = "cpu"; -+ reg = <33>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu33_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu34: cpu@34 { -+ device_type = "cpu"; -+ reg = <34>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu34_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu35: cpu@35 { -+ device_type = "cpu"; -+ reg = <35>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu35_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu36: cpu@36 { -+ device_type = "cpu"; -+ reg = <36>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu36_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu37: cpu@37 { -+ device_type = "cpu"; -+ reg = <37>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu37_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu38: cpu@38 { -+ device_type = "cpu"; -+ reg = <38>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu38_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu39: cpu@39 { -+ device_type = "cpu"; -+ reg = <39>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu39_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu40: cpu@40 { -+ device_type = "cpu"; -+ reg = <40>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu40_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu41: cpu@41 { -+ device_type = "cpu"; -+ reg = <41>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu41_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu42: cpu@42 { -+ device_type = "cpu"; -+ reg = <42>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu42_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu43: cpu@43 { -+ device_type = "cpu"; -+ reg = <43>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu43_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu44: cpu@44 { -+ device_type = "cpu"; -+ reg = <44>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu44_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu45: cpu@45 { -+ device_type = "cpu"; -+ reg = <45>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu45_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu46: cpu@46 { -+ device_type = "cpu"; -+ reg = <46>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu46_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu47: cpu@47 { -+ device_type = "cpu"; -+ reg = <47>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu47_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu48: cpu@48 { -+ device_type = "cpu"; -+ reg = <48>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu48_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu49: cpu@49 { -+ device_type = "cpu"; -+ reg = <49>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu49_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu50: cpu@50 { -+ device_type = "cpu"; -+ reg = <50>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu50_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu51: cpu@51 { -+ device_type = "cpu"; -+ reg = <51>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu51_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu52: cpu@52 { -+ device_type = "cpu"; -+ reg = <52>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu52_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu53: cpu@53 { -+ device_type = "cpu"; -+ reg = <53>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu53_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu54: cpu@54 { -+ device_type = "cpu"; -+ reg = <54>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu54_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu55: cpu@55 { -+ device_type = "cpu"; -+ reg = <55>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <2>; -+ cpu55_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu56: cpu@56 { -+ device_type = "cpu"; -+ reg = <56>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu56_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu57: cpu@57 { -+ device_type = "cpu"; -+ reg = <57>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu57_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu58: cpu@58 { -+ device_type = "cpu"; -+ reg = <58>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu58_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu59: cpu@59 { -+ device_type = "cpu"; -+ reg = <59>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu59_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu60: cpu@60 { -+ device_type = "cpu"; -+ reg = <60>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu60_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu61: cpu@61 { -+ device_type = "cpu"; -+ reg = <61>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu61_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu62: cpu@62 { -+ device_type = "cpu"; -+ reg = <62>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu62_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ cpu63: cpu@63 { -+ device_type = "cpu"; -+ reg = <63>; -+ status = "okay"; -+ compatible = "riscv"; -+ riscv,isa = "rv64imafdcv"; -+ mmu-type = "riscv,sv39"; -+ numa-node-id = <3>; -+ cpu63_intc: interrupt-controller { -+ #interrupt-cells = <1>; -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ }; -+ }; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts -new file mode 100644 -index 000000000000..00f2d5e2c674 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts -@@ -0,0 +1,163 @@ -+#include "mango.dtsi" -+#include "mango-pcie-4rc.dtsi" -+ -+/ { -+ info { -+ file-name = "mango-milkv-pioneer.dts"; -+ }; -+}; -+ -+&i2c1 { -+ mcu: sg2042mcu@17 { -+ compatible = "sophgo,sg20xx-mcu"; -+ reg = <0x17>; -+ #thermal-sensor-cells = <1>; -+ }; -+ -+ mango_srst: mango-reset@17 { -+ compatible = "mango,reset"; -+ reg = <0x17>; -+ }; -+}; -+ -+&i2c2 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c2_acquire>; -+}; -+ -+&soc { -+ /delete-node/ ethernet@7040026000; -+ gpio-poweroff { -+ compatible = "gpio-keys"; -+ input-name = "gpio-keys"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwr_key>; -+ -+ power { -+ label = "GPIO Key Power"; -+ linux,code = <KEY_POWER>; -+ gpios = <&port0a 22 GPIO_ACTIVE_HIGH>; -+ linux,input-type = <1>; -+ debounce-interval = <100>; -+ }; -+ }; -+ -+ gpio-restart { -+ compatible = "gpio-keys"; -+ input-name = "gpio-keys"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&restart_key>; -+ -+ restart { -+ label = "GPIO Key Restart"; -+ linux,code = <KEY_RESTART>; -+ gpios = <&port0a 23 GPIO_ACTIVE_HIGH>; -+ linux,input-type = <1>; -+ debounce-interval = <100>; -+ }; -+ }; -+}; -+ -+&tach0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&fan0_acquire>; -+}; -+ -+&tach1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&fan1_acquire>; -+}; -+ -+/ { -+ pwmfan: pwm-fan { -+ compatible = "pwm-fan"; -+ pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns -+ pwm-names = "pwm0","pwm1"; -+ pwm_inuse = "pwm0"; -+ #cooling-cells = <2>; -+ cooling-levels = <1 1 1 1 1>; //total 255 -+ }; -+ -+ thermal_zones: thermal-zones { -+ soc { -+ polling-delay-passive = <1000>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&mcu 0>; -+ -+ trips { -+ soc_pwmfan_trip1: soc_pwmfan_trip@1 { -+ temperature = <30000>; /* millicelsius */ -+ hysteresis = <8000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip2: soc_pwmfan_trip@2 { -+ temperature = <40000>; /* millicelsius */ -+ hysteresis = <12000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip3: soc_pwmfan_trip@3 { -+ temperature = <50000>; /* millicelsius */ -+ hysteresis = <10000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip4: soc_pwmfan_trip@4 { -+ temperature = <60000>; /* millicelsius */ -+ hysteresis = <5000>; /* millicelsius */ -+ type = "active"; -+ }; -+ }; -+ -+ cooling-maps { -+ map0 { -+ trip = <&soc_pwmfan_trip1>; -+ cooling-device = <&pwmfan 0 1>; -+ }; -+ -+ map1 { -+ trip = <&soc_pwmfan_trip2>; -+ cooling-device = <&pwmfan 1 2>; -+ }; -+ -+ map2 { -+ trip = <&soc_pwmfan_trip3>; -+ cooling-device = <&pwmfan 2 3>; -+ }; -+ -+ map3 { -+ trip = <&soc_pwmfan_trip4>; -+ cooling-device = <&pwmfan 3 4>; -+ }; -+ }; -+ -+ }; -+ -+ board { -+ polling-delay-passive = <1000>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&mcu 1>; -+ -+ trips { -+ board_pwmfan_trip1: board_pwmfan_trip@1 { -+ temperature = <75000>; /* millicelsius */ -+ hysteresis = <8000>; /* millicelsius */ -+ type = "active"; -+ }; -+ }; -+ -+ cooling-maps { -+ map4 { -+ trip = <&board_pwmfan_trip1>; -+ cooling-device = <&pwmfan 3 4>; -+ }; -+ }; -+ }; -+ }; -+ -+}; -+ -+&chosen { -+ bootargs = "console=ttyS0,115200 console=tty1 earlycon maxcpus=1"; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi -new file mode 100644 -index 000000000000..fb4eb57d82f0 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi -@@ -0,0 +1,83 @@ -+#include <dt-bindings/interrupt-controller/irq.h> -+ -+#define SOC_PERIPHERAL_IRQ(nr) (nr) -+ -+/ { -+ pcie@7062000000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x00 0x7f>; -+ linux,pci-domain = <0>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x1>; -+ link-id = /bits/ 16 <0x0>; -+ top-intc-used = <1>; -+ top-intc-id = <0>; -+ msix-supported = <0>; -+ interrupt-parent = <&intc1>; -+ //interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>; -+ //interrupt-names = "msi"; -+ reg = <0x70 0x62000000 0x0 0x02000000>, -+ <0x48 0x00000000 0x0 0x00001000>; -+ reg-names = "reg", "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00000000 0x48 0x10000000 0x0 0x00800000>, -+ <0x42000000 0x0 0x20000000 0x48 0x20000000 0x0 0x50000000>, -+ <0x02000000 0x0 0x70000000 0x48 0x70000000 0x0 0x20000000>, -+ <0x43000000 0x49 0x00000000 0x49 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x4b 0x00000000 0x4b 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+ -+ pcie@f060000000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x80 0xff>; -+ linux,pci-domain = <1>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x0>; -+ link-id = /bits/ 16 <0x0>; -+ top-intc-used = <1>; -+ top-intc-id = <1>; -+ msix-supported = <0>; -+ interrupt-parent = <&intc2>; -+ //interrupts = <SOC_PERIPHERAL_IRQ(346) IRQ_TYPE_LEVEL_HIGH>; -+ //interrupt-names = "msi"; -+ reg = <0xf0 0x60000000 0x0 0x02000000>, -+ <0xc0 0x00000000 0x0 0x00001000>; -+ reg-names = "reg", "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00800000 0xc0 0x10800000 0x0 0x00800000>, -+ <0x42000000 0x0 0x90000000 0xc0 0x90000000 0x0 0x50000000>, -+ <0x02000000 0x0 0xe0000000 0xc0 0xe0000000 0x0 0x20000000>, -+ <0x43000000 0xc1 0x00000000 0xc1 0x00000000 0x2 0x00000000>, -+ <0x03000000 0xc3 0x00000000 0xc3 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi -new file mode 100644 -index 000000000000..0414f892bfb7 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi -@@ -0,0 +1,118 @@ -+#include <dt-bindings/interrupt-controller/irq.h> -+ -+#define SOC_PERIPHERAL_IRQ(nr) (nr) -+ -+/ { -+ pcie@7060000000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x0 0x3f>; -+ linux,pci-domain = <0>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x0>; -+ link-id = /bits/ 16 <0x0>; -+ top-intc-used = <0>; -+ top-intc-id = <0>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "msi"; -+ reg = <0x70 0x60000000 0x0 0x02000000>, -+ <0x40 0x00000000 0x0 0x00001000>; -+ reg-names = "reg", "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00000000 0x40 0x10000000 0x0 0x00400000>, -+ <0x42000000 0x0 0xc0000000 0x40 0xc0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, -+ <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+ -+ pcie@7060800000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x40 0x7f>; -+ linux,pci-domain = <1>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x0>; -+ link-id = /bits/ 16 <0x1>; -+ top-intc-used = <1>; -+ top-intc-id = <0>; -+ msix-supported = <0>; -+ interrupt-parent = <&intc1>; -+ //interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>; -+ //interrupt-names = "msi"; -+ reg = <0x44 0x00000000 0x0 0x00001000>; -+ reg-names = "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00400000 0x44 0x10400000 0x0 0x00400000>, -+ <0x42000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xc0000000 0x44 0xc0000000 0x0 0x20000000>, -+ <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+ -+ pcie@7062000000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x80 0xff>; -+ linux,pci-domain = <2>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x1>; -+ link-id = /bits/ 16 <0x0>; -+ top-intc-used = <0>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "msi"; -+ reg = <0x70 0x62000000 0x0 0x02000000>, -+ <0x48 0x00000000 0x0 0x00001000>; -+ reg-names = "reg", "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00800000 0x48 0x10800000 0x0 0x00800000>, -+ <0x42000000 0x0 0xc0000000 0x48 0xc0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, -+ <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi -new file mode 100644 -index 000000000000..296d4207c9b2 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi -@@ -0,0 +1,115 @@ -+#include <dt-bindings/interrupt-controller/irq.h> -+ -+#define SOC_PERIPHERAL_IRQ(nr) (nr) -+ -+/ { -+ pcie@7060000000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x0 0x3f>; -+ linux,pci-domain = <0>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x0>; -+ link-id = /bits/ 16 <0x0>; -+ top-intc-used = <0>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "msi"; -+ reg = <0x70 0x60000000 0x0 0x02000000>, -+ <0x40 0x00000000 0x0 0x00001000>; -+ reg-names = "reg", "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00000000 0x40 0x10000000 0x0 0x00400000>, -+ <0x42000000 0x0 0xc0000000 0x40 0xc0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, -+ <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+ -+ pcie@7060800000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x40 0x7f>; -+ linux,pci-domain = <1>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x0>; -+ link-id = /bits/ 16 <0x1>; -+ top-intc-used = <1>; -+ top-intc-id = <0>; -+ msix-supported = <0>; -+ interrupt-parent = <&intc1>; -+ reg = <0x44 0x00000000 0x0 0x00001000>; -+ reg-names = "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00400000 0x44 0x10400000 0x0 0x00400000>, -+ <0x42000000 0x0 0xc0000000 0x44 0xc0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, -+ <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+ -+ pcie@7062000000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x80 0xff>; -+ linux,pci-domain = <2>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x1>; -+ link-id = /bits/ 16 <0x0>; -+ top-intc-used = <0>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "msi"; -+ reg = <0x70 0x62000000 0x0 0x02000000>, -+ <0x48 0x00000000 0x0 0x00001000>; -+ reg-names = "reg", "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00800000 0x48 0x10800000 0x0 0x00800000>, -+ <0x42000000 0x0 0xc0000000 0x48 0xc0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, -+ <0x43000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>, -+ <0x03000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi -new file mode 100644 -index 000000000000..4fe6bd3f52a0 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi -@@ -0,0 +1,151 @@ -+#include <dt-bindings/interrupt-controller/irq.h> -+ -+#define SOC_PERIPHERAL_IRQ(nr) (nr) -+ -+/ { -+ pcie@7060000000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x0 0x3f>; -+ linux,pci-domain = <0>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x0>; -+ link-id = /bits/ 16 <0x0>; -+ top-intc-used = <0>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "msi"; -+ reg = <0x70 0x60000000 0x0 0x02000000>, -+ <0x40 0x00000000 0x0 0x00001000>; -+ reg-names = "reg", "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00000000 0x40 0x10000000 0x0 0x00400000>, -+ <0x42000000 0x0 0xc0000000 0x40 0xc0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, -+ <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+ -+ pcie@7060800000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x40 0x7f>; -+ linux,pci-domain = <1>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x0>; -+ link-id = /bits/ 16 <0x1>; -+ top-intc-used = <1>; -+ top-intc-id = <0>; -+ msix-supported = <0>; -+ interrupt-parent = <&intc1>; -+ reg = <0x44 0x00000000 0x0 0x00001000>; -+ reg-names = "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00400000 0x44 0x10400000 0x0 0x00400000>, -+ <0x42000000 0x0 0xc0000000 0x44 0xc0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, -+ <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+ -+ pcie@7062000000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0x80 0xbf>; -+ linux,pci-domain = <2>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x1>; -+ link-id = /bits/ 16 <0x0>; -+ top-intc-used = <0>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "msi"; -+ reg = <0x70 0x62000000 0x0 0x02000000>, -+ <0x48 0x00000000 0x0 0x00001000>; -+ reg-names = "reg", "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00800000 0x48 0x10800000 0x0 0x00400000>, -+ <0x42000000 0x0 0xc0000000 0x48 0xc0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, -+ <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>, -+ <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+ -+ pcie@7062800000 { -+ compatible = "sophgo,cdns-pcie-host"; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ bus-range = <0xc0 0xff>; -+ linux,pci-domain = <3>; -+ cdns,max-outbound-regions = <16>; -+ cdns,no-bar-match-nbits = <48>; -+ vendor-id = /bits/ 16 <0x1E30>; -+ device-id = /bits/ 16 <0x2042>; -+ pcie-id = /bits/ 16 <0x1>; -+ link-id = /bits/ 16 <0x1>; -+ top-intc-used = <1>; -+ top-intc-id = <0>; -+ msix-supported = <0>; -+ interrupt-parent = <&intc1>; -+ reg = <0x4c 0x00000000 0x0 0x00001000>; -+ reg-names = "cfg"; -+ -+ // IO, check IO_SPACE_LIMIT -+ // 32bit prefetchable memory -+ // 32bit non-prefetchable memory -+ // 64bit prefetchable memory -+ // 64bit non-prefetchable memory -+ ranges = <0x01000000 0x0 0x00c00000 0x4c 0x10c00000 0x0 0x00400000>, -+ <0x42000000 0x0 0xd0000000 0x4c 0xd0000000 0x0 0x20000000>, -+ <0x02000000 0x0 0xf0000000 0x4c 0xf0000000 0x0 0x10000000>, -+ <0x43000000 0x4d 0x00000000 0x4d 0x00000000 0x2 0x00000000>, -+ <0x03000000 0x4f 0x00000000 0x4f 0x00000000 0x1 0x00000000>; -+ dma-ranges = <0x03000000 0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ status = "okay"; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi b/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi -new file mode 100644 -index 000000000000..f3fb2e39af26 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi -@@ -0,0 +1,434 @@ -+/ { -+ bmpctrl: pinctrl@50010400 { -+ compatible = "sophgo, pinctrl-mango"; -+ subctrl-syscon = <&top_misc>; -+ top_pinctl_offset = <0x1000>; -+ -+ lpc_acquire: lpc_acquire { -+ mux { -+ groups = "lpc_grp"; -+ function = "lpc_a"; -+ }; -+ }; -+ -+ lpc_release: lpc_release{ -+ mux { -+ groups = "lpc_grp"; -+ function = "lpc_r"; -+ }; -+ }; -+ -+ pcie_acquire: pcie_acquire { -+ mux { -+ groups = "pcie_grp"; -+ function = "pcie_a"; -+ }; -+ }; -+ -+ pcie_release: pcie_release{ -+ mux { -+ groups = "pcie_grp"; -+ function = "pcie_r"; -+ }; -+ }; -+ -+ spif_acquire: spif_acquire { -+ mux { -+ groups = "spif_grp"; -+ function = "spif_a"; -+ }; -+ }; -+ -+ spif_release: spif_release{ -+ mux { -+ groups = "spif_grp"; -+ function = "spif_r"; -+ }; -+ }; -+ -+ emmc_acquire: emmc_acquire { -+ mux { -+ groups = "emmc_grp"; -+ function = "emmc_a"; -+ }; -+ }; -+ -+ emmc_release: emmc_release{ -+ mux { -+ groups = "emmc_grp"; -+ function = "emmc_r"; -+ }; -+ }; -+ -+ sdio_acquire: sdio_acquire { -+ mux { -+ groups = "sdio_grp"; -+ function = "sdio_a"; -+ }; -+ }; -+ -+ sdio_release: sdio_release{ -+ mux { -+ groups = "sdio_grp"; -+ function = "sdio_r"; -+ }; -+ }; -+ -+ eth0_acquire: eth0_acquire { -+ mux { -+ groups = "eth0_grp"; -+ function = "eth0_a"; -+ }; -+ }; -+ -+ eth0_release: eth0_release{ -+ mux { -+ groups = "eth0_grp"; -+ function = "eth0_r"; -+ }; -+ }; -+ -+ pwm0_acquire: pwm0_acquire { -+ mux { -+ groups = "pwm0_grp"; -+ function = "pwm0_a"; -+ }; -+ }; -+ -+ pwm0_release: pwm0_release{ -+ mux { -+ groups = "pwm0_grp"; -+ function = "pwm0_r"; -+ }; -+ }; -+ -+ pwm1_acquire: pwm1_acquire { -+ mux { -+ groups = "pwm1_grp"; -+ function = "pwm1_a"; -+ }; -+ }; -+ -+ pwm1_release: pwm1_release{ -+ mux { -+ groups = "pwm1_grp"; -+ function = "pwm1_r"; -+ }; -+ }; -+ -+ pwm2_acquire: pwm2_acquire { -+ mux { -+ groups = "pwm2_grp"; -+ function = "pwm2_a"; -+ }; -+ }; -+ -+ pwm2_release: pwm2_release{ -+ mux { -+ groups = "pwm2_grp"; -+ function = "pwm2_r"; -+ }; -+ }; -+ -+ pwm3_acquire: pwm3_acquire { -+ mux { -+ groups = "pwm3_grp"; -+ function = "pwm3_a"; -+ }; -+ }; -+ -+ pwm3_release: pwm3_release{ -+ mux { -+ groups = "pwm3_grp"; -+ function = "pwm3_r"; -+ }; -+ }; -+ -+ fan0_acquire: fan0_acquire { -+ mux { -+ groups = "fan0_grp"; -+ function = "fan0_a"; -+ }; -+ }; -+ -+ fan0_release: fan0_release{ -+ mux { -+ groups = "fan0_grp"; -+ function = "fan0_r"; -+ }; -+ }; -+ -+ fan1_acquire: fan1_acquire { -+ mux { -+ groups = "fan1_grp"; -+ function = "fan1_a"; -+ }; -+ }; -+ -+ fan1_release: fan1_release{ -+ mux { -+ groups = "fan1_grp"; -+ function = "fan1_r"; -+ }; -+ }; -+ -+ fan2_acquire: fan2_acquire { -+ mux { -+ groups = "fan2_grp"; -+ function = "fan2_a"; -+ }; -+ }; -+ -+ fan2_release: fan2_release{ -+ mux { -+ roups = "fan2_grp"; -+ function = "fan2_r"; -+ }; -+ }; -+ -+ fan3_acquire: fan3_acquire { -+ mux { -+ groups = "fan3_grp"; -+ function = "fan3_a"; -+ }; -+ }; -+ -+ fan3_release: fan3_release{ -+ mux { -+ groups = "fan3_grp"; -+ function = "fan3_r"; -+ }; -+ }; -+ -+ i2c0_acquire: i2c0_acquire { -+ mux { -+ groups = "i2c0_grp"; -+ function = "i2c0_a"; -+ }; -+ }; -+ -+ i2c0_release: i2c0_release{ -+ mux { -+ groups = "i2c0_grp"; -+ function = "i2c0_r"; -+ }; -+ }; -+ -+ i2c1_acquire: i2c1_acquire { -+ mux { -+ groups = "i2c1_grp"; -+ function = "i2c1_a"; -+ }; -+ }; -+ -+ i2c1_release: i2c1_release{ -+ mux { -+ groups = "i2c1_grp"; -+ function = "i2c1_r"; -+ }; -+ }; -+ -+ i2c2_acquire: i2c2_acquire { -+ mux { -+ groups = "i2c2_grp"; -+ function = "i2c2_a"; -+ }; -+ }; -+ -+ i2c2_release: i2c2_release{ -+ mux { -+ groups = "i2c2_grp"; -+ function = "i2c2_r"; -+ }; -+ }; -+ -+ i2c3_acquire: i2c3_acquire { -+ mux { -+ groups = "i2c3_grp"; -+ function = "i2c3_a"; -+ }; -+ }; -+ -+ i2c3_release: i2c3_release{ -+ mux { -+ groups = "i2c3_grp"; -+ function = "i2c3_r"; -+ }; -+ }; -+ -+ uart0_acquire: uart0_acquire { -+ mux { -+ groups = "uart0_grp"; -+ function = "uart0_a"; -+ }; -+ }; -+ -+ uart0_release: uart0_release{ -+ mux { -+ groups = "uart0_grp"; -+ function = "uart0_r"; -+ }; -+ }; -+ -+ uart1_acquire: uart1_acquire { -+ mux { -+ groups = "uart1_grp"; -+ function = "uart1_a"; -+ }; -+ }; -+ -+ uart1_release: uart1_release{ -+ mux { -+ groups = "uart1_grp"; -+ function = "uart1_r"; -+ }; -+ }; -+ -+ uart2_acquire: uart2_acquire { -+ mux { -+ groups = "uart2_grp"; -+ function = "uart2_a"; -+ }; -+ }; -+ -+ uart2_release: uart2_release{ -+ mux { -+ groups = "uart2_grp"; -+ function = "uart2_r"; -+ }; -+ }; -+ -+ uart3_acquire: uart3_acquire { -+ mux { -+ groups = "uart3_grp"; -+ function = "uart3_a"; -+ }; -+ }; -+ -+ uart3_release: uart3_release{ -+ mux { -+ groups = "uart3_grp"; -+ function = "uart3_r"; -+ }; -+ }; -+ -+ spi0_acquire: spi0_acquire { -+ mux { -+ groups = "spi0_grp"; -+ function = "spi0_a"; -+ }; -+ }; -+ -+ spi0_release: spi0_release{ -+ mux { -+ groups = "spi0_grp"; -+ function = "spi0_r"; -+ }; -+ }; -+ -+ spi1_acquire: spi1_acquire { -+ mux { -+ groups = "spi1_grp"; -+ function = "spi1_a"; -+ }; -+ }; -+ -+ spi1_release: spi1_release{ -+ mux { -+ groups = "spi1_grp"; -+ function = "spi1_r"; -+ }; -+ }; -+ -+ jtag0_acquire: jtag0_acquire { -+ mux { -+ groups = "jtag0_grp"; -+ function = "jtag0_a"; -+ }; -+ }; -+ -+ jtag0_release: jtag0_release{ -+ mux { -+ groups = "jtag0_grp"; -+ function = "jtag0_r"; -+ }; -+ }; -+ -+ jtag1_acquire: jtag1_acquire { -+ mux { -+ groups = "jtag1_grp"; -+ function = "jtag1_a"; -+ }; -+ }; -+ -+ jtag1_release: jtag1_release{ -+ mux { -+ groups = "jtag1_grp"; -+ function = "jtag1_r"; -+ }; -+ }; -+ -+ jtag2_acquire: jtag2_acquire { -+ mux { -+ groups = "jtag2_grp"; -+ function = "jtag2_a"; -+ }; -+ }; -+ -+ jtag2_release: jtag2_release{ -+ mux { -+ groups = "jtag2_grp"; -+ function = "jtag2_r"; -+ }; -+ }; -+ -+ gpio2_acquire: gpio2_acquire { -+ mux { -+ pins = <127>; -+ function = "gpio0_a"; -+ }; -+ }; -+ -+ gpio3_release: gpio3_release { -+ mux { -+ pins = <128>; -+ function = "gpio0_r"; -+ }; -+ }; -+ -+ gpio5_release: gpio5_release { -+ mux { -+ pins = <130>; -+ function = "gpio0_r"; -+ }; -+ }; -+ -+ pwr_key: pwr-key { -+ mux { -+ pins = <147>; -+ function = "gpio0_a"; -+ }; -+ }; -+ -+ restart_key: restart-key { -+ mux { -+ pins = <148>; -+ function = "gpio0_a"; -+ }; -+ }; -+ -+ dbgi2c_acquire: dbgi2c_acquire { -+ mux { -+ groups = "dbgi2c_grp"; -+ function = "dbgi2c_a"; -+ }; -+ }; -+ -+ dbgi2c_release: dbgi2c_release{ -+ mux { -+ groups = "dbgi2c_grp"; -+ function = "dbgi2c_r"; -+ }; -+ }; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts -new file mode 100644 -index 000000000000..78495159bbb4 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts -@@ -0,0 +1,137 @@ -+#include "mango.dtsi" -+#include "mango-pcie-3rc-v2.dtsi" -+ -+/ { -+ info { -+ file-name = "mango-sophgo-x4evb.dts"; -+ }; -+}; -+ -+&i2c1 { -+ mcu: sg2042mcu@17 { -+ compatible = "sophgo,sg20xx-mcu"; -+ reg = <0x17>; -+ #thermal-sensor-cells = <1>; -+ }; -+ -+ mango_srst: mango-reset@17 { -+ compatible = "mango,reset"; -+ reg = <0x17>; -+ }; -+}; -+ -+&i2c2 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c2_acquire>; -+}; -+ -+&tach0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&fan0_acquire>; -+}; -+ -+&tach1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&fan1_acquire>; -+}; -+ -+ðernet0 { -+ max-speed = <1000>; -+ eth-sophgo-config { -+ autoneg = "enable"; -+ }; -+}; -+ -+&soc { -+ /delete-node/ flash-controller@7000180000; -+}; -+ -+/ { -+ pwmfan: pwm-fan { -+ compatible = "pwm-fan"; -+ pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns -+ pwm-names = "pwm0","pwm1"; -+ pwm_inuse = "pwm0"; -+ #cooling-cells = <2>; -+ cooling-levels = <102 127 178 229 254>; //total 255 -+ }; -+ -+ thermal_zones: thermal-zones { -+ soc { -+ polling-delay-passive = <1000>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&mcu 0>; -+ -+ trips { -+ soc_pwmfan_trip1: soc_pwmfan_trip@1 { -+ temperature = <40000>; /* millicelsius */ -+ hysteresis = <8000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip2: soc_pwmfan_trip@2 { -+ temperature = <58000>; /* millicelsius */ -+ hysteresis = <12000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip3: soc_pwmfan_trip@3 { -+ temperature = <70000>; /* millicelsius */ -+ hysteresis = <10000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip4: soc_pwmfan_trip@4 { -+ temperature = <85000>; /* millicelsius */ -+ hysteresis = <5000>; /* millicelsius */ -+ type = "active"; -+ }; -+ }; -+ -+ cooling-maps { -+ map0 { -+ trip = <&soc_pwmfan_trip1>; -+ cooling-device = <&pwmfan 0 1>; -+ }; -+ -+ map1 { -+ trip = <&soc_pwmfan_trip2>; -+ cooling-device = <&pwmfan 1 2>; -+ }; -+ -+ map2 { -+ trip = <&soc_pwmfan_trip3>; -+ cooling-device = <&pwmfan 2 3>; -+ }; -+ -+ map3 { -+ trip = <&soc_pwmfan_trip4>; -+ cooling-device = <&pwmfan 3 4>; -+ }; -+ }; -+ -+ }; -+ -+ board { -+ polling-delay-passive = <1000>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&mcu 1>; -+ -+ trips { -+ board_pwmfan_trip1: board_pwmfan_trip@1 { -+ temperature = <75000>; /* millicelsius */ -+ hysteresis = <8000>; /* millicelsius */ -+ type = "active"; -+ }; -+ }; -+ -+ cooling-maps { -+ map4 { -+ trip = <&board_pwmfan_trip1>; -+ cooling-device = <&pwmfan 3 4>; -+ }; -+ }; -+ }; -+ }; -+ -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts -new file mode 100644 -index 000000000000..83e4f1411f2e ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts -@@ -0,0 +1,165 @@ -+#include "mango.dtsi" -+#include "mango-pcie-3rc.dtsi" -+ -+/ { -+ info { -+ file-name = "mango-sophgo-x8evb.dts"; -+ }; -+}; -+ -+&i2c1 { -+ mcu: sg2042mcu@17 { -+ compatible = "sophgo,sg20xx-mcu"; -+ reg = <0x17>; -+ #thermal-sensor-cells = <1>; -+ }; -+ -+ mango_srst: mango-reset@17 { -+ compatible = "mango,reset"; -+ reg = <0x17>; -+ }; -+}; -+ -+&i2c2 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c2_acquire>; -+}; -+ -+&soc { -+ gpio-poweroff { -+ compatible = "gpio-keys"; -+ input-name = "gpio-keys"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwr_key>; -+ -+ power { -+ label = "GPIO Key Power"; -+ linux,code = <KEY_POWER>; -+ gpios = <&port0a 22 GPIO_ACTIVE_HIGH>; -+ linux,input-type = <1>; -+ debounce-interval = <100>; -+ }; -+ }; -+ -+ gpio-restart { -+ compatible = "gpio-keys"; -+ input-name = "gpio-keys"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&restart_key>; -+ -+ restart { -+ label = "GPIO Key Restart"; -+ linux,code = <KEY_RESTART>; -+ gpios = <&port0a 23 GPIO_ACTIVE_HIGH>; -+ linux,input-type = <1>; -+ debounce-interval = <100>; -+ }; -+ }; -+}; -+ -+&tach0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&fan0_acquire>; -+}; -+ -+&tach1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&fan1_acquire>; -+}; -+ -+ðernet0 { -+ max-speed = <1000>; -+ eth-sophgo-config { -+ autoneg = "enable"; -+ }; -+}; -+ -+/ { -+ pwmfan: pwm-fan { -+ compatible = "pwm-fan"; -+ pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns -+ pwm-names = "pwm0","pwm1"; -+ pwm_inuse = "pwm0"; -+ #cooling-cells = <2>; -+ cooling-levels = <153 128 77 26 1>; //total 255 -+ }; -+ -+ thermal_zones: thermal-zones { -+ soc { -+ polling-delay-passive = <1000>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&mcu 0>; -+ -+ trips { -+ soc_pwmfan_trip1: soc_pwmfan_trip@1 { -+ temperature = <40000>; /* millicelsius */ -+ hysteresis = <8000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip2: soc_pwmfan_trip@2 { -+ temperature = <58000>; /* millicelsius */ -+ hysteresis = <12000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip3: soc_pwmfan_trip@3 { -+ temperature = <70000>; /* millicelsius */ -+ hysteresis = <10000>; /* millicelsius */ -+ type = "active"; -+ }; -+ -+ soc_pwmfan_trip4: soc_pwmfan_trip@4 { -+ temperature = <85000>; /* millicelsius */ -+ hysteresis = <5000>; /* millicelsius */ -+ type = "active"; -+ }; -+ }; -+ -+ cooling-maps { -+ map0 { -+ trip = <&soc_pwmfan_trip1>; -+ cooling-device = <&pwmfan 0 1>; -+ }; -+ -+ map1 { -+ trip = <&soc_pwmfan_trip2>; -+ cooling-device = <&pwmfan 1 2>; -+ }; -+ -+ map2 { -+ trip = <&soc_pwmfan_trip3>; -+ cooling-device = <&pwmfan 2 3>; -+ }; -+ -+ map3 { -+ trip = <&soc_pwmfan_trip4>; -+ cooling-device = <&pwmfan 3 4>; -+ }; -+ }; -+ -+ }; -+ -+ board { -+ polling-delay-passive = <1000>; /* milliseconds */ -+ polling-delay = <1000>; /* milliseconds */ -+ thermal-sensors = <&mcu 1>; -+ -+ trips { -+ board_pwmfan_trip1: board_pwmfan_trip@1 { -+ temperature = <75000>; /* millicelsius */ -+ hysteresis = <8000>; /* millicelsius */ -+ type = "active"; -+ }; -+ }; -+ -+ cooling-maps { -+ map4 { -+ trip = <&board_pwmfan_trip1>; -+ cooling-device = <&pwmfan 3 4>; -+ }; -+ }; -+ }; -+ }; -+ -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi b/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi -new file mode 100644 -index 000000000000..6d364cf6b3c5 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi -@@ -0,0 +1,62 @@ -+#include <dt-bindings/interrupt-controller/irq.h> -+ -+#define SOC_PERIPHERAL_IRQ(nr) (nr) -+ -+/ { -+ intc2: top_intc@f030010300 { -+ compatible = "sophgo,top-intc"; -+ reg = <0xf0 0x300102E0 0x0 0x4>, -+ <0xf0 0x30010300 0x0 0x4>, -+ <0xf0 0x30010304 0x0 0x4>; -+ reg-names = "sta", "set", "clr"; -+ reg-bitwidth = <32>; -+ top-intc-id = <1>; -+ interrupt-controller; -+ #interrupt-cells = <0x1>; // only applies to child node -+ for-msi; -+ -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(288) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(289) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(290) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(291) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(292) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(293) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(294) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(295) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(296) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(297) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(298) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(299) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(300) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(301) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(302) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(303) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(304) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(305) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(306) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(307) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(308) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(309) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(310) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(311) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(312) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(313) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(314) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(315) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(316) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(317) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(318) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(319) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "msi0", "msi1", "msi2", "msi3", -+ "msi4", "msi5", "msi6", "msi7", -+ "msi8", "msi9", "msi10", "msi11", -+ "msi12", "msi13", "msi14", "msi15", -+ "msi16", "msi17", "msi18", "msi19", -+ "msi20", "msi21", "msi22", "msi23", -+ "msi24", "msi25", "msi26", "msi27", -+ "msi28", "msi29", "msi30", "msi31"; -+ -+ }; -+ -+}; -diff --git a/arch/riscv/boot/dts/sophgo/mango.dtsi b/arch/riscv/boot/dts/sophgo/mango.dtsi -new file mode 100644 -index 000000000000..9ac0898b0906 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/mango.dtsi -@@ -0,0 +1,941 @@ -+/dts-v1/; -+#include <dt-bindings/clock/sophgo.h> -+#include <dt-bindings/clock/sophgo-mango-clock.h> -+#include <dt-bindings/gpio/gpio.h> -+#include <dt-bindings/input/input.h> -+#include <dt-bindings/reset/sophgo-mango-resets.h> -+#include <dt-bindings/interrupt-controller/irq.h> -+ -+#include "mango-cpus-socket0.dtsi" -+#include "mango-clock-socket0.dtsi" -+#include "mango-pinctrl.dtsi" -+ -+#define SOC_PERIPHERAL_IRQ(nr) (nr) -+ -+/ { -+ model = "Sophgo Mango"; -+ compatible = "sophgo,mango"; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ dma-noncoherent; -+ -+ distance-map { -+ compatible = "numa-distance-map-v1"; -+ distance-matrix = <0 0 10>, -+ <0 1 15>, -+ <0 2 25>, -+ <0 3 30>, -+ <1 0 15>, -+ <1 1 10>, -+ <1 2 30>, -+ <1 3 25>, -+ <2 0 25>, -+ <2 1 30>, -+ <2 2 10>, -+ <2 3 15>, -+ <3 0 30>, -+ <3 1 25>, -+ <3 2 15>, -+ <3 3 10>; -+ }; -+ -+ pmu { -+ compatible = "riscv,pmu"; -+ riscv,event-to-mhpmevent = -+ <0x00003 0x00000000 0x00000010>, -+ <0x00004 0x00000000 0x00000011>, -+ <0x00005 0x00000000 0x00000007>, -+ <0x00006 0x00000000 0x00000006>, -+ <0x00008 0x00000000 0x00000027>, -+ <0x00009 0x00000000 0x00000028>, -+ <0x10000 0x00000000 0x0000000c>, -+ <0x10001 0x00000000 0x0000000d>, -+ <0x10002 0x00000000 0x0000000e>, -+ <0x10003 0x00000000 0x0000000f>, -+ <0x10008 0x00000000 0x00000001>, -+ <0x10009 0x00000000 0x00000002>, -+ <0x10010 0x00000000 0x00000010>, -+ <0x10011 0x00000000 0x00000011>, -+ <0x10012 0x00000000 0x00000012>, -+ <0x10013 0x00000000 0x00000013>, -+ <0x10019 0x00000000 0x00000004>, -+ <0x10021 0x00000000 0x00000003>, -+ <0x10030 0x00000000 0x0000001c>, -+ <0x10031 0x00000000 0x0000001b>; -+ riscv,event-to-mhpmcounters = -+ <0x00003 0x00003 0xfffffff8>, -+ <0x00004 0x00004 0xfffffff8>, -+ <0x00005 0x00005 0xfffffff8>, -+ <0x00006 0x00006 0xfffffff8>, -+ <0x00007 0x00007 0xfffffff8>, -+ <0x00008 0x00008 0xfffffff8>, -+ <0x00009 0x00009 0xfffffff8>, -+ <0x0000a 0x0000a 0xfffffff8>, -+ <0x10000 0x10000 0xfffffff8>, -+ <0x10001 0x10001 0xfffffff8>, -+ <0x10002 0x10002 0xfffffff8>, -+ <0x10003 0x10003 0xfffffff8>, -+ <0x10008 0x10008 0xfffffff8>, -+ <0x10009 0x10009 0xfffffff8>, -+ <0x10010 0x10010 0xfffffff8>, -+ <0x10011 0x10011 0xfffffff8>, -+ <0x10012 0x10012 0xfffffff8>, -+ <0x10013 0x10013 0xfffffff8>, -+ <0x10019 0x10019 0xfffffff8>, -+ <0x10021 0x10021 0xfffffff8>, -+ <0x10030 0x10030 0xfffffff8>, -+ <0x10031 0x10031 0xfffffff8>; -+ riscv,raw-event-to-mhpmcounters = -+ <0x00000000 0x00000001 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000002 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000003 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000004 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000005 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000006 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000007 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000008 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000009 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000000a 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000000b 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000000c 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000000d 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000000e 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000000f 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000010 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000011 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000012 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000013 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000014 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000015 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000016 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000017 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000018 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000019 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000001a 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000001b 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000001c 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000001d 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000001e 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000001f 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000020 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000021 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000022 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000023 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000024 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000025 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000026 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000027 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000028 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x00000029 0xffffffff 0xffffffff 0xfffffff8>, -+ <0x00000000 0x0000002a 0xffffffff 0xffffffff 0xfffffff8>; -+ }; -+ -+ soc: soc { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ compatible = "simple-bus"; -+ ranges; -+ dma-ranges = <0x0 0x0 0x0 0x0 0x1f 0x0>; -+ -+ clint_mswi: clint-mswi@7094000000 { -+ compatible = "thead,c900-clint-mswi"; -+ reg = <0x00000070 0x94000000 0x00000000 0x00004000>; -+ interrupts-extended = < -+ &cpu0_intc 3 -+ &cpu1_intc 3 -+ &cpu2_intc 3 -+ &cpu3_intc 3 -+ &cpu4_intc 3 -+ &cpu5_intc 3 -+ &cpu6_intc 3 -+ &cpu7_intc 3 -+ &cpu8_intc 3 -+ &cpu9_intc 3 -+ &cpu10_intc 3 -+ &cpu11_intc 3 -+ &cpu12_intc 3 -+ &cpu13_intc 3 -+ &cpu14_intc 3 -+ &cpu15_intc 3 -+ &cpu16_intc 3 -+ &cpu17_intc 3 -+ &cpu18_intc 3 -+ &cpu19_intc 3 -+ &cpu20_intc 3 -+ &cpu21_intc 3 -+ &cpu22_intc 3 -+ &cpu23_intc 3 -+ &cpu24_intc 3 -+ &cpu25_intc 3 -+ &cpu26_intc 3 -+ &cpu27_intc 3 -+ &cpu28_intc 3 -+ &cpu29_intc 3 -+ &cpu30_intc 3 -+ &cpu31_intc 3 -+ &cpu32_intc 3 -+ &cpu33_intc 3 -+ &cpu34_intc 3 -+ &cpu35_intc 3 -+ &cpu36_intc 3 -+ &cpu37_intc 3 -+ &cpu38_intc 3 -+ &cpu39_intc 3 -+ &cpu40_intc 3 -+ &cpu41_intc 3 -+ &cpu42_intc 3 -+ &cpu43_intc 3 -+ &cpu44_intc 3 -+ &cpu45_intc 3 -+ &cpu46_intc 3 -+ &cpu47_intc 3 -+ &cpu48_intc 3 -+ &cpu49_intc 3 -+ &cpu50_intc 3 -+ &cpu51_intc 3 -+ &cpu52_intc 3 -+ &cpu53_intc 3 -+ &cpu54_intc 3 -+ &cpu55_intc 3 -+ &cpu56_intc 3 -+ &cpu57_intc 3 -+ &cpu58_intc 3 -+ &cpu59_intc 3 -+ &cpu60_intc 3 -+ &cpu61_intc 3 -+ &cpu62_intc 3 -+ &cpu63_intc 3 -+ >; -+ }; -+ -+ clint_mtimer0: clint-mtimer@70ac000000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu0_intc 7 -+ &cpu1_intc 7 -+ &cpu2_intc 7 -+ &cpu3_intc 7 -+ >; -+ }; -+ -+ clint_mtimer1: clint-mtimer@70ac010000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu4_intc 7 -+ &cpu5_intc 7 -+ &cpu6_intc 7 -+ &cpu7_intc 7 -+ >; -+ }; -+ -+ clint_mtimer2: clint-mtimer@70ac020000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu8_intc 7 -+ &cpu9_intc 7 -+ &cpu10_intc 7 -+ &cpu11_intc 7 -+ >; -+ }; -+ -+ clint_mtimer3: clint-mtimer@70ac030000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu12_intc 7 -+ &cpu13_intc 7 -+ &cpu14_intc 7 -+ &cpu15_intc 7 -+ >; -+ }; -+ -+ clint_mtimer4: clint-mtimer@70ac040000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu16_intc 7 -+ &cpu17_intc 7 -+ &cpu18_intc 7 -+ &cpu19_intc 7 -+ >; -+ }; -+ -+ clint_mtimer5: clint-mtimer@70ac050000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu20_intc 7 -+ &cpu21_intc 7 -+ &cpu22_intc 7 -+ &cpu23_intc 7 -+ >; -+ }; -+ -+ clint_mtimer6: clint-mtimer@70ac060000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu24_intc 7 -+ &cpu25_intc 7 -+ &cpu26_intc 7 -+ &cpu27_intc 7 -+ >; -+ }; -+ -+ clint_mtimer7: clint-mtimer@70ac070000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu28_intc 7 -+ &cpu29_intc 7 -+ &cpu30_intc 7 -+ &cpu31_intc 7 -+ >; -+ }; -+ -+ clint_mtimer8: clint-mtimer@70ac080000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu32_intc 7 -+ &cpu33_intc 7 -+ &cpu34_intc 7 -+ &cpu35_intc 7 -+ >; -+ }; -+ -+ clint_mtimer9: clint-mtimer@70ac090000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu36_intc 7 -+ &cpu37_intc 7 -+ &cpu38_intc 7 -+ &cpu39_intc 7 -+ >; -+ }; -+ -+ clint_mtimer10: clint-mtimer@70ac0a0000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu40_intc 7 -+ &cpu41_intc 7 -+ &cpu42_intc 7 -+ &cpu43_intc 7 -+ >; -+ }; -+ -+ clint_mtimer11: clint-mtimer@70ac0b0000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu44_intc 7 -+ &cpu45_intc 7 -+ &cpu46_intc 7 -+ &cpu47_intc 7 -+ >; -+ }; -+ -+ clint_mtimer12: clint-mtimer@70ac0c0000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu48_intc 7 -+ &cpu49_intc 7 -+ &cpu50_intc 7 -+ &cpu51_intc 7 -+ >; -+ }; -+ -+ clint_mtimer13: clint-mtimer@70ac0d0000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu52_intc 7 -+ &cpu53_intc 7 -+ &cpu54_intc 7 -+ &cpu55_intc 7 -+ >; -+ }; -+ -+ clint_mtimer14: clint-mtimer@70ac0e0000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu56_intc 7 -+ &cpu57_intc 7 -+ &cpu58_intc 7 -+ &cpu59_intc 7 -+ >; -+ }; -+ -+ clint_mtimer15: clint-mtimer@70ac0f0000 { -+ compatible = "thead,c900-clint-mtimer"; -+ reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>; -+ interrupts-extended = < -+ &cpu60_intc 7 -+ &cpu61_intc 7 -+ &cpu62_intc 7 -+ &cpu63_intc 7 -+ >; -+ }; -+ -+ intc: interrupt-controller@7090000000 { -+ #address-cells = <0>; -+ #interrupt-cells = <2>; -+ compatible = "thead,c900-plic"; -+ interrupt-controller; -+ interrupts-extended = < -+ &cpu0_intc 11 &cpu0_intc 9 -+ &cpu1_intc 11 &cpu1_intc 9 -+ &cpu2_intc 11 &cpu2_intc 9 -+ &cpu3_intc 11 &cpu3_intc 9 -+ &cpu4_intc 11 &cpu4_intc 9 -+ &cpu5_intc 11 &cpu5_intc 9 -+ &cpu6_intc 11 &cpu6_intc 9 -+ &cpu7_intc 11 &cpu7_intc 9 -+ &cpu8_intc 11 &cpu8_intc 9 -+ &cpu9_intc 11 &cpu9_intc 9 -+ &cpu10_intc 11 &cpu10_intc 9 -+ &cpu11_intc 11 &cpu11_intc 9 -+ &cpu12_intc 11 &cpu12_intc 9 -+ &cpu13_intc 11 &cpu13_intc 9 -+ &cpu14_intc 11 &cpu14_intc 9 -+ &cpu15_intc 11 &cpu15_intc 9 -+ &cpu16_intc 11 &cpu16_intc 9 -+ &cpu17_intc 11 &cpu17_intc 9 -+ &cpu18_intc 11 &cpu18_intc 9 -+ &cpu19_intc 11 &cpu19_intc 9 -+ &cpu20_intc 11 &cpu20_intc 9 -+ &cpu21_intc 11 &cpu21_intc 9 -+ &cpu22_intc 11 &cpu22_intc 9 -+ &cpu23_intc 11 &cpu23_intc 9 -+ &cpu24_intc 11 &cpu24_intc 9 -+ &cpu25_intc 11 &cpu25_intc 9 -+ &cpu26_intc 11 &cpu26_intc 9 -+ &cpu27_intc 11 &cpu27_intc 9 -+ &cpu28_intc 11 &cpu28_intc 9 -+ &cpu29_intc 11 &cpu29_intc 9 -+ &cpu30_intc 11 &cpu30_intc 9 -+ &cpu31_intc 11 &cpu31_intc 9 -+ &cpu32_intc 11 &cpu32_intc 9 -+ &cpu33_intc 11 &cpu33_intc 9 -+ &cpu34_intc 11 &cpu34_intc 9 -+ &cpu35_intc 11 &cpu35_intc 9 -+ &cpu36_intc 11 &cpu36_intc 9 -+ &cpu37_intc 11 &cpu37_intc 9 -+ &cpu38_intc 11 &cpu38_intc 9 -+ &cpu39_intc 11 &cpu39_intc 9 -+ &cpu40_intc 11 &cpu40_intc 9 -+ &cpu41_intc 11 &cpu41_intc 9 -+ &cpu42_intc 11 &cpu42_intc 9 -+ &cpu43_intc 11 &cpu43_intc 9 -+ &cpu44_intc 11 &cpu44_intc 9 -+ &cpu45_intc 11 &cpu45_intc 9 -+ &cpu46_intc 11 &cpu46_intc 9 -+ &cpu47_intc 11 &cpu47_intc 9 -+ &cpu48_intc 11 &cpu48_intc 9 -+ &cpu49_intc 11 &cpu49_intc 9 -+ &cpu50_intc 11 &cpu50_intc 9 -+ &cpu51_intc 11 &cpu51_intc 9 -+ &cpu52_intc 11 &cpu52_intc 9 -+ &cpu53_intc 11 &cpu53_intc 9 -+ &cpu54_intc 11 &cpu54_intc 9 -+ &cpu55_intc 11 &cpu55_intc 9 -+ &cpu56_intc 11 &cpu56_intc 9 -+ &cpu57_intc 11 &cpu57_intc 9 -+ &cpu58_intc 11 &cpu58_intc 9 -+ &cpu59_intc 11 &cpu59_intc 9 -+ &cpu60_intc 11 &cpu60_intc 9 -+ &cpu61_intc 11 &cpu61_intc 9 -+ &cpu62_intc 11 &cpu62_intc 9 -+ &cpu63_intc 11 &cpu63_intc 9 -+ >; -+ reg = <0x00000070 0x90000000 0x00000000 0x04000000>; -+ reg-names = "control"; -+ riscv,max-priority = <7>; -+ riscv,ndev = <224>; -+ }; -+ -+ timer0: dw-apb-timer0@7030003000 { -+ compatible = "snps,dw-apb-timer"; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_LEVEL_HIGH>; -+ reg = <0x70 0x30003000 0x0 0x14>; -+ clocks = <&div_clk GATE_CLK_TIMER1>, -+ <&div_clk GATE_CLK_APB_TIMER>; -+ clock-names = "timer", "pclk"; -+ clk-drv-rating = <300>; -+ }; -+ -+ timer1: dw-apb-timer1@7030003014 { -+ compatible = "snps,dw-apb-timer"; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_LEVEL_HIGH>; -+ reg = <0x70 0x30003014 0x0 0x10>; -+ clocks = <&div_clk GATE_CLK_TIMER2>, -+ <&div_clk GATE_CLK_APB_TIMER>; -+ clock-names = "timer", "pclk"; -+ clk-drv-rating = <300>; -+ }; -+ -+ top_misc: top_misc_ctrl@7030010000 { -+ compatible = "syscon"; -+ reg = <0x70 0x30010000 0x0 0x8000>; -+ }; -+ -+ rst: reset-controller { -+ #reset-cells = <1>; -+ compatible = "bitmain,reset"; -+ subctrl-syscon = <&top_misc>; -+ top_rst_offset = <0x3000>; -+ nr_resets = <RST_MAX_NUM>; -+ }; -+ -+ i2c0: i2c@7030005000 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "snps,designware-i2c"; -+ clocks = <&div_clk GATE_CLK_APB_I2C>; -+ clock-names = "clk_gate_apb_i2c"; -+ reg = <0x70 0x30005000 0x0 0x1000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(101) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <100000>; -+ resets = <&rst RST_I2C0>; -+ reset-names = "i2c0"; -+ }; -+ -+ i2c1: i2c@7030006000 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "snps,designware-i2c"; -+ clocks = <&div_clk GATE_CLK_APB_I2C>; -+ clock-names = "clk_gate_apb_i2c"; -+ reg = <0x70 0x30006000 0x0 0x1000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(102) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <100000>; -+ resets = <&rst RST_I2C1>; -+ reset-names = "i2c1"; -+ }; -+ -+ i2c2: i2c@7030007000 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "snps,designware-i2c"; -+ clocks = <&div_clk GATE_CLK_APB_I2C>; -+ clock-names = "clk_gate_apb_i2c"; -+ reg = <0x70 0x30007000 0x0 0x1000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(103) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <100000>; -+ resets = <&rst RST_I2C2>; -+ reset-names = "i2c2"; -+ }; -+ -+ i2c3: i2c@7030008000 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "snps,designware-i2c"; -+ clocks = <&div_clk GATE_CLK_APB_I2C>; -+ clock-names = "clk_gate_apb_i2c"; -+ reg = <0x70 0x30008000 0x0 0x1000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(104) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <100000>; -+ resets = <&rst RST_I2C3>; -+ reset-names = "i2c3"; -+ }; -+ -+ gpio0: gpio@7030009000 { -+ compatible = "snps,dw-apb-gpio"; -+ reg = <0x70 0x30009000 0x0 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&div_clk GATE_CLK_APB_GPIO>, -+ <&div_clk GATE_CLK_APB_GPIO_INTR>, -+ <&div_clk GATE_CLK_GPIO_DB>; -+ clock-names = "base_clk", "intr_clk", "db_clk"; -+ -+ port0a: gpio-controller@0 { -+ compatible = "snps,dw-apb-gpio-port"; -+ bank-name = "port0a"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ snps,nr-gpios = <32>; -+ reg = <0>; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(96) IRQ_TYPE_LEVEL_HIGH>; -+ }; -+ }; -+ -+ gpio1: gpio@703000a000 { -+ compatible = "snps,dw-apb-gpio"; -+ reg = <0x70 0x3000a000 0x0 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&div_clk GATE_CLK_APB_GPIO>, -+ <&div_clk GATE_CLK_APB_GPIO_INTR>, -+ <&div_clk GATE_CLK_GPIO_DB>; -+ clock-names = "base_clk", "intr_clk", "db_clk"; -+ -+ port1a: gpio-controller@0 { -+ compatible = "snps,dw-apb-gpio-port"; -+ bank-name = "port0a"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ snps,nr-gpios = <32>; -+ reg = <0>; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(97) IRQ_TYPE_LEVEL_HIGH>; -+ }; -+ }; -+ -+ gpio2: gpio@703000b000 { -+ compatible = "snps,dw-apb-gpio"; -+ reg = <0x70 0x3000b000 0x0 0x400>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ clocks = <&div_clk GATE_CLK_APB_GPIO>, -+ <&div_clk GATE_CLK_APB_GPIO_INTR>, -+ <&div_clk GATE_CLK_GPIO_DB>; -+ clock-names = "base_clk", "intr_clk", "db_clk"; -+ -+ port2a: gpio-controller@0 { -+ compatible = "snps,dw-apb-gpio-port"; -+ bank-name = "port0a"; -+ gpio-controller; -+ #gpio-cells = <2>; -+ snps,nr-gpios = <32>; -+ reg = <0>; -+ interrupt-controller; -+ #interrupt-cells = <2>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(98) IRQ_TYPE_LEVEL_HIGH>; -+ }; -+ }; -+ -+ pwm: pwm@703000C000 { -+ compatible = "sophgo,sophgo-pwm"; -+ reg = <0x70 0x3000C000 0x0 0x20>; -+ clocks = <&div_clk GATE_CLK_APB_PWM>; -+ clock-names = "clk_gate_apb_pwm"; -+ #pwm-cells = <2>; -+ pwm-num = <2>; -+ no-polarity; -+ }; -+ -+ tach0: tach@703000C020 { -+ compatible = "sophgo,sophgo-tach"; -+ reg = <0x70 0x3000C020 0x0 0x8>; -+ }; -+ -+ tach1: tach@703000C028 { -+ compatible = "sophgo,sophgo-tach"; -+ reg = <0x70 0x3000C028 0x0 0x8>; -+ }; -+ -+ uart0: serial@7040000000 { -+ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; -+ reg = <0x00000070 0x40000000 0x00000000 0x00001000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(112) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <500000000>; -+ clocks = <&div_clk GATE_CLK_UART_500M>, -+ <&div_clk GATE_CLK_APB_UART>; -+ clock-names = "baudclk", "apb_pclk"; -+ reg-shift = <2>; -+ reg-io-width = <4>; -+ }; -+ -+ uart1: serial@7040001000 { -+ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; -+ reg = <0x00000070 0x40001000 0x00000000 0x00001000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(113) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <500000000>; -+ clocks = <&div_clk GATE_CLK_UART_500M>, -+ <&div_clk GATE_CLK_APB_UART>; -+ clock-names = "baudclk", "apb_pclk"; -+ reg-shift = <2>; -+ reg-io-width = <4>; -+ }; -+ -+ uart2: serial@7040002000 { -+ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; -+ reg = <0x00000070 0x40002000 0x00000000 0x00001000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(114) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <500000000>; -+ clocks = <&div_clk GATE_CLK_UART_500M>, -+ <&div_clk GATE_CLK_APB_UART>; -+ clock-names = "baudclk", "apb_pclk"; -+ reg-shift = <2>; -+ reg-io-width = <4>; -+ }; -+ -+ uart3: serial@7040003000 { -+ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; -+ reg = <0x00000070 0x40003000 0x00000000 0x00001000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(115) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <500000000>; -+ clocks = <&div_clk GATE_CLK_UART_500M>, -+ <&div_clk GATE_CLK_APB_UART>; -+ clock-names = "baudclk", "apb_pclk"; -+ reg-shift = <2>; -+ reg-io-width = <4>; -+ }; -+ -+ emmc: bm-emmc@704002A000 { -+ compatible = "bitmain,bm-emmc"; -+ reg = <0x70 0x4002A000 0x0 0x1000>; -+ reg-names = "core_mem"; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(134) IRQ_TYPE_LEVEL_HIGH>; -+ bus-width = <4>; -+ non-removable; -+ no-sdio; -+ no-sd; -+ resets = <&rst RST_EMMC>; -+ reset-names = "emmc"; -+ clocks = -+ <&div_clk GATE_CLK_EMMC_100M>, -+ <&div_clk GATE_CLK_AXI_EMMC>, -+ <&div_clk GATE_CLK_100K_EMMC>; -+ clock-names = -+ "clk_gate_emmc", -+ "clk_gate_axi_emmc", -+ "clk_gate_100k_emmc"; -+ }; -+ -+ sd: bm-sd@704002B000 { -+ compatible = "bitmain,bm-sd"; -+ reg = <0x70 0x4002B000 0x0 0x1000>; -+ reg-names = "core_mem"; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(136) IRQ_TYPE_LEVEL_HIGH>; -+ bus-width = <4>; -+ no-sdio; -+ no-mmc; -+ resets = <&rst RST_SD>; -+ reset-names = "sdio"; -+ clocks = -+ <&div_clk GATE_CLK_SD_100M>, -+ <&div_clk GATE_CLK_AXI_SD>, -+ <&div_clk GATE_CLK_100K_SD>; -+ clock-names = -+ "clk_gate_sd", -+ "clk_gate_axi_sd", -+ "clk_gate_100k_sd"; -+ }; -+ -+ spifmc0: flash-controller@7000180000 { -+ compatible = "sophgo,spifmc"; -+ reg = <0x70 0x00180000 0x0 0x1000000>; -+ reg-names = "memory"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(108) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <100000000>; -+ clocks = <&div_clk GATE_CLK_AHB_SF>; -+ flash@0 { -+ reg = <0>; -+ compatible = "jedec,spi-nor"; -+ }; -+ }; -+ -+ spifmc1: flash-controller@7002180000 { -+ compatible = "sophgo,spifmc"; -+ reg = <0x70 0x02180000 0x0 0x1000000>; -+ reg-names = "memory"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(109) IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <100000000>; -+ clocks = <&div_clk GATE_CLK_AHB_SF>; -+ flash@0 { -+ reg = <0>; -+ compatible = "jedec,spi-nor"; -+ }; -+ }; -+ -+ spi0: spi@7040004000 { -+ compatible = "snps,dw-apb-ssi"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <0x70 0x40004000 0x0 0x1000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(110) IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&div_clk GATE_CLK_APB_SPI>, -+ <&div_clk GATE_CLK_SYSDMA_AXI>; -+ clock-frequency = <250000000>; -+ resets = <&rst RST_SPI0>; -+ reset-names = "spi0"; -+ num-cs = <2>; -+ status = "okay"; -+ }; -+ -+ spi1: spi@7040005000 { -+ compatible = "snps,dw-apb-ssi"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <0x70 0x40005000 0x0 0x1000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(111) IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&div_clk GATE_CLK_APB_SPI>, -+ <&div_clk GATE_CLK_SYSDMA_AXI>; -+ clock-frequency = <250000000>; -+ resets = <&rst RST_SPI1>; -+ reset-names = "spi1"; -+ num-cs = <2>; -+ status = "okay"; -+ }; -+ -+ stmmac_axi_setup: stmmac-axi-config { -+ snps,wr_osr_lmt = <1>; -+ snps,rd_osr_lmt = <2>; -+ snps,blen = <4 8 16 0 0 0 0>; -+ }; -+ -+ mtl_rx_setup: rx-queues-config { -+ snps,rx-queues-to-use = <8>; -+ queue0 {}; -+ queue1 {}; -+ queue2 {}; -+ queue3 {}; -+ queue4 {}; -+ queue5 {}; -+ queue6 {}; -+ queue7 {}; -+ }; -+ -+ mtl_tx_setup: tx-queues-config { -+ snps,tx-queues-to-use = <8>; -+ queue0 {}; -+ queue1 {}; -+ queue2 {}; -+ queue3 {}; -+ queue4 {}; -+ queue5 {}; -+ queue6 {}; -+ queue7 {}; -+ }; -+ -+ ethernet0: ethernet@7040026000 { -+ compatible = "bitmain,ethernet"; -+ reg = <0x70 0x40026000 0x0 0x4000>; -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(132) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "macirq"; -+ clock-names = "clk_tx", "gate_clk_tx", "stmmaceth", "ptp_ref", "gate_clk_ref"; -+ clocks = <&div_clk DIV_CLK_FPLL_TX_ETH0>, -+ <&div_clk GATE_CLK_TX_ETH0>, -+ <&div_clk GATE_CLK_AXI_ETH0>, -+ <&div_clk GATE_CLK_PTP_REF_I_ETH0>, -+ <&div_clk GATE_CLK_REF_ETH0>; -+ -+ /* no hash filter and perfect filter support */ -+ snps,multicast-filter-bins = <0>; -+ snps,perfect-filter-entries = <1>; -+ -+ snps,txpbl = <32>; -+ snps,rxpbl = <32>; -+ snps,aal; -+ -+ snps,axi-config = <&stmmac_axi_setup>; -+ snps,mtl-rx-config = <&mtl_rx_setup>; -+ snps,mtl-tx-config = <&mtl_tx_setup>; -+ -+ phy-mode = "rgmii-txid"; -+ phy-reset-gpios = <&port0a 27 0>; -+ phy-handle = <&phy0>; -+ mdio { -+ #address-cells = <0x1>; -+ #size-cells = <0x0>; -+ compatible = "snps,dwmac-mdio"; -+ phy0: phy@0 { -+ compatible = "ethernet-phy-ieee802.3-c22"; -+ device_type = "ethernet-phy"; -+ reg = <0x0>; -+ }; -+ }; -+ }; -+ }; -+ -+ intc1: top_intc@7030010300 { -+ compatible = "sophgo,top-intc"; -+ reg = <0x70 0x300102E0 0x0 0x4>, -+ <0x70 0x30010300 0x0 0x4>, -+ <0x70 0x30010304 0x0 0x4>; -+ reg-names = "sta", "set", "clr"; -+ reg-bitwidth = <32>; -+ top_intc_id = <0>; -+ interrupt-controller; -+ #interrupt-cells = <0x1>; // only applies to child node -+ for-msi; -+ -+ interrupt-parent = <&intc>; -+ interrupts = <SOC_PERIPHERAL_IRQ(64) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(65) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(66) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(67) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(68) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(69) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(70) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(71) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(72) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(73) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(74) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(75) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(76) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(77) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(78) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(79) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(80) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(81) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(82) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(83) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(84) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(85) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(86) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(87) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(88) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(89) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(90) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(91) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(92) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(93) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(94) IRQ_TYPE_LEVEL_HIGH>, -+ <SOC_PERIPHERAL_IRQ(95) IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "msi0", "msi1", "msi2", "msi3", -+ "msi4", "msi5", "msi6", "msi7", -+ "msi8", "msi9", "msi10", "msi11", -+ "msi12", "msi13", "msi14", "msi15", -+ "msi16", "msi17", "msi18", "msi19", -+ "msi20", "msi21", "msi22", "msi23", -+ "msi24", "msi25", "msi26", "msi27", -+ "msi28", "msi29", "msi30", "msi31"; -+ -+ }; -+ -+ aliases { -+ serial0 = &uart0; -+ }; -+ -+ chosen: chosen { -+ bootargs = "console=ttyS0,115200 earlycon maxcpus=1"; -+ stdout-path = "serial0"; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi b/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi -new file mode 100644 -index 000000000000..b136b6c4128c ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi -@@ -0,0 +1,2000 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR MIT) -+/* -+ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. -+ */ -+ -+/ { -+ cpus { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ timebase-frequency = <50000000>; -+ -+ cpu-map { -+ socket0 { -+ cluster0 { -+ core0 { -+ cpu = <&cpu0>; -+ }; -+ core1 { -+ cpu = <&cpu1>; -+ }; -+ core2 { -+ cpu = <&cpu2>; -+ }; -+ core3 { -+ cpu = <&cpu3>; -+ }; -+ }; -+ -+ cluster1 { -+ core0 { -+ cpu = <&cpu4>; -+ }; -+ core1 { -+ cpu = <&cpu5>; -+ }; -+ core2 { -+ cpu = <&cpu6>; -+ }; -+ core3 { -+ cpu = <&cpu7>; -+ }; -+ }; -+ -+ cluster2 { -+ core0 { -+ cpu = <&cpu16>; -+ }; -+ core1 { -+ cpu = <&cpu17>; -+ }; -+ core2 { -+ cpu = <&cpu18>; -+ }; -+ core3 { -+ cpu = <&cpu19>; -+ }; -+ }; -+ -+ cluster3 { -+ core0 { -+ cpu = <&cpu20>; -+ }; -+ core1 { -+ cpu = <&cpu21>; -+ }; -+ core2 { -+ cpu = <&cpu22>; -+ }; -+ core3 { -+ cpu = <&cpu23>; -+ }; -+ }; -+ -+ cluster4 { -+ core0 { -+ cpu = <&cpu8>; -+ }; -+ core1 { -+ cpu = <&cpu9>; -+ }; -+ core2 { -+ cpu = <&cpu10>; -+ }; -+ core3 { -+ cpu = <&cpu11>; -+ }; -+ }; -+ -+ cluster5 { -+ core0 { -+ cpu = <&cpu12>; -+ }; -+ core1 { -+ cpu = <&cpu13>; -+ }; -+ core2 { -+ cpu = <&cpu14>; -+ }; -+ core3 { -+ cpu = <&cpu15>; -+ }; -+ }; -+ -+ cluster6 { -+ core0 { -+ cpu = <&cpu24>; -+ }; -+ core1 { -+ cpu = <&cpu25>; -+ }; -+ core2 { -+ cpu = <&cpu26>; -+ }; -+ core3 { -+ cpu = <&cpu27>; -+ }; -+ }; -+ -+ cluster7 { -+ core0 { -+ cpu = <&cpu28>; -+ }; -+ core1 { -+ cpu = <&cpu29>; -+ }; -+ core2 { -+ cpu = <&cpu30>; -+ }; -+ core3 { -+ cpu = <&cpu31>; -+ }; -+ }; -+ -+ cluster8 { -+ core0 { -+ cpu = <&cpu32>; -+ }; -+ core1 { -+ cpu = <&cpu33>; -+ }; -+ core2 { -+ cpu = <&cpu34>; -+ }; -+ core3 { -+ cpu = <&cpu35>; -+ }; -+ }; -+ -+ cluster9 { -+ core0 { -+ cpu = <&cpu36>; -+ }; -+ core1 { -+ cpu = <&cpu37>; -+ }; -+ core2 { -+ cpu = <&cpu38>; -+ }; -+ core3 { -+ cpu = <&cpu39>; -+ }; -+ }; -+ -+ cluster10 { -+ core0 { -+ cpu = <&cpu48>; -+ }; -+ core1 { -+ cpu = <&cpu49>; -+ }; -+ core2 { -+ cpu = <&cpu50>; -+ }; -+ core3 { -+ cpu = <&cpu51>; -+ }; -+ }; -+ -+ cluster11 { -+ core0 { -+ cpu = <&cpu52>; -+ }; -+ core1 { -+ cpu = <&cpu53>; -+ }; -+ core2 { -+ cpu = <&cpu54>; -+ }; -+ core3 { -+ cpu = <&cpu55>; -+ }; -+ }; -+ -+ cluster12 { -+ core0 { -+ cpu = <&cpu40>; -+ }; -+ core1 { -+ cpu = <&cpu41>; -+ }; -+ core2 { -+ cpu = <&cpu42>; -+ }; -+ core3 { -+ cpu = <&cpu43>; -+ }; -+ }; -+ -+ cluster13 { -+ core0 { -+ cpu = <&cpu44>; -+ }; -+ core1 { -+ cpu = <&cpu45>; -+ }; -+ core2 { -+ cpu = <&cpu46>; -+ }; -+ core3 { -+ cpu = <&cpu47>; -+ }; -+ }; -+ -+ cluster14 { -+ core0 { -+ cpu = <&cpu56>; -+ }; -+ core1 { -+ cpu = <&cpu57>; -+ }; -+ core2 { -+ cpu = <&cpu58>; -+ }; -+ core3 { -+ cpu = <&cpu59>; -+ }; -+ }; -+ -+ cluster15 { -+ core0 { -+ cpu = <&cpu60>; -+ }; -+ core1 { -+ cpu = <&cpu61>; -+ }; -+ core2 { -+ cpu = <&cpu62>; -+ }; -+ core3 { -+ cpu = <&cpu63>; -+ }; -+ }; -+ }; -+ }; -+ -+ cpu0: cpu@0 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <0>; -+ 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 = <&l2_cache0>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu0_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu1: cpu@1 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <1>; -+ 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 = <&l2_cache0>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu1_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu2: cpu@2 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <2>; -+ 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 = <&l2_cache0>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu2_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu3: cpu@3 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <3>; -+ 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 = <&l2_cache0>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu3_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu4: cpu@4 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <4>; -+ 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 = <&l2_cache1>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu4_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu5: cpu@5 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <5>; -+ 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 = <&l2_cache1>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu5_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu6: cpu@6 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <6>; -+ 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 = <&l2_cache1>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu6_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu7: cpu@7 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <7>; -+ 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 = <&l2_cache1>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu7_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu8: cpu@8 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <8>; -+ 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 = <&l2_cache4>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu8_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu9: cpu@9 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <9>; -+ 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 = <&l2_cache4>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu9_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu10: cpu@10 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <10>; -+ 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 = <&l2_cache4>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu10_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu11: cpu@11 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <11>; -+ 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 = <&l2_cache4>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu11_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu12: cpu@12 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <12>; -+ 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 = <&l2_cache5>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu12_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu13: cpu@13 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <13>; -+ 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 = <&l2_cache5>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu13_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu14: cpu@14 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <14>; -+ 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 = <&l2_cache5>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu14_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu15: cpu@15 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <15>; -+ 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 = <&l2_cache5>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu15_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu16: cpu@16 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <16>; -+ 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 = <&l2_cache2>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu16_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu17: cpu@17 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <17>; -+ 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 = <&l2_cache2>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu17_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu18: cpu@18 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <18>; -+ 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 = <&l2_cache2>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu18_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu19: cpu@19 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <19>; -+ 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 = <&l2_cache2>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu19_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu20: cpu@20 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <20>; -+ 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 = <&l2_cache3>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu20_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu21: cpu@21 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <21>; -+ 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 = <&l2_cache3>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu21_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu22: cpu@22 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <22>; -+ 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 = <&l2_cache3>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu22_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu23: cpu@23 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <23>; -+ 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 = <&l2_cache3>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu23_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu24: cpu@24 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <24>; -+ 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 = <&l2_cache6>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu24_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu25: cpu@25 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <25>; -+ 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 = <&l2_cache6>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu25_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu26: cpu@26 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <26>; -+ 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 = <&l2_cache6>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu26_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu27: cpu@27 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <27>; -+ 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 = <&l2_cache6>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu27_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu28: cpu@28 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <28>; -+ 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 = <&l2_cache7>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu28_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu29: cpu@29 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <29>; -+ 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 = <&l2_cache7>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu29_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu30: cpu@30 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <30>; -+ 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 = <&l2_cache7>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu30_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu31: cpu@31 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <31>; -+ 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 = <&l2_cache7>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu31_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu32: cpu@32 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <32>; -+ 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 = <&l2_cache8>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu32_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu33: cpu@33 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <33>; -+ 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 = <&l2_cache8>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu33_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu34: cpu@34 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <34>; -+ 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 = <&l2_cache8>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu34_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu35: cpu@35 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <35>; -+ 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 = <&l2_cache8>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu35_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu36: cpu@36 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <36>; -+ 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 = <&l2_cache9>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu36_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu37: cpu@37 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <37>; -+ 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 = <&l2_cache9>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu37_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu38: cpu@38 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <38>; -+ 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 = <&l2_cache9>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu38_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu39: cpu@39 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <39>; -+ 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 = <&l2_cache9>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu39_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu40: cpu@40 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <40>; -+ 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 = <&l2_cache12>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu40_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu41: cpu@41 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <41>; -+ 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 = <&l2_cache12>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu41_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu42: cpu@42 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <42>; -+ 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 = <&l2_cache12>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu42_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu43: cpu@43 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <43>; -+ 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 = <&l2_cache12>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu43_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu44: cpu@44 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <44>; -+ 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 = <&l2_cache13>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu44_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu45: cpu@45 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <45>; -+ 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 = <&l2_cache13>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu45_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu46: cpu@46 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <46>; -+ 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 = <&l2_cache13>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu46_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu47: cpu@47 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <47>; -+ 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 = <&l2_cache13>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu47_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu48: cpu@48 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <48>; -+ 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 = <&l2_cache10>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu48_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu49: cpu@49 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <49>; -+ 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 = <&l2_cache10>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu49_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu50: cpu@50 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <50>; -+ 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 = <&l2_cache10>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu50_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu51: cpu@51 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <51>; -+ 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 = <&l2_cache10>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu51_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu52: cpu@52 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <52>; -+ 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 = <&l2_cache11>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu52_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu53: cpu@53 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <53>; -+ 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 = <&l2_cache11>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu53_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu54: cpu@54 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <54>; -+ 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 = <&l2_cache11>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu54_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu55: cpu@55 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <55>; -+ 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 = <&l2_cache11>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu55_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu56: cpu@56 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <56>; -+ 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 = <&l2_cache14>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu56_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu57: cpu@57 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <57>; -+ 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 = <&l2_cache14>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu57_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu58: cpu@58 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <58>; -+ 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 = <&l2_cache14>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu58_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu59: cpu@59 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <59>; -+ 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 = <&l2_cache14>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu59_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu60: cpu@60 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <60>; -+ 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 = <&l2_cache15>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu60_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu61: cpu@61 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <61>; -+ 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 = <&l2_cache15>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu61_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu62: cpu@62 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <62>; -+ 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 = <&l2_cache15>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu62_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ cpu63: cpu@63 { -+ compatible = "thead,c920", "riscv"; -+ device_type = "cpu"; -+ riscv,isa = "rv64imafdc"; -+ riscv,isa-base = "rv64i"; -+ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", -+ "zicntr", "zicsr", "zifencei", -+ "zihpm"; -+ reg = <63>; -+ 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 = <&l2_cache15>; -+ mmu-type = "riscv,sv39"; -+ -+ cpu63_intc: interrupt-controller { -+ compatible = "riscv,cpu-intc"; -+ interrupt-controller; -+ #interrupt-cells = <1>; -+ }; -+ }; -+ -+ l2_cache0: cache-controller-0 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache1: cache-controller-1 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache2: cache-controller-2 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache3: cache-controller-3 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache4: cache-controller-4 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache5: cache-controller-5 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache6: cache-controller-6 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache7: cache-controller-7 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache8: cache-controller-8 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache9: cache-controller-9 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache10: cache-controller-10 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache11: cache-controller-11 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache12: cache-controller-12 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache13: cache-controller-13 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache14: cache-controller-14 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ -+ l2_cache15: cache-controller-15 { -+ compatible = "cache"; -+ cache-block-size = <64>; -+ cache-level = <2>; -+ cache-size = <1048576>; -+ cache-sets = <1024>; -+ cache-unified; -+ }; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts -new file mode 100644 -index 000000000000..49b4b9c2c101 ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts -@@ -0,0 +1,19 @@ -+// SPDX-License-Identifier: GPL-2.0 OR MIT -+/* -+ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. -+ */ -+ -+#include "sg2042.dtsi" -+ -+/ { -+ model = "Milk-V Pioneer"; -+ compatible = "milkv,pioneer", "sophgo,sg2042"; -+ -+ chosen { -+ stdout-path = "serial0"; -+ }; -+}; -+ -+&uart0 { -+ status = "okay"; -+}; -diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi -new file mode 100644 -index 000000000000..ead1cc35d88b ---- /dev/null -+++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi -@@ -0,0 +1,341 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR MIT) -+/* -+ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. -+ */ -+ -+/dts-v1/; -+#include <dt-bindings/interrupt-controller/irq.h> -+ -+#include "sg2042-cpus.dtsi" -+ -+/ { -+ compatible = "sophgo,sg2042"; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ dma-noncoherent; -+ -+ aliases { -+ serial0 = &uart0; -+ }; -+ -+ soc: soc { -+ compatible = "simple-bus"; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ clint_mswi: interrupt-controller@7094000000 { -+ compatible = "sophgo,sg2042-aclint-mswi", "thead,c900-aclint-mswi"; -+ reg = <0x00000070 0x94000000 0x00000000 0x00004000>; -+ interrupts-extended = <&cpu0_intc 3>, -+ <&cpu1_intc 3>, -+ <&cpu2_intc 3>, -+ <&cpu3_intc 3>, -+ <&cpu4_intc 3>, -+ <&cpu5_intc 3>, -+ <&cpu6_intc 3>, -+ <&cpu7_intc 3>, -+ <&cpu8_intc 3>, -+ <&cpu9_intc 3>, -+ <&cpu10_intc 3>, -+ <&cpu11_intc 3>, -+ <&cpu12_intc 3>, -+ <&cpu13_intc 3>, -+ <&cpu14_intc 3>, -+ <&cpu15_intc 3>, -+ <&cpu16_intc 3>, -+ <&cpu17_intc 3>, -+ <&cpu18_intc 3>, -+ <&cpu19_intc 3>, -+ <&cpu20_intc 3>, -+ <&cpu21_intc 3>, -+ <&cpu22_intc 3>, -+ <&cpu23_intc 3>, -+ <&cpu24_intc 3>, -+ <&cpu25_intc 3>, -+ <&cpu26_intc 3>, -+ <&cpu27_intc 3>, -+ <&cpu28_intc 3>, -+ <&cpu29_intc 3>, -+ <&cpu30_intc 3>, -+ <&cpu31_intc 3>, -+ <&cpu32_intc 3>, -+ <&cpu33_intc 3>, -+ <&cpu34_intc 3>, -+ <&cpu35_intc 3>, -+ <&cpu36_intc 3>, -+ <&cpu37_intc 3>, -+ <&cpu38_intc 3>, -+ <&cpu39_intc 3>, -+ <&cpu40_intc 3>, -+ <&cpu41_intc 3>, -+ <&cpu42_intc 3>, -+ <&cpu43_intc 3>, -+ <&cpu44_intc 3>, -+ <&cpu45_intc 3>, -+ <&cpu46_intc 3>, -+ <&cpu47_intc 3>, -+ <&cpu48_intc 3>, -+ <&cpu49_intc 3>, -+ <&cpu50_intc 3>, -+ <&cpu51_intc 3>, -+ <&cpu52_intc 3>, -+ <&cpu53_intc 3>, -+ <&cpu54_intc 3>, -+ <&cpu55_intc 3>, -+ <&cpu56_intc 3>, -+ <&cpu57_intc 3>, -+ <&cpu58_intc 3>, -+ <&cpu59_intc 3>, -+ <&cpu60_intc 3>, -+ <&cpu61_intc 3>, -+ <&cpu62_intc 3>, -+ <&cpu63_intc 3>; -+ }; -+ -+ clint_mtimer0: timer@70ac004000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac004000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu0_intc 7>, -+ <&cpu1_intc 7>, -+ <&cpu2_intc 7>, -+ <&cpu3_intc 7>; -+ }; -+ -+ clint_mtimer1: timer@70ac014000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac014000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu4_intc 7>, -+ <&cpu5_intc 7>, -+ <&cpu6_intc 7>, -+ <&cpu7_intc 7>; -+ }; -+ -+ clint_mtimer2: timer@70ac024000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac024000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu8_intc 7>, -+ <&cpu9_intc 7>, -+ <&cpu10_intc 7>, -+ <&cpu11_intc 7>; -+ }; -+ -+ clint_mtimer3: timer@70ac034000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac034000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu12_intc 7>, -+ <&cpu13_intc 7>, -+ <&cpu14_intc 7>, -+ <&cpu15_intc 7>; -+ }; -+ -+ clint_mtimer4: timer@70ac044000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac044000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu16_intc 7>, -+ <&cpu17_intc 7>, -+ <&cpu18_intc 7>, -+ <&cpu19_intc 7>; -+ }; -+ -+ clint_mtimer5: timer@70ac054000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac054000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu20_intc 7>, -+ <&cpu21_intc 7>, -+ <&cpu22_intc 7>, -+ <&cpu23_intc 7>; -+ }; -+ -+ clint_mtimer6: timer@70ac064000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac064000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu24_intc 7>, -+ <&cpu25_intc 7>, -+ <&cpu26_intc 7>, -+ <&cpu27_intc 7>; -+ }; -+ -+ clint_mtimer7: timer@70ac074000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac074000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu28_intc 7>, -+ <&cpu29_intc 7>, -+ <&cpu30_intc 7>, -+ <&cpu31_intc 7>; -+ }; -+ -+ clint_mtimer8: timer@70ac084000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac084000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu32_intc 7>, -+ <&cpu33_intc 7>, -+ <&cpu34_intc 7>, -+ <&cpu35_intc 7>; -+ }; -+ -+ clint_mtimer9: timer@70ac094000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac094000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu36_intc 7>, -+ <&cpu37_intc 7>, -+ <&cpu38_intc 7>, -+ <&cpu39_intc 7>; -+ }; -+ -+ clint_mtimer10: timer@70ac0a4000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac0a4000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu40_intc 7>, -+ <&cpu41_intc 7>, -+ <&cpu42_intc 7>, -+ <&cpu43_intc 7>; -+ }; -+ -+ clint_mtimer11: timer@70ac0b4000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac0b4000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu44_intc 7>, -+ <&cpu45_intc 7>, -+ <&cpu46_intc 7>, -+ <&cpu47_intc 7>; -+ }; -+ -+ clint_mtimer12: timer@70ac0c4000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac0c4000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu48_intc 7>, -+ <&cpu49_intc 7>, -+ <&cpu50_intc 7>, -+ <&cpu51_intc 7>; -+ }; -+ -+ clint_mtimer13: timer@70ac0d4000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac0d4000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu52_intc 7>, -+ <&cpu53_intc 7>, -+ <&cpu54_intc 7>, -+ <&cpu55_intc 7>; -+ }; -+ -+ clint_mtimer14: timer@70ac0e4000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac0e4000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu56_intc 7>, -+ <&cpu57_intc 7>, -+ <&cpu58_intc 7>, -+ <&cpu59_intc 7>; -+ }; -+ -+ clint_mtimer15: timer@70ac0f4000 { -+ compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; -+ reg = <0x00000070 0xac0f4000 0x00000000 0x0000c000>; -+ reg-names = "mtimecmp"; -+ interrupts-extended = <&cpu60_intc 7>, -+ <&cpu61_intc 7>, -+ <&cpu62_intc 7>, -+ <&cpu63_intc 7>; -+ }; -+ -+ intc: interrupt-controller@7090000000 { -+ compatible = "sophgo,sg2042-plic", "thead,c900-plic"; -+ #address-cells = <0>; -+ #interrupt-cells = <2>; -+ reg = <0x00000070 0x90000000 0x00000000 0x04000000>; -+ interrupt-controller; -+ interrupts-extended = -+ <&cpu0_intc 11>, <&cpu0_intc 9>, -+ <&cpu1_intc 11>, <&cpu1_intc 9>, -+ <&cpu2_intc 11>, <&cpu2_intc 9>, -+ <&cpu3_intc 11>, <&cpu3_intc 9>, -+ <&cpu4_intc 11>, <&cpu4_intc 9>, -+ <&cpu5_intc 11>, <&cpu5_intc 9>, -+ <&cpu6_intc 11>, <&cpu6_intc 9>, -+ <&cpu7_intc 11>, <&cpu7_intc 9>, -+ <&cpu8_intc 11>, <&cpu8_intc 9>, -+ <&cpu9_intc 11>, <&cpu9_intc 9>, -+ <&cpu10_intc 11>, <&cpu10_intc 9>, -+ <&cpu11_intc 11>, <&cpu11_intc 9>, -+ <&cpu12_intc 11>, <&cpu12_intc 9>, -+ <&cpu13_intc 11>, <&cpu13_intc 9>, -+ <&cpu14_intc 11>, <&cpu14_intc 9>, -+ <&cpu15_intc 11>, <&cpu15_intc 9>, -+ <&cpu16_intc 11>, <&cpu16_intc 9>, -+ <&cpu17_intc 11>, <&cpu17_intc 9>, -+ <&cpu18_intc 11>, <&cpu18_intc 9>, -+ <&cpu19_intc 11>, <&cpu19_intc 9>, -+ <&cpu20_intc 11>, <&cpu20_intc 9>, -+ <&cpu21_intc 11>, <&cpu21_intc 9>, -+ <&cpu22_intc 11>, <&cpu22_intc 9>, -+ <&cpu23_intc 11>, <&cpu23_intc 9>, -+ <&cpu24_intc 11>, <&cpu24_intc 9>, -+ <&cpu25_intc 11>, <&cpu25_intc 9>, -+ <&cpu26_intc 11>, <&cpu26_intc 9>, -+ <&cpu27_intc 11>, <&cpu27_intc 9>, -+ <&cpu28_intc 11>, <&cpu28_intc 9>, -+ <&cpu29_intc 11>, <&cpu29_intc 9>, -+ <&cpu30_intc 11>, <&cpu30_intc 9>, -+ <&cpu31_intc 11>, <&cpu31_intc 9>, -+ <&cpu32_intc 11>, <&cpu32_intc 9>, -+ <&cpu33_intc 11>, <&cpu33_intc 9>, -+ <&cpu34_intc 11>, <&cpu34_intc 9>, -+ <&cpu35_intc 11>, <&cpu35_intc 9>, -+ <&cpu36_intc 11>, <&cpu36_intc 9>, -+ <&cpu37_intc 11>, <&cpu37_intc 9>, -+ <&cpu38_intc 11>, <&cpu38_intc 9>, -+ <&cpu39_intc 11>, <&cpu39_intc 9>, -+ <&cpu40_intc 11>, <&cpu40_intc 9>, -+ <&cpu41_intc 11>, <&cpu41_intc 9>, -+ <&cpu42_intc 11>, <&cpu42_intc 9>, -+ <&cpu43_intc 11>, <&cpu43_intc 9>, -+ <&cpu44_intc 11>, <&cpu44_intc 9>, -+ <&cpu45_intc 11>, <&cpu45_intc 9>, -+ <&cpu46_intc 11>, <&cpu46_intc 9>, -+ <&cpu47_intc 11>, <&cpu47_intc 9>, -+ <&cpu48_intc 11>, <&cpu48_intc 9>, -+ <&cpu49_intc 11>, <&cpu49_intc 9>, -+ <&cpu50_intc 11>, <&cpu50_intc 9>, -+ <&cpu51_intc 11>, <&cpu51_intc 9>, -+ <&cpu52_intc 11>, <&cpu52_intc 9>, -+ <&cpu53_intc 11>, <&cpu53_intc 9>, -+ <&cpu54_intc 11>, <&cpu54_intc 9>, -+ <&cpu55_intc 11>, <&cpu55_intc 9>, -+ <&cpu56_intc 11>, <&cpu56_intc 9>, -+ <&cpu57_intc 11>, <&cpu57_intc 9>, -+ <&cpu58_intc 11>, <&cpu58_intc 9>, -+ <&cpu59_intc 11>, <&cpu59_intc 9>, -+ <&cpu60_intc 11>, <&cpu60_intc 9>, -+ <&cpu61_intc 11>, <&cpu61_intc 9>, -+ <&cpu62_intc 11>, <&cpu62_intc 9>, -+ <&cpu63_intc 11>, <&cpu63_intc 9>; -+ riscv,ndev = <224>; -+ }; -+ -+ uart0: serial@7040000000 { -+ compatible = "snps,dw-apb-uart"; -+ reg = <0x00000070 0x40000000 0x00000000 0x00001000>; -+ interrupt-parent = <&intc>; -+ interrupts = <112 IRQ_TYPE_LEVEL_HIGH>; -+ clock-frequency = <500000000>; -+ reg-shift = <2>; -+ reg-io-width = <4>; -+ status = "disabled"; -+ }; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/thead/Makefile b/arch/riscv/boot/dts/thead/Makefile -index b55a17127c2b..1f14fdaf6add 100644 ---- a/arch/riscv/boot/dts/thead/Makefile -+++ b/arch/riscv/boot/dts/thead/Makefile -@@ -1,2 +1,5 @@ - # SPDX-License-Identifier: GPL-2.0 - dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-pi-4a.dtb th1520-beaglev-ahead.dtb -+dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-pi-4a-16g.dtb -+dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-cluster-4a.dtb th1520-lichee-cluster-4a-16g.dtb -+dtb-$(CONFIG_ARCH_THEAD) += th1520-milkv-meles.dtb th1520-milkv-meles-4g.dtb -diff --git a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts -index 70e8042c8304..2c2d43433586 100644 ---- a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts -+++ b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts -@@ -7,22 +7,29 @@ - /dts-v1/; - - #include "th1520.dtsi" -+#include <dt-bindings/gpio/gpio.h> -+#include <dt-bindings/leds/common.h> - - / { - model = "BeagleV Ahead"; - compatible = "beagle,beaglev-ahead", "thead,th1520"; - - aliases { -+ ethernet0 = &gmac0; - gpio0 = &gpio0; - gpio1 = &gpio1; - gpio2 = &gpio2; - gpio3 = &gpio3; -+ gpio4 = &gpio4; -+ gpio5 = &aogpio; - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; - serial4 = &uart4; - serial5 = &uart5; -+ mmc0 = &emmc; -+ mmc1 = &sdio0; - }; - - chosen { -@@ -32,11 +39,46 @@ chosen { - memory@0 { - device_type = "memory"; - reg = <0x0 0x00000000 0x1 0x00000000>; -+ }; -+ -+ leds { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&led_pins>; -+ compatible = "gpio-leds"; -+ -+ led-1 { -+ gpios = <&gpio4 8 GPIO_ACTIVE_LOW>; -+ color = <LED_COLOR_ID_BLUE>; -+ label = "led1"; -+ }; -+ -+ led-2 { -+ gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; -+ color = <LED_COLOR_ID_BLUE>; -+ label = "led2"; -+ }; -+ -+ led-3 { -+ gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; -+ color = <LED_COLOR_ID_BLUE>; -+ label = "led3"; -+ }; - -+ led-4 { -+ gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; -+ color = <LED_COLOR_ID_BLUE>; -+ label = "led4"; -+ }; -+ -+ led-5 { -+ gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; -+ color = <LED_COLOR_ID_BLUE>; -+ label = "led5"; -+ }; - }; - }; - --&osc { -+&osc_24m { - clock-frequency = <24000000>; - }; - -@@ -44,10 +86,18 @@ &osc_32k { - clock-frequency = <32768>; - }; - -+&aonsys_clk { -+ clock-frequency = <73728000>; -+}; -+ - &apb_clk { - clock-frequency = <62500000>; - }; - -+&sdhci_clk { -+ clock-frequency = <198000000>; -+}; -+ - &uart_sclk { - clock-frequency = <100000000>; - }; -@@ -56,6 +106,153 @@ &dmac0 { - status = "okay"; - }; - -+&gmac_clk { -+ clock-frequency = <500000000>; -+}; -+ -+&gmac_axi_clk { -+ clock-frequency = <100000000>; -+}; -+ -+&emmc { -+ bus-width = <8>; -+ max-frequency = <198000000>; -+ mmc-hs400-1_8v; -+ non-removable; -+ no-sdio; -+ no-sd; -+ status = "okay"; -+}; -+ -+&gmac0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&gmac0_pins>; -+ phy-mode = "rgmii-id"; -+ status = "okay"; -+}; -+ -+&mdio0 { -+ phy0: ethernet-phy@1 { -+ reg = <1>; -+ }; -+}; -+ -+&padctrl_aosys { -+ led_pins: led-0 { -+ led-pins { -+ pins = "AUDIO_PA8", /* GPIO4_8 */ -+ "AUDIO_PA9", /* GPIO4_9 */ -+ "AUDIO_PA10", /* GPIO4_10 */ -+ "AUDIO_PA11", /* GPIO4_11 */ -+ "AUDIO_PA12"; /* GPIO4_12 */ -+ function = "gpio"; -+ bias-disable; -+ drive-strength = <3>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ }; -+}; -+ -+&padctrl0_apsys { -+ gmac0_pins: gmac0-0 { -+ tx-pins { -+ pins = "GMAC0_TX_CLK", -+ "GMAC0_TXEN", -+ "GMAC0_TXD0", -+ "GMAC0_TXD1", -+ "GMAC0_TXD2", -+ "GMAC0_TXD3"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <25>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ rx-pins { -+ pins = "GMAC0_RX_CLK", -+ "GMAC0_RXDV", -+ "GMAC0_RXD0", -+ "GMAC0_RXD1", -+ "GMAC0_RXD2", -+ "GMAC0_RXD3"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ mdc-pins { -+ pins = "GMAC0_MDC"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <13>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ mdio-pins { -+ pins = "GMAC0_MDIO"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <13>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ sdio0_pins: sdio0-0 { -+ detn-pins { -+ pins = "SDIO0_DETN"; -+ function = "sdio"; -+ bias-disable; /* external pull-up */ -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ uart0_pins: uart0-0 { -+ tx-pins { -+ pins = "UART0_TXD"; -+ function = "uart"; -+ bias-disable; -+ drive-strength = <3>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ rx-pins { -+ pins = "UART0_RXD"; -+ function = "uart"; -+ bias-disable; -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+}; -+ -+&sdio0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdio0_pins>; -+ bus-width = <4>; -+ max-frequency = <198000000>; -+ status = "okay"; -+}; -+ - &uart0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart0_pins>; - status = "okay"; - }; -diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts -new file mode 100644 -index 000000000000..c65cd1c83101 ---- /dev/null -+++ b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts -@@ -0,0 +1,18 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR MIT) -+/* -+ * Copyright (C) 2024 NekoRouter <nekorouter@outlook.com> -+ */ -+ -+/dts-v1/; -+ -+#include "th1520-lichee-cluster-4a.dts" -+ -+/ { -+ model = "Sipeed Lichee Cluster 4A 16G"; -+ compatible = "sipeed,lichee-cluster-4a", "sipeed,lichee-module-4a", "thead,th1520"; -+ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x00000000 0x4 0x00000000>; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts -new file mode 100644 -index 000000000000..f1116426233f ---- /dev/null -+++ b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts -@@ -0,0 +1,45 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR MIT) -+/* -+ * Copyright (C) 2024 NekoRouter <nekorouter@outlook.com> -+ */ -+ -+/dts-v1/; -+ -+#include "th1520-lichee-pi-4a.dts" -+ -+/ { -+ model = "Sipeed Lichee Cluster 4A"; -+ compatible = "sipeed,lichee-cluster-4a", "sipeed,lichee-module-4a", "thead,th1520"; -+ -+ /delete-node/ regulator-hub_5v; -+ -+ /delete-node/ regulator-vcc5v_usb; -+ -+ /delete-node/ regulator-hub_5v; -+ -+ /delete-node/ regulator-vcc5v_usb; -+ -+ /delete-node/ wireless-wlan; -+ -+ /delete-node/ wireless-bluetooth; -+ -+ /delete-node/ soc_wcn33_en; -+}; -+ -+&i2c0 { -+ status = "okay"; -+ -+ /delete-node/ gpio@18; -+}; -+ -+&i2c3 { -+ status = "okay"; -+ -+ /delete-node/ gpio@18; -+}; -+ -+&usb_dwc3 { -+ /delete-node/ hub@1; -+ -+ /delete-node/ hub@2; -+}; -diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi -index a802ab110429..8e2d281c7dee 100644 ---- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi -+++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi -@@ -15,9 +15,33 @@ memory@0 { - device_type = "memory"; - reg = <0x0 0x00000000 0x2 0x00000000>; - }; -+ -+ resmem: reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ //Note: with "no-map" reserv mem not saved in hibernation -+ rpmsgmem: memory@1E000000 { -+ reg = <0x0 0x1E000000 0x0 0x10000>; -+ }; -+ }; -+ -+ light_rpmsg: light_rpmsg { -+ compatible = "light,rpmsg-bus", "simple-bus"; -+ memory-region = <&rpmsgmem>; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ rpmsg: rpmsg { -+ vdev-nums = <1>; -+ reg = <0x0 0x1E000000 0 0x10000>; -+ compatible = "light,light-rpmsg"; -+ status = "okay"; -+ }; -+ }; - }; - --&osc { -+&osc_24m { - clock-frequency = <24000000>; - }; - -@@ -25,14 +49,139 @@ &osc_32k { - clock-frequency = <32768>; - }; - -+&aonsys_clk { -+ clock-frequency = <73728000>; -+}; -+ - &apb_clk { - clock-frequency = <62500000>; - }; - -+&sdhci_clk { -+ clock-frequency = <198000000>; -+}; -+ - &uart_sclk { - clock-frequency = <100000000>; - }; - -+&gmac_clk { -+ clock-frequency = <500000000>; -+}; -+ -+&gmac_axi_clk { -+ clock-frequency = <100000000>; -+}; -+ - &dmac0 { - status = "okay"; - }; -+ -+&emmc { -+ bus-width = <8>; -+ max-frequency = <198000000>; -+ mmc-hs400-1_8v; -+ non-removable; -+ no-sdio; -+ no-sd; -+ status = "okay"; -+}; -+ -+&padctrl0_apsys { -+ sdio0_pins: sdio0-0 { -+ detn-pins { -+ pins = "SDIO0_DETN"; -+ function = "sdio"; -+ bias-disable; /* external pull-up */ -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+}; -+ -+&sdio0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdio0_pins>; -+ bus-width = <4>; -+ max-frequency = <198000000>; -+ status = "okay"; -+}; -+ -+&cpus { -+ c910_0: cpu@0 { -+ operating-points = < -+ /* kHz uV */ -+ 300000 650000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 800000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ dvdd-supply = <&dvdd_cpu_reg>; -+ dvddm-supply = <&dvddm_cpu_reg>; -+ }; -+ c910_1: cpu@1 { -+ operating-points = < -+ /* kHz uV */ -+ 300000 650000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 800000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ dvdd-supply = <&dvdd_cpu_reg>; -+ dvddm-supply = <&dvddm_cpu_reg>; -+ }; -+ c910_2: cpu@2 { -+ -+ operating-points = < -+ /* kHz uV */ -+ 300000 650000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 800000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ dvdd-supply = <&dvdd_cpu_reg>; -+ dvddm-supply = <&dvddm_cpu_reg>; -+ }; -+ c910_3: cpu@3 { -+ -+ operating-points = < -+ /* kHz uV */ -+ 300000 650000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 800000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ dvdd-supply = <&dvdd_cpu_reg>; -+ dvddm-supply = <&dvddm_cpu_reg>; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts -new file mode 100644 -index 000000000000..a3a991baf716 ---- /dev/null -+++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts -@@ -0,0 +1,18 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR MIT) -+/* -+ * Copyright (C) 2023 Han Gao <gaohan@iscas.ac.cn> -+ */ -+ -+/dts-v1/; -+ -+#include "th1520-lichee-pi-4a.dts" -+ -+/ { -+ model = "Sipeed Lichee Pi 4A 16G"; -+ compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520"; -+ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x00000000 0x4 0x00000000>; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts -index 9a3884a73e13..6c0709e5193f 100644 ---- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts -+++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts -@@ -4,29 +4,741 @@ - */ - - #include "th1520-lichee-module-4a.dtsi" -+#include <dt-bindings/gpio/gpio.h> - - / { - model = "Sipeed Lichee Pi 4A"; - compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520"; - - aliases { -+ ethernet0 = &gmac0; -+ ethernet1 = &gmac1; - gpio0 = &gpio0; - gpio1 = &gpio1; - gpio2 = &gpio2; - gpio3 = &gpio3; -+ gpio4 = &gpio4; -+ gpio5 = &aogpio; - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; - serial4 = &uart4; - serial5 = &uart5; -+ i2c0 = &i2c0; -+ i2c1 = &i2c1; -+ i2c2 = &i2c2; -+ i2c3 = &i2c3; -+ i2c4 = &i2c4; -+ i2c5 = &audio_i2c0; -+ i2c6 = &audio_i2c1; -+ mmc0 = &emmc; -+ mmc1 = &sdio0; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -+ -+ fan: pwm-fan { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&fan_pins>; -+ compatible = "pwm-fan"; -+ #cooling-cells = <2>; -+ pwms = <&pwm 1 10000000 0>; -+ cooling-levels = <0 66 196 255>; -+ }; -+ -+ hub_5v: regulator-hub_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "HUB_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ vcc5v_usb: regulator-vcc5v_usb { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC5V_USB"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ thermal-zones { -+ cpu-thermal { -+ polling-delay = <1000>; -+ polling-delay-passive = <1000>; -+ thermal-sensors = <&pvt 0>; -+ -+ trips { -+ trip_active0: active-0 { -+ temperature = <39000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ -+ trip_active1: active-1 { -+ temperature = <50000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ -+ trip_active2: active-2 { -+ temperature = <60000>; -+ hysteresis = <5000>; -+ type = "active"; -+ }; -+ }; -+ -+ cooling-maps { -+ map-active-0 { -+ cooling-device = <&fan 1 1>; -+ trip = <&trip_active0>; -+ }; -+ -+ map-active-1 { -+ cooling-device = <&fan 2 2>; -+ trip = <&trip_active1>; -+ }; -+ -+ map-active-2 { -+ cooling-device = <&fan 3 3>; -+ trip = <&trip_active2>; -+ }; -+ }; -+ }; -+ }; -+ -+ hub_5v: regulator-hub_5v { -+ compatible = "regulator-fixed"; -+ regulator-name = "HUB_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ vcc5v_usb: regulator-vcc5v_usb { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC5V_USB"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ wcn_wifi: wireless-wlan { -+ compatible = "wlan-platdata"; -+ clock-names = "clk_wifi"; -+ ref-clock-frequency = <24000000>; -+ keep_wifi_power_on; -+ pinctrl-names = "default"; -+ wifi_chip_type = "rtl8723ds"; -+ WIFI,poweren_gpio = <&ioexp2 5 0>; -+ status = "okay"; -+ }; -+ -+ wcn_bt: wireless-bluetooth { -+ compatible = "bluetooth-platdata"; -+ pinctrl-names = "default", "rts_gpio"; -+ BT,power_gpio = <&ioexp2 6 0>; -+ status = "okay"; -+ }; -+ -+ aon: aon { -+ compatible = "thead,light-aon"; -+ mbox-names = "aon"; -+ mboxes = <&mbox_910t 1 0>; -+ status = "okay"; -+ -+ pd: light-aon-pd { -+ compatible = "thead,light-aon-pd"; -+ #power-domain-cells = <1>; -+ }; -+ -+ soc_aud_3v3_en_reg: soc_aud_3v3_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_aud_3v3_en"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ soc_aud_1v8_en_reg: soc_aud_1v8_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_aud_1v8_en"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ soc_vdd_3v3_en_reg: soc_vdd_3v3_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_vdd_3v3_en"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ gpio = <&gpio0 30 1>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ soc_vdd33_lcd0_en_reg: soc_lcd0_vdd33_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_lcd0_vdd33_en"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ gpio = <&ioexp2 5 1>; -+ enable-active-high; -+ }; -+ -+ soc_vdd18_lcd0_en_reg: soc_lcd0_vdd18_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_lcd0_vdd18_en"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ gpio = <&ioexp2 6 1>; -+ enable-active-high; -+ }; -+ -+ soc_vdd5v_se_en_reg: soc_vdd5v_se_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_vdd5v_se_en"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ gpio = <&gpio2 14 1>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ soc_wcn33_en_reg: soc_wcn33_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_wcn33_en"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ gpio = <&gpio2 29 1>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ soc_vbus_en_reg: soc_vbus_en { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_vbus_en"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ gpio = <&gpio1 22 1>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ -+ soc_avdd28_rgb_reg: soc_avdd28_rgb { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_avdd28_rgb"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <2800000>; -+ gpio = <&ioexp2 1 1>; -+ enable-active-high; -+ }; -+ -+ soc_dovdd18_rgb_reg: soc_dovdd18_rgb { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_dovdd18_rgb"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <2800000>; -+ gpio = <&ioexp2 2 1>; -+ enable-active-high; -+ }; -+ -+ soc_dvdd12_rgb_reg: soc_dvdd12_rgb { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_dvdd12_rgb"; -+ regulator-min-microvolt = <2800000>; -+ regulator-max-microvolt = <2800000>; -+ gpio = <&ioexp2 0 1>; -+ enable-active-high; -+ }; -+ -+ soc_avdd25_ir_reg: soc_avdd25_ir { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_avdd25_ir"; -+ regulator-min-microvolt = <2500000>; -+ regulator-max-microvolt = <2500000>; -+ gpio = <&ioexp2 5 1>; -+ enable-active-high; -+ }; -+ -+ soc_dovdd18_ir_reg: soc_dovdd18_ir { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_dovdd18_ir"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ gpio = <&ioexp2 3 1>; -+ enable-active-high; -+ }; -+ -+ soc_dvdd12_ir_reg: soc_dvdd12_ir { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_dvdd12_ir"; -+ regulator-min-microvolt = <1200000>; -+ regulator-max-microvolt = <1200000>; -+ gpio = <&ioexp2 4 1>; -+ enable-active-high; -+ }; -+ -+ soc_cam2_avdd25_ir_reg: soc_cam2_avdd25_ir { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_cam2_avdd25_ir"; -+ regulator-min-microvolt = <2500000>; -+ regulator-max-microvolt = <2500000>; -+ gpio = <&ioexp2 7 1>; -+ enable-active-high; -+ }; -+ -+ soc_cam2_dovdd18_ir_reg: soc_cam2_dovdd18_ir { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_cam2_dovdd18_ir"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ gpio = <&ioexp2 6 1>; -+ enable-active-high; -+ }; -+ -+ soc_cam2_dvdd12_ir_reg: soc_cam2_dvdd12_ir { -+ compatible = "regulator-fixed"; -+ regulator-name = "soc_cam2_dvdd12_ir"; -+ regulator-min-microvolt = <1200000>; -+ regulator-max-microvolt = <1200000>; -+ gpio = <&ioexp2 0 1>; -+ enable-active-high; -+ }; -+ -+ aon_reg_dialog: light-dialog-reg { -+ compatible = "thead,light-dialog-pmic-ant"; -+ status = "okay"; -+ -+ dvdd_cpu_reg: appcpu_dvdd { -+ regulator-name = "appcpu_dvdd"; -+ regulator-min-microvolt = <300000>; -+ regulator-max-microvolt = <1570000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ dvddm_cpu_reg: appcpu_dvddm { -+ regulator-name = "appcpu_dvddm"; -+ regulator-min-microvolt = <300000>; -+ regulator-max-microvolt = <1570000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dvdd18_aon_reg: soc_dvdd18_aon { -+ regulator-name = "soc_dvdd18_aon"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_avdd33_usb3_reg: soc_avdd33_usb3 { -+ regulator-name = "soc_avdd33_usb3"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dvdd08_aon_reg: soc_dvdd08_aon { -+ regulator-name = "soc_dvdd08_aon"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dvdd08_ddr_reg: soc_dvdd08_ddr { -+ regulator-name = "soc_dvdd08_ddr"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd_ddr_1v8_reg: soc_vdd_ddr_1v8 { -+ regulator-name = "soc_vdd_ddr_1v8"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd_ddr_1v1_reg: soc_vdd_ddr_1v1 { -+ regulator-name = "soc_vdd_ddr_1v1"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd_ddr_0v6_reg: soc_vdd_ddr_0v6 { -+ regulator-name = "soc_vdd_ddr_0v6"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dvdd18_ap_reg: soc_dvdd18_ap { -+ regulator-name = "soc_dvdd18_ap"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_avdd08_mipi_hdmi_reg: soc_avdd08_mipi_hdmi { -+ regulator-name = "soc_avdd08_mipi_hdmi"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_avdd18_mipi_hdmi_reg: soc_avdd18_mipi_hdmi { -+ regulator-name = "soc_avdd18_mipi_hdmi"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd33_emmc_reg: soc_vdd33_emmc { -+ regulator-name = "soc_vdd33_emmc"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd18_emmc_reg: soc_vdd18_emmc { -+ regulator-name = "soc_vdd18_emmc"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dovdd18_scan_reg: soc_dovdd18_scan { -+ regulator-name = "soc_dovdd18_scan"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <3600000>; -+ }; -+ -+ soc_dvdd12_scan_reg: soc_dvdd12_scan { -+ regulator-name = "soc_dvdd12_scan"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <3600000>; -+ }; -+ -+ soc_avdd28_scan_en_reg: soc_avdd28_scan_en { -+ regulator-name = "soc_avdd28_scan_en"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <3600000>; -+ }; -+ -+ }; -+ -+ c910_cpufreq { -+ compatible = "thead,light-mpw-cpufreq"; -+ status = "okay"; -+ }; -+ -+ test: light-aon-test { -+ compatible = "thead,light-aon-test"; -+ }; -+ }; -+ -+}; -+ -+&aogpio { -+ sel-usb-hub-hog { -+ gpio-hog; -+ gpios = <4 GPIO_ACTIVE_HIGH>; -+ output-high; -+ }; -+}; -+ -+&gmac0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&gmac0_pins>; -+ phy-handle = <&phy0>; -+ phy-mode = "rgmii-id"; -+ status = "okay"; -+}; -+ -+&gmac1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&gmac1_pins>; -+ phy-handle = <&phy1>; -+ phy-mode = "rgmii-id"; -+ status = "okay"; -+}; -+ -+&i2c0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c0_pins>; -+ clock-frequency = <100000>; -+ i2c-sda-hold-time-ns = <300>; -+ i2c-sda-falling-time-ns = <510>; -+ i2c-scl-falling-time-ns = <510>; -+ status = "okay"; -+ -+ ioexp1: gpio@18 { -+ compatible = "nxp,pca9557"; -+ reg = <0x18>; -+ gpio-controller; -+ #gpio-cells = <2>; -+ gpio-line-names = "cam0_dvdd12", -+ "cam0_avdd28", -+ "cam0_dovdd18"; -+ }; -+}; -+ -+&i2c1 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c1_pins>; -+ clock-frequency = <100000>; -+ i2c-sda-hold-time-ns = <300>; -+ i2c-sda-falling-time-ns = <510>; -+ i2c-scl-falling-time-ns = <510>; -+ status = "okay"; -+ -+ ioexp2: gpio@18 { -+ compatible = "nxp,pca9557"; -+ reg = <0x18>; -+ gpio-controller; -+ #gpio-cells = <2>; -+ gpio-line-names = "", -+ "cam0_reset", -+ "cam1_reset", -+ "cam2_reset", -+ "wl_host_wake", -+ "bt_resetn", -+ "", -+ "bt_host_wake"; -+ }; -+}; -+ -+&i2c3 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&i2c3_pins>; -+ clock-frequency = <100000>; -+ i2c-sda-hold-time-ns = <300>; -+ i2c-sda-falling-time-ns = <510>; -+ i2c-scl-falling-time-ns = <510>; -+ status = "okay"; -+ -+ ioexp3: gpio@18 { -+ compatible = "nxp,pca9557"; -+ reg = <0x18>; -+ gpio-controller; -+ #gpio-cells = <2>; -+ gpio-line-names = "tp0_rst", -+ "", -+ "", -+ "vcc5v_usb", -+ "vdd28_tp0", -+ "vdd33_lcd0", -+ "vdd18_lcd0", -+ "lcd0_reset"; -+ }; -+}; -+ -+&mdio0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&mdio0_pins>; -+ -+ phy0: ethernet-phy@1 { -+ reg = <1>; -+ }; -+ -+ phy1: ethernet-phy@2 { -+ reg = <2>; -+ }; -+}; -+ -+&padctrl0_apsys { -+ fan_pins: fan-0 { -+ pwm1-pins { -+ pins = "GPIO3_3"; /* PWM1 */ -+ function = "pwm"; -+ bias-disable; -+ drive-strength = <25>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ gmac0_pins: gmac0-0 { -+ tx-pins { -+ pins = "GMAC0_TX_CLK", -+ "GMAC0_TXEN", -+ "GMAC0_TXD0", -+ "GMAC0_TXD1", -+ "GMAC0_TXD2", -+ "GMAC0_TXD3"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <25>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ rx-pins { -+ pins = "GMAC0_RX_CLK", -+ "GMAC0_RXDV", -+ "GMAC0_RXD0", -+ "GMAC0_RXD1", -+ "GMAC0_RXD2", -+ "GMAC0_RXD3"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ gmac1_pins: gmac1-0 { -+ tx-pins { -+ pins = "GPIO2_18", /* GMAC1_TX_CLK */ -+ "GPIO2_20", /* GMAC1_TXEN */ -+ "GPIO2_21", /* GMAC1_TXD0 */ -+ "GPIO2_22", /* GMAC1_TXD1 */ -+ "GPIO2_23", /* GMAC1_TXD2 */ -+ "GPIO2_24"; /* GMAC1_TXD3 */ -+ function = "gmac1"; -+ bias-disable; -+ drive-strength = <25>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ rx-pins { -+ pins = "GPIO2_19", /* GMAC1_RX_CLK */ -+ "GPIO2_25", /* GMAC1_RXDV */ -+ "GPIO2_30", /* GMAC1_RXD0 */ -+ "GPIO2_31", /* GMAC1_RXD1 */ -+ "GPIO3_0", /* GMAC1_RXD2 */ -+ "GPIO3_1"; /* GMAC1_RXD3 */ -+ function = "gmac1"; -+ bias-disable; -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ i2c3_pins: i2c3-0 { -+ i2c-pins { -+ pins = "I2C3_SCL", "I2C3_SDA"; -+ function = "i2c"; -+ bias-disable; -+ drive-strength = <7>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ mdio0_pins: mdio0-0 { -+ mdc-pins { -+ pins = "GMAC0_MDC"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <13>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ mdio-pins { -+ pins = "GMAC0_MDIO"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <13>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ uart0_pins: uart0-0 { -+ tx-pins { -+ pins = "UART0_TXD"; -+ function = "uart"; -+ bias-disable; -+ drive-strength = <3>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ rx-pins { -+ pins = "UART0_RXD"; -+ function = "uart"; -+ bias-disable; -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+}; -+ -+&padctrl1_apsys { -+ i2c0_pins: i2c0-0 { -+ i2c-pins { -+ pins = "I2C0_SCL", "I2C0_SDA"; -+ function = "i2c"; -+ bias-disable; -+ drive-strength = <7>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ i2c1_pins: i2c1-0 { -+ i2c-pins { -+ pins = "I2C1_SCL", "I2C1_SDA"; -+ function = "i2c"; -+ bias-disable; -+ drive-strength = <7>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; - }; - - &uart0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart0_pins>; -+ status = "okay"; -+}; -+ -+&usb { - status = "okay"; - }; -+ -+&usb_dwc3 { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ hub_2_0: hub@1 { -+ compatible = "usb2109,2817"; -+ reg = <1>; -+ peer-hub = <&hub_3_0>; -+ vdd-supply = <&hub_5v>; -+ vbus-supply = <&vcc5v_usb>; -+ }; -+ -+ hub_3_0: hub@2 { -+ compatible = "usb2109,817"; -+ reg = <2>; -+ peer-hub = <&hub_2_0>; -+ vbus-supply = <&vcc5v_usb>; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts b/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts -new file mode 100644 -index 000000000000..5a6baccd1684 ---- /dev/null -+++ b/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts -@@ -0,0 +1,19 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ * Copyright (C) 2024 Milk-V Limited. -+ */ -+ -+/dts-v1/; -+ -+#include "th1520-milkv-meles.dts" -+ -+/ { -+ model = "Milk-V Meles 4G"; -+ compatible = "milkv,meles", "thead,light"; -+ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x00000000 0x1 0x00000000>; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts b/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts -new file mode 100644 -index 000000000000..394385afd53d ---- /dev/null -+++ b/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts -@@ -0,0 +1,441 @@ -+// SPDX-License-Identifier: (GPL-2.0 OR MIT) -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ * Copyright (C) 2024 Milk-V Limited. -+ */ -+ -+/dts-v1/; -+ -+#include "th1520.dtsi" -+#include <dt-bindings/gpio/gpio.h> -+ -+/ { -+ model = "Milk-V Meles"; -+ compatible = "milkv,meles", "thead,th1520"; -+ -+ aliases { -+ ethernet0 = &gmac0; -+ gpio0 = &gpio0; -+ gpio1 = &gpio1; -+ gpio2 = &gpio2; -+ gpio3 = &gpio3; -+ gpio4 = &gpio4; -+ gpio5 = &aogpio; -+ serial0 = &uart0; -+ serial1 = &uart1; -+ serial2 = &uart2; -+ serial3 = &uart3; -+ serial4 = &uart4; -+ serial5 = &uart5; -+ }; -+ -+ chosen { -+ stdout-path = "serial0:115200n8"; -+ }; -+ -+ memory@0 { -+ device_type = "memory"; -+ reg = <0x0 0x00000000 0x2 0x00000000>; -+ }; -+ -+ resmem: reserved-memory { -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ //Note: with "no-map" reserv mem not saved in hibernation -+ rpmsgmem: memory@1E000000 { -+ reg = <0x0 0x1E000000 0x0 0x10000>; -+ }; -+ }; -+ -+ light_rpmsg: light_rpmsg { -+ compatible = "light,rpmsg-bus", "simple-bus"; -+ memory-region = <&rpmsgmem>; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ rpmsg: rpmsg { -+ vdev-nums = <1>; -+ reg = <0x0 0x1E000000 0 0x10000>; -+ compatible = "light,light-rpmsg"; -+ status = "okay"; -+ }; -+ }; -+ -+ aon: aon { -+ compatible = "thead,light-aon"; -+ mbox-names = "aon"; -+ mboxes = <&mbox_910t 1 0>; -+ status = "okay"; -+ -+ pd: light-aon-pd { -+ compatible = "thead,light-aon-pd"; -+ #power-domain-cells = <1>; -+ }; -+ -+ aon_reg_dialog: light-dialog-reg { -+ compatible = "thead,light-dialog-pmic-ant"; -+ status = "okay"; -+ -+ dvdd_cpu_reg: appcpu_dvdd { -+ regulator-name = "appcpu_dvdd"; -+ regulator-min-microvolt = <300000>; -+ regulator-max-microvolt = <1570000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ dvddm_cpu_reg: appcpu_dvddm { -+ regulator-name = "appcpu_dvddm"; -+ regulator-min-microvolt = <300000>; -+ regulator-max-microvolt = <1570000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dvdd18_aon_reg: soc_dvdd18_aon { -+ regulator-name = "soc_dvdd18_aon"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_avdd33_usb3_reg: soc_avdd33_usb3 { -+ regulator-name = "soc_avdd33_usb3"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dvdd08_aon_reg: soc_dvdd08_aon { -+ regulator-name = "soc_dvdd08_aon"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dvdd08_ddr_reg: soc_dvdd08_ddr { -+ regulator-name = "soc_dvdd08_ddr"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd_ddr_1v8_reg: soc_vdd_ddr_1v8 { -+ regulator-name = "soc_vdd_ddr_1v8"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd_ddr_1v1_reg: soc_vdd_ddr_1v1 { -+ regulator-name = "soc_vdd_ddr_1v1"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd_ddr_0v6_reg: soc_vdd_ddr_0v6 { -+ regulator-name = "soc_vdd_ddr_0v6"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dvdd18_ap_reg: soc_dvdd18_ap { -+ regulator-name = "soc_dvdd18_ap"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_avdd08_mipi_hdmi_reg: soc_avdd08_mipi_hdmi { -+ regulator-name = "soc_avdd08_mipi_hdmi"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_avdd18_mipi_hdmi_reg: soc_avdd18_mipi_hdmi { -+ regulator-name = "soc_avdd18_mipi_hdmi"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd33_emmc_reg: soc_vdd33_emmc { -+ regulator-name = "soc_vdd33_emmc"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_vdd18_emmc_reg: soc_vdd18_emmc { -+ regulator-name = "soc_vdd18_emmc"; -+ regulator-boot-on; -+ regulator-always-on; -+ }; -+ -+ soc_dovdd18_scan_reg: soc_dovdd18_scan { -+ regulator-name = "soc_dovdd18_scan"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <3600000>; -+ }; -+ -+ soc_dvdd12_scan_reg: soc_dvdd12_scan { -+ regulator-name = "soc_dvdd12_scan"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <3600000>; -+ }; -+ -+ soc_avdd28_scan_en_reg: soc_avdd28_scan_en { -+ regulator-name = "soc_avdd28_scan_en"; -+ regulator-min-microvolt = <900000>; -+ regulator-max-microvolt = <3600000>; -+ }; -+ }; -+ -+ c910_cpufreq { -+ compatible = "thead,light-mpw-cpufreq"; -+ status = "okay"; -+ }; -+ -+ test: light-aon-test { -+ compatible = "thead,light-aon-test"; -+ }; -+ }; -+}; -+ -+&osc_24m { -+ clock-frequency = <24000000>; -+}; -+ -+&osc_32k { -+ clock-frequency = <32768>; -+}; -+ -+&aonsys_clk { -+ clock-frequency = <73728000>; -+}; -+ -+&apb_clk { -+ clock-frequency = <62500000>; -+}; -+ -+&sdhci_clk { -+ clock-frequency = <198000000>; -+}; -+ -+&uart_sclk { -+ clock-frequency = <100000000>; -+}; -+ -+&gmac_clk { -+ clock-frequency = <500000000>; -+}; -+ -+&gmac_axi_clk { -+ clock-frequency = <100000000>; -+}; -+ -+&dmac0 { -+ status = "okay"; -+}; -+ -+&emmc { -+ bus-width = <8>; -+ max-frequency = <198000000>; -+ mmc-hs400-1_8v; -+ non-removable; -+ no-sdio; -+ no-sd; -+ status = "okay"; -+}; -+ -+&gmac0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&gmac0_pins>; -+ phy-handle = <&phy0>; -+ phy-mode = "rgmii-id"; -+ status = "okay"; -+}; -+ -+&mdio0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&mdio0_pins>; -+ -+ phy0: ethernet-phy@1 { -+ reg = <1>; -+ }; -+}; -+ -+&sdio0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdio0_pins>; -+ bus-width = <4>; -+ max-frequency = <198000000>; -+ status = "okay"; -+}; -+ -+&uart0 { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart0_pins>; -+ status = "okay"; -+}; -+ -+&cpus { -+ c910_0: cpu@0 { -+ operating-points = < -+ /* kHz uV */ -+ 300000 650000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 800000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ dvdd-supply = <&dvdd_cpu_reg>; -+ dvddm-supply = <&dvddm_cpu_reg>; -+ }; -+ -+ c910_1: cpu@1 { -+ operating-points = < -+ /* kHz uV */ -+ 300000 650000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 800000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ dvdd-supply = <&dvdd_cpu_reg>; -+ dvddm-supply = <&dvddm_cpu_reg>; -+ }; -+ -+ c910_2: cpu@2 { -+ operating-points = < -+ /* kHz uV */ -+ 300000 650000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 800000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ dvdd-supply = <&dvdd_cpu_reg>; -+ dvddm-supply = <&dvddm_cpu_reg>; -+ }; -+ -+ c910_3: cpu@3 { -+ operating-points = < -+ /* kHz uV */ -+ 300000 650000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 800000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ dvdd-supply = <&dvdd_cpu_reg>; -+ dvddm-supply = <&dvddm_cpu_reg>; -+ }; -+}; -+ -+&padctrl0_apsys { -+ gmac0_pins: gmac0-0 { -+ tx-pins { -+ pins = "GMAC0_TX_CLK", -+ "GMAC0_TXEN", -+ "GMAC0_TXD0", -+ "GMAC0_TXD1", -+ "GMAC0_TXD2", -+ "GMAC0_TXD3"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <25>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ rx-pins { -+ pins = "GMAC0_RX_CLK", -+ "GMAC0_RXDV", -+ "GMAC0_RXD0", -+ "GMAC0_RXD1", -+ "GMAC0_RXD2", -+ "GMAC0_RXD3"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ mdio0_pins: mdio0-0 { -+ mdc-pins { -+ pins = "GMAC0_MDC"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <13>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ mdio-pins { -+ pins = "GMAC0_MDIO"; -+ function = "gmac0"; -+ bias-disable; -+ drive-strength = <13>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ sdio0_pins: sdio0-0 { -+ detn-pins { -+ pins = "SDIO0_DETN"; -+ function = "sdio"; -+ bias-disable; /* external pull-up */ -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ uart0_pins: uart0-0 { -+ tx-pins { -+ pins = "UART0_TXD"; -+ function = "uart"; -+ bias-disable; -+ drive-strength = <3>; -+ input-disable; -+ input-schmitt-disable; -+ slew-rate = <0>; -+ }; -+ -+ rx-pins { -+ pins = "UART0_RXD"; -+ function = "uart"; -+ bias-disable; -+ drive-strength = <1>; -+ input-enable; -+ input-schmitt-enable; -+ slew-rate = <0>; -+ }; -+ }; -+}; -diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi -index ff364709a6df..fab3b5f17f22 100644 ---- a/arch/riscv/boot/dts/thead/th1520.dtsi -+++ b/arch/riscv/boot/dts/thead/th1520.dtsi -@@ -5,6 +5,9 @@ - */ - - #include <dt-bindings/interrupt-controller/irq.h> -+#include <dt-bindings/clock/light-fm-ap-clock.h> -+#include <dt-bindings/gpio/gpio.h> -+#include <dt-bindings/reset/thead,th1520-reset.h> - - / { - compatible = "thead,th1520"; -@@ -29,6 +32,30 @@ c910_0: cpu@0 { - d-cache-sets = <512>; - next-level-cache = <&l2_cache>; - mmu-type = "riscv,sv39"; -+ cpu-freq = "1.848Ghz"; -+ cpu-cacheline = "64Bytes"; -+ -+ operating-points = < -+ /* kHz uV */ -+ 300000 600000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 750000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ clock-latency = <61036>; -+ clocks = <&clk C910_CCLK>, -+ <&clk C910_CCLK_I0>, -+ <&clk CPU_PLL1_FOUTPOSTDIV>, -+ <&clk CPU_PLL0_FOUTPOSTDIV>; -+ clock-names = "c910_cclk", "c910_cclk_i0", -+ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; - - cpu0_intc: interrupt-controller { - compatible = "riscv,cpu-intc"; -@@ -50,6 +77,30 @@ c910_1: cpu@1 { - d-cache-sets = <512>; - next-level-cache = <&l2_cache>; - mmu-type = "riscv,sv39"; -+ cpu-freq = "1.848Ghz"; -+ cpu-cacheline = "64Bytes"; -+ -+ operating-points = < -+ /* kHz uV */ -+ 300000 600000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 750000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ clock-latency = <61036>; -+ clocks = <&clk C910_CCLK>, -+ <&clk C910_CCLK_I0>, -+ <&clk CPU_PLL1_FOUTPOSTDIV>, -+ <&clk CPU_PLL0_FOUTPOSTDIV>; -+ clock-names = "c910_cclk", "c910_cclk_i0", -+ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; - - cpu1_intc: interrupt-controller { - compatible = "riscv,cpu-intc"; -@@ -71,6 +122,30 @@ c910_2: cpu@2 { - d-cache-sets = <512>; - next-level-cache = <&l2_cache>; - mmu-type = "riscv,sv39"; -+ cpu-freq = "1.848Ghz"; -+ cpu-cacheline = "64Bytes"; -+ -+ operating-points = < -+ /* kHz uV */ -+ 300000 600000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 750000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ clock-latency = <61036>; -+ clocks = <&clk C910_CCLK>, -+ <&clk C910_CCLK_I0>, -+ <&clk CPU_PLL1_FOUTPOSTDIV>, -+ <&clk CPU_PLL0_FOUTPOSTDIV>; -+ clock-names = "c910_cclk", "c910_cclk_i0", -+ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; - - cpu2_intc: interrupt-controller { - compatible = "riscv,cpu-intc"; -@@ -92,6 +167,30 @@ c910_3: cpu@3 { - d-cache-sets = <512>; - next-level-cache = <&l2_cache>; - mmu-type = "riscv,sv39"; -+ cpu-freq = "1.848Ghz"; -+ cpu-cacheline = "64Bytes"; -+ -+ operating-points = < -+ /* kHz uV */ -+ 300000 600000 -+ 800000 700000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ light,dvddm-operating-points = < -+ /* kHz uV */ -+ 300000 750000 -+ 800000 800000 -+ 1500000 800000 -+ 1848000 1000000 -+ >; -+ clock-latency = <61036>; -+ clocks = <&clk C910_CCLK>, -+ <&clk C910_CCLK_I0>, -+ <&clk CPU_PLL1_FOUTPOSTDIV>, -+ <&clk CPU_PLL0_FOUTPOSTDIV>; -+ clock-names = "c910_cclk", "c910_cclk_i0", -+ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv"; - - cpu3_intc: interrupt-controller { - compatible = "riscv,cpu-intc"; -@@ -110,15 +209,111 @@ l2_cache: l2-cache { - }; - }; - -- osc: oscillator { -+ pmu { -+ compatible = "riscv,pmu"; -+ riscv,event-to-mhpmcounters = -+ <0x00003 0x00003 0x0007fff8>, -+ <0x00004 0x00004 0x0007fff8>, -+ <0x00005 0x00005 0x0007fff8>, -+ <0x00006 0x00006 0x0007fff8>, -+ <0x00007 0x00007 0x0007fff8>, -+ <0x00008 0x00008 0x0007fff8>, -+ <0x00009 0x00009 0x0007fff8>, -+ <0x0000a 0x0000a 0x0007fff8>, -+ <0x10000 0x10000 0x0007fff8>, -+ <0x10001 0x10001 0x0007fff8>, -+ <0x10002 0x10002 0x0007fff8>, -+ <0x10003 0x10003 0x0007fff8>, -+ <0x10010 0x10010 0x0007fff8>, -+ <0x10011 0x10011 0x0007fff8>, -+ <0x10012 0x10012 0x0007fff8>, -+ <0x10013 0x10013 0x0007fff8>; -+ riscv,event-to-mhpmevent = -+ <0x00003 0x00000000 0x00000001>, -+ <0x00004 0x00000000 0x00000002>, -+ <0x00006 0x00000000 0x00000006>, -+ <0x00005 0x00000000 0x00000007>, -+ <0x00007 0x00000000 0x00000008>, -+ <0x00008 0x00000000 0x00000009>, -+ <0x00009 0x00000000 0x0000000a>, -+ <0x0000a 0x00000000 0x0000000b>, -+ <0x10000 0x00000000 0x0000000c>, -+ <0x10001 0x00000000 0x0000000d>, -+ <0x10002 0x00000000 0x0000000e>, -+ <0x10003 0x00000000 0x0000000f>, -+ <0x10010 0x00000000 0x00000010>, -+ <0x10011 0x00000000 0x00000011>, -+ <0x10012 0x00000000 0x00000012>, -+ <0x10013 0x00000000 0x00000013>; -+ riscv,raw-event-to-mhpmcounters = -+ <0x00000000 0x00000001 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000002 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000003 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000004 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000005 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000006 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000007 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000008 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000009 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000000a 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000000b 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000000c 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000000d 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000000e 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000000f 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000010 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000011 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000012 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000013 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000014 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000015 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000016 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000017 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000018 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000019 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000001a 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000001b 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000001c 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000001d 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000001e 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000001f 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000020 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000021 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000022 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000023 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000024 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000025 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000026 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000027 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000028 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x00000029 0xffffffff 0xffffffff 0x0007fff8>, -+ <0x00000000 0x0000002a 0xffffffff 0xffffffff 0x0007fff8>; -+ }; -+ -+ osc_32k: clock-osc-32k { - compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <32768>; -+ clock-output-names = "osc_32k"; -+ }; -+ -+ osc_24m: clock-osc-24m { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <24000000>; - clock-output-names = "osc_24m"; -+ }; -+ -+ rc_24m: clock-rc-24m { -+ compatible = "fixed-clock"; - #clock-cells = <0>; -+ clock-frequency = <24000000>; -+ clock-output-names = "rc_24m"; - }; - -- osc_32k: 32k-oscillator { -+ aonsys_clk: aonsys-clk { - compatible = "fixed-clock"; -- clock-output-names = "osc_32k"; -+ clock-output-names = "aonsys_clk"; - #clock-cells = <0>; - }; - -@@ -134,6 +329,36 @@ uart_sclk: uart-sclk-clock { - #clock-cells = <0>; - }; - -+ sdhci_clk: sdhci-clock { -+ compatible = "fixed-clock"; -+ clock-frequency = <198000000>; -+ clock-output-names = "sdhci_clk"; -+ #clock-cells = <0>; -+ }; -+ -+ gmac_axi_clk: gmac-axi-clock { -+ compatible = "fixed-clock"; -+ clock-output-names = "gmac_axi_clk"; -+ #clock-cells = <0>; -+ }; -+ -+ gmac_clk: gmac-clock { -+ compatible = "fixed-clock"; -+ clock-output-names = "gmac_clk"; -+ #clock-cells = <0>; -+ }; -+ -+ stmmac_axi_config: stmmac-axi-config { -+ snps,wr_osr_lmt = <15>; -+ snps,rd_osr_lmt = <15>; -+ snps,blen = <0 0 64 32 0 0 0>; -+ }; -+ -+ aon_iram: aon-iram@ffffef8000 { -+ compatible = "syscon"; -+ reg = <0xff 0xffef8000 0x0 0x10000>; -+ }; -+ - soc { - compatible = "simple-bus"; - interrupt-parent = <&plic>; -@@ -142,6 +367,41 @@ soc { - dma-noncoherent; - ranges; - -+ cpurst: cpurst { -+ compatible = "thead,reset-sample"; -+ entry-reg = <0xff 0xff019050>; -+ entry-cnt = <4>; -+ control-reg = <0xff 0xff015004>; -+ control-val = <0x1c>; -+ csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>; -+ }; -+ -+ light_event: light-event { -+ compatible = "thead,light-event"; -+ aon-iram-regmap = <&aon_iram>; -+ status = "okay"; -+ }; -+ -+ audio_i2c0: i2c@ffcb01a000 { -+ compatible = "snps,designware-i2c"; -+ reg = <0xff 0xcb01a000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ interrupts = <182 IRQ_TYPE_LEVEL_HIGH>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ audio_i2c1: i2c@ffcb01b000 { -+ compatible = "snps,designware-i2c"; -+ reg = <0xff 0xcb01b000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ interrupts = <183 IRQ_TYPE_LEVEL_HIGH>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ - plic: interrupt-controller@ffd8000000 { - compatible = "thead,th1520-plic", "thead,c900-plic"; - reg = <0xff 0xd8000000 0x0 0x01000000>; -@@ -164,6 +424,50 @@ clint: timer@ffdc000000 { - <&cpu3_intc 3>, <&cpu3_intc 7>; - }; - -+ gmac0: ethernet@ffe7070000 { -+ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; -+ reg = <0xff 0xe7070000 0x0 0x2000>; -+ interrupts = <66 IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "macirq"; -+ clocks = <&gmac_clk>, <&gmac_axi_clk>; -+ clock-names = "stmmaceth", "pclk"; -+ snps,pbl = <32>; -+ snps,fixed-burst; -+ snps,multicast-filter-bins = <64>; -+ snps,perfect-filter-entries = <32>; -+ snps,axi-config = <&stmmac_axi_config>; -+ thead,gmacapb = <&gmac0_apb>; -+ status = "disabled"; -+ -+ mdio0: mdio { -+ compatible = "snps,dwmac-mdio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ }; -+ -+ gmac1: ethernet@ffe7060000 { -+ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a"; -+ reg = <0xff 0xe7060000 0x0 0x2000>; -+ interrupts = <67 IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "macirq"; -+ clocks = <&gmac_clk>, <&gmac_axi_clk>; -+ clock-names = "stmmaceth", "pclk"; -+ snps,pbl = <32>; -+ snps,fixed-burst; -+ snps,multicast-filter-bins = <64>; -+ snps,perfect-filter-entries = <32>; -+ snps,axi-config = <&stmmac_axi_config>; -+ thead,gmacapb = <&gmac1_apb>; -+ status = "disabled"; -+ -+ mdio1: mdio { -+ compatible = "snps,dwmac-mdio"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ }; -+ - uart0: serial@ffe7014000 { - compatible = "snps,dw-apb-uart"; - reg = <0xff 0xe7014000 0x0 0x100>; -@@ -194,17 +498,48 @@ uart3: serial@ffe7f04000 { - status = "disabled"; - }; - -- gpio2: gpio@ffe7f34000 { -+ i2c0: i2c@ffe7f20000 { -+ compatible = "snps,designware-i2c"; -+ reg = <0xff 0xe7f20000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c1: i2c@ffe7f24000 { -+ compatible = "snps,designware-i2c"; -+ reg = <0xff 0xe7f24000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ i2c4: i2c@ffe7f28000 { -+ compatible = "snps,designware-i2c"; -+ reg = <0xff 0xe7f28000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ gpio@ffe7f34000 { - compatible = "snps,dw-apb-gpio"; - reg = <0xff 0xe7f34000 0x0 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - -- portc: gpio-controller@0 { -+ gpio2: gpio-controller@0 { - compatible = "snps,dw-apb-gpio-port"; - gpio-controller; - #gpio-cells = <2>; - ngpios = <32>; -+ gpio-ranges = <&padctrl0_apsys 0 0 32>; - reg = <0>; - interrupt-controller; - #interrupt-cells = <2>; -@@ -212,17 +547,18 @@ portc: gpio-controller@0 { - }; - }; - -- gpio3: gpio@ffe7f38000 { -+ gpio@ffe7f38000 { - compatible = "snps,dw-apb-gpio"; - reg = <0xff 0xe7f38000 0x0 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - -- portd: gpio-controller@0 { -+ gpio3: gpio-controller@0 { - compatible = "snps,dw-apb-gpio-port"; - gpio-controller; - #gpio-cells = <2>; -- ngpios = <32>; -+ ngpios = <23>; -+ gpio-ranges = <&padctrl0_apsys 0 32 23>; - reg = <0>; - interrupt-controller; - #interrupt-cells = <2>; -@@ -230,17 +566,34 @@ portd: gpio-controller@0 { - }; - }; - -- gpio0: gpio@ffec005000 { -+ padctrl1_apsys: pinctrl@ffe7f3c000 { -+ compatible = "thead,th1520-group2-pinctrl"; -+ reg = <0xff 0xe7f3c000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ }; -+ -+ gmac0_apb: syscon@ffec003000 { -+ compatible = "thead,th1520-gmac-apb", "syscon"; -+ reg = <0xff 0xec003000 0x0 0x1000>; -+ }; -+ -+ gmac1_apb: syscon@ffec004000 { -+ compatible = "thead,th1520-gmac-apb", "syscon"; -+ reg = <0xff 0xec004000 0x0 0x1000>; -+ }; -+ -+ gpio@ffec005000 { - compatible = "snps,dw-apb-gpio"; - reg = <0xff 0xec005000 0x0 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - -- porta: gpio-controller@0 { -+ gpio0: gpio-controller@0 { - compatible = "snps,dw-apb-gpio-port"; - gpio-controller; - #gpio-cells = <2>; - ngpios = <32>; -+ gpio-ranges = <&padctrl1_apsys 0 0 32>; - reg = <0>; - interrupt-controller; - #interrupt-cells = <2>; -@@ -248,17 +601,18 @@ porta: gpio-controller@0 { - }; - }; - -- gpio1: gpio@ffec006000 { -+ gpio@ffec006000 { - compatible = "snps,dw-apb-gpio"; - reg = <0xff 0xec006000 0x0 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - -- portb: gpio-controller@0 { -+ gpio1: gpio-controller@0 { - compatible = "snps,dw-apb-gpio-port"; - gpio-controller; - #gpio-cells = <2>; -- ngpios = <32>; -+ ngpios = <31>; -+ gpio-ranges = <&padctrl1_apsys 0 32 31>; - reg = <0>; - interrupt-controller; - #interrupt-cells = <2>; -@@ -266,6 +620,22 @@ portb: gpio-controller@0 { - }; - }; - -+ padctrl0_apsys: pinctrl@ffec007000 { -+ compatible = "thead,th1520-group3-pinctrl"; -+ reg = <0xff 0xec007000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ }; -+ -+ i2c2: i2c@ffec00c000 { -+ compatible = "snps,designware-i2c"; -+ reg = <0xff 0xec00c000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ - uart2: serial@ffec010000 { - compatible = "snps,dw-apb-uart"; - reg = <0xff 0xec010000 0x0 0x4000>; -@@ -276,6 +646,88 @@ uart2: serial@ffec010000 { - status = "disabled"; - }; - -+ i2c3: i2c@ffec014000 { -+ compatible = "snps,designware-i2c"; -+ reg = <0xff 0xec014000 0x0 0x1000>; -+ clocks = <&apb_clk>; -+ interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "disabled"; -+ }; -+ -+ pwm: pwm@ffec01c000 { -+ compatible = "thead,th1520-pwm"; -+ reg = <0xff 0xec01c000 0x0 0x4000>; -+ #pwm-cells = <3>; -+ clocks = <&osc_24m>; -+ }; -+ -+ audio_mbox: audio_mbox@0xffefc48000 { -+ compatible = "thead,light-audio-mbox-reg", "syscon"; -+ reg = <0xff 0xefc48000 0x0 0x1000>; -+ status = "okay"; -+ }; -+ -+ mbox_910t_client1: mbox_910t_client1 { -+ compatible = "thead,light-mbox-client"; -+ mbox-names = "902"; -+ mboxes = <&mbox_910t 1 0>; -+ status = "disabled"; -+ }; -+ -+ mbox_910t_client2: mbox_910t_client2 { -+ compatible = "thead,light-mbox-client"; -+ mbox-names = "906"; -+ mboxes = <&mbox_910t 2 0>; -+ audio-mbox-regmap = <&audio_mbox>; -+ status = "okay"; -+ }; -+ -+ clk: clock-controller@ffef010000 { -+ compatible = "thead,light-fm-ree-clk"; -+ reg = <0xff 0xef010000 0x0 0x1000>; -+ #clock-cells = <1>; -+ clocks = <&osc_32k>, <&osc_24m>, <&rc_24m>; -+ clock-names = "osc_32k", "osc_24m", "rc_24m"; -+ status = "okay"; -+ }; -+ -+ rst: reset-controller@ffef014000 { -+ compatible = "thead,th1520-reset", "syscon"; -+ reg = <0xff 0xef014000 0x0 0x1000>; -+ #reset-cells = <1>; -+ }; -+ -+ sys_reg: sys_reg@ffef010100 { -+ compatible = "thead,light_sys_reg"; -+ reg = <0xff 0xef010100 0x0 0x100>; -+ status = "okay"; -+ }; -+ -+ misc_sysreg: misc_sysreg@ffec02c000 { -+ compatible = "thead,th1520-misc-sysreg", "syscon"; -+ reg = <0xff 0xec02c000 0x0 0x1000>; -+ }; -+ -+ usb: usb@ffec03f000 { -+ compatible = "thead,th1520-usb"; -+ reg = <0xff 0xec03f000 0x0 0x1000>; -+ thead,misc-sysreg = <&misc_sysreg>; -+ #address-cells = <2>; -+ #size-cells = <2>; -+ ranges; -+ -+ usb_dwc3: usb@ffe7040000 { -+ compatible = "snps,dwc3"; -+ reg = <0xff 0xe7040000 0x0 0x10000>; -+ interrupts = <68 IRQ_TYPE_LEVEL_HIGH>; -+ dr_mode = "host"; -+ snps,usb3_lpm_capable; -+ status = "disabled"; -+ }; -+ }; -+ - dmac0: dma-controller@ffefc00000 { - compatible = "snps,axi-dma-1.01a"; - reg = <0xff 0xefc00000 0x0 0x1000>; -@@ -292,6 +744,33 @@ dmac0: dma-controller@ffefc00000 { - status = "disabled"; - }; - -+ emmc: mmc@ffe7080000 { -+ compatible = "thead,th1520-dwcmshc"; -+ reg = <0xff 0xe7080000 0x0 0x10000>; -+ interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&sdhci_clk>; -+ clock-names = "core"; -+ status = "disabled"; -+ }; -+ -+ sdio0: mmc@ffe7090000 { -+ compatible = "thead,th1520-dwcmshc"; -+ reg = <0xff 0xe7090000 0x0 0x10000>; -+ interrupts = <64 IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&sdhci_clk>; -+ clock-names = "core"; -+ status = "disabled"; -+ }; -+ -+ sdio1: mmc@ffe70a0000 { -+ compatible = "thead,th1520-dwcmshc"; -+ reg = <0xff 0xe70a0000 0x0 0x10000>; -+ interrupts = <71 IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&sdhci_clk>; -+ clock-names = "core"; -+ status = "disabled"; -+ }; -+ - timer0: timer@ffefc32000 { - compatible = "snps,dw-apb-timer"; - reg = <0xff 0xefc32000 0x0 0x14>; -@@ -384,17 +863,18 @@ timer7: timer@ffffc3303c { - status = "disabled"; - }; - -- ao_gpio0: gpio@fffff41000 { -+ gpio@fffff41000 { - compatible = "snps,dw-apb-gpio"; - reg = <0xff 0xfff41000 0x0 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - -- porte: gpio-controller@0 { -+ aogpio: gpio-controller@0 { - compatible = "snps,dw-apb-gpio-port"; - gpio-controller; - #gpio-cells = <2>; -- ngpios = <32>; -+ ngpios = <16>; -+ gpio-ranges = <&padctrl_aosys 0 9 16>; - reg = <0>; - interrupt-controller; - #interrupt-cells = <2>; -@@ -402,22 +882,77 @@ porte: gpio-controller@0 { - }; - }; - -- ao_gpio1: gpio@fffff52000 { -+ padctrl_aosys: pinctrl@fffff4a000 { -+ compatible = "thead,th1520-group1-pinctrl"; -+ reg = <0xff 0xfff4a000 0x0 0x2000>; -+ clocks = <&aonsys_clk>; -+ }; -+ -+ pvt: pvt@fffff4e000 { -+ compatible = "moortec,mr75203"; -+ reg = <0xff 0xfff4e000 0x0 0x80>, -+ <0xff 0xfff4e080 0x0 0x100>, -+ <0xff 0xfff4e180 0x0 0x680>, -+ <0xff 0xfff4e800 0x0 0x600>; -+ reg-names = "common", "ts", "pd", "vm"; -+ clocks = <&aonsys_clk>; -+ #thermal-sensor-cells = <1>; -+ }; -+ -+ gpio@fffff52000 { - compatible = "snps,dw-apb-gpio"; - reg = <0xff 0xfff52000 0x0 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - -- portf: gpio-controller@0 { -+ gpio4: gpio-controller@0 { - compatible = "snps,dw-apb-gpio-port"; - gpio-controller; - #gpio-cells = <2>; -- ngpios = <32>; -+ ngpios = <23>; -+ gpio-ranges = <&padctrl_aosys 0 25 22>, <&padctrl_aosys 22 7 1>; - reg = <0>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <55 IRQ_TYPE_LEVEL_HIGH>; - }; - }; -+ -+ mbox_910t: mbox@ffffc38000 { -+ compatible = "thead,light-mbox"; -+ reg = <0xff 0xffc38000 0x0 0x4000>, -+ <0xff 0xffc44000 0x0 0x1000>, -+ <0xff 0xffc4c000 0x0 0x1000>, -+ <0xff 0xffc54000 0x0 0x1000>; -+ reg-names = "local_base", "remote_icu0", "remote_icu1", "remote_icu2"; -+ #interrupt-cells = <2>; -+ interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&apb_clk>; -+ clock-names = "ipg"; -+ icu_cpu_id = <0>; -+ #mbox-cells = <2>; -+ }; -+ -+ watchdog0: watchdog@ffefc30000 { -+ compatible = "snps,dw-wdt"; -+ reg = <0xff 0xefc30000 0x0 0x1000>; -+ interrupt-parent = <&plic>; -+ interrupts = <24>; -+ clocks = <&clk CLKGEN_WDT0_PCLK>; -+ clock-names = "tclk"; -+ resets = <&rst TH1520_RESET_WDT0>; -+ status = "okay"; -+ }; -+ -+ watchdog1: watchdog@ffefc31000 { -+ compatible = "snps,dw-wdt"; -+ reg = <0xff 0xefc31000 0x0 0x1000>; -+ interrupt-parent = <&plic>; -+ interrupts = <25>; -+ clocks = <&clk CLKGEN_WDT1_PCLK>; -+ clock-names = "tclk"; -+ resets = <&rst TH1520_RESET_WDT1>; -+ status = "okay"; -+ }; - }; - }; -diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig -index ab86ec3b9eab..3de25be550fd 100644 ---- a/arch/riscv/configs/defconfig -+++ b/arch/riscv/configs/defconfig -@@ -27,10 +27,11 @@ CONFIG_EXPERT=y - CONFIG_PROFILING=y - CONFIG_SOC_MICROCHIP_POLARFIRE=y - CONFIG_ARCH_RENESAS=y --CONFIG_ARCH_THEAD=y - CONFIG_SOC_SIFIVE=y -+CONFIG_ARCH_SOPHGO=y - CONFIG_SOC_STARFIVE=y - CONFIG_ARCH_SUNXI=y -+CONFIG_ARCH_THEAD=y - CONFIG_SOC_VIRT=y - CONFIG_SMP=y - CONFIG_HOTPLUG_CPU=y -@@ -168,12 +169,15 @@ CONFIG_MMC=y - CONFIG_MMC_SDHCI=y - CONFIG_MMC_SDHCI_PLTFM=y - CONFIG_MMC_SDHCI_CADENCE=y -+CONFIG_MMC_SDHCI_OF_DWCMSHC=y - CONFIG_MMC_SPI=y - CONFIG_MMC_SUNXI=y - CONFIG_RTC_CLASS=y - CONFIG_RTC_DRV_SUN6I=y - CONFIG_DMADEVICES=y - CONFIG_DMA_SUN6I=m -+CONFIG_DW_AXI_DMAC=y -+CONFIG_RZ_DMAC=y - CONFIG_VIRTIO_PCI=y - CONFIG_VIRTIO_BALLOON=y - CONFIG_VIRTIO_INPUT=y -diff --git a/arch/riscv/configs/openeuler_defconfig b/arch/riscv/configs/openeuler_defconfig -index 24a04cd8c1c0..514aee201d9b 100644 ---- a/arch/riscv/configs/openeuler_defconfig -+++ b/arch/riscv/configs/openeuler_defconfig -@@ -2,6 +2,7 @@ - # Automatically generated file; DO NOT EDIT. - # Linux/riscv 6.6.0 Kernel Configuration - # -+CONFIG_TOOLS_SUPPORT_RELR=y - CONFIG_IRQ_WORK=y - CONFIG_BUILDTIME_TABLE_SORT=y - CONFIG_THREAD_INFO_IN_TASK=y -@@ -12,6 +13,7 @@ CONFIG_THREAD_INFO_IN_TASK=y - CONFIG_INIT_ENV_ARG_LIMIT=32 - # CONFIG_COMPILE_TEST is not set - # CONFIG_WERROR is not set -+# CONFIG_UAPI_HEADER_TEST is not set - CONFIG_LOCALVERSION="" - # CONFIG_LOCALVERSION_AUTO is not set - CONFIG_BUILD_SALT="" -@@ -70,6 +72,7 @@ CONFIG_CONTEXT_TRACKING_USER=y - # CONFIG_CONTEXT_TRACKING_USER_FORCE is not set - CONFIG_NO_HZ=y - CONFIG_HIGH_RES_TIMERS=y -+# CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE is not set - # end of Timers subsystem - - CONFIG_BPF=y -@@ -85,6 +88,7 @@ CONFIG_BPF_JIT_DEFAULT_ON=y - # CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set - # CONFIG_BPF_PRELOAD is not set - # CONFIG_BPF_LSM is not set -+# CONFIG_BPF_SCHED is not set - # end of BPF subsystem - - CONFIG_PREEMPT_VOLUNTARY_BUILD=y -@@ -110,6 +114,8 @@ CONFIG_TASK_XACCT=y - CONFIG_TASK_IO_ACCOUNTING=y - CONFIG_PSI=y - CONFIG_PSI_DEFAULT_DISABLED=y -+# CONFIG_PSI_CGROUP_V1 is not set -+# CONFIG_PSI_FINE_GRAINED is not set - # end of CPU/Task time and stats accounting - - CONFIG_CPU_ISOLATION=y -@@ -163,6 +169,7 @@ CONFIG_CGROUP_SCHED=y - CONFIG_FAIR_GROUP_SCHED=y - CONFIG_CFS_BANDWIDTH=y - CONFIG_RT_GROUP_SCHED=y -+# CONFIG_QOS_SCHED_DYNAMIC_AFFINITY is not set - CONFIG_SCHED_MM_CID=y - CONFIG_CGROUP_PIDS=y - CONFIG_CGROUP_RDMA=y -@@ -178,6 +185,8 @@ CONFIG_CGROUP_BPF=y - # CONFIG_CGROUP_DEBUG is not set - CONFIG_SOCK_CGROUP_DATA=y - # CONFIG_CGROUP_V1_KILL is not set -+# CONFIG_CGROUP_V1_STAT is not set -+# CONFIG_CGROUP_FILES is not set - CONFIG_NAMESPACES=y - CONFIG_UTS_NS=y - CONFIG_TIME_NS=y -@@ -185,6 +194,7 @@ CONFIG_IPC_NS=y - CONFIG_USER_NS=y - CONFIG_PID_NS=y - CONFIG_NET_NS=y -+# CONFIG_SCHED_STEAL is not set - CONFIG_CHECKPOINT_RESTORE=y - CONFIG_SCHED_AUTOGROUP=y - CONFIG_RELAY=y -@@ -197,6 +207,7 @@ CONFIG_RD_XZ=y - CONFIG_RD_LZO=y - CONFIG_RD_LZ4=y - CONFIG_RD_ZSTD=y -+CONFIG_INITRAMFS_FILE_METADATA="" - CONFIG_BOOT_CONFIG=y - # CONFIG_BOOT_CONFIG_FORCE is not set - # CONFIG_BOOT_CONFIG_EMBED is not set -@@ -291,19 +302,20 @@ CONFIG_FIX_EARLYCON_MEM=y - CONFIG_PGTABLE_LEVELS=5 - CONFIG_LOCKDEP_SUPPORT=y - CONFIG_RISCV_DMA_NONCOHERENT=y -+CONFIG_RISCV_NONSTANDARD_CACHE_OPS=y - - # - # SoC selection - # --CONFIG_ARCH_MICROCHIP_POLARFIRE=y --CONFIG_SOC_MICROCHIP_POLARFIRE=y -+# CONFIG_SOC_MICROCHIP_POLARFIRE is not set - # CONFIG_ARCH_RENESAS is not set - CONFIG_ARCH_SIFIVE=y - CONFIG_SOC_SIFIVE=y -+CONFIG_ARCH_SOPHGO=y - CONFIG_ARCH_STARFIVE=y - CONFIG_SOC_STARFIVE=y - # CONFIG_ARCH_SUNXI is not set --# CONFIG_ARCH_THEAD is not set -+CONFIG_ARCH_THEAD=y - CONFIG_ARCH_VIRT=y - CONFIG_SOC_VIRT=y - # end of SoC selection -@@ -315,7 +327,10 @@ CONFIG_SOC_VIRT=y - CONFIG_ERRATA_SIFIVE=y - CONFIG_ERRATA_SIFIVE_CIP_453=y - CONFIG_ERRATA_SIFIVE_CIP_1200=y --# CONFIG_ERRATA_THEAD is not set -+CONFIG_ERRATA_THEAD=y -+CONFIG_ERRATA_THEAD_PBMT=y -+CONFIG_ERRATA_THEAD_CMO=y -+CONFIG_ERRATA_THEAD_PMU=y - # end of CPU errata selection - - # -@@ -334,15 +349,12 @@ CONFIG_TUNE_GENERIC=y - CONFIG_NUMA=y - CONFIG_NODES_SHIFT=7 - CONFIG_RISCV_ALTERNATIVE=y -+CONFIG_RISCV_ALTERNATIVE_EARLY=y - CONFIG_RISCV_ISA_C=y - CONFIG_RISCV_ISA_SVNAPOT=y - CONFIG_RISCV_ISA_SVPBMT=y --CONFIG_TOOLCHAIN_HAS_V=y --CONFIG_RISCV_ISA_V=y --CONFIG_RISCV_ISA_V_DEFAULT_ENABLE=y - CONFIG_RISCV_ISA_ZICBOM=y - CONFIG_RISCV_ISA_ZICBOZ=y --CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE=y - CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y - CONFIG_FPU=y - CONFIG_IRQ_STACKS=y -@@ -374,14 +386,9 @@ CONFIG_COMPAT=y - # - # Boot options - # --CONFIG_CMDLINE="console=ttyAMA0" --CONFIG_CMDLINE_FALLBACK=y --# CONFIG_CMDLINE_EXTEND is not set --# CONFIG_CMDLINE_FORCE is not set -+CONFIG_CMDLINE="" - CONFIG_EFI_STUB=y - CONFIG_EFI=y --CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y --CONFIG_STACKPROTECTOR_PER_TASK=y - CONFIG_RISCV_ISA_FALLBACK=y - # end of Boot options - -@@ -461,6 +468,7 @@ CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y - # - CONFIG_CPUFREQ_DT=y - CONFIG_CPUFREQ_DT_PLATDEV=y -+CONFIG_RISCV_THEAD_LIGHT_CPUFREQ=y - # end of CPU Frequency scaling - # end of CPU Power Management - -@@ -566,7 +574,6 @@ CONFIG_HAVE_PREEMPT_DYNAMIC_KEY=y - CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y - CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y - CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y --CONFIG_DYNAMIC_SIGFRAME=y - - # - # GCOV-based kernel profiling -@@ -622,6 +629,7 @@ CONFIG_BLK_DEV_WRITE_MOUNTED=y - CONFIG_BLK_DEV_ZONED=y - CONFIG_BLK_DEV_THROTTLING=y - # CONFIG_BLK_DEV_THROTTLING_LOW is not set -+# CONFIG_BLK_DEV_SUPPORT_LEGACY_GLOBAL_LIMIT is not set - CONFIG_BLK_WBT=y - CONFIG_BLK_WBT_MQ=y - # CONFIG_BLK_CGROUP_IOLATENCY is not set -@@ -631,7 +639,10 @@ CONFIG_BLK_WBT_MQ=y - CONFIG_BLK_DEBUG_FS=y - CONFIG_BLK_DEBUG_FS_ZONED=y - # CONFIG_BLK_SED_OPAL is not set --# CONFIG_BLK_INLINE_ENCRYPTION is not set -+CONFIG_BLK_INLINE_ENCRYPTION=y -+CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y -+# CONFIG_BLK_DEV_DETECT_WRITING_PART0 is not set -+# CONFIG_BLK_DEV_WRITE_MOUNTED_DUMP is not set - - # - # Partition Types -@@ -692,13 +703,13 @@ CONFIG_ARCH_HAS_MMIOWB=y - CONFIG_MMIOWB=y - CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y - CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y -+# CONFIG_PID_MAX_PER_NAMESPACE is not set - CONFIG_FREEZER=y - - # - # Executable file formats - # - CONFIG_BINFMT_ELF=y --CONFIG_COMPAT_BINFMT_ELF=y - CONFIG_ELFCORE=y - CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y - CONFIG_BINFMT_SCRIPT=y -@@ -785,8 +796,8 @@ CONFIG_USE_PERCPU_NUMA_NODE_ID=y - CONFIG_CMA=y - # CONFIG_CMA_DEBUG is not set - # CONFIG_CMA_DEBUGFS is not set --# CONFIG_CMA_SYSFS is not set --CONFIG_CMA_AREAS=7 -+CONFIG_CMA_SYSFS=y -+CONFIG_CMA_AREAS=19 - CONFIG_GENERIC_EARLY_IOREMAP=y - # CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set - CONFIG_PAGE_IDLE_FLAG=y -@@ -810,7 +821,6 @@ CONFIG_LRU_GEN_ENABLED=y - CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y - CONFIG_PER_VMA_LOCK=y - CONFIG_LOCK_MM_AND_FIND_VMA=y --# CONFIG_ASCEND_OOM is not set - # CONFIG_PAGE_CACHE_LIMIT is not set - - # -@@ -917,6 +927,7 @@ CONFIG_DEFAULT_CUBIC=y - # CONFIG_DEFAULT_RENO is not set - CONFIG_DEFAULT_TCP_CONG="cubic" - CONFIG_TCP_MD5SIG=y -+# CONFIG_TCP_COMP is not set - CONFIG_IPV6=y - CONFIG_IPV6_ROUTER_PREF=y - CONFIG_IPV6_ROUTE_INFO=y -@@ -1556,10 +1567,12 @@ CONFIG_PAGE_POOL_STATS=y - CONFIG_FAILOVER=y - CONFIG_ETHTOOL_NETLINK=y - CONFIG_NETACC_BPF=y -+CONFIG_NETACC_TERRACE=y - - # - # Device Drivers - # -+CONFIG_ARM_AMBA=y - CONFIG_HAVE_PCI=y - CONFIG_PCI=y - CONFIG_PCI_DOMAINS=y -@@ -1606,14 +1619,22 @@ CONFIG_HOTPLUG_PCI_SHPC=y - # CONFIG_PCI_FTPCI100 is not set - CONFIG_PCI_HOST_COMMON=y - CONFIG_PCI_HOST_GENERIC=y --# CONFIG_PCIE_MICROCHIP_HOST is not set -+CONFIG_PCIE_MICROCHIP_HOST=y - CONFIG_PCIE_XILINX=y - - # - # Cadence-based PCIe controllers - # --# CONFIG_PCIE_CADENCE_PLAT_HOST is not set --# CONFIG_PCI_J721E_HOST is not set -+CONFIG_PCIE_CADENCE=y -+CONFIG_PCIE_CADENCE_HOST=y -+CONFIG_PCIE_CADENCE_EP=y -+CONFIG_PCIE_CADENCE_PLAT=y -+CONFIG_PCIE_CADENCE_PLAT_HOST=y -+CONFIG_PCIE_CADENCE_PLAT_EP=y -+CONFIG_PCIE_CADENCE_SOPHGO=y -+CONFIG_PCI_J721E=y -+CONFIG_PCI_J721E_HOST=y -+# CONFIG_PCI_J721E_EP is not set - # end of Cadence-based PCIe controllers - - # -@@ -1621,8 +1642,11 @@ CONFIG_PCIE_XILINX=y - # - CONFIG_PCIE_DW=y - CONFIG_PCIE_DW_HOST=y -+CONFIG_PCIE_DW_EP=y - # CONFIG_PCI_MESON is not set --# CONFIG_PCIE_DW_PLAT_HOST is not set -+CONFIG_PCIE_DW_PLAT=y -+CONFIG_PCIE_DW_PLAT_HOST=y -+CONFIG_PCIE_DW_PLAT_EP=y - CONFIG_PCIE_FU740=y - # end of DesignWare-based PCIe controllers - -@@ -1635,7 +1659,10 @@ CONFIG_PCIE_FU740=y - # - # PCI Endpoint - # --# CONFIG_PCI_ENDPOINT is not set -+CONFIG_PCI_ENDPOINT=y -+CONFIG_PCI_ENDPOINT_CONFIGFS=y -+# CONFIG_PCI_EPF_TEST is not set -+# CONFIG_PCI_EPF_NTB is not set - # end of PCI Endpoint - - # -@@ -1677,8 +1704,9 @@ CONFIG_WANT_DEV_COREDUMP=y - # CONFIG_DEBUG_DEVRES is not set - # CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set - # CONFIG_TEST_ASYNC_DRIVER_PROBE is not set -+CONFIG_GENERIC_CPU_DEVICES=y - CONFIG_REGMAP=y --CONFIG_REGMAP_I2C=m -+CONFIG_REGMAP_I2C=y - CONFIG_REGMAP_SPI=m - CONFIG_REGMAP_MMIO=y - CONFIG_DMA_SHARED_BUFFER=y -@@ -1716,7 +1744,7 @@ CONFIG_PROC_EVENTS=y - - # CONFIG_FIRMWARE_MEMMAP is not set - CONFIG_SYSFB=y --# CONFIG_SYSFB_SIMPLEFB is not set -+CONFIG_SYSFB_SIMPLEFB=y - # CONFIG_GOOGLE_FIRMWARE is not set - - # -@@ -1743,6 +1771,9 @@ CONFIG_EFI_EARLYCON=y - # Tegra firmware driver - # - # end of Tegra firmware driver -+ -+CONFIG_LIGHT_AON=y -+CONFIG_LIGHT_AON_PD=y - # end of Firmware Drivers - - # CONFIG_GNSS is not set -@@ -1922,8 +1953,8 @@ CONFIG_BLK_DEV_RBD=m - # - # NVME Support - # --CONFIG_NVME_CORE=m --CONFIG_BLK_DEV_NVME=m -+CONFIG_NVME_CORE=y -+CONFIG_BLK_DEV_NVME=y - CONFIG_NVME_MULTIPATH=y - # CONFIG_NVME_VERBOSE_ERRORS is not set - # CONFIG_NVME_HWMON is not set -@@ -1963,7 +1994,7 @@ CONFIG_SENSORS_APDS990X=m - # CONFIG_HMC6352 is not set - # CONFIG_DS1682 is not set - # CONFIG_LATTICE_ECP3_CONFIG is not set --# CONFIG_SRAM is not set -+CONFIG_SRAM=y - # CONFIG_DW_XDATA_PCIE is not set - # CONFIG_PCI_ENDPOINT_TEST is not set - # CONFIG_XILINX_SDFEC is not set -@@ -2163,6 +2194,7 @@ CONFIG_ATA_PIIX=m - # CONFIG_SATA_ULI is not set - # CONFIG_SATA_VIA is not set - # CONFIG_SATA_VITESSE is not set -+# CONFIG_SATA_ZHAOXIN is not set - - # - # PATA SFF controllers with BMDMA -@@ -2431,6 +2463,8 @@ CONFIG_ICE=m - CONFIG_ICE_SWITCHDEV=y - CONFIG_FM10K=m - # CONFIG_IGC is not set -+CONFIG_NET_VENDOR_MUCSE=y -+# CONFIG_MXGBE is not set - # CONFIG_JME is not set - CONFIG_NET_VENDOR_ADI=y - # CONFIG_ADIN1110 is not set -@@ -2535,7 +2569,17 @@ CONFIG_EPIC100=m - CONFIG_SMSC911X=m - CONFIG_SMSC9420=m - # CONFIG_NET_VENDOR_SOCIONEXT is not set --# CONFIG_NET_VENDOR_STMICRO is not set -+CONFIG_NET_VENDOR_STMICRO=y -+CONFIG_STMMAC_ETH=m -+# CONFIG_STMMAC_SELFTESTS is not set -+CONFIG_STMMAC_PLATFORM=m -+# CONFIG_DWMAC_DWC_QOS_ETH is not set -+CONFIG_DWMAC_GENERIC=m -+CONFIG_DWMAC_STARFIVE=m -+CONFIG_DWMAC_THEAD=m -+# CONFIG_DWMAC_INTEL_PLAT is not set -+# CONFIG_DWMAC_LOONGSON is not set -+# CONFIG_STMMAC_PCI is not set - # CONFIG_NET_VENDOR_SUN is not set - # CONFIG_NET_VENDOR_SYNOPSYS is not set - # CONFIG_NET_VENDOR_TEHUTI is not set -@@ -2903,7 +2947,7 @@ CONFIG_KEYBOARD_ATKBD=y - # CONFIG_KEYBOARD_QT2160 is not set - # CONFIG_KEYBOARD_DLINK_DIR685 is not set - # CONFIG_KEYBOARD_LKKBD is not set --# CONFIG_KEYBOARD_GPIO is not set -+CONFIG_KEYBOARD_GPIO=y - # CONFIG_KEYBOARD_GPIO_POLLED is not set - # CONFIG_KEYBOARD_TCA6416 is not set - # CONFIG_KEYBOARD_TCA8418 is not set -@@ -3005,6 +3049,7 @@ CONFIG_RMI4_F30=y - # - CONFIG_SERIO=y - CONFIG_SERIO_SERPORT=y -+# CONFIG_SERIO_AMBAKMI is not set - # CONFIG_SERIO_PCIPS2 is not set - CONFIG_SERIO_LIBPS2=y - CONFIG_SERIO_RAW=m -@@ -3063,6 +3108,8 @@ CONFIG_SERIAL_OF_PLATFORM=y - # - # Non-8250 serial port support - # -+# CONFIG_SERIAL_AMBA_PL010 is not set -+# CONFIG_SERIAL_AMBA_PL011 is not set - # CONFIG_SERIAL_EARLYCON_SEMIHOST is not set - # CONFIG_SERIAL_KGDB_NMI is not set - # CONFIG_SERIAL_MAX3100 is not set -@@ -3148,7 +3195,7 @@ CONFIG_TCG_TIS_ST33ZP24_SPI=m - CONFIG_I2C=y - CONFIG_I2C_BOARDINFO=y - CONFIG_I2C_COMPAT=y --CONFIG_I2C_CHARDEV=m -+CONFIG_I2C_CHARDEV=y - CONFIG_I2C_MUX=m - - # -@@ -3166,16 +3213,9 @@ CONFIG_I2C_MUX_PINCTRL=m - CONFIG_I2C_MUX_MLXCPLD=m - # end of Multiplexer I2C Chip support - --# CONFIG_I2C_HELPER_AUTO is not set --CONFIG_I2C_SMBUS=m -- --# --# I2C Algorithms --# -+CONFIG_I2C_HELPER_AUTO=y - CONFIG_I2C_ALGOBIT=y --# CONFIG_I2C_ALGOPCF is not set - CONFIG_I2C_ALGOPCA=m --# end of I2C Algorithms - - # - # I2C Hardware Bus support -@@ -3184,6 +3224,7 @@ CONFIG_I2C_ALGOPCA=m - # - # PC SMBus host controller drivers - # -+CONFIG_I2C_CCGX_UCSI=m - # CONFIG_I2C_ALI1535 is not set - # CONFIG_I2C_ALI1563 is not set - # CONFIG_I2C_ALI15X3 is not set -@@ -3204,14 +3245,14 @@ CONFIG_I2C_NFORCE2=m - # I2C system bus drivers (mostly embedded / system-on-chip) - # - # CONFIG_I2C_CBUS_GPIO is not set --CONFIG_I2C_DESIGNWARE_CORE=m --# CONFIG_I2C_DESIGNWARE_SLAVE is not set --CONFIG_I2C_DESIGNWARE_PLATFORM=m --# CONFIG_I2C_DESIGNWARE_PCI is not set -+CONFIG_I2C_DESIGNWARE_CORE=y -+CONFIG_I2C_DESIGNWARE_SLAVE=y -+CONFIG_I2C_DESIGNWARE_PLATFORM=y -+CONFIG_I2C_DESIGNWARE_PCI=m - # CONFIG_I2C_EMEV2 is not set - CONFIG_I2C_GPIO=m - # CONFIG_I2C_GPIO_FAULT_INJECTOR is not set --# CONFIG_I2C_MICROCHIP_CORE is not set -+# CONFIG_I2C_NOMADIK is not set - # CONFIG_I2C_OCORES is not set - CONFIG_I2C_PCA_PLATFORM=m - # CONFIG_I2C_RK3X is not set -@@ -3268,6 +3309,7 @@ CONFIG_SPI_DW_MMIO=y - # CONFIG_SPI_MICROCHIP_CORE_QSPI is not set - # CONFIG_SPI_OC_TINY is not set - # CONFIG_SPI_PCI1XXXX is not set -+# CONFIG_SPI_PL022 is not set - # CONFIG_SPI_PXA2XX is not set - # CONFIG_SPI_SC18IS602 is not set - CONFIG_SPI_SIFIVE=y -@@ -3334,6 +3376,7 @@ CONFIG_GENERIC_PINCONF=y - # CONFIG_PINCTRL_SINGLE is not set - # CONFIG_PINCTRL_STMFX is not set - # CONFIG_PINCTRL_SX150X is not set -+CONFIG_PINCTRL_TH1520=y - - # - # Renesas pinctrl drivers -@@ -3359,7 +3402,7 @@ CONFIG_GPIO_GENERIC=y - # - # CONFIG_GPIO_74XX_MMIO is not set - # CONFIG_GPIO_ALTERA is not set --# CONFIG_GPIO_CADENCE is not set -+CONFIG_GPIO_CADENCE=m - CONFIG_GPIO_DWAPB=y - # CONFIG_GPIO_EXAR is not set - # CONFIG_GPIO_FTGPIO010 is not set -@@ -3368,6 +3411,7 @@ CONFIG_GPIO_GENERIC_PLATFORM=m - # CONFIG_GPIO_HLWD is not set - # CONFIG_GPIO_LOGICVC is not set - # CONFIG_GPIO_MB86S7X is not set -+# CONFIG_GPIO_PL061 is not set - CONFIG_GPIO_SIFIVE=y - # CONFIG_GPIO_SYSCON is not set - # CONFIG_GPIO_XILINX is not set -@@ -3383,7 +3427,8 @@ CONFIG_GPIO_SIFIVE=y - # CONFIG_GPIO_GW_PLD is not set - # CONFIG_GPIO_MAX7300 is not set - # CONFIG_GPIO_MAX732X is not set --# CONFIG_GPIO_PCA953X is not set -+CONFIG_GPIO_PCA953X=y -+CONFIG_GPIO_PCA953X_IRQ=y - # CONFIG_GPIO_PCA9570 is not set - # CONFIG_GPIO_PCF857X is not set - # CONFIG_GPIO_TPIC2810 is not set -@@ -3566,7 +3611,7 @@ CONFIG_SENSORS_MAX31790=m - CONFIG_SENSORS_MCP3021=m - # CONFIG_SENSORS_TC654 is not set - # CONFIG_SENSORS_TPS23861 is not set --# CONFIG_SENSORS_MR75203 is not set -+CONFIG_SENSORS_MR75203=m - CONFIG_SENSORS_ADCXX=m - CONFIG_SENSORS_LM63=m - CONFIG_SENSORS_LM70=m -@@ -3646,7 +3691,7 @@ CONFIG_SENSORS_UCD9200=m - # CONFIG_SENSORS_XDPE152 is not set - # CONFIG_SENSORS_XDPE122 is not set - CONFIG_SENSORS_ZL6100=m --CONFIG_SENSORS_PWM_FAN=m -+CONFIG_SENSORS_PWM_FAN=y - # CONFIG_SENSORS_SBTSI is not set - # CONFIG_SENSORS_SBRMI is not set - CONFIG_SENSORS_SHT15=m -@@ -3744,6 +3789,7 @@ CONFIG_ALIM7101_WDT=m - CONFIG_I6300ESB_WDT=m - # CONFIG_MEN_A21_WDT is not set - CONFIG_STARFIVE_WATCHDOG=y -+CONFIG_LIGHT_PMIC_WATCHDOG=y - - # - # PCI-based Watchdog Cards -@@ -3894,7 +3940,7 @@ CONFIG_MFD_SYSCON=y - - CONFIG_REGULATOR=y - # CONFIG_REGULATOR_DEBUG is not set --# CONFIG_REGULATOR_FIXED_VOLTAGE is not set -+CONFIG_REGULATOR_FIXED_VOLTAGE=y - # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set - # CONFIG_REGULATOR_USERSPACE_CONSUMER is not set - # CONFIG_REGULATOR_88PG86X is not set -@@ -3937,7 +3983,7 @@ CONFIG_REGULATOR=y - # CONFIG_REGULATOR_PV88060 is not set - # CONFIG_REGULATOR_PV88080 is not set - # CONFIG_REGULATOR_PV88090 is not set --# CONFIG_REGULATOR_PWM is not set -+CONFIG_REGULATOR_PWM=y - # CONFIG_REGULATOR_RAA215300 is not set - # CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set - # CONFIG_REGULATOR_RT4801 is not set -@@ -3965,6 +4011,7 @@ CONFIG_REGULATOR=y - # CONFIG_REGULATOR_TPS65132 is not set - # CONFIG_REGULATOR_TPS6524X is not set - # CONFIG_REGULATOR_VCTRL is not set -+CONFIG_REGULATOR_LIGHT_AON=y - # CONFIG_RC_CORE is not set - - # -@@ -4644,8 +4691,9 @@ CONFIG_AUXDISPLAY=y - # CONFIG_CHARLCD_BL_OFF is not set - # CONFIG_CHARLCD_BL_ON is not set - CONFIG_CHARLCD_BL_FLASH=y --CONFIG_DRM=m --CONFIG_DRM_KMS_HELPER=m -+CONFIG_DRM=y -+# CONFIG_DRM_DEBUG_MM is not set -+CONFIG_DRM_KMS_HELPER=y - # CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set - # CONFIG_DRM_DEBUG_MODESET_LOCK is not set - CONFIG_DRM_FBDEV_EMULATION=y -@@ -4841,7 +4889,10 @@ CONFIG_FB_EFI=y - # CONFIG_FB_RIVA is not set - # CONFIG_FB_I740 is not set - # CONFIG_FB_MATROX is not set --# CONFIG_FB_RADEON is not set -+CONFIG_FB_RADEON=y -+CONFIG_FB_RADEON_I2C=y -+CONFIG_FB_RADEON_BACKLIGHT=y -+# CONFIG_FB_RADEON_DEBUG is not set - # CONFIG_FB_ATY128 is not set - # CONFIG_FB_ATY is not set - # CONFIG_FB_S3 is not set -@@ -4871,6 +4922,7 @@ CONFIG_FB_CORE=y - CONFIG_FB_NOTIFY=y - # CONFIG_FIRMWARE_EDID is not set - CONFIG_FB_DEVICE=y -+CONFIG_FB_DDC=y - CONFIG_FB_CFB_FILLRECT=y - CONFIG_FB_CFB_COPYAREA=y - CONFIG_FB_CFB_IMAGEBLIT=y -@@ -4883,7 +4935,7 @@ CONFIG_FB_DEFERRED_IO=y - CONFIG_FB_IOMEM_HELPERS=y - CONFIG_FB_SYSMEM_HELPERS=y - CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y --CONFIG_FB_BACKLIGHT=m -+CONFIG_FB_BACKLIGHT=y - CONFIG_FB_MODE_HELPERS=y - CONFIG_FB_TILEBLITTING=y - # end of Frame buffer Devices -@@ -4931,10 +4983,10 @@ CONFIG_DUMMY_CONSOLE=y - CONFIG_DUMMY_CONSOLE_COLUMNS=80 - CONFIG_DUMMY_CONSOLE_ROWS=25 - CONFIG_FRAMEBUFFER_CONSOLE=y --# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set -+CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION=y - CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y - CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y --# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set -+CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y - # end of Console display driver support - - CONFIG_LOGO=y -@@ -5319,8 +5371,29 @@ CONFIG_USB_MICROTEK=m - # USB dual-mode controller drivers - # - # CONFIG_USB_CDNS_SUPPORT is not set --# CONFIG_USB_MUSB_HDRC is not set --# CONFIG_USB_DWC3 is not set -+CONFIG_USB_MUSB_HDRC=y -+CONFIG_USB_MUSB_HOST=y -+ -+# -+# Platform Glue Layer -+# -+ -+# -+# MUSB DMA mode -+# -+# CONFIG_MUSB_PIO_ONLY is not set -+CONFIG_USB_DWC3=m -+# CONFIG_USB_DWC3_ULPI is not set -+# CONFIG_USB_DWC3_HOST is not set -+# CONFIG_USB_DWC3_GADGET is not set -+CONFIG_USB_DWC3_DUAL_ROLE=y -+ -+# -+# Platform Glue Driver Support -+# -+CONFIG_USB_DWC3_HAPS=m -+CONFIG_USB_DWC3_OF_SIMPLE=m -+CONFIG_USB_DWC3_THEAD=m - # CONFIG_USB_DWC2 is not set - # CONFIG_USB_CHIPIDEA is not set - # CONFIG_USB_ISP1760 is not set -@@ -5412,7 +5485,7 @@ CONFIG_USB_HSIC_USB3503=m - # CONFIG_USB_HSIC_USB4604 is not set - # CONFIG_USB_LINK_LAYER_TEST is not set - CONFIG_USB_CHAOSKEY=m --# CONFIG_USB_ONBOARD_HUB is not set -+CONFIG_USB_ONBOARD_HUB=m - CONFIG_USB_ATM=m - # CONFIG_USB_SPEEDTOUCH is not set - CONFIG_USB_CXACRU=m -@@ -5427,7 +5500,59 @@ CONFIG_USB_XUSBATM=m - # CONFIG_USB_ISP1301 is not set - # end of USB Physical Layer drivers - --# CONFIG_USB_GADGET is not set -+CONFIG_USB_GADGET=m -+# CONFIG_USB_GADGET_DEBUG is not set -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+# CONFIG_USB_GADGET_DEBUG_FS is not set -+CONFIG_USB_GADGET_VBUS_DRAW=2 -+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 -+ -+# -+# USB Peripheral Controller -+# -+# CONFIG_USB_GR_UDC is not set -+# CONFIG_USB_R8A66597 is not set -+# CONFIG_USB_PXA27X is not set -+# CONFIG_USB_MV_UDC is not set -+# CONFIG_USB_MV_U3D is not set -+# CONFIG_USB_SNP_UDC_PLAT is not set -+# CONFIG_USB_M66592 is not set -+# CONFIG_USB_BDC_UDC is not set -+# CONFIG_USB_AMD5536UDC is not set -+# CONFIG_USB_NET2272 is not set -+# CONFIG_USB_NET2280 is not set -+# CONFIG_USB_GOKU is not set -+# CONFIG_USB_EG20T is not set -+# CONFIG_USB_GADGET_XILINX is not set -+# CONFIG_USB_MAX3420_UDC is not set -+# CONFIG_USB_DUMMY_HCD is not set -+# end of USB Peripheral Controller -+ -+# CONFIG_USB_CONFIGFS is not set -+ -+# -+# USB Gadget precomposed configurations -+# -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_AUDIO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_G_NCM is not set -+# CONFIG_USB_GADGETFS is not set -+# CONFIG_USB_FUNCTIONFS is not set -+# CONFIG_USB_MASS_STORAGE is not set -+# CONFIG_USB_GADGET_TARGET is not set -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_MIDI_GADGET is not set -+# CONFIG_USB_G_PRINTER is not set -+# CONFIG_USB_CDC_COMPOSITE is not set -+# CONFIG_USB_G_ACM_MS is not set -+# CONFIG_USB_G_MULTI is not set -+# CONFIG_USB_G_HID is not set -+# CONFIG_USB_G_DBGP is not set -+# CONFIG_USB_G_WEBCAM is not set -+# CONFIG_USB_RAW_GADGET is not set -+# end of USB Gadget precomposed configurations -+ - CONFIG_TYPEC=m - CONFIG_TYPEC_TCPM=m - CONFIG_TYPEC_TCPCI=m -@@ -5464,15 +5589,17 @@ CONFIG_USB_ROLE_SWITCH=y - CONFIG_MMC=y - CONFIG_PWRSEQ_EMMC=m - CONFIG_PWRSEQ_SIMPLE=m --CONFIG_MMC_BLOCK=m -+CONFIG_MMC_BLOCK=y - CONFIG_MMC_BLOCK_MINORS=8 - CONFIG_SDIO_UART=m - # CONFIG_MMC_TEST is not set -+CONFIG_MMC_CRYPTO=y - - # - # MMC/SD/SDIO Host Controller Drivers - # - # CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_ARMMMCI is not set - CONFIG_MMC_SDHCI=y - CONFIG_MMC_SDHCI_IO_ACCESSORS=y - CONFIG_MMC_SDHCI_PCI=m -@@ -5480,12 +5607,13 @@ CONFIG_MMC_RICOH_MMC=y - CONFIG_MMC_SDHCI_PLTFM=y - # CONFIG_MMC_SDHCI_OF_ARASAN is not set - # CONFIG_MMC_SDHCI_OF_AT91 is not set --# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set -+CONFIG_MMC_SDHCI_OF_DWCMSHC=y - CONFIG_MMC_SDHCI_CADENCE=y - # CONFIG_MMC_SDHCI_F_SDH30 is not set - # CONFIG_MMC_SDHCI_MILBEAUT is not set - CONFIG_MMC_TIFM_SD=m - CONFIG_MMC_SPI=y -+CONFIG_MMC_SDHCI_SOPHGO=y - CONFIG_MMC_CB710=m - CONFIG_MMC_VIA_SDMMC=m - CONFIG_MMC_DW=m -@@ -5494,15 +5622,15 @@ CONFIG_MMC_DW_BLUEFIELD=m - # CONFIG_MMC_DW_EXYNOS is not set - # CONFIG_MMC_DW_HI3798CV200 is not set - # CONFIG_MMC_DW_K3 is not set --# CONFIG_MMC_DW_PCI is not set -+CONFIG_MMC_DW_PCI=m - # CONFIG_MMC_DW_STARFIVE is not set - CONFIG_MMC_VUB300=m - CONFIG_MMC_USHC=m - # CONFIG_MMC_USDHI6ROL0 is not set --# CONFIG_MMC_REALTEK_PCI is not set --# CONFIG_MMC_REALTEK_USB is not set --CONFIG_MMC_CQHCI=m --# CONFIG_MMC_HSQ is not set -+CONFIG_MMC_REALTEK_PCI=m -+CONFIG_MMC_REALTEK_USB=m -+CONFIG_MMC_CQHCI=y -+CONFIG_MMC_HSQ=m - CONFIG_MMC_TOSHIBA_PCI=m - CONFIG_MMC_MTK=m - CONFIG_MMC_SDHCI_XENON=m -@@ -5656,6 +5784,7 @@ CONFIG_EDAC_SUPPORT=y - CONFIG_EDAC=y - CONFIG_EDAC_LEGACY_SYSFS=y - # CONFIG_EDAC_DEBUG is not set -+# CONFIG_EDAC_SIFIVE is not set - CONFIG_RTC_LIB=y - CONFIG_RTC_CLASS=y - CONFIG_RTC_HCTOSYS=y -@@ -5766,6 +5895,8 @@ CONFIG_RTC_DRV_RP5C01=m - # - # on-CPU RTC drivers - # -+# CONFIG_RTC_DRV_PL030 is not set -+# CONFIG_RTC_DRV_PL031 is not set - # CONFIG_RTC_DRV_CADENCE is not set - # CONFIG_RTC_DRV_FTRTC010 is not set - # CONFIG_RTC_DRV_R7301 is not set -@@ -5774,7 +5905,6 @@ CONFIG_RTC_DRV_RP5C01=m - # HID Sensor RTC drivers - # - CONFIG_RTC_DRV_GOLDFISH=y --# CONFIG_RTC_DRV_POLARFIRE_SOC is not set - CONFIG_DMADEVICES=y - # CONFIG_DMADEVICES_DEBUG is not set - -@@ -5782,11 +5912,14 @@ CONFIG_DMADEVICES=y - # DMA Devices - # - CONFIG_DMA_ENGINE=y -+CONFIG_DMA_VIRTUAL_CHANNELS=y - CONFIG_DMA_OF=y - # CONFIG_ALTERA_MSGDMA is not set --# CONFIG_DW_AXI_DMAC is not set -+# CONFIG_AMBA_PL08X is not set -+CONFIG_DW_AXI_DMAC=y - # CONFIG_FSL_EDMA is not set - # CONFIG_INTEL_IDMA64 is not set -+# CONFIG_PL330_DMA is not set - # CONFIG_PLX_DMA is not set - # CONFIG_XILINX_DMA is not set - # CONFIG_XILINX_XDMA is not set -@@ -5867,6 +6000,7 @@ CONFIG_VHOST_MENU=y - CONFIG_VHOST_NET=m - CONFIG_VHOST_SCSI=m - CONFIG_VHOST_VSOCK=m -+# CONFIG_VHOST_VDPA_MIGRATION is not set - # CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set - - # -@@ -5901,7 +6035,6 @@ CONFIG_COMMON_CLK=y - # CONFIG_COMMON_CLK_VC7 is not set - # CONFIG_COMMON_CLK_FIXED_MMIO is not set - CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC=y --CONFIG_MCHP_CLK_MPFS=y - CONFIG_CLK_SIFIVE=y - CONFIG_CLK_SIFIVE_PRCI=y - CONFIG_CLK_STARFIVE_JH71X0=y -@@ -5915,6 +6048,9 @@ CONFIG_CLK_STARFIVE_JH7110_ISP=m - CONFIG_CLK_STARFIVE_JH7110_VOUT=m - # CONFIG_XILINX_VCU is not set - # CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set -+CONFIG_THEAD_CLK=y -+# CONFIG_CLK_LIGHT_MPW is not set -+CONFIG_CLK_LIGHT_FM=y - CONFIG_HWSPINLOCK=y - - # -@@ -5922,14 +6058,19 @@ CONFIG_HWSPINLOCK=y - # - CONFIG_TIMER_OF=y - CONFIG_TIMER_PROBE=y -+CONFIG_DW_APB_TIMER=y -+CONFIG_DW_APB_TIMER_OF=y - CONFIG_RISCV_TIMER=y - # end of Clock Source drivers - - CONFIG_MAILBOX=y -+# CONFIG_ARM_MHU is not set -+# CONFIG_ARM_MHU_V2 is not set - # CONFIG_PLATFORM_MHU is not set -+# CONFIG_PL320_MBOX is not set - # CONFIG_ALTERA_MBOX is not set - # CONFIG_MAILBOX_TEST is not set --# CONFIG_POLARFIRE_SOC_MAILBOX is not set -+CONFIG_THEAD_LIGHT_MBOX=y - CONFIG_IOMMU_API=y - CONFIG_IOMMU_SUPPORT=y - -@@ -5939,8 +6080,8 @@ CONFIG_IOMMU_SUPPORT=y - # end of Generic IOMMU Pagetable Support - - # CONFIG_IOMMU_DEBUGFS is not set --CONFIG_IOMMU_DEFAULT_DMA_STRICT=y --# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set -+# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set -+CONFIG_IOMMU_DEFAULT_DMA_LAZY=y - # CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set - CONFIG_OF_IOMMU=y - # CONFIG_IOMMUFD is not set -@@ -5959,6 +6100,7 @@ CONFIG_RPMSG_CHAR=y - CONFIG_RPMSG_CTRL=y - CONFIG_RPMSG_NS=y - # CONFIG_RPMSG_QCOM_GLINK_RPM is not set -+CONFIG_RPMSG_THEAD_LIGHT=y - CONFIG_RPMSG_VIRTIO=y - # end of Rpmsg drivers - -@@ -6007,7 +6149,7 @@ CONFIG_RPMSG_VIRTIO=y - # CONFIG_QCOM_PMIC_GLINK is not set - # end of Qualcomm SoC drivers - --# CONFIG_SIFIVE_CCACHE is not set -+CONFIG_SIFIVE_CCACHE=y - CONFIG_JH71XX_PMU=y - # CONFIG_SOC_TI is not set - -@@ -6015,6 +6157,12 @@ CONFIG_JH71XX_PMU=y - # Xilinx SoC drivers - # - # end of Xilinx SoC drivers -+ -+# -+# Thead SoC drivers -+# -+CONFIG_LIGHT_REBOOTMODE=y -+# end of Thead SoC drivers - # end of SOC (System On Chip) specific Drivers - - # CONFIG_PM_DEVFREQ is not set -@@ -6041,9 +6189,9 @@ CONFIG_PWM_SYSFS=y - # CONFIG_PWM_CLK is not set - # CONFIG_PWM_DWC is not set - # CONFIG_PWM_FSL_FTM is not set --# CONFIG_PWM_MICROCHIP_CORE is not set - # CONFIG_PWM_PCA9685 is not set --# CONFIG_PWM_SIFIVE is not set -+CONFIG_PWM_SIFIVE=m -+CONFIG_PWM_THEAD=m - # CONFIG_PWM_XILINX is not set - - # -@@ -6058,8 +6206,8 @@ CONFIG_SIFIVE_PLIC=y - - # CONFIG_IPACK_BUS is not set - CONFIG_RESET_CONTROLLER=y --CONFIG_RESET_POLARFIRE_SOC=y - CONFIG_RESET_SIMPLE=y -+CONFIG_RESET_TH1520=y - # CONFIG_RESET_TI_SYSCON is not set - # CONFIG_RESET_TI_TPS380X is not set - CONFIG_RESET_STARFIVE_JH71X0=y -@@ -6118,6 +6266,12 @@ CONFIG_USB4=m - # CONFIG_ANDROID_BINDER_IPC is not set - # end of Android - -+# -+# Vendor Hooks -+# -+# CONFIG_VENDOR_HOOKS is not set -+# end of Vendor Hooks -+ - CONFIG_LIBNVDIMM=m - CONFIG_BLK_DEV_PMEM=m - CONFIG_ND_CLAIM=y -@@ -6153,17 +6307,23 @@ CONFIG_NVMEM_SYSFS=y - CONFIG_PM_OPP=y - # CONFIG_SIOX is not set - # CONFIG_SLIMBUS is not set --# CONFIG_INTERCONNECT is not set -+CONFIG_INTERCONNECT=y - # CONFIG_COUNTER is not set - # CONFIG_MOST is not set - # CONFIG_PECI is not set - # CONFIG_HTE is not set -+ -+# -+# CPU Inspect -+# -+# CONFIG_CPU_INSPECT is not set -+# end of CPU Inspect - # end of Device Drivers - - # - # File systems - # --# CONFIG_VALIDATE_FS_PARSER is not set -+CONFIG_VALIDATE_FS_PARSER=y - CONFIG_FS_IOMAP=y - CONFIG_BUFFER_HEAD=y - CONFIG_LEGACY_DIRECT_IO=y -@@ -6176,6 +6336,7 @@ CONFIG_EXT4_USE_FOR_EXT2=y - CONFIG_EXT4_FS_POSIX_ACL=y - CONFIG_EXT4_FS_SECURITY=y - # CONFIG_EXT4_DEBUG is not set -+# CONFIG_EXT4_ERROR_REPORT is not set - CONFIG_JBD2=y - # CONFIG_JBD2_DEBUG is not set - CONFIG_FS_MBCACHE=y -@@ -6296,6 +6457,7 @@ CONFIG_PROC_PAGE_MONITOR=y - CONFIG_PROC_CHILDREN=y - CONFIG_KERNFS=y - CONFIG_SYSFS=y -+CONFIG_DIRTY_PAGES=y - CONFIG_TMPFS=y - CONFIG_TMPFS_POSIX_ACL=y - CONFIG_TMPFS_XATTR=y -@@ -6306,6 +6468,7 @@ CONFIG_HUGETLBFS=y - CONFIG_HUGETLB_PAGE=y - CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y - # CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set -+# CONFIG_HUGETLB_ALLOC_LIMIT is not set - CONFIG_ARCH_HAS_GIGANTIC_PAGE=y - CONFIG_CONFIGFS_FS=y - CONFIG_EFIVAR_FS=y -@@ -6570,7 +6733,12 @@ CONFIG_IMA_X509_PATH="/etc/keys/x509_ima.der" - CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS=y - CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS=y - # CONFIG_IMA_DISABLE_HTABLE is not set -+# CONFIG_IMA_DIGEST_LIST is not set - CONFIG_EVM=y -+# CONFIG_EVM_DEFAULT_HASH_SHA1 is not set -+CONFIG_EVM_DEFAULT_HASH_SHA256=y -+# CONFIG_EVM_DEFAULT_HASH_SHA512 is not set -+CONFIG_EVM_DEFAULT_HASH="sha256" - CONFIG_EVM_ATTR_FSUUID=y - # CONFIG_EVM_ADD_XATTRS is not set - CONFIG_EVM_LOAD_X509=y -@@ -6819,6 +6987,9 @@ CONFIG_PKCS7_MESSAGE_PARSER=y - # CONFIG_PKCS7_TEST_KEY is not set - CONFIG_SIGNED_PE_FILE_VERIFICATION=y - # CONFIG_FIPS_SIGNATURE_SELFTEST is not set -+# CONFIG_PGP_LIBRARY is not set -+# CONFIG_PGP_KEY_PARSER is not set -+# CONFIG_PGP_PRELOAD is not set - - # - # Certificates for signature checking -@@ -6835,6 +7006,7 @@ CONFIG_SYSTEM_BLACKLIST_HASH_LIST="" - CONFIG_SYSTEM_REVOCATION_LIST=y - CONFIG_SYSTEM_REVOCATION_KEYS="" - # CONFIG_SYSTEM_BLACKLIST_AUTH_UPDATE is not set -+# CONFIG_PGP_PRELOAD_PUBLIC_KEYS is not set - # end of Certificates for signature checking - - CONFIG_BINARY_PRINTF=y -@@ -7034,8 +7206,8 @@ CONFIG_DEBUG_MISC=y - # - CONFIG_DEBUG_INFO=y - # CONFIG_DEBUG_INFO_NONE is not set --# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set --CONFIG_DEBUG_INFO_DWARF4=y -+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y -+# CONFIG_DEBUG_INFO_DWARF4 is not set - # CONFIG_DEBUG_INFO_DWARF5 is not set - # CONFIG_DEBUG_INFO_REDUCED is not set - CONFIG_DEBUG_INFO_COMPRESSED_NONE=y -@@ -7049,7 +7221,8 @@ CONFIG_DEBUG_INFO_BTF_MODULES=y - CONFIG_FRAME_WARN=2048 - CONFIG_STRIP_ASM_SYMS=y - # CONFIG_READABLE_ASM is not set --# CONFIG_HEADERS_INSTALL is not set -+CONFIG_HEADERS_INSTALL=y -+# CONFIG_OPTIMIZE_INLINING is not set - CONFIG_DEBUG_SECTION_MISMATCH=y - CONFIG_SECTION_MISMATCH_WARN_ONLY=y - # CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set -@@ -7204,8 +7377,6 @@ CONFIG_DEBUG_LIST=y - # CONFIG_DEBUG_MAPLE_TREE is not set - # end of Debug kernel data structures - --# CONFIG_DEBUG_CREDENTIALS is not set -- - # - # RCU Debugging - # -@@ -7271,7 +7442,7 @@ CONFIG_DYNAMIC_EVENTS=y - CONFIG_PROBE_EVENTS=y - # CONFIG_BPF_KPROBE_OVERRIDE is not set - CONFIG_FTRACE_MCOUNT_RECORD=y --CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT=y -+CONFIG_FTRACE_MCOUNT_USE_CC=y - CONFIG_SYNTH_EVENTS=y - # CONFIG_USER_EVENTS is not set - # CONFIG_TRACE_EVENT_INJECT is not set -@@ -7314,3 +7485,5 @@ CONFIG_ARCH_USE_MEMTEST=y - # - # end of Rust hacking - # end of Kernel hacking -+ -+# CONFIG_KWORKER_NUMA_AFFINITY is not set -diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c -index 0554ed4bf087..07c7ab6bcb4a 100644 ---- a/arch/riscv/errata/thead/errata.c -+++ b/arch/riscv/errata/thead/errata.c -@@ -12,8 +12,10 @@ - #include <asm/alternative.h> - #include <asm/cacheflush.h> - #include <asm/cpufeature.h> -+#include <asm/dma-noncoherent.h> - #include <asm/errata_list.h> - #include <asm/hwprobe.h> -+#include <asm/io.h> - #include <asm/patch.h> - #include <asm/vendorid_list.h> - -@@ -33,6 +35,69 @@ static bool errata_probe_pbmt(unsigned int stage, - return false; - } - -+/* -+ * th.dcache.ipa rs1 (invalidate, physical address) -+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | -+ * 0000001 01010 rs1 000 00000 0001011 -+ * th.dcache.iva rs1 (invalidate, virtual address) -+ * 0000001 00110 rs1 000 00000 0001011 -+ * -+ * th.dcache.cpa rs1 (clean, physical address) -+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | -+ * 0000001 01001 rs1 000 00000 0001011 -+ * th.dcache.cva rs1 (clean, virtual address) -+ * 0000001 00101 rs1 000 00000 0001011 -+ * -+ * th.dcache.cipa rs1 (clean then invalidate, physical address) -+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | -+ * 0000001 01011 rs1 000 00000 0001011 -+ * th.dcache.civa rs1 (clean then invalidate, virtual address) -+ * 0000001 00111 rs1 000 00000 0001011 -+ * -+ * th.sync.s (make sure all cache operations finished) -+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | -+ * 0000000 11001 00000 000 00000 0001011 -+ */ -+#define THEAD_INVAL_A0 ".long 0x02a5000b" -+#define THEAD_CLEAN_A0 ".long 0x0295000b" -+#define THEAD_FLUSH_A0 ".long 0x02b5000b" -+#define THEAD_SYNC_S ".long 0x0190000b" -+ -+#define THEAD_CMO_OP(_op, _start, _size, _cachesize) \ -+asm volatile("mv a0, %1\n\t" \ -+ "j 2f\n\t" \ -+ "3:\n\t" \ -+ THEAD_##_op##_A0 "\n\t" \ -+ "add a0, a0, %0\n\t" \ -+ "2:\n\t" \ -+ "bltu a0, %2, 3b\n\t" \ -+ THEAD_SYNC_S \ -+ : : "r"(_cachesize), \ -+ "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ -+ "r"((unsigned long)(_start) + (_size)) \ -+ : "a0") -+ -+static void thead_errata_cache_inv(phys_addr_t paddr, size_t size) -+{ -+ THEAD_CMO_OP(INVAL, paddr, size, riscv_cbom_block_size); -+} -+ -+static void thead_errata_cache_wback(phys_addr_t paddr, size_t size) -+{ -+ THEAD_CMO_OP(CLEAN, paddr, size, riscv_cbom_block_size); -+} -+ -+static void thead_errata_cache_wback_inv(phys_addr_t paddr, size_t size) -+{ -+ THEAD_CMO_OP(FLUSH, paddr, size, riscv_cbom_block_size); -+} -+ -+static const struct riscv_nonstd_cache_ops thead_errata_cmo_ops = { -+ .wback = &thead_errata_cache_wback_inv, -+ .inv = &thead_errata_cache_inv, -+ .wback_inv = &thead_errata_cache_wback_inv, -+}; -+ - static bool errata_probe_cmo(unsigned int stage, - unsigned long arch_id, unsigned long impid) - { -@@ -48,6 +113,7 @@ static bool errata_probe_cmo(unsigned int stage, - if (stage == RISCV_ALTERNATIVES_BOOT) { - riscv_cbom_block_size = L1_CACHE_BYTES; - riscv_noncoherent_supported(); -+ riscv_noncoherent_register_cache_ops(&thead_errata_cmo_ops); - } - - return true; -@@ -77,8 +143,7 @@ static u32 thead_errata_probe(unsigned int stage, - if (errata_probe_pbmt(stage, archid, impid)) - cpu_req_errata |= BIT(ERRATA_THEAD_PBMT); - -- if (errata_probe_cmo(stage, archid, impid)) -- cpu_req_errata |= BIT(ERRATA_THEAD_CMO); -+ errata_probe_cmo(stage, archid, impid); - - if (errata_probe_pmu(stage, archid, impid)) - cpu_req_errata |= BIT(ERRATA_THEAD_PMU); -diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h -index b55b434f0059..ea33288f8a25 100644 ---- a/arch/riscv/include/asm/errata_list.h -+++ b/arch/riscv/include/asm/errata_list.h -@@ -24,9 +24,8 @@ - - #ifdef CONFIG_ERRATA_THEAD - #define ERRATA_THEAD_PBMT 0 --#define ERRATA_THEAD_CMO 1 --#define ERRATA_THEAD_PMU 2 --#define ERRATA_THEAD_NUMBER 3 -+#define ERRATA_THEAD_PMU 1 -+#define ERRATA_THEAD_NUMBER 2 - #endif - - #ifdef __ASSEMBLY__ -@@ -94,54 +93,17 @@ asm volatile(ALTERNATIVE( \ - #define ALT_THEAD_PMA(_val) - #endif - --/* -- * dcache.ipa rs1 (invalidate, physical address) -- * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | -- * 0000001 01010 rs1 000 00000 0001011 -- * dache.iva rs1 (invalida, virtual address) -- * 0000001 00110 rs1 000 00000 0001011 -- * -- * dcache.cpa rs1 (clean, physical address) -- * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | -- * 0000001 01001 rs1 000 00000 0001011 -- * dcache.cva rs1 (clean, virtual address) -- * 0000001 00101 rs1 000 00000 0001011 -- * -- * dcache.cipa rs1 (clean then invalidate, physical address) -- * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | -- * 0000001 01011 rs1 000 00000 0001011 -- * dcache.civa rs1 (... virtual address) -- * 0000001 00111 rs1 000 00000 0001011 -- * -- * sync.s (make sure all cache operations finished) -- * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | -- * 0000000 11001 00000 000 00000 0001011 -- */ --#define THEAD_inval_A0 ".long 0x0265000b" --#define THEAD_clean_A0 ".long 0x0255000b" --#define THEAD_flush_A0 ".long 0x0275000b" --#define THEAD_SYNC_S ".long 0x0190000b" -- - #define ALT_CMO_OP(_op, _start, _size, _cachesize) \ --asm volatile(ALTERNATIVE_2( \ -- __nops(6), \ -+asm volatile(ALTERNATIVE( \ -+ __nops(5), \ - "mv a0, %1\n\t" \ - "j 2f\n\t" \ - "3:\n\t" \ - CBO_##_op(a0) \ - "add a0, a0, %0\n\t" \ - "2:\n\t" \ -- "bltu a0, %2, 3b\n\t" \ -- "nop", 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ -- "mv a0, %1\n\t" \ -- "j 2f\n\t" \ -- "3:\n\t" \ -- THEAD_##_op##_A0 "\n\t" \ -- "add a0, a0, %0\n\t" \ -- "2:\n\t" \ -- "bltu a0, %2, 3b\n\t" \ -- THEAD_SYNC_S, THEAD_VENDOR_ID, \ -- ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO) \ -+ "bltu a0, %2, 3b\n\t", \ -+ 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM) \ - : : "r"(_cachesize), \ - "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ - "r"((unsigned long)(_start) + (_size)) \ -diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h -index 7a5097202e15..783837bbd878 100644 ---- a/arch/riscv/include/asm/pgtable-64.h -+++ b/arch/riscv/include/asm/pgtable-64.h -@@ -126,14 +126,18 @@ enum napot_cont_order { - - /* - * 63:59 T-Head Memory Type definitions: -- * -- * 00000 - NC Weakly-ordered, Non-cacheable, Non-bufferable, Non-shareable, Non-trustable -+ * bit63 SO - Strong Order -+ * bit62 C - Cacheable -+ * bit61 B - Bufferable -+ * bit60 SH - Shareable -+ * bit59 Sec - Trustable -+ * 00110 - NC Weakly-ordered, Non-cacheable, Bufferable, Shareable, Non-trustable - * 01110 - PMA Weakly-ordered, Cacheable, Bufferable, Shareable, Non-trustable -- * 10000 - IO Strongly-ordered, Non-cacheable, Non-bufferable, Non-shareable, Non-trustable -+ * 10010 - IO Strongly-ordered, Non-cacheable, Non-bufferable, Shareable, Non-trustable - */ - #define _PAGE_PMA_THEAD ((1UL << 62) | (1UL << 61) | (1UL << 60)) --#define _PAGE_NOCACHE_THEAD 0UL --#define _PAGE_IO_THEAD (1UL << 63) -+#define _PAGE_NOCACHE_THEAD ((1UL << 61) | (1UL << 60)) -+#define _PAGE_IO_THEAD ((1UL << 63) | (1UL << 60)) - #define _PAGE_MTMASK_THEAD (_PAGE_PMA_THEAD | _PAGE_IO_THEAD | (1UL << 59)) - - static inline u64 riscv_page_mtmask(void) -diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig -index c30099866174..1578cc32432d 100644 ---- a/drivers/clk/Kconfig -+++ b/drivers/clk/Kconfig -@@ -501,6 +501,7 @@ source "drivers/clk/visconti/Kconfig" - source "drivers/clk/x86/Kconfig" - source "drivers/clk/xilinx/Kconfig" - source "drivers/clk/zynqmp/Kconfig" -+source "drivers/clk/thead/Kconfig" - - # Kunit test cases - config CLK_KUNIT_TEST -diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile -index 18969cbd4bb1..ebecef837e58 100644 ---- a/drivers/clk/Makefile -+++ b/drivers/clk/Makefile -@@ -124,6 +124,7 @@ obj-$(CONFIG_ARCH_STM32) += stm32/ - obj-y += starfive/ - obj-$(CONFIG_ARCH_SUNXI) += sunxi/ - obj-y += sunxi-ng/ -+obj-$(CONFIG_ARCH_SOPHGO) += sophgo/ - obj-$(CONFIG_ARCH_TEGRA) += tegra/ - obj-y += ti/ - obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ -@@ -136,3 +137,4 @@ endif - obj-y += xilinx/ - obj-$(CONFIG_ARCH_ZYNQ) += zynq/ - obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/ -+obj-$(CONFIG_ARCH_THEAD) += thead/ -diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile -new file mode 100644 -index 000000000000..55997fc07b5b ---- /dev/null -+++ b/drivers/clk/sophgo/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_ARCH_SOPHGO) += clk-dummy.o -+obj-$(CONFIG_ARCH_SOPHGO) += clk.o -+obj-$(CONFIG_ARCH_SOPHGO) += clk-mango.o -diff --git a/drivers/clk/sophgo/clk-dummy.c b/drivers/clk/sophgo/clk-dummy.c -new file mode 100644 -index 000000000000..99af0e6dae6a ---- /dev/null -+++ b/drivers/clk/sophgo/clk-dummy.c -@@ -0,0 +1,600 @@ -+/* -+ * Copyright (c) 2022 SOPHGO -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include <linux/of_device.h> -+#include <linux/platform_device.h> -+#include <linux/spinlock.h> -+#include <linux/mfd/syscon.h> -+#include <linux/io.h> -+#include <linux/of_address.h> -+#include <linux/string.h> -+#include <linux/log2.h> -+ -+#include "clk.h" -+ -+/* -+ * @hw: handle between common and hardware-specific interfaces -+ * @reg: register containing divider -+ * @shift: shift to the divider bit field -+ * @width: width of the divider bit field -+ * @initial_val:initial value of the divider -+ * @table: the div table that the divider supports -+ * @lock: register lock -+ */ -+struct mango_clk_divider { -+ struct clk_hw hw; -+ void __iomem *reg; -+ u8 shift; -+ u8 width; -+ u8 flags; -+ u32 initial_val; -+ const struct clk_div_table *table; -+ spinlock_t *lock; -+}; -+ -+static unsigned long mango_clk_divider_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct device_node *node; -+ struct of_phandle_args clkspec; -+ int rc, index = 0; -+ u32 rate; -+ struct property *prop; -+ const __be32 *cur; -+ struct clk *clk; -+ -+ node = of_find_node_by_name(NULL, "default_rates"); -+ -+ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) { -+ if (rate) { -+ rc = of_parse_phandle_with_args(node, "clocks", -+ "#clock-cells", index, &clkspec); -+ if (rc < 0) { -+ /* skip empty (null) phandles */ -+ if (rc == -ENOENT) -+ continue; -+ else -+ return rc; -+ } -+ -+ clk = of_clk_get_from_provider(&clkspec); -+ if (IS_ERR(clk)) -+ return PTR_ERR(clk); -+ if (!strcmp(clk_hw_get_name(hw), __clk_get_name(clk))) -+ return rate; -+ } -+ index++; -+ } -+ return 0; -+} -+ -+static long mango_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ return rate; -+} -+ -+static int mango_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ return 0; -+} -+ -+/* -+ * @hw: ccf use to hook get mango_pll_clock -+ * @parent_rate: parent rate -+ * -+ * The is function will be called through clk_get_rate -+ * and return current rate after decoding reg value -+ */ -+static unsigned long mango_clk_pll_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct device_node *node; -+ struct of_phandle_args clkspec; -+ int rc, index = 0; -+ u32 rate; -+ struct property *prop; -+ const __be32 *cur; -+ -+ node = of_find_node_by_name(NULL, "default_rates"); -+ -+ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) { -+ if (rate) { -+ rc = of_parse_phandle_with_args(node, "clocks", -+ "#clock-cells", index, &clkspec); -+ if (rc < 0) { -+ /* skip empty (null) phandles */ -+ if (rc == -ENOENT) -+ continue; -+ else -+ return rc; -+ } -+ -+ if (!strncmp(clk_hw_get_name(hw), clkspec.np->name, 4)) -+ return rate; -+ } -+ index++; -+ } -+ return 0; -+} -+ -+static long mango_clk_pll_round_rate(struct clk_hw *hw, -+ unsigned long req_rate, unsigned long *prate) -+{ -+ return req_rate; -+} -+ -+static int mango_clk_pll_determine_rate(struct clk_hw *hw, -+ struct clk_rate_request *req) -+{ -+ req->rate = mango_clk_pll_round_rate(hw, min(req->rate, req->max_rate), -+ &req->best_parent_rate); -+ return 0; -+} -+ -+static int mango_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ return 0; -+} -+ -+const struct clk_ops dm_mango_clk_divider_ops = { -+ .recalc_rate = mango_clk_divider_recalc_rate, -+ .round_rate = mango_clk_divider_round_rate, -+ .set_rate = mango_clk_divider_set_rate, -+}; -+ -+const struct clk_ops dm_mango_clk_divider_ro_ops = { -+ .recalc_rate = mango_clk_divider_recalc_rate, -+ .round_rate = mango_clk_divider_round_rate, -+}; -+ -+const struct clk_ops dm_mango_clk_pll_ops = { -+ .recalc_rate = mango_clk_pll_recalc_rate, -+ .round_rate = mango_clk_pll_round_rate, -+ .determine_rate = mango_clk_pll_determine_rate, -+ .set_rate = mango_clk_pll_set_rate, -+}; -+ -+const struct clk_ops dm_mango_clk_pll_ro_ops = { -+ .recalc_rate = mango_clk_pll_recalc_rate, -+ .round_rate = mango_clk_pll_round_rate, -+}; -+ -+struct mux_cb_clk_name { -+ const char *name; -+ struct list_head node; -+}; -+ -+static struct list_head mux_cb_clk_name_list = -+ LIST_HEAD_INIT(mux_cb_clk_name_list); -+static int mux_notifier_cb(struct notifier_block *nb, -+ unsigned long event, void *data) -+{ -+ int ret = 0; -+ static unsigned char mux_id = 1; -+ struct clk_notifier_data *ndata = data; -+ struct clk_hw *hw = __clk_get_hw(ndata->clk); -+ const struct clk_ops *ops = &clk_mux_ops; -+ struct mux_cb_clk_name *cb_lsit; -+ -+ if (event == PRE_RATE_CHANGE) { -+ struct clk_hw *hw_p = clk_hw_get_parent(hw); -+ -+ cb_lsit = kmalloc(sizeof(*cb_lsit), GFP_KERNEL); -+ if (cb_lsit) { -+ INIT_LIST_HEAD(&cb_lsit->node); -+ list_add_tail(&cb_lsit->node, &mux_cb_clk_name_list); -+ } else { -+ pr_err("mux cb kmalloc mem fail\n"); -+ goto out; -+ } -+ -+ cb_lsit->name = clk_hw_get_name(hw_p); -+ mux_id = ops->get_parent(hw); -+ if (mux_id > 1) { -+ ret = 1; -+ goto out; -+ } -+ ops->set_parent(hw, !mux_id); -+ } else if (event == POST_RATE_CHANGE) { -+ struct clk_hw *hw_p = clk_hw_get_parent(hw); -+ -+ cb_lsit = list_first_entry_or_null(&mux_cb_clk_name_list, -+ typeof(*cb_lsit), node); -+ if (cb_lsit) { -+ const char *pre_name = cb_lsit->name; -+ -+ list_del_init(&cb_lsit->node); -+ kfree(cb_lsit); -+ if (strcmp(clk_hw_get_name(hw_p), pre_name)) -+ goto out; -+ } -+ -+ ops->set_parent(hw, mux_id); -+ } -+ -+out: -+ return notifier_from_errno(ret); -+} -+ -+int dm_set_default_clk_rates(struct device_node *node) -+{ -+ struct of_phandle_args clkspec; -+ struct property *prop; -+ const __be32 *cur; -+ int rc, index = 0; -+ struct clk *clk; -+ u32 rate; -+ -+ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) { -+ if (rate) { -+ rc = of_parse_phandle_with_args(node, "clocks", -+ "#clock-cells", index, &clkspec); -+ if (rc < 0) { -+ /* skip empty (null) phandles */ -+ if (rc == -ENOENT) -+ continue; -+ else -+ return rc; -+ } -+ -+ clk = of_clk_get_from_provider(&clkspec); -+ if (IS_ERR(clk)) { -+ pr_warn("clk: couldn't get clock %d for %s\n", -+ index, node->full_name); -+ return PTR_ERR(clk); -+ } -+ -+ rc = clk_set_rate(clk, rate); -+ if (rc < 0) -+ pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n", -+ __clk_get_name(clk), rate, rc, -+ clk_get_rate(clk)); -+ clk_put(clk); -+ } -+ index++; -+ } -+ -+ return 0; -+} -+ -+static struct clk *__register_divider_clks(struct device *dev, const char *name, -+ const char *parent_name, -+ unsigned long flags, -+ void __iomem *reg, u8 shift, -+ u8 width, u32 initial_val, -+ u8 clk_divider_flags, -+ const struct clk_div_table *table, -+ spinlock_t *lock) -+{ -+ struct mango_clk_divider *div; -+ struct clk_hw *hw; -+ struct clk_init_data init; -+ int ret; -+ -+ if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { -+ if (width + shift > 16) { -+ pr_warn("divider value exceeds LOWORD field\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ } -+ -+ /* allocate the divider */ -+ div = kzalloc(sizeof(*div), GFP_KERNEL); -+ if (!div) -+ return ERR_PTR(-ENOMEM); -+ -+ init.name = name; -+ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) -+ init.ops = &dm_mango_clk_divider_ro_ops; -+ else -+ init.ops = &dm_mango_clk_divider_ops; -+ init.flags = flags; -+ init.parent_names = (parent_name ? &parent_name : NULL); -+ init.num_parents = (parent_name ? 1 : 0); -+ -+ /* struct mango_clk_divider assignments */ -+ div->reg = reg; -+ div->shift = shift; -+ div->width = width; -+ div->flags = clk_divider_flags; -+ div->lock = lock; -+ div->hw.init = &init; -+ div->table = table; -+ div->initial_val = initial_val; -+ -+ /* register the clock */ -+ hw = &div->hw; -+ ret = clk_hw_register(dev, hw); -+ if (ret) { -+ kfree(div); -+ hw = ERR_PTR(ret); -+ return ERR_PTR(-EBUSY); -+ } -+ -+ return hw->clk; -+} -+ -+static inline int register_provider_clks -+(struct device_node *node, struct mango_clk_data *clk_data, int clk_num) -+{ -+ return of_clk_add_provider(node, of_clk_src_onecell_get, -+ &clk_data->clk_data); -+} -+ -+static int register_gate_clks(struct device *dev, struct mango_clk_data *clk_data) -+{ -+ struct clk *clk; -+ const struct mango_clk_table *table = clk_data->table; -+ const struct mango_gate_clock *gate_clks = table->gate_clks; -+ void __iomem *base = clk_data->base; -+ int clk_num = table->gate_clks_num; -+ int i; -+ -+ for (i = 0; i < clk_num; i++) { -+ clk = clk_register_gate( -+ dev, gate_clksi.name, gate_clksi.parent_name, -+ gate_clksi.flags | CLK_IS_CRITICAL, base + gate_clksi.offset, -+ gate_clksi.bit_idx, gate_clksi.gate_flags, -+ &clk_data->lock); -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register clock %s\n", __func__, -+ gate_clksi.name); -+ goto err; -+ } -+ -+ if (gate_clksi.alias) -+ clk_register_clkdev(clk, gate_clksi.alias, NULL); -+ -+ clk_data->clk_data.clksgate_clksi.id = clk; -+ } -+ -+ return 0; -+ -+err: -+ while (i--) -+ clk_unregister_gate(clk_data->clk_data.clksgate_clksi.id); -+ -+ return PTR_ERR(clk); -+} -+ -+static int register_divider_clks(struct device *dev, -+ struct mango_clk_data *clk_data) -+{ -+ struct clk *clk; -+ const struct mango_clk_table *table = clk_data->table; -+ const struct mango_divider_clock *div_clks = table->div_clks; -+ void __iomem *base = clk_data->base; -+ int clk_num = table->div_clks_num; -+ int i, val; -+ -+ for (i = 0; i < clk_num; i++) { -+ clk = __register_divider_clks( -+ NULL, div_clksi.name, div_clksi.parent_name, -+ div_clksi.flags, base + div_clksi.offset, -+ div_clksi.shift, div_clksi.width, -+ div_clksi.initial_val, -+ (div_clksi.initial_sel & MANGO_CLK_USE_INIT_VAL) ? -+ div_clksi.div_flags | CLK_DIVIDER_READ_ONLY : -+ div_clksi.div_flags, -+ div_clksi.table, &clk_data->lock); -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register clock %s\n", __func__, -+ div_clksi.name); -+ goto err; -+ } -+ -+ clk_data->clk_data.clksdiv_clksi.id = clk; -+ -+ if (div_clksi.initial_sel == MANGO_CLK_USE_REG_VAL) { -+ regmap_read(clk_data->syscon_top, div_clksi.offset, -+ &val); -+ -+ /* -+ * set a default divider factor, -+ * clk driver should not select divider clock as the -+ * clock source, before set the divider by right process -+ * (assert div, set div factor, de assert div). -+ */ -+ if (div_clksi.initial_val > 0) -+ val |= (div_clksi.initial_val << 16 | 1 << 3); -+ else { -+ /* -+ * the div register is config to use divider factor, don't change divider -+ */ -+ if (!(val >> 3 & 0x1)) -+ val |= 1 << 16; -+ } -+ -+ regmap_write(clk_data->syscon_top, div_clksi.offset, -+ val); -+ } -+ } -+ -+ return 0; -+ -+err: -+ while (i--) -+ clk_unregister_divider(clk_data->clk_data.clksdiv_clksi.id); -+ -+ return PTR_ERR(clk); -+} -+ -+static int register_mux_clks(struct device *dev, struct mango_clk_data *clk_data) -+{ -+ struct clk *clk; -+ const struct mango_clk_table *table = clk_data->table; -+ const struct mango_mux_clock *mux_clks = table->mux_clks; -+ void __iomem *base = clk_data->base; -+ int clk_num = table->mux_clks_num; -+ int i; -+ -+ for (i = 0; i < clk_num; i++) { -+ u32 mask = BIT(mux_clksi.width) - 1; -+ -+ clk = clk_register_mux_table( -+ dev, mux_clksi.name, mux_clksi.parent_names, -+ mux_clksi.num_parents, mux_clksi.flags, -+ base + mux_clksi.offset, mux_clksi.shift, mask, -+ mux_clksi.mux_flags, mux_clksi.table, -+ &clk_data->lock); -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register clock %s\n", __func__, -+ mux_clksi.name); -+ goto err; -+ } -+ -+ clk_data->clk_data.clksmux_clksi.id = clk; -+ -+ if (!(mux_clksi.flags & CLK_MUX_READ_ONLY)) { -+ struct clk *parent; -+ struct notifier_block *clk_nb; -+ -+ /* set mux clock default parent here, it's parent index -+ * value is read from the mux clock reg. dts can override -+ * setting the mux clock parent later. -+ */ -+ parent = clk_get_parent(clk); -+ clk_set_parent(clk, parent); -+ -+ /* add a notify callback function */ -+ clk_nb = kzalloc(sizeof(*clk_nb), GFP_KERNEL); -+ if (!clk_nb) -+ goto err; -+ clk_nb->notifier_call = mux_notifier_cb; -+ if (clk_notifier_register(clk, clk_nb)) -+ pr_err("%s: failed to register clock notifier for %s\n", -+ __func__, mux_clksi.name); -+ } -+ } -+ -+ return 0; -+ -+err: -+ while (i--) -+ clk_unregister_mux(clk_data->clk_data.clksmux_clksi.id); -+ -+ return PTR_ERR(clk); -+} -+ -+/* pll clock init */ -+int dm_mango_register_pll_clks(struct device_node *node, -+ struct mango_clk_data *clk_data, const char *clk_name) -+{ -+ struct clk *clk = NULL; -+ struct mango_pll_clock *pll_clks; -+ int i, ret = 0; -+ const struct clk_ops *local_ops; -+ -+ pll_clks = (struct mango_pll_clock *)clk_data->table->pll_clks; -+ for (i = 0; i < clk_data->table->pll_clks_num; i++) { -+ if (!strcmp(clk_name, pll_clksi.name)) { -+ /* have to assigne pll_clks.syscon_top first -+ * since clk_register_composite will need it -+ * to calculate current rate. -+ */ -+ pll_clksi.syscon_top = clk_data->syscon_top; -+ pll_clksi.lock = &clk_data->lock; -+ if (pll_clksi.ini_flags & MANGO_CLK_RO) -+ local_ops = &dm_mango_clk_pll_ro_ops; -+ else -+ local_ops = &dm_mango_clk_pll_ops; -+ clk = clk_register_composite( -+ NULL, pll_clksi.name, &pll_clksi.parent_name, -+ 1, NULL, NULL, &pll_clksi.hw, local_ops, -+ NULL, NULL, pll_clksi.flags); -+ -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register clock %s\n", __func__, -+ pll_clksi.name); -+ ret = -EINVAL; -+ goto out; -+ } -+ ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); -+ if (ret) -+ clk_unregister(clk); -+ } else { -+ continue; -+ } -+ } -+ -+out: -+ return ret; -+} -+ -+/* mux clk init */ -+int dm_mango_register_mux_clks(struct device_node *node, struct mango_clk_data *clk_data) -+{ -+ int ret; -+ int count; -+ struct clk **clk_table; -+ -+ count = clk_data->table->mux_clks_num + clk_data->table->gate_clks_num; -+ clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL); -+ if (!clk_table) -+ return -ENOMEM; -+ -+ clk_data->clk_data.clks = clk_table; -+ clk_data->clk_data.clk_num = count; -+ -+ ret = register_mux_clks(NULL, clk_data); -+ if (ret) -+ goto err; -+ -+ ret = register_gate_clks(NULL, clk_data); -+ if (ret) -+ goto err; -+ -+ ret = register_provider_clks(node, clk_data, count); -+ if (ret) -+ goto err; -+ -+ return 0; -+err: -+ kfree(clk_table); -+ return ret; -+} -+ -+/* pll divider init */ -+int dm_mango_register_div_clks(struct device_node *node, struct mango_clk_data *clk_data) -+{ -+ int ret; -+ int count; -+ -+ struct clk **clk_table; -+ -+ count = clk_data->table->div_clks_num + clk_data->table->gate_clks_num; -+ clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL); -+ if (!clk_table) -+ return -ENOMEM; -+ -+ clk_data->clk_data.clks = clk_table; -+ clk_data->clk_data.clk_num = count; -+ -+ ret = register_divider_clks(NULL, clk_data); -+ if (ret) -+ goto err; -+ -+ ret = register_gate_clks(NULL, clk_data); -+ if (ret) -+ goto err; -+ -+ ret = register_provider_clks(node, clk_data, count); -+ if (ret) -+ goto err; -+ -+ -+ return 0; -+err: -+ kfree(clk_table); -+ pr_err("%s error %d\n", __func__, ret); -+ return ret; -+} -diff --git a/drivers/clk/sophgo/clk-mango.c b/drivers/clk/sophgo/clk-mango.c -new file mode 100644 -index 000000000000..70e17f65c6fb ---- /dev/null -+++ b/drivers/clk/sophgo/clk-mango.c -@@ -0,0 +1,977 @@ -+/* -+ * Copyright (c) 2022 SOPHGO -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include <linux/of_address.h> -+#include <linux/mfd/syscon.h> -+#include <dt-bindings/clock/sophgo-mango-clock.h> -+ -+#include "clk.h" -+ -+/* fixed clocks */ -+struct mango_pll_clock mango_root_pll_clks = { -+ { -+ .id = FPLL_CLK, -+ .name = "fpll_clock", -+ .parent_name = "cgi", -+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, -+ .ini_flags = MANGO_CLK_RO, -+ }, { -+ .id = DPLL0_CLK, -+ .name = "dpll0_clock", -+ .parent_name = "cgi", -+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, -+ .ini_flags = MANGO_CLK_RO, -+ .status_offset = 0xc0, -+ .enable_offset = 0xc4, -+ }, { -+ .id = DPLL1_CLK, -+ .name = "dpll1_clock", -+ .parent_name = "cgi", -+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, -+ .ini_flags = MANGO_CLK_RO, -+ .status_offset = 0xc0, -+ .enable_offset = 0xc4, -+ }, { -+ .id = MPLL_CLK, -+ .name = "mpll_clock", -+ .parent_name = "cgi", -+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, -+ .status_offset = 0xc0, -+ .enable_offset = 0xc4, -+ },{ -+ .id = FPLL_CLK, -+ .name = "s1_fpll_clock", -+ .parent_name = "s1_cgi", -+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, -+ .ini_flags = MANGO_CLK_RO, -+ }, { -+ .id = DPLL0_CLK, -+ .name = "s1_dpll0_clock", -+ .parent_name = "s1_cgi", -+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, -+ .ini_flags = MANGO_CLK_RO, -+ .status_offset = 0xc0, -+ .enable_offset = 0xc4, -+ }, { -+ .id = DPLL1_CLK, -+ .name = "s1_dpll1_clock", -+ .parent_name = "s1_cgi", -+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, -+ .ini_flags = MANGO_CLK_RO, -+ .status_offset = 0xc0, -+ .enable_offset = 0xc4, -+ }, { -+ .id = MPLL_CLK, -+ .name = "s1_mpll_clock", -+ .parent_name = "s1_cgi", -+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE, -+ .status_offset = 0xc0, -+ .enable_offset = 0xc4, -+ } -+}; -+ -+/* divider clocks */ -+static const struct mango_divider_clock s0_div_clks = { -+ { DIV_CLK_MPLL_RP_CPU_NORMAL_0, "clk_div_rp_cpu_normal_0", "clk_gate_rp_cpu_normal_div0", -+ 0, 0x2044, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_MPLL_AXI_DDR_0, "clk_div_axi_ddr_0", "clk_gate_axi_ddr_div0", -+ 0, 0x20a8, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5}, -+ { DIV_CLK_FPLL_DDR01_1, "clk_div_ddr01_1", "clk_gate_ddr01_div1", -+ 0, 0x20b0, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, -+ { DIV_CLK_FPLL_DDR23_1, "clk_div_ddr23_1", "clk_gate_ddr23_div1", -+ 0, 0x20b8, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, -+ { DIV_CLK_FPLL_RP_CPU_NORMAL_1, "clk_div_rp_cpu_normal_1", "clk_gate_rp_cpu_normal_div1", -+ 0, 0x2040, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_50M_A53, "clk_div_50m_a53", "fpll_clock", -+ 0, 0x2048, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_TOP_RP_CMN_DIV2, "clk_div_top_rp_cmn_div2", "clk_mux_rp_cpu_normal", -+ 0, 0x204c, 16, 16, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_UART_500M, "clk_div_uart_500m", "fpll_clock", -+ 0, 0x2050, 16, 7, CLK_DIVIDER_READ_ONLY, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_AHB_LPC, "clk_div_ahb_lpc", "fpll_clock", -+ 0, 0x2054, 16, 16, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_EFUSE, "clk_div_efuse", "fpll_clock", -+ 0, 0x2078, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_TX_ETH0, "clk_div_tx_eth0", "fpll_clock", -+ 0, 0x2080, 16, 11, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_PTP_REF_I_ETH0, "clk_div_ptp_ref_i_eth0", "fpll_clock", -+ 0, 0x2084, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_REF_ETH0, "clk_div_ref_eth0", "fpll_clock", -+ 0, 0x2088, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_EMMC, "clk_div_emmc", "fpll_clock", -+ 0, 0x208c, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_SD, "clk_div_sd", "fpll_clock", -+ 0, 0x2094, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_TOP_AXI0, "clk_div_top_axi0", "fpll_clock", -+ 0, 0x209c, 16, 5, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_TOP_AXI_HSPERI, "clk_div_top_axi_hsperi", "fpll_clock", -+ 0, 0x20a0, 16, 5, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_AXI_DDR_1, "clk_div_axi_ddr_1", "clk_gate_axi_ddr_div1", -+ 0, 0x20a4, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5}, -+ { DIV_CLK_FPLL_DIV_TIMER1, "clk_div_timer1", "clk_div_50m_a53", -+ 0, 0x2058, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER2, "clk_div_timer2", "clk_div_50m_a53", -+ 0, 0x205c, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER3, "clk_div_timer3", "clk_div_50m_a53", -+ 0, 0x2060, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER4, "clk_div_timer4", "clk_div_50m_a53", -+ 0, 0x2064, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER5, "clk_div_timer5", "clk_div_50m_a53", -+ 0, 0x2068, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER6, "clk_div_timer6", "clk_div_50m_a53", -+ 0, 0x206c, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER7, "clk_div_timer7", "clk_div_50m_a53", -+ 0, 0x2070, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER8, "clk_div_timer8", "clk_div_50m_a53", -+ 0, 0x2074, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_100K_EMMC, "clk_div_100k_emmc", "clk_div_top_axi0", -+ 0, 0x2090, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_100K_SD, "clk_div_100k_sd", "clk_div_top_axi0", -+ 0, 0x2098, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_GPIO_DB, "clk_div_gpio_db", "clk_div_top_axi0", -+ 0, 0x207c, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_DPLL0_DDR01_0, "clk_div_ddr01_0", "clk_gate_ddr01_div0", -+ 0, 0x20ac, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, -+ { DIV_CLK_DPLL1_DDR23_0, "clk_div_ddr23_0", "clk_gate_ddr23_div0", -+ 0, 0x20b4, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, -+}; -+ -+/* gate clocks */ -+static const struct mango_gate_clock s0_gate_clks = { -+ { GATE_CLK_RP_CPU_NORMAL_DIV0, "clk_gate_rp_cpu_normal_div1", "mpll_clock", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, -+ { GATE_CLK_AXI_DDR_DIV0, "clk_gate_axi_ddr_div1", "mpll_clock", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, -+ { GATE_CLK_DDR01_DIV0, "clk_gate_ddr01_div0", "fpll_clock", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 }, -+ { GATE_CLK_DDR23_DIV0, "clk_gate_ddr23_div0", "fpll_clock", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 }, -+ { GATE_CLK_RP_CPU_NORMAL_DIV1, "clk_gate_rp_cpu_normal_div0", "fpll_clock", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, -+ { GATE_CLK_AXI_DDR_DIV1, "clk_gate_axi_ddr_div0", "fpll_clock", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, -+ { GATE_CLK_DDR01_DIV1, "clk_gate_ddr01_div1", "dpll0_clock", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 14, 0 }, -+ { GATE_CLK_DDR23_DIV1, "clk_gate_ddr23_div1", "dpll1_clock", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 15, 0 }, -+ { GATE_CLK_A53_50M, "clk_gate_a53_50m", "clk_div_50m_a53", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 1, 0 }, -+ { GATE_CLK_TOP_RP_CMN_DIV2, "clk_gate_top_rp_cmn_div2", "clk_gate_rp_cpu_normal", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 2, 0 }, -+ { GATE_CLK_AXI_PCIE0, "clk_gate_axi_pcie0", "clk_gate_rp_cpu_normal", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 8, 0 }, -+ { GATE_CLK_AXI_PCIE1, "clk_gate_axi_pcie1", "clk_gate_rp_cpu_normal", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 9, 0 }, -+ { GATE_CLK_HSDMA, "clk_gate_hsdma", "clk_gate_top_rp_cmn_div2", -+ CLK_SET_RATE_PARENT, 0x2004, 10, 0 }, -+ { GATE_CLK_EMMC_100M, "clk_gate_emmc", "clk_div_emmc", -+ CLK_SET_RATE_PARENT, 0x2004, 3, 0 }, -+ { GATE_CLK_SD_100M, "clk_gate_sd", "clk_div_sd", -+ CLK_SET_RATE_PARENT, 0x2004, 6, 0 }, -+ { GATE_CLK_TX_ETH0, "clk_gate_tx_eth0", "clk_div_tx_eth0", -+ CLK_SET_RATE_PARENT, 0x2000, 30, 0 }, -+ { GATE_CLK_PTP_REF_I_ETH0, "clk_gate_ptp_ref_i_eth0", "clk_div_ptp_ref_i_eth0", -+ CLK_SET_RATE_PARENT, 0x2004, 0, 0 }, -+ { GATE_CLK_REF_ETH0, "clk_gate_ref_eth0", "clk_div_ref_eth0", -+ CLK_SET_RATE_PARENT, 0x2004, 1, 0 }, -+ { GATE_CLK_UART_500M, "clk_gate_uart_500m", "clk_div_uart_500m", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 4, 0 }, -+ { GATE_CLK_AHB_LPC, "clk_gate_ahb_lpc", "clk_div_ahb_lpc", -+ CLK_SET_RATE_PARENT, 0x2000, 7, 0 }, -+ { GATE_CLK_EFUSE, "clk_gate_efuse", "clk_div_efuse", -+ CLK_SET_RATE_PARENT, 0x2000, 20, 0}, -+ { GATE_CLK_TOP_AXI0, "clk_gate_top_axi0", "clk_div_top_axi0", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 11, 0 }, -+ { GATE_CLK_TOP_AXI_HSPERI, "clk_gate_top_axi_hsperi", "clk_div_top_axi_hsperi", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 12, 0 }, -+ { GATE_CLK_AHB_ROM, "clk_gate_ahb_rom", "clk_gate_top_axi0", -+ 0, 0x2000, 8, 0 }, -+ { GATE_CLK_AHB_SF, "clk_gate_ahb_sf", "clk_gate_top_axi0", -+ 0, 0x2000, 9, 0 }, -+ { GATE_CLK_AXI_SRAM, "clk_gate_axi_sram", "clk_gate_top_axi0", -+ CLK_IGNORE_UNUSED, 0x2000, 10, 0 }, -+ { GATE_CLK_APB_TIMER, "clk_gate_apb_timer", "clk_gate_top_axi0", -+ CLK_IGNORE_UNUSED, 0x2000, 11, 0 }, -+ { GATE_CLK_APB_EFUSE, "clk_gate_apb_efuse", "clk_gate_top_axi0", -+ 0, 0x2000, 21, 0 }, -+ { GATE_CLK_APB_GPIO, "clk_gate_apb_gpio", "clk_gate_top_axi0", -+ 0, 0x2000, 22, 0 }, -+ { GATE_CLK_APB_GPIO_INTR, "clk_gate_apb_gpio_intr", "clk_gate_top_axi0", -+ 0, 0x2000, 23, 0 }, -+ { GATE_CLK_APB_I2C, "clk_gate_apb_i2c", "clk_gate_top_axi0", -+ 0, 0x2000, 26, 0 }, -+ { GATE_CLK_APB_WDT, "clk_gate_apb_wdt", "clk_gate_top_axi0", -+ 0, 0x2000, 27, 0 }, -+ { GATE_CLK_APB_PWM, "clk_gate_apb_pwm", "clk_gate_top_axi0", -+ 0, 0x2000, 28, 0 }, -+ { GATE_CLK_APB_RTC, "clk_gate_apb_rtc", "clk_gate_top_axi0", -+ 0, 0x2000, 29, 0 }, -+ { GATE_CLK_SYSDMA_AXI, "clk_gate_sysdma_axi", "clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 3, 0 }, -+ { GATE_CLK_APB_UART, "clk_gate_apb_uart", "clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 5, 0 }, -+ { GATE_CLK_AXI_DBG_I2C, "clk_gate_axi_dbg_i2c", "clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 6, 0 }, -+ { GATE_CLK_APB_SPI, "clk_gate_apb_spi", "clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 25, 0 }, -+ { GATE_CLK_AXI_ETH0, "clk_gate_axi_eth0", "clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 31, 0 }, -+ { GATE_CLK_AXI_EMMC, "clk_gate_axi_emmc", "clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2004, 2, 0 }, -+ { GATE_CLK_AXI_SD, "clk_gate_axi_sd", "clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2004, 5, 0 }, -+ { GATE_CLK_TIMER1, "clk_gate_timer1", "clk_div_timer1", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 12, 0 }, -+ { GATE_CLK_TIMER2, "clk_gate_timer2", "clk_div_timer2", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 13, 0 }, -+ { GATE_CLK_TIMER3, "clk_gate_timer3", "clk_div_timer3", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 14, 0 }, -+ { GATE_CLK_TIMER4, "clk_gate_timer4", "clk_div_timer4", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 15, 0 }, -+ { GATE_CLK_TIMER5, "clk_gate_timer5", "clk_div_timer5", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 16, 0 }, -+ { GATE_CLK_TIMER6, "clk_gate_timer6", "clk_div_timer6", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 17, 0 }, -+ { GATE_CLK_TIMER7, "clk_gate_timer7", "clk_div_timer7", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 18, 0 }, -+ { GATE_CLK_TIMER8, "clk_gate_timer8", "clk_div_timer8", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 19, 0 }, -+ { GATE_CLK_100K_EMMC, "clk_gate_100k_emmc", "clk_div_100k_emmc", -+ CLK_SET_RATE_PARENT, 0x2004, 4, 0 }, -+ { GATE_CLK_100K_SD, "clk_gate_100k_sd", "clk_div_100k_sd", -+ CLK_SET_RATE_PARENT, 0x2004, 7, 0 }, -+ { GATE_CLK_GPIO_DB, "clk_gate_gpio_db", "clk_div_gpio_db", -+ CLK_SET_RATE_PARENT, 0x2000, 24, 0 }, -+ { GATE_CLK_DDR01, "clk_gate_ddr01", "clk_mux_ddr01", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 }, -+ { GATE_CLK_DDR23, "clk_gate_ddr23", "clk_mux_ddr23", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 }, -+ { GATE_CLK_RP_CPU_NORMAL, "clk_gate_rp_cpu_normal", "clk_mux_rp_cpu_normal", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, -+ { GATE_CLK_AXI_DDR, "clk_gate_axi_ddr", "clk_mux_axi_ddr", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, -+ { GATE_CLK_RXU0, "clk_gate_rxu0", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 0, 0 }, -+ { GATE_CLK_RXU1, "clk_gate_rxu1", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 1, 0 }, -+ { GATE_CLK_RXU2, "clk_gate_rxu2", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 2, 0 }, -+ { GATE_CLK_RXU3, "clk_gate_rxu3", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 3, 0 }, -+ { GATE_CLK_RXU4, "clk_gate_rxu4", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 4, 0 }, -+ { GATE_CLK_RXU5, "clk_gate_rxu5", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 5, 0 }, -+ { GATE_CLK_RXU6, "clk_gate_rxu6", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 6, 0 }, -+ { GATE_CLK_RXU7, "clk_gate_rxu7", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 7, 0 }, -+ { GATE_CLK_RXU8, "clk_gate_rxu8", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 8, 0 }, -+ { GATE_CLK_RXU9, "clk_gate_rxu9", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 9, 0 }, -+ { GATE_CLK_RXU10, "clk_gate_rxu10", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 10, 0 }, -+ { GATE_CLK_RXU11, "clk_gate_rxu11", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 11, 0 }, -+ { GATE_CLK_RXU12, "clk_gate_rxu12", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 12, 0 }, -+ { GATE_CLK_RXU13, "clk_gate_rxu13", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 13, 0 }, -+ { GATE_CLK_RXU14, "clk_gate_rxu14", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 14, 0 }, -+ { GATE_CLK_RXU15, "clk_gate_rxu15", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 15, 0 }, -+ { GATE_CLK_RXU16, "clk_gate_rxu16", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 16, 0 }, -+ { GATE_CLK_RXU17, "clk_gate_rxu17", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 17, 0 }, -+ { GATE_CLK_RXU18, "clk_gate_rxu18", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 18, 0 }, -+ { GATE_CLK_RXU19, "clk_gate_rxu19", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 19, 0 }, -+ { GATE_CLK_RXU20, "clk_gate_rxu20", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 20, 0 }, -+ { GATE_CLK_RXU21, "clk_gate_rxu21", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 21, 0 }, -+ { GATE_CLK_RXU22, "clk_gate_rxu22", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 22, 0 }, -+ { GATE_CLK_RXU23, "clk_gate_rxu23", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 23, 0 }, -+ { GATE_CLK_RXU24, "clk_gate_rxu24", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 24, 0 }, -+ { GATE_CLK_RXU25, "clk_gate_rxu25", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 25, 0 }, -+ { GATE_CLK_RXU26, "clk_gate_rxu26", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 26, 0 }, -+ { GATE_CLK_RXU27, "clk_gate_rxu27", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 27, 0 }, -+ { GATE_CLK_RXU28, "clk_gate_rxu28", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 28, 0 }, -+ { GATE_CLK_RXU29, "clk_gate_rxu29", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 29, 0 }, -+ { GATE_CLK_RXU30, "clk_gate_rxu30", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 30, 0 }, -+ { GATE_CLK_RXU31, "clk_gate_rxu31", "clk_gate_rp_cpu_normal", -+ 0, 0x368, 31, 0 }, -+ { GATE_CLK_MP0, "clk_gate_mp0", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x384, 0, 0 }, -+ { GATE_CLK_MP1, "clk_gate_mp1", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x38c, 0, 0 }, -+ { GATE_CLK_MP2, "clk_gate_mp2", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x394, 0, 0 }, -+ { GATE_CLK_MP3, "clk_gate_mp3", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x39c, 0, 0 }, -+ { GATE_CLK_MP4, "clk_gate_mp4", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3a4, 0, 0 }, -+ { GATE_CLK_MP5, "clk_gate_mp5", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ac, 0, 0 }, -+ { GATE_CLK_MP6, "clk_gate_mp6", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3b4, 0, 0 }, -+ { GATE_CLK_MP7, "clk_gate_mp7", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3bc, 0, 0 }, -+ { GATE_CLK_MP8, "clk_gate_mp8", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3c4, 0, 0 }, -+ { GATE_CLK_MP9, "clk_gate_mp9", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3cc, 0, 0 }, -+ { GATE_CLK_MP10, "clk_gate_mp10", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3d4, 0, 0 }, -+ { GATE_CLK_MP11, "clk_gate_mp11", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3dc, 0, 0 }, -+ { GATE_CLK_MP12, "clk_gate_mp12", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3e4, 0, 0 }, -+ { GATE_CLK_MP13, "clk_gate_mp13", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ec, 0, 0 }, -+ { GATE_CLK_MP14, "clk_gate_mp14", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3f4, 0, 0 }, -+ { GATE_CLK_MP15, "clk_gate_mp15", "clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3fc, 0, 0 }, -+}; -+ -+static const struct mango_divider_clock s1_div_clks = { -+ { DIV_CLK_MPLL_RP_CPU_NORMAL_0, "s1_clk_div_rp_cpu_normal_0", "s1_clk_gate_rp_cpu_normal_div0", -+ 0, 0x2044, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_MPLL_AXI_DDR_0, "s1_clk_div_axi_ddr_0", "s1_clk_gate_axi_ddr_div0", -+ 0, 0x20a8, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5}, -+ { DIV_CLK_FPLL_DDR01_1, "s1_clk_div_ddr01_1", "s1_clk_gate_ddr01_div1", -+ 0, 0x20b0, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, -+ { DIV_CLK_FPLL_DDR23_1, "s1_clk_div_ddr23_1", "s1_clk_gate_ddr23_div1", -+ 0, 0x20b8, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, -+ { DIV_CLK_FPLL_RP_CPU_NORMAL_1, "s1_clk_div_rp_cpu_normal_1", "s1_clk_gate_rp_cpu_normal_div1", -+ 0, 0x2040, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_50M_A53, "s1_clk_div_50m_a53", "s1_fpll_clock", -+ 0, 0x2048, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_TOP_RP_CMN_DIV2, "s1_clk_div_top_rp_cmn_div2", "s1_clk_mux_rp_cpu_normal", -+ 0, 0x204c, 16, 16, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_UART_500M, "s1_clk_div_uart_500m", "s1_fpll_clock", -+ 0, 0x2050, 16, 7, CLK_DIVIDER_READ_ONLY, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_AHB_LPC, "s1_clk_div_ahb_lpc", "s1_fpll_clock", -+ 0, 0x2054, 16, 16, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_EFUSE, "s1_clk_div_efuse", "s1_fpll_clock", -+ 0, 0x2078, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_TX_ETH0, "s1_clk_div_tx_eth0", "s1_fpll_clock", -+ 0, 0x2080, 16, 11, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_PTP_REF_I_ETH0, "s1_clk_div_ptp_ref_i_eth0", "s1_fpll_clock", -+ 0, 0x2084, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_REF_ETH0, "s1_clk_div_ref_eth0", "s1_fpll_clock", -+ 0, 0x2088, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_EMMC, "s1_clk_div_emmc", "s1_fpll_clock", -+ 0, 0x208c, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_SD, "s1_clk_div_sd", "s1_fpll_clock", -+ 0, 0x2094, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_TOP_AXI0, "s1_clk_div_top_axi0", "s1_fpll_clock", -+ 0, 0x209c, 16, 5, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_TOP_AXI_HSPERI, "s1_clk_div_top_axi_hsperi", "s1_fpll_clock", -+ 0, 0x20a0, 16, 5, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_AXI_DDR_1, "s1_clk_div_axi_ddr_1", "s1_clk_gate_axi_ddr_div1", -+ 0, 0x20a4, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5}, -+ { DIV_CLK_FPLL_DIV_TIMER1, "s1_clk_div_timer1", "s1_clk_div_50m_a53", -+ 0, 0x2058, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER2, "s1_clk_div_timer2", "s1_clk_div_50m_a53", -+ 0, 0x205c, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER3, "s1_clk_div_timer3", "s1_clk_div_50m_a53", -+ 0, 0x2060, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER4, "s1_clk_div_timer4", "s1_clk_div_50m_a53", -+ 0, 0x2064, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER5, "s1_clk_div_timer5", "s1_clk_div_50m_a53", -+ 0, 0x2068, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER6, "s1_clk_div_timer6", "s1_clk_div_50m_a53", -+ 0, 0x206c, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER7, "s1_clk_div_timer7", "s1_clk_div_50m_a53", -+ 0, 0x2070, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_DIV_TIMER8, "s1_clk_div_timer8", "s1_clk_div_50m_a53", -+ 0, 0x2074, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_100K_EMMC, "s1_clk_div_100k_emmc", "s1_clk_div_top_axi0", -+ 0, 0x2090, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_100K_SD, "s1_clk_div_100k_sd", "s1_clk_div_top_axi0", -+ 0, 0x2098, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_FPLL_GPIO_DB, "s1_clk_div_gpio_db", "s1_clk_div_top_axi0", -+ 0, 0x207c, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, }, -+ { DIV_CLK_DPLL0_DDR01_0, "s1_clk_div_ddr01_0", "s1_clk_gate_ddr01_div0", -+ 0, 0x20ac, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, -+ { DIV_CLK_DPLL1_DDR23_0, "s1_clk_div_ddr23_0", "s1_clk_gate_ddr23_div0", -+ 0, 0x20b4, 16, 8, CLK_DIVIDER_ONE_BASED | -+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, }, -+}; -+ -+static const struct mango_gate_clock s1_gate_clks = { -+ { GATE_CLK_RP_CPU_NORMAL_DIV0, "s1_clk_gate_rp_cpu_normal_div1", "s1_mpll_clock", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, -+ { GATE_CLK_AXI_DDR_DIV0, "s1_clk_gate_axi_ddr_div1", "s1_mpll_clock", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, -+ { GATE_CLK_DDR01_DIV0, "s1_clk_gate_ddr01_div0", "s1_fpll_clock", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 }, -+ { GATE_CLK_DDR23_DIV0, "s1_clk_gate_ddr23_div0", "s1_fpll_clock", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 }, -+ { GATE_CLK_RP_CPU_NORMAL_DIV1, "s1_clk_gate_rp_cpu_normal_div0", "s1_fpll_clock", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, -+ { GATE_CLK_AXI_DDR_DIV1, "s1_clk_gate_axi_ddr_div0", "s1_fpll_clock", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, -+ { GATE_CLK_DDR01_DIV1, "s1_clk_gate_ddr01_div1", "s1_dpll0_clock", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 14, 0 }, -+ { GATE_CLK_DDR23_DIV1, "s1_clk_gate_ddr23_div1", "s1_dpll1_clock", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 15, 0 }, -+ { GATE_CLK_A53_50M, "s1_clk_gate_a53_50m", "s1_clk_div_50m_a53", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 1, 0 }, -+ { GATE_CLK_TOP_RP_CMN_DIV2, "s1_clk_gate_top_rp_cmn_div2", "s1_clk_gate_rp_cpu_normal", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 2, 0 }, -+ { GATE_CLK_AXI_PCIE0, "s1_clk_gate_axi_pcie0", "s1_clk_gate_rp_cpu_normal", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 8, 0 }, -+ { GATE_CLK_AXI_PCIE1, "s1_clk_gate_axi_pcie1", "s1_clk_gate_rp_cpu_normal", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 9, 0 }, -+ { GATE_CLK_HSDMA, "s1_clk_gate_hsdma", "s1_clk_gate_top_rp_cmn_div2", -+ CLK_SET_RATE_PARENT, 0x2004, 10, 0 }, -+ { GATE_CLK_EMMC_100M, "s1_clk_gate_emmc", "s1_clk_div_emmc", -+ CLK_SET_RATE_PARENT, 0x2004, 3, 0 }, -+ { GATE_CLK_SD_100M, "s1_clk_gate_sd", "s1_clk_div_sd", -+ CLK_SET_RATE_PARENT, 0x2004, 6, 0 }, -+ { GATE_CLK_TX_ETH0, "s1_clk_gate_tx_eth0", "s1_clk_div_tx_eth0", -+ CLK_SET_RATE_PARENT, 0x2000, 30, 0 }, -+ { GATE_CLK_PTP_REF_I_ETH0, "s1_clk_gate_ptp_ref_i_eth0", "s1_clk_div_ptp_ref_i_eth0", -+ CLK_SET_RATE_PARENT, 0x2004, 0, 0 }, -+ { GATE_CLK_REF_ETH0, "s1_clk_gate_ref_eth0", "s1_clk_div_ref_eth0", -+ CLK_SET_RATE_PARENT, 0x2004, 1, 0 }, -+ { GATE_CLK_UART_500M, "s1_clk_gate_uart_500m", "s1_clk_div_uart_500m", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 4, 0 }, -+ { GATE_CLK_AHB_LPC, "s1_clk_gate_ahb_lpc", "s1_clk_div_ahb_lpc", -+ CLK_SET_RATE_PARENT, 0x2000, 7, 0 }, -+ { GATE_CLK_EFUSE, "s1_clk_gate_efuse", "s1_clk_div_efuse", -+ CLK_SET_RATE_PARENT, 0x2000, 20, 0}, -+ { GATE_CLK_TOP_AXI0, "s1_clk_gate_top_axi0", "s1_clk_div_top_axi0", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 11, 0 }, -+ { GATE_CLK_TOP_AXI_HSPERI, "s1_clk_gate_top_axi_hsperi", "s1_clk_div_top_axi_hsperi", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 12, 0 }, -+ { GATE_CLK_AHB_ROM, "s1_clk_gate_ahb_rom", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 8, 0 }, -+ { GATE_CLK_AHB_SF, "s1_clk_gate_ahb_sf", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 9, 0 }, -+ { GATE_CLK_AXI_SRAM, "s1_clk_gate_axi_sram", "s1_clk_gate_top_axi0", -+ CLK_IGNORE_UNUSED, 0x2000, 10, 0 }, -+ { GATE_CLK_APB_TIMER, "s1_clk_gate_apb_timer", "s1_clk_gate_top_axi0", -+ CLK_IGNORE_UNUSED, 0x2000, 11, 0 }, -+ { GATE_CLK_APB_EFUSE, "s1_clk_gate_apb_efuse", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 21, 0 }, -+ { GATE_CLK_APB_GPIO, "s1_clk_gate_apb_gpio", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 22, 0 }, -+ { GATE_CLK_APB_GPIO_INTR, "s1_clk_gate_apb_gpio_intr", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 23, 0 }, -+ { GATE_CLK_APB_I2C, "s1_clk_gate_apb_i2c", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 26, 0 }, -+ { GATE_CLK_APB_WDT, "s1_clk_gate_apb_wdt", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 27, 0 }, -+ { GATE_CLK_APB_PWM, "s1_clk_gate_apb_pwm", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 28, 0 }, -+ { GATE_CLK_APB_RTC, "s1_clk_gate_apb_rtc", "s1_clk_gate_top_axi0", -+ 0, 0x2000, 29, 0 }, -+ { GATE_CLK_SYSDMA_AXI, "s1_clk_gate_sysdma_axi", "s1_clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 3, 0 }, -+ { GATE_CLK_APB_UART, "s1_clk_gate_apb_uart", "s1_clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 5, 0 }, -+ { GATE_CLK_AXI_DBG_I2C, "s1_clk_gate_axi_dbg_i2c", "s1_clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 6, 0 }, -+ { GATE_CLK_APB_SPI, "s1_clk_gate_apb_spi", "s1_clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 25, 0 }, -+ { GATE_CLK_AXI_ETH0, "s1_clk_gate_axi_eth0", "s1_clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2000, 31, 0 }, -+ { GATE_CLK_AXI_EMMC, "s1_clk_gate_axi_emmc", "s1_clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2004, 2, 0 }, -+ { GATE_CLK_AXI_SD, "s1_clk_gate_axi_sd", "s1_clk_gate_top_axi_hsperi", -+ CLK_SET_RATE_PARENT, 0x2004, 5, 0 }, -+ { GATE_CLK_TIMER1, "s1_clk_gate_timer1", "s1_clk_div_timer1", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 12, 0 }, -+ { GATE_CLK_TIMER2, "s1_clk_gate_timer2", "s1_clk_div_timer2", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 13, 0 }, -+ { GATE_CLK_TIMER3, "s1_clk_gate_timer3", "s1_clk_div_timer3", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 14, 0 }, -+ { GATE_CLK_TIMER4, "s1_clk_gate_timer4", "s1_clk_div_timer4", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 15, 0 }, -+ { GATE_CLK_TIMER5, "s1_clk_gate_timer5", "s1_clk_div_timer5", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 16, 0 }, -+ { GATE_CLK_TIMER6, "s1_clk_gate_timer6", "s1_clk_div_timer6", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 17, 0 }, -+ { GATE_CLK_TIMER7, "s1_clk_gate_timer7", "s1_clk_div_timer7", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 18, 0 }, -+ { GATE_CLK_TIMER8, "s1_clk_gate_timer8", "s1_clk_div_timer8", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 19, 0 }, -+ { GATE_CLK_100K_EMMC, "s1_clk_gate_100k_emmc", "s1_clk_div_100k_emmc", -+ CLK_SET_RATE_PARENT, 0x2004, 4, 0 }, -+ { GATE_CLK_100K_SD, "s1_clk_gate_100k_sd", "s1_clk_div_100k_sd", -+ CLK_SET_RATE_PARENT, 0x2004, 7, 0 }, -+ { GATE_CLK_GPIO_DB, "s1_clk_gate_gpio_db", "s1_clk_div_gpio_db", -+ CLK_SET_RATE_PARENT, 0x2000, 24, 0 }, -+ { GATE_CLK_DDR01, "s1_clk_gate_ddr01", "s1_clk_mux_ddr01", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 }, -+ { GATE_CLK_DDR23, "s1_clk_gate_ddr23", "s1_clk_mux_ddr23", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 }, -+ { GATE_CLK_RP_CPU_NORMAL, "s1_clk_gate_rp_cpu_normal", "s1_clk_mux_rp_cpu_normal", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 }, -+ { GATE_CLK_AXI_DDR, "s1_clk_gate_axi_ddr", "s1_clk_mux_axi_ddr", -+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 }, -+ { GATE_CLK_RXU0, "s1_clk_gate_rxu0", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 0, 0 }, -+ { GATE_CLK_RXU1, "s1_clk_gate_rxu1", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 1, 0 }, -+ { GATE_CLK_RXU2, "s1_clk_gate_rxu2", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 2, 0 }, -+ { GATE_CLK_RXU3, "s1_clk_gate_rxu3", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 3, 0 }, -+ { GATE_CLK_RXU4, "s1_clk_gate_rxu4", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 4, 0 }, -+ { GATE_CLK_RXU5, "s1_clk_gate_rxu5", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 5, 0 }, -+ { GATE_CLK_RXU6, "s1_clk_gate_rxu6", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 6, 0 }, -+ { GATE_CLK_RXU7, "s1_clk_gate_rxu7", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 7, 0 }, -+ { GATE_CLK_RXU8, "s1_clk_gate_rxu8", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 8, 0 }, -+ { GATE_CLK_RXU9, "s1_clk_gate_rxu9", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 9, 0 }, -+ { GATE_CLK_RXU10, "s1_clk_gate_rxu10", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 10, 0 }, -+ { GATE_CLK_RXU11, "s1_clk_gate_rxu11", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 11, 0 }, -+ { GATE_CLK_RXU12, "s1_clk_gate_rxu12", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 12, 0 }, -+ { GATE_CLK_RXU13, "s1_clk_gate_rxu13", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 13, 0 }, -+ { GATE_CLK_RXU14, "s1_clk_gate_rxu14", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 14, 0 }, -+ { GATE_CLK_RXU15, "s1_clk_gate_rxu15", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 15, 0 }, -+ { GATE_CLK_RXU16, "s1_clk_gate_rxu16", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 16, 0 }, -+ { GATE_CLK_RXU17, "s1_clk_gate_rxu17", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 17, 0 }, -+ { GATE_CLK_RXU18, "s1_clk_gate_rxu18", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 18, 0 }, -+ { GATE_CLK_RXU19, "s1_clk_gate_rxu19", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 19, 0 }, -+ { GATE_CLK_RXU20, "s1_clk_gate_rxu20", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 20, 0 }, -+ { GATE_CLK_RXU21, "s1_clk_gate_rxu21", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 21, 0 }, -+ { GATE_CLK_RXU22, "s1_clk_gate_rxu22", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 22, 0 }, -+ { GATE_CLK_RXU23, "s1_clk_gate_rxu23", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 23, 0 }, -+ { GATE_CLK_RXU24, "s1_clk_gate_rxu24", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 24, 0 }, -+ { GATE_CLK_RXU25, "s1_clk_gate_rxu25", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 25, 0 }, -+ { GATE_CLK_RXU26, "s1_clk_gate_rxu26", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 26, 0 }, -+ { GATE_CLK_RXU27, "s1_clk_gate_rxu27", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 27, 0 }, -+ { GATE_CLK_RXU28, "s1_clk_gate_rxu28", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 28, 0 }, -+ { GATE_CLK_RXU29, "s1_clk_gate_rxu29", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 29, 0 }, -+ { GATE_CLK_RXU30, "s1_clk_gate_rxu30", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 30, 0 }, -+ { GATE_CLK_RXU31, "s1_clk_gate_rxu31", "s1_clk_gate_rp_cpu_normal", -+ 0, 0x368, 31, 0 }, -+ { GATE_CLK_MP0, "s1_clk_gate_mp0", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x384, 0, 0 }, -+ { GATE_CLK_MP1, "s1_clk_gate_mp1", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x38c, 0, 0 }, -+ { GATE_CLK_MP2, "s1_clk_gate_mp2", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x394, 0, 0 }, -+ { GATE_CLK_MP3, "s1_clk_gate_mp3", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x39c, 0, 0 }, -+ { GATE_CLK_MP4, "s1_clk_gate_mp4", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3a4, 0, 0 }, -+ { GATE_CLK_MP5, "s1_clk_gate_mp5", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ac, 0, 0 }, -+ { GATE_CLK_MP6, "s1_clk_gate_mp6", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3b4, 0, 0 }, -+ { GATE_CLK_MP7, "s1_clk_gate_mp7", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3bc, 0, 0 }, -+ { GATE_CLK_MP8, "s1_clk_gate_mp8", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3c4, 0, 0 }, -+ { GATE_CLK_MP9, "s1_clk_gate_mp9", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3cc, 0, 0 }, -+ { GATE_CLK_MP10, "s1_clk_gate_mp10", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3d4, 0, 0 }, -+ { GATE_CLK_MP11, "s1_clk_gate_mp11", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3dc, 0, 0 }, -+ { GATE_CLK_MP12, "s1_clk_gate_mp12", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3e4, 0, 0 }, -+ { GATE_CLK_MP13, "s1_clk_gate_mp13", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3ec, 0, 0 }, -+ { GATE_CLK_MP14, "s1_clk_gate_mp14", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3f4, 0, 0 }, -+ { GATE_CLK_MP15, "s1_clk_gate_mp15", "s1_clk_gate_rp_cpu_normal", -+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x3fc, 0, 0 }, -+}; -+ -+/* socket0 mux clocks */ -+static const char *const clk_mux_ddr01_p = { -+ "clk_div_ddr01_0", "clk_div_ddr01_1"}; -+static const char *const clk_mux_ddr23_p = { -+ "clk_div_ddr23_0", "clk_div_ddr23_1"}; -+static const char *const clk_mux_rp_cpu_normal_p = { -+ "clk_div_rp_cpu_normal_0", "clk_div_rp_cpu_normal_1"}; -+static const char *const clk_mux_axi_ddr_p = { -+ "clk_div_axi_ddr_0", "clk_div_axi_ddr_1"}; -+ -+struct mango_mux_clock s0_mux_clks = { -+ { -+ MUX_CLK_DDR01, "clk_mux_ddr01", clk_mux_ddr01_p, -+ ARRAY_SIZE(clk_mux_ddr01_p), -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | -+ CLK_MUX_READ_ONLY, -+ 0x2020, 2, 1, 0, -+ }, -+ { -+ MUX_CLK_DDR23, "clk_mux_ddr23", clk_mux_ddr23_p, -+ ARRAY_SIZE(clk_mux_ddr23_p), -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | -+ CLK_MUX_READ_ONLY, -+ 0x2020, 3, 1, 0, -+ }, -+ { -+ MUX_CLK_RP_CPU_NORMAL, "clk_mux_rp_cpu_normal", clk_mux_rp_cpu_normal_p, -+ ARRAY_SIZE(clk_mux_rp_cpu_normal_p), -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, -+ 0x2020, 0, 1, 0, -+ }, -+ { -+ MUX_CLK_AXI_DDR, "clk_mux_axi_ddr", clk_mux_axi_ddr_p, -+ ARRAY_SIZE(clk_mux_axi_ddr_p), -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, -+ 0x2020, 1, 1, 0, -+ }, -+}; -+ -+/* socket1 mux clocks */ -+static const char *const s1_clk_mux_ddr01_p = { -+ "s1_clk_div_ddr01_0", "s1_clk_div_ddr01_1"}; -+static const char *const s1_clk_mux_ddr23_p = { -+ "s1_clk_div_ddr23_0", "s1_clk_div_ddr23_1"}; -+static const char *const s1_clk_mux_rp_cpu_normal_p = { -+ "s1_clk_div_rp_cpu_normal_0", "s1_clk_div_rp_cpu_normal_1"}; -+static const char *const s1_clk_mux_axi_ddr_p = { -+ "s1_clk_div_axi_ddr_0", "s1_clk_div_axi_ddr_1"}; -+ -+struct mango_mux_clock s1_mux_clks = { -+ { -+ MUX_CLK_DDR01, "s1_clk_mux_ddr01", s1_clk_mux_ddr01_p, -+ ARRAY_SIZE(s1_clk_mux_ddr01_p), -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | -+ CLK_MUX_READ_ONLY, -+ 0x2020, 2, 1, 0, -+ }, -+ { -+ MUX_CLK_DDR23, "s1_clk_mux_ddr23", s1_clk_mux_ddr23_p, -+ ARRAY_SIZE(s1_clk_mux_ddr23_p), -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | -+ CLK_MUX_READ_ONLY, -+ 0x2020, 3, 1, 0, -+ }, -+ { -+ MUX_CLK_RP_CPU_NORMAL, "s1_clk_mux_rp_cpu_normal", s1_clk_mux_rp_cpu_normal_p, -+ ARRAY_SIZE(s1_clk_mux_rp_cpu_normal_p), -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, -+ 0x2020, 0, 1, 0, -+ }, -+ { -+ MUX_CLK_AXI_DDR, "s1_clk_mux_axi_ddr", s1_clk_mux_axi_ddr_p, -+ ARRAY_SIZE(s1_clk_mux_axi_ddr_p), -+ CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, -+ 0x2020, 1, 1, 0, -+ }, -+}; -+ -+struct mango_clk_table pll_clk_tables = { -+ .pll_clks_num = ARRAY_SIZE(mango_root_pll_clks), -+ .pll_clks = mango_root_pll_clks, -+}; -+ -+struct mango_clk_table div_clk_tables = { -+ { -+ .id = S0_DIV_CLK_TABLE, -+ .div_clks_num = ARRAY_SIZE(s0_div_clks), -+ .div_clks = s0_div_clks, -+ .gate_clks_num = ARRAY_SIZE(s0_gate_clks), -+ .gate_clks = s0_gate_clks, -+ },{ -+ .id = S1_DIV_CLK_TABLE, -+ .div_clks_num = ARRAY_SIZE(s1_div_clks), -+ .div_clks = s1_div_clks, -+ .gate_clks_num = ARRAY_SIZE(s1_gate_clks), -+ .gate_clks = s1_gate_clks, -+ }, -+}; -+ -+struct mango_clk_table mux_clk_tables = { -+ { -+ .id = S0_MUX_CLK_TABLE, -+ .mux_clks_num = ARRAY_SIZE(s0_mux_clks), -+ .mux_clks = s0_mux_clks, -+ },{ -+ .id = S1_MUX_CLK_TABLE, -+ .mux_clks_num = ARRAY_SIZE(s1_mux_clks), -+ .mux_clks = s1_mux_clks, -+ }, -+}; -+ -+static const struct of_device_id mango_clk_match_ids_tables = { -+ { -+ .compatible = "mango, pll-clock", -+ .data = &pll_clk_tables, -+ }, -+ { -+ .compatible = "mango, pll-child-clock", -+ .data = div_clk_tables, -+ }, -+ { -+ .compatible = "mango, pll-mux-clock", -+ .data = mux_clk_tables, -+ }, -+ { -+ .compatible = "mango, clk-default-rates", -+ }, -+ { -+ .compatible = "mango, dm-pll-clock", -+ .data = &pll_clk_tables, -+ }, -+ { -+ .compatible = "mango, dm-pll-child-clock", -+ .data = div_clk_tables, -+ }, -+ { -+ .compatible = "mango, dm-pll-mux-clock", -+ .data = mux_clk_tables, -+ }, -+ { -+ .compatible = "mango, dm-clk-default-rates", -+ }, -+ {} -+}; -+ -+static void __init mango_clk_init(struct device_node *node) -+{ -+ struct device_node *np_top; -+ struct mango_clk_data *clk_data = NULL; -+ const struct mango_clk_table *dev_data; -+ struct regmap *syscon; -+ void __iomem *base; -+ int i, ret = 0; -+ unsigned int id; -+ const char *clk_name; -+ const struct of_device_id *match = NULL; -+ -+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); -+ if (!clk_data) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ match = of_match_node(mango_clk_match_ids_tables, node); -+ if (match) { -+ dev_data = (struct mango_clk_table *)match->data; -+ } else { -+ pr_err("%s did't match node data\n", __func__); -+ ret = -ENODEV; -+ goto no_match_data; -+ } -+ -+ np_top = of_parse_phandle(node, "subctrl-syscon", 0); -+ if (!np_top) { -+ pr_err("%s can't get subctrl-syscon node\n", -+ __func__); -+ ret = -EINVAL; -+ goto no_match_data; -+ } -+ -+ syscon = device_node_to_regmap(np_top); -+ if (IS_ERR_OR_NULL(syscon)) { -+ pr_err("%s cannot get regmap %ld\n", __func__, PTR_ERR(syscon)); -+ ret = -ENODEV; -+ goto no_match_data; -+ } -+ base = of_iomap(np_top, 0); -+ -+ spin_lock_init(&clk_data->lock); -+ if (of_device_is_compatible(node, "mango, pll-clock") || -+ of_device_is_compatible(node, "mango, dm-pll-clock")) { -+ if (!dev_data->pll_clks_num) { -+ ret = -EINVAL; -+ goto no_match_data; -+ } -+ -+ clk_data->table = dev_data; -+ clk_data->base = base; -+ clk_data->syscon_top = syscon; -+ -+ if (of_property_read_string(node, "clock-output-names", &clk_name)) { -+ pr_err("%s cannot get pll name for %s\n", -+ __func__, node->full_name); -+ ret = -ENODEV; -+ goto no_match_data; -+ } -+ if (of_device_is_compatible(node, "mango, pll-clock")) -+ ret = mango_register_pll_clks(node, clk_data, clk_name); -+ else -+ ret = dm_mango_register_pll_clks(node, clk_data, clk_name); -+ } -+ -+ if (of_device_is_compatible(node, "mango, pll-child-clock") || -+ of_device_is_compatible(node, "mango, dm-pll-child-clock")) { -+ ret = of_property_read_u32(node, "id", &id); -+ if (ret) { -+ pr_err("not assigned id for %s\n", node->full_name); -+ ret = -ENODEV; -+ goto no_match_data; -+ } -+ -+ /* Below brute-force to check dts property "id" -+ * whether match id of array -+ */ -+ for (i = 0; i < ARRAY_SIZE(div_clk_tables); i++) { -+ if (id == dev_datai.id) -+ break; /* found */ -+ } -+ clk_data->table = &dev_datai; -+ clk_data->base = base; -+ clk_data->syscon_top = syscon; -+ if (of_device_is_compatible(node, "mango, pll-child-clock")) -+ ret = mango_register_div_clks(node, clk_data); -+ else -+ ret = dm_mango_register_div_clks(node, clk_data); -+ } -+ -+ if (of_device_is_compatible(node, "mango, pll-mux-clock") || -+ of_device_is_compatible(node, "mango, dm-pll-mux-clock")) { -+ ret = of_property_read_u32(node, "id", &id); -+ if (ret) { -+ pr_err("not assigned id for %s\n", node->full_name); -+ ret = -ENODEV; -+ goto no_match_data; -+ } -+ -+ /* Below brute-force to check dts property "id" -+ * whether match id of array -+ */ -+ for (i = 0; i < ARRAY_SIZE(mux_clk_tables); i++) { -+ if (id == dev_datai.id) -+ break; /* found */ -+ } -+ clk_data->table = &dev_datai; -+ clk_data->base = base; -+ clk_data->syscon_top = syscon; -+ if (of_device_is_compatible(node, "mango, pll-mux-clock")) -+ ret = mango_register_mux_clks(node, clk_data); -+ else -+ ret = dm_mango_register_mux_clks(node, clk_data); -+ } -+ -+ if (of_device_is_compatible(node, "mango, clk-default-rates")) -+ ret = set_default_clk_rates(node); -+ -+ if (of_device_is_compatible(node, "mango, dm-clk-default-rates")) -+ ret = dm_set_default_clk_rates(node); -+ -+ if (!ret) -+ return; -+ -+no_match_data: -+ kfree(clk_data); -+ -+out: -+ pr_err("%s failed error number %d\n", __func__, ret); -+} -+ -+CLK_OF_DECLARE(mango_clk_pll, "mango, pll-clock", mango_clk_init); -+CLK_OF_DECLARE(mango_clk_pll_child, "mango, pll-child-clock", mango_clk_init); -+CLK_OF_DECLARE(mango_clk_pll_mux, "mango, pll-mux-clock", mango_clk_init); -+CLK_OF_DECLARE(mango_clk_default_rate, "mango, clk-default-rates", mango_clk_init); -+CLK_OF_DECLARE(dm_mango_clk_pll, "mango, dm-pll-clock", mango_clk_init); -+CLK_OF_DECLARE(dm_mango_clk_pll_child, "mango, dm-pll-child-clock", mango_clk_init); -+CLK_OF_DECLARE(dm_mango_clk_pll_mux, "mango, dm-pll-mux-clock", mango_clk_init); -+CLK_OF_DECLARE(dm_mango_clk_default_rate, "mango, dm-clk-default-rates", mango_clk_init); -diff --git a/drivers/clk/sophgo/clk.c b/drivers/clk/sophgo/clk.c -new file mode 100644 -index 000000000000..4d3893ace2b9 ---- /dev/null -+++ b/drivers/clk/sophgo/clk.c -@@ -0,0 +1,883 @@ -+/* -+ * Copyright (c) 2022 SOPHGO -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include <linux/of_device.h> -+#include <linux/platform_device.h> -+#include <linux/spinlock.h> -+#include <linux/mfd/syscon.h> -+#include <linux/io.h> -+#include <linux/of_address.h> -+#include <linux/string.h> -+#include <linux/log2.h> -+ -+#include "clk.h" -+ -+/* -+ * @hw: handle between common and hardware-specific interfaces -+ * @reg: register containing divider -+ * @shift: shift to the divider bit field -+ * @width: width of the divider bit field -+ * @initial_val:initial value of the divider -+ * @table: the div table that the divider supports -+ * @lock: register lock -+ */ -+struct mango_clk_divider { -+ struct clk_hw hw; -+ void __iomem *reg; -+ u8 shift; -+ u8 width; -+ u8 flags; -+ u32 initial_val; -+ const struct clk_div_table *table; -+ spinlock_t *lock; -+}; -+ -+static inline int mango_pll_enable(struct regmap *map, -+ struct mango_pll_clock *pll, bool en) -+{ -+ unsigned int value; -+ unsigned long enter; -+ unsigned int id = pll->id; -+ -+ if (en) { -+ /* wait pll lock */ -+ enter = jiffies; -+ regmap_read(map, pll->status_offset, &value); -+ while (!((value >> (PLL_STAT_LOCK_OFFSET + id)) & 0x1)) { -+ regmap_read(map, pll->status_offset, &value); -+ if (time_after(jiffies, enter + HZ / 10)) -+ pr_warn("%s not locked\n", pll->name); -+ } -+ /* wait pll updating */ -+ enter = jiffies; -+ regmap_read(map, pll->status_offset, &value); -+ while (((value >> id) & 0x1)) { -+ regmap_read(map, pll->status_offset, &value); -+ if (time_after(jiffies, enter + HZ / 10)) -+ pr_warn("%s still updating\n", pll->name); -+ } -+ /* enable pll */ -+ regmap_read(map, pll->enable_offset, &value); -+ regmap_write(map, pll->enable_offset, value | (1 << id)); -+ } else { -+ /* disable pll */ -+ regmap_read(map, pll->enable_offset, &value); -+ regmap_write(map, pll->enable_offset, value & (~(1 << id))); -+ } -+ -+ return 0; -+} -+ -+static inline int mango_pll_write(struct regmap *map, int id, int value) -+{ -+ return regmap_write(map, PLL_CTRL_OFFSET + (id << 2), value); -+} -+ -+static inline int mango_pll_read(struct regmap *map, int id, unsigned int *pvalue) -+{ -+ return regmap_read(map, PLL_CTRL_OFFSET + (id << 2), pvalue); -+} -+ -+static unsigned int _get_table_div(const struct clk_div_table *table, -+ unsigned int val) -+{ -+ const struct clk_div_table *clkt; -+ -+ for (clkt = table; clkt->div; clkt++) -+ if (clkt->val == val) -+ return clkt->div; -+ return 0; -+} -+ -+static unsigned int _get_div(const struct clk_div_table *table, -+ unsigned int val, unsigned long flags, u8 width) -+{ -+ if (flags & CLK_DIVIDER_ONE_BASED) -+ return val; -+ if (flags & CLK_DIVIDER_POWER_OF_TWO) -+ return 1 << val; -+ if (flags & CLK_DIVIDER_MAX_AT_ZERO) -+ return val ? val : div_mask(width) + 1; -+ if (table) -+ return _get_table_div(table, val); -+ return val + 1; -+} -+ -+static unsigned long mango_clk_divider_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct mango_clk_divider *divider = to_mango_clk_divider(hw); -+ unsigned int val; -+ -+ val = readl(divider->reg) >> divider->shift; -+ val &= div_mask(divider->width); -+ -+#ifdef CONFIG_ARCH_BM1880 -+ /* if select divide factor from initial value */ -+ if (!(readl(divider->reg) & BIT(3))) -+ val = divider->initial_val; -+#endif -+ -+ return divider_recalc_rate(hw, parent_rate, val, divider->table, -+ divider->flags, divider->width); -+} -+ -+static long mango_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ int bestdiv; -+ struct mango_clk_divider *divider = to_mango_clk_divider(hw); -+ -+ /* if read only, just return current value */ -+ if (divider->flags & CLK_DIVIDER_READ_ONLY) { -+ bestdiv = readl(divider->reg) >> divider->shift; -+ bestdiv &= div_mask(divider->width); -+ bestdiv = _get_div(divider->table, bestdiv, divider->flags, -+ divider->width); -+ return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); -+ } -+ -+ return divider_round_rate(hw, rate, prate, divider->table, -+ divider->width, divider->flags); -+} -+ -+static int mango_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ unsigned int value; -+ unsigned int val; -+ unsigned long flags = 0; -+ struct mango_clk_divider *divider = to_mango_clk_divider(hw); -+ -+ value = divider_get_val(rate, parent_rate, divider->table, -+ divider->width, divider->flags); -+ -+ if (divider->lock) -+ spin_lock_irqsave(divider->lock, flags); -+ else -+ __acquire(divider->lock); -+ -+ /* div assert */ -+ val = readl(divider->reg); -+ val &= ~0x1; -+ writel(val, divider->reg); -+ -+ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { -+ val = div_mask(divider->width) << (divider->shift + 16); -+ } else { -+ val = readl(divider->reg); -+ val &= ~(div_mask(divider->width) << divider->shift); -+ } -+ -+ val |= value << divider->shift; -+ writel(val, divider->reg); -+ -+ if (!(divider->flags & CLK_DIVIDER_READ_ONLY)) -+ val |= 1 << 3; -+ -+ /* de-assert */ -+ val |= 1; -+ writel(val, divider->reg); -+ if (divider->lock) -+ spin_unlock_irqrestore(divider->lock, flags); -+ else -+ __release(divider->lock); -+ -+ return 0; -+} -+ -+/* Below array is the total combination lists of POSTDIV1 and POSTDIV2 -+ * for example: -+ * postdiv1_20 = {1, 1, 1} -+ * ==> div1 = 1, div2 = 1 , div1 * div2 = 1 -+ * postdiv1_222 = {6, 7, 42} -+ * ==> div1 = 6, div2 = 7 , div1 * div2 = 42 -+ * -+ * And POSTDIV_RESULT_INDEX point to 3rd element in the array -+ */ -+#define POSTDIV_RESULT_INDEX 2 -+int postdiv1_23 = { -+ {2, 4, 8}, {3, 3, 9}, {2, 5, 10}, {2, 6, 12}, -+ {2, 7, 14}, {3, 5, 15}, {4, 4, 16}, {3, 6, 18}, -+ {4, 5, 20}, {3, 7, 21}, {4, 6, 24}, {5, 5, 25}, -+ {4, 7, 28}, {5, 6, 30}, {5, 7, 35}, {6, 6, 36}, -+ {6, 7, 42}, {7, 7, 49} -+}; -+ -+/* -+ * @reg_value: current register value -+ * @parent_rate: parent frequency -+ * -+ * This function is used to calculate below "rate" in equation -+ * rate = (parent_rate/REFDIV) x FBDIV/POSTDIV1/POSTDIV2 -+ * = (parent_rate x FBDIV) / (REFDIV x POSTDIV1 x POSTDIV2) -+ */ -+static unsigned long __pll_recalc_rate(unsigned int reg_value, -+ unsigned long parent_rate) -+{ -+ unsigned int fbdiv, refdiv; -+ unsigned int postdiv1, postdiv2; -+ u64 rate, numerator, denominator; -+ -+ fbdiv = (reg_value >> 16) & 0xfff; -+ refdiv = reg_value & 0x3f; -+ postdiv1 = (reg_value >> 8) & 0x7; -+ postdiv2 = (reg_value >> 12) & 0x7; -+ -+ numerator = parent_rate * fbdiv; -+ denominator = refdiv * postdiv1 * postdiv2; -+ do_div(numerator, denominator); -+ rate = numerator; -+ -+ return rate; -+} -+ -+/* -+ * @reg_value: current register value -+ * @rate: request rate -+ * @prate: parent rate -+ * @pctrl_table: use to save div1/div2/fbdiv/refdiv -+ * -+ * We use below equation to get POSTDIV1 and POSTDIV2 -+ * POSTDIV = (parent_rate/REFDIV) x FBDIV/input_rate -+ * above POSTDIV = POSTDIV1*POSTDIV2 -+ */ -+static int __pll_get_postdiv_1_2(unsigned long rate, unsigned long prate, -+ unsigned int fbdiv, unsigned int refdiv, unsigned int *postdiv1, -+ unsigned int *postdiv2) -+{ -+ int index = 0; -+ int ret = 0; -+ u64 tmp0; -+ -+ /* calculate (parent_rate/refdiv) -+ * and result save to prate -+ */ -+ tmp0 = prate; -+ do_div(tmp0, refdiv); -+ -+ /* calcuate ((parent_rate/REFDIV) x FBDIV) -+ * and result save to prate -+ */ -+ tmp0 *= fbdiv; -+ -+ /* calcuate (((parent_rate/REFDIV) x FBDIV)/input_rate) -+ * and result save to prate -+ * here *prate is (POSTDIV1*POSTDIV2) -+ */ -+ do_div(tmp0, rate); -+ -+ /* calculate div1 and div2 value */ -+ if (tmp0 <= 7) { -+ /* (div1 * div2) <= 7, no need to use array search */ -+ *postdiv1 = tmp0; -+ *postdiv2 = 1; -+ } else { -+ /* (div1 * div2) > 7, use array search */ -+ for (index = 0; index < ARRAY_SIZE(postdiv1_2); index++) { -+ if (tmp0 > postdiv1_2indexPOSTDIV_RESULT_INDEX) { -+ continue; -+ } else { -+ /* found it */ -+ break; -+ } -+ } -+ if (index < ARRAY_SIZE(postdiv1_2)) { -+ *postdiv1 = postdiv1_2index1; -+ *postdiv2 = postdiv1_2index0; -+ } else { -+ pr_debug("%s out of postdiv array range!\n", __func__); -+ ret = -ESPIPE; -+ } -+ } -+ -+ return ret; -+} -+ -+static int __get_pll_ctl_setting(struct mango_pll_ctrl *best, -+ unsigned long req_rate, unsigned long parent_rate) -+{ -+ int ret; -+ unsigned int fbdiv, refdiv, fref, postdiv1, postdiv2; -+ unsigned long tmp = 0, foutvco; -+ -+ fref = parent_rate; -+ -+ for (refdiv = REFDIV_MIN; refdiv < REFDIV_MAX + 1; refdiv++) { -+ for (fbdiv = FBDIV_MIN; fbdiv < FBDIV_MAX + 1; fbdiv++) { -+ foutvco = fref * fbdiv / refdiv; -+ /* check fpostdiv pfd */ -+ if (foutvco < PLL_FREQ_MIN || foutvco > PLL_FREQ_MAX -+ || (fref / refdiv) < 10) -+ continue; -+ -+ ret = __pll_get_postdiv_1_2(req_rate, fref, fbdiv, -+ refdiv, &postdiv1, &postdiv2); -+ if (ret) -+ continue; -+ -+ tmp = foutvco / (postdiv1 * postdiv2); -+ if (abs_diff(tmp, req_rate) < abs_diff(best->freq, req_rate)) { -+ best->freq = tmp; -+ best->refdiv = refdiv; -+ best->fbdiv = fbdiv; -+ best->postdiv1 = postdiv1; -+ best->postdiv2 = postdiv2; -+ if (tmp == req_rate) -+ return 0; -+ } -+ continue; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * @hw: ccf use to hook get mango_pll_clock -+ * @parent_rate: parent rate -+ * -+ * The is function will be called through clk_get_rate -+ * and return current rate after decoding reg value -+ */ -+static unsigned long mango_clk_pll_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ unsigned int value; -+ unsigned long rate; -+ struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw); -+ -+ mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value); -+ rate = __pll_recalc_rate(value, parent_rate); -+ return rate; -+} -+ -+static long mango_clk_pll_round_rate(struct clk_hw *hw, -+ unsigned long req_rate, unsigned long *prate) -+{ -+ unsigned int value; -+ struct mango_pll_ctrl pctrl_table; -+ struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw); -+ long proper_rate; -+ -+ memset(&pctrl_table, 0, sizeof(struct mango_pll_ctrl)); -+ -+ /* use current setting to get fbdiv, refdiv -+ * then combine with prate, and req_rate to -+ * get postdiv1 and postdiv2 -+ */ -+ mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value); -+ __get_pll_ctl_setting(&pctrl_table, req_rate, *prate); -+ if (!pctrl_table.freq) { -+ proper_rate = 0; -+ goto out; -+ } -+ -+ value = TOP_PLL_CTRL(pctrl_table.fbdiv, pctrl_table.postdiv1, -+ pctrl_table.postdiv2, pctrl_table.refdiv); -+ proper_rate = (long)__pll_recalc_rate(value, *prate); -+ -+out: -+ return proper_rate; -+} -+ -+static int mango_clk_pll_determine_rate(struct clk_hw *hw, -+ struct clk_rate_request *req) -+{ -+ req->rate = mango_clk_pll_round_rate(hw, min(req->rate, req->max_rate), -+ &req->best_parent_rate); -+ return 0; -+} -+ -+static int mango_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ unsigned long flags; -+ unsigned int value; -+ int ret = 0; -+ struct mango_pll_ctrl pctrl_table; -+ struct mango_pll_clock *mango_pll = to_mango_pll_clk(hw); -+ -+ memset(&pctrl_table, 0, sizeof(struct mango_pll_ctrl)); -+ spin_lock_irqsave(mango_pll->lock, flags); -+ if (mango_pll_enable(mango_pll->syscon_top, mango_pll, 0)) { -+ pr_warn("Can't disable pll(%s), status error\n", mango_pll->name); -+ goto out; -+ } -+ mango_pll_read(mango_pll->syscon_top, mango_pll->id, &value); -+ __get_pll_ctl_setting(&pctrl_table, rate, parent_rate); -+ if (!pctrl_table.freq) { -+ pr_warn("%s: Can't find a proper pll setting\n", mango_pll->name); -+ goto out; -+ } -+ -+ value = TOP_PLL_CTRL(pctrl_table.fbdiv, pctrl_table.postdiv1, -+ pctrl_table.postdiv2, pctrl_table.refdiv); -+ -+ /* write the value to top register */ -+ mango_pll_write(mango_pll->syscon_top, mango_pll->id, value); -+ mango_pll_enable(mango_pll->syscon_top, mango_pll, 1); -+out: -+ spin_unlock_irqrestore(mango_pll->lock, flags); -+ return ret; -+} -+ -+const struct clk_ops mango_clk_divider_ops = { -+ .recalc_rate = mango_clk_divider_recalc_rate, -+ .round_rate = mango_clk_divider_round_rate, -+ .set_rate = mango_clk_divider_set_rate, -+}; -+ -+const struct clk_ops mango_clk_divider_ro_ops = { -+ .recalc_rate = mango_clk_divider_recalc_rate, -+ .round_rate = mango_clk_divider_round_rate, -+}; -+ -+const struct clk_ops mango_clk_pll_ops = { -+ .recalc_rate = mango_clk_pll_recalc_rate, -+ .round_rate = mango_clk_pll_round_rate, -+ .determine_rate = mango_clk_pll_determine_rate, -+ .set_rate = mango_clk_pll_set_rate, -+}; -+ -+const struct clk_ops mango_clk_pll_ro_ops = { -+ .recalc_rate = mango_clk_pll_recalc_rate, -+ .round_rate = mango_clk_pll_round_rate, -+}; -+ -+struct mux_cb_clk_name { -+ const char *name; -+ struct list_head node; -+}; -+ -+static struct list_head mux_cb_clk_name_list = -+ LIST_HEAD_INIT(mux_cb_clk_name_list); -+static int mux_notifier_cb(struct notifier_block *nb, -+ unsigned long event, void *data) -+{ -+ int ret = 0; -+ static unsigned char mux_id = 1; -+ struct clk_notifier_data *ndata = data; -+ struct clk_hw *hw = __clk_get_hw(ndata->clk); -+ const struct clk_ops *ops = &clk_mux_ops; -+ struct mux_cb_clk_name *cb_lsit; -+ -+ if (event == PRE_RATE_CHANGE) { -+ struct clk_hw *hw_p = clk_hw_get_parent(hw); -+ -+ cb_lsit = kmalloc(sizeof(*cb_lsit), GFP_KERNEL); -+ if (cb_lsit) { -+ INIT_LIST_HEAD(&cb_lsit->node); -+ list_add_tail(&cb_lsit->node, &mux_cb_clk_name_list); -+ } else { -+ pr_err("mux cb kmalloc mem fail\n"); -+ goto out; -+ } -+ -+ cb_lsit->name = clk_hw_get_name(hw_p); -+ mux_id = ops->get_parent(hw); -+ if (mux_id > 1) { -+ ret = 1; -+ goto out; -+ } -+ ops->set_parent(hw, !mux_id); -+ } else if (event == POST_RATE_CHANGE) { -+ struct clk_hw *hw_p = clk_hw_get_parent(hw); -+ -+ cb_lsit = list_first_entry_or_null(&mux_cb_clk_name_list, -+ typeof(*cb_lsit), node); -+ if (cb_lsit) { -+ const char *pre_name = cb_lsit->name; -+ -+ list_del_init(&cb_lsit->node); -+ kfree(cb_lsit); -+ if (strcmp(clk_hw_get_name(hw_p), pre_name)) -+ goto out; -+ } -+ -+ ops->set_parent(hw, mux_id); -+ } -+ -+out: -+ return notifier_from_errno(ret); -+} -+ -+int set_default_clk_rates(struct device_node *node) -+{ -+ struct of_phandle_args clkspec; -+ struct property *prop; -+ const __be32 *cur; -+ int rc, index = 0; -+ struct clk *clk; -+ u32 rate; -+ -+ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) { -+ if (rate) { -+ rc = of_parse_phandle_with_args(node, "clocks", -+ "#clock-cells", index, &clkspec); -+ if (rc < 0) { -+ /* skip empty (null) phandles */ -+ if (rc == -ENOENT) -+ continue; -+ else -+ return rc; -+ } -+ -+ clk = of_clk_get_from_provider(&clkspec); -+ if (IS_ERR(clk)) { -+ pr_warn("clk: couldn't get clock %d for %s\n", -+ index, node->full_name); -+ return PTR_ERR(clk); -+ } -+ -+ rc = clk_set_rate(clk, rate); -+ if (rc < 0) -+ pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n", -+ __clk_get_name(clk), rate, rc, -+ clk_get_rate(clk)); -+ clk_put(clk); -+ } -+ index++; -+ } -+ -+ return 0; -+} -+ -+static struct clk *__register_divider_clks(struct device *dev, const char *name, -+ const char *parent_name, -+ unsigned long flags, -+ void __iomem *reg, u8 shift, -+ u8 width, u32 initial_val, -+ u8 clk_divider_flags, -+ const struct clk_div_table *table, -+ spinlock_t *lock) -+{ -+ struct mango_clk_divider *div; -+ struct clk_hw *hw; -+ struct clk_init_data init; -+ int ret; -+ -+ if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { -+ if (width + shift > 16) { -+ pr_warn("divider value exceeds LOWORD field\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ } -+ -+ /* allocate the divider */ -+ div = kzalloc(sizeof(*div), GFP_KERNEL); -+ if (!div) -+ return ERR_PTR(-ENOMEM); -+ -+ init.name = name; -+ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) -+ init.ops = &mango_clk_divider_ro_ops; -+ else -+ init.ops = &mango_clk_divider_ops; -+ init.flags = flags; -+ init.parent_names = (parent_name ? &parent_name : NULL); -+ init.num_parents = (parent_name ? 1 : 0); -+ -+ /* struct mango_clk_divider assignments */ -+ div->reg = reg; -+ div->shift = shift; -+ div->width = width; -+ div->flags = clk_divider_flags; -+ div->lock = lock; -+ div->hw.init = &init; -+ div->table = table; -+ div->initial_val = initial_val; -+ -+ /* register the clock */ -+ hw = &div->hw; -+ ret = clk_hw_register(dev, hw); -+ if (ret) { -+ kfree(div); -+ hw = ERR_PTR(ret); -+ return ERR_PTR(-EBUSY); -+ } -+ -+ return hw->clk; -+} -+ -+static inline int register_provider_clks -+(struct device_node *node, struct mango_clk_data *clk_data, int clk_num) -+{ -+ return of_clk_add_provider(node, of_clk_src_onecell_get, -+ &clk_data->clk_data); -+} -+ -+static int register_gate_clks(struct device *dev, struct mango_clk_data *clk_data) -+{ -+ struct clk *clk; -+ const struct mango_clk_table *table = clk_data->table; -+ const struct mango_gate_clock *gate_clks = table->gate_clks; -+ void __iomem *base = clk_data->base; -+ int clk_num = table->gate_clks_num; -+ int i; -+ -+ for (i = 0; i < clk_num; i++) { -+ clk = clk_register_gate( -+ dev, gate_clksi.name, gate_clksi.parent_name, -+ gate_clksi.flags, base + gate_clksi.offset, -+ gate_clksi.bit_idx, gate_clksi.gate_flags, -+ &clk_data->lock); -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register clock %s\n", __func__, -+ gate_clksi.name); -+ goto err; -+ } -+ -+ if (gate_clksi.alias) -+ clk_register_clkdev(clk, gate_clksi.alias, NULL); -+ -+ clk_data->clk_data.clksgate_clksi.id = clk; -+ } -+ -+ return 0; -+ -+err: -+ while (i--) -+ clk_unregister_gate(clk_data->clk_data.clksgate_clksi.id); -+ -+ return PTR_ERR(clk); -+} -+ -+static int register_divider_clks(struct device *dev, -+ struct mango_clk_data *clk_data) -+{ -+ struct clk *clk; -+ const struct mango_clk_table *table = clk_data->table; -+ const struct mango_divider_clock *div_clks = table->div_clks; -+ void __iomem *base = clk_data->base; -+ int clk_num = table->div_clks_num; -+ int i, val; -+ -+ for (i = 0; i < clk_num; i++) { -+ clk = __register_divider_clks( -+ NULL, div_clksi.name, div_clksi.parent_name, -+ div_clksi.flags, base + div_clksi.offset, -+ div_clksi.shift, div_clksi.width, -+ div_clksi.initial_val, -+ (div_clksi.initial_sel & MANGO_CLK_USE_INIT_VAL) ? -+ div_clksi.div_flags | CLK_DIVIDER_READ_ONLY : -+ div_clksi.div_flags, -+ div_clksi.table, &clk_data->lock); -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register clock %s\n", __func__, -+ div_clksi.name); -+ goto err; -+ } -+ -+ clk_data->clk_data.clksdiv_clksi.id = clk; -+ -+ if (div_clksi.initial_sel == MANGO_CLK_USE_REG_VAL) { -+ regmap_read(clk_data->syscon_top, div_clksi.offset, -+ &val); -+ -+ /* -+ * set a default divider factor, -+ * clk driver should not select divider clock as the -+ * clock source, before set the divider by right process -+ * (assert div, set div factor, de assert div). -+ */ -+ if (div_clksi.initial_val > 0) -+ val |= (div_clksi.initial_val << 16 | 1 << 3); -+ else { -+ /* -+ * the div register is config to use divider factor, don't change divider -+ */ -+ if (!(val >> 3 & 0x1)) -+ val |= 1 << 16; -+ } -+ -+ regmap_write(clk_data->syscon_top, div_clksi.offset, -+ val); -+ } -+ } -+ -+ return 0; -+ -+err: -+ while (i--) -+ clk_unregister_divider(clk_data->clk_data.clksdiv_clksi.id); -+ -+ return PTR_ERR(clk); -+} -+ -+static int register_mux_clks(struct device *dev, struct mango_clk_data *clk_data) -+{ -+ struct clk *clk; -+ const struct mango_clk_table *table = clk_data->table; -+ const struct mango_mux_clock *mux_clks = table->mux_clks; -+ void __iomem *base = clk_data->base; -+ int clk_num = table->mux_clks_num; -+ int i; -+ -+ for (i = 0; i < clk_num; i++) { -+ u32 mask = BIT(mux_clksi.width) - 1; -+ -+ clk = clk_register_mux_table( -+ dev, mux_clksi.name, mux_clksi.parent_names, -+ mux_clksi.num_parents, mux_clksi.flags, -+ base + mux_clksi.offset, mux_clksi.shift, mask, -+ mux_clksi.mux_flags, mux_clksi.table, -+ &clk_data->lock); -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register clock %s\n", __func__, -+ mux_clksi.name); -+ goto err; -+ } -+ -+ clk_data->clk_data.clksmux_clksi.id = clk; -+ -+ if (!(mux_clksi.flags & CLK_MUX_READ_ONLY)) { -+ struct clk *parent; -+ struct notifier_block *clk_nb; -+ -+ /* set mux clock default parent here, it's parent index -+ * value is read from the mux clock reg. dts can override -+ * setting the mux clock parent later. -+ */ -+ parent = clk_get_parent(clk); -+ clk_set_parent(clk, parent); -+ -+ /* add a notify callback function */ -+ clk_nb = kzalloc(sizeof(*clk_nb), GFP_KERNEL); -+ if (!clk_nb) -+ goto err; -+ clk_nb->notifier_call = mux_notifier_cb; -+ if (clk_notifier_register(clk, clk_nb)) -+ pr_err("%s: failed to register clock notifier for %s\n", -+ __func__, mux_clksi.name); -+ } -+ } -+ -+ return 0; -+ -+err: -+ while (i--) -+ clk_unregister_mux(clk_data->clk_data.clksmux_clksi.id); -+ -+ return PTR_ERR(clk); -+} -+ -+/* pll clock init */ -+int mango_register_pll_clks(struct device_node *node, -+ struct mango_clk_data *clk_data, const char *clk_name) -+{ -+ struct clk *clk = NULL; -+ struct mango_pll_clock *pll_clks; -+ int i, ret = 0; -+ const struct clk_ops *local_ops; -+ -+ pll_clks = (struct mango_pll_clock *)clk_data->table->pll_clks; -+ for (i = 0; i < clk_data->table->pll_clks_num; i++) { -+ if (!strcmp(clk_name, pll_clksi.name)) { -+ /* have to assigne pll_clks.syscon_top first -+ * since clk_register_composite will need it -+ * to calculate current rate. -+ */ -+ pll_clksi.syscon_top = clk_data->syscon_top; -+ pll_clksi.lock = &clk_data->lock; -+ if (pll_clksi.ini_flags & MANGO_CLK_RO) -+ local_ops = &mango_clk_pll_ro_ops; -+ else -+ local_ops = &mango_clk_pll_ops; -+ clk = clk_register_composite( -+ NULL, pll_clksi.name, &pll_clksi.parent_name, -+ 1, NULL, NULL, &pll_clksi.hw, local_ops, -+ NULL, NULL, pll_clksi.flags); -+ -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register clock %s\n", __func__, -+ pll_clksi.name); -+ ret = -EINVAL; -+ goto out; -+ } -+ ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); -+ if (ret) -+ clk_unregister(clk); -+ } else { -+ continue; -+ } -+ } -+ -+out: -+ return ret; -+} -+ -+/* mux clk init */ -+int mango_register_mux_clks(struct device_node *node, struct mango_clk_data *clk_data) -+{ -+ int ret; -+ int count; -+ struct clk **clk_table; -+ -+ count = clk_data->table->mux_clks_num + clk_data->table->gate_clks_num; -+ clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL); -+ if (!clk_table) -+ return -ENOMEM; -+ -+ clk_data->clk_data.clks = clk_table; -+ clk_data->clk_data.clk_num = count; -+ -+ ret = register_mux_clks(NULL, clk_data); -+ if (ret) -+ goto err; -+ -+ ret = register_gate_clks(NULL, clk_data); -+ if (ret) -+ goto err; -+ -+ ret = register_provider_clks(node, clk_data, count); -+ if (ret) -+ goto err; -+ -+ return 0; -+err: -+ kfree(clk_table); -+ return ret; -+} -+ -+/* pll divider init */ -+int mango_register_div_clks(struct device_node *node, struct mango_clk_data *clk_data) -+{ -+ int ret; -+ int count; -+ -+ struct clk **clk_table; -+ -+ count = clk_data->table->div_clks_num + clk_data->table->gate_clks_num; -+ clk_table = kcalloc(count, sizeof(*clk_table), GFP_KERNEL); -+ if (!clk_table) -+ return -ENOMEM; -+ -+ clk_data->clk_data.clks = clk_table; -+ clk_data->clk_data.clk_num = count; -+ -+ ret = register_divider_clks(NULL, clk_data); -+ if (ret) -+ goto err; -+ -+ ret = register_gate_clks(NULL, clk_data); -+ if (ret) -+ goto err; -+ -+ ret = register_provider_clks(node, clk_data, count); -+ if (ret) -+ goto err; -+ -+ -+ return 0; -+err: -+ kfree(clk_table); -+ pr_err("%s error %d\n", __func__, ret); -+ return ret; -+} -diff --git a/drivers/clk/sophgo/clk.h b/drivers/clk/sophgo/clk.h -new file mode 100644 -index 000000000000..81e9f9eb1b20 ---- /dev/null -+++ b/drivers/clk/sophgo/clk.h -@@ -0,0 +1,152 @@ -+#ifndef __SOPHGO_CLOCK__ -+#define __SOPHGO_CLOCK__ -+ -+#include <linux/regmap.h> -+#include <linux/slab.h> -+#include <linux/clk.h> -+#include <linux/clk-provider.h> -+#include <linux/device.h> -+#include <linux/clkdev.h> -+ -+#include <dt-bindings/clock/sophgo.h> -+ -+#define KHZ 1000L -+#define MHZ (KHZ * KHZ) -+ -+#define MANGO_CLK_USE_INIT_VAL BIT(0) /* use default value */ -+#define MANGO_CLK_USE_REG_VAL BIT(1) /* use reg divider value */ -+#define MANGO_CLK_RO BIT(2) /* use reg divider value */ -+ -+#define CLK_PLL BIT(0) -+#define CLK_MUX BIT(1) -+ -+#define PLL_CTRL_OFFSET 0xE8 -+#define PLL_STAT_LOCK_OFFSET 0x8 -+#define CLK_MODE 0x4 -+#define CLK_MODE_MASK 0x3 -+ -+#define REFDIV_MIN 1 -+#define REFDIV_MAX 64 -+#define FBDIV_MIN 16 -+#define FBDIV_MAX 321 -+ -+#define PLL_FREQ_MIN (16 * MHZ) -+#define PLL_FREQ_MAX (3200 * MHZ) -+ -+#define div_mask(width) ((1 << (width)) - 1) -+#define TOP_PLL_CTRL(fbdiv, p1, p2, refdiv) \ -+ (((fbdiv & 0xfff) << 16) | ((p2 & 0x7) << 12) | ((p1 & 0x7) << 8) | (refdiv & 0x3f)) -+ -+struct mango_pll_ctrl { -+ unsigned int mode; -+ unsigned long freq; -+ -+ unsigned int fbdiv; -+ unsigned int postdiv1; -+ unsigned int postdiv2; -+ unsigned int refdiv; -+}; -+ -+struct mango_pll_clock { -+ unsigned int id; -+ char *name; -+ const char *parent_name; -+ unsigned long flags; -+ struct clk_hw hw; -+ struct regmap *syscon_top; -+ -+ /* Below lock used to protect PLL top register during write */ -+ spinlock_t *lock; -+ u32 ini_flags; -+ -+ u32 status_offset; -+ u32 enable_offset; -+ -+ struct mango_pll_ctrl pctrl_table4; -+}; -+ -+#define to_mango_pll_clk(_hw) container_of(_hw, struct mango_pll_clock, hw) -+ -+#define to_mango_clk_divider(_hw) \ -+ container_of(_hw, struct mango_clk_divider, hw) -+ -+#define to_mango_clk_mux(nb) \ -+ container_of(nb, struct mango_mux_clock, clk_nb) -+ -+struct mango_divider_clock { -+ unsigned int id; -+ const char *name; -+ const char *parent_name; -+ unsigned long flags; -+ unsigned long offset; -+ u8 shift; -+ u8 width; -+ u8 div_flags; -+ u32 initial_sel; -+ u32 initial_val; -+ struct clk_div_table *table; -+}; -+ -+struct mango_mux_clock { -+ unsigned int id; -+ const char *name; -+ const char *const *parent_names; -+ u8 num_parents; -+ unsigned long flags; -+ unsigned long offset; -+ u8 shift; -+ u8 width; -+ u8 mux_flags; -+ u32 *table; -+ -+ struct notifier_block clk_nb; -+}; -+ -+struct mango_gate_clock { -+ unsigned int id; -+ const char *name; -+ const char *parent_name; -+ unsigned long flags; -+ unsigned long offset; -+ u8 bit_idx; -+ u8 gate_flags; -+ const char *alias; -+}; -+ -+struct mango_clk_table { -+ u32 id; -+ u32 pll_clks_num; -+ u32 div_clks_num; -+ u32 gate_clks_num; -+ u32 mux_clks_num; -+ -+ const struct mango_pll_clock *pll_clks; -+ const struct mango_divider_clock *div_clks; -+ const struct mango_gate_clock *gate_clks; -+ const struct mango_mux_clock *mux_clks; -+}; -+ -+struct mango_clk_data { -+ void __iomem *base; -+ spinlock_t lock; -+ struct regmap *syscon_top; -+ struct clk_onecell_data clk_data; -+ const struct mango_clk_table *table; -+}; -+ -+int mango_register_mux_clks -+(struct device_node *node, struct mango_clk_data *clk_data); -+int mango_register_div_clks -+(struct device_node *node, struct mango_clk_data *clk_data); -+int mango_register_pll_clks -+(struct device_node *node, struct mango_clk_data *clk_data, const char *clk_name); -+int set_default_clk_rates(struct device_node *node); -+ -+int dm_mango_register_mux_clks -+(struct device_node *node, struct mango_clk_data *clk_data); -+int dm_mango_register_div_clks -+(struct device_node *node, struct mango_clk_data *clk_data); -+int dm_mango_register_pll_clks -+(struct device_node *node, struct mango_clk_data *clk_data, const char *name); -+int dm_set_default_clk_rates(struct device_node *node); -+#endif -diff --git a/drivers/clk/thead/Kconfig b/drivers/clk/thead/Kconfig -new file mode 100644 -index 000000000000..4fa0021a195d ---- /dev/null -+++ b/drivers/clk/thead/Kconfig -@@ -0,0 +1,19 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+config THEAD_CLK -+ bool -+ def_bool ARCH_THEAD -+ -+config CLK_LIGHT_MPW -+ bool "Thead Light MPW Clock Driver" -+ depends on ARCH_THEAD -+ default n -+ help -+ Build the driver for light mpw Clock Driver -+ -+config CLK_LIGHT_FM -+ bool "Thead Light Fullmask Clock Driver" -+ depends on ARCH_THEAD -+ default n -+ help -+ Build the driver for light fullmask Clock Driver -diff --git a/drivers/clk/thead/Makefile b/drivers/clk/thead/Makefile -new file mode 100644 -index 000000000000..24a349f91989 ---- /dev/null -+++ b/drivers/clk/thead/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+obj-$(CONFIG_THEAD_CLK) += \ -+ clk.o -+ -+obj-$(CONFIG_CLK_LIGHT_MPW) += clk-light-mpw.o -+obj-$(CONFIG_CLK_LIGHT_FM) += clk-light-fm.o -+obj-$(CONFIG_CLK_LIGHT_FM) += gate/ -diff --git a/drivers/clk/thead/clk-light-fm.c b/drivers/clk/thead/clk-light-fm.c -new file mode 100644 -index 000000000000..2fe47c063a53 ---- /dev/null -+++ b/drivers/clk/thead/clk-light-fm.c -@@ -0,0 +1,646 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <dt-bindings/clock/light-fm-ap-clock.h> -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/types.h> -+ -+#include "clk.h" -+ -+static struct clk *clksCLK_END; -+static struct clk_onecell_data clk_data; -+ -+/* Light Fullmask */ -+static u32 share_cnt_x2h_cpusys_clk_en; -+static u32 share_cnt_dmac_cpusys_clk_en; -+static u32 share_cnt_timer0_clk_en; -+static u32 share_cnt_timer1_clk_en; -+static u32 share_cnt_axi4_cpusys2_clk_en; -+static u32 share_cnt_bmu_c910_clk_en; -+static u32 share_cnt_aon2cpu_a2x_clk_en; -+static u32 share_cnt_chip_dbg_clk_en; -+static u32 share_cnt_x2x_cpusys_clk_en; -+static u32 share_cnt_cfg2tee_x2h_clk_en; -+static u32 share_cnt_cpu2aon_x2h_clk_en; -+static u32 share_cnt_cpu2vp_x2p_clk_en; -+static u32 share_cnt_npu_core_clk_en; -+static u32 share_cnt_cpu2peri_x2h_clk_en; -+static u32 share_cnt_cpu2vi_x2h_clk_en; -+static u32 share_cnt_vpsys_axi_aclk_en; -+static u32 share_cnt_gmac1_clk_en; -+static u32 share_cnt_gmac0_clk_en; -+static u32 share_cnt_perisys_apb3_hclk_en; -+static u32 share_cnt_qspi0_clk_en; -+static u32 share_cnt_gmac_axi_clk_en; -+static u32 share_cnt_gpio0_clk_en; -+static u32 share_cnt_gpio1_clk_en; -+static u32 share_cnt_pwm_clk_en; -+static u32 share_cnt_spi_clk_en; -+static u32 share_cnt_uart0_clk_en; -+static u32 share_cnt_uart2_clk_en; -+static u32 share_cnt_i2c2_clk_en; -+static u32 share_cnt_peri_i2s_clk_en; -+static u32 share_cnt_qspi1_clk_en; -+static u32 share_cnt_uart1_clk_en; -+static u32 share_cnt_uart3_clk_en; -+static u32 share_cnt_uart4_clk_en; -+static u32 share_cnt_uart5_clk_en; -+static u32 share_cnt_i2c0_clk_en; -+static u32 share_cnt_i2c1_clk_en; -+static u32 share_cnt_i2c4_clk_en; -+static u32 share_cnt_i2c5_clk_en; -+static u32 share_cnt_gpio2_clk_en; -+static u32 share_cnt_gpio3_clk_en; -+static u32 share_cnt_vosys_axi_aclk_en; -+ -+/* Light Fullmask PLL Bypass */ -+static const char * const cpu_pll0_bypass_sels = {"cpu_pll0_foutpostdiv", "osc_24m", }; -+static const char * const cpu_pll1_bypass_sels = {"cpu_pll1_foutpostdiv", "osc_24m", }; -+static const char * const gmac_pll_bypass_sels = {"gmac_pll_foutpostdiv", "osc_24m", }; -+static const char * const video_pll_bypass_sels = {"video_pll_foutpostdiv", "osc_24m", }; -+static const char * const tee_pll_bypass_sels = {"tee_pll_foutpostdiv", "osc_24m"}; -+static const char * const dpu0_pll_bypass_sels = {"dpu0_pll_foutpostdiv", "osc_24m"}; -+static const char * const dpu1_pll_bypass_sels = {"dpu1_pll_foutpostdiv", "osc_24m"}; -+ -+/* light fullmask mux */ -+static const char * const ahb2_cpusys_hclk_sels = {"ahb2_cpusys_hclk_out_div", "osc_24m"}; -+static const char * const c910_cclk_i0_sels = {"cpu_pll0_foutpostdiv", "osc_24m"}; -+static const char * const c910_cclk_sels = {"c910_cclk_i0", "cpu_pll1_foutpostdiv"}; -+static const char * const cfg_axi_aclk_sels = {"cfg_axi_aclk_out_div", "osc_24m"}; -+static const char * const teesys_hclk_sels = {"teesys_i1_hclk", "teesys_i0_hclk"}; -+static const char * const perisys_ahb_hclk_sels = {"perisys_ahb_hclk_out_div", "osc_24m"}; -+static const char * const clk_out_1_sels = {"osc_24m", "clk_out_1_out_div"}; -+static const char * const clk_out_2_sels = {"osc_24m", "clk_out_2_out_div"}; -+static const char * const clk_out_3_sels = {"osc_24m", "clk_out_3_out_div"}; -+static const char * const clk_out_4_sels = {"osc_24m", "clk_out_4_out_div"}; -+static const char * const peri_i2s_src_clk_sels = {"clkgen_peri_i2s_src_clk_0", "clkgen_peri_i2s_src_clk_1"}; -+static const char * const npu_cclk_sels = {"gmac_pll_foutpostdiv", "npu_cclk_out_div"}; -+static const char * const cfg_apb_pclk_sels = {"cfg_apb_pclk_out_div", "osc_24m"}; -+static const char * const uart_sclk_sels = {"clk_100m", "osc_24m"}; -+ -+static const struct light_pll_rate_table light_cpupll_tbl = { -+ LIGHT_PLL_RATE(2616000000U, 2616000000U, 1, 109, 0, 1, 1), -+ LIGHT_PLL_RATE(2592000000U, 2592000000U, 1, 108, 0, 1, 1), -+ LIGHT_PLL_RATE(2568000000U, 2568000000U, 1, 107, 0, 1, 1), -+ LIGHT_PLL_RATE(2544000000U, 2544000000U, 1, 106, 0, 1, 1), -+ LIGHT_PLL_RATE(2520000000U, 2520000000U, 1, 105, 0, 1, 1), -+ LIGHT_PLL_RATE(2496000000U, 2496000000U, 1, 104, 0, 1, 1), -+ LIGHT_PLL_RATE(2472000000U, 2472000000U, 1, 103, 0, 1, 1), -+ LIGHT_PLL_RATE(2448000000U, 2448000000U, 1, 102, 0, 1, 1), -+ LIGHT_PLL_RATE(2424000000U, 2424000000U, 1, 101, 0, 1, 1), -+ LIGHT_PLL_RATE(2400000000U, 2400000000U, 1, 100, 0, 1, 1), -+ LIGHT_PLL_RATE(2376000000U, 2376000000U, 1, 99, 0, 1, 1), -+ LIGHT_PLL_RATE(2352000000U, 2352000000U, 1, 98, 0, 1, 1), -+ LIGHT_PLL_RATE(2328000000U, 2328000000U, 1, 97, 0, 1, 1), -+ LIGHT_PLL_RATE(2304000000U, 2304000000U, 1, 96, 0, 1, 1), -+ LIGHT_PLL_RATE(2280000000U, 2280000000U, 1, 95, 0, 1, 1), -+ LIGHT_PLL_RATE(2256000000U, 2256000000U, 1, 94, 0, 1, 1), -+ LIGHT_PLL_RATE(2232000000U, 2232000000U, 1, 93, 0, 1, 1), -+ LIGHT_PLL_RATE(2208000000U, 2208000000U, 1, 92, 0, 1, 1), -+ LIGHT_PLL_RATE(2184000000U, 2184000000U, 1, 91, 0, 1, 1), -+ LIGHT_PLL_RATE(2160000000U, 2160000000U, 1, 90, 0, 1, 1), -+ LIGHT_PLL_RATE(2136000000U, 2136000000U, 1, 89, 0, 1, 1), -+ LIGHT_PLL_RATE(2112000000U, 2112000000U, 1, 88, 0, 1, 1), -+ LIGHT_PLL_RATE(2088000000U, 2088000000U, 1, 87, 0, 1, 1), -+ LIGHT_PLL_RATE(2064000000U, 2064000000U, 1, 86, 0, 1, 1), -+ LIGHT_PLL_RATE(2040000000U, 2040000000U, 1, 85, 0, 1, 1), -+ LIGHT_PLL_RATE(2016000000U, 2016000000U, 1, 84, 0, 1, 1), -+ LIGHT_PLL_RATE(1992000000U, 1992000000U, 1, 83, 0, 1, 1), -+ LIGHT_PLL_RATE(1968000000U, 1968000000U, 1, 82, 0, 1, 1), -+ LIGHT_PLL_RATE(1944000000U, 1944000000U, 1, 81, 0, 1, 1), -+ LIGHT_PLL_RATE(1920000000U, 1920000000U, 1, 80, 0, 1, 1), -+ LIGHT_PLL_RATE(1896000000U, 1896000000U, 1, 79, 0, 1, 1), -+ LIGHT_PLL_RATE(1872000000U, 1872000000U, 1, 78, 0, 1, 1), -+ LIGHT_PLL_RATE(1848000000U, 1848000000U, 1, 77, 0, 1, 1), -+ LIGHT_PLL_RATE(1824000000U, 1824000000U, 1, 76, 0, 1, 1), -+ LIGHT_PLL_RATE(1800000000U, 1800000000U, 1, 75, 0, 1, 1), -+ LIGHT_PLL_RATE(1776000000U, 1776000000U, 1, 74, 0, 1, 1), -+ LIGHT_PLL_RATE(1752000000U, 1752000000U, 1, 73, 0, 1, 1), -+ LIGHT_PLL_RATE(1728000000U, 1728000000U, 1, 72, 0, 1, 1), -+ LIGHT_PLL_RATE(1704000000U, 1704000000U, 1, 71, 0, 1, 1), -+ LIGHT_PLL_RATE(1680000000U, 1680000000U, 1, 70, 0, 1, 1), -+ LIGHT_PLL_RATE(1656000000U, 1656000000U, 1, 69, 0, 1, 1), -+ LIGHT_PLL_RATE(1632000000U, 1632000000U, 1, 68, 0, 1, 1), -+ LIGHT_PLL_RATE(1608000000U, 1608000000U, 1, 67, 0, 1, 1), -+ LIGHT_PLL_RATE(1584000000U, 1584000000U, 1, 66, 0, 1, 1), -+ LIGHT_PLL_RATE(1560000000U, 1560000000U, 1, 65, 0, 1, 1), -+ LIGHT_PLL_RATE(1536000000U, 1536000000U, 1, 64, 0, 1, 1), -+ LIGHT_PLL_RATE(1512000000U, 1512000000U, 1, 63, 0, 1, 1), -+ LIGHT_PLL_RATE(3000000000U, 1500000000U, 1, 125, 0, 2, 1), -+ LIGHT_PLL_RATE(2976000000U, 1488000000U, 1, 124, 0, 2, 1), -+ LIGHT_PLL_RATE(2952000000U, 1476000000U, 1, 123, 0, 2, 1), -+ LIGHT_PLL_RATE(2928000000U, 1464000000U, 1, 122, 0, 2, 1), -+ LIGHT_PLL_RATE(2904000000U, 1452000000U, 1, 121, 0, 2, 1), -+ LIGHT_PLL_RATE(2880000000U, 1440000000U, 1, 120, 0, 2, 1), -+ LIGHT_PLL_RATE(2856000000U, 1428000000U, 1, 119, 0, 2, 1), -+ LIGHT_PLL_RATE(2832000000U, 1416000000U, 1, 118, 0, 2, 1), -+ LIGHT_PLL_RATE(2808000000U, 1404000000U, 1, 117, 0, 2, 1), -+ LIGHT_PLL_RATE(2784000000U, 1392000000U, 1, 116, 0, 2, 1), -+ LIGHT_PLL_RATE(2760000000U, 1380000000U, 1, 115, 0, 2, 1), -+ LIGHT_PLL_RATE(2736000000U, 1368000000U, 1, 114, 0, 2, 1), -+ LIGHT_PLL_RATE(2712000000U, 1356000000U, 1, 113, 0, 2, 1), -+ LIGHT_PLL_RATE(2688000000U, 1344000000U, 1, 112, 0, 2, 1), -+ LIGHT_PLL_RATE(2664000000U, 1332000000U, 1, 111, 0, 2, 1), -+ LIGHT_PLL_RATE(2640000000U, 1320000000U, 1, 110, 0, 2, 1), -+ LIGHT_PLL_RATE(2616000000U, 1308000000U, 1, 109, 0, 2, 1), -+ LIGHT_PLL_RATE(2592000000U, 1296000000U, 1, 108, 0, 2, 1), -+ LIGHT_PLL_RATE(2568000000U, 1284000000U, 1, 107, 0, 2, 1), -+ LIGHT_PLL_RATE(2544000000U, 1272000000U, 1, 106, 0, 2, 1), -+ LIGHT_PLL_RATE(2520000000U, 1260000000U, 1, 105, 0, 2, 1), -+ LIGHT_PLL_RATE(2496000000U, 1248000000U, 1, 104, 0, 2, 1), -+ LIGHT_PLL_RATE(2472000000U, 1236000000U, 1, 103, 0, 2, 1), -+ LIGHT_PLL_RATE(2448000000U, 1224000000U, 1, 102, 0, 2, 1), -+ LIGHT_PLL_RATE(2424000000U, 1212000000U, 1, 101, 0, 2, 1), -+ LIGHT_PLL_RATE(2400000000U, 1200000000U, 1, 100, 0, 2, 1), -+ LIGHT_PLL_RATE(2376000000U, 1188000000U, 1, 99, 0, 2, 1), -+ LIGHT_PLL_RATE(2352000000U, 1176000000U, 1, 98, 0, 2, 1), -+ LIGHT_PLL_RATE(2328000000U, 1164000000U, 1, 97, 0, 2, 1), -+ LIGHT_PLL_RATE(2304000000U, 1152000000U, 1, 96, 0, 2, 1), -+ LIGHT_PLL_RATE(2280000000U, 1140000000U, 1, 95, 0, 2, 1), -+ LIGHT_PLL_RATE(2256000000U, 1128000000U, 1, 94, 0, 2, 1), -+ LIGHT_PLL_RATE(2232000000U, 1116000000U, 1, 93, 0, 2, 1), -+ LIGHT_PLL_RATE(2208000000U, 1104000000U, 1, 92, 0, 2, 1), -+ LIGHT_PLL_RATE(2184000000U, 1092000000U, 1, 91, 0, 2, 1), -+ LIGHT_PLL_RATE(2160000000U, 1080000000U, 1, 90, 0, 2, 1), -+ LIGHT_PLL_RATE(2136000000U, 1068000000U, 1, 89, 0, 2, 1), -+ LIGHT_PLL_RATE(2112000000U, 1056000000U, 1, 88, 0, 2, 1), -+ LIGHT_PLL_RATE(2088000000U, 1044000000U, 1, 87, 0, 2, 1), -+ LIGHT_PLL_RATE(2064000000U, 1032000000U, 1, 86, 0, 2, 1), -+ LIGHT_PLL_RATE(2040000000U, 1020000000U, 1, 85, 0, 2, 1), -+ LIGHT_PLL_RATE(2016000000U, 1008000000U, 1, 84, 0, 2, 1), -+ LIGHT_PLL_RATE(3000000000U, 1000000000U, 1, 125, 0, 3, 1), -+ LIGHT_PLL_RATE(2976000000U, 992000000U, 1, 124, 0, 3, 1), -+ LIGHT_PLL_RATE(2952000000U, 984000000U, 1, 123, 0, 3, 1), -+ LIGHT_PLL_RATE(2928000000U, 976000000U, 1, 122, 0, 3, 1), -+ LIGHT_PLL_RATE(2904000000U, 968000000U, 1, 121, 0, 3, 1), -+ LIGHT_PLL_RATE(2880000000U, 960000000U, 1, 120, 0, 3, 1), -+ LIGHT_PLL_RATE(2856000000U, 952000000U, 1, 119, 0, 3, 1), -+ LIGHT_PLL_RATE(2832000000U, 944000000U, 1, 118, 0, 3, 1), -+ LIGHT_PLL_RATE(2808000000U, 936000000U, 1, 117, 0, 3, 1), -+ LIGHT_PLL_RATE(2784000000U, 928000000U, 1, 116, 0, 3, 1), -+ LIGHT_PLL_RATE(2760000000U, 920000000U, 1, 115, 0, 3, 1), -+ LIGHT_PLL_RATE(2736000000U, 912000000U, 1, 114, 0, 3, 1), -+ LIGHT_PLL_RATE(2712000000U, 904000000U, 1, 113, 0, 3, 1), -+ LIGHT_PLL_RATE(1800000000U, 900000000U, 1, 75, 0, 2, 1), -+ LIGHT_PLL_RATE(2688000000U, 896000000U, 1, 112, 0, 3, 1), -+ LIGHT_PLL_RATE(2664000000U, 888000000U, 1, 111, 0, 3, 1), -+ LIGHT_PLL_RATE(2640000000U, 880000000U, 1, 110, 0, 3, 1), -+ LIGHT_PLL_RATE(2616000000U, 872000000U, 1, 109, 0, 3, 1), -+ LIGHT_PLL_RATE(2592000000U, 864000000U, 1, 108, 0, 3, 1), -+ LIGHT_PLL_RATE(2568000000U, 856000000U, 1, 107, 0, 3, 1), -+ LIGHT_PLL_RATE(2544000000U, 848000000U, 1, 106, 0, 3, 1), -+ LIGHT_PLL_RATE(2520000000U, 840000000U, 1, 105, 0, 3, 1), -+ LIGHT_PLL_RATE(2496000000U, 832000000U, 1, 104, 0, 3, 1), -+ LIGHT_PLL_RATE(2472000000U, 824000000U, 1, 103, 0, 3, 1), -+ LIGHT_PLL_RATE(2448000000U, 816000000U, 1, 102, 0, 3, 1), -+ LIGHT_PLL_RATE(2424000000U, 808000000U, 1, 101, 0, 3, 1), -+ LIGHT_PLL_RATE(2400000000U, 800000000U, 1, 100, 0, 3, 1), -+ LIGHT_PLL_RATE(2376000000U, 792000000U, 1, 99, 0, 3, 1), -+ LIGHT_PLL_RATE(2352000000U, 784000000U, 1, 98, 0, 3, 1), -+ LIGHT_PLL_RATE(2328000000U, 776000000U, 1, 97, 0, 3, 1), -+ LIGHT_PLL_RATE(2304000000U, 768000000U, 1, 96, 0, 3, 1), -+ LIGHT_PLL_RATE(2280000000U, 760000000U, 1, 95, 0, 3, 1), -+ LIGHT_PLL_RATE(2256000000U, 752000000U, 1, 94, 0, 3, 1), -+ LIGHT_PLL_RATE(2232000000U, 744000000U, 1, 93, 0, 3, 1), -+ LIGHT_PLL_RATE(2208000000U, 736000000U, 1, 92, 0, 3, 1), -+ LIGHT_PLL_RATE(2184000000U, 728000000U, 1, 91, 0, 3, 1), -+ LIGHT_PLL_RATE(2160000000U, 720000000U, 1, 90, 0, 3, 1), -+ LIGHT_PLL_RATE(2136000000U, 712000000U, 1, 89, 0, 3, 1), -+ LIGHT_PLL_RATE(2808000000U, 702000000U, 1, 117, 0, 4, 1), -+ LIGHT_PLL_RATE(2760000000U, 690000000U, 1, 115, 0, 4, 1), -+ LIGHT_PLL_RATE(2712000000U, 678000000U, 1, 113, 0, 4, 1), -+ LIGHT_PLL_RATE(2664000000U, 666000000U, 1, 111, 0, 4, 1), -+ LIGHT_PLL_RATE(2616000000U, 654000000U, 1, 109, 0, 4, 1), -+ LIGHT_PLL_RATE(2568000000U, 642000000U, 1, 107, 0, 4, 1), -+ LIGHT_PLL_RATE(2520000000U, 630000000U, 1, 105, 0, 4, 1), -+ LIGHT_PLL_RATE(2472000000U, 618000000U, 1, 103, 0, 4, 1), -+ LIGHT_PLL_RATE(2424000000U, 606000000U, 1, 101, 0, 4, 1), -+ LIGHT_PLL_RATE(3000000000U, 600000000U, 1, 125, 0, 5, 1), -+ LIGHT_PLL_RATE(2952000000U, 590400000U, 1, 123, 0, 5, 1), -+ LIGHT_PLL_RATE(2904000000U, 580800000U, 1, 121, 0, 5, 1), -+ LIGHT_PLL_RATE(2856000000U, 571200000U, 1, 119, 0, 5, 1), -+ LIGHT_PLL_RATE(2808000000U, 561600000U, 1, 117, 0, 5, 1), -+ LIGHT_PLL_RATE(2760000000U, 552000000U, 1, 115, 0, 5, 1), -+ LIGHT_PLL_RATE(2712000000U, 542400000U, 1, 113, 0, 5, 1), -+ LIGHT_PLL_RATE(2664000000U, 532800000U, 1, 111, 0, 5, 1), -+ LIGHT_PLL_RATE(2616000000U, 523200000U, 1, 109, 0, 5, 1), -+ LIGHT_PLL_RATE(2568000000U, 513600000U, 1, 107, 0, 5, 1), -+ LIGHT_PLL_RATE(2520000000U, 504000000U, 1, 105, 0, 5, 1), -+ LIGHT_PLL_RATE(3000000000U, 500000000U, 1, 125, 0, 6, 1), -+ LIGHT_PLL_RATE(2952000000U, 492000000U, 1, 123, 0, 6, 1), -+ LIGHT_PLL_RATE(2904000000U, 484000000U, 1, 121, 0, 6, 1), -+ LIGHT_PLL_RATE(2856000000U, 476000000U, 1, 119, 0, 6, 1), -+ LIGHT_PLL_RATE(2808000000U, 468000000U, 1, 117, 0, 6, 1), -+ LIGHT_PLL_RATE(2760000000U, 460000000U, 1, 115, 0, 6, 1), -+ LIGHT_PLL_RATE(2712000000U, 452000000U, 1, 113, 0, 6, 1), -+ LIGHT_PLL_RATE(2664000000U, 444000000U, 1, 111, 0, 6, 1), -+ LIGHT_PLL_RATE(2616000000U, 436000000U, 1, 109, 0, 6, 1), -+ LIGHT_PLL_RATE(2568000000U, 428000000U, 1, 107, 0, 6, 1), -+ LIGHT_PLL_RATE(2520000000U, 420000000U, 1, 105, 0, 6, 1), -+ LIGHT_PLL_RATE(2472000000U, 412000000U, 1, 103, 0, 6, 1), -+ LIGHT_PLL_RATE(2400000000U, 400000000U, 1, 100, 0, 3, 2), -+ LIGHT_PLL_RATE(2352000000U, 392000000U, 1, 98, 0, 3, 2), -+ LIGHT_PLL_RATE(2304000000U, 384000000U, 1, 96, 0, 3, 2), -+ LIGHT_PLL_RATE(2256000000U, 376000000U, 1, 94, 0, 3, 2), -+ LIGHT_PLL_RATE(2208000000U, 368000000U, 1, 92, 0, 3, 2), -+ LIGHT_PLL_RATE(2160000000U, 360000000U, 1, 90, 0, 3, 2), -+ LIGHT_PLL_RATE(2112000000U, 352000000U, 1, 88, 0, 3, 2), -+ LIGHT_PLL_RATE(2064000000U, 344000000U, 1, 86, 0, 3, 2), -+ LIGHT_PLL_RATE(2016000000U, 336000000U, 1, 84, 0, 3, 2), -+ LIGHT_PLL_RATE(1968000000U, 328000000U, 1, 82, 0, 3, 2), -+ LIGHT_PLL_RATE(1920000000U, 320000000U, 1, 80, 0, 3, 2), -+ LIGHT_PLL_RATE(1872000000U, 312000000U, 1, 78, 0, 3, 2), -+ LIGHT_PLL_RATE(1824000000U, 304000000U, 1, 76, 0, 3, 2), -+ LIGHT_PLL_RATE(3000000000U, 300000000U, 1, 125, 0, 5, 2), -+ LIGHT_PLL_RATE(2880000000U, 288000000U, 1, 120, 0, 5, 2), -+ LIGHT_PLL_RATE(2760000000U, 276000000U, 1, 115, 0, 5, 2), -+ LIGHT_PLL_RATE(2640000000U, 264000000U, 1, 110, 0, 5, 2), -+ LIGHT_PLL_RATE(2520000000U, 252000000U, 1, 105, 0, 5, 2), -+ LIGHT_PLL_RATE(2400000000U, 240000000U, 1, 100, 0, 5, 2), -+ LIGHT_PLL_RATE(2280000000U, 228000000U, 1, 95, 0, 5, 2), -+ LIGHT_PLL_RATE(2160000000U, 216000000U, 1, 90, 0, 5, 2), -+ LIGHT_PLL_RATE(2040000000U, 204000000U, 1, 85, 0, 5, 2), -+ LIGHT_PLL_RATE(3000000000U, 200000000U, 1, 125, 0, 5, 3), -+ LIGHT_PLL_RATE(2880000000U, 192000000U, 1, 120, 0, 5, 3), -+ LIGHT_PLL_RATE(2760000000U, 184000000U, 1, 115, 0, 5, 3), -+ LIGHT_PLL_RATE(2640000000U, 176000000U, 1, 110, 0, 5, 3), -+ LIGHT_PLL_RATE(2520000000U, 168000000U, 1, 105, 0, 5, 3), -+ LIGHT_PLL_RATE(2400000000U, 160000000U, 1, 100, 0, 5, 3), -+ LIGHT_PLL_RATE(2280000000U, 152000000U, 1, 95, 0, 5, 3), -+ LIGHT_PLL_RATE(2160000000U, 144000000U, 1, 90, 0, 5, 3), -+ LIGHT_PLL_RATE(2040000000U, 136000000U, 1, 85, 0, 5, 3), -+ LIGHT_PLL_RATE(1920000000U, 128000000U, 1, 80, 0, 5, 3), -+ LIGHT_PLL_RATE(3000000000U, 125000000U, 1, 125, 0, 6, 4), -+ LIGHT_PLL_RATE(2760000000U, 115000000U, 1, 115, 0, 6, 4), -+ LIGHT_PLL_RATE(2520000000U, 105000000U, 1, 105, 0, 6, 4), -+ LIGHT_PLL_RATE(2280000000U, 95000000U, 1, 95, 0, 6, 4), -+ LIGHT_PLL_RATE(2040000000U, 85000000U, 1, 85, 0, 6, 4), -+ LIGHT_PLL_RATE(1800000000U, 75000000U, 1, 75, 0, 6, 4), -+ LIGHT_PLL_RATE(1560000000U, 65000000U, 1, 65, 0, 6, 4), -+ LIGHT_PLL_RATE(1320000000U, 55000000U, 1, 55, 0, 6, 4), -+}; -+ -+static const struct light_pll_rate_table light_dpupll_tbl = { -+ LIGHT_PLL_RATE(2376000000U, 1188000000U, 1, 99, 0, 2, 1), -+ LIGHT_PLL_RATE(1980000000U, 990000000U, 2, 165, 0, 2, 1), -+ LIGHT_PLL_RATE(2970000000U, 742500000U, 4, 495, 0, 4, 1), -+ LIGHT_PLL_RATE(2304000000U, 1152000000U, 1, 96, 0, 2, 1), -+ LIGHT_PLL_RATE(1512000000U, 504000000U, 1, 63, 0, 3, 1), -+ LIGHT_PLL_RATE(1512000000U, 503500000U, 1, 63, 0, 3, 1), -+ LIGHT_PLL_RATE(2898000000U, 483000000U, 4, 483, 0, 6, 1), -+ LIGHT_PLL_RATE(2592000000U, 648000000U, 1, 108, 0, 4, 1), -+ LIGHT_PLL_RATE(2772000000U, 924000000U, 2, 231, 0, 3, 1), -+ LIGHT_PLL_RATE(2856000000U, 476000000U, 1, 119, 0, 6, 1), -+ LIGHT_PLL_RATE(2130000000U, 355000000U, 4, 355, 0, 6, 1), -+ LIGHT_PLL_RATE(3192000000U, 456000000U, 1, 133, 0, 7, 1), -+ LIGHT_PLL_RATE(2730000000U, 390000000U, 4, 455, 0, 7, 1), -+ LIGHT_PLL_RATE(1680000000U, 240000000U, 1, 70, 0, 7, 1), -+ LIGHT_PLL_RATE(2832000000U, 708000000U, 1, 118, 0, 4, 1), -+ LIGHT_PLL_RATE(1026000000U, 342000000U, 4, 171, 0, 3, 1), -+ LIGHT_PLL_RATE(1260000000U, 630000000U, 4, 210, 0, 2, 1), -+}; -+ -+static struct light_pll_clk light_cpu_pll0div = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_CPU_PLL0, -+ .rate_table = light_cpupll_tbl, -+ .rate_count = ARRAY_SIZE(light_cpupll_tbl), -+}; -+ -+static struct light_pll_clk light_cpu_pll1div = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_CPU_PLL1, -+ .rate_table = light_cpupll_tbl, -+ .rate_count = ARRAY_SIZE(light_cpupll_tbl), -+}; -+ -+static struct light_pll_clk light_dpu0_plldiv = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_DPU0_PLL, -+ .rate_table = light_dpupll_tbl, -+ .rate_count = ARRAY_SIZE(light_dpupll_tbl), -+}; -+ -+static struct light_pll_clk light_dpu1_plldiv = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_DPU1_PLL, -+ .rate_table = light_dpupll_tbl, -+ .rate_count = ARRAY_SIZE(light_dpupll_tbl), -+}; -+ -+static int light_clocks_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ void __iomem *ap_base; -+ int ret; -+ const bool *teesys = of_device_get_match_data(dev); -+ -+ /* Clock source */ -+ clksCLK_DUMMY = thead_clk_fixed("dummy", 0); -+ clksOSC_32K = of_clk_get_by_name(np, "osc_32k"); -+ clksOSC_24M = of_clk_get_by_name(np, "osc_24m"); -+ clksRC_24M = of_clk_get_by_name(np, "rc_24m"); -+ -+ np = dev->of_node; -+ ap_base = devm_platform_ioremap_resource(pdev, 0); -+ if (WARN_ON(IS_ERR(ap_base))) { -+ ret = PTR_ERR(ap_base); -+ goto unregister_clks; -+ } -+ -+ /* Light Fullmask AP PLL clocks */ -+ clksCPU_PLL0_FOUTPOSTDIV = thead_light_pll("cpu_pll0_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll0div); -+ clksCPU_PLL1_FOUTPOSTDIV = thead_light_pll("cpu_pll1_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll1div); -+ -+ clksDPU0_PLL_FOUTPOSTDIV = thead_light_pll("dpu0_pll_foutpostdiv", "osc_24m", ap_base, &light_dpu0_plldiv); -+ clksDPU1_PLL_FOUTPOSTDIV = thead_light_pll("dpu1_pll_foutpostdiv", "osc_24m", ap_base, &light_dpu1_plldiv); -+ -+ /* Light Fullmask AP Fixed PLL */ -+ clksGMAC_PLL_FOUTPOSTDIV = thead_clk_fixed("gmac_pll_foutpostdiv", 1000000000); -+ clksVIDEO_PLL_FOUTPOSTDIV = thead_clk_fixed("video_pll_foutpostdiv", 792000000); -+ clksVIDEO_PLL_FOUTVCO = thead_clk_fixed("video_pll_foutvco", 2376000000); -+ clksTEE_PLL_FOUTPOSTDIV = thead_clk_fixed("tee_pll_foutpostdiv", 792000000); -+ clksCLKGEN_PERI_I2S_SRC_CLK_0 = thead_clk_fixed("clkgen_peri_i2s_src_clk_0", 294912000); //from audio_pll_foutpostdiv -+ clksCLKGEN_PERI_I2S_SRC_CLK_1 = thead_clk_fixed("clkgen_peri_i2s_src_clk_1", 135475200); //from sys_pll_foutpostdiv -+ clksCLKGEN_C910_BUS_CLK_NO_ICG = thead_clk_fixed("clkgen_c910_bus_clk_no_icg", 750000000); -+ clksAONSYS_BUS_CLK = thead_clk_fixed("aonsys_hclk", 101606400); //from sys_pll, maybe change ? -+ -+ /* Light Fullmask AP MUX */ -+ clksCPU_PLL0_BYPASS = thead_light_clk_mux_flags("cpu_pll0_bypass", ap_base + 0x4, 30, 1, cpu_pll0_bypass_sels, ARRAY_SIZE(cpu_pll0_bypass_sels), CLK_SET_RATE_PARENT); -+ clksCPU_PLL1_BYPASS = thead_light_clk_mux_flags("cpu_pll1_bypass", ap_base + 0x14, 30, 1, cpu_pll1_bypass_sels, ARRAY_SIZE(cpu_pll1_bypass_sels), CLK_SET_RATE_PARENT); -+ clksGMAC_PLL_BYPASS = thead_light_clk_mux_flags("gmac_pll_bypass", ap_base + 0x24, 30, 1, gmac_pll_bypass_sels, ARRAY_SIZE(gmac_pll_bypass_sels), CLK_SET_RATE_PARENT); -+ clksVIDEO_PLL_BYPASS = thead_light_clk_mux_flags("video_pll_bypass", ap_base + 0x34, 30, 1, video_pll_bypass_sels, ARRAY_SIZE(video_pll_bypass_sels), CLK_SET_RATE_PARENT); -+ clksTEE_PLL_BYPASS = thead_light_clk_mux_flags("tee_pll_bypass", ap_base + 0x64, 30, 1, tee_pll_bypass_sels, ARRAY_SIZE(tee_pll_bypass_sels), CLK_SET_RATE_PARENT); -+ clksDPU0_PLL_BYPASS = thead_light_clk_mux_flags("dpu0_pll_bypass", ap_base + 0x44, 30, 1, dpu0_pll_bypass_sels, ARRAY_SIZE(dpu0_pll_bypass_sels), CLK_SET_RATE_PARENT); -+ clksDPU1_PLL_BYPASS = thead_light_clk_mux_flags("dpu1_pll_bypass", ap_base + 0x54, 30, 1, dpu1_pll_bypass_sels, ARRAY_SIZE(dpu1_pll_bypass_sels), CLK_SET_RATE_PARENT); -+ -+ clksAHB2_CPUSYS_HCLK = thead_light_clk_mux_flags("ahb2_cpusys_hclk", ap_base + 0x120, 5, 1, ahb2_cpusys_hclk_sels, ARRAY_SIZE(ahb2_cpusys_hclk_sels), CLK_SET_RATE_PARENT); -+ clksC910_CCLK_I0 = thead_light_clk_mux_flags("c910_cclk_i0", ap_base + 0x100, 1, 1, c910_cclk_i0_sels, ARRAY_SIZE(c910_cclk_i0_sels), CLK_SET_RATE_PARENT); -+ clksC910_CCLK = thead_light_clk_mux_flags("c910_cclk", ap_base + 0x100, 0, 1, c910_cclk_sels, ARRAY_SIZE(c910_cclk_sels), CLK_SET_RATE_PARENT); -+ clksCFG_AXI_ACLK = thead_light_clk_mux_flags("cfg_axi_aclk", ap_base + 0x138, 5, 1, cfg_axi_aclk_sels, ARRAY_SIZE(cfg_axi_aclk_sels), CLK_SET_RATE_PARENT); -+ -+ if (teesys) -+ clksTEESYS_HCLK = thead_light_clk_mux_flags("teesys_hclk", ap_base + 0x1cc, 13, 1, teesys_hclk_sels, ARRAY_SIZE(teesys_hclk_sels), CLK_SET_RATE_PARENT); //just for teesys!!! -+ -+ clksPERISYS_AHB_HCLK = thead_light_clk_mux_flags("perisys_ahb_hclk", ap_base + 0x140, 5, 1, perisys_ahb_hclk_sels, ARRAY_SIZE(perisys_ahb_hclk_sels), CLK_SET_RATE_PARENT); -+ clksCLK_OUT_1 = thead_light_clk_mux_flags("clk_out_1", ap_base + 0x1b4, 4, 1, clk_out_1_sels, ARRAY_SIZE(clk_out_1_sels), CLK_SET_RATE_PARENT); -+ clksCLK_OUT_2 = thead_light_clk_mux_flags("clk_out_2", ap_base + 0x1b8, 4, 1, clk_out_2_sels, ARRAY_SIZE(clk_out_2_sels), CLK_SET_RATE_PARENT); -+ clksCLK_OUT_3 = thead_light_clk_mux_flags("clk_out_3", ap_base + 0x1bc, 4, 1, clk_out_3_sels, ARRAY_SIZE(clk_out_3_sels), CLK_SET_RATE_PARENT); -+ clksCLK_OUT_4 = thead_light_clk_mux_flags("clk_out_4", ap_base + 0x1c0, 4, 1, clk_out_4_sels, ARRAY_SIZE(clk_out_4_sels), CLK_SET_RATE_PARENT); -+ clksPERI_I2S_SRC_CLK = thead_light_clk_mux_flags("peri_i2s_src_clk", ap_base + 0x1f0, 0, 1, peri_i2s_src_clk_sels, ARRAY_SIZE(peri_i2s_src_clk_sels), CLK_SET_RATE_PARENT); -+ clksNPU_CCLK = thead_light_clk_mux_flags("npu_cclk", ap_base + 0x1c8, 6, 1, npu_cclk_sels, ARRAY_SIZE(npu_cclk_sels), CLK_SET_RATE_PARENT); -+ clksCFG_APB_PCLK = thead_light_clk_mux_flags("cfg_apb_pclk", ap_base + 0x1c4, 7, 1, cfg_apb_pclk_sels, ARRAY_SIZE(cfg_apb_pclk_sels), CLK_SET_RATE_PARENT); -+ clksUART_SCLK = thead_light_clk_mux_flags("uart_sclk", ap_base + 0x210, 0, 1, uart_sclk_sels, ARRAY_SIZE(uart_sclk_sels), CLK_SET_RATE_PARENT); -+ -+ /* Light Fullmask AP Divider */ -+ clksAHB2_CPUSYS_HCLK_OUT_DIV = thead_clk_light_divider("ahb2_cpusys_hclk_out_div", "gmac_pll_fout1ph0", ap_base + 0x120, 0, 3, 4, MUX_TYPE_DIV, 2, 7); -+ clksAPB3_CPUSYS_PCLK = thead_clk_light_divider("apb3_cpusys_pclk", "ahb2_cpusys_hclk", ap_base + 0x130, 0, 3, 3, MUX_TYPE_CDE, 1, 7); -+ clksAXI4_CPUSYS2_ACLK = thead_clk_light_divider("axi4_cpusys2_aclk", "gmac_pll_foutpostdiv", ap_base + 0x134, 0, 3, 4, MUX_TYPE_DIV, 2, 7); -+ clksCFG_AXI_ACLK_OUT_DIV = thead_clk_light_divider("cfg_axi_aclk_out_div", "video_pll_foutpostdiv", ap_base + 0x138, 0, 4, 4, MUX_TYPE_DIV, 2, 15); -+ -+ if (teesys) { -+ clksTEESYS_I0_HCLK = thead_clk_light_divider("teesys_i0_hclk", "tee_pll_foutpostdiv", ap_base + 0x1cc, 0, 4, 4, MUX_TYPE_DIV, 2, 15); //just for teesys!!! -+ clksTEESYS_I1_HCLK = thead_clk_light_divider("teesys_i1_hclk", "video_pll_foutpostdiv", ap_base + 0x1cc, 8, 4, 12, MUX_TYPE_DIV, 2, 15); //just for teesys!!! -+ } -+ -+ clksPERISYS_AHB_HCLK_OUT_DIV = thead_clk_light_divider("perisys_ahb_hclk_out_div", "gmac_pll_fout1ph0", ap_base + 0x140, 0, 4, 4, MUX_TYPE_DIV, 2, 7); -+ clksPERISYS_APB_PCLK = thead_clk_light_divider("perisys_apb_pclk", "perisys_ahb_hclk", ap_base + 0x150, 0, 3, 3, MUX_TYPE_CDE, 3, 7); -+ clksPERI2SYS_APB_PCLK = thead_clk_light_divider("peri2sys_apb_pclk", "gmac_pll_fout4", ap_base + 0x150, 4, 3, 8, MUX_TYPE_DIV, 2, 7); -+ clksCLK_OUT_1_OUT_DIV = thead_clk_light_divider("clk_out_1_out_div", "osc_24m", ap_base + 0x1b4, 0, 3, 3, MUX_TYPE_DIV, 2, 4); -+ clksCLK_OUT_2_OUT_DIV = thead_clk_light_divider("clk_out_2_out_div", "osc_24m", ap_base + 0x1b8, 0, 3, 3, MUX_TYPE_DIV, 2, 4); -+ clksCLK_OUT_3_OUT_DIV = thead_clk_light_divider("clk_out_3_out_div", "osc_24m", ap_base + 0x1bc, 0, 3, 3, MUX_TYPE_DIV, 2, 4); -+ clksCLK_OUT_4_OUT_DIV = thead_clk_light_divider("clk_out_4_out_div", "osc_24m", ap_base + 0x1c0, 0, 3, 3, MUX_TYPE_DIV, 2, 4); -+ clksVOSYS_ACLK_M = thead_clk_light_divider("vosys_aclk_m", "video_pll_foutvco", ap_base + 0x1dc, 0, 4, 4, MUX_TYPE_DIV, 3, 15); -+ clksNPU_CCLK_OUT_DIV = thead_clk_light_divider("npu_cclk_out_div", "video_pll_foutvco", ap_base + 0x1c8, 0, 3, 3, MUX_TYPE_DIV, 3, 7); -+ clksCFG_APB_PCLK_OUT_DIV = thead_clk_light_divider("cfg_apb_pclk_out_div", "gmac_pll_foutpostdiv", ap_base + 0x1c4, 0, 4, 4, MUX_TYPE_DIV, 4, 15); -+ clksVISYS_ACLK_M = thead_clk_light_divider("visys_aclk_m", "video_pll_foutvco", ap_base + 0x1d0, 16, 4, 20, MUX_TYPE_DIV, 3, 15); -+ clksVISYS_AHB_HCLK = thead_clk_light_divider("visys_ahb_hclk", "video_pll_foutvco", ap_base + 0x1d0, 0, 4, 4, MUX_TYPE_DIV, 6, 15); -+ clksVPSYS_APB_PCLK = thead_clk_light_divider("vpsys_apb_pclk", "gmac_pll_fout1ph0", ap_base + 0x1e0, 0, 3, 4, MUX_TYPE_DIV, 2, 7); -+ clksVPSYS_AXI_ACLK = thead_clk_light_divider("vpsys_axi_aclk", "video_pll_foutvco", ap_base + 0x1e0, 8, 4, 12, MUX_TYPE_DIV, 3, 15); -+ clksVENC_CCLK = thead_clk_light_divider("venc_cclk", "gmac_pll_foutpostdiv", ap_base + 0x1e4, 0, 3, 4, MUX_TYPE_DIV, 2, 7); -+ clksDPU0_PLL_DIV_CLK = thead_clk_light_divider("dpu0_pll_div_clk", "dpu0_pll_foutpostdiv", ap_base + 0x1e8, 0, 8, 8, MUX_TYPE_DIV, 2, 214); -+ clksDPU1_PLL_DIV_CLK = thead_clk_light_divider("dpu1_pll_div_clk", "dpu1_pll_foutpostdiv", ap_base + 0x1ec, 0, 8, 8, MUX_TYPE_DIV, 2, 214); -+ -+ /* Light Fullmask PLL FOUT */ -+ clksGMAC_PLL_FOUT1PH0 = thead_light_clk_fixed_factor("gmac_pll_fout1ph0", "gmac_pll_bypass", 1, 2); -+ clksGMAC_PLL_FOUT4 = thead_light_clk_fixed_factor("gmac_pll_fout4", "gmac_pll_bypass", 1, 8); -+ clksVIDEO_PLL_FOUT1PH0 = thead_light_clk_fixed_factor("video_pll_fout1ph0", "video_pll_bybass", 1, 2); -+ clksVIDEO_PLL_FOUT4 = thead_light_clk_fixed_factor("video_pll_fout4", "video_pll_bypass", 1, 8); -+ clksTEE_PLL_FOUT4 = thead_light_clk_fixed_factor("tee_pll_fout4", "tee_pll_bypass", 1, 8); -+ clksCPU_PLL0_FOUT4 = thead_light_clk_fixed_factor("cpu_pll0_fout4", "cpu_pll0_bypass", 1, 8); -+ clksCPU_PLL1_FOUT4 = thead_light_clk_fixed_factor("cpu_pll1_fout4", "cpu_pll1_bypass", 1, 8); -+ clksDPU0_PLL_FOUT4 = thead_light_clk_fixed_factor("dpu0_pll_fout4", "dpu0_pll_bypass", 1, 8); -+ clksDPU1_PLL_FOUT4 = thead_light_clk_fixed_factor("dpu1_pll_fout4", "dpu1_pll_bypass", 1, 8); -+ -+ /* Light Fullmask Fixed Factor */ -+ clksC910_OSC_CLK = thead_light_clk_fixed_factor("c910_osc_clk", "osc_24m", 1, 1); -+ clksQSPI_SSI_CLK = thead_light_clk_fixed_factor("qspi_ssi_clk", "video_pll_foutpostdiv", 1, 1); /* Note: no mux to select, use default value */ -+ clksQSPI0_SSI_CLK = thead_light_clk_fixed_factor("qspi0_ssi_clk", "qspi_ssi_clk", 1, 1); -+ clksQSPI1_SSI_CLK = thead_light_clk_fixed_factor("qspi1_ssi_clk", "video_pll_fout1ph0", 1, 1); -+ clksSPI_SSI_CLK = thead_light_clk_fixed_factor("spi_ssi_clk", "video_pll_fout1ph0", 1, 1); -+ clksEMMC_SDIO_REF_CLK = thead_light_clk_fixed_factor("emmc_sdio_ref_clk", "video_pll_foutpostdiv", 1, 1); /* Note: no mux to select, use default value */ -+ clksPWM_CCLK = thead_light_clk_fixed_factor("pwm_cclk", "osc_24m", 1, 1); -+ clksCHIP_DBG_CCLK = thead_light_clk_fixed_factor("chip_dbg_cclk", "osc_24m", 1, 1); -+ clksGMAC_CCLK = thead_light_clk_fixed_factor("gmac_cclk", "gmac_pll_fout1ph0", 1, 1); -+ clksGPIO0_DBCLK = thead_light_clk_fixed_factor("gpio0_dbclk", "pad_rtc_clk", 1, 1); -+ clksGPIO1_DBCLK = thead_light_clk_fixed_factor("gpio1_dbclk", "pad_rtc_clk", 1, 1); -+ clksGPIO2_DBCLK = thead_light_clk_fixed_factor("gpio2_dbclk", "pad_rtc_clk", 1, 1); -+ clksGPIO3_DBCLK = thead_light_clk_fixed_factor("gpio3_dbclk", "pad_rtc_clk", 1, 1); -+ clksCLK_100M = thead_light_clk_fixed_factor("clk_100m", "gmac_pll_foutpostdiv", 1, 10); -+ clksI2C_IC_CLK = thead_light_clk_fixed_factor("i2c_ic_clk", "clk_100m", 1, 2); -+ clksTIMER_CCLK = thead_light_clk_fixed_factor("timer_cclk", "osc_24m", 1, 1); -+ clksAXI4_CPUSYS1_ACLK = thead_light_clk_fixed_factor("axi4_cpusys1_aclk", "clkgen_c910_bus_clk_no_icg", 1, 1); -+ clksCPU_BUS_DFTCLK = thead_light_clk_fixed_factor("cpu_bus_dftclk", "cpu_pll0_foutpostdiv", 1, 2); -+ clksCPU_PLL0_TEST_CLK = thead_light_clk_fixed_factor("cpu_pll0_test_clk", "cpu_pll0_fout4", 1, 8); -+ clksCPU_PLL1_TEST_CLK = thead_light_clk_fixed_factor("cpu_pll1_test_clk", "cpu_pll1_fout4", 1, 8); -+ clksDPU0_PLL_TEST_CLK = thead_light_clk_fixed_factor("dpu0_pll_test_clk", "dpu0_pll_fout4", 1, 8); -+ clksDPU1_PLL_TEST_CLK = thead_light_clk_fixed_factor("dpu1_pll_test_clk", "dpu1_pll_fout4", 1, 8); -+ clksGMAC_PLL_TEST_CLK = thead_light_clk_fixed_factor("gmac_pll_test_clk", "gmac_pll_fout4", 1, 8); -+ clksVIDEO_PLL_TEST_CLK = thead_light_clk_fixed_factor("video_pll_test_clk", "video_pll_fout4", 1, 8); -+ clksTEE_PLL_TEST_CLK = thead_light_clk_fixed_factor("tee_pll_test_clk", "tee_pll_fout4", 1, 8); -+ clksAONSYS_BUS_CLK = thead_light_clk_fixed_factor("aonsys_bus_clk", "aonsys_hclk", 1, 1); -+ -+ /* Light Fullmask Clock Gate */ -+ clksCLKGEN_AHB2_CPUSYS_HCLK = thead_clk_light_gate("clkgen_ahb2_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x120, 6); -+ clksCLKGEN_APB3_CPUSYS_HCLK = thead_clk_light_gate("clkgen_apb3_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x130, 4); -+ clksCLKGEN_C910_BROM_HCLK = thead_clk_light_gate("clkgen_c910_brom_hclk", "ahb2_cpusys_hclk", ap_base + 0x100, 4); -+ clksCLKGEN_SPINLOCK_HCLK = thead_clk_light_gate("clkgen_spinlock_hclk", "ahb2_cpusys_hclk", ap_base + 0x208, 10); -+ clksCLKGEN_MBOX0_PCLK = thead_clk_light_gate("clkgen_mbox0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 7); -+ clksCLKGEN_MBOX1_PCLK = thead_clk_light_gate("clkgen_mbox1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 6); -+ clksCLKGEN_MBOX2_PCLK = thead_clk_light_gate("clkgen_mbox2_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 5); -+ clksCLKGEN_MBOX3_PCLK = thead_clk_light_gate("clkgen_mbox3_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 4); -+ clksCLKGEN_WDT0_PCLK = thead_clk_light_gate("clkgen_wdt0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 3); -+ clksCLKGEN_WDT1_PCLK = thead_clk_light_gate("clkgen_wdt1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 2); -+ -+ if (teesys) -+ clksCLKGEN_MISCSYS_TEE_CCLK = thead_clk_light_gate("clkgen_miscsys_tee_cclk", "teesys_hclk", ap_base + 0x1cc, 25); //just for teesys!!! -+ -+ clksCLKGEN_SRAM_AXI_ACLK_2 = thead_clk_light_gate("clkgen_sram_axi_aclk_2", "axi4_cpusys1_aclk", ap_base + 0x20c, 2); -+ clksCLKGEN_PERISYS_AHB_HCLK = thead_clk_light_gate("clkgen_perisys_ahb_hclk", "perisys_ahb_hclk", ap_base + 0x140, 6); -+ clksCLKGEN_PERISYS_APB1_HCLK = thead_clk_light_gate("clkgen_perisys_apb1_hclk", "perisys_ahb_hclk", ap_base + 0x150, 9); -+ clksCLKGEN_PERISYS_APB2_HCLK = thead_clk_light_gate("clkgen_perisys_apb2_hclk", "perisys_ahb_hclk", ap_base + 0x150, 10); -+ clksCLKGEN_PERISYS_APB4_HCLK = thead_clk_light_gate("clkgen_perisys_apb4_hclk", "perisys_ahb_hclk", ap_base + 0x150, 12); -+ clksCLKGEN_PADCTRL0_APSYS_PCLK = thead_clk_light_gate("clkgen_padctrl0_apsys_pclk", "perisys_ahb_hclk", ap_base + 0x204, 22); -+ clksCLKGEN_DSMART_PCLK = thead_clk_light_gate("clkgen_dsmart_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 23); -+ clksCLKGEN_PADCTRL1_APSYS_PCLK = thead_clk_light_gate("clkgen_padctrl1_apsys_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 24); -+ clksCLKGEN_CLK_OUT_1_CLK = thead_clk_light_gate("clkgen_clk_out_1_clk", "clk_out_1", ap_base + 0x1b4, 5); -+ clksCLKGEN_CLK_OUT_2_CLK = thead_clk_light_gate("clkgen_clk_out_2_clk", "clk_out_2", ap_base + 0x1b8, 5); -+ clksCLKGEN_CLK_OUT_3_CLK = thead_clk_light_gate("clkgen_clk_out_3_clk", "clk_out_3", ap_base + 0x1bc, 5); -+ clksCLKGEN_CLK_OUT_4_CLK = thead_clk_light_gate("clkgen_clk_out_4_clk", "clk_out_4", ap_base + 0x1c0, 5); -+ clksCLKGEN_NPUSYS_AXI_ACLK = thead_clk_light_gate("clkgen_npusys_axi_aclk", "npu_cclk", ap_base + 0x1c8, 5); -+ clksCLKGEN_SRAM_AXI_ACLK_0 = thead_clk_light_gate("clkgen_sram_axi_aclk_0", "npu_cclk", ap_base + 0x20c, 4); -+ clksCLKGEN_APB_CPU2CFG_HCLK = thead_clk_light_gate("clkgen_apb_cpu2cfg_hclk", "cfg_apb_pclk", ap_base + 0x1c4, 5); -+ clksCLKGEN_SRAM_AXI_ACLK_1 = thead_clk_light_gate("clkgen_sram_axi_aclk_1", "visys_aclk_m", ap_base + 0x20c, 3); -+ clksCLKGEN_SRAM_AXI_ACLK_3 = thead_clk_light_gate("clkgen_sram_axi_aclk_3", "vpsys_axi_aclk", ap_base + 0x20c, 1); -+ clksCLKGEN_VPSYS_VENC_CCLK = thead_clk_light_gate("clkgen_vpsys_venc_cclk", "venc_cclk", ap_base + 0x1e4, 5); -+ clksCLKGEN_EMMC_SDIO_REF_CLK = thead_clk_light_gate("clkgen_emmc_sdio_ref_clk", "emmc_sdio_ref_clk", ap_base + 0x204, 30); -+ -+ clksCLKGEN_X2H_CPUSYS_MHCLK = thead_clk_light_gate_shared("clkgen_x2h_cpusys_mhclk", "ahb2_cpusys_hclk", ap_base + 0x120, 7, &share_cnt_x2h_cpusys_clk_en); -+ clksCLKGEN_X2H_CPUSYS_ACLK = thead_clk_light_gate_shared("clkgen_x2h_cpusys_aclk", "cfg_axi_aclk", ap_base + 0x120, 7, &share_cnt_x2h_cpusys_clk_en); -+ clksCLKGEN_DMAC_CPUSYS_HCLK = thead_clk_light_gate_shared("clkgen_dmac_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); -+ clksCLKGEN_IOPMP_DMAC_CPUSYS_PCLK = thead_clk_light_gate_shared("clkgen_iopmp_dmac_cpusys_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); -+ clksCLKGEN_DMAC_CPUSYS_ACLK = thead_clk_light_gate_shared("clkgen_dmac_cpusys_aclk", "axi4_cpusys2_aclk", ap_base + 0x208, 8, &share_cnt_dmac_cpusys_clk_en); -+ clksCLKGEN_TIMER0_PCLK = thead_clk_light_gate_shared("clkgen_timer0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 1, &share_cnt_timer0_clk_en); -+ clksCLKGEN_TIMER0_CCLK = thead_clk_light_gate_shared("clkgen_timer0_cclk", "timer_cclk", ap_base + 0x208, 1, &share_cnt_timer0_clk_en); -+ clksCLKGEN_TIMER1_PCLK = thead_clk_light_gate_shared("clkgen_timer1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 0, &share_cnt_timer1_clk_en); -+ clksCLKGEN_TIMER1_CCLK = thead_clk_light_gate_shared("clkgen_timer1_cclk", "timer_cclk", ap_base + 0x208, 0, &share_cnt_timer1_clk_en); -+ clksCLKGEN_AXI4_CPUSYS2_PCLK = thead_clk_light_gate_shared("clkgen_axi4_cpusys2_pclk", "apb3_cpusys_pclk", ap_base + 0x134, 5, &share_cnt_axi4_cpusys2_clk_en); -+ clksCLKGEN_AXI4_CPUSYS2_ACLK = thead_clk_light_gate_shared("clkgen_axi4_cpusys2_aclk", "axi4_cpusys2_aclk", ap_base + 0x134, 5, &share_cnt_axi4_cpusys2_clk_en); -+ clksCLKGEN_BMU_C910_PCLK = thead_clk_light_gate_shared("clkgen_bmu_c910_pclk", "apb3_cpusys_pclk", ap_base + 0x100, 5, &share_cnt_bmu_c910_clk_en); -+ clksCLKGEN_BMU_C910_ACLK = thead_clk_light_gate_shared("clkgen_bmu_c910_aclk", "axi4_cpusys1_aclk", ap_base + 0x100, 5, &share_cnt_bmu_c910_clk_en); -+ clksCLKGEN_IOPMP_AON_PCLK = thead_clk_light_gate_shared("clkgen_iopmp_aon_pclk", "apb3_cpusys_pclk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); -+ clksCLKGEN_AON2CPU_A2X_ACLK = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_aclk", "axi4_cpusys2_aclk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); -+ clksCLKGEN_AON2CPU_A2X_HCLK = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_hclk", "aonsys_bus_clk", ap_base + 0x134, 8, &share_cnt_aon2cpu_a2x_clk_en); -+ clksCLKGEN_IOPMP_CHIP_DBG_PCLK = thead_clk_light_gate_shared("clkgen_iopmp_chip_dbg_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); -+ clksCLKGEN_CHIP_DBG_ACLK = thead_clk_light_gate_shared("clkgen_chip_dbg_aclk", "axi4_cpusys2_aclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); -+ clksCLKGEN_CHIP_DBG_CCLK = thead_clk_light_gate_shared("clkgen_chip_dbg_cclk", "chip_dbg_cclk", ap_base + 0x208, 9, &share_cnt_chip_dbg_clk_en); -+ clksCLKGEN_X2X_CPUSYS_ACLK_M = thead_clk_light_gate_shared("clkgen_x2x_cpusys_aclk_m", "axi4_cpusys2_aclk", ap_base + 0x134, 7, &share_cnt_x2x_cpusys_clk_en); -+ clksCLKGEN_X2X_CPUSYS_ACLK_S = thead_clk_light_gate_shared("clkgen_x2x_cpusys_aclk_s", "axi4_cpusys1_aclk", ap_base + 0x134, 7, &share_cnt_x2x_cpusys_clk_en); -+ clksCLKGEN_CPU2PERI_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_aclk", "axi4_cpusys1_aclk", ap_base + 0x140, 9, &share_cnt_cpu2peri_x2h_clk_en); -+ clksCLKGEN_CPU2PERI_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_mhclk", "perisys_ahb_hclk", ap_base + 0x140, 9, &share_cnt_cpu2peri_x2h_clk_en); -+ clksCLKGEN_CPU2VI_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2vi_x2h_aclk", "axi4_cpusys1_aclk", ap_base + 0x1d0, 21, &share_cnt_cpu2vi_x2h_clk_en); -+ clksCLKGEN_CPU2VI_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2vi_x2h_mhclk", "visys_ahb_hclk", ap_base + 0x1d0, 21, &share_cnt_cpu2vi_x2h_clk_en); -+ clksCLKGEN_CFG2TEE_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cfg2tee_x2h_aclk", "cfg_axi_aclk", ap_base + 0x1cc, 24, &share_cnt_cfg2tee_x2h_clk_en); // just for teesys!!! -+ clksCLKGEN_CFG2TEE_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cfg2tee_x2h_mhclk", "teesys_hclk", ap_base + 0x1cc, 24, &share_cnt_cfg2tee_x2h_clk_en); // just for teesys!!! -+ clksCLKGEN_CPU2AON_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_aclk", "cfg_axi_aclk", ap_base + 0x138, 8, &share_cnt_cpu2aon_x2h_clk_en); -+ clksCLKGEN_CPU2AON_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_mhclk", "aonsys_bus_clk", ap_base + 0x138, 8, &share_cnt_cpu2aon_x2h_clk_en); -+ clksCLKGEN_CPU2VP_X2P_ACLK = thead_clk_light_gate_shared("clkgen_cpu2vp_x2p_aclk", "cfg_axi_aclk", ap_base + 0x1e0, 13, &share_cnt_cpu2vp_x2p_clk_en); -+ clksCLKGEN_CPU2VP_X2P_PCLK = thead_clk_light_gate_shared("clkgen_cpu2vp_x2p_pclk", "vpsys_apb_pclk", ap_base + 0x1e0, 13, &share_cnt_cpu2vp_x2p_clk_en); -+ clksCLKGEN_TOP_AXI4S_ACLK = thead_clk_light_gate_shared("clkgen_top_axi4s_aclk", "cfg_axi_aclk", ap_base + 0x1c8, 4, &share_cnt_npu_core_clk_en); -+ clksCLKGEN_TOP_APB_SX_PCLK = thead_clk_light_gate_shared("clkgen_top_apb_sx_pclk", "cfg_apb_pclk", ap_base + 0x1c8, 4, &share_cnt_npu_core_clk_en); -+ clksCLKGEN_MISC2VP_X2X_ACLK_M = thead_clk_light_gate_shared("clkgen_misc2vp_x2x_aclk_m", "perisys_ahb_hclk", ap_base + 0x1e0, 15, &share_cnt_vpsys_axi_aclk_en); -+ clksCLKGEN_VPSYS_ACLK = thead_clk_light_gate_shared("clkgen_vpsys_aclk", "vpsys_axi_aclk", ap_base + 0x1e0, 15, &share_cnt_vpsys_axi_aclk_en); -+ clksCLKGEN_GMAC1_HCLK = thead_clk_light_gate_shared("clkgen_gmac1_hclk", "perisys_ahb_hclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); -+ clksCLKGEN_GMAC1_PCLK = thead_clk_light_gate_shared("clkgen_gmac1_pclk", "perisys_ahb_hclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); -+ clksCLKGEN_GMAC1_CCLK = thead_clk_light_gate_shared("clkgen_gmac1_cclk", "gmac_cclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); -+ clksCLKGEN_GMAC0_HCLK = thead_clk_light_gate_shared("clkgen_gmac0_hclk", "perisys_ahb_hclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); -+ clksCLKGEN_GMAC0_PCLK = thead_clk_light_gate_shared("clkgen_gmac0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); -+ clksCLKGEN_GMAC0_CCLK = thead_clk_light_gate_shared("clkgen_gmac0_cclk", "gmac_cclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); -+ clksCLKGEN_PERI2PERI1_APB_HCLK = thead_clk_light_gate_shared("clkgen_peri2peri1_apb_hclk", "perisys_ahb_hclk", ap_base + 0x150, 11, &share_cnt_perisys_apb3_hclk_en); -+ clksCLKGEN_PERI2PERI1_APB_PCLK = thead_clk_light_gate_shared("clkgen_peri2peri1_apb_pclk", "peri2sys_apb_pclk", ap_base + 0x150, 11, &share_cnt_perisys_apb3_hclk_en); -+ clksCLKGEN_QSPI0_PCLK = thead_clk_light_gate_shared("clkgen_qspi0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 17, &share_cnt_qspi0_clk_en); -+ clksCLKGEN_QSPI0_SSI_CLK = thead_clk_light_gate_shared("clkgen_qspi0_ssi_clk", "qspi0_ssi_clk", ap_base + 0x204, 17, &share_cnt_qspi0_clk_en); -+ clksCLKGEN_GMAC_AXI_ACLK = thead_clk_light_gate_shared("clkgen_gmac_axi_aclk", "perisys_ahb_hclk", ap_base + 0x204, 21, &share_cnt_gmac_axi_clk_en); -+ clksCLKGEN_GMAC_AXI_PCLK = thead_clk_light_gate_shared("clkgen_gmac_axi_pclk", "perisys_ahb_hclk", ap_base + 0x204, 21, &share_cnt_gmac_axi_clk_en); -+ clksCLKGEN_GPIO0_PCLK = thead_clk_light_gate_shared("clkgen_gpio0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 8, &share_cnt_gpio0_clk_en); -+ clksCLKGEN_GPIO0_DBCLK = thead_clk_light_gate_shared("clkgen_gpio0_dbclk", "gpio0_dbclk", ap_base + 0x204, 8, &share_cnt_gpio0_clk_en); -+ clksCLKGEN_GPIO1_PCLK = thead_clk_light_gate_shared("clkgen_gpio1_pclk", "perisys_ahb_hclk", ap_base + 0x204, 7, &share_cnt_gpio0_clk_en); -+ clksCLKGEN_GPIO1_DBCLK = thead_clk_light_gate_shared("clkgen_gpio1_dbclk", "gpio1_dbclk", ap_base + 0x204, 7, &share_cnt_gpio1_clk_en); -+ clksCLKGEN_PWM_PCLK = thead_clk_light_gate_shared("clkgen_pwm_pclk", "perisys_apb_pclk", ap_base + 0x204, 18, &share_cnt_pwm_clk_en); -+ clksCLKGEN_PWM_CCLK = thead_clk_light_gate_shared("clkgen_pwm_cclk", "pwm_cclk", ap_base + 0x204, 18, &share_cnt_pwm_clk_en); -+ clksCLKGEN_SPI_PCLK = thead_clk_light_gate_shared("clkgen_spi_pclk", "perisys_apb_pclk", ap_base + 0x204, 15, &share_cnt_spi_clk_en); -+ clksCLKGEN_SPI_SSI_CLK = thead_clk_light_gate_shared("clkgen_spi_ssi_clk", "spi_ssi_clk", ap_base + 0x204, 15, &share_cnt_spi_clk_en); -+ clksCLKGEN_UART0_PCLK = thead_clk_light_gate_shared("clkgen_uart0_pclk", "perisys_apb_pclk", ap_base + 0x204, 14, &share_cnt_uart0_clk_en); -+ clksCLKGEN_UART0_SCLK = thead_clk_light_gate_shared("clkgen_uart0_sclk", "uart_sclk", ap_base + 0x204, 14, &share_cnt_uart0_clk_en); -+ clksCLKGEN_UART2_PCLK = thead_clk_light_gate_shared("clkgen_uart2_pclk", "perisys_apb_pclk", ap_base + 0x204, 12, &share_cnt_uart2_clk_en); -+ clksCLKGEN_UART2_SCLK = thead_clk_light_gate_shared("clkgen_uart2_sclk", "uart_sclk", ap_base + 0x204, 12, &share_cnt_uart2_clk_en); -+ clksCLKGEN_I2C2_PCLK = thead_clk_light_gate_shared("clkgen_i2c2_pclk", "perisys_apb_pclk", ap_base + 0x204, 3, &share_cnt_i2c2_clk_en); -+ clksCLKGEN_I2C2_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c2_ic_clk", "i2c_ic_clk", ap_base + 0x204, 3, &share_cnt_i2c2_clk_en); -+ clksCLKGEN_I2C3_PCLK = thead_clk_light_gate_shared("clkgen_i2c3_pclk", "perisys_apb_pclk", ap_base + 0x204, 2, &share_cnt_i2c2_clk_en); -+ clksCLKGEN_I2C3_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c3_ic_clk", "i2c_ic_clk", ap_base + 0x204, 2, &share_cnt_i2c2_clk_en); -+ clksCLKGEN_I2S_PCLK = thead_clk_light_gate_shared("clkgen_i2s_pclk", "perisys_apb_pclk", ap_base + 0x1f0, 1, &share_cnt_peri_i2s_clk_en); -+ clksCLKGEN_I2S_SRC_CLK = thead_clk_light_gate_shared("clkgen_i2s_src_clk", "peri_i2s_src_clk", ap_base + 0x1f0, 1, &share_cnt_peri_i2s_clk_en); -+ clksCLKGEN_QSPI1_PCLK = thead_clk_light_gate_shared("clkgen_qspi1_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 16, &share_cnt_qspi1_clk_en); -+ clksCLKGEN_QSPI1_SSI_CLK = thead_clk_light_gate_shared("clkgen_qspi1_ssi_clk", "qspi1_ssi_clk", ap_base + 0x204, 16, &share_cnt_qspi1_clk_en); -+ clksCLKGEN_UART1_PCLK = thead_clk_light_gate_shared("clkgen_uart1_pclk", "per2sys_apb_pclk", ap_base + 0x204, 13, &share_cnt_uart1_clk_en); -+ clksCLKGEN_UART1_SCLK = thead_clk_light_gate_shared("clkgen_uart1_sclk", "uart_sclk", ap_base + 0x204, 13, &share_cnt_uart1_clk_en); -+ clksCLKGEN_UART3_PCLK = thead_clk_light_gate_shared("clkgen_uart3_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 11, &share_cnt_uart3_clk_en); -+ clksCLKGEN_UART3_SCLK = thead_clk_light_gate_shared("clkgen_uart3_sclk", "uart_sclk", ap_base + 0x204, 11, &share_cnt_uart3_clk_en); -+ clksCLKGEN_UART4_PCLK = thead_clk_light_gate_shared("clkgen_uart4_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 10, &share_cnt_uart4_clk_en); -+ clksCLKGEN_UART4_SCLK = thead_clk_light_gate_shared("clkgen_uart4_sclk", "uart_sclk", ap_base + 0x204, 10, &share_cnt_uart4_clk_en); -+ clksCLKGEN_UART5_PCLK = thead_clk_light_gate_shared("clkgen_uart5_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 9, &share_cnt_uart5_clk_en); -+ clksCLKGEN_UART5_SCLK = thead_clk_light_gate_shared("clkgen_uart5_sclk", "uart_sclk", ap_base + 0x204, 9, &share_cnt_uart5_clk_en); -+ clksCLKGEN_I2C0_PCLK = thead_clk_light_gate_shared("clkgen_i2c0_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 5, &share_cnt_i2c0_clk_en); -+ clksCLKGEN_I2C0_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c0_ic_clk", "i2c_ic_clk", ap_base + 0x204, 5, &share_cnt_i2c0_clk_en); -+ clksCLKGEN_I2C1_PCLK = thead_clk_light_gate_shared("clkgen_i2c1_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 4, &share_cnt_i2c1_clk_en); -+ clksCLKGEN_I2C1_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c1_ic_clk", "i2c_ic_clk", ap_base + 0x204, 4, &share_cnt_i2c1_clk_en); -+ clksCLKGEN_I2C4_PCLK = thead_clk_light_gate_shared("clkgen_i2c4_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 1, &share_cnt_i2c4_clk_en); -+ clksCLKGEN_I2C4_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c4_ic_clk", "i2c_ic_clk", ap_base + 0x204, 1, &share_cnt_i2c4_clk_en); -+ clksCLKGEN_I2C5_PCLK = thead_clk_light_gate_shared("clkgen_i2c5_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 0, &share_cnt_i2c5_clk_en); -+ clksCLKGEN_I2C5_IC_CLK = thead_clk_light_gate_shared("clkgen_i2c5_ic_clk", "i2c_ic_clk", ap_base + 0x204, 0, &share_cnt_i2c5_clk_en); -+ clksCLKGEN_GPIO2_PCLK = thead_clk_light_gate_shared("clkgen_gpio2_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); -+ clksCLKGEN_GPIO2_DBCLK = thead_clk_light_gate_shared("clkgen_gpio2_dbclk", "gpio2_dbclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); -+ clksCLKGEN_GPIO3_PCLK = thead_clk_light_gate_shared("clkgen_gpio3_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); //!!! gpio3 pclk is controlled by gpio2_clk_en -+ clksCLKGEN_GPIO3_DBCLK = thead_clk_light_gate_shared("clkgen_gpio3_dbclk", "gpio3_dbclk", ap_base + 0x204, 20, &share_cnt_gpio3_clk_en); -+ clksCLKGEN_VOSYS_AXI_ACLK = thead_clk_light_gate_shared("clkgen_vosys_axi_aclk", "vosys_aclk_m", ap_base + 0x1dc, 5, &share_cnt_vosys_axi_aclk_en); -+ clksCLKGEN_VOSYS_X2X_ACLK_S = thead_clk_light_gate_shared("clkgen_vosys_x2x_aclk_s", "npu_cclk", ap_base + 0x1dc, 5, &share_cnt_vosys_axi_aclk_en); -+ -+ clk_data.clks = clks; -+ clk_data.clk_num = ARRAY_SIZE(clks); -+ -+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); -+ if (ret < 0) { -+ dev_err(dev, "failed to register clks for light\n"); -+ goto unregister_clks; -+ } -+ -+#ifndef FPGA_EMU -+ /* HW defalut */ -+ clk_set_parent(clksC910_CCLK, clksCPU_PLL1_FOUTPOSTDIV); -+#else -+ clk_set_parent(clksC910_CCLK_I0, clksOSC_24M); -+ clk_set_parent(clksC910_CCLK, clksC910_CCLK_I0); -+#endif -+ dev_info(dev, "succeed to register light fullmask clock driver\n"); -+ -+ return 0; -+ -+unregister_clks: -+ thead_unregister_clocks(clks, ARRAY_SIZE(clks)); -+ return ret; -+} -+ -+ -+const bool tee_sys_flag; -+ -+static const struct of_device_id light_clk_of_match = { -+ { .compatible = "thead,light-fm-ree-clk" }, -+ { .compatible = "thead,light-fm-tee-clk", .data = &tee_sys_flag,}, -+ { /* Sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, light_clk_of_match); -+ -+static struct platform_driver light_clk_driver = { -+ .probe = light_clocks_probe, -+ .driver = { -+ .name = "light-fm-clk", -+ .of_match_table = of_match_ptr(light_clk_of_match), -+ }, -+}; -+ -+module_platform_driver(light_clk_driver); -+MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light Fullmask clock driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/clk/thead/clk-light-mpw.c b/drivers/clk/thead/clk-light-mpw.c -new file mode 100644 -index 000000000000..f7356ddf4684 ---- /dev/null -+++ b/drivers/clk/thead/clk-light-mpw.c -@@ -0,0 +1,492 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <dt-bindings/clock/light-mpw-clock.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/types.h> -+ -+#include "clk.h" -+ -+static struct clk *clksLIGHT_CLK_END; -+static struct clk_onecell_data clk_data; -+ -+static u32 share_cnt_cpu2cfg_x2x_clk_en; -+static u32 share_cnt_cpu2peri_x2h_clk_en; -+static u32 share_cnt_aon2cpu_a2x_clk_en; -+static u32 share_cnt_dmac_clk_en; -+static u32 share_cnt_x2h_cpusys_clk_en; -+static u32 share_cnt_cpu2tee_x2h_clk_en; -+static u32 share_cnt_cpu2aon_x2h_clk_en; -+static u32 share_cnt_cpu2cfg_x2h_clk_en; -+static u32 share_cnt_timer0_clk_en; -+static u32 share_cnt_timer1_clk_en; -+static u32 share_cnt_peri2ddr_x2x_clk_en; -+static u32 share_cnt_usb3_drd_clk_en; -+static u32 share_cnt_gmac_clk_en; -+static u32 share_cnt_emmc0_clk_en; -+static u32 share_cnt_emmc1_clk_en; -+static u32 share_cnt_pwm_clk_en; -+static u32 share_cnt_qspi0_clk_en; -+static u32 share_cnt_qspi1_clk_en; -+static u32 share_cnt_spi_clk_en; -+static u32 share_cnt_gpio0_clk_en; -+static u32 share_cnt_gpio1_clk_en; -+static u32 share_cnt_gpio2_clk_en; -+static u32 share_cnt_dmac_1_clk_en; -+static u32 share_cnt_dmac_2_clk_en; -+static u32 share_cnt_dmac_3_clk_en; -+ -+#ifdef THEAD_LIGHT_AON_CLK -+static const char * const audio_pll_bypass_sels = {"audio_pll_foutpostdiv", "osc_24m", }; -+static const char * const sys_pll_bypass_sels = {"sys_pll_foutpostdiv", "osc_24m", }; -+#endif -+#ifdef THEAD_LIGHT_DDR_CLK -+static const char * const ddr_pll_bypass_sels = {"ddr_pll_foutpostdiv", "osc_24m", }; -+#endif -+static const char * const cpu_pll0_bypass_sels = {"cpu_pll0_foutpostdiv", "osc_24m", }; -+static const char * const cpu_pll1_bypass_sels = {"cpu_pll1_foutpostdiv", "osc_24m", }; -+static const char * const gmac_pll_bypass_sels = {"gmac_pll_foutpostdiv", "osc_24m", }; -+static const char * const video_pll_bypass_sels = {"video_pll_foutpostdiv", "osc_24m", }; -+ -+#ifdef THEAD_LIGHT_AON_CLK -+static const char * const aonsys_clk_switch_0_sels = {"audio_pll_fout3", "osc_24m", }; -+static const char * const aonsys_clk_switch_1_sels = {"aonsys_clk_switch_0", "rc_24m", }; -+#endif -+ -+static const char * const c910_cclk_i0_sels = {"cpu_pll0_bypass", "osc_24m", }; -+static const char * const c910_cclk_sels = {"c910_cclk_i0", "cpu_pll1_foutpostdiv", }; -+static const char * const cpusys_ahb_hclk_sel = {"cpusys_ahb_hclk_div", "osc_24m"}; -+static const char * const cpusys_cfg_axi_aclk_sel = {"cpusys_cfg_axi_aclk_div", "osc_24m"}; -+static const char * const perisys_ahb_hclk_sel = {"perisys_ahb_hclk_div", "osc_24m"}; -+static const char * const clk_out_1_sel = {"clk_out_1_div", "osc_24m"}; -+static const char * const clk_out_2_sel = {"clk_out_2_div", "osc_24m"}; -+static const char * const clk_out_3_sel = {"clk_out_3_div", "osc_24m"}; -+static const char * const clk_out_4_sel = {"clk_out_4_div", "osc_24m"}; -+ -+static const struct light_pll_rate_table light_audiopll_tbl = { -+ LIGHT_PLL_RATE(2654208000U, 147456000U, 1, 110, 9932112, 6, 3), -+ LIGHT_PLL_RATE(884736000U, 294912000U, 1, 36, 14495600, 3, 1), -+}; -+ -+static const struct light_pll_rate_table light_syspll_tbl = { -+ LIGHT_PLL_RATE(2438553600U, 812851200U, 1, 101, 10173704, 3, 1), -+ LIGHT_PLL_RATE(884736000U, 294912000U, 1, 36, 14495600, 3, 1), -+}; -+ -+static const struct light_pll_rate_table light_cpupll_tbl = { -+ LIGHT_PLL_RATE(1800000000U, 1800000000U, 1, 75, 0, 1, 1), -+ LIGHT_PLL_RATE(3000000000U, 1500000000U, 1, 125, 0, 2, 1), -+ LIGHT_PLL_RATE(3000000000U, 1000000000U, 1, 125, 0, 3, 1), -+ LIGHT_PLL_RATE(3000000000U, 125000000U, 1, 125, 0, 6, 4), -+}; -+ -+#ifdef THEAD_LIGHT_DDR_CLK -+static const struct light_pll_rate_table light_ddrpll_tbl = { -+ LIGHT_PLL_RATE(3192000000U, 798000000U, 1, 133, 0, 4, 1), -+ LIGHT_PLL_RATE(3192000000U, 532000000U, 1, 133, 0, 6, 1), -+ LIGHT_PLL_RATE(2112000000U, 1056000000U, 1, 88, 0, 2, 1), -+}; -+#endif -+ -+#ifdef THEAD_LIGHT_AON_CLK -+static struct light_pll_clk light_audio_pllvco = { -+ .out_type = LIGHT_PLL_VCO, -+ .clk_type = LIGHT_AUDIO_PLL, -+ .rate_table = light_audiopll_tbl, -+ .rate_count = ARRAY_SIZE(light_audiopll_tbl), -+}; -+ -+static struct light_pll_clk light_audio_plldiv = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_AUDIO_PLL, -+ .rate_table = light_audiopll_tbl, -+ .rate_count = ARRAY_SIZE(light_audiopll_tbl), -+}; -+ -+static struct light_pll_clk light_sys_pllvco = { -+ .out_type = LIGHT_PLL_VCO, -+ .clk_type = LIGHT_SYS_PLL, -+ .rate_table = light_syspll_tbl, -+ .rate_count = ARRAY_SIZE(light_syspll_tbl), -+}; -+ -+static struct light_pll_clk light_sys_plldiv = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_SYS_PLL, -+ .rate_table = light_syspll_tbl, -+ .rate_count = ARRAY_SIZE(light_syspll_tbl), -+}; -+#endif -+ -+static struct light_pll_clk light_cpu_pll0vco = { -+ .out_type = LIGHT_PLL_VCO, -+ .clk_type = LIGHT_CPU_PLL0, -+ .rate_table = light_cpupll_tbl, -+ .rate_count = ARRAY_SIZE(light_cpupll_tbl), -+}; -+ -+static struct light_pll_clk light_cpu_pll0div = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_CPU_PLL0, -+ .rate_table = light_cpupll_tbl, -+ .rate_count = ARRAY_SIZE(light_cpupll_tbl), -+}; -+ -+static struct light_pll_clk light_cpu_pll1vco = { -+ .out_type = LIGHT_PLL_VCO, -+ .clk_type = LIGHT_CPU_PLL1, -+ .rate_table = light_cpupll_tbl, -+ .rate_count = ARRAY_SIZE(light_cpupll_tbl), -+}; -+ -+static struct light_pll_clk light_cpu_pll1div = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_CPU_PLL1, -+ .rate_table = light_cpupll_tbl, -+ .rate_count = ARRAY_SIZE(light_cpupll_tbl), -+}; -+ -+#ifdef THEAD_LIGHT_DDR_CLK -+static struct light_pll_clk light_ddr_pllvco = { -+ .out_type = LIGHT_PLL_VCO, -+ .clk_type = LIGHT_DDR_PLL, -+ .rate_table = light_ddrpll_tbl, -+ .rate_count = ARRAY_SIZE(light_ddrpll_tbl), -+}; -+ -+static struct light_pll_clk light_ddr_plldiv = { -+ .out_type = LIGHT_PLL_DIV, -+ .clk_type = LIGHT_DDR_PLL, -+ .rate_table = light_ddrpll_tbl, -+ .rate_count = ARRAY_SIZE(light_ddrpll_tbl), -+}; -+#endif -+ -+static int light_clocks_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ void __iomem *ap_base; -+#ifdef THEAD_LIGHT_DDR_CLK -+ void __iomem *ddr_base; -+#endif -+#ifdef THEAD_LIGHT_AON_CLK -+ void __iomem *aon_base; -+#endif -+ int ret; -+ -+#ifdef THEAD_LIGHT_AON_CLK -+ np = of_find_compatible_node(NULL, NULL, "thead,light-aon-clk"); -+ aon_base = of_iomap(np, 0); -+ if (WARN_ON(!aon_base)) { -+ ret = -ENOMEM; -+ goto unregister_clks; -+ } -+ of_node_put(np); -+#endif -+ -+ /* Clock source */ -+ clksLIGHT_CLK_DUMMY = thead_clk_fixed("dummy", 0); -+ clksLIGHT_CLK_32K = of_clk_get_by_name(np, "osc_32k"); -+ clksLIGHT_CLK_24M = of_clk_get_by_name(np, "osc_24m"); -+ clksLIGHT_RC_24M = of_clk_get_by_name(np, "rc_24m"); -+ -+ /* AP Fixed PLL */ -+ clksLIGHT_VIDEO_PLL_FOUTVCO = thead_clk_fixed("video_pll_foutvco", 2376000000); -+ clksLIGHT_VIDEO_PLL_FOUTPOSTDIV = thead_clk_fixed("video_pll_foutpostdiv", 796000000); -+ clksLIGHT_GMAC_PLL_FOUTVCO = thead_clk_fixed("gmac_pll_foutvco", 2000000000); -+ clksLIGHT_GMAC_PLL_FOUTPOSTDIV = thead_clk_fixed("gmac_pll_foutpostdiv", 1000000000); -+ -+#ifdef THEAD_LIGHT_AON_CLK -+ /* Aon PLL clocks */ -+ clksLIGHT_AUDIO_PLL_FOUTVCO = thead_light_pll("audio_pll_foutvco", "osc_24m", aon_base, &light_audio_pllvco); -+ clksLIGHT_AUDIO_PLL_FOUTPOSTDIV = thead_light_pll("audio_pll_foutpostdiv", "osc_24m", aon_base, &light_audio_plldiv); -+ clksLIGHT_SYS_PLL_FOUTVCO = thead_light_pll("sys_pll_foutvco", "osc_24m", aon_base, &light_sys_pllvco); -+ clksLIGHT_SYS_PLL_FOUTPOSTDIV = thead_light_pll("sys_pll_foutpostdiv", "osc_24m", aon_base, &light_sys_plldiv); -+#endif -+ -+#ifdef THEAD_LIGHT_DDR_CLK -+ np = of_find_compatible_node(NULL, NULL, "thead,light-ddr-clk"); -+ ddr_base = of_iomap(np, 0); -+ if (WARN_ON(!ddr_base)) { -+ ret = -ENOMEM; -+ goto unregister_clks; -+ } -+ of_node_put(np); -+ -+ /* DDR PLL */ -+ clksLIGHT_DDR_PLL_FOUTVCO = thead_light_pll("ddr_pll_foutvco", "osc_24m", ddr_base, &light_ddr_pllvco); -+ clksLIGHT_DDR_PLL_FOUTPOSTDIV = thead_light_pll("ddr_pll_foutpostdiv", "osc_24m", ddr_base, &light_ddr_plldiv); -+#endif -+ -+ np = dev->of_node; -+ ap_base = devm_platform_ioremap_resource(pdev, 0); -+ if (WARN_ON(IS_ERR(ap_base))) { -+ ret = PTR_ERR(ap_base); -+ goto unregister_clks; -+ } -+ -+ /* AP PLL clocks */ -+ clksLIGHT_CPU_PLL0_FOUTVCO = thead_light_pll("cpu_pll0_foutvco", "osc_24m", ap_base, &light_cpu_pll0vco); -+ clksLIGHT_CPU_PLL0_FOUTPOSTDIV = thead_light_pll("cpu_pll0_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll0div); -+ clksLIGHT_CPU_PLL1_FOUTVCO = thead_light_pll("cpu_pll1_foutvco", "osc_24m", ap_base, &light_cpu_pll1vco); -+ clksLIGHT_CPU_PLL1_FOUTPOSTDIV = thead_light_pll("cpu_pll1_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll1div); -+ -+ /* PLL bypass */ -+#ifdef THEAD_LIGHT_AON_CLK -+ clksLIGHT_AUDIO_PLL_BYPASS = thead_light_clk_mux_flags("audio_pll_bypass", aon_base + 0x4, 31, 1, audio_pll_bypass_sels, ARRAY_SIZE(audio_pll_bypass_sels), CLK_SET_RATE_PARENT); -+ clksLIGHT_SYS_PLL_BYPASS = thead_light_clk_mux_flags("sys_pll_bypass", aon_base + 0x14, 31, 1, sys_pll_bypass_sels, ARRAY_SIZE(sys_pll_bypass_sels), CLK_SET_RATE_PARENT); -+#endif -+#ifdef THEAD_LIGHT_DDR_CLK -+ clksLIGHT_DDR_PLL_BYPASS = thead_light_clk_mux_flags("ddr_pll_bypass", ddr_base + 0xc, 31, 1, ddr_pll_bypass_sels, ARRAY_SIZE(ddr_pll_bypass_sels), CLK_SET_RATE_PARENT); -+#endif -+ clksLIGHT_CPU_PLL0_BYPASS = thead_light_clk_mux_flags("cpu_pll0_bypass", ap_base + 0x4, 31, 1, cpu_pll0_bypass_sels, ARRAY_SIZE(cpu_pll0_bypass_sels), CLK_SET_RATE_PARENT); -+ clksLIGHT_CPU_PLL1_BYPASS = thead_light_clk_mux_flags("cpu_pll1_bypass", ap_base + 0x14, 31, 1, cpu_pll1_bypass_sels, ARRAY_SIZE(cpu_pll1_bypass_sels), CLK_SET_RATE_PARENT); -+ clksLIGHT_GMAC_PLL_BYPASS = thead_light_clk_mux_flags("gmac_pll_bypass", ap_base + 0x24, 31, 1, gmac_pll_bypass_sels, ARRAY_SIZE(gmac_pll_bypass_sels), CLK_SET_RATE_PARENT); -+ clksLIGHT_VIDEO_PLL_BYPASS = thead_light_clk_mux_flags("video_pll_bypass", ap_base + 0x34, 31, 1, video_pll_bypass_sels, ARRAY_SIZE(video_pll_bypass_sels), CLK_SET_RATE_PARENT); -+ -+ /* PLL FOUT */ -+#ifdef THEAD_LIGHT_AON_CLK -+ clksLIGHT_AUDIO_PLL_FOUT3 = thead_light_clk_fixed_factor("audio_pll_fout3", "audio_pll_bypass", 1, 6); -+ clksLIGHT_SYS_PLL_FOUT4 = thead_light_clk_fixed_factor("sys_pll_fout4", "sys_pll_bypass", 1, 8); -+#endif -+#ifdef THEAD_LIGHT_DDR_CLK -+ clksLIGHT_DDR_PLL_FOUT4 = thead_light_clk_fixed_factor("ddr_pll_fout4", "ddr_pll_bypass", 1, 8); -+#endif -+ clksLIGHT_CPU_PLL0_FOUT4 = thead_light_clk_fixed_factor("cpu_pll0_fout4", "cpu_pll0_bypass", 1, 8); -+ clksLIGHT_CPU_PLL1_FOUT4 = thead_light_clk_fixed_factor("cpu_pll1_fout4", "cpu_pll1_bypass", 1, 8); -+ clksLIGHT_GMAC_PLL_FOUT1PH0 = thead_light_clk_fixed_factor("gmac_pll_fout1ph0", "gmac_pll_bypass", 1, 2); -+ clksLIGHT_GMAC_CORECLK = thead_light_clk_fixed_factor("gmac_coreclk", "gmac_pll_fout1ph0", 1, 1); -+ clksLIGHT_GMAC_PLL_FOUT4 = thead_light_clk_fixed_factor("gmac_pll_fout4", "gmac_pll_bypass", 1, 8); -+ clksLIGHT_VIDEO_PLL_FOUT4 = thead_light_clk_fixed_factor("video_pll_fout4", "video_pll_bypass", 1, 8); -+ clksLIGHT_GMAC_PLL_FOUTVCO_DIV5 = thead_light_clk_fixed_factor("gmac_pll_foutvco_div5", "gmac_pll_foutvco", 1, 5); -+ clksLIGHT_OSC_CLK_DIV24 = thead_light_clk_fixed_factor("osc_clk_div24", "osc_24m", 1, 24); -+ clksLIGHT_CHIP_DBG_CCLK = thead_light_clk_fixed_factor("chip_dbg_cclk", "osc_24m", 1, 1); -+ clksLIGHT_AXI_ACLK = thead_light_clk_fixed_factor("cpusys_axi_aclk", "cpu_pll0_bypass", 1, 2); -+ clksLIGHT_X2H_HCLK = thead_light_clk_fixed_factor("aonsys_x2h_hclk", "osc_24m", 1, 1); -+ clksLIGHT_EMMC_CLK_DIV = thead_light_clk_fixed_factor("emmc_clk_div", "video_pll_bypass", 1, 4); -+ clksLIGHT_EMMC0_OSC_CLK = thead_light_clk_fixed_factor("emmc0_osc_clk", "osc_24m", 1, 1); -+ clksLIGHT_EMMC1_OSC_CLK = thead_light_clk_fixed_factor("emmc1_osc_clk", "osc_24m", 1, 1); -+ clksLIGHT_PWM_CCLK = thead_light_clk_fixed_factor("pwm_cclk", "osc_24m", 1, 1); -+ clksLIGHT_USB3_PHY_REF_CLK = thead_light_clk_fixed_factor("usb3_phy_ref_clk", "osc_24m", 1, 1); -+ clksLIGHT_SPI_CLK = thead_light_clk_fixed_factor("spi_clk", "gmac_pll_foutvco_div5", 1, 1); -+ clksLIGHT_GPIO_DBCLK = thead_light_clk_fixed_factor("gpio_dbclk", "osc_32k", 1, 1); -+ -+#ifdef THEAD_LIGHT_AON_CLK -+ /* Aon sys mux tree */ -+ clksLIGHT_AONSYS_CLK_SWITCH_0 = thead_light_clk_mux_flags("aonsys_clk_switch_0", aon_base + 0x100, 4, 1, aonsys_clk_switch_0_sels, ARRAY_SIZE(aonsys_clk_switch_0_sels), CLK_SET_RATE_PARENT); -+ clksLIGHT_AONSYS_CLK_SWITCH_1 = thead_light_clk_mux_flags("aonsys_clk_switch_1", aon_base + 0x100, 5, 1, aonsys_clk_switch_1_sels, ARRAY_SIZE(aonsys_clk_switch_1_sels), CLK_SET_RATE_PARENT); -+ -+ /* Aon sys div tree */ -+ clksLIGHT_AONSYS_CLK = thead_clk_light_divider("aonsys_clk", "aonsys_clk_switch_1", aon_base + 0x100, 0, 3, 3, MUX_TYPE_CDE, 0, 7); -+ clksLIGHT_SHARE_SRAM_CLK = thead_clk_light_divider("share_sram_clk", "sys_pll_foutvco", aon_base + 0x104, 0, 4, 4, MUX_TYPE_DIV, 3, 12); -+ -+ /* Aon sys gate tree */ -+ clksLIGHT_CLKGEN_RTC_PCLK = thead_clk_light_gate("rtc_pclk_en", "aonsys_clk", aon_base + 0x120, 0); -+ clksLIGHT_CLKGEN_AOGPIO_PCLK = thead_clk_light_gate("aogpio_pclk_en", "aonsys_clk", aon_base + 0x120, 1); -+ clksLIGHT_CLKGEN_AOI2C_PCLK = thead_clk_light_gate("aoi2c_pclk_en", "aonsys_clk", aon_base + 0x120, 2); -+ clksLIGHT_CLKGEN_PVTC_PCLK = thead_clk_light_gate("pvtc_pclk_en", "aonsys_clk", aon_base + 0x120, 3); -+ clksLIGHT_CLKGEN_SRAM_AXI_ACLK = thead_clk_light_gate("share_sram_clk_en", "aonsys_clk", aon_base + 0x120, 4); -+ clksLIGHT_CLKGEN_AOPAD_PCLK = thead_clk_light_gate("aopad_pclk_en", "aonsys_clk", aon_base + 0x120, 5); -+ clksLIGHT_CLKGEN_AOAPB_HCLK = thead_clk_light_gate("aoapb_hclk_en", "aonsys_clk", aon_base + 0x120, 6); -+ clksLIGHT_CLKGEN_AOSRAM_HCLK = thead_clk_light_gate("aosram_hclk_en", "aonsys_clk", aon_base + 0x120, 7); -+ clksLIGHT_CLKGEN_AOAHB_HCLK = thead_clk_light_gate("aoahb_hclk_en", "aonsys_clk", aon_base + 0x120, 8); -+ clksLIGHT_CLKGEN_AOGPIO_DBCLK = thead_clk_light_gate("aogpio_dbclk_en", "aonsys_clk", aon_base + 0x120, 9); -+ clksLIGHT_CLKGEN_AOTIMER_PCLK = thead_clk_light_gate("aotimer_pclk_en", "aonsys_clk", aon_base + 0x120, 10); -+ clksLIGHT_CLKGEN_AOTIMER_CCLK = thead_clk_light_gate("aotimer_cclk_en", "aonsys_clk", aon_base + 0x120, 11); -+ clksLIGHT_CLKGEN_CPU2RAM_X2X_ACLK_S = thead_clk_light_gate("apsys_clk_en", "aonsys_clk", aon_base + 0x130, 0); -+#endif -+ -+ /* AP sys mux tree */ -+ clksLIGHT_C910_CCLK_I0 = thead_light_clk_mux_flags("c910_cclk_i0", ap_base + 0x100, 1, 1, c910_cclk_i0_sels, ARRAY_SIZE(c910_cclk_i0_sels), CLK_SET_RATE_PARENT); -+ clksLIGHT_C910_CCLK = thead_light_clk_mux_flags("c910_cclk", ap_base + 0x100, 0, 1, c910_cclk_sels, ARRAY_SIZE(c910_cclk_sels), CLK_SET_RATE_PARENT); -+ clksLIGHT_CPUSYS_AHB_HCLK = thead_light_clk_mux_flags("cpusys_ahb_hclk", ap_base + 0x120, 5, 1, cpusys_ahb_hclk_sel, ARRAY_SIZE(cpusys_ahb_hclk_sel), CLK_SET_RATE_PARENT); -+ clksLIGHT_CPUSYS_CFG_AXI_ACLK = thead_light_clk_mux_flags("cpusys_cfg_axi_aclk", ap_base + 0x138, 5, 1, cpusys_cfg_axi_aclk_sel, ARRAY_SIZE(cpusys_cfg_axi_aclk_sel), CLK_SET_RATE_PARENT); -+ clksLIGHT_PERISYS_AHB_HCLK = thead_light_clk_mux_flags("perisys_ahb_hclk", ap_base + 0x40, 5, 1, perisys_ahb_hclk_sel, ARRAY_SIZE(perisys_ahb_hclk_sel), CLK_SET_RATE_PARENT); -+ clksLIGHT_CLK_OUT_1 = thead_light_clk_mux_flags("clk_out_1", ap_base + 0x1b4, 4, 1, clk_out_1_sel, ARRAY_SIZE(clk_out_1_sel), CLK_SET_RATE_PARENT); -+ clksLIGHT_CLK_OUT_2 = thead_light_clk_mux_flags("clk_out_2", ap_base + 0x1b8, 4, 1, clk_out_2_sel, ARRAY_SIZE(clk_out_2_sel), CLK_SET_RATE_PARENT); -+ clksLIGHT_CLK_OUT_3 = thead_light_clk_mux_flags("clk_out_3", ap_base + 0x1bc, 4, 1, clk_out_3_sel, ARRAY_SIZE(clk_out_3_sel), CLK_SET_RATE_PARENT); -+ clksLIGHT_CLK_OUT_4 = thead_light_clk_mux_flags("clk_out_4", ap_base + 0x1c0, 4, 1, clk_out_4_sel, ARRAY_SIZE(clk_out_4_sel), CLK_SET_RATE_PARENT); -+ -+ /* AP sys div tree */ -+ clksLIGHT_CPUSYS_AHB_HCLK_DIV = thead_clk_light_divider("cpusys_ahb_hclk_div", "gmac_pll_fout1ph0", ap_base + 0x120, 0, 4, 4, MUX_TYPE_DIV, 2, 8); -+ clksLIGHT_APB3_CPUSYS_PCLK = thead_clk_light_divider("apb3_cpusys_pclk", "cpusys_ahb_hclk", ap_base + 0x130, 0, 3, 3, MUX_TYPE_CDE, 1, 7); -+ clksLIGHT_CPUSYS_SUB_AXI_ACLK = thead_clk_light_divider("cpusys_sub_axi_aclk", "gmac_pll_bypass", ap_base + 0x134, 0, 4, 4, MUX_TYPE_DIV, 2, 8); -+ clksLIGHT_CPUSYS_CFG_AXI_ACLK_DIV = thead_clk_light_divider("cpusys_cfg_axi_aclk_div", "gmac_pll_bypass", ap_base + 0x138, 0, 4, 4, MUX_TYPE_DIV, 8, 15); -+ clksLIGHT_TEESYS_HCLK = thead_clk_light_divider("teesys_hclk", "gmac_pll_fout1ph0", ap_base + 0x154, 0, 2, 2, MUX_TYPE_DIV, 2, 3); -+ clksLIGHT_DMAC_1_CLK = thead_clk_light_divider("dmac_1_clk", "video_pll_bypass", ap_base + 0x158, 0, 2, 2, MUX_TYPE_CDE, 0, 7); -+ clksLIGHT_DMAC_2_CLK = thead_clk_light_divider("dmac_2_clk", "video_pll_bypass", ap_base + 0x16c, 0, 2, 2, MUX_TYPE_CDE, 0, 7); -+ clksLIGHT_DMAC_3_CLK = thead_clk_light_divider("dmac_3_clk", "gmac_pll_bypass", ap_base + 0x160, 0, 2, 2, MUX_TYPE_CDE, 0, 7); -+ clksLIGHT_AXI_PORT4_CLK = thead_clk_light_divider("axi_port4_clk", "video_pll_bypass", ap_base + 0x164, 0, 2, 2, MUX_TYPE_CDE, 0, 7); -+ clksLIGHT_PERISYS_AHB_HCLK_DIV = thead_clk_light_divider("perisys_ahb_hclk_div", "gmac_pll_fout1ph0", ap_base + 0x140, 0, 4, 4, MUX_TYPE_DIV, 2, 8); -+ clksLIGHT_PERISYS_APB_PCLK = thead_clk_light_divider("perisys_apb_pclk", "perisys_ahb_hclk", ap_base + 0x150, 0, 3, 3, MUX_TYPE_CDE, 3, 7); -+ clksLIGHT_CLK_OUT_1_DIV = thead_clk_light_divider("clk_out_1_div", "osc_24m", ap_base + 0x1b4, 0, 3, 3, MUX_TYPE_DIV, 2, 7); -+ clksLIGHT_CLK_OUT_2_DIV = thead_clk_light_divider("clk_out_2_div", "osc_24m", ap_base + 0x1b8, 0, 3, 3, MUX_TYPE_DIV, 2, 7); -+ clksLIGHT_CLK_OUT_3_DIV = thead_clk_light_divider("clk_out_3_div", "osc_24m", ap_base + 0x1bc, 0, 3, 3, MUX_TYPE_DIV, 2, 7); -+ clksLIGHT_CLK_OUT_4_DIV = thead_clk_light_divider("clk_out_4_div", "osc_24m", ap_base + 0x1c0, 0, 3, 3, MUX_TYPE_DIV, 2, 7); -+ -+ /* AP sys gate tree */ -+ clksLIGHT_CLKGEN_PERISYS_AXI_ACLK = thead_clk_light_gate("clkgen_perisys_axi_aclk", "perisys_ahb_hclk", ap_base + 0x200, 31); -+ clksLIGHT_CLKGEN_PERISYS_AHB_HCLK = thead_clk_light_gate("clkgen_perisys_ahb_hclk", "perisys_ahb_hclk", ap_base + 0x200, 30); -+ clksLIGHT_CLKGEN_PERISYS_APB1_HCLK = thead_clk_light_gate("clkgen_perisys_apb1_hclk", "perisys_ahb_hclk", ap_base + 0x200, 29); -+ clksLIGHT_CLKGEN_PERISYS_APB2_HCLK = thead_clk_light_gate("clkgen_perisys_apb2_hclk", "perisys_ahb_hclk", ap_base + 0x200, 28); -+ clksLIGHT_CLKGEN_USB3_DRD_PHY_REF_CLK = thead_clk_light_gate("clkgen_usb3_drd_phy_ref_clk", "usb3_phy_ref_clk", ap_base + 0x200, 27); -+ clksLIGHT_CLKGEN_USB3_DRD_CTRL_REF_CLK = thead_clk_light_gate("clkgen_usb3_drd_ctrl_ref_clk", "usb3_ctrl_ref_clk", ap_base + 0x200, 26); -+ clksLIGHT_CLKGEN_USB3_DRD_SPDCLK = thead_clk_light_gate("clkgen_usb3_drd_spdclk", "osc_clk_div24", ap_base + 0x200, 25); -+ clksLIGHT_CLKGEN_EMMC1_X2X_ACLK = thead_clk_light_gate("clkgen_emmc1_x2x_aclk", "perisys_ahb_hclk", ap_base + 0x200, 23); -+ clksLIGHT_CLKGEN_EMMC0_X2X_ACLK = thead_clk_light_gate("clkgen_emmc0_x2x_aclk", "perisys_ahb_hclk", ap_base + 0x200, 22); -+ clksLIGHT_CLKGEN_UART0_PCLK = thead_clk_light_gate("clkgen_uart0_pclk", "perisys_apb_pclk", ap_base + 0x200, 14); -+ clksLIGHT_CLKGEN_UART1_PCLK = thead_clk_light_gate("clkgen_uart1_pclk", "perisys_apb_pclk", ap_base + 0x200, 13); -+ clksLIGHT_CLKGEN_UART2_PCLK = thead_clk_light_gate("clkgen_uart2_pclk", "perisys_apb_pclk", ap_base + 0x200, 12); -+ clksLIGHT_CLKGEN_UART3_PCLK = thead_clk_light_gate("clkgen_uart3_pclk", "perisys_apb_pclk", ap_base + 0x200, 11); -+ clksLIGHT_CLKGEN_UART4_PCLK = thead_clk_light_gate("clkgen_uart4_pclk", "perisys_apb_pclk", ap_base + 0x200, 10); -+ clksLIGHT_CLKGEN_UART5_PCLK = thead_clk_light_gate("clkgen_uart5_pclk", "perisys_apb_pclk", ap_base + 0x200, 9); -+ clksLIGHT_CLKGEN_I2C0_IC_CLK = thead_clk_light_gate("clkgen_i2c0_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 5); -+ clksLIGHT_CLKGEN_I2C1_IC_CLK = thead_clk_light_gate("clkgen_i2c1_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 4); -+ clksLIGHT_CLKGEN_I2C2_IC_CLK = thead_clk_light_gate("clkgen_i2c2_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 3); -+ clksLIGHT_CLKGEN_I2C3_IC_CLK = thead_clk_light_gate("clkgen_i2c3_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 2); -+ clksLIGHT_CLKGEN_I2C4_IC_CLK = thead_clk_light_gate("clkgen_i2c4_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 1); -+ clksLIGHT_CLKGEN_I2C5_IC_CLK = thead_clk_light_gate("clkgen_i2c5_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 0); -+ -+ clksLIGHT_CLKGEN_AXI_DUMMY_SLV_4_ACLK = thead_clk_light_gate("clkgen_axi_dummy_slv_4_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 28); -+ clksLIGHT_CLKGEN_AXI_DUMMY_SLV_3_ACLK = thead_clk_light_gate("clkgen_axi_dummy_slv_3_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 27); -+ clksLIGHT_CLKGEN_AXI_DUMMY_SLV_2_ACLK = thead_clk_light_gate("clkgen_axi_dummy_slv_2_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 26); -+ clksLIGHT_CLKGEN_AXI_DUMMY_SLV_1_ACLK = thead_clk_light_gate("clkgen_axi_dummy_slv_1_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 25); -+ clksLIGHT_CLKGEN_APB_CPU2FG_HCLK = thead_clk_light_gate("clkgen_apb_cpu2cfg_hclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 24); -+ clksLIGHT_CLKGEN_CPU2RAM_X2X_ACLK_M = thead_clk_light_gate("clkgen_cpu2ram_x2x_aclk_m", "cpusys_axi_aclk", ap_base + 0x204, 21); -+ clksLIGHT_CLKGEN_AXI4_CPUSYS2_ACLK = thead_clk_light_gate("clkgen_axi4_cpusys2_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 20); -+ clksLIGHT_CLKGEN_X2X_CPUSYS_ACLK_M = thead_clk_light_gate("clkgen_x2x_cpusys_aclk_m", "cpusys_sub_axi_aclk", ap_base + 0x204, 19); -+ clksLIGHT_CLKGEN_CHIP_DBG_ACLK = thead_clk_light_gate("clkgen_chip_dbg_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 18); -+ clksLIGHT_CLKGEN_AXI4_CFG_BUS_ACLK = thead_clk_light_gate("clkgen_axi4_cfg_bus_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 17); -+ clksLIGHT_CLKGEN_AHB2_CPUSYS_HCLK = thead_clk_light_gate("clkgen_ahb2_cpusys_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 11); -+ clksLIGHT_CLKGEN_APB3_CPUSYS_HCLK = thead_clk_light_gate("clkgen_apb3_cpusys_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 10); -+ clksLIGHT_CLKGEN_C910_BROM_HCLK = thead_clk_light_gate("clkgen_c910_brom_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 9); -+ clksLIGHT_CLKGEN_MBOX0_PCLK = thead_clk_light_gate("clkgen_mbox0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 7); -+ clksLIGHT_CLKGEN_MBOX1_PCLK = thead_clk_light_gate("clkgen_mbox1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 6); -+ clksLIGHT_CLKGEN_MBOX2_PCLK = thead_clk_light_gate("clkgen_mbox2_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 5); -+ clksLIGHT_CLKGEN_MBOX3_PCLK = thead_clk_light_gate("clkgen_mbox3_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 4); -+ clksLIGHT_CLKGEN_WDT0_PCLK = thead_clk_light_gate("clkgen_wdt0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 3); -+ clksLIGHT_CLKGEN_WDT1_PCLK = thead_clk_light_gate("clkgen_wdt1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 2); -+ -+ clksLIGHT_CLKGEN_TRNG_RB_HCLK = thead_clk_light_gate("clkgen_trng_rb_hclk", "teesys_hclk", ap_base + 0x208, 19); -+ clksLIGHT_CLKGEN_ADC_PCLK = thead_clk_light_gate("clkgen_adc_pclk", "perisys_apb_pclk", ap_base + 0x208, 18); -+ clksLIGHT_CLKGEN_AXI_ACLK_4 = thead_clk_light_gate("axi_aclk_4", "axi_port4_clk", ap_base + 0x208, 17); -+ clksLIGHT_CLKGEN_AXI_ACLK_3 = thead_clk_light_gate("axi_aclk_3", "dmac_3_clk", ap_base + 0x208, 16); -+ clksLIGHT_CLKGEN_AXI_ACLK_2 = thead_clk_light_gate("axi_aclk_2", "dmac_2_clk", ap_base + 0x208, 15); -+ clksLIGHT_CLKGEN_AXI_ACLK_1 = thead_clk_light_gate("axi_aclk_1", "dmac_1_clk", ap_base + 0x208, 14); -+ clksLIGHT_CLKGEN_AXI_ACLK_0 = thead_clk_light_gate("axi_aclk_0", "cpusys_axi_aclk", ap_base + 0x208, 13); -+ clksLIGHT_CLKGEN_SRAM_AXI_PCLK = thead_clk_light_gate("clkgen_sram_axi_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 9); -+ clksLIGHT_CLKGEN_AHB2_TEESYS_HCLK = thead_clk_light_gate("clkgen_ahb2_teesys_hclk", "teesys_hclk", ap_base + 0x208, 8); -+ clksLIGHT_CLKGEN_EFUSE_MPW_PCLK = thead_clk_light_gate("clkgen_efuse_mpw_pclk", "perisys_apb_pclk", ap_base + 0x208, 7); -+ clksLIGHT_CLKGEN_CLK_OUT_4_CLK = thead_clk_light_gate("clkgen_clk_out_4_clk", "clk_out_4", ap_base + 0x208, 6); -+ clksLIGHT_CLKGEN_CLK_OUT_3_CLK = thead_clk_light_gate("clkgen_clk_out_3_clk", "clk_out_3", ap_base + 0x208, 5); -+ clksLIGHT_CLKGEN_CLK_OUT_2_CLK = thead_clk_light_gate("clkgen_clk_out_2_clk", "clk_out_2", ap_base + 0x208, 4); -+ clksLIGHT_CLKGEN_CLK_OUT_1_CLK = thead_clk_light_gate("clkgen_clk_out_1_clk", "clk_out_1", ap_base + 0x208, 3); -+ clksLIGHT_CLKGEN_DDR_APB_PCLK = thead_clk_light_gate("clkgen_ddr_apb_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 2); -+ clksLIGHT_CLKGEN_PADCTRL_APSYS_PCLK = thead_clk_light_gate("clkgen_padctrl_apsys_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 1); -+ clksLIGHT_CLKGEN_CHIP_DBG_CCLK = thead_clk_light_gate("clkgen_chip_dbg_cclk", "chip_dbg_cclk", ap_base + 0x208, 0); -+ -+ /* register AP shared gate */ -+ clksLIGHT_CLKGEN_CPU2CFG_X2X_ACLK_M = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2x_aclk_m", "cpusys_axi_aclk", ap_base + 0x204, 22, &share_cnt_cpu2cfg_x2x_clk_en); -+ clksLIGHT_CLKGEN_CPU2CFG_X2X_ACLK_S = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2x_aclk_s", "cpusys_cfg_axi_aclk", ap_base + 0x204, 22, &share_cnt_cpu2cfg_x2x_clk_en); -+ clksLIGHT_CLKGEN_CPU2PERI_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_mhclk", "perisys_ahb_hclk", ap_base + 0x204, 12, &share_cnt_cpu2peri_x2h_clk_en); -+ clksLIGHT_CLKGEN_CPU2CFG_X2H_ACLK_S = thead_clk_light_gate_shared("clkgen_cpu2peri_x2h_aclk", "cpusys_axi_aclk", ap_base + 0x204, 12, &share_cnt_cpu2peri_x2h_clk_en); -+ clksLIGHT_CLKGEN_AON2CPU_A2X_ACLK = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 23, &share_cnt_aon2cpu_a2x_clk_en); -+ clksLIGHT_CLKGEN_AON2CPU_A2X_HCLK = thead_clk_light_gate_shared("clkgen_aon2cpu_a2x_hclk", "aonsys_x2h_hclk", ap_base + 0x204, 23, &share_cnt_aon2cpu_a2x_clk_en); -+ clksLIGHT_CLKGEN_DMAC_ACLK = thead_clk_light_gate_shared("clkgen_dmac_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 8, &share_cnt_dmac_clk_en); -+ clksLIGHT_CLKGEN_DMAC_HCLK = thead_clk_light_gate_shared("clkgen_dmac_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 8, &share_cnt_dmac_clk_en); -+ clksLIGHT_CLKGEN_X2H_CPUSYS_ACLK = thead_clk_light_gate_shared("clkgen_x2h_cpusys_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 16, &share_cnt_x2h_cpusys_clk_en); -+ clksLIGHT_CLKGEN_X2H_CPUSYS_MHCLK = thead_clk_light_gate_shared("clkgen_x2h_cpusys_mhclk", "cpusys_ahb_hclk", ap_base + 0x204, 16, &share_cnt_x2h_cpusys_clk_en); -+ clksLIGHT_CLKGEN_CPU2TEE_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2tee_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 15, &share_cnt_cpu2tee_x2h_clk_en); -+ clksLIGHT_CLKGEN_CPU2TEE_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2tee_x2h_mhclk", "teesys_hclk", ap_base + 0x204, 15, &share_cnt_cpu2tee_x2h_clk_en); -+ clksLIGHT_CLKGEN_CPU2AON_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 14, &share_cnt_cpu2aon_x2h_clk_en); -+ clksLIGHT_CLKGEN_CPU2AON_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2aon_x2h_mhclk", "aonsys_x2h_hclk", ap_base + 0x204, 14, &share_cnt_cpu2aon_x2h_clk_en); -+ clksLIGHT_CLKGEN_CPU2CFG_X2H_ACLK = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2h_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 13, &share_cnt_cpu2cfg_x2h_clk_en); -+ clksLIGHT_CLKGEN_CPU2CFG_X2H_MHCLK = thead_clk_light_gate_shared("clkgen_cpu2cfg_x2h_mhclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 13, &share_cnt_cpu2cfg_x2h_clk_en); -+ clksLIGHT_CLKGEN_TIMER0_CCLK = thead_clk_light_gate_shared("clkgen_timer0_cclk", "apb3_cpusys_pclk", ap_base + 0x204, 1, &share_cnt_timer0_clk_en); -+ clksLIGHT_CLKGEN_TIMER0_PCLK = thead_clk_light_gate_shared("clkgen_timer0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 1, &share_cnt_timer0_clk_en); -+ clksLIGHT_CLKGEN_TIMER1_CCLK = thead_clk_light_gate_shared("clkgen_timer1_cclk", "apb3_cpusys_pclk", ap_base + 0x204, 0, &share_cnt_timer1_clk_en); -+ clksLIGHT_CLKGEN_TIMER1_PCLK = thead_clk_light_gate_shared("clkgen_timer1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 0, &share_cnt_timer1_clk_en); -+ clksLIGHT_CLKGEN_PERI2DDR_X2X_ACLK_M = thead_clk_light_gate_shared("clkgen_peri2ddr_x2x_aclk_m", "perisys_ahb_hclk", ap_base + 0x204, 29, &share_cnt_peri2ddr_x2x_clk_en); -+ clksLIGHT_CLKGEN_PERI2DDR_X2X_ACLK_S = thead_clk_light_gate_shared("clkgen_peri2ddr_x2x_aclk_s", "axi_port4_clk", ap_base + 0x204, 29, &share_cnt_peri2ddr_x2x_clk_en); -+ clksLIGHT_CLKGEN_USB3_DRD_ACLK = thead_clk_light_gate_shared("clkgen_usb3_drd_aclk", "perisys_ahb_hclk", ap_base + 0x200, 24, &share_cnt_usb3_drd_clk_en); -+ clksLIGHT_CLKGEN_USB3_DRD_PCLK = thead_clk_light_gate_shared("clkgen_usb3_drd_pclk", "perisys_apb_pclk", ap_base + 0x200, 24, &share_cnt_usb3_drd_clk_en); -+ clksLIGHT_CLKGEN_GMAC_HCLK = thead_clk_light_gate_shared("clkgen_gmac_hclk", "perisys_ahb_hclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); -+ clksLIGHT_CLKGEN_GMAC_ACLK = thead_clk_light_gate_shared("clkgen_gmac_aclk", "perisys_ahb_hclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); -+ clksLIGHT_CLKGEN_GMAC_PCLK = thead_clk_light_gate_shared("clkgen_gmac_pclk", "perisys_apb_pclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); -+ clksLIGHT_CLKGEN_GMAC_CCLK = thead_clk_light_gate_shared("clkgen_gmac_cclk", "gmac_coreclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); -+ clksLIGHT_CLKGEN_EMMC0_HCLK = thead_clk_light_gate_shared("clkgen_emmc0_hclk", "perisys_ahb_hclk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); -+ clksLIGHT_CLKGEN_EMMC0_ACLK = thead_clk_light_gate_shared("clkgen_emmc0_aclk", "perisys_ahb_hclk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); -+ clksLIGHT_CLKGEN_EMMC0_REF_CLK = thead_clk_light_gate_shared("clkgen_emmc0_ref_clk", "emmc_clk_div", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); -+ clksLIGHT_CLKGEN_EMMC0_OSC_CLK = thead_clk_light_gate_shared("clkgen_emmc0_osc_clk", "emmc0_osc_clk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); -+ clksLIGHT_CLKGEN_EMMC1_HCLK = thead_clk_light_gate_shared("clkgen_emmc1_hclk", "perisys_ahb_hclk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); -+ clksLIGHT_CLKGEN_EMMC1_ACLK = thead_clk_light_gate_shared("clkgen_emmc1_aclk", "perisys_ahb_hclk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); -+ clksLIGHT_CLKGEN_EMMC1_REF_CLK = thead_clk_light_gate_shared("clkgen_emmc1_ref_clk", "emmc_clk_div", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); -+ clksLIGHT_CLKGEN_EMMC1_OSC_CLK = thead_clk_light_gate_shared("clkgen_emmc1_osc_clk", "emmc1_osc_clk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); -+ clksLIGHT_CLKGEN_PWM_PCLK = thead_clk_light_gate_shared("clkgen_pwm_pclk", "perisys_ahb_hclk", ap_base + 0x200, 18, &share_cnt_pwm_clk_en); -+ clksLIGHT_CLKGEN_PWM_CCLK = thead_clk_light_gate_shared("clkgen_pwm_cclk", "pwm_cclk", ap_base + 0x200, 18, &share_cnt_pwm_clk_en); -+ clksLIGHT_CLKGEN_QSPI0_PCLK = thead_clk_light_gate_shared("clkgen_qspi0_pclk", "perisys_apb_pclk", ap_base + 0x200, 17, &share_cnt_qspi0_clk_en); -+ clksLIGHT_CLKGEN_QSPI0_SSI_CLK = thead_clk_light_gate_shared("clkgen_qspi0_ssi_clk", "spi_clk", ap_base + 0x200, 17, &share_cnt_qspi0_clk_en); -+ clksLIGHT_CLKGEN_QSPI1_PCLK = thead_clk_light_gate_shared("clkgen_qspi1_pclk", "perisys_apb_pclk", ap_base + 0x200, 16, &share_cnt_qspi1_clk_en); -+ clksLIGHT_CLKGEN_QSPI1_SSI_CLK = thead_clk_light_gate_shared("clkgen_qspi1_ssi_clk", "spi_clk", ap_base + 0x200, 16, &share_cnt_qspi0_clk_en); -+ clksLIGHT_CLKGEN_SPI_PCLK = thead_clk_light_gate_shared("clkgen_spi_pclk", "perisys_apb_pclk", ap_base + 0x200, 15, &share_cnt_spi_clk_en); -+ clksLIGHT_CLKGEN_SPI_SSI_CLK = thead_clk_light_gate_shared("clkgen_spi_ssi_clk", "spi_clk", ap_base + 0x200, 15, &share_cnt_spi_clk_en); -+ clksLIGHT_CLKGEN_GPIO0_PCLK = thead_clk_light_gate_shared("clkgen_gpio0_pclk", "perisys_apb_pclk", ap_base + 0x200, 8, &share_cnt_gpio0_clk_en); -+ clksLIGHT_CLKGEN_GPIO0_DBCLK = thead_clk_light_gate_shared("clkgen_gpio0_dbclk", "gpio_dbclk", ap_base + 0x200, 8, &share_cnt_gpio0_clk_en); -+ clksLIGHT_CLKGEN_GPIO1_PCLK = thead_clk_light_gate_shared("clkgen_gpio1_pclk", "perisys_apb_pclk", ap_base + 0x200, 7, &share_cnt_gpio1_clk_en); -+ clksLIGHT_CLKGEN_GPIO1_DBCLK = thead_clk_light_gate_shared("clkgen_gpio1_dbclk", "gpio_dbclk", ap_base + 0x200, 7, &share_cnt_gpio1_clk_en); -+ clksLIGHT_CLKGEN_GPIO2_PCLK = thead_clk_light_gate_shared("clkgen_gpio2_pclk", "perisys_apb_pclk", ap_base + 0x200, 6, &share_cnt_gpio2_clk_en); -+ clksLIGHT_CLKGEN_GPIO2_DBCLK = thead_clk_light_gate_shared("clkgen_gpio2_dbclk", "gpio_dbclk", ap_base + 0x200, 6, &share_cnt_gpio2_clk_en); -+ clksLIGHT_CLKGEN_DMAC_1_ACLK = thead_clk_light_gate_shared("clkgen_dmac_1_aclk", "dmac_1_clk", ap_base + 0x208, 12, &share_cnt_dmac_1_clk_en); -+ clksLIGHT_CLKGEN_DMAC_1_HCLK = thead_clk_light_gate_shared("clkgen_dmac_1_hclk", "teesys_hclk", ap_base + 0x208, 12, &share_cnt_dmac_1_clk_en); -+ clksLIGHT_CLKGEN_DMAC_2_ACLK = thead_clk_light_gate_shared("clkgen_dmac_2_aclk", "dmac_2_clk", ap_base + 0x208, 11, &share_cnt_dmac_2_clk_en); -+ clksLIGHT_CLKGEN_DMAC_2_HCLK = thead_clk_light_gate_shared("clkgen_dmac_2_hclk", "teesys_hclk", ap_base + 0x208, 11, &share_cnt_dmac_2_clk_en); -+ clksLIGHT_CLKGEN_DMAC_3_ACLK = thead_clk_light_gate_shared("clkgen_dmac_3_aclk", "dmac_3_clk", ap_base + 0x208, 10, &share_cnt_dmac_3_clk_en); -+ clksLIGHT_CLKGEN_DMAC_3_HCLK = thead_clk_light_gate_shared("clkgen_dmac_3_hclk", "teesys_hclk", ap_base + 0x208, 10, &share_cnt_dmac_3_clk_en); -+ -+ clk_data.clks = clks; -+ clk_data.clk_num = ARRAY_SIZE(clks); -+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); -+ -+ if (ret < 0) { -+ dev_err(dev, "failed to register clks for light\n"); -+ goto unregister_clks; -+ } -+ -+ /* HW defalut */ -+ clk_set_parent(clksLIGHT_C910_CCLK, clksLIGHT_CPU_PLL1_FOUTPOSTDIV); -+ -+ return 0; -+ -+unregister_clks: -+ thead_unregister_clocks(clks, ARRAY_SIZE(clks)); -+ return ret; -+} -+ -+static const struct of_device_id light_clk_of_match = { -+ { .compatible = "thead,light-mpw-clk" }, -+ { /* Sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, light_clk_of_match); -+ -+static struct platform_driver light_clk_driver = { -+ .probe = light_clocks_probe, -+ .driver = { -+ .name = "light-mpw-clk", -+ .of_match_table = of_match_ptr(light_clk_of_match), -+ }, -+}; -+ -+module_platform_driver(light_clk_driver); -+MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light MPW clock driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/clk/thead/clk.c b/drivers/clk/thead/clk.c -new file mode 100644 -index 000000000000..2e181a9fd180 ---- /dev/null -+++ b/drivers/clk/thead/clk.c -@@ -0,0 +1,739 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+#include <linux/clk.h> -+#include <linux/clk-provider.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/iopoll.h> -+#include <linux/of.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+ -+#include "clk.h" -+ -+#define LIGHT_PLL_CFG0 0x0 -+#define LIGHT_PLL_CFG1 0x04 -+#define LIGHT_PLL_CFG2 0x8 -+#define LIGHT_POSTDIV2_SHIFT 24 -+#define LIGHT_POSTDIV2_MASK GENMASK(26, 24) -+#define LIGHT_POSTDIV1_SHIFT 20 -+#define LIGHT_POSTDIV1_MASK GENMASK(22, 20) -+#define LIGHT_FBDIV_SHIFT 8 -+#define LIGHT_FBDIV_MASK GENMASK(19, 8) -+#define LIGHT_REFDIV_SHIFT 0 -+#define LIGHT_REFDIV_MASK GENMASK(5, 0) -+#define LIGHT_BYPASS_MASK BIT(30) -+#define LIGHT_RST_MASK BIT(29) -+#define LIGHT_DSMPD_MASK BIT(24) -+#define LIGHT_DACPD_MASK BIT(25) -+#define LIGHT_FRAC_MASK GENMASK(23, 0) -+#define LIGHT_FRAC_SHIFT 0 -+#define LIGHT_FRAC_DIV BIT(24) -+ -+#define LOCK_TIMEOUT_US 10000 -+ -+#define div_mask(d) ((1 << (d->width)) - 1) -+ -+DEFINE_SPINLOCK(thead_light_clk_lock); -+ -+enum light_pll_mode { -+ PLL_MODE_FRAC, -+ PLL_MODE_INT, -+}; -+ -+struct clk_lightpll { -+ struct clk_hw hw; -+ void __iomem *base; -+ enum light_pll_clktype clk_type; -+ enum light_pll_outtype out_type; -+ enum light_pll_mode pll_mode; -+ const struct light_pll_rate_table *rate_table; -+ int rate_count; -+ -+ u32 cfg0_reg_off; -+ u32 pll_sts_off; -+ int pll_lock_bit; -+ -+ /* Light MPW Aon/ddr pll define bypass:rst bits as: 31:30 -+ * but AP pll define bypass:rst bits as: 30:29 -+ * -+ * Light Fullmask align these register field define, all pll -+ * define bypss:rst bits as: 30:29 -+ */ -+ int pll_rst_bit; -+ int pll_bypass_bit; -+}; -+ -+struct clk_lightdiv { -+ struct clk_divider divider; -+ enum light_div_type div_type; -+ u16 min_div; -+ u16 max_div; -+ u8 sync_en; -+ const struct clk_ops *ops; -+}; -+ -+struct clk_lightgate { -+ struct clk_gate gate; -+ unsigned int *share_count; -+ const struct clk_ops *ops; -+}; -+ -+#define to_clk_lightpll(_hw) container_of(_hw, struct clk_lightpll, hw) -+ -+void thead_unregister_clocks(struct clk *clks, unsigned int count) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < count; i++) -+ clk_unregister(clksi); -+} -+ -+static void clk_light_pll_cfg_init(struct clk_lightpll *pll) -+{ -+ switch (pll->clk_type) { -+ case LIGHT_AUDIO_PLL: -+ pll->cfg0_reg_off = 0x0; -+ pll->pll_sts_off = 0x90; -+ pll->pll_lock_bit = BIT(0); -+ pll->pll_bypass_bit = BIT(31); -+ pll->pll_rst_bit = BIT(30); -+ pll->pll_mode = PLL_MODE_FRAC; -+ break; -+ case LIGHT_SYS_PLL: -+ pll->cfg0_reg_off = 0x10; -+ pll->pll_sts_off = 0x90; -+ pll->pll_lock_bit = BIT(1); -+ pll->pll_bypass_bit = BIT(31); -+ pll->pll_rst_bit = BIT(30); -+ pll->pll_mode = PLL_MODE_FRAC; -+ break; -+ case LIGHT_CPU_PLL0: -+ pll->cfg0_reg_off = 0x0; -+ pll->pll_sts_off = 0x80; -+ pll->pll_lock_bit = BIT(1); -+ pll->pll_bypass_bit = BIT(30); -+ pll->pll_rst_bit = BIT(29); -+ pll->pll_mode = PLL_MODE_INT; -+ break; -+ case LIGHT_CPU_PLL1: -+ pll->cfg0_reg_off = 0x10; -+ pll->pll_sts_off = 0x80; -+ pll->pll_lock_bit = BIT(4); -+ pll->pll_bypass_bit = BIT(30); -+ pll->pll_rst_bit = BIT(29); -+ pll->pll_mode = PLL_MODE_INT; -+ break; -+ case LIGHT_GMAC_PLL: -+ pll->cfg0_reg_off = 0x20; -+ pll->pll_sts_off = 0x80; -+ pll->pll_lock_bit = BIT(3); -+ pll->pll_bypass_bit = BIT(30); -+ pll->pll_rst_bit = BIT(29); -+ pll->pll_mode = PLL_MODE_INT; -+ break; -+ case LIGHT_VIDEO_PLL: -+ pll->cfg0_reg_off = 0x30; -+ pll->pll_sts_off = 0x80; -+ pll->pll_lock_bit = BIT(7); -+ pll->pll_bypass_bit = BIT(30); -+ pll->pll_rst_bit = BIT(29); -+ pll->pll_mode = PLL_MODE_INT; -+ break; -+ case LIGHT_DDR_PLL: -+ pll->cfg0_reg_off = 0x8; -+ pll->pll_sts_off = 0x18; -+ pll->pll_lock_bit = BIT(0); -+ pll->pll_bypass_bit = BIT(31); -+ pll->pll_rst_bit = BIT(30); -+ pll->pll_mode = PLL_MODE_INT; -+ break; -+ case LIGHT_DPU0_PLL: -+ pll->cfg0_reg_off = 0x40; -+ pll->pll_sts_off = 0x80; -+ pll->pll_lock_bit = BIT(8); -+ pll->pll_bypass_bit = BIT(30); -+ pll->pll_rst_bit = BIT(29); -+ pll->pll_mode = PLL_MODE_INT; -+ break; -+ case LIGHT_DPU1_PLL: -+ pll->cfg0_reg_off = 0x50; -+ pll->pll_sts_off = 0x80; -+ pll->pll_lock_bit = BIT(9); -+ pll->pll_bypass_bit = BIT(30); -+ pll->pll_rst_bit = BIT(29); -+ pll->pll_mode = PLL_MODE_INT; -+ break; -+ default: -+ pr_err("%s: Unknown pll type\n", __func__); -+ }; -+} -+ -+static int clk_light_pll_wait_lock(struct clk_lightpll *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_light_pll_prepare(struct clk_hw *hw) -+{ -+ struct clk_lightpll *pll = to_clk_lightpll(hw); -+ void __iomem *cfg1_off; -+ u32 val; -+ int ret; -+ -+ cfg1_off = pll->base + pll->cfg0_reg_off + LIGHT_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_light_pll_wait_lock(pll); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int clk_light_pll_is_prepared(struct clk_hw *hw) -+{ -+ struct clk_lightpll *pll = to_clk_lightpll(hw); -+ u32 val; -+ -+ val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); -+ -+ return (val & pll->pll_rst_bit) ? 0 : 1; -+} -+ -+static void clk_light_pll_unprepare(struct clk_hw *hw) -+{ -+ struct clk_lightpll *pll = to_clk_lightpll(hw); -+ u32 val; -+ -+ val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); -+ val |= pll->pll_rst_bit; -+ writel_relaxed(val, pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); -+} -+ -+static unsigned long clk_light_pll_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+#ifndef CONFIG_LIGHT_CLK_EMU -+ struct clk_lightpll *pll = to_clk_lightpll(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 + LIGHT_PLL_CFG1); -+ refdiv = (pll_cfg0 & LIGHT_REFDIV_MASK) >> LIGHT_REFDIV_SHIFT; -+ fbdiv = (pll_cfg0 & LIGHT_FBDIV_MASK) >> LIGHT_FBDIV_SHIFT; -+ postdiv1 = (pll_cfg0 & LIGHT_POSTDIV1_MASK) >> LIGHT_POSTDIV1_SHIFT; -+ postdiv2 = (pll_cfg0 & LIGHT_POSTDIV2_MASK) >> LIGHT_POSTDIV2_SHIFT; -+ frac = (pll_cfg1 & LIGHT_FRAC_MASK) >> LIGHT_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) / LIGHT_FRAC_DIV; -+ -+ fvco += (parent_rate * fbdiv); -+ do_div(fvco, refdiv); -+ -+ if (pll->out_type == LIGHT_PLL_DIV) -+ do_div(fvco, postdiv1 * postdiv2); -+ -+ return fvco; -+#else -+ -+ struct clk_lightpll *pll = to_clk_lightpll(hw); -+ const struct light_pll_rate_table *rate_table = pll->rate_table; -+ -+ /* return minimum supported value */ -+ if (pll->out_type == LIGHT_PLL_DIV) -+ return rate_table0.rate; -+ -+ return rate_table0.vco_rate; -+#endif -+} -+ -+static const struct light_pll_rate_table *light_get_pll_div_settings( -+ struct clk_lightpll *pll, unsigned long rate) -+{ -+ const struct light_pll_rate_table *rate_table = pll->rate_table; -+ int i; -+ -+ for (i = 0; i < pll->rate_count; i++) -+ if (rate == rate_tablei.rate) -+ return &rate_tablei; -+ -+ return NULL; -+} -+ -+static const struct light_pll_rate_table *light_get_pll_vco_settings( -+ struct clk_lightpll *pll, unsigned long rate) -+{ -+ const struct light_pll_rate_table *rate_table = pll->rate_table; -+ int i; -+ -+ for (i = 0; i < pll->rate_count; i++) -+ if (rate == rate_tablei.vco_rate) -+ return &rate_tablei; -+ -+ return NULL; -+} -+ -+static inline bool clk_light_pll_change(struct clk_lightpll *pll, -+ const struct light_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 + LIGHT_PLL_CFG1); -+ -+ refdiv_old = (cfg0 & LIGHT_REFDIV_MASK) >> LIGHT_REFDIV_SHIFT; -+ fbdiv_old = (cfg0 & LIGHT_FBDIV_MASK) >> LIGHT_FBDIV_SHIFT; -+ postdiv1_old = (cfg0 & LIGHT_POSTDIV1_MASK) >> LIGHT_POSTDIV1_SHIFT; -+ postdiv2_old = (cfg0 & LIGHT_POSTDIV2_MASK) >> LIGHT_POSTDIV2_SHIFT; -+ frac_old = (cfg1 & LIGHT_FRAC_MASK) >> LIGHT_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_light_pll_set_rate(struct clk_hw *hw, unsigned long drate, -+ unsigned long prate) -+{ -+ struct clk_lightpll *pll = to_clk_lightpll(hw); -+ const struct light_pll_rate_table *rate; -+ void __iomem *cfg1_off; -+ u32 tmp, div_val; -+ int ret; -+ -+ if (pll->out_type == LIGHT_PLL_VCO) { -+ rate = light_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 = light_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_light_pll_change(pll, rate)) -+ return 0; -+ -+ /* Enable RST */ -+ cfg1_off = pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1; -+ tmp = readl_relaxed(cfg1_off); -+ tmp |= pll->pll_rst_bit; -+ writel_relaxed(tmp, cfg1_off); -+ -+ div_val = (rate->refdiv << LIGHT_REFDIV_SHIFT) | -+ (rate->fbdiv << LIGHT_FBDIV_SHIFT) | -+ (rate->postdiv1 << LIGHT_POSTDIV1_SHIFT) | -+ (rate->postdiv2 << LIGHT_POSTDIV2_SHIFT); -+ writel_relaxed(div_val, pll->base + pll->cfg0_reg_off); -+ -+ if (pll->pll_mode == PLL_MODE_FRAC) { -+ tmp &= ~(LIGHT_FRAC_MASK << LIGHT_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_light_pll_wait_lock(pll); -+ if (ret) -+ return ret; -+ -+ /* HW requires 30us for pll stable */ -+ udelay(30); -+ -+ return 0; -+} -+ -+static long clk_light_pllvco_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct clk_lightpll *pll = to_clk_lightpll(hw); -+ const struct light_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_tablei.vco_rate; -+ -+ if (rate == now) { -+ return rate_tablei.vco_rate; -+ } else if (abs(now - rate) < abs(best - rate)) { -+ best = now; -+ best_i = i; -+ } -+ } -+ -+ /* return minimum supported value */ -+ return rate_tablebest_i.vco_rate; -+} -+ -+static long clk_light_plldiv_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct clk_lightpll *pll = to_clk_lightpll(hw); -+ const struct light_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_tablei.rate; -+ -+ if (rate == now) { -+ return rate_tablei.rate; -+ } else if (abs(now - rate) < abs(best - rate)) { -+ best = now; -+ best_i = i; -+ } -+ } -+ -+ /* return minimum supported value */ -+ return rate_tablebest_i.rate; -+} -+ -+static const struct clk_ops clk_light_pll_def_ops = { -+ .recalc_rate = clk_light_pll_recalc_rate, -+}; -+ -+static const struct clk_ops clk_light_pllvco_ops = { -+ .prepare = clk_light_pll_prepare, -+ .unprepare = clk_light_pll_unprepare, -+ .is_prepared = clk_light_pll_is_prepared, -+ .recalc_rate = clk_light_pll_recalc_rate, -+ .round_rate = clk_light_pllvco_round_rate, -+ .set_rate = clk_light_pll_set_rate, -+}; -+ -+static const struct clk_ops clk_light_plldiv_ops = { -+ .prepare = clk_light_pll_prepare, -+ .unprepare = clk_light_pll_unprepare, -+ .is_prepared = clk_light_pll_is_prepared, -+ .recalc_rate = clk_light_pll_recalc_rate, -+ .round_rate = clk_light_plldiv_round_rate, -+ .set_rate = clk_light_pll_set_rate, -+}; -+ -+struct clk *thead_light_pll(const char *name, const char *parent_name, -+ void __iomem *base, -+ const struct light_pll_clk *pll_clk) -+{ -+ struct clk_lightpll *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 LIGHT_PLL_VCO: -+ if (pll_clk->rate_table) -+ init.ops = &clk_light_pllvco_ops; -+ break; -+ case LIGHT_PLL_DIV: -+ if (pll_clk->rate_table) -+ init.ops = &clk_light_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_light_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; -+ -+ clk_light_pll_cfg_init(pll); -+ -+ val = readl_relaxed(pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); -+ val &= ~pll->pll_bypass_bit; -+ val |= LIGHT_DACPD_MASK; -+ val |= LIGHT_DSMPD_MASK; -+ if (pll->pll_mode == PLL_MODE_FRAC) { -+ val &= ~LIGHT_DSMPD_MASK; -+ val &= ~LIGHT_DACPD_MASK; -+ } -+ writel_relaxed(val, pll->base + pll->cfg0_reg_off + LIGHT_PLL_CFG1); -+ -+ clk = clk_register(NULL, &pll->hw); -+ if (IS_ERR(clk)) { -+ pr_err("%s: failed to register pll %s %lu\n", -+ __func__, name, PTR_ERR(clk)); -+ kfree(pll); -+ } -+ -+ return clk; -+} -+ -+static inline struct clk_lightdiv *to_clk_lightdiv(struct clk_hw *hw) -+{ -+ struct clk_divider *divider = to_clk_divider(hw); -+ -+ return container_of(divider, struct clk_lightdiv, divider); -+} -+ -+static unsigned long clk_lightdiv_recalc_rate(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct clk_lightdiv *light_div = to_clk_lightdiv(hw); -+ -+ return light_div->ops->recalc_rate(&light_div->divider.hw, parent_rate); -+} -+ -+static long clk_lightdiv_round_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long *prate) -+{ -+ struct clk_lightdiv *light_div = to_clk_lightdiv(hw); -+ -+ return light_div->ops->round_rate(&light_div->divider.hw, rate, prate); -+} -+ -+static int clk_lightdiv_set_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct clk_lightdiv *light_div = to_clk_lightdiv(hw); -+ struct clk_divider *div = to_clk_divider(hw); -+ unsigned int divider, value; -+ unsigned long flags = 0; -+ u32 val; -+ -+ divider = parent_rate / rate; -+ -+ /* DIV is zero based divider, but CDE is not */ -+ if (light_div->div_type == MUX_TYPE_DIV) -+ value = divider; -+ else -+ value = divider - 1; -+ -+ /* handle the div valid range */ -+ if (value > light_div->max_div) -+ value = light_div->max_div; -+ if (value < light_div->min_div) -+ value = light_div->min_div; -+ -+ spin_lock_irqsave(div->lock, flags); -+ -+ val = readl(div->reg); -+ val &= ~BIT(light_div->sync_en); -+ writel(val, div->reg); -+ -+ udelay(1); -+ -+ val &= ~(div_mask(div) << div->shift); -+ val |= value << div->shift; -+ writel(val, div->reg); -+ -+ udelay(1); -+ -+ val |= BIT(light_div->sync_en); -+ writel(val, div->reg); -+ -+ spin_unlock_irqrestore(div->lock, flags); -+ -+ return 0; -+} -+ -+static const struct clk_ops clk_lightdiv_ops = { -+ .recalc_rate = clk_lightdiv_recalc_rate, -+ .round_rate = clk_lightdiv_round_rate, -+ .set_rate = clk_lightdiv_set_rate, -+}; -+ -+struct clk *thead_clk_light_divider(const char *name, const char *parent, -+ void __iomem *reg, u8 shift, u8 width, -+ u8 sync, enum light_div_type div_type, -+ u16 min, u16 max) -+{ -+ struct clk_lightdiv *light_div; -+ struct clk_hw *hw; -+ struct clk_init_data init; -+ int ret; -+ -+ light_div = kzalloc(sizeof(*light_div), GFP_KERNEL); -+ if (!light_div) -+ return ERR_PTR(-ENOMEM); -+ -+ init.name = name; -+ init.ops = &clk_lightdiv_ops; -+ init.flags = CLK_SET_RATE_PARENT; -+ init.parent_names = parent ? &parent : NULL; -+ init.num_parents = parent ? 1 : 0; -+ -+ light_div->divider.reg = reg; -+ light_div->divider.shift = shift; -+ light_div->divider.width = width; -+ light_div->divider.lock = &thead_light_clk_lock; -+ light_div->divider.hw.init = &init; -+ light_div->ops = &clk_divider_ops; -+ light_div->sync_en = sync; -+ light_div->div_type = div_type; -+ if (light_div->div_type == MUX_TYPE_DIV) -+ light_div->divider.flags = CLK_DIVIDER_ONE_BASED; -+ light_div->min_div = min > ((1 << width) - 1) ? -+ ((1 << width) - 1) : min; -+ light_div->max_div = max > ((1 << width) - 1) ? -+ ((1 << width) - 1) : max; -+ -+ hw = &light_div->divider.hw; -+ -+ ret = clk_hw_register(NULL, hw); -+ if (ret) { -+ kfree(light_div); -+ return ERR_PTR(ret); -+ } -+ -+ return hw->clk; -+} -+ -+static inline struct clk_lightgate *to_clk_lightgate(struct clk_hw *hw) -+{ -+ struct clk_gate *gate = to_clk_gate(hw); -+ -+ return container_of(gate, struct clk_lightgate, gate); -+} -+ -+static int clk_light_gate_share_is_enabled(struct clk_hw *hw) -+{ -+ struct clk_lightgate *light_gate = to_clk_lightgate(hw); -+ -+ return light_gate->ops->is_enabled(hw); -+} -+ -+static int clk_light_gate_share_enable(struct clk_hw *hw) -+{ -+ struct clk_lightgate *light_gate = to_clk_lightgate(hw); -+ -+ if (light_gate->share_count && (*light_gate->share_count)++ > 0) { -+ pr_debug("%s,%dshare_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); -+ return 0; -+ } -+ -+ pr_debug("%s,%dshare_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); -+ -+ return light_gate->ops->enable(hw); -+} -+ -+static void clk_light_gate_share_disable(struct clk_hw *hw) -+{ -+ struct clk_lightgate *light_gate = to_clk_lightgate(hw); -+ -+ if (light_gate->share_count) { -+ if (WARN_ON(*light_gate->share_count == 0)) -+ return; -+ else if (--(*light_gate->share_count) > 0) { -+ pr_debug("%s,%dshare_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); -+ return; -+ } -+ } -+ -+ pr_debug("%s,%dshare_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); -+ -+ light_gate->ops->disable(hw); -+} -+ -+static void clk_light_gate_share_disable_unused(struct clk_hw *hw) -+{ -+ struct clk_lightgate *light_gate = to_clk_lightgate(hw); -+ -+ if (!light_gate->share_count || *light_gate->share_count == 0) -+ return light_gate->ops->disable(hw); -+} -+ -+static const struct clk_ops clk_lightgate_share_ops = { -+ .enable = clk_light_gate_share_enable, -+ .disable = clk_light_gate_share_disable, -+ .disable_unused = clk_light_gate_share_disable_unused, -+ .is_enabled = clk_light_gate_share_is_enabled, -+}; -+ -+struct clk *thead_clk_light_register_gate_shared(const char *name, const char *parent, -+ unsigned long flags, void __iomem *reg, -+ u8 shift, spinlock_t *lock, -+ unsigned int *share_count) -+{ -+ struct clk_lightgate *light_gate; -+ struct clk_hw *hw; -+ struct clk_init_data init; -+ int ret; -+ -+ light_gate = kzalloc(sizeof(*light_gate), GFP_KERNEL); -+ if (!light_gate) -+ return ERR_PTR(-ENOMEM); -+ -+ light_gate->gate.reg = reg; -+ light_gate->gate.bit_idx = shift; -+ light_gate->gate.flags = 0; -+ light_gate->gate.lock = lock; -+ light_gate->gate.hw.init = &init; -+ light_gate->ops = &clk_gate_ops; -+ light_gate->share_count = share_count; -+ -+ init.name = name; -+ init.ops = &clk_lightgate_share_ops; -+ init.flags = flags; -+ init.parent_names = parent ? &parent : NULL; -+ init.num_parents = parent ? 1 : 0; -+ -+ hw = &light_gate->gate.hw; -+ -+ ret = clk_hw_register(NULL, hw); -+ if (ret) { -+ kfree(light_gate); -+ return ERR_PTR(ret); -+ } -+ -+ return hw->clk; -+} -diff --git a/drivers/clk/thead/clk.h b/drivers/clk/thead/clk.h -new file mode 100644 -index 000000000000..cad975e8ede4 ---- /dev/null -+++ b/drivers/clk/thead/clk.h -@@ -0,0 +1,117 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef __MACH_THEAD_CLK_H -+#define __MACH_THEAD_CLK_H -+ -+#include <linux/spinlock.h> -+#include <linux/clk-provider.h> -+ -+extern spinlock_t thead_light_clk_lock; -+ -+#define LIGHT_PLL_RATE(_vco, _rate, _r, _b, _f, _p, _k) \ -+ { \ -+ .vco_rate = (_vco), \ -+ .rate = (_rate), \ -+ .refdiv = (_r), \ -+ .fbdiv = (_b), \ -+ .frac = (_f), \ -+ .postdiv1 = (_p), \ -+ .postdiv2 = (_k), \ -+ } -+ -+enum light_pll_outtype { -+ LIGHT_PLL_VCO, -+ LIGHT_PLL_DIV, -+}; -+ -+enum light_div_type { -+ MUX_TYPE_DIV, -+ MUX_TYPE_CDE, -+}; -+ -+enum light_pll_clktype { -+ LIGHT_AUDIO_PLL, -+ LIGHT_SYS_PLL, -+ LIGHT_CPU_PLL0, -+ LIGHT_CPU_PLL1, -+ LIGHT_GMAC_PLL, -+ LIGHT_VIDEO_PLL, -+ LIGHT_DDR_PLL, -+ LIGHT_DPU0_PLL, -+ LIGHT_DPU1_PLL, -+}; -+ -+struct light_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; -+}; -+ -+struct light_pll_clk { -+ enum light_pll_outtype out_type; -+ enum light_pll_clktype clk_type; -+ const struct light_pll_rate_table *rate_table; -+ int rate_count; -+ int flags; -+}; -+ -+static inline struct clk *thead_light_clk_fixed_factor(const char *name, -+ const char *parent, unsigned int mult, unsigned int div) -+{ -+ return clk_register_fixed_factor(NULL, name, parent, -+ CLK_SET_RATE_PARENT, mult, div); -+} -+ -+struct clk *thead_light_pll(const char *name, const char *parent_name, -+ void __iomem *base, -+ const struct light_pll_clk *pll_clk); -+ -+static inline struct clk *thead_clk_light_gate(const char *name, const char *parent, -+ void __iomem *reg, u8 shift) -+{ -+ return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg, -+ shift, 0, &thead_light_clk_lock); -+} -+ -+struct clk *thead_clk_light_register_gate_shared(const char *name, const char *parent, -+ unsigned long flags, void __iomem *reg, -+ u8 shift, spinlock_t *lock, -+ unsigned int *share_count); -+ -+struct clk *thead_clk_light_divider(const char *name, const char *parent, -+ void __iomem *reg, u8 shift, u8 width, -+ u8 sync, enum light_div_type div_type, -+ u16 min, u16 max); -+ -+void thead_unregister_clocks(struct clk *clks, unsigned int count); -+ -+static inline struct clk *thead_clk_fixed(const char *name, unsigned long rate) -+{ -+ return clk_register_fixed_rate(NULL, name, NULL, 0, rate); -+} -+ -+static inline struct clk *thead_clk_light_gate_shared(const char *name, const char *parent, -+ void __iomem *reg, u8 shift, -+ unsigned int *share_count) -+{ -+ return thead_clk_light_register_gate_shared(name, parent, CLK_SET_RATE_PARENT, reg, -+ shift, &thead_light_clk_lock, share_count); -+} -+ -+static inline struct clk *thead_light_clk_mux_flags(const char *name, -+ void __iomem *reg, u8 shift, u8 width, -+ const char * const *parents, int num_parents, -+ unsigned long flags) -+{ -+ return clk_register_mux(NULL, name, parents, num_parents, -+ flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0, -+ &thead_light_clk_lock); -+} -+#endif -diff --git a/drivers/clk/thead/gate/Makefile b/drivers/clk/thead/gate/Makefile -new file mode 100644 -index 000000000000..b0ad8b2011c0 ---- /dev/null -+++ b/drivers/clk/thead/gate/Makefile -@@ -0,0 +1,3 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+obj-$(CONFIG_CLK_LIGHT_FM) += thead-gate.o visys-gate.o vpsys-gate.o vosys-gate.o dspsys-gate.o -diff --git a/drivers/clk/thead/gate/clk-gate.h b/drivers/clk/thead/gate/clk-gate.h -new file mode 100644 -index 000000000000..ebb190374a0e ---- /dev/null -+++ b/drivers/clk/thead/gate/clk-gate.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef CLK_GATE_H -+#define CLK_GATE_H -+ -+#include <linux/clk-provider.h> -+#include <linux/mfd/syscon.h> -+ -+enum clk_gate_type { -+ GATE_NOT_SHARED, -+ GATE_SHARED, -+}; -+ -+struct thead_clk_gate { -+ struct clk_hw hw; -+ struct regmap *regmap; -+ u32 offset; -+ u8 bit; -+ bool shared; -+ u32 *share_count; -+}; -+ -+struct clk *thead_gate_clk_register(const char *name, -+ const char *parent_name, -+ struct regmap *regmap, -+ int offset, -+ u8 bit, -+ bool shared, -+ u32 *share_count, -+ struct device *dev); -+ -+#endif -diff --git a/drivers/clk/thead/gate/dspsys-gate.c b/drivers/clk/thead/gate/dspsys-gate.c -new file mode 100644 -index 000000000000..e68a5d4e6151 ---- /dev/null -+++ b/drivers/clk/thead/gate/dspsys-gate.c -@@ -0,0 +1,109 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#include <dt-bindings/clock/light-dspsys.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/mfd/syscon.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/types.h> -+#include "clk-gate.h" -+#include "../clk.h" -+ -+static struct clk *gatesLIGHT_CLKGEN_DSPSYS_CLK_END; -+static struct clk_onecell_data clk_gate_data; -+ -+static int light_dspsys_clk_probe(struct platform_device *pdev) -+{ -+ struct regmap *dspsys_regmap, *tee_dspsys_regmap; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ int ret; -+ -+ dspsys_regmap = syscon_regmap_lookup_by_phandle(np, "dspsys-regmap"); -+ if (IS_ERR(dspsys_regmap)) { -+ dev_err(&pdev->dev, "cannot find regmap for dsp system register\n"); -+ return PTR_ERR(dspsys_regmap); -+ } -+ -+ tee_dspsys_regmap = syscon_regmap_lookup_by_phandle(np, "tee-dspsys-regmap"); -+ if (IS_ERR(tee_dspsys_regmap)) { -+ dev_warn(&pdev->dev, "cannot find regmap for tee dsp system register\n"); -+ tee_dspsys_regmap = NULL; -+ } -+ -+ gatesCLKGEN_DSP0_PCLK = thead_gate_clk_register("clkgen_dsp0_pclk", NULL, dspsys_regmap, -+ 0x24, 0, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_DSP1_PCLK = thead_gate_clk_register("clkgen_dsp1_pclk", NULL, dspsys_regmap, -+ 0x24, 1, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_DSP1_CCLK = thead_gate_clk_register("clkgen_dsp1_cclk", NULL, dspsys_regmap, -+ 0x24, 2, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_DSP0_CCLK = thead_gate_clk_register("clkgen_dsp0_cclk", NULL, dspsys_regmap, -+ 0x24, 3, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_X2X_DSP2_ACLK_S = thead_gate_clk_register("clkgen_x2x_dsp2_aclk_s", NULL, dspsys_regmap, -+ 0x24, 4, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_X2X_DSP0_ACLK_S = thead_gate_clk_register("clkgen_x2x_dsp0_aclk_s", NULL, dspsys_regmap, -+ 0x24, 5, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_X2X_X4_DSPSLV_DSP1_ACLK_M = thead_gate_clk_register("clkgen_x2x_x4_dspslv_dsp1_aclk_m", -+ NULL, dspsys_regmap, 0x24, 6, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_X2X_X4_DSPSLV_DSP0_ACLK_M = thead_gate_clk_register("clkgen_x2x_x4_dspslv_dsp0_aclk_m", -+ NULL, dspsys_regmap, 0x24, 7, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_AXI4_DSPSYS_SLV_ACLK = thead_gate_clk_register("clkgen_axi4_dspsys_slv_aclk", NULL, dspsys_regmap, -+ 0x24, 20, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_AXI4_DSPSYS_SLV_PCLK = thead_gate_clk_register("clkgen_axi4_dspsys_slv_pclk", NULL, dspsys_regmap, -+ 0x24, 21, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_AXI4_DSPSYS_ACLK = thead_gate_clk_register("clkgen_axi4_dspsys_aclk", NULL, dspsys_regmap, -+ 0x24, 23, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_AXI4_DSPSYS_PCLK = thead_gate_clk_register("clkgen_axi4_dspsys_pclk", NULL, dspsys_regmap, -+ 0x24, 24, GATE_NOT_SHARED, NULL, dev); -+ if (tee_dspsys_regmap) { -+ gatesCLKGEN_IOPMP_DSP1_PCLK = thead_gate_clk_register("clkgen_iopmp_dsp1_pclk", NULL, tee_dspsys_regmap, -+ 0x24, 25, GATE_NOT_SHARED, NULL, dev); -+ gatesCLKGEN_IOPMP_DSP0_PCLK = thead_gate_clk_register("clkgen_iopmp_dsp0_pclk", NULL, tee_dspsys_regmap, -+ 0x24, 26, GATE_NOT_SHARED, NULL, dev); -+ } -+ -+ clk_gate_data.clks = gates; -+ clk_gate_data.clk_num = ARRAY_SIZE(gates); -+ -+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); -+ if (ret < 0) { -+ dev_err(dev, "failed to register gate clks for light dspsys\n"); -+ goto unregister_clks; -+ } -+ -+ dev_info(dev, "succeed to register dspsys gate clock provider\n"); -+ -+ return 0; -+ -+unregister_clks: -+ thead_unregister_clocks(gates, ARRAY_SIZE(gates)); -+ return ret; -+} -+ -+static const struct of_device_id dspsys_clk_gate_of_match = { -+ { .compatible = "thead,dspsys-gate-controller" }, -+ { /* sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, dspsys_clk_gate_of_match); -+ -+static struct platform_driver light_dspsys_clk_driver = { -+ .probe = light_dspsys_clk_probe, -+ .driver = { -+ .name = "dspsys-clk-gate-provider", -+ .of_match_table = of_match_ptr(dspsys_clk_gate_of_match), -+ }, -+}; -+ -+module_platform_driver(light_dspsys_clk_driver); -+MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light Fullmask dspsys clock gate provider"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/clk/thead/gate/thead-gate.c b/drivers/clk/thead/gate/thead-gate.c -new file mode 100644 -index 000000000000..372c11dee1b9 ---- /dev/null -+++ b/drivers/clk/thead/gate/thead-gate.c -@@ -0,0 +1,114 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/types.h> -+#include <linux/regmap.h> -+#include "clk-gate.h" -+ -+#define to_thead_clk_gate(_hw) container_of(_hw, struct thead_clk_gate, hw) -+ -+static int thead_clk_gate_is_enabled(struct clk_hw *hw) -+{ -+ struct thead_clk_gate *tcg = to_thead_clk_gate(hw); -+ u32 val; -+ -+ regmap_read(tcg->regmap, tcg->offset, &val); -+ -+ val &= BIT(tcg->bit); -+ -+ return val != 0; -+} -+ -+static void thead_clk_gate_disable(struct clk_hw *hw) -+{ -+ struct thead_clk_gate *tcg = to_thead_clk_gate(hw); -+ -+ if (!tcg->shared) -+ goto out; -+ -+ if (tcg->share_count) { -+ if (WARN_ON(*tcg->share_count == 0)) -+ return; -+ else if (--(*tcg->share_count) > 0) { -+ pr_info("%s,%dshare_count = %d\n", __func__, __LINE__, -+ (*tcg->share_count)); -+ return; -+ } -+ } -+ -+out: -+ regmap_update_bits(tcg->regmap, tcg->offset, -+ BIT(tcg->bit), 0); -+} -+ -+static int thead_clk_gate_enable(struct clk_hw *hw) -+{ -+ struct thead_clk_gate *tcg = to_thead_clk_gate(hw); -+ -+ if (!tcg->shared) -+ goto out; -+ -+ if (tcg->share_count && (*tcg->share_count)++ > 0) { -+ pr_info("%s,%dshare_count = %d\n", __func__, __LINE__, (*tcg->share_count)); -+ return 0; -+ } -+ -+out: -+ return regmap_update_bits(tcg->regmap, tcg->offset, -+ BIT(tcg->bit), BIT(tcg->bit)); -+} -+ -+const struct clk_ops thead_gate_clk_ops = { -+ .enable = thead_clk_gate_enable, -+ .disable = thead_clk_gate_disable, -+ .is_enabled = thead_clk_gate_is_enabled, -+}; -+ -+struct clk *thead_gate_clk_register(const char *name, -+ const char *parent_name, -+ struct regmap *regmap, -+ int offset, -+ u8 bit, -+ bool shared, -+ u32 *share_count, -+ struct device *dev) -+{ -+ struct thead_clk_gate *tcg; -+ struct clk *clk; -+ struct clk_init_data init = {}; -+ -+ tcg = kzalloc(sizeof(*tcg), GFP_KERNEL); -+ if (!tcg) -+ return ERR_PTR(-ENOMEM); -+ -+ tcg->regmap = regmap; -+ tcg->offset = offset; -+ tcg->bit = bit; -+ tcg->shared = shared; -+ tcg->share_count = share_count; -+ -+ init.name = name; -+ init.flags = CLK_SET_RATE_PARENT; -+ init.parent_names = parent_name ? &parent_name : NULL; -+ init.num_parents = parent_name ? 1 : 0; -+ init.ops = &thead_gate_clk_ops; -+ -+ tcg->hw.init = &init; -+ -+ clk = clk_register(dev, &tcg->hw); -+ if (IS_ERR(clk)) -+ kfree(tcg); -+ -+ return clk; -+} -diff --git a/drivers/clk/thead/gate/visys-gate.c b/drivers/clk/thead/gate/visys-gate.c -new file mode 100644 -index 000000000000..b023e42b8269 ---- /dev/null -+++ b/drivers/clk/thead/gate/visys-gate.c -@@ -0,0 +1,144 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#include <dt-bindings/clock/light-fm-ap-clock.h> -+#include <dt-bindings/clock/light-visys.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/types.h> -+#include "clk-gate.h" -+#include "../clk.h" -+ -+static struct clk *gatesLIGHT_CLKGEN_VISYS_CLK_END; -+static struct clk_onecell_data clk_gate_data; -+ -+static u32 share_cnt_isp0_hclk_en; -+static u32 share_cnt_isp0_aclk_en; -+ -+static int light_visys_clk_probe(struct platform_device *pdev) -+{ -+ struct regmap *visys_regmap; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ int ret; -+ -+ visys_regmap = syscon_regmap_lookup_by_phandle(np, "visys-regmap"); -+ if (IS_ERR(visys_regmap)) { -+ dev_err(&pdev->dev, "cannot find regmap for vi system register\n"); -+ return PTR_ERR(visys_regmap); -+ } -+ -+ /* we assume that the gate clock is a root clock */ -+ gatesLIGHT_CLKGEN_DW200_ACLK = thead_gate_clk_register("clkgen_dw200_aclk", NULL, -+ visys_regmap, 0xa0, 27, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_AXI4_VISYS1_ACLK = thead_gate_clk_register("clkgen_axi4_visys1_aclk", NULL, -+ visys_regmap, 0xa0, 26, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_AXI4_VISYS2_ACLK = thead_gate_clk_register("clkgen_axi4_visys2_aclk", NULL, -+ visys_regmap, 0xa0, 25, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_AXI4_VISYS3_ACLK = thead_gate_clk_register("clkgen_axi4_visys3_aclk", NULL, -+ visys_regmap, 0xa0, 24, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP_RY_ACLK = thead_gate_clk_register("clkgen_isp_ry_aclk", NULL, -+ visys_regmap, 0xa0, 22, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP_VENC_SHAKE_ACLK = thead_gate_clk_register("clkgen_isp_venc_shake_aclk", NULL, -+ visys_regmap, 0xa0, 30, GATE_NOT_SHARED, NULL, dev); -+ -+ gatesLIGHT_CLKGEN_VIPRE_ACLK = thead_gate_clk_register("clkgen_vipre_aclk", NULL, -+ visys_regmap, 0xa0, 31, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_DW200_HCLK = thead_gate_clk_register("clkgen_dw200_hclk", NULL, -+ visys_regmap, 0xa0, 13, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP_RY_HCLK = thead_gate_clk_register("clkgen_isp_ry_hclk", NULL, -+ visys_regmap, 0xa0, 12, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_MIPI_CSI0_PCLK = thead_gate_clk_register("clkgen_mipi_csi0_pclk", NULL, -+ visys_regmap, 0xa0, 18, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_MIPI_CSI1_PCLK = thead_gate_clk_register("clkgen_mipi_csi1_pclk", NULL, -+ visys_regmap, 0xa0, 17, GATE_NOT_SHARED, NULL, dev); -+ -+ gatesLIGHT_CLKGEN_MIPI_CSI2_PCLK = thead_gate_clk_register("clkgen_mipi_csi2_pclk", NULL, -+ visys_regmap, 0xa0, 16, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_VIPRE_PCLK = thead_gate_clk_register("clkgen_vipre_pclk", NULL, -+ visys_regmap, 0xa0, 15, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP_VENC_SHAKE_PCLK = thead_gate_clk_register("clkgen_isp_venc_shake_pclk", NULL, -+ visys_regmap, 0xa0, 29, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_MIPI_CSI0_PIXCLK = thead_gate_clk_register("clkgen_mipi_csi0_pixclk", NULL, -+ visys_regmap, 0xa0, 11, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_MIPI_CSI1_PIXCLK = thead_gate_clk_register("clkgen_mipi_csi1_pixclk", NULL, -+ visys_regmap, 0xa0, 10, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_MIPI_CSI2_PIXCLK = thead_gate_clk_register("clkgen_mipi_csi2_pixclk", NULL, -+ visys_regmap, 0xa0, 9, GATE_NOT_SHARED, NULL, dev); -+ -+ gatesLIGHT_CLKGEN_VIPRE_PIXELCLK = thead_gate_clk_register("clkgen_vipre_pixelclk", NULL, -+ visys_regmap, 0xa4, 23, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_MIPI_CSI0_CFG_CLK = thead_gate_clk_register("clkgen_mipi_csi0_cfg_clk", NULL, -+ visys_regmap, 0xa0, 8, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_MIPI_CSI1_CFG_CLK = thead_gate_clk_register("clkgen_mipi_csi1_cfg_clk", NULL, -+ visys_regmap, 0xa0, 6, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_MIPI_CSI2_CFG_CLK = thead_gate_clk_register("clkgen_mipi_csi2_cfg_clk", NULL, -+ visys_regmap, 0xa0, 7, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_DW200_CLK_VSE = thead_gate_clk_register("clkgen_dw200_clk_vse", NULL, -+ visys_regmap, 0xa0, 5, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_DW200_CLK_DWE = thead_gate_clk_register("clkgen_dw200_clk_dwe", NULL, -+ visys_regmap, 0xa0, 4, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP0_CLK = thead_gate_clk_register("clkgen_isp_clk_0", NULL, -+ visys_regmap, 0xa4, 31, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP1_CLK = thead_gate_clk_register("clkgen_isp_clk_1", NULL, -+ visys_regmap, 0xa4, 30, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP_RY_CCLK = thead_gate_clk_register("clkgen_isp_ry_cclk", NULL, -+ visys_regmap, 0xa0, 21, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP1_PIXELCLK = thead_gate_clk_register("clkgen_isp1_pixelclk", NULL, -+ visys_regmap, 0xa4, 28, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP0_PIXELCLK = thead_gate_clk_register("clkgen_isp0_pixelclk", NULL, -+ visys_regmap, 0xa4, 29, GATE_NOT_SHARED, NULL, dev); -+ gatesLIGHT_CLKGEN_ISP1_HCLK = thead_gate_clk_register("clkgen_isp1_hclk", NULL, -+ visys_regmap, 0xa0, 1, GATE_SHARED, &share_cnt_isp0_hclk_en, dev); -+ gatesLIGHT_CLKGEN_ISP0_HCLK = thead_gate_clk_register("clkgen_isp0_hclk", NULL, -+ visys_regmap, 0xa0, 1, GATE_SHARED, &share_cnt_isp0_hclk_en, dev); -+ gatesLIGHT_CLKGEN_ISP1_ACLK = thead_gate_clk_register("clkgen_isp1_aclk", NULL, -+ visys_regmap, 0xa0, 3, GATE_SHARED, &share_cnt_isp0_aclk_en, dev); -+ gatesLIGHT_CLKGEN_ISP0_ACLK = thead_gate_clk_register("clkgen_isp0_aclk", NULL, -+ visys_regmap, 0xa0, 3, GATE_SHARED, &share_cnt_isp0_aclk_en, dev); -+ -+ clk_gate_data.clks = gates; -+ clk_gate_data.clk_num = ARRAY_SIZE(gates); -+ -+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); -+ if (ret < 0) { -+ dev_err(dev, "failed to register gate clks for light visys\n"); -+ goto unregister_clks; -+ } -+ -+ dev_info(dev, "succeed to register visys gate clock provider\n"); -+ -+ return 0; -+ -+unregister_clks: -+ thead_unregister_clocks(gates, ARRAY_SIZE(gates)); -+ return ret; -+} -+ -+static const struct of_device_id visys_clk_gate_of_match = { -+ { .compatible = "thead,visys-gate-controller" }, -+ { /* sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, visys_clk_gate_of_match); -+ -+static struct platform_driver light_visys_clk_driver = { -+ .probe = light_visys_clk_probe, -+ .driver = { -+ .name = "visys-clk-gate-provider", -+ .of_match_table = of_match_ptr(visys_clk_gate_of_match), -+ }, -+}; -+ -+module_platform_driver(light_visys_clk_driver); -+MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light Fullmask visys clock gate provider"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/clk/thead/gate/vosys-gate.c b/drivers/clk/thead/gate/vosys-gate.c -new file mode 100644 -index 000000000000..e53ba1a3e763 ---- /dev/null -+++ b/drivers/clk/thead/gate/vosys-gate.c -@@ -0,0 +1,111 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#include <dt-bindings/clock/light-fm-ap-clock.h> -+#include <dt-bindings/clock/light-vosys.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/types.h> -+#include "../clk.h" -+ -+static struct clk *gatesLIGHT_CLKGEN_VOSYS_CLK_END; -+static struct clk_onecell_data clk_gate_data; -+ -+static int light_vosys_clk_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ void __iomem *gate_base; -+ int ret; -+ -+ gate_base = devm_platform_ioremap_resource(pdev, 0); -+ if (WARN_ON(IS_ERR(gate_base))) -+ return PTR_ERR(gate_base); -+ -+ /* we assume that the gate clock is a root clock */ -+ gatesLIGHT_CLKGEN_AXI4_VO_PCLK = thead_clk_light_gate("clkgen_axi4_vo_pclk", NULL, -+ gate_base + 0x50, 22); -+ gatesLIGHT_CLKGEN_IOPMP_VOSYS_DPU_PCLK = thead_clk_light_gate("clkgen_iopmp_dpu_pclk", NULL, -+ gate_base + 0x50, 23); -+ gatesLIGHT_CLKGEN_IOPMP_VOSYS_DPU1_PCLK = thead_clk_light_gate("clkgen_iopmp_dpu1_pclk", NULL, -+ gate_base + 0x50, 24); -+ gatesLIGHT_CLKGEN_IOPMP_VOSYS_GPU_PCLK = thead_clk_light_gate("clkgen_iopmp_gpu_pclk", NULL, -+ gate_base + 0x50, 25); -+ gatesLIGHT_CLKGEN_HDMI_PCLK = thead_clk_light_gate("clkgen_hdmi_pclk", NULL, gate_base + 0x50, 11); -+ gatesLIGHT_CLKGEN_MIPIDSI0_PCLK = thead_clk_light_gate("clkgen_mipidsi0_pclk", NULL, -+ gate_base + 0x50, 13); -+ gatesLIGHT_CLKGEN_MIPIDSI1_PCLK = thead_clk_light_gate("clkgen_mipidsi1_pclk", NULL, -+ gate_base + 0x50, 14); -+ gatesLIGHT_CLKGEN_AXI4_VO_ACLK = thead_clk_light_gate("clkgen_axi4_vo_aclk", NULL, -+ gate_base + 0x50, 0); -+ gatesLIGHT_CLKGEN_IOPMP_GPU_ACLK = thead_clk_light_gate("clkgen_iopmp_gpu_aclk", NULL, -+ gate_base + 0x50, 29); -+ gatesLIGHT_CLKGEN_IOPMP_DPU_ACLK = thead_clk_light_gate("clkgen_iopmp_dpu_aclk", NULL, -+ gate_base + 0x50, 28); -+ gatesLIGHT_CLKGEN_IOPMP_DPU1_ACLK = thead_clk_light_gate("clkgen_iopmp_dpu1_aclk", NULL, -+ gate_base + 0x50, 27); -+ gatesLIGHT_CLKGEN_X2H_DPU_ACLK = thead_clk_light_gate("clkgen_x2h_dpu_aclk", NULL, gate_base + 0x50, 21); -+ gatesLIGHT_CLKGEN_X2H_DPU1_ACLK = thead_clk_light_gate("clkgen_x2h_dpu1_aclk", NULL, gate_base + 0x50, 20); -+ gatesLIGHT_CLKGEN_MIPIDSI0_PIXCLK = thead_clk_light_gate("clkgen_mipidsi0_pixclk", NULL, gate_base + 0x50, 30); -+ gatesLIGHT_CLKGEN_HDMI_PIXCLK = thead_clk_light_gate("clkgen_hdmi_pixclk", NULL, gate_base + 0x54, 0); -+ gatesLIGHT_CLKGEN_MIPIDSI1_PIXCLK = thead_clk_light_gate("clkgen_mipidsi1_pixclk", NULL, gate_base + 0x50, 31); -+ gatesLIGHT_CLKGEN_HDMI_SFR_CLK = thead_clk_light_gate("clkgen_hdmi_sfr_clk", NULL, gate_base + 0x50, 10); -+ gatesLIGHT_CLKGEN_HDMI_CEC_CLK = thead_clk_light_gate("clkgen_hdmi_cec_cclk", NULL, gate_base + 0x50, 12); -+ gatesLIGHT_CLKGEN_HDMI_I2S_CLK = thead_clk_light_gate("clkgen_hdmi_i2s_clk", NULL, gate_base + 0x50, 19); -+ gatesLIGHT_CLKGEN_MIPIDSI0_CFG_CLK = thead_clk_light_gate("clkgen_mipidsi0_cfg_clk", NULL, gate_base + 0x50, 15); -+ gatesLIGHT_CLKGEN_MIPIDSI1_CFG_CLK = thead_clk_light_gate("clkgen_mipidsi1_cfg_clk", NULL, gate_base + 0x50, 16); -+ gatesLIGHT_CLKGEN_MIPIDSI0_REFCLK = thead_clk_light_gate("clkgen_mipidsi0_refclk", NULL, gate_base + 0x50, 17); -+ gatesLIGHT_CLKGEN_MIPIDSI1_REFCLK = thead_clk_light_gate("clkgen_mipidsi1_refclk", NULL, gate_base + 0x50, 18); -+ gatesLIGHT_CLKGEN_GPU_CORE_CLK = thead_clk_light_gate("clkgen_gpu_core_clk", NULL, gate_base + 0x50, 3); -+ gatesLIGHT_CLKGEN_GPU_CFG_ACLK = thead_clk_light_gate("clkgen_gpu_cfg_aclk", NULL, gate_base + 0x50, 4); -+ gatesLIGHT_CLKGEN_DPU_HCLK = thead_clk_light_gate("clkgen_dpu_hclk", NULL, gate_base + 0x50, 7); -+ gatesLIGHT_CLKGEN_DPU_ACLK = thead_clk_light_gate("clkgen_dpu_aclk", NULL, gate_base + 0x50, 8); -+ gatesLIGHT_CLKGEN_DPU_CCLK = thead_clk_light_gate("clkgen_dpu_cclk", NULL, gate_base + 0x50, 9); -+ gatesLIGHT_CLKGEN_DPU_PIXCLK0 = thead_clk_light_gate("clkgen_dpu_pixclk0", NULL, gate_base + 0x50, 5); -+ gatesLIGHT_CLKGEN_DPU_PIXCLK1 = thead_clk_light_gate("clkgen_dpu_pixclk1", NULL, gate_base + 0x50, 6); -+ -+ clk_gate_data.clks = gates; -+ clk_gate_data.clk_num = ARRAY_SIZE(gates); -+ -+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); -+ if (ret < 0) { -+ dev_err(dev, "failed to register gate clks for light vosys\n"); -+ goto unregister_clks; -+ } -+ -+ dev_info(dev, "succeed to register vosys gate clock provider\n"); -+ -+ return 0; -+ -+unregister_clks: -+ thead_unregister_clocks(gates, ARRAY_SIZE(gates)); -+ return ret; -+} -+ -+static const struct of_device_id vosys_clk_gate_of_match = { -+ { .compatible = "thead,vosys-gate-controller" }, -+ { /* sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, vosys_clk_gate_of_match); -+ -+static struct platform_driver light_vosys_clk_driver = { -+ .probe = light_vosys_clk_probe, -+ .driver = { -+ .name = "vosys-clk-gate-provider", -+ .of_match_table = of_match_ptr(vosys_clk_gate_of_match), -+ }, -+}; -+ -+module_platform_driver(light_vosys_clk_driver); -+MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light Fullmask vosys clock gate provider"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/clk/thead/gate/vpsys-gate.c b/drivers/clk/thead/gate/vpsys-gate.c -new file mode 100644 -index 000000000000..78613188da70 ---- /dev/null -+++ b/drivers/clk/thead/gate/vpsys-gate.c -@@ -0,0 +1,94 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#include <dt-bindings/clock/light-fm-ap-clock.h> -+#include <dt-bindings/clock/light-vpsys.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/types.h> -+#include "../clk.h" -+ -+static struct clk *gatesLIGHT_VPSYS_CLK_END; -+static struct clk_onecell_data clk_gate_data; -+ -+static u32 share_cnt_g2d_clk_en; -+static u32 share_cnt_fce_clk_en; -+ -+static int light_vpsys_clk_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ void __iomem *gate_base; -+ int ret; -+ -+ gate_base = devm_platform_ioremap_resource(pdev, 0); -+ if (WARN_ON(IS_ERR(gate_base))) -+ return PTR_ERR(gate_base); -+ -+ /* we assume that the gate clock is a root clock */ -+ gatesLIGHT_VPSYS_G2D_PCLK = thead_clk_light_gate_shared("clkgen_vpsys_g2d_pclk", NULL, -+ gate_base + 0x20, 3, &share_cnt_g2d_clk_en); -+ gatesLIGHT_VPSYS_G2D_ACLK = thead_clk_light_gate_shared("clkgen_vpsys_g2d_aclk", NULL, -+ gate_base + 0x20, 3, &share_cnt_g2d_clk_en); -+ gatesLIGHT_VPSYS_G2D_CCLK = thead_clk_light_gate_shared("clkgen_vpsys_g2d_cclk", NULL, -+ gate_base + 0x20, 3, &share_cnt_g2d_clk_en); -+ -+ -+ gatesLIGHT_VPSYS_FCE_PCLK = thead_clk_light_gate_shared("clkgen_vpsys_fce_pclk", NULL, -+ gate_base + 0x20, 2, &share_cnt_fce_clk_en); -+ gatesLIGHT_VPSYS_FCE_ACLK = thead_clk_light_gate_shared("clkgen_vpsys_fce_aclk", NULL, -+ gate_base + 0x20, 2, &share_cnt_fce_clk_en); -+ -+ gatesLIGHT_VPSYS_VDEC_ACLK = thead_clk_light_gate("clkgen_vdec_aclk", NULL, gate_base + 0x20, 4); -+ gatesLIGHT_VPSYS_VDEC_CCLK = thead_clk_light_gate("clkgen_vdec_cclk", NULL, gate_base + 0x20, 5); -+ gatesLIGHT_VPSYS_VDEC_PCLK = thead_clk_light_gate("clkgen_vdec_pclk", NULL, gate_base + 0x20, 6); -+ -+ gatesLIGHT_VPSYS_VENC_CCLK = thead_clk_light_gate("clkgen_venc_cclk", NULL, gate_base + 0x20, 8); -+ gatesLIGHT_VPSYS_VENC_PCLK = thead_clk_light_gate("clkgen_venc_pclk", NULL, gate_base + 0x20, 9); -+ gatesLIGHT_VPSYS_VENC_ACLK = thead_clk_light_gate("clkgen_venc_aclk", NULL, gate_base + 0x20, 7); -+ -+ clk_gate_data.clks = gates; -+ clk_gate_data.clk_num = ARRAY_SIZE(gates); -+ -+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_gate_data); -+ if (ret < 0) { -+ dev_err(dev, "failed to register gate clks for light vpsys\n"); -+ goto unregister_clks; -+ } -+ -+ dev_info(dev, "succeed to register vpsys gate clock provider\n"); -+ -+ return 0; -+ -+unregister_clks: -+ thead_unregister_clocks(gates, ARRAY_SIZE(gates)); -+ return ret; -+} -+ -+static const struct of_device_id vpsys_clk_gate_of_match = { -+ { .compatible = "thead,vpsys-gate-controller" }, -+ { /* sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, vpsys_clk_gate_of_match); -+ -+static struct platform_driver light_vpsys_clk_driver = { -+ .probe = light_vpsys_clk_probe, -+ .driver = { -+ .name = "vpsys-clk-gate-provider", -+ .of_match_table = of_match_ptr(vpsys_clk_gate_of_match), -+ }, -+}; -+ -+module_platform_driver(light_vpsys_clk_driver); -+MODULE_AUTHOR("wei.liu <lw312886@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light Fullmask vpsys clock gate provider"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig -index d1fdea27eb0d..4c67dd5991d1 100644 ---- a/drivers/cpufreq/Kconfig -+++ b/drivers/cpufreq/Kconfig -@@ -346,5 +346,15 @@ config QORIQ_CPUFREQ - This adds the CPUFreq driver support for Freescale QorIQ SoCs - which are capable of changing the CPU's frequency dynamically. - -+config RISCV_THEAD_LIGHT_CPUFREQ -+ tristate "CPU frequency scaling driver for Thead light SoCs" -+ depends on OF && COMMON_CLK -+ select CLK_LIGHT -+ select PM_OPP -+ help -+ This adds the CPUFreq driver support for Thead light SoCs -+ which are capable of changing the CPU's frequency dynamically. -+ -+ - endif - endmenu -diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index f9c1c9012ce7..4c87824d45eb 100644 ---- a/drivers/cpufreq/Makefile -+++ b/drivers/cpufreq/Makefile -@@ -110,3 +110,4 @@ obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o - obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o - obj-$(CONFIG_SW64_CPUFREQ) += sw64_cpufreq.o - obj-$(CONFIG_SW64_CPUFREQ_DEBUGFS) += sw64_cpufreq_debugfs.o -+obj-$(CONFIG_RISCV_THEAD_LIGHT_CPUFREQ) += light-mpw-cpufreq.o -diff --git a/drivers/cpufreq/light-mpw-cpufreq.c b/drivers/cpufreq/light-mpw-cpufreq.c -new file mode 100644 -index 000000000000..72f8b348778c ---- /dev/null -+++ b/drivers/cpufreq/light-mpw-cpufreq.c -@@ -0,0 +1,491 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/clk.h> -+#include <linux/cpu.h> -+#include <linux/cpufreq.h> -+#include <linux/delay.h> -+#include <linux/err.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/pm_opp.h> -+#include <linux/platform_device.h> -+#include <linux/reboot.h> -+#include <linux/regulator/consumer.h> -+#include <linux/suspend.h> -+#include <linux/clk-provider.h> -+#include <linux/smp.h> -+#include <linux/kernel.h> -+#include <linux/notifier.h> -+ -+extern struct atomic_notifier_head panic_notifier_list; -+ -+static DEFINE_MUTEX(cpufreq_lock); -+ -+bool cpufreq_denied = false; -+ -+struct regulator *dvdd_cpu_reg; -+struct regulator *dvddm_cpu_reg; -+ -+enum LIGHT_MPW_CPUFREQ_CLKS { -+ LIGHT_C910_CCLK, -+ LIGHT_C910_CCLK_I0, -+ LIGHT_CPU_PLL1_FOUTPOSTDIV, -+ LIGHT_CPU_PLL0_FOUTPOSTDIV, -+}; -+ -+#define LIGHT_MPW_CPUFREQ_CLK_NUM 4 -+#define LIGHT_CPUFREQ_THRE 2000000 -+#define LIGHT_C910_BUS_CLK_SYNC BIT(11) -+#define LIGHT_C910_BUS_CLK_RATIO_MASK 0x700 -+#define LIGHT_C910_BUS_CLK_DIV_RATIO_2 0x100 -+#define LIGHT_C910_BUS_CLK_DIV_RATIO_3 0x200 -+ -+static int num_clks; -+static struct clk_bulk_data clks = { -+ { .id = "c910_cclk" }, -+ { .id = "c910_cclk_i0" }, -+ { .id = "cpu_pll1_foutpostdiv" }, -+ { .id = "cpu_pll0_foutpostdiv" }, -+}; -+ -+static struct device *cpu_dev; -+static struct cpufreq_frequency_table *freq_table; -+static unsigned int max_freq; -+static unsigned int transition_latency; -+static void __iomem *ap_sys_reg; -+static bool light_dvfs_sv = false; -+ -+static u32 *light_dvddm_volt; -+static u32 soc_opp_count = 0; -+ -+static int light_set_target(struct cpufreq_policy *policy, unsigned int index) -+{ -+ struct dev_pm_opp *opp; -+ unsigned long freq_hz; -+ int volt, volt_old; -+ unsigned int old_freq, new_freq; -+ int ret; -+ u32 val; -+ u32 re_modify_bus_freq = 0; -+ -+ mutex_lock(&cpufreq_lock); -+ -+ if (cpufreq_denied) { -+ dev_emerg(cpu_dev, "Denied to set cpu frequency temporarily on reboot\n"); -+ mutex_unlock(&cpufreq_lock); -+ return 0; -+ } -+ new_freq = freq_tableindex.frequency; -+ freq_hz = new_freq * 1000; -+ old_freq = policy->cur; -+ -+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); -+ if (IS_ERR(opp)) { -+ dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); -+ mutex_unlock(&cpufreq_lock); -+ return PTR_ERR(opp); -+ } -+ -+ volt = dev_pm_opp_get_voltage(opp); -+ dev_pm_opp_put(opp); -+ -+ volt_old = regulator_get_voltage(dvdd_cpu_reg); -+ if (volt_old < 0) { -+ dev_err(cpu_dev, "failed to get cpu voltage\n"); -+ mutex_unlock(&cpufreq_lock); -+ return volt_old; -+ } -+ -+ dev_dbg(cpu_dev, "%u MHz, %d mV --> %u MHz, %d mV\n", -+ old_freq / 1000, volt_old / 1000, -+ new_freq / 1000, volt / 1000); -+ -+ /* change AXI bus clock ratio to match: BUS_CLK = CPU_CCLK/ratio <= 750MHz */ -+ val = readl(ap_sys_reg); -+ if (new_freq > LIGHT_CPUFREQ_THRE) { -+ val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; -+ val |= LIGHT_C910_BUS_CLK_DIV_RATIO_3; -+ } else { -+ val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; -+ -+ if (old_freq > LIGHT_CPUFREQ_THRE) { -+ re_modify_bus_freq = 1; -+ val |= LIGHT_C910_BUS_CLK_DIV_RATIO_3; -+ }else -+ val |= LIGHT_C910_BUS_CLK_DIV_RATIO_2; -+ } -+ -+ writel(val, ap_sys_reg); -+ val &= ~LIGHT_C910_BUS_CLK_SYNC; -+ writel(val, ap_sys_reg); -+ udelay(1); -+ val |= LIGHT_C910_BUS_CLK_SYNC; -+ writel(val, ap_sys_reg); -+ udelay(1); -+ -+ /* scaling up? scale voltage before frequency */ -+ if (new_freq > old_freq && !light_dvfs_sv) { -+ ret = regulator_set_voltage_tol(dvddm_cpu_reg, light_dvddm_voltindex, 0); -+ if (ret) { -+ dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); -+ mutex_unlock(&cpufreq_lock); -+ return ret; -+ } -+ ret = regulator_set_voltage_tol(dvdd_cpu_reg, volt, 0); -+ if (ret) { -+ dev_err(cpu_dev, -+ "failed to scale vddarm up: %d\n", ret); -+ mutex_unlock(&cpufreq_lock); -+ return ret; -+ } -+ } -+ -+ if (!strcmp(__clk_get_name(clk_get_parent(clksLIGHT_C910_CCLK.clk)), -+ __clk_get_name(clksLIGHT_C910_CCLK_I0.clk))) { -+ clk_prepare_enable(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk); -+ clk_set_rate(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk, new_freq * 1000); -+ ret = clk_set_parent(clksLIGHT_C910_CCLK.clk, clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk); -+ udelay(1); -+ if (ret) -+ clk_disable_unprepare(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk); -+ } else { -+ clk_prepare_enable(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk); -+ clk_set_rate(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk, new_freq * 1000); -+ ret = clk_set_parent(clksLIGHT_C910_CCLK.clk, clksLIGHT_C910_CCLK_I0.clk); -+ udelay(1); -+ if (ret) -+ clk_disable_unprepare(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk); -+ } -+ -+ /*add delay for clk-switch*/ -+ udelay(1); -+ -+ /* Ensure the c910_cclk clock divider is what we expect */ -+ ret = clk_set_rate(clksLIGHT_C910_CCLK.clk, new_freq * 1000); -+ if (ret) { -+ int ret1; -+ -+ dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); -+ ret1 = regulator_set_voltage_tol(dvdd_cpu_reg, volt_old, 0); -+ if (ret1) -+ dev_err(cpu_dev, "failed to restore dvdd_cpu voltage: %d\n", ret1); -+ mutex_unlock(&cpufreq_lock); -+ return ret; -+ } -+ -+ /* scaling down? scale voltage after frequency */ -+ if (new_freq < old_freq && !light_dvfs_sv) { -+ ret = regulator_set_voltage_tol(dvddm_cpu_reg, light_dvddm_voltindex, 0); -+ if (ret) -+ dev_err(cpu_dev, "failed to scale dvddm down: %d\n", ret); -+ ret = regulator_set_voltage_tol(dvdd_cpu_reg, volt, 0); -+ if (ret) -+ dev_err(cpu_dev, "failed to scale dvdd_cpu down: %d\n", ret); -+ } -+ -+ val = readl(ap_sys_reg); -+ if (re_modify_bus_freq) { -+ val &= ~LIGHT_C910_BUS_CLK_RATIO_MASK; -+ val |= LIGHT_C910_BUS_CLK_DIV_RATIO_2; -+ -+ writel(val, ap_sys_reg); -+ val &= ~LIGHT_C910_BUS_CLK_SYNC; -+ writel(val, ap_sys_reg); -+ udelay(1); -+ val |= LIGHT_C910_BUS_CLK_SYNC; -+ writel(val, ap_sys_reg); -+ udelay(1); -+ } -+ -+ mutex_unlock(&cpufreq_lock); -+ -+ return 0; -+} -+ -+static int light_cpufreq_init(struct cpufreq_policy *policy) -+{ -+ policy->clk = clksLIGHT_C910_CCLK.clk; -+ policy->cur = clk_get_rate(policy->clk) / 1000; -+ cpufreq_generic_init(policy, freq_table, transition_latency); -+ policy->suspend_freq = max_freq; -+ dev_pm_opp_of_register_em(cpu_dev, policy->cpus); -+ -+ return 0; -+} -+ -+static int light_cpufreq_reboot_notifier(struct notifier_block *this, -+ unsigned long event, void *ptr) -+{ -+ mutex_lock(&cpufreq_lock); -+ cpufreq_denied = true; -+ mutex_unlock(&cpufreq_lock); -+ -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block cpufreq_reboot_notifier = { -+ .notifier_call = light_cpufreq_reboot_notifier, -+}; -+ -+static struct cpufreq_driver light_cpufreq_driver = { -+ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK | -+ CPUFREQ_IS_COOLING_DEV, -+ .verify = cpufreq_generic_frequency_table_verify, -+ .target_index = light_set_target, -+ .get = cpufreq_generic_get, -+ .init = light_cpufreq_init, -+ .name = "light-cpufreq", -+ .attr = cpufreq_generic_attr, -+ .suspend = cpufreq_generic_suspend, -+}; -+ -+static int light_cpufreq_pm_notify(struct notifier_block *nb, -+ unsigned long event, void *dummy) -+{ -+ switch (event) { -+ case PM_SUSPEND_PREPARE: -+ /* TBD */ -+ break; -+ case PM_POST_SUSPEND: -+ /* TBD */ -+ break; -+ default: -+ break; -+ } -+ -+ return NOTIFY_OK; -+} -+ -+static struct notifier_block light_cpufreq_pm_notifier = { -+ .notifier_call = light_cpufreq_pm_notify, -+}; -+ -+/* -+ * Set CPU PLL1's frequency as minimum on panic -+ */ -+static int panic_cpufreq_notifier_call(struct notifier_block *nb, -+ unsigned long action, void *data) -+{ -+ int cpu = smp_processor_id(); -+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); -+ -+ pr_info("enter panic_cpufreq_notifier_call\n"); -+ -+ /* -+ * set CPU PLL1's frequency as minimum to compatible voltage -+ * becarefull if the PLL1 is serving the cpu core, swith to PLL0 first -+ */ -+ if (strcmp(__clk_get_name(clk_get_parent(clksLIGHT_C910_CCLK.clk)), -+ __clk_get_name(clksLIGHT_C910_CCLK_I0.clk))) { -+ pr_debug("%s,%d\n", __func__, __LINE__); -+ clk_prepare_enable(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk); -+ clk_set_rate(clksLIGHT_CPU_PLL0_FOUTPOSTDIV.clk, policy->min * 1000); -+ udelay(1); -+ clk_set_parent(clksLIGHT_C910_CCLK.clk, clksLIGHT_C910_CCLK_I0.clk); -+ -+ pr_debug("%s,%d\n", __func__, __LINE__); -+ } -+ -+ pr_debug("%s,%d\n", __func__, __LINE__); -+ /* -+ * since the clk driver will use PLL1 as the default clock source, -+ * in order to compatible voltage which is unpredictable we should -+ * set the CPU PLL1's frequency as minimum in advance, otherwise the -+ * system may crash in crash kernel stage. -+ */ -+ clk_prepare_enable(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk); -+ clk_set_rate(clksLIGHT_CPU_PLL1_FOUTPOSTDIV.clk, policy->min * 1000); -+ udelay(1); -+ -+ pr_info("finish to execute cpufreq notifier callback on panic\n"); -+ -+ return 0; -+} -+ -+static struct notifier_block panic_cpufreq_notifier = { -+ .notifier_call = panic_cpufreq_notifier_call, -+}; -+ -+static int light_cpufreq_probe(struct platform_device *pdev) -+{ -+ struct device_node *np; -+ int num, ret; -+ const struct property *prop; -+ const __be32 *val; -+ u32 nr, i, j; -+ -+ np = of_find_compatible_node(NULL, NULL, "thead,light_sys_reg"); -+ if (!np) -+ return -ENOENT; -+ ap_sys_reg = of_iomap(np, 0); -+ WARN_ON(!ap_sys_reg); -+ -+ cpu_dev = get_cpu_device(0); -+ if (!cpu_dev) { -+ pr_err("failed to get cpu0 device\n"); -+ return -ENODEV; -+ } -+ -+ np = of_node_get(cpu_dev->of_node); -+ if (!np) { -+ dev_err(cpu_dev, "failed to find cpu0 node\n"); -+ return -ENOENT; -+ } -+ -+ num_clks = LIGHT_MPW_CPUFREQ_CLK_NUM; -+ ret = clk_bulk_get(cpu_dev, num_clks, clks); -+ if (ret) -+ goto put_node; -+ -+ dvdd_cpu_reg = regulator_get(cpu_dev, "dvdd"); -+ dvddm_cpu_reg = regulator_get(cpu_dev, "dvddm"); -+ if (PTR_ERR(dvdd_cpu_reg) == -EPROBE_DEFER || -+ PTR_ERR(dvddm_cpu_reg) == -EPROBE_DEFER) { -+ ret = -EPROBE_DEFER; -+ dev_dbg(cpu_dev, "regulators not ready, defer\n"); -+ goto put_reg; -+ } -+ -+ if (IS_ERR(dvdd_cpu_reg) || IS_ERR(dvddm_cpu_reg)) { -+ dev_err(cpu_dev, "failed to get regulators\n"); -+ ret = -ENOENT; -+ goto put_reg; -+ } -+ -+ ret = dev_pm_opp_of_add_table(cpu_dev); -+ if (ret < 0) { -+ dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); -+ goto put_reg; -+ } -+ -+ num = dev_pm_opp_get_opp_count(cpu_dev); -+ if (num < 0) { -+ ret = num; -+ dev_err(cpu_dev, "no OPP table is found: %d\n", ret); -+ goto out_free_opp; -+ } -+ -+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); -+ if (ret) { -+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); -+ goto out_free_opp; -+ } -+ -+ /* Make light_dvddm_volt array's size same as dvdd opp number */ -+ light_dvddm_volt = devm_kcalloc(cpu_dev, num, sizeof(*light_dvddm_volt), -+ GFP_KERNEL); -+ if (light_dvddm_volt == NULL) { -+ ret = -ENOMEM; -+ goto free_freq_table; -+ } -+ -+ if (of_get_property(np, "dvfs_sv", NULL)) -+ light_dvfs_sv = true; -+ else -+ light_dvfs_sv = false; -+ -+ prop = of_find_property(np, "light,dvddm-operating-points", NULL); -+ if (!prop || !prop->value) -+ goto soc_opp_out; -+ -+ nr = prop->length / sizeof(u32); -+ if (nr % 2 || (nr / 2) < num) -+ goto soc_opp_out; -+ -+ for (j = 0; j < num; j++) { -+ val = prop->value; -+ for (i = 0; i < nr / 2; i++) { -+ unsigned long freq = be32_to_cpup(val++); -+ unsigned long volt = be32_to_cpup(val++); -+ if (freq_tablej.frequency == freq) { -+ light_dvddm_voltsoc_opp_count++ = volt; -+ break; -+ } -+ } -+ } -+ -+soc_opp_out: -+ if (soc_opp_count != num) -+ dev_warn(cpu_dev, "Not find valid light,dvddm-operating-points property\n"); -+ -+ if (of_property_read_u32(np, "clock-latency", &transition_latency)) -+ transition_latency = CPUFREQ_ETERNAL; -+ -+ max_freq = freq_table--num.frequency; -+ -+ ret = cpufreq_register_driver(&light_cpufreq_driver); -+ if (ret) { -+ dev_err(cpu_dev, "failed register driver: %d\n", ret); -+ goto free_freq_table; -+ } -+ -+ register_pm_notifier(&light_cpufreq_pm_notifier); -+ -+ of_node_put(np); -+ -+ ret = atomic_notifier_chain_register(&panic_notifier_list, -+ &panic_cpufreq_notifier); -+ if (ret) { -+ pr_err("unable to register notifier(%d)\n", ret); -+ goto free_freq_table; -+ } -+ -+ register_reboot_notifier(&cpufreq_reboot_notifier); -+ -+ dev_info(cpu_dev, "finish to register cpufreq driver\n"); -+ -+ return 0; -+ -+free_freq_table: -+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); -+out_free_opp: -+ dev_pm_opp_of_remove_table(cpu_dev); -+put_reg: -+ if (!IS_ERR(dvdd_cpu_reg)) -+ regulator_put(dvdd_cpu_reg); -+ if (!IS_ERR(dvddm_cpu_reg)) -+ regulator_put(dvddm_cpu_reg); -+ -+ clk_bulk_put(num_clks, clks); -+put_node: -+ of_node_put(np); -+ -+ return ret; -+} -+ -+static int light_cpufreq_remove(struct platform_device *pdev) -+{ -+ cpufreq_unregister_driver(&light_cpufreq_driver); -+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); -+ dev_pm_opp_of_remove_table(cpu_dev); -+ regulator_put(dvdd_cpu_reg); -+ regulator_put(dvddm_cpu_reg); -+ -+ clk_bulk_put(num_clks, clks); -+ -+ return 0; -+} -+ -+static const struct of_device_id light_cpufreq_match = { -+ { .compatible = "thead,light-mpw-cpufreq" }, -+ {}, -+}; -+ -+static struct platform_driver light_cpufreq_platdrv = { -+ .driver = { -+ .name = "thead,light-mpw-cpufreq", -+ .of_match_table = light_cpufreq_match, -+ }, -+ .probe = light_cpufreq_probe, -+ .remove = light_cpufreq_remove, -+}; -+module_platform_driver(light_cpufreq_platdrv); -+ -+MODULE_ALIAS("platform:light-cpufreq"); -+MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light cpufreq driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig -index 9cb284a6e7a1..52f07f9c5db7 100644 ---- a/drivers/firmware/Kconfig -+++ b/drivers/firmware/Kconfig -@@ -314,5 +314,6 @@ source "drivers/firmware/psci/Kconfig" - source "drivers/firmware/smccc/Kconfig" - source "drivers/firmware/tegra/Kconfig" - source "drivers/firmware/xilinx/Kconfig" -+source "drivers/firmware/thead/Kconfig" - - endmenu -diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile -index 28fcddcd688f..a817fe549c9f 100644 ---- a/drivers/firmware/Makefile -+++ b/drivers/firmware/Makefile -@@ -38,3 +38,4 @@ obj-y += psci/ - obj-y += smccc/ - obj-y += tegra/ - obj-y += xilinx/ -+obj-y += thead/ -diff --git a/drivers/firmware/thead/Kconfig b/drivers/firmware/thead/Kconfig -new file mode 100644 -index 000000000000..ad5b82dd51e8 ---- /dev/null -+++ b/drivers/firmware/thead/Kconfig -@@ -0,0 +1,18 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+config LIGHT_AON -+ bool "Thead Light Aon Protocol driver" -+ depends on THEAD_LIGHT_MBOX -+ default y -+ help -+ Thead light Aon is a low-level system function which runs a dedicated -+ thead riscv E902 core to provide power, clock and resource management. -+ -+ This driver manages the IPC interface between host cpu liks thead -+ and the Aon firmware running on thead riscv E902 core. -+ -+config LIGHT_AON_PD -+ bool "Thead Light Aon Power Domain driver" -+ depends on LIGHT_AON -+ select PM_GENERIC_DOMAINS if PM -+ help -+ The Aon power domain virtual driver. -diff --git a/drivers/firmware/thead/Makefile b/drivers/firmware/thead/Makefile -new file mode 100644 -index 000000000000..6bd2afe817ef ---- /dev/null -+++ b/drivers/firmware/thead/Makefile -@@ -0,0 +1,3 @@ -+# SPDX-License-Identifier: GPL-2.0 -+obj-$(CONFIG_LIGHT_AON) += light_aon.o light_aon_misc.o light_aon_test.o -+obj-$(CONFIG_LIGHT_AON_PD) += light_aon_pd.o -diff --git a/drivers/firmware/thead/light_aon.c b/drivers/firmware/thead/light_aon.c -new file mode 100644 -index 000000000000..5af7de821e76 ---- /dev/null -+++ b/drivers/firmware/thead/light_aon.c -@@ -0,0 +1,261 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/err.h> -+#include <linux/firmware/thead/ipc.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/kernel.h> -+#include <linux/mailbox_client.h> -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/of_platform.h> -+#include <linux/platform_device.h> -+ -+/* 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 light_aon_chan { -+ struct light_aon_ipc *aon_ipc; -+ -+ struct mbox_client cl; -+ struct mbox_chan *ch; -+ struct completion tx_done; -+}; -+ -+struct light_aon_ipc { -+ struct light_aon_chan chans; -+ struct device *dev; -+ struct mutex lock; -+ struct completion done; -+ u32 *msg; -+}; -+ -+/* -+ * This type is used to indicate error response for most functions. -+ */ -+enum light_aon_error_codes { -+ LIGHT_AON_ERR_NONE = 0, /* Success */ -+ LIGHT_AON_ERR_VERSION = 1, /* Incompatible API version */ -+ LIGHT_AON_ERR_CONFIG = 2, /* Configuration error */ -+ LIGHT_AON_ERR_PARM = 3, /* Bad parameter */ -+ LIGHT_AON_ERR_NOACCESS = 4, /* Permission error (no access) */ -+ LIGHT_AON_ERR_LOCKED = 5, /* Permission error (locked) */ -+ LIGHT_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */ -+ LIGHT_AON_ERR_NOTFOUND = 7, /* Not found */ -+ LIGHT_AON_ERR_NOPOWER = 8, /* No power */ -+ LIGHT_AON_ERR_IPC = 9, /* Generic IPC error */ -+ LIGHT_AON_ERR_BUSY = 10, /* Resource is currently busy/active */ -+ LIGHT_AON_ERR_FAIL = 11, /* General I/O failure */ -+ LIGHT_AON_ERR_LAST -+}; -+ -+static int light_aon_linux_errmapLIGHT_AON_ERR_LAST = { -+ 0, /* LIGHT_AON_ERR_NONE */ -+ -EINVAL, /* LIGHT_AON_ERR_VERSION */ -+ -EINVAL, /* LIGHT_AON_ERR_CONFIG */ -+ -EINVAL, /* LIGHT_AON_ERR_PARM */ -+ -EACCES, /* LIGHT_AON_ERR_NOACCESS */ -+ -EACCES, /* LIGHT_AON_ERR_LOCKED */ -+ -ERANGE, /* LIGHT_AON_ERR_UNAVAILABLE */ -+ -EEXIST, /* LIGHT_AON_ERR_NOTFOUND */ -+ -EPERM, /* LIGHT_AON_ERR_NOPOWER */ -+ -EPIPE, /* LIGHT_AON_ERR_IPC */ -+ -EBUSY, /* LIGHT_AON_ERR_BUSY */ -+ -EIO, /* LIGHT_AON_ERR_FAIL */ -+}; -+ -+static struct light_aon_ipc *light_aon_ipc_handle; -+ -+static inline int light_aon_to_linux_errno(int errno) -+{ -+ if (errno >= LIGHT_AON_ERR_NONE && errno < LIGHT_AON_ERR_LAST) -+ return light_aon_linux_errmaperrno; -+ return -EIO; -+} -+ -+/* -+ * Get the default handle used by SCU -+ */ -+int light_aon_get_handle(struct light_aon_ipc **ipc) -+{ -+ if (!light_aon_ipc_handle) -+ return -EPROBE_DEFER; -+ -+ *ipc = light_aon_ipc_handle; -+ return 0; -+} -+EXPORT_SYMBOL(light_aon_get_handle); -+ -+static void light_aon_tx_done(struct mbox_client *cl, void *mssg, int r) -+{ -+ struct light_aon_chan *aon_chan = container_of(cl, struct light_aon_chan, cl); -+ -+ complete(&aon_chan->tx_done); -+} -+ -+static void light_aon_rx_callback(struct mbox_client *c, void *msg) -+{ -+ struct light_aon_chan *aon_chan = container_of(c, struct light_aon_chan, cl); -+ struct light_aon_ipc *aon_ipc = aon_chan->aon_ipc; -+ -+ memcpy(aon_ipc->msg, msg, LIGHT_AON_RPC_MSG_NUM * sizeof(u32)); -+ dev_dbg(aon_ipc->dev, "msg head: 0x%x\n", *((u32 *)msg)); -+ complete(&aon_ipc->done); -+} -+ -+static int light_aon_ipc_write(struct light_aon_ipc *aon_ipc, void *msg) -+{ -+ struct light_aon_rpc_msg_hdr *hdr = msg; -+ struct light_aon_chan *aon_chan; -+ u32 *data = msg; -+ int ret; -+ -+ /* check size, currently it requires 7 MSG in one transfer */ -+ if (hdr->size != LIGHT_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 light_aon_call_rpc(struct light_aon_ipc *aon_ipc, void *msg, bool have_resp) -+{ -+ struct light_aon_rpc_msg_hdr *hdr; -+ int ret; -+ -+ if (WARN_ON(!aon_ipc || !msg)) -+ return -EINVAL; -+ -+ mutex_lock(&aon_ipc->lock); -+ reinit_completion(&aon_ipc->done); -+ -+ if (have_resp) -+ aon_ipc->msg = msg; -+ -+ ret = light_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 hdr->func field */ -+ hdr = msg; -+ ret = hdr->func; -+ } -+ -+out: -+ mutex_unlock(&aon_ipc->lock); -+ -+ dev_dbg(aon_ipc->dev, "RPC SVC done\n"); -+ -+ return light_aon_to_linux_errno(ret); -+} -+EXPORT_SYMBOL(light_aon_call_rpc); -+ -+static int light_aon_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct light_aon_ipc *aon_ipc; -+ struct light_aon_chan *aon_chan; -+ struct mbox_client *cl; -+ 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 = light_aon_rx_callback; -+ -+ /* Initial tx_done completion as "done" */ -+ cl->tx_done = light_aon_tx_done; -+ init_completion(&aon_chan->tx_done); -+ complete(&aon_chan->tx_done); -+ -+ aon_chan->aon_ipc = aon_ipc; -+ aon_chan->ch = mbox_request_channel_byname(cl, "aon"); -+ 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 thead mbox chan: aon\n"); -+ -+ aon_ipc->dev = dev; -+ mutex_init(&aon_ipc->lock); -+ init_completion(&aon_ipc->done); -+ -+ light_aon_ipc_handle = aon_ipc; -+ -+ return devm_of_platform_populate(dev); -+} -+ -+static const struct of_device_id light_aon_match = { -+ { .compatible = "thead,light-aon", }, -+ { /* Sentinel */ } -+}; -+ -+static int __maybe_unused light_aon_resume_noirq(struct device *dev) -+{ -+ struct light_aon_chan *aon_chan; -+ int ret; -+ -+ aon_chan = &light_aon_ipc_handle->chans; -+ -+ complete(&aon_chan->tx_done); -+ return 0; -+} -+ -+static const struct dev_pm_ops light_aon_pm_ops = { -+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, -+ light_aon_resume_noirq) -+}; -+static struct platform_driver light_aon_driver = { -+ .driver = { -+ .name = "light-aon", -+ .of_match_table = light_aon_match, -+ .pm = &light_aon_pm_ops, -+ }, -+ .probe = light_aon_probe, -+}; -+builtin_platform_driver(light_aon_driver); -+ -+MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light firmware protocol driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/firmware/thead/light_aon_misc.c b/drivers/firmware/thead/light_aon_misc.c -new file mode 100644 -index 000000000000..3fb689f4b261 ---- /dev/null -+++ b/drivers/firmware/thead/light_aon_misc.c -@@ -0,0 +1,74 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/firmware/thead/ipc.h> -+ -+struct light_aon_msg_req_misc_set_ctrl { -+ struct light_aon_rpc_msg_hdr hdr; -+ u32 ctrl; -+ u32 val; -+ u16 resource; -+ u16 reserved7; -+} __packed __aligned(4); -+ -+struct light_aon_msg_req_misc_get_ctrl { -+ struct light_aon_rpc_msg_hdr hdr; -+ u32 ctrl; -+ u16 resource; -+ u16 reserved9; -+} __packed __aligned(4); -+ -+struct light_aon_msg_resp_misc_get_ctrl { -+ struct light_aon_rpc_msg_hdr hdr; -+ u32 val; -+ u32 reserved5; -+} __packed __aligned(4); -+ -+int light_aon_misc_set_control(struct light_aon_ipc *ipc, u16 resource, -+ u32 ctrl, u32 val) -+{ -+ struct light_aon_msg_req_misc_set_ctrl msg; -+ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; -+ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; -+ hdr->func = (uint8_t)LIGHT_AON_MISC_FUNC_SET_CONTROL; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+ -+ msg.ctrl = ctrl; -+ msg.val = val; -+ msg.resource = resource; -+ -+ return light_aon_call_rpc(ipc, &msg, true); -+} -+EXPORT_SYMBOL(light_aon_misc_set_control); -+ -+int light_aon_misc_get_control(struct light_aon_ipc *ipc, u16 resource, -+ u32 ctrl, u32 *val) -+{ -+ struct light_aon_msg_req_misc_get_ctrl msg; -+ struct light_aon_msg_resp_misc_get_ctrl *resp; -+ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; -+ int ret; -+ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; -+ hdr->func = (uint8_t)LIGHT_AON_MISC_FUNC_GET_CONTROL; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+ -+ msg.ctrl = ctrl; -+ msg.resource = resource; -+ -+ ret = light_aon_call_rpc(ipc, &msg, true); -+ if (ret) -+ return ret; -+ -+ resp = (struct light_aon_msg_resp_misc_get_ctrl *)&msg; -+ if (val != NULL) -+ *val = resp->val; -+ -+ return 0; -+} -+EXPORT_SYMBOL(light_aon_misc_get_control); -diff --git a/drivers/firmware/thead/light_aon_pd.c b/drivers/firmware/thead/light_aon_pd.c -new file mode 100644 -index 000000000000..3bef67df5a0a ---- /dev/null -+++ b/drivers/firmware/thead/light_aon_pd.c -@@ -0,0 +1,417 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <dt-bindings/firmware/thead/rsrc.h> -+#include <linux/ctype.h> -+#include <linux/debugfs.h> -+#include <linux/firmware/thead/ipc.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/of_platform.h> -+#include <linux/platform_device.h> -+#include <linux/pm.h> -+#include <linux/pm_domain.h> -+#include <linux/seq_file.h> -+#include <linux/slab.h> -+ -+struct light_aon_msg_req_set_resource_power_mode { -+ struct light_aon_rpc_msg_hdr hdr; -+ u16 resource; -+ u16 mode; -+ u16 reserved10; -+} __packed __aligned(4); -+ -+#define LIGHT_AONU_PD_NAME_SIZE 20 -+#define LIGHT_AONU_PD_STATE_NAME_SIZE 10 -+ -+struct light_aon_pm_domain { -+ struct generic_pm_domain pd; -+ char nameLIGHT_AONU_PD_NAME_SIZE; -+ u16 rsrc; -+}; -+ -+struct light_aon_pd_range { -+ char *name; -+ u32 rsrc; -+ u8 num; -+ -+ /* add domain index */ -+ bool postfix; -+ u8 start_from; -+}; -+ -+struct light_aon_pd_soc { -+ const struct light_aon_pd_range *pd_ranges; -+ u8 num_ranges; -+}; -+ -+static const struct light_aon_pd_range light_aon_pd_ranges = { -+ /* AUDIO SS */ -+ { "audio", LIGHT_AON_AUDIO_PD, 1, false, 0 }, -+ { "vdec", LIGHT_AON_VDEC_PD, 1, false, 0}, -+ { "npu", LIGHT_AON_NPU_PD, 1, false, 0}, -+ { "venc", LIGHT_AON_VENC_PD, 1, false, 0}, -+ { "gpu", LIGHT_AON_GPU_PD, 1, false, 0}, -+ { "dsp0", LIGHT_AON_DSP0_PD, 1, false, 0}, -+ { "dsp1", LIGHT_AON_DSP1_PD, 1, false, 0}, -+ {}, -+}; -+ -+static const struct light_aon_pd_soc light_aon_pd = { -+ .pd_ranges = light_aon_pd_ranges, -+ .num_ranges = ARRAY_SIZE(light_aon_pd_ranges), -+}; -+ -+static struct light_aon_ipc *pm_ipc_handle; -+static struct dentry *pd_debugfs_root; -+struct dentry *pd_pde; -+struct genpd_onecell_data *genpd_data; -+ -+static inline struct light_aon_pm_domain *to_light_aon_pd(struct generic_pm_domain *genpd) -+{ -+ return container_of(genpd, struct light_aon_pm_domain, pd); -+} -+ -+static int light_aon_pd_power(struct generic_pm_domain *domain, bool power_on) -+{ -+ struct light_aon_msg_req_set_resource_power_mode msg; -+ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; -+ struct light_aon_pm_domain *pd; -+ int ret; -+ -+ pd = to_light_aon_pd(domain); -+ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = LIGHT_AON_RPC_SVC_PM; -+ hdr->func = LIGHT_AON_PM_FUNC_SET_RESOURCE_POWER_MODE; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+ -+ msg.resource = pd->rsrc; -+ msg.mode = power_on ? LIGHT_AON_PM_PW_MODE_ON : LIGHT_AON_PM_PW_MODE_OFF; -+ -+ ret = light_aon_call_rpc(pm_ipc_handle, &msg, true); -+ if (ret) -+ dev_err(&domain->dev, "failed to power %s resource %d ret %d\n", -+ power_on ? "up" : "off", pd->rsrc, ret); -+ -+ return ret; -+} -+ -+static int light_aon_pd_power_on(struct generic_pm_domain *domain) -+{ -+ return light_aon_pd_power(domain, true); -+} -+ -+static int light_aon_pd_power_off(struct generic_pm_domain *domain) -+{ -+ return light_aon_pd_power(domain, false); -+} -+ -+static struct generic_pm_domain *light_aon_pd_xlate(struct of_phandle_args *spec, -+ void *data) -+{ -+ struct generic_pm_domain *domain = ERR_PTR(-ENOENT); -+ struct genpd_onecell_data *pd_data = data; -+ unsigned int i; -+ -+ for (i = 0; i < pd_data->num_domains; i++) { -+ struct light_aon_pm_domain *aon_pd; -+ -+ aon_pd = to_light_aon_pd(pd_data->domainsi); -+ if (aon_pd->rsrc == spec->args0) { -+ domain = &aon_pd->pd; -+ break; -+ } -+ } -+ -+ return domain; -+} -+ -+static struct light_aon_pm_domain * -+light_aon_add_pm_domain(struct device *dev, int idx, -+ const struct light_aon_pd_range *pd_ranges) -+{ -+ struct light_aon_pm_domain *aon_pd; -+ int ret; -+ -+ aon_pd = devm_kzalloc(dev, sizeof(*aon_pd), GFP_KERNEL); -+ if (!aon_pd) -+ return ERR_PTR(-ENOMEM); -+ -+ aon_pd->rsrc = pd_ranges->rsrc + idx; -+ aon_pd->pd.power_off = light_aon_pd_power_off; -+ aon_pd->pd.power_on = light_aon_pd_power_on; -+ -+ if (pd_ranges->postfix) -+ snprintf(aon_pd->name, sizeof(aon_pd->name), -+ "%s%i", pd_ranges->name, pd_ranges->start_from + idx); -+ else -+ snprintf(aon_pd->name, sizeof(aon_pd->name), -+ "%s", pd_ranges->name); -+ -+ aon_pd->pd.name = aon_pd->name; -+ -+#if 0 -+ if (aon_pd->rsrc >= LIGHT_AON_R_LAST) { -+ dev_warn(dev, "invalid pd %s rsrc id %d found", -+ aon_pd->name, aon_pd->rsrc); -+ -+ devm_kfree(dev, aon_pd); -+ return NULL; -+ } -+#endif -+ -+ ret = pm_genpd_init(&aon_pd->pd, NULL, true); -+ if (ret) { -+ dev_warn(dev, "failed to init pd %s rsrc id %d", -+ aon_pd->name, aon_pd->rsrc); -+ devm_kfree(dev, aon_pd); -+ return NULL; -+ } -+ -+ return aon_pd; -+} -+ -+static int light_aon_init_pm_domains(struct device *dev, -+ const struct light_aon_pd_soc *pd_soc) -+{ -+ const struct light_aon_pd_range *pd_ranges = pd_soc->pd_ranges; -+ struct generic_pm_domain **domains; -+ struct genpd_onecell_data *pd_data; -+ struct light_aon_pm_domain *aon_pd; -+ u32 count = 0; -+ int i, j; -+ -+ for (i = 0; i < pd_soc->num_ranges; i++) -+ count += pd_rangesi.num; -+ -+ domains = devm_kcalloc(dev, count, sizeof(*domains), GFP_KERNEL); -+ if (!domains) -+ return -ENOMEM; -+ -+ pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL); -+ if (!pd_data) -+ return -ENOMEM; -+ -+ count = 0; -+ for (i = 0; i < pd_soc->num_ranges; i++) { -+ for (j = 0; j < pd_rangesi.num; j++) { -+ aon_pd = light_aon_add_pm_domain(dev, j, &pd_rangesi); -+ if (IS_ERR_OR_NULL(aon_pd)) -+ continue; -+ -+ domainscount++ = &aon_pd->pd; -+ dev_dbg(dev, "added power domain %s\n", aon_pd->pd.name); -+ } -+ } -+ -+ pd_data->domains = domains; -+ pd_data->num_domains = count; -+ pd_data->xlate = light_aon_pd_xlate; -+ genpd_data = pd_data; -+ -+ of_genpd_add_provider_onecell(dev->of_node, pd_data); -+ -+ return 0; -+} -+ -+static char *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); -+ } -+ -+ /* got the string, now strip linefeed. */ -+ if (bufferuserlen - 1 == '\n') -+ bufferuserlen -1 = '\0'; -+ else -+ bufferuserlen = '\0'; -+ -+ pr_debug("buffer = %s\n", buffer); -+ -+ return buffer; -+} -+ -+static ssize_t light_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 genpd_onecell_data *aon_pds_data = m->private; -+ struct generic_pm_domain *hitted_pm_genpd; -+ char pd_nameLIGHT_AONU_PD_NAME_SIZE; -+ char pd_stateLIGHT_AONU_PD_STATE_NAME_SIZE; -+ int idx, ret; -+ size_t origin_len = userlen; -+ -+ buffer = pd_get_user_string(userbuf, userlen); -+ if (IS_ERR(buffer)) -+ return PTR_ERR(buffer); -+ -+ start = skip_spaces(buffer); -+ end = start; -+ while(!isspace(*end) && *end != '\0') -+ end++; -+ -+ *end = '\0'; -+ strcpy(pd_name, start); -+ pr_debug("power domain name: %s\n", pd_name); -+ -+ /* find the target power domain */ -+ for (idx = 0; idx < aon_pds_data->num_domains; idx++) { -+ struct generic_pm_domain *domain = aon_pds_data->domainsidx; -+ pr_debug("generic pm domain name: %s, pd_name: %s, ret = %d\n", -+ domain->name, pd_name, strcmp(pd_name, domain->name)); -+ if (strcmp(pd_name, domain->name)) -+ continue; -+ else { -+ hitted_pm_genpd = aon_pds_data->domainsidx; -+ pr_debug("target pm power domain-%s found, index: %d\n", -+ hitted_pm_genpd->name, idx); -+ break; -+ } -+ } -+ -+ if (idx >= aon_pds_data->num_domains) { -+ pr_err("no taget power domain-%s found, idx = %d, total pd numbers = %d\n", -+ pd_name, idx, aon_pds_data->num_domains); -+ userlen = -EINVAL; -+ goto out; -+ } -+ -+ if (!hitted_pm_genpd->power_on && !hitted_pm_genpd->power_off) { -+ pr_err("no power operations registered for power domain-%s\n", pd_name); -+ userlen = -EINVAL; -+ goto out; -+ } -+ -+ end = end + 1; -+ start = skip_spaces(end); -+ end = start; -+ while(!isspace(*end) && *end != '\0') -+ end++; -+ -+ *end = '\0'; -+ strcpy(pd_state, start); -+ pr_debug("power domain target state: %s\n", pd_state); -+ -+ if (!strcmp(pd_state, "on")) { -+ ret = hitted_pm_genpd->power_on(hitted_pm_genpd); -+ if (ret) { -+ userlen = ret; -+ goto out; -+ } -+ } else if (!strcmp(pd_state, "off")) { -+ ret = hitted_pm_genpd->power_off(hitted_pm_genpd); -+ if (ret) { -+ userlen = ret; -+ goto out; -+ } -+ } else { -+ pr_err("invalid power domain target state, not 'on' or 'off'\n"); -+ userlen = -EINVAL; -+ goto out; -+ } -+ -+out: -+ memset(buffer, 0, origin_len); -+ vfree(buffer); -+ -+ return userlen; -+} -+ -+static int light_power_domain_show(struct seq_file *m, void *v) -+{ -+ struct genpd_onecell_data *pd_data = m->private; -+ u32 count = pd_data->num_domains; -+ int idx; -+ -+ seq_puts(m, "Power domain name list: "); -+ for(idx = 0; idx < count; idx++) -+ seq_printf(m, "%s ", pd_data->domainsidx->name); -+ seq_printf(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 light_power_domain_open(struct inode *inode, struct file *file) -+{ -+ struct genpd_onecell_data *pd_data = inode->i_private; -+ -+ return single_open(file, light_power_domain_show, pd_data); -+} -+ -+static const struct file_operations light_power_domain_fops = { -+ .owner = THIS_MODULE, -+ .write = light_power_domain_write, -+ .read = seq_read, -+ .open = light_power_domain_open, -+ .llseek = generic_file_llseek, -+}; -+ -+static void pd_debugfs_init(struct genpd_onecell_data *aon_pds_data) -+{ -+ umode_t mode = S_IRUSR | S_IWUSR | S_IFREG; -+ -+ pd_debugfs_root = debugfs_create_dir("power_domain", NULL); -+ if (!pd_debugfs_root || IS_ERR(pd_debugfs_root)) -+ return; -+ -+ pd_pde = debugfs_create_file("domain", mode, pd_debugfs_root, (void *)aon_pds_data, &light_power_domain_fops); -+ -+ pr_info("succeed to create power domain debugfs direntry\n"); -+} -+ -+static int light_aon_pd_probe(struct platform_device *pdev) -+{ -+ const struct light_aon_pd_soc *pd_soc; -+ int ret; -+ -+ ret = light_aon_get_handle(&pm_ipc_handle); -+ if (ret) -+ return ret; -+ -+ pd_soc = of_device_get_match_data(&pdev->dev); -+ if (!pd_soc) -+ return -ENODEV; -+ -+ ret = light_aon_init_pm_domains(&pdev->dev, pd_soc); -+ if (ret) -+ return ret; -+ -+ pd_debugfs_init(genpd_data); -+ -+ return 0; -+} -+ -+static const struct of_device_id light_aon_pd_match = { -+ { .compatible = "thead,light-aon-pd", &light_aon_pd}, -+ { /* sentinel */ } -+}; -+ -+static struct platform_driver light_aon_pd_driver = { -+ .driver = { -+ .name = "light-aon-pd", -+ .of_match_table = light_aon_pd_match, -+ }, -+ .probe = light_aon_pd_probe, -+}; -+builtin_platform_driver(light_aon_pd_driver); -+ -+MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light firmware protocol driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/firmware/thead/light_aon_test.c b/drivers/firmware/thead/light_aon_test.c -new file mode 100644 -index 000000000000..172025430853 ---- /dev/null -+++ b/drivers/firmware/thead/light_aon_test.c -@@ -0,0 +1,163 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/debugfs.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/firmware/thead/ipc.h> -+ -+#define MBOX_MAX_MSG_LEN 28 -+ -+static struct dentry *root_debugfs_dir; -+ -+struct light_aon_msg_req_misc_set_ctrl { -+ struct light_aon_rpc_msg_hdr hdr; -+ u32 ctrl; -+ u32 val; -+ u16 resource; -+ u16 reserved7; -+} __packed __aligned(4); -+ -+struct light_aon_msg_req_misc_get_ctrl { -+ struct light_aon_rpc_msg_hdr hdr; -+ u32 ctrl; -+ u16 resource; -+ u16 reserved9; -+} __packed __aligned(4); -+ -+struct light_aon_msg_resp_misc_get_ctrl { -+ struct light_aon_rpc_msg_hdr hdr; -+ u32 val; -+ u32 reserved5; -+} __packed __aligned(4); -+ -+struct light_aon_device { -+ struct device *dev; -+ char *test_buf; -+ struct light_aon_ipc *ipc_handle; -+}; -+ -+static ssize_t light_aon_test_buf_write(struct file *filp, -+ const char __user *userbuf, -+ size_t count, loff_t *ppos) -+{ -+ struct light_aon_device *tdev = filp->private_data; -+ int ret; -+ -+ if (count > MBOX_MAX_MSG_LEN) -+ count = MBOX_MAX_MSG_LEN; -+ -+ ret = copy_from_user(tdev->test_buf, userbuf, count); -+ if (ret) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ ret = light_aon_misc_set_control(tdev->ipc_handle, 0x1, 0x2, 0x3); -+ ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x11, 0x12, 0x13); -+ ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x21, 0x22, 0x23); -+ ret |= light_aon_misc_set_control(tdev->ipc_handle, 0x31, 0x32, 0x33); -+ if (ret) -+ dev_err(tdev->dev, "failed to set control\n"); -+ -+ //print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->test_buf, MBOX_MAX_MSG_LEN, true); -+ -+out: -+ return ret < 0 ? ret : count; -+} -+ -+static ssize_t light_aon_test_buf_read(struct file *filp, -+ char __user *userbuf, -+ size_t count, loff_t *ppos) -+{ -+ struct light_aon_device *tdev = filp->private_data; -+ -+ //print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->test_buf, MBOX_MAX_MSG_LEN, true); -+ memset(tdev->test_buf, 0, MBOX_MAX_MSG_LEN); -+ -+ return MBOX_MAX_MSG_LEN; -+} -+ -+static const struct file_operations light_aon_test_buf_ops = { -+ .write = light_aon_test_buf_write, -+ .read = light_aon_test_buf_read, -+ .open = simple_open, -+ .llseek = generic_file_llseek, -+}; -+ -+static int light_aon_add_debugfs(struct platform_device *pdev, struct light_aon_device *tdev) -+{ -+ root_debugfs_dir = debugfs_create_dir("light_aon",NULL); -+ if (!root_debugfs_dir) { -+ dev_err(&pdev->dev, "Failed to create light_aon_test debugfs\n"); -+ return -EINVAL; -+ } -+ -+ debugfs_create_file("test", 0600, root_debugfs_dir, tdev, &light_aon_test_buf_ops); -+ return 0; -+} -+ -+static int light_aon_probe(struct platform_device *pdev) -+{ -+ struct light_aon_device *tdev; -+ int ret; -+ -+ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); -+ if (!tdev) -+ return -ENOMEM; -+ -+ tdev->dev = &pdev->dev; -+ platform_set_drvdata(pdev, tdev); -+ -+ tdev->test_buf = devm_kzalloc(&pdev->dev, MBOX_MAX_MSG_LEN, GFP_KERNEL); -+ if (!tdev->test_buf) -+ return -ENOMEM; -+ -+ ret = light_aon_get_handle(&(tdev->ipc_handle)); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to get ipc_handle\n"); -+ return ret; -+ } -+ -+ ret = light_aon_add_debugfs(pdev, tdev); -+ if (ret) -+ return ret; -+ -+ dev_info(&pdev->dev, "Successfully registered\n"); -+ -+ return 0; -+} -+ -+static int light_aon_remove(struct platform_device *pdev) -+{ -+ debugfs_remove_recursive(root_debugfs_dir); -+ return 0; -+} -+ -+static const struct of_device_id light_aon_match = { -+ { .compatible = "thead,light-aon-test" }, -+ {}, -+}; -+ -+static struct platform_driver light_aon_driver = { -+ .driver = { -+ .name = "thead,light-aon-test", -+ .of_match_table = light_aon_match, -+ }, -+ .probe = light_aon_probe, -+ .remove = light_aon_remove, -+}; -+module_platform_driver(light_aon_driver); -+ -+MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light firmware protocol test driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c -index c22fcaa44a61..47f550689d53 100644 ---- a/drivers/gpio/gpio-dwapb.c -+++ b/drivers/gpio/gpio-dwapb.c -@@ -411,13 +411,12 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc, - static int dwapb_gpio_set_config(struct gpio_chip *gc, unsigned offset, - unsigned long config) - { -- u32 debounce; -- -- if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) -- return -ENOTSUPP; -+ if (pinconf_to_config_param(config) == PIN_CONFIG_INPUT_DEBOUNCE) { -+ u32 debounce = pinconf_to_config_argument(config); -+ return dwapb_gpio_set_debounce(gc, offset, debounce); -+ } - -- debounce = pinconf_to_config_argument(config); -- return dwapb_gpio_set_debounce(gc, offset, debounce); -+ return gpiochip_generic_config(gc, offset, config); - } - - static int dwapb_convert_irqs(struct dwapb_gpio_port_irqchip *pirq, -@@ -527,10 +526,14 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, - port->gc.fwnode = pp->fwnode; - port->gc.ngpio = pp->ngpio; - port->gc.base = pp->gpio_base; -+ port->gc.request = gpiochip_generic_request; -+ port->gc.free = gpiochip_generic_free; - - /* Only port A support debounce */ - if (pp->idx == 0) - port->gc.set_config = dwapb_gpio_set_config; -+ else -+ port->gc.set_config = gpiochip_generic_config; - - /* Only port A can provide interrupts in all configurations of the IP */ - if (pp->idx == 0) -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c -index 94e91516952c..628ae4b95b67 100644 ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c -@@ -1109,6 +1109,8 @@ int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev) - u16 cmd; - int r; - -+ return 0; -+ - if (!IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT)) - return 0; - -diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c -index b67eafa55715..5ebe418bd383 100644 ---- a/drivers/gpu/drm/drm_gem_vram_helper.c -+++ b/drivers/gpu/drm/drm_gem_vram_helper.c -@@ -870,7 +870,7 @@ static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo, - if (!tt) - return NULL; - -- ret = ttm_tt_init(tt, bo, page_flags, ttm_cached, 0); -+ ret = ttm_tt_init(tt, bo, page_flags, ttm_write_combined, 0); - if (ret < 0) - goto err_ttm_tt_init; - -diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c -index c4dda908666c..33b56ca7af6f 100644 ---- a/drivers/gpu/drm/radeon/radeon_irq_kms.c -+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c -@@ -250,10 +250,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev) - * of address for "64-bit" MSIs which breaks on some platforms, notably - * IBM POWER servers, so we limit them - */ -+#if 0 - if (rdev->family < CHIP_BONAIRE) { - dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n"); - rdev->pdev->no_64bit_msi = 1; - } -+#endif - - /* force MSI on */ - if (radeon_msi == 1) -diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c -index fd9fd3d15101..0c29e322cb60 100644 ---- a/drivers/gpu/drm/ttm/ttm_bo_util.c -+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c -@@ -345,7 +345,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, - ret = ttm_tt_populate(bo->bdev, ttm, &ctx); - if (ret) - return ret; -- -+#if 0 - if (num_pages == 1 && ttm->caching == ttm_cached) { - /* - * We're mapping a single page, and the desired -@@ -355,7 +355,9 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, - map->bo_kmap_type = ttm_bo_map_kmap; - map->page = ttm->pagesstart_page; - map->virtual = kmap(map->page); -- } else { -+ } else -+#endif -+ { - /* - * We need to use vmap to get the desired page protection - * or to make the buffer object look contiguous. -diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c -index b3fffe7b5062..aa137ead5cc5 100644 ---- a/drivers/gpu/drm/ttm/ttm_module.c -+++ b/drivers/gpu/drm/ttm/ttm_module.c -@@ -74,7 +74,8 @@ pgprot_t ttm_prot_from_caching(enum ttm_caching caching, pgprot_t tmp) - #endif /* CONFIG_UML */ - #endif /* __i386__ || __x86_64__ */ - #if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \ -- defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) -+ defined(__powerpc__) || defined(__mips__) || defined(__loongarch__) || \ -+ defined(__riscv) - if (caching == ttm_write_combined) - tmp = pgprot_writecombine(tmp); - else -diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c -index 46ff9c75bb12..63a9b8d41b94 100644 ---- a/drivers/gpu/drm/ttm/ttm_resource.c -+++ b/drivers/gpu/drm/ttm/ttm_resource.c -@@ -187,7 +187,7 @@ void ttm_resource_init(struct ttm_buffer_object *bo, - res->bus.addr = NULL; - res->bus.offset = 0; - res->bus.is_iomem = false; -- res->bus.caching = ttm_cached; -+ res->bus.caching = ttm_write_combined; - res->bo = bo; - - man = ttm_manager_type(bo->bdev, place->mem_type); -@@ -670,17 +670,18 @@ ttm_kmap_iter_linear_io_init(struct ttm_kmap_iter_linear_io *iter_io, - } else { - iter_io->needs_unmap = true; - memset(&iter_io->dmap, 0, sizeof(iter_io->dmap)); -- if (mem->bus.caching == ttm_write_combined) -+ if (mem->bus.caching == ttm_write_combined || mem->bus.caching == ttm_cached) - iosys_map_set_vaddr_iomem(&iter_io->dmap, - ioremap_wc(mem->bus.offset, - mem->size)); -+#if 0 - else if (mem->bus.caching == ttm_cached) - iosys_map_set_vaddr(&iter_io->dmap, - memremap(mem->bus.offset, mem->size, - MEMREMAP_WB | - MEMREMAP_WT | - MEMREMAP_WC)); -- -+#endif - /* If uncached requested or if mapping cached or wc failed */ - if (iosys_map_is_null(&iter_io->dmap)) - iosys_map_set_vaddr_iomem(&iter_io->dmap, -diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c -index e0a77671edd6..8ed5f661d536 100644 ---- a/drivers/gpu/drm/ttm/ttm_tt.c -+++ b/drivers/gpu/drm/ttm/ttm_tt.c -@@ -141,7 +141,7 @@ static void ttm_tt_init_fields(struct ttm_tt *ttm, - ttm->dma_address = NULL; - ttm->swap_storage = NULL; - ttm->sg = bo->sg; -- ttm->caching = caching; -+ ttm->caching = ttm_write_combined; - } - - int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo, -diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig -index bc2e265cb02d..ca9cfa3ac9f7 100644 ---- a/drivers/mailbox/Kconfig -+++ b/drivers/mailbox/Kconfig -@@ -295,4 +295,12 @@ config QCOM_IPCC - acts as an interrupt controller for receiving interrupts from clients. - Say Y here if you want to build this driver. - -+config THEAD_LIGHT_MBOX -+ bool "Thead light Mailbox" -+ depends on ARCH_THEAD || COMPILE_TEST -+ default y -+ help -+ Mailbox implementation for Thead light SoCs. -+ -+ - endif -diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile -index fc9376117111..7e82b9edccd4 100644 ---- a/drivers/mailbox/Makefile -+++ b/drivers/mailbox/Makefile -@@ -62,3 +62,6 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o - obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o - - obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o -+ -+obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox.o -+#obj-$(CONFIG_THEAD_LIGHT_MBOX) += light-mailbox-client.o -diff --git a/drivers/mailbox/light-mailbox-client.c b/drivers/mailbox/light-mailbox-client.c -new file mode 100644 -index 000000000000..10cf7ae15cbc ---- /dev/null -+++ b/drivers/mailbox/light-mailbox-client.c -@@ -0,0 +1,242 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/debugfs.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/mailbox_client.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+#define MBOX_MAX_MSG_LEN 28 -+#define WJ_MBOX_SEND_MAX_MESSAGE_LENGTH 28 -+#define HEXDUMP_BYTES_PER_LINE 28 -+#define HEXDUMP_LINE_LEN ((HEXDUMP_BYTES_PER_LINE * 4) + 2) -+#define HEXDUMP_MAX_LEN (HEXDUMP_LINE_LEN * \ -+ (MBOX_MAX_MSG_LEN / HEXDUMP_BYTES_PER_LINE)) -+ -+static struct dentry *root_debugfs_dir; -+ -+struct mbox_client_light_device { -+ struct device *dev; -+ void __iomem *tx_mmio; -+ void __iomem *rx_mmio; -+ struct mbox_chan *tx_channel; -+ struct mbox_chan *rx_channel; -+ char *rx_buffer; -+ char *message; -+ spinlock_t lock; -+}; -+ -+static ssize_t mbox_client_light_message_write(struct file *filp, -+ const char __user *userbuf, -+ size_t count, loff_t *ppos) -+{ -+ struct mbox_client_light_device *tdev = filp->private_data; -+ void *data; -+ int ret; -+ -+ if (!tdev->tx_channel) { -+ dev_err(tdev->dev, "Channel cannot do Tx\n"); -+ return -EINVAL; -+ } -+ -+ if (count > WJ_MBOX_SEND_MAX_MESSAGE_LENGTH) -+ count = WJ_MBOX_SEND_MAX_MESSAGE_LENGTH; -+ -+ tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); -+ if (!tdev->message) -+ return -ENOMEM; -+ -+ ret = copy_from_user(tdev->message, userbuf, count); -+ if (ret) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ data = tdev->message; -+ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->message, MBOX_MAX_MSG_LEN, true); -+ -+ ret = mbox_send_message(tdev->tx_channel, data); -+ if (ret < 0) -+ dev_err(tdev->dev, "Failed to send message via mailbox\n"); -+ -+out: -+ kfree(tdev->message); -+ return ret < 0 ? ret : count; -+} -+ -+static ssize_t mbox_client_light_message_read(struct file *filp, -+ char __user *userbuf, -+ size_t count, loff_t *ppos) -+{ -+ struct mbox_client_light_device *tdev = filp->private_data; -+ unsigned long flags; -+ -+ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); -+ spin_lock_irqsave(&tdev->lock, flags); -+ memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); -+ spin_unlock_irqrestore(&tdev->lock, flags); -+ -+ return MBOX_MAX_MSG_LEN; -+} -+ -+static const struct file_operations mbox_client_light_message_ops = { -+ .write = mbox_client_light_message_write, -+ .read = mbox_client_light_message_read, -+ .open = simple_open, -+ .llseek = generic_file_llseek, -+}; -+ -+static int index_names = 0; -+static bool debugfs_dir_created = false; -+static const char* file_names = {"mbox-client0", "mbox-client1"}; -+ -+static int mbox_client_light_add_debugfs(struct platform_device *pdev, -+ struct mbox_client_light_device *tdev) -+{ -+ if (!debugfs_initialized()) -+ return 0; -+ -+ if (index_names > 2) { -+ dev_err(&pdev->dev, "Max device index is 2\n"); -+ return 0; -+ } -+ -+ if (!debugfs_dir_created) { -+ root_debugfs_dir = debugfs_create_dir("mailbox",NULL); -+ if (!root_debugfs_dir) { -+ dev_err(&pdev->dev, -+ "Failed to create mailbox debugfs\n"); -+ return -EINVAL; -+ } -+ debugfs_dir_created = true; -+ } -+ -+ debugfs_create_file(file_namesindex_names, 0600, root_debugfs_dir, -+ tdev, &mbox_client_light_message_ops); -+ -+ index_names++; -+ return 0; -+} -+ -+static void mbox_client_light_receive_message(struct mbox_client *client, -+ void *message) -+{ -+ struct mbox_client_light_device *tdev = dev_get_drvdata(client->dev); -+ char *data = message; -+ -+ spin_lock(&tdev->lock); -+ memcpy(tdev->rx_buffer, data, MBOX_MAX_MSG_LEN); -+ spin_unlock(&tdev->lock); -+ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); -+} -+ -+static struct mbox_chan * -+mbox_client_light_request_channel(struct platform_device *pdev, -+ const char *name) -+{ -+ struct mbox_client *client; -+ struct mbox_chan *channel; -+ -+ client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); -+ if (!client) -+ return ERR_PTR(-ENOMEM); -+ -+ client->dev = &pdev->dev; -+ client->tx_block = true; -+ client->knows_txdone = false; -+ client->tx_tout = 500; -+ client->rx_callback = mbox_client_light_receive_message; -+ -+ channel = mbox_request_channel_byname(client, name); -+ if (IS_ERR(channel)) { -+ devm_kfree(&pdev->dev, client); -+ dev_warn(&pdev->dev, "Failed to request %s channel\n", name); -+ return NULL; -+ } -+ -+ return channel; -+} -+ -+static int mbox_client_light_probe(struct platform_device *pdev) -+{ -+ struct mbox_client_light_device *tdev; -+ int ret; -+ static int chan_idx = 0; -+ -+ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); -+ if (!tdev) -+ return -ENOMEM; -+ -+ if (!chan_idx) -+ tdev->tx_channel = mbox_client_light_request_channel(pdev, "902"); -+ else -+ tdev->tx_channel = mbox_client_light_request_channel(pdev, "906"); -+ if (!tdev->tx_channel) { -+ dev_err(&pdev->dev, "Request channel failed\n"); -+ return -EPROBE_DEFER; -+ } -+ chan_idx++; -+ /* In fact, rx_channel is same with tx_channel in C-SKY's mailbox */ -+ tdev->rx_channel = tdev->tx_channel; -+ -+ tdev->dev = &pdev->dev; -+ platform_set_drvdata(pdev, tdev); -+ -+ spin_lock_init(&tdev->lock); -+ -+ tdev->rx_buffer = devm_kzalloc(&pdev->dev, -+ MBOX_MAX_MSG_LEN, GFP_KERNEL); -+ if (!tdev->rx_buffer) -+ return -ENOMEM; -+ -+ ret = mbox_client_light_add_debugfs(pdev, tdev); -+ if (ret) -+ return ret; -+ -+ dev_info(&pdev->dev, "Successfully registered\n"); -+ -+ return 0; -+} -+ -+static int mbox_client_light_remove(struct platform_device *pdev) -+{ -+ struct mbox_client_light_device *tdev = platform_get_drvdata(pdev); -+ -+ debugfs_remove_recursive(root_debugfs_dir); -+ -+ if (tdev->tx_channel) -+ mbox_free_channel(tdev->tx_channel); -+ -+ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) -+ mbox_free_channel(tdev->rx_channel); -+ -+ return 0; -+} -+ -+static const struct of_device_id mbox_client_light_match = { -+ { .compatible = "thead,light-mbox-client" }, -+ {}, -+}; -+ -+static struct platform_driver mbox_client_light_driver = { -+ .driver = { -+ .name = "thead,light-mbox-client", -+ .of_match_table = mbox_client_light_match, -+ }, -+ .probe = mbox_client_light_probe, -+ .remove = mbox_client_light_remove, -+}; -+module_platform_driver(mbox_client_light_driver); -+ -+MODULE_AUTHOR("Alibaba Group Holding Limited"); -+MODULE_DESCRIPTION("Thead Light mailbox IPC client driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/mailbox/light-mailbox.c b/drivers/mailbox/light-mailbox.c -new file mode 100644 -index 000000000000..f3d34d947ec4 ---- /dev/null -+++ b/drivers/mailbox/light-mailbox.c -@@ -0,0 +1,507 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/clk.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/mailbox_controller.h> -+#include <linux/module.h> -+#include <linux/of_device.h> -+#include <linux/slab.h> -+ -+/* Status Register */ -+#define LIGHT_MBOX_STA 0x0 -+#define LIGHT_MBOX_CLR 0x4 -+#define LIGHT_MBOX_MASK 0xc -+ -+/* Transmit/receive data register: -+ * INFO0 ~ INFO6 -+ */ -+#define LIGHT_MBOX_INFO_NUM 8 -+#define LIGHT_MBOX_DATA_INFO_NUM 7 -+#define LIGHT_MBOX_INFO0 0x14 -+/* Transmit ack register: INFO7 */ -+#define LIGHT_MBOX_INFO7 0x30 -+ -+/* Generate remote icu IRQ Register */ -+#define LIGHT_MBOX_GEN 0x10 -+#define LIGHT_MBOX_GEN_RX_DATA BIT(6) -+#define LIGHT_MBOX_GEN_TX_ACK BIT(7) -+ -+#define LIGHT_MBOX_CHAN_RES_SIZE 0x1000 -+#define LIGHT_MBOX_CHANS 4 -+#define LIGHT_MBOX_CHAN_NAME_SIZE 20 -+ -+#define LIGHT_MBOX_ACK_MAGIC 0xdeadbeaf -+ -+enum light_mbox_chan_type { -+ LIGHT_MBOX_TYPE_TXRX, /* Tx & Rx chan */ -+ LIGHT_MBOX_TYPE_DB, /* Tx & Rx doorbell */ -+}; -+ -+enum light_mbox_icu_cpu_id { -+ LIGHT_MBOX_ICU_CPU0, /* 910T */ -+ LIGHT_MBOX_ICU_CPU1, /* 902 */ -+ LIGHT_MBOX_ICU_CPU2, /* 906 */ -+ LIGHT_MBOX_ICU_CPU3, /* 910R */ -+}; -+ -+struct light_mbox_con_priv { -+ enum light_mbox_icu_cpu_id idx; -+ enum light_mbox_chan_type type; -+ void __iomem *comm_local_base; -+ void __iomem *comm_remote_base; -+ char irq_descLIGHT_MBOX_CHAN_NAME_SIZE; -+ struct mbox_chan *chan; -+ struct tasklet_struct txdb_tasklet; -+}; -+ -+struct light_mbox_priv { -+ struct device *dev; -+ void __iomem *local_icuLIGHT_MBOX_CHANS; -+ void __iomem *remote_icuLIGHT_MBOX_CHANS - 1; -+ void __iomem *cur_cpu_ch_base; -+ enum light_mbox_icu_cpu_id cur_icu_cpu_id; -+ spinlock_t mbox_lock; /* control register lock */ -+ -+ struct mbox_controller mbox; -+ struct mbox_chan mbox_chansLIGHT_MBOX_CHANS; -+ -+ struct light_mbox_con_priv con_privLIGHT_MBOX_CHANS; -+ struct clk *clk; -+ int irq; -+}; -+ -+static struct light_mbox_priv *to_light_mbox_priv(struct mbox_controller *mbox) -+{ -+ return container_of(mbox, struct light_mbox_priv, mbox); -+} -+ -+static void light_mbox_write(struct light_mbox_priv *priv, u32 val, u32 offs) -+{ -+ iowrite32(val, priv->cur_cpu_ch_base + offs); -+} -+ -+static u32 light_mbox_read(struct light_mbox_priv *priv, u32 offs) -+{ -+ return ioread32(priv->cur_cpu_ch_base + offs); -+} -+ -+static u32 light_mbox_rmw(struct light_mbox_priv *priv, u32 off, u32 set, u32 clr) -+{ -+ unsigned long flags; -+ u32 val; -+ -+ spin_lock_irqsave(&priv->mbox_lock, flags); -+ val = light_mbox_read(priv, off); -+ val &= ~clr; -+ val |= set; -+ light_mbox_write(priv, val, off); -+ spin_unlock_irqrestore(&priv->mbox_lock, flags); -+ -+ return val; -+} -+ -+static void light_mbox_chan_write(struct light_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 light_mbox_chan_read(struct light_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 light_mbox_chan_rmw(struct light_mbox_con_priv *cp, u32 off, u32 set, u32 clr, bool is_remote) -+{ -+ struct light_mbox_priv *priv = to_light_mbox_priv(cp->chan->mbox); -+ unsigned long flags; -+ u32 val; -+ -+ spin_lock_irqsave(&priv->mbox_lock, flags); -+ val = light_mbox_chan_read(cp, off, is_remote); -+ val &= ~clr; -+ val |= set; -+ light_mbox_chan_write(cp, val, off, is_remote); -+ spin_unlock_irqrestore(&priv->mbox_lock, flags); -+} -+ -+static void light_mbox_chan_rd_data(struct light_mbox_con_priv *cp, void *data, bool is_remote) -+{ -+ u32 off = LIGHT_MBOX_INFO0; -+ u32 *arg = data; -+ u32 i; -+ -+ /* read info0 ~ info6, totally 28 bytes -+ * requires data memory size is 28 bytes -+ */ -+ for (i = 0; i < LIGHT_MBOX_DATA_INFO_NUM; i++) { -+ *arg = light_mbox_chan_read(cp, off, is_remote); -+ off += 4; -+ arg++; -+ } -+} -+ -+static void light_mbox_chan_wr_data(struct light_mbox_con_priv *cp, void *data, bool is_remote) -+{ -+ u32 off = LIGHT_MBOX_INFO0; -+ u32 *arg = data; -+ u32 i; -+ -+ /* write info0 ~ info6, totally 28 bytes -+ * requires data memory is 28 bytes valid data -+ */ -+ for (i = 0; i < LIGHT_MBOX_DATA_INFO_NUM; i++) { -+ light_mbox_chan_write(cp, *arg, off, is_remote); -+ off += 4; -+ arg++; -+ } -+} -+ -+static void light_mbox_chan_wr_ack(struct light_mbox_con_priv *cp, void *data, bool is_remote) -+{ -+ u32 off = LIGHT_MBOX_INFO7; -+ u32 *arg = data; -+ -+ light_mbox_chan_write(cp, *arg, off, is_remote); -+} -+ -+static int light_mbox_chan_id_to_mapbit(struct light_mbox_con_priv *cp) -+{ -+ struct light_mbox_priv *priv = to_light_mbox_priv(cp->chan->mbox); -+ int mapbit = 0; -+ int i; -+ -+ for (i = 0; i < LIGHT_MBOX_CHANS; i++) { -+ if (i == cp->idx) -+ return mapbit; -+ -+ if (i != priv->cur_icu_cpu_id) -+ mapbit++; -+ } -+ -+ if (i == LIGHT_MBOX_CHANS) -+ dev_err(cp->chan->mbox->dev, "convert to mapbit failed\n"); -+ -+ return 0; -+} -+ -+static void light_mbox_txdb_tasklet(unsigned long data) -+{ -+ struct light_mbox_con_priv *cp = (struct light_mbox_con_priv *)data; -+ -+ mbox_chan_txdone(cp->chan, 0); -+} -+ -+static irqreturn_t light_mbox_isr(int irq, void *p) -+{ -+ struct mbox_chan *chan = p; -+ struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); -+ struct light_mbox_con_priv *cp = chan->con_priv; -+ int mapbit = light_mbox_chan_id_to_mapbit(cp); -+ u32 sta, datLIGHT_MBOX_DATA_INFO_NUM; -+ u32 ack_magic = LIGHT_MBOX_ACK_MAGIC; -+ u32 info0_data, info7_data; -+ -+ sta = light_mbox_read(priv, LIGHT_MBOX_STA); -+ if (!(sta & BIT(mapbit))) -+ return IRQ_NONE; -+ -+ /* clear chan irq bit in STA register */ -+ light_mbox_rmw(priv, LIGHT_MBOX_CLR, BIT(mapbit), 0); -+ -+ /* rx doorbell */ -+ if (cp->type == LIGHT_MBOX_TYPE_DB) { -+ mbox_chan_received_data(cp->chan, NULL); -+ return IRQ_HANDLED; -+ } -+ -+ /* info0 is the protocol word, shoud not be zero! */ -+ info0_data = light_mbox_chan_read(cp, LIGHT_MBOX_INFO0, false); -+ if (info0_data) { -+ /* read info0~info6 data */ -+ light_mbox_chan_rd_data(cp, dat, false); -+ -+ /* clear local info0 */ -+ light_mbox_chan_write(cp, 0x0, LIGHT_MBOX_INFO0, false); -+ -+ /* notify remote cpu */ -+ light_mbox_chan_wr_ack(cp, &ack_magic, true); -+ /* CPU1 902/906 use polling mode to monitor info7 */ -+ if (cp->idx != LIGHT_MBOX_ICU_CPU1 && cp->idx != LIGHT_MBOX_ICU_CPU2) -+ light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, LIGHT_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 = light_mbox_chan_read(cp, LIGHT_MBOX_INFO7, false); -+ if (info7_data == LIGHT_MBOX_ACK_MAGIC) { -+ /* clear local info7 */ -+ light_mbox_chan_write(cp, 0x0, LIGHT_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 light_mbox_send_data(struct mbox_chan *chan, void *data) -+{ -+ struct light_mbox_con_priv *cp = chan->con_priv; -+ -+ if (cp->type == LIGHT_MBOX_TYPE_DB) -+ tasklet_schedule(&cp->txdb_tasklet); -+ else -+ light_mbox_chan_wr_data(cp, data, true); -+ light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, LIGHT_MBOX_GEN_RX_DATA, 0, true); -+ return 0; -+} -+ -+static int light_mbox_startup(struct mbox_chan *chan) -+{ -+ struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); -+ struct light_mbox_con_priv *cp = chan->con_priv; -+ u32 data8 = {0}; -+ int mask_bit; -+ int ret; -+ -+ /* clear local and remote generate and info0~info7 */ -+ light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, 0x0, 0xff, true); -+ light_mbox_chan_rmw(cp, LIGHT_MBOX_GEN, 0x0, 0xff, false); -+ light_mbox_chan_wr_ack(cp, &data7, true); -+ light_mbox_chan_wr_ack(cp, &data7, false); -+ light_mbox_chan_wr_data(cp, &data0, true); -+ light_mbox_chan_wr_data(cp, &data0, false); -+ -+ /* enable the chan mask */ -+ mask_bit = light_mbox_chan_id_to_mapbit(cp); -+ light_mbox_rmw(priv, LIGHT_MBOX_MASK, BIT(mask_bit), 0); -+ -+ if (cp->type == LIGHT_MBOX_TYPE_DB) -+ /* tx doorbell doesn't have ACK, rx doorbell requires isr */ -+ tasklet_init(&cp->txdb_tasklet, light_mbox_txdb_tasklet, -+ (unsigned long)cp); -+ -+ ret = request_irq(priv->irq, light_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 light_mbox_shutdown(struct mbox_chan *chan) -+{ -+ struct light_mbox_priv *priv = to_light_mbox_priv(chan->mbox); -+ struct light_mbox_con_priv *cp = chan->con_priv; -+ int mask_bit; -+ -+ /* clear the chan mask */ -+ mask_bit = light_mbox_chan_id_to_mapbit(cp); -+ light_mbox_rmw(priv, LIGHT_MBOX_MASK, 0, BIT(mask_bit)); -+ -+ free_irq(priv->irq, chan); -+} -+ -+static const struct mbox_chan_ops light_mbox_ops = { -+ .send_data = light_mbox_send_data, -+ .startup = light_mbox_startup, -+ .shutdown = light_mbox_shutdown, -+}; -+ -+static void light_mbox_init_generic(struct light_mbox_priv *priv) -+{ -+ /* Set default configuration */ -+ light_mbox_write(priv, 0xff, LIGHT_MBOX_CLR); -+ light_mbox_write(priv, 0x0, LIGHT_MBOX_MASK); -+} -+ -+static struct mbox_chan *light_mbox_xlate(struct mbox_controller *mbox, -+ const struct of_phandle_args *sp) -+{ -+ struct light_mbox_priv *priv = to_light_mbox_priv(mbox); -+ struct light_mbox_con_priv *cp; -+ u32 chan, type; -+ -+ if (sp->args_count != 2) { -+ dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ chan = sp->args0; /* comm remote channel */ -+ type = sp->args1; /* comm channel type */ -+ -+ if (chan >= mbox->num_chans) { -+ dev_err(mbox->dev, "Not supported channel number: %d\n", chan); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ if (chan == priv->cur_icu_cpu_id) { -+ dev_err(mbox->dev, "Cannot communicate with yourself\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ if (type > LIGHT_MBOX_TYPE_DB) { -+ dev_err(mbox->dev, "Not supported the type for channel%d\n", chan); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ cp = mbox->chanschan.con_priv; -+ cp->type = type; -+ -+ return &mbox->chanschan; -+} -+ -+static int light_mbox_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct light_mbox_priv *priv; -+ struct resource *res; -+ unsigned int remote_idx = 0; -+ unsigned int i; -+ int ret; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ if (of_property_read_u32(np, "icu_cpu_id", &priv->cur_icu_cpu_id)) { -+ dev_err(dev, "icu_cpu_id is missing\n"); -+ return -EINVAL; -+ } -+ -+ if (priv->cur_icu_cpu_id != LIGHT_MBOX_ICU_CPU0 && -+ priv->cur_icu_cpu_id != LIGHT_MBOX_ICU_CPU3) { -+ dev_err(dev, "icu_cpu_id is invalid\n"); -+ return -EINVAL; -+ } -+ -+ priv->dev = dev; -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "local_base"); -+ priv->local_icuLIGHT_MBOX_ICU_CPU0 = devm_ioremap_resource(dev, res); -+ if (IS_ERR(priv->local_icuLIGHT_MBOX_ICU_CPU0)) -+ return PTR_ERR(priv->local_icuLIGHT_MBOX_ICU_CPU0); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu0"); -+ priv->remote_icu0 = devm_ioremap_resource(dev, res); -+ if (IS_ERR(priv->remote_icu0)) -+ return PTR_ERR(priv->remote_icu0); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu1"); -+ priv->remote_icu1 = devm_ioremap_resource(dev, res); -+ if (IS_ERR(priv->remote_icu1)) -+ return PTR_ERR(priv->remote_icu1); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu2"); -+ priv->remote_icu2 = devm_ioremap_resource(dev, res); -+ if (IS_ERR(priv->remote_icu2)) -+ return PTR_ERR(priv->remote_icu2); -+ -+ priv->local_icuLIGHT_MBOX_ICU_CPU1 = priv->local_icuLIGHT_MBOX_ICU_CPU0 + -+ LIGHT_MBOX_CHAN_RES_SIZE; -+ priv->local_icuLIGHT_MBOX_ICU_CPU2 = priv->local_icuLIGHT_MBOX_ICU_CPU1 + -+ LIGHT_MBOX_CHAN_RES_SIZE; -+ priv->local_icuLIGHT_MBOX_ICU_CPU3 = priv->local_icuLIGHT_MBOX_ICU_CPU2 + -+ LIGHT_MBOX_CHAN_RES_SIZE; -+ -+ priv->cur_cpu_ch_base = priv->local_icupriv->cur_icu_cpu_id; -+ -+ priv->irq = platform_get_irq(pdev, 0); -+ if (priv->irq < 0) -+ return priv->irq; -+ -+ priv->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(priv->clk)) { -+ if (PTR_ERR(priv->clk) != -ENOENT) -+ return PTR_ERR(priv->clk); -+ -+ priv->clk = NULL; -+ } -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) { -+ dev_err(dev, "Failed to enable clock\n"); -+ return ret; -+ } -+ -+ /* init the chans */ -+ for (i = 0; i < LIGHT_MBOX_CHANS; i++) { -+ struct light_mbox_con_priv *cp = &priv->con_privi; -+ -+ cp->idx = i; -+ cp->chan = &priv->mbox_chansi; -+ priv->mbox_chansi.con_priv = cp; -+ snprintf(cp->irq_desc, sizeof(cp->irq_desc), -+ "light_mbox_chan%i", cp->idx); -+ -+ cp->comm_local_base = priv->local_icui; -+ if (i != priv->cur_icu_cpu_id) { -+ cp->comm_remote_base = priv->remote_icuremote_idx; -+ remote_idx++; -+ } -+ } -+ -+ spin_lock_init(&priv->mbox_lock); -+ -+ priv->mbox.dev = dev; -+ priv->mbox.ops = &light_mbox_ops; -+ priv->mbox.chans = priv->mbox_chans; -+ priv->mbox.num_chans = LIGHT_MBOX_CHANS; -+ priv->mbox.of_xlate = light_mbox_xlate; -+ priv->mbox.txdone_irq = true; -+ -+ platform_set_drvdata(pdev, priv); -+ -+ light_mbox_init_generic(priv); -+ -+ return devm_mbox_controller_register(dev, &priv->mbox); -+} -+ -+static int light_mbox_remove(struct platform_device *pdev) -+{ -+ struct light_mbox_priv *priv = platform_get_drvdata(pdev); -+ -+ clk_disable_unprepare(priv->clk); -+ -+ return 0; -+} -+ -+static const struct of_device_id light_mbox_dt_ids = { -+ { .compatible = "thead,light-mbox" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, light_mbox_dt_ids); -+ -+static struct platform_driver light_mbox_driver = { -+ .probe = light_mbox_probe, -+ .remove = light_mbox_remove, -+ .driver = { -+ .name = "light_mbox", -+ .of_match_table = light_mbox_dt_ids, -+ }, -+}; -+module_platform_driver(light_mbox_driver); -+ -+MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light mailbox IPC driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 554e67103c1a..97dd14701193 100644 ---- a/drivers/mmc/host/Kconfig -+++ b/drivers/mmc/host/Kconfig -@@ -654,6 +654,20 @@ config MMC_SDHCI_SPRD - - If unsure, say N. - -+config MMC_SDHCI_SOPHGO -+ tristate "Sophgo/BitMain SDIO host Controller" -+ depends on MMC_SDHCI_PLTFM -+ help -+ This selects the SDIO Host Controller in Sophgo/BitMain -+ SoCs. -+ -+ If you have a controller with this interface, say Y or M here. -+ -+ If unsure, say N. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called sdhci-sophgo. -+ - config MMC_TMIO_CORE - tristate - -diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile -index a693fa3d3f1c..36976786afe2 100644 ---- a/drivers/mmc/host/Makefile -+++ b/drivers/mmc/host/Makefile -@@ -95,6 +95,7 @@ obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o - obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o - obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o - obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o -+obj-$(CONFIG_MMC_SDHCI_SOPHGO) += sdhci-sophgo.o - obj-$(CONFIG_MMC_SUNPLUS) += sunplus-mmc.o - obj-$(CONFIG_MMC_CQHCI) += cqhci.o - cqhci-y += cqhci-core.o -diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c -index 3a3bae6948a8..0eb72544c09e 100644 ---- a/drivers/mmc/host/sdhci-of-dwcmshc.c -+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c -@@ -8,6 +8,7 @@ - */ - - #include <linux/acpi.h> -+#include <linux/bitfield.h> - #include <linux/clk.h> - #include <linux/dma-mapping.h> - #include <linux/iopoll.h> -@@ -35,6 +36,21 @@ - #define DWCMSHC_CARD_IS_EMMC BIT(0) - #define DWCMSHC_ENHANCED_STROBE BIT(8) - #define DWCMSHC_EMMC_ATCTRL 0x40 -+/* Tuning and auto-tuning fields in AT_CTRL_R control register */ -+#define AT_CTRL_AT_EN BIT(0) /* autotuning is enabled */ -+#define AT_CTRL_CI_SEL BIT(1) /* interval to drive center phase select */ -+#define AT_CTRL_SWIN_TH_EN BIT(2) /* sampling window threshold enable */ -+#define AT_CTRL_RPT_TUNE_ERR BIT(3) /* enable reporting framing errors */ -+#define AT_CTRL_SW_TUNE_EN BIT(4) /* enable software managed tuning */ -+#define AT_CTRL_WIN_EDGE_SEL_MASK GENMASK(11, 8) /* bits 11:8 */ -+#define AT_CTRL_WIN_EDGE_SEL 0xf /* sampling window edge select */ -+#define AT_CTRL_TUNE_CLK_STOP_EN BIT(16) /* clocks stopped during phase code change */ -+#define AT_CTRL_PRE_CHANGE_DLY_MASK GENMASK(18, 17) /* bits 18:17 */ -+#define AT_CTRL_PRE_CHANGE_DLY 0x1 /* 2-cycle latency */ -+#define AT_CTRL_POST_CHANGE_DLY_MASK GENMASK(20, 19) /* bits 20:19 */ -+#define AT_CTRL_POST_CHANGE_DLY 0x3 /* 4-cycle latency */ -+#define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits 31:24 */ -+#define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */ - - /* Rockchip specific Registers */ - #define DWCMSHC_EMMC_DLL_CTRL 0x800 -@@ -72,6 +88,82 @@ - (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) - #define RK35xx_MAX_CLKS 3 - -+/* PHY register area pointer */ -+#define DWC_MSHC_PTR_PHY_R 0x300 -+ -+/* PHY general configuration */ -+#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00) -+#define PHY_CNFG_RSTN_DEASSERT 0x1 /* Deassert PHY reset */ -+#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16) /* bits 19:16 */ -+#define PHY_CNFG_PAD_SP 0x0c /* PMOS TX drive strength */ -+#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20) /* bits 23:20 */ -+#define PHY_CNFG_PAD_SN 0x0c /* NMOS TX drive strength */ -+ -+/* PHY command/response pad settings */ -+#define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04) -+ -+/* PHY data pad settings */ -+#define PHY_DATAPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x06) -+ -+/* PHY clock pad settings */ -+#define PHY_CLKPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x08) -+ -+/* PHY strobe pad settings */ -+#define PHY_STBPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0a) -+ -+/* PHY reset pad settings */ -+#define PHY_RSTNPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0c) -+ -+/* Bitfields are common for all pad settings */ -+#define PHY_PAD_RXSEL_1V8 0x1 /* Receiver type select for 1.8V */ -+#define PHY_PAD_RXSEL_3V3 0x2 /* Receiver type select for 3.3V */ -+ -+#define PHY_PAD_WEAKPULL_MASK GENMASK(4, 3) /* bits 4:3 */ -+#define PHY_PAD_WEAKPULL_PULLUP 0x1 /* Weak pull up enabled */ -+#define PHY_PAD_WEAKPULL_PULLDOWN 0x2 /* Weak pull down enabled */ -+ -+#define PHY_PAD_TXSLEW_CTRL_P_MASK GENMASK(8, 5) /* bits 8:5 */ -+#define PHY_PAD_TXSLEW_CTRL_P 0x3 /* Slew control for P-Type pad TX */ -+#define PHY_PAD_TXSLEW_CTRL_N_MASK GENMASK(12, 9) /* bits 12:9 */ -+#define PHY_PAD_TXSLEW_CTRL_N 0x3 /* Slew control for N-Type pad TX */ -+ -+/* PHY CLK delay line settings */ -+#define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d) -+#define PHY_SDCLKDL_CNFG_UPDATE BIT(4) /* set before writing to SDCLKDL_DC */ -+ -+/* PHY CLK delay line delay code */ -+#define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e) -+#define PHY_SDCLKDL_DC_INITIAL 0x40 /* initial delay code */ -+#define PHY_SDCLKDL_DC_DEFAULT 0x32 /* default delay code */ -+#define PHY_SDCLKDL_DC_HS400 0x18 /* delay code for HS400 mode */ -+ -+/* PHY drift_cclk_rx delay line configuration setting */ -+#define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21) -+#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2) /* bits 3:2 */ -+#define PHY_ATDL_CNFG_INPSEL 0x3 /* delay line input source */ -+ -+/* PHY DLL control settings */ -+#define PHY_DLL_CTRL_R (DWC_MSHC_PTR_PHY_R + 0x24) -+#define PHY_DLL_CTRL_DISABLE 0x0 /* PHY DLL is enabled */ -+#define PHY_DLL_CTRL_ENABLE 0x1 /* PHY DLL is disabled */ -+ -+/* PHY DLL configuration register 1 */ -+#define PHY_DLL_CNFG1_R (DWC_MSHC_PTR_PHY_R + 0x25) -+#define PHY_DLL_CNFG1_SLVDLY_MASK GENMASK(5, 4) /* bits 5:4 */ -+#define PHY_DLL_CNFG1_SLVDLY 0x2 /* DLL slave update delay input */ -+#define PHY_DLL_CNFG1_WAITCYCLE 0x5 /* DLL wait cycle input */ -+ -+/* PHY DLL configuration register 2 */ -+#define PHY_DLL_CNFG2_R (DWC_MSHC_PTR_PHY_R + 0x26) -+#define PHY_DLL_CNFG2_JUMPSTEP 0xa /* DLL jump step input */ -+ -+/* PHY DLL master and slave delay line configuration settings */ -+#define PHY_DLLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x28) -+#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5) /* bits 6:5 */ -+#define PHY_DLLDL_CNFG_SLV_INPSEL 0x3 /* clock source select for slave DL */ -+ -+#define FLAG_IO_FIXED_1V8 BIT(0) -+ - #define BOUNDARY_OK(addr, len) \ - ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) - -@@ -92,6 +184,8 @@ struct dwcmshc_priv { - struct clk *bus_clk; - int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ - void *priv; /* pointer to SoC private stuff */ -+ u16 delay_line; -+ u16 flags; - }; - - /* -@@ -157,6 +251,127 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq) - sdhci_request(mmc, mrq); - } - -+static void dwcmshc_phy_1_8v_init(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); -+ u32 val; -+ -+ /* deassert phy reset & set tx drive strength */ -+ val = PHY_CNFG_RSTN_DEASSERT; -+ val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP); -+ val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN); -+ sdhci_writel(host, val, PHY_CNFG_R); -+ -+ /* disable delay line */ -+ sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R); -+ -+ /* set delay line */ -+ sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R); -+ sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R); -+ -+ /* enable delay lane */ -+ val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); -+ val &= ~(PHY_SDCLKDL_CNFG_UPDATE); -+ sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); -+ -+ /* configure phy pads */ -+ val = PHY_PAD_RXSEL_1V8; -+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); -+ sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); -+ sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); -+ sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); -+ -+ val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); -+ sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); -+ -+ val = PHY_PAD_RXSEL_1V8; -+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); -+ sdhci_writew(host, val, PHY_STBPAD_CNFG_R); -+ -+ /* enable data strobe mode */ -+ sdhci_writeb(host, FIELD_PREP(PHY_DLLDL_CNFG_SLV_INPSEL_MASK, PHY_DLLDL_CNFG_SLV_INPSEL), -+ PHY_DLLDL_CNFG_R); -+ -+ /* enable phy dll */ -+ sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); -+} -+ -+static void dwcmshc_phy_3_3v_init(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); -+ u32 val; -+ -+ /* deassert phy reset & set tx drive strength */ -+ val = PHY_CNFG_RSTN_DEASSERT; -+ val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP); -+ val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN); -+ sdhci_writel(host, val, PHY_CNFG_R); -+ -+ /* disable delay line */ -+ sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R); -+ -+ /* set delay line */ -+ sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R); -+ sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R); -+ -+ /* enable delay lane */ -+ val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R); -+ val &= ~(PHY_SDCLKDL_CNFG_UPDATE); -+ sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R); -+ -+ /* configure phy pads */ -+ val = PHY_PAD_RXSEL_3V3; -+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); -+ sdhci_writew(host, val, PHY_CMDPAD_CNFG_R); -+ sdhci_writew(host, val, PHY_DATAPAD_CNFG_R); -+ sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R); -+ -+ val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); -+ sdhci_writew(host, val, PHY_CLKPAD_CNFG_R); -+ -+ val = PHY_PAD_RXSEL_3V3; -+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P); -+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N); -+ sdhci_writew(host, val, PHY_STBPAD_CNFG_R); -+ -+ /* enable phy dll */ -+ sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R); -+} -+ -+static void th1520_sdhci_set_phy(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); -+ u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; -+ u16 emmc_ctrl; -+ -+ /* Before power on, set PHY configs */ -+ if (priv->flags & FLAG_IO_FIXED_1V8) -+ dwcmshc_phy_1_8v_init(host); -+ else -+ dwcmshc_phy_3_3v_init(host); -+ -+ if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { -+ emmc_ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); -+ emmc_ctrl |= DWCMSHC_CARD_IS_EMMC; -+ sdhci_writew(host, emmc_ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); -+ } -+ -+ sdhci_writeb(host, FIELD_PREP(PHY_DLL_CNFG1_SLVDLY_MASK, PHY_DLL_CNFG1_SLVDLY) | -+ PHY_DLL_CNFG1_WAITCYCLE, PHY_DLL_CNFG1_R); -+} -+ - static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, - unsigned int timing) - { -@@ -189,9 +404,25 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, - ctrl_2 |= DWCMSHC_CTRL_HS400; - } - -+ if (priv->flags & FLAG_IO_FIXED_1V8) -+ ctrl_2 |= SDHCI_CTRL_VDD_180; - sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); - } - -+static void th1520_set_uhs_signaling(struct sdhci_host *host, -+ unsigned int timing) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); -+ -+ dwcmshc_set_uhs_signaling(host, timing); -+ if (timing == MMC_TIMING_MMC_HS400) -+ priv->delay_line = PHY_SDCLKDL_DC_HS400; -+ else -+ sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R); -+ th1520_sdhci_set_phy(host); -+} -+ - static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc, - struct mmc_ios *ios) - { -@@ -338,6 +569,79 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) - sdhci_reset(host, mask); - } - -+static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); -+ u32 val = 0; -+ -+ if (host->flags & SDHCI_HS400_TUNING) -+ return 0; -+ -+ sdhci_writeb(host, FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL), -+ PHY_ATDL_CNFG_R); -+ val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); -+ -+ /* -+ * configure tuning settings: -+ * - center phase select code driven in block gap interval -+ * - disable reporting of framing errors -+ * - disable software managed tuning -+ * - disable user selection of sampling window edges, -+ * instead tuning calculated edges are used -+ */ -+ val &= ~(AT_CTRL_CI_SEL | AT_CTRL_RPT_TUNE_ERR | AT_CTRL_SW_TUNE_EN | -+ FIELD_PREP(AT_CTRL_WIN_EDGE_SEL_MASK, AT_CTRL_WIN_EDGE_SEL)); -+ -+ /* -+ * configure tuning settings: -+ * - enable auto-tuning -+ * - enable sampling window threshold -+ * - stop clocks during phase code change -+ * - set max latency in cycles between tx and rx clocks -+ * - set max latency in cycles to switch output phase -+ * - set max sampling window threshold value -+ */ -+ val |= AT_CTRL_AT_EN | AT_CTRL_SWIN_TH_EN | AT_CTRL_TUNE_CLK_STOP_EN; -+ val |= FIELD_PREP(AT_CTRL_PRE_CHANGE_DLY_MASK, AT_CTRL_PRE_CHANGE_DLY); -+ val |= FIELD_PREP(AT_CTRL_POST_CHANGE_DLY_MASK, AT_CTRL_POST_CHANGE_DLY); -+ val |= FIELD_PREP(AT_CTRL_SWIN_TH_VAL_MASK, AT_CTRL_SWIN_TH_VAL); -+ -+ sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); -+ val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); -+ -+ /* perform tuning */ -+ sdhci_start_tuning(host); -+ host->tuning_err = __sdhci_execute_tuning(host, opcode); -+ if (host->tuning_err) { -+ /* disable auto-tuning upon tuning error */ -+ val &= ~AT_CTRL_AT_EN; -+ sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); -+ dev_err(mmc_dev(host->mmc), "tuning failed: %d\n", host->tuning_err); -+ return -EIO; -+ } -+ sdhci_end_tuning(host); -+ -+ return 0; -+} -+ -+static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask) -+{ -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); -+ u16 ctrl_2; -+ -+ sdhci_reset(host, mask); -+ -+ if (priv->flags & FLAG_IO_FIXED_1V8) { -+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ if (!(ctrl_2 & SDHCI_CTRL_VDD_180)) { -+ ctrl_2 |= SDHCI_CTRL_VDD_180; -+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); -+ } -+ } -+} -+ - static const struct sdhci_ops sdhci_dwcmshc_ops = { - .set_clock = sdhci_set_clock, - .set_bus_width = sdhci_set_bus_width, -@@ -356,6 +660,17 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { - .adma_write_desc = dwcmshc_adma_write_desc, - }; - -+static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = { -+ .set_clock = sdhci_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .set_uhs_signaling = th1520_set_uhs_signaling, -+ .get_max_clock = dwcmshc_get_max_clock, -+ .reset = th1520_sdhci_reset, -+ .adma_write_desc = dwcmshc_adma_write_desc, -+ .voltage_switch = dwcmshc_phy_1_8v_init, -+ .platform_execute_tuning = &th1520_execute_tuning, -+}; -+ - static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { - .ops = &sdhci_dwcmshc_ops, - .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, -@@ -379,6 +694,12 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { - SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, - }; - -+static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = { -+ .ops = &sdhci_dwcmshc_th1520_ops, -+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, -+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, -+}; -+ - static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) - { - int err; -@@ -447,6 +768,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids = { - .compatible = "snps,dwcmshc-sdhci", - .data = &sdhci_dwcmshc_pdata, - }, -+ { -+ .compatible = "thead,th1520-dwcmshc", -+ .data = &sdhci_dwcmshc_th1520_pdata, -+ }, - {}, - }; - MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); -@@ -542,6 +867,30 @@ static int dwcmshc_probe(struct platform_device *pdev) - goto err_clk; - } - -+ if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) { -+ priv->delay_line = PHY_SDCLKDL_DC_DEFAULT; -+ -+ if ((device_property_read_bool(dev, "mmc-ddr-1_8v")) | -+ (device_property_read_bool(dev, "mmc-hs200-1_8v")) | -+ (device_property_read_bool(dev, "mmc-hs400-1_8v"))) -+ priv->flags |= FLAG_IO_FIXED_1V8; -+ else -+ priv->flags &= ~FLAG_IO_FIXED_1V8; -+ -+ /* -+ * start_signal_voltage_switch() will try 3.3V first -+ * then 1.8V. Use SDHCI_SIGNALING_180 rather than -+ * SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V -+ * in sdhci_start_signal_voltage_switch(). -+ */ -+ if (priv->flags & FLAG_IO_FIXED_1V8) { -+ host->flags &= ~SDHCI_SIGNALING_330; -+ host->flags |= SDHCI_SIGNALING_180; -+ } -+ -+ sdhci_enable_v4_mode(host); -+ } -+ - #ifdef CONFIG_ACPI - if (pltfm_data == &sdhci_dwcmshc_bf3_pdata) - sdhci_enable_v4_mode(host); -diff --git a/drivers/mmc/host/sdhci-sophgo.c b/drivers/mmc/host/sdhci-sophgo.c -new file mode 100644 -index 000000000000..8200ccaa68f6 ---- /dev/null -+++ b/drivers/mmc/host/sdhci-sophgo.c -@@ -0,0 +1,619 @@ -+/* -+ * Sophgo SDHCI Platform driver -+ * -+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/of_device.h> -+#include <linux/delay.h> -+#include <linux/mmc/mmc.h> -+#include <linux/slab.h> -+#include <linux/reset.h> -+#include "sdhci-pltfm.h" -+#include "sdhci-sophgo.h" -+ -+#define DRIVER_NAME "bm" -+ -+#define BM_SDHCI_VENDOR_OFFSET 0x500 -+#define BM_SDHCI_VENDOR_MSHC_CTRL_R (BM_SDHCI_VENDOR_OFFSET + 0x8) -+#define BM_SDHCI_VENDOR_A_CTRL_R (BM_SDHCI_VENDOR_OFFSET + 0x40) -+#define BM_SDHCI_VENDOR_A_STAT_R (BM_SDHCI_VENDOR_OFFSET + 0x44) -+ -+static void bm_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) -+{ -+ sdhci_writel(host, 0x0, BM_SDHCI_VENDOR_MSHC_CTRL_R); -+ sdhci_writel(host, 0x18, BM_SDHCI_VENDOR_A_CTRL_R); -+ sdhci_writel(host, tap, BM_SDHCI_VENDOR_A_STAT_R); -+} -+ -+static int sdhci_bm_execute_software_tuning(struct sdhci_host *host, u32 opcode) -+{ -+ unsigned int maxwidth = 0; -+ unsigned int tuntap; -+ struct { -+ unsigned int start; -+ unsigned int end; -+ unsigned int width; -+ } tunlist4; -+ unsigned int listcount; -+ unsigned int listsel; -+ -+ unsigned int tun = 0; -+ unsigned int max = 256; -+ int i; -+ -+ listcount = 0; -+ for (i = 0; i < ARRAY_SIZE(tunlist); i++) { -+ while (tun < max) { -+ bm_sdhci_set_tap(host, tun); -+ if (!mmc_send_tuning(host->mmc, opcode, NULL)) -+ break; -+ tun++; -+ } -+ tunlisti.start = tun; -+ tun++; -+ while (tun < max) { -+ bm_sdhci_set_tap(host, tun); -+ if (mmc_send_tuning(host->mmc, opcode, NULL)) -+ break; -+ tun++; -+ } -+ tunlisti.end = tun-1; -+ tunlisti.width = tunlisti.end - tunlisti.start; -+ listcount++; -+ tun++; -+ pr_info("%s id:%d start:%d end:%d width:%d\n", mmc_hostname(host->mmc), -+ i, tunlisti.start, tunlisti.end, tunlisti.width); -+ if (tun >= max) -+ break; -+ } -+ -+ //find maxwidth -+ listsel = 0; -+ for (i = 0; i < listcount; i++) { -+ if (tunlisti.width > maxwidth) { -+ maxwidth = tunlisti.width; -+ listsel = i; -+ } -+ } -+ tuntap = tunlistlistsel.start + (tunlistlistsel.width/2); -+ -+ /* The TRM states the ideal tap value is at 75% in the passing range. */ -+ bm_sdhci_set_tap(host, tuntap); -+ pr_info("%s listsel:%d tuntap:%d\n", -+ mmc_hostname(host->mmc), listsel, tuntap); -+ -+ return mmc_send_tuning(host->mmc, opcode, NULL); -+} -+ -+static int sdhci_bm_select_drive_strength(struct mmc_card *card, -+ unsigned int max_dtr, int host_drv, -+ int card_drv, int *drv_type) -+{ -+ struct sdhci_host *host = mmc_priv(card->host); -+ struct mmc_host *mmc = host->mmc; -+ uint32_t reg; -+ int driver_type; -+ -+ pr_info("%s max_dtr %d, host_drv %d, card_drv %d, drv_type %d\n", -+ mmc_hostname(mmc), -+ max_dtr, host_drv, card_drv, *drv_type); -+ -+ driver_type = MMC_SET_DRIVER_TYPE_C; -+ *drv_type = MMC_SET_DRIVER_TYPE_C; -+ -+ reg = (1 << PHY_CNFG_PHY_PWRGOOD) | (0xe << PHY_CNFG_PAD_SP) | -+ (0xe << PHY_CNFG_PAD_SN) | (1 << PHY_CNFG_PHY_RSTN); -+ sdhci_writel(host, reg, SDHCI_P_PHY_CNFG); -+ -+ return driver_type; -+} -+ -+static void sdhci_bm_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) -+{ -+ struct mmc_host *mmc = host->mmc; -+ u16 ctrl_2; -+ -+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ /* Select Bus Speed Mode for host */ -+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; -+ switch (uhs) { -+ case MMC_TIMING_UHS_SDR12: -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12; -+ break; -+ case MMC_TIMING_UHS_SDR25: -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25; -+ break; -+ case MMC_TIMING_UHS_SDR50: -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR50; -+ break; -+ case MMC_TIMING_MMC_HS200: -+ case MMC_TIMING_UHS_SDR104: -+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104; -+ break; -+ case MMC_TIMING_UHS_DDR50: -+ case MMC_TIMING_MMC_DDR52: -+ ctrl_2 |= SDHCI_CTRL_UHS_DDR50; -+ break; -+ } -+ -+ /* -+ * When clock frequency is less than 100MHz, the feedback clock must be -+ * provided and DLL must not be used so that tuning can be skipped. To -+ * provide feedback clock, the mode selection can be any value less -+ * than 3'b011 in bits 2:0 of HOST CONTROL2 register. -+ */ -+ if (host->clock <= 100000000 && -+ (uhs == MMC_TIMING_MMC_HS400 || -+ uhs == MMC_TIMING_MMC_HS200 || -+ uhs == MMC_TIMING_UHS_SDR104)) -+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; -+ -+ dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n", -+ mmc_hostname(host->mmc), host->clock, uhs, ctrl_2); -+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); -+} -+ -+static unsigned int bm_sdhci_get_min_clock(struct sdhci_host *host) -+{ -+ return 200 * 1000; -+} -+ -+static unsigned int bm_sdhci_get_max_clock(struct sdhci_host *host) -+{ -+ return 50 * 1000 * 1000; -+} -+ -+#if 0 // FIXME, SD card not working after this. -+static void bm_sdhci_hw_reset(struct sdhci_host *host) -+{ -+ struct sdhci_pltfm_host *pltfm_host; -+ struct sdhci_bm_host *bm_host; -+ struct mmc_host *mmc = host->mmc; -+ -+ pltfm_host = sdhci_priv(host); -+ bm_host = sdhci_pltfm_priv(pltfm_host); -+ -+ pr_info("%s hardware reset\n", mmc_hostname(mmc)); -+ reset_control_assert(bm_host->reset); -+ udelay(10); -+ reset_control_deassert(bm_host->reset); -+} -+#endif -+ -+void bm_sdhci_reset(struct sdhci_host *host, u8 mask) -+{ -+#if 0 // FIXME, SD card not working after this. -+ bm_sdhci_hw_reset(host); -+#endif -+ sdhci_reset(host, mask); -+ -+ if (mask & SDHCI_RESET_ALL) -+ bm_sdhci_phy_init(host); -+} -+ -+int bm_sdhci_phy_init(struct sdhci_host *host) -+{ -+ // Asset reset of phy -+ sdhci_writel(host, sdhci_readl(host, SDHCI_P_PHY_CNFG) & ~(1 << PHY_CNFG_PHY_RSTN), SDHCI_P_PHY_CNFG); -+ -+ // Set PAD_SN PAD_SP -+ sdhci_writel(host, -+ (1 << PHY_CNFG_PHY_PWRGOOD) | (0x9 << PHY_CNFG_PAD_SP) | (0x8 << PHY_CNFG_PAD_SN), -+ SDHCI_P_PHY_CNFG); -+ -+ // Set CMDPAD -+ sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | -+ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_CMDPAD_CNFG); -+ -+ // Set DATAPAD -+ sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | -+ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_DATPAD_CNFG); -+ -+ // Set CLKPAD -+ sdhci_writew(host, -+ (0x2 << PAD_CNFG_RXSEL) | (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), -+ SDHCI_P_CLKPAD_CNFG); -+ -+ // Set STB_PAD -+ sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (0x2 << PAD_CNFG_WEAKPULL_EN) | -+ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_STBPAD_CNFG); -+ -+ // Set RSTPAD -+ sdhci_writew(host, (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | -+ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N), SDHCI_P_RSTNPAD_CNFG); -+ -+ // Set SDCLKDL_CNFG, EXTDLY_EN = 1, fix delay -+ sdhci_writeb(host, (1 << SDCLKDL_CNFG_EXTDLY_EN), SDHCI_P_SDCLKDL_CNFG); -+ -+ // Add 10 * 70ps = 0.7ns for output delay -+ sdhci_writeb(host, 10, SDHCI_P_SDCLKDL_DC); -+ -+ //if (host->index == 1) { -+ // Set SMPLDL_CNFG, Bypass -+ sdhci_writeb(host, (1 << SMPLDL_CNFG_BYPASS_EN), SDHCI_P_SMPLDL_CNFG); -+ //} -+ //else { -+ // Set SMPLDL_CNFG, INPSEL_CNFG = 0x2 -+ //sdhci_writeb(host, (0x2 << SMPLDL_CNFG_INPSEL_CNFG), SDHCI_P_SMPLDL_CNFG); -+ //} -+ -+ // Set ATDL_CNFG, tuning clk not use for init -+ sdhci_writeb(host, (2 << ATDL_CNFG_INPSEL_CNFG), SDHCI_P_ATDL_CNFG); -+ -+ // deasset reset of phy -+ sdhci_writel(host, sdhci_readl(host, SDHCI_P_PHY_CNFG) | (1 << PHY_CNFG_PHY_RSTN), SDHCI_P_PHY_CNFG); -+ -+ return 0; -+} -+ -+void bm_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) -+{ -+ sdhci_set_clock(host, clock); -+ -+ if (clock == 0) -+ // forward tx -+ sdhci_writeb(host, 0x0, SDHCI_P_SDCLKDL_DC); -+ else -+ // revert tx -+ sdhci_writeb(host, 0x10, SDHCI_P_SDCLKDL_DC); -+} -+ -+/* -+ * If DMA addr spans 128MB boundary, we split the DMA transfer into two -+ * so that each DMA transfer doesn't exceed the boundary. -+ */ -+#define BOUNDARY_OK(addr, len) \ -+ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) -+ -+static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, -+ dma_addr_t addr, int len, unsigned int cmd) -+{ -+ int tmplen, offset; -+ -+ if (likely(!len || BOUNDARY_OK(addr, len))) { -+ sdhci_adma_write_desc(host, desc, addr, len, cmd); -+ return; -+ } -+ -+ offset = addr & (SZ_128M - 1); -+ tmplen = SZ_128M - offset; -+ sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); -+ -+ addr += tmplen; -+ len -= tmplen; -+ sdhci_adma_write_desc(host, desc, addr, len, cmd); -+} -+ -+ -+/* ------------- bm palludium sdcard --------------- */ -+static const struct sdhci_ops sdhci_bm_pldm_sd_ops = { -+ .reset = bm_sdhci_reset, -+ .set_clock = bm_sdhci_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .set_uhs_signaling = sdhci_bm_set_uhs_signaling, -+ .get_max_clock = bm_sdhci_get_max_clock, -+ .get_min_clock = bm_sdhci_get_min_clock, -+ .adma_write_desc = dwcmshc_adma_write_desc, -+}; -+ -+static const struct sdhci_pltfm_data sdhci_bm_pldm_sd_pdata = { -+ .ops = &sdhci_bm_pldm_sd_ops, -+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_INVERTED_WRITE_PROTECT, -+ .quirks2 = SDHCI_QUIRK2_NO_1_8_V, -+}; -+ -+static inline bool sdhci_data_line_cmd(struct mmc_command *cmd) -+{ -+ return cmd->data || cmd->flags & MMC_RSP_BUSY; -+} -+ -+static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) -+{ -+ if (sdhci_data_line_cmd(mrq->cmd)) -+ del_timer(&host->data_timer); -+ else -+ del_timer(&host->timer); -+} -+ -+int bm_platform_execute_tuning(struct sdhci_host *host, u32 opcode) -+{ -+ u16 ctrl; -+ int tuning_loop_counter = 0; -+ int err = 0; -+ unsigned long flags; -+ unsigned int tuning_count = 0; -+ bool hs400_tuning; -+ int hit = 0; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ -+ hs400_tuning = host->flags & SDHCI_HS400_TUNING; -+ host->flags &= ~SDHCI_HS400_TUNING; -+ -+ if (host->tuning_mode == SDHCI_TUNING_MODE_1) -+ tuning_count = host->tuning_count; -+ -+ switch (host->timing) { -+ /* HS400 tuning is done in HS200 mode */ -+ case MMC_TIMING_MMC_HS400: -+ err = -EINVAL; -+ goto out_unlock; -+ -+ case MMC_TIMING_MMC_HS200: -+ /* -+ * Periodic re-tuning for HS400 is not expected to be needed, so -+ * disable it here. -+ */ -+ if (hs400_tuning) -+ tuning_count = 0; -+ break; -+ -+ case MMC_TIMING_UHS_SDR104: -+ case MMC_TIMING_UHS_DDR50: -+ break; -+ -+ case MMC_TIMING_UHS_SDR50: -+ if (host->flags & SDHCI_SDR50_NEEDS_TUNING) -+ break; -+ -+ default: -+ goto out_unlock; -+ } -+ -+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); -+ ctrl |= SDHCI_CTRL_EXEC_TUNING; -+ -+ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE); -+ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE); -+ -+ sdhci_writew(host, 0x704b | (0x3<<4) | (0x1<<3), SDHCI_HOST_CONTROL2);/*drv_strength | 1.8v*/ -+ -+ sdhci_writel(host, 0, SDHCI_DMA_ADDRESS);/*sdmasa*/ -+ sdhci_writel(host, 0, SDHCI_MSHC_CTRL); -+ -+ sdhci_writel(host, 0x18, SDHCI_AT_CTRL); -+ -+ sdhci_writew(host, 0x0, SDHCI_BLOCK_COUNT); -+ sdhci_writew(host, 0x1040, SDHCI_BLOCK_SIZE); -+ sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); -+ -+ do { -+ struct mmc_command cmd = {0}; -+ struct mmc_request mrq = {NULL}; -+ -+ cmd.opcode = opcode; -+ cmd.arg = 0; -+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; -+ cmd.retries = 0; -+ cmd.data = NULL; -+ cmd.mrq = &mrq; -+ cmd.error = 0; -+ -+ sdhci_writel(host, tuning_loop_counter, SDHCI_AT_STAT); -+ mrq.cmd = &cmd; -+ sdhci_send_command(host, &cmd); -+ -+ host->cmd = NULL; -+ sdhci_del_timer(host, &mrq); -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ /* Wait for Buffer Read Ready interrupt */ -+ wait_event_timeout(host->buf_ready_int, -+ (host->tuning_done == 1), -+ msecs_to_jiffies(10)); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ if (host->tuning_done == 1) { -+ u16 stat; -+ -+ stat = sdhci_readw(host, SDHCI_ERR_INT_STATUS) & 0x3F; -+ if (stat == 0) -+ hit = tuning_loop_counter; -+ } -+ -+ host->tuning_done = 0; -+ tuning_loop_counter++; -+ sdhci_writeb(host, 0xFF, SDHCI_INT_STATUS); -+ sdhci_writeb(host, 0xFF, SDHCI_ERR_INT_STATUS); -+ sdhci_writeb(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA, SDHCI_SOFTWARE_RESET); -+ } while (tuning_loop_counter < MAX_TUNING_STEP); -+ -+ if (tuning_loop_counter >= MAX_TUNING_STEP) { -+ ctrl &= ~(SDHCI_CTRL_TUNED_CLK | SDHCI_CTRL_EXEC_TUNING); -+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); -+ } -+ -+ sdhci_writel(host, 0, SDHCI_AT_CTRL); -+ sdhci_writeb(host, 0xFF, SDHCI_INT_STATUS);/*clear normal int*/ -+ sdhci_writeb(host, 0xFF, SDHCI_ERR_INT_STATUS);/*clear error int*/ -+ sdhci_writel(host, sdhci_readl(host, SDHCI_AT_CTRL) | (0x1<<4), SDHCI_AT_CTRL);/*en sw_tuning_en bit*/ -+ sdhci_writel(host, (sdhci_readl(host, SDHCI_AT_STAT) & (~0xFF)) | hit, SDHCI_AT_STAT);/*center_ph_code*/ -+ sdhci_writel(host, sdhci_readl(host, SDHCI_AT_CTRL) & (~(0x1<<4)), SDHCI_AT_CTRL);/*dis sw_tuning_en bit*/ -+ sdhci_writeb(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA, SDHCI_SOFTWARE_RESET); -+ -+ if (tuning_count) -+ err = 0; -+ -+ host->mmc->retune_period = err ? 0 : tuning_count; -+ -+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); -+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); -+out_unlock: -+ spin_unlock_irqrestore(&host->lock, flags); -+ return err; -+} -+ -+/* ------------- bm palludium emmc --------------- */ -+static const struct sdhci_ops sdhci_bm_pldm_emmc_ops = { -+ .reset = sdhci_reset, -+ .set_clock = sdhci_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .set_uhs_signaling = sdhci_bm_set_uhs_signaling, -+ .get_max_clock = bm_sdhci_get_max_clock, -+ .get_min_clock = bm_sdhci_get_min_clock, -+ .platform_execute_tuning = bm_platform_execute_tuning, -+ .adma_write_desc = dwcmshc_adma_write_desc, -+}; -+ -+static const struct sdhci_pltfm_data sdhci_bm_pldm_emmc_pdata = { -+ .ops = &sdhci_bm_pldm_emmc_ops, -+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, -+}; -+ -+/* ------------ bm asic ------------ */ -+static const struct sdhci_ops sdhci_bm_ops = { -+ .reset = bm_sdhci_reset, -+ .set_clock = sdhci_set_clock, -+ .set_bus_width = sdhci_set_bus_width, -+ .set_uhs_signaling = sdhci_bm_set_uhs_signaling, -+ .platform_execute_tuning = sdhci_bm_execute_software_tuning, -+ .adma_write_desc = dwcmshc_adma_write_desc, -+}; -+ -+static const struct sdhci_pltfm_data sdhci_bm_emmc_pdata = { -+ .ops = &sdhci_bm_ops, -+ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT, -+ .quirks2 = 0, -+}; -+ -+static const struct sdhci_pltfm_data sdhci_bm_sd_pdata = { -+ .ops = &sdhci_bm_ops, -+ .quirks = SDHCI_QUIRK_INVERTED_WRITE_PROTECT, -+ .quirks2 = 0, -+}; -+ -+static const struct of_device_id sdhci_bm_dt_match = { -+ {.compatible = "bitmain,bm-pldm-sdcard", .data = &sdhci_bm_pldm_sd_pdata}, -+ {.compatible = "bitmain,bm-pldm-emmc", .data = &sdhci_bm_pldm_emmc_pdata}, -+ {.compatible = "bitmain,bm-emmc", .data = &sdhci_bm_emmc_pdata}, -+ {.compatible = "bitmain,bm-sd", .data = &sdhci_bm_sd_pdata}, -+ { /* sentinel */ } -+}; -+ -+MODULE_DEVICE_TABLE(of, sdhci_bm_dt_match); -+ -+static int sdhci_bm_probe(struct platform_device *pdev) -+{ -+ struct sdhci_host *host; -+ struct sdhci_pltfm_host *pltfm_host; -+ struct sdhci_bm_host *bm_host; -+ const struct of_device_id *match; -+ const struct sdhci_pltfm_data *pdata; -+ int ret; -+ -+ match = of_match_device(sdhci_bm_dt_match, &pdev->dev); -+ if (!match) -+ return -EINVAL; -+ -+ pdata = match->data; -+ -+ host = sdhci_pltfm_init(pdev, pdata, sizeof(*bm_host)); -+ if (IS_ERR(host)) -+ return PTR_ERR(host); -+ -+ pltfm_host = sdhci_priv(host); -+ bm_host = sdhci_pltfm_priv(pltfm_host); -+ bm_host->mmc = host->mmc; -+ bm_host->pdev = pdev; -+ bm_host->core_mem = host->ioaddr; -+ -+ ret = mmc_of_parse(host->mmc); -+ if (ret) -+ goto pltfm_free; -+ -+ sdhci_get_of_property(pdev); -+ -+ if (host->mmc->caps2 & MMC_CAP2_NO_SD) { -+ bm_host->reset = devm_reset_control_get(&pdev->dev, "emmc"); -+ if (IS_ERR(bm_host->reset)) { -+ ret = PTR_ERR(bm_host->reset); -+ goto pltfm_free; -+ } -+ -+ bm_host->clkaxi = devm_clk_get(&pdev->dev, "clk_gate_axi_emmc"); -+ if (IS_ERR(bm_host->clkaxi)) -+ dev_err(&pdev->dev, "get emmc clk axi failed\n"); -+ else -+ clk_prepare_enable(bm_host->clkaxi); -+ bm_host->clk = devm_clk_get(&pdev->dev, "clk_gate_emmc"); -+ if (IS_ERR(bm_host->clk)) -+ dev_err(&pdev->dev, "get emmc clk failed\n"); -+ else -+ clk_prepare_enable(bm_host->clk); -+ bm_host->clk100k = devm_clk_get(&pdev->dev, "clk_gate_100k_emmc"); -+ if (IS_ERR(bm_host->clk100k)) -+ dev_err(&pdev->dev, "get emmc clk 100k failed\n"); -+ else -+ clk_prepare_enable(bm_host->clk100k); -+ } else if (host->mmc->caps2 & MMC_CAP2_NO_MMC) { -+ bm_host->reset = devm_reset_control_get(&pdev->dev, "sdio"); -+ if (IS_ERR(bm_host->reset)) { -+ ret = PTR_ERR(bm_host->reset); -+ goto pltfm_free; -+ } -+ -+ bm_host->clkaxi = devm_clk_get(&pdev->dev, "clk_gate_axi_sd"); -+ if (IS_ERR(bm_host->clkaxi)) -+ dev_err(&pdev->dev, "get sd clk axi failed\n"); -+ else -+ clk_prepare_enable(bm_host->clkaxi); -+ bm_host->clk = devm_clk_get(&pdev->dev, "clk_gate_sd"); -+ if (IS_ERR(bm_host->clk)) -+ dev_err(&pdev->dev, "get sd clk failed\n"); -+ else -+ clk_prepare_enable(bm_host->clk); -+ bm_host->clk100k = devm_clk_get(&pdev->dev, "clk_gate_100k_sd"); -+ if (IS_ERR(bm_host->clk100k)) -+ dev_err(&pdev->dev, "get sd clk 100k failed\n"); -+ else -+ clk_prepare_enable(bm_host->clk100k); -+ } -+ -+ host->mmc_host_ops.select_drive_strength = sdhci_bm_select_drive_strength; -+ -+ ret = sdhci_add_host(host); -+ if (ret) -+ goto err_add_host; -+ -+ return 0; -+ -+err_add_host: -+pltfm_free: -+ sdhci_pltfm_free(pdev); -+ return ret; -+} -+ -+static int sdhci_bm_remove(struct platform_device *pdev) -+{ -+ struct sdhci_host *host = platform_get_drvdata(pdev); -+ int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); -+ -+ sdhci_remove_host(host, dead); -+ sdhci_pltfm_free(pdev); -+ return 0; -+} -+ -+static struct platform_driver sdhci_bm_driver = { -+ .probe = sdhci_bm_probe, -+ .remove = sdhci_bm_remove, -+ .driver = { -+ .name = DRIVER_NAME, -+ .of_match_table = sdhci_bm_dt_match, -+ }, -+}; -+ -+module_platform_driver(sdhci_bm_driver); -+MODULE_DESCRIPTION("BitMain Secure Digital Host Controller Interface driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/mmc/host/sdhci-sophgo.h b/drivers/mmc/host/sdhci-sophgo.h -new file mode 100644 -index 000000000000..508d0a16d71e ---- /dev/null -+++ b/drivers/mmc/host/sdhci-sophgo.h -@@ -0,0 +1,121 @@ -+/* -+ * drivers/mmc/host/sdhci-bm.c - BitMain SDHCI Platform driver -+ * -+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ */ -+ -+#ifndef __SDHCI_BM_H -+#define __SDHCI_BM_H -+ -+#include <linux/module.h> -+#include <linux/of_device.h> -+#include <linux/delay.h> -+#include <linux/mmc/mmc.h> -+#include <linux/slab.h> -+ -+/*register macro */ -+#define P_VENDOR_SPECIFIC_AREA 0xE8 -+#define P_VENDOR2_SPECIFIC_AREA 0xEA -+#define VENDOR_EMMC_CTRL 0x2C -+#define SW_RST_R 0x2F -+#define SDHCI_NORMAL_INT_STATUS 0x30 -+#define SDHCI_ERR_INT_STATUS 0x32 -+#define SDHCI_ERR_INT_STATUS_EN 0x36 -+#define SDHCI_HOST_CTRL2_R 0x3E -+#define SDHCI_MSHC_CTRL 0x508 -+#define SDHCI_AT_CTRL 0x540 -+#define SDHCI_AT_STAT 0x544 -+ -+/* PHY register */ -+#define SDHCI_PHY_R_OFFSET 0x300 -+ -+#define SDHCI_P_PHY_CNFG (SDHCI_PHY_R_OFFSET + 0x00) -+#define SDHCI_P_CMDPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x04) -+#define SDHCI_P_DATPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x06) -+#define SDHCI_P_CLKPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x08) -+#define SDHCI_P_STBPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0A) -+#define SDHCI_P_RSTNPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0C) -+#define SDHCI_P_PADTEST_CNFG (SDHCI_PHY_R_OFFSET + 0x0E) -+#define SDHCI_P_PADTEST_OUT (SDHCI_PHY_R_OFFSET + 0x10) -+#define SDHCI_P_PADTEST_IN (SDHCI_PHY_R_OFFSET + 0x12) -+#define SDHCI_P_COMMDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1C) -+#define SDHCI_P_SDCLKDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1D) -+#define SDHCI_P_SDCLKDL_DC (SDHCI_PHY_R_OFFSET + 0x1E) -+#define SDHCI_P_SMPLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x20) -+#define SDHCI_P_ATDL_CNFG (SDHCI_PHY_R_OFFSET + 0x21) -+#define SDHCI_P_DLL_CTRL (SDHCI_PHY_R_OFFSET + 0x24) -+#define SDHCI_P_DLL_CNFG1 (SDHCI_PHY_R_OFFSET + 0x25) -+#define SDHCI_P_DLL_CNFG2 (SDHCI_PHY_R_OFFSET + 0x26) -+#define SDHCI_P_DLLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x28) -+#define SDHCI_P_DLL_OFFST (SDHCI_PHY_R_OFFSET + 0x29) -+#define SDHCI_P_DLLMST_TSTDC (SDHCI_PHY_R_OFFSET + 0x2A) -+#define SDHCI_P_DLLLBT_CNFG (SDHCI_PHY_R_OFFSET + 0x2C) -+#define SDHCI_P_DLL_STATUS (SDHCI_PHY_R_OFFSET + 0x2E) -+#define SDHCI_P_DLLDBG_MLKDC (SDHCI_PHY_R_OFFSET + 0x30) -+#define SDHCI_P_DLLDBG_SLKDC (SDHCI_PHY_R_OFFSET + 0x32) -+ -+#define PHY_CNFG_PHY_RSTN 0 -+#define PHY_CNFG_PHY_PWRGOOD 1 -+#define PHY_CNFG_PAD_SP 16 -+#define PHY_CNFG_PAD_SP_MSK 0xf -+#define PHY_CNFG_PAD_SN 20 -+#define PHY_CNFG_PAD_SN_MSK 0xf -+ -+#define PAD_CNFG_RXSEL 0 -+#define PAD_CNFG_RXSEL_MSK 0x7 -+#define PAD_CNFG_WEAKPULL_EN 3 -+#define PAD_CNFG_WEAKPULL_EN_MSK 0x3 -+#define PAD_CNFG_TXSLEW_CTRL_P 5 -+#define PAD_CNFG_TXSLEW_CTRL_P_MSK 0xf -+#define PAD_CNFG_TXSLEW_CTRL_N 9 -+#define PAD_CNFG_TXSLEW_CTRL_N_MSK 0xf -+ -+#define COMMDL_CNFG_DLSTEP_SEL 0 -+#define COMMDL_CNFG_DLOUT_EN 1 -+ -+#define SDCLKDL_CNFG_EXTDLY_EN 0 -+#define SDCLKDL_CNFG_BYPASS_EN 1 -+#define SDCLKDL_CNFG_INPSEL_CNFG 2 -+#define SDCLKDL_CNFG_INPSEL_CNFG_MSK 0x3 -+#define SDCLKDL_CNFG_UPDATE_DC 4 -+ -+#define SMPLDL_CNFG_EXTDLY_EN 0 -+#define SMPLDL_CNFG_BYPASS_EN 1 -+#define SMPLDL_CNFG_INPSEL_CNFG 2 -+#define SMPLDL_CNFG_INPSEL_CNFG_MSK 0x3 -+#define SMPLDL_CNFG_INPSEL_OVERRIDE 4 -+ -+#define ATDL_CNFG_EXTDLY_EN 0 -+#define ATDL_CNFG_BYPASS_EN 1 -+#define ATDL_CNFG_INPSEL_CNFG 2 -+#define ATDL_CNFG_INPSEL_CNFG_MSK 0x3 -+ -+#define MAX_TUNING_STEP 128 -+ -+struct sdhci_bm_host { -+ struct platform_device *pdev; -+ void __iomem *core_mem; /* bm SDCC mapped address */ -+ struct clk *clk; /* main SD/MMC bus clock */ -+ struct clk *clk100k; -+ struct clk *clkaxi; -+ struct mmc_host *mmc; -+ struct reset_control *reset; -+ -+ struct reset_control *clk_rst_axi_emmc_ctrl; -+ struct reset_control *clk_rst_emmc_ctrl; -+ struct reset_control *clk_rst_100k_emmc_ctrl; -+}; -+ -+int bm_sdhci_phy_init(struct sdhci_host *host); -+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); -+#endif -diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index ff41aa56564e..526df8063579 100644 ---- a/drivers/mmc/host/sdhci.c -+++ b/drivers/mmc/host/sdhci.c -@@ -49,7 +49,9 @@ static unsigned int debug_quirks2; - - static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); - -+#ifndef CONFIG_ARCH_SOPHGO - static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); -+#endif - - void sdhci_dumpregs(struct sdhci_host *host) - { -@@ -1627,7 +1629,11 @@ static void sdhci_finish_data(struct sdhci_host *host) - __sdhci_finish_data(host, false); - } - -+#ifndef CONFIG_ARCH_SOPHGO - static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) -+#else -+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) -+#endif - { - int flags; - u32 mask; -@@ -1717,6 +1723,9 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) - - return true; - } -+#ifdef CONFIG_ARCH_SOPHGO -+EXPORT_SYMBOL_GPL(sdhci_send_command); -+#endif - - static bool sdhci_present_error(struct sdhci_host *host, - struct mmc_command *cmd, bool present) -@@ -2841,7 +2850,7 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode) - } - EXPORT_SYMBOL_GPL(sdhci_send_tuning); - --static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) -+int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) - { - int i; - -@@ -2879,6 +2888,7 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) - sdhci_reset_tuning(host); - return -EAGAIN; - } -+EXPORT_SYMBOL_GPL(__sdhci_execute_tuning); - - int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) - { -diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h -index f219bdea8f28..149e699aac92 100644 ---- a/drivers/mmc/host/sdhci.h -+++ b/drivers/mmc/host/sdhci.h -@@ -793,6 +793,7 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width); - void sdhci_reset(struct sdhci_host *host, u8 mask); - void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); - int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); -+int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode); - void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); - int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct mmc_ios *ios); -@@ -823,5 +824,8 @@ void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode); - void sdhci_switch_external_dma(struct sdhci_host *host, bool en); - void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable); - void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd); -+#ifdef CONFIG_ARCH_SOPHGO -+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); -+#endif - - #endif /* __SDHCI_HW_H */ -diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig -index 25f2d42de406..f70de0533599 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig -+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig -@@ -216,6 +216,17 @@ config DWMAC_SUN8I - stmmac device driver. This driver is used for H3/A83T/A64 - EMAC ethernet controller. - -+config DWMAC_THEAD -+ tristate "T-HEAD dwmac support" -+ depends on OF && (ARCH_THEAD || COMPILE_TEST) -+ select MFD_SYSCON -+ help -+ Support for ethernet controllers on T-HEAD RISC-V SoCs -+ -+ This selects the T-HEAD platform specific glue layer support for -+ the stmmac device driver. This driver is used for T-HEAD TH1520 -+ ethernet controller. -+ - 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 5b57aee19267..3d8221783e57 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/Makefile -+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile -@@ -27,6 +27,8 @@ obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o - obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o - obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o - obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o -+obj-$(CONFIG_ARCH_SOPHGO) += dwmac-sophgo.o -+obj-$(CONFIG_DWMAC_THEAD) += dwmac-thead.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-sophgo.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c -new file mode 100644 -index 000000000000..50a76c8f0df6 ---- /dev/null -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c -@@ -0,0 +1,268 @@ -+/* -+ * DWMAC specific glue layer -+ * -+ * Copyright (c) 2018 Bitmain Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include <linux/stmmac.h> -+#include <linux/module.h> -+#include <linux/phy.h> -+#include <linux/platform_device.h> -+#include <linux/of_net.h> -+#include <linux/of_gpio.h> -+#include <linux/io.h> -+ -+#include "stmmac_platform.h" -+ -+struct bm_mac { -+ struct device *dev; -+ struct reset_control *rst; -+ struct clk *clk_tx; -+ struct clk *gate_clk_tx; -+ struct clk *gate_clk_ref; -+ struct gpio_desc *reset; -+}; -+ -+static u64 bm_dma_mask = DMA_BIT_MASK(40); -+ -+static int bm_eth_reset_phy(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ int phy_reset_gpio; -+ -+ if (!np) -+ return 0; -+ -+ phy_reset_gpio = of_get_named_gpio(np, "phy-reset-gpios", 0); -+ -+ if (phy_reset_gpio < 0) -+ return 0; -+ -+ if (gpio_request(phy_reset_gpio, "eth-phy-reset")) -+ return 0; -+ -+ /* RESET_PU */ -+ gpio_direction_output(phy_reset_gpio, 0); -+ mdelay(100); -+ -+ gpio_direction_output(phy_reset_gpio, 1); -+ /* RC charging time */ -+ mdelay(100); -+ -+ return 0; -+} -+ -+static void bm_mac_fix_speed(void *priv, unsigned int speed, unsigned int mode) -+{ -+ struct bm_mac *bsp_priv = priv; -+ unsigned long rate = 125000000; -+ bool needs_calibration = false; -+ int err; -+ -+ switch (speed) { -+ case SPEED_1000: -+ needs_calibration = true; -+ rate = 125000000; -+ break; -+ -+ case SPEED_100: -+ needs_calibration = true; -+ rate = 25000000; -+ break; -+ -+ case SPEED_10: -+ needs_calibration = true; -+ rate = 2500000; -+ break; -+ -+ default: -+ dev_err(bsp_priv->dev, "invalid speed %u\n", speed); -+ break; -+ } -+ -+ if (needs_calibration) { -+ err = clk_set_rate(bsp_priv->clk_tx, rate); -+ if (err < 0) -+ dev_err(bsp_priv->dev, "failed to set TX rate: %d\n" -+ , err); -+ } -+} -+ -+void bm_dwmac_exit(struct platform_device *pdev, void *priv) -+{ -+ struct bm_mac *bsp_priv = priv; -+ -+ clk_disable_unprepare(bsp_priv->gate_clk_tx); -+ clk_disable_unprepare(bsp_priv->gate_clk_ref); -+} -+ -+static int bm_validate_ucast_entries(struct device *dev, int ucast_entries) -+{ -+ int x = ucast_entries; -+ -+ switch (x) { -+ case 1 ... 32: -+ case 64: -+ case 128: -+ break; -+ default: -+ x = 1; -+ dev_info(dev, "Unicast table entries set to unexpected value %d\n", -+ ucast_entries); -+ break; -+ } -+ return x; -+} -+ -+static int bm_validate_mcast_bins(struct device *dev, int mcast_bins) -+{ -+ int x = mcast_bins; -+ -+ switch (x) { -+ case HASH_TABLE_SIZE: -+ case 128: -+ case 256: -+ break; -+ default: -+ x = 0; -+ dev_info(dev, "Hash table entries set to unexpected value %d\n", -+ mcast_bins); -+ break; -+ } -+ return x; -+} -+ -+static void bm_dwmac_probe_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ -+ of_property_read_u32(np, "snps,multicast-filter-bins", &plat->multicast_filter_bins); -+ of_property_read_u32(np, "snps,perfect-filter-entries", &plat->unicast_filter_entries); -+ plat->unicast_filter_entries = bm_validate_ucast_entries(&pdev->dev, -+ plat->unicast_filter_entries); -+ plat->multicast_filter_bins = bm_validate_mcast_bins(&pdev->dev, -+ plat->multicast_filter_bins); -+ plat->flags |= (STMMAC_FLAG_TSO_EN); -+ plat->has_gmac4 = 1; -+ plat->has_gmac = 0; -+ plat->pmt = 0; -+} -+ -+static int bm_dwmac_probe(struct platform_device *pdev) -+{ -+ struct plat_stmmacenet_data *plat_dat; -+ struct stmmac_resources stmmac_res; -+ struct bm_mac *bsp_priv = NULL; -+ struct phy_device *phydev = NULL; -+ struct stmmac_priv *priv = NULL; -+ struct net_device *ndev = NULL; -+ int ret; -+ -+ pdev->dev.dma_mask = &bm_dma_mask; -+ pdev->dev.coherent_dma_mask = bm_dma_mask; -+ -+ bm_eth_reset_phy(pdev); -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return ret; -+ -+ plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); -+ if (IS_ERR(plat_dat)) -+ return PTR_ERR(plat_dat); -+ -+ bm_dwmac_probe_config_dt(pdev, plat_dat); -+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -+ if (ret) -+ goto err_remove_config_dt; -+ -+ bsp_priv = devm_kzalloc(&pdev->dev, sizeof(*bsp_priv), GFP_KERNEL); -+ if (!bsp_priv) -+ return PTR_ERR(bsp_priv); -+ -+ bsp_priv->dev = &pdev->dev; -+ -+ /* clock setup */ -+ bsp_priv->clk_tx = devm_clk_get(&pdev->dev, -+ "clk_tx"); -+ if (IS_ERR(bsp_priv->clk_tx)) -+ dev_warn(&pdev->dev, "Cannot get mac tx clock!\n"); -+ else -+ plat_dat->fix_mac_speed = bm_mac_fix_speed; -+ -+ bsp_priv->gate_clk_tx = devm_clk_get(&pdev->dev, "gate_clk_tx"); -+ if (IS_ERR(bsp_priv->gate_clk_tx)) -+ dev_warn(&pdev->dev, "Cannot get mac tx gating clock!\n"); -+ else -+ clk_prepare_enable(bsp_priv->gate_clk_tx); -+ -+ bsp_priv->gate_clk_ref = devm_clk_get(&pdev->dev, "gate_clk_ref"); -+ if (IS_ERR(bsp_priv->gate_clk_ref)) -+ dev_warn(&pdev->dev, "Cannot get mac ref gating clock!\n"); -+ else -+ clk_prepare_enable(bsp_priv->gate_clk_ref); -+ -+ plat_dat->bsp_priv = bsp_priv; -+ plat_dat->exit = bm_dwmac_exit; -+ -+ ndev = dev_get_drvdata(&pdev->dev); -+ priv = netdev_priv(ndev); -+ phydev = mdiobus_get_phy(priv->mii, 0); -+ if (phydev == NULL) { -+ dev_err(&pdev->dev, "Can not get phy in addr 0\n"); -+ goto err_remove_config_dt; -+ } -+ -+ /* set green LED0 active for transmit, yellow LED1 for link*/ -+ ret = phy_write_paged(phydev, 0, 0x1f, 0xd04); -+ if (ret < 0) -+ dev_err(&pdev->dev, "Can not select page 0xd04\n"); -+ ret = phy_write_paged(phydev, 0xd04, 0x10, 0x617f); -+ if (ret < 0) -+ dev_err(&pdev->dev, "Can not alter LED Configuration\n"); -+ /* disable eee LED function */ -+ ret = phy_write_paged(phydev, 0xd04, 0x11, 0x0); -+ if (ret < 0) -+ dev_err(&pdev->dev, "Can not disable EEE Configuration\n"); -+ ret = phy_write_paged(phydev, 0, 0x1f, 0); -+ if (ret < 0) -+ dev_err(&pdev->dev, "Can not select page 0\n"); -+ -+ return 0; -+ -+err_remove_config_dt: -+ stmmac_remove_config_dt(pdev, plat_dat); -+ -+ return ret; -+} -+ -+static const struct of_device_id bm_dwmac_match = { -+ { .compatible = "bitmain,ethernet" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, bm_dwmac_match); -+ -+static struct platform_driver bm_dwmac_driver = { -+ .probe = bm_dwmac_probe, -+ .remove_new = stmmac_pltfr_remove, -+ .driver = { -+ .name = "bm-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = bm_dwmac_match, -+ }, -+}; -+module_platform_driver(bm_dwmac_driver); -+ -+MODULE_AUTHOR("Wei Huang<wei.huang01@bitmain.com>"); -+MODULE_DESCRIPTION("Bitmain DWMAC specific glue layer"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c -new file mode 100644 -index 000000000000..fec27f78a417 ---- /dev/null -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c -@@ -0,0 +1,289 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * T-HEAD DWMAC platform driver -+ * -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org> -+ * -+ */ -+ -+#include <linux/bitfield.h> -+#include <linux/mfd/syscon.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/of_net.h> -+#include <linux/platform_device.h> -+#include <linux/regmap.h> -+ -+#include "stmmac_platform.h" -+ -+#define GMAC_CLK_EN 0x00 -+#define GMAC_TX_CLK_EN BIT(1) -+#define GMAC_TX_CLK_N_EN BIT(2) -+#define GMAC_TX_CLK_OUT_EN BIT(3) -+#define GMAC_RX_CLK_EN BIT(4) -+#define GMAC_RX_CLK_N_EN BIT(5) -+#define GMAC_EPHY_REF_CLK_EN BIT(6) -+#define GMAC_RXCLK_DELAY_CTRL 0x04 -+#define GMAC_RXCLK_BYPASS BIT(15) -+#define GMAC_RXCLK_INVERT BIT(14) -+#define GMAC_RXCLK_DELAY_MASK GENMASK(4, 0) -+#define GMAC_RXCLK_DELAY_VAL(x) FIELD_PREP(GMAC_RXCLK_DELAY_MASK, (x)) -+#define GMAC_TXCLK_DELAY_CTRL 0x08 -+#define GMAC_TXCLK_BYPASS BIT(15) -+#define GMAC_TXCLK_INVERT BIT(14) -+#define GMAC_TXCLK_DELAY_MASK GENMASK(4, 0) -+#define GMAC_TXCLK_DELAY_VAL(x) FIELD_PREP(GMAC_RXCLK_DELAY_MASK, (x)) -+#define GMAC_PLLCLK_DIV 0x0c -+#define GMAC_PLLCLK_DIV_EN BIT(31) -+#define GMAC_PLLCLK_DIV_MASK GENMASK(7, 0) -+#define GMAC_PLLCLK_DIV_NUM(x) FIELD_PREP(GMAC_PLLCLK_DIV_MASK, (x)) -+#define GMAC_GTXCLK_SEL 0x18 -+#define GMAC_GTXCLK_SEL_PLL BIT(0) -+#define GMAC_INTF_CTRL 0x1c -+#define PHY_INTF_MASK BIT(0) -+#define PHY_INTF_RGMII FIELD_PREP(PHY_INTF_MASK, 1) -+#define PHY_INTF_MII_GMII FIELD_PREP(PHY_INTF_MASK, 0) -+#define GMAC_TXCLK_OEN 0x20 -+#define TXCLK_DIR_MASK BIT(0) -+#define TXCLK_DIR_OUTPUT FIELD_PREP(TXCLK_DIR_MASK, 0) -+#define TXCLK_DIR_INPUT FIELD_PREP(TXCLK_DIR_MASK, 1) -+ -+#define GMAC_GMII_RGMII_RATE 125000000 -+#define GMAC_MII_RATE 25000000 -+ -+struct thead_dwmac { -+ struct plat_stmmacenet_data *plat; -+ struct regmap *apb_regmap; -+ struct device *dev; -+ u32 rx_delay; -+ u32 tx_delay; -+}; -+ -+static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat) -+{ -+ struct thead_dwmac *dwmac = plat->bsp_priv; -+ u32 phyif; -+ -+ switch (plat->mac_interface) { -+ case PHY_INTERFACE_MODE_MII: -+ phyif = PHY_INTF_MII_GMII; -+ break; -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ phyif = PHY_INTF_RGMII; -+ break; -+ default: -+ dev_err(dwmac->dev, "unsupported phy interface %d\n", -+ plat->mac_interface); -+ return -EINVAL; -+ }; -+ -+ regmap_write(dwmac->apb_regmap, GMAC_INTF_CTRL, phyif); -+ -+ return 0; -+} -+ -+static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) -+{ -+ struct thead_dwmac *dwmac = plat->bsp_priv; -+ u32 txclk_dir; -+ -+ switch (plat->mac_interface) { -+ case PHY_INTERFACE_MODE_MII: -+ txclk_dir = TXCLK_DIR_INPUT; -+ break; -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ txclk_dir = TXCLK_DIR_OUTPUT; -+ break; -+ default: -+ dev_err(dwmac->dev, "unsupported phy interface %d\n", -+ plat->mac_interface); -+ return -EINVAL; -+ }; -+ -+ regmap_write(dwmac->apb_regmap, GMAC_TXCLK_OEN, txclk_dir); -+ -+ return 0; -+} -+ -+static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode) -+{ -+ struct thead_dwmac *dwmac = priv; -+ struct plat_stmmacenet_data *plat = dwmac->plat; -+ unsigned long rate; -+ u32 div; -+ -+ switch (plat->mac_interface) { -+ /* For MII, rxc/txc is provided by phy */ -+ case PHY_INTERFACE_MODE_MII: -+ return; -+ -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ rate = clk_get_rate(plat->stmmac_clk); -+ if (!rate || rate % GMAC_GMII_RGMII_RATE != 0 || -+ rate % GMAC_MII_RATE != 0) { -+ dev_err(dwmac->dev, "invalid gmac rate %ld\n", rate); -+ return; -+ } -+ -+ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, GMAC_PLLCLK_DIV_EN, 0); -+ -+ switch (speed) { -+ case SPEED_1000: -+ div = rate / GMAC_GMII_RGMII_RATE; -+ break; -+ case SPEED_100: -+ div = rate / GMAC_MII_RATE; -+ break; -+ case SPEED_10: -+ div = rate * 10 / GMAC_MII_RATE; -+ break; -+ default: -+ dev_err(dwmac->dev, "invalid speed %u\n", speed); -+ return; -+ } -+ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, -+ GMAC_PLLCLK_DIV_MASK, GMAC_PLLCLK_DIV_NUM(div)); -+ -+ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, -+ GMAC_PLLCLK_DIV_EN, GMAC_PLLCLK_DIV_EN); -+ break; -+ default: -+ dev_err(dwmac->dev, "unsupported phy interface %d\n", -+ plat->mac_interface); -+ return; -+ } -+} -+ -+static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) -+{ -+ struct thead_dwmac *dwmac = plat->bsp_priv; -+ u32 reg; -+ -+ switch (plat->mac_interface) { -+ case PHY_INTERFACE_MODE_MII: -+ reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN; -+ break; -+ -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ /* use pll */ -+ regmap_write(dwmac->apb_regmap, GMAC_GTXCLK_SEL, GMAC_GTXCLK_SEL_PLL); -+ -+ reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN | -+ GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN; -+ break; -+ -+ default: -+ dev_err(dwmac->dev, "unsupported phy interface %d\n", -+ plat->mac_interface); -+ return -EINVAL; -+ } -+ -+ regmap_write(dwmac->apb_regmap, GMAC_CLK_EN, reg); -+ -+ return 0; -+} -+ -+static int thead_dwmac_init(struct platform_device *pdev, -+ struct plat_stmmacenet_data *plat) -+{ -+ struct thead_dwmac *dwmac = plat->bsp_priv; -+ int ret; -+ -+ ret = thead_dwmac_set_phy_if(plat); -+ if (ret) -+ return ret; -+ -+ ret = thead_dwmac_set_txclk_dir(plat); -+ if (ret) -+ return ret; -+ -+ regmap_write(dwmac->apb_regmap, GMAC_RXCLK_DELAY_CTRL, -+ GMAC_RXCLK_DELAY_VAL(dwmac->rx_delay)); -+ regmap_write(dwmac->apb_regmap, GMAC_TXCLK_DELAY_CTRL, -+ GMAC_TXCLK_DELAY_VAL(dwmac->tx_delay)); -+ -+ thead_dwmac_fix_speed(dwmac, SPEED_1000, 0); -+ -+ return thead_dwmac_enable_clk(plat); -+} -+ -+static int thead_dwmac_probe(struct platform_device *pdev) -+{ -+ struct plat_stmmacenet_data *plat; -+ struct stmmac_resources stmmac_res; -+ struct thead_dwmac *dwmac; -+ struct device_node *np = pdev->dev.of_node; -+ u32 delay_ps; -+ int ret; -+ -+ ret = stmmac_get_platform_resources(pdev, &stmmac_res); -+ if (ret) -+ return dev_err_probe(&pdev->dev, ret, -+ "failed to get resources\n"); -+ -+ plat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); -+ if (IS_ERR(plat)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(plat), -+ "dt configuration failed\n"); -+ -+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); -+ if (!dwmac) -+ return -ENOMEM; -+ -+ if (!of_property_read_u32(np, "rx-internal-delay-ps", &delay_ps)) -+ dwmac->rx_delay = delay_ps; -+ if (!of_property_read_u32(np, "tx-internal-delay-ps", &delay_ps)) -+ dwmac->tx_delay = delay_ps; -+ -+ dwmac->apb_regmap = syscon_regmap_lookup_by_phandle(np, "thead,gmacapb"); -+ if (IS_ERR(dwmac->apb_regmap)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->apb_regmap), -+ "Failed to get gmac apb syscon\n"); -+ -+ dwmac->dev = &pdev->dev; -+ dwmac->plat = plat; -+ plat->bsp_priv = dwmac; -+ plat->fix_mac_speed = thead_dwmac_fix_speed; -+ -+ ret = thead_dwmac_init(pdev, plat); -+ if (ret) -+ return ret; -+ -+ return stmmac_dvr_probe(&pdev->dev, plat, &stmmac_res); -+} -+ -+static const struct of_device_id thead_dwmac_match = { -+ { .compatible = "thead,th1520-dwmac" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, thead_dwmac_match); -+ -+static struct platform_driver thead_dwmac_driver = { -+ .probe = thead_dwmac_probe, -+ .remove_new = stmmac_pltfr_remove, -+ .driver = { -+ .name = "thead-dwmac", -+ .pm = &stmmac_pltfr_pm_ops, -+ .of_match_table = thead_dwmac_match, -+ }, -+}; -+module_platform_driver(thead_dwmac_driver); -+ -+MODULE_AUTHOR("T-HEAD"); -+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); -+MODULE_DESCRIPTION("T-HEAD dwmac platform driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig -index 291d12711363..25c768d5afb4 100644 ---- a/drivers/pci/controller/cadence/Kconfig -+++ b/drivers/pci/controller/cadence/Kconfig -@@ -42,6 +42,17 @@ config PCIE_CADENCE_PLAT_EP - endpoint mode. This PCIe controller may be embedded into many - different vendors SoCs. - -+config PCIE_CADENCE_SOPHGO -+ bool "Cadence Sophgo PCIe Host controller" -+ depends on OF -+ select IRQ_DOMAIN -+ select PCIE_CADENCE -+ help -+ Say Y here if you want to support the Cadence PCIe controller in host mode -+ for Sophgo SoCs. this PCIe controller is from cadence, integrated into the -+ Sophgo SoCs. PCIe is one of subsystems, it is choisable, Don't be -+ care of this if it is not used in your systems. -+ - config PCI_J721E - bool - -diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile -index 9bac5fb2f13d..edac7c5e94a3 100644 ---- a/drivers/pci/controller/cadence/Makefile -+++ b/drivers/pci/controller/cadence/Makefile -@@ -4,3 +4,4 @@ obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o - obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o - obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o - obj-$(CONFIG_PCI_J721E) += pci-j721e.o -+obj-$(CONFIG_PCIE_CADENCE_SOPHGO) += pcie-cadence-sophgo.o -diff --git a/drivers/pci/controller/cadence/pcie-cadence-sophgo.c b/drivers/pci/controller/cadence/pcie-cadence-sophgo.c -new file mode 100644 -index 000000000000..feb9bfdc7e75 ---- /dev/null -+++ b/drivers/pci/controller/cadence/pcie-cadence-sophgo.c -@@ -0,0 +1,963 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2017 Cadence -+// Cadence PCIe host controller driver. -+// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> -+ -+#include <linux/kernel.h> -+#include <linux/of_address.h> -+#include <linux/of_pci.h> -+#include <linux/msi.h> -+#include <linux/irq.h> -+#include <linux/irqdomain.h> -+#include <linux/irqchip/chained_irq.h> -+#include <linux/platform_device.h> -+#include <linux/pm_runtime.h> -+ -+#include "pcie-cadence.h" -+#include "pcie-cadence-sophgo.h" -+ -+#define MAX_MSI_IRQS 512 -+#define MAX_MSI_IRQS_PER_CTRL 1 -+#define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL) -+#define MSI_DEF_NUM_VECTORS 512 -+#define BYTE_NUM_PER_MSI_VEC 4 -+ -+// mango sideband signals -+#define CDNS_PCIE_CFG_MANGO_APB 0x1800000 -+#define CDNS_PCIE_IRS_REG0400 0x0400 -+#define CDNS_PCIE_IRS_REG0404 0x0404 -+#define CDNS_PCIE_IRS_REG0418 0x0418 -+#define CDNS_PCIE_IRS_REG041C 0x041C -+#define CDNS_PCIE_IRS_REG0804 0x0804 -+#define CDNS_PCIE_IRS_REG080C 0x080C -+#define CDNS_PCIE_IRS_REG0810 0x0810 -+#define CDNS_PCIE_IRS_REG085C 0x085C -+#define CDNS_PCIE_IRS_REG0860 0x0860 -+#define CDNS_PCIE_IRS_REG0864 0x0864 -+#define CDNS_PCIE_IRS_REG0868 0x0868 -+#define CDNS_PCIE_IRS_REG086C 0x086C -+ -+#define CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT 2 -+#define CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT 3 -+#define CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT 2 -+#define CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT 3 -+ -+#define CDNS_PLAT_CPU_TO_BUS_ADDR 0xCFFFFFFFFF -+ -+struct cdns_pcie_database { -+ void __iomem *pcie_reg_base; -+}; -+ -+static struct cdns_pcie_database cdns_pcie_db; -+ -+static inline void cdns_pcie_rp_writel(struct cdns_pcie *pcie, -+ u32 reg, u32 value) -+{ -+ writel(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); -+} -+ -+static inline u32 cdns_pcie_rp_readl(struct cdns_pcie *pcie, -+ u32 reg) -+{ -+ return readl(pcie->reg_base + CDNS_PCIE_RP_BASE + reg); -+} -+ -+/** -+ * struct cdns_mango_pcie_rc - private data for this PCIe Root Complex driver -+ * @pcie: Cadence PCIe controller -+ * @dev: pointer to PCIe device -+ * @cfg_res: start/end offsets in the physical system memory to map PCI -+ * configuration space accesses -+ * @bus_range: first/last buses behind the PCIe host controller -+ * @cfg_base: IO mapped window to access the PCI configuration space of a -+ * single function at a time -+ * @max_regions: maximum number of regions supported by the hardware -+ * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address -+ * translation (nbits sets into the "no BAR match" register) -+ * @vendor_id: PCI vendor ID -+ * @device_id: PCI device ID -+ */ -+struct cdns_mango_pcie_rc { -+ struct cdns_pcie pcie; -+ struct device *dev; -+ struct resource *cfg_res; -+ struct resource *bus_range; -+ void __iomem *cfg_base; -+ u32 max_regions; -+ u32 no_bar_nbits; -+ u16 vendor_id; -+ u16 device_id; -+ u16 pcie_id; -+ u16 link_id; -+ u32 top_intc_used; -+ u32 msix_supported; -+ struct irq_domain *msi_domain; -+ int msi_irq; -+ struct irq_domain *irq_domain; -+ dma_addr_t msi_data; -+ void *msi_page; -+ struct irq_chip *msi_irq_chip; -+ u32 num_vectors; -+ u32 num_applied_vecs; -+ u32 irq_maskMAX_MSI_CTRLS; -+ struct pci_bus *root_bus; -+ raw_spinlock_t lock; -+ DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); -+}; -+ -+static u64 cdns_mango_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr) -+{ -+ return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR; -+} -+ -+static const struct cdns_pcie_ops cdns_mango_ops = { -+ .cpu_addr_fixup = cdns_mango_cpu_addr_fixup, -+}; -+ -+static void __iomem *cdns_mango_pci_map_bus(struct pci_bus *bus, unsigned int devfn, -+ int where) -+{ -+ struct pci_host_bridge *bridge = pci_find_host_bridge(bus); -+ struct cdns_mango_pcie_rc *rc = pci_host_bridge_priv(bridge); -+ struct cdns_pcie *pcie = &rc->pcie; -+ unsigned int busn = bus->number; -+ u32 addr0, desc0; -+ -+ if (pci_is_root_bus(bus)) { -+ /* -+ * Only the root port (devfn == 0) is connected to this bus. -+ * All other PCI devices are behind some bridge hence on another -+ * bus. -+ */ -+ if (devfn) -+ return NULL; -+ -+ return pcie->reg_base + CDNS_PCIE_RP_BASE + (where & 0xfff); -+ } -+ /* Check that the link is up */ -+ if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1)) -+ return NULL; -+ /* Clear AXI link-down status */ -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_LINKDOWN, 0x0); -+ -+ /* Update Output registers for AXI region 0. */ -+ addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | -+ CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) | -+ CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn); -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0); -+ -+ /* Configuration Type 0 or Type 1 access. */ -+ desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | -+ CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); -+ /* -+ * The bus number was already set once for all in desc1 by -+ * cdns_pcie_host_init_address_translation(). -+ */ -+ if (busn == bridge->busnr + 1) -+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0; -+ else -+ desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1; -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0); -+ -+ return rc->cfg_base + (where & 0xfff); -+} -+ -+int cdns_pcie_config_read(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 *val) -+{ -+ unsigned long addr; -+ unsigned int value, offset; -+ void __iomem *aligned_addr; -+ -+ if ((bus->number != 0) && (bus->number != 0x40) && -+ (bus->number != 0x80) && (bus->number != 0xc0)) -+ return pci_generic_config_read(bus, devfn, where, size, val); -+ -+ addr = (unsigned long)bus->ops->map_bus(bus, devfn, where); -+ if (!addr) { -+ *val = ~0; -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ } -+ -+ if (size == 1) { -+ offset = addr & 0x3; -+ aligned_addr = (void __iomem *)(addr & ~0x3UL); -+ value = readl(aligned_addr); -+ *val = (value >> (8 * offset)) & 0xff; -+ } else if (size == 2) { -+ WARN_ON((addr & 0x1) != 0); // address should be aligned to 2 bytes -+ offset = addr & 0x3; -+ aligned_addr = (void __iomem *)(addr & ~0x3UL); -+ value = readl(aligned_addr); -+ *val = (value >> (8 * offset)) & 0xffff; -+ } else { -+ WARN_ON((addr & 0x3) != 0); // address should be aligned to 4 bytes -+ *val = readl((void __iomem *)(addr)); -+ } -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+int cdns_pcie_config_write(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 val) -+{ -+ unsigned long addr; -+ unsigned int value, offset; -+ void __iomem *aligned_addr; -+ -+ if ((bus->number != 0) && (bus->number != 0x40) && -+ (bus->number != 0x80) && (bus->number != 0xc0)) -+ return pci_generic_config_write(bus, devfn, where, size, val); -+ -+ addr = (unsigned long)bus->ops->map_bus(bus, devfn, where); -+ if (!addr) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ if (size == 1) { -+ offset = addr & 0x3; -+ aligned_addr = (void __iomem *)(addr & ~0x3UL); -+ value = readl(aligned_addr); -+ value &= ~(0xFF << (8 * offset)); -+ value |= ((val << (8 * offset)) & (0xFF << (8 * offset))); -+ writel(value, aligned_addr); -+ } else if (size == 2) { -+ WARN_ON((addr & 0x1) != 0); -+ offset = addr & 0x3; -+ aligned_addr = (void __iomem *)(addr & ~0x3UL); -+ value = readl(aligned_addr); -+ value &= ~(0xFFFF << (8 * offset)); -+ value |= ((val << (8 * offset)) & (0xFFFF << (8 * offset))); -+ writel(value, aligned_addr); -+ } else { -+ WARN_ON((addr & 0x3) != 0); -+ writel(val, (void __iomem *)(addr)); -+ } -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+ -+static struct pci_ops cdns_pcie_host_ops = { -+ .map_bus = cdns_mango_pci_map_bus, -+ .read = cdns_pcie_config_read, -+ .write = cdns_pcie_config_write, -+}; -+ -+static const struct of_device_id cdns_pcie_host_of_match = { -+ { .compatible = "sophgo,cdns-pcie-host" }, -+ -+ { }, -+}; -+ -+static int cdns_pcie_host_init_root_port(struct cdns_mango_pcie_rc *rc) -+{ -+ struct cdns_pcie *pcie = &rc->pcie; -+ u32 value, ctrl; -+ u32 id; -+ -+ /* -+ * Set the root complex BAR configuration register: -+ * - disable both BAR0 and BAR1. -+ * - enable Prefetchable Memory Base and Limit registers in type 1 -+ * config space (64 bits). -+ * - enable IO Base and Limit registers in type 1 config -+ * space (32 bits). -+ */ -+ ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; -+ value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) | -+ CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) | -+ CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE | -+ CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS | -+ CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE | -+ CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS; -+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); -+ -+ /* Set root port configuration space */ -+ if (rc->vendor_id != 0xffff) { -+ id = CDNS_PCIE_LM_ID_VENDOR(rc->vendor_id) | -+ CDNS_PCIE_LM_ID_SUBSYS(rc->vendor_id); -+ cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id); -+ } -+ -+ if (rc->device_id != 0xffff) { -+ value = cdns_pcie_rp_readl(pcie, PCI_VENDOR_ID); -+ value &= 0x0000FFFF; -+ value |= (rc->device_id << 16); -+ cdns_pcie_rp_writel(pcie, PCI_VENDOR_ID, value); -+ } -+ -+ cdns_pcie_rp_writel(pcie, PCI_CLASS_REVISION, PCI_CLASS_BRIDGE_PCI << 16); -+ -+ return 0; -+} -+ -+static int cdns_pcie_host_init_address_translation(struct cdns_mango_pcie_rc *rc) -+{ -+ struct cdns_pcie *pcie = &rc->pcie; -+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc); -+ struct resource *cfg_res = rc->cfg_res; -+ struct resource_entry *entry = NULL; -+ u32 addr0, addr1, desc1; -+ u64 cpu_addr; -+ int r, busnr = 0; -+ -+ entry = resource_list_first_type(&bridge->windows, IORESOURCE_BUS); -+ if (entry) -+ busnr = entry->res->start; -+ -+ /* -+ * Reserve region 0 for PCI configure space accesses: -+ * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by -+ * cdns_pci_map_bus(), other region registers are set here once for all. -+ */ -+ addr1 = 0; /* Should be programmed to zero. */ -+ desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr); -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1); -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1); -+ -+ cpu_addr = cfg_res->start; -+ addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) | -+ (lower_32_bits(cpu_addr) & GENMASK(31, 8)); -+ addr1 = upper_32_bits(cpu_addr); -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0); -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1); -+ -+ r = 1; -+ resource_list_for_each_entry(entry, &bridge->windows) { -+ struct resource *res = entry->res; -+ u64 pci_addr = res->start - entry->offset; -+ -+ if (resource_type(res) == IORESOURCE_IO) -+ cdns_pcie_set_outbound_region(pcie, busnr, 0, r, -+ true, -+ pci_pio_to_address(res->start), -+ pci_addr, -+ resource_size(res)); -+ else -+ cdns_pcie_set_outbound_region(pcie, busnr, 0, r, -+ false, -+ res->start, -+ pci_addr, -+ resource_size(res)); -+ -+ r++; -+ } -+ -+ /* -+ * Set Root Port no BAR match Inbound Translation registers: -+ * needed for MSI and DMA. -+ * Root Port BAR0 and BAR1 are disabled, hence no need to set their -+ * inbound translation registers. -+ */ -+ addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits); -+ addr1 = 0; -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0); -+ cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1); -+ -+ return 0; -+} -+ -+static int cdns_pcie_msi_init(struct cdns_mango_pcie_rc *rc) -+{ -+ struct device *dev = rc->dev; -+ struct cdns_pcie *pcie = &rc->pcie; -+ u32 apb_base = CDNS_PCIE_CFG_MANGO_APB; -+ u64 msi_target = 0; -+ u32 value = 0; -+ -+ // support 512 msi vectors -+ rc->msi_page = dma_alloc_coherent(dev, 2048, &rc->msi_data, -+ (GFP_KERNEL|GFP_DMA32|__GFP_ZERO)); -+ if (rc->msi_page == NULL) -+ return -1; -+ -+ dev_info(dev, "msi_data is 0x%llx\n", rc->msi_data); -+ msi_target = (u64)rc->msi_data; -+ -+ if (rc->link_id == 1) { -+ apb_base -= 0x800000; -+ /* Program the msi_data */ -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0868), -+ lower_32_bits(msi_target)); -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG086C), -+ upper_32_bits(msi_target)); -+ -+ value = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG080C)); -+ value = (value & 0xffff0000) | MAX_MSI_IRQS; -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG080C), value); -+ } else { -+ /* Program the msi_data */ -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0860), -+ lower_32_bits(msi_target)); -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0864), -+ upper_32_bits(msi_target)); -+ -+ value = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG085C)); -+ value = (value & 0x0000ffff) | (MAX_MSI_IRQS << 16); -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG085C), value); -+ } -+ -+ return 0; -+} -+ -+static int cdns_pcie_host_init(struct device *dev, struct cdns_mango_pcie_rc *rc) -+{ -+ int err; -+ -+ err = cdns_pcie_host_init_root_port(rc); -+ if (err) -+ return err; -+ -+ err = cdns_pcie_host_init_address_translation(rc); -+ if (err) -+ return err; -+ -+ if (rc->top_intc_used == 0) { -+ rc->num_vectors = MSI_DEF_NUM_VECTORS; -+ rc->num_applied_vecs = 0; -+ if (IS_ENABLED(CONFIG_PCI_MSI)) { -+ err = cdns_pcie_msi_init(rc); -+ if (err) -+ return err; -+ } -+ } -+ return 0; -+} -+ -+ -+static void cdns_pcie_msi_ack_irq(struct irq_data *d) -+{ -+ irq_chip_ack_parent(d); -+} -+ -+static void cdns_pcie_msi_mask_irq(struct irq_data *d) -+{ -+ pci_msi_mask_irq(d); -+ irq_chip_mask_parent(d); -+} -+ -+static void cdns_pcie_msi_unmask_irq(struct irq_data *d) -+{ -+ pci_msi_unmask_irq(d); -+ irq_chip_unmask_parent(d); -+} -+ -+static struct irq_chip cdns_pcie_msi_irq_chip = { -+ .name = "cdns-msi", -+ .irq_ack = cdns_pcie_msi_ack_irq, -+ .irq_mask = cdns_pcie_msi_mask_irq, -+ .irq_unmask = cdns_pcie_msi_unmask_irq, -+}; -+ -+static struct msi_domain_info cdns_pcie_msi_domain_info = { -+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), -+ .chip = &cdns_pcie_msi_irq_chip, -+}; -+ -+static struct msi_domain_info cdns_pcie_top_intr_msi_domain_info = { -+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS -+ | MSI_FLAG_PCI_MSIX), -+ .chip = &cdns_pcie_msi_irq_chip, -+}; -+ -+struct vendor_id_list vendor_id_list = { -+ {"Inter X520", 0x8086, 0x10fb}, -+ //{"WangXun RP1000", 0x8088}, -+ {"Switchtec", 0x11f8,4052}, -+}; -+ -+size_t vendor_id_list_num = ARRAY_SIZE(vendor_id_list); -+ -+int check_vendor_id(struct pci_dev *dev, struct vendor_id_list vendor_id_list, -+ size_t vendor_id_list_num) -+{ -+ uint16_t device_vendor_id; -+ uint16_t device_id; -+ -+ if (pci_read_config_word(dev, PCI_VENDOR_ID, &device_vendor_id) != 0) { -+ pr_err("Failed to read device vendor ID\n"); -+ return 0; -+ } -+ -+ if (pci_read_config_word(dev, PCI_DEVICE_ID, &device_id) != 0) { -+ pr_err("Failed to read device vendor ID\n"); -+ return 0; -+ } -+ -+ for (int i = 0; i < vendor_id_list_num; ++i) { -+ if (device_vendor_id == vendor_id_listi.vendor_id && device_id == vendor_id_listi.device_id) { -+ pr_info("dev: %s vendor ID: 0x%04x device ID: 0x%04x Enable MSI-X IRQ\n", -+ vendor_id_listi.name, device_vendor_id, device_id); -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+ -+static int cdns_pcie_msi_setup_for_top_intc(struct cdns_mango_pcie_rc *rc, int intc_id) -+{ -+ struct irq_domain *irq_parent = cdns_pcie_get_parent_irq_domain(intc_id); -+ struct fwnode_handle *fwnode = of_node_to_fwnode(rc->dev->of_node); -+ -+ if (rc->msix_supported == 1) { -+ rc->msi_domain = pci_msi_create_irq_domain(fwnode, -+ &cdns_pcie_top_intr_msi_domain_info, -+ irq_parent); -+ } else { -+ rc->msi_domain = pci_msi_create_irq_domain(fwnode, -+ &cdns_pcie_msi_domain_info, -+ irq_parent); -+ } -+ -+ if (!rc->msi_domain) { -+ dev_err(rc->dev, "create msi irq domain failed\n"); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+/* MSI int handler */ -+irqreturn_t cdns_handle_msi_irq(struct cdns_mango_pcie_rc *rc) -+{ -+ u32 i, pos, irq; -+ unsigned long val; -+ u32 status, num_vectors; -+ irqreturn_t ret = IRQ_NONE; -+ -+ num_vectors = rc->num_applied_vecs; -+ for (i = 0; i <= num_vectors; i++) { -+ status = readl((void *)(rc->msi_page + i * BYTE_NUM_PER_MSI_VEC)); -+ if (!status) -+ continue; -+ -+ ret = IRQ_HANDLED; -+ val = status; -+ pos = 0; -+ while ((pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL, -+ pos)) != MAX_MSI_IRQS_PER_CTRL) { -+ irq = irq_find_mapping(rc->irq_domain, -+ (i * MAX_MSI_IRQS_PER_CTRL) + -+ pos); -+ generic_handle_irq(irq); -+ pos++; -+ } -+ writel(0, ((void *)(rc->msi_page) + i * BYTE_NUM_PER_MSI_VEC)); -+ } -+ if (ret == IRQ_NONE) { -+ ret = IRQ_HANDLED; -+ for (i = 0; i <= num_vectors; i++) { -+ for (pos = 0; pos < MAX_MSI_IRQS_PER_CTRL; pos++) { -+ irq = irq_find_mapping(rc->irq_domain, -+ (i * MAX_MSI_IRQS_PER_CTRL) + -+ pos); -+ if (!irq) -+ continue; -+ generic_handle_irq(irq); -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+static irqreturn_t cdns_pcie_irq_handler(int irq, void *arg) -+{ -+ struct cdns_mango_pcie_rc *rc = arg; -+ struct cdns_pcie *pcie = &rc->pcie; -+ u32 apb_base = CDNS_PCIE_CFG_MANGO_APB; -+ u32 status = 0; -+ u32 st_msi_in_bit = 0; -+ u32 clr_msi_in_bit = 0; -+ -+ if (rc->link_id == 1) { -+ apb_base -= 0x800000; -+ st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT; -+ clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT; -+ } else { -+ st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT; -+ clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT; -+ } -+ -+ status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0810)); -+ if ((status >> st_msi_in_bit) & 0x1) { -+ WARN_ON(!IS_ENABLED(CONFIG_PCI_MSI)); -+ -+ //clear msi interrupt bit reg08102 -+ status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0804)); -+ status |= ((u32)0x1 << clr_msi_in_bit); -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status); -+ -+ status &= ~((u32)0x1 << clr_msi_in_bit); -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status); -+ -+ cdns_handle_msi_irq(rc); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* Chained MSI interrupt service routine */ -+static void cdns_chained_msi_isr(struct irq_desc *desc) -+{ -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ struct cdns_mango_pcie_rc *rc; -+ struct cdns_pcie *pcie; -+ u32 apb_base = CDNS_PCIE_CFG_MANGO_APB; -+ u32 status = 0; -+ u32 st_msi_in_bit = 0; -+ u32 clr_msi_in_bit = 0; -+ -+ chained_irq_enter(chip, desc); -+ -+ rc = irq_desc_get_handler_data(desc); -+ pcie = &rc->pcie; -+ if (rc->link_id == 1) { -+ apb_base -= 0x800000; -+ st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT; -+ clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT; -+ } else { -+ st_msi_in_bit = CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT; -+ clr_msi_in_bit = CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT; -+ } -+ -+ status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0810)); -+ if ((status >> st_msi_in_bit) & 0x1) { -+ WARN_ON(!IS_ENABLED(CONFIG_PCI_MSI)); -+ -+ //clear msi interrupt bit reg08102 -+ status = cdns_pcie_readl(pcie, (apb_base + CDNS_PCIE_IRS_REG0804)); -+ status |= ((u32)0x1 << clr_msi_in_bit); -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status); -+ -+ status &= ~((u32)0x1 << clr_msi_in_bit); -+ cdns_pcie_writel(pcie, (apb_base + CDNS_PCIE_IRS_REG0804), status); -+ -+ cdns_handle_msi_irq(rc); -+ } -+ -+ chained_irq_exit(chip, desc); -+} -+ -+static int cdns_pci_msi_set_affinity(struct irq_data *d, -+ const struct cpumask *mask, bool force) -+{ -+ return -EINVAL; -+} -+ -+static void cdns_pci_bottom_mask(struct irq_data *d) -+{ -+} -+ -+static void cdns_pci_bottom_unmask(struct irq_data *d) -+{ -+} -+ -+static void cdns_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg) -+{ -+ struct cdns_mango_pcie_rc *rc = irq_data_get_irq_chip_data(d); -+ u64 msi_target; -+ -+ msi_target = (u64)rc->msi_data; -+ -+ msg->address_lo = lower_32_bits(msi_target) + BYTE_NUM_PER_MSI_VEC * d->hwirq; -+ msg->address_hi = upper_32_bits(msi_target); -+ msg->data = 1; -+ -+ rc->num_applied_vecs = d->hwirq; -+ -+ dev_err(rc->dev, "msi#%d address_hi %#x address_lo %#x\n", -+ (int)d->hwirq, msg->address_hi, msg->address_lo); -+} -+ -+static void cdns_pci_bottom_ack(struct irq_data *d) -+{ -+} -+ -+static struct irq_chip cdns_pci_msi_bottom_irq_chip = { -+ .name = "CDNS-PCI-MSI", -+ .irq_ack = cdns_pci_bottom_ack, -+ .irq_compose_msi_msg = cdns_pci_setup_msi_msg, -+ .irq_set_affinity = cdns_pci_msi_set_affinity, -+ .irq_mask = cdns_pci_bottom_mask, -+ .irq_unmask = cdns_pci_bottom_unmask, -+}; -+ -+static int cdns_pcie_irq_domain_alloc(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs, -+ void *args) -+{ -+ struct cdns_mango_pcie_rc *rc = domain->host_data; -+ unsigned long flags; -+ u32 i; -+ int bit; -+ -+ raw_spin_lock_irqsave(&rc->lock, flags); -+ -+ bit = bitmap_find_free_region(rc->msi_irq_in_use, rc->num_vectors, -+ order_base_2(nr_irqs)); -+ -+ raw_spin_unlock_irqrestore(&rc->lock, flags); -+ -+ if (bit < 0) -+ return -ENOSPC; -+ -+ for (i = 0; i < nr_irqs; i++) -+ irq_domain_set_info(domain, virq + i, bit + i, -+ rc->msi_irq_chip, -+ rc, handle_edge_irq, -+ NULL, NULL); -+ -+ return 0; -+} -+ -+static void cdns_pcie_irq_domain_free(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs) -+{ -+ struct irq_data *d = irq_domain_get_irq_data(domain, virq); -+ struct cdns_mango_pcie_rc *rc = irq_data_get_irq_chip_data(d); -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&rc->lock, flags); -+ -+ bitmap_release_region(rc->msi_irq_in_use, d->hwirq, -+ order_base_2(nr_irqs)); -+ -+ raw_spin_unlock_irqrestore(&rc->lock, flags); -+} -+ -+static const struct irq_domain_ops cdns_pcie_msi_domain_ops = { -+ .alloc = cdns_pcie_irq_domain_alloc, -+ .free = cdns_pcie_irq_domain_free, -+}; -+ -+int cdns_pcie_allocate_domains(struct cdns_mango_pcie_rc *rc) -+{ -+ struct fwnode_handle *fwnode = of_node_to_fwnode(rc->dev->of_node); -+ -+ rc->irq_domain = irq_domain_create_linear(fwnode, rc->num_vectors, -+ &cdns_pcie_msi_domain_ops, rc); -+ if (!rc->irq_domain) { -+ dev_err(rc->dev, "Failed to create IRQ domain\n"); -+ return -ENOMEM; -+ } -+ -+ irq_domain_update_bus_token(rc->irq_domain, DOMAIN_BUS_NEXUS); -+ -+ rc->msi_domain = pci_msi_create_irq_domain(fwnode, -+ &cdns_pcie_msi_domain_info, -+ rc->irq_domain); -+ if (!rc->msi_domain) { -+ dev_err(rc->dev, "Failed to create MSI domain\n"); -+ irq_domain_remove(rc->irq_domain); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+void cdns_pcie_free_msi(struct cdns_mango_pcie_rc *rc) -+{ -+ if (rc->msi_irq) { -+ irq_set_chained_handler(rc->msi_irq, NULL); -+ irq_set_handler_data(rc->msi_irq, NULL); -+ } -+ -+ irq_domain_remove(rc->msi_domain); -+ irq_domain_remove(rc->irq_domain); -+ -+ if (rc->msi_page) -+ dma_free_coherent(rc->dev, 1024, rc->msi_page, rc->msi_data); -+ -+} -+ -+static int cdns_pcie_msi_setup(struct cdns_mango_pcie_rc *rc) -+{ -+ int ret = 0; -+ -+ raw_spin_lock_init(&rc->lock); -+ -+ if (IS_ENABLED(CONFIG_PCI_MSI)) { -+ rc->msi_irq_chip = &cdns_pci_msi_bottom_irq_chip; -+ -+ ret = cdns_pcie_allocate_domains(rc); -+ if (ret) -+ return ret; -+ -+ if (rc->msi_irq) -+ irq_set_chained_handler_and_data(rc->msi_irq, cdns_chained_msi_isr, rc); -+ } -+ -+ return ret; -+} -+ -+static int cdns_pcie_host_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct pci_host_bridge *bridge; -+ struct cdns_mango_pcie_rc *rc; -+ struct cdns_pcie *pcie; -+ struct resource *res; -+ int ret; -+ int phy_count; -+ int top_intc_id = -1; -+ -+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); -+ if (!bridge) -+ return -ENOMEM; -+ -+ rc = pci_host_bridge_priv(bridge); -+ rc->dev = dev; -+ -+ pcie = &rc->pcie; -+ pcie->is_rc = true; -+ pcie->ops = &cdns_mango_ops; -+ -+ rc->max_regions = 32; -+ of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions); -+ -+ rc->no_bar_nbits = 32; -+ of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits); -+ -+ rc->vendor_id = 0xffff; -+ of_property_read_u16(np, "vendor-id", &rc->vendor_id); -+ -+ rc->device_id = 0xffff; -+ of_property_read_u16(np, "device-id", &rc->device_id); -+ -+ rc->pcie_id = 0xffff; -+ of_property_read_u16(np, "pcie-id", &rc->pcie_id); -+ -+ rc->link_id = 0xffff; -+ of_property_read_u16(np, "link-id", &rc->link_id); -+ -+ rc->msix_supported = 0; -+ of_property_read_u32(np, "msix-supported", &rc->msix_supported); -+ -+ rc->top_intc_used = 0; -+ of_property_read_u32(np, "top-intc-used", &rc->top_intc_used); -+ if (rc->top_intc_used == 1) -+ of_property_read_u32(np, "top-intc-id", &top_intc_id); -+ -+ if (rc->link_id == 0) { -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); -+ pcie->reg_base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(pcie->reg_base)) { -+ dev_err(dev, "missing \"reg\"\n"); -+ return PTR_ERR(pcie->reg_base); -+ } -+ cdns_pcie_db.pcie_reg_base = pcie->reg_base; -+ } else if (rc->link_id == 1) { -+ pcie->reg_base = cdns_pcie_db.pcie_reg_base + 0x800000; -+ } -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); -+ rc->cfg_base = devm_pci_remap_cfg_resource(dev, res); -+ if (IS_ERR(rc->cfg_base)) { -+ dev_err(dev, "missing \"cfg\"\n"); -+ return PTR_ERR(rc->cfg_base); -+ } -+ rc->cfg_res = res; -+ -+ ret = cdns_pcie_init_phy(dev, pcie); -+ if (ret) { -+ dev_err(dev, "failed to init phy\n"); -+ return ret; -+ } -+ platform_set_drvdata(pdev, pcie); -+ -+ pm_runtime_enable(dev); -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ dev_err(dev, "pm_runtime_get_sync() failed\n"); -+ goto err_get_sync; -+ } -+ -+ ret = cdns_pcie_host_init(dev, rc); -+ if (ret) -+ goto err_init; -+ -+ if ((rc->top_intc_used == 0) && (IS_ENABLED(CONFIG_PCI_MSI))) { -+ rc->msi_irq = platform_get_irq_byname(pdev, "msi"); -+ if (rc->msi_irq <= 0) { -+ dev_err(dev, "failed to get MSI irq\n"); -+ goto err_init_irq; -+ } -+ -+ ret = devm_request_irq(dev, rc->msi_irq, cdns_pcie_irq_handler, -+ IRQF_SHARED | IRQF_NO_THREAD, -+ "cdns-pcie-irq", rc); -+ -+ if (ret) { -+ dev_err(dev, "failed to request MSI irq\n"); -+ goto err_init_irq; -+ } -+ } -+ -+ bridge->dev.parent = dev; -+ bridge->ops = &cdns_pcie_host_ops; -+ bridge->map_irq = of_irq_parse_and_map_pci; -+ bridge->swizzle_irq = pci_common_swizzle; -+ if (rc->top_intc_used == 0) -+ bridge->sysdata = rc; -+ -+ if (rc->top_intc_used == 0) { -+ ret = cdns_pcie_msi_setup(rc); -+ if (ret < 0) -+ goto err_host_probe; -+ } else if (rc->top_intc_used == 1) { -+ ret = cdns_pcie_msi_setup_for_top_intc(rc, top_intc_id); -+ if (ret < 0) -+ goto err_host_probe; -+ } -+ -+ ret = pci_host_probe(bridge); -+ if (ret < 0) -+ goto err_host_probe; -+ -+ return 0; -+ -+ err_host_probe: -+ err_init_irq: -+ if ((rc->top_intc_used == 0) && pci_msi_enabled()) -+ cdns_pcie_free_msi(rc); -+ -+ err_init: -+ pm_runtime_put_sync(dev); -+ -+ err_get_sync: -+ pm_runtime_disable(dev); -+ cdns_pcie_disable_phy(pcie); -+ phy_count = pcie->phy_count; -+ while (phy_count--) -+ device_link_del(pcie->linkphy_count); -+ -+ return ret; -+} -+ -+static void cdns_pcie_shutdown(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct cdns_pcie *pcie = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = pm_runtime_put_sync(dev); -+ if (ret < 0) -+ dev_dbg(dev, "pm_runtime_put_sync failed\n"); -+ -+ pm_runtime_disable(dev); -+ cdns_pcie_disable_phy(pcie); -+} -+ -+static struct platform_driver cdns_pcie_host_driver = { -+ .driver = { -+ .name = "cdns-pcie-host", -+ .of_match_table = cdns_pcie_host_of_match, -+ .pm = &cdns_pcie_pm_ops, -+ }, -+ .probe = cdns_pcie_host_probe, -+ .shutdown = cdns_pcie_shutdown, -+}; -+builtin_platform_driver(cdns_pcie_host_driver); -diff --git a/drivers/pci/controller/cadence/pcie-cadence-sophgo.h b/drivers/pci/controller/cadence/pcie-cadence-sophgo.h -new file mode 100644 -index 000000000000..ef46c46678ed ---- /dev/null -+++ b/drivers/pci/controller/cadence/pcie-cadence-sophgo.h -@@ -0,0 +1,17 @@ -+#ifndef PCIE_CADENCE_SOPHGO -+#define PCIE_CADENCE_SOPHGO -+ -+ -+struct vendor_id_list { -+ const char *name; -+ uint16_t vendor_id; -+ uint16_t device_id; -+}; -+ -+extern struct vendor_id_list vendor_id_list; -+extern size_t vendor_id_list_num; -+ -+extern struct irq_domain *cdns_pcie_get_parent_irq_domain(int intc_id); -+int check_vendor_id(struct pci_dev *dev, struct vendor_id_list vendor_id_list, -+ size_t vendor_id_list_num); -+#endif -diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c -index 46fad0d813b2..560b3a236d84 100644 ---- a/drivers/pci/pcie/portdrv.c -+++ b/drivers/pci/pcie/portdrv.c -@@ -598,7 +598,7 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *drv) - } - - /* If this switch is set, PCIe port native services should not be enabled. */ --bool pcie_ports_disabled; -+bool pcie_ports_disabled = true; - - /* - * If the user specified "pcie_ports=native", use the PCIe services regardless -diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig -index 79753411b778..15ad8ada527d 100644 ---- a/drivers/pinctrl/Kconfig -+++ b/drivers/pinctrl/Kconfig -@@ -22,7 +22,7 @@ config PINCONF - bool "Support pin configuration controllers" if COMPILE_TEST - - config GENERIC_PINCONF -- bool -+ bool "GENERIC_PINCONF" - select PINCONF - - config DEBUG_PINCTRL -@@ -469,6 +469,15 @@ config PINCTRL_TB10X - depends on OF && ARC_PLAT_TB10X - select GPIOLIB - -+config PINCTRL_TH1520 -+ tristate "Pinctrl driver for the T-Head TH1520 SoC" -+ depends on ARCH_THEAD || COMPILE_TEST -+ select GENERIC_PINMUX_FUNCTIONS -+ select GENERIC_PINCONF -+ select PINMUX -+ help -+ This selects the pinctrl driver for T-Head TH1520 RISC-V SoC. -+ - config PINCTRL_ZYNQ - bool "Pinctrl driver for Xilinx Zynq" - depends on ARCH_ZYNQ -diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile -index 4275eca92488..f07a2ee92197 100644 ---- a/drivers/pinctrl/Makefile -+++ b/drivers/pinctrl/Makefile -@@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o - obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o - obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o - 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 - -@@ -75,6 +76,7 @@ obj-$(CONFIG_SOC_STARFIVE) += starfive/ - obj-$(CONFIG_PINCTRL_STM32) += stm32/ - obj-y += sunplus/ - obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/ -+obj-$(CONFIG_ARCH_SOPHGO) += sophgo/ - obj-$(CONFIG_ARCH_TEGRA) += tegra/ - obj-y += ti/ - obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ -diff --git a/drivers/pinctrl/pinctrl-th1520.c b/drivers/pinctrl/pinctrl-th1520.c -new file mode 100644 -index 000000000000..6af46d59d0fa ---- /dev/null -+++ b/drivers/pinctrl/pinctrl-th1520.c -@@ -0,0 +1,860 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Pinctrl driver for the T-Head TH1520 SoC -+ * -+ * Copyright (C) 2023 Emil Renner Berthing <emil.renner.berthing@canonical.com> -+ */ -+ -+#include <linux/bits.h> -+#include <linux/cleanup.h> -+#include <linux/clk.h> -+#include <linux/device.h> -+#include <linux/io.h> -+#include <linux/mod_devicetable.h> -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+#include <linux/seq_file.h> -+#include <linux/spinlock.h> -+ -+#include <linux/pinctrl/pinconf.h> -+#include <linux/pinctrl/pinconf-generic.h> -+#include <linux/pinctrl/pinctrl.h> -+#include <linux/pinctrl/pinmux.h> -+ -+#include "core.h" -+#include "pinmux.h" -+#include "pinconf.h" -+ -+#define TH1520_PADCFG_IE BIT(9) -+#define TH1520_PADCFG_SL BIT(8) -+#define TH1520_PADCFG_ST BIT(7) -+#define TH1520_PADCFG_SPU BIT(6) -+#define TH1520_PADCFG_PS BIT(5) -+#define TH1520_PADCFG_PE BIT(4) -+#define TH1520_PADCFG_BIAS (TH1520_PADCFG_SPU | TH1520_PADCFG_PS | TH1520_PADCFG_PE) -+#define TH1520_PADCFG_DS GENMASK(3, 0) -+ -+#define TH1520_PULL_DOWN_OHM 44000 /* typ. 44kOhm */ -+#define TH1520_PULL_UP_OHM 48000 /* typ. 48kOhm */ -+#define TH1520_PULL_STRONG_OHM 2100 /* typ. 2.1kOhm */ -+ -+#define TH1520_PAD_NO_PADCFG BIT(30) -+#define TH1520_PAD_MUXDATA GENMASK(29, 0) -+ -+struct th1520_pad_group { -+ const char *name; -+ const struct pinctrl_pin_desc *pins; -+ unsigned int npins; -+}; -+ -+struct th1520_pinctrl { -+ struct pinctrl_desc desc; -+ struct mutex mutex; /* serialize adding functions */ -+ raw_spinlock_t lock; /* serialize register access */ -+ void __iomem *base; -+ struct pinctrl_dev *pctl; -+}; -+ -+static void __iomem *th1520_padcfg(struct th1520_pinctrl *thp, -+ unsigned int pin) -+{ -+ return thp->base + 4 * (pin / 2); -+} -+ -+static unsigned int th1520_padcfg_shift(unsigned int pin) -+{ -+ return 16 * (pin & BIT(0)); -+} -+ -+static void __iomem *th1520_muxcfg(struct th1520_pinctrl *thp, -+ unsigned int pin) -+{ -+ return thp->base + 0x400 + 4 * (pin / 8); -+} -+ -+static unsigned int th1520_muxcfg_shift(unsigned int pin) -+{ -+ return 4 * (pin & GENMASK(2, 0)); -+} -+ -+enum th1520_muxtype { -+ TH1520_MUX_____, -+ TH1520_MUX_GPIO, -+ TH1520_MUX_PWM, -+ TH1520_MUX_UART, -+ TH1520_MUX_IR, -+ TH1520_MUX_I2C, -+ TH1520_MUX_SPI, -+ TH1520_MUX_QSPI, -+ TH1520_MUX_SDIO, -+ TH1520_MUX_AUD, -+ TH1520_MUX_I2S, -+ TH1520_MUX_MAC0, -+ TH1520_MUX_MAC1, -+ TH1520_MUX_DPU0, -+ TH1520_MUX_DPU1, -+ TH1520_MUX_ISP, -+ TH1520_MUX_HDMI, -+ TH1520_MUX_BSEL, -+ TH1520_MUX_DBG, -+ TH1520_MUX_CLK, -+ TH1520_MUX_JTAG, -+ TH1520_MUX_ISO, -+ TH1520_MUX_FUSE, -+ TH1520_MUX_RST, -+}; -+ -+static const char *const th1520_muxtype_string = { -+ TH1520_MUX_GPIO = "gpio", -+ TH1520_MUX_PWM = "pwm", -+ TH1520_MUX_UART = "uart", -+ TH1520_MUX_IR = "ir", -+ TH1520_MUX_I2C = "i2c", -+ TH1520_MUX_SPI = "spi", -+ TH1520_MUX_QSPI = "qspi", -+ TH1520_MUX_SDIO = "sdio", -+ TH1520_MUX_AUD = "audio", -+ TH1520_MUX_I2S = "i2s", -+ TH1520_MUX_MAC0 = "gmac0", -+ TH1520_MUX_MAC1 = "gmac1", -+ TH1520_MUX_DPU0 = "dpu0", -+ TH1520_MUX_DPU1 = "dpu1", -+ TH1520_MUX_ISP = "isp", -+ TH1520_MUX_HDMI = "hdmi", -+ TH1520_MUX_BSEL = "bootsel", -+ TH1520_MUX_DBG = "debug", -+ TH1520_MUX_CLK = "clock", -+ TH1520_MUX_JTAG = "jtag", -+ TH1520_MUX_ISO = "iso7816", -+ TH1520_MUX_FUSE = "efuse", -+ TH1520_MUX_RST = "reset", -+}; -+ -+static enum th1520_muxtype th1520_muxtype_get(const char *str) -+{ -+ enum th1520_muxtype mt; -+ -+ for (mt = TH1520_MUX_GPIO; mt < ARRAY_SIZE(th1520_muxtype_string); mt++) { -+ if (!strcmp(str, th1520_muxtype_stringmt)) -+ return mt; -+ } -+ return TH1520_MUX_____; -+} -+ -+#define TH1520_PAD(_nr, _name, m0, m1, m2, m3, m4, m5, _flags) \ -+ { .number = _nr, .name = #_name, .drv_data = (void *)((_flags) | \ -+ (TH1520_MUX_##m0 << 0) | (TH1520_MUX_##m1 << 5) | (TH1520_MUX_##m2 << 10) | \ -+ (TH1520_MUX_##m3 << 15) | (TH1520_MUX_##m4 << 20) | (TH1520_MUX_##m5 << 25)) } -+ -+static const struct pinctrl_pin_desc th1520_group1_pins = { -+ TH1520_PAD(0, OSC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), -+ TH1520_PAD(1, OSC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), -+ TH1520_PAD(2, SYS_RST_N, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), -+ TH1520_PAD(3, RTC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), -+ TH1520_PAD(4, RTC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), -+ /* skip number 5 so we can calculate register offsets and shifts from the pin number */ -+ TH1520_PAD(6, TEST_MODE, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), -+ TH1520_PAD(7, DEBUG_MODE, DBG, ____, ____, GPIO, ____, ____, TH1520_PAD_NO_PADCFG), -+ TH1520_PAD(8, POR_SEL, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), -+ TH1520_PAD(9, I2C_AON_SCL, I2C, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(10, I2C_AON_SDA, I2C, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(11, CPU_JTG_TCLK, JTAG, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(12, CPU_JTG_TMS, JTAG, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(13, CPU_JTG_TDI, JTAG, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(14, CPU_JTG_TDO, JTAG, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(15, CPU_JTG_TRST, JTAG, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(16, AOGPIO_7, CLK, AUD, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(17, AOGPIO_8, UART, AUD, IR, GPIO, ____, ____, 0), -+ TH1520_PAD(18, AOGPIO_9, UART, AUD, IR, GPIO, ____, ____, 0), -+ TH1520_PAD(19, AOGPIO_10, CLK, AUD, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(20, AOGPIO_11, GPIO, AUD, ____, ____, ____, ____, 0), -+ TH1520_PAD(21, AOGPIO_12, GPIO, AUD, ____, ____, ____, ____, 0), -+ TH1520_PAD(22, AOGPIO_13, GPIO, AUD, ____, ____, ____, ____, 0), -+ TH1520_PAD(23, AOGPIO_14, GPIO, AUD, ____, ____, ____, ____, 0), -+ TH1520_PAD(24, AOGPIO_15, GPIO, AUD, ____, ____, ____, ____, 0), -+ TH1520_PAD(25, AUDIO_PA0, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(26, AUDIO_PA1, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(27, AUDIO_PA2, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(28, AUDIO_PA3, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(29, AUDIO_PA4, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(30, AUDIO_PA5, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(31, AUDIO_PA6, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(32, AUDIO_PA7, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(33, AUDIO_PA8, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(34, AUDIO_PA9, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(35, AUDIO_PA10, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(36, AUDIO_PA11, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(37, AUDIO_PA12, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(38, AUDIO_PA13, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(39, AUDIO_PA14, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(40, AUDIO_PA15, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(41, AUDIO_PA16, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(42, AUDIO_PA17, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(43, AUDIO_PA27, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(44, AUDIO_PA28, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(45, AUDIO_PA29, AUD, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(46, AUDIO_PA30, AUD, RST, ____, GPIO, ____, ____, 0), -+}; -+ -+static const struct pinctrl_pin_desc th1520_group2_pins = { -+ TH1520_PAD(0, QSPI1_SCLK, QSPI, ISO, ____, GPIO, FUSE, ____, 0), -+ TH1520_PAD(1, QSPI1_CSN0, QSPI, ____, I2C, GPIO, FUSE, ____, 0), -+ TH1520_PAD(2, QSPI1_D0_MOSI, QSPI, ISO, I2C, GPIO, FUSE, ____, 0), -+ TH1520_PAD(3, QSPI1_D1_MISO, QSPI, ISO, ____, GPIO, FUSE, ____, 0), -+ TH1520_PAD(4, QSPI1_D2_WP, QSPI, ISO, UART, GPIO, FUSE, ____, 0), -+ TH1520_PAD(5, QSPI1_D3_HOLD, QSPI, ISO, UART, GPIO, ____, ____, 0), -+ TH1520_PAD(6, I2C0_SCL, I2C, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(7, I2C0_SDA, I2C, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(8, I2C1_SCL, I2C, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(9, I2C1_SDA, I2C, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(10, UART1_TXD, UART, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(11, UART1_RXD, UART, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(12, UART4_TXD, UART, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(13, UART4_RXD, UART, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(14, UART4_CTSN, UART, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(15, UART4_RTSN, UART, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(16, UART3_TXD, DBG, UART, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(17, UART3_RXD, DBG, UART, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(18, GPIO0_18, GPIO, I2C, ____, ____, ____, ____, 0), -+ TH1520_PAD(19, GPIO0_19, GPIO, I2C, ____, ____, ____, ____, 0), -+ TH1520_PAD(20, GPIO0_20, GPIO, UART, IR, ____, ____, ____, 0), -+ TH1520_PAD(21, GPIO0_21, GPIO, UART, IR, ____, DPU0, DPU1, 0), -+ TH1520_PAD(22, GPIO0_22, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), -+ TH1520_PAD(23, GPIO0_23, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), -+ TH1520_PAD(24, GPIO0_24, GPIO, JTAG, QSPI, ____, DPU0, DPU1, 0), -+ TH1520_PAD(25, GPIO0_25, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(26, GPIO0_26, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(27, GPIO0_27, GPIO, ____, I2C, ____, DPU0, DPU1, 0), -+ TH1520_PAD(28, GPIO0_28, GPIO, ____, I2C, ____, DPU0, DPU1, 0), -+ TH1520_PAD(29, GPIO0_29, GPIO, ____, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(30, GPIO0_30, GPIO, ____, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(31, GPIO0_31, GPIO, ____, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(32, GPIO1_0, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(33, GPIO1_1, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(34, GPIO1_2, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(35, GPIO1_3, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(36, GPIO1_4, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(37, GPIO1_5, GPIO, ____, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(38, GPIO1_6, GPIO, ____, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(39, GPIO1_7, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(40, GPIO1_8, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(41, GPIO1_9, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(42, GPIO1_10, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(43, GPIO1_11, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(44, GPIO1_12, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(45, GPIO1_13, GPIO, UART, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(46, GPIO1_14, GPIO, UART, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(47, GPIO1_15, GPIO, UART, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(48, GPIO1_16, GPIO, UART, ____, ____, DPU0, DPU1, 0), -+ TH1520_PAD(49, CLK_OUT_0, BSEL, CLK, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(50, CLK_OUT_1, BSEL, CLK, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(51, CLK_OUT_2, BSEL, CLK, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(52, CLK_OUT_3, BSEL, CLK, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(53, GPIO1_21, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(54, GPIO1_22, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(55, GPIO1_23, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(56, GPIO1_24, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(57, GPIO1_25, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(58, GPIO1_26, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(59, GPIO1_27, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(60, GPIO1_28, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(61, GPIO1_29, GPIO, ____, ISP, ____, ____, ____, 0), -+ TH1520_PAD(62, GPIO1_30, GPIO, ____, ISP, ____, ____, ____, 0), -+}; -+ -+static const struct pinctrl_pin_desc th1520_group3_pins = { -+ TH1520_PAD(0, UART0_TXD, UART, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(1, UART0_RXD, UART, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(2, QSPI0_SCLK, QSPI, PWM, I2S, GPIO, ____, ____, 0), -+ TH1520_PAD(3, QSPI0_CSN0, QSPI, PWM, I2S, GPIO, ____, ____, 0), -+ TH1520_PAD(4, QSPI0_CSN1, QSPI, PWM, I2S, GPIO, ____, ____, 0), -+ TH1520_PAD(5, QSPI0_D0_MOSI, QSPI, PWM, I2S, GPIO, ____, ____, 0), -+ TH1520_PAD(6, QSPI0_D1_MISO, QSPI, PWM, I2S, GPIO, ____, ____, 0), -+ TH1520_PAD(7, QSPI0_D2_WP, QSPI, PWM, I2S, GPIO, ____, ____, 0), -+ TH1520_PAD(8, QSPI1_D3_HOLD, QSPI, ____, I2S, GPIO, ____, ____, 0), -+ TH1520_PAD(9, I2C2_SCL, I2C, UART, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(10, I2C2_SDA, I2C, UART, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(11, I2C3_SCL, I2C, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(12, I2C3_SDA, I2C, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(13, GPIO2_13, GPIO, SPI, ____, ____, ____, ____, 0), -+ TH1520_PAD(14, SPI_SCLK, SPI, UART, IR, GPIO, ____, ____, 0), -+ TH1520_PAD(15, SPI_CSN, SPI, UART, IR, GPIO, ____, ____, 0), -+ TH1520_PAD(16, SPI_MOSI, SPI, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(17, SPI_MISO, SPI, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(18, GPIO2_18, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(19, GPIO2_19, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(20, GPIO2_20, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(21, GPIO2_21, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(22, GPIO2_22, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(23, GPIO2_23, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(24, GPIO2_24, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(25, GPIO2_25, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(26, SDIO0_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(27, SDIO0_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(28, SDIO1_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(29, SDIO1_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(30, GPIO2_30, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(31, GPIO2_31, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(32, GPIO3_0, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(33, GPIO3_1, GPIO, MAC1, ____, ____, ____, ____, 0), -+ TH1520_PAD(34, GPIO3_2, GPIO, PWM, ____, ____, ____, ____, 0), -+ TH1520_PAD(35, GPIO3_3, GPIO, PWM, ____, ____, ____, ____, 0), -+ TH1520_PAD(36, HDMI_SCL, HDMI, PWM, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(37, HDMI_SDA, HDMI, PWM, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(38, HDMI_CEC, HDMI, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(39, GMAC0_TX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(40, GMAC0_RX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(41, GMAC0_TXEN, MAC0, UART, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(42, GMAC0_TXD0, MAC0, UART, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(43, GMAC0_TXD1, MAC0, UART, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(44, GMAC0_TXD2, MAC0, UART, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(45, GMAC0_TXD3, MAC0, I2C, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(46, GMAC0_RXDV, MAC0, I2C, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(47, GMAC0_RXD0, MAC0, I2C, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(48, GMAC0_RXD1, MAC0, I2C, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(49, GMAC0_RXD2, MAC0, SPI, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(50, GMAC0_RXD3, MAC0, SPI, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(51, GMAC0_MDC, MAC0, SPI, MAC1, GPIO, ____, ____, 0), -+ TH1520_PAD(52, GMAC0_MDIO, MAC0, SPI, MAC1, GPIO, ____, ____, 0), -+ TH1520_PAD(53, GMAC0_COL, MAC0, PWM, ____, GPIO, ____, ____, 0), -+ TH1520_PAD(54, GMAC0_CRS, MAC0, PWM, ____, GPIO, ____, ____, 0), -+}; -+ -+static const struct th1520_pad_group th1520_group1 = { -+ .name = "th1520-group1", -+ .pins = th1520_group1_pins, -+ .npins = ARRAY_SIZE(th1520_group1_pins), -+}; -+ -+static const struct th1520_pad_group th1520_group2 = { -+ .name = "th1520-group2", -+ .pins = th1520_group2_pins, -+ .npins = ARRAY_SIZE(th1520_group2_pins), -+}; -+ -+static const struct th1520_pad_group th1520_group3 = { -+ .name = "th1520-group3", -+ .pins = th1520_group3_pins, -+ .npins = ARRAY_SIZE(th1520_group3_pins), -+}; -+ -+static int th1520_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) -+{ -+ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); -+ -+ return thp->desc.npins; -+} -+ -+static const char *th1520_pinctrl_get_group_name(struct pinctrl_dev *pctldev, -+ unsigned int gsel) -+{ -+ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); -+ -+ return thp->desc.pinsgsel.name; -+} -+ -+static int th1520_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, -+ unsigned int gsel, -+ const unsigned int **pins, -+ unsigned int *npins) -+{ -+ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); -+ -+ *pins = &thp->desc.pinsgsel.number; -+ *npins = 1; -+ return 0; -+} -+ -+#ifdef CONFIG_DEBUG_FS -+static void th1520_pin_dbg_show(struct pinctrl_dev *pctldev, -+ struct seq_file *s, unsigned int pin) -+{ -+ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); -+ void __iomem *padcfg = th1520_padcfg(thp, pin); -+ void __iomem *muxcfg = th1520_muxcfg(thp, pin); -+ u32 pad; -+ u32 mux; -+ -+ scoped_guard(raw_spinlock_irqsave, &thp->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 th1520_pin_dbg_show NULL -+#endif -+ -+static void th1520_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 (mapi.type == PIN_MAP_TYPE_CONFIGS_PIN && -+ mapi.data.configs.configs != seen) { -+ seen = mapi.data.configs.configs; -+ kfree(seen); -+ } -+ } -+ -+ kfree(map); -+} -+ -+static int th1520_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, -+ struct device_node *np, -+ struct pinctrl_map **maps, -+ unsigned int *num_maps) -+{ -+ struct th1520_pinctrl *thp = 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(thp->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(&thp->mutex); -+ for_each_available_child_of_node(np, child) { -+ unsigned int rollback = nmaps; -+ enum th1520_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(thp->pctl->dev, "%pOFn.%pOFn: error parsing pin config\n", -+ np, child); -+ goto put_child; -+ } -+ -+ if (!of_property_read_string(child, "function", &funcname)) { -+ muxtype = th1520_muxtype_get(funcname); -+ if (!muxtype) { -+ dev_err(thp->pctl->dev, "%pOFn.%pOFn: unknown function '%s'\n", -+ np, child, funcname); -+ ret = -EINVAL; -+ goto free_configs; -+ } -+ -+ funcname = devm_kasprintf(thp->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(thp->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 < thp->desc.npins; i++) { -+ if (!strcmp(pinname, thp->desc.pinsi.name)) -+ break; -+ } -+ if (i == thp->desc.npins) { -+ nmaps = rollback; -+ dev_err(thp->pctl->dev, "%pOFn.%pOFn: unknown pin '%s'\n", -+ np, child, pinname); -+ goto free_configs; -+ } -+ -+ if (nconfigs) { -+ mapnmaps.type = PIN_MAP_TYPE_CONFIGS_PIN; -+ mapnmaps.data.configs.group_or_pin = thp->desc.pinsi.name; -+ mapnmaps.data.configs.configs = configs; -+ mapnmaps.data.configs.num_configs = nconfigs; -+ nmaps += 1; -+ } -+ if (funcname) { -+ pgnamesnpins++ = thp->desc.pinsi.name; -+ mapnmaps.type = PIN_MAP_TYPE_MUX_GROUP; -+ mapnmaps.data.mux.function = funcname; -+ mapnmaps.data.mux.group = thp->desc.pinsi.name; -+ nmaps += 1; -+ } -+ } -+ -+ if (funcname) { -+ ret = pinmux_generic_add_function(pctldev, funcname, pgnames, -+ npins, (void *)muxtype); -+ if (ret < 0) { -+ dev_err(thp->pctl->dev, "error adding function %s\n", funcname); -+ goto put_child; -+ } -+ } -+ } -+ -+ *maps = map; -+ *num_maps = nmaps; -+ mutex_unlock(&thp->mutex); -+ return 0; -+ -+free_configs: -+ kfree(configs); -+put_child: -+ of_node_put(child); -+ th1520_pinctrl_dt_free_map(pctldev, map, nmaps); -+ mutex_unlock(&thp->mutex); -+ return ret; -+} -+ -+static const struct pinctrl_ops th1520_pinctrl_ops = { -+ .get_groups_count = th1520_pinctrl_get_groups_count, -+ .get_group_name = th1520_pinctrl_get_group_name, -+ .get_group_pins = th1520_pinctrl_get_group_pins, -+ .pin_dbg_show = th1520_pin_dbg_show, -+ .dt_node_to_map = th1520_pinctrl_dt_node_to_map, -+ .dt_free_map = th1520_pinctrl_dt_free_map, -+}; -+ -+static int th1520_pinmux_set_mux(struct pinctrl_dev *pctldev, -+ unsigned int fsel, unsigned int gsel) -+{ -+ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); -+ const struct function_desc *func = pinmux_generic_get_function(pctldev, fsel); -+ uintptr_t muxdata = (uintptr_t)thp->desc.pinsgsel.drv_data & TH1520_PAD_MUXDATA; -+ uintptr_t muxtype = (uintptr_t)func->data; -+ unsigned int pin = thp->desc.pinsgsel.number; -+ void __iomem *muxcfg = th1520_muxcfg(thp, pin); -+ unsigned int shift = th1520_muxcfg_shift(pin); -+ u32 mask, value, tmp; -+ -+ for (value = 0; muxdata; muxdata >>= 5, value++) { -+ if ((muxdata & GENMASK(4, 0)) == muxtype) -+ break; -+ } -+ if (!muxdata) { -+ dev_err(thp->pctl->dev, "%s: invalid mux %s for pin %s\n", -+ func->name, th1520_muxtype_stringmuxtype, thp->desc.pinsgsel.name); -+ return -EINVAL; -+ } -+ -+ mask = GENMASK(3, 0) << shift; -+ value = value << shift; -+ -+ scoped_guard(raw_spinlock_irqsave, &thp->lock) { -+ tmp = readl_relaxed(muxcfg); -+ tmp = (tmp & ~mask) | value; -+ writel_relaxed(tmp, muxcfg); -+ } -+ return 0; -+} -+ -+static const struct pinmux_ops th1520_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 = th1520_pinmux_set_mux, -+ .strict = true, -+}; -+ -+static const u8 th1520_drive_strength_in_mA16 = { -+ 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25, -+}; -+ -+static u16 th1520_drive_strength_from_mA(u32 arg) -+{ -+ u16 ds; -+ -+ for (ds = 0; ds < TH1520_PADCFG_DS; ds++) { -+ if (arg <= th1520_drive_strength_in_mAds) -+ return ds; -+ } -+ return TH1520_PADCFG_DS; -+} -+ -+static int th1520_padcfg_rmw(struct th1520_pinctrl *thp, unsigned int pin, -+ u32 mask, u32 value) -+{ -+ void __iomem *padcfg = th1520_padcfg(thp, pin); -+ unsigned int shift = th1520_padcfg_shift(pin); -+ u32 tmp; -+ -+ mask <<= shift; -+ value <<= shift; -+ -+ scoped_guard(raw_spinlock_irqsave, &thp->lock) { -+ tmp = readl_relaxed(padcfg); -+ tmp = (tmp & ~mask) | value; -+ writel_relaxed(tmp, padcfg); -+ } -+ return 0; -+} -+ -+static int th1520_pinconf_get(struct pinctrl_dev *pctldev, -+ unsigned int pin, unsigned long *config) -+{ -+ struct th1520_pinctrl *thp = 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 & TH1520_PAD_NO_PADCFG) -+ return -ENOTSUPP; -+ -+ value = readl_relaxed(th1520_padcfg(thp, pin)); -+ value = (value >> th1520_padcfg_shift(pin)) & GENMASK(9, 0); -+ -+ param = pinconf_to_config_param(*config); -+ switch (param) { -+ case PIN_CONFIG_BIAS_DISABLE: -+ enabled = !(value & (TH1520_PADCFG_SPU | TH1520_PADCFG_PE)); -+ arg = 0; -+ break; -+ case PIN_CONFIG_BIAS_PULL_DOWN: -+ enabled = (value & TH1520_PADCFG_BIAS) == TH1520_PADCFG_PE; -+ arg = enabled ? TH1520_PULL_DOWN_OHM : 0; -+ break; -+ case PIN_CONFIG_BIAS_PULL_UP: -+ if (value & TH1520_PADCFG_SPU) { -+ enabled = true; -+ arg = TH1520_PULL_STRONG_OHM; -+ } else if ((value & (TH1520_PADCFG_PE | TH1520_PADCFG_PS)) == -+ (TH1520_PADCFG_PE | TH1520_PADCFG_PS)) { -+ enabled = true; -+ arg = TH1520_PULL_UP_OHM; -+ } else { -+ enabled = false; -+ arg = 0; -+ } -+ break; -+ case PIN_CONFIG_DRIVE_STRENGTH: -+ enabled = true; -+ arg = th1520_drive_strength_in_mAvalue & TH1520_PADCFG_DS; -+ break; -+ case PIN_CONFIG_INPUT_ENABLE: -+ enabled = value & TH1520_PADCFG_IE; -+ arg = enabled ? 1 : 0; -+ break; -+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: -+ enabled = value & TH1520_PADCFG_ST; -+ arg = enabled ? 1 : 0; -+ break; -+ case PIN_CONFIG_SLEW_RATE: -+ enabled = value & TH1520_PADCFG_SL; -+ arg = enabled ? 1 : 0; -+ break; -+ default: -+ return -ENOTSUPP; -+ } -+ -+ *config = pinconf_to_config_packed(param, arg); -+ return enabled ? 0 : -EINVAL; -+} -+ -+static int th1520_pinconf_group_get(struct pinctrl_dev *pctldev, -+ unsigned int gsel, unsigned long *config) -+{ -+ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); -+ unsigned int pin = thp->desc.pinsgsel.number; -+ -+ return th1520_pinconf_get(pctldev, pin, config); -+} -+ -+static int th1520_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, -+ unsigned long *configs, unsigned int num_configs) -+{ -+ struct th1520_pinctrl *thp = 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 & TH1520_PAD_NO_PADCFG) -+ return -ENOTSUPP; -+ -+ mask = 0; -+ value = 0; -+ for (i = 0; i < num_configs; i++) { -+ int param = pinconf_to_config_param(configsi); -+ u32 arg = pinconf_to_config_argument(configsi); -+ -+ switch (param) { -+ case PIN_CONFIG_BIAS_DISABLE: -+ mask |= TH1520_PADCFG_BIAS; -+ value &= ~TH1520_PADCFG_BIAS; -+ break; -+ case PIN_CONFIG_BIAS_PULL_DOWN: -+ if (arg == 0) -+ return -ENOTSUPP; -+ mask |= TH1520_PADCFG_BIAS; -+ value &= ~TH1520_PADCFG_BIAS; -+ value |= TH1520_PADCFG_PE; -+ break; -+ case PIN_CONFIG_BIAS_PULL_UP: -+ if (arg == 0) -+ return -ENOTSUPP; -+ mask |= TH1520_PADCFG_BIAS; -+ value &= ~TH1520_PADCFG_BIAS; -+ if (arg == TH1520_PULL_STRONG_OHM) -+ value |= TH1520_PADCFG_SPU; -+ else -+ value |= TH1520_PADCFG_PE | TH1520_PADCFG_PS; -+ break; -+ case PIN_CONFIG_DRIVE_STRENGTH: -+ mask |= TH1520_PADCFG_DS; -+ value &= ~TH1520_PADCFG_DS; -+ value |= th1520_drive_strength_from_mA(arg); -+ break; -+ case PIN_CONFIG_INPUT_ENABLE: -+ mask |= TH1520_PADCFG_IE; -+ if (arg) -+ value |= TH1520_PADCFG_IE; -+ else -+ value &= ~TH1520_PADCFG_IE; -+ break; -+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE: -+ mask |= TH1520_PADCFG_ST; -+ if (arg) -+ value |= TH1520_PADCFG_ST; -+ else -+ value &= ~TH1520_PADCFG_ST; -+ break; -+ case PIN_CONFIG_SLEW_RATE: -+ mask |= TH1520_PADCFG_SL; -+ if (arg) -+ value |= TH1520_PADCFG_SL; -+ else -+ value &= ~TH1520_PADCFG_SL; -+ break; -+ default: -+ return -ENOTSUPP; -+ } -+ } -+ -+ return th1520_padcfg_rmw(thp, pin, mask, value); -+} -+ -+static int th1520_pinconf_group_set(struct pinctrl_dev *pctldev, -+ unsigned int gsel, -+ unsigned long *configs, -+ unsigned int num_configs) -+{ -+ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); -+ unsigned int pin = thp->desc.pinsgsel.number; -+ -+ return th1520_pinconf_set(pctldev, pin, configs, num_configs); -+} -+ -+#ifdef CONFIG_DEBUG_FS -+static void th1520_pinconf_dbg_show(struct pinctrl_dev *pctldev, -+ struct seq_file *s, unsigned int pin) -+{ -+ struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); -+ u32 value = readl_relaxed(th1520_padcfg(thp, pin)); -+ -+ value = (value >> th1520_padcfg_shift(pin)) & GENMASK(9, 0); -+ -+ seq_printf(s, " 0x%03x", value); -+} -+#else -+#define th1520_pinconf_dbg_show NULL -+#endif -+ -+static const struct pinconf_ops th1520_pinconf_ops = { -+ .pin_config_get = th1520_pinconf_get, -+ .pin_config_group_get = th1520_pinconf_group_get, -+ .pin_config_set = th1520_pinconf_set, -+ .pin_config_group_set = th1520_pinconf_group_set, -+ .pin_config_dbg_show = th1520_pinconf_dbg_show, -+ .is_generic = true, -+}; -+ -+static int th1520_pinctrl_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ const struct th1520_pad_group *group = device_get_match_data(dev); -+ struct th1520_pinctrl *thp; -+ struct clk *clk; -+ int ret; -+ -+ thp = devm_kzalloc(dev, sizeof(*thp), GFP_KERNEL); -+ if (!thp) -+ return -ENOMEM; -+ -+ thp->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(thp->base)) -+ return PTR_ERR(thp->base); -+ -+ clk = devm_clk_get_enabled(dev, NULL); -+ if (IS_ERR(clk)) -+ return dev_err_probe(dev, PTR_ERR(clk), "error getting clock\n"); -+ -+ thp->desc.name = group->name; -+ thp->desc.pins = group->pins; -+ thp->desc.npins = group->npins; -+ thp->desc.pctlops = &th1520_pinctrl_ops; -+ thp->desc.pmxops = &th1520_pinmux_ops; -+ thp->desc.confops = &th1520_pinconf_ops; -+ thp->desc.owner = THIS_MODULE; -+ mutex_init(&thp->mutex); -+ raw_spin_lock_init(&thp->lock); -+ -+ ret = devm_pinctrl_register_and_init(dev, &thp->desc, thp, &thp->pctl); -+ if (ret) -+ return dev_err_probe(dev, ret, "could not register pinctrl driver\n"); -+ -+ return pinctrl_enable(thp->pctl); -+} -+ -+static const struct of_device_id th1520_pinctrl_of_match = { -+ { .compatible = "thead,th1520-group1-pinctrl", .data = &th1520_group1 }, -+ { .compatible = "thead,th1520-group2-pinctrl", .data = &th1520_group2 }, -+ { .compatible = "thead,th1520-group3-pinctrl", .data = &th1520_group3 }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, th1520_pinctrl_of_match); -+ -+static struct platform_driver th1520_pinctrl_driver = { -+ .probe = th1520_pinctrl_probe, -+ .driver = { -+ .name = "pinctrl-th1520", -+ .of_match_table = th1520_pinctrl_of_match, -+ }, -+}; -+module_platform_driver(th1520_pinctrl_driver); -+ -+MODULE_DESCRIPTION("Pinctrl driver for the T-Head TH1520 SoC"); -+MODULE_AUTHOR("Emil Renner Berthing <emil.renner.berthing@canonical.com>"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/pinctrl/sophgo/Makefile b/drivers/pinctrl/sophgo/Makefile -new file mode 100644 -index 000000000000..2f2cd0d5a99d ---- /dev/null -+++ b/drivers/pinctrl/sophgo/Makefile -@@ -0,0 +1,2 @@ -+obj-$(CONFIG_ARCH_SOPHGO) += pinctrl-sophgo.o -+obj-$(CONFIG_ARCH_SOPHGO) += pinctrl-mango.o -diff --git a/drivers/pinctrl/sophgo/pinctrl-mango.c b/drivers/pinctrl/sophgo/pinctrl-mango.c -new file mode 100644 -index 000000000000..8e7bd08a73db ---- /dev/null -+++ b/drivers/pinctrl/sophgo/pinctrl-mango.c -@@ -0,0 +1,453 @@ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+#include <linux/pinctrl/pinctrl.h> -+#include <linux/pinctrl/pinmux.h> -+#include <linux/pinctrl/pinconf.h> -+#include <linux/pinctrl/pinconf-generic.h> -+#include <linux/device.h> -+#include <linux/of.h> -+ -+#include "../pinctrl-utils.h" -+#include "pinctrl-sophgo.h" -+ -+#define DRV_PINCTRL_NAME "mango_pinctrl" -+#define DRV_PINMUX_NAME "mango_pinmux" -+ -+#define FUNCTION(fname, gname, fmode) \ -+ { \ -+ .name = #fname, \ -+ .groups = gname##_group, \ -+ .num_groups = ARRAY_SIZE(gname##_group), \ -+ .mode = fmode, \ -+ } -+ -+#define PIN_GROUP(gname) \ -+ { \ -+ .name = #gname "_grp", \ -+ .pins = gname##_pins, \ -+ .num_pins = ARRAY_SIZE(gname##_pins), \ -+ } -+ -+static const struct pinctrl_pin_desc mango_pins = { -+ PINCTRL_PIN(0, "MIO0"), -+ PINCTRL_PIN(1, "MIO1"), -+ PINCTRL_PIN(2, "MIO2"), -+ PINCTRL_PIN(3, "MIO3"), -+ PINCTRL_PIN(4, "MIO4"), -+ PINCTRL_PIN(5, "MIO5"), -+ PINCTRL_PIN(6, "MIO6"), -+ PINCTRL_PIN(7, "MIO7"), -+ PINCTRL_PIN(8, "MIO8"), -+ PINCTRL_PIN(9, "MIO9"), -+ PINCTRL_PIN(10, "MIO10"), -+ PINCTRL_PIN(11, "MIO11"), -+ PINCTRL_PIN(12, "MIO12"), -+ PINCTRL_PIN(13, "MIO13"), -+ PINCTRL_PIN(14, "MIO14"), -+ PINCTRL_PIN(15, "MIO15"), -+ PINCTRL_PIN(16, "MIO16"), -+ PINCTRL_PIN(17, "MIO17"), -+ PINCTRL_PIN(18, "MIO18"), -+ PINCTRL_PIN(19, "MIO19"), -+ PINCTRL_PIN(20, "MIO20"), -+ PINCTRL_PIN(21, "MIO21"), -+ PINCTRL_PIN(22, "MIO22"), -+ PINCTRL_PIN(23, "MIO23"), -+ PINCTRL_PIN(24, "MIO24"), -+ PINCTRL_PIN(25, "MIO25"), -+ PINCTRL_PIN(26, "MIO26"), -+ PINCTRL_PIN(27, "MIO27"), -+ PINCTRL_PIN(28, "MIO28"), -+ PINCTRL_PIN(29, "MIO29"), -+ PINCTRL_PIN(30, "MIO30"), -+ PINCTRL_PIN(31, "MIO31"), -+ PINCTRL_PIN(32, "MIO32"), -+ PINCTRL_PIN(33, "MIO33"), -+ PINCTRL_PIN(34, "MIO34"), -+ PINCTRL_PIN(35, "MIO35"), -+ PINCTRL_PIN(36, "MIO36"), -+ PINCTRL_PIN(37, "MIO37"), -+ PINCTRL_PIN(38, "MIO38"), -+ PINCTRL_PIN(39, "MIO39"), -+ PINCTRL_PIN(40, "MIO40"), -+ PINCTRL_PIN(41, "MIO41"), -+ PINCTRL_PIN(42, "MIO42"), -+ PINCTRL_PIN(43, "MIO43"), -+ PINCTRL_PIN(44, "MIO44"), -+ PINCTRL_PIN(45, "MIO45"), -+ PINCTRL_PIN(46, "MIO46"), -+ PINCTRL_PIN(47, "MIO47"), -+ PINCTRL_PIN(48, "MIO48"), -+ PINCTRL_PIN(49, "MIO49"), -+ PINCTRL_PIN(50, "MIO50"), -+ PINCTRL_PIN(51, "MIO51"), -+ PINCTRL_PIN(52, "MIO52"), -+ PINCTRL_PIN(53, "MIO53"), -+ PINCTRL_PIN(54, "MIO54"), -+ PINCTRL_PIN(55, "MIO55"), -+ PINCTRL_PIN(56, "MIO56"), -+ PINCTRL_PIN(57, "MIO57"), -+ PINCTRL_PIN(58, "MIO58"), -+ PINCTRL_PIN(59, "MIO59"), -+ PINCTRL_PIN(60, "MIO60"), -+ PINCTRL_PIN(61, "MIO61"), -+ PINCTRL_PIN(62, "MIO62"), -+ PINCTRL_PIN(63, "MIO63"), -+ PINCTRL_PIN(64, "MIO64"), -+ PINCTRL_PIN(65, "MIO65"), -+ PINCTRL_PIN(66, "MIO66"), -+ PINCTRL_PIN(67, "MIO67"), -+ PINCTRL_PIN(68, "MIO68"), -+ PINCTRL_PIN(69, "MIO69"), -+ PINCTRL_PIN(70, "MIO70"), -+ PINCTRL_PIN(71, "MIO71"), -+ PINCTRL_PIN(72, "MIO72"), -+ PINCTRL_PIN(73, "MIO73"), -+ PINCTRL_PIN(74, "MIO74"), -+ PINCTRL_PIN(75, "MIO75"), -+ PINCTRL_PIN(76, "MIO76"), -+ PINCTRL_PIN(77, "MIO77"), -+ PINCTRL_PIN(78, "MIO78"), -+ PINCTRL_PIN(79, "MIO79"), -+ PINCTRL_PIN(80, "MIO80"), -+ PINCTRL_PIN(81, "MIO81"), -+ PINCTRL_PIN(82, "MIO82"), -+ PINCTRL_PIN(83, "MIO83"), -+ PINCTRL_PIN(84, "MIO84"), -+ PINCTRL_PIN(85, "MIO85"), -+ PINCTRL_PIN(86, "MIO86"), -+ PINCTRL_PIN(87, "MIO87"), -+ PINCTRL_PIN(88, "MIO88"), -+ PINCTRL_PIN(89, "MIO89"), -+ PINCTRL_PIN(90, "MIO90"), -+ PINCTRL_PIN(91, "MIO91"), -+ PINCTRL_PIN(92, "MIO92"), -+ PINCTRL_PIN(93, "MIO93"), -+ PINCTRL_PIN(94, "MIO94"), -+ PINCTRL_PIN(95, "MIO95"), -+ PINCTRL_PIN(96, "MIO96"), -+ PINCTRL_PIN(97, "MIO97"), -+ PINCTRL_PIN(98, "MIO98"), -+ PINCTRL_PIN(99, "MIO99"), -+ PINCTRL_PIN(100, "MIO100"), -+ PINCTRL_PIN(101, "MIO101"), -+ PINCTRL_PIN(102, "MIO102"), -+ PINCTRL_PIN(103, "MIO103"), -+ PINCTRL_PIN(104, "MIO104"), -+ PINCTRL_PIN(105, "MIO105"), -+ PINCTRL_PIN(106, "MIO106"), -+ PINCTRL_PIN(107, "MIO107"), -+ PINCTRL_PIN(108, "MIO108"), -+ PINCTRL_PIN(109, "MIO109"), -+ PINCTRL_PIN(110, "MIO110"), -+ PINCTRL_PIN(111, "MIO111"), -+ PINCTRL_PIN(112, "MIO112"), -+ PINCTRL_PIN(113, "MIO113"), -+ PINCTRL_PIN(114, "MIO114"), -+ PINCTRL_PIN(115, "MIO115"), -+ PINCTRL_PIN(116, "MIO116"), -+ PINCTRL_PIN(117, "MIO117"), -+ PINCTRL_PIN(118, "MIO118"), -+ PINCTRL_PIN(119, "MIO119"), -+ PINCTRL_PIN(120, "MIO120"), -+ PINCTRL_PIN(121, "MIO121"), -+ PINCTRL_PIN(122, "MIO122"), -+ PINCTRL_PIN(123, "MIO123"), -+ PINCTRL_PIN(124, "MIO124"), -+ PINCTRL_PIN(125, "MIO125"), -+ PINCTRL_PIN(126, "MIO126"), -+ PINCTRL_PIN(127, "MIO127"), -+ PINCTRL_PIN(128, "MIO128"), -+ PINCTRL_PIN(129, "MIO129"), -+ PINCTRL_PIN(130, "MIO130"), -+ PINCTRL_PIN(131, "MIO131"), -+ PINCTRL_PIN(132, "MIO132"), -+ PINCTRL_PIN(133, "MIO133"), -+ PINCTRL_PIN(134, "MIO134"), -+ PINCTRL_PIN(135, "MIO135"), -+ PINCTRL_PIN(136, "MIO136"), -+ PINCTRL_PIN(137, "MIO137"), -+ PINCTRL_PIN(138, "MIO138"), -+ PINCTRL_PIN(139, "MIO139"), -+ PINCTRL_PIN(140, "MIO140"), -+ PINCTRL_PIN(141, "MIO141"), -+ PINCTRL_PIN(142, "MIO142"), -+ PINCTRL_PIN(143, "MIO143"), -+ PINCTRL_PIN(144, "MIO144"), -+ PINCTRL_PIN(145, "MIO145"), -+ PINCTRL_PIN(146, "MIO146"), -+ PINCTRL_PIN(147, "MIO147"), -+ PINCTRL_PIN(148, "MIO148"), -+ PINCTRL_PIN(149, "MIO149"), -+ PINCTRL_PIN(150, "MIO150"), -+ PINCTRL_PIN(151, "MIO151"), -+ PINCTRL_PIN(152, "MIO152"), -+ PINCTRL_PIN(153, "MIO153"), -+ PINCTRL_PIN(154, "MIO154"), -+ PINCTRL_PIN(155, "MIO155"), -+ PINCTRL_PIN(156, "MIO156"), -+}; -+ -+static const unsigned int lpc_pins = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; -+static const unsigned int pcie_pins = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; -+static const unsigned int spif_pins = {25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40}; -+static const unsigned int emmc_pins = {41, 42, 43, 44}; -+static const unsigned int sdio_pins = {45, 46, 47, 48}; -+static const unsigned int eth0_pins = {49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}; -+static const unsigned int pwm0_pins = {65}; -+static const unsigned int pwm1_pins = {66}; -+static const unsigned int pwm2_pins = {67}; -+static const unsigned int pwm3_pins = {68}; -+static const unsigned int fan0_pins = {69}; -+static const unsigned int fan1_pins = {70}; -+static const unsigned int fan2_pins = {71}; -+static const unsigned int fan3_pins = {72}; -+static const unsigned int i2c0_pins = {73, 74}; -+static const unsigned int i2c1_pins = {75, 76}; -+static const unsigned int i2c2_pins = {77, 78}; -+static const unsigned int i2c3_pins = {79, 80}; -+static const unsigned int uart0_pins = {81, 82, 83, 84}; -+static const unsigned int uart1_pins = {85, 86, 87, 88}; -+static const unsigned int uart2_pins = {89, 90, 91, 92}; -+static const unsigned int uart3_pins = {93, 94, 95, 96}; -+static const unsigned int spi0_pins = {97, 98, 99, 100, 101}; -+static const unsigned int spi1_pins = {102, 103, 104, 105, 106}; -+static const unsigned int jtag0_pins = {107, 108, 109, 110, 111, 112}; -+static const unsigned int jtag1_pins = {113, 114, 115, 116, 117, 118}; -+static const unsigned int jtag2_pins = {119, 120, 121, 122, 123, 124}; -+static const unsigned int gpio0_pins = {125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,\ -+ 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,\ -+ 151, 152, 153}; -+static const unsigned int dbgi2c_pins = {154, 155, 156}; -+ -+static const char * const lpc_group = {"lpc_grp"}; -+static const char * const pcie_group = {"pcie_grp"}; -+static const char * const spif_group = {"spif_grp"}; -+static const char * const emmc_group = {"emmc_grp"}; -+static const char * const sdio_group = {"sdio_grp"}; -+static const char * const eth0_group = {"eth0_grp"}; -+static const char * const pwm0_group = {"pwm0_grp"}; -+static const char * const pwm1_group = {"pwm1_grp"}; -+static const char * const pwm2_group = {"pwm2_grp"}; -+static const char * const pwm3_group = {"pwm3_grp"}; -+static const char * const fan0_group = {"fan0_grp"}; -+static const char * const fan1_group = {"fan1_grp"}; -+static const char * const fan2_group = {"fan2_grp"}; -+static const char * const fan3_group = {"fan3_grp"}; -+static const char * const i2c0_group = {"i2c0_grp"}; -+static const char * const i2c1_group = {"i2c1_grp"}; -+static const char * const i2c2_group = {"i2c2_grp"}; -+static const char * const i2c3_group = {"i2c3_grp"}; -+static const char * const uart0_group = {"uart0_grp"}; -+static const char * const uart1_group = {"uart1_grp"}; -+static const char * const uart2_group = {"uart2_grp"}; -+static const char * const uart3_group = {"uart3_grp"}; -+static const char * const spi0_group = {"spi0_grp"}; -+static const char * const spi1_group = {"spi1_grp"}; -+static const char * const jtag0_group = {"jtag0_grp"}; -+static const char * const jtag1_group = {"jtag1_grp"}; -+static const char * const jtag2_group = {"jtag2_grp"}; -+static const char * const gpio0_group = {"gpio0_grp"}; -+static const char * const dbgi2c_group = {"dbgi2c_grp"}; -+ -+static struct mango_group mango_groups = { -+ PIN_GROUP(lpc), -+ PIN_GROUP(pcie), -+ PIN_GROUP(spif), -+ PIN_GROUP(emmc), -+ PIN_GROUP(sdio), -+ PIN_GROUP(eth0), -+ PIN_GROUP(pwm0), -+ PIN_GROUP(pwm1), -+ PIN_GROUP(pwm2), -+ PIN_GROUP(pwm3), -+ PIN_GROUP(fan0), -+ PIN_GROUP(fan1), -+ PIN_GROUP(fan2), -+ PIN_GROUP(fan3), -+ PIN_GROUP(i2c0), -+ PIN_GROUP(i2c1), -+ PIN_GROUP(i2c2), -+ PIN_GROUP(i2c3), -+ PIN_GROUP(uart0), -+ PIN_GROUP(uart1), -+ PIN_GROUP(uart2), -+ PIN_GROUP(uart3), -+ PIN_GROUP(spi0), -+ PIN_GROUP(spi1), -+ PIN_GROUP(jtag0), -+ PIN_GROUP(jtag1), -+ PIN_GROUP(jtag2), -+ PIN_GROUP(gpio0), -+ PIN_GROUP(dbgi2c), -+}; -+ -+static const struct mango_pmx_func mango_funcs = { -+ FUNCTION(lpc_a, lpc, FUNC_MODE0), -+ FUNCTION(lpc_r, lpc, FUNC_MODE1), -+ FUNCTION(pcie_a, pcie, FUNC_MODE0), -+ FUNCTION(pcie_r, pcie, FUNC_MODE1), -+ FUNCTION(spif_a, spif, FUNC_MODE0), -+ FUNCTION(spif_r, spif, FUNC_MODE1), -+ FUNCTION(emmc_a, emmc, FUNC_MODE0), -+ FUNCTION(emmc_r, emmc, FUNC_MODE1), -+ FUNCTION(sdio_a, sdio, FUNC_MODE0), -+ FUNCTION(sdio_r, sdio, FUNC_MODE1), -+ FUNCTION(eth0_a, eth0, FUNC_MODE1), -+ FUNCTION(eth0_r, eth0, FUNC_MODE0), -+ FUNCTION(pwm0_a, pwm0, FUNC_MODE0), -+ FUNCTION(pwm0_r, pwm0, FUNC_MODE1), -+ FUNCTION(pwm1_a, pwm1, FUNC_MODE0), -+ FUNCTION(pwm1_r, pwm1, FUNC_MODE1), -+ FUNCTION(pwm2_a, pwm2, FUNC_MODE0), -+ FUNCTION(pwm2_r, pwm2, FUNC_MODE1), -+ FUNCTION(pwm3_a, pwm3, FUNC_MODE0), -+ FUNCTION(pwm3_r, pwm3, FUNC_MODE1), -+ FUNCTION(fan0_a, fan0, FUNC_MODE1), -+ FUNCTION(fan0_r, fan0, FUNC_MODE0), -+ FUNCTION(fan1_a, fan1, FUNC_MODE1), -+ FUNCTION(fan1_r, fan1, FUNC_MODE0), -+ FUNCTION(fan2_a, fan2, FUNC_MODE1), -+ FUNCTION(fan2_r, fan2, FUNC_MODE0), -+ FUNCTION(fan3_a, fan3, FUNC_MODE1), -+ FUNCTION(fan3_r, fan3, FUNC_MODE0), -+ FUNCTION(i2c0_a, i2c0, FUNC_MODE0), -+ FUNCTION(i2c0_r, i2c0, FUNC_MODE1), -+ FUNCTION(i2c1_a, i2c1, FUNC_MODE0), -+ FUNCTION(i2c1_r, i2c1, FUNC_MODE1), -+ FUNCTION(i2c2_a, i2c2, FUNC_MODE1), -+ FUNCTION(i2c2_r, i2c2, FUNC_MODE0), -+ FUNCTION(i2c3_a, i2c3, FUNC_MODE1), -+ FUNCTION(i2c3_r, i2c3, FUNC_MODE0), -+ FUNCTION(uart0_a, uart0, FUNC_MODE0), -+ FUNCTION(uart0_r, uart0, FUNC_MODE1), -+ FUNCTION(uart1_a, uart1, FUNC_MODE0), -+ FUNCTION(uart1_r, uart1, FUNC_MODE1), -+ FUNCTION(uart2_a, uart2, FUNC_MODE1), -+ FUNCTION(uart2_r, uart2, FUNC_MODE0), -+ FUNCTION(uart3_a, uart3, FUNC_MODE1), -+ FUNCTION(uart3_r, uart3, FUNC_MODE0), -+ FUNCTION(spi0_a, spi0, FUNC_MODE1), -+ FUNCTION(spi0_r, spi0, FUNC_MODE0), -+ FUNCTION(spi1_a, spi1, FUNC_MODE0), -+ FUNCTION(spi1_r, spi1, FUNC_MODE1), -+ FUNCTION(jtag0_a, jtag0, FUNC_MODE0), -+ FUNCTION(jtag0_r, jtag0, FUNC_MODE1), -+ FUNCTION(jtag1_a, jtag1, FUNC_MODE1), -+ FUNCTION(jtag1_r, jtag1, FUNC_MODE0), -+ FUNCTION(jtag2_a, jtag2, FUNC_MODE1), -+ FUNCTION(jtag2_r, jtag2, FUNC_MODE0), -+ FUNCTION(gpio0_a, gpio0, FUNC_MODE1), -+ FUNCTION(gpio0_r, gpio0, FUNC_MODE0), -+ FUNCTION(dbgi2c_a, dbgi2c, FUNC_MODE0), -+ FUNCTION(dbgi2c_r, dbgi2c, FUNC_MODE1), -+}; -+ -+static struct device_attribute lpc_attr = __ATTR(lpc, 0664, pinmux_show, pinmux_store); -+static struct device_attribute pcie_attr = __ATTR(pcie, 0664, pinmux_show, pinmux_store); -+static struct device_attribute spif_attr = __ATTR(spif, 0664, pinmux_show, pinmux_store); -+static struct device_attribute emmc_attr = __ATTR(emmc, 0664, pinmux_show, pinmux_store); -+static struct device_attribute sdio_attr = __ATTR(sdio, 0664, pinmux_show, pinmux_store); -+static struct device_attribute eth0_attr = __ATTR(eth0, 0664, pinmux_show, pinmux_store); -+static struct device_attribute pwm0_attr = __ATTR(pwm0, 0664, pinmux_show, pinmux_store); -+static struct device_attribute pwm1_attr = __ATTR(pwm1, 0664, pinmux_show, pinmux_store); -+static struct device_attribute pwm2_attr = __ATTR(pwm2, 0664, pinmux_show, pinmux_store); -+static struct device_attribute pwm3_attr = __ATTR(pwm3, 0664, pinmux_show, pinmux_store); -+static struct device_attribute fan0_attr = __ATTR(fan0, 0664, pinmux_show, pinmux_store); -+static struct device_attribute fan1_attr = __ATTR(fan1, 0664, pinmux_show, pinmux_store); -+static struct device_attribute fan2_attr = __ATTR(fan2, 0664, pinmux_show, pinmux_store); -+static struct device_attribute fan3_attr = __ATTR(fan3, 0664, pinmux_show, pinmux_store); -+static struct device_attribute i2c0_attr = __ATTR(i2c0, 0664, pinmux_show, pinmux_store); -+static struct device_attribute i2c1_attr = __ATTR(i2c1, 0664, pinmux_show, pinmux_store); -+static struct device_attribute i2c2_attr = __ATTR(i2c2, 0664, pinmux_show, pinmux_store); -+static struct device_attribute i2c3_attr = __ATTR(i2c3, 0664, pinmux_show, pinmux_store); -+static struct device_attribute uart0_attr = __ATTR(uart0, 0664, pinmux_show, pinmux_store); -+static struct device_attribute uart1_attr = __ATTR(uart1, 0664, pinmux_show, pinmux_store); -+static struct device_attribute uart2_attr = __ATTR(uart2, 0664, pinmux_show, pinmux_store); -+static struct device_attribute uart3_attr = __ATTR(uart3, 0664, pinmux_show, pinmux_store); -+static struct device_attribute spi0_attr = __ATTR(spi0, 0664, pinmux_show, pinmux_store); -+static struct device_attribute spi1_attr = __ATTR(spi1, 0664, pinmux_show, pinmux_store); -+static struct device_attribute jtag0_attr = __ATTR(jtag0, 0664, pinmux_show, pinmux_store); -+static struct device_attribute jtag1_attr = __ATTR(jtag1, 0664, pinmux_show, pinmux_store); -+static struct device_attribute jtag2_attr = __ATTR(jtag2, 0664, pinmux_show, pinmux_store); -+static struct device_attribute gpio0_attr = __ATTR(gpio0, 0664, pinmux_show, pinmux_store); -+static struct device_attribute dbgi2c_attr = __ATTR(dbgi2c, 0664, pinmux_show, pinmux_store); -+ -+ -+static struct attribute *pinmux_attrs = { -+ &lpc_attr.attr, -+ &pcie_attr.attr, -+ &spif_attr.attr, -+ &emmc_attr.attr, -+ &sdio_attr.attr, -+ ð0_attr.attr, -+ &pwm0_attr.attr, -+ &pwm1_attr.attr, -+ &pwm2_attr.attr, -+ &pwm3_attr.attr, -+ &fan0_attr.attr, -+ &fan1_attr.attr, -+ &fan2_attr.attr, -+ &fan3_attr.attr, -+ &i2c0_attr.attr, -+ &i2c1_attr.attr, -+ &i2c2_attr.attr, -+ &i2c3_attr.attr, -+ &uart0_attr.attr, -+ &uart1_attr.attr, -+ &uart2_attr.attr, -+ &uart3_attr.attr, -+ &spi0_attr.attr, -+ &spi1_attr.attr, -+ &jtag0_attr.attr, -+ &jtag1_attr.attr, -+ &jtag2_attr.attr, -+ &gpio0_attr.attr, -+ &dbgi2c_attr.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(pinmux); -+ -+static struct class pinmux_class = { -+ .name = "pinmux", -+ .dev_groups = pinmux_groups, -+}; -+ -+static struct mango_soc_pinctrl_data mango_pinctrl_data = { -+ .pins = mango_pins, -+ .npins = ARRAY_SIZE(mango_pins), -+ .groups = mango_groups, -+ .groups_count = ARRAY_SIZE(mango_groups), -+ .functions = mango_funcs, -+ .functions_count = ARRAY_SIZE(mango_funcs), -+ .p_class = &pinmux_class, -+}; -+ -+static const struct of_device_id mango_pinctrl_of_table = { -+ { -+ .compatible = "sophgo, pinctrl-mango", -+ .data = &mango_pinctrl_data, -+ }, -+ {} -+}; -+ -+static int mango_pinctrl_probe(struct platform_device *pdev) -+{ -+ return sophgo_pinctrl_probe(pdev); -+} -+ -+static struct platform_driver mango_pinctrl_driver = { -+ .probe = mango_pinctrl_probe, -+ .driver = { -+ .name = DRV_PINCTRL_NAME, -+ .of_match_table = of_match_ptr(mango_pinctrl_of_table), -+ }, -+}; -+ -+static int __init mango_pinctrl_init(void) -+{ -+ return platform_driver_register(&mango_pinctrl_driver); -+} -+postcore_initcall(mango_pinctrl_init); -diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.c b/drivers/pinctrl/sophgo/pinctrl-sophgo.c -new file mode 100644 -index 000000000000..0862177d4144 ---- /dev/null -+++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.c -@@ -0,0 +1,292 @@ -+#include <linux/init.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+#include <linux/of_device.h> -+#include <linux/mfd/syscon.h> -+#include <linux/regmap.h> -+ -+#include "pinctrl-sophgo.h" -+ -+ -+static int mango_get_groups(struct pinctrl_dev *pctldev, unsigned int selector, -+ const char * const **groups, -+ unsigned int * const num_groups); -+ -+static struct mango_soc_pinctrl_data *get_pinmux_data(struct pinctrl_dev *pctldev) -+{ -+ struct mango_pinctrl *mangopctrl = pinctrl_dev_get_drvdata(pctldev); -+ -+ return mangopctrl->data; -+} -+ -+static int mango_get_functions_count(struct pinctrl_dev *pctldev) -+{ -+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); -+ -+ return data->functions_count; -+} -+ -+static const char *mango_get_fname(struct pinctrl_dev *pctldev, -+ unsigned int selector) -+{ -+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); -+ -+ return data->functionsselector.name; -+} -+ -+static int mango_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, -+ unsigned int group) -+{ -+ int p; -+ unsigned int pidx; -+ u32 offset, regval, mux_offset; -+ struct mango_pinctrl *ctrl = pinctrl_dev_get_drvdata(pctldev); -+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); -+ -+ data->groupsgroup.cur_func_idx = data->functionsselector.mode; -+ for (p = 0; p < data->groupsgroup.num_pins; p++) { -+ pidx = data->groupsgroup.pinsp; -+ offset = (pidx >> 1) << 2; -+ regmap_read(ctrl->syscon_pinctl, -+ ctrl->top_pinctl_offset + offset, ®val); -+ mux_offset = ((!((pidx + 1) & 1) << 4) + 4); -+ -+ regval = regval & ~(3 << mux_offset); -+ regval |= data->functionsselector.mode << mux_offset; -+ regmap_write(ctrl->syscon_pinctl, -+ ctrl->top_pinctl_offset + offset, regval); -+ regmap_read(ctrl->syscon_pinctl, -+ ctrl->top_pinctl_offset + offset, ®val); -+ dev_dbg(ctrl->dev, "%s : check new reg=0x%x val=0x%x\n", -+ data->groupsgroup.name, -+ ctrl->top_pinctl_offset + offset, regval); -+ } -+ -+ return 0; -+} -+ -+static const struct pinmux_ops mango_pinmux_ops = { -+ .get_functions_count = mango_get_functions_count, -+ .get_function_name = mango_get_fname, -+ .get_function_groups = mango_get_groups, -+ .set_mux = mango_set_mux, -+ .strict = true, -+}; -+ -+static int mango_pinconf_cfg_get(struct pinctrl_dev *pctldev, unsigned int pin, -+ unsigned long *config) -+{ -+ return 0; -+} -+ -+static int mango_pinconf_cfg_set(struct pinctrl_dev *pctldev, unsigned int pin, -+ unsigned long *configs, unsigned int num_configs) -+{ -+ return 0; -+} -+ -+static int mango_pinconf_group_set(struct pinctrl_dev *pctldev, -+ unsigned int selector, unsigned long *configs, unsigned int num_configs) -+{ -+ return 0; -+} -+ -+static const struct pinconf_ops mango_pinconf_ops = { -+ .is_generic = true, -+ .pin_config_get = mango_pinconf_cfg_get, -+ .pin_config_set = mango_pinconf_cfg_set, -+ .pin_config_group_set = mango_pinconf_group_set, -+}; -+ -+static int mango_get_groups(struct pinctrl_dev *pctldev, unsigned int selector, -+ const char * const **groups, -+ unsigned int * const num_groups) -+{ -+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); -+ -+ *groups = data->functionsselector.groups; -+ *num_groups = data->functionsselector.num_groups; -+ -+ return 0; -+} -+ -+static int mango_get_groups_count(struct pinctrl_dev *pctldev) -+{ -+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); -+ -+ return data->groups_count; -+} -+ -+static const char *mango_get_group_name(struct pinctrl_dev *pctldev, -+ unsigned int selector) -+{ -+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); -+ -+ return data->groupsselector.name; -+} -+ -+static int mango_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, -+ const unsigned int **pins, -+ unsigned int *num_pins) -+{ -+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev); -+ -+ *pins = data->groupsselector.pins; -+ *num_pins = data->groupsselector.num_pins; -+ -+ return 0; -+} -+ -+static void mango_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, -+ unsigned int offset) -+{ -+} -+ -+static const struct pinctrl_ops mango_pctrl_ops = { -+ .get_groups_count = mango_get_groups_count, -+ .get_group_name = mango_get_group_name, -+ .get_group_pins = mango_get_group_pins, -+ .pin_dbg_show = mango_pin_dbg_show, -+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all, -+ .dt_free_map = pinctrl_utils_free_map, -+}; -+ -+static struct pinctrl_desc mango_desc = { -+ .name = "mango_pinctrl", -+ .pctlops = &mango_pctrl_ops, -+ .pmxops = &mango_pinmux_ops, -+ .confops = &mango_pinconf_ops, -+ .owner = THIS_MODULE, -+}; -+ -+ssize_t pinmux_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct mango_pinctrl *mangopctrl; -+ int p, ret, group, selector = -1; -+ struct mango_soc_pinctrl_data *data; -+ -+ mangopctrl = dev_get_drvdata(dev); -+ data = (struct mango_soc_pinctrl_data *)mangopctrl->data; -+ -+ for (p = 0; p < data->functions_count; p++) { -+ if (!strncmp(attr->attr.name, data->functionsp.name, -+ strlen(attr->attr.name))) { -+ selector = p; -+ break; -+ } -+ } -+ if (selector < 0) -+ return -ENXIO; -+ -+ group = selector/2; -+ ret = snprintf(buf, 128, "%d\n", data->groupsgroup.cur_func_idx); -+ if (ret <= 0 || ret > 128) { -+ dev_err(dev, "snprintf failed %d\n", ret); -+ return -EFAULT; -+ } -+ return ret; -+} -+ -+ssize_t pinmux_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t size) -+{ -+ struct mango_pinctrl *mangopctrl; -+ int p, ret, group, selector = -1; -+ unsigned long user_data; -+ struct mango_soc_pinctrl_data *data; -+ -+ ret = kstrtoul(buf, 0, &user_data); -+ if (ret) -+ return -EINVAL; -+ -+ if (user_data != 0 && user_data != 1) -+ return -EINVAL; -+ -+ mangopctrl = dev_get_drvdata(dev); -+ data = (struct mango_soc_pinctrl_data *)mangopctrl->data; -+ -+ for (p = 0; p < data->functions_count; p++) { -+ if (!strncmp(attr->attr.name, data->functionsp.name, -+ strlen(attr->attr.name)) && -+ (user_data == data->functionsp.mode)) { -+ selector = p; -+ break; -+ } -+ } -+ if (selector < 0) -+ return -ENXIO; -+ -+ group = selector/2; -+ mango_set_mux(mangopctrl->pctl, selector, group); -+ -+ dev_info(dev, "pinmux store set %s to func %d\n", -+ attr->attr.name, data->functionsselector.mode); -+ return size; -+} -+ -+ -+int sophgo_pinctrl_probe(struct platform_device *pdev) -+{ -+ struct mango_pinctrl *mangopctrl; -+ struct pinctrl_desc *desc; -+ struct mango_soc_pinctrl_data *data; -+ struct device *dev = &pdev->dev; -+ struct device *pin_dev = NULL; -+ struct device_node *np = dev->of_node, *np_top; -+ static struct regmap *syscon; -+ int ret; -+ -+ data = (struct mango_soc_pinctrl_data *)of_device_get_match_data(&pdev->dev); -+ if (!data) -+ return -EINVAL; -+ mangopctrl = devm_kzalloc(&pdev->dev, sizeof(*mangopctrl), GFP_KERNEL); -+ if (!mangopctrl) -+ return -ENOMEM; -+ -+ mangopctrl->dev = &pdev->dev; -+ -+ np_top = of_parse_phandle(np, "subctrl-syscon", 0); -+ if (!np_top) { -+ dev_err(dev, "%s can't get subctrl-syscon node\n", __func__); -+ return -EINVAL; -+ } -+ syscon = syscon_node_to_regmap(np_top); -+ if (IS_ERR(syscon)) { -+ dev_err(dev, "cannot get regmap\n"); -+ return PTR_ERR(syscon); -+ } -+ mangopctrl->syscon_pinctl = syscon; -+ -+ ret = device_property_read_u32(&pdev->dev, -+ "top_pinctl_offset", &mangopctrl->top_pinctl_offset); -+ if (ret < 0) { -+ dev_err(dev, "cannot get top_pinctl_offset\n"); -+ return ret; -+ } -+ -+ desc = &mango_desc; -+ desc->pins = data->pins; -+ desc->npins = data->npins; -+ -+ mangopctrl->data = (void *)data; -+ mangopctrl->pctl = devm_pinctrl_register(&pdev->dev, desc, mangopctrl); -+ if (IS_ERR(mangopctrl->pctl)) { -+ dev_err(&pdev->dev, "could not register Sophgo pin ctrl driver\n"); -+ return PTR_ERR(mangopctrl->pctl); -+ } -+ -+ platform_set_drvdata(pdev, mangopctrl); -+ -+ ret = class_register(data->p_class); -+ if (ret < 0) { -+ dev_err(dev, "cannot register pinmux class\n"); -+ return ret; -+ } -+ pin_dev = device_create(data->p_class, &pdev->dev, MKDEV(0, 0), mangopctrl, "mango_pinmux"); -+ if (IS_ERR(pin_dev)) -+ return PTR_ERR(pin_dev); -+ -+ return 0; -+} -diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.h b/drivers/pinctrl/sophgo/pinctrl-sophgo.h -new file mode 100644 -index 000000000000..f3a30f0275b1 ---- /dev/null -+++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.h -@@ -0,0 +1,70 @@ -+#ifndef __mango_PINCTRL_CORE_H__ -+#define __mango_PINCTRL_CORE_H__ -+ -+#include <linux/pinctrl/pinctrl.h> -+#include <linux/pinctrl/pinmux.h> -+#include <linux/pinctrl/pinconf.h> -+#include <linux/pinctrl/pinconf-generic.h> -+#include "../pinctrl-utils.h" -+#include "../core.h" -+ -+enum FUNC_MODE { -+ FUNC_MODE0, -+ FUNC_MODE1, -+ FUNC_MODE2, -+ FUNC_MODE3, -+ FUNC_MASK, -+}; -+ -+struct mango_pinctrl { -+ struct device *dev; -+ struct pinctrl_dev *pctl; -+ u32 top_pinctl_offset; -+ struct regmap *syscon_pinctl; -+ void *data; -+}; -+ -+struct mango_group { -+ const char *name; -+ const unsigned int *pins; -+ const unsigned int num_pins; -+ int cur_func_idx; -+ struct mango_pmx_func *funcs; -+}; -+ -+struct mango_pmx_func { -+ const char *name; -+ const char * const *groups; -+ unsigned int num_groups; -+ enum FUNC_MODE mode; -+}; -+ -+struct mango_soc_pinmux_info { -+ const char name16; -+ const char name_a16; -+ const char name_r16; -+ struct pinctrl_state *pinctrl_a; -+ struct pinctrl_state *pinctrl_r; -+ const unsigned int def_state; /* default state */ -+ int (*set)(struct device *dev, unsigned int data); -+}; -+ -+struct mango_soc_pinctrl_data { -+ const struct pinctrl_pin_desc *pins; -+ unsigned int npins; -+ struct mango_group *groups; -+ int groups_count; -+ const struct mango_pmx_func *functions; -+ int functions_count; -+ struct class *p_class; -+}; -+ -+int sophgo_pinctrl_probe(struct platform_device *pdev); -+int mango_pmux_probe(struct platform_device *pdev); -+ -+ssize_t pinmux_show(struct device *dev, -+ struct device_attribute *attr, char *buf); -+ -+ssize_t pinmux_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t size); -+#endif -diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig -index 8ebcddf91f7b..428fa365a19a 100644 ---- a/drivers/pwm/Kconfig -+++ b/drivers/pwm/Kconfig -@@ -637,6 +637,17 @@ config PWM_TEGRA - To compile this driver as a module, choose M here: the module - will be called pwm-tegra. - -+config PWM_THEAD -+ tristate "T-HEAD PWM support" -+ depends on ARCH_THEAD || COMPILE_TEST -+ depends on HAS_IOMEM -+ help -+ Generic PWM framework driver for the PWFM controller found on THEAD -+ SoCs. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called pwm-thead. -+ - config PWM_TIECAP - tristate "ECAP PWM support" - depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST -diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile -index c822389c2a24..4847ffd6997d 100644 ---- a/drivers/pwm/Makefile -+++ b/drivers/pwm/Makefile -@@ -50,6 +50,7 @@ obj-$(CONFIG_PWM_RZ_MTU3) += pwm-rz-mtu3.o - obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o - obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o - obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o -+obj-$(CONFIG_ARCH_SOPHGO) += pwm-sophgo.o - obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o - obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o - obj-$(CONFIG_PWM_STI) += pwm-sti.o -@@ -59,6 +60,7 @@ obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o - obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o - obj-$(CONFIG_PWM_SUNPLUS) += pwm-sunplus.o - obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o -+obj-$(CONFIG_PWM_THEAD) += pwm-thead.o - obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o - obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o - obj-$(CONFIG_PWM_TWL) += pwm-twl.o -diff --git a/drivers/pwm/pwm-sophgo.c b/drivers/pwm/pwm-sophgo.c -new file mode 100644 -index 000000000000..b6297175a5b7 ---- /dev/null -+++ b/drivers/pwm/pwm-sophgo.c -@@ -0,0 +1,276 @@ -+/* -+ * Copyright (c) 2007 Ben Dooks -+ * Copyright (c) 2008 Simtec Electronics -+ * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org> -+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com> -+ * -+ * PWM driver for Samsung SoCs -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License. -+ */ -+ -+#include <linux/bitops.h> -+#include <linux/clk.h> -+#include <linux/export.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+#include <linux/pwm.h> -+#include <linux/slab.h> -+ -+ -+ -+#define REG_HLPERIOD 0x0 -+#define REG_PERIOD 0x4 -+#define REG_GROUP 0x8 -+#define REG_POLARITY 0x20 -+ -+ -+/** -+ * struct sophgo_pwm_channel - private data of PWM channel -+ * @period_ns: current period in nanoseconds programmed to the hardware -+ * @duty_ns: current duty time in nanoseconds programmed to the hardware -+ * @tin_ns: time of one timer tick in nanoseconds with current timer rate -+ */ -+struct sophgo_pwm_channel { -+ u32 period; -+ u32 hlperiod; -+}; -+ -+/** -+ * struct sophgo_pwm_chip - private data of PWM chip -+ * @chip: generic PWM chip -+ * @variant: local copy of hardware variant data -+ * @inverter_mask: inverter status for all channels - one bit per channel -+ * @base: base address of mapped PWM registers -+ * @base_clk: base clock used to drive the timers -+ * @tclk0: external clock 0 (can be ERR_PTR if not present) -+ * @tclk1: external clock 1 (can be ERR_PTR if not present) -+ */ -+struct sophgo_pwm_chip { -+ struct pwm_chip chip; -+ void __iomem *base; -+ struct clk *base_clk; -+ u8 polarity_mask; -+ bool no_polarity; -+}; -+ -+ -+static inline -+struct sophgo_pwm_chip *to_sophgo_pwm_chip(struct pwm_chip *chip) -+{ -+ return container_of(chip, struct sophgo_pwm_chip, chip); -+} -+ -+static int pwm_sophgo_request(struct pwm_chip *chip, struct pwm_device *pwm_dev) -+{ -+ struct sophgo_pwm_channel *channel; -+ -+ channel = kzalloc(sizeof(*channel), GFP_KERNEL); -+ if (!channel) -+ return -ENOMEM; -+ -+ return pwm_set_chip_data(pwm_dev, channel); -+} -+ -+static void pwm_sophgo_free(struct pwm_chip *chip, struct pwm_device *pwm_dev) -+{ -+ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev); -+ -+ pwm_set_chip_data(pwm_dev, NULL); -+ kfree(channel); -+} -+ -+static int pwm_sophgo_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, -+ int duty_ns, int period_ns) -+{ -+ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip); -+ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev); -+ u64 cycles; -+ -+ cycles = clk_get_rate(our_chip->base_clk); -+ cycles *= period_ns; -+ do_div(cycles, NSEC_PER_SEC); -+ -+ channel->period = cycles; -+ cycles = cycles * duty_ns; -+ do_div(cycles, period_ns); -+ channel->hlperiod = channel->period - cycles; -+ -+ return 0; -+} -+ -+static int pwm_sophgo_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev) -+{ -+ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip); -+ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev); -+ -+ writel(channel->period, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_PERIOD); -+ writel(channel->hlperiod, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_HLPERIOD); -+ -+ return 0; -+} -+ -+static void pwm_sophgo_disable(struct pwm_chip *chip, -+ struct pwm_device *pwm_dev) -+{ -+ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip); -+ -+ writel(0, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_PERIOD); -+ writel(0, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_HLPERIOD); -+} -+ -+static int pwm_sophgo_apply(struct pwm_chip *chip, struct pwm_device *pwm, -+ const struct pwm_state *state) -+{ -+ int ret; -+ -+ bool enabled = pwm->state.enabled; -+ -+ if (state->polarity != pwm->state.polarity && pwm->state.enabled) { -+ pwm_sophgo_disable(chip, pwm); -+ enabled = false; -+ } -+ -+ if (!state->enabled) { -+ if (enabled) -+ pwm_sophgo_disable(chip, pwm); -+ return 0; -+ } -+ -+ ret = pwm_sophgo_config(chip, pwm, state->duty_cycle, state->period); -+ if (ret) { -+ dev_err(chip->dev, "pwm apply err\n"); -+ return ret; -+ } -+ dev_dbg(chip->dev, "%s tate->enabled =%d\n", __func__, state->enabled); -+ if (state->enabled) -+ ret = pwm_sophgo_enable(chip, pwm); -+ else -+ pwm_sophgo_disable(chip, pwm); -+ -+ if (ret) { -+ dev_err(chip->dev, "pwm apply failed\n"); -+ return ret; -+ } -+ return ret; -+} -+ -+static const struct pwm_ops pwm_sophgo_ops = { -+ .request = pwm_sophgo_request, -+ .free = pwm_sophgo_free, -+ .apply = pwm_sophgo_apply, -+ .owner = THIS_MODULE, -+}; -+ -+static const struct of_device_id sophgo_pwm_match = { -+ { .compatible = "sophgo,sophgo-pwm" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, sophgo_pwm_match); -+ -+static int pwm_sophgo_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct sophgo_pwm_chip *chip; -+ struct resource *res; -+ int ret; -+ -+ pr_info("%s\n", __func__); -+ -+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); -+ if (chip == NULL) -+ return -ENOMEM; -+ -+ chip->chip.dev = &pdev->dev; -+ chip->chip.ops = &pwm_sophgo_ops; -+ chip->chip.base = -1; -+ chip->polarity_mask = 0; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ chip->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(chip->base)) -+ return PTR_ERR(chip->base); -+ -+ chip->base_clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(chip->base_clk)) { -+ dev_err(dev, "failed to get pwm source clk\n"); -+ return PTR_ERR(chip->base_clk); -+ } -+ -+ ret = clk_prepare_enable(chip->base_clk); -+ if (ret < 0) { -+ dev_err(dev, "failed to enable base clock\n"); -+ return ret; -+ } -+ -+ //pwm-num default is 4, compatible with sg2042 -+ if (of_property_read_bool(pdev->dev.of_node, "pwm-num")) -+ device_property_read_u32(&pdev->dev, "pwm-num", &chip->chip.npwm); -+ else -+ chip->chip.npwm = 4; -+ -+ //no_polarity default is false(have polarity) , compatible with sg2042 -+ if (of_property_read_bool(pdev->dev.of_node, "no-polarity")) -+ chip->no_polarity = true; -+ else -+ chip->no_polarity = false; -+ pr_debug("chip->chip.npwm =%d chip->no_polarity=%d\n", chip->chip.npwm, chip->no_polarity); -+ -+ platform_set_drvdata(pdev, chip); -+ -+ ret = pwmchip_add(&chip->chip); -+ if (ret < 0) { -+ dev_err(dev, "failed to register PWM chip\n"); -+ clk_disable_unprepare(chip->base_clk); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int pwm_sophgo_remove(struct platform_device *pdev) -+{ -+ struct sophgo_pwm_chip *chip = platform_get_drvdata(pdev); -+ -+ pwmchip_remove(&chip->chip); -+ -+ clk_disable_unprepare(chip->base_clk); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int pwm_sophgo_suspend(struct device *dev) -+{ -+ return 0; -+} -+ -+static int pwm_sophgo_resume(struct device *dev) -+{ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(pwm_sophgo_pm_ops, pwm_sophgo_suspend, -+ pwm_sophgo_resume); -+ -+static struct platform_driver pwm_sophgo_driver = { -+ .driver = { -+ .name = "sophgo-pwm", -+ .pm = &pwm_sophgo_pm_ops, -+ .of_match_table = of_match_ptr(sophgo_pwm_match), -+ }, -+ .probe = pwm_sophgo_probe, -+ .remove = pwm_sophgo_remove, -+}; -+module_platform_driver(pwm_sophgo_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("chunzhi.lin"); -+MODULE_DESCRIPTION("Sophgo PWM driver"); -diff --git a/drivers/pwm/pwm-thead.c b/drivers/pwm/pwm-thead.c -new file mode 100644 -index 000000000000..3b4772c3b8ca ---- /dev/null -+++ b/drivers/pwm/pwm-thead.c -@@ -0,0 +1,269 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * T-HEAD PWM driver -+ * -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org> -+ * -+ * Limitations: -+ * - The THEAD_PWM_CTRL_START bit is only effective when 0 -> 1, which is used -+ * to start the channel, 1 -> 0 doesn't change anything. so 0 % duty cycle -+ * is used to "disable" the channel. -+ * - The THEAD_PWM_CTRL_START bit is automatically cleared once PWM channel is -+ * started. -+ * - The THEAD_PWM_CFG_UPDATE atomically updates and only updates period and duty. -+ * - To update period and duty, THEAD_PWM_CFG_UPDATE needs to go through 0 -> 1 -+ * step, I.E if THEAD_PWM_CFG_UPDATE is already 1, it's necessary to clear it -+ * to 0 beforehand. -+ * - Polarity can only be changed if never started before. -+ */ -+ -+#include <linux/bitfield.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/mod_devicetable.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/pm_runtime.h> -+#include <linux/pwm.h> -+#include <linux/slab.h> -+ -+#define THEAD_PWM_MAX_NUM 6 -+#define THEAD_PWM_MAX_PERIOD GENMASK(31, 0) -+#define THEAD_PWM_MAX_DUTY GENMASK(31, 0) -+ -+#define THEAD_PWM_CHN_BASE(n) ((n) * 0x20) -+#define THEAD_PWM_CTRL(n) (THEAD_PWM_CHN_BASE(n) + 0x00) -+#define THEAD_PWM_CTRL_START BIT(0) -+#define THEAD_PWM_CTRL_SOFT_RST BIT(1) -+#define THEAD_PWM_CTRL_CFG_UPDATE BIT(2) -+#define THEAD_PWM_CTRL_INTEN BIT(3) -+#define THEAD_PWM_CTRL_MODE GENMASK(5, 4) -+#define THEAD_PWM_CTRL_MODE_CONTINUOUS FIELD_PREP(THEAD_PWM_CTRL_MODE, 2) -+#define THEAD_PWM_CTRL_EVTRIG GENMASK(7, 6) -+#define THEAD_PWM_CTRL_FPOUT BIT(8) -+#define THEAD_PWM_CTRL_INFACTOUT BIT(9) -+#define THEAD_PWM_RPT(n) (THEAD_PWM_CHN_BASE(n) + 0x04) -+#define THEAD_PWM_PER(n) (THEAD_PWM_CHN_BASE(n) + 0x08) -+#define THEAD_PWM_FP(n) (THEAD_PWM_CHN_BASE(n) + 0x0c) -+#define THEAD_PWM_STATUS(n) (THEAD_PWM_CHN_BASE(n) + 0x10) -+#define THEAD_PWM_STATUS_CYCLE GENMASK(7, 0) -+ -+struct thead_pwm_chip { -+ struct pwm_chip chip; -+ void __iomem *mmio_base; -+ struct clk *clk; -+ u8 channel_ever_started; -+}; -+ -+static inline struct thead_pwm_chip *thead_pwm_from_chip(struct pwm_chip *chip) -+{ -+ return container_of(chip, struct thead_pwm_chip, chip); -+} -+ -+static int thead_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, -+ const struct pwm_state *state) -+{ -+ struct thead_pwm_chip *priv = thead_pwm_from_chip(chip); -+ u32 val = THEAD_PWM_CTRL_INFACTOUT | THEAD_PWM_CTRL_FPOUT | THEAD_PWM_CTRL_MODE_CONTINUOUS; -+ u64 period_cycle, duty_cycle, rate; -+ int ret; -+ -+ /* if ever started, can't change the polarity */ -+ if ((priv->channel_ever_started & (1 << pwm->hwpwm)) && -+ state->polarity != pwm->state.polarity) -+ return -EINVAL; -+ -+ if (!state->enabled) { -+ if (pwm->state.enabled) { -+ val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); -+ val &= ~THEAD_PWM_CTRL_CFG_UPDATE; -+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); -+ -+ writel(0, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); -+ -+ val |= THEAD_PWM_CTRL_CFG_UPDATE; -+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); -+ pm_runtime_put_sync(chip->dev); -+ } -+ return 0; -+ } -+ -+ if (!pwm->state.enabled) { -+ ret = pm_runtime_resume_and_get(chip->dev); -+ if (ret < 0) -+ return ret; -+ } -+ -+ if (state->polarity == PWM_POLARITY_INVERSED) -+ val &= ~THEAD_PWM_CTRL_FPOUT; -+ -+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); -+ -+ rate = clk_get_rate(priv->clk); -+ /* -+ * The following calculations might overflow if clk is bigger -+ * than 1 GHz. In practise it's 24MHz, so this limitation -+ * is only theoretic. -+ */ -+ if (rate > NSEC_PER_SEC) -+ return -EINVAL; -+ -+ period_cycle = mul_u64_u64_div_u64(rate, state->period, NSEC_PER_SEC); -+ if (period_cycle > THEAD_PWM_MAX_PERIOD) -+ period_cycle = THEAD_PWM_MAX_PERIOD; -+ /* -+ * With limitation above we have period_cycle <= THEAD_PWM_MAX_PERIOD, -+ * so this cannot overflow. -+ */ -+ writel(period_cycle, priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm)); -+ -+ duty_cycle = mul_u64_u64_div_u64(rate, state->duty_cycle, NSEC_PER_SEC); -+ if (duty_cycle > THEAD_PWM_MAX_DUTY) -+ duty_cycle = THEAD_PWM_MAX_DUTY; -+ /* -+ * With limitation above we have duty_cycle <= THEAD_PWM_MAX_DUTY, -+ * so this cannot overflow. -+ */ -+ writel(duty_cycle, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); -+ -+ val |= THEAD_PWM_CTRL_CFG_UPDATE; -+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); -+ -+ if (!pwm->state.enabled) { -+ val |= THEAD_PWM_CTRL_START; -+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); -+ priv->channel_ever_started |= 1 << pwm->hwpwm; -+ } -+ -+ return 0; -+} -+ -+static int thead_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, -+ struct pwm_state *state) -+{ -+ struct thead_pwm_chip *priv = thead_pwm_from_chip(chip); -+ u64 rate = clk_get_rate(priv->clk); -+ u32 val; -+ int ret; -+ -+ ret = pm_runtime_resume_and_get(chip->dev); -+ if (ret < 0) -+ return ret; -+ -+ val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm)); -+ if (val & THEAD_PWM_CTRL_FPOUT) -+ state->polarity = PWM_POLARITY_NORMAL; -+ else -+ state->polarity = PWM_POLARITY_INVERSED; -+ -+ val = readl(priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm)); -+ /* -+ * val 32 bits, multiply NSEC_PER_SEC, won't overflow. -+ */ -+ state->period = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); -+ -+ val = readl(priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm)); -+ state->enabled = !!val; -+ /* -+ * val 32 bits, multiply NSEC_PER_SEC, won't overflow. -+ */ -+ state->duty_cycle = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate); -+ -+ pm_runtime_put_sync(chip->dev); -+ -+ return 0; -+} -+ -+static const struct pwm_ops thead_pwm_ops = { -+ .apply = thead_pwm_apply, -+ .get_state = thead_pwm_get_state, -+}; -+ -+static int __maybe_unused thead_pwm_runtime_suspend(struct device *dev) -+{ -+ struct thead_pwm_chip *priv = dev_get_drvdata(dev); -+ -+ clk_disable_unprepare(priv->clk); -+ -+ return 0; -+} -+ -+static int __maybe_unused thead_pwm_runtime_resume(struct device *dev) -+{ -+ struct thead_pwm_chip *priv = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = clk_prepare_enable(priv->clk); -+ if (ret) -+ dev_err(dev, "failed to enable pwm clock(%pe)\n", ERR_PTR(ret)); -+ -+ return ret; -+} -+ -+static int thead_pwm_probe(struct platform_device *pdev) -+{ -+ struct thead_pwm_chip *priv; -+ int ret, i; -+ u32 val; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, priv); -+ -+ priv->mmio_base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(priv->mmio_base)) -+ return PTR_ERR(priv->mmio_base); -+ -+ priv->clk = devm_clk_get_enabled(&pdev->dev, NULL); -+ if (IS_ERR(priv->clk)) -+ return PTR_ERR(priv->clk); -+ -+ priv->chip.ops = &thead_pwm_ops; -+ priv->chip.dev = &pdev->dev; -+ priv->chip.npwm = THEAD_PWM_MAX_NUM; -+ -+ /* check whether PWM is ever started or not */ -+ for (i = 0; i < priv->chip.npwm; i++) { -+ val = readl(priv->mmio_base + THEAD_PWM_FP(i)); -+ if (val) -+ priv->channel_ever_started |= 1 << i; -+ } -+ -+ ret = devm_pwmchip_add(&pdev->dev, &priv->chip); -+ if (ret) -+ return ret; -+ -+ devm_pm_runtime_enable(&pdev->dev); -+ -+ return 0; -+} -+ -+static const struct of_device_id thead_pwm_dt_ids = { -+ {.compatible = "thead,th1520-pwm",}, -+ {/* sentinel */} -+}; -+MODULE_DEVICE_TABLE(of, thead_pwm_dt_ids); -+ -+static const struct dev_pm_ops thead_pwm_pm_ops = { -+ SET_RUNTIME_PM_OPS(thead_pwm_runtime_suspend, thead_pwm_runtime_resume, NULL) -+}; -+ -+static struct platform_driver thead_pwm_driver = { -+ .driver = { -+ .name = "thead-pwm", -+ .of_match_table = thead_pwm_dt_ids, -+ .pm = &thead_pwm_pm_ops, -+ }, -+ .probe = thead_pwm_probe, -+}; -+module_platform_driver(thead_pwm_driver); -+ -+MODULE_AUTHOR("Wei Liu <lw312886@linux.alibaba.com>"); -+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); -+MODULE_DESCRIPTION("T-HEAD pwm driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig -index 965d4f0c18a6..8a2c579c783c 100644 ---- a/drivers/regulator/Kconfig -+++ b/drivers/regulator/Kconfig -@@ -1663,4 +1663,13 @@ config REGULATOR_QCOM_LABIBB - boost regulator and IBB can be used as a negative boost regulator - for LCD display panel. - -+config REGULATOR_LIGHT_AON -+ tristate "Thead Light Aon regulator" -+ depends on LIGHT_AON -+ default y -+ help -+ This driver provides support for the thead light virtal regulators that -+ inmplemented on Light Aon system. -+ -+ - endif -diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile -index 23074714a81a..aa1d8ca59499 100644 ---- a/drivers/regulator/Makefile -+++ b/drivers/regulator/Makefile -@@ -195,5 +195,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_LIGHT_AON) += light-regulator-aon.o - - ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG -diff --git a/drivers/regulator/light-regulator-aon.c b/drivers/regulator/light-regulator-aon.c -new file mode 100644 -index 000000000000..d30cb956145b ---- /dev/null -+++ b/drivers/regulator/light-regulator-aon.c -@@ -0,0 +1,888 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/debugfs.h> -+#include <linux/err.h> -+#include <linux/slab.h> -+#include <linux/interrupt.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/platform_device.h> -+#include <linux/regulator/driver.h> -+#include <linux/regulator/machine.h> -+#include <linux/regulator/of_regulator.h> -+#include <linux/regulator/machine.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/firmware/thead/ipc.h> -+ -+#define MBOX_MAX_MSG_LEN 28 -+ -+#define CONFIG_AON_REG_DEBUG 1 -+ -+struct rpc_msg_regu_vol_set { -+ u16 regu_id; ///< virtual regu id -+ u16 is_dual_rail; ///< whether this regu has dual rails -+ u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail -+ u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false -+ u16 reserved6; -+} __packed __aligned(4); -+ -+struct rpc_msg_regu_vol_get { -+ u16 regu_id; ///< virtual regu id -+ u16 is_dual_rail; ///< whether this regu has dual rails -+ u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail -+ u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false -+ u16 reserved6; -+ -+} __packed __aligned(4); -+ -+struct rpc_msg_regu_pwr_set { -+ u16 regu_id; ///< virtual regu id -+ u16 status; ///< 0: power off; 1: powr on -+ u32 reserved5; -+} __packed __aligned(4); -+ -+struct rpc_msg_regu_pwr_get { -+ u16 regu_id; ///< virtual regu id -+ u16 status; ///< 0: power off; 1: powr on -+ u32 reserved5; -+ -+} __packed __aligned(4); -+ -+struct light_aon_msg_regulator_ctrl { -+ struct light_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(4) rpc; -+} __packed __aligned(4); -+ -+enum pm_resource { -+ SOC_DVDD18_AON, /*da9063: ldo-3 */ -+ SOC_AVDD33_USB3, /*da9063: ldo-9 */ -+ SOC_DVDD08_AON, /*da9063: ldo-2 */ -+ SOC_APCPU_DVDD_DVDDM,/*da9063: vbcore1 & vbcore2*/ -+ SOC_DVDD08_DDR, /*da9063: buckperi */ -+ SOC_VDD_DDR_1V8, /*da9063: ldo-4 */ -+ SOC_VDD_DDR_1V1, /*da9063: buckmem & buckio */ -+ SOC_VDD_DDR_0V6, /*da9063: buckpro */ -+ SOC_DVDD18_AP, /*da9063: ldo-11 */ -+ SOC_DVDD08_AP, /*da9121: da9121_ex */ -+ SOC_AVDD08_MIPI_HDMI,/*da9063: ldo-1 */ -+ SOC_AVDD18_MIPI_HDMI,/*da9063: ldo-5 */ -+ SOC_DVDD33_EMMC, /*da9063: ldo-10 */ -+ SOC_DVDD18_EMMC, /*slg51000:ldo-3 */ -+ SOC_DOVDD18_SCAN, /*da9063: ldo-6 */ -+ SOC_VEXT_2V8, /*da9063: ldo-7 */ -+ SOC_DVDD12_SCAN, /*da9063: ld0-8 */ -+ SOC_AVDD28_SCAN_EN, /*da9063: gpio4 */ -+ SOC_AVDD28_RGB, /*slg51000:ldo-1 */ -+ SOC_DOVDD18_RGB, /*slg51000:ldo-4 */ -+ SOC_DVDD12_RGB, /*slg51000:ldo-5 */ -+ SOC_AVDD25_IR, /*slg51000:ldo-2 */ -+ SOC_DOVDD18_IR, /*slg51000:ldo-7 */ -+ SOC_DVDD12_IR, /*slg51000:ldo-6 */ -+ SOC_ADC_VREF, -+ SOC_LCD0_EN, -+ SOC_VEXT_1V8, -+ -+ -+ SOC_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; ///< discription of regulator -+ u32 regu_num; ///< element number of regulators,which point to regu-dsc-array -+}; -+ -+struct aon_regu_info { -+ struct device *dev; -+ const struct apcpu_vol_set *cpu_vol; ///< signed-off voltage of cpu -+ u32 vddm; ///< cpu-mem voltage -+ struct aon_regu_desc *regu_desc; ///< regu-desc set -+ struct light_aon_ipc *ipc_handle; ///< handle of mail-box -+}; -+ -+static struct aon_regu_info light_aon_pmic_info; -+ -+#define APCPU_VOL_DEF(_vdd, _vddm) \ -+ { \ -+ .vdd = _vdd, \ -+ .vddm = _vddm, \ -+ } -+ -+static const struct apcpu_vol_set apcpu_volts = { -+ /*300Mhz*/ -+ APCPU_VOL_DEF(600000U, 750000U), -+ APCPU_VOL_DEF(600000U, 800000U), -+ APCPU_VOL_DEF(650000U, 800000U), -+ APCPU_VOL_DEF(720000U, 770000U), -+ /*800Mhz*/ -+ APCPU_VOL_DEF(700000U,800000U), -+ APCPU_VOL_DEF(720000U,820000U), -+ /*1500Mhz*/ -+ APCPU_VOL_DEF(800000U,800000U), -+ APCPU_VOL_DEF(820000U,820000U), -+ /*1850Mhz*/ -+ APCPU_VOL_DEF(1000000U,1000000U), -+}; -+ -+/* dc2 is valid when is_dual_rail is true -+ * -+ * dual-rail regulator means that a virtual regulator involes two hw-regulators -+ */ -+static int aon_set_regulator(struct light_aon_ipc *ipc, u16 regu_id, -+ u32 dc1, u32 dc2, u16 is_dual_rail) -+{ -+ struct light_aon_msg_regulator_ctrl msg = {0}; -+ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; -+ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; -+ hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_SET_RESOURCE_REGULATOR; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+ -+ msg.rpc.regu_vol_set.regu_id = regu_id; -+ msg.rpc.regu_vol_set.is_dual_rail = is_dual_rail; -+ msg.rpc.regu_vol_set.dc1 = dc1; -+ msg.rpc.regu_vol_set.dc2 = dc2; -+ -+ return light_aon_call_rpc(ipc, &msg, true); -+} -+ -+/* dc2 is valid when is_dual_rail is true -+ * -+ * dual-rail regulator means that a virtual regulator involes two hw-regulators -+ */ -+static int aon_get_regulator(struct light_aon_ipc *ipc, u16 regu_id, -+ u32 *dc1, u32 *dc2, u16 is_dual_rail) -+{ -+ struct light_aon_msg_regulator_ctrl msg = {0}; -+ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; -+ int ret; -+ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; -+ hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_GET_RESOURCE_REGULATOR; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+ msg.rpc.regu_vol_get.regu_id = regu_id; -+ msg.rpc.regu_vol_get.is_dual_rail = is_dual_rail; -+ -+ ret = light_aon_call_rpc(ipc, &msg, true); -+ if (ret) -+ return ret; -+ -+ if (dc1 != NULL) -+ *dc1 = msg.rpc.regu_vol_get.dc1; -+ -+ if (dc2 != NULL) -+ *dc2 = msg.rpc.regu_vol_get.dc2; -+ -+ return 0; -+} -+ -+static int aon_regu_power_ctrl(struct light_aon_ipc *ipc,u32 regu_id,u16 pwr_on) -+{ -+ struct light_aon_msg_regulator_ctrl msg = {0}; -+ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; -+ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; -+ hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_PWR_SET; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+ -+ msg.rpc.regu_pwr_set.regu_id = regu_id; -+ msg.rpc.regu_pwr_set.status = pwr_on; -+ return light_aon_call_rpc(ipc, &msg, true); -+} -+static int aon_regu_dummy_enable(struct regulator_dev *reg) -+{ -+ return 0; -+} -+static int aon_regu_dummy_disable(struct regulator_dev *reg) -+{ -+ return 0; -+} -+static int aon_regu_dummy_is_enabled(struct regulator_dev *reg) -+{ -+ return 0; -+} -+static int aon_regu_enable(struct regulator_dev *reg) -+{ -+ u16 regu_id =(u16) rdev_get_id(reg); -+ return aon_regu_power_ctrl(light_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(light_aon_pmic_info.ipc_handle, regu_id, 0); -+} -+ -+static int aon_regu_is_enabled(struct regulator_dev *reg) -+{ -+ struct light_aon_msg_regulator_ctrl msg = {0}; -+ struct light_aon_rpc_msg_hdr *hdr = &msg.hdr; -+ int ret; -+ u16 regu_id =(u16) rdev_get_id(reg); -+ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_PM; -+ hdr->func = (uint8_t)LIGHT_AON_PM_FUNC_PWR_GET; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+ -+ msg.rpc.regu_pwr_get.regu_id = regu_id; -+ ret = light_aon_call_rpc(light_aon_pmic_info.ipc_handle, &msg, true); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ return (int) msg.rpc.regu_pwr_get.status; -+} -+ -+static int aon_regu_set_voltage(struct regulator_dev *reg, -+ int minuV, int uV, unsigned *selector) -+{ -+ u16 regu_id =(u16) rdev_get_id(reg); -+ u32 voltage = minuV; /* uV */ -+ int err; -+ -+ pr_debug("%s,%dminuV = %d, uV = %d\n", __func__, __LINE__, minuV, uV); -+ -+ err = aon_set_regulator(light_aon_pmic_info.ipc_handle, regu_id, -+ voltage, 0, 0); -+ if (err) { -+ pr_err("failed to set Voltages to %d!\n", minuV); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+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(light_aon_pmic_info.ipc_handle, regu_id, -+ &voltage, NULL, 0); -+ if (ret) { -+ pr_err("failed to get voltage\n"); -+ return -EINVAL; -+ } -+ -+ pr_debug("%s,%dvoltage = %d\n", __func__, __LINE__, voltage); -+ -+ return voltage; -+} -+ -+static const struct apcpu_vol_set *apcpu_get_matched_signed_off_voltage(u32 vdd, u32 vddm) -+{ -+ int vol_count = ARRAY_SIZE(apcpu_volts); -+ int i; -+ -+ for (i = 0; i < vol_count; i++) -+ if ((vdd == apcpu_voltsi.vdd) && -+ (vddm == apcpu_voltsi.vddm)) -+ return &apcpu_voltsi; -+ -+#ifdef CONFIG_AON_REG_DEBUG -+ return &apcpu_volts2; -+#else -+ return NULL; -+#endif -+} -+ -+static int apcpu_set_vdd_vddm_voltage(struct regulator_dev *reg, -+ int minuV, int uV, unsigned *selector) -+{ -+ struct aon_regu_info *info = rdev_get_drvdata(reg); -+ const struct apcpu_vol_set *cpu_vol; -+ u32 vol = minuV; /* uV */ -+ u32 dc1, dc2; -+ int err; -+ -+ cpu_vol = apcpu_get_matched_signed_off_voltage(vol, light_aon_pmic_info.vddm); -+ if (!cpu_vol) { -+ dev_err(info->dev, "failed to find bcore1/bcore2 matching table\n"); -+#ifndef CONFIG_AON_REG_DEBUG -+ return -EINVAL; -+#endif -+ } -+ -+ dc1 = cpu_vol->vdd; -+ dc2 = cpu_vol->vddm; -+ info->cpu_vol = cpu_vol; -+ info->vddm = cpu_vol->vddm; -+ -+ err = aon_set_regulator(light_aon_pmic_info.ipc_handle, (u16)SOC_APCPU_DVDD_DVDDM, -+ dc1, dc2, 1); -+ if (err) { -+ dev_err(info->dev, "failed to set Voltages to %d!\n", uV); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int apcpu_set_vddm_voltage(struct regulator_dev *reg, -+ int minuV, int uV, unsigned *selector) -+{ -+ struct aon_regu_info *info = rdev_get_drvdata(reg); -+ int bcore_table_count = ARRAY_SIZE(apcpu_volts); -+ u32 vol = minuV; /* uV */ -+ int i; -+ -+ for (i = 0; i < bcore_table_count; i++) -+ if (vol == apcpu_voltsi.vddm) -+ break; -+ -+ if (i >= bcore_table_count) { -+ dev_err(info->dev, "The vol is not existed in matching table\n"); -+#ifndef CONFIG_AON_REG_DEBUG -+ return -EINVAL; -+#endif -+ } -+ -+ /* update the vddm */ -+ info->vddm = vol; -+ return 0; -+} -+ -+static int apcpu_get_voltage(struct regulator_dev *reg, bool is_vdd) -+{ -+ struct aon_regu_info *info = rdev_get_drvdata(reg); -+ const struct apcpu_vol_set *cpu_vol; -+ u32 dc1, dc2; -+ int err; -+ -+ err = aon_get_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, -+ &dc1, &dc2, 1); -+ if (err) { -+ dev_err(info->dev, "failed to get Voltages!\n"); -+ return -EINVAL; -+ } -+ cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); -+ if (!cpu_vol) { -+ dev_err(info->dev, "Voltage %d:%d is not existing in matching table\n", dc1, dc2); -+ return -EINVAL; -+ } -+ -+ info->cpu_vol = cpu_vol; -+ -+ return is_vdd ? cpu_vol->vdd : cpu_vol->vddm; -+} -+ -+static int apcpu_get_vdd_voltage(struct regulator_dev *reg) -+{ -+ return apcpu_get_voltage(reg, true); -+} -+ -+static int apcpu_get_vddm_voltage(struct regulator_dev *reg) -+{ -+ return apcpu_get_voltage(reg, false); -+} -+ -+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, -+}; -+static const struct regulator_ops apcpu_dvdd_ops = { -+ .enable = aon_regu_dummy_enable, -+ .disable = aon_regu_dummy_disable, -+ .is_enabled = aon_regu_dummy_is_enabled, -+ .list_voltage = regulator_list_voltage_linear, -+ .set_voltage = apcpu_set_vdd_vddm_voltage, -+ .get_voltage = apcpu_get_vdd_voltage, -+}; -+ -+static const struct regulator_ops apcpu_dvddm_ops = { -+ .enable = aon_regu_dummy_enable, -+ .disable = aon_regu_dummy_disable, -+ .is_enabled = aon_regu_dummy_is_enabled, -+ .list_voltage = regulator_list_voltage_linear, -+ .set_voltage = apcpu_set_vddm_voltage, -+ .get_voltage = apcpu_get_vddm_voltage, -+}; -+ -+/* Macros for voltage DC/DC converters (BUCKs) for cpu */ -+#define REGU_DSC_DEF(regu_id, of_math_name) \ -+ .id = regu_id, \ -+ .name = #regu_id, \ -+ .of_match = of_match_ptr(__stringify(of_math_name)), \ -+ .ops = ®u_common_ops, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE -+ -+#define BUCK_APCPU_DVDD(regu_id,min_mV, step_mV, max_mV) \ -+ .id = regu_id, \ -+ .name = "APCPU_DVDD", \ -+ .of_match = of_match_ptr("appcpu_dvdd"), \ -+ .ops = &apcpu_dvdd_ops, \ -+ .min_uV = (min_mV), \ -+ .uV_step = (step_mV), \ -+ .n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE -+ -+#define BUCK_APCPU_DVDDM(regu_id, min_mV, step_mV, max_mV) \ -+ .id = regu_id, \ -+ .name = "APCPU_DVDDM", \ -+ .of_match = of_match_ptr("appcpu_dvddm"), \ -+ .ops = &apcpu_dvddm_ops, \ -+ .min_uV = (min_mV) , \ -+ .uV_step = (step_mV), \ -+ .n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \ -+ .type = REGULATOR_VOLTAGE, \ -+ .owner = THIS_MODULE -+ -+/* regulator desc for dialog */ -+static struct regulator_desc light_dialog_ant_regu_desc = { -+ /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ -+ { -+ BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), -+ }, -+ { -+ BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), -+ }, -+ -+ /*common regu ,no need to adjust vol dynamicaly */ -+ { -+ REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DOVDD18_SCAN,soc_dovdd18_scan), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD12_SCAN,soc_dvdd12_scan), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD28_SCAN_EN,soc_avdd28_scan_en), -+ }, -+}; -+ -+static struct regulator_desc light_dialog_regu_desc = { -+ /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ -+ { -+ BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), -+ }, -+ { -+ BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 300000, 10000, 1570000), -+ }, -+ -+ /*common regu ,no need to adjust vol dynamicaly */ -+ { -+ REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DOVDD18_SCAN,soc_dovdd18_scan), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VEXT_2V8,soc_vext_2v8), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD12_SCAN,soc_dvdd12_scan), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD28_SCAN_EN,soc_avdd28_scan_en), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD28_RGB,soc_avdd28_rgb), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DOVDD18_RGB,soc_dovdd18_rgb), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD12_RGB,soc_dvdd12_rgb), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD25_IR,soc_avdd25_ir), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DOVDD18_IR,soc_dovdd18_ir), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD12_IR,soc_dvdd12_ir), -+ }, -+}; -+ -+/* regulator desc for ricoh */ -+static struct regulator_desc light_ricoh_regu_desc = { -+ /*cpu vdd vddm regulators, used to adjust vol dynamicaly */ -+ { -+ BUCK_APCPU_DVDD(SOC_APCPU_DVDD_DVDDM, 600000, 12500, 1500000), -+ }, -+ { -+ BUCK_APCPU_DVDDM(SOC_APCPU_DVDD_DVDDM, 600000, 12500, 1500000), -+ }, -+ -+ /*common regu ,no need to adjust vol dynamicaly */ -+ { -+ REGU_DSC_DEF(SOC_DVDD18_AON,soc_dvdd18_aon), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD33_USB3,soc_avdd33_usb3), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_AON,soc_dvdd08_aon), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_DDR,soc_dvdd08_ddr), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_1V8,soc_vdd_ddr_1v8), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_1V1,soc_vdd_ddr_1v1), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VDD_DDR_0V6,soc_vdd_ddr_0v6), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD18_AP,soc_dvdd18_ap), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD08_AP,soc_dvdd08_ap), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD08_MIPI_HDMI,soc_avdd08_mipi_hdmi), -+ }, -+ { -+ REGU_DSC_DEF(SOC_AVDD18_MIPI_HDMI,soc_avdd18_mipi_hdmi), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD33_EMMC,soc_dvdd33_emmc), -+ }, -+ { -+ REGU_DSC_DEF(SOC_DVDD18_EMMC,soc_dvdd18_emmc), -+ }, -+ { -+ REGU_DSC_DEF(SOC_LCD0_EN,soc_lcd0_en), -+ }, -+ { -+ REGU_DSC_DEF(SOC_VEXT_1V8,soc_vext_1v8), -+ }, -+}; -+ -+#define GEN_REGISTER_SHOW(x, y) \ -+static ssize_t x##_registers_show(struct device *dev, \ -+ struct device_attribute *attr, \ -+ char *buf) \ -+{ \ -+ struct platform_device *pdev = to_platform_device(dev); \ -+ struct aon_regu_info *info = platform_get_drvdata(pdev); \ -+ u32 dc1, dc2; \ -+ ssize_t ret; \ -+ \ -+ ret = aon_get_regulator(light_aon_pmic_info.ipc_handle, y, \ -+ &dc1, &dc2, 0); \ -+ if (ret) { \ -+ dev_err(info->dev, "failed to get Voltages!\n"); \ -+ return -EINVAL; \ -+ } \ -+ \ -+ ret = sprintf(buf, "%u\n", dc1); \ -+ return ret; \ -+} -+ -+#define GEN_REGISTER_STORE(x, y) \ -+static ssize_t x##_register_store(struct device *dev, \ -+ struct device_attribute *attr, \ -+ const char *buf, size_t count) \ -+{ \ -+ struct platform_device *pdev = to_platform_device(dev); \ -+ struct aon_regu_info *info = platform_get_drvdata(pdev); \ -+ unsigned long dc1, dc2 = 0; \ -+ int err; \ -+ \ -+ if (kstrtoul(buf, 0, &dc1)) \ -+ return -EINVAL; \ -+ \ -+ err = aon_set_regulator(light_aon_pmic_info.ipc_handle, y, \ -+ dc1, dc2, 0); \ -+ if (err) { \ -+ dev_err(info->dev, "failed to set Voltages to %lu!\n", dc1); \ -+ return -EINVAL; \ -+ } \ -+ \ -+ return count; \ -+} -+ -+static ssize_t soc_apcpu_dvdd_dvddm_registers_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct aon_regu_info *info = platform_get_drvdata(pdev); -+ size_t bufpos = 0, count = 26; -+ const struct apcpu_vol_set *cpu_vol; -+ u32 dc1, dc2; -+ int i = 0; -+ int err; -+ err = aon_get_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, -+ &dc1, &dc2, 1); -+ if (err) { -+ dev_err(info->dev, "failed to get Voltages!\n"); -+ return -EINVAL; -+ } -+ cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); -+ if (!cpu_vol) -+ dev_err(info->dev, "Read %d:%d is not existing in matching table\n", dc1, dc2); -+ snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i); -+ bufpos += 4; -+ snprintf(buf + bufpos, count - bufpos, "%u", dc1); -+ bufpos += 8; -+ bufbufpos++ = '\n'; -+ i++; -+ snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i); -+ bufpos += 4; -+ snprintf(buf + bufpos, count - bufpos, "%u", dc2); -+ bufpos += 8; -+ bufbufpos++ = '\n'; -+ return bufpos; -+} -+static ssize_t soc_apcpu_dvdd_dvddm_register_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t size) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct aon_regu_info *info = platform_get_drvdata(pdev); -+ const struct apcpu_vol_set *cpu_vol; -+ char *start = (char *)buf; -+ unsigned long dc1, dc2; -+ int err; -+ while (*start == ' ') -+ start++; -+ dc1 = simple_strtoul(start, &start, 0); -+ while (*start == ' ') -+ start++; -+ if (kstrtoul(start, 0, &dc2)) -+ return -EINVAL; -+ cpu_vol = apcpu_get_matched_signed_off_voltage(dc1, dc2); -+ if (!cpu_vol) { -+ dev_err(info->dev, "failed to find bcore1/bcore2 matching table\n"); -+#ifndef CONFIG_AON_REG_DEBUG -+ return -EINVAL; -+#endif -+ } -+ info->cpu_vol = cpu_vol; -+ info->vddm = cpu_vol->vddm; -+ err = aon_set_regulator(light_aon_pmic_info.ipc_handle, SOC_APCPU_DVDD_DVDDM, -+ dc1, dc2, 1); -+ if (err) { -+ dev_err(info->dev, "failed to set Voltages to %lu,%lu!\n", dc1, dc2); -+#ifndef CONFIG_AON_REG_DEBUG -+ return -EINVAL; -+#endif -+ } -+ return size; -+} -+ -+GEN_REGISTER_SHOW(soc_dvdd18_aon, SOC_DVDD18_AON) -+GEN_REGISTER_STORE(soc_dvdd18_aon, SOC_DVDD18_AON) -+GEN_REGISTER_SHOW(soc_dvdd08_ap, SOC_DVDD08_AP) -+GEN_REGISTER_STORE(soc_dvdd08_ap, SOC_DVDD08_AP) -+GEN_REGISTER_SHOW(soc_dvdd18_emmc, SOC_DVDD18_EMMC) -+GEN_REGISTER_STORE(soc_dvdd18_emmc, SOC_DVDD18_EMMC) -+GEN_REGISTER_SHOW(soc_dvdd33_emmc, SOC_DVDD33_EMMC) -+GEN_REGISTER_STORE(soc_dvdd33_emmc, SOC_DVDD33_EMMC) -+ -+static DEVICE_ATTR(soc_dvdd18_aon_regs, 0644, soc_dvdd18_aon_registers_show, soc_dvdd18_aon_register_store); -+static DEVICE_ATTR(soc_dvdd08_ap_regs, 0644, soc_dvdd08_ap_registers_show, soc_dvdd08_ap_register_store); -+static DEVICE_ATTR(soc_dvdd33_emmc_regs, 0644, soc_dvdd33_emmc_registers_show, soc_dvdd33_emmc_register_store); -+static DEVICE_ATTR(soc_dvdd18_emmc_regs, 0644, soc_dvdd18_emmc_registers_show, soc_dvdd18_emmc_register_store); -+static DEVICE_ATTR(soc_apcpu_dvdd_dvddm_regs, 0644, soc_apcpu_dvdd_dvddm_registers_show, soc_apcpu_dvdd_dvddm_register_store); -+ -+static struct attribute *aon_regs_sysfs_entries = { -+ &dev_attr_soc_dvdd18_aon_regs.attr, -+ &dev_attr_soc_dvdd08_ap_regs.attr, -+ &dev_attr_soc_dvdd33_emmc_regs.attr, -+ &dev_attr_soc_dvdd18_emmc_regs.attr, -+ &dev_attr_soc_apcpu_dvdd_dvddm_regs.attr, -+ NULL -+}; -+static const struct attribute_group dev_attr_aon_regs_group = { -+ .attrs = aon_regs_sysfs_entries, -+}; -+ -+ -+static const struct aon_regu_desc light_dialog_regus = { -+ .regu_desc = (struct regulator_desc*) &light_dialog_regu_desc, -+ .regu_num = ARRAY_SIZE(light_dialog_regu_desc), -+}; -+ -+static const struct aon_regu_desc light_dialog_ant_regus = { -+ .regu_desc = (struct regulator_desc*) &light_dialog_ant_regu_desc, -+ .regu_num = ARRAY_SIZE(light_dialog_ant_regu_desc), -+}; -+ -+static const struct aon_regu_desc light_ricoh_regus = { -+ .regu_desc = (struct regulator_desc*)&light_ricoh_regu_desc, -+ .regu_num = ARRAY_SIZE(light_ricoh_regu_desc), -+}; -+ -+static int light_aon_regulator_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct regulator_config config = { }; -+ int i; -+ int ret; -+ struct aon_regu_desc *regus_set = NULL; -+ -+ 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 = light_aon_get_handle(&(light_aon_pmic_info.ipc_handle)); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to get ipc_handle\n"); -+ return ret; -+ } -+ -+ /*init private drv data */ -+ light_aon_pmic_info.dev = &pdev->dev; -+ light_aon_pmic_info.regu_desc = regus_set; -+ light_aon_pmic_info.cpu_vol = &apcpu_volts2; /* pmic default voltages */ -+ light_aon_pmic_info.vddm = light_aon_pmic_info.cpu_vol->vddm; -+ -+ /*register all regulators*/ -+ config.dev = &pdev->dev; -+ config.driver_data = &light_aon_pmic_info; -+ for (i = 0; i < regus_set->regu_num; i++) { -+ struct regulator_dev *rdev; -+ struct regulator_desc *desc; -+ -+ desc = ®us_set->regu_desci; -+ rdev = devm_regulator_register(&pdev->dev, desc, &config); -+ if (IS_ERR(rdev)) { -+ dev_err(&pdev->dev, -+ "Failed to initialize regulator-%d\n", i); -+ return PTR_ERR(rdev); -+ } -+ } -+ -+ i = sysfs_create_group(&config.dev->kobj, &dev_attr_aon_regs_group); -+ if (i) { -+ dev_err(&pdev->dev, "Failed to create aon regs debug sysfs.\n"); -+ return i; -+ } -+ -+ platform_set_drvdata(pdev, &light_aon_pmic_info); -+ -+ return 0; -+} -+ -+static const struct of_device_id light_pmic_dev_id = { -+ { .compatible = "thead,light-dialog-pmic-ant", .data = &light_dialog_ant_regus}, -+ { .compatible = "thead,light-dialog-pmic", .data = &light_dialog_regus}, -+ { .compatible = "thead,light-ricoh-pmic", .data = &light_ricoh_regus}, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, light_pmic_dev_id); -+ -+static struct platform_driver light_aon_regulator_driver = { -+ .driver = { -+ .name = "light-aon-reg", -+ .owner = THIS_MODULE, -+ .of_match_table = light_pmic_dev_id, -+ }, -+ .probe = light_aon_regulator_probe, -+}; -+ -+module_platform_driver(light_aon_regulator_driver); -+ -+MODULE_AUTHOR("fugang.duan <duanfugang.dfg@linux.alibaba.com>"); -+MODULE_AUTHOR("linghui.zlh <linghui.zlh@linux.alibaba.com>"); -+MODULE_DESCRIPTION("Thead Light Aon regulator virtual driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig -index ccd59ddd7610..ec69e6bbba6e 100644 ---- a/drivers/reset/Kconfig -+++ b/drivers/reset/Kconfig -@@ -253,6 +253,16 @@ config RESET_SUNXI - help - This enables the reset driver for Allwinner SoCs. - -+config RESET_TH1520 -+ bool "TH1520 Reset Driver" -+ depends on (ARCH_THEAD || COMPILE_TEST) && OF -+ select MFD_SYSCON -+ default ARCH_THEAD -+ help -+ Support for the T-HEAD 1520 RISC-V SoC reset controller. -+ Say Y if you want to control reset signals provided by this -+ controller. -+ - config RESET_TI_SCI - tristate "TI System Control Interface (TI-SCI) reset driver" - depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) -diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile -index 8270da8a4baa..ca0abdce468d 100644 ---- a/drivers/reset/Makefile -+++ b/drivers/reset/Makefile -@@ -33,6 +33,8 @@ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o - obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o - obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o - obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o -+obj-$(CONFIG_ARCH_SOPHGO) += reset-sophgo.o -+obj-$(CONFIG_RESET_TH1520) += reset-th1520.o - obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o - obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o - obj-$(CONFIG_RESET_TI_TPS380X) += reset-tps380x.o -diff --git a/drivers/reset/reset-sophgo.c b/drivers/reset/reset-sophgo.c -new file mode 100644 -index 000000000000..3c46a43e24ba ---- /dev/null -+++ b/drivers/reset/reset-sophgo.c -@@ -0,0 +1,163 @@ -+/* -+ * Sophgo SoCs Reset Controller driver -+ * -+ * Copyright (c) 2018 Bitmain Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/reset-controller.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/types.h> -+#include <linux/of_device.h> -+#include <linux/mfd/syscon.h> -+#include <linux/regmap.h> -+ -+#define BITS_PER_REG 32 -+ -+struct bm_reset_data { -+ spinlock_t lock; -+ void __iomem *membase; -+ struct reset_controller_dev rcdev; -+ struct regmap *syscon_rst; -+ u32 top_rst_offset; -+}; -+ -+static int bm_reset_assert(struct reset_controller_dev *rcdev, -+ unsigned long id) -+{ -+ struct bm_reset_data *data = container_of(rcdev, -+ struct bm_reset_data, -+ rcdev); -+ int bank = id / BITS_PER_REG; -+ int offset = id % BITS_PER_REG; -+ unsigned long flags; -+ u32 reg; -+ -+ spin_lock_irqsave(&data->lock, flags); -+ -+ regmap_read(data->syscon_rst, data->top_rst_offset + (bank * 4), -+ ®); -+ regmap_write(data->syscon_rst, data->top_rst_offset + (bank * 4), -+ reg & ~BIT(offset)); -+ -+ spin_unlock_irqrestore(&data->lock, flags); -+ -+ return 0; -+} -+ -+static int bm_reset_deassert(struct reset_controller_dev *rcdev, -+ unsigned long id) -+{ -+ struct bm_reset_data *data = container_of(rcdev, -+ struct bm_reset_data, -+ rcdev); -+ int bank = id / BITS_PER_REG; -+ int offset = id % BITS_PER_REG; -+ unsigned long flags; -+ u32 reg; -+ -+ spin_lock_irqsave(&data->lock, flags); -+ -+ regmap_read(data->syscon_rst, data->top_rst_offset + (bank * 4), -+ ®); -+ regmap_write(data->syscon_rst, data->top_rst_offset + (bank * 4), -+ reg | BIT(offset)); -+ -+ spin_unlock_irqrestore(&data->lock, flags); -+ -+ return 0; -+} -+ -+static const struct reset_control_ops bm_reset_ops = { -+ .assert = bm_reset_assert, -+ .deassert = bm_reset_deassert, -+}; -+ -+static const struct of_device_id bm_reset_dt_ids = { -+ { .compatible = "bitmain,reset", }, -+ { /* sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, bm_reset_dt_ids); -+ -+static int bm_reset_probe(struct platform_device *pdev) -+{ -+ struct bm_reset_data *data; -+ int ret = 0; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node, *np_top; -+ static struct regmap *syscon; -+ -+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ np_top = of_parse_phandle(np, "subctrl-syscon", 0); -+ if (!np_top) { -+ dev_err(dev, "%s can't get subctrl-syscon node\n", __func__); -+ goto out_free_devm; -+ } -+ -+ syscon = syscon_node_to_regmap(np_top); -+ if (IS_ERR(syscon)) { -+ dev_err(dev, "cannot get regmap\n"); -+ goto out_free_devm; -+ } -+ -+ data->syscon_rst = syscon; -+ ret = device_property_read_u32(&pdev->dev, "top_rst_offset", -+ &data->top_rst_offset); -+ if (ret < 0) { -+ dev_err(dev, "cannot get top_rst_offset\n"); -+ goto out_free_devm; -+ } -+ -+ ret = device_property_read_u32(&pdev->dev, "nr_resets", -+ &data->rcdev.nr_resets); -+ if (ret < 0) { -+ dev_err(dev, "cannot get nr_resets\n"); -+ goto out_free_devm; -+ } -+ -+ spin_lock_init(&data->lock); -+ -+ data->rcdev.owner = THIS_MODULE; -+ data->rcdev.ops = &bm_reset_ops; -+ data->rcdev.of_node = pdev->dev.of_node; -+ -+ ret = devm_reset_controller_register(&pdev->dev, &data->rcdev); -+ if (!ret) -+ return 0; -+ -+out_free_devm: -+ devm_kfree(&pdev->dev, data); -+ return ret; -+} -+ -+static struct platform_driver bm_reset_driver = { -+ .probe = bm_reset_probe, -+ .driver = { -+ .name = "bm-reset", -+ .of_match_table = bm_reset_dt_ids, -+ }, -+}; -+ -+static int __init bm_reset_init(void) -+{ -+ return platform_driver_register(&bm_reset_driver); -+} -+postcore_initcall(bm_reset_init); -+ -+MODULE_AUTHOR("Wei Huang<wei.huang01@bitmain.com>"); -+MODULE_DESCRIPTION("Bitmain SoC Reset Controoler Driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/reset/reset-th1520.c b/drivers/reset/reset-th1520.c -new file mode 100644 -index 000000000000..5a89d201fc0c ---- /dev/null -+++ b/drivers/reset/reset-th1520.c -@@ -0,0 +1,109 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+ -+#include <linux/mfd/syscon.h> -+#include <linux/of_device.h> -+#include <linux/platform_device.h> -+#include <linux/reset-controller.h> -+#include <linux/regmap.h> -+#include <dt-bindings/reset/thead,th1520-reset.h> -+ -+struct th1520_rst_signal { -+ unsigned int offset, bit; -+}; -+ -+struct th1520_rst { -+ struct reset_controller_dev rcdev; -+ struct regmap *regmap; -+ const struct th1520_rst_signal *signals; -+}; -+ -+enum th1520_rst_registers { -+ RST_WDT0 = 0x0034, -+ RST_WDT1 = 0x0038, -+}; -+ -+static int th1520_reset_update(struct th1520_rst *rst, unsigned long id, -+ unsigned int value) -+{ -+ const struct th1520_rst_signal *signal = &rst->signalsid; -+ -+ return regmap_update_bits(rst->regmap, signal->offset, signal->bit, -+ value); -+} -+ -+static const struct th1520_rst_signal th1520_rst_signals = { -+ TH1520_RESET_WDT0 = { RST_WDT0, BIT(0) }, -+ TH1520_RESET_WDT1 = { RST_WDT1, BIT(0) }, -+}; -+ -+static struct th1520_rst *to_th1520_rst(struct reset_controller_dev *rcdev) -+{ -+ return container_of(rcdev, struct th1520_rst, rcdev); -+} -+ -+static int th1520_reset_set(struct reset_controller_dev *rcdev, -+ unsigned long id, bool assert) -+{ -+ struct th1520_rst *rst = to_th1520_rst(rcdev); -+ const unsigned int bit = rst->signalsid.bit; -+ unsigned int value = assert ? bit : 0; -+ -+ return th1520_reset_update(rst, id, value); -+} -+ -+static int th1520_reset_assert(struct reset_controller_dev *rcdev, -+ unsigned long id) -+{ -+ return th1520_reset_set(rcdev, id, false); -+} -+ -+static int th1520_reset_deassert(struct reset_controller_dev *rcdev, -+ unsigned long id) -+{ -+ return th1520_reset_set(rcdev, id, true); -+} -+ -+static const struct reset_control_ops th1520_rst_ops = { -+ .assert = th1520_reset_assert, -+ .deassert = th1520_reset_deassert, -+}; -+ -+static int th1520_reset_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct th1520_rst *rst; -+ struct regmap_config config = { .name = "rst" }; -+ -+ rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL); -+ if (!rst) -+ return -ENOMEM; -+ -+ rst->signals = th1520_rst_signals; -+ rst->regmap = syscon_node_to_regmap(dev->of_node); -+ if (IS_ERR(rst->regmap)) -+ return PTR_ERR(rst->regmap); -+ -+ regmap_attach_dev(dev, rst->regmap, &config); -+ -+ rst->rcdev.owner = THIS_MODULE; -+ rst->rcdev.dev = dev; -+ rst->rcdev.of_node = dev->of_node; -+ rst->rcdev.ops = &th1520_rst_ops; -+ rst->rcdev.nr_resets = ARRAY_SIZE(th1520_rst_signals); -+ -+ return devm_reset_controller_register(dev, &rst->rcdev); -+} -+ -+static const struct of_device_id th1520_reset_dt_ids = { -+ { .compatible = "thead,th1520-reset" }, -+ { /* sentinel */ }, -+}; -+ -+static struct platform_driver th1520_reset_driver = { -+ .probe = th1520_reset_probe, -+ .driver = { -+ .name = "th1520-reset", -+ .of_match_table = th1520_reset_dt_ids, -+ }, -+}; -+builtin_platform_driver(th1520_reset_driver); -diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig -index d3795860f5c0..34e4d97766c3 100644 ---- a/drivers/rpmsg/Kconfig -+++ b/drivers/rpmsg/Kconfig -@@ -74,6 +74,10 @@ config RPMSG_QCOM_SMD - providing communication channels to remote processors in Qualcomm - platforms. - -+config RPMSG_THEAD_LIGHT -+ tristate "THEAD Light RPM Driver" -+ depends on RPMSG -+ - config RPMSG_VIRTIO - tristate "Virtio RPMSG bus driver" - depends on HAS_DMA -diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile -index 58e3b382e316..35c46c704a7c 100644 ---- a/drivers/rpmsg/Makefile -+++ b/drivers/rpmsg/Makefile -@@ -10,3 +10,4 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o - obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o - obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o - obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o -+obj-$(CONFIG_RPMSG_THEAD_LIGHT) += light_rpmsg.o -diff --git a/drivers/rpmsg/light_rpmsg.c b/drivers/rpmsg/light_rpmsg.c -new file mode 100644 -index 000000000000..cecda6e251a9 ---- /dev/null -+++ b/drivers/rpmsg/light_rpmsg.c -@@ -0,0 +1,864 @@ -+/* -+ * Copyright (C) 2023 Alibaba Group Holding Limited. -+ * -+ * derived from the omap-rpmsg implementation. -+ * -+ * The code contained herein is licensed under the GNU General Public -+ * License. You may obtain a copy of the GNU General Public License -+ * Version 2 or later at the following locations: -+ * -+ * http://www.opensource.org/licenses/gpl-license.html -+ * http://www.gnu.org/copyleft/gpl.html -+ */ -+ -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/module.h> -+#include <linux/notifier.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/of_device.h> -+#include <linux/of_irq.h> -+#include <linux/platform_device.h> -+#include <linux/rpmsg.h> -+#include <linux/slab.h> -+#include <linux/virtio.h> -+#include <linux/virtio_config.h> -+#include <linux/virtio_ids.h> -+#include <linux/virtio_ring.h> -+#include <linux/light_rpmsg.h> -+#include <linux/delay.h> -+#include <linux/regmap.h> -+#include <linux/mfd/syscon.h> -+#include <linux/debugfs.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/mailbox_client.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/workqueue.h> -+#include <linux/light_rpmsg.h> -+ -+#define MBOX_MAX_MSG_LEN 28 -+#define WJ_MBOX_SEND_MAX_MESSAGE_LENGTH 28 -+#define HEXDUMP_BYTES_PER_LINE 28 -+#define HEXDUMP_LINE_LEN ((HEXDUMP_BYTES_PER_LINE * 4) + 2) -+#define HEXDUMP_MAX_LEN (HEXDUMP_LINE_LEN * \ -+ (MBOX_MAX_MSG_LEN / HEXDUMP_BYTES_PER_LINE)) -+ -+//extern struct light_rpmsg_vproc *pri_rpdev; -+static struct dentry *root_debugfs_dir; -+ -+struct mbox_client_light_device { -+ struct device *dev; -+ void __iomem *tx_mmio; -+ void __iomem *rx_mmio; -+ struct mbox_chan *tx_channel; -+ struct mbox_chan *rx_channel; -+ char *rx_buffer; -+ struct regmap *audio_mbox_regmap; -+ char *message; -+ spinlock_t lock; -+}; -+ -+struct mbox_client_light_device *tdev_priv; -+ -+static volatile uint32_t *p_mbox_reg; -+static volatile uint32_t *p_mbox_reg1; -+static volatile uint32_t *p_mbox_reg2; -+ -+/* -+ * For now, allocate 256 buffers of 512 bytes for each side. each buffer -+ * will then have 16B for the msg header and 496B for the payload. -+ * This will require a total space of 256KB for the buffers themselves, and -+ * 3 pages for every vring (the size of the vring depends on the number of -+ * buffers it supports). -+ */ -+#define RPMSG_NUM_BUFS (512) -+//#define RPMSG_BUF_SIZE (512) -+//#define RPMSG_BUFS_SPACE (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE) -+ -+/* -+ * The alignment between the consumer and producer parts of the vring. -+ * Note: this is part of the "wire" protocol. If you change this, you need -+ * to update your BIOS image as well -+ */ -+#define RPMSG_VRING_ALIGN (4096) -+ -+/* With 256 buffers, our vring will occupy 3 pages */ -+#define RPMSG_RING_SIZE ((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \ -+ RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE) -+ -+#define to_light_virdev(vd) container_of(vd, struct light_virdev, vdev) -+#define to_light_rpdev(vd, id) container_of(vd, struct light_rpmsg_vproc, ivdevid) -+ -+struct light_rpmsg_vq_info { -+ __u16 num; /* number of entries in the virtio_ring */ -+ __u16 vq_id; /* a globaly unique index of this virtqueue */ -+ void *addr; /* address where we mapped the virtio ring */ -+ struct light_rpmsg_vproc *rpdev; -+}; -+ -+static u64 light_rpmsg_get_features(struct virtio_device *vdev) -+{ -+ /* VIRTIO_RPMSG_F_NS has been made private */ -+ return 1 << 0; -+} -+ -+static int light_rpmsg_finalize_features(struct virtio_device *vdev) -+{ -+ /* Give virtio_ring a chance to accept features */ -+ vring_transport_features(vdev); -+ return 0; -+} -+ -+/* kick the remote processor, and let it know which virtqueue to poke at */ -+static bool light_rpmsg_notify(struct virtqueue *vq) -+{ -+ unsigned int mu_rpmsg = 0; -+ int ret; -+ struct light_rpmsg_vq_info *rpvq = vq->priv; -+ -+#ifdef CONFIG_PM_SLEEP -+ if(rpvq->rpdev->sleep_flag) { -+ dev_err(tdev_priv->dev, "dev in deep sleep, Channel cannot do Tx+++\n"); -+ return -EINVAL; -+ } -+#endif -+ -+ mu_rpmsg = rpvq->vq_id << 16; -+ mutex_lock(&rpvq->rpdev->lock); -+ -+ //pr_info("light rpmsg: notify %d\n", rpvq->rpdev->first_notify); -+ if (unlikely(rpvq->rpdev->first_notify > 0)) { -+ rpvq->rpdev->first_notify--; -+ if (!tdev_priv->tx_channel) { -+ dev_err(tdev_priv->dev, "Channel cannot do Tx+++\n"); -+ return -EINVAL; -+ } -+ -+ ret = mbox_send_message(tdev_priv->tx_channel, "Hello, Queue!"); -+ } else { -+ *p_mbox_reg1 |= 1 << 0; -+ *p_mbox_reg2 |= 1 << 0; -+ } -+ mutex_unlock(&rpvq->rpdev->lock); -+ -+ return true; -+} -+ -+static int light_mu_rpmsg_callback(struct notifier_block *this, -+ unsigned long index, void *data) -+{ -+ u32 mu_msg = (phys_addr_t) data; -+ struct light_virdev *virdev; -+ -+ virdev = container_of(this, struct light_virdev, nb); -+ -+ pr_debug("light rpmsg: %s notifier_call mu_msg: 0x%x\n", __func__, mu_msg); -+ /* ignore vq indices which are clearly not for us */ -+ mu_msg = mu_msg >> 16; -+ if (mu_msg < virdev->base_vq_id || mu_msg > virdev->base_vq_id + 1) { -+ pr_debug("light rpmsg: mu_msg 0x%x is invalid\n", mu_msg); -+ //return NOTIFY_DONE; -+ } -+ -+ mu_msg -= virdev->base_vq_id; -+ pr_debug("%smu_msg 0x%xbase_vq_id 0x%xvirdev num_of_vqs0x%x\n", __func__, mu_msg, virdev->base_vq_id, virdev->num_of_vqs); -+ -+ /* -+ * Currently both PENDING_MSG and explicit-virtqueue-index -+ * messaging are supported. -+ * Whatever approach is taken, at this point 'mu_msg' contains -+ * the index of the vring which was just triggered. -+ */ -+ //if (mu_msg < virdev->num_of_vqs) -+ vring_interrupt(mu_msg, virdev->vqmu_msg); -+ -+ return NOTIFY_DONE; -+} -+ -+static int light_mu_rpmsg_register_nb(struct light_rpmsg_vproc *rpdev, -+ struct notifier_block *nb) -+{ -+ if ((rpdev == NULL) || (nb == NULL)) -+ return -EINVAL; -+ -+ blocking_notifier_chain_register(&(rpdev->notifier), nb); -+ -+ return 0; -+} -+ -+static int light_mu_rpmsg_unregister_nb(struct light_rpmsg_vproc *rpdev, -+ struct notifier_block *nb) -+{ -+ if ((rpdev == NULL) || (nb == NULL)) -+ return -EINVAL; -+ -+ blocking_notifier_chain_unregister(&(rpdev->notifier), nb); -+ -+ return 0; -+} -+ -+static struct virtqueue *rp_find_vq(struct virtio_device *vdev, -+ unsigned int index, -+ void (*callback)(struct virtqueue *vq), -+ const char *name, -+ bool ctx) -+{ -+ struct light_virdev *virdev = to_light_virdev(vdev); -+ struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev, -+ virdev->base_vq_id / 2); -+ struct light_rpmsg_vq_info *rpvq; -+ struct virtqueue *vq; -+ int err; -+ //static void __iomem *brd_io; -+ -+ rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL); -+ if (!rpvq) -+ return ERR_PTR(-ENOMEM); -+ -+ /* ioremap'ing normal memory, so we cast away sparse's complaints */ -+ //rpvq->addr = (__force void *) ioremap_nocache(virdev->vringindex, -+ // RPMSG_RING_SIZE); -+ rpvq->addr = (__force void *) ioremap(virdev->vringindex, -+ RPMSG_RING_SIZE); -+ if (!rpvq->addr) { -+ err = -ENOMEM; -+ goto free_rpvq; -+ } -+ -+ p_mbox_reg = ioremap(0xffefc48000,25); -+ p_mbox_reg1 = p_mbox_reg + 4; -+ p_mbox_reg2 = p_mbox_reg + 5; -+ -+ memset_io(rpvq->addr, 0, RPMSG_RING_SIZE); -+ -+ pr_debug("vring%d: phys 0x%x, virt 0x%p\n", index, virdev->vringindex, -+ rpvq->addr); -+ -+ vq = vring_new_virtqueue(index, RPMSG_NUM_BUFS / 2, RPMSG_VRING_ALIGN, -+ vdev, true, ctx, -+ rpvq->addr, -+ light_rpmsg_notify, callback, -+ name); -+ if (!vq) { -+ pr_err("light rpmsg: vring_new_virtqueue failed\n"); -+ err = -ENOMEM; -+ goto unmap_vring; -+ } -+ -+ virdev->vqindex = vq; -+ vq->priv = rpvq; -+ /* system-wide unique id for this virtqueue */ -+ rpvq->vq_id = virdev->base_vq_id + index; -+ rpvq->rpdev = rpdev; -+ mutex_init(&rpdev->lock); -+ -+ return vq; -+ -+unmap_vring: -+ /* iounmap normal memory, so make sparse happy */ -+ iounmap((__force void __iomem *) rpvq->addr); -+free_rpvq: -+ kfree(rpvq); -+ return ERR_PTR(err); -+} -+ -+static void light_rpmsg_del_vqs(struct virtio_device *vdev) -+{ -+ struct virtqueue *vq, *n; -+ struct light_virdev *virdev = to_light_virdev(vdev); -+ struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev, -+ virdev->base_vq_id / 2); -+ -+ list_for_each_entry_safe(vq, n, &vdev->vqs, list) { -+ struct light_rpmsg_vq_info *rpvq = vq->priv; -+ -+ iounmap(rpvq->addr); -+ vring_del_virtqueue(vq); -+ kfree(rpvq); -+ } -+ -+ if (&virdev->nb) -+ light_mu_rpmsg_unregister_nb(rpdev, &virdev->nb); -+} -+ -+static int light_rpmsg_find_vqs(struct virtio_device *vdev, unsigned int nvqs, -+ struct virtqueue *vqs, -+ vq_callback_t *callbacks, -+ const char * const names, -+ const bool *ctx, -+ struct irq_affinity *desc) -+{ -+ struct light_virdev *virdev = to_light_virdev(vdev); -+ struct light_rpmsg_vproc *rpdev = to_light_rpdev(virdev, -+ virdev->base_vq_id / 2); -+ int i, err; -+ -+ /* we maintain two virtqueues per remote processor (for RX and TX) */ -+ if (nvqs != 2) -+ return -EINVAL; -+ -+ for (i = 0; i < nvqs; ++i) { -+ vqsi = rp_find_vq(vdev, i, callbacksi, namesi, -+ ctx ? ctxi : false); -+ if (IS_ERR(vqsi)) { -+ err = PTR_ERR(vqsi); -+ goto error; -+ } -+ } -+ -+ virdev->num_of_vqs = nvqs; -+ -+ virdev->nb.notifier_call = light_mu_rpmsg_callback; -+ light_mu_rpmsg_register_nb(rpdev, &virdev->nb); -+ -+ return 0; -+ -+error: -+ light_rpmsg_del_vqs(vdev); -+ return err; -+} -+ -+static void light_rpmsg_reset(struct virtio_device *vdev) -+{ -+ dev_dbg(&vdev->dev, "reset!\n"); -+} -+ -+static u8 light_rpmsg_get_status(struct virtio_device *vdev) -+{ -+ return 0; -+} -+ -+static void light_rpmsg_set_status(struct virtio_device *vdev, u8 status) -+{ -+ dev_dbg(&vdev->dev, "%s new status: %d\n", __func__, status); -+} -+ -+static void light_rpmsg_vproc_release(struct device *dev) -+{ -+ /* this handler is provided so driver core doesn't yell at us */ -+} -+ -+static struct virtio_config_ops light_rpmsg_config_ops = { -+ .get_features = light_rpmsg_get_features, -+ .finalize_features = light_rpmsg_finalize_features, -+ .find_vqs = light_rpmsg_find_vqs, -+ .del_vqs = light_rpmsg_del_vqs, -+ .reset = light_rpmsg_reset, -+ .set_status = light_rpmsg_set_status, -+ .get_status = light_rpmsg_get_status, -+}; -+ -+static struct light_rpmsg_vproc light_rpmsg_vprocs = { -+ { -+ .rproc_name = "m4", -+ }, -+ { -+ .rproc_name = "m4", -+ }, -+}; -+ -+static const struct of_device_id light_rpmsg_dt_ids = { -+ { .compatible = "light,light-rpmsg", .data = (void *)LIGHT_RPMSG, }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, light_rpmsg_dt_ids); -+ -+static int set_vring_phy_buf(struct platform_device *pdev, -+ struct light_rpmsg_vproc *rpdev, int vdev_nums) -+{ -+ struct resource *res; -+ resource_size_t size; -+ unsigned int start, end; -+ int i, ret = 0; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (res) { -+ size = resource_size(res); -+ start = res->start; -+ end = res->start + size; -+ for (i = 0; i < vdev_nums; i++) { -+ rpdev->ivdevi.vring0 = start; -+ rpdev->ivdevi.vring1 = start + -+ 0x8000; -+ start += 0x10000; -+ if (start > end) { -+ pr_err("Too small memory size %x!\n", -+ (u32)size); -+ ret = -EINVAL; -+ break; -+ } -+ } -+ } else { -+ return -ENOMEM; -+ } -+ -+ return ret; -+} -+ -+static void rpmsg_work_handler(struct work_struct *work) -+{ -+ u32 message = 0; -+ struct delayed_work *dwork = to_delayed_work(work); -+ struct light_rpmsg_vproc *rpdev = container_of(dwork, -+ struct light_rpmsg_vproc, rpmsg_work); -+ -+ //spin_lock_irqsave(&rpdev->mu_lock, flags); -+ blocking_notifier_call_chain(&(rpdev->notifier), 4, -+ (void *)(phys_addr_t)message); -+ //spin_unlock_irqrestore(&rpdev->mu_lock, flags); -+} -+ -+struct light_rpmsg_vproc *pri_rpdev; -+EXPORT_SYMBOL_GPL(pri_rpdev); -+ -+static int light_rpmsg_probe(struct platform_device *pdev) -+{ -+ int core_id, j, ret = 0; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = pdev->dev.of_node; -+ struct light_rpmsg_vproc *rpdev; -+ -+ if (of_property_read_u32(np, "multi-core-id", &core_id)) -+ core_id = 0; -+ rpdev = &light_rpmsg_vprocscore_id; -+ rpdev->core_id = core_id; -+ rpdev->variant = (enum light_rpmsg_variants)of_device_get_match_data(dev); -+ -+ spin_lock_init(&rpdev->mu_lock); -+ -+ pri_rpdev = rpdev; -+ -+ INIT_DELAYED_WORK(&(rpdev->rpmsg_work), rpmsg_work_handler); -+ BLOCKING_INIT_NOTIFIER_HEAD(&(rpdev->notifier)); -+#ifdef CONFIG_PM_SLEEP -+ sema_init(&rpdev->pm_sem, 0); -+#endif -+ pr_info("light rpmsg: Ready for cross core communication!\n"); -+ -+ ret = of_property_read_u32(np, "vdev-nums", &rpdev->vdev_nums); -+ if (ret) { -+ rpdev->vdev_nums = 1; -+ } -+ -+ if (rpdev->vdev_nums > MAX_VDEV_NUMS) { -+ pr_err("light rpmsg: vdev-nums exceed the max %d\n", MAX_VDEV_NUMS); -+ return -EINVAL; -+ } -+ -+ rpdev->first_notify = rpdev->vdev_nums; -+ -+ pr_info("light rpmsg: rproc_name = %s",rpdev->rproc_name); -+ if (!strcmp(rpdev->rproc_name, "m4")) { -+ ret = set_vring_phy_buf(pdev, rpdev, -+ rpdev->vdev_nums); -+ if (ret) { -+ pr_err("light rpmsg: No vring buffer.\n"); -+ return -ENOMEM; -+ } -+ } else { -+ pr_err("light rpmsg: No remote processor.\n"); -+ return -ENODEV; -+ } -+ -+ for (j = 0; j < rpdev->vdev_nums; j++) { -+ pr_debug("%s rpdev%d vdev%d: vring0 0x%x, vring1 0x%x\n", -+ __func__, rpdev->core_id, rpdev->vdev_nums, -+ rpdev->ivdevj.vring0, -+ rpdev->ivdevj.vring1); -+ rpdev->ivdevj.vdev.id.device = VIRTIO_ID_RPMSG; -+ rpdev->ivdevj.vdev.config = &light_rpmsg_config_ops; -+ rpdev->ivdevj.vdev.dev.parent = &pdev->dev; -+ rpdev->ivdevj.vdev.dev.release = light_rpmsg_vproc_release; -+ rpdev->ivdevj.base_vq_id = j * 2; -+ -+ ret = register_virtio_device(&rpdev->ivdevj.vdev); -+ if (ret) { -+ pr_err("light rpmsg: %s failed to register rpdev: %d\n", __func__, ret); -+ return ret; -+ } -+ -+ } -+ platform_set_drvdata(pdev, rpdev); -+ -+ return ret; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+ -+typedef enum { -+ RPMSG_MAILBOX_TYPE_PM = 0xA0, -+ RPMSG_MAILBOX_TYPE_MAX -+} rpmsg_mailbox_message_type_en; -+ -+typedef enum { -+ RPMSG_PM_CTRL = 0x50, -+ RPMSG_PM_GET, -+ RPMSG_PM_STATUS, -+ RPMSG_PM_MAX -+} rpmsg_pm_message_type_en; -+ -+typedef enum { -+ LIGHT_PM_DISABLE = 0xA0, -+ LIGHT_PM_OFF, -+ LIGHT_PM_HW_VAD, -+ LIGHT_PM_TYPE_MAX -+} light_pm_type_en; -+ -+typedef enum { -+ LIGHT_PM_WAKEUP = 0x50, -+ LIGHT_PM_SLEEP, -+ LIGHT_PM_STATUS_MAX -+} light_pm_status_en; -+ -+#define MAX_PM_NOTIFY_TIME 10 -+#define MAX_PM_ASK_TIME 10 -+ -+static int light_rpmsg_sleep_notify(struct virtqueue *vq, light_pm_type_en type) -+{ -+ int ret; -+ struct light_rpmsg_vq_info *rpvq = vq->priv; -+ uint8_t sleep_ctrl4 = {RPMSG_MAILBOX_TYPE_PM, RPMSG_PM_CTRL, type, '\n'}; -+ mutex_lock(&rpvq->rpdev->lock); -+ ret = mbox_send_message(tdev_priv->tx_channel, sleep_ctrl); -+ if(ret < 0) { -+ pr_err("sleep notify faild %d", ret); -+ mutex_unlock(&rpvq->rpdev->lock); -+ return ret; -+ } -+ mutex_unlock(&rpvq->rpdev->lock); -+ return 0; -+} -+ -+static int light_rpmsg_sleep_ask(struct virtqueue *vq) -+{ -+ int ret; -+ struct light_rpmsg_vq_info *rpvq = vq->priv; -+ uint8_t sleep_get3 = {RPMSG_MAILBOX_TYPE_PM, RPMSG_PM_GET, '\n'}; -+ mutex_lock(&rpvq->rpdev->lock); -+ ret = mbox_send_message(tdev_priv->tx_channel, sleep_get); -+ if(ret < 0) { -+ pr_err("sleep ask send faild %d", ret); -+ mutex_unlock(&rpvq->rpdev->lock); -+ return ret; -+ } -+ mutex_unlock(&rpvq->rpdev->lock); -+ return 0; -+} -+ -+static int light_rpmsg_suspend(struct device *dev) -+ -+{ -+ int ret; -+ int try_num = 0; -+ struct light_rpmsg_vproc *rpdev = dev_get_drvdata(dev); -+ -+ //clk_disable_unprepare(rpdev->mu_clk); -+ printk("%s,%d,enter",__func__,__LINE__); -+ light_rpmsg_sleep_notify(rpdev->ivdev0.vq0, LIGHT_PM_OFF); -+ try_num++; -+ down_timeout(&rpdev->pm_sem, msecs_to_jiffies(200)); -+ while(!rpdev->sleep_flag) { -+ light_rpmsg_sleep_notify(rpdev->ivdev0.vq0, LIGHT_PM_OFF); -+ down_timeout(&rpdev->pm_sem, msecs_to_jiffies(200)); -+ if(try_num++ > MAX_PM_NOTIFY_TIME) { -+ pr_err("sleep notify faild after try %d time", MAX_PM_NOTIFY_TIME); -+ printk("%s,%d,try %d times, exist",__func__,__LINE__, try_num); -+ return -1; -+ } -+ } -+ printk("%s,%d,try %d times, exist",__func__,__LINE__, try_num); -+ return 0; -+} -+ -+static int light_rpmsg_resume(struct device *dev) -+{ -+ struct light_rpmsg_vproc *rpdev = dev_get_drvdata(dev); -+ int ret; -+ int try_num = 0; -+ printk("%s,%d,enter",__func__,__LINE__); -+ while(rpdev->sleep_flag) { -+ ret = light_rpmsg_sleep_ask(rpdev->ivdev0.vq0); -+ down_timeout(&rpdev->pm_sem, msecs_to_jiffies(200)); -+ if(try_num++ > MAX_PM_ASK_TIME) { -+ pr_err("sleep status check faild after try %d time", MAX_PM_ASK_TIME); -+ printk("%s,%d,try %d times, exist",__func__,__LINE__, try_num); -+ return -1; -+ } -+ } -+ printk("%s,%d,try %d times, exist",__func__,__LINE__, try_num); -+ return ret; -+} -+ -+#endif -+ -+static SIMPLE_DEV_PM_OPS(light_rpmsg_pm_ops, light_rpmsg_suspend, light_rpmsg_resume); -+ -+static struct platform_driver light_rpmsg_driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "light-rpmsg", -+ .of_match_table = light_rpmsg_dt_ids, -+ .pm = &light_rpmsg_pm_ops, -+ }, -+ .probe = light_rpmsg_probe, -+}; -+ -+static int __init light_rpmsg_init(void) -+{ -+ int ret; -+ -+ ret = platform_driver_register(&light_rpmsg_driver); -+ if (ret) -+ pr_err("light rpmsg: Unable to initialize\n"); -+ else -+ pr_info("light rpmsg: driver is registered.\n"); -+ -+ return ret; -+} -+ -+late_initcall(light_rpmsg_init); -+ -+static ssize_t mbox_client_light_message_write(struct file *filp, -+ const char __user *userbuf, -+ size_t count, loff_t *ppos) -+{ -+ struct mbox_client_light_device *tdev = filp->private_data; -+ void *data; -+ int ret; -+ -+ if (!tdev->tx_channel) { -+ dev_err(tdev->dev, "Channel cannot do Tx\n"); -+ return -EINVAL; -+ } -+ -+ if (count > WJ_MBOX_SEND_MAX_MESSAGE_LENGTH) -+ count = WJ_MBOX_SEND_MAX_MESSAGE_LENGTH; -+ -+ tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL); -+ if (!tdev->message) -+ return -ENOMEM; -+ -+ ret = copy_from_user(tdev->message, userbuf, count); -+ if (ret) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ data = tdev->message; -+ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->message, MBOX_MAX_MSG_LEN, true); -+ -+ ret = mbox_send_message(tdev->tx_channel, data); -+ if (ret < 0) -+ dev_err(tdev->dev, "Failed to send message via mailbox\n"); -+ -+out: -+ kfree(tdev->message); -+ return ret < 0 ? ret : count; -+} -+ -+static ssize_t mbox_client_light_message_read(struct file *filp, -+ char __user *userbuf, -+ size_t count, loff_t *ppos) -+{ -+ struct mbox_client_light_device *tdev = filp->private_data; -+ unsigned long flags; -+ -+ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); -+ spin_lock_irqsave(&tdev->lock, flags); -+ memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN); -+ spin_unlock_irqrestore(&tdev->lock, flags); -+ -+ return MBOX_MAX_MSG_LEN; -+} -+ -+static const struct file_operations mbox_client_light_message_ops = { -+ .write = mbox_client_light_message_write, -+ .read = mbox_client_light_message_read, -+ .open = simple_open, -+ .llseek = generic_file_llseek, -+}; -+ -+static int index_names = 0; -+static bool debugfs_dir_created = false; -+static const char* file_names = {"mbox-client0", "mbox-client1"}; -+ -+static int mbox_client_light_add_debugfs(struct platform_device *pdev, -+ struct mbox_client_light_device *tdev) -+{ -+ if (!debugfs_initialized()) -+ return 0; -+ -+ if (index_names > 2) { -+ dev_err(&pdev->dev, "Max device index is 2\n"); -+ return 0; -+ } -+ -+ if (!debugfs_dir_created) { -+ root_debugfs_dir = debugfs_create_dir("mailbox",NULL); -+ if (!root_debugfs_dir) { -+ dev_err(&pdev->dev, -+ "Failed to create mailbox debugfs\n"); -+ return -EINVAL; -+ } -+ debugfs_dir_created = true; -+ } -+ -+ debugfs_create_file(file_namesindex_names, 0600, root_debugfs_dir, -+ tdev, &mbox_client_light_message_ops); -+ -+ index_names++; -+ return 0; -+} -+ -+static void mbox_client_light_receive_message(struct mbox_client *client, -+ void *message) -+{ -+ struct mbox_client_light_device *tdev = dev_get_drvdata(client->dev); -+ char *data = message; -+ -+ spin_lock(&tdev->lock); -+ memcpy(tdev->rx_buffer, data, MBOX_MAX_MSG_LEN); -+ spin_unlock(&tdev->lock); -+ -+ //printk("mbox_client receive rpmsg_work\n"); -+ schedule_delayed_work(&(pri_rpdev->rpmsg_work), 0); -+#ifdef CONFIG_PM_SLEEP -+ if(data0 == RPMSG_MAILBOX_TYPE_PM && data1 == RPMSG_PM_STATUS) { -+ if(data2 == LIGHT_PM_WAKEUP) { -+ pri_rpdev->sleep_flag = 0; -+ up(&pri_rpdev->pm_sem); -+ printk("audio wakeup"); -+ } else if(data2 == LIGHT_PM_SLEEP) { -+ pri_rpdev->sleep_flag = 1; -+ up(&pri_rpdev->pm_sem); -+ printk("audio sleep"); -+ } -+ } -+#endif -+ //print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true); -+} -+ -+static struct mbox_chan * -+mbox_client_light_request_channel(struct platform_device *pdev, -+ const char *name) -+{ -+ struct mbox_client *client; -+ struct mbox_chan *channel; -+ -+ client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); -+ if (!client) -+ return ERR_PTR(-ENOMEM); -+ -+ client->dev = &pdev->dev; -+ client->tx_block = true; -+ client->knows_txdone = false; -+ client->tx_tout = 500; -+ client->rx_callback = mbox_client_light_receive_message; -+ -+ channel = mbox_request_channel_byname(client, name); -+ if (IS_ERR(channel)) { -+ devm_kfree(&pdev->dev, client); -+ dev_warn(&pdev->dev, "Failed to request %s channel\n", name); -+ return NULL; -+ } -+ -+ return channel; -+} -+ -+static int mbox_client_light_probe(struct platform_device *pdev) -+{ -+ struct mbox_client_light_device *tdev; -+ struct device_node *np = pdev->dev.of_node; -+ int ret; -+ -+ static int chan_idx = 1; -+ -+ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); -+ if (!tdev) -+ return -ENOMEM; -+ -+ tdev_priv = tdev; -+ -+ if (!chan_idx) -+ tdev->tx_channel = mbox_client_light_request_channel(pdev, "902"); -+ else -+ tdev->tx_channel = mbox_client_light_request_channel(pdev, "906"); -+ -+ if (!tdev->tx_channel) { -+ dev_err(&pdev->dev, "Request channel failed\n"); -+ return -EPROBE_DEFER; -+ } -+ chan_idx++; -+ -+ /* In fact, rx_channel is same with tx_channel in C-SKY's mailbox */ -+ tdev->rx_channel = tdev->tx_channel; -+ -+ tdev->dev = &pdev->dev; -+ platform_set_drvdata(pdev, tdev); -+ -+ tdev->audio_mbox_regmap = syscon_regmap_lookup_by_phandle(np, "audio-mbox-regmap"); -+ if (IS_ERR(tdev->audio_mbox_regmap)) { -+ dev_err(&pdev->dev, "cannot find regmap for audio mbox register\n"); -+ } else { -+ dev_dbg(&pdev->dev, "audio_mbox_regmap ok\n"); -+ } -+ -+ spin_lock_init(&tdev->lock); -+ -+ tdev->rx_buffer = devm_kzalloc(&pdev->dev, -+ MBOX_MAX_MSG_LEN, GFP_KERNEL); -+ if (!tdev->rx_buffer) -+ return -ENOMEM; -+ -+ ret = mbox_client_light_add_debugfs(pdev, tdev); -+ if (ret) -+ return ret; -+ -+ dev_err(&pdev->dev, "Successfully registered\n"); -+ -+ return 0; -+} -+ -+static int mbox_client_light_remove(struct platform_device *pdev) -+{ -+ struct mbox_client_light_device *tdev = platform_get_drvdata(pdev); -+ -+ debugfs_remove_recursive(root_debugfs_dir); -+ -+ if (tdev->tx_channel) -+ mbox_free_channel(tdev->tx_channel); -+ -+ if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel) -+ mbox_free_channel(tdev->rx_channel); -+ -+ return 0; -+} -+ -+static const struct of_device_id mbox_client_light_match = { -+ { .compatible = "thead,light-mbox-client" }, -+ {}, -+}; -+ -+static struct platform_driver mbox_client_light_driver = { -+ .driver = { -+ .name = "thead,light-mbox-client", -+ .of_match_table = mbox_client_light_match, -+ }, -+ .probe = mbox_client_light_probe, -+ .remove = mbox_client_light_remove, -+}; -+module_platform_driver(mbox_client_light_driver); -+ -+MODULE_AUTHOR("Alibaba Group Holding Limited"); -+MODULE_DESCRIPTION("Thead Light mailbox IPC client driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig -index d21e75d69294..6ce6f6300055 100644 ---- a/drivers/soc/Kconfig -+++ b/drivers/soc/Kconfig -@@ -31,5 +31,6 @@ source "drivers/soc/ti/Kconfig" - source "drivers/soc/ux500/Kconfig" - source "drivers/soc/versatile/Kconfig" - source "drivers/soc/xilinx/Kconfig" -+source "drivers/soc/thead/Kconfig" - - endmenu -diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile -index 0706a27d13be..f34415578e9e 100644 ---- a/drivers/soc/Makefile -+++ b/drivers/soc/Makefile -@@ -30,8 +30,10 @@ obj-y += rockchip/ - obj-$(CONFIG_SOC_SAMSUNG) += samsung/ - obj-y += sifive/ - obj-y += sunxi/ -+obj-$(CONFIG_ARCH_SOPHGO) += sophgo/ - obj-$(CONFIG_ARCH_TEGRA) += tegra/ - obj-y += ti/ - obj-$(CONFIG_ARCH_U8500) += ux500/ - obj-$(CONFIG_PLAT_VERSATILE) += versatile/ - obj-y += xilinx/ -+obj-y += thead/ -diff --git a/drivers/soc/sophgo/Makefile b/drivers/soc/sophgo/Makefile -new file mode 100644 -index 000000000000..1e143d85aa17 ---- /dev/null -+++ b/drivers/soc/sophgo/Makefile -@@ -0,0 +1,3 @@ -+obj-$(CONFIG_ARCH_SOPHGO) += top/top_intc.o -+obj-$(CONFIG_ARCH_SOPHGO) += umcu/mcu.o -+obj-$(CONFIG_ARCH_SOPHGO) += tach/sophgo-tach.o -diff --git a/drivers/soc/sophgo/tach/sophgo-tach.c b/drivers/soc/sophgo/tach/sophgo-tach.c -new file mode 100644 -index 000000000000..77884d80eace ---- /dev/null -+++ b/drivers/soc/sophgo/tach/sophgo-tach.c -@@ -0,0 +1,330 @@ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/workqueue.h> -+#include <linux/delay.h> -+#include <linux/of.h> -+#include <linux/netlink.h> -+#include <net/sock.h> -+ -+#define DEV_NAME "sophgo-tach" -+#define MHZ 1000000 -+#define USER_PORT 100 -+#define USER_MSG 30 -+ -+struct fan_state { -+ unsigned int freq_num; -+ bool enable; -+}; -+ -+struct sophgo_fan_speed_device { -+ struct device *dev; -+ struct device *parent; -+ struct class *class; -+ dev_t devno; -+ u32 __iomem *regs; -+ struct delayed_work poll_queue; -+ struct fan_state fan_state; -+ struct mutex enable_lock; -+ struct mutex freqnum_lock; -+}; -+ -+static int fan_index; -+static struct class *sophgo_fan_speed_class; -+static struct sock *nl_fd; -+ -+static int send_msg(char *pbuf, uint16_t len) -+{ -+ struct sk_buff *nl_skb; -+ struct nlmsghdr *nlh; -+ int ret = 0; -+ -+ //alloc a new netlink message -+ nl_skb = nlmsg_new(len, GFP_ATOMIC); -+ if (!nl_skb) { -+ pr_err("sophgo_fan_speed, netlink alloc skb error!\n"); -+ return -ENOMEM; -+ } -+ -+ //add a new netlink message to skb -+ nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0); -+ if (nlh == NULL) { -+ pr_err("sophgo_fan_speed, nlmsg_put error!\n"); -+ nlmsg_free(nl_skb); -+ return -EFAULT; -+ } -+ -+ memcpy(nlmsg_data(nlh), pbuf, len); -+ ret = netlink_unicast(nl_fd, nl_skb, USER_PORT, MSG_DONTWAIT); -+ -+ return ret; -+} -+ -+static void recv_cb(struct sk_buff *skb) -+{ -+ struct nlmsghdr *nlh = NULL; -+ void *data = NULL; -+ -+ if (skb->len >= nlmsg_total_size(0)) { -+ nlh = nlmsg_hdr(skb); -+ data = nlmsg_data(nlh); -+ if (data) { -+ pr_info("sophgo_fan_speed, kernel receive data: %s\n", (int8_t *)data); -+ send_msg(data, nlmsg_len(nlh)); -+ } -+ } -+} -+ -+struct netlink_kernel_cfg cfg = { -+ .input = recv_cb, -+}; -+ -+static void fan_speed_check(struct work_struct *work) -+{ -+ struct sophgo_fan_speed_device *sophgo_fan = container_of(work, -+ struct sophgo_fan_speed_device, poll_queue.work); -+ int speed, ret = 0; -+ char buf64; -+ -+ speed = readl(sophgo_fan->regs + 1); -+ if (speed == 0) { -+ dev_dbg(sophgo_fan->dev, "fan stop!"); -+ ret = snprintf(buf, 32, "%s fan stop!\n", dev_name(sophgo_fan->dev)); -+ if (ret <= 0 || ret > 32) { -+ dev_err(sophgo_fan->dev, "%s snprintf failed\n", __func__); -+ return; -+ } -+ ret = send_msg(buf, sizeof(buf)); -+ if (ret < 0) -+ dev_dbg(sophgo_fan->dev, "%s send msg failed, ret=%d\n", __func__, ret); -+ } -+ mod_delayed_work(system_freezable_wq, &sophgo_fan->poll_queue, -+ round_jiffies(msecs_to_jiffies(5000))); -+} -+ -+static void fan_speed_enable(bool enalbe, struct sophgo_fan_speed_device *sophgo_fan) -+{ -+ if (enalbe) { -+ cancel_delayed_work(&sophgo_fan->poll_queue); -+ writel(sophgo_fan->fan_state.freq_num, sophgo_fan->regs); -+ mod_delayed_work(system_freezable_wq, &sophgo_fan->poll_queue, -+ round_jiffies(msecs_to_jiffies(5000))); -+ sophgo_fan->fan_state.enable = true; -+ } else { -+ cancel_delayed_work(&sophgo_fan->poll_queue); -+ writel(0, sophgo_fan->regs); -+ sophgo_fan->fan_state.enable = false; -+ } -+} -+ -+static ssize_t freq_num_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct sophgo_fan_speed_device *sophgo_fan; -+ -+ sophgo_fan = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%d\n", sophgo_fan->fan_state.freq_num); -+} -+ -+static ssize_t freq_num_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t size) -+{ -+ int val, ret = 0; -+ struct sophgo_fan_speed_device *sophgo_fan; -+ -+ sophgo_fan = dev_get_drvdata(dev); -+ -+ ret = kstrtoint(buf, 0, &val); -+ if (ret) -+ return ret; -+ -+ if (val < (MHZ/10) || val > (1000*MHZ)) -+ ret = -EINVAL; -+ -+ mutex_lock(&sophgo_fan->freqnum_lock); -+ sophgo_fan->fan_state.freq_num = val; -+ mutex_unlock(&sophgo_fan->freqnum_lock); -+ -+ return ret ? : size; -+} -+ -+static ssize_t enable_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct sophgo_fan_speed_device *sophgo_fan; -+ -+ sophgo_fan = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%d\n", sophgo_fan->fan_state.enable); -+} -+ -+static ssize_t enable_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t size) -+{ -+ int val, ret = 0; -+ struct sophgo_fan_speed_device *sophgo_fan; -+ -+ sophgo_fan = dev_get_drvdata(dev); -+ -+ ret = kstrtoint(buf, 0, &val); -+ if (ret) -+ return ret; -+ -+ mutex_lock(&sophgo_fan->enable_lock); -+ switch (val) { -+ case 0: -+ fan_speed_enable(false, sophgo_fan); -+ break; -+ case 1: -+ fan_speed_enable(true, sophgo_fan); -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ mutex_unlock(&sophgo_fan->enable_lock); -+ -+ return ret ? : size; -+} -+ -+static ssize_t fan_speed_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ int ret = -1; -+ struct sophgo_fan_speed_device *sophgo_fan; -+ -+ sophgo_fan = dev_get_drvdata(dev); -+ ret = snprintf(buf, 32, "fan_speed:%d\n", readl(sophgo_fan->regs + 1)); -+ if (ret <= 0 || ret > 32) { -+ dev_err(sophgo_fan->dev, "%s snprintf failed %d\n", __func__, ret); -+ return -EFAULT; -+ } -+ dev_dbg(sophgo_fan->dev, "%s\n", buf); -+ return ret; -+} -+ -+static DEVICE_ATTR_RW(enable); -+static DEVICE_ATTR_RW(freq_num); -+static DEVICE_ATTR_RO(fan_speed); -+ -+static struct attribute *fan_speed_attrs = { -+ &dev_attr_enable.attr, -+ &dev_attr_freq_num.attr, -+ &dev_attr_fan_speed.attr, -+ NULL, -+}; -+ATTRIBUTE_GROUPS(fan_speed); -+ -+static int sophgo_fan_speed_probe(struct platform_device *pdev) -+{ -+ struct resource *res; -+ struct sophgo_fan_speed_device *sophgo_fan; -+ char dev_name32; -+ int ret; -+ -+ sophgo_fan = devm_kzalloc(&pdev->dev, sizeof(*sophgo_fan), GFP_KERNEL); -+ if (sophgo_fan == NULL) -+ return -ENOMEM; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ sophgo_fan->regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(sophgo_fan->regs)) -+ return PTR_ERR(sophgo_fan->regs); -+ -+ ret = snprintf(dev_name, 15, "%s-%d", DEV_NAME, fan_index++); -+ if (ret <= 0 || ret > 15) { -+ dev_err(&pdev->dev, "%s snprintf failed\n", __func__); -+ return -EINVAL; -+ } -+ ret = alloc_chrdev_region(&sophgo_fan->devno, 0, 1, dev_name); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "register chrdev error\n"); -+ return ret; -+ } -+ sophgo_fan->class = sophgo_fan_speed_class; -+ sophgo_fan->dev = device_create(sophgo_fan->class, sophgo_fan->parent, -+ sophgo_fan->devno, sophgo_fan, dev_name); -+ if (IS_ERR(sophgo_fan->dev)) { -+ ret = PTR_ERR(sophgo_fan->dev); -+ dev_err(&pdev->dev, "create device failed\n"); -+ unregister_chrdev_region(sophgo_fan->devno, 1); -+ return ret; -+ } -+ -+ //as fan source clk 100M, we advise to set freq num 100M -+ sophgo_fan->fan_state.freq_num = 100*MHZ; -+ mutex_init(&sophgo_fan->freqnum_lock); -+ mutex_init(&sophgo_fan->enable_lock); -+ -+ platform_set_drvdata(pdev, sophgo_fan); -+ INIT_DELAYED_WORK(&sophgo_fan->poll_queue, fan_speed_check); -+ -+ return 0; -+} -+ -+static int sophgo_fan_speed_remove(struct platform_device *pdev) -+{ -+ struct sophgo_fan_speed_device *sophgo_fan = platform_get_drvdata(pdev); -+ -+ cancel_delayed_work(&sophgo_fan->poll_queue); -+ device_destroy(sophgo_fan->class, sophgo_fan->devno); -+ unregister_chrdev_region(sophgo_fan->devno, 1); -+ kfree(sophgo_fan); -+ sophgo_fan = NULL; -+ return 0; -+} -+ -+static const struct of_device_id sophgo_fan_speed_of_match = { -+ { -+ .compatible = "sophgo,sophgo-tach", -+ }, -+ {} -+}; -+ -+static struct platform_driver sophgo_fan_speed_driver = { -+ .probe = sophgo_fan_speed_probe, -+ .remove = sophgo_fan_speed_remove, -+ .driver = { -+ .name = "sophgo,sophgo-tach", -+ .of_match_table = sophgo_fan_speed_of_match, -+ }, -+}; -+ -+static int __init sophgo_fan_speed_init(void) -+{ -+ sophgo_fan_speed_class = class_create(DEV_NAME); -+ if (IS_ERR(sophgo_fan_speed_class)) { -+ pr_err("class create failed\n"); -+ return PTR_ERR(sophgo_fan_speed_class); -+ } -+ sophgo_fan_speed_class->dev_groups = fan_speed_groups; -+ -+ nl_fd = netlink_kernel_create(&init_net, USER_MSG, &cfg); -+ if (!nl_fd) { -+ pr_err("sophgo_fan_speed, cannot create netlink socket!\n"); -+ return -1; -+ } -+ fan_index = 0; -+ return platform_driver_register(&sophgo_fan_speed_driver); -+} -+ -+static void __exit sophgo_fan_speed_exit(void) -+{ -+ class_destroy(sophgo_fan_speed_class); -+ if (nl_fd) { -+ netlink_kernel_release(nl_fd); -+ nl_fd = NULL; -+ } -+} -+ -+module_init(sophgo_fan_speed_init); -+module_exit(sophgo_fan_speed_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Xiao Wang"); -+MODULE_DESCRIPTION("minimal module"); -+MODULE_VERSION("ALPHA"); -diff --git a/drivers/soc/sophgo/top/top_intc.c b/drivers/soc/sophgo/top/top_intc.c -new file mode 100644 -index 000000000000..2577137fbc4f ---- /dev/null -+++ b/drivers/soc/sophgo/top/top_intc.c -@@ -0,0 +1,412 @@ -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+#include <linux/of.h> -+#include <linux/of_platform.h> -+#include <linux/of_pci.h> -+#include <linux/msi.h> -+#include <linux/irq.h> -+#include <linux/irqdomain.h> -+#include <linux/irqchip/chained_irq.h> -+ -+#define MAX_IRQ_NUMBER 32 -+#define TOP_INTC_NUM 2 -+/* -+ * here we assume all plic hwirq and tic hwirq should -+ * be contiguous. -+ * topc_intc hwirq is index of bitmap (both software and -+ * hardware), and starts from 0. -+ * so we use tic hwirq as index to get plic hwirq and its -+ * irq data. -+ * when used as a msi parent, tic hwirq is written to Top -+ * reg for triggering irq by a PCIe device. -+ * -+ * now we pre-requested plic interrupt, but may try request -+ * plic interrupt when needed, like gicp_irq_domain_alloc. -+ */ -+struct top_intc_data { -+ struct platform_device *pdev; -+ int irq_num; -+ struct irq_domain *domain; -+ struct irq_chip *chip; -+ int for_msi; -+ int reg_bitwidth; -+ -+ DECLARE_BITMAP(irq_bitmap, MAX_IRQ_NUMBER); -+ spinlock_t lock; -+ -+ void __iomem *reg_sta; -+ void __iomem *reg_set; -+ void __iomem *reg_clr; -+ -+ phys_addr_t reg_set_phys; -+ -+ irq_hw_number_t plic_hwirqsMAX_IRQ_NUMBER; -+ int plic_irqsMAX_IRQ_NUMBER; -+ struct irq_data *plic_irq_datasMAX_IRQ_NUMBER; -+ int tic_to_plicMAX_IRQ_NUMBER; // mapping from tic hwirq to plic hwirq -+}; -+ -+// workaround for using in other modules -+struct top_intc_data *tic_dataTOP_INTC_NUM; -+ -+struct irq_domain *cdns_pcie_get_parent_irq_domain(int intc_id) -+{ -+ if (intc_id >= TOP_INTC_NUM) -+ return NULL; -+ -+ if (tic_dataintc_id) -+ return tic_dataintc_id->domain; -+ else -+ return NULL; -+} -+ -+static int top_intc_domain_translate(struct irq_domain *d, -+ struct irq_fwspec *fwspec, -+ unsigned long *hwirq, -+ unsigned int *type) -+{ -+ struct top_intc_data *data = d->host_data; -+ -+ if (fwspec->param_count != 2) -+ return -EINVAL; -+ if (fwspec->param1 >= data->irq_num) -+ return -EINVAL; -+ -+ *hwirq = fwspec->param0; -+ *type = fwspec->param1 & IRQ_TYPE_SENSE_MASK; -+ pr_debug("%s hwirq %d, flag %d\n", __func__, fwspec->param0, fwspec->param1); -+ return 0; -+} -+ -+static int top_intc_domain_alloc(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs, -+ void *args) -+{ -+ unsigned long flags; -+ irq_hw_number_t hwirq; -+ int i, type, ret = -1; -+ struct top_intc_data *data = domain->host_data; -+ -+ if (data->for_msi) { -+ // dynamically alloc hwirq -+ spin_lock_irqsave(&data->lock, flags); -+ ret = bitmap_find_free_region(data->irq_bitmap, data->irq_num, -+ order_base_2(nr_irqs)); -+ spin_unlock_irqrestore(&data->lock, flags); -+ -+ if (ret < 0) { -+ pr_err("%s failed to alloc irq %d, total %d\n", __func__, virq, nr_irqs); -+ return -ENOSPC; -+ } -+ -+ hwirq = ret; -+ for (i = 0; i < nr_irqs; i++) { -+ irq_domain_set_info(domain, virq + i, hwirq + i, -+ data->chip, -+ data, handle_edge_irq, -+ NULL, NULL); -+ data->tic_to_plichwirq + i = data->plic_hwirqshwirq + i; -+ } -+ } else { -+ // try use hwirq specified in parameter -+ ret = top_intc_domain_translate(domain, args, &hwirq, &type); -+ if (ret) { -+ pr_err("%s failed to translate virq %d, %d\n", __func__, virq, ret); -+ return ret; -+ } -+ -+ // try to occupy bitmap for the given hwirq -+ spin_lock_irqsave(&data->lock, flags); -+ ret = bitmap_allocate_region(data->irq_bitmap, hwirq, order_base_2(1)); -+ spin_unlock_irqrestore(&data->lock, flags); -+ if (ret < 0) { -+ pr_err("%s virq %d found hwirq %ld occupied\n", __func__, virq, hwirq); -+ return -EBUSY; -+ } -+ -+ irq_domain_set_info(domain, virq, hwirq, -+ data->chip, -+ data, handle_edge_irq, -+ NULL, NULL); -+ -+ // explicitly set parent -+ data->tic_to_plichwirq = data->plic_hwirqshwirq; -+ } -+ -+ pr_debug("%s hwirq %ld, irq %d, plic irq %d, total %d\n", __func__, -+ hwirq, virq, data->plic_irqshwirq, nr_irqs); -+ return 0; -+} -+ -+static void top_intc_domain_free(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs) -+{ -+ struct irq_data *d = irq_domain_get_irq_data(domain, virq); -+ struct top_intc_data *data = irq_data_get_irq_chip_data(d); -+ unsigned long flags; -+ -+ pr_debug("%s hwirq %ld, irq %d, total %d\n", __func__, d->hwirq, virq, nr_irqs); -+ -+ spin_lock_irqsave(&data->lock, flags); -+ bitmap_release_region(data->irq_bitmap, d->hwirq, -+ order_base_2(nr_irqs)); -+ spin_unlock_irqrestore(&data->lock, flags); -+} -+ -+static const struct irq_domain_ops top_intc_domain_ops = { -+ .translate = top_intc_domain_translate, -+ .alloc = top_intc_domain_alloc, -+ .free = top_intc_domain_free, -+}; -+ -+static void top_intc_ack_irq(struct irq_data *d) -+{ -+ struct top_intc_data *data = irq_data_get_irq_chip_data(d); -+ int reg_off, bit_off; -+ struct irq_data *plic_irq_data = data->plic_irq_datasd->hwirq; -+ -+ reg_off = d->hwirq / data->reg_bitwidth; -+ bit_off = d->hwirq - data->reg_bitwidth * reg_off; -+ writel(1 << bit_off, (unsigned int *)data->reg_clr + reg_off); -+ -+ pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq, -+ plic_irq_data->domain->name, plic_irq_data->hwirq); -+ if (plic_irq_data->chip->irq_ack) -+ plic_irq_data->chip->irq_ack(plic_irq_data); -+} -+ -+static void top_intc_mask_irq(struct irq_data *d) -+{ -+ struct top_intc_data *data = irq_data_get_irq_chip_data(d); -+ struct irq_data *plic_irq_data = data->plic_irq_datasd->hwirq; -+ -+ pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq, -+ plic_irq_data->domain->name, plic_irq_data->hwirq); -+ plic_irq_data->chip->irq_mask(plic_irq_data); -+} -+ -+static void top_intc_unmask_irq(struct irq_data *d) -+{ -+ struct top_intc_data *data = irq_data_get_irq_chip_data(d); -+ struct irq_data *plic_irq_data = data->plic_irq_datasd->hwirq; -+ -+ pr_debug("%s %ld, parent %s/%ld\n", __func__, d->hwirq, -+ plic_irq_data->domain->name, plic_irq_data->hwirq); -+ plic_irq_data->chip->irq_unmask(plic_irq_data); -+} -+ -+static void top_intc_setup_msi_msg(struct irq_data *d, struct msi_msg *msg) -+{ -+ struct top_intc_data *data = irq_data_get_irq_chip_data(d); -+ -+ msg->address_lo = lower_32_bits(data->reg_set_phys); -+ msg->address_hi = upper_32_bits(data->reg_set_phys); -+ msg->data = 1 << d->hwirq; -+ -+ pr_debug("%s msi#%d: address_hi %#x, address_lo %#x, data %#x\n", __func__, -+ (int)d->hwirq, msg->address_hi, msg->address_lo, msg->data); -+} -+ -+static int top_intc_set_affinity(struct irq_data *d, -+ const struct cpumask *mask, bool force) -+{ -+ struct top_intc_data *data = irq_data_get_irq_chip_data(d); -+ struct irq_data *plic_irq_data = data->plic_irq_datasd->hwirq; -+ -+ irq_data_update_effective_affinity(d, mask); -+ if (plic_irq_data->chip->irq_set_affinity) -+ return plic_irq_data->chip->irq_set_affinity(plic_irq_data, mask, force); -+ else -+ return -EINVAL; -+} -+ -+static int top_intc_set_type(struct irq_data *d, u32 type) -+{ -+ /* -+ * dummy function, so __irq_set_trigger can continue to set -+ * correct trigger type. -+ */ -+ return 0; -+} -+ -+static struct irq_chip top_intc_irq_chip = { -+ .name = "top-intc", -+ .irq_ack = top_intc_ack_irq, -+ .irq_mask = top_intc_mask_irq, -+ .irq_unmask = top_intc_unmask_irq, -+ .irq_compose_msi_msg = top_intc_setup_msi_msg, -+ .irq_set_affinity = top_intc_set_affinity, -+ .irq_set_type = top_intc_set_type, -+}; -+ -+static void top_intc_irq_handler(struct irq_desc *plic_desc) -+{ -+ struct irq_chip *plic_chip = irq_desc_get_chip(plic_desc); -+ struct top_intc_data *data = irq_desc_get_handler_data(plic_desc); -+ irq_hw_number_t plic_hwirq = irq_desc_get_irq_data(plic_desc)->hwirq; -+ irq_hw_number_t top_intc_hwirq; -+ int top_intc_irq, i, ret; -+ -+ chained_irq_enter(plic_chip, plic_desc); -+ -+ for (i = 0; i < data->irq_num; i++) { -+ if (data->tic_to_plici == plic_hwirq) -+ break; -+ } -+ if (i < data->irq_num) { -+ top_intc_hwirq = i; -+ top_intc_irq = irq_find_mapping(data->domain, top_intc_hwirq); -+ pr_debug("%s plic hwirq %ld, tic hwirq %ld, tic irq %d\n", __func__, -+ plic_hwirq, top_intc_hwirq, top_intc_irq); -+ if (top_intc_irq) -+ ret = generic_handle_irq(top_intc_irq); -+ pr_debug("%s handled tic irq %d, %d\n", __func__, top_intc_irq, ret); -+ } else { -+ pr_debug("%s not found tic hwirq for plic hwirq %ld\n", __func__, plic_hwirq); -+ // workaround, ack unexpected(unregistered) interrupt -+ writel(1 << (plic_hwirq - data->plic_hwirqs0), data->reg_clr); -+ } -+ -+ chained_irq_exit(plic_chip, plic_desc); -+} -+ -+static int top_intc_probe(struct platform_device *pdev) -+{ -+ struct top_intc_data *data; -+ struct resource *res; -+ struct fwnode_handle *fwnode = of_node_to_fwnode(pdev->dev.of_node); -+ int ret = 0, i; -+ int intc_id = 0; -+ -+ device_property_read_u32(&pdev->dev, "top-intc-id", &intc_id); -+ if (intc_id >= TOP_INTC_NUM) -+ return -EINVAL; -+ -+ // alloc private data -+ data = kzalloc(sizeof(struct top_intc_data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ platform_set_drvdata(pdev, data); -+ data->pdev = pdev; -+ spin_lock_init(&data->lock); -+ -+ if (device_property_read_bool(&pdev->dev, "for-msi")) { -+ dev_info(&pdev->dev, "is a msi parent\n"); -+ data->for_msi = 1; -+ } -+ if (device_property_read_u32(&pdev->dev, "reg-bitwidth", &data->reg_bitwidth)) -+ data->reg_bitwidth = 32; -+ -+ // get register address -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sta"); -+ data->reg_sta = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(data->reg_sta)) { -+ dev_err(&pdev->dev, "failed map status register\n"); -+ ret = PTR_ERR(data->reg_sta); -+ goto out; -+ } -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set"); -+ data->reg_set = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(data->reg_set)) { -+ dev_err(&pdev->dev, "failed map set register\n"); -+ ret = PTR_ERR(data->reg_set); -+ goto out; -+ } -+ data->reg_set_phys = res->start; -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr"); -+ data->reg_clr = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(data->reg_clr)) { -+ dev_err(&pdev->dev, "failed map clear register\n"); -+ ret = PTR_ERR(data->reg_clr); -+ goto out; -+ } -+ -+ // get irq numbers -+ for (i = 0; i < ARRAY_SIZE(data->plic_hwirqs); i++) { -+ char name8; -+ int irq; -+ -+ snprintf(name, ARRAY_SIZE(name), "msi%d", i); -+ irq = platform_get_irq_byname(pdev, name); -+ if (irq < 0) -+ break; -+ -+ data->plic_irqsi = irq; -+ data->plic_irq_datasi = irq_get_irq_data(irq); -+ data->plic_hwirqsi = data->plic_irq_datasi->hwirq; -+ dev_dbg(&pdev->dev, "%s: plic hwirq %ld, plic irq %d\n", name, -+ data->plic_hwirqsi, data->plic_irqsi); -+ } -+ data->irq_num = i; -+ dev_dbg(&pdev->dev, "got %d plic irqs\n", data->irq_num); -+ -+ // create IRQ domain -+ data->domain = irq_domain_create_linear(fwnode, data->irq_num, -+ &top_intc_domain_ops, data); -+ if (!data->domain) { -+ dev_err(&pdev->dev, "create linear irq doamin failed\n"); -+ ret = -ENODEV; -+ goto out; -+ } -+ data->chip = &top_intc_irq_chip; -+ -+ /* -+ * workaround to deal with IRQ conflict with TPU driver, -+ * skip the firt IRQ and mark it as used. -+ */ -+ //bitmap_allocate_region(data->irq_bitmap, 0, order_base_2(1)); -+ for (i = 0; i < data->irq_num; i++) -+ irq_set_chained_handler_and_data(data->plic_irqsi, -+ top_intc_irq_handler, data); -+ -+ if (data->for_msi) { -+ irq_domain_update_bus_token(data->domain, DOMAIN_BUS_NEXUS); -+ if (tic_dataintc_id) -+ dev_err(&pdev->dev, "tic_data is not empty, %s\n", -+ dev_name(&tic_dataintc_id->pdev->dev)); -+ tic_dataintc_id = data; -+ } else { -+ /* -+ * populate child nodes. when test device node is a child, it will not be -+ * automatically enumerated as a platform device. -+ */ -+ of_platform_populate(pdev->dev.of_node, NULL, NULL, NULL); -+ } -+ return ret; -+ -+out: -+ if (data->reg_sta) -+ iounmap(data->reg_sta); -+ if (data->reg_set) -+ iounmap(data->reg_set); -+ if (data->reg_clr) -+ iounmap(data->reg_clr); -+ kfree(data); -+ return ret; -+} -+ -+static const struct of_device_id top_intc_of_match = { -+ { -+ .compatible = "sophgo,top-intc", -+ }, -+ {}, -+}; -+ -+static struct platform_driver top_intc_driver = { -+ .driver = { -+ .name = "sophgo,top-intc", -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(top_intc_of_match), -+ }, -+ .probe = top_intc_probe, -+}; -+ -+static int __init top_intc_init(void) -+{ -+ return platform_driver_register(&top_intc_driver); -+} -+ -+arch_initcall(top_intc_init); -diff --git a/drivers/soc/sophgo/umcu/mcu.c b/drivers/soc/sophgo/umcu/mcu.c -new file mode 100644 -index 000000000000..bf419f1821ef ---- /dev/null -+++ b/drivers/soc/sophgo/umcu/mcu.c -@@ -0,0 +1,1144 @@ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/nvmem-consumer.h> -+#include <linux/i2c.h> -+#include <linux/err.h> -+#include <linux/hwmon.h> -+#include <linux/mutex.h> -+#include <linux/slab.h> -+ -+/* fixed MCU registers */ -+#define MCU_REG_BOARD_TYPE 0x00 -+#define MCU_REG_VERSION 0x01 -+#define MCU_REG_SOC_TEMP 0x04 -+#define MCU_REG_BOARD_TEMP 0x05 -+#define MCU_REG_PWROFF_REASON1 0x06 -+#define MCU_REG_PWROFF_REASON2 0x07 -+ -+#define MCU_REG_CRITICAL_ACTIONS 0x65 -+#define MCU_REG_CRITICAL_TEMP 0x66 -+#define MCU_REG_REPOWERON_TEMP 0x67 -+#define MCU_REG_KEEP_DDR_POWERON 0x68 -+ -+#define MCU_CRITICAL_ACTION_POWEROFF 0x2 -+#define MCU_CRITICAL_ACTION_REBOOT 0X1 -+ -+#define MANGO_BOARD_TYPE_MASK 1 << 7 -+ -+#ifndef assert -+#define assert(exp) WARN_ON(!(exp)) -+#endif -+ -+struct mcu_features { -+ u8 id; -+ char *proj; -+ char *soc; -+ char *chip; -+ -+ int board_type; -+ int mcu_ver; -+ int pcb_ver; -+ int soc_tmp; -+ int board_tmp; -+ int alert_status; -+ int alert_mask; -+ int rst_cnt; -+ int uptime; -+ int lock; -+ int power; -+ int power_tpu; -+ int brd_id; -+ int brd_ip; -+ -+ int critical_action; -+ int critical_temp; -+ int repoweron_temp; -+ int keep_ddr_poweron; -+ -+ char *alert_table16; -+}; -+ -+struct mcu_info { -+ u8 board_type; -+ u8 mcu_ver; -+ u8 pcb_ver; -+ u8 rst_cnt; -+ int updated; -+}; -+ -+struct mcu_ctx { -+ const struct mcu_features *features; -+ struct i2c_client *i2c; -+ struct mcu_info info; -+ u32 channel_config4; -+ struct hwmon_channel_info temp_info; -+ const struct hwmon_channel_info *channel_info3; -+ struct hwmon_chip_info chip; -+ struct mutex update_lock; -+ unsigned int hwmon_update_interval; /* in milliseconds */ -+}; -+ -+const struct mcu_features mcu_list = { -+ { -+ 0x80, "SG2042 EVB", "SG2042", "GD32", -+ 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1, -+ -1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS, -+ MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP, -+ MCU_REG_KEEP_DDR_POWERON, -+ { -+ "SoC overheat", -+ "Power supply overheat", -+ "Board overheat", -+ "Board overheat and shutdown", -+ "SoC overheat and shutdown", -+ "Power supply failure", -+ "12V power supply failure", -+ "SoC required reboot", -+ }, -+ }, -+ -+ { -+ 0x83, "SG2042 X4", "SG2042", "GD32", -+ 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1, -+ -1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS, -+ MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP, -+ MCU_REG_KEEP_DDR_POWERON, -+ { -+ "SoC overheat", -+ "Power supply overheat", -+ "Board overheat", -+ "Board overheat and shutdown", -+ "SoC overheat and shutdown", -+ "Power supply failure", -+ "12V power supply failure", -+ "SoC required reboot", -+ }, -+ }, -+ -+ { -+ 0x90, "MILKV PIONEER", "SG2042", "GD32", -+ 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0b, -1, -+ -1, -1, -1, -1, MCU_REG_CRITICAL_ACTIONS, -+ MCU_REG_CRITICAL_TEMP, MCU_REG_REPOWERON_TEMP, -+ MCU_REG_KEEP_DDR_POWERON, -+ { -+ "SoC overheat", -+ "Power supply overheat", -+ "Board overheat", -+ "Board overheat and shutdown", -+ "SoC overheat and shutdown", -+ "Power supply failure", -+ "12V power supply failure", -+ "SoC required reboot", -+ }, -+ }, -+}; -+ -+static const char help = -+"\n" -+"sys files description\n" -+"======================\n" -+"Bitmain unified mcu device driver\n" -+"You can get/set MCU though read/write operation\n" -+"eg. You can get fixed information though command\n" -+"$cat /sys/bus/i2c/0-0017/information\n" -+"You can set alert mask though command\n" -+"$echo 0xffff /sys/bus/i2c/0-0017/alert\n" -+"\n" -+"information\n" -+"-----------\n" -+"Fixed information during SoC uptime\n" -+"Read this file will return such information\n" -+"Write this file to force SoC re-get such information from MCU\n" -+"No matter what data you write to or just invoke write with a length of 0\n" -+"File pointer will move forward after read,\n" -+"write has no effect on file pointer\n" -+"\n" -+"temperature\n" -+"-----------\n" -+"Temperature value, sensors located on SoC and on board\n" -+"Read this file will return temperature of both in celsius\n" -+"Write is forbidden\n" -+"\n" -+"uptime\n" -+"------\n" -+"Uptime (from SoC poweron) in seconds\n" -+"Read will get this value, write is forbidden\n" -+"\n" -+"alert\n" -+"-----\n" -+"Alert control and status\n" -+"Read will get current alert status\n" -+"Write corresponding bit to 1 will mask this alert\n" -+"You can use 0x/0X for hex, 0 for octal\n" -+"other leading characters will be considered as decimal\n" -+"Values larger than 0xffff is forbidden\n" -+"\n"; -+ -+enum { -+ MCU_I2C_TYPE_U = 0, -+ MCU_I2C_TYPE_U8, -+ MCU_I2C_TYPE_U16, -+ MCU_I2C_TYPE_U32, -+ MCU_I2C_TYPE_U64, -+ MCU_I2C_TYPE_D, -+ MCU_I2C_TYPE_S8, -+ MCU_I2C_TYPE_S16, -+ MCU_I2C_TYPE_S32, -+ MCU_I2C_TYPE_S64, -+ MCU_I2C_TYPE_MAX, -+}; -+ -+static const char *mcu_i2c_type_listMCU_I2C_TYPE_MAX = { -+ MCU_I2C_TYPE_U = "u", -+ MCU_I2C_TYPE_U8 = "u8", -+ MCU_I2C_TYPE_U16 = "u16", -+ MCU_I2C_TYPE_U32 = "u32", -+ MCU_I2C_TYPE_U64 = "u64", -+ MCU_I2C_TYPE_D = "d", -+ MCU_I2C_TYPE_S8 = "s8", -+ MCU_I2C_TYPE_S16 = "s16", -+ MCU_I2C_TYPE_S32 = "s32", -+ MCU_I2C_TYPE_S64 = "s64", -+}; -+ -+static int check_token(char *token) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mcu_i2c_type_list); ++i) { -+ if (strcmp(token, mcu_i2c_type_listi) == 0) -+ return i; -+ } -+ return -EINVAL; -+} -+ -+static inline struct device *i2c2dev(struct i2c_client *i2c) -+{ -+ return &i2c->dev; -+} -+ -+static int mcu_i2c_write_byte(struct i2c_client *i2c, int reg, u8 data) -+{ -+ int err; -+ -+ if (reg == -1) -+ return 0; -+ err = i2c_smbus_write_byte_data(i2c, reg, data); -+ dev_dbg(i2c2dev(i2c), "%d : %u\n", reg, data); -+ return err; -+} -+ -+static int mcu_i2c_read_byte(struct i2c_client *i2c, int reg) -+{ -+ int err; -+ -+ if (reg == -1) -+ return 0; -+ err = i2c_smbus_read_byte_data(i2c, reg); -+ dev_dbg(i2c2dev(i2c), "%d : %d\n", reg, err); -+ return err; -+} -+ -+static int mcu_i2c_write_block(struct i2c_client *i2c, int reg, -+ int len, void *data) -+{ -+ int err, i; -+ -+ if (reg == -1) -+ return 0; -+ -+ err = i2c_smbus_write_i2c_block_data(i2c, reg, len, data); -+ for (i = 0; i < len; ++i) -+ dev_dbg(i2c2dev(i2c), "%d : %u\n", reg + i, ((u8 *)data)i); -+ return err; -+} -+ -+static int mcu_i2c_read_block(struct i2c_client *i2c, int reg, -+ int len, void *data) -+{ -+ int err, i; -+ -+ if (reg == -1) -+ return 0; -+ -+ err = i2c_smbus_read_i2c_block_data(i2c, reg, len, data); -+ for (i = 0; i < len; ++i) -+ dev_dbg(i2c2dev(i2c), "%d : %u\n", reg + i, ((u8 *)data)i); -+ -+ return err; -+} -+ -+static int mcu_i2c_sreadf(struct i2c_client *i2c, const char *fmt, ...) -+{ -+ va_list arg; -+ const char *p = fmt; -+ const char *start, *end; -+ char token16; -+ int tokenlen; -+ int ret = -EINVAL; -+ int idx; -+ -+ if (fmt == NULL) -+ return -EINVAL; -+ -+ va_start(arg, fmt); -+ -+ while (*p) { -+ /* skip all % */ -+ while (*p == '%') -+ ++p; -+ start = p; -+ while (*p && *p != '%') -+ ++p; -+ /* now *p is ether \0 or % */ -+ end = p; -+ tokenlen = end - start; -+ if (tokenlen > sizeof(token) - 1) { -+ ret = -EINVAL; -+ goto end; -+ } -+ if (tokenlen == 0) -+ continue; -+ /* get this token */ -+ memcpy(token, start, tokenlen); -+ tokentokenlen = 0; /* terminat this string */ -+ idx = check_token(token); -+ if (idx < 0) { -+ ret = idx; -+ goto end; -+ } -+ -+ ret = mcu_i2c_read_byte(i2c, va_arg(arg, int)); -+ if (ret < 0) -+ goto end; -+ -+ switch (idx) { -+ case MCU_I2C_TYPE_U: -+ *va_arg(arg, unsigned int *) = ret; -+ break; -+ case MCU_I2C_TYPE_U8: -+ *va_arg(arg, u8 *) = ret; -+ break; -+ case MCU_I2C_TYPE_U16: -+ *va_arg(arg, u16 *) = ret; -+ break; -+ case MCU_I2C_TYPE_U32: -+ *va_arg(arg, u32 *) = ret; -+ break; -+ case MCU_I2C_TYPE_U64: -+ *va_arg(arg, u64 *) = ret; -+ break; -+ case MCU_I2C_TYPE_D: -+ *va_arg(arg, int *) = ret; -+ break; -+ case MCU_I2C_TYPE_S8: -+ *va_arg(arg, s8 *) = ret; -+ break; -+ case MCU_I2C_TYPE_S16: -+ *va_arg(arg, s16 *) = ret; -+ break; -+ case MCU_I2C_TYPE_S32: -+ *va_arg(arg, s32 *) = ret; -+ break; -+ case MCU_I2C_TYPE_S64: -+ *va_arg(arg, s64 *) = ret; -+ break; -+ default: -+ assert(false); -+ break; -+ } -+ } -+ -+ ret = 0; -+end: -+ va_end(arg); -+ return ret; -+} -+ -+/* sysfs callbacks */ -+ -+static inline struct i2c_client *dev2i2c(struct device *dev) -+{ -+ return container_of(dev, struct i2c_client, dev); -+} -+ -+static const inline struct mcu_features *dev2features(struct device *dev) -+{ -+ struct i2c_client *i2c = dev2i2c(dev); -+ struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c); -+ -+ return ctx->features; -+} -+ -+static ssize_t help_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ buf0 = 0; -+ strncpy(buf, help, PAGE_SIZE); -+ return strlen(buf); -+} -+ -+static int mcu_msg_append(char *base, unsigned long limit, -+ const char *fmt, ...) -+{ -+ int len = strlen(base); -+ va_list arg; -+ -+ va_start(arg, fmt); -+ len += vsnprintf(base + len, limit - len, fmt, arg); -+ va_end(arg); -+ return len; -+} -+ -+ssize_t info_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct i2c_client *i2c = dev2i2c(dev); -+ struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c); -+ struct mcu_info *info = &ctx->info; -+ const struct mcu_features *features = ctx->features; -+ int err; -+ -+ if (info->updated == 0) { -+ /* get information from mcu through i2c */ -+ err = mcu_i2c_sreadf(i2c, "%u8%u8%u8%u8", -+ features->board_type, &info->board_type, -+ features->mcu_ver, &info->mcu_ver, -+ features->pcb_ver, &info->pcb_ver, -+ features->rst_cnt, &info->rst_cnt); -+ if (err) -+ return err; -+ info->updated = 1; -+ } -+ -+ /* convert to json text */ -+ mcu_msg_append(buf, PAGE_SIZE, "{\n"); -+ mcu_msg_append(buf, PAGE_SIZE, "\t\"model\": \"%s\",\n", features->proj); -+ mcu_msg_append(buf, PAGE_SIZE, "\t\"chip\": \"%s\",\n", features->soc); -+ mcu_msg_append(buf, PAGE_SIZE, "\t\"mcu\": \"%s\",\n", features->chip); -+ mcu_msg_append(buf, PAGE_SIZE, "\t\"board type\": \"0x%02X\",\n", info->board_type); -+ mcu_msg_append(buf, PAGE_SIZE, "\t\"mcu version\": \"0x%02X\",\n", info->mcu_ver); -+ mcu_msg_append(buf, PAGE_SIZE, "\t\"pcb version\": \"0x%02X\",\n", info->pcb_ver); -+ mcu_msg_append(buf, PAGE_SIZE, "\t\"reset count\": %u\n", info->rst_cnt); -+ err = mcu_msg_append(buf, PAGE_SIZE, "}\n"); -+ -+ return err; -+} -+ -+static ssize_t info_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *i2c = dev2i2c(dev); -+ struct mcu_ctx *ctx = (struct mcu_ctx *)i2c_get_clientdata(i2c); -+ struct mcu_info *info = &ctx->info; -+ -+ info->updated = 0; -+ return count; -+} -+ -+ssize_t brdid_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ int err = 0; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->brd_id == -1) -+ return -ENODEV; -+ -+ err = mcu_i2c_read_byte(dev2i2c(dev), features->brd_id); -+ if (err < 0) -+ return err; -+ -+ return sprintf(buf, "brdid:%u\n", err); -+} -+ -+ssize_t brdip_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ u8 ip4; -+ int err; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->brd_ip == -1) -+ return -ENODEV; -+ -+ memset(ip, 0, sizeof(ip)); -+ err = mcu_i2c_read_block(dev2i2c(dev), features->brd_ip, -+ sizeof(ip), ip); -+ if (err < 0) -+ return err; -+ -+ return mcu_msg_append(buf, PAGE_SIZE, "brdip:%u.%u.%u.%u\n", -+ ip0, ip1, ip2, ip3); -+} -+ -+static ssize_t brdip_store(struct device *dev, struct device_attribute *attr, -+ const char *ubuf, size_t len) -+{ -+ u8 ip4; -+ char buf32; -+ char *s, *p, *n; -+ unsigned long res; -+ int i, err; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->brd_ip == -1) -+ return -ENODEV; -+ -+ memset(buf, 0, sizeof(buf)); -+ len = min(sizeof(buf), len); -+ memcpy(buf, ubuf, len); -+ s = buf; -+ for (i = 0; i < 4; i++) { -+ if (i != 3) { -+ p = strchr(s, '.'); -+ n = p+1; -+ *p = '\0'; -+ } -+ err = kstrtoul(s, 10, &res); -+ if (err) -+ return err; -+ ipi = (u8)res; -+ dev_dbg(dev, "ip%d = %d\n", i, ipi); -+ s = n; -+ } -+ err = mcu_i2c_write_block(dev2i2c(dev), features->brd_ip, -+ sizeof(ip), ip); -+ if (err < 0) -+ return err; -+ -+ return len; -+} -+ssize_t uptime_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ u8 t2; -+ int err; -+ const struct mcu_features *features = dev2features(dev); -+ -+ err = mcu_i2c_read_block(dev2i2c(dev), features->uptime, -+ sizeof(t), t); -+ if (err < 0) -+ return err; -+ -+ return mcu_msg_append(buf, PAGE_SIZE, -+ "%u Seconds\n", t0 | (t1 << 8)); -+} -+ -+ssize_t temp_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ s8 t2; -+ int err; -+ const struct mcu_features *features = dev2features(dev); -+ -+ /* get information from mcu through i2c */ -+ err = mcu_i2c_sreadf(dev2i2c(dev), "%s8%s8", -+ features->soc_tmp, t, -+ features->board_tmp, t + 1); -+ if (err) -+ return err; -+ -+ mcu_msg_append(buf, PAGE_SIZE, -+ "SoC temperature: %d Cel\n", t0); -+ return mcu_msg_append(buf, PAGE_SIZE, -+ "Board temperature: %d Cel\n", t1); -+} -+ -+ -+static const char *alert_id2name(const struct mcu_features *features, int id) -+{ -+ if (features->alert_tableid) -+ return features->alert_tableid; -+ return "Unknown alert"; -+} -+ -+ssize_t alert_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ int cnt = 0; -+ int i, err; -+ u8 t4; -+ u16 mask, status; -+ const struct mcu_features *features = dev2features(dev); -+ const char *alt_msg; -+ -+ if (features->alert_status == -1) -+ return 0; -+ -+ err = mcu_i2c_read_block(dev2i2c(dev), features->alert_mask, -+ sizeof(t), t); -+ /* get information from mcu through i2c */ -+ if (err < 0) -+ return err; -+ -+ status = t0 | (t1 << 8); -+ mask = t2 | (t3 << 8); -+ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, -+ "Mask 0x%02x, Status 0x%02x\n", -+ mask, status); -+ -+ if (status == 0) { -+ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, -+ "Working fine\n"); -+ } else { -+ for (i = 0; i < sizeof(status) * 8; ++i) { -+ if ((status >> i) & 1) { -+ alt_msg = alert_id2name(features, i); -+ cnt += snprintf(buf + cnt, -+ PAGE_SIZE - cnt, -+ "%d: %s\n", -+ i, alt_msg); -+ } -+ } -+ } -+ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, -+ "**************************************************\n"); -+ -+ for (i = 0; i < 16; ++i) { -+ if (features->alert_tablei == NULL) -+ continue; -+ cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, -+ "%d: %s\n", i, alert_id2name(features, i)); -+ } -+ -+ return cnt; -+} -+ -+static ssize_t alert_store(struct device *dev, struct device_attribute *attr, -+ const char *ubuf, size_t len) -+{ -+ char buf32; -+ u8 t2; -+ unsigned long res; -+ int err; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->alert_mask == -1) -+ return -ENODEV; -+ -+ len = min(sizeof(buf) - 1, len); -+ memcpy(buf, ubuf, len); -+ -+ buflen = 0; // zero terminated -+ err = kstrtoul(buf, 0, &res); -+ if (err) -+ return err; -+ if (res > 0xffff) -+ return -EINVAL; -+ -+ t0 = res & 0xff; -+ t1 = (res >> 8) & 0xff; -+ err = mcu_i2c_write_block(dev2i2c(dev), features->alert_mask, -+ sizeof(t), t); -+ if (err < 0) -+ return err; -+ -+ return len; -+} -+ -+ssize_t lock_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ int err; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->lock == -1) -+ return -ENODEV; -+ -+ err = mcu_i2c_read_byte(dev2i2c(dev), features->lock); -+ -+ if (err < 0) -+ return err; -+ -+ return mcu_msg_append(buf, PAGE_SIZE, -+ "%d", err ? 1 : 0); -+} -+ -+static ssize_t lock_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int err; -+ unsigned long res; -+ const u8 *code = { "CK", "LO", }; -+ const u8 *p; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->lock == -1) -+ return -ENODEV; -+ -+ err = kstrtoul(buf, 0, &res); -+ if (err) -+ return err; -+ -+ res = res ? 1 : 0; -+ -+ for (p = coderes; *p; ++p) { -+ err = mcu_i2c_write_byte(dev2i2c(dev), features->lock, *p); -+ if (err < 0) -+ return err; -+ } -+ -+ return len; -+} -+ -+ssize_t power_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ u8 t2; -+ int err; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->power < 0) -+ return -EOPNOTSUPP; -+ -+ err = mcu_i2c_read_block(dev2i2c(dev), features->power, sizeof(t), t); -+ if (err < 0) -+ return err; -+ -+ err = sprintf(buf, "%umW\n", ((u16)t0) | (t1 << 8)); -+ -+ return err; -+} -+ -+static ssize_t power_tpu_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int err; -+ unsigned long res; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->power_tpu < 0) -+ return -EOPNOTSUPP; -+ -+ err = kstrtoul(buf, 0, &res); -+ if (err) -+ return err; -+ -+ data = res ? 1 : 0; -+ -+ err = mcu_i2c_write_block(dev2i2c(dev), features->power_tpu, -+ sizeof(data), &data); -+ return len; -+} -+ -+static ssize_t power_tpu_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ int err; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (features->power_tpu < 0) -+ return -EOPNOTSUPP; -+ -+ err = mcu_i2c_read_block(dev2i2c(dev), features->power_tpu, sizeof(data), &data); -+ if (err < 0) -+ return err; -+ -+ err = sprintf(buf, "%u\n", data); -+ -+ return err; -+} -+ -+static ssize_t mcu_critical_action_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int err; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ -+ if (!strcmp(buf, "reboot\n")) -+ data = MCU_CRITICAL_ACTION_REBOOT; -+ else if (!strcmp(buf, "poweroff\n")) -+ data = MCU_CRITICAL_ACTION_POWEROFF; -+ else -+ data = 0; -+ -+ if (data) { -+ err = mcu_i2c_write_block(dev2i2c(dev), -+ features->critical_action, sizeof(data), &data); -+ } -+ return len; -+} -+ -+static ssize_t mcu_critical_action_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ int err; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ err = mcu_i2c_read_block(dev2i2c(dev), features->critical_action, -+ sizeof(data), &data); -+ if (err < 0) -+ return err; -+ -+ if (data == MCU_CRITICAL_ACTION_REBOOT) -+ err = sprintf(buf, "reboot\n"); -+ else if (data == MCU_CRITICAL_ACTION_POWEROFF) -+ err = sprintf(buf, "poweroff\n"); -+ else -+ err = sprintf(buf, "unknown critical action\n"); -+ -+ return err; -+} -+ -+ -+static ssize_t mcu_critical_temp_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int err; -+ unsigned long res; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ err = kstrtoul(buf, 0, &res); -+ if (err) -+ return err; -+ -+ data = res; -+ -+ err = mcu_i2c_write_block(dev2i2c(dev), features->critical_temp, -+ sizeof(data), &data); -+ return len; -+} -+ -+static ssize_t mcu_critical_temp_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ int err; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ err = mcu_i2c_read_block(dev2i2c(dev), features->critical_temp, -+ sizeof(data), &data); -+ if (err < 0) -+ return err; -+ -+ err = sprintf(buf, "%u Cel\n", data); -+ -+ return err; -+} -+ -+ -+static ssize_t mcu_repoweron_temp_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int err; -+ unsigned long res; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ err = kstrtoul(buf, 0, &res); -+ if (err) -+ return err; -+ -+ data = res; -+ -+ err = mcu_i2c_write_block(dev2i2c(dev), features->repoweron_temp, -+ sizeof(data), &data); -+ return len; -+} -+ -+static ssize_t mcu_repoweron_temp_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ int err; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ err = mcu_i2c_read_block(dev2i2c(dev), features->repoweron_temp, -+ sizeof(data), &data); -+ if (err < 0) -+ return err; -+ -+ err = sprintf(buf, "%u Cel\n", data); -+ -+ return err; -+} -+ -+ -+static ssize_t mcu_keep_ddr_poweron_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int err; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ if (!strcmp(buf, "disable\n")) -+ data = 1; -+ else if (!strcmp(buf, "enable\n")) -+ data = 0; -+ else -+ return 0; -+ -+ err = mcu_i2c_write_block(dev2i2c(dev), features->keep_ddr_poweron, -+ sizeof(data), &data); -+ return len; -+} -+ -+static ssize_t mcu_keep_ddr_poweron_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ int err; -+ unsigned char data; -+ const struct mcu_features *features = dev2features(dev); -+ -+ err = mcu_i2c_read_block(dev2i2c(dev), features->keep_ddr_poweron, -+ sizeof(data), &data); -+ if (err < 0) -+ return err; -+ -+ if (data == 1) -+ err = sprintf(buf, "disable\n"); -+ else if (data == 0) -+ err = sprintf(buf, "enable\n"); -+ else -+ err = sprintf(buf, "unknown states\n"); -+ -+ return err; -+} -+ -+/* end of sysfs callbacks */ -+ -+const struct device_attribute mcu_attrs = { -+ {{"help", 0444}, help_show, NULL}, -+ {{"information", 0644}, info_show, info_store}, -+ {{"temperature", 0444}, temp_show, NULL}, -+ {{"uptime", 0444}, uptime_show, NULL}, -+ {{"alert", 0644}, alert_show, alert_store}, -+ {{"lock", 0644}, lock_show, lock_store}, -+ {{"power-now", 0444}, power_show, NULL}, -+ {{"power-tpu", 0644}, power_tpu_show, power_tpu_store}, -+ {{"board-id", 0444}, brdid_show, NULL}, -+ {{"board-ip", 0644}, brdip_show, brdip_store}, -+ {{"critical-action", 0644}, mcu_critical_action_show, -+ mcu_critical_action_store}, -+ {{"critical-temp", 0644}, mcu_critical_temp_show, -+ mcu_critical_temp_store}, -+ {{"repoweron-temp", 0664}, mcu_repoweron_temp_show, -+ mcu_repoweron_temp_store}, -+ {{"keep-ddr-poweron", 0664}, mcu_keep_ddr_poweron_show, -+ mcu_keep_ddr_poweron_store}, -+}; -+ -+static umode_t mcu_chip_is_visible(const void *data, enum hwmon_sensor_types type, -+ u32 attr, int channel) -+{ -+ switch (type) { -+ case hwmon_chip: -+ return 0444; -+ case hwmon_temp: -+ return 0444; -+ default: -+ return 0; -+ } -+} -+ -+static int mcu_hwmon_chip_read(struct device *dev, u32 attr, int channel, long *val) -+{ -+ struct mcu_ctx *ctx = dev_get_drvdata(dev); -+ -+ switch (attr) { -+ case hwmon_chip_update_interval: -+ *val = ctx->hwmon_update_interval; -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static int mcu_hwmon_temp_read(struct device *dev, u32 attr, int channel, long *val) -+{ -+ int soc_temp, board_temp; -+ -+ struct mcu_ctx *ctx = dev_get_drvdata(dev); -+ struct i2c_client *i2c = ctx->i2c; -+ mutex_lock(&ctx->update_lock); -+ soc_temp = mcu_i2c_read_byte(i2c, MCU_REG_SOC_TEMP); -+ mutex_unlock(&ctx->update_lock); -+ -+ mutex_lock(&ctx->update_lock); -+ board_temp = mcu_i2c_read_byte(i2c, MCU_REG_BOARD_TEMP); -+ mutex_unlock(&ctx->update_lock); -+ -+ switch (attr) { -+ case hwmon_temp_input: -+ if (channel == 0) -+ *val = soc_temp * 1000; -+ else if (channel == 1) -+ *val = board_temp * 1000; -+ else -+ *val = 0; -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+ -+static int mcu_hwmon_read(struct device *dev, enum hwmon_sensor_types type, -+ u32 attr, int channel, long *val) -+{ -+ -+ switch (type) { -+ case hwmon_chip: -+ return mcu_hwmon_chip_read(dev, attr, channel, val); -+ case hwmon_temp: -+ return mcu_hwmon_temp_read(dev, attr, channel, val); -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static const struct hwmon_ops mcu_ops = { -+ .is_visible = mcu_chip_is_visible, -+ .read = mcu_hwmon_read, -+ .read_string = NULL, -+ .write = NULL, -+}; -+ -+static int register_hwmon_temp_sensor(struct i2c_client *i2c, -+ struct mcu_ctx *ctx) -+{ -+ struct device *dev = &i2c->dev; -+ struct hwmon_channel_info *info; -+ struct device *hwmon_dev; -+ -+ mutex_init(&ctx->update_lock); -+ -+ ctx->i2c = i2c; -+ ctx->hwmon_update_interval = 1000; -+ -+ ctx->chip.ops = &mcu_ops; -+ ctx->chip.info = ctx->channel_info; -+ ctx->channel_info0 = HWMON_CHANNEL_INFO(chip, -+ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL); -+ ctx->channel_info1 = &ctx->temp_info; -+ -+ info = &ctx->temp_info; -+ info->type = hwmon_temp; -+ info->config = ctx->channel_config; -+ -+ ctx->channel_config0 = HWMON_T_INPUT; -+ ctx->channel_config1 = HWMON_T_INPUT; -+ hwmon_dev = devm_hwmon_device_register_with_info( -+ dev, -+ dev->driver->name, -+ ctx, -+ &ctx->chip, -+ NULL); -+ -+ if (IS_ERR(hwmon_dev)) -+ return PTR_ERR(hwmon_dev); -+ -+ return 0; -+} -+ -+static int sub_probe(struct i2c_client *i2c, -+ const struct mcu_features *features) -+{ -+ struct mcu_ctx *ctx; -+ int i, err; -+ -+ ctx = devm_kzalloc(i2c2dev(i2c), sizeof(*ctx), GFP_KERNEL); -+ if (ctx == NULL) -+ return -ENOMEM; -+ -+ for (i = 0; i < ARRAY_SIZE(mcu_attrs); ++i) { -+ err = device_create_file(i2c2dev(i2c), mcu_attrs + i); -+ if (err) -+ return err; -+ } -+ -+ ctx->features = features; -+ -+ assert(features->alert_status + 2 == features->alert_mask); -+ -+ if ((features->id & MANGO_BOARD_TYPE_MASK) == 0x80 ) { -+ err = register_hwmon_temp_sensor(i2c, ctx); -+ if (err) -+ dev_warn(i2c2dev(i2c), "mcu board id %u register hwmon failed\n", features->id); -+ } -+ -+ i2c_set_clientdata(i2c, ctx); -+ return 0; -+} -+ -+static int mcu_i2c_probe(struct i2c_client *i2c) -+{ -+ int id; -+ int err; -+ int i; -+ uint8_t regs3; -+ -+ /* get information from mcu through i2c */ -+ err = mcu_i2c_sreadf(i2c, "%u8%u8%u8", -+ MCU_REG_VERSION, regs, -+ MCU_REG_PWROFF_REASON1, regs + 1, -+ MCU_REG_PWROFF_REASON2, regs + 2); -+ if (err) -+ return err; -+ -+ dev_info(i2c2dev(i2c), "MCU: version 0x%x, reason 0x%x/0x%x\n", -+ regs0, regs1, regs2); -+ -+ id = mcu_i2c_read_byte(i2c, MCU_REG_BOARD_TYPE); -+ if (id < 0) -+ return id; -+ -+ for (i = 0; i < ARRAY_SIZE(mcu_list); ++i) { -+ if (mcu_listi.id == id) -+ return sub_probe(i2c, mcu_list + i); -+ } -+ -+ dev_warn(i2c2dev(i2c), "not registered mcu id %u\n", id); -+ return -ENODEV; -+} -+ -+static void mcu_i2c_remove(struct i2c_client *i2c) -+{ -+ return; -+} -+ -+static const struct of_device_id mcu_i2c_dt_table = { -+ { .compatible = "sophgo,sg20xx-mcu" }, -+ {}, -+}; -+ -+static const struct i2c_device_id mcu_i2c_id_table = { -+ { "sg20xx-mcu", 0 }, -+ {}, -+}; -+ -+static struct i2c_driver mcu_i2c_drv = { -+ .driver = { -+ .name = "sg20xx-mcu", -+ .of_match_table = mcu_i2c_dt_table, -+ }, -+ .probe = mcu_i2c_probe, -+ .remove = mcu_i2c_remove, -+ .id_table = mcu_i2c_id_table, -+}; -+ -+module_i2c_driver(mcu_i2c_drv); -+ -+MODULE_DESCRIPTION("MCU I2C driver for bm16xx soc platform"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Chao.Wei@bitmain.com>"); -diff --git a/drivers/soc/thead/Kconfig b/drivers/soc/thead/Kconfig -new file mode 100644 -index 000000000000..7948bbb61568 ---- /dev/null -+++ b/drivers/soc/thead/Kconfig -@@ -0,0 +1,10 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+menu "Thead SoC drivers" -+ -+config LIGHT_REBOOTMODE -+ bool "Thead light rebootmode support" -+ default y -+ help -+ This driver supports check rebootmode feature in Light FM platform -+ -+endmenu -diff --git a/drivers/soc/thead/Makefile b/drivers/soc/thead/Makefile -new file mode 100644 -index 000000000000..1af5bb20810e ---- /dev/null -+++ b/drivers/soc/thead/Makefile -@@ -0,0 +1,2 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+obj-$(CONFIG_LIGHT_REBOOTMODE) += light_event.o -diff --git a/drivers/soc/thead/light_event.c b/drivers/soc/thead/light_event.c -new file mode 100644 -index 000000000000..f8f6292bac6e ---- /dev/null -+++ b/drivers/soc/thead/light_event.c -@@ -0,0 +1,279 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+#include <linux/kernel.h> -+#include <linux/of.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+#include <linux/mfd/syscon.h> -+#include <linux/regmap.h> -+#include <linux/platform_device.h> -+#include <linux/firmware/thead/ipc.h> -+#include <linux/firmware/thead/light_event.h> -+ -+/* -+ * AON SRAM total size is 0x10000, reserve 0x100 for event. -+ * Notice: c902 *.ld also need resize. -+ * -------------- 0xff_ffef8000 -+ * | | -+ * | | -+ * | | -+ * | c902 | -+ * | | -+ * | | -+ * | | -+ * -------------- 0xff_fff07f00 -+ * | reserve | -+ * | | -+ * -------------- -+ */ -+#define LIGHT_AON_SRAM_LEN 0x10000 -+#define LIGHT_AON_SRAM_RESERV (LIGHT_AON_SRAM_LEN - 0x100) -+#define LIGHT_EVENT_OFFSET (LIGHT_AON_SRAM_RESERV + 0x10) -+#define LIGHT_EVENT_CHECK (LIGHT_EVENT_OFFSET + 0x4) -+ -+#define LIGHT_EVENT_MAGIC 0x5A5A5A5A -+ -+struct light_aon_msg_event_ctrl { -+ struct light_aon_rpc_msg_hdr hdr; -+ u32 reserve_offset; -+ u32 reserved5; -+} __packed __aligned(4); -+ -+struct light_event { -+ struct device *dev; -+ -+ struct light_aon_ipc *ipc_handle; -+ struct light_aon_msg_event_ctrl msg; -+ -+ struct regmap *aon_iram; -+ bool init; -+}; -+ -+struct light_event *light_event; -+ -+static void light_event_msg_hdr_fill(struct light_aon_rpc_msg_hdr *hdr, enum light_aon_misc_func func) -+{ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; -+ hdr->func = (uint8_t)func; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+} -+ -+static int light_event_aon_reservemem(struct light_event *event) -+{ -+ struct light_aon_ipc *ipc = event->ipc_handle; -+ int ret = 0; -+ -+ dev_dbg(event->dev, "aon reservemem...\n"); -+ -+ light_event_msg_hdr_fill(&event->msg.hdr, LIGHT_AON_MISC_FUNC_AON_RESERVE_MEM); -+ event->msg.reserve_offset = LIGHT_EVENT_OFFSET; -+ -+ ret = light_aon_call_rpc(ipc, &event->msg, true); -+ if (ret) -+ dev_err(event->dev, "failed to set aon reservemem\n"); -+ -+ return ret; -+} -+ -+int light_event_set_rebootmode(enum light_rebootmode_index mode) -+{ -+ int ret; -+ -+ if (!light_event || !light_event->init) -+ return -EINVAL; -+ -+ ret = regmap_write(light_event->aon_iram, LIGHT_EVENT_OFFSET, mode); -+ if (ret) { -+ dev_err(light_event->dev, "set rebootmode failed,ret:%d\n", ret); -+ return ret; -+ } -+ -+ dev_info(light_event->dev, "set rebootmode:0x%x\n", mode); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(light_event_set_rebootmode); -+ -+int light_event_get_rebootmode(enum light_rebootmode_index *mode) -+{ -+ int ret; -+ -+ if (!light_event || !light_event->init) -+ return -EINVAL; -+ -+ ret = regmap_read(light_event->aon_iram, LIGHT_EVENT_OFFSET, mode); -+ if (ret) { -+ dev_err(light_event->dev, "get rebootmode failed,ret:%d\n", ret); -+ return ret; -+ } -+ dev_dbg(light_event->dev, "%s get rebootmode:0x%x\n", __func__, *mode); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(light_event_get_rebootmode); -+ -+static int light_event_check_powerup(void) -+{ -+ enum light_rebootmode_index mode; -+ unsigned int val; -+ int ret; -+ -+ if (!light_event->init) -+ return -EINVAL; -+ -+ ret = regmap_read(light_event->aon_iram, LIGHT_EVENT_CHECK, &val); -+ if (ret) { -+ dev_err(light_event->dev, "get magicnum failed,ret:%d\n", ret); -+ return ret; -+ } -+ ret = regmap_read(light_event->aon_iram, LIGHT_EVENT_OFFSET, &mode); -+ if (ret) { -+ dev_err(light_event->dev, "get rebootmode failed,ret:%d\n", ret); -+ return ret; -+ } -+ dev_info(light_event->dev, "magicnum:0x%x mode:0x%x\n", val, mode); -+ -+ /* powerup means SRAM data is randam */ -+ if (val != LIGHT_EVENT_MAGIC && mode != LIGHT_EVENT_PMIC_ONKEY) -+ light_event_set_rebootmode(LIGHT_EVENT_PMIC_POWERUP); -+ -+ ret = regmap_write(light_event->aon_iram, LIGHT_EVENT_CHECK, LIGHT_EVENT_MAGIC); -+ if (ret) { -+ dev_err(light_event->dev, "set magicnum failed,ret:%d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static ssize_t rebootmode_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ enum light_rebootmode_index mode; -+ -+ if (kstrtouint(buf, 0, &mode) < 0) -+ return -EINVAL; -+ light_event_set_rebootmode(mode); -+ -+ return count; -+} -+ -+static ssize_t -+rebootmode_show(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ enum light_rebootmode_index mode; -+ -+ light_event_get_rebootmode(&mode); -+ -+ return sprintf(buf, "0x%x\n", mode); -+} -+static DEVICE_ATTR_RW(rebootmode); -+ -+static struct attribute *event_attrs = { -+ &dev_attr_rebootmode.attr, -+ NULL -+}; -+ATTRIBUTE_GROUPS(event); -+ -+static int light_event_open(struct inode *inode, struct file *f) -+{ -+ return 0; -+} -+ -+static int light_event_release(struct inode *inode, struct file *f) -+{ -+ return 0; -+} -+ -+static long light_event_ioctl(struct file *f, unsigned int ioctl, -+ unsigned long arg) -+{ -+ return 0; -+} -+ -+static const struct file_operations light_event_fops = { -+ .owner = THIS_MODULE, -+ .release = light_event_release, -+ .open = light_event_open, -+ .unlocked_ioctl = light_event_ioctl, -+}; -+ -+static struct miscdevice light_event_misc = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "light-event", -+ .fops = &light_event_fops, -+}; -+ -+static int light_event_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct light_event *thead; -+ int ret; -+ -+ thead = devm_kzalloc(&pdev->dev, sizeof(*thead), GFP_KERNEL); -+ if (!thead) -+ return -ENOMEM; -+ -+ ret = light_aon_get_handle(&(thead->ipc_handle)); -+ if (ret == -EPROBE_DEFER) -+ return ret; -+ -+ platform_set_drvdata(pdev, thead); -+ thead->dev = &pdev->dev; -+ -+ thead->aon_iram = syscon_regmap_lookup_by_phandle(np, "aon-iram-regmap"); -+ if (IS_ERR(thead->aon_iram)) -+ return PTR_ERR(thead->aon_iram); -+ -+ ret = misc_register(&light_event_misc); -+ if (ret < 0) -+ return ret; -+ -+ ret = light_event_aon_reservemem(thead); -+ if (ret) { -+ dev_err(dev, "set aon reservemem failed!\n"); -+ return -EPERM; -+ } -+ thead->init = true; -+ light_event = thead; -+ -+ ret = light_event_check_powerup(); -+ if (ret) { -+ dev_err(dev, "check powerup failed!\n"); -+ light_event = NULL; -+ return -EPERM; -+ } -+ dev_info(dev, "light-event driver init successfully\n"); -+ -+ return 0; -+} -+ -+static int light_event_remove(struct platform_device *pdev) -+{ -+ misc_deregister(&light_event_misc); -+ -+ return 0; -+} -+ -+static const struct of_device_id light_event_of_match = { -+ { .compatible = "thead,light-event" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, light_event_of_match); -+ -+static struct platform_driver light_event_driver = { -+ .probe = light_event_probe, -+ .remove = light_event_remove, -+ .driver = { -+ .name = "light-event", -+ .dev_groups = event_groups, -+ .of_match_table = light_event_of_match, -+ }, -+}; -+ -+module_platform_driver(light_event_driver); -+ -+MODULE_DESCRIPTION("light-event driver"); -+MODULE_LICENSE("GPL v2"); -diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig -index 98efcbb76c88..a2183b8e7772 100644 ---- a/drivers/usb/dwc3/Kconfig -+++ b/drivers/usb/dwc3/Kconfig -@@ -178,4 +178,24 @@ config USB_DWC3_OCTEON - Only the host mode is currently supported. - Say 'Y' or 'M' here if you have one such device. - -+config USB_DWC3_RTK -+ tristate "Realtek DWC3 Platform Driver" -+ depends on OF && ARCH_REALTEK -+ default USB_DWC3 -+ select USB_ROLE_SWITCH -+ help -+ RTK DHC RTD SoCs with DesignWare Core USB3 IP inside, -+ and IP Core configured for USB 2.0 and USB 3.0 in host -+ or dual-role mode. -+ Say 'Y' or 'M' if you have such device. -+ -+config USB_DWC3_THEAD -+ tristate "T-HEAD Platform" -+ depends on ARCH_THEAD || COMPILE_TEST -+ default USB_DWC3 -+ help -+ Support T-HEAD platform with DesignWare Core USB3 IP. -+ Only the host mode is currently supported. -+ Say 'Y' or 'M' here if you have one such device. -+ - endif -diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile -index fe1493d4bbe5..79afa5c03c10 100644 ---- a/drivers/usb/dwc3/Makefile -+++ b/drivers/usb/dwc3/Makefile -@@ -55,3 +55,5 @@ obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o - obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o - obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o - obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o -+obj-$(CONFIG_USB_DWC3_RTK) += dwc3-rtk.o -+obj-$(CONFIG_USB_DWC3_THEAD) += dwc3-thead.o -diff --git a/drivers/usb/dwc3/dwc3-thead.c b/drivers/usb/dwc3/dwc3-thead.c -new file mode 100644 -index 000000000000..987ac70a5afc ---- /dev/null -+++ b/drivers/usb/dwc3/dwc3-thead.c -@@ -0,0 +1,112 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * dwc3-thead.c - T-HEAD platform specific glue layer -+ * -+ * Inspired by dwc3-of-simple.c -+ * -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org> -+ * Copyright (c) 2018, The Linux Foundation. All rights reserved. -+ */ -+ -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/mfd/syscon.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/of_platform.h> -+#include <linux/platform_device.h> -+#include <linux/regmap.h> -+ -+#include "core.h" -+ -+#define USB_SSP_EN 0x34 -+#define REF_SSP_EN BIT(0) -+#define USB_SYS 0x3c -+#define COMMONONN BIT(0) -+ -+#define USB3_DRD_SWRST 0x14 -+#define USB3_DRD_PRST BIT(0) -+#define USB3_DRD_PHYRST BIT(1) -+#define USB3_DRD_VCCRST BIT(2) -+#define USB3_DRD_RSTMASK (USB3_DRD_PRST | USB3_DRD_PHYRST | USB3_DRD_VCCRST) -+ -+struct dwc3_thead { -+ void __iomem *base; -+ struct regmap *misc_sysreg; -+ struct regulator *vbus; -+}; -+ -+static void dwc3_thead_optimize_power(struct dwc3_thead *thead) -+{ -+ u32 val; -+ -+ /* config usb top within USB ctrl & PHY reset */ -+ regmap_update_bits(thead->misc_sysreg, USB3_DRD_SWRST, -+ USB3_DRD_RSTMASK, USB3_DRD_PRST); -+ -+ /* -+ * dwc reg also need to be configed to save power -+ * 1. set USB_SYSCOMMONONN -+ * 2. set DWC3_GCTLSOFITPSYNC(done by core.c) -+ * 3. set GUSB3PIPECTLSUSPENDEN (done by core.c) -+ */ -+ val = readl(thead->base + USB_SYS); -+ val |= COMMONONN; -+ writel(val, thead->base + USB_SYS); -+ val = readl(thead->base + USB_SSP_EN); -+ val |= REF_SSP_EN; -+ writel(val, thead->base + USB_SSP_EN); -+ -+ regmap_update_bits(thead->misc_sysreg, USB3_DRD_SWRST, -+ USB3_DRD_RSTMASK, USB3_DRD_RSTMASK); -+} -+ -+static int dwc3_thead_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct dwc3_thead *thead; -+ int ret; -+ -+ thead = devm_kzalloc(&pdev->dev, sizeof(*thead), GFP_KERNEL); -+ if (!thead) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, thead); -+ -+ ret = devm_regulator_get_enable_optional(dev, "vbus"); -+ if (ret < 0 && ret != -ENODEV) -+ return ret; -+ -+ thead->misc_sysreg = syscon_regmap_lookup_by_phandle(np, "thead,misc-sysreg"); -+ if (IS_ERR(thead->misc_sysreg)) -+ return PTR_ERR(thead->misc_sysreg); -+ -+ thead->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(thead->base)) -+ return PTR_ERR(thead->base); -+ -+ dwc3_thead_optimize_power(thead); -+ -+ return devm_of_platform_populate(dev); -+} -+ -+static const struct of_device_id dwc3_thead_of_match = { -+ { .compatible = "thead,th1520-usb" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, dwc3_thead_of_match); -+ -+static struct platform_driver dwc3_thead_driver = { -+ .probe = dwc3_thead_probe, -+ .driver = { -+ .name = "dwc3-thead", -+ .of_match_table = dwc3_thead_of_match, -+ }, -+}; -+module_platform_driver(dwc3_thead_driver); -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_DESCRIPTION("DesignWare DWC3 T-HEAD Glue Driver"); -+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); -diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index 751458959411..b26aac73333a 100644 ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -2044,6 +2044,20 @@ config STARFIVE_WATCHDOG - Say Y here to support the watchdog of StarFive JH7100 and JH7110 - SoC. This driver can also be built as a module if choose M. - -+config LIGHT_PMIC_WATCHDOG -+ tristate "THEAD Light pmic watchdog" -+ depends on THEAD_LIGHT_MBOX -+ select WATCHDOG_CORE -+ help -+ This is the driver for the hardware watchdog on Light Board. This watchdog -+ simply watches your kernel to make sure it doesn't freeze, and if -+ it does, it reboots your computer after a certain amount of time. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called acquirewdt. -+ -+ Most people will say N. -+ - # S390 Architecture - - config DIAG288_WATCHDOG -diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile -index 7eab9de311cb..5c36e33f8b6e 100644 ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -196,6 +196,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o - - # RISC-V Architecture - obj-$(CONFIG_STARFIVE_WATCHDOG) += starfive-wdt.o -+obj-$(CONFIG_LIGHT_PMIC_WATCHDOG) += light_wdt.o - - # S390 Architecture - obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o -diff --git a/drivers/watchdog/light_wdt.c b/drivers/watchdog/light_wdt.c -new file mode 100644 -index 000000000000..d5fa5f77cec1 ---- /dev/null -+++ b/drivers/watchdog/light_wdt.c -@@ -0,0 +1,376 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/regmap.h> -+#include <linux/device.h> -+#include <linux/watchdog.h> -+#include <linux/firmware/thead/ipc.h> -+#include <linux/firmware/thead/light_event.h> -+ -+#define DRV_NAME "light-wdt" -+ -+/* -+ * Watchdog selector to timeout in seconds. -+ * 0: WDT disabled; -+ * others: timeout = 2048 ms * 2^(TWDSCALE-1). -+ */ -+static const unsigned int wdt_timeout = {8, 16, 32,128}; -+#define LIGHT_TWDSCALE_DISABLE 0 -+#define LIGHT_TWDSCALE_MIN 1 -+#define LIGHT_TWDSCALE_MAX (ARRAY_SIZE(wdt_timeout) - 1) -+#define LIGHT_WDT_MIN_TIMEOUT wdt_timeoutLIGHT_TWDSCALE_MIN -+#define LIGHT_WDT_MAX_TIMEOUT wdt_timeoutLIGHT_TWDSCALE_MAX -+#define LIGHT_WDT_TIMEOUT wdt_timeout3 -+#define LIGHT_RESET_PROTECTION_MS 256 -+ -+struct light_aon_msg_wdg_ctrl { -+ struct light_aon_rpc_msg_hdr hdr; -+ u32 timeout; -+ u32 running_state; -+ u32 reserved4; -+}_packed __aligned(4); -+ -+struct light_wdt_device { -+ struct device *dev; -+ struct light_aon_ipc *ipc_handle; -+ struct light_aon_msg_wdg_ctrl msg; -+ unsigned int is_aon_wdt_ena; -+}; -+ -+struct light_wdt_device *light_power_off_wdt; -+ -+static unsigned int light_wdt_timeout_to_sel(unsigned secs) -+{ -+ unsigned int i; -+ -+ for (i = LIGHT_TWDSCALE_MIN; i <= LIGHT_TWDSCALE_MAX; i++) { -+ if (wdt_timeouti >= secs) -+ return i; -+ } -+ -+ return LIGHT_TWDSCALE_MAX; -+} -+ -+static void light_wdt_msg_hdr_fill(struct light_aon_rpc_msg_hdr *hdr, enum light_aon_misc_func func) -+{ -+ hdr->ver = LIGHT_AON_RPC_VERSION; -+ hdr->svc = (uint8_t)LIGHT_AON_RPC_SVC_MISC; -+ hdr->func = (uint8_t)func; -+ hdr->size = LIGHT_AON_RPC_MSG_NUM; -+} -+ -+static int light_wdt_is_running(struct light_wdt_device *wdt_dev) -+{ -+ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; -+ int ret; -+ -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_GET_STATE); -+ wdt_dev->msg.running_state = -1; -+ -+ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); -+ if (ret) -+ return ret; -+ -+ pr_debug("ret = %d, timeout = %d, running_state = %d\n", ret, wdt_dev->msg.timeout, -+ wdt_dev->msg.running_state); -+ -+ return wdt_dev->msg.running_state; -+} -+ -+static int light_wdt_update_timeout(struct light_wdt_device *wdt_dev, unsigned int timeout) -+{ -+ /* -+ * The watchdog triggers a reboot if a timeout value is already -+ * programmed because the timeout value combines two functions -+ * in one: indicating the counter limit and starting the watchdog. -+ * The watchdog must be disabled to be able to change the timeout -+ * value if the watchdog is already running. Then we can set the -+ * new timeout value which enables the watchdog again. -+ */ -+ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; -+ int ret; -+ -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_TIMEOUTSET); -+ wdt_dev->msg.timeout = timeout; -+ -+ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int light_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout) -+{ -+ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); -+ int ret = 0; -+ -+ /* -+ * There are two cases when a set_timeout() will be called: -+ * 1. The watchdog is off and someone wants to set the timeout for the -+ * further use. -+ * 2. The watchdog is already running and a new timeout value should be -+ * set. -+ * -+ * The watchdog can't store a timeout value not equal zero without -+ * enabling the watchdog, so the timeout must be buffered by the driver. -+ */ -+ if (watchdog_active(wdd)) -+ ret = light_wdt_update_timeout(wdt_dev, timeout); -+ else -+ wdd->timeout = wdt_timeoutlight_wdt_timeout_to_sel(timeout); -+ -+ return ret; -+} -+ -+static int light_wdt_start(struct watchdog_device *wdd) -+{ -+ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); -+ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; -+ int ret; -+ -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_START); -+ -+ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int light_wdt_stop(struct watchdog_device *wdd) -+{ -+ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); -+ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; -+ int ret; -+ -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_STOP); -+ -+ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int light_wdt_ping(struct watchdog_device *wdd) -+{ -+ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); -+ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; -+ int ret; -+ -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_PING); -+ -+ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int light_wdt_restart(struct watchdog_device *wdd, unsigned long action, void *data) -+{ -+ struct light_wdt_device *wdt_dev = watchdog_get_drvdata(wdd); -+ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; -+ int ret; -+ -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_RESTART); -+ -+ pr_debug("%s,%d: Inform aon to restart the whole system....\n", __func__, __LINE__); -+ -+ light_event_set_rebootmode(LIGHT_EVENT_SW_REBOOT); -+ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, false); -+ if (ret) -+ return ret; -+ pr_debug("%s,%d: Finish to inform aon to restart the whole system....\n", __func__, __LINE__); -+ -+ return 0; -+} -+ -+static const struct watchdog_info light_watchdog_info = { -+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, -+ .identity = "Light Watchdog", -+}; -+ -+ -+static const struct watchdog_ops light_watchdog_ops = { -+ .owner = THIS_MODULE, -+ .start = light_wdt_start, -+ .stop = light_wdt_stop, -+ .ping = light_wdt_ping, -+ .set_timeout = light_wdt_set_timeout, -+ .restart = light_wdt_restart, -+}; -+ -+static ssize_t aon_sys_wdt_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct light_wdt_device *wdt_dev = platform_get_drvdata(pdev); -+ return sprintf(buf,"%u\n",wdt_dev->is_aon_wdt_ena); -+} -+ -+static ssize_t aon_sys_wdt_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t size) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct light_wdt_device *wdt_dev = platform_get_drvdata(pdev); -+ struct light_aon_ipc *ipc; -+ int ret; -+ char *start = (char *)buf; -+ unsigned long val; -+ -+ ipc = wdt_dev->ipc_handle; -+ val = simple_strtoul(start, &start, 0); -+ wdt_dev->is_aon_wdt_ena = val; -+ if (val) -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_AON_WDT_ON); -+ else -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_AON_WDT_OFF); -+ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); -+ if (ret){ -+ pr_err("%s: err:%d \n",__func__,ret); -+ return -EINVAL; -+ } -+ return size; -+} -+ -+void light_pm_power_off(void) -+{ -+ struct light_wdt_device *wdt_dev = light_power_off_wdt; -+ struct light_aon_ipc *ipc = wdt_dev->ipc_handle; -+ int ret; -+ -+ pr_info("%s,%dpoweroff system...\n", __func__, __LINE__); -+ -+ light_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, LIGHT_AON_MISC_FUNC_WDG_POWER_OFF); -+ -+ ret = light_aon_call_rpc(ipc, &wdt_dev->msg, true); -+ -+ if (ret) -+ pr_err("failed to power off the system\n"); -+} -+ -+ -+static DEVICE_ATTR(aon_sys_wdt, 0644, aon_sys_wdt_show, aon_sys_wdt_store); -+ -+static struct attribute *aon_sys_wdt_sysfs_entries = { -+ &dev_attr_aon_sys_wdt.attr, -+ NULL -+}; -+static const struct attribute_group dev_attr_aon_sys_wdt_group = { -+ .attrs = aon_sys_wdt_sysfs_entries, -+}; -+ -+static int light_wdt_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct light_wdt_device *wdt_dev; -+ int ret; -+ struct watchdog_device *wdd; -+ -+ wdt_dev = devm_kzalloc(dev, sizeof(*wdt_dev), GFP_KERNEL); -+ if (!wdt_dev) -+ return -ENOMEM; -+ wdt_dev->is_aon_wdt_ena = 0; -+ -+ ret = light_aon_get_handle(&(wdt_dev->ipc_handle)); -+ if (ret == -EPROBE_DEFER) -+ return ret; -+ -+ wdd = devm_kzalloc(dev, sizeof(*wdd), GFP_KERNEL); -+ if (!wdd) -+ return -ENOMEM; -+ -+ wdd->info = &light_watchdog_info; -+ wdd->ops = &light_watchdog_ops; -+ wdd->min_timeout = LIGHT_WDT_MIN_TIMEOUT; -+ wdd->max_timeout = LIGHT_WDT_MAX_TIMEOUT; -+ wdd->min_hw_heartbeat_ms = LIGHT_RESET_PROTECTION_MS; -+ wdd->status = WATCHDOG_NOWAYOUT_INIT_STATUS; -+ -+ watchdog_set_restart_priority(wdd, 128); -+ watchdog_set_drvdata(wdd, wdt_dev); -+ -+ /* Set default timeout, maybe default value if the watchdog is running */ -+ wdd->timeout = LIGHT_WDT_TIMEOUT; -+ watchdog_init_timeout(wdd, 0, dev); -+ light_wdt_set_timeout(wdd, wdd->timeout); -+ -+ platform_set_drvdata(pdev, wdt_dev); -+ ret = light_wdt_is_running(wdt_dev); -+ if (ret < 0) { -+ pr_err("failed to get pmic wdt running state\n"); -+ return ret; -+ } -+ -+ if (ret) { -+ light_wdt_update_timeout(wdt_dev, wdd->timeout); -+ set_bit(WDOG_HW_RUNNING, &wdd->status); -+ } -+ -+ ret = devm_watchdog_register_device(dev, wdd); -+ if (ret) -+ return ret; -+ -+ pr_info("%s,%d register power off callback\n", __func__, __LINE__); -+ -+ pm_power_off = light_pm_power_off; -+ -+ light_power_off_wdt = wdt_dev; -+ -+ ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_aon_sys_wdt_group); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to create aon_sys_wdt sysfs.\n"); -+ return ret; -+ } -+ -+ pr_info("succeed to register light pmic watchdog\n"); -+ -+ return 0; -+} -+ -+static struct platform_driver light_wdt_driver = { -+ .driver = { -+ .name = DRV_NAME, -+ }, -+ .probe = light_wdt_probe, -+}; -+ -+static int __init light_wdt_init(void) -+{ -+ static struct platform_device *pdev; -+ int ret; -+ -+ pdev = platform_device_register_simple(DRV_NAME, -1, NULL, 0); -+ if (IS_ERR(pdev)) -+ return PTR_ERR(pdev); -+ -+ ret = platform_driver_register(&light_wdt_driver); -+ if (ret) { -+ platform_device_unregister(pdev); -+ return PTR_ERR(pdev); -+ } -+ -+ pr_info("Watchdog module: %s loaded\n", DRV_NAME); -+ -+ return 0; -+} -+device_initcall(light_wdt_init); -+ -+MODULE_AUTHOR("Wei.Liu <lw312886@linux.alibaba.com>"); -+MODULE_DESCRIPTION("PMIC Watchdog Driver for Light"); -+MODULE_LICENSE("GPL"); -diff --git a/include/dt-bindings/clock/light-dspsys.h b/include/dt-bindings/clock/light-dspsys.h -new file mode 100644 -index 000000000000..6473e12623c6 ---- /dev/null -+++ b/include/dt-bindings/clock/light-dspsys.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef _LIGHT_DSPSYS_H -+#define _LIGHT_DSPSYS_H -+ -+#define CLKGEN_DSP0_PCLK 0 -+#define CLKGEN_DSP0_CCLK 1 -+#define CLKGEN_DSP1_PCLK 2 -+#define CLKGEN_DSP1_CCLK 3 -+#define CLKGEN_X2X_X4_DSPSLV_DSP0_ACLK_M 4 -+#define CLKGEN_X2X_X4_DSPSLV_DSP1_ACLK_M 5 -+#define CLKGEN_AXI4_DSPSYS_SLV_ACLK 6 -+#define CLKGEN_AXI4_DSPSYS_ACLK 7 -+#define CLKGEN_IOPMP_DSP0_PCLK 8 -+#define CLKGEN_IOPMP_DSP1_PCLK 9 -+#define CLKGEN_AXI4_DSPSYS_SLV_PCLK 10 -+#define CLKGEN_AXI4_DSPSYS_PCLK 11 -+#define CLKGEN_X2X_DSP0_ACLK_S 12 -+#define CLKGEN_X2X_DSP2_ACLK_S 13 -+#define LIGHT_CLKGEN_DSPSYS_CLK_END 14 -+ -+#endif -diff --git a/include/dt-bindings/clock/light-fm-ap-clock.h b/include/dt-bindings/clock/light-fm-ap-clock.h -new file mode 100644 -index 000000000000..8bb23b690f98 ---- /dev/null -+++ b/include/dt-bindings/clock/light-fm-ap-clock.h -@@ -0,0 +1,513 @@ -+#ifndef _APSYS_CLKGEN_H -+#define _APSYS_CLKGEN_H -+ -+#define C910_CCLK_I0 0 -+#define AXI4_CPUSYS1_ACLK 1 -+#define CLKGEN_GPIO2_DBCLK 2 -+#define CLKGEN_MBOX0_PCLK 3 -+#define CLKGEN_GMAC0_CCLK 4 -+#define CLKGEN_SPI_PCLK 5 -+#define CLKGEN_CLK_OUT_1_CLK 6 -+#define PAD_RTC_CLK 7 -+#define CLKGEN_SPINLOCK_HCLK 8 -+#define CLKGEN_QSPI1_PCLK 9 -+#define CLKGEN_HDMI_ISCAN_CK_REF_CLK 10 -+#define CLKGEN_IOPMP_AON_PCLK 11 -+#define CLKGEN_ISP_RY_ACLK 12 -+#define CLKGEN_MIPIDSI0_SCANRXCLKESC 13 -+#define CLKGEN_EIP120SII_HCLK 14 -+#define CLKGEN_MIPI_CSI0_PIXCLK 15 -+#define CLKGEN_SRAM_AXI_ACLK_3 16 -+#define CLKGEN_PERISYS_AHB_HCLK 17 -+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK0_CLK 18 -+#define CLKGEN_QSPI0_SSI_CLK 19 -+#define CLKGEN_DW200_ACLK 20 -+#define CLKGEN_IOPMP_EIP120SIII_PCLK 21 -+#define VISYS_MIPI_CSI2_CFGCLK 22 -+#define CLKGEN_APB3_CPUSYS_HCLK 23 -+#define CLKGEN_PERISYS_APB1_HCLK 24 -+#define CLKGEN_GPU_CORE_CLK 25 -+#define CLKGEN_USB3_DRD_ACLK 26 -+#define CLKGEN_VISYS_ACLK 27 -+#define CLKGEN_USB3_DRD_CTRL_REF_CLK 28 -+#define CLKGEN_TEE_DMAC_ACLK 29 -+#define CLKGEN_AUDIO_SUBSYS_ACLK_CP2AP 30 -+#define CLKGEN_SRAM_AXI_ACLK_2 31 -+#define CLKGEN_IOPMP_VOSYS_GPU_PCLK 32 -+#define CLKGEN_CFG2TEE_X2H_ACLK 33 -+#define CLKGEN_SRAM_AXI_ACLK_1 34 -+#define MISC_SDIO0_OSC_CLK 35 -+#define CLKGEN_SDIO0_ACLK 36 -+#define CLKGEN_MIPI_DSI1_CFGCLK 37 -+#define APB3_CPUSYS_PCLK 38 -+#define CLKGEN_TEE_DMAC_HCLK 39 -+#define VOSYS_DPU0_PIXELCLK 40 -+#define CLKGEN_CPU2CFG_X2H_MHCLK 41 -+#define CLKGEN_VPSYS_ACLK 42 -+#define CLKGEN_MIPIDSI1_SCANRXCLKESC 43 -+#define CLKGEN_MISC2VP_X2X_ACLK_S 44 -+#define CLKGEN_MIPI_CSI_SCANBYTECLK 45 -+#define CLKGEN_APB3_TEESYS_HCLK 46 -+#define VENC_CCLK 47 -+#define VPSYS_VDEC_CCLK 48 -+#define CLKGEN_MIPI_CSI0_CFG_CLK 49 -+#define CLKGEN_MISCSYS_BUS_CLK 50 -+#define CLKGEN_DPU_HCLK 51 -+#define CLKGEN_UART1_SCLK 52 -+#define GMAC_PLL_FOUTPOSTDIV 53 -+#define MISC_BUS_CLK 54 -+#define CLKGEN_USB3_DRD_SPDCLK 55 -+#define CLKGEN_MIPI_CSI2_CFG_CLK 56 -+#define CLKGEN_TOP_AXI4S_ACLK 57 -+#define CLKGEN_IOPMP_EIP120SII_ACLK 58 -+#define CORE_CLK 59 -+#define CLKGEN_VPSYS_FCE_ACLK 60 -+#define CLKGEN_I2C3_PCLK 61 -+#define DPU1_PLL_DIV_CLK 62 -+#define CLKGEN_USB3_DRD_PHY_REF_CLK 63 -+#define CLKGEN_AON2CPU_A2X_ACLK 64 -+#define CLKGEN_QSPI1_SSI_CLK 65 -+#define CLKGEN_DPU_CCLK 66 -+#define VISYS_MASTER_BUS_ACLK 67 -+#define CLKGEN_PERI_I2S_SRC_CLK_0 68 -+#define VOSYS_ACLK_M 69 -+#define TEESYS_I0_HCLK 70 -+#define CLKGEN_MIPI_DSI1_REFCLK 71 -+#define CLKGEN_MIPI_DSI0_PCLK 72 -+#define CLKGEN_VOSYS_ACLK_S 73 -+#define CLKGEN_CPU2VP_X2P_PCLK 74 -+#define CLKGEN_X2X_CPUSYS_ACLK_S 75 -+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK1_CLK 76 -+#define CLKGEN_IOPMP_VOSYS_DPU1_PCLK 77 -+#define CLKGEN_MISC2VP_X2X_ACLK_M 78 -+#define CLKGEN_WDT0_PCLK 79 -+#define VOSYS_MIPIDSI0_SCANTXCLKESC 80 -+#define VISYS_MIPI_CSI1_CFGCLK 81 -+#define AHB2_CPUSYS_HCLK 82 -+#define CLKGEN_SDIO1_HCLK 83 -+#define CLKGEN_SDIO0_HCLK 84 -+#define CLKGEN_CLK_OUT_3_CLK 85 -+#define CLKGEN_GMAC_AXI_ACLK 86 -+#define GMAC_CCLK 87 -+#define CLKGEN_VIPRE_PCLK 88 -+#define CLKGEN_HDMI_ISCAN_TX_CK_OUT2_CLK 89 -+#define CLKGEN_MIPIDSI1_SCANTXCLKESC 90 -+#define CLKGEN_VISYS_SLAVE_HCLK 91 -+#define VOSYS_HDMI_ISCAN_TX_CK_OUT1_CLK 92 -+#define CLKGEN_X2X_CPUSYS_ACLK_M 93 -+#define CLKGEN_CPU2CFG_X2X_ACLK_S 94 -+#define C910_OSC_CLK 95 -+#define CLKGEN_X2H_DPU1_ACLK 96 -+#define CLKGEN_I2C4_PCLK 97 -+#define CLKGEN_GMAC0_ACLK 98 -+#define MISC_USB3_PHY_REF_CLK 99 -+#define VOSYS_MIPIDSI0_CFG_CLK 100 -+#define CLKGEN_VPSYS_VDEC_CCLK 101 -+#define VOSYS_MIPIDSI1_CFG_CLK 102 -+#define CLKGEN_I2S_PCLK 103 -+#define CLKGEN_DMAC_CPUSYS_ACLK 104 -+#define VISYS_DW200_CLK_DWE 105 -+#define CLKGEN_OCRAM_HCLK 106 -+#define CLKGEN_EFUSE_PCLK 107 -+#define CLKGEN_X2H_DPU_ACLK 108 -+#define CLKGEN_IOPMP_SDIO0_ACLK 109 -+#define VOSYS_DPU1_PIXELCLK 110 -+#define CPU_PLL1_FOUT4 111 -+#define CLKGEN_GPIO2_PCLK 112 -+#define CLKGEN_GMAC1_CCLK 113 -+#define CPU_PLL1_FOUTPOSTDIV 114 -+#define VOSYS_HDMI_ISCAN_40M_CLK 115 -+#define CLKGEN_VOSYS_X2X_ACLK_S 116 -+#define CLKGEN_PERISYS_APB2_HCLK 117 -+#define VOSYS_OSC_CLK_MUX_I2S_CLK_OCCBUF 118 -+#define CLKGEN_HDMI_CEC_CLK 119 -+#define CLKGEN_X2P_X4_VOSYS_PCLK 120 -+#define CLKGEN_VOSYS_ACLK_M 121 -+#define CLKGEN_EMMC_SDIO_REF_CLK 122 -+#define CLKGEN_IOPMP_EMMC_ACLK 123 -+#define VIDEO_PLL_FOUTVCO 124 -+#define CLKGEN_HDMI_ISCAN_CKO_WORD_CLK 125 -+#define CLKGEN_IOPMP_VOSYS_DPU_PCLK 126 -+#define CLKGEN_AXI4_VISYS3_ACLK 127 -+#define CLKGEN_VISYS_SYSREG_PCLK 128 -+#define CLKGEN_MIPIDSI0_SCANTXCLKESC 129 -+#define CLKGEN_HDMI_ISCAN_TX_CK_OUT1_CLK 130 -+#define CLKGEN_IOPMP_EIP120SIII_ACLK 131 -+#define CLKGEN_EIP120SII_ACLK 132 -+#define CLKGEN_MBOX2_PCLK 133 -+#define CLKGEN_AXI4_VISYS1_ACLK 134 -+#define CLKGEN_UART1_PCLK 135 -+#define CLK_OUT_3 136 -+#define CLKGEN_UART5_SCLK 137 -+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK2_CLK 138 -+#define CLKGEN_MBOX3_PCLK 139 -+#define QSPI1_SSI_CLK 140 -+#define CLKGEN_I2C1_PCLK 141 -+#define CLKGEN_HDMI_I2S_CLK 142 -+#define CLKGEN_AXI4_CPUSYS2_PCLK 143 -+#define CLKGEN_CFG2TEE_X2H_MHCLK 144 -+#define CLKGEN_C910_CPU_CLK 145 -+#define VOSYS_HDMI_ISCAN_TX_CK_OUT2_CLK 146 -+#define CLKGEN_HDMI_PCLK 147 -+#define CLKGEN_IOPMP_EIP120SII_PCLK 148 -+#define CLKGEN_MISCSYS_AXI_PCLK 149 -+#define CLKGEN_EIP120SI_ACLK 150 -+#define TEESYS_I1_HCLK 151 -+#define PERISYS_APB_PCLK 152 -+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK0_DIV2_CLK 153 -+#define CLKGEN_TIMER0_CCLK 154 -+#define CLKGEN_IOPMP_USB3_ACLK 155 -+#define CLKGEN_UART2_PCLK 156 -+#define CLK_OUT_4 157 -+#define AXI4_CPUSYS2_ACLK 158 -+#define CLKGEN_AUDIO_SUBSYS_ACLK_AP2CP 159 -+#define CLKGEN_I2C3_IC_CLK 160 -+#define CLKGEN_IOPMP_GPU_ACLK 161 -+#define CLKGEN_TIMER1_CCLK 162 -+#define VOSYS_I2S_CLK 163 -+#define CLKGEN_I2C5_IC_CLK 164 -+#define VOSYS_OSC_CLK_MUX_I2S_CLK 165 -+#define CLKGEN_DDR_SUBSYS_ACLK_0 166 -+#define CLKGEN_TIMER1_PCLK 167 -+#define CLKGEN_I2C1_IC_CLK 168 -+#define CLKGEN_I2S_SRC_CLK 169 -+#define VISYS_DW200_CLK_VSE 170 -+#define CLKGEN_MIPIDSI1_PIXCLK 171 -+#define VOSYS_RTC_CLK 172 -+#define CLK_OUT_1 173 -+#define CLKGEN_PERISYS_APB4_HCLK 174 -+#define MISC_USB3_CTRL_REF_CLK 175 -+#define CLKGEN_TEE_SYSREG_PCLK 176 -+#define CLKGEN_MISCSYS_AXI_ACLK 177 -+#define CLKGEN_MIPIDSI1_SCANCLK 178 -+#define CLKGEN_GPIO3_DBCLK 179 -+#define CLKGEN_HDMI_ISCAN_40M_CLK 180 -+#define CLKGEN_PERI2PERI1_APB_HCLK 181 -+#define CLKGEN_GMAC0_HCLK 182 -+#define CLKGEN_DDR_SUBSYS_PCLK 183 -+#define VOSYS_PCLK 184 -+#define CLKGEN_MIPIDSI1_SCANBYTECLK 185 -+#define CLKGEN_VPSYS_G2D_ACLK 186 -+#define CLKGEN_EIP150B_HCLK 187 -+#define CLKGEN_UART4_SCLK 188 -+#define DPU1_PLL_TEST_CLK 189 -+#define CLKGEN_VOSYS_X2X_ACLK_M 190 -+#define CLKGEN_IOPMP_EIP120SI_ACLK 191 -+#define CLKGEN_CLK_OUT_4_CLK 192 -+#define CLKGEN_GPIO0_FPCLK 193 -+#define PAD_OSC_CLK 194 -+#define CLKGEN_C910_BUS_CLK_NO_ICG 195 -+#define CLKGEN_TIMER0_PCLK 196 -+#define CLKGEN_AHB2_CPUSYS_HCLK 197 -+#define EMMC_SDIO_REF_CLK 198 -+#define CLKGEN_IOPMP_CHIP_DBG_PCLK 199 -+#define CLKGEN_BMU_C910_PCLK 200 -+#define CLKGEN_IOPMP_DPU1_ACLK 201 -+#define CLKGEN_PADCTRL0_APSYS_PCLK 202 -+#define MISC_SDIO1_OSC_CLK 203 -+#define CLKGEN_C910_OSC_CLK 204 -+#define VISYS_ISP_RY_CCLK 205 -+#define CLKGEN_VPSYS_PCLK 206 -+#define VISYS_MIPI_CSI0_PIXELCLK 207 -+#define NPU_CCLK 208 -+#define CLKGEN_AXI4_TEESYS_ACLK 209 -+#define PERI2SYS_APB_PCLK 210 -+#define CLKGEN_IOPMP_GMAC0_PCLK 211 -+#define CLKGEN_VPSYS_G2D_PCLK 212 -+#define CLKGEN_EMMC_ACLK 213 -+#define CLKGEN_UART3_SCLK 214 -+#define AONSYS_BUS_CLK 215 -+#define DPU0_PLL_FOUT4 216 -+#define VOSYS_MIPIDSI1_SCANCLK 217 -+#define CLKGEN_UART4_PCLK 218 -+#define CLKGEN_HDMI_ISCAN_SCL 219 -+#define CLKGEN_MIPI_CSI1_PIXCLK 220 -+#define CLKGEN_APSYS_CLKGEN_PCLK 221 -+#define CLKGEN_GPU_TIMER_REFCLK 222 -+#define GMAC_PLL_FOUT1PH0 223 -+#define VOSYS_MIPIDSI1_SCANBYTECLK 224 -+#define CLKGEN_GPIO3_FPCLK 225 -+#define CLKGEN_SDIO1_OSC_CLK 226 -+#define CLKGEN_GPIO3_PCLK 227 -+#define CLKGEN_VPSYS_AXI_ACLK 228 -+#define CLKGEN_HDMI_ISCAN_TX_CK_20B_CLK 229 -+#define CLKGEN_VOSYSREG_PCLK 230 -+#define VIDEO_PLL_TEST_CLK 231 -+#define CLKGEN_MBOX1_PCLK 232 -+#define CLKGEN_I2C2_IC_CLK 233 -+#define VOSYS_MIPIDSI0_PLL_SCANCLK 234 -+#define VOSYS_MIPIDSI1_SCANTXCLKESC 235 -+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK1_DIV2_CLK 236 -+#define CLKGEN_UART2_SCLK 237 -+#define MISC_TEESYS_PCLK 238 -+#define AUDIO_PLL_TEST_CLK 239 -+#define CLKGEN_DPU_PIXELCLK1 240 -+#define CLKGEN_IOPMP_TEEDMAC_PCLK 241 -+#define CLKGEN_TOP_APB_SX_PCLK 242 -+#define CLKGEN_I2C4_IC_CLK 243 -+#define GMAC_PLL_TEST_CLK 244 -+#define CLKGEN_HDMI_JTAG_TCLK 245 -+#define VISYS_MIPI_CSI0_CFGCLK 246 -+#define CLKGEN_CPU2AON_X2H_ACLK 247 -+#define VOSYS_HDMI_ISCAN_TX_CK_OUT0_CLK 248 -+#define QSPI_SSI_CLK 249 -+#define VOSYS_DPU_CCLK 250 -+#define CLKGEN_CPU2VI_X2H_MHCLK 251 -+#define CLKGEN_MIPI_DSI0_REFCLK 252 -+#define CLKGEN_DSPSYS_HCLK 253 -+#define CLKGEN_IOPMP_AUD_PCLK 254 -+#define CLKGEN_PERI2PERI1_APB_PCLK 255 -+#define CFG_AXI_ACLK 256 -+#define VPSYS_FCE_CCLK 257 -+#define CLKGEN_HDMI_ISCAN_CLK 258 -+#define CPU_PLL0_TEST_CLK 259 -+#define CLKGEN_CPU2PERI_X2H_MHCLK 260 -+#define VISYS_ACLK_M 261 -+#define VOSYS_HDMI_JTAG_TCLK 262 -+#define CLKGEN_IOPMP_AUD_ACLK 263 -+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK1_DIV2_CLK 264 -+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK1_CLK 265 -+#define VOSYS_MIPIDSI0_REFCLK 266 -+#define CLKGEN_VISYS_ACLK_M 267 -+#define VOSYS_MIPIDSI0_SCANRXCLKESC 268 -+#define CLKGEN_SDIO1_ACLK 269 -+#define CFG_APB_PCLK 270 -+#define CLKGEN_PADCTRL1_APSYS_PCLK 271 -+#define VOSYS_MIPIDSI0_SCANCLK 272 -+#define CLKGEN_I2C0_IC_CLK 273 -+#define CLKGEN_VPSYS_APB_PCLK 274 -+#define CLKGEN_VPSYS_VENC_CCLK 275 -+#define CLKGEN_AXI4_CFG_BUS_ACLK 276 -+#define CLKGEN_MIPIDSI0_SCANBYTECLK 277 -+#define GPIO3_DBCLK 278 -+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK0_CLK 279 -+#define CLKGEN_UART5_PCLK 280 -+#define DPU0_PLL_FOUTPOSTDIV_ICG 281 -+#define CPU_PLL0_FOUT4 282 -+#define CLKGEN_GPIO2_FPCLK 283 -+#define CLKGEN_DPU_ACLK 284 -+#define CLKGEN_AXI4_CPUSYS2_ACLK 285 -+#define CLKGEN_DSPSYS_PCLK 286 -+#define TEE_PLL_FOUTPOSTDIV 287 -+#define TIMER_CCLK 288 -+#define VOSYS_MIPIDSI1_PLL_SCANCLK 289 -+#define CLKGEN_GMAC_AXI_PCLK 290 -+#define CLKGEN_USB3_DRD_PCLK 291 -+#define CLKGEN_AXI4_CPUSYS1_PCLK 292 -+#define VOSYS_ACLK 293 -+#define CLKGEN_IOPMP_EIP120SI_PCLK 294 -+#define VOSYS_HDMI_ISCAN_TMDSCLKIN_CLK 295 -+#define VOSYS_HDMI_ISCAN_CKO_WORD_CLK 296 -+#define CLKGEN_NPUSYS_AXI_ACLK 297 -+#define CLKGEN_IOPMP_SDIO0_PCLK 298 -+#define CLKGEN_DW200_HCLK 299 -+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK2_CLK 300 -+#define CLKGEN_UART0_PCLK 301 -+#define CLKGEN_CLK_OUT_2_CLK 302 -+#define CLKGEN_GPIO0_PCLK 303 -+#define CLKGEN_EMMC_OSC_CLK 304 -+#define VPSYS_APB_PCLK 305 -+#define CLKGEN_HDMI_PIXCLK 306 -+#define CLKGEN_IOPMP_TEEDMAC_ACLK 307 -+#define AUDIO_PLL_FOUT4 308 -+#define CLKGEN_MIPI_CSI2_PCLK 309 -+#define CLKGEN_MIPI_DSI1_PCLK 310 -+#define CLKGEN_MIPI_DSI0_CFGCLK 311 -+#define VISYS_ISP0_CLK 312 -+#define VISYS_ISP1_CLK 313 -+#define MISC_EMMC_OSC_CLK 314 -+#define DPU0_PLL_FOUTPOSTDIV 315 -+#define VISYS_AHB_HCLK 316 -+#define CLKGEN_IOPMP_SDIO1_ACLK 317 -+#define CLKGEN_EMMC_HCLK 318 -+#define I2S_CLK 319 -+#define CLKGEN_CPU2PERI_X2H_ACLK 320 -+#define VPSYS_AXI_ACLK 321 -+#define CLKGEN_IOPMP_SDIO1_PCLK 322 -+#define CLKGEN_EIP120SIII_HCLK 323 -+#define CLKGEN_BMU_C910_ACLK 324 -+#define CLKGEN_IOPMP_DMAC_CPUSYS_PCLK 325 -+#define GPIO2_DBCLK 326 -+#define CHIP_DBG_CCLK 327 -+#define CLKGEN_MISCSYS_TEE_CCLK 328 -+#define CLKGEN_I2C5_PCLK 329 -+#define CLKGEN_X2H_CPUSYS_MHCLK 330 -+#define CLKGEN_PWM_CCLK 331 -+#define DPU0_PLL_TEST_CLK 332 -+#define CLKGEN_VISYS_PCLK 333 -+#define MISC_TEESYS_HCLK 334 -+#define SPI_SSI_CLK 335 -+#define CLKGEN_PWM_PCLK 336 -+#define VOSYS_MIPIDSI1_SCANRXCLKESC 337 -+#define QSPI0_SSI_CLK 338 -+#define CLKGEN_HDMI_ISCAN_TMDSCLKIN_CLK 339 -+#define CLKGEN_SPI_SSI_CLK 340 -+#define VIDEO_PLL_FOUT4 341 -+#define CLKGEN_IOPMP_GMAC0_ACLK 342 -+#define CLKGEN_VIPRE_ACLK 343 -+#define MISC_OSC_CLK_DIV24 344 -+#define CLKGEN_ISP_VENC_SHAKE_PCLK 345 -+#define CLKGEN_HDMI_ISCAN_TX_CK_OUT0_CLK 346 -+#define CLKGEN_VPSYS_G2D_CCLK 347 -+#define CLKGEN_CPU2CFG_X2X_ACLK_M 348 -+#define CLKGEN_GMAC1_PCLK 349 -+#define CLKGEN_MIPIDSI0_PLL_SCANCLK 350 -+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK0_DIV2_CLK 351 -+#define TEE_PLL_FOUT4 352 -+#define PERISYS_AHB_HCLK 353 -+#define VIDEO_PLL_FOUT1PH0 354 -+#define CLKGEN_MIPIDSI0_PIXCLK 355 -+#define CLKGEN_PERI_I2S_SRC_CLK_1 356 -+#define CLKGEN_MIPI_CSI0_PCLK 357 -+#define CLKGEN_DDR_SUBSYS_ACLK_1 358 -+#define CLKGEN_GMAC0_PCLK 359 -+#define CLK_OUT_2 360 -+#define CLKGEN_EIP120SIII_ACLK 361 -+#define AONSYS_HCLK 362 -+#define CLKGEN_ISP0_CLK 363 -+#define CLKGEN_C910_BROM_HCLK 364 -+#define DPU1_PLL_FOUT4 365 -+#define PERI_I2S_SRC_CLK 366 -+#define CPU_PLL1_TEST_CLK 367 -+#define CLKGEN_DDR_SUBSYS_ACLK_2 368 -+#define CLKGEN_MIPIDSI0_SCANCLK 369 -+#define I2C_IC_CLK 370 -+#define CLKGEN_DPU_PIXELCLK0 371 -+#define CLKGEN_GPIO1_DBCLK 372 -+#define CLKGEN_C910_TOP_DS_PCLK 373 -+#define CLKGEN_DSPSYS_ACLK_M 374 -+#define CLKGEN_AON2CPU_A2X_HCLK 375 -+#define VOSYS_HDMI_ISCAN_CK_REF_CLK 376 -+#define CLKGEN_IOPMP_EMMC_PCLK 377 -+#define NPU_CORE_CLK 378 -+#define CLKGEN_IOPMP_USB3_PCLK 379 -+#define VPSYS_PCLK 380 -+#define VIDEO_PLL_FOUTPOSTDIV 381 -+#define CLKGEN_CPU2VP_X2P_ACLK 382 -+#define CLKGEN_APB_CPU2CFG_HCLK 383 -+#define VOSYS_OSC_CLK_MUX_CEC_CLK_OCCBUF 384 -+#define CLKGEN_GPIO1_PCLK 385 -+#define CLKGEN_APSYS_SYSREG_PCLK 386 -+#define CLKGEN_VISYS_HCLK 387 -+#define CLKGEN_MIPI_CSI1_PCLK 388 -+#define CLKGEN_AHB2_TEESYS_HCLK 389 -+#define CLKGEN_DDR_SUBSYS_ACLK_4 390 -+#define SYS_PLL_TEST_CLK 391 -+#define VISYS_MIPI_CSI_SCANCLK 392 -+#define CPU_PLL0_FOUTPOSTDIV 393 -+#define CLKGEN_UART3_PCLK 394 -+#define CLKGEN_X2H_CPUSYS_ACLK 395 -+#define CLKGEN_MIPI_CSI1_CFG_CLK 396 -+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK2_DIV2_CLK 397 -+#define CLKGEN_MISCSYS_APB_HCLK 398 -+#define CLKGEN_CPU2CFG_X2H_ACLK 399 -+#define CLKGEN_MIPI_CSI2_FPCLK 400 -+#define CLKGEN_ISP_RY_CCLK 401 -+#define CLKGEN_X2P_VOSYS_ACLK 402 -+#define CLKGEN_VIPRE_PIXELCLK 403 -+#define VOSYS_GPU_TIMER_REFCLK 404 -+#define VOSYS_OSC_CLK_MUX_CEC_CLK 405 -+#define CLKGEN_APSYS_RSTGEN_PCLK 406 -+#define VOSYS_HDMI_ISCAN_SCL 407 -+#define CLKGEN_ISP_RY_HCLK 408 -+#define VOSYS_OSC_CLK 409 -+#define VISYS_PCLK 410 -+#define CLKGEN_AXI4_VO_ACLK 411 -+#define CLKGEN_MIPIDSI1_PLL_SCANCLK 412 -+#define GPIO1_DBCLK 413 -+#define CLKGEN_AXI4_VISYS2_ACLK 414 -+#define CLKGEN_EIP120SI_HCLK 415 -+#define CLKGEN_IOPMP_CHIP_DBG_ACLK 416 -+#define VOSYS_HDMI_ISCAN_TX_CK_20B_CLK 417 -+#define VOSYS_MIPIDSI1_REFCLK 418 -+#define CLKGEN_CHIP_DBG_ACLK 419 -+#define VOSYS_CFG_ACLK 420 -+#define CLKGEN_VOSYS_AXI_ACLK 421 -+#define CPU_BUS_DFTCLK 422 -+#define VOSYS_HDMI_ISCAN_CLK 423 -+#define VISYS_SLAVE_BUS_HCLK 424 -+#define CLKGEN_VPSYS_VDEC_PCLK 425 -+#define GMAC_PLL_FOUT4 426 -+#define CLKGEN_QSPI0_PCLK 427 -+#define CLKGEN_ISP1_CLK 428 -+#define CLKGEN_MIPI_CSI0_FPCLK 429 -+#define CLKGEN_ISP0_ACLK 430 -+#define CLKGEN_CPU2VI_X2H_ACLK 431 -+#define C910_CCLK 432 -+#define CLKGEN_DW200_CLK_VSE 433 -+#define CLKGEN_AXI4_CPUSYS1_ACLK 434 -+#define CLKGEN_GPU_CFG_ACLK 435 -+#define CLKGEN_GPIO1_FPCLK 436 -+#define CLKGEN_SRAM_AXI_ACLK_0 437 -+#define CLKGEN_I2C2_PCLK 438 -+#define CLKGEN_IOPMP_GMAC1_PCLK 439 -+#define CLKGEN_ISP0_S_HCLK 440 -+#define GPIO0_DBCLK 441 -+#define CLKGEN_AXI4_VO_CFG_ACLK 442 -+#define CLKGEN_NPU_CORE_CLK 443 -+#define DPU0_PLL_DIV_CLK 444 -+#define VOSYS_MIPIDSI0_SCANBYTECLK 445 -+#define CLKGEN_CHIP_DBG_CCLK 446 -+#define CLKGEN_DMAC_CPUSYS_HCLK 447 -+#define CLKGEN_IOPMP_DPU_ACLK 448 -+#define CLKGEN_DDR_SUBSYS_ACLK_3 449 -+#define CLK_100M 450 -+#define CLKGEN_DSMART_PCLK 451 -+#define CLKGEN_DW200_CLK_DWE 452 -+#define VPSYS_G2D_CCLK 453 -+#define CLKGEN_WDT1_PCLK 454 -+#define DPU1_PLL_FOUTPOSTDIV 455 -+#define CLKGEN_IOPMP_GMAC1_ACLK 456 -+#define CLKGEN_VPSYS_FCE_PCLK 457 -+#define CLKGEN_MIPI_CSI_SCANCLK 458 -+#define CLKGEN_MIPI_CSI2_PIXCLK 459 -+#define CLKGEN_I2C0_PCLK 460 -+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK2_DIV2_CLK 461 -+#define CLKGEN_HDMI_SFR_CLK 462 -+#define TEE_PLL_TEST_CLK 463 -+#define CLKGEN_IOPMP_DMAC_CPUSYS_ACLK 464 -+#define CLKGEN_ISP_PIXELCLK 465 -+#define CLKGEN_MIPI_CSI1_FPCLK 466 -+#define SYS_PLL_FOUT4 467 -+#define CLKGEN_AXI4_VO_PCLK 468 -+#define CLKGEN_UART0_SCLK 469 -+#define CLKGEN_CPU2AON_X2H_MHCLK 470 -+#define VISYS_MIPI_CSI_SCANBYTECLK 471 -+#define UART_SCLK 472 -+#define CLKGEN_IOPMP_AON_ACLK 473 -+#define CLKGEN_VPSYS_VDEC_ACLK 474 -+#define CLKGEN_GMAC1_HCLK 475 -+#define CLKGEN_ISP_VENC_SHAKE_ACLK 476 -+#define TEESYS_HCLK 477 -+#define PWM_CCLK 478 -+#define CLKGEN_GPIO0_DBCLK 479 -+#define CLKGEN_SDIO0_OSC_CLK 480 -+#define CLKGEN_GMAC1_ACLK 481 -+#define VPSYS_ACLK 482 -+ -+#define AHB2_CPUSYS_HCLK_OUT_DIV 483 -+#define APB3_CPUSYS_PCLK_DIV 484 -+#define CFG_AXI_ACLK_OUT_DIV 485 -+#define PERISYS_AHB_HCLK_OUT_DIV 486 -+#define CLK_OUT_1_OUT_DIV 487 -+#define CLK_OUT_2_OUT_DIV 488 -+#define CLK_OUT_3_OUT_DIV 489 -+#define CLK_OUT_4_OUT_DIV 490 -+#define NPU_CCLK_OUT_DIV 491 -+#define CFG_APB_PCLK_OUT_DIV 492 -+#define CPU_PLL0_BYPASS 493 -+#define CPU_PLL1_BYPASS 494 -+#define GMAC_PLL_BYPASS 495 -+#define VIDEO_PLL_BYPASS 496 -+#define TEE_PLL_BYPASS 497 -+#define DPU0_PLL_BYPASS 498 -+#define DPU1_PLL_BYPASS 499 -+ -+#define CLK_DUMMY 500 -+#define OSC_32K 501 -+#define OSC_24M 502 -+#define RC_24M 503 -+ -+#define CLK_END 504 -+ -+#endif -diff --git a/include/dt-bindings/clock/light-mpw-clock.h b/include/dt-bindings/clock/light-mpw-clock.h -new file mode 100644 -index 000000000000..46c2a052a9d2 ---- /dev/null -+++ b/include/dt-bindings/clock/light-mpw-clock.h -@@ -0,0 +1,222 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef __DT_BINDINGS_CLOCK_LIGHT_H -+#define __DT_BINDINGS_CLOCK_LIGHT_H -+ -+#define LIGHT_CLK_DUMMY 0 -+#define LIGHT_CLK_32K 1 -+#define LIGHT_CLK_24M 2 -+#define LIGHT_RC_24M 3 -+ -+#define LIGHT_VIDEO_PLL_FOUTVCO 4 -+#define LIGHT_VIDEO_PLL_FOUTPOSTDIV 5 -+#define LIGHT_VIDEO_PLL_FOUT4 6 -+#define LIGHT_VIDEO_PLL_BYPASS 7 -+ -+#define LIGHT_GMAC_PLL_FOUTVCO 8 -+#define LIGHT_GMAC_PLL_FOUTPOSTDIV 9 -+#define LIGHT_GMAC_PLL_FOUT1PH0 10 -+#define LIGHT_GMAC_PLL_FOUT4 11 -+#define LIGHT_GMAC_PLL_BYPASS 12 -+ -+#define LIGHT_AUDIO_PLL_FOUTVCO 13 -+#define LIGHT_AUDIO_PLL_FOUTPOSTDIV 14 -+#define LIGHT_AUDIO_PLL_FOUT3 15 -+#define LIGHT_AUDIO_PLL_BYPASS 16 -+ -+#define LIGHT_SYS_PLL_FOUTVCO 17 -+#define LIGHT_SYS_PLL_FOUTPOSTDIV 18 -+#define LIGHT_SYS_PLL_FOUT4 19 -+#define LIGHT_SYS_PLL_BYPASS 20 -+ -+#define LIGHT_CPU_PLL0_FOUTVCO 21 -+#define LIGHT_CPU_PLL0_FOUTPOSTDIV 22 -+#define LIGHT_CPU_PLL0_FOUT4 23 -+#define LIGHT_CPU_PLL0_BYPASS 24 -+ -+#define LIGHT_CPU_PLL1_FOUTVCO 25 -+#define LIGHT_CPU_PLL1_FOUTPOSTDIV 26 -+#define LIGHT_CPU_PLL1_FOUT4 27 -+#define LIGHT_CPU_PLL1_BYPASS 28 -+ -+#define LIGHT_DDR_PLL_FOUTVCO 29 -+#define LIGHT_DDR_PLL_FOUTPOSTDIV 30 -+#define LIGHT_DDR_PLL_FOUT4 31 -+#define LIGHT_DDR_PLL_BYPASS 32 -+ -+#define LIGHT_AONSYS_CLK_SWITCH_0 33 -+#define LIGHT_AONSYS_CLK_SWITCH_1 34 -+#define LIGHT_AONSYS_CLK 35 -+#define LIGHT_SHARE_SRAM_CLK 36 -+#define LIGHT_CLKGEN_RTC_PCLK 37 -+#define LIGHT_CLKGEN_AOGPIO_PCLK 38 -+#define LIGHT_CLKGEN_AOI2C_PCLK 39 -+#define LIGHT_CLKGEN_PVTC_PCLK 40 -+#define LIGHT_CLKGEN_AOAHB_HCLK 41 -+#define LIGHT_CLKGEN_AOSRAM_HCLK 42 -+#define LIGHT_CLKGEN_AOAPB_HCLK 43 -+#define LIGHT_CLKGEN_AOPAD_PCLK 44 -+#define LIGHT_CLKGEN_AOTIMER_PCLK 45 -+#define LIGHT_CLKGEN_AOTIMER_CCLK 46 -+#define LIGHT_CLKGEN_SRAM_AXI_ACLK 47 -+#define LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_S 48 -+#define LIGHT_CLKGEN_AOGPIO_DBCLK 49 -+ -+#define LIGHT_GMAC_CORECLK 50 -+#define LIGHT_OSC_CLK_DIV24 51 -+#define LIGHT_GMAC_PLL_FOUTVCO_DIV5 52 -+#define LIGHT_C910_CCLK_I0 53 -+#define LIGHT_C910_CCLK 54 -+#define LIGHT_CPUSYS_AHB_HCLK 55 -+#define LIGHT_CPUSYS_CFG_AXI_ACLK 56 -+#define LIGHT_PERISYS_AHB_HCLK 57 -+#define LIGHT_CLK_OUT_1 58 -+#define LIGHT_CLK_OUT_2 59 -+#define LIGHT_CLK_OUT_3 60 -+#define LIGHT_CLK_OUT_4 61 -+#define LIGHT_CPUSYS_AHB_HCLK_DIV 62 -+#define LIGHT_APB3_CPUSYS_PCLK 63 -+#define LIGHT_CPUSYS_SUB_AXI_ACLK 64 -+#define LIGHT_CPUSYS_CFG_AXI_ACLK_DIV 65 -+#define LIGHT_TEESYS_HCLK 66 -+#define LIGHT_DMAC_1_CLK 67 -+#define LIGHT_DMAC_2_CLK 68 -+#define LIGHT_DMAC_3_CLK 69 -+#define LIGHT_AXI_PORT4_CLK 70 -+#define LIGHT_PERISYS_AHB_HCLK_DIV 71 -+#define LIGHT_PERISYS_APB_PCLK 72 -+#define LIGHT_CLK_OUT_1_DIV 73 -+#define LIGHT_CLK_OUT_2_DIV 74 -+#define LIGHT_CLK_OUT_3_DIV 75 -+#define LIGHT_CLK_OUT_4_DIV 76 -+#define LIGHT_CLKGEN_PERISYS_AXI_ACLK 77 -+#define LIGHT_CLKGEN_PERISYS_AHB_HCLK 78 -+#define LIGHT_CLKGEN_PERISYS_APB1_HCLK 79 -+#define LIGHT_CLKGEN_PERISYS_APB2_HCLK 80 -+#define LIGHT_CLKGEN_USB3_DRD_PHY_REF_CLK 81 -+#define LIGHT_CLKGEN_USB3_DRD_CTRL_REF_CLK 82 -+#define LIGHT_CLKGEN_USB3_DRD_SPDCLK 83 -+#define LIGHT_CLKGEN_USB3_DRD_ACLK 84 -+#define LIGHT_CLKGEN_EMMC1_X2X_ACLK 85 -+#define LIGHT_CLKGEN_EMMC0_X2X_ACLK 86 -+#define LIGHT_CLKGEN_EMMC0_HCLK 87 -+#define LIGHT_CLKGEN_EMMC1_HCLK 88 -+#define LIGHT_CLKGEN_GMAC_ACLK 89 -+#define LIGHT_CLKGEN_PWM_PCLK 90 -+#define LIGHT_CLKGEN_QSPI0_PCLK 91 -+#define LIGHT_CLKGEN_QSPI1_PCLK 92 -+#define LIGHT_CLKGEN_SPI_PCLK 93 -+#define LIGHT_CLKGEN_UART0_PCLK 94 -+#define LIGHT_CLKGEN_UART1_PCLK 95 -+#define LIGHT_CLKGEN_UART2_PCLK 96 -+#define LIGHT_CLKGEN_UART3_PCLK 97 -+#define LIGHT_CLKGEN_UART4_PCLK 98 -+#define LIGHT_CLKGEN_UART5_PCLK 99 -+#define LIGHT_CLKGEN_GPIO0_PCLK 100 -+#define LIGHT_CLKGEN_GPIO1_PCLK 101 -+#define LIGHT_CLKGEN_GPIO2_PCLK 102 -+#define LIGHT_CLKGEN_I2C0_IC_CLK 103 -+#define LIGHT_CLKGEN_I2C1_IC_CLK 104 -+#define LIGHT_CLKGEN_I2C2_IC_CLK 105 -+#define LIGHT_CLKGEN_I2C3_IC_CLK 106 -+#define LIGHT_CLKGEN_I2C4_IC_CLK 107 -+#define LIGHT_CLKGEN_I2C5_IC_CLK 108 -+#define LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_M 109 -+#define LIGHT_CLKGEN_AXI_DUMMY_SLV_4_ACLK 110 -+#define LIGHT_CLKGEN_AXI_DUMMY_SLV_3_ACLK 111 -+#define LIGHT_CLKGEN_AXI_DUMMY_SLV_2_ACLK 112 -+#define LIGHT_CLKGEN_AXI_DUMMY_SLV_1_ACLK 113 -+#define LIGHT_CLKGEN_APB_CPU2FG_HCLK 114 -+#define LIGHT_CLKGEN_AON2CPU_A2X_ACLK 115 -+#define LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_M 116 -+#define LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_M 117 -+#define LIGHT_CLKGEN_AXI4_CPUSYS2_ACLK 118 -+#define LIGHT_CLKGEN_X2X_CPUSYS_ACLK_M 119 -+#define LIGHT_CLKGEN_CHIP_DBG_ACLK 120 -+#define LIGHT_CLKGEN_AXI4_CFG_BUS_ACLK 121 -+#define LIGHT_CLKGEN_X2H_CPUSYS_ACLK 122 -+#define LIGHT_CLKGEN_CPU2TEE_X2H_ACLK 123 -+#define LIGHT_CLKGEN_CPU2AON_X2H_ACLK 124 -+#define LIGHT_CLKGEN_CPU2CFG_X2H_ACLK 125 -+#define LIGHT_CLKGEN_CPU2PERI_X2H_MHCLK 126 -+#define LIGHT_CLKGEN_AHB2_CPUSYS_HCLK 127 -+#define LIGHT_CLKGEN_APB3_CPUSYS_HCLK 128 -+#define LIGHT_CLKGEN_C910_BROM_HCLK 129 -+#define LIGHT_CLKGEN_DMAC_ACLK 130 -+#define LIGHT_CLKGEN_MBOX0_PCLK 131 -+#define LIGHT_CLKGEN_MBOX1_PCLK 132 -+#define LIGHT_CLKGEN_MBOX2_PCLK 133 -+#define LIGHT_CLKGEN_MBOX3_PCLK 134 -+#define LIGHT_CLKGEN_WDT0_PCLK 135 -+#define LIGHT_CLKGEN_WDT1_PCLK 136 -+#define LIGHT_CLKGEN_TIMER0_CCLK 137 -+#define LIGHT_CLKGEN_TIMER1_CCLK 138 -+#define LIGHT_CLKGEN_TRNG_RB_HCLK 139 -+#define LIGHT_CLKGEN_ADC_PCLK 140 -+#define LIGHT_CLKGEN_AXI_ACLK_4 141 -+#define LIGHT_CLKGEN_AXI_ACLK_3 142 -+#define LIGHT_CLKGEN_AXI_ACLK_2 143 -+#define LIGHT_CLKGEN_AXI_ACLK_1 145 -+#define LIGHT_CLKGEN_AXI_ACLK_0 146 -+#define LIGHT_CLKGEN_DMAC_1_ACLK 147 -+#define LIGHT_CLKGEN_DMAC_2_ACLK 148 -+#define LIGHT_CLKGEN_DMAC_3_ACLK 149 -+#define LIGHT_CLKGEN_SRAM_AXI_PCLK 150 -+#define LIGHT_CLKGEN_AHB2_TEESYS_HCLK 151 -+#define LIGHT_CLKGEN_EFUSE_MPW_PCLK 152 -+#define LIGHT_CLKGEN_CLK_OUT_4_CLK 153 -+#define LIGHT_CLKGEN_CLK_OUT_3_CLK 154 -+#define LIGHT_CLKGEN_CLK_OUT_2_CLK 155 -+#define LIGHT_CLKGEN_CLK_OUT_1_CLK 156 -+#define LIGHT_CLKGEN_DDR_APB_PCLK 157 -+#define LIGHT_CLKGEN_PADCTRL_APSYS_PCLK 158 -+#define LIGHT_CLKGEN_CHIP_DBG_CCLK 159 -+#define LIGHT_CHIP_DBG_CCLK 160 -+#define LIGHT_AXI_ACLK 161 -+ -+#define LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_S 162 -+#define LIGHT_CLKGEN_CPU2CFG_X2H_ACLK_S 163 -+#define LIGHT_CLKGEN_AON2CPU_A2X_HCLK 164 -+#define LIGHT_CLKGEN_DMAC_HCLK 165 -+#define LIGHT_CLKGEN_X2H_CPUSYS_MHCLK 166 -+#define LIGHT_CLKGEN_CPU2TEE_X2H_MHCLK 167 -+#define LIGHT_CLKGEN_CPU2AON_X2H_MHCLK 168 -+#define LIGHT_AXI_HCLK 169 -+#define LIGHT_CLKGEN_CPU2CFG_X2H_MHCLK 170 -+#define LIGHT_CLKGEN_TIMER0_PCLK 171 -+#define LIGHT_CLKGEN_TIMER1_PCLK 172 -+#define LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_S 173 -+#define LIGHT_CLKGEN_USB3_DRD_PCLK 174 -+#define LIGHT_CLKGEN_GMAC_HCLK 175 -+#define LIGHT_CLKGEN_GMAC_PCLK 176 -+#define LIGHT_CLKGEN_GMAC_CCLK 177 -+#define LIGHT_CLKGEN_EMMC0_ACLK 178 -+#define LIGHT_CLKGEN_EMMC0_REF_CLK 179 -+#define LIGHT_CLKGEN_EMMC0_OSC_CLK 180 -+#define LIGHT_CLKGEN_EMMC1_ACLK 181 -+#define LIGHT_CLKGEN_EMMC1_REF_CLK 182 -+#define LIGHT_CLKGEN_EMMC1_OSC_CLK 183 -+#define LIGHT_CLKGEN_PWM_CCLK 184 -+#define LIGHT_CLKGEN_QSPI0_SSI_CLK 185 -+#define LIGHT_CLKGEN_QSPI1_SSI_CLK 186 -+#define LIGHT_CLKGEN_SPI_SSI_CLK 187 -+#define LIGHT_CLKGEN_GPIO0_DBCLK 188 -+#define LIGHT_CLKGEN_GPIO1_DBCLK 189 -+#define LIGHT_CLKGEN_GPIO2_DBCLK 190 -+#define LIGHT_CLKGEN_DMAC_1_HCLK 191 -+#define LIGHT_CLKGEN_DMAC_2_HCLK 192 -+#define LIGHT_CLKGEN_DMAC_3_HCLK 193 -+#define LIGHT_EMMC_CLK_DIV 194 -+#define LIGHT_EMMC0_OSC_CLK 195 -+#define LIGHT_EMMC1_OSC_CLK 196 -+#define LIGHT_PWM_CCLK 197 -+#define LIGHT_USB3_PHY_REF_CLK 198 -+#define LIGHT_SPI_CLK 199 -+#define LIGHT_GPIO_DBCLK 200 -+#define LIGHT_X2H_HCLK 201 -+ -+#define LIGHT_CLK_END 202 -+#endif -diff --git a/include/dt-bindings/clock/light-visys.h b/include/dt-bindings/clock/light-visys.h -new file mode 100644 -index 000000000000..53fed0bfb624 ---- /dev/null -+++ b/include/dt-bindings/clock/light-visys.h -@@ -0,0 +1,54 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef _LIGHT_VISYS_H -+#define _LIGHT_VISYS_H -+ -+#define LIGHT_CLKGEN_VISYS_ACLK 0 -+#define LIGHT_CLKGEN_DW200_ACLK 1 -+#define LIGHT_CLKGEN_AXI4_VISYS1_ACLK 2 -+#define LIGHT_CLKGEN_AXI4_VISYS2_ACLK 3 -+#define LIGHT_CLKGEN_AXI4_VISYS3_ACLK 4 -+#define LIGHT_CLKGEN_ISP0_ACLK 5 -+#define LIGHT_CLKGEN_ISP_RY_ACLK 6 -+#define LIGHT_CLKGEN_ISP_VENC_SHAKE_ACLK 7 -+#define LIGHT_CLKGEN_VIPRE_ACLK 8 -+#define LIGHT_CLKGEN_VISYS_SLAVE_HCLK 9 -+#define LIGHT_CLKGEN_ISP0_S_HCLK 10 -+#define LIGHT_CLKGEN_DW200_HCLK 11 -+#define LIGHT_CLKGEN_ISP_RY_HCLK 12 -+#define LIGHT_CLKGEN_MIPI_CSI0_PCLK 13 -+#define LIGHT_CLKGEN_MIPI_CSI0_FPCLK 14 -+#define LIGHT_CLKGEN_MIPI_CSI1_PCLK 15 -+#define LIGHT_CLKGEN_MIPI_CSI1_FPCLK 16 -+#define LIGHT_CLKGEN_MIPI_CSI2_PCLK 17 -+#define LIGHT_CLKGEN_MIPI_CSI2_FPCLK 18 -+#define LIGHT_CLKGEN_VIPRE_PCLK 19 -+#define LIGHT_CLKGEN_VISYS_PCLK 20 -+#define LIGHT_CLKGEN_VISYS_SYSREG_PCLK 21 -+#define LIGHT_CLKGEN_ISP_VENC_SHAKE_PCLK 22 -+#define LIGHT_CLKGEN_MIPI_CSI0_PIXCLK 23 -+#define LIGHT_CLKGEN_MIPI_CSI1_PIXCLK 24 -+#define LIGHT_CLKGEN_MIPI_CSI2_PIXCLK 25 -+#define LIGHT_CLKGEN_VIPRE_PIXELCLK 26 -+#define LIGHT_CLKGEN_ISP_PIXELCLK 27 -+#define LIGHT_CLKGEN_MIPI_CSI0_CFG_CLK 28 -+#define LIGHT_CLKGEN_MIPI_CSI1_CFG_CLK 29 -+#define LIGHT_CLKGEN_MIPI_CSI2_CFG_CLK 30 -+#define LIGHT_CLKGEN_DW200_CLK_VSE 31 -+#define LIGHT_CLKGEN_DW200_CLK_DWE 32 -+#define LIGHT_CLKGEN_ISP0_CLK 33 -+#define LIGHT_CLKGEN_ISP1_CLK 34 -+#define LIGHT_CLKGEN_ISP_RY_CCLK 35 -+#define LIGHT_CLKGEN_MIPI_CSI_SCANBYTECLK 36 -+#define LIGHT_CLKGEN_MIPI_CSI_SCANCLK 37 -+#define LIGHT_CLKGEN_ISP1_PIXELCLK 38 -+#define LIGHT_CLKGEN_ISP0_PIXELCLK 39 -+#define LIGHT_CLKGEN_ISP1_HCLK 40 -+#define LIGHT_CLKGEN_ISP0_HCLK 41 -+#define LIGHT_CLKGEN_ISP1_ACLK 42 -+#define LIGHT_CLKGEN_VISYS_CLK_END 43 -+ -+#endif -diff --git a/include/dt-bindings/clock/light-vosys.h b/include/dt-bindings/clock/light-vosys.h -new file mode 100644 -index 000000000000..dbdd7fa7016b ---- /dev/null -+++ b/include/dt-bindings/clock/light-vosys.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef LIGHT_VOSYS_H -+#define LIGHT_VOSYS_H -+ -+#define LIGHT_CLKGEN_AXI4_VO_PCLK 0 -+#define LIGHT_CLKGEN_IOPMP_VOSYS_DPU_PCLK 1 -+#define LIGHT_CLKGEN_IOPMP_VOSYS_DPU1_PCLK 2 -+#define LIGHT_CLKGEN_IOPMP_VOSYS_GPU_PCLK 3 -+#define LIGHT_CLKGEN_HDMI_PCLK 4 -+#define LIGHT_CLKGEN_MIPIDSI0_PCLK 5 -+#define LIGHT_CLKGEN_MIPIDSI1_PCLK 6 -+#define LIGHT_CLKGEN_AXI4_VO_ACLK 7 -+#define LIGHT_CLKGEN_IOPMP_GPU_ACLK 8 -+#define LIGHT_CLKGEN_IOPMP_DPU_ACLK 9 -+#define LIGHT_CLKGEN_IOPMP_DPU1_ACLK 10 -+#define LIGHT_CLKGEN_X2H_DPU_ACLK 11 -+#define LIGHT_CLKGEN_X2H_DPU1_ACLK 12 -+#define LIGHT_CLKGEN_MIPIDSI0_PIXCLK 13 -+#define LIGHT_CLKGEN_HDMI_PIXCLK 14 -+#define LIGHT_CLKGEN_MIPIDSI1_PIXCLK 15 -+#define LIGHT_CLKGEN_HDMI_SFR_CLK 16 -+#define LIGHT_CLKGEN_HDMI_CEC_CLK 17 -+#define LIGHT_CLKGEN_HDMI_I2S_CLK 18 -+#define LIGHT_CLKGEN_MIPIDSI0_CFG_CLK 19 -+#define LIGHT_CLKGEN_MIPIDSI1_CFG_CLK 20 -+#define LIGHT_CLKGEN_MIPIDSI0_REFCLK 21 -+#define LIGHT_CLKGEN_MIPIDSI1_REFCLK 22 -+#define LIGHT_CLKGEN_GPU_CORE_CLK 23 -+#define LIGHT_CLKGEN_GPU_CFG_ACLK 24 -+#define LIGHT_CLKGEN_DPU_HCLK 25 -+#define LIGHT_CLKGEN_DPU_ACLK 26 -+#define LIGHT_CLKGEN_DPU_CCLK 27 -+#define LIGHT_CLKGEN_DPU_PIXCLK0 28 -+#define LIGHT_CLKGEN_DPU_PIXCLK1 29 -+#define LIGHT_CLKGEN_VOSYS_CLK_END 30 -+ -+#endif -diff --git a/include/dt-bindings/clock/light-vpsys.h b/include/dt-bindings/clock/light-vpsys.h -new file mode 100644 -index 000000000000..188aaa6cc435 ---- /dev/null -+++ b/include/dt-bindings/clock/light-vpsys.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef _LIGHT_VPSYS_H -+#define _LIGHT_VPSYS_H -+ -+#define LIGHT_VPSYS_G2D_PCLK 0 -+#define LIGHT_VPSYS_G2D_ACLK 1 -+#define LIGHT_VPSYS_G2D_CCLK 2 -+#define LIGHT_VPSYS_FCE_PCLK 3 -+#define LIGHT_VPSYS_FCE_ACLK 4 -+#define LIGHT_VPSYS_VDEC_PCLK 5 -+#define LIGHT_VPSYS_VDEC_ACLK 6 -+#define LIGHT_VPSYS_VDEC_CCLK 7 -+#define LIGHT_VPSYS_AXI_ACLK 8 -+#define LIGHT_VPSYS_VENC_CCLK 9 -+#define LIGHT_VPSYS_VENC_PCLK 10 -+#define LIGHT_VPSYS_VENC_ACLK 11 -+#define LIGHT_VPSYS_CLK_END 12 -+ -+#endif -+ -diff --git a/include/dt-bindings/clock/sophgo-mango-clock.h b/include/dt-bindings/clock/sophgo-mango-clock.h -new file mode 100644 -index 000000000000..aaed4ad27dc1 ---- /dev/null -+++ b/include/dt-bindings/clock/sophgo-mango-clock.h -@@ -0,0 +1,165 @@ -+#ifndef __SOPHGO_MANGO_CLOCK__ -+#define __SOPHGO_MANGO_CLOCK__ -+ -+#include <dt-bindings/clock/sophgo.h> -+ -+/*div clock*/ -+#define DIV_CLK_MPLL_RP_CPU_NORMAL_0 0 -+#define DIV_CLK_MPLL_AXI_DDR_0 1 -+#define DIV_CLK_FPLL_DDR01_1 2 -+#define DIV_CLK_FPLL_DDR23_1 3 -+#define DIV_CLK_FPLL_RP_CPU_NORMAL_1 4 -+#define DIV_CLK_FPLL_50M_A53 5 -+#define DIV_CLK_FPLL_TOP_RP_CMN_DIV2 6 -+#define DIV_CLK_FPLL_UART_500M 7 -+#define DIV_CLK_FPLL_AHB_LPC 8 -+#define DIV_CLK_FPLL_EFUSE 9 -+#define DIV_CLK_FPLL_TX_ETH0 10 -+#define DIV_CLK_FPLL_PTP_REF_I_ETH0 11 -+#define DIV_CLK_FPLL_REF_ETH0 12 -+#define DIV_CLK_FPLL_EMMC 13 -+#define DIV_CLK_FPLL_SD 14 -+#define DIV_CLK_FPLL_TOP_AXI0 15 -+#define DIV_CLK_FPLL_TOP_AXI_HSPERI 16 -+#define DIV_CLK_FPLL_AXI_DDR_1 17 -+#define DIV_CLK_FPLL_DIV_TIMER1 18 -+#define DIV_CLK_FPLL_DIV_TIMER2 19 -+#define DIV_CLK_FPLL_DIV_TIMER3 20 -+#define DIV_CLK_FPLL_DIV_TIMER4 21 -+#define DIV_CLK_FPLL_DIV_TIMER5 22 -+#define DIV_CLK_FPLL_DIV_TIMER6 23 -+#define DIV_CLK_FPLL_DIV_TIMER7 24 -+#define DIV_CLK_FPLL_DIV_TIMER8 25 -+#define DIV_CLK_FPLL_100K_EMMC 26 -+#define DIV_CLK_FPLL_100K_SD 27 -+#define DIV_CLK_FPLL_GPIO_DB 28 -+#define DIV_CLK_DPLL0_DDR01_0 29 -+#define DIV_CLK_DPLL1_DDR23_0 30 -+ -+/* MPLL */ -+#define GATE_CLK_RP_CPU_NORMAL_DIV0 31 -+#define GATE_CLK_AXI_DDR_DIV0 32 -+ -+/* FPLL */ -+#define GATE_CLK_RP_CPU_NORMAL_DIV1 33 -+#define GATE_CLK_A53_50M 34 -+#define GATE_CLK_TOP_RP_CMN_DIV2 35 -+#define GATE_CLK_HSDMA 36 -+#define GATE_CLK_EMMC_100M 37 -+#define GATE_CLK_SD_100M 38 -+#define GATE_CLK_TX_ETH0 39 -+#define GATE_CLK_PTP_REF_I_ETH0 40 -+#define GATE_CLK_REF_ETH0 41 -+#define GATE_CLK_UART_500M 42 -+#define GATE_CLK_EFUSE 43 -+ -+#define GATE_CLK_AHB_LPC 44 -+#define GATE_CLK_AHB_ROM 45 -+#define GATE_CLK_AHB_SF 46 -+ -+#define GATE_CLK_APB_UART 47 -+#define GATE_CLK_APB_TIMER 48 -+#define GATE_CLK_APB_EFUSE 49 -+#define GATE_CLK_APB_GPIO 50 -+#define GATE_CLK_APB_GPIO_INTR 51 -+#define GATE_CLK_APB_SPI 52 -+#define GATE_CLK_APB_I2C 53 -+#define GATE_CLK_APB_WDT 54 -+#define GATE_CLK_APB_PWM 55 -+#define GATE_CLK_APB_RTC 56 -+ -+#define GATE_CLK_AXI_PCIE0 57 -+#define GATE_CLK_AXI_PCIE1 58 -+#define GATE_CLK_SYSDMA_AXI 59 -+#define GATE_CLK_AXI_DBG_I2C 60 -+#define GATE_CLK_AXI_SRAM 61 -+#define GATE_CLK_AXI_ETH0 62 -+#define GATE_CLK_AXI_EMMC 63 -+#define GATE_CLK_AXI_SD 64 -+#define GATE_CLK_TOP_AXI0 65 -+#define GATE_CLK_TOP_AXI_HSPERI 66 -+ -+#define GATE_CLK_TIMER1 67 -+#define GATE_CLK_TIMER2 68 -+#define GATE_CLK_TIMER3 69 -+#define GATE_CLK_TIMER4 70 -+#define GATE_CLK_TIMER5 71 -+#define GATE_CLK_TIMER6 72 -+#define GATE_CLK_TIMER7 73 -+#define GATE_CLK_TIMER8 74 -+#define GATE_CLK_100K_EMMC 75 -+#define GATE_CLK_100K_SD 76 -+#define GATE_CLK_GPIO_DB 77 -+ -+#define GATE_CLK_AXI_DDR_DIV1 78 -+#define GATE_CLK_DDR01_DIV1 79 -+#define GATE_CLK_DDR23_DIV1 80 -+/* DPLL0 */ -+#define GATE_CLK_DDR01_DIV0 81 -+/* DPLL1 */ -+#define GATE_CLK_DDR23_DIV0 82 -+ -+#define GATE_CLK_DDR01 83 -+#define GATE_CLK_DDR23 84 -+#define GATE_CLK_RP_CPU_NORMAL 85 -+#define GATE_CLK_AXI_DDR 86 -+#define GATE_CLK_RXU0 87 -+#define GATE_CLK_RXU1 88 -+#define GATE_CLK_RXU2 89 -+#define GATE_CLK_RXU3 90 -+#define GATE_CLK_RXU4 91 -+#define GATE_CLK_RXU5 92 -+#define GATE_CLK_RXU6 93 -+#define GATE_CLK_RXU7 94 -+#define GATE_CLK_RXU8 95 -+#define GATE_CLK_RXU9 96 -+#define GATE_CLK_RXU10 97 -+#define GATE_CLK_RXU11 98 -+#define GATE_CLK_RXU12 99 -+#define GATE_CLK_RXU13 100 -+#define GATE_CLK_RXU14 101 -+#define GATE_CLK_RXU15 102 -+#define GATE_CLK_RXU16 103 -+#define GATE_CLK_RXU17 104 -+#define GATE_CLK_RXU18 105 -+#define GATE_CLK_RXU19 106 -+#define GATE_CLK_RXU20 107 -+#define GATE_CLK_RXU21 108 -+#define GATE_CLK_RXU22 109 -+#define GATE_CLK_RXU23 110 -+#define GATE_CLK_RXU24 111 -+#define GATE_CLK_RXU25 112 -+#define GATE_CLK_RXU26 113 -+#define GATE_CLK_RXU27 114 -+#define GATE_CLK_RXU28 115 -+#define GATE_CLK_RXU29 116 -+#define GATE_CLK_RXU30 117 -+#define GATE_CLK_RXU31 118 -+#define GATE_CLK_MP0 119 -+#define GATE_CLK_MP1 120 -+#define GATE_CLK_MP2 121 -+#define GATE_CLK_MP3 122 -+#define GATE_CLK_MP4 123 -+#define GATE_CLK_MP5 124 -+#define GATE_CLK_MP6 125 -+#define GATE_CLK_MP7 126 -+#define GATE_CLK_MP8 127 -+#define GATE_CLK_MP9 128 -+#define GATE_CLK_MP10 129 -+#define GATE_CLK_MP11 130 -+#define GATE_CLK_MP12 131 -+#define GATE_CLK_MP13 132 -+#define GATE_CLK_MP14 133 -+#define GATE_CLK_MP15 134 -+ -+/* MUX */ -+#define MUX_CLK_DDR01 0 -+#define MUX_CLK_DDR23 1 -+#define MUX_CLK_RP_CPU_NORMAL 2 -+#define MUX_CLK_AXI_DDR 3 -+ -+#define S0_DIV_CLK_TABLE 0 -+#define S1_DIV_CLK_TABLE 1 -+#define S0_MUX_CLK_TABLE 2 -+#define S1_MUX_CLK_TABLE 3 -+#endif -diff --git a/include/dt-bindings/clock/sophgo.h b/include/dt-bindings/clock/sophgo.h -new file mode 100644 -index 000000000000..5584243f9135 ---- /dev/null -+++ b/include/dt-bindings/clock/sophgo.h -@@ -0,0 +1,15 @@ -+#ifndef __SOPHGO_CLK__ -+#define __SOPHGO_CLK__ -+ -+//PLL ID -+#define MPLL_CLK 0 -+#define FPLL_CLK 3 -+#define DPLL0_CLK 4 -+#define DPLL1_CLK 5 -+ -+//clock mode -+#define NORMAL_MODE 0 -+#define FAST_MODE 1 -+#define SAFE_MODE 2 -+#define BYPASS_MODE 3 -+#endif -diff --git a/include/dt-bindings/firmware/thead/rsrc.h b/include/dt-bindings/firmware/thead/rsrc.h -new file mode 100644 -index 000000000000..8cee0fcaeb74 ---- /dev/null -+++ b/include/dt-bindings/firmware/thead/rsrc.h -@@ -0,0 +1,17 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2022 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef __DT_BINDINGS_RSCRC_LIGHT_H -+#define __DT_BINDINGS_RSCRC_LIGHT_H -+ -+#define LIGHT_AON_AUDIO_PD 0 -+#define LIGHT_AON_VDEC_PD 1 -+#define LIGHT_AON_NPU_PD 2 -+#define LIGHT_AON_VENC_PD 3 -+#define LIGHT_AON_GPU_PD 4 -+#define LIGHT_AON_DSP0_PD 5 -+#define LIGHT_AON_DSP1_PD 6 -+ -+#endif -diff --git a/include/dt-bindings/reset/sophgo-mango-resets.h b/include/dt-bindings/reset/sophgo-mango-resets.h -new file mode 100644 -index 000000000000..9ff8ca4c3d67 ---- /dev/null -+++ b/include/dt-bindings/reset/sophgo-mango-resets.h -@@ -0,0 +1,96 @@ -+/* -+ * Sophgo SoCs Reset definitions -+ * -+ * Copyright (c) 2018 Bitmain Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#ifndef _DT_BINDINGS_RST_MANGO_H_ -+#define _DT_BINDINGS_RST_MANGO_H_ -+ -+#define RST_MAIN_AP 0 -+#define RST_RISCV_CPU 1 -+#define RST_RISCV_LOW_SPEED_LOGIC 2 -+#define RST_RISCV_CMN 3 -+#define RST_HSDMA 4 -+#define RST_SYSDMA 5 -+#define RST_EFUSE0 6 -+#define RST_EFUSE1 7 -+#define RST_RTC 8 -+#define RST_TIMER 9 -+#define RST_WDT 10 -+#define RST_AHB_ROM0 11 -+#define RST_AHB_ROM1 12 -+#define RST_I2C0 13 -+#define RST_I2C1 14 -+#define RST_I2C2 15 -+#define RST_I2C3 16 -+#define RST_GPIO0 17 -+#define RST_GPIO1 18 -+#define RST_GPIO2 19 -+#define RST_PWM 20 -+#define RST_AXI_SRAM0 21 -+#define RST_AXI_SRAM1 22 -+#define RST_SF0 23 -+#define RST_SF1 24 -+#define RST_LPC 25 -+#define RST_ETH0 26 -+#define RST_EMMC 27 -+#define RST_SD 28 -+#define RST_UART0 29 -+#define RST_UART1 30 -+#define RST_UART2 31 -+ -+#define RST_UART3 32 -+#define RST_SPI0 33 -+#define RST_SPI1 34 -+#define RST_DBG_I2C 35 -+#define RST_PCIE0 36 -+#define RST_PCIE1 37 -+#define RST_DDR0 38 -+#define RST_DDR1 39 -+#define RST_DDR2 40 -+#define RST_DDR3 41 -+#define RST_FAU0 42 -+#define RST_FAU1 43 -+#define RST_FAU2 44 -+#define RST_RXU0 45 -+#define RST_RXU1 46 -+#define RST_RXU2 47 -+#define RST_RXU3 48 -+#define RST_RXU4 49 -+#define RST_RXU5 50 -+#define RST_RXU6 51 -+#define RST_RXU7 52 -+#define RST_RXU8 53 -+#define RST_RXU9 54 -+#define RST_RXU10 55 -+#define RST_RXU11 56 -+#define RST_RXU12 57 -+#define RST_RXU13 58 -+#define RST_RXU14 59 -+#define RST_RXU15 60 -+#define RST_RXU16 61 -+#define RST_RXU17 62 -+#define RST_RXU18 63 -+#define RST_RXU19 64 -+#define RST_RXU20 65 -+#define RST_RXU21 66 -+#define RST_RXU22 67 -+#define RST_RXU23 68 -+#define RST_RXU24 69 -+#define RST_RXU25 70 -+#define RST_RXU26 71 -+#define RST_RXU27 72 -+#define RST_RXU28 73 -+#define RST_RXU29 74 -+#define RST_RXU30 75 -+#define RST_RXU31 76 -+ -+#define RST_MAX_NUM (RST_RXU31+1) -+ -+#endif -diff --git a/include/dt-bindings/reset/thead,th1520-reset.h b/include/dt-bindings/reset/thead,th1520-reset.h -new file mode 100644 -index 000000000000..ec10751814e5 ---- /dev/null -+++ b/include/dt-bindings/reset/thead,th1520-reset.h -@@ -0,0 +1,9 @@ -+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ -+ -+#ifndef DT_BINDING_RESET_TH1520_H -+#define DT_BINDING_RESET_TH1520_H -+ -+#define TH1520_RESET_WDT0 0 -+#define TH1520_RESET_WDT1 1 -+ -+#endif -diff --git a/include/linux/firmware/thead/ipc.h b/include/linux/firmware/thead/ipc.h -new file mode 100644 -index 000000000000..dfda60e76725 ---- /dev/null -+++ b/include/linux/firmware/thead/ipc.h -@@ -0,0 +1,74 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Copyright (C) 2021 Alibaba Group Holding Limited. -+ */ -+ -+#ifndef _SC_IPC_H -+#define _SC_IPC_H -+ -+#include <linux/device.h> -+#include <linux/types.h> -+ -+#define AON_RPC_MSG_MAGIC (0xef) -+#define LIGHT_AON_RPC_VERSION 1 -+#define LIGHT_AON_RPC_MSG_NUM 7 -+ -+struct light_aon_ipc; -+ -+enum light_aon_rpc_svc { -+ LIGHT_AON_RPC_SVC_UNKNOWN = 0, -+ LIGHT_AON_RPC_SVC_RETURN = 1, -+ LIGHT_AON_RPC_SVC_PM = 2, -+ LIGHT_AON_RPC_SVC_MISC = 3, -+ LIGHT_AON_RPC_SVC_AVFS = 4, -+}; -+ -+enum light_aon_misc_func { -+ LIGHT_AON_MISC_FUNC_UNKNOWN = 0, -+ LIGHT_AON_MISC_FUNC_SET_CONTROL = 1, -+ LIGHT_AON_MISC_FUNC_GET_CONTROL = 2, -+ LIGHT_AON_MISC_FUNC_WDG_START = 3, -+ LIGHT_AON_MISC_FUNC_WDG_STOP = 4, -+ LIGHT_AON_MISC_FUNC_WDG_PING = 5, -+ LIGHT_AON_MISC_FUNC_WDG_TIMEOUTSET = 6, -+ LIGHT_AON_MISC_FUNC_WDG_RESTART = 7, -+ LIGHT_AON_MISC_FUNC_WDG_GET_STATE = 8, -+ LIGHT_AON_MISC_FUNC_WDG_POWER_OFF = 9, -+ LIGHT_AON_MISC_FUNC_AON_WDT_ON = 10, -+ LIGHT_AON_MISC_FUNC_AON_WDT_OFF = 11, -+ LIGHT_AON_MISC_FUNC_AON_RESERVE_MEM = 12, -+ LIGHT_AON_MISC_FUNC_REQUIRE_STR = 13, -+ LIGHT_AON_MISC_FUNC_RESUME_STR = 14, -+ LIGHT_AON_MISC_FUNC_REQUIRE_STD = 15, -+ LIGHT_AON_MISC_FUNC_CPUHP = 16, -+}; -+ -+enum light_aon_pm_func { -+ LIGHT_AON_PM_FUNC_UNKNOWN = 0, -+ LIGHT_AON_PM_FUNC_SET_RESOURCE_REGULATOR = 1, -+ LIGHT_AON_PM_FUNC_GET_RESOURCE_REGULATOR = 2, -+ LIGHT_AON_PM_FUNC_SET_RESOURCE_POWER_MODE = 3, -+ LIGHT_AON_PM_FUNC_PWR_SET = 4, -+ LIGHT_AON_PM_FUNC_PWR_GET = 5, -+}; -+ -+struct light_aon_rpc_msg_hdr { -+ uint8_t ver; ///< version of msg hdr -+ uint8_t size; ///< msg size ,uinit in bytes,the size includes rpc msg header self. -+ uint8_t svc; ///< rpc main service id -+ uint8_t func; ///< rpc sub func id of specific service, sent by caller -+} __packed __aligned(4); -+ -+/* -+ * Defines for SC PM Power Mode -+ */ -+#define LIGHT_AON_PM_PW_MODE_OFF 0 /* Power off */ -+#define LIGHT_AON_PM_PW_MODE_STBY 1 /* Power in standby */ -+#define LIGHT_AON_PM_PW_MODE_LP 2 /* Power in low-power */ -+#define LIGHT_AON_PM_PW_MODE_ON 3 /* Power on */ -+ -+int light_aon_call_rpc(struct light_aon_ipc *ipc, void *msg, bool have_resp); -+int light_aon_get_handle(struct light_aon_ipc **ipc); -+int light_aon_misc_set_control(struct light_aon_ipc *ipc, u16 resource, u32 ctrl, u32 val); -+int light_aon_misc_get_control(struct light_aon_ipc *ipc, u16 resource, u32 ctrl, u32 *val); -+#endif /* _SC_IPC_H */ -diff --git a/include/linux/firmware/thead/light_event.h b/include/linux/firmware/thead/light_event.h -new file mode 100644 -index 000000000000..a4f99d41c2d1 ---- /dev/null -+++ b/include/linux/firmware/thead/light_event.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+#ifndef _LIGHT_EVENT_H -+#define _LIGHT_EVENT_H -+ -+enum light_rebootmode_index { -+ /* C902 event rebootmode */ -+ LIGHT_EVENT_PMIC_RESET = 0x0, -+ LIGHT_EVENT_PMIC_ONKEY, -+ LIGHT_EVENT_PMIC_POWERUP, -+ -+ /* C910 event rebootmode */ -+ LIGHT_EVENT_SW_REBOOT = 0x20, -+ LIGHT_EVENT_SW_WATCHDOG, -+ LIGHT_EVENT_SW_PANIC, -+ LIGHT_EVENT_SW_HANG, -+ LIGHT_EVENT_MAX, -+}; -+ -+#if IS_ENABLED(CONFIG_LIGHT_REBOOTMODE) -+extern int light_event_set_rebootmode(enum light_rebootmode_index mode); -+extern int light_event_get_rebootmode(enum light_rebootmode_index *mode); -+#else -+static int light_event_set_rebootmode(enum light_rebootmode_index mode) -+{ -+ return 0; -+} -+static int light_event_get_rebootmode(enum light_rebootmode_index *mode) -+{ -+ *mode = LIGHT_EVENT_MAX; -+ -+ return 0; -+} -+#endif -+ -+#endif -diff --git a/include/linux/light_rpmsg.h b/include/linux/light_rpmsg.h -new file mode 100644 -index 000000000000..8930845604a0 ---- /dev/null -+++ b/include/linux/light_rpmsg.h -@@ -0,0 +1,92 @@ -+/* -+ * Copyright (C) 2023 Alibaba Group Holding Limited. -+ */ -+ -+/* -+ * The code contained herein is licensed under the GNU Lesser General -+ * Public License. You may obtain a copy of the GNU Lesser General -+ * Public License Version 2.1 or later at the following locations: -+ * -+ * http://www.opensource.org/licenses/lgpl-license.html -+ * http://www.gnu.org/copyleft/lgpl.html -+ */ -+ -+/* -+ * @file linux/light_rpmsg.h -+ * -+ * @brief Global header file for imx RPMSG -+ * -+ * @ingroup RPMSG -+ */ -+#ifndef __LINUX_LIGHT_RPMSG_H__ -+#define __LINUX_LIGHT_RPMSG_H__ -+ -+#include <linux/rpmsg.h> -+#include <linux/slab.h> -+#include <linux/virtio.h> -+#include <linux/virtio_config.h> -+#include <linux/virtio_ids.h> -+#include <linux/virtio_ring.h> -+ -+/* Category define */ -+#define LIGHT_RMPSG_LIFECYCLE 1 -+#define LIGHT_RPMSG_PMIC 2 -+#define LIGHT_RPMSG_AUDIO 3 -+#define LIGHT_RPMSG_KEY 4 -+#define LIGHT_RPMSG_GPIO 5 -+#define LIGHT_RPMSG_RTC 6 -+#define LIGHT_RPMSG_SENSOR 7 -+/* rpmsg version */ -+#define LIGHT_RMPSG_MAJOR 1 -+#define LIGHT_RMPSG_MINOR 0 -+ -+enum light_rpmsg_variants { -+ LIGHTA, -+ LIGHTB, -+ LIGHT_RPMSG, -+}; -+ -+struct light_virdev { -+ struct virtio_device vdev; -+ unsigned int vring2; -+ struct virtqueue *vq2; -+ int base_vq_id; -+ int num_of_vqs; -+ struct notifier_block nb; -+}; -+ -+struct light_rpmsg_vproc { -+ char *rproc_name; -+ struct mutex lock; -+ struct clk *mu_clk; -+ enum light_rpmsg_variants variant; -+ int vdev_nums; -+ int first_notify; -+#define MAX_VDEV_NUMS 8 -+ struct light_virdev ivdevMAX_VDEV_NUMS; -+ void __iomem *mu_base; -+ struct delayed_work rpmsg_work; -+ struct blocking_notifier_head notifier; -+#define MAX_NUM 10 /* enlarge it if overflow happen */ -+ u32 m4_messageMAX_NUM; -+ u32 in_idx; -+ u32 out_idx; -+ u32 core_id; -+ spinlock_t mu_lock; -+#ifdef CONFIG_PM_SLEEP -+ struct semaphore pm_sem; -+ int sleep_flag; -+#endif -+}; -+ -+struct light_rpmsg_head { -+ u8 cate; -+ u8 major; -+ u8 minor; -+ u8 type; -+ u8 cmd; -+ u8 reserved5; -+} __attribute__ ((packed)); -+ -+#endif /* __LINUX_LIGHT_RPMSG_H__*/ -+ -diff --git a/kernel/panic.c b/kernel/panic.c -index ffa037fa777d..d054d02133f9 100644 ---- a/kernel/panic.c -+++ b/kernel/panic.c -@@ -37,6 +37,7 @@ - #include <linux/context_tracking.h> - #include <trace/events/error_report.h> - #include <asm/sections.h> -+#include <linux/firmware/thead/light_event.h> - - #define PANIC_TIMER_STEP 100 - #define PANIC_BLINK_SPD 18 -@@ -281,6 +282,11 @@ void panic(const char *fmt, ...) - int state = 0; - int old_cpu, this_cpu; - bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers; -+ enum light_rebootmode_index mode; -+ -+ if (!light_event_get_rebootmode(&mode) && -+ mode != LIGHT_EVENT_SW_WATCHDOG) -+ light_event_set_rebootmode(LIGHT_EVENT_SW_PANIC); - - if (panic_on_warn) { - /* -diff --git a/mm/memblock.c b/mm/memblock.c -index e18a25f6ce04..047b45ade06f 100644 ---- a/mm/memblock.c -+++ b/mm/memblock.c -@@ -1779,6 +1779,7 @@ phys_addr_t __init_memblock memblock_end_of_DRAM(void) - - static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit) - { -+ phys_addr_t phys_ram_base = memblock_start_of_DRAM(); - phys_addr_t max_addr = PHYS_ADDR_MAX; - struct memblock_region *r; - -@@ -1788,11 +1789,10 @@ static phys_addr_t __init_memblock __find_max_addr(phys_addr_t limit) - * of those regions, max_addr will keep original value PHYS_ADDR_MAX - */ - for_each_mem_region(r) { -- if (limit <= r->size) { -- max_addr = r->base + limit; -+ if ((r->base + r->size) >= (phys_ram_base + limit)) { -+ max_addr = phys_ram_base + limit; - break; - } -- limit -= r->size; - } - - return max_addr; -diff --git a/scripts/package/builddeb b/scripts/package/builddeb -index d7dd0d04c70c..259668daea63 100755 ---- a/scripts/package/builddeb -+++ b/scripts/package/builddeb -@@ -85,7 +85,7 @@ install_linux_image () { - case "${SRCARCH}" in - um) - installed_image_path="usr/bin/linux-${KERNELRELEASE}";; -- parisc|mips|powerpc) -+ parisc|mips|powerpc|riscv*) - installed_image_path="boot/vmlinux-${KERNELRELEASE}";; - *) - installed_image_path="boot/vmlinuz-${KERNELRELEASE}";; -diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c -index af2b2bb9a8ff..d825d925f641 100644 ---- a/sound/pci/hda/hda_intel.c -+++ b/sound/pci/hda/hda_intel.c -@@ -298,8 +298,7 @@ enum { - - /* quirks for ATI/AMD HDMI */ - #define AZX_DCAPS_PRESET_ATI_HDMI \ -- (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB|\ -- AZX_DCAPS_NO_MSI64) -+ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB) - - /* quirks for ATI HDMI with snoop off */ - #define AZX_DCAPS_PRESET_ATI_HDMI_NS \ -@@ -313,7 +312,7 @@ enum { - - /* quirks for Nvidia */ - #define AZX_DCAPS_PRESET_NVIDIA \ -- (AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\ -+ (AZX_DCAPS_CORBRP_SELF_CLEAR |\ - AZX_DCAPS_SNOOP_TYPE(NVIDIA)) - - #define AZX_DCAPS_PRESET_CTHDA \ -diff --git a/tools/perf/pmu-events/arch/riscv/mapfile.csv b/tools/perf/pmu-events/arch/riscv/mapfile.csv -index c61b3d6ef616..b42b65d09c36 100644 ---- a/tools/perf/pmu-events/arch/riscv/mapfile.csv -+++ b/tools/perf/pmu-events/arch/riscv/mapfile.csv -@@ -15,3 +15,4 @@ - # - #MVENDORID-MARCHID-MIMPID,Version,Filename,EventType - 0x489-0x8000000000000007-0x:xdigit:+,v1,sifive/u74,core -+0x5b7-0x0-0x0,v1,thead/c900-legacy,core -diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json -new file mode 100644 -index 000000000000..2b142348d635 ---- /dev/null -+++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json -@@ -0,0 +1,67 @@ -+ -+ { -+ "EventName": "L1_ICACHE_ACCESS", -+ "EventCode": "0x00000001", -+ "BriefDescription": "L1 instruction cache access" -+ }, -+ { -+ "EventName": "L1_ICACHE_MISS", -+ "EventCode": "0x00000002", -+ "BriefDescription": "L1 instruction cache miss" -+ }, -+ { -+ "EventName": "ITLB_MISS", -+ "EventCode": "0x00000003", -+ "BriefDescription": "I-UTLB miss" -+ }, -+ { -+ "EventName": "DTLB_MISS", -+ "EventCode": "0x00000004", -+ "BriefDescription": "D-UTLB miss" -+ }, -+ { -+ "EventName": "JTLB_MISS", -+ "EventCode": "0x00000005", -+ "BriefDescription": "JTLB miss" -+ }, -+ { -+ "EventName": "L1_DCACHE_READ_ACCESS", -+ "EventCode": "0x0000000c", -+ "BriefDescription": "L1 data cache read access" -+ }, -+ { -+ "EventName": "L1_DCACHE_READ_MISS", -+ "EventCode": "0x0000000d", -+ "BriefDescription": "L1 data cache read miss" -+ }, -+ { -+ "EventName": "L1_DCACHE_WRITE_ACCESS", -+ "EventCode": "0x0000000e", -+ "BriefDescription": "L1 data cache write access" -+ }, -+ { -+ "EventName": "L1_DCACHE_WRITE_MISS", -+ "EventCode": "0x0000000f", -+ "BriefDescription": "L1 data cache write miss" -+ }, -+ { -+ "EventName": "LL_CACHE_READ_ACCESS", -+ "EventCode": "0x00000010", -+ "BriefDescription": "LL Cache read access" -+ }, -+ { -+ "EventName": "LL_CACHE_READ_MISS", -+ "EventCode": "0x00000011", -+ "BriefDescription": "LL Cache read miss" -+ }, -+ { -+ "EventName": "LL_CACHE_WRITE_ACCESS", -+ "EventCode": "0x00000012", -+ "BriefDescription": "LL Cache write access" -+ }, -+ { -+ "EventName": "LL_CACHE_WRITE_MISS", -+ "EventCode": "0x00000013", -+ "BriefDescription": "LL Cache write miss" -+ } -+ -diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json -new file mode 100644 -index 000000000000..9b4a032186a7 ---- /dev/null -+++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json -@@ -0,0 +1,68 @@ -+ -+ { -+ "ArchStdEvent": "FW_MISALIGNED_LOAD" -+ }, -+ { -+ "ArchStdEvent": "FW_MISALIGNED_STORE" -+ }, -+ { -+ "ArchStdEvent": "FW_ACCESS_LOAD" -+ }, -+ { -+ "ArchStdEvent": "FW_ACCESS_STORE" -+ }, -+ { -+ "ArchStdEvent": "FW_ILLEGAL_INSN" -+ }, -+ { -+ "ArchStdEvent": "FW_SET_TIMER" -+ }, -+ { -+ "ArchStdEvent": "FW_IPI_SENT" -+ }, -+ { -+ "ArchStdEvent": "FW_IPI_RECEIVED" -+ }, -+ { -+ "ArchStdEvent": "FW_FENCE_I_SENT" -+ }, -+ { -+ "ArchStdEvent": "FW_FENCE_I_RECEIVED" -+ }, -+ { -+ "ArchStdEvent": "FW_SFENCE_VMA_SENT" -+ }, -+ { -+ "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED" -+ }, -+ { -+ "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED" -+ }, -+ { -+ "ArchStdEvent": "FW_SFENCE_VMA_ASID_RECEIVED" -+ }, -+ { -+ "ArchStdEvent": "FW_HFENCE_GVMA_SENT" -+ }, -+ { -+ "ArchStdEvent": "FW_HFENCE_GVMA_RECEIVED" -+ }, -+ { -+ "ArchStdEvent": "FW_HFENCE_GVMA_VMID_SENT" -+ }, -+ { -+ "ArchStdEvent": "FW_HFENCE_GVMA_VMID_RECEIVED" -+ }, -+ { -+ "ArchStdEvent": "FW_HFENCE_VVMA_SENT" -+ }, -+ { -+ "ArchStdEvent": "FW_HFENCE_VVMA_RECEIVED" -+ }, -+ { -+ "ArchStdEvent": "FW_HFENCE_VVMA_ASID_SENT" -+ }, -+ { -+ "ArchStdEvent": "FW_HFENCE_VVMA_ASID_RECEIVED" -+ } -+ -diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json -new file mode 100644 -index 000000000000..c822b5373333 ---- /dev/null -+++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json -@@ -0,0 +1,72 @@ -+ -+ { -+ "EventName": "INST_BRANCH_MISPREDICT", -+ "EventCode": "0x00000006", -+ "BriefDescription": "Mispredicted branch instructions" -+ }, -+ { -+ "EventName": "INST_BRANCH", -+ "EventCode": "0x00000007", -+ "BriefDescription": "Retired branch instructions" -+ }, -+ { -+ "EventName": "INST_JMP_MISPREDICT", -+ "EventCode": "0x00000008", -+ "BriefDescription": "Indirect branch mispredict" -+ }, -+ { -+ "EventName": "INST_JMP", -+ "EventCode": "0x00000009", -+ "BriefDescription": "Retired jmp instructions" -+ }, -+ { -+ "EventName": "INST_STORE", -+ "EventCode": "0x0000000b", -+ "BriefDescription": "Retired store instructions" -+ }, -+ { -+ "EventName": "INST_ALU", -+ "EventCode": "0x0000001d", -+ "BriefDescription": "Retired ALU instructions" -+ }, -+ { -+ "EventName": "INST_LDST", -+ "EventCode": "0x0000001e", -+ "BriefDescription": "Retired Load/Store instructions" -+ }, -+ { -+ "EventName": "INST_VECTOR", -+ "EventCode": "0x0000001f", -+ "BriefDescription": "Retired Vector instructions" -+ }, -+ { -+ "EventName": "INST_CSR", -+ "EventCode": "0x00000020", -+ "BriefDescription": "Retired CSR instructions" -+ }, -+ { -+ "EventName": "INST_SYNC", -+ "EventCode": "0x00000021", -+ "BriefDescription": "Retired sync instructions (AMO/LR/SC instructions)" -+ }, -+ { -+ "EventName": "INST_UNALIGNED_ACCESS", -+ "EventCode": "0x00000022", -+ "BriefDescription": "Retired Store/Load instructions with unaligned memory access" -+ }, -+ { -+ "EventName": "INST_ECALL", -+ "EventCode": "0x00000025", -+ "BriefDescription": "Retired ecall instructions" -+ }, -+ { -+ "EventName": "INST_LONG_JP", -+ "EventCode": "0x00000026", -+ "BriefDescription": "Retired long jump instructions" -+ }, -+ { -+ "EventName": "INST_FP", -+ "EventCode": "0x0000002a", -+ "BriefDescription": "Retired FPU instructions" -+ } -+ -diff --git a/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json -new file mode 100644 -index 000000000000..0ab6f288af91 ---- /dev/null -+++ b/tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json -@@ -0,0 +1,80 @@ -+ -+ { -+ "EventName": "LSU_SPEC_FAIL", -+ "EventCode": "0x0000000a", -+ "BriefDescription": "LSU speculation fail" -+ }, -+ { -+ "EventName": "IDU_RF_PIPE_FAIL", -+ "EventCode": "0x00000014", -+ "BriefDescription": "Instruction decode unit launch pipeline failed in RF state" -+ }, -+ { -+ "EventName": "IDU_RF_REG_FAIL", -+ "EventCode": "0x00000015", -+ "BriefDescription": "Instruction decode unit launch register file fail in RF state" -+ }, -+ { -+ "EventName": "IDU_RF_INSTRUCTION", -+ "EventCode": "0x00000016", -+ "BriefDescription": "retired instruction count of Instruction decode unit in RF (Register File) stage" -+ }, -+ { -+ "EventName": "LSU_4K_STALL", -+ "EventCode": "0x00000017", -+ "BriefDescription": "LSU stall times for long distance data access (Over 4K)", -+ "PublicDescription": "This stall occurs when translate virtual address with page offset over 4k" -+ }, -+ { -+ "EventName": "LSU_OTHER_STALL", -+ "EventCode": "0x00000018", -+ "BriefDescription": "LSU stall times for other reasons (except the 4k stall)" -+ }, -+ { -+ "EventName": "LSU_SQ_OTHER_DIS", -+ "EventCode": "0x00000019", -+ "BriefDescription": "LSU store queue discard others" -+ }, -+ { -+ "EventName": "LSU_SQ_DATA_DISCARD", -+ "EventCode": "0x0000001a", -+ "BriefDescription": "LSU store queue discard data (uops)" -+ }, -+ { -+ "EventName": "BRANCH_DIRECTION_MISPREDICTION", -+ "EventCode": "0x0000001b", -+ "BriefDescription": "Branch misprediction in BTB" -+ }, -+ { -+ "EventName": "BRANCH_DIRECTION_PREDICTION", -+ "EventCode": "0x0000001c", -+ "BriefDescription": "All branch prediction in BTB", -+ "PublicDescription": "This event including both successful prediction and failed prediction in BTB" -+ }, -+ { -+ "EventName": "INTERRUPT_ACK_COUNT", -+ "EventCode": "0x00000023", -+ "BriefDescription": "acknowledged interrupt count" -+ }, -+ { -+ "EventName": "INTERRUPT_OFF_CYCLE", -+ "EventCode": "0x00000024", -+ "BriefDescription": "PLIC arbitration time when the interrupt is not responded", -+ "PublicDescription": "The arbitration time is recorded while meeting any of the following:\n- CPU is M-mode and MIE == 0\n- CPU is S-mode and delegation and SIE == 0\n" -+ }, -+ { -+ "EventName": "IFU_STALLED_CYCLE", -+ "EventCode": "0x00000027", -+ "BriefDescription": "Number of stall cycles of the instruction fetch unit (IFU)." -+ }, -+ { -+ "EventName": "IDU_STALLED_CYCLE", -+ "EventCode": "0x00000028", -+ "BriefDescription": "hpcp_backend_stall Number of stall cycles of the instruction decoding unit (IDU) and next-level pipeline unit." -+ }, -+ { -+ "EventName": "SYNC_STALL", -+ "EventCode": "0x00000029", -+ "BriefDescription": "Sync instruction stall cycle fence/fence.i/sync/sfence" -+ } -+ --- -2.34.1 -
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2