From 9d1e1ac5c1d745bc8108246848152902fd539f26 Mon Sep 17 00:00:00 2001 From: Mingzheng Xing Date: Wed, 5 Jun 2024 22:39:47 +0800 Subject: [PATCH] riscv kernel Signed-off-by: Mingzheng Xing --- .../bindings/gpio/snps,dw-apb-gpio.yaml | 2 + .../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 + .../bindings/usb/thead,th1520-usb.yaml | 73 ++ MAINTAINERS | 2 + arch/riscv/Kconfig | 14 +- arch/riscv/Kconfig.errata | 1 + arch/riscv/Kconfig.socs | 14 + arch/riscv/Makefile | 19 +- arch/riscv/Makefile.isa | 18 + arch/riscv/boot/dts/Makefile | 1 + arch/riscv/boot/dts/sophgo/Makefile | 7 + .../riscv/boot/dts/sophgo/mango-2sockets.dtsi | 699 ++++++++++ .../boot/dts/sophgo/mango-clock-socket0.dtsi | 124 ++ .../boot/dts/sophgo/mango-clock-socket1.dtsi | 124 ++ .../boot/dts/sophgo/mango-cpus-socket0.dtsi | 1148 ++++++++++++++++ .../boot/dts/sophgo/mango-cpus-socket1.dtsi | 1149 +++++++++++++++++ .../boot/dts/sophgo/mango-milkv-pioneer.dts | 170 +++ .../riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi | 81 ++ .../dts/sophgo/mango-pcie-3rc-capricorn.dtsi | 116 ++ .../boot/dts/sophgo/mango-pcie-3rc-v2.dtsi | 115 ++ .../riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi | 112 ++ .../boot/dts/sophgo/mango-pcie-4rc-v2.dtsi | 155 +++ .../riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi | 151 +++ arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi | 434 +++++++ .../dts/sophgo/mango-sophgo-capricorn.dts | 57 + .../boot/dts/sophgo/mango-sophgo-pisces.dts | 58 + .../boot/dts/sophgo/mango-sophgo-x4evb.dts | 144 +++ .../boot/dts/sophgo/mango-sophgo-x8evb.dts | 172 +++ .../boot/dts/sophgo/mango-top-intc2.dtsi | 62 + .../boot/dts/sophgo/mango-yixin-s2110.dts | 63 + arch/riscv/boot/dts/sophgo/mango.dtsi | 938 ++++++++++++++ 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 | 3 + arch/riscv/configs/openeuler_defconfig | 265 +++- arch/riscv/errata/thead/errata.c | 69 +- arch/riscv/include/asm/barrier.h | 22 + arch/riscv/include/asm/errata_list.h | 50 +- arch/riscv/include/asm/fixmap.h | 13 + arch/riscv/include/asm/highmem.h | 13 + arch/riscv/include/asm/io.h | 4 + arch/riscv/include/asm/kexec.h | 1 + arch/riscv/include/asm/pgtable-64.h | 14 +- arch/riscv/include/asm/pgtable.h | 34 +- arch/riscv/include/asm/sparsemem.h | 2 +- arch/riscv/include/asm/switch_to.h | 15 + arch/riscv/include/asm/timex.h | 15 + arch/riscv/include/asm/vdso/gettimeofday.h | 20 + arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/elf_kexec.c | 6 + arch/riscv/kernel/image_kexec.c | 305 +++++ arch/riscv/kernel/machine_kexec_file.c | 1 + arch/riscv/kernel/module.c | 83 +- arch/riscv/kernel/process.c | 3 + arch/riscv/kvm/vcpu_timer.c | 8 + arch/riscv/mm/init.c | 175 ++- arch/riscv/mm/pageattr.c | 275 +--- drivers/base/arch_numa.c | 4 + drivers/char/ipmi/ipmi_si_hardcode.c | 26 +- drivers/char/ipmi/ipmi_si_intf.c | 3 +- drivers/char/ipmi/ipmi_si_pci.c | 6 + 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/clocksource/dw_apb_timer_of.c | 24 + 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/amd/display/Kconfig | 1 + .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 6 +- drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 + drivers/gpu/drm/drm_gem_vram_helper.c | 2 +- drivers/gpu/drm/radeon/radeon_drv.c | 7 +- drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 + drivers/gpu/drm/ttm/ttm_bo_util.c | 5 +- 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/mtd/spi-nor/controllers/Kconfig | 11 + drivers/mtd/spi-nor/controllers/Makefile | 1 + .../mtd/spi-nor/controllers/sophgo-spifmc.c | 445 +++++++ drivers/mtd/spi-nor/gigadevice.c | 14 + drivers/net/ethernet/intel/i40e/i40e_common.c | 3 +- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 2 +- 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 | 972 ++++++++++++++ .../controller/cadence/pcie-cadence-sophgo.h | 17 + drivers/pci/msi/msi.c | 97 +- 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/rtc/Kconfig | 6 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-astbmc.c | 535 ++++++++ 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/kexec_core.c | 2 +- kernel/panic.c | 6 + kernel/sched/fair.c | 3 + kernel/time/tick-oneshot.c | 2 +- mm/memblock.c | 28 +- scripts/package/builddeb | 2 +- sound/pci/hda/hda_intel.c | 5 +- tools/lib/perf/cpumap.c | 10 +- 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 ++ 211 files changed, 29953 insertions(+), 500 deletions(-) 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/usb/thead,th1520-usb.yaml create mode 100644 arch/riscv/Makefile.isa create mode 100644 arch/riscv/boot/dts/sophgo/Makefile create mode 100644 arch/riscv/boot/dts/sophgo/mango-2sockets.dtsi create mode 100644 arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi create mode 100644 arch/riscv/boot/dts/sophgo/mango-clock-socket1.dtsi create mode 100644 arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi create mode 100644 arch/riscv/boot/dts/sophgo/mango-cpus-socket1.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-capricorn.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-v2.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-capricorn.dts create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-pisces.dts 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-yixin-s2110.dts create mode 100644 arch/riscv/boot/dts/sophgo/mango.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 arch/riscv/include/asm/highmem.h create mode 100644 arch/riscv/kernel/image_kexec.c 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/mtd/spi-nor/controllers/sophgo-spifmc.c 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/rtc/rtc-astbmc.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/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 5c2769dc689a..eeed9d2b940e 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 @@ -591,6 +592,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 + +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 + +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 + +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 + +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 + + 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/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 + +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/MAINTAINERS b/MAINTAINERS index 1c70622103e0..e41153dd877b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18529,6 +18529,8 @@ M: Fu Wei 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 diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bb40f2eae472..12aba075395c 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -39,6 +39,7 @@ config RISCV select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_UBSAN_SANITIZE_ALL select ARCH_HAS_VDSO_DATA + select ARCH_KEEP_MEMBLOCK select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT select ARCH_STACKWALK @@ -155,7 +156,7 @@ config RISCV select PCI_MSI if PCI select RISCV_ALTERNATIVE if !XIP_KERNEL select RISCV_INTC - select RISCV_TIMER if RISCV_SBI + select RISCV_TIMER if RISCV_SBI && !SOPHGO_MULTI_CHIP_CLOCK_SYNC select SIFIVE_PLIC select SPARSE_IRQ select SYSCTL_EXCEPTION_TRACE @@ -402,6 +403,15 @@ config TUNE_GENERIC endchoice +config HIGHMEM + bool "High Memory Support" + depends on MMU + select KMAP_LOCAL + default y + help + Enable high memory support on riscv64 which uses supports + max 39-bit virtual address spaces. + # Common NUMA Features config NUMA bool "NUMA Memory Allocation and Scheduler Support" @@ -501,7 +511,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..1adb9086fa42 100644 --- a/arch/riscv/Kconfig.socs +++ b/arch/riscv/Kconfig.socs @@ -22,6 +22,20 @@ 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 SOPHGO_MULTI_CHIP_CLOCK_SYNC + bool "Sophgo multi-chip clock synchronous" + depends on ARCH_SOPHGO + default n + help + To solve the problem of asynchronous multi-chip clocks, + the local timer has been replaced with an APB timer. + config ARCH_STARFIVE def_bool SOC_STARFIVE diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index b43a6bb7e4dc..c33a055a06f3 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -54,22 +54,7 @@ endif endif endif -# ISA string setting -riscv-march-$(CONFIG_ARCH_RV32I) := rv32ima -riscv-march-$(CONFIG_ARCH_RV64I) := rv64ima -riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd -riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c -riscv-march-$(CONFIG_RISCV_ISA_V) := $(riscv-march-y)v - -ifdef CONFIG_TOOLCHAIN_NEEDS_OLD_ISA_SPEC -KBUILD_CFLAGS += -Wa,-misa-spec=2.2 -KBUILD_AFLAGS += -Wa,-misa-spec=2.2 -else -riscv-march-$(CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI) := $(riscv-march-y)_zicsr_zifencei -endif - -# Check if the toolchain supports Zihintpause extension -riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE) := $(riscv-march-y)_zihintpause +include $(srctree)/arch/riscv/Makefile.isa # Remove F,D,V from isa string for all. Keep extensions between "fd" and "v" by # matching non-v and non-multi-letter extensions out with the filter ([^v_]*) @@ -152,7 +137,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/Makefile.isa b/arch/riscv/Makefile.isa new file mode 100644 index 000000000000..322a83958b96 --- /dev/null +++ b/arch/riscv/Makefile.isa @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# ISA string setting +riscv-march-$(CONFIG_ARCH_RV32I) := rv32ima +riscv-march-$(CONFIG_ARCH_RV64I) := rv64ima +riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd +riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c +riscv-march-$(CONFIG_RISCV_ISA_V) := $(riscv-march-y)v + +ifdef CONFIG_TOOLCHAIN_NEEDS_OLD_ISA_SPEC +KBUILD_CFLAGS += -Wa,-misa-spec=2.2 +KBUILD_AFLAGS += -Wa,-misa-spec=2.2 +else +riscv-march-$(CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI) := $(riscv-march-y)_zicsr_zifencei +endif + +# Check if the toolchain supports Zihintpause extension +riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE) := $(riscv-march-y)_zihintpause 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..6e7c7763b0a9 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-x4evb.dtb +dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-x8evb.dtb +dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-pisces.dtb +dtb-$(CONFIG_ARCH_SOPHGO) += mango-sophgo-capricorn.dtb +dtb-$(CONFIG_ARCH_SOPHGO) += mango-milkv-pioneer.dtb +dtb-$(CONFIG_ARCH_SOPHGO) += mango-yixin-s2110.dtb diff --git a/arch/riscv/boot/dts/sophgo/mango-2sockets.dtsi b/arch/riscv/boot/dts/sophgo/mango-2sockets.dtsi new file mode 100644 index 000000000000..8c6e22c33cef --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-2sockets.dtsi @@ -0,0 +1,699 @@ +#define NR_CPUS 128 + +#include "mango.dtsi" +#if NR_CPUS > 64 +#include "mango-cpus-socket1.dtsi" +#endif +#include "mango-clock-socket1.dtsi" + +/ { + /delete-node/ distance-map; + distance-map { + compatible = "numa-distance-map-v1"; + distance-matrix = <0 0 10>, //chip0 + <0 1 15>, + <0 2 25>, + <0 3 30>, + <0 4 110>, + <0 5 115>, + <0 6 125>, + <0 7 130>, + <1 0 15>, + <1 1 10>, + <1 2 30>, + <1 3 25>, + <1 4 115>, + <1 5 110>, + <1 6 130>, + <1 7 125>, + <2 0 25>, + <2 1 30>, + <2 2 10>, + <2 3 15>, + <2 4 125>, + <2 5 130>, + <2 6 110>, + <2 7 115>, + <3 0 30>, + <3 1 25>, + <3 2 15>, + <3 3 10>, + <3 4 130>, + <3 5 125>, + <3 6 115>, + <3 7 110>, + <4 0 110>, //chip1 + <4 1 115>, + <4 2 125>, + <4 3 130>, + <4 4 10>, + <4 5 15>, + <4 6 25>, + <4 7 30>, + <5 0 115>, + <5 1 110>, + <5 2 130>, + <5 3 125>, + <5 4 15>, + <5 5 10>, + <5 6 30>, + <5 7 25>, + <6 0 125>, + <6 1 130>, + <6 2 110>, + <6 3 115>, + <6 4 25>, + <6 5 30>, + <6 6 10>, + <6 7 15>, + <7 0 130>, + <7 1 125>, + <7 2 115>, + <7 3 110>, + <7 4 30>, + <7 5 25>, + <7 6 15>, + <7 7 10>; + }; + + soc { +#if NR_CPUS > 64 + /delete-node/ clint-mswi@7094000000; + 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 + + // chip 1 + &cpu64_intc 3 + &cpu65_intc 3 + &cpu66_intc 3 + &cpu67_intc 3 + &cpu68_intc 3 + &cpu69_intc 3 + &cpu70_intc 3 + &cpu71_intc 3 + &cpu72_intc 3 + &cpu73_intc 3 + &cpu74_intc 3 + &cpu75_intc 3 + &cpu76_intc 3 + &cpu77_intc 3 + &cpu78_intc 3 + &cpu79_intc 3 + &cpu80_intc 3 + &cpu81_intc 3 + &cpu82_intc 3 + &cpu83_intc 3 + &cpu84_intc 3 + &cpu85_intc 3 + &cpu86_intc 3 + &cpu87_intc 3 + &cpu88_intc 3 + &cpu89_intc 3 + &cpu90_intc 3 + &cpu91_intc 3 + &cpu92_intc 3 + &cpu93_intc 3 + &cpu94_intc 3 + &cpu95_intc 3 + &cpu96_intc 3 + &cpu97_intc 3 + &cpu98_intc 3 + &cpu99_intc 3 + &cpu100_intc 3 + &cpu101_intc 3 + &cpu102_intc 3 + &cpu103_intc 3 + &cpu104_intc 3 + &cpu105_intc 3 + &cpu106_intc 3 + &cpu107_intc 3 + &cpu108_intc 3 + &cpu109_intc 3 + &cpu110_intc 3 + &cpu111_intc 3 + &cpu112_intc 3 + &cpu113_intc 3 + &cpu114_intc 3 + &cpu115_intc 3 + &cpu116_intc 3 + &cpu117_intc 3 + &cpu118_intc 3 + &cpu119_intc 3 + &cpu120_intc 3 + &cpu121_intc 3 + &cpu122_intc 3 + &cpu123_intc 3 + &cpu124_intc 3 + &cpu125_intc 3 + &cpu126_intc 3 + &cpu127_intc 3 + >; + }; + + clint_mtimer16: clint-mtimer@70ac100000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac100000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu64_intc 7 + &cpu65_intc 7 + &cpu66_intc 7 + &cpu67_intc 7 + >; + }; + + clint_mtimer17: clint-mtimer@70ac110000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac110000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu68_intc 7 + &cpu69_intc 7 + &cpu70_intc 7 + &cpu71_intc 7 + >; + }; + + clint_mtimer18: clint-mtimer@70ac120000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac120000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu72_intc 7 + &cpu73_intc 7 + &cpu74_intc 7 + &cpu75_intc 7 + >; + }; + + clint_mtimer19: clint-mtimer@70ac130000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac130000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu76_intc 7 + &cpu77_intc 7 + &cpu78_intc 7 + &cpu79_intc 7 + >; + }; + + clint_mtimer20: clint-mtimer@70ac140000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac140000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu80_intc 7 + &cpu81_intc 7 + &cpu82_intc 7 + &cpu83_intc 7 + >; + }; + + clint_mtimer21: clint-mtimer@70ac150000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac150000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu84_intc 7 + &cpu85_intc 7 + &cpu86_intc 7 + &cpu87_intc 7 + >; + }; + + clint_mtimer22: clint-mtimer@70ac160000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac160000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu88_intc 7 + &cpu89_intc 7 + &cpu90_intc 7 + &cpu91_intc 7 + >; + }; + + clint_mtimer23: clint-mtimer@70ac170000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac170000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu92_intc 7 + &cpu93_intc 7 + &cpu94_intc 7 + &cpu95_intc 7 + >; + }; + + clint_mtimer24: clint-mtimer@70ac180000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac180000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu96_intc 7 + &cpu97_intc 7 + &cpu98_intc 7 + &cpu99_intc 7 + >; + }; + + clint_mtimer25: clint-mtimer@70ac190000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac190000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu100_intc 7 + &cpu101_intc 7 + &cpu102_intc 7 + &cpu103_intc 7 + >; + }; + + clint_mtimer26: clint-mtimer@70ac1a0000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac1a0000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu104_intc 7 + &cpu105_intc 7 + &cpu106_intc 7 + &cpu107_intc 7 + >; + }; + + clint_mtimer27: clint-mtimer@70ac1b0000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac1b0000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu108_intc 7 + &cpu109_intc 7 + &cpu110_intc 7 + &cpu111_intc 7 + >; + }; + + clint_mtimer28: clint-mtimer@70ac1c0000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac1c0000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu112_intc 7 + &cpu113_intc 7 + &cpu114_intc 7 + &cpu115_intc 7 + >; + }; + + clint_mtimer29: clint-mtimer@70ac1d0000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac1d0000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu116_intc 7 + &cpu117_intc 7 + &cpu118_intc 7 + &cpu119_intc 7 + >; + }; + + clint_mtimer30: clint-mtimer@70ac1e0000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac1e0000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu120_intc 7 + &cpu121_intc 7 + &cpu122_intc 7 + &cpu123_intc 7 + >; + }; + + clint_mtimer31: clint-mtimer@70ac1f0000 { + compatible = "thead,c900-clint-mtimer"; + reg = <0x00000070 0xac1f0000 0x00000000 0x00007ff8>; + interrupts-extended = < + &cpu124_intc 7 + &cpu125_intc 7 + &cpu126_intc 7 + &cpu127_intc 7 + >; + }; +#endif + + /delete-node/ interrupt-controller@7090000000; + 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 + +#if NR_CPUS > 64 + //chip 1 + &cpu64_intc 11 &cpu64_intc 9 + &cpu65_intc 11 &cpu65_intc 9 + &cpu66_intc 11 &cpu66_intc 9 + &cpu67_intc 11 &cpu67_intc 9 + &cpu68_intc 11 &cpu68_intc 9 + &cpu69_intc 11 &cpu69_intc 9 + &cpu70_intc 11 &cpu70_intc 9 + &cpu71_intc 11 &cpu71_intc 9 + &cpu72_intc 11 &cpu72_intc 9 + &cpu73_intc 11 &cpu73_intc 9 + &cpu74_intc 11 &cpu74_intc 9 + &cpu75_intc 11 &cpu75_intc 9 + &cpu76_intc 11 &cpu76_intc 9 + &cpu77_intc 11 &cpu77_intc 9 + &cpu78_intc 11 &cpu78_intc 9 + &cpu79_intc 11 &cpu79_intc 9 + &cpu80_intc 11 &cpu80_intc 9 + &cpu81_intc 11 &cpu81_intc 9 + &cpu82_intc 11 &cpu82_intc 9 + &cpu83_intc 11 &cpu83_intc 9 + &cpu84_intc 11 &cpu84_intc 9 + &cpu85_intc 11 &cpu85_intc 9 + &cpu86_intc 11 &cpu86_intc 9 + &cpu87_intc 11 &cpu87_intc 9 + &cpu88_intc 11 &cpu88_intc 9 + &cpu89_intc 11 &cpu89_intc 9 + &cpu90_intc 11 &cpu90_intc 9 + &cpu91_intc 11 &cpu91_intc 9 + &cpu92_intc 11 &cpu92_intc 9 + &cpu93_intc 11 &cpu93_intc 9 + &cpu94_intc 11 &cpu94_intc 9 + &cpu95_intc 11 &cpu95_intc 9 + &cpu96_intc 11 &cpu96_intc 9 + &cpu97_intc 11 &cpu97_intc 9 + &cpu98_intc 11 &cpu98_intc 9 + &cpu99_intc 11 &cpu99_intc 9 + &cpu100_intc 11 &cpu100_intc 9 + &cpu101_intc 11 &cpu101_intc 9 + &cpu102_intc 11 &cpu102_intc 9 + &cpu103_intc 11 &cpu103_intc 9 + &cpu104_intc 11 &cpu104_intc 9 + &cpu105_intc 11 &cpu105_intc 9 + &cpu106_intc 11 &cpu106_intc 9 + &cpu107_intc 11 &cpu107_intc 9 + &cpu108_intc 11 &cpu108_intc 9 + &cpu109_intc 11 &cpu109_intc 9 + &cpu110_intc 11 &cpu110_intc 9 + &cpu111_intc 11 &cpu111_intc 9 + &cpu112_intc 11 &cpu112_intc 9 + &cpu113_intc 11 &cpu113_intc 9 + &cpu114_intc 11 &cpu114_intc 9 + &cpu115_intc 11 &cpu115_intc 9 + &cpu116_intc 11 &cpu116_intc 9 + &cpu117_intc 11 &cpu117_intc 9 + &cpu118_intc 11 &cpu118_intc 9 + &cpu119_intc 11 &cpu119_intc 9 + &cpu120_intc 11 &cpu120_intc 9 + &cpu121_intc 11 &cpu121_intc 9 + &cpu122_intc 11 &cpu122_intc 9 + &cpu123_intc 11 &cpu123_intc 9 + &cpu124_intc 11 &cpu124_intc 9 + &cpu125_intc 11 &cpu125_intc 9 + &cpu126_intc 11 &cpu126_intc 9 + &cpu127_intc 11 &cpu127_intc 9 +#endif + >; + reg = <0x00000070 0x90000000 0x00000000 0x04000000>; + reg-names = "control"; + riscv,max-priority = <7>; + riscv,ndev = <448>; + }; + + top1_misc: top_misc_ctrl@f030010000 { + compatible = "syscon"; + reg = <0xf0 0x30010000 0x0 0x8000>; + }; + + rst1: reset1-controller { + #reset-cells = <1>; + compatible = "bitmain,reset"; + subctrl-syscon = <&top1_misc>; + top_rst_offset = <0x3000>; + nr_resets = ; + }; + + gpio3: gpio@f030009000 { + compatible = "snps,dw-apb-gpio"; + reg = <0xf0 0x30009000 0x0 0x400>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&s1_div_clk GATE_CLK_APB_GPIO>, + <&s1_div_clk GATE_CLK_GPIO_DB>; + clock-names = "bus", "db"; + + port3a: 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 = ; + }; + }; + + ethernet1: ethernet@f040026000 { + compatible = "bitmain,ethernet"; + reg = <0xf0 0x40026000 0x0 0x4000>; + interrupt-parent = <&intc>; + interrupts = ; + interrupt-names = "macirq"; + clock-names = "clk_tx", "gate_clk_tx", "stmmaceth", "ptp_ref", "gate_clk_ref"; + clocks = <&s1_div_clk DIV_CLK_FPLL_TX_ETH0>, + <&s1_div_clk GATE_CLK_TX_ETH0>, + <&s1_div_clk GATE_CLK_AXI_ETH0>, + <&s1_div_clk GATE_CLK_PTP_REF_I_ETH0>, + <&s1_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 = <&port3a 27 0>; + phy-handle = <&phy1>; + mdio { + #address-cells = <0x1>; + #size-cells = <0x0>; + compatible = "snps,dwmac-mdio"; + phy1: phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x0>; + }; + }; + }; + + emmc1: bm-emmc@f04002A000 { + compatible = "bitmain,bm-emmc"; + reg = <0xf0 0x4002A000 0x0 0x1000>; + reg-names = "core_mem"; + interrupt-parent = <&intc>; + interrupts = ; + bus-width = <4>; + non-removable; + no-sdio; + no-sd; + resets = <&rst1 RST_EMMC>; + reset-names = "emmc"; + clocks = + <&s1_div_clk GATE_CLK_EMMC_100M>, + <&s1_div_clk GATE_CLK_AXI_EMMC>, + <&s1_div_clk GATE_CLK_100K_EMMC>; + clock-names = + "clk_gate_emmc", + "clk_gate_axi_emmc", + "clk_gate_100k_emmc"; + }; + + sd1: bm-sd@f04002B000 { + compatible = "bitmain,bm-sd"; + reg = <0xf0 0x4002B000 0x0 0x1000>; + reg-names = "core_mem"; + interrupt-parent = <&intc>; + interrupts = ; + bus-width = <4>; + no-sdio; + no-mmc; + resets = <&rst1 RST_SD>; + reset-names = "sdio"; + clocks = + <&s1_div_clk GATE_CLK_SD_100M>, + <&s1_div_clk GATE_CLK_AXI_SD>, + <&s1_div_clk GATE_CLK_100K_SD>; + clock-names = + "clk_gate_sd", + "clk_gate_axi_sd", + "clk_gate_100k_sd"; + }; + }; + + spifmc2: flash-controller@f000180000 { + compatible = "sophgo,spifmc"; + reg = <0xf0 0x00180000 0x0 0x1000000>; + reg-names = "memory"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&intc>; + interrupts = ; + clock-frequency = <100000000>; + clocks = <&s1_div_clk GATE_CLK_AHB_SF>; + flash@0 { + reg = <0>; + compatible = "jedec,spi-nor"; + }; + }; + + spifmc3: flash-controller@f002180000 { + compatible = "sophgo,spifmc"; + reg = <0xf0 0x02180000 0x0 0x1000000>; + reg-names = "memory"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&intc>; + interrupts = ; + clock-frequency = <100000000>; + clocks = <&s1_div_clk GATE_CLK_AHB_SF>; + flash@0 { + reg = <0>; + compatible = "jedec,spi-nor"; + }; + }; + + aliases { + serial0 = &uart0; + ethernet0 = ðernet0; + ethernet1 = ðernet1; + }; +}; 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 = ; + mode = ; + subctrl-syscon = <&top_misc>; + clocks = <&cgi>; + clock-output-names = "mpll_clock"; + }; + + fpll: fpll { + compatible = "mango, pll-clock"; + #clock-cells = <0>; + id = ; + mode = ; + subctrl-syscon = <&top_misc>; + clocks = <&cgi>; + clock-output-names = "fpll_clock"; + }; + + dpll0: dpll0 { + compatible = "mango, pll-clock"; + #clock-cells = <0>; + id = ; + mode = ; + subctrl-syscon = <&top_misc>; + clocks = <&cgi>; + clock-output-names = "dpll0_clock"; + }; + + dpll1: dpll1 { + compatible = "mango, pll-clock"; + #clock-cells = <0>; + mode = ; + subctrl-syscon = <&top_misc>; + clocks = <&cgi>; + id = ; + clock-output-names = "dpll1_clock"; + }; + + div_clk: div_clk { + compatible = "mango, pll-child-clock"; + #clock-cells = <1>; + id = ; + subctrl-syscon = <&top_misc>; + }; + + mux_clk: mux_clk { + compatible = "mango, pll-mux-clock"; + #clock-cells = <1>; + id = ; + 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-clock-socket1.dtsi b/arch/riscv/boot/dts/sophgo/mango-clock-socket1.dtsi new file mode 100644 index 000000000000..cfe34495e4fd --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-clock-socket1.dtsi @@ -0,0 +1,124 @@ +/ { + socket1-clocks { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + cgi1: ctrystal1 { + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "s1_cgi"; + #clock-cells = <0>; + }; + + /* pll clock */ + mpll1: mpll1 { + compatible = "mango, pll-clock"; + #clock-cells = <0>; + id = ; + mode = ; + subctrl-syscon = <&top1_misc>; + clocks = <&cgi1>; + clock-output-names = "s1_mpll_clock"; + }; + + fpll1: fpll1 { + compatible = "mango, pll-clock"; + #clock-cells = <0>; + id = ; + mode = ; + subctrl-syscon = <&top1_misc>; + clocks = <&cgi1>; + clock-output-names = "s1_fpll_clock"; + }; + + dpll01: dpll01 { + compatible = "mango, pll-clock"; + #clock-cells = <0>; + id = ; + mode = ; + subctrl-syscon = <&top1_misc>; + clocks = <&cgi1>; + clock-output-names = "s1_dpll0_clock"; + }; + + dpll11: dpll11 { + compatible = "mango, pll-clock"; + #clock-cells = <0>; + mode = ; + subctrl-syscon = <&top1_misc>; + clocks = <&cgi1>; + id = ; + clock-output-names = "s1_dpll1_clock"; + }; + + s1_div_clk: s1_div_clk { + compatible = "mango, pll-child-clock"; + #clock-cells = <1>; + id = ; + subctrl-syscon = <&top1_misc>; + }; + + s1_mux_clk: s1_mux_clk { + compatible = "mango, pll-mux-clock"; + #clock-cells = <1>; + id = ; + subctrl-syscon = <&top1_misc>; + }; + + socket1_default_rates { + compatible = "mango, clk-default-rates"; + #clock-cells = <1>; + subctrl-syscon = <&top1_misc>; + clocks = \ + <&mpll1>, <&fpll1>, + + <&s1_div_clk DIV_CLK_FPLL_RP_CPU_NORMAL_1>, + <&s1_div_clk DIV_CLK_FPLL_50M_A53>, + <&s1_div_clk DIV_CLK_FPLL_TOP_RP_CMN_DIV2>, + <&s1_div_clk DIV_CLK_FPLL_UART_500M>, + <&s1_div_clk DIV_CLK_FPLL_AHB_LPC>, + <&s1_div_clk DIV_CLK_FPLL_EFUSE>, + <&s1_div_clk DIV_CLK_FPLL_TX_ETH0>, + <&s1_div_clk DIV_CLK_FPLL_PTP_REF_I_ETH0>, + <&s1_div_clk DIV_CLK_FPLL_REF_ETH0>, + <&s1_div_clk DIV_CLK_FPLL_EMMC>, + <&s1_div_clk DIV_CLK_FPLL_SD>, + <&s1_div_clk DIV_CLK_FPLL_TOP_AXI0>, + <&s1_div_clk DIV_CLK_FPLL_TOP_AXI_HSPERI>, + <&s1_div_clk DIV_CLK_FPLL_AXI_DDR_1>, + <&s1_div_clk DIV_CLK_FPLL_DIV_TIMER1>, + <&s1_div_clk DIV_CLK_FPLL_DIV_TIMER2>, + <&s1_div_clk DIV_CLK_FPLL_DIV_TIMER3>, + <&s1_div_clk DIV_CLK_FPLL_DIV_TIMER4>, + <&s1_div_clk DIV_CLK_FPLL_DIV_TIMER5>, + <&s1_div_clk DIV_CLK_FPLL_DIV_TIMER6>, + <&s1_div_clk DIV_CLK_FPLL_DIV_TIMER7>, + <&s1_div_clk DIV_CLK_FPLL_DIV_TIMER8>, + <&s1_div_clk DIV_CLK_FPLL_100K_EMMC>, + <&s1_div_clk DIV_CLK_FPLL_100K_SD>, + <&s1_div_clk DIV_CLK_FPLL_GPIO_DB>, + + <&s1_div_clk DIV_CLK_MPLL_RP_CPU_NORMAL_0>, + <&s1_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..7efc9741f3e7 --- /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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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 = "rv64imafdc"; + 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-cpus-socket1.dtsi b/arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi new file mode 100644 index 000000000000..255306410f40 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi @@ -0,0 +1,1149 @@ +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <50000000>; + + cpu-map { + socket1 { + cluster0 { + core0 { + cpu = <&cpu64>; + }; + core1 { + cpu = <&cpu65>; + }; + core2 { + cpu = <&cpu66>; + }; + core3 { + cpu = <&cpu67>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu68>; + }; + core1 { + cpu = <&cpu69>; + }; + core2 { + cpu = <&cpu70>; + }; + core3 { + cpu = <&cpu71>; + }; + }; + + cluster2 { + core0 { + cpu = <&cpu80>; + }; + core1 { + cpu = <&cpu81>; + }; + core2 { + cpu = <&cpu82>; + }; + core3 { + cpu = <&cpu83>; + }; + }; + + cluster3 { + core0 { + cpu = <&cpu84>; + }; + core1 { + cpu = <&cpu85>; + }; + core2 { + cpu = <&cpu86>; + }; + core3 { + cpu = <&cpu87>; + }; + }; + + cluster4 { + core0 { + cpu = <&cpu72>; + }; + core1 { + cpu = <&cpu73>; + }; + core2 { + cpu = <&cpu74>; + }; + core3 { + cpu = <&cpu75>; + }; + }; + + cluster5 { + core0 { + cpu = <&cpu76>; + }; + core1 { + cpu = <&cpu77>; + }; + core2 { + cpu = <&cpu78>; + }; + core3 { + cpu = <&cpu79>; + }; + }; + + cluster6 { + core0 { + cpu = <&cpu88>; + }; + core1 { + cpu = <&cpu89>; + }; + core2 { + cpu = <&cpu90>; + }; + core3 { + cpu = <&cpu91>; + }; + }; + + cluster7 { + core0 { + cpu = <&cpu92>; + }; + core1 { + cpu = <&cpu93>; + }; + core2 { + cpu = <&cpu94>; + }; + core3 { + cpu = <&cpu95>; + }; + }; + + cluster8 { + core0 { + cpu = <&cpu96>; + }; + core1 { + cpu = <&cpu97>; + }; + core2 { + cpu = <&cpu98>; + }; + core3 { + cpu = <&cpu99>; + }; + }; + + cluster9 { + core0 { + cpu = <&cpu100>; + }; + core1 { + cpu = <&cpu101>; + }; + core2 { + cpu = <&cpu102>; + }; + core3 { + cpu = <&cpu103>; + }; + }; + + cluster10 { + core0 { + cpu = <&cpu112>; + }; + core1 { + cpu = <&cpu113>; + }; + core2 { + cpu = <&cpu114>; + }; + core3 { + cpu = <&cpu115>; + }; + }; + + cluster11 { + core0 { + cpu = <&cpu116>; + }; + core1 { + cpu = <&cpu117>; + }; + core2 { + cpu = <&cpu118>; + }; + core3 { + cpu = <&cpu119>; + }; + }; + + cluster12 { + core0 { + cpu = <&cpu104>; + }; + core1 { + cpu = <&cpu105>; + }; + core2 { + cpu = <&cpu106>; + }; + core3 { + cpu = <&cpu107>; + }; + }; + + cluster13 { + core0 { + cpu = <&cpu108>; + }; + core1 { + cpu = <&cpu109>; + }; + core2 { + cpu = <&cpu110>; + }; + core3 { + cpu = <&cpu111>; + }; + }; + + cluster14 { + core0 { + cpu = <&cpu120>; + }; + core1 { + cpu = <&cpu121>; + }; + core2 { + cpu = <&cpu122>; + }; + core3 { + cpu = <&cpu123>; + }; + }; + + cluster15 { + core0 { + cpu = <&cpu124>; + }; + core1 { + cpu = <&cpu125>; + }; + core2 { + cpu = <&cpu126>; + }; + core3 { + cpu = <&cpu127>; + }; + }; + }; + }; + + + cpu64: cpu@64 { + device_type = "cpu"; + reg = <64>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu64_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu65: cpu@65 { + device_type = "cpu"; + reg = <65>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu65_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu66: cpu@66 { + device_type = "cpu"; + reg = <66>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu66_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu67: cpu@67 { + device_type = "cpu"; + reg = <67>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu67_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu68: cpu@68 { + device_type = "cpu"; + reg = <68>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu68_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu69: cpu@69 { + device_type = "cpu"; + reg = <69>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu69_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu70: cpu@70 { + device_type = "cpu"; + reg = <70>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu70_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu71: cpu@71 { + device_type = "cpu"; + reg = <71>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu71_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu72: cpu@72 { + device_type = "cpu"; + reg = <72>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu72_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu73: cpu@73 { + device_type = "cpu"; + reg = <73>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu73_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu74: cpu@74 { + device_type = "cpu"; + reg = <74>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu74_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu75: cpu@75 { + device_type = "cpu"; + reg = <75>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu75_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu76: cpu@76 { + device_type = "cpu"; + reg = <76>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu76_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu77: cpu@77 { + device_type = "cpu"; + reg = <77>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu77_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu78: cpu@78 { + device_type = "cpu"; + reg = <78>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu78_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu79: cpu@79 { + device_type = "cpu"; + reg = <79>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu79_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu80: cpu@80 { + device_type = "cpu"; + reg = <80>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu80_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu81: cpu@81 { + device_type = "cpu"; + reg = <81>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu81_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu82: cpu@82 { + device_type = "cpu"; + reg = <82>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu82_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu83: cpu@83 { + device_type = "cpu"; + reg = <83>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu83_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu84: cpu@84 { + device_type = "cpu"; + reg = <84>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu84_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu85: cpu@85 { + device_type = "cpu"; + reg = <85>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu85_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu86: cpu@86 { + device_type = "cpu"; + reg = <86>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu86_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu87: cpu@87 { + device_type = "cpu"; + reg = <87>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <4>; + cpu87_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu88: cpu@88 { + device_type = "cpu"; + reg = <88>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu88_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu89: cpu@89 { + device_type = "cpu"; + reg = <89>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu89_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu90: cpu@90 { + device_type = "cpu"; + reg = <90>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu90_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu91: cpu@91 { + device_type = "cpu"; + reg = <91>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu91_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu92: cpu@92 { + device_type = "cpu"; + reg = <92>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu92_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu93: cpu@93 { + device_type = "cpu"; + reg = <93>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu93_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu94: cpu@94 { + device_type = "cpu"; + reg = <94>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu94_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu95: cpu@95 { + device_type = "cpu"; + reg = <95>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <5>; + cpu95_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu96: cpu@96 { + device_type = "cpu"; + reg = <96>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu96_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu97: cpu@97 { + device_type = "cpu"; + reg = <97>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu97_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu98: cpu@98 { + device_type = "cpu"; + reg = <98>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu98_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu99: cpu@99 { + device_type = "cpu"; + reg = <99>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu99_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu100: cpu@100 { + device_type = "cpu"; + reg = <100>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu100_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu101: cpu@101 { + device_type = "cpu"; + reg = <101>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu101_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu102: cpu@102 { + device_type = "cpu"; + reg = <102>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu102_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu103: cpu@103 { + device_type = "cpu"; + reg = <103>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu103_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu104: cpu@104 { + device_type = "cpu"; + reg = <104>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu104_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu105: cpu@105 { + device_type = "cpu"; + reg = <105>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu105_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu106: cpu@106 { + device_type = "cpu"; + reg = <106>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu106_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu107: cpu@107 { + device_type = "cpu"; + reg = <107>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu107_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu108: cpu@108 { + device_type = "cpu"; + reg = <108>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu108_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu109: cpu@109 { + device_type = "cpu"; + reg = <109>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu109_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu110: cpu@110 { + device_type = "cpu"; + reg = <110>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu110_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu111: cpu@111 { + device_type = "cpu"; + reg = <111>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu111_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu112: cpu@112 { + device_type = "cpu"; + reg = <112>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu112_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu113: cpu@113 { + device_type = "cpu"; + reg = <113>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu113_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu114: cpu@114 { + device_type = "cpu"; + reg = <114>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu114_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu115: cpu@115 { + device_type = "cpu"; + reg = <115>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu115_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu116: cpu@116 { + device_type = "cpu"; + reg = <116>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu116_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu117: cpu@117 { + device_type = "cpu"; + reg = <117>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu117_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu118: cpu@118 { + device_type = "cpu"; + reg = <118>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu118_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu119: cpu@119 { + device_type = "cpu"; + reg = <119>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <6>; + cpu119_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu120: cpu@120 { + device_type = "cpu"; + reg = <120>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu120_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu121: cpu@121 { + device_type = "cpu"; + reg = <121>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu121_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu122: cpu@122 { + device_type = "cpu"; + reg = <122>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu122_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu123: cpu@123 { + device_type = "cpu"; + reg = <123>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu123_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu124: cpu@124 { + device_type = "cpu"; + reg = <124>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu124_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu125: cpu@125 { + device_type = "cpu"; + reg = <125>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu125_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu126: cpu@126 { + device_type = "cpu"; + reg = <126>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu126_intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu127: cpu@127 { + device_type = "cpu"; + reg = <127>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + numa-node-id = <7>; + cpu127_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..3e9bd7ca6793 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts @@ -0,0 +1,170 @@ +#include "mango.dtsi" +#include "mango-pcie-4rc.dtsi" + +/ { + info { + file-name = "mango-milkv-pioneer.dts"; + }; +}; + +&i2c0 { + rtc: rtc@68 { + compatible = "dallas,ds1307"; + reg = <0x68>; + }; +}; + +&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 = ; + 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 = ; + 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..e39b3a80bf06 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi @@ -0,0 +1,81 @@ +#include + +#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 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 <0x1>; + link-id = /bits/ 16 <0x0>; + top-intc-used = <1>; + top-intc-id = <0>; + msix-supported = <1>; + interrupt-parent = <&intc1>; + //interrupts = ; + //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 0xc0000000 0x48 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x48 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, + <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>, + <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>; + + 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 = ; + //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 0xc0800000 0xc0 0xc0800000 0x0 0x00800000>, + <0x42000000 0x0 0xd0000000 0xc0 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0xc0 0xe0000000 0x0 0x20000000>, + <0x43000000 0xc2 0x00000000 0xc2 0x00000000 0x2 0x00000000>, + <0x03000000 0xc1 0x00000000 0xc1 0x00000000 0x1 0x00000000>; + + status = "okay"; + }; +}; diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-capricorn.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-capricorn.dtsi new file mode 100644 index 000000000000..776889585272 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-capricorn.dtsi @@ -0,0 +1,116 @@ +#include + +#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 = <1>; + top-intc-id = <0>; + msix-supported = <0>; + interrupt-parent = <&intc1>; + 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 0xc0000000 0x40 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x40 0xd0000000 0x0 0x10000000>, + <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 = <0>; + top-intc-id = <0>; + interrupt-parent = <&intc>; + interrupts = ; + 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 0xc0400000 0x44 0xc0400000 0x0 0x00400000>, + <0x42000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, + <0x02000000 0x0 0xd0000000 0x44 0xd0000000 0x0 0x10000000>, + <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 = ; + 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 0xc0800000 0x48 0xc0800000 0x0 0x00800000>, + <0x42000000 0x0 0xd0000000 0x48 0xd0000000 0x0 0x10000000>, + <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-v2.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi new file mode 100644 index 000000000000..9c4c9641e1c0 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi @@ -0,0 +1,115 @@ +#include + +#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 = ; + 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 0xc0000000 0x40 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x40 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, + <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, + <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; + + 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 = ; + //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 0xc0400000 0x44 0xc0400000 0x0 0x00400000>, + <0x42000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, + <0x02000000 0x0 0xd0000000 0x44 0xd0000000 0x0 0x10000000>, + <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, + <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; + + 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 = ; + 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 0xc0800000 0x48 0xc0800000 0x0 0x00800000>, + <0x42000000 0x0 0xd0000000 0x48 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, + <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>, + <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>; + + 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..63fb41b43809 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi @@ -0,0 +1,112 @@ +#include + +#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 = ; + 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 0xc0000000 0x40 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x40 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, + <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, + <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; + + 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 0xc0400000 0x44 0xc0400000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x44 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, + <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, + <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; + + 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 = ; + 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 0xc0800000 0x48 0xc0800000 0x0 0x00800000>, + <0x42000000 0x0 0xd0000000 0x48 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, + <0x43000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>, + <0x03000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>; + + status = "okay"; + }; +}; diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-4rc-v2.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc-v2.dtsi new file mode 100644 index 000000000000..efbcc5c04740 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc-v2.dtsi @@ -0,0 +1,155 @@ +#include + +#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 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 <0x1>; + link-id = /bits/ 16 <0x0>; + top-intc-used = <1>; + top-intc-id = <0>; + msix-supported = <0>; + interrupt-parent = <&intc1>; + 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 0xc0000000 0x48 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x48 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, + <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>, + <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>; + + status = "okay"; + }; + + pcie@7062800000 { + 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 <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 0xc0000000 0x4c 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x4c 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x4c 0xe0000000 0x0 0x20000000>, + <0x43000000 0x4e 0x00000000 0x4e 0x00000000 0x2 0x00000000>, + <0x03000000 0x4d 0x00000000 0x4d 0x00000000 0x1 0x00000000>; + + status = "okay"; + }; + + pcie@f060000000 { + 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 <0x0>; + link-id = /bits/ 16 <0x0>; + top-intc-used = <1>; + top-intc-id = <1>; + msix-supported = <0>; + interrupt-parent = <&intc2>; + 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 0xc0000000 0xc0 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0xc0 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0xc0 0xe0000000 0x0 0x20000000>, + <0x43000000 0xc2 0x00000000 0xc2 0x00000000 0x2 0x00000000>, + <0x03000000 0xc1 0x00000000 0xc1 0x00000000 0x1 0x00000000>; + + status = "okay"; + }; + + pcie@f068000000 { + 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 <0x0>; + link-id = /bits/ 16 <0x1>; + top-intc-used = <1>; + top-intc-id = <1>; + msix-supported = <0>; + interrupt-parent = <&intc2>; + reg = <0xc4 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 0xc0000000 0xc4 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0xc4 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0xc4 0xe0000000 0x0 0x20000000>, + <0x43000000 0xc6 0x00000000 0xc6 0x00000000 0x2 0x00000000>, + <0x03000000 0xc5 0x00000000 0xc5 0x00000000 0x1 0x00000000>; + + 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..22bc466757bf --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi @@ -0,0 +1,151 @@ +#include + +#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 = <1>; + top-intc-id = <0>; + msix-supported = <1>; + interrupt-parent = <&intc1>; + //top-intc-used = <0>; + //interrupt-parent = <&intc>; + //interrupts = ; + //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 0xc0000000 0x40 0xc0000000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x40 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x40 0xe0000000 0x0 0x20000000>, + <0x43000000 0x42 0x00000000 0x42 0x00000000 0x2 0x00000000>, + <0x03000000 0x41 0x00000000 0x41 0x00000000 0x1 0x00000000>; + + status = "okay"; + }; +#if 0 + 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 0xc0400000 0x44 0xc0400000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x44 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x44 0xe0000000 0x0 0x20000000>, + <0x43000000 0x46 0x00000000 0x46 0x00000000 0x2 0x00000000>, + <0x03000000 0x45 0x00000000 0x45 0x00000000 0x1 0x00000000>; + + status = "okay"; + }; +#endif + pcie@7062000000 { + compatible = "sophgo,cdns-pcie-host"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + + bus-range = <0x80 0xbf>; + 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 <0x1>; + link-id = /bits/ 16 <0x0>; + top-intc-used = <0>; + interrupt-parent = <&intc>; + interrupts = ; + 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 0xc0800000 0x48 0xc0800000 0x0 0x00400000>, + <0x42000000 0x0 0xd0000000 0x48 0xd0000000 0x0 0x10000000>, + <0x02000000 0x0 0xe0000000 0x48 0xe0000000 0x0 0x20000000>, + <0x03000000 0x49 0x00000000 0x49 0x00000000 0x1 0x00000000>, + <0x43000000 0x4a 0x00000000 0x4a 0x00000000 0x2 0x00000000>; + + 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 = <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 <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 0xc0c00000 0x4c 0xc0c00000 0x0 0x00400000>, + <0x42000000 0x0 0xf8000000 0x4c 0xf8000000 0x0 0x04000000>, + <0x02000000 0x0 0xfc000000 0x4c 0xfc000000 0x0 0x04000000>, + <0x43000000 0x4e 0x00000000 0x4e 0x00000000 0x2 0x00000000>, + <0x03000000 0x4d 0x00000000 0x4d 0x00000000 0x1 0x00000000>; + + 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-capricorn.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-capricorn.dts new file mode 100644 index 000000000000..94892b74467f --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-capricorn.dts @@ -0,0 +1,57 @@ +#include "mango.dtsi" +#include "mango-pcie-3rc-capricorn.dtsi" + +/ { + info { + file-name = "mango-sophgo-capricorn.dts"; + }; +}; + +ðernet0 { + max-speed = <1000>; + eth-sophgo-config { + autoneg = "enable"; + }; +}; + +&soc { + gpio-poweroff { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio2_acquire>; + + power { + label = "GPIO Key Power"; + linux,code = ; + gpios = <&port0a 2 GPIO_ACTIVE_HIGH>; + linux,input-type = <1>; + debounce-interval = <100>; + }; + }; +}; + +&port0a { + compatible = "snps,dw-apb-gpio-port", "sophgo,gpio0"; + + cpld_poweroff: cpld-poweroff { + compatible = "mango,cpld-poweroff"; + gpios = <&port0a 3 GPIO_ACTIVE_HIGH>; + }; + + cpld_reboot: cpld-reboot { + compatible = "mango,cpld-reboot"; + gpios = <&port0a 5 GPIO_ACTIVE_HIGH>; + }; +}; + +/ { + board-info { + /* compatible MUST be sophgo,board-info */ + compatible = "sophgo,board-info"; + /* valid values are: full-function, xmr */ + chip-package = "full-function"; + /* valid values are: x4, x8 */ + ddr-pcb-type = "x4"; + }; +}; diff --git a/arch/riscv/boot/dts/sophgo/mango-sophgo-pisces.dts b/arch/riscv/boot/dts/sophgo/mango-sophgo-pisces.dts new file mode 100644 index 000000000000..98761cbf42e8 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-pisces.dts @@ -0,0 +1,58 @@ +#include "mango-2sockets.dtsi" +#include "mango-top-intc2.dtsi" +#include "mango-pcie-2rc.dtsi" + +/ { + info { + file-name = "mango-sophgo-pisces.dts"; + }; +}; + +ðernet0 { + max-speed = <1000>; + eth-sophgo-config { + autoneg = "enable"; + }; +}; + +&soc { + gpio-poweroff { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio2_acquire>; + + power { + label = "GPIO Key Power"; + linux,code = ; + gpios = <&port0a 2 GPIO_ACTIVE_HIGH>; + linux,input-type = <1>; + debounce-interval = <100>; + }; + }; +}; + +&port0a { + compatible = "snps,dw-apb-gpio-port", "sophgo,gpio0"; + + cpld_poweroff: cpld-poweroff { + compatible = "mango,cpld-poweroff"; + gpios = <&port0a 3 GPIO_ACTIVE_HIGH>; + }; + + cpld_reboot: cpld-reboot { + compatible = "mango,cpld-reboot"; + gpios = <&port0a 5 GPIO_ACTIVE_HIGH>; + }; +}; + +/ { + board-info { + /* compatible MUST be sophgo,board-info */ + compatible = "sophgo,board-info"; + /* valid values are: full-function, xmr */ + chip-package = "full-function"; + /* valid values are: x4, x8 */ + ddr-pcb-type = "x4"; + }; +}; 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..3fe655eaf69a --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts @@ -0,0 +1,144 @@ +#include "mango.dtsi" +#include "mango-pcie-3rc-v2.dtsi" + +/ { + info { + file-name = "mango-sophgo-x4evb.dts"; + }; +}; + +&i2c0 { + rtc: rtc@68 { + compatible = "dallas,ds1307"; + reg = <0x68>; + }; +}; + +&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..9e0cf5348051 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts @@ -0,0 +1,172 @@ +#include "mango.dtsi" +#include "mango-pcie-3rc.dtsi" + +/ { + info { + file-name = "mango-sophgo-x8evb.dts"; + }; +}; + +&i2c0 { + rtc: rtc@68 { + compatible = "dallas,ds1307"; + reg = <0x68>; + }; +}; + +&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 = ; + 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 = ; + 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 + +#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 = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + 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-yixin-s2110.dts b/arch/riscv/boot/dts/sophgo/mango-yixin-s2110.dts new file mode 100644 index 000000000000..172421ffc196 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango-yixin-s2110.dts @@ -0,0 +1,63 @@ +#include "mango-2sockets.dtsi" +#include "mango-top-intc2.dtsi" +#include "mango-pcie-4rc-v2.dtsi" + +/ { + info { + file-name = "mango-yixin-s2110.dts"; + }; +}; + +ðernet0 { + max-speed = <1000>; + eth-sophgo-config { + autoneg = "enable"; + }; +}; + +&soc { + gpio-poweroff { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio2_acquire>; + + power { + label = "GPIO Key Power"; + linux,code = ; + gpios = <&port0a 2 GPIO_ACTIVE_HIGH>; + linux,input-type = <1>; + debounce-interval = <100>; + }; + }; +}; + +&gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&dbgi2c_release>; +}; + +&port0a { + compatible = "snps,dw-apb-gpio-port", "sophgo,gpio0"; + + cpld_poweroff: cpld-poweroff { + compatible = "mango,cpld-poweroff"; + gpios = <&port0a 3 GPIO_ACTIVE_HIGH>; + }; + + cpld_reboot: cpld-reboot { + compatible = "mango,cpld-reboot"; + gpios = <&port0a 29 GPIO_ACTIVE_HIGH>; + }; +}; + +/ { + board-info { + /* compatible MUST be sophgo,board-info */ + compatible = "sophgo,board-info"; + /* valid values are: full-function, xmr */ + chip-package = "full-function"; + /* valid values are: x4, x8 */ + ddr-pcb-type = "x8"; + }; +}; diff --git a/arch/riscv/boot/dts/sophgo/mango.dtsi b/arch/riscv/boot/dts/sophgo/mango.dtsi new file mode 100644 index 000000000000..57f304fc778f --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/mango.dtsi @@ -0,0 +1,938 @@ +/dts-v1/; +#include +#include +#include +#include +#include +#include + +#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 = ; + 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 = ; + 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 = ; + }; + + 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 = ; + 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 = ; + 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 = ; + 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 = ; + 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_GPIO_DB>; + clock-names = "bus", "db"; + + 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 = ; + }; + }; + + 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_GPIO_DB>; + clock-names = "bus", "db"; + + 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 = ; + }; + }; + + 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_GPIO_DB>; + clock-names = "bus", "db"; + + 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 = ; + }; + }; + + 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 = "snps,dw-apb-uart"; + reg = <0x00000070 0x40000000 0x00000000 0x00001000>; + interrupt-parent = <&intc>; + interrupts = ; + 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 = "snps,dw-apb-uart"; + reg = <0x00000070 0x40001000 0x00000000 0x00001000>; + interrupt-parent = <&intc>; + interrupts = ; + 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 = "snps,dw-apb-uart"; + reg = <0x00000070 0x40002000 0x00000000 0x00001000>; + interrupt-parent = <&intc>; + interrupts = ; + 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 = "snps,dw-apb-uart"; + reg = <0x00000070 0x40003000 0x00000000 0x00001000>; + interrupt-parent = <&intc>; + interrupts = ; + 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 = ; + 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 = ; + 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 = ; + 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 = ; + 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 = ; + 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 = ; + 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 = ; + 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 = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + 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/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 +#include / { 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 = ; + label = "led1"; + }; + + led-2 { + gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; + color = ; + label = "led2"; + }; + + led-3 { + gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; + color = ; + label = "led3"; + }; + led-4 { + gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; + color = ; + label = "led4"; + }; + + led-5 { + gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; + color = ; + 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 + */ + +/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 + */ + +/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 + */ + +/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 / { 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 + +/ { + 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 +#include +#include +#include / { 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..b715550e3ed1 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -168,12 +168,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 026582613f2c..a948aadd1d6f 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_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -148,7 +149,7 @@ CONFIG_GENERIC_SCHED_CLOCK=y CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" -CONFIG_GCC11_NO_ARRAY_BOUNDS=y +CONFIG_GCC10_NO_ARRAY_BOUNDS=y CONFIG_CC_NO_ARRAY_BOUNDS=y CONFIG_ARCH_SUPPORTS_INT128=y CONFIG_NUMA_BALANCING=y @@ -301,6 +302,7 @@ 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 @@ -309,6 +311,8 @@ CONFIG_RISCV_DMA_NONCOHERENT=y # CONFIG_ARCH_RENESAS is not set CONFIG_ARCH_SIFIVE=y CONFIG_SOC_SIFIVE=y +CONFIG_ARCH_SOPHGO=y +# CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC is not set CONFIG_ARCH_STARFIVE=y CONFIG_SOC_STARFIVE=y # CONFIG_ARCH_SUNXI is not set @@ -343,17 +347,19 @@ CONFIG_SMP=y CONFIG_NR_CPUS=512 CONFIG_HOTPLUG_CPU=y CONFIG_TUNE_GENERIC=y +CONFIG_HIGHMEM=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_SVNAPOT is not set 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_V is not set +CONFIG_TOOLCHAIN_HAS_ZBB=y +CONFIG_RISCV_ISA_ZBB=y +# CONFIG_RISCV_ISA_ZICBOM is not set CONFIG_RISCV_ISA_ZICBOZ=y CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE=y CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y @@ -471,6 +477,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 @@ -488,6 +495,19 @@ CONFIG_VIRTUALIZATION=y CONFIG_KVM=m CONFIG_ARCH_SUPPORTS_ACPI=y # CONFIG_ACPI is not set +CONFIG_HAVE_LIVEPATCH_WO_FTRACE=y + +# +# Enable Livepatch +# +CONFIG_LIVEPATCH=y +CONFIG_LIVEPATCH_WO_FTRACE=y +CONFIG_LIVEPATCH_STOP_MACHINE_CONSISTENCY=y +CONFIG_LIVEPATCH_STACK=y +CONFIG_LIVEPATCH_RESTRICT_KPROBE=y +# end of Enable Livepatch + +CONFIG_CPU_MITIGATIONS=y # # General architecture-dependent options @@ -576,7 +596,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 @@ -753,9 +772,9 @@ CONFIG_ZSMALLOC_CHAIN_SIZE=8 # CONFIG_SLAB_DEPRECATED is not set CONFIG_SLUB=y # CONFIG_SLUB_TINY is not set -CONFIG_SLAB_MERGE_DEFAULT=y +# CONFIG_SLAB_MERGE_DEFAULT is not set CONFIG_SLAB_FREELIST_RANDOM=y -# CONFIG_SLAB_FREELIST_HARDENED is not set +CONFIG_SLAB_FREELIST_HARDENED=y # CONFIG_SLUB_STATS is not set CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_RANDOM_KMALLOC_CACHES is not set @@ -768,8 +787,9 @@ CONFIG_SPARSEMEM_MANUAL=y CONFIG_SPARSEMEM=y CONFIG_SPARSEMEM_EXTREME=y CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y -CONFIG_SPARSEMEM_VMEMMAP=y +# CONFIG_SPARSEMEM_VMEMMAP is not set CONFIG_ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP=y +CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_MEMORY_ISOLATION=y CONFIG_EXCLUSIVE_SYSTEM_RAM=y CONFIG_SPLIT_PTLOCK_CPUS=4 @@ -785,13 +805,15 @@ CONFIG_ARCH_ENABLE_THP_MIGRATION=y CONFIG_CONTIG_ALLOC=y CONFIG_PCP_BATCH_SCALE_MAX=5 CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_BOUNCE=y CONFIG_MMU_NOTIFIER=y CONFIG_KSM=y CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y CONFIG_ARCH_WANTS_THP_SWAP=y CONFIG_TRANSPARENT_HUGEPAGE=y -CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y -# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set +# CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS is not set +CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y CONFIG_THP_SWAP=y # CONFIG_READ_ONLY_THP_FOR_FS is not set CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y @@ -808,19 +830,19 @@ CONFIG_IDLE_PAGE_TRACKING=y CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y CONFIG_ZONE_DMA32=y CONFIG_HMM_MIRROR=y +CONFIG_GET_FREE_REGION=y CONFIG_VM_EVENT_COUNTERS=y # CONFIG_PERCPU_STATS is not set # CONFIG_GUP_TEST is not set # CONFIG_DMAPOOL_TEST is not set CONFIG_ARCH_HAS_PTE_SPECIAL=y +CONFIG_KMAP_LOCAL=y CONFIG_MEMFD_CREATE=y CONFIG_SECRETMEM=y # CONFIG_ANON_VMA_NAME is not set CONFIG_USERFAULTFD=y CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y -CONFIG_LRU_GEN=y -CONFIG_LRU_GEN_ENABLED=y -# CONFIG_LRU_GEN_STATS is not set +# CONFIG_LRU_GEN is not set CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y CONFIG_PER_VMA_LOCK=y CONFIG_LOCK_MM_AND_FIND_VMA=y @@ -1585,6 +1607,7 @@ CONFIG_PCIEPORTBUS=y CONFIG_HOTPLUG_PCI_PCIE=y CONFIG_PCIEAER=y CONFIG_PCIEAER_INJECT=m +CONFIG_PCIEAER_CXL=y CONFIG_PCIE_ECRC=y CONFIG_PCIEASPM=y CONFIG_PCIEASPM_DEFAULT=y @@ -1601,6 +1624,7 @@ CONFIG_PCI_QUIRKS=y CONFIG_PCI_STUB=y # CONFIG_PCI_PF_STUB is not set CONFIG_PCI_ATS=y +CONFIG_PCI_DOE=y CONFIG_PCI_ECAM=y CONFIG_PCI_IOV=y CONFIG_PCI_PRI=y @@ -1635,6 +1659,7 @@ 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 @@ -1674,7 +1699,16 @@ CONFIG_PCI_ENDPOINT_CONFIGFS=y # CONFIG_PCI_SW_SWITCHTEC is not set # end of PCI switch controller drivers -# CONFIG_CXL_BUS is not set +CONFIG_CXL_BUS=y +CONFIG_CXL_PCI=y +# CONFIG_CXL_MEM_RAW_COMMANDS is not set +CONFIG_CXL_PMEM=m +CONFIG_CXL_MEM=y +CONFIG_CXL_PORT=y +CONFIG_CXL_SUSPEND=y +CONFIG_CXL_REGION=y +# CONFIG_CXL_REGION_INVALIDATION_TEST is not set +CONFIG_CXL_PMU=y # CONFIG_PCCARD is not set # CONFIG_RAPIDIO is not set @@ -1694,11 +1728,13 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER=y CONFIG_FW_LOADER_DEBUG=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_FW_LOADER_SYSFS=y CONFIG_EXTRA_FIRMWARE="" # CONFIG_FW_LOADER_USER_HELPER is not set # CONFIG_FW_LOADER_COMPRESS is not set CONFIG_FW_CACHE=y -# CONFIG_FW_UPLOAD is not set +CONFIG_FW_UPLOAD=y # end of Firmware loader CONFIG_WANT_DEV_COREDUMP=y @@ -1709,7 +1745,7 @@ CONFIG_WANT_DEV_COREDUMP=y # 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 @@ -1774,6 +1810,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 @@ -1899,6 +1938,7 @@ CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y # CONFIG_MTD_SPI_NOR_SWP_DISABLE is not set CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE=y # CONFIG_MTD_SPI_NOR_SWP_KEEP is not set +CONFIG_SPI_SOPHGO_SPIFMC=m CONFIG_MTD_UBI=m CONFIG_MTD_UBI_WL_THRESHOLD=4096 CONFIG_MTD_UBI_BEB_LIMIT=20 @@ -2277,7 +2317,6 @@ CONFIG_DM_THIN_PROVISIONING=m CONFIG_DM_CACHE=m CONFIG_DM_CACHE_SMQ=m # CONFIG_DM_WRITECACHE is not set -# CONFIG_DM_EBS is not set CONFIG_DM_ERA=m # CONFIG_DM_CLONE is not set CONFIG_DM_MIRROR=m @@ -2365,6 +2404,7 @@ CONFIG_VSOCKMON=m CONFIG_ETHERNET=y CONFIG_MDIO=m # CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_3SNIC is not set # CONFIG_NET_VENDOR_ADAPTEC is not set # CONFIG_NET_VENDOR_AGERE is not set CONFIG_NET_VENDOR_ALACRITECH=y @@ -2441,6 +2481,7 @@ CONFIG_NET_VENDOR_FUNGIBLE=y # CONFIG_FUN_ETH is not set CONFIG_NET_VENDOR_GOOGLE=y CONFIG_NET_VENDOR_HUAWEI=y +# CONFIG_BMA is not set # CONFIG_NET_VENDOR_I825XX is not set CONFIG_NET_VENDOR_INTEL=y # CONFIG_E100 is not set @@ -2465,6 +2506,10 @@ CONFIG_FM10K=m # CONFIG_IGC is not set CONFIG_NET_VENDOR_MUCSE=y # CONFIG_MXGBE is not set +# CONFIG_MXGBEVF is not set +# CONFIG_MXGBEM is not set +# CONFIG_MGBE is not set +# CONFIG_MGBEVF is not set # CONFIG_JME is not set CONFIG_NET_VENDOR_ADI=y # CONFIG_ADIN1110 is not set @@ -2569,7 +2614,16 @@ 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_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 @@ -2583,6 +2637,8 @@ CONFIG_NGBE=m CONFIG_TXGBE=m # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set +CONFIG_NET_VENDOR_BZWX=y +# CONFIG_NCE is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PHYLINK=y @@ -3366,6 +3422,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 @@ -3416,7 +3473,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 @@ -3599,7 +3657,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 @@ -3777,6 +3835,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 @@ -3877,7 +3936,6 @@ CONFIG_MFD_CORE=m # CONFIG_MFD_SKY81452 is not set # CONFIG_MFD_STMPE is not set CONFIG_MFD_SYSCON=y -# CONFIG_MFD_TI_AM335X_TSCADC is not set # CONFIG_MFD_LP3943 is not set # CONFIG_MFD_LP8788 is not set # CONFIG_MFD_TI_LMU is not set @@ -3998,6 +4056,7 @@ CONFIG_REGULATOR_PWM=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 # @@ -5357,8 +5416,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 @@ -5450,7 +5530,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 @@ -5465,7 +5545,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 @@ -5520,12 +5652,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 @@ -5546,8 +5679,6 @@ CONFIG_MMC_HSQ=m CONFIG_MMC_TOSHIBA_PCI=m CONFIG_MMC_MTK=m CONFIG_MMC_SDHCI_XENON=m -# CONFIG_MMC_SDHCI_OMAP is not set -# CONFIG_MMC_SDHCI_AM654 is not set # CONFIG_SCSI_UFSHCD is not set CONFIG_MEMSTICK=m # CONFIG_MEMSTICK_DEBUG is not set @@ -5670,7 +5801,6 @@ CONFIG_INFINIBAND_USER_MEM=y CONFIG_INFINIBAND_ON_DEMAND_PAGING=y CONFIG_INFINIBAND_ADDR_TRANS=y CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS=y -CONFIG_INFINIBAND_VIRT_DMA=y CONFIG_INFINIBAND_BNXT_RE=m CONFIG_INFINIBAND_CXGB4=m # CONFIG_INFINIBAND_EFA is not set @@ -5681,8 +5811,6 @@ CONFIG_MLX5_INFINIBAND=m # CONFIG_INFINIBAND_MTHCA is not set # CONFIG_INFINIBAND_OCRDMA is not set CONFIG_INFINIBAND_QEDR=m -CONFIG_RDMA_RXE=m -# CONFIG_RDMA_SIW is not set CONFIG_INFINIBAND_IPOIB=m CONFIG_INFINIBAND_IPOIB_CM=y # CONFIG_INFINIBAND_IPOIB_DEBUG is not set @@ -5817,6 +5945,7 @@ CONFIG_RTC_DRV_RP5C01=m # HID Sensor RTC drivers # CONFIG_RTC_DRV_GOLDFISH=y +# CONFIG_RTC_DRV_ASTBMC is not set CONFIG_DMADEVICES=y # CONFIG_DMADEVICES_DEBUG is not set @@ -5824,10 +5953,11 @@ 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_AMBA_PL08X is not set -# CONFIG_DW_AXI_DMAC 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 @@ -5959,6 +6089,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 # @@ -5966,6 +6099,8 @@ 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 @@ -5976,6 +6111,7 @@ CONFIG_MAILBOX=y # CONFIG_PL320_MBOX is not set # CONFIG_ALTERA_MBOX is not set # CONFIG_MAILBOX_TEST is not set +CONFIG_THEAD_LIGHT_MBOX=y CONFIG_IOMMU_API=y CONFIG_IOMMU_SUPPORT=y @@ -6005,6 +6141,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 @@ -6061,6 +6198,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 @@ -6089,6 +6232,7 @@ CONFIG_PWM_SYSFS=y # CONFIG_PWM_FSL_FTM is not set # CONFIG_PWM_PCA9685 is not set CONFIG_PWM_SIFIVE=m +CONFIG_PWM_THEAD=m # CONFIG_PWM_XILINX is not set # @@ -6104,6 +6248,7 @@ CONFIG_SIFIVE_PLIC=y # CONFIG_IPACK_BUS is not set CONFIG_RESET_CONTROLLER=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 @@ -6178,6 +6323,7 @@ CONFIG_NVDIMM_KEYS=y # CONFIG_NVDIMM_SECURITY_TEST is not set CONFIG_DAX=y CONFIG_DEV_DAX=m +CONFIG_DEV_DAX_CXL=m CONFIG_NVMEM=y CONFIG_NVMEM_SYSFS=y @@ -6362,8 +6508,6 @@ CONFIG_TMPFS_XATTR=y CONFIG_ARCH_SUPPORTS_HUGETLBFS=y 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 @@ -6652,6 +6796,8 @@ CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,appar # Memory initialization # CONFIG_INIT_STACK_NONE=y +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set # CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set # CONFIG_INIT_ON_FREE_DEFAULT_ON is not set # CONFIG_ZERO_CALL_USED_REGS is not set @@ -6866,6 +7012,7 @@ CONFIG_CRYPTO_HW=y # CONFIG_CRYPTO_DEV_QAT_C3XXX is not set # CONFIG_CRYPTO_DEV_QAT_C62X is not set # CONFIG_CRYPTO_DEV_QAT_4XXX is not set +# CONFIG_CRYPTO_DEV_QAT_420XX is not set # CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set # CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set # CONFIG_CRYPTO_DEV_QAT_C62XVF is not set @@ -7108,6 +7255,7 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y # CONFIG_DEBUG_INFO_REDUCED is not set CONFIG_DEBUG_INFO_COMPRESSED_NONE=y # CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set +# CONFIG_DEBUG_INFO_SPLIT is not set CONFIG_DEBUG_INFO_BTF=y CONFIG_PAHOLE_HAS_SPLIT_BTF=y CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y @@ -7190,16 +7338,14 @@ CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN=y # CONFIG_DEBUG_STACK_USAGE is not set # CONFIG_SCHED_STACK_END_CHECK is not set CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y -CONFIG_DEBUG_VM_IRQSOFF=y -CONFIG_DEBUG_VM=y -# CONFIG_DEBUG_VM_MAPLE_TREE is not set -# CONFIG_DEBUG_VM_RB is not set -# CONFIG_DEBUG_VM_PGFLAGS is not set +# CONFIG_DEBUG_VM is not set # CONFIG_DEBUG_VM_PGTABLE is not set CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y # CONFIG_DEBUG_VIRTUAL is not set CONFIG_DEBUG_MEMORY_INIT=y CONFIG_DEBUG_PER_CPU_MAPS=y +# CONFIG_DEBUG_KMAP_LOCAL is not set +# CONFIG_DEBUG_HIGHMEM is not set CONFIG_HAVE_ARCH_KASAN=y CONFIG_HAVE_ARCH_KASAN_VMALLOC=y # CONFIG_KASAN is not set @@ -7353,7 +7499,38 @@ CONFIG_RING_BUFFER_BENCHMARK=m # CONFIG_SYNTH_EVENT_GEN_TEST is not set # CONFIG_KPROBE_EVENT_GEN_TEST is not set # CONFIG_RV is not set -# CONFIG_SAMPLES is not set +CONFIG_SAMPLES=y +# CONFIG_SAMPLE_AUXDISPLAY is not set +# CONFIG_SAMPLE_TRACE_EVENTS is not set +# CONFIG_SAMPLE_TRACE_CUSTOM_EVENTS is not set +# CONFIG_SAMPLE_TRACE_PRINTK is not set +# CONFIG_SAMPLE_FTRACE_OPS is not set +# CONFIG_SAMPLE_TRACE_ARRAY is not set +# CONFIG_SAMPLE_KOBJECT is not set +# CONFIG_SAMPLE_KPROBES is not set +# CONFIG_SAMPLE_KFIFO is not set +# CONFIG_SAMPLE_KDB is not set +# CONFIG_SAMPLE_RPMSG_CLIENT is not set +CONFIG_SAMPLE_LIVEPATCH=m +# CONFIG_SAMPLE_CONFIGFS is not set +# CONFIG_SAMPLE_CONNECTOR is not set +# CONFIG_SAMPLE_FANOTIFY_ERROR is not set +# CONFIG_SAMPLE_HIDRAW is not set +# CONFIG_SAMPLE_LANDLOCK is not set +# CONFIG_SAMPLE_PIDFD is not set +# CONFIG_SAMPLE_SECCOMP is not set +# CONFIG_SAMPLE_TIMER is not set +# CONFIG_SAMPLE_UHID is not set +# CONFIG_SAMPLE_VFIO_MDEV_MTTY is not set +# CONFIG_SAMPLE_VFIO_MDEV_MDPY is not set +# CONFIG_SAMPLE_VFIO_MDEV_MDPY_FB is not set +# CONFIG_SAMPLE_VFIO_MDEV_MBOCHS is not set +# CONFIG_SAMPLE_ANDROID_BINDERFS is not set +# CONFIG_SAMPLE_VFS is not set +# CONFIG_SAMPLE_TPS6594_PFSM is not set +# CONFIG_SAMPLE_WATCHDOG is not set +# CONFIG_SAMPLE_WATCH_QUEUE is not set +# CONFIG_SAMPLE_KMEMLEAK is not set CONFIG_STRICT_DEVMEM=y CONFIG_IO_STRICT_DEVMEM=y @@ -7383,9 +7560,3 @@ CONFIG_ARCH_USE_MEMTEST=y # end of Kernel hacking # CONFIG_KWORKER_NUMA_AFFINITY is not set - -# enable openEuler livepatch -CONFIG_LIVEPATCH=y -CONFIG_LIVEPATCH_WO_FTRACE=y -CONFIG_SAMPLES=y -CONFIG_SAMPLE_LIVEPATCH=m 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 #include #include +#include #include #include +#include #include #include @@ -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/barrier.h b/arch/riscv/include/asm/barrier.h index 110752594228..2b1f98b7e9bf 100644 --- a/arch/riscv/include/asm/barrier.h +++ b/arch/riscv/include/asm/barrier.h @@ -29,12 +29,22 @@ #define __smp_rmb() RISCV_FENCE(r,r) #define __smp_wmb() RISCV_FENCE(w,w) +#ifdef CONFIG_ARCH_SOPHGO #define __smp_store_release(p, v) \ do { \ compiletime_assert_atomic_type(*p); \ RISCV_FENCE(rw,w); \ WRITE_ONCE(*p, v); \ + RISCV_FENCE(w,rw); \ } while (0) +#else +#define __smp_store_release(p, v) \ +do { \ + compiletime_assert_atomic_type(*p); \ + RISCV_FENCE(rw,w); \ + WRITE_ONCE(*p, v); \ +} while (0) +#endif #define __smp_load_acquire(p) \ ({ \ @@ -44,6 +54,18 @@ do { \ ___p1; \ }) +#define smp_cond_load_acquire(ptr, cond_expr) ({ \ + typeof(ptr) __PTR = (ptr); \ + __unqual_scalar_typeof(*ptr) VAL; \ + for (;;) { \ + VAL = __smp_load_acquire(__PTR); \ + if (cond_expr) \ + break; \ + cpu_relax(); \ + } \ + (typeof(*ptr))VAL; \ +}) + /* * This is a very specific barrier: it's currently only used in two places in * the kernel, both in the scheduler. See include/linux/spinlock.h for the two 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/fixmap.h b/arch/riscv/include/asm/fixmap.h index 0a55099bb734..672bfe1121fe 100644 --- a/arch/riscv/include/asm/fixmap.h +++ b/arch/riscv/include/asm/fixmap.h @@ -10,6 +10,10 @@ #include #include #include +#ifdef CONFIG_HIGHMEM +#include +#include +#endif #ifdef CONFIG_MMU /* @@ -37,6 +41,10 @@ enum fixed_addresses { FIX_TEXT_POKE1, FIX_TEXT_POKE0, FIX_EARLYCON_MEM_BASE, +#ifdef CONFIG_HIGHMEM + FIX_KMAP_BEGIN, + FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_MAX_IDX * NR_CPUS) - 1, +#endif __end_of_permanent_fixed_addresses, /* @@ -47,7 +55,12 @@ enum fixed_addresses { #define FIX_BTMAPS_SLOTS 7 #define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS) +#ifdef CONFIG_HIGHMEM + FIX_BTMAP_END = __ALIGN_MASK(__end_of_permanent_fixed_addresses, + ((PMD_SIZE / PAGE_SIZE) - 1)) + 1, +#else FIX_BTMAP_END = __end_of_permanent_fixed_addresses, +#endif FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1, __end_of_fixed_addresses diff --git a/arch/riscv/include/asm/highmem.h b/arch/riscv/include/asm/highmem.h new file mode 100644 index 000000000000..a36fc835b8ab --- /dev/null +++ b/arch/riscv/include/asm/highmem.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#include +#include +#include + +#define flush_cache_kmaps() do {} while (0) + +extern pte_t *pkmap_page_table; +#endif diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h index 42497d487a17..bbdc3c7ed6ca 100644 --- a/arch/riscv/include/asm/io.h +++ b/arch/riscv/include/asm/io.h @@ -140,4 +140,8 @@ __io_writes_outs(outs, u64, q, __io_pbr(), __io_paw()) ((__force void *)ioremap_prot((addr), (size), _PAGE_KERNEL)) #endif +#undef ioremap_wc +#define ioremap_wc(addr, size) \ + ioremap_prot((addr), (size), _PAGE_IOREMAP_WC) + #endif /* _ASM_RISCV_IO_H */ diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h index 2b56769cb530..62f3ddc7c498 100644 --- a/arch/riscv/include/asm/kexec.h +++ b/arch/riscv/include/asm/kexec.h @@ -56,6 +56,7 @@ extern riscv_kexec_method riscv_kexec_norelocate; #ifdef CONFIG_KEXEC_FILE extern const struct kexec_file_ops elf_kexec_ops; +extern const struct kexec_file_ops image_kexec_ops; struct purgatory_info; int arch_kexec_apply_relocations_add(struct purgatory_info *pi, 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 + * bit[63] SO - Strong Order + * bit[62] C - Cacheable + * bit[61] B - Bufferable + * bit[60] SH - Shareable + * bit[59] 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/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index a16fcdf91f39..4774cd9e5a83 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -94,7 +94,12 @@ #ifdef CONFIG_64BIT #define MAX_FDT_SIZE PMD_SIZE #define FIX_FDT_SIZE (MAX_FDT_SIZE + SZ_2M) +#ifdef CONFIG_HIGHMEM +#define FIXADDR_PMD_NUM 20 +#define FIXADDR_SIZE ((PMD_SIZE * FIXADDR_PMD_NUM) + FIX_FDT_SIZE) +#else #define FIXADDR_SIZE (PMD_SIZE + FIX_FDT_SIZE) +#endif #else #define MAX_FDT_SIZE PGDIR_SIZE #define FIX_FDT_SIZE MAX_FDT_SIZE @@ -104,6 +109,14 @@ #endif +#ifdef CONFIG_HIGHMEM +#define PKMAP_BASE ((FIXADDR_START - PMD_SIZE) & (PMD_MASK)) +#define LAST_PKMAP (PMD_SIZE >> PAGE_SHIFT) +#define LAST_PKMAP_MASK (LAST_PKMAP - 1) +#define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) +#endif + #ifdef CONFIG_XIP_KERNEL #define XIP_OFFSET SZ_32M #define XIP_OFFSET_MASK (SZ_32M - 1) @@ -205,7 +218,8 @@ extern struct pt_alloc_ops pt_ops __initdata; #define PAGE_TABLE __pgprot(_PAGE_TABLE) -#define _PAGE_IOREMAP ((_PAGE_KERNEL & ~_PAGE_MTMASK) | _PAGE_IO) +#define _PAGE_IOREMAP ((_PAGE_KERNEL & ~_PAGE_MTMASK) | _PAGE_IO) +#define _PAGE_IOREMAP_WC ((_PAGE_KERNEL & ~_PAGE_MTMASK) | _PAGE_NOCACHE) #define PAGE_KERNEL_IO __pgprot(_PAGE_IOREMAP) extern pgd_t swapper_pg_dir[]; @@ -520,12 +534,17 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) void flush_icache_pte(pte_t pte); -static inline void __set_pte_at(pte_t *ptep, pte_t pteval) +static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) { if (pte_present(pteval) && pte_exec(pteval)) flush_icache_pte(pteval); set_pte(ptep, pteval); + +#ifdef CONFIG_HIGHMEM + local_flush_tlb_page(addr); +#endif } #define PFN_PTE_SHIFT _PAGE_PFN_SHIFT @@ -536,9 +555,10 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr, page_table_check_ptes_set(mm, ptep, pteval, nr); for (;;) { - __set_pte_at(ptep, pteval); + __set_pte_at(mm, addr, ptep, pteval); if (--nr == 0) break; + addr += PAGE_SIZE; ptep++; pte_val(pteval) += 1 << _PAGE_PFN_SHIFT; } @@ -548,7 +568,7 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr, static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - __set_pte_at(ptep, __pte(0)); + __set_pte_at(mm, addr, ptep, __pte(0)); } #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS @@ -557,7 +577,7 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma, pte_t entry, int dirty) { if (!pte_same(*ptep, entry)) - __set_pte_at(ptep, entry); + __set_pte_at(vma->vm_mm, address, ptep, entry); /* * update_mmu_cache will unconditionally execute, handling both * the case that the PTE changed and the spurious fault case. @@ -730,14 +750,14 @@ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pmd_t pmd) { page_table_check_pmd_set(mm, pmdp, pmd); - return __set_pte_at((pte_t *)pmdp, pmd_pte(pmd)); + return __set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd)); } static inline void set_pud_at(struct mm_struct *mm, unsigned long addr, pud_t *pudp, pud_t pud) { page_table_check_pud_set(mm, pudp, pud); - return __set_pte_at((pte_t *)pudp, pud_pte(pud)); + return __set_pte_at(mm, addr, (pte_t *)pudp, pud_pte(pud)); } #ifdef CONFIG_PAGE_TABLE_CHECK diff --git a/arch/riscv/include/asm/sparsemem.h b/arch/riscv/include/asm/sparsemem.h index 63acaecc3374..7ed3519b2d77 100644 --- a/arch/riscv/include/asm/sparsemem.h +++ b/arch/riscv/include/asm/sparsemem.h @@ -5,7 +5,7 @@ #ifdef CONFIG_SPARSEMEM #ifdef CONFIG_64BIT -#define MAX_PHYSMEM_BITS 56 +#define MAX_PHYSMEM_BITS 44 #else #define MAX_PHYSMEM_BITS 34 #endif /* CONFIG_64BIT */ diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index a727be723c56..1da3f54d52f0 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -63,6 +63,21 @@ static __always_inline bool has_fpu(void) return riscv_has_extension_likely(RISCV_ISA_EXT_f) || riscv_has_extension_likely(RISCV_ISA_EXT_d); } + + +static inline void kernel_fpu_begin(void) +{ + preempt_disable(); + fstate_save(current, task_pt_regs(current)); + csr_set(CSR_SSTATUS, SR_FS); +} + +static inline void kernel_fpu_end(void) +{ + csr_clear(CSR_SSTATUS, SR_FS); + fstate_restore(current, task_pt_regs(current)); + preempt_enable(); +} #else static __always_inline bool has_fpu(void) { return false; } #define fstate_save(task, regs) do { } while (0) diff --git a/arch/riscv/include/asm/timex.h b/arch/riscv/include/asm/timex.h index a06697846e69..a0e24f329381 100644 --- a/arch/riscv/include/asm/timex.h +++ b/arch/riscv/include/asm/timex.h @@ -9,6 +9,10 @@ #include typedef unsigned long cycles_t; +#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC +extern u64 dw_timer_read_counter(void); +extern void __iomem *sched_io_base; +#endif #ifdef CONFIG_RISCV_M_MODE @@ -52,7 +56,18 @@ static inline cycles_t get_cycles(void) { return csr_read(CSR_TIME); } +#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC +static inline cycles_t dw_get_cycles(void) +{ + if (sched_io_base) + return dw_timer_read_counter(); + else + return csr_read(CSR_TIME); +} +#define get_cycles dw_get_cycles +#else #define get_cycles get_cycles +#endif static inline u32 get_cycles_hi(void) { diff --git a/arch/riscv/include/asm/vdso/gettimeofday.h b/arch/riscv/include/asm/vdso/gettimeofday.h index ba3283cf7acc..ece0654e5767 100644 --- a/arch/riscv/include/asm/vdso/gettimeofday.h +++ b/arch/riscv/include/asm/vdso/gettimeofday.h @@ -84,6 +84,26 @@ static __always_inline const struct vdso_data *__arch_get_vdso_data(void) return _vdso_data; } +#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC +static inline bool sophgo_vdso_hres_capable(void) +{ + return false; +} +#define __arch_vdso_hres_capable sophgo_vdso_hres_capable + +static inline bool sophgo_vdso_clocksource_ok(const struct vdso_data *vd) +{ + return false; +} +#define vdso_clocksource_ok sophgo_vdso_clocksource_ok + +static inline bool sophgo_vdso_cycles_ok(u64 cycles) +{ + return false; +} +#define vdso_cycles_ok sophgo_vdso_cycles_ok +#endif + #ifdef CONFIG_TIME_NS static __always_inline const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd) diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index a2499fcc1cf3..668e5e5c8e41 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -88,7 +88,7 @@ endif obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KEXEC_CORE) += kexec_relocate.o crash_save_regs.o machine_kexec.o -obj-$(CONFIG_KEXEC_FILE) += elf_kexec.o machine_kexec_file.o +obj-$(CONFIG_KEXEC_FILE) += elf_kexec.o image_kexec.o machine_kexec_file.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_CRASH_CORE) += crash_core.o diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c index e60fbd8660c4..3b80befe0519 100644 --- a/arch/riscv/kernel/elf_kexec.c +++ b/arch/riscv/kernel/elf_kexec.c @@ -450,6 +450,12 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi, case R_RISCV_SUB32: *(u32 *)loc -= val; break; + case R_RISCV_ADD16: + *(u16 *)loc += val; + break; + case R_RISCV_SUB16: + *(u16 *)loc -= val; + break; /* It has been applied by R_RISCV_PCREL_HI20 sym */ case R_RISCV_PCREL_LO12_I: case R_RISCV_ALIGN: diff --git a/arch/riscv/kernel/image_kexec.c b/arch/riscv/kernel/image_kexec.c new file mode 100644 index 000000000000..37c5bd813958 --- /dev/null +++ b/arch/riscv/kernel/image_kexec.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Kexec image loader + + * Adapted from arch/arm64/kernel/kexec_image.c + * Copyright (C) 2018 Linaro Limited + * Author: AKASHI Takahiro + */ +#define pr_fmt(fmt) "kexec_file(Image): " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int prepare_elf_headers(void **addr, unsigned long *sz) +{ + struct crash_mem *cmem; + unsigned int nr_ranges; + int ret; + u64 i; + phys_addr_t start, end; + + nr_ranges = 2; /* for exclusion of crashkernel region */ + for_each_mem_range(i, &start, &end) + nr_ranges++; + + cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL); + if (!cmem) + return -ENOMEM; + + cmem->max_nr_ranges = nr_ranges; + cmem->nr_ranges = 0; + for_each_mem_range(i, &start, &end) { + cmem->ranges[cmem->nr_ranges].start = start; + cmem->ranges[cmem->nr_ranges].end = end - 1; + cmem->nr_ranges++; + } + + /* Exclude crashkernel region */ + ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); + if (ret) + goto out; + + if (crashk_low_res.end) { + ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end); + if (ret) + goto out; + } + + ret = crash_prepare_elf64_headers(cmem, true, addr, sz); + +out: + kfree(cmem); + return ret; +} + +/* + * Tries to add the initrd and DTB to the image. If it is not possible to find + * valid locations, this function will undo changes to the image and return non + * zero. + */ +static int load_other_segments(struct kimage *image, + unsigned long kernel_load_addr, + unsigned long kernel_size, + char *initrd, unsigned long initrd_len, + char *cmdline) +{ + struct kexec_buf kbuf; + void *headers, *fdt = NULL; + unsigned long headers_sz, initrd_load_addr = 0, + orig_segments = image->nr_segments; + int ret = 0; + + kbuf.image = image; + /* not allocate anything below the kernel */ + kbuf.buf_min = kernel_load_addr + kernel_size; + + /* load elf core header */ + if (image->type == KEXEC_TYPE_CRASH) { + ret = prepare_elf_headers(&headers, &headers_sz); + if (ret) { + pr_err("Preparing elf core header failed\n"); + goto out_err; + } + + kbuf.buffer = headers; + kbuf.bufsz = headers_sz; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = headers_sz; + kbuf.buf_align = PAGE_SIZE; + kbuf.buf_max = ULONG_MAX; + kbuf.top_down = true; + + ret = kexec_add_buffer(&kbuf); + if (ret) { + vfree(headers); + goto out_err; + } + image->elf_headers = headers; + image->elf_load_addr = kbuf.mem; + image->elf_headers_sz = headers_sz; + + pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + image->elf_load_addr, kbuf.bufsz, kbuf.memsz); + } + + /* load initrd */ + if (initrd) { + kbuf.buffer = initrd; + kbuf.bufsz = initrd_len; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = initrd_len; + kbuf.buf_align = PAGE_SIZE; + /* avoid to overlap kernel address */ + kbuf.buf_min = round_up(kernel_load_addr, SZ_1G); + kbuf.buf_max = ULONG_MAX; + kbuf.top_down = false; + + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out_err; + initrd_load_addr = kbuf.mem; + + pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + initrd_load_addr, kbuf.bufsz, kbuf.memsz); + } + + /* load dtb */ + fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr, + initrd_len, cmdline, 0); + if (!fdt) { + pr_err("Preparing for new dtb failed\n"); + ret = -EINVAL; + goto out_err; + } + + /* trim it */ + fdt_pack(fdt); + kbuf.buffer = fdt; + kbuf.bufsz = kbuf.memsz = fdt_totalsize(fdt); + kbuf.buf_align = PAGE_SIZE; + kbuf.buf_max = ULONG_MAX; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.top_down = false; + + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out_err; + /* Cache the fdt buffer address for memory cleanup */ + image->arch.fdt = fdt; + image->arch.fdt_addr = kbuf.mem; + + pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + kbuf.mem, kbuf.bufsz, kbuf.memsz); + + return 0; + +out_err: + image->nr_segments = orig_segments; + kvfree(fdt); + return ret; +} + +static int image_probe(const char *kernel_buf, unsigned long kernel_len) +{ + const struct riscv_image_header *h = + (const struct riscv_image_header *)(kernel_buf); + + if (!h || (kernel_len < sizeof(*h))) + return -EINVAL; + + if (memcmp(&h->magic2, RISCV_IMAGE_MAGIC2, sizeof(h->magic2))) + return -EINVAL; + + return 0; +} + +static void *image_load(struct kimage *image, + char *kernel, unsigned long kernel_len, + char *initrd, unsigned long initrd_len, + char *cmdline, unsigned long cmdline_len) +{ + struct riscv_image_header *h; + u64 flags; + bool be_image, be_kernel; + struct kexec_buf kbuf; + unsigned long text_offset, kernel_segment_number; + unsigned long kernel_start; + struct kexec_segment *kernel_segment; + int ret; + + h = (struct riscv_image_header *)kernel; + if (!h->image_size) + return ERR_PTR(-EINVAL); + + /* Check cpu features */ + flags = le64_to_cpu(h->flags); + be_image = __HEAD_FLAG(BE); + be_kernel = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); + if (be_image != be_kernel) + return ERR_PTR(-EINVAL); + + /* Load the kernel */ + kbuf.image = image; + kbuf.buf_min = 0; + kbuf.buf_max = ULONG_MAX; + kbuf.top_down = false; + + kbuf.buffer = kernel; + kbuf.bufsz = kernel_len; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = le64_to_cpu(h->image_size); + text_offset = le64_to_cpu(h->text_offset); + kbuf.buf_align = PMD_SIZE; + + /* Adjust kernel segment with TEXT_OFFSET */ + kbuf.memsz += text_offset; + + kernel_segment_number = image->nr_segments; + + /* + * The location of the kernel segment may make it impossible to satisfy + * the other segment requirements, so we try repeatedly to find a + * location that will work. + */ + while ((ret = kexec_add_buffer(&kbuf)) == 0) { + /* Try to load additional data */ + kernel_segment = &image->segment[kernel_segment_number]; + ret = load_other_segments(image, kernel_segment->mem, + kernel_segment->memsz, initrd, + initrd_len, cmdline); + if (!ret) + break; + + /* + * We couldn't find space for the other segments; erase the + * kernel segment and try the next available hole. + */ + image->nr_segments -= 1; + kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + } + + if (ret) { + pr_err("Could not find any suitable kernel location!"); + return ERR_PTR(ret); + } + + kernel_segment = &image->segment[kernel_segment_number]; + kernel_segment->mem += text_offset; + kernel_segment->memsz -= text_offset; + kernel_start = kernel_segment->mem; + image->start = kernel_start; + + + pr_debug("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + kernel_segment->mem, kbuf.bufsz, + kernel_segment->memsz); + +#ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY + /* Add purgatory to the image */ + kbuf.top_down = true; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + ret = kexec_load_purgatory(image, &kbuf); + if (ret) { + pr_err("Error loading purgatory ret=%d\n", ret); + return ERR_PTR(ret); + } + ret = kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry", + &kernel_start, + sizeof(kernel_start), 0); + if (ret) + pr_err("Error update purgatory ret=%d\n", ret); +#endif /* CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY */ + + return ret ? ERR_PTR(ret) : NULL; +} + +#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG +static int image_verify_sig(const char *kernel, unsigned long kernel_len) +{ + return verify_pefile_signature(kernel, kernel_len, NULL, + VERIFYING_KEXEC_PE_SIGNATURE); +} +#endif + +const struct kexec_file_ops image_kexec_ops = { + .probe = image_probe, + .load = image_load, +#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG + .verify_sig = image_verify_sig, +#endif +}; diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c index b0bf8c1722c0..401edfd1774f 100644 --- a/arch/riscv/kernel/machine_kexec_file.c +++ b/arch/riscv/kernel/machine_kexec_file.c @@ -9,6 +9,7 @@ #include const struct kexec_file_ops * const kexec_file_loaders[] = { + &image_kexec_ops, &elf_kexec_ops, NULL }; diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c index df4f6fec5d17..ced5a09abaaa 100644 --- a/arch/riscv/kernel/module.c +++ b/arch/riscv/kernel/module.c @@ -337,6 +337,45 @@ static int (*reloc_handlers_rela[]) (struct module *me, u32 *location, [R_RISCV_SUB64] = apply_r_riscv_sub64_rela, }; +static inline unsigned int apply_calc_pcrel_lo12(Elf_Shdr *sechdrs, + Elf_Rela *rel, Elf_Sym *sym, unsigned int idx, + unsigned int symindex, unsigned int relsec, + struct module *me, Elf_Addr *v) +{ + unsigned long hi20_loc = + sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[idx].r_offset; + u32 hi20_type = ELF_RISCV_R_TYPE(rel[idx].r_info); + unsigned int found = 0; + + /* Find the corresponding HI20 relocation entry */ + if (hi20_loc == sym->st_value + && (hi20_type == R_RISCV_PCREL_HI20 + || hi20_type == R_RISCV_GOT_HI20)) { + s32 hi20, lo12; + Elf_Sym *hi20_sym = + (Elf_Sym *)sechdrs[symindex].sh_addr + + ELF_RISCV_R_SYM(rel[idx].r_info); + unsigned long hi20_sym_val = + hi20_sym->st_value + rel[idx].r_addend; + + /* Calculate lo12 */ + size_t offset = hi20_sym_val - hi20_loc; + if (IS_ENABLED(CONFIG_MODULE_SECTIONS) + && hi20_type == R_RISCV_GOT_HI20) { + offset = module_emit_got_entry(me, hi20_sym_val); + offset = offset - hi20_loc; + } + hi20 = (offset + 0x800) & 0xfffff000; + lo12 = offset - hi20; + *v = (Elf_Addr)lo12; + + found = 1; + } + + return found; +} + int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me) @@ -385,40 +424,24 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) { unsigned int j; + unsigned int found = 0; - for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) { - unsigned long hi20_loc = - sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[j].r_offset; - u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info); - - /* Find the corresponding HI20 relocation entry */ - if (hi20_loc == sym->st_value - && (hi20_type == R_RISCV_PCREL_HI20 - || hi20_type == R_RISCV_GOT_HI20)) { - s32 hi20, lo12; - Elf_Sym *hi20_sym = - (Elf_Sym *)sechdrs[symindex].sh_addr - + ELF_RISCV_R_SYM(rel[j].r_info); - unsigned long hi20_sym_val = - hi20_sym->st_value - + rel[j].r_addend; - - /* Calculate lo12 */ - size_t offset = hi20_sym_val - hi20_loc; - if (IS_ENABLED(CONFIG_MODULE_SECTIONS) - && hi20_type == R_RISCV_GOT_HI20) { - offset = module_emit_got_entry( - me, hi20_sym_val); - offset = offset - hi20_loc; - } - hi20 = (offset + 0x800) & 0xfffff000; - lo12 = offset - hi20; - v = lo12; + if (i > 0) { + j = i - 1; + found = apply_calc_pcrel_lo12(sechdrs, rel, sym, j, + symindex, relsec, me, &v); + } - break; + if (found == 0) { + for (j = 0; j < sechdrs[relsec].sh_size/sizeof(*rel); j++) { + found = apply_calc_pcrel_lo12(sechdrs, rel, sym, + j, symindex, relsec, me, &v); + if (found) { + break; + } } } + if (j == sechdrs[relsec].sh_size / sizeof(*rel)) { pr_err( "%s: Can not find HI20 relocation information\n", diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 83e223318822..dd973216e31c 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -204,3 +204,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) p->thread.sp = (unsigned long)childregs; /* kernel sp */ return 0; } + +EXPORT_SYMBOL_GPL(__fstate_save); +EXPORT_SYMBOL_GPL(__fstate_restore); diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c index 75486b25ac45..ba803aa15b89 100644 --- a/arch/riscv/kvm/vcpu_timer.c +++ b/arch/riscv/kvm/vcpu_timer.c @@ -15,6 +15,10 @@ #include #include +#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC +extern void dw_cs_get_mult_shift(u32 *mult, u32 *shift); +#endif + static u64 kvm_riscv_current_cycles(struct kvm_guest_timer *gt) { return get_cycles64() + gt->time_delta; @@ -358,6 +362,10 @@ void kvm_riscv_guest_timer_init(struct kvm *kvm) { struct kvm_guest_timer *gt = &kvm->arch.timer; +#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC + dw_cs_get_mult_shift(>->nsec_mult, >->nsec_shift); +#else riscv_cs_get_mult_shift(>->nsec_mult, >->nsec_shift); +#endif gt->time_delta = -get_cycles64(); } diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index ec02ea86aa39..0980d6c683ad 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -36,6 +36,11 @@ #include "../kernel/head.h" +#ifdef CONFIG_HIGHMEM +#include +extern phys_addr_t __init_memblock find_max_low_addr(phys_addr_t limit); +#endif + struct kernel_mapping kernel_map __ro_after_init; EXPORT_SYMBOL(kernel_map); #ifdef CONFIG_XIP_KERNEL @@ -75,6 +80,9 @@ static void __init zone_sizes_init(void) max_zone_pfns[ZONE_DMA32] = PFN_DOWN(dma32_phys_limit); #endif max_zone_pfns[ZONE_NORMAL] = max_low_pfn; +#ifdef CONFIG_HIGHMEM + max_zone_pfns[ZONE_HIGHMEM] = max_pfn; +#endif free_area_init(max_zone_pfns); } @@ -131,6 +139,10 @@ static inline void print_ml(char *name, unsigned long b, unsigned long t) static void __init print_vm_layout(void) { pr_notice("Virtual kernel memory layout:\n"); +#ifdef CONFIG_HIGHMEM + print_ml("pkmap", (unsigned long)PKMAP_BASE, + (unsigned long)FIXADDR_START); +#endif print_ml("fixmap", (unsigned long)FIXADDR_START, (unsigned long)FIXADDR_TOP); print_ml("pci io", (unsigned long)PCI_IO_START, @@ -158,6 +170,106 @@ static void __init print_vm_layout(void) static void print_vm_layout(void) { } #endif /* CONFIG_DEBUG_VM */ +#ifdef CONFIG_HIGHMEM + +#ifdef CONFIG_DEBUG_VM +#error Please unset CONFIG_DEBUG_VM when CONFIG_HIGHMEM is set, \ +because CONFIG_DEBUG_VM will trigger VM_BUG_ON_PAGE in __free_pages()->put_page_testzero(). +#endif +#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_NUMA) +#error Please unset CONFIG_SPARSEMEM_VMEMMAP when CONFIG_HIGHMEM and CONFIG_NUMA are set, \ +because vmemmap_verify will report warning that [xxx-xxx] potential offnode page_structs. +#endif + +/* free order size pages for optimize system boot time. */ +#define OPTIMIZE_FREE_PAGES + +#ifdef OPTIMIZE_FREE_PAGES +#define ORDER_SIZE(order) (1UL << order) +#define ORDER_MASK(order) (~(ORDER_SIZE(order) - 1)) +#define PFN_ALIGN_ORDER(pfn, order) \ + (((u64)(pfn) + (ORDER_SIZE(order) - 1)) & ORDER_MASK(order)) + +/* Free the reserved page into the buddy system, so it gets managed. */ +static void __init free_highmem_pages(u64 start, u64 order) +{ + struct page *page; + u64 i, pfn; + + for (i = 0, pfn = start; i < ORDER_SIZE(order); i++, pfn++) { + page = pfn_to_page(pfn); + ClearPageReserved(page); + set_page_count(page, 0); + } + + page = pfn_to_page(start); + __free_pages(page, order); + adjust_managed_page_count(page, ORDER_SIZE(order)); +} + +static void __init free_highpages(void) +{ + phys_addr_t range_start, range_end; + u64 max_low = max_low_pfn; + u64 i, order; + + /* set highmem page free */ + for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, + &range_start, &range_end, NULL) { + u64 start = PFN_UP(range_start), start_align; + u64 end = PFN_DOWN(range_end); + + /* Ignore complete lowmem entries */ + if (end <= max_low) + continue; + + /* Truncate partial highmem entries */ + if (start < max_low) + start = max_low; + + order = MAX_ORDER; + start_align = PFN_ALIGN_ORDER(start, order); + + for (; start < start_align; start++) + free_highmem_page(pfn_to_page(start)); + + //step by order size + for (; start < end; start += ORDER_SIZE(order)) + free_highmem_pages(start, order); + + for (; start < end; start++) + free_highmem_page(pfn_to_page(start)); + } +} +#else +static void __init free_highpages(void) +{ + unsigned long max_low = max_low_pfn; + phys_addr_t range_start, range_end; + u64 i; + + /* set highmem page free */ + for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, + &range_start, &range_end, NULL) { + unsigned long start = PFN_UP(range_start); + unsigned long end = PFN_DOWN(range_end); + + + /* Ignore complete lowmem entries */ + if (end <= max_low) + continue; + + /* Truncate partial highmem entries */ + if (start < max_low) + start = max_low; + + for (; start < end; start++) + free_highmem_page(pfn_to_page(start)); + } +} +#endif +#endif + void __init mem_init(void) { #ifdef CONFIG_FLATMEM @@ -166,6 +278,9 @@ void __init mem_init(void) swiotlb_init(max_pfn > PFN_DOWN(dma32_phys_limit), SWIOTLB_VERBOSE); memblock_free_all(); +#ifdef CONFIG_HIGHMEM + free_highpages(); +#endif print_vm_layout(); } @@ -197,13 +312,18 @@ static void __init setup_bootmem(void) phys_addr_t vmlinux_end = __pa_symbol(&_end); phys_addr_t max_mapped_addr; phys_addr_t phys_ram_end, vmlinux_start; +#ifdef CONFIG_HIGHMEM + phys_addr_t max_low_addr; +#endif if (IS_ENABLED(CONFIG_XIP_KERNEL)) vmlinux_start = __pa_symbol(&_sdata); else vmlinux_start = __pa_symbol(&_start); +#ifndef CONFIG_HIGHMEM memblock_enforce_memory_limit(memory_limit); +#endif /* * Make sure we align the reservation on PMD_SIZE since we will @@ -249,12 +369,22 @@ static void __init setup_bootmem(void) } min_low_pfn = PFN_UP(phys_ram_base); +#ifdef CONFIG_HIGHMEM + max_low_addr = find_max_low_addr(memory_limit); + max_low_pfn = PFN_DOWN(max_low_addr); + max_pfn = PFN_DOWN(phys_ram_end); + memblock_set_current_limit(max_low_addr); +#else max_low_pfn = max_pfn = PFN_DOWN(phys_ram_end); +#endif high_memory = (void *)(__va(PFN_PHYS(max_low_pfn))); dma32_phys_limit = min(4UL * SZ_1G, (unsigned long)PFN_PHYS(max_low_pfn)); +#ifdef CONFIG_HIGHMEM + set_max_mapnr(max_pfn - ARCH_PFN_OFFSET); +#else set_max_mapnr(max_low_pfn - ARCH_PFN_OFFSET); - +#endif reserve_initrd_mem(); /* @@ -283,8 +413,14 @@ struct pt_alloc_ops pt_ops __initdata; pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss; pgd_t trampoline_pg_dir[PTRS_PER_PGD] __page_aligned_bss; +#ifdef CONFIG_HIGHMEM +static pte_t fixmap_pte[PTRS_PER_PTE * FIXADDR_PMD_NUM] __page_aligned_bss; +#else static pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss; - +#endif +#ifdef CONFIG_HIGHMEM +static pte_t pkmap_pte[PTRS_PER_PTE] __page_aligned_bss; +#endif pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); #ifdef CONFIG_XIP_KERNEL @@ -318,10 +454,17 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot) { unsigned long addr = __fix_to_virt(idx); pte_t *ptep; +#ifdef CONFIG_HIGHMEM + unsigned long pte_idx = (addr - FIXADDR_START) >> PAGE_SHIFT; +#endif BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses); +#ifdef CONFIG_HIGHMEM + ptep = &fixmap_pte[pte_idx]; +#else ptep = &fixmap_pte[pte_index(addr)]; +#endif if (pgprot_val(prot)) set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot)); @@ -1144,8 +1287,26 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) if (pgtable_l4_enabled) create_pud_mapping(fixmap_pud, FIXADDR_START, (uintptr_t)fixmap_pmd, PUD_SIZE, PAGE_TABLE); +#ifdef CONFIG_HIGHMEM + { + int i; + for (i = 0; i < FIXADDR_PMD_NUM; i++) + create_pmd_mapping(fixmap_pmd, + (FIXADDR_START + i * PMD_SIZE), + (uintptr_t)&(fixmap_pte[i * PTRS_PER_PTE]), + PMD_SIZE, + PAGE_TABLE); + } +#else create_pmd_mapping(fixmap_pmd, FIXADDR_START, (uintptr_t)fixmap_pte, PMD_SIZE, PAGE_TABLE); +#endif +#ifdef CONFIG_HIGHMEM + /* Setup pkmap PMD */ + create_pmd_mapping(fixmap_pmd, PKMAP_BASE, + (uintptr_t)pkmap_pte, PMD_SIZE, PAGE_TABLE); +#endif + /* Setup trampoline PGD and PMD */ create_pgd_mapping(trampoline_pg_dir, kernel_map.virt_addr, trampoline_pgd_next, PGDIR_SIZE, PAGE_TABLE); @@ -1488,6 +1649,13 @@ static void __init reserve_crashkernel(void) crashk_res.end = crash_base + crash_size - 1; } +#ifdef CONFIG_HIGHMEM +static void __init pkmap_init(void) +{ + pkmap_page_table = &pkmap_pte[pte_index(PKMAP_BASE)]; +} +#endif + void __init paging_init(void) { setup_bootmem(); @@ -1507,6 +1675,9 @@ void __init misc_mem_init(void) local_flush_tlb_kernel_range(VMEMMAP_START, VMEMMAP_END); #endif zone_sizes_init(); +#ifdef CONFIG_HIGHMEM + pkmap_init(); +#endif reserve_crashkernel(); memblock_dump_all(); } diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c index 01398fee5cf8..161d0b34c2cb 100644 --- a/arch/riscv/mm/pageattr.c +++ b/arch/riscv/mm/pageattr.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -26,6 +25,19 @@ static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk) return new_val; } +static int pageattr_pgd_entry(pgd_t *pgd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + pgd_t val = READ_ONCE(*pgd); + + if (pgd_leaf(val)) { + val = __pgd(set_pageattr_masks(pgd_val(val), walk)); + set_pgd(pgd, val); + } + + return 0; +} + static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr, unsigned long next, struct mm_walk *walk) { @@ -84,6 +96,7 @@ static int pageattr_pte_hole(unsigned long addr, unsigned long next, } static const struct mm_walk_ops pageattr_ops = { + .pgd_entry = pageattr_pgd_entry, .p4d_entry = pageattr_p4d_entry, .pud_entry = pageattr_pud_entry, .pmd_entry = pageattr_pmd_entry, @@ -92,181 +105,12 @@ static const struct mm_walk_ops pageattr_ops = { .walk_lock = PGWALK_RDLOCK, }; -#ifdef CONFIG_64BIT -static int __split_linear_mapping_pmd(pud_t *pudp, - unsigned long vaddr, unsigned long end) -{ - pmd_t *pmdp; - unsigned long next; - - pmdp = pmd_offset(pudp, vaddr); - - do { - next = pmd_addr_end(vaddr, end); - - if (next - vaddr >= PMD_SIZE && - vaddr <= (vaddr & PMD_MASK) && end >= next) - continue; - - if (pmd_leaf(*pmdp)) { - struct page *pte_page; - unsigned long pfn = _pmd_pfn(*pmdp); - pgprot_t prot = __pgprot(pmd_val(*pmdp) & ~_PAGE_PFN_MASK); - pte_t *ptep_new; - int i; - - pte_page = alloc_page(GFP_KERNEL); - if (!pte_page) - return -ENOMEM; - - ptep_new = (pte_t *)page_address(pte_page); - for (i = 0; i < PTRS_PER_PTE; ++i, ++ptep_new) - set_pte(ptep_new, pfn_pte(pfn + i, prot)); - - smp_wmb(); - - set_pmd(pmdp, pfn_pmd(page_to_pfn(pte_page), PAGE_TABLE)); - } - } while (pmdp++, vaddr = next, vaddr != end); - - return 0; -} - -static int __split_linear_mapping_pud(p4d_t *p4dp, - unsigned long vaddr, unsigned long end) -{ - pud_t *pudp; - unsigned long next; - int ret; - - pudp = pud_offset(p4dp, vaddr); - - do { - next = pud_addr_end(vaddr, end); - - if (next - vaddr >= PUD_SIZE && - vaddr <= (vaddr & PUD_MASK) && end >= next) - continue; - - if (pud_leaf(*pudp)) { - struct page *pmd_page; - unsigned long pfn = _pud_pfn(*pudp); - pgprot_t prot = __pgprot(pud_val(*pudp) & ~_PAGE_PFN_MASK); - pmd_t *pmdp_new; - int i; - - pmd_page = alloc_page(GFP_KERNEL); - if (!pmd_page) - return -ENOMEM; - - pmdp_new = (pmd_t *)page_address(pmd_page); - for (i = 0; i < PTRS_PER_PMD; ++i, ++pmdp_new) - set_pmd(pmdp_new, - pfn_pmd(pfn + ((i * PMD_SIZE) >> PAGE_SHIFT), prot)); - - smp_wmb(); - - set_pud(pudp, pfn_pud(page_to_pfn(pmd_page), PAGE_TABLE)); - } - - ret = __split_linear_mapping_pmd(pudp, vaddr, next); - if (ret) - return ret; - } while (pudp++, vaddr = next, vaddr != end); - - return 0; -} - -static int __split_linear_mapping_p4d(pgd_t *pgdp, - unsigned long vaddr, unsigned long end) -{ - p4d_t *p4dp; - unsigned long next; - int ret; - - p4dp = p4d_offset(pgdp, vaddr); - - do { - next = p4d_addr_end(vaddr, end); - - /* - * If [vaddr; end] contains [vaddr & P4D_MASK; next], we don't - * need to split, we'll change the protections on the whole P4D. - */ - if (next - vaddr >= P4D_SIZE && - vaddr <= (vaddr & P4D_MASK) && end >= next) - continue; - - if (p4d_leaf(*p4dp)) { - struct page *pud_page; - unsigned long pfn = _p4d_pfn(*p4dp); - pgprot_t prot = __pgprot(p4d_val(*p4dp) & ~_PAGE_PFN_MASK); - pud_t *pudp_new; - int i; - - pud_page = alloc_page(GFP_KERNEL); - if (!pud_page) - return -ENOMEM; - - /* - * Fill the pud level with leaf puds that have the same - * protections as the leaf p4d. - */ - pudp_new = (pud_t *)page_address(pud_page); - for (i = 0; i < PTRS_PER_PUD; ++i, ++pudp_new) - set_pud(pudp_new, - pfn_pud(pfn + ((i * PUD_SIZE) >> PAGE_SHIFT), prot)); - - /* - * Make sure the pud filling is not reordered with the - * p4d store which could result in seeing a partially - * filled pud level. - */ - smp_wmb(); - - set_p4d(p4dp, pfn_p4d(page_to_pfn(pud_page), PAGE_TABLE)); - } - - ret = __split_linear_mapping_pud(p4dp, vaddr, next); - if (ret) - return ret; - } while (p4dp++, vaddr = next, vaddr != end); - - return 0; -} - -static int __split_linear_mapping_pgd(pgd_t *pgdp, - unsigned long vaddr, - unsigned long end) -{ - unsigned long next; - int ret; - - do { - next = pgd_addr_end(vaddr, end); - /* We never use PGD mappings for the linear mapping */ - ret = __split_linear_mapping_p4d(pgdp, vaddr, next); - if (ret) - return ret; - } while (pgdp++, vaddr = next, vaddr != end); - - return 0; -} - -static int split_linear_mapping(unsigned long start, unsigned long end) -{ - return __split_linear_mapping_pgd(pgd_offset_k(start), start, end); -} -#endif /* CONFIG_64BIT */ - static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, pgprot_t clear_mask) { int ret; unsigned long start = addr; unsigned long end = start + PAGE_SIZE * numpages; - unsigned long __maybe_unused lm_start; - unsigned long __maybe_unused lm_end; struct pageattr_masks masks = { .set_mask = set_mask, .clear_mask = clear_mask @@ -276,72 +120,11 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, return 0; mmap_write_lock(&init_mm); - -#ifdef CONFIG_64BIT - /* - * We are about to change the permissions of a kernel mapping, we must - * apply the same changes to its linear mapping alias, which may imply - * splitting a huge mapping. - */ - - if (is_vmalloc_or_module_addr((void *)start)) { - struct vm_struct *area = NULL; - int i, page_start; - - area = find_vm_area((void *)start); - page_start = (start - (unsigned long)area->addr) >> PAGE_SHIFT; - - for (i = page_start; i < page_start + numpages; ++i) { - lm_start = (unsigned long)page_address(area->pages[i]); - lm_end = lm_start + PAGE_SIZE; - - ret = split_linear_mapping(lm_start, lm_end); - if (ret) - goto unlock; - - ret = walk_page_range_novma(&init_mm, lm_start, lm_end, - &pageattr_ops, NULL, &masks); - if (ret) - goto unlock; - } - } else if (is_kernel_mapping(start) || is_linear_mapping(start)) { - if (is_kernel_mapping(start)) { - lm_start = (unsigned long)lm_alias(start); - lm_end = (unsigned long)lm_alias(end); - } else { - lm_start = start; - lm_end = end; - } - - ret = split_linear_mapping(lm_start, lm_end); - if (ret) - goto unlock; - - ret = walk_page_range_novma(&init_mm, lm_start, lm_end, - &pageattr_ops, NULL, &masks); - if (ret) - goto unlock; - } - ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, &masks); - -unlock: - mmap_write_unlock(&init_mm); - - /* - * We can't use flush_tlb_kernel_range() here as we may have split a - * hugepage that is larger than that, so let's flush everything. - */ - flush_tlb_all(); -#else - ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, - &masks); - mmap_write_unlock(&init_mm); flush_tlb_kernel_range(start, end); -#endif return ret; } @@ -376,14 +159,36 @@ int set_memory_nx(unsigned long addr, int numpages) int set_direct_map_invalid_noflush(struct page *page) { - return __set_memory((unsigned long)page_address(page), 1, - __pgprot(0), __pgprot(_PAGE_PRESENT)); + int ret; + unsigned long start = (unsigned long)page_address(page); + unsigned long end = start + PAGE_SIZE; + struct pageattr_masks masks = { + .set_mask = __pgprot(0), + .clear_mask = __pgprot(_PAGE_PRESENT) + }; + + mmap_read_lock(&init_mm); + ret = walk_page_range(&init_mm, start, end, &pageattr_ops, &masks); + mmap_read_unlock(&init_mm); + + return ret; } int set_direct_map_default_noflush(struct page *page) { - return __set_memory((unsigned long)page_address(page), 1, - PAGE_KERNEL, __pgprot(_PAGE_EXEC)); + int ret; + unsigned long start = (unsigned long)page_address(page); + unsigned long end = start + PAGE_SIZE; + struct pageattr_masks masks = { + .set_mask = PAGE_KERNEL, + .clear_mask = __pgprot(0) + }; + + mmap_read_lock(&init_mm); + ret = walk_page_range(&init_mm, start, end, &pageattr_ops, &masks); + mmap_read_unlock(&init_mm); + + return ret; } #ifdef CONFIG_DEBUG_PAGEALLOC diff --git a/drivers/base/arch_numa.c b/drivers/base/arch_numa.c index 96281de7010d..4b0b582bfc1a 100644 --- a/drivers/base/arch_numa.c +++ b/drivers/base/arch_numa.c @@ -359,7 +359,11 @@ static int __init numa_alloc_distance(void) int i, j; size = nr_node_ids * nr_node_ids * sizeof(numa_distance[0]); +#ifdef CONFIG_HIGHMEM + numa_distance = memblock_alloc_low(size, PAGE_SIZE); +#else numa_distance = memblock_alloc(size, PAGE_SIZE); +#endif if (WARN_ON(!numa_distance)) return -ENOMEM; diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c index ed5e91b1e040..210644f3d863 100644 --- a/drivers/char/ipmi/ipmi_si_hardcode.c +++ b/drivers/char/ipmi/ipmi_si_hardcode.c @@ -6,7 +6,7 @@ #include #include "ipmi_si.h" #include "ipmi_plat_data.h" - +#include /* * There can be 4 IO ports passed in (with or without IRQs), 4 addresses, * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS. @@ -90,6 +90,24 @@ static void __init ipmi_hardcode_init_one(const char *si_type_str, ipmi_platform_add("hardcode-ipmi-si", i, &p); } +#ifdef CONFIG_ARCH_SOPHGO +static void variable_init(struct pci_dev *pdev) +{ + unsigned long addr_data = pci_resource_start(pdev, 1) + 0x0e80; + // printk("addr_data=0x%lx\n", addr_data); + strcpy(si_type_str, "kcs"); + addrs[0] = addr_data; + num_addrs = 1; + regspacings[0] = 4; + num_regspacings = 1; + regsizes[0] = 4; + num_regsizes = 1; + irqs[0] = 0; + num_irqs = 1; + slave_addrs[0] = 0; + num_slave_addrs = 1; +} +#endif void __init ipmi_hardcode_init(void) { unsigned int i; @@ -97,7 +115,11 @@ void __init ipmi_hardcode_init(void) char *si_type[SI_MAX_PARMS]; memset(si_type, 0, sizeof(si_type)); - +#ifdef CONFIG_ARCH_SOPHGO + struct pci_dev *pdev = pci_get_device(0x1A03, 0x2402, NULL); + if (pdev != NULL) + variable_init(pdev); +#endif /* Parse out the si_type string into its components. */ str = si_type_str; if (*str != '\0') { diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 373ee71811e3..8e316d49bce1 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2158,7 +2158,8 @@ static int __init init_ipmi_si(void) return 0; } } -module_init(init_ipmi_si); +// module_init(init_ipmi_si); +late_initcall(init_ipmi_si); static void wait_msg_processed(struct smi_info *smi_info) { diff --git a/drivers/char/ipmi/ipmi_si_pci.c b/drivers/char/ipmi/ipmi_si_pci.c index 74fa2055868b..6a935100e1ae 100644 --- a/drivers/char/ipmi/ipmi_si_pci.c +++ b/drivers/char/ipmi/ipmi_si_pci.c @@ -111,6 +111,12 @@ static int ipmi_pci_probe(struct pci_dev *pdev, io.regsize = DEFAULT_REGSIZE; io.regshift = 0; +#ifdef CONFIG_ARCH_SOPHGO + io.addr_data = pci_resource_start(pdev, 1) + 0x0e80; + io.slave_addr = 0x20; + io.regspacing = 4; + io.regsize = 4; +#endif io.irq = pdev->irq; if (io.irq) io.irq_setup = ipmi_std_irq_setup; 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 +#include +#include +#include +#include +#include +#include +#include + +#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_clks[i].name, gate_clks[i].parent_name, + gate_clks[i].flags | CLK_IS_CRITICAL, base + gate_clks[i].offset, + gate_clks[i].bit_idx, gate_clks[i].gate_flags, + &clk_data->lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + gate_clks[i].name); + goto err; + } + + if (gate_clks[i].alias) + clk_register_clkdev(clk, gate_clks[i].alias, NULL); + + clk_data->clk_data.clks[gate_clks[i].id] = clk; + } + + return 0; + +err: + while (i--) + clk_unregister_gate(clk_data->clk_data.clks[gate_clks[i].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_clks[i].name, div_clks[i].parent_name, + div_clks[i].flags, base + div_clks[i].offset, + div_clks[i].shift, div_clks[i].width, + div_clks[i].initial_val, + (div_clks[i].initial_sel & MANGO_CLK_USE_INIT_VAL) ? + div_clks[i].div_flags | CLK_DIVIDER_READ_ONLY : + div_clks[i].div_flags, + div_clks[i].table, &clk_data->lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + div_clks[i].name); + goto err; + } + + clk_data->clk_data.clks[div_clks[i].id] = clk; + + if (div_clks[i].initial_sel == MANGO_CLK_USE_REG_VAL) { + regmap_read(clk_data->syscon_top, div_clks[i].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_clks[i].initial_val > 0) + val |= (div_clks[i].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_clks[i].offset, + val); + } + } + + return 0; + +err: + while (i--) + clk_unregister_divider(clk_data->clk_data.clks[div_clks[i].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_clks[i].width) - 1; + + clk = clk_register_mux_table( + dev, mux_clks[i].name, mux_clks[i].parent_names, + mux_clks[i].num_parents, mux_clks[i].flags, + base + mux_clks[i].offset, mux_clks[i].shift, mask, + mux_clks[i].mux_flags, mux_clks[i].table, + &clk_data->lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + mux_clks[i].name); + goto err; + } + + clk_data->clk_data.clks[mux_clks[i].id] = clk; + + if (!(mux_clks[i].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_clks[i].name); + } + } + + return 0; + +err: + while (i--) + clk_unregister_mux(clk_data->clk_data.clks[mux_clks[i].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_clks[i].name)) { + /* have to assigne pll_clks.syscon_top first + * since clk_register_composite will need it + * to calculate current rate. + */ + pll_clks[i].syscon_top = clk_data->syscon_top; + pll_clks[i].lock = &clk_data->lock; + if (pll_clks[i].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_clks[i].name, &pll_clks[i].parent_name, + 1, NULL, NULL, &pll_clks[i].hw, local_ops, + NULL, NULL, pll_clks[i].flags); + + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + pll_clks[i].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..894f2f177db8 --- /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 +#include +#include + +#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", + CLK_IS_CRITICAL, 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, 0x2000, 12, 0 }, + { GATE_CLK_TIMER2, "clk_gate_timer2", "clk_div_timer2", + CLK_SET_RATE_PARENT, 0x2000, 13, 0 }, + { GATE_CLK_TIMER3, "clk_gate_timer3", "clk_div_timer3", + CLK_SET_RATE_PARENT, 0x2000, 14, 0 }, + { GATE_CLK_TIMER4, "clk_gate_timer4", "clk_div_timer4", + CLK_SET_RATE_PARENT, 0x2000, 15, 0 }, + { GATE_CLK_TIMER5, "clk_gate_timer5", "clk_div_timer5", + CLK_SET_RATE_PARENT, 0x2000, 16, 0 }, + { GATE_CLK_TIMER6, "clk_gate_timer6", "clk_div_timer6", + CLK_SET_RATE_PARENT, 0x2000, 17, 0 }, + { GATE_CLK_TIMER7, "clk_gate_timer7", "clk_div_timer7", + CLK_SET_RATE_PARENT, 0x2000, 18, 0 }, + { GATE_CLK_TIMER8, "clk_gate_timer8", "clk_div_timer8", + CLK_SET_RATE_PARENT, 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", + CLK_IS_CRITICAL, 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, 0x2000, 12, 0 }, + { GATE_CLK_TIMER2, "s1_clk_gate_timer2", "s1_clk_div_timer2", + CLK_SET_RATE_PARENT, 0x2000, 13, 0 }, + { GATE_CLK_TIMER3, "s1_clk_gate_timer3", "s1_clk_div_timer3", + CLK_SET_RATE_PARENT, 0x2000, 14, 0 }, + { GATE_CLK_TIMER4, "s1_clk_gate_timer4", "s1_clk_div_timer4", + CLK_SET_RATE_PARENT, 0x2000, 15, 0 }, + { GATE_CLK_TIMER5, "s1_clk_gate_timer5", "s1_clk_div_timer5", + CLK_SET_RATE_PARENT, 0x2000, 16, 0 }, + { GATE_CLK_TIMER6, "s1_clk_gate_timer6", "s1_clk_div_timer6", + CLK_SET_RATE_PARENT, 0x2000, 17, 0 }, + { GATE_CLK_TIMER7, "s1_clk_gate_timer7", "s1_clk_div_timer7", + CLK_SET_RATE_PARENT, 0x2000, 18, 0 }, + { GATE_CLK_TIMER8, "s1_clk_gate_timer8", "s1_clk_div_timer8", + CLK_SET_RATE_PARENT, 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_data[i].id) + break; /* found */ + } + clk_data->table = &dev_data[i]; + 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_data[i].id) + break; /* found */ + } + clk_data->table = &dev_data[i]; + 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 +#include +#include +#include +#include +#include +#include +#include + +#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_2[0] = {1, 1, 1} + * ==> div1 = 1, div2 = 1 , div1 * div2 = 1 + * postdiv1_2[22] = {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_2[][3] = { + {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_2[index][POSTDIV_RESULT_INDEX]) { + continue; + } else { + /* found it */ + break; + } + } + if (index < ARRAY_SIZE(postdiv1_2)) { + *postdiv1 = postdiv1_2[index][1]; + *postdiv2 = postdiv1_2[index][0]; + } 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_clks[i].name, gate_clks[i].parent_name, + gate_clks[i].flags, base + gate_clks[i].offset, + gate_clks[i].bit_idx, gate_clks[i].gate_flags, + &clk_data->lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + gate_clks[i].name); + goto err; + } + + if (gate_clks[i].alias) + clk_register_clkdev(clk, gate_clks[i].alias, NULL); + + clk_data->clk_data.clks[gate_clks[i].id] = clk; + } + + return 0; + +err: + while (i--) + clk_unregister_gate(clk_data->clk_data.clks[gate_clks[i].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_clks[i].name, div_clks[i].parent_name, + div_clks[i].flags, base + div_clks[i].offset, + div_clks[i].shift, div_clks[i].width, + div_clks[i].initial_val, + (div_clks[i].initial_sel & MANGO_CLK_USE_INIT_VAL) ? + div_clks[i].div_flags | CLK_DIVIDER_READ_ONLY : + div_clks[i].div_flags, + div_clks[i].table, &clk_data->lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + div_clks[i].name); + goto err; + } + + clk_data->clk_data.clks[div_clks[i].id] = clk; + + if (div_clks[i].initial_sel == MANGO_CLK_USE_REG_VAL) { + regmap_read(clk_data->syscon_top, div_clks[i].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_clks[i].initial_val > 0) + val |= (div_clks[i].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_clks[i].offset, + val); + } + } + + return 0; + +err: + while (i--) + clk_unregister_divider(clk_data->clk_data.clks[div_clks[i].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_clks[i].width) - 1; + + clk = clk_register_mux_table( + dev, mux_clks[i].name, mux_clks[i].parent_names, + mux_clks[i].num_parents, mux_clks[i].flags, + base + mux_clks[i].offset, mux_clks[i].shift, mask, + mux_clks[i].mux_flags, mux_clks[i].table, + &clk_data->lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + mux_clks[i].name); + goto err; + } + + clk_data->clk_data.clks[mux_clks[i].id] = clk; + + if (!(mux_clks[i].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_clks[i].name); + } + } + + return 0; + +err: + while (i--) + clk_unregister_mux(clk_data->clk_data.clks[mux_clks[i].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_clks[i].name)) { + /* have to assigne pll_clks.syscon_top first + * since clk_register_composite will need it + * to calculate current rate. + */ + pll_clks[i].syscon_top = clk_data->syscon_top; + pll_clks[i].lock = &clk_data->lock; + if (pll_clks[i].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_clks[i].name, &pll_clks[i].parent_name, + 1, NULL, NULL, &pll_clks[i].hw, local_ops, + NULL, NULL, pll_clks[i].flags); + + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", __func__, + pll_clks[i].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 +#include +#include +#include +#include +#include + +#include + +#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_table[4]; +}; + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static struct clk *clks[CLK_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 */ + clks[CLK_DUMMY] = thead_clk_fixed("dummy", 0); + clks[OSC_32K] = of_clk_get_by_name(np, "osc_32k"); + clks[OSC_24M] = of_clk_get_by_name(np, "osc_24m"); + clks[RC_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 */ + clks[CPU_PLL0_FOUTPOSTDIV] = thead_light_pll("cpu_pll0_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll0div); + clks[CPU_PLL1_FOUTPOSTDIV] = thead_light_pll("cpu_pll1_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll1div); + + clks[DPU0_PLL_FOUTPOSTDIV] = thead_light_pll("dpu0_pll_foutpostdiv", "osc_24m", ap_base, &light_dpu0_plldiv); + clks[DPU1_PLL_FOUTPOSTDIV] = thead_light_pll("dpu1_pll_foutpostdiv", "osc_24m", ap_base, &light_dpu1_plldiv); + + /* Light Fullmask AP Fixed PLL */ + clks[GMAC_PLL_FOUTPOSTDIV] = thead_clk_fixed("gmac_pll_foutpostdiv", 1000000000); + clks[VIDEO_PLL_FOUTPOSTDIV] = thead_clk_fixed("video_pll_foutpostdiv", 792000000); + clks[VIDEO_PLL_FOUTVCO] = thead_clk_fixed("video_pll_foutvco", 2376000000); + clks[TEE_PLL_FOUTPOSTDIV] = thead_clk_fixed("tee_pll_foutpostdiv", 792000000); + clks[CLKGEN_PERI_I2S_SRC_CLK_0] = thead_clk_fixed("clkgen_peri_i2s_src_clk_0", 294912000); //from audio_pll_foutpostdiv + clks[CLKGEN_PERI_I2S_SRC_CLK_1] = thead_clk_fixed("clkgen_peri_i2s_src_clk_1", 135475200); //from sys_pll_foutpostdiv + clks[CLKGEN_C910_BUS_CLK_NO_ICG] = thead_clk_fixed("clkgen_c910_bus_clk_no_icg", 750000000); + clks[AONSYS_BUS_CLK] = thead_clk_fixed("aonsys_hclk", 101606400); //from sys_pll, maybe change ? + + /* Light Fullmask AP MUX */ + clks[CPU_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); + clks[CPU_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); + clks[GMAC_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); + clks[VIDEO_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); + clks[TEE_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); + clks[DPU0_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); + clks[DPU1_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); + + clks[AHB2_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); + clks[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); + clks[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); + clks[CFG_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) + clks[TEESYS_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!!! + + clks[PERISYS_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); + clks[CLK_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); + clks[CLK_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); + clks[CLK_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); + clks[CLK_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); + clks[PERI_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); + clks[NPU_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); + clks[CFG_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); + clks[UART_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 */ + clks[AHB2_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); + clks[APB3_CPUSYS_PCLK] = thead_clk_light_divider("apb3_cpusys_pclk", "ahb2_cpusys_hclk", ap_base + 0x130, 0, 3, 3, MUX_TYPE_CDE, 1, 7); + clks[AXI4_CPUSYS2_ACLK] = thead_clk_light_divider("axi4_cpusys2_aclk", "gmac_pll_foutpostdiv", ap_base + 0x134, 0, 3, 4, MUX_TYPE_DIV, 2, 7); + clks[CFG_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) { + clks[TEESYS_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!!! + clks[TEESYS_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!!! + } + + clks[PERISYS_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); + clks[PERISYS_APB_PCLK] = thead_clk_light_divider("perisys_apb_pclk", "perisys_ahb_hclk", ap_base + 0x150, 0, 3, 3, MUX_TYPE_CDE, 3, 7); + clks[PERI2SYS_APB_PCLK] = thead_clk_light_divider("peri2sys_apb_pclk", "gmac_pll_fout4", ap_base + 0x150, 4, 3, 8, MUX_TYPE_DIV, 2, 7); + clks[CLK_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); + clks[CLK_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); + clks[CLK_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); + clks[CLK_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); + clks[VOSYS_ACLK_M] = thead_clk_light_divider("vosys_aclk_m", "video_pll_foutvco", ap_base + 0x1dc, 0, 4, 4, MUX_TYPE_DIV, 3, 15); + clks[NPU_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); + clks[CFG_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); + clks[VISYS_ACLK_M] = thead_clk_light_divider("visys_aclk_m", "video_pll_foutvco", ap_base + 0x1d0, 16, 4, 20, MUX_TYPE_DIV, 3, 15); + clks[VISYS_AHB_HCLK] = thead_clk_light_divider("visys_ahb_hclk", "video_pll_foutvco", ap_base + 0x1d0, 0, 4, 4, MUX_TYPE_DIV, 6, 15); + clks[VPSYS_APB_PCLK] = thead_clk_light_divider("vpsys_apb_pclk", "gmac_pll_fout1ph0", ap_base + 0x1e0, 0, 3, 4, MUX_TYPE_DIV, 2, 7); + clks[VPSYS_AXI_ACLK] = thead_clk_light_divider("vpsys_axi_aclk", "video_pll_foutvco", ap_base + 0x1e0, 8, 4, 12, MUX_TYPE_DIV, 3, 15); + clks[VENC_CCLK] = thead_clk_light_divider("venc_cclk", "gmac_pll_foutpostdiv", ap_base + 0x1e4, 0, 3, 4, MUX_TYPE_DIV, 2, 7); + clks[DPU0_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); + clks[DPU1_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 */ + clks[GMAC_PLL_FOUT1PH0] = thead_light_clk_fixed_factor("gmac_pll_fout1ph0", "gmac_pll_bypass", 1, 2); + clks[GMAC_PLL_FOUT4] = thead_light_clk_fixed_factor("gmac_pll_fout4", "gmac_pll_bypass", 1, 8); + clks[VIDEO_PLL_FOUT1PH0] = thead_light_clk_fixed_factor("video_pll_fout1ph0", "video_pll_bybass", 1, 2); + clks[VIDEO_PLL_FOUT4] = thead_light_clk_fixed_factor("video_pll_fout4", "video_pll_bypass", 1, 8); + clks[TEE_PLL_FOUT4] = thead_light_clk_fixed_factor("tee_pll_fout4", "tee_pll_bypass", 1, 8); + clks[CPU_PLL0_FOUT4] = thead_light_clk_fixed_factor("cpu_pll0_fout4", "cpu_pll0_bypass", 1, 8); + clks[CPU_PLL1_FOUT4] = thead_light_clk_fixed_factor("cpu_pll1_fout4", "cpu_pll1_bypass", 1, 8); + clks[DPU0_PLL_FOUT4] = thead_light_clk_fixed_factor("dpu0_pll_fout4", "dpu0_pll_bypass", 1, 8); + clks[DPU1_PLL_FOUT4] = thead_light_clk_fixed_factor("dpu1_pll_fout4", "dpu1_pll_bypass", 1, 8); + + /* Light Fullmask Fixed Factor */ + clks[C910_OSC_CLK] = thead_light_clk_fixed_factor("c910_osc_clk", "osc_24m", 1, 1); + clks[QSPI_SSI_CLK] = thead_light_clk_fixed_factor("qspi_ssi_clk", "video_pll_foutpostdiv", 1, 1); /* Note: no mux to select, use default value */ + clks[QSPI0_SSI_CLK] = thead_light_clk_fixed_factor("qspi0_ssi_clk", "qspi_ssi_clk", 1, 1); + clks[QSPI1_SSI_CLK] = thead_light_clk_fixed_factor("qspi1_ssi_clk", "video_pll_fout1ph0", 1, 1); + clks[SPI_SSI_CLK] = thead_light_clk_fixed_factor("spi_ssi_clk", "video_pll_fout1ph0", 1, 1); + clks[EMMC_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 */ + clks[PWM_CCLK] = thead_light_clk_fixed_factor("pwm_cclk", "osc_24m", 1, 1); + clks[CHIP_DBG_CCLK] = thead_light_clk_fixed_factor("chip_dbg_cclk", "osc_24m", 1, 1); + clks[GMAC_CCLK] = thead_light_clk_fixed_factor("gmac_cclk", "gmac_pll_fout1ph0", 1, 1); + clks[GPIO0_DBCLK] = thead_light_clk_fixed_factor("gpio0_dbclk", "pad_rtc_clk", 1, 1); + clks[GPIO1_DBCLK] = thead_light_clk_fixed_factor("gpio1_dbclk", "pad_rtc_clk", 1, 1); + clks[GPIO2_DBCLK] = thead_light_clk_fixed_factor("gpio2_dbclk", "pad_rtc_clk", 1, 1); + clks[GPIO3_DBCLK] = thead_light_clk_fixed_factor("gpio3_dbclk", "pad_rtc_clk", 1, 1); + clks[CLK_100M] = thead_light_clk_fixed_factor("clk_100m", "gmac_pll_foutpostdiv", 1, 10); + clks[I2C_IC_CLK] = thead_light_clk_fixed_factor("i2c_ic_clk", "clk_100m", 1, 2); + clks[TIMER_CCLK] = thead_light_clk_fixed_factor("timer_cclk", "osc_24m", 1, 1); + clks[AXI4_CPUSYS1_ACLK] = thead_light_clk_fixed_factor("axi4_cpusys1_aclk", "clkgen_c910_bus_clk_no_icg", 1, 1); + clks[CPU_BUS_DFTCLK] = thead_light_clk_fixed_factor("cpu_bus_dftclk", "cpu_pll0_foutpostdiv", 1, 2); + clks[CPU_PLL0_TEST_CLK] = thead_light_clk_fixed_factor("cpu_pll0_test_clk", "cpu_pll0_fout4", 1, 8); + clks[CPU_PLL1_TEST_CLK] = thead_light_clk_fixed_factor("cpu_pll1_test_clk", "cpu_pll1_fout4", 1, 8); + clks[DPU0_PLL_TEST_CLK] = thead_light_clk_fixed_factor("dpu0_pll_test_clk", "dpu0_pll_fout4", 1, 8); + clks[DPU1_PLL_TEST_CLK] = thead_light_clk_fixed_factor("dpu1_pll_test_clk", "dpu1_pll_fout4", 1, 8); + clks[GMAC_PLL_TEST_CLK] = thead_light_clk_fixed_factor("gmac_pll_test_clk", "gmac_pll_fout4", 1, 8); + clks[VIDEO_PLL_TEST_CLK] = thead_light_clk_fixed_factor("video_pll_test_clk", "video_pll_fout4", 1, 8); + clks[TEE_PLL_TEST_CLK] = thead_light_clk_fixed_factor("tee_pll_test_clk", "tee_pll_fout4", 1, 8); + clks[AONSYS_BUS_CLK] = thead_light_clk_fixed_factor("aonsys_bus_clk", "aonsys_hclk", 1, 1); + + /* Light Fullmask Clock Gate */ + clks[CLKGEN_AHB2_CPUSYS_HCLK] = thead_clk_light_gate("clkgen_ahb2_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x120, 6); + clks[CLKGEN_APB3_CPUSYS_HCLK] = thead_clk_light_gate("clkgen_apb3_cpusys_hclk", "ahb2_cpusys_hclk", ap_base + 0x130, 4); + clks[CLKGEN_C910_BROM_HCLK] = thead_clk_light_gate("clkgen_c910_brom_hclk", "ahb2_cpusys_hclk", ap_base + 0x100, 4); + clks[CLKGEN_SPINLOCK_HCLK] = thead_clk_light_gate("clkgen_spinlock_hclk", "ahb2_cpusys_hclk", ap_base + 0x208, 10); + clks[CLKGEN_MBOX0_PCLK] = thead_clk_light_gate("clkgen_mbox0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 7); + clks[CLKGEN_MBOX1_PCLK] = thead_clk_light_gate("clkgen_mbox1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 6); + clks[CLKGEN_MBOX2_PCLK] = thead_clk_light_gate("clkgen_mbox2_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 5); + clks[CLKGEN_MBOX3_PCLK] = thead_clk_light_gate("clkgen_mbox3_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 4); + clks[CLKGEN_WDT0_PCLK] = thead_clk_light_gate("clkgen_wdt0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 3); + clks[CLKGEN_WDT1_PCLK] = thead_clk_light_gate("clkgen_wdt1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 2); + + if (teesys) + clks[CLKGEN_MISCSYS_TEE_CCLK] = thead_clk_light_gate("clkgen_miscsys_tee_cclk", "teesys_hclk", ap_base + 0x1cc, 25); //just for teesys!!! + + clks[CLKGEN_SRAM_AXI_ACLK_2] = thead_clk_light_gate("clkgen_sram_axi_aclk_2", "axi4_cpusys1_aclk", ap_base + 0x20c, 2); + clks[CLKGEN_PERISYS_AHB_HCLK] = thead_clk_light_gate("clkgen_perisys_ahb_hclk", "perisys_ahb_hclk", ap_base + 0x140, 6); + clks[CLKGEN_PERISYS_APB1_HCLK] = thead_clk_light_gate("clkgen_perisys_apb1_hclk", "perisys_ahb_hclk", ap_base + 0x150, 9); + clks[CLKGEN_PERISYS_APB2_HCLK] = thead_clk_light_gate("clkgen_perisys_apb2_hclk", "perisys_ahb_hclk", ap_base + 0x150, 10); + clks[CLKGEN_PERISYS_APB4_HCLK] = thead_clk_light_gate("clkgen_perisys_apb4_hclk", "perisys_ahb_hclk", ap_base + 0x150, 12); + clks[CLKGEN_PADCTRL0_APSYS_PCLK] = thead_clk_light_gate("clkgen_padctrl0_apsys_pclk", "perisys_ahb_hclk", ap_base + 0x204, 22); + clks[CLKGEN_DSMART_PCLK] = thead_clk_light_gate("clkgen_dsmart_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 23); + clks[CLKGEN_PADCTRL1_APSYS_PCLK] = thead_clk_light_gate("clkgen_padctrl1_apsys_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 24); + clks[CLKGEN_CLK_OUT_1_CLK] = thead_clk_light_gate("clkgen_clk_out_1_clk", "clk_out_1", ap_base + 0x1b4, 5); + clks[CLKGEN_CLK_OUT_2_CLK] = thead_clk_light_gate("clkgen_clk_out_2_clk", "clk_out_2", ap_base + 0x1b8, 5); + clks[CLKGEN_CLK_OUT_3_CLK] = thead_clk_light_gate("clkgen_clk_out_3_clk", "clk_out_3", ap_base + 0x1bc, 5); + clks[CLKGEN_CLK_OUT_4_CLK] = thead_clk_light_gate("clkgen_clk_out_4_clk", "clk_out_4", ap_base + 0x1c0, 5); + clks[CLKGEN_NPUSYS_AXI_ACLK] = thead_clk_light_gate("clkgen_npusys_axi_aclk", "npu_cclk", ap_base + 0x1c8, 5); + clks[CLKGEN_SRAM_AXI_ACLK_0] = thead_clk_light_gate("clkgen_sram_axi_aclk_0", "npu_cclk", ap_base + 0x20c, 4); + clks[CLKGEN_APB_CPU2CFG_HCLK] = thead_clk_light_gate("clkgen_apb_cpu2cfg_hclk", "cfg_apb_pclk", ap_base + 0x1c4, 5); + clks[CLKGEN_SRAM_AXI_ACLK_1] = thead_clk_light_gate("clkgen_sram_axi_aclk_1", "visys_aclk_m", ap_base + 0x20c, 3); + clks[CLKGEN_SRAM_AXI_ACLK_3] = thead_clk_light_gate("clkgen_sram_axi_aclk_3", "vpsys_axi_aclk", ap_base + 0x20c, 1); + clks[CLKGEN_VPSYS_VENC_CCLK] = thead_clk_light_gate("clkgen_vpsys_venc_cclk", "venc_cclk", ap_base + 0x1e4, 5); + clks[CLKGEN_EMMC_SDIO_REF_CLK] = thead_clk_light_gate("clkgen_emmc_sdio_ref_clk", "emmc_sdio_ref_clk", ap_base + 0x204, 30); + + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_TIMER0_PCLK] = thead_clk_light_gate_shared("clkgen_timer0_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 1, &share_cnt_timer0_clk_en); + clks[CLKGEN_TIMER0_CCLK] = thead_clk_light_gate_shared("clkgen_timer0_cclk", "timer_cclk", ap_base + 0x208, 1, &share_cnt_timer0_clk_en); + clks[CLKGEN_TIMER1_PCLK] = thead_clk_light_gate_shared("clkgen_timer1_pclk", "apb3_cpusys_pclk", ap_base + 0x208, 0, &share_cnt_timer1_clk_en); + clks[CLKGEN_TIMER1_CCLK] = thead_clk_light_gate_shared("clkgen_timer1_cclk", "timer_cclk", ap_base + 0x208, 0, &share_cnt_timer1_clk_en); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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!!! + clks[CLKGEN_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!!! + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_VPSYS_ACLK] = thead_clk_light_gate_shared("clkgen_vpsys_aclk", "vpsys_axi_aclk", ap_base + 0x1e0, 15, &share_cnt_vpsys_axi_aclk_en); + clks[CLKGEN_GMAC1_HCLK] = thead_clk_light_gate_shared("clkgen_gmac1_hclk", "perisys_ahb_hclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); + clks[CLKGEN_GMAC1_PCLK] = thead_clk_light_gate_shared("clkgen_gmac1_pclk", "perisys_ahb_hclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); + clks[CLKGEN_GMAC1_CCLK] = thead_clk_light_gate_shared("clkgen_gmac1_cclk", "gmac_cclk", ap_base + 0x204, 26, &share_cnt_gmac1_clk_en); + clks[CLKGEN_GMAC0_HCLK] = thead_clk_light_gate_shared("clkgen_gmac0_hclk", "perisys_ahb_hclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); + clks[CLKGEN_GMAC0_PCLK] = thead_clk_light_gate_shared("clkgen_gmac0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); + clks[CLKGEN_GMAC0_CCLK] = thead_clk_light_gate_shared("clkgen_gmac0_cclk", "gmac_cclk", ap_base + 0x204, 19, &share_cnt_gmac0_clk_en); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_QSPI0_PCLK] = thead_clk_light_gate_shared("clkgen_qspi0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 17, &share_cnt_qspi0_clk_en); + clks[CLKGEN_QSPI0_SSI_CLK] = thead_clk_light_gate_shared("clkgen_qspi0_ssi_clk", "qspi0_ssi_clk", ap_base + 0x204, 17, &share_cnt_qspi0_clk_en); + clks[CLKGEN_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); + clks[CLKGEN_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); + clks[CLKGEN_GPIO0_PCLK] = thead_clk_light_gate_shared("clkgen_gpio0_pclk", "perisys_ahb_hclk", ap_base + 0x204, 8, &share_cnt_gpio0_clk_en); + clks[CLKGEN_GPIO0_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio0_dbclk", "gpio0_dbclk", ap_base + 0x204, 8, &share_cnt_gpio0_clk_en); + clks[CLKGEN_GPIO1_PCLK] = thead_clk_light_gate_shared("clkgen_gpio1_pclk", "perisys_ahb_hclk", ap_base + 0x204, 7, &share_cnt_gpio0_clk_en); + clks[CLKGEN_GPIO1_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio1_dbclk", "gpio1_dbclk", ap_base + 0x204, 7, &share_cnt_gpio1_clk_en); + clks[CLKGEN_PWM_PCLK] = thead_clk_light_gate_shared("clkgen_pwm_pclk", "perisys_apb_pclk", ap_base + 0x204, 18, &share_cnt_pwm_clk_en); + clks[CLKGEN_PWM_CCLK] = thead_clk_light_gate_shared("clkgen_pwm_cclk", "pwm_cclk", ap_base + 0x204, 18, &share_cnt_pwm_clk_en); + clks[CLKGEN_SPI_PCLK] = thead_clk_light_gate_shared("clkgen_spi_pclk", "perisys_apb_pclk", ap_base + 0x204, 15, &share_cnt_spi_clk_en); + clks[CLKGEN_SPI_SSI_CLK] = thead_clk_light_gate_shared("clkgen_spi_ssi_clk", "spi_ssi_clk", ap_base + 0x204, 15, &share_cnt_spi_clk_en); + clks[CLKGEN_UART0_PCLK] = thead_clk_light_gate_shared("clkgen_uart0_pclk", "perisys_apb_pclk", ap_base + 0x204, 14, &share_cnt_uart0_clk_en); + clks[CLKGEN_UART0_SCLK] = thead_clk_light_gate_shared("clkgen_uart0_sclk", "uart_sclk", ap_base + 0x204, 14, &share_cnt_uart0_clk_en); + clks[CLKGEN_UART2_PCLK] = thead_clk_light_gate_shared("clkgen_uart2_pclk", "perisys_apb_pclk", ap_base + 0x204, 12, &share_cnt_uart2_clk_en); + clks[CLKGEN_UART2_SCLK] = thead_clk_light_gate_shared("clkgen_uart2_sclk", "uart_sclk", ap_base + 0x204, 12, &share_cnt_uart2_clk_en); + clks[CLKGEN_I2C2_PCLK] = thead_clk_light_gate_shared("clkgen_i2c2_pclk", "perisys_apb_pclk", ap_base + 0x204, 3, &share_cnt_i2c2_clk_en); + clks[CLKGEN_I2C2_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c2_ic_clk", "i2c_ic_clk", ap_base + 0x204, 3, &share_cnt_i2c2_clk_en); + clks[CLKGEN_I2C3_PCLK] = thead_clk_light_gate_shared("clkgen_i2c3_pclk", "perisys_apb_pclk", ap_base + 0x204, 2, &share_cnt_i2c2_clk_en); + clks[CLKGEN_I2C3_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c3_ic_clk", "i2c_ic_clk", ap_base + 0x204, 2, &share_cnt_i2c2_clk_en); + clks[CLKGEN_I2S_PCLK] = thead_clk_light_gate_shared("clkgen_i2s_pclk", "perisys_apb_pclk", ap_base + 0x1f0, 1, &share_cnt_peri_i2s_clk_en); + clks[CLKGEN_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); + clks[CLKGEN_QSPI1_PCLK] = thead_clk_light_gate_shared("clkgen_qspi1_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 16, &share_cnt_qspi1_clk_en); + clks[CLKGEN_QSPI1_SSI_CLK] = thead_clk_light_gate_shared("clkgen_qspi1_ssi_clk", "qspi1_ssi_clk", ap_base + 0x204, 16, &share_cnt_qspi1_clk_en); + clks[CLKGEN_UART1_PCLK] = thead_clk_light_gate_shared("clkgen_uart1_pclk", "per2sys_apb_pclk", ap_base + 0x204, 13, &share_cnt_uart1_clk_en); + clks[CLKGEN_UART1_SCLK] = thead_clk_light_gate_shared("clkgen_uart1_sclk", "uart_sclk", ap_base + 0x204, 13, &share_cnt_uart1_clk_en); + clks[CLKGEN_UART3_PCLK] = thead_clk_light_gate_shared("clkgen_uart3_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 11, &share_cnt_uart3_clk_en); + clks[CLKGEN_UART3_SCLK] = thead_clk_light_gate_shared("clkgen_uart3_sclk", "uart_sclk", ap_base + 0x204, 11, &share_cnt_uart3_clk_en); + clks[CLKGEN_UART4_PCLK] = thead_clk_light_gate_shared("clkgen_uart4_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 10, &share_cnt_uart4_clk_en); + clks[CLKGEN_UART4_SCLK] = thead_clk_light_gate_shared("clkgen_uart4_sclk", "uart_sclk", ap_base + 0x204, 10, &share_cnt_uart4_clk_en); + clks[CLKGEN_UART5_PCLK] = thead_clk_light_gate_shared("clkgen_uart5_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 9, &share_cnt_uart5_clk_en); + clks[CLKGEN_UART5_SCLK] = thead_clk_light_gate_shared("clkgen_uart5_sclk", "uart_sclk", ap_base + 0x204, 9, &share_cnt_uart5_clk_en); + clks[CLKGEN_I2C0_PCLK] = thead_clk_light_gate_shared("clkgen_i2c0_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 5, &share_cnt_i2c0_clk_en); + clks[CLKGEN_I2C0_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c0_ic_clk", "i2c_ic_clk", ap_base + 0x204, 5, &share_cnt_i2c0_clk_en); + clks[CLKGEN_I2C1_PCLK] = thead_clk_light_gate_shared("clkgen_i2c1_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 4, &share_cnt_i2c1_clk_en); + clks[CLKGEN_I2C1_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c1_ic_clk", "i2c_ic_clk", ap_base + 0x204, 4, &share_cnt_i2c1_clk_en); + clks[CLKGEN_I2C4_PCLK] = thead_clk_light_gate_shared("clkgen_i2c4_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 1, &share_cnt_i2c4_clk_en); + clks[CLKGEN_I2C4_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c4_ic_clk", "i2c_ic_clk", ap_base + 0x204, 1, &share_cnt_i2c4_clk_en); + clks[CLKGEN_I2C5_PCLK] = thead_clk_light_gate_shared("clkgen_i2c5_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 0, &share_cnt_i2c5_clk_en); + clks[CLKGEN_I2C5_IC_CLK] = thead_clk_light_gate_shared("clkgen_i2c5_ic_clk", "i2c_ic_clk", ap_base + 0x204, 0, &share_cnt_i2c5_clk_en); + clks[CLKGEN_GPIO2_PCLK] = thead_clk_light_gate_shared("clkgen_gpio2_pclk", "peri2sys_apb_pclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); + clks[CLKGEN_GPIO2_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio2_dbclk", "gpio2_dbclk", ap_base + 0x204, 6, &share_cnt_gpio2_clk_en); + clks[CLKGEN_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 + clks[CLKGEN_GPIO3_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio3_dbclk", "gpio3_dbclk", ap_base + 0x204, 20, &share_cnt_gpio3_clk_en); + clks[CLKGEN_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); + clks[CLKGEN_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(clks[C910_CCLK], clks[CPU_PLL1_FOUTPOSTDIV]); +#else + clk_set_parent(clks[C910_CCLK_I0], clks[OSC_24M]); + clk_set_parent(clks[C910_CCLK], clks[C910_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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static struct clk *clks[LIGHT_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 */ + clks[LIGHT_CLK_DUMMY] = thead_clk_fixed("dummy", 0); + clks[LIGHT_CLK_32K] = of_clk_get_by_name(np, "osc_32k"); + clks[LIGHT_CLK_24M] = of_clk_get_by_name(np, "osc_24m"); + clks[LIGHT_RC_24M] = of_clk_get_by_name(np, "rc_24m"); + + /* AP Fixed PLL */ + clks[LIGHT_VIDEO_PLL_FOUTVCO] = thead_clk_fixed("video_pll_foutvco", 2376000000); + clks[LIGHT_VIDEO_PLL_FOUTPOSTDIV] = thead_clk_fixed("video_pll_foutpostdiv", 796000000); + clks[LIGHT_GMAC_PLL_FOUTVCO] = thead_clk_fixed("gmac_pll_foutvco", 2000000000); + clks[LIGHT_GMAC_PLL_FOUTPOSTDIV] = thead_clk_fixed("gmac_pll_foutpostdiv", 1000000000); + +#ifdef THEAD_LIGHT_AON_CLK + /* Aon PLL clocks */ + clks[LIGHT_AUDIO_PLL_FOUTVCO] = thead_light_pll("audio_pll_foutvco", "osc_24m", aon_base, &light_audio_pllvco); + clks[LIGHT_AUDIO_PLL_FOUTPOSTDIV] = thead_light_pll("audio_pll_foutpostdiv", "osc_24m", aon_base, &light_audio_plldiv); + clks[LIGHT_SYS_PLL_FOUTVCO] = thead_light_pll("sys_pll_foutvco", "osc_24m", aon_base, &light_sys_pllvco); + clks[LIGHT_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 */ + clks[LIGHT_DDR_PLL_FOUTVCO] = thead_light_pll("ddr_pll_foutvco", "osc_24m", ddr_base, &light_ddr_pllvco); + clks[LIGHT_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 */ + clks[LIGHT_CPU_PLL0_FOUTVCO] = thead_light_pll("cpu_pll0_foutvco", "osc_24m", ap_base, &light_cpu_pll0vco); + clks[LIGHT_CPU_PLL0_FOUTPOSTDIV] = thead_light_pll("cpu_pll0_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll0div); + clks[LIGHT_CPU_PLL1_FOUTVCO] = thead_light_pll("cpu_pll1_foutvco", "osc_24m", ap_base, &light_cpu_pll1vco); + clks[LIGHT_CPU_PLL1_FOUTPOSTDIV] = thead_light_pll("cpu_pll1_foutpostdiv", "osc_24m", ap_base, &light_cpu_pll1div); + + /* PLL bypass */ +#ifdef THEAD_LIGHT_AON_CLK + clks[LIGHT_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); + clks[LIGHT_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 + clks[LIGHT_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 + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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 + clks[LIGHT_AUDIO_PLL_FOUT3] = thead_light_clk_fixed_factor("audio_pll_fout3", "audio_pll_bypass", 1, 6); + clks[LIGHT_SYS_PLL_FOUT4] = thead_light_clk_fixed_factor("sys_pll_fout4", "sys_pll_bypass", 1, 8); +#endif +#ifdef THEAD_LIGHT_DDR_CLK + clks[LIGHT_DDR_PLL_FOUT4] = thead_light_clk_fixed_factor("ddr_pll_fout4", "ddr_pll_bypass", 1, 8); +#endif + clks[LIGHT_CPU_PLL0_FOUT4] = thead_light_clk_fixed_factor("cpu_pll0_fout4", "cpu_pll0_bypass", 1, 8); + clks[LIGHT_CPU_PLL1_FOUT4] = thead_light_clk_fixed_factor("cpu_pll1_fout4", "cpu_pll1_bypass", 1, 8); + clks[LIGHT_GMAC_PLL_FOUT1PH0] = thead_light_clk_fixed_factor("gmac_pll_fout1ph0", "gmac_pll_bypass", 1, 2); + clks[LIGHT_GMAC_CORECLK] = thead_light_clk_fixed_factor("gmac_coreclk", "gmac_pll_fout1ph0", 1, 1); + clks[LIGHT_GMAC_PLL_FOUT4] = thead_light_clk_fixed_factor("gmac_pll_fout4", "gmac_pll_bypass", 1, 8); + clks[LIGHT_VIDEO_PLL_FOUT4] = thead_light_clk_fixed_factor("video_pll_fout4", "video_pll_bypass", 1, 8); + clks[LIGHT_GMAC_PLL_FOUTVCO_DIV5] = thead_light_clk_fixed_factor("gmac_pll_foutvco_div5", "gmac_pll_foutvco", 1, 5); + clks[LIGHT_OSC_CLK_DIV24] = thead_light_clk_fixed_factor("osc_clk_div24", "osc_24m", 1, 24); + clks[LIGHT_CHIP_DBG_CCLK] = thead_light_clk_fixed_factor("chip_dbg_cclk", "osc_24m", 1, 1); + clks[LIGHT_AXI_ACLK] = thead_light_clk_fixed_factor("cpusys_axi_aclk", "cpu_pll0_bypass", 1, 2); + clks[LIGHT_X2H_HCLK] = thead_light_clk_fixed_factor("aonsys_x2h_hclk", "osc_24m", 1, 1); + clks[LIGHT_EMMC_CLK_DIV] = thead_light_clk_fixed_factor("emmc_clk_div", "video_pll_bypass", 1, 4); + clks[LIGHT_EMMC0_OSC_CLK] = thead_light_clk_fixed_factor("emmc0_osc_clk", "osc_24m", 1, 1); + clks[LIGHT_EMMC1_OSC_CLK] = thead_light_clk_fixed_factor("emmc1_osc_clk", "osc_24m", 1, 1); + clks[LIGHT_PWM_CCLK] = thead_light_clk_fixed_factor("pwm_cclk", "osc_24m", 1, 1); + clks[LIGHT_USB3_PHY_REF_CLK] = thead_light_clk_fixed_factor("usb3_phy_ref_clk", "osc_24m", 1, 1); + clks[LIGHT_SPI_CLK] = thead_light_clk_fixed_factor("spi_clk", "gmac_pll_foutvco_div5", 1, 1); + clks[LIGHT_GPIO_DBCLK] = thead_light_clk_fixed_factor("gpio_dbclk", "osc_32k", 1, 1); + +#ifdef THEAD_LIGHT_AON_CLK + /* Aon sys mux tree */ + clks[LIGHT_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); + clks[LIGHT_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 */ + clks[LIGHT_AONSYS_CLK] = thead_clk_light_divider("aonsys_clk", "aonsys_clk_switch_1", aon_base + 0x100, 0, 3, 3, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_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 */ + clks[LIGHT_CLKGEN_RTC_PCLK] = thead_clk_light_gate("rtc_pclk_en", "aonsys_clk", aon_base + 0x120, 0); + clks[LIGHT_CLKGEN_AOGPIO_PCLK] = thead_clk_light_gate("aogpio_pclk_en", "aonsys_clk", aon_base + 0x120, 1); + clks[LIGHT_CLKGEN_AOI2C_PCLK] = thead_clk_light_gate("aoi2c_pclk_en", "aonsys_clk", aon_base + 0x120, 2); + clks[LIGHT_CLKGEN_PVTC_PCLK] = thead_clk_light_gate("pvtc_pclk_en", "aonsys_clk", aon_base + 0x120, 3); + clks[LIGHT_CLKGEN_SRAM_AXI_ACLK] = thead_clk_light_gate("share_sram_clk_en", "aonsys_clk", aon_base + 0x120, 4); + clks[LIGHT_CLKGEN_AOPAD_PCLK] = thead_clk_light_gate("aopad_pclk_en", "aonsys_clk", aon_base + 0x120, 5); + clks[LIGHT_CLKGEN_AOAPB_HCLK] = thead_clk_light_gate("aoapb_hclk_en", "aonsys_clk", aon_base + 0x120, 6); + clks[LIGHT_CLKGEN_AOSRAM_HCLK] = thead_clk_light_gate("aosram_hclk_en", "aonsys_clk", aon_base + 0x120, 7); + clks[LIGHT_CLKGEN_AOAHB_HCLK] = thead_clk_light_gate("aoahb_hclk_en", "aonsys_clk", aon_base + 0x120, 8); + clks[LIGHT_CLKGEN_AOGPIO_DBCLK] = thead_clk_light_gate("aogpio_dbclk_en", "aonsys_clk", aon_base + 0x120, 9); + clks[LIGHT_CLKGEN_AOTIMER_PCLK] = thead_clk_light_gate("aotimer_pclk_en", "aonsys_clk", aon_base + 0x120, 10); + clks[LIGHT_CLKGEN_AOTIMER_CCLK] = thead_clk_light_gate("aotimer_cclk_en", "aonsys_clk", aon_base + 0x120, 11); + clks[LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_S] = thead_clk_light_gate("apsys_clk_en", "aonsys_clk", aon_base + 0x130, 0); +#endif + + /* AP sys mux tree */ + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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 */ + clks[LIGHT_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); + clks[LIGHT_APB3_CPUSYS_PCLK] = thead_clk_light_divider("apb3_cpusys_pclk", "cpusys_ahb_hclk", ap_base + 0x130, 0, 3, 3, MUX_TYPE_CDE, 1, 7); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_TEESYS_HCLK] = thead_clk_light_divider("teesys_hclk", "gmac_pll_fout1ph0", ap_base + 0x154, 0, 2, 2, MUX_TYPE_DIV, 2, 3); + clks[LIGHT_DMAC_1_CLK] = thead_clk_light_divider("dmac_1_clk", "video_pll_bypass", ap_base + 0x158, 0, 2, 2, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_DMAC_2_CLK] = thead_clk_light_divider("dmac_2_clk", "video_pll_bypass", ap_base + 0x16c, 0, 2, 2, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_DMAC_3_CLK] = thead_clk_light_divider("dmac_3_clk", "gmac_pll_bypass", ap_base + 0x160, 0, 2, 2, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_AXI_PORT4_CLK] = thead_clk_light_divider("axi_port4_clk", "video_pll_bypass", ap_base + 0x164, 0, 2, 2, MUX_TYPE_CDE, 0, 7); + clks[LIGHT_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); + clks[LIGHT_PERISYS_APB_PCLK] = thead_clk_light_divider("perisys_apb_pclk", "perisys_ahb_hclk", ap_base + 0x150, 0, 3, 3, MUX_TYPE_CDE, 3, 7); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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 */ + clks[LIGHT_CLKGEN_PERISYS_AXI_ACLK] = thead_clk_light_gate("clkgen_perisys_axi_aclk", "perisys_ahb_hclk", ap_base + 0x200, 31); + clks[LIGHT_CLKGEN_PERISYS_AHB_HCLK] = thead_clk_light_gate("clkgen_perisys_ahb_hclk", "perisys_ahb_hclk", ap_base + 0x200, 30); + clks[LIGHT_CLKGEN_PERISYS_APB1_HCLK] = thead_clk_light_gate("clkgen_perisys_apb1_hclk", "perisys_ahb_hclk", ap_base + 0x200, 29); + clks[LIGHT_CLKGEN_PERISYS_APB2_HCLK] = thead_clk_light_gate("clkgen_perisys_apb2_hclk", "perisys_ahb_hclk", ap_base + 0x200, 28); + clks[LIGHT_CLKGEN_USB3_DRD_PHY_REF_CLK] = thead_clk_light_gate("clkgen_usb3_drd_phy_ref_clk", "usb3_phy_ref_clk", ap_base + 0x200, 27); + clks[LIGHT_CLKGEN_USB3_DRD_CTRL_REF_CLK] = thead_clk_light_gate("clkgen_usb3_drd_ctrl_ref_clk", "usb3_ctrl_ref_clk", ap_base + 0x200, 26); + clks[LIGHT_CLKGEN_USB3_DRD_SPDCLK] = thead_clk_light_gate("clkgen_usb3_drd_spdclk", "osc_clk_div24", ap_base + 0x200, 25); + clks[LIGHT_CLKGEN_EMMC1_X2X_ACLK] = thead_clk_light_gate("clkgen_emmc1_x2x_aclk", "perisys_ahb_hclk", ap_base + 0x200, 23); + clks[LIGHT_CLKGEN_EMMC0_X2X_ACLK] = thead_clk_light_gate("clkgen_emmc0_x2x_aclk", "perisys_ahb_hclk", ap_base + 0x200, 22); + clks[LIGHT_CLKGEN_UART0_PCLK] = thead_clk_light_gate("clkgen_uart0_pclk", "perisys_apb_pclk", ap_base + 0x200, 14); + clks[LIGHT_CLKGEN_UART1_PCLK] = thead_clk_light_gate("clkgen_uart1_pclk", "perisys_apb_pclk", ap_base + 0x200, 13); + clks[LIGHT_CLKGEN_UART2_PCLK] = thead_clk_light_gate("clkgen_uart2_pclk", "perisys_apb_pclk", ap_base + 0x200, 12); + clks[LIGHT_CLKGEN_UART3_PCLK] = thead_clk_light_gate("clkgen_uart3_pclk", "perisys_apb_pclk", ap_base + 0x200, 11); + clks[LIGHT_CLKGEN_UART4_PCLK] = thead_clk_light_gate("clkgen_uart4_pclk", "perisys_apb_pclk", ap_base + 0x200, 10); + clks[LIGHT_CLKGEN_UART5_PCLK] = thead_clk_light_gate("clkgen_uart5_pclk", "perisys_apb_pclk", ap_base + 0x200, 9); + clks[LIGHT_CLKGEN_I2C0_IC_CLK] = thead_clk_light_gate("clkgen_i2c0_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 5); + clks[LIGHT_CLKGEN_I2C1_IC_CLK] = thead_clk_light_gate("clkgen_i2c1_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 4); + clks[LIGHT_CLKGEN_I2C2_IC_CLK] = thead_clk_light_gate("clkgen_i2c2_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 3); + clks[LIGHT_CLKGEN_I2C3_IC_CLK] = thead_clk_light_gate("clkgen_i2c3_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 2); + clks[LIGHT_CLKGEN_I2C4_IC_CLK] = thead_clk_light_gate("clkgen_i2c4_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 1); + clks[LIGHT_CLKGEN_I2C5_IC_CLK] = thead_clk_light_gate("clkgen_i2c5_ic_clk", "perisys_apb_pclk", ap_base + 0x200, 0); + + clks[LIGHT_CLKGEN_AXI_DUMMY_SLV_4_ACLK] = thead_clk_light_gate("clkgen_axi_dummy_slv_4_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 28); + clks[LIGHT_CLKGEN_AXI_DUMMY_SLV_3_ACLK] = thead_clk_light_gate("clkgen_axi_dummy_slv_3_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 27); + clks[LIGHT_CLKGEN_AXI_DUMMY_SLV_2_ACLK] = thead_clk_light_gate("clkgen_axi_dummy_slv_2_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 26); + clks[LIGHT_CLKGEN_AXI_DUMMY_SLV_1_ACLK] = thead_clk_light_gate("clkgen_axi_dummy_slv_1_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 25); + clks[LIGHT_CLKGEN_APB_CPU2FG_HCLK] = thead_clk_light_gate("clkgen_apb_cpu2cfg_hclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 24); + clks[LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_M] = thead_clk_light_gate("clkgen_cpu2ram_x2x_aclk_m", "cpusys_axi_aclk", ap_base + 0x204, 21); + clks[LIGHT_CLKGEN_AXI4_CPUSYS2_ACLK] = thead_clk_light_gate("clkgen_axi4_cpusys2_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 20); + clks[LIGHT_CLKGEN_X2X_CPUSYS_ACLK_M] = thead_clk_light_gate("clkgen_x2x_cpusys_aclk_m", "cpusys_sub_axi_aclk", ap_base + 0x204, 19); + clks[LIGHT_CLKGEN_CHIP_DBG_ACLK] = thead_clk_light_gate("clkgen_chip_dbg_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 18); + clks[LIGHT_CLKGEN_AXI4_CFG_BUS_ACLK] = thead_clk_light_gate("clkgen_axi4_cfg_bus_aclk", "cpusys_cfg_axi_aclk", ap_base + 0x204, 17); + clks[LIGHT_CLKGEN_AHB2_CPUSYS_HCLK] = thead_clk_light_gate("clkgen_ahb2_cpusys_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 11); + clks[LIGHT_CLKGEN_APB3_CPUSYS_HCLK] = thead_clk_light_gate("clkgen_apb3_cpusys_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 10); + clks[LIGHT_CLKGEN_C910_BROM_HCLK] = thead_clk_light_gate("clkgen_c910_brom_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 9); + clks[LIGHT_CLKGEN_MBOX0_PCLK] = thead_clk_light_gate("clkgen_mbox0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 7); + clks[LIGHT_CLKGEN_MBOX1_PCLK] = thead_clk_light_gate("clkgen_mbox1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 6); + clks[LIGHT_CLKGEN_MBOX2_PCLK] = thead_clk_light_gate("clkgen_mbox2_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 5); + clks[LIGHT_CLKGEN_MBOX3_PCLK] = thead_clk_light_gate("clkgen_mbox3_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 4); + clks[LIGHT_CLKGEN_WDT0_PCLK] = thead_clk_light_gate("clkgen_wdt0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 3); + clks[LIGHT_CLKGEN_WDT1_PCLK] = thead_clk_light_gate("clkgen_wdt1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 2); + + clks[LIGHT_CLKGEN_TRNG_RB_HCLK] = thead_clk_light_gate("clkgen_trng_rb_hclk", "teesys_hclk", ap_base + 0x208, 19); + clks[LIGHT_CLKGEN_ADC_PCLK] = thead_clk_light_gate("clkgen_adc_pclk", "perisys_apb_pclk", ap_base + 0x208, 18); + clks[LIGHT_CLKGEN_AXI_ACLK_4] = thead_clk_light_gate("axi_aclk_4", "axi_port4_clk", ap_base + 0x208, 17); + clks[LIGHT_CLKGEN_AXI_ACLK_3] = thead_clk_light_gate("axi_aclk_3", "dmac_3_clk", ap_base + 0x208, 16); + clks[LIGHT_CLKGEN_AXI_ACLK_2] = thead_clk_light_gate("axi_aclk_2", "dmac_2_clk", ap_base + 0x208, 15); + clks[LIGHT_CLKGEN_AXI_ACLK_1] = thead_clk_light_gate("axi_aclk_1", "dmac_1_clk", ap_base + 0x208, 14); + clks[LIGHT_CLKGEN_AXI_ACLK_0] = thead_clk_light_gate("axi_aclk_0", "cpusys_axi_aclk", ap_base + 0x208, 13); + clks[LIGHT_CLKGEN_SRAM_AXI_PCLK] = thead_clk_light_gate("clkgen_sram_axi_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 9); + clks[LIGHT_CLKGEN_AHB2_TEESYS_HCLK] = thead_clk_light_gate("clkgen_ahb2_teesys_hclk", "teesys_hclk", ap_base + 0x208, 8); + clks[LIGHT_CLKGEN_EFUSE_MPW_PCLK] = thead_clk_light_gate("clkgen_efuse_mpw_pclk", "perisys_apb_pclk", ap_base + 0x208, 7); + clks[LIGHT_CLKGEN_CLK_OUT_4_CLK] = thead_clk_light_gate("clkgen_clk_out_4_clk", "clk_out_4", ap_base + 0x208, 6); + clks[LIGHT_CLKGEN_CLK_OUT_3_CLK] = thead_clk_light_gate("clkgen_clk_out_3_clk", "clk_out_3", ap_base + 0x208, 5); + clks[LIGHT_CLKGEN_CLK_OUT_2_CLK] = thead_clk_light_gate("clkgen_clk_out_2_clk", "clk_out_2", ap_base + 0x208, 4); + clks[LIGHT_CLKGEN_CLK_OUT_1_CLK] = thead_clk_light_gate("clkgen_clk_out_1_clk", "clk_out_1", ap_base + 0x208, 3); + clks[LIGHT_CLKGEN_DDR_APB_PCLK] = thead_clk_light_gate("clkgen_ddr_apb_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 2); + clks[LIGHT_CLKGEN_PADCTRL_APSYS_PCLK] = thead_clk_light_gate("clkgen_padctrl_apsys_pclk", "cpusys_cfg_axi_aclk", ap_base + 0x208, 1); + clks[LIGHT_CLKGEN_CHIP_DBG_CCLK] = thead_clk_light_gate("clkgen_chip_dbg_cclk", "chip_dbg_cclk", ap_base + 0x208, 0); + + /* register AP shared gate */ + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_CLKGEN_DMAC_ACLK] = thead_clk_light_gate_shared("clkgen_dmac_aclk", "cpusys_sub_axi_aclk", ap_base + 0x204, 8, &share_cnt_dmac_clk_en); + clks[LIGHT_CLKGEN_DMAC_HCLK] = thead_clk_light_gate_shared("clkgen_dmac_hclk", "cpusys_ahb_hclk", ap_base + 0x204, 8, &share_cnt_dmac_clk_en); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_CLKGEN_TIMER0_CCLK] = thead_clk_light_gate_shared("clkgen_timer0_cclk", "apb3_cpusys_pclk", ap_base + 0x204, 1, &share_cnt_timer0_clk_en); + clks[LIGHT_CLKGEN_TIMER0_PCLK] = thead_clk_light_gate_shared("clkgen_timer0_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 1, &share_cnt_timer0_clk_en); + clks[LIGHT_CLKGEN_TIMER1_CCLK] = thead_clk_light_gate_shared("clkgen_timer1_cclk", "apb3_cpusys_pclk", ap_base + 0x204, 0, &share_cnt_timer1_clk_en); + clks[LIGHT_CLKGEN_TIMER1_PCLK] = thead_clk_light_gate_shared("clkgen_timer1_pclk", "apb3_cpusys_pclk", ap_base + 0x204, 0, &share_cnt_timer1_clk_en); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_CLKGEN_GMAC_HCLK] = thead_clk_light_gate_shared("clkgen_gmac_hclk", "perisys_ahb_hclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); + clks[LIGHT_CLKGEN_GMAC_ACLK] = thead_clk_light_gate_shared("clkgen_gmac_aclk", "perisys_ahb_hclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); + clks[LIGHT_CLKGEN_GMAC_PCLK] = thead_clk_light_gate_shared("clkgen_gmac_pclk", "perisys_apb_pclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); + clks[LIGHT_CLKGEN_GMAC_CCLK] = thead_clk_light_gate_shared("clkgen_gmac_cclk", "gmac_coreclk", ap_base + 0x200, 19, &share_cnt_gmac_clk_en); + clks[LIGHT_CLKGEN_EMMC0_HCLK] = thead_clk_light_gate_shared("clkgen_emmc0_hclk", "perisys_ahb_hclk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); + clks[LIGHT_CLKGEN_EMMC0_ACLK] = thead_clk_light_gate_shared("clkgen_emmc0_aclk", "perisys_ahb_hclk", ap_base + 0x200, 21, &share_cnt_emmc0_clk_en); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_CLKGEN_EMMC1_HCLK] = thead_clk_light_gate_shared("clkgen_emmc1_hclk", "perisys_ahb_hclk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); + clks[LIGHT_CLKGEN_EMMC1_ACLK] = thead_clk_light_gate_shared("clkgen_emmc1_aclk", "perisys_ahb_hclk", ap_base + 0x200, 20, &share_cnt_emmc1_clk_en); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_CLKGEN_PWM_PCLK] = thead_clk_light_gate_shared("clkgen_pwm_pclk", "perisys_ahb_hclk", ap_base + 0x200, 18, &share_cnt_pwm_clk_en); + clks[LIGHT_CLKGEN_PWM_CCLK] = thead_clk_light_gate_shared("clkgen_pwm_cclk", "pwm_cclk", ap_base + 0x200, 18, &share_cnt_pwm_clk_en); + clks[LIGHT_CLKGEN_QSPI0_PCLK] = thead_clk_light_gate_shared("clkgen_qspi0_pclk", "perisys_apb_pclk", ap_base + 0x200, 17, &share_cnt_qspi0_clk_en); + clks[LIGHT_CLKGEN_QSPI0_SSI_CLK] = thead_clk_light_gate_shared("clkgen_qspi0_ssi_clk", "spi_clk", ap_base + 0x200, 17, &share_cnt_qspi0_clk_en); + clks[LIGHT_CLKGEN_QSPI1_PCLK] = thead_clk_light_gate_shared("clkgen_qspi1_pclk", "perisys_apb_pclk", ap_base + 0x200, 16, &share_cnt_qspi1_clk_en); + clks[LIGHT_CLKGEN_QSPI1_SSI_CLK] = thead_clk_light_gate_shared("clkgen_qspi1_ssi_clk", "spi_clk", ap_base + 0x200, 16, &share_cnt_qspi0_clk_en); + clks[LIGHT_CLKGEN_SPI_PCLK] = thead_clk_light_gate_shared("clkgen_spi_pclk", "perisys_apb_pclk", ap_base + 0x200, 15, &share_cnt_spi_clk_en); + clks[LIGHT_CLKGEN_SPI_SSI_CLK] = thead_clk_light_gate_shared("clkgen_spi_ssi_clk", "spi_clk", ap_base + 0x200, 15, &share_cnt_spi_clk_en); + clks[LIGHT_CLKGEN_GPIO0_PCLK] = thead_clk_light_gate_shared("clkgen_gpio0_pclk", "perisys_apb_pclk", ap_base + 0x200, 8, &share_cnt_gpio0_clk_en); + clks[LIGHT_CLKGEN_GPIO0_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio0_dbclk", "gpio_dbclk", ap_base + 0x200, 8, &share_cnt_gpio0_clk_en); + clks[LIGHT_CLKGEN_GPIO1_PCLK] = thead_clk_light_gate_shared("clkgen_gpio1_pclk", "perisys_apb_pclk", ap_base + 0x200, 7, &share_cnt_gpio1_clk_en); + clks[LIGHT_CLKGEN_GPIO1_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio1_dbclk", "gpio_dbclk", ap_base + 0x200, 7, &share_cnt_gpio1_clk_en); + clks[LIGHT_CLKGEN_GPIO2_PCLK] = thead_clk_light_gate_shared("clkgen_gpio2_pclk", "perisys_apb_pclk", ap_base + 0x200, 6, &share_cnt_gpio2_clk_en); + clks[LIGHT_CLKGEN_GPIO2_DBCLK] = thead_clk_light_gate_shared("clkgen_gpio2_dbclk", "gpio_dbclk", ap_base + 0x200, 6, &share_cnt_gpio2_clk_en); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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); + clks[LIGHT_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(clks[LIGHT_C910_CCLK], clks[LIGHT_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 "); +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 +#include +#include +#include +#include +#include +#include +#include + +#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(clks[i]); +} + +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_table[0].rate; + + return rate_table[0].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_table[i].rate) + return &rate_table[i]; + + 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_table[i].vco_rate) + return &rate_table[i]; + + 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_table[i].vco_rate; + + if (rate == now) { + return rate_table[i].vco_rate; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + /* return minimum supported value */ + return rate_table[best_i].vco_rate; +} + +static long clk_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_table[i].rate; + + if (rate == now) { + return rate_table[i].rate; + } else if (abs(now - rate) < abs(best - rate)) { + best = now; + best_i = i; + } + } + + /* return minimum supported value */ + return rate_table[best_i].rate; +} + +static const struct clk_ops clk_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,%d]share_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); + return 0; + } + + pr_debug("[%s,%d]share_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,%d]share_count = %d\n", __func__, __LINE__, (*light_gate->share_count)); + return; + } + } + + pr_debug("[%s,%d]share_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 +#include + +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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk-gate.h" +#include "../clk.h" + +static struct clk *gates[LIGHT_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; + } + + gates[CLKGEN_DSP0_PCLK] = thead_gate_clk_register("clkgen_dsp0_pclk", NULL, dspsys_regmap, + 0x24, 0, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_DSP1_PCLK] = thead_gate_clk_register("clkgen_dsp1_pclk", NULL, dspsys_regmap, + 0x24, 1, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_DSP1_CCLK] = thead_gate_clk_register("clkgen_dsp1_cclk", NULL, dspsys_regmap, + 0x24, 2, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_DSP0_CCLK] = thead_gate_clk_register("clkgen_dsp0_cclk", NULL, dspsys_regmap, + 0x24, 3, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_X2X_DSP2_ACLK_S] = thead_gate_clk_register("clkgen_x2x_dsp2_aclk_s", NULL, dspsys_regmap, + 0x24, 4, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_X2X_DSP0_ACLK_S] = thead_gate_clk_register("clkgen_x2x_dsp0_aclk_s", NULL, dspsys_regmap, + 0x24, 5, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_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); + gates[CLKGEN_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); + gates[CLKGEN_AXI4_DSPSYS_SLV_ACLK] = thead_gate_clk_register("clkgen_axi4_dspsys_slv_aclk", NULL, dspsys_regmap, + 0x24, 20, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_AXI4_DSPSYS_SLV_PCLK] = thead_gate_clk_register("clkgen_axi4_dspsys_slv_pclk", NULL, dspsys_regmap, + 0x24, 21, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_AXI4_DSPSYS_ACLK] = thead_gate_clk_register("clkgen_axi4_dspsys_aclk", NULL, dspsys_regmap, + 0x24, 23, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_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) { + gates[CLKGEN_IOPMP_DSP1_PCLK] = thead_gate_clk_register("clkgen_iopmp_dsp1_pclk", NULL, tee_dspsys_regmap, + 0x24, 25, GATE_NOT_SHARED, NULL, dev); + gates[CLKGEN_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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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,%d]share_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,%d]share_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "clk-gate.h" +#include "../clk.h" + +static struct clk *gates[LIGHT_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 */ + gates[LIGHT_CLKGEN_DW200_ACLK] = thead_gate_clk_register("clkgen_dw200_aclk", NULL, + visys_regmap, 0xa0, 27, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_AXI4_VISYS1_ACLK] = thead_gate_clk_register("clkgen_axi4_visys1_aclk", NULL, + visys_regmap, 0xa0, 26, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_AXI4_VISYS2_ACLK] = thead_gate_clk_register("clkgen_axi4_visys2_aclk", NULL, + visys_regmap, 0xa0, 25, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_AXI4_VISYS3_ACLK] = thead_gate_clk_register("clkgen_axi4_visys3_aclk", NULL, + visys_regmap, 0xa0, 24, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_RY_ACLK] = thead_gate_clk_register("clkgen_isp_ry_aclk", NULL, + visys_regmap, 0xa0, 22, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_VENC_SHAKE_ACLK] = thead_gate_clk_register("clkgen_isp_venc_shake_aclk", NULL, + visys_regmap, 0xa0, 30, GATE_NOT_SHARED, NULL, dev); + + gates[LIGHT_CLKGEN_VIPRE_ACLK] = thead_gate_clk_register("clkgen_vipre_aclk", NULL, + visys_regmap, 0xa0, 31, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_DW200_HCLK] = thead_gate_clk_register("clkgen_dw200_hclk", NULL, + visys_regmap, 0xa0, 13, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_RY_HCLK] = thead_gate_clk_register("clkgen_isp_ry_hclk", NULL, + visys_regmap, 0xa0, 12, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI0_PCLK] = thead_gate_clk_register("clkgen_mipi_csi0_pclk", NULL, + visys_regmap, 0xa0, 18, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI1_PCLK] = thead_gate_clk_register("clkgen_mipi_csi1_pclk", NULL, + visys_regmap, 0xa0, 17, GATE_NOT_SHARED, NULL, dev); + + gates[LIGHT_CLKGEN_MIPI_CSI2_PCLK] = thead_gate_clk_register("clkgen_mipi_csi2_pclk", NULL, + visys_regmap, 0xa0, 16, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_VIPRE_PCLK] = thead_gate_clk_register("clkgen_vipre_pclk", NULL, + visys_regmap, 0xa0, 15, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_VENC_SHAKE_PCLK] = thead_gate_clk_register("clkgen_isp_venc_shake_pclk", NULL, + visys_regmap, 0xa0, 29, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI0_PIXCLK] = thead_gate_clk_register("clkgen_mipi_csi0_pixclk", NULL, + visys_regmap, 0xa0, 11, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI1_PIXCLK] = thead_gate_clk_register("clkgen_mipi_csi1_pixclk", NULL, + visys_regmap, 0xa0, 10, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI2_PIXCLK] = thead_gate_clk_register("clkgen_mipi_csi2_pixclk", NULL, + visys_regmap, 0xa0, 9, GATE_NOT_SHARED, NULL, dev); + + gates[LIGHT_CLKGEN_VIPRE_PIXELCLK] = thead_gate_clk_register("clkgen_vipre_pixelclk", NULL, + visys_regmap, 0xa4, 23, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI0_CFG_CLK] = thead_gate_clk_register("clkgen_mipi_csi0_cfg_clk", NULL, + visys_regmap, 0xa0, 8, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI1_CFG_CLK] = thead_gate_clk_register("clkgen_mipi_csi1_cfg_clk", NULL, + visys_regmap, 0xa0, 6, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_MIPI_CSI2_CFG_CLK] = thead_gate_clk_register("clkgen_mipi_csi2_cfg_clk", NULL, + visys_regmap, 0xa0, 7, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_DW200_CLK_VSE] = thead_gate_clk_register("clkgen_dw200_clk_vse", NULL, + visys_regmap, 0xa0, 5, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_DW200_CLK_DWE] = thead_gate_clk_register("clkgen_dw200_clk_dwe", NULL, + visys_regmap, 0xa0, 4, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP0_CLK] = thead_gate_clk_register("clkgen_isp_clk_0", NULL, + visys_regmap, 0xa4, 31, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP1_CLK] = thead_gate_clk_register("clkgen_isp_clk_1", NULL, + visys_regmap, 0xa4, 30, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP_RY_CCLK] = thead_gate_clk_register("clkgen_isp_ry_cclk", NULL, + visys_regmap, 0xa0, 21, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP1_PIXELCLK] = thead_gate_clk_register("clkgen_isp1_pixelclk", NULL, + visys_regmap, 0xa4, 28, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP0_PIXELCLK] = thead_gate_clk_register("clkgen_isp0_pixelclk", NULL, + visys_regmap, 0xa4, 29, GATE_NOT_SHARED, NULL, dev); + gates[LIGHT_CLKGEN_ISP1_HCLK] = thead_gate_clk_register("clkgen_isp1_hclk", NULL, + visys_regmap, 0xa0, 1, GATE_SHARED, &share_cnt_isp0_hclk_en, dev); + gates[LIGHT_CLKGEN_ISP0_HCLK] = thead_gate_clk_register("clkgen_isp0_hclk", NULL, + visys_regmap, 0xa0, 1, GATE_SHARED, &share_cnt_isp0_hclk_en, dev); + gates[LIGHT_CLKGEN_ISP1_ACLK] = thead_gate_clk_register("clkgen_isp1_aclk", NULL, + visys_regmap, 0xa0, 3, GATE_SHARED, &share_cnt_isp0_aclk_en, dev); + gates[LIGHT_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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../clk.h" + +static struct clk *gates[LIGHT_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 */ + gates[LIGHT_CLKGEN_AXI4_VO_PCLK] = thead_clk_light_gate("clkgen_axi4_vo_pclk", NULL, + gate_base + 0x50, 22); + gates[LIGHT_CLKGEN_IOPMP_VOSYS_DPU_PCLK] = thead_clk_light_gate("clkgen_iopmp_dpu_pclk", NULL, + gate_base + 0x50, 23); + gates[LIGHT_CLKGEN_IOPMP_VOSYS_DPU1_PCLK] = thead_clk_light_gate("clkgen_iopmp_dpu1_pclk", NULL, + gate_base + 0x50, 24); + gates[LIGHT_CLKGEN_IOPMP_VOSYS_GPU_PCLK] = thead_clk_light_gate("clkgen_iopmp_gpu_pclk", NULL, + gate_base + 0x50, 25); + gates[LIGHT_CLKGEN_HDMI_PCLK] = thead_clk_light_gate("clkgen_hdmi_pclk", NULL, gate_base + 0x50, 11); + gates[LIGHT_CLKGEN_MIPIDSI0_PCLK] = thead_clk_light_gate("clkgen_mipidsi0_pclk", NULL, + gate_base + 0x50, 13); + gates[LIGHT_CLKGEN_MIPIDSI1_PCLK] = thead_clk_light_gate("clkgen_mipidsi1_pclk", NULL, + gate_base + 0x50, 14); + gates[LIGHT_CLKGEN_AXI4_VO_ACLK] = thead_clk_light_gate("clkgen_axi4_vo_aclk", NULL, + gate_base + 0x50, 0); + gates[LIGHT_CLKGEN_IOPMP_GPU_ACLK] = thead_clk_light_gate("clkgen_iopmp_gpu_aclk", NULL, + gate_base + 0x50, 29); + gates[LIGHT_CLKGEN_IOPMP_DPU_ACLK] = thead_clk_light_gate("clkgen_iopmp_dpu_aclk", NULL, + gate_base + 0x50, 28); + gates[LIGHT_CLKGEN_IOPMP_DPU1_ACLK] = thead_clk_light_gate("clkgen_iopmp_dpu1_aclk", NULL, + gate_base + 0x50, 27); + gates[LIGHT_CLKGEN_X2H_DPU_ACLK] = thead_clk_light_gate("clkgen_x2h_dpu_aclk", NULL, gate_base + 0x50, 21); + gates[LIGHT_CLKGEN_X2H_DPU1_ACLK] = thead_clk_light_gate("clkgen_x2h_dpu1_aclk", NULL, gate_base + 0x50, 20); + gates[LIGHT_CLKGEN_MIPIDSI0_PIXCLK] = thead_clk_light_gate("clkgen_mipidsi0_pixclk", NULL, gate_base + 0x50, 30); + gates[LIGHT_CLKGEN_HDMI_PIXCLK] = thead_clk_light_gate("clkgen_hdmi_pixclk", NULL, gate_base + 0x54, 0); + gates[LIGHT_CLKGEN_MIPIDSI1_PIXCLK] = thead_clk_light_gate("clkgen_mipidsi1_pixclk", NULL, gate_base + 0x50, 31); + gates[LIGHT_CLKGEN_HDMI_SFR_CLK] = thead_clk_light_gate("clkgen_hdmi_sfr_clk", NULL, gate_base + 0x50, 10); + gates[LIGHT_CLKGEN_HDMI_CEC_CLK] = thead_clk_light_gate("clkgen_hdmi_cec_cclk", NULL, gate_base + 0x50, 12); + gates[LIGHT_CLKGEN_HDMI_I2S_CLK] = thead_clk_light_gate("clkgen_hdmi_i2s_clk", NULL, gate_base + 0x50, 19); + gates[LIGHT_CLKGEN_MIPIDSI0_CFG_CLK] = thead_clk_light_gate("clkgen_mipidsi0_cfg_clk", NULL, gate_base + 0x50, 15); + gates[LIGHT_CLKGEN_MIPIDSI1_CFG_CLK] = thead_clk_light_gate("clkgen_mipidsi1_cfg_clk", NULL, gate_base + 0x50, 16); + gates[LIGHT_CLKGEN_MIPIDSI0_REFCLK] = thead_clk_light_gate("clkgen_mipidsi0_refclk", NULL, gate_base + 0x50, 17); + gates[LIGHT_CLKGEN_MIPIDSI1_REFCLK] = thead_clk_light_gate("clkgen_mipidsi1_refclk", NULL, gate_base + 0x50, 18); + gates[LIGHT_CLKGEN_GPU_CORE_CLK] = thead_clk_light_gate("clkgen_gpu_core_clk", NULL, gate_base + 0x50, 3); + gates[LIGHT_CLKGEN_GPU_CFG_ACLK] = thead_clk_light_gate("clkgen_gpu_cfg_aclk", NULL, gate_base + 0x50, 4); + gates[LIGHT_CLKGEN_DPU_HCLK] = thead_clk_light_gate("clkgen_dpu_hclk", NULL, gate_base + 0x50, 7); + gates[LIGHT_CLKGEN_DPU_ACLK] = thead_clk_light_gate("clkgen_dpu_aclk", NULL, gate_base + 0x50, 8); + gates[LIGHT_CLKGEN_DPU_CCLK] = thead_clk_light_gate("clkgen_dpu_cclk", NULL, gate_base + 0x50, 9); + gates[LIGHT_CLKGEN_DPU_PIXCLK0] = thead_clk_light_gate("clkgen_dpu_pixclk0", NULL, gate_base + 0x50, 5); + gates[LIGHT_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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../clk.h" + +static struct clk *gates[LIGHT_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 */ + gates[LIGHT_VPSYS_G2D_PCLK] = thead_clk_light_gate_shared("clkgen_vpsys_g2d_pclk", NULL, + gate_base + 0x20, 3, &share_cnt_g2d_clk_en); + gates[LIGHT_VPSYS_G2D_ACLK] = thead_clk_light_gate_shared("clkgen_vpsys_g2d_aclk", NULL, + gate_base + 0x20, 3, &share_cnt_g2d_clk_en); + gates[LIGHT_VPSYS_G2D_CCLK] = thead_clk_light_gate_shared("clkgen_vpsys_g2d_cclk", NULL, + gate_base + 0x20, 3, &share_cnt_g2d_clk_en); + + + gates[LIGHT_VPSYS_FCE_PCLK] = thead_clk_light_gate_shared("clkgen_vpsys_fce_pclk", NULL, + gate_base + 0x20, 2, &share_cnt_fce_clk_en); + gates[LIGHT_VPSYS_FCE_ACLK] = thead_clk_light_gate_shared("clkgen_vpsys_fce_aclk", NULL, + gate_base + 0x20, 2, &share_cnt_fce_clk_en); + + gates[LIGHT_VPSYS_VDEC_ACLK] = thead_clk_light_gate("clkgen_vdec_aclk", NULL, gate_base + 0x20, 4); + gates[LIGHT_VPSYS_VDEC_CCLK] = thead_clk_light_gate("clkgen_vdec_cclk", NULL, gate_base + 0x20, 5); + gates[LIGHT_VPSYS_VDEC_PCLK] = thead_clk_light_gate("clkgen_vdec_pclk", NULL, gate_base + 0x20, 6); + + gates[LIGHT_VPSYS_VENC_CCLK] = thead_clk_light_gate("clkgen_venc_cclk", NULL, gate_base + 0x20, 8); + gates[LIGHT_VPSYS_VENC_PCLK] = thead_clk_light_gate("clkgen_venc_pclk", NULL, gate_base + 0x20, 9); + gates[LIGHT_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 "); +MODULE_DESCRIPTION("Thead Light Fullmask vpsys clock gate provider"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index 3245eb0c602d..1ef476b80044 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -107,9 +107,30 @@ static int __init add_clockevent(struct device_node *event_timer) return 0; } +#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC +void __iomem *sched_io_base; +EXPORT_SYMBOL_GPL(sched_io_base); +static struct dw_apb_clocksource *cs_g; +#else static void __iomem *sched_io_base; +#endif static u32 sched_rate; +#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC +u64 dw_timer_read_counter(void) +{ + return ~readl_relaxed(sched_io_base); +} +EXPORT_SYMBOL_GPL(dw_timer_read_counter); + +void dw_cs_get_mult_shift(u32 *mult, u32 *shift) +{ + *mult = cs_g->cs.mult; + *shift = cs_g->cs.shift; +} +EXPORT_SYMBOL_GPL(dw_cs_get_mult_shift); +#endif + static int __init add_clocksource(struct device_node *source_timer) { void __iomem *iobase; @@ -135,6 +156,9 @@ static int __init add_clocksource(struct device_node *source_timer) */ sched_io_base = iobase + 0x04; sched_rate = rate; +#ifdef CONFIG_SOPHGO_MULTI_CHIP_CLOCK_SYNC + cs_g = cs; +#endif return 0; } 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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_table[index].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_volt[index], 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(clks[LIGHT_C910_CCLK].clk)), + __clk_get_name(clks[LIGHT_C910_CCLK_I0].clk))) { + clk_prepare_enable(clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk); + clk_set_rate(clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk, new_freq * 1000); + ret = clk_set_parent(clks[LIGHT_C910_CCLK].clk, clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk); + udelay(1); + if (ret) + clk_disable_unprepare(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk); + } else { + clk_prepare_enable(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk); + clk_set_rate(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk, new_freq * 1000); + ret = clk_set_parent(clks[LIGHT_C910_CCLK].clk, clks[LIGHT_C910_CCLK_I0].clk); + udelay(1); + if (ret) + clk_disable_unprepare(clks[LIGHT_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(clks[LIGHT_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_volt[index], 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 = clks[LIGHT_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(clks[LIGHT_C910_CCLK].clk)), + __clk_get_name(clks[LIGHT_C910_CCLK_I0].clk))) { + pr_debug("[%s,%d]\n", __func__, __LINE__); + clk_prepare_enable(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk); + clk_set_rate(clks[LIGHT_CPU_PLL0_FOUTPOSTDIV].clk, policy->min * 1000); + udelay(1); + clk_set_parent(clks[LIGHT_C910_CCLK].clk, clks[LIGHT_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(clks[LIGHT_CPU_PLL1_FOUTPOSTDIV].clk); + clk_set_rate(clks[LIGHT_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_table[j].frequency == freq) { + light_dvddm_volt[soc_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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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_errmap[LIGHT_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_errmap[errno]; + 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 "); +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 + +struct light_aon_msg_req_misc_set_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 ctrl; + u32 val; + u16 resource; + u16 reserved[7]; +} __packed __aligned(4); + +struct light_aon_msg_req_misc_get_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 ctrl; + u16 resource; + u16 reserved[9]; +} __packed __aligned(4); + +struct light_aon_msg_resp_misc_get_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 val; + u32 reserved[5]; +} __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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct light_aon_msg_req_set_resource_power_mode { + struct light_aon_rpc_msg_hdr hdr; + u16 resource; + u16 mode; + u16 reserved[10]; +} __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 name[LIGHT_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->domains[i]); + if (aon_pd->rsrc == spec->args[0]) { + 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_ranges[i].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_ranges[i].num; j++) { + aon_pd = light_aon_add_pm_domain(dev, j, &pd_ranges[i]); + if (IS_ERR_OR_NULL(aon_pd)) + continue; + + domains[count++] = &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 (buffer[userlen - 1] == '\n') + buffer[userlen -1] = '\0'; + else + buffer[userlen] = '\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_name[LIGHT_AONU_PD_NAME_SIZE]; + char pd_state[LIGHT_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->domains[idx]; + 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->domains[idx]; + 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->domains[idx]->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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 reserved[7]; +} __packed __aligned(4); + +struct light_aon_msg_req_misc_get_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 ctrl; + u16 resource; + u16 reserved[9]; +} __packed __aligned(4); + +struct light_aon_msg_resp_misc_get_ctrl { + struct light_aon_rpc_msg_hdr hdr; + u32 val; + u32 reserved[5]; +} __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 "); +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 6b7d47a52b10..8a63ff1e5f73 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -415,13 +415,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, @@ -531,10 +530,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 062d78818da1..57fc15a0d2df 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/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 901d1961b739..90489b55efa7 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -9,6 +9,7 @@ config DRM_AMD_DC select SND_HDA_COMPONENT if SND_HDA_CORE # !CC_IS_CLANG: https://github.com/ClangBuiltLinux/linux/issues/1752 select DRM_AMD_DC_FP if (X86 || LOONGARCH || (PPC64 && ALTIVEC) || (ARM64 && KERNEL_MODE_NEON && !CC_IS_CLANG)) + select DRM_AMD_DC_DCN if RISCV && FPU help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c index 172aa10a8800..53a7122ba98d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c @@ -35,6 +35,8 @@ #include #elif defined(CONFIG_LOONGARCH) #include +#elif defined(CONFIG_RISCV) +#include #endif /** @@ -90,7 +92,7 @@ void dc_fpu_begin(const char *function_name, const int line) *pcpu += 1; if (*pcpu == 1) { -#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) +#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) || defined(CONFIG_RISCV) migrate_disable(); kernel_fpu_begin(); #elif defined(CONFIG_PPC64) @@ -130,7 +132,7 @@ void dc_fpu_end(const char *function_name, const int line) pcpu = get_cpu_ptr(&fpu_recursion_depth); *pcpu -= 1; if (*pcpu <= 0) { -#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) +#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH) || defined(CONFIG_RISCV) kernel_fpu_end(); migrate_enable(); #elif defined(CONFIG_PPC64) diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 0ba9a7997d56..abd04d13997d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -43,6 +43,12 @@ dml_ccflags := -mfpu=64 dml_rcflags := -msoft-float endif +ifdef CONFIG_RISCV +include $(srctree)/arch/riscv/Makefile.isa +# Remove V from the ISA string, like in arch/riscv/Makefile, but keep F and D. +dml_ccflags := -march=$(subst v0p7,,$(riscv-march-y)) +endif + ifdef CONFIG_CC_IS_GCC ifneq ($(call gcc-min-version, 70100),y) IS_OLD_GCC = 1 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_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 7bf08164140e..b0476feba79c 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -336,10 +337,10 @@ radeon_pci_remove(struct pci_dev *pdev) static void radeon_pci_shutdown(struct pci_dev *pdev) { - /* if we are running in a VM, make sure the device - * torn down properly on reboot/shutdown + /* if we are running in a VM or kexec another kernel, + * make sure the device torn down properly on reboot/shutdown */ - if (radeon_device_is_virtual()) + if (radeon_device_is_virtual() || kexec_in_progress) radeon_pci_remove(pdev); #if defined(CONFIG_PPC64) || defined(CONFIG_MACH_LOONGSON64) 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 0b3f4267130c..f469067c8187 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -354,6 +354,7 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, if (ret) return ret; +#if 0 if (num_pages == 1 && ttm->caching == ttm_cached && !(man->use_tt && (ttm->page_flags & TTM_TT_FLAG_DECRYPTED))) { /* @@ -364,7 +365,9 @@ static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo, map->bo_kmap_type = ttm_bo_map_kmap; map->page = ttm->pages[start_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 43eaffa7faae..507c27f2270a 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -154,7 +154,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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_names[index_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 +#include +#include +#include +#include +#include +#include +#include + +/* 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_desc[LIGHT_MBOX_CHAN_NAME_SIZE]; + struct mbox_chan *chan; + struct tasklet_struct txdb_tasklet; +}; + +struct light_mbox_priv { + struct device *dev; + void __iomem *local_icu[LIGHT_MBOX_CHANS]; + void __iomem *remote_icu[LIGHT_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_chans[LIGHT_MBOX_CHANS]; + + struct light_mbox_con_priv con_priv[LIGHT_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, dat[LIGHT_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 data[8] = {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, &data[7], true); + light_mbox_chan_wr_ack(cp, &data[7], false); + light_mbox_chan_wr_data(cp, &data[0], true); + light_mbox_chan_wr_data(cp, &data[0], 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->args[0]; /* comm remote channel */ + type = sp->args[1]; /* comm channel type */ + + if (chan >= mbox->num_chans) { + dev_err(mbox->dev, "Not supported channel number: %d\n", chan); + return ERR_PTR(-EINVAL); + } + + if (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->chans[chan].con_priv; + cp->type = type; + + return &mbox->chans[chan]; +} + +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_icu[LIGHT_MBOX_ICU_CPU0] = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->local_icu[LIGHT_MBOX_ICU_CPU0])) + return PTR_ERR(priv->local_icu[LIGHT_MBOX_ICU_CPU0]); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu0"); + priv->remote_icu[0] = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->remote_icu[0])) + return PTR_ERR(priv->remote_icu[0]); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu1"); + priv->remote_icu[1] = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->remote_icu[1])) + return PTR_ERR(priv->remote_icu[1]); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu2"); + priv->remote_icu[2] = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->remote_icu[2])) + return PTR_ERR(priv->remote_icu[2]); + + priv->local_icu[LIGHT_MBOX_ICU_CPU1] = priv->local_icu[LIGHT_MBOX_ICU_CPU0] + + LIGHT_MBOX_CHAN_RES_SIZE; + priv->local_icu[LIGHT_MBOX_ICU_CPU2] = priv->local_icu[LIGHT_MBOX_ICU_CPU1] + + LIGHT_MBOX_CHAN_RES_SIZE; + priv->local_icu[LIGHT_MBOX_ICU_CPU3] = priv->local_icu[LIGHT_MBOX_ICU_CPU2] + + LIGHT_MBOX_CHAN_RES_SIZE; + + priv->cur_cpu_ch_base = priv->local_icu[priv->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_priv[i]; + + cp->idx = i; + cp->chan = &priv->mbox_chans[i]; + priv->mbox_chans[i].con_priv = cp; + snprintf(cp->irq_desc, sizeof(cp->irq_desc), + "light_mbox_chan[%i]", cp->idx); + + cp->comm_local_base = priv->local_icu[i]; + if (i != priv->cur_icu_cpu_id) { + cp->comm_remote_base = priv->remote_icu[remote_idx]; + remote_idx++; + } + } + + 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 "); +MODULE_DESCRIPTION("Thead Light mailbox IPC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index bc7e2ad37002..5c705adef829 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 a0524127ca07..1a737a239d30 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -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 +#include +#include +#include +#include +#include +#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; + } tunlist[4]; + 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++; + } + tunlist[i].start = tun; + tun++; + while (tun < max) { + bm_sdhci_set_tap(host, tun); + if (mmc_send_tuning(host->mmc, opcode, NULL)) + break; + tun++; + } + tunlist[i].end = tun-1; + tunlist[i].width = tunlist[i].end - tunlist[i].start; + listcount++; + tun++; + pr_info("%s id:%d start:%d end:%d width:%d\n", mmc_hostname(host->mmc), + i, tunlist[i].start, tunlist[i].end, tunlist[i].width); + if (tun >= max) + break; + } + + //find maxwidth + listsel = 0; + for (i = 0; i < listcount; i++) { + if (tunlist[i].width > maxwidth) { + maxwidth = tunlist[i].width; + listsel = i; + } + } + tuntap = tunlist[listsel].start + (tunlist[listsel].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 +#include +#include +#include +#include + +/*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/mtd/spi-nor/controllers/Kconfig b/drivers/mtd/spi-nor/controllers/Kconfig index ca45dcd3ffe8..d2138370f1fc 100644 --- a/drivers/mtd/spi-nor/controllers/Kconfig +++ b/drivers/mtd/spi-nor/controllers/Kconfig @@ -16,3 +16,14 @@ config SPI_NXP_SPIFI SPIFI is a specialized controller for connecting serial SPI Flash. Enable this option if you have a device with a SPIFI controller and want to access the Flash as a mtd device. + +config SPI_SOPHGO_SPIFMC + tristate "Sophgo SPI Flash Master Controller (SPIFMC)" + depends on ARCH_SOPHGO || COMPILE_TEST + depends on HAS_IOMEM + help + Enable support for the Sophgo SPI Flash Master controller. + + SPIFMC is a master controller to control serial SPI Flash. + Enable this option if you have a device with a SPIFMC controller + and want to access the Flash as a mtd device. diff --git a/drivers/mtd/spi-nor/controllers/Makefile b/drivers/mtd/spi-nor/controllers/Makefile index 0b8e1d530913..627ac8850ab1 100644 --- a/drivers/mtd/spi-nor/controllers/Makefile +++ b/drivers/mtd/spi-nor/controllers/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o +obj-$(CONFIG_SPI_SOPHGO_SPIFMC) += sophgo-spifmc.o diff --git a/drivers/mtd/spi-nor/controllers/sophgo-spifmc.c b/drivers/mtd/spi-nor/controllers/sophgo-spifmc.c new file mode 100644 index 000000000000..f7d85cc03137 --- /dev/null +++ b/drivers/mtd/spi-nor/controllers/sophgo-spifmc.c @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * SPI Flash Master Controller (SPIFMC) + * + * Copyright (c) 2023 Sophgo. + */ +#include +#include +#include +#include +#include +#include +#include + +/* Hardware register definitions */ +#define SPIFMC_CTRL 0x00 +#define SPIFMC_CTRL_CPHA BIT(12) +#define SPIFMC_CTRL_CPOL BIT(13) +#define SPIFMC_CTRL_HOLD_OL BIT(14) +#define SPIFMC_CTRL_WP_OL BIT(15) +#define SPIFMC_CTRL_LSBF BIT(20) +#define SPIFMC_CTRL_SRST BIT(21) +#define SPIFMC_CTRL_SCK_DIV_SHIFT 0 +#define SPIFMC_CTRL_FRAME_LEN_SHIFT 16 + +#define SPIFMC_CE_CTRL 0x04 +#define SPIFMC_CE_CTRL_CEMANUAL BIT(0) +#define SPIFMC_CE_CTRL_CEMANUAL_EN BIT(1) + +#define SPIFMC_DLY_CTRL 0x08 +#define SPIFMC_CTRL_FM_INTVL_MASK 0x000f +#define SPIFMC_CTRL_FM_INTVL BIT(0) +#define SPIFMC_CTRL_CET_MASK 0x0f00 +#define SPIFMC_CTRL_CET BIT(8) + +#define SPIFMC_DMMR 0x0c + +#define SPIFMC_TRAN_CSR 0x10 +#define SPIFMC_TRAN_CSR_TRAN_MODE_MASK 0x0003 +#define SPIFMC_TRAN_CSR_TRAN_MODE_RX BIT(0) +#define SPIFMC_TRAN_CSR_TRAN_MODE_TX BIT(1) +#define SPIFMC_TRAN_CSR_CNTNS_READ BIT(2) +#define SPIFMC_TRAN_CSR_FAST_MODE BIT(3) +#define SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT (0x00 << 4) +#define SPIFMC_TRAN_CSR_BUS_WIDTH_2_BIT (0x01 << 4) +#define SPIFMC_TRAN_CSR_BUS_WIDTH_4_BIT (0x02 << 4) +#define SPIFMC_TRAN_CSR_DMA_EN BIT(6) +#define SPIFMC_TRAN_CSR_MISO_LEVEL BIT(7) +#define SPIFMC_TRAN_CSR_ADDR_BYTES_MASK 0x0700 +#define SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT 8 +#define SPIFMC_TRAN_CSR_WITH_CMD BIT(11) +#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_MASK 0x3000 +#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE (0x00 << 12) +#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_2_BYTE (0x01 << 12) +#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_4_BYTE (0x02 << 12) +#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE (0x03 << 12) +#define SPIFMC_TRAN_CSR_GO_BUSY BIT(15) + +#define SPIFMC_TRAN_NUM 0x14 +#define SPIFMC_FIFO_PORT 0x18 +#define SPIFMC_FIFO_PT 0x20 + +#define SPIFMC_INT_STS 0x28 +#define SPIFMC_INT_TRAN_DONE BIT(0) +#define SPIFMC_INT_RD_FIFO BIT(2) +#define SPIFMC_INT_WR_FIFO BIT(3) +#define SPIFMC_INT_RX_FRAME BIT(4) +#define SPIFMC_INT_TX_FRAME BIT(5) + +#define SPIFMC_INT_EN 0x2c +#define SPIFMC_INT_TRAN_DONE_EN BIT(0) +#define SPIFMC_INT_RD_FIFO_EN BIT(2) +#define SPIFMC_INT_WR_FIFO_EN BIT(3) +#define SPIFMC_INT_RX_FRAME_EN BIT(4) +#define SPIFMC_INT_TX_FRAME_EN BIT(5) + +#define SPIFMC_MAX_FIFO_DEPTH 8 + +struct sophgo_spifmc { + struct device *dev; + struct clk *clk; + void __iomem *io_base; + struct spi_nor nor; +}; + +static inline int sophgo_spifmc_wait_int(struct sophgo_spifmc *spifmc, + u8 int_type) +{ + u32 stat; + + return readl_poll_timeout(spifmc->io_base + SPIFMC_INT_STS, stat, + (stat & int_type), 0, 0); +} + +static inline u32 sophgo_spifmc_init_reg(struct sophgo_spifmc *spifmc) +{ + u32 reg; + + reg = readl(spifmc->io_base + SPIFMC_TRAN_CSR); + reg &= ~(SPIFMC_TRAN_CSR_TRAN_MODE_MASK + | SPIFMC_TRAN_CSR_CNTNS_READ + | SPIFMC_TRAN_CSR_FAST_MODE + | SPIFMC_TRAN_CSR_BUS_WIDTH_2_BIT + | SPIFMC_TRAN_CSR_BUS_WIDTH_4_BIT + | SPIFMC_TRAN_CSR_DMA_EN + | SPIFMC_TRAN_CSR_ADDR_BYTES_MASK + | SPIFMC_TRAN_CSR_WITH_CMD + | SPIFMC_TRAN_CSR_FIFO_TRG_LVL_MASK); + + return reg; +} + +/* + * sophgo_spifmc_read_reg is a workaround function: + * AHB bus could only do 32-bit access to SPIFMC fifo, + * so cmd without 3-byte addr will leave 3-byte data in fifo. + * Set TX to mark that these 3-byte data would be sent out. + */ +static int sophgo_spifmc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, + size_t len) +{ + struct sophgo_spifmc *spifmc = nor->priv; + u32 reg; + int ret, i; + + reg = sophgo_spifmc_init_reg(spifmc); + reg |= SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT; + reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE; + reg |= SPIFMC_TRAN_CSR_WITH_CMD; + reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX | SPIFMC_TRAN_CSR_TRAN_MODE_TX; + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + writeb(opcode, spifmc->io_base + SPIFMC_FIFO_PORT); + + for (i = 0; i < len; i++) + writeb(0, spifmc->io_base + SPIFMC_FIFO_PORT); + + writel(0, spifmc->io_base + SPIFMC_INT_STS); + writel(len, spifmc->io_base + SPIFMC_TRAN_NUM); + reg |= SPIFMC_TRAN_CSR_GO_BUSY; + writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR); + + ret = sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE); + if (ret) + return ret; + + while (len--) + *buf++ = readb(spifmc->io_base + SPIFMC_FIFO_PORT); + + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + + return 0; +} + +static int sophgo_spifmc_write_reg(struct spi_nor *nor, u8 opcode, + const u8 *buf, size_t len) +{ + struct sophgo_spifmc *spifmc = nor->priv; + u32 reg; + int i; + + reg = sophgo_spifmc_init_reg(spifmc); + reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE; + reg |= SPIFMC_TRAN_CSR_WITH_CMD; + + /* + * If write values to the Status Register, + * configure TRAN_CSR register as the same as sophgo_spifmc_read_reg. + */ + if (opcode == SPINOR_OP_WRSR) { + reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX | SPIFMC_TRAN_CSR_TRAN_MODE_TX; + writel(len, spifmc->io_base + SPIFMC_TRAN_NUM); + } + + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + writeb(opcode, spifmc->io_base + SPIFMC_FIFO_PORT); + + for (i = 0; i < len; i++) + writeb(buf[i], spifmc->io_base + SPIFMC_FIFO_PORT); + + writel(0, spifmc->io_base + SPIFMC_INT_STS); + reg |= SPIFMC_TRAN_CSR_GO_BUSY; + writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR); + sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE); + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + + return 0; +} + +static ssize_t sophgo_spifmc_read(struct spi_nor *nor, loff_t from, + size_t len, u_char *buf) +{ + struct sophgo_spifmc *spifmc = nor->priv; + u32 reg; + int xfer_size, offset; + int i; + + reg = sophgo_spifmc_init_reg(spifmc); + reg |= (nor->addr_nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT; + reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE; + reg |= SPIFMC_TRAN_CSR_WITH_CMD; + reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX; + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + writeb(nor->read_opcode, spifmc->io_base + SPIFMC_FIFO_PORT); + + for (i = nor->addr_nbytes - 1; i >= 0; i--) + writeb((from >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT); + + writel(0, spifmc->io_base + SPIFMC_INT_STS); + writel(len, spifmc->io_base + SPIFMC_TRAN_NUM); + reg |= SPIFMC_TRAN_CSR_GO_BUSY; + writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR); + sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_RD_FIFO); + + offset = 0; + while (offset < len) { + xfer_size = min_t(size_t, SPIFMC_MAX_FIFO_DEPTH, len - offset); + + while ((readl(spifmc->io_base + SPIFMC_FIFO_PT) & 0xf) != xfer_size) + ; + + for (i = 0; i < xfer_size; i++) + buf[i + offset] = readb(spifmc->io_base + SPIFMC_FIFO_PORT); + + offset += xfer_size; + } + + sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE); + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + + return len; +} + +static ssize_t sophgo_spifmc_write(struct spi_nor *nor, loff_t to, + size_t len, const u_char *buf) +{ + struct sophgo_spifmc *spifmc = nor->priv; + u32 reg; + int i, offset; + int xfer_size, wait; + + reg = sophgo_spifmc_init_reg(spifmc); + reg |= nor->addr_nbytes << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT; + reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE; + reg |= SPIFMC_TRAN_CSR_WITH_CMD; + reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX; + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + writeb(nor->program_opcode, spifmc->io_base + SPIFMC_FIFO_PORT); + + for (i = nor->addr_nbytes - 1; i >= 0; i--) + writeb((to >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT); + + writel(0, spifmc->io_base + SPIFMC_INT_STS); + writel(len, spifmc->io_base + SPIFMC_TRAN_NUM); + reg |= SPIFMC_TRAN_CSR_GO_BUSY; + writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR); + + while ((readl(spifmc->io_base + SPIFMC_FIFO_PT) & 0xf) != 0) + ; + + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + + offset = 0; + while (offset < len) { + xfer_size = min_t(size_t, SPIFMC_MAX_FIFO_DEPTH, len - offset); + + wait = 0; + while ((readl(spifmc->io_base + SPIFMC_FIFO_PT) & 0xf) != 0) { + wait++; + udelay(10); + if (wait > 30000) { + dev_warn(spifmc->dev, "Wait to write FIFO timeout.\n"); + return -1; + } + } + + for (i = 0; i < xfer_size; i++) + writeb(buf[i + offset], spifmc->io_base + SPIFMC_FIFO_PORT); + + offset += xfer_size; + } + + sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE); + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + + return len; +} + +static int sophgo_spifmc_erase(struct spi_nor *nor, loff_t offs) +{ + struct sophgo_spifmc *spifmc = nor->priv; + u32 reg; + int i; + + reg = sophgo_spifmc_init_reg(spifmc); + reg |= nor->addr_nbytes << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT; + reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE; + reg |= SPIFMC_TRAN_CSR_WITH_CMD; + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + writeb(nor->erase_opcode, spifmc->io_base + SPIFMC_FIFO_PORT); + + for (i = nor->addr_nbytes - 1; i >= 0; i--) + writeb((offs >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT); + + writel(0, spifmc->io_base + SPIFMC_INT_STS); + reg |= SPIFMC_TRAN_CSR_GO_BUSY; + writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR); + sophgo_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE); + writel(0, spifmc->io_base + SPIFMC_FIFO_PT); + + return 0; +} + +static const struct spi_nor_controller_ops sophgo_spifmc_controller_ops = { + .read_reg = sophgo_spifmc_read_reg, + .write_reg = sophgo_spifmc_write_reg, + .read = sophgo_spifmc_read, + .write = sophgo_spifmc_write, + .erase = sophgo_spifmc_erase, +}; + +static void sophgo_spifmc_init(struct sophgo_spifmc *spifmc) +{ + u32 reg; + + /* disable DMMR (Direct Memory Mapping Read) */ + writel(0, spifmc->io_base + SPIFMC_DMMR); + /* soft reset */ + writel(readl(spifmc->io_base + SPIFMC_CTRL) | SPIFMC_CTRL_SRST | 0x3, + spifmc->io_base + SPIFMC_CTRL); + /* hardware CE contrl, soft reset cannot change the register */ + writel(0, spifmc->io_base + SPIFMC_CE_CTRL); + reg = spifmc->nor.addr_nbytes << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT; + reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_4_BYTE; + reg |= SPIFMC_TRAN_CSR_WITH_CMD; + writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR); +} + +static int sophgo_spifmc_register(struct device_node *np, + struct sophgo_spifmc *spifmc) +{ + /* TODO: support DUAL and QUAD operations */ + const struct spi_nor_hwcaps hwcaps = { + .mask = SNOR_HWCAPS_READ | + SNOR_HWCAPS_PP, + }; + int ret; + + spifmc->nor.dev = spifmc->dev; + spi_nor_set_flash_node(&spifmc->nor, np); + spifmc->nor.priv = spifmc; + spifmc->nor.controller_ops = &sophgo_spifmc_controller_ops; + + ret = spi_nor_scan(&spifmc->nor, NULL, &hwcaps); + if (ret) { + dev_err(spifmc->dev, "Device scan failed.\n"); + return ret; + } + + ret = mtd_device_register(&spifmc->nor.mtd, NULL, 0); + if (ret) { + dev_err(spifmc->dev, "mtd device parse failed.\n"); + return ret; + } + + return 0; +} + +static int sophgo_spifmc_probe(struct platform_device *pdev) +{ + struct device_node *np; + struct sophgo_spifmc *spifmc; + int ret; + + spifmc = devm_kzalloc(&pdev->dev, sizeof(*spifmc), GFP_KERNEL); + if (!spifmc) + return -ENOMEM; + + spifmc->io_base = devm_platform_ioremap_resource_byname(pdev, "memory"); + if (IS_ERR(spifmc->io_base)) + return PTR_ERR(spifmc->io_base); + + spifmc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(spifmc->clk)) { + dev_err(&pdev->dev, "AHB clock not found.\n"); + return PTR_ERR(spifmc->clk); + } + + ret = clk_prepare_enable(spifmc->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable AHB clock.\n"); + return ret; + } + + spifmc->dev = &pdev->dev; + platform_set_drvdata(pdev, spifmc); + sophgo_spifmc_init(spifmc); + + np = of_get_next_available_child(pdev->dev.of_node, NULL); + if (!np) { + dev_err(&pdev->dev, "No SPI flash device to configure.\n"); + ret = -ENODEV; + goto fail; + } + + ret = sophgo_spifmc_register(np, spifmc); + of_node_put(np); + if (ret) { + dev_err(&pdev->dev, "Unable to register spifmc.\n"); + goto fail; + } + + return ret; +fail: + clk_disable_unprepare(spifmc->clk); + return ret; +} + +static int sophgo_spifmc_remove(struct platform_device *pdev) +{ + struct sophgo_spifmc *spifmc = platform_get_drvdata(pdev); + + mtd_device_unregister(&spifmc->nor.mtd); + clk_disable_unprepare(spifmc->clk); + + return 0; +} + +static const struct of_device_id sophgo_spifmc_match[] = { + {.compatible = "sophgo,spifmc"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sophgo_spifmc_match); + +static struct platform_driver sophgo_spifmc_driver = { + .probe = sophgo_spifmc_probe, + .remove = sophgo_spifmc_remove, + .driver = { + .name = "sophgo-spifmc", + .of_match_table = sophgo_spifmc_match, + }, +}; +module_platform_driver(sophgo_spifmc_driver); + +MODULE_DESCRIPTION("Sophgo SPI Flash Master Controller Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c index d57ddaf1525b..c60656702063 100644 --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c @@ -33,6 +33,15 @@ static const struct spi_nor_fixups gd25q256_fixups = { .post_bfpt = gd25q256_post_bfpt, }; +static void gd25lb512me_default_init(struct spi_nor *nor) +{ + nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; +} + +static const struct spi_nor_fixups gd25lb512me_fixups = { + .default_init = gd25lb512me_default_init, +}; + static const struct flash_info gigadevice_nor_parts[] = { { "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) @@ -67,6 +76,11 @@ static const struct flash_info gigadevice_nor_parts[] = { FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6) FIXUP_FLAGS(SPI_NOR_4B_OPCODES) .fixups = &gd25q256_fixups }, + { "gd25lb512me", INFO(0xc8671a, 0, 64 * 1024, 1024) + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) + FIXUP_FLAGS(SPI_NOR_4B_OPCODES) + .fixups = &gd25lb512me_fixups }, }; const struct spi_nor_manufacturer spi_nor_gigadevice = { diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 4d7caa119971..0a9efd8c6471 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -3213,7 +3213,8 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, p->base_queue = phys_id; break; case I40E_AQ_CAP_ID_MSIX: - p->num_msix_vectors = number; + //p->num_msix_vectors = number; + p->num_msix_vectors = 8; i40e_debug(hw, I40E_DEBUG_INIT, "HW Capability: MSIX vector count = %d\n", p->num_msix_vectors); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 61b9774b3d31..1b18fa4eb082 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -2069,7 +2069,7 @@ enum { #define IXGBE_DEVICE_CAPS 0x2C #define IXGBE_SERIAL_NUMBER_MAC_ADDR 0x11 #define IXGBE_PCIE_MSIX_82599_CAPS 0x72 -#define IXGBE_MAX_MSIX_VECTORS_82599 0x40 +#define IXGBE_MAX_MSIX_VECTORS_82599 0x09 #define IXGBE_PCIE_MSIX_82598_CAPS 0x62 #define IXGBE_MAX_MSIX_VECTORS_82598 0x13 diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 92d7d5a00b84..d86875c039a2 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..a071e84272e3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -22,11 +22,13 @@ obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o +obj-$(CONFIG_ARCH_SOPHGO) += dwmac-sophgo.o obj-$(CONFIG_DWMAC_STARFIVE) += dwmac-starfive.o 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_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 +#include +#include +#include +#include +#include +#include + +#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"); +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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +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..c0dd61e31adc --- /dev/null +++ b/drivers/pci/controller/cadence/pcie-cadence-sophgo.c @@ -0,0 +1,972 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Cadence +// Cadence PCIe host controller driver. +// Author: Cyrille Pitchen + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_mask[MAX_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}, + {"Inter I40E", 0x8086, 0x1572}, + //{"WangXun RP1000", 0x8088}, + {"Switchtec", 0x11f8,0x4052}, +}; + +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_list[i].vendor_id && device_id == vendor_id_list[i].device_id) { + pr_info("dev: %s vendor ID: 0x%04x device ID: 0x%04x Enable MSI-X IRQ\n", + vendor_id_list[i].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 reg0810[2] + 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 reg0810[2] + 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_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) +{ + return 0; /* Proper return code 0 == NO_IRQ */ +} + +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; + if (rc->top_intc_used == 1) + bridge->map_irq = of_irq_parse_and_map_pci; + else + bridge->map_irq = cdns_pcie_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->link[phy_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/msi/msi.c b/drivers/pci/msi/msi.c index 7078200be11f..d701b49055c4 100644 --- a/drivers/pci/msi/msi.c +++ b/drivers/pci/msi/msi.c @@ -12,6 +12,7 @@ #include "../pci.h" #include "msi.h" +#include "../controller/cadence/pcie-cadence-sophgo.h" int pci_msi_enable = 1; int pci_msi_ignore_mask; @@ -818,66 +819,70 @@ int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int } #endif - if (maxvec < minvec) - return -ERANGE; + if (check_vendor_id(dev, vendor_id_list, vendor_id_list_num)) { + if (maxvec < minvec) + return -ERANGE; - if (dev->msi_enabled) { - pci_info(dev, "can't enable MSI-X (MSI already enabled)\n"); - return -EINVAL; - } + if (dev->msi_enabled) { + pci_info(dev, "can't enable MSI-X (MSI already enabled)\n"); + return -EINVAL; + } - if (WARN_ON_ONCE(dev->msix_enabled)) - return -EINVAL; + if (WARN_ON_ONCE(dev->msix_enabled)) + return -EINVAL; - /* Check MSI-X early on irq domain enabled architectures */ - if (!pci_msi_domain_supports(dev, MSI_FLAG_PCI_MSIX, ALLOW_LEGACY)) - return -ENOTSUPP; + /* Check MSI-X early on irq domain enabled architectures */ + if (!pci_msi_domain_supports(dev, MSI_FLAG_PCI_MSIX, ALLOW_LEGACY)) + return -ENOTSUPP; - if (!pci_msi_supported(dev, nvec) || dev->current_state != PCI_D0) - return -EINVAL; + if (!pci_msi_supported(dev, nvec) || dev->current_state != PCI_D0) + return -EINVAL; - hwsize = pci_msix_vec_count(dev); - if (hwsize < 0) - return hwsize; + hwsize = pci_msix_vec_count(dev); + if (hwsize < 0) + return hwsize; - if (!pci_msix_validate_entries(dev, entries, nvec)) - return -EINVAL; + if (!pci_msix_validate_entries(dev, entries, nvec)) + return -EINVAL; - if (hwsize < nvec) { - /* Keep the IRQ virtual hackery working */ - if (flags & PCI_IRQ_VIRTUAL) - hwsize = nvec; - else - nvec = hwsize; - } + if (hwsize < nvec) { + /* Keep the IRQ virtual hackery working */ + if (flags & PCI_IRQ_VIRTUAL) + hwsize = nvec; + else + nvec = hwsize; + } - if (nvec < minvec) - return -ENOSPC; + if (nvec < minvec) + return -ENOSPC; - rc = pci_setup_msi_context(dev); - if (rc) - return rc; + rc = pci_setup_msi_context(dev); + if (rc) + return rc; - if (!pci_setup_msix_device_domain(dev, hwsize)) - return -ENODEV; + if (!pci_setup_msix_device_domain(dev, hwsize)) + return -ENODEV; - for (;;) { - if (affd) { - nvec = irq_calc_affinity_vectors(minvec, nvec, affd); - if (nvec < minvec) - return -ENOSPC; - } + for (;;) { + if (affd) { + nvec = irq_calc_affinity_vectors(minvec, nvec, affd); + if (nvec < minvec) + return -ENOSPC; + } - rc = msix_capability_init(dev, entries, nvec, affd); - if (rc == 0) - return nvec; + rc = msix_capability_init(dev, entries, nvec, affd); + if (rc == 0) + return nvec; - if (rc < 0) - return rc; - if (rc < minvec) - return -ENOSPC; + if (rc < 0) + return rc; + if (rc < minvec) + return -ENOSPC; - nvec = rc; + nvec = rc; + } + } else { + return -1; } } 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "core.h" +#include "pinmux.h" +#include "pinconf.h" + +#define 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_string[mt])) + 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.pins[gsel].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.pins[gsel].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 (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN && + map[i].data.configs.configs != seen) { + seen = map[i].data.configs.configs; + kfree(seen); + } + } + + kfree(map); +} + +static int 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.pins[i].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) { + map[nmaps].type = PIN_MAP_TYPE_CONFIGS_PIN; + map[nmaps].data.configs.group_or_pin = thp->desc.pins[i].name; + map[nmaps].data.configs.configs = configs; + map[nmaps].data.configs.num_configs = nconfigs; + nmaps += 1; + } + if (funcname) { + pgnames[npins++] = thp->desc.pins[i].name; + map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + map[nmaps].data.mux.function = funcname; + map[nmaps].data.mux.group = thp->desc.pins[i].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.pins[gsel].drv_data & TH1520_PAD_MUXDATA; + uintptr_t muxtype = (uintptr_t)func->data; + unsigned int pin = thp->desc.pins[gsel].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_string[muxtype], thp->desc.pins[gsel].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_mA[16] = { + 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_mA[ds]) + 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_mA[value & 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.pins[gsel].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(configs[i]); + u32 arg = pinconf_to_config_argument(configs[i]); + + 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.pins[gsel].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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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->functions[selector].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->groups[group].cur_func_idx = data->functions[selector].mode; + for (p = 0; p < data->groups[group].num_pins; p++) { + pidx = data->groups[group].pins[p]; + 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->functions[selector].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->groups[group].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->functions[selector].groups; + *num_groups = data->functions[selector].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->groups[selector].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->groups[selector].pins; + *num_pins = data->groups[selector].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->functions[p].name, + strlen(attr->attr.name))) { + selector = p; + break; + } + } + if (selector < 0) + return -ENXIO; + + group = selector/2; + ret = snprintf(buf, 128, "%d\n", data->groups[group].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->functions[p].name, + strlen(attr->attr.name)) && + (user_data == data->functions[p].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->functions[selector].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 +#include +#include +#include +#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 name[16]; + const char name_a[16]; + const char name_r[16]; + 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 , + * Copyright (c) 2013 Tomasz Figa + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_AUTHOR("Jisheng Zhang "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 reserved[6]; +} __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 reserved[6]; + +} __packed __aligned(4); + +struct rpc_msg_regu_pwr_set { + u16 regu_id; ///< virtual regu id + u16 status; ///< 0: power off; 1: powr on + u32 reserved[5]; +} __packed __aligned(4); + +struct rpc_msg_regu_pwr_get { + u16 regu_id; ///< virtual regu id + u16 status; ///< 0: power off; 1: powr on + u32 reserved[5]; + +} __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,%d]minuV = %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,%d]voltage = %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_volts[i].vdd) && + (vddm == apcpu_volts[i].vddm)) + return &apcpu_volts[i]; + +#ifdef CONFIG_AON_REG_DEBUG + return &apcpu_volts[2]; +#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_volts[i].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; + buf[bufpos++] = '\n'; + i++; + snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i); + bufpos += 4; + snprintf(buf + bufpos, count - bufpos, "%u", dc2); + bufpos += 8; + buf[bufpos++] = '\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_volts[2]; /* 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_desc[i]; + 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 "); +MODULE_AUTHOR("linghui.zlh "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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"); +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 +#include +#include +#include +#include +#include + +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->signals[id]; + + 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->signals[id].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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, ivdev[id]) + +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->vq[mu_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->vring[index], + // RPMSG_RING_SIZE); + rpvq->addr = (__force void *) ioremap(virdev->vring[index], + 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->vring[index], + 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->vq[index] = 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) { + vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i], + ctx ? ctx[i] : false); + if (IS_ERR(vqs[i])) { + err = PTR_ERR(vqs[i]); + 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->ivdev[i].vring[0] = start; + rpdev->ivdev[i].vring[1] = 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_vprocs[core_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->ivdev[j].vring[0], + rpdev->ivdev[j].vring[1]); + rpdev->ivdev[j].vdev.id.device = VIRTIO_ID_RPMSG; + rpdev->ivdev[j].vdev.config = &light_rpmsg_config_ops; + rpdev->ivdev[j].vdev.dev.parent = &pdev->dev; + rpdev->ivdev[j].vdev.dev.release = light_rpmsg_vproc_release; + rpdev->ivdev[j].base_vq_id = j * 2; + + ret = register_virtio_device(&rpdev->ivdev[j].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_ctrl[4] = {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_get[3] = {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->ivdev[0].vq[0], LIGHT_PM_OFF); + try_num++; + down_timeout(&rpdev->pm_sem, msecs_to_jiffies(200)); + while(!rpdev->sleep_flag) { + light_rpmsg_sleep_notify(rpdev->ivdev[0].vq[0], 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->ivdev[0].vq[0]); + 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_names[index_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(data[0] == RPMSG_MAILBOX_TYPE_PM && data[1] == RPMSG_PM_STATUS) { + if(data[2] == LIGHT_PM_WAKEUP) { + pri_rpdev->sleep_flag = 0; + up(&pri_rpdev->pm_sem); + printk("audio wakeup"); + } else if(data[2] == 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/rtc/Kconfig b/drivers/rtc/Kconfig index 6f270577df86..f5e30f724f74 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1992,4 +1992,10 @@ config RTC_DRV_POLARFIRE_SOC This driver can also be built as a module, if so, the module will be called "rtc-mpfs". +config RTC_DRV_ASTBMC + tristate "SG2042 server get rtc time from bmc via pci bus" + help + This driver can also be built as a module, if so, the module + will be called "rtc-astbmc". + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 7711f79787ac..441b27e2d8fd 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -189,3 +189,4 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o +obj-$(CONFIG_RTC_DRV_ASTBMC) += rtc-astbmc.o diff --git a/drivers/rtc/rtc-astbmc.c b/drivers/rtc/rtc-astbmc.c new file mode 100644 index 000000000000..8b56090cf0f8 --- /dev/null +++ b/drivers/rtc/rtc-astbmc.c @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* rtc-astbmc.c + * + * Driver for Dallas Semiconductor astbmcrtc Low Current, PCI Compatible + * Real Time Clock + * + * Author : Raghavendra Chandra Ganiga + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers in astbmcrtc rtc */ + +#define ASPEED_PCI_BMC_HOST2BMC_Q1 0x30000 +#define ASPEED_PCI_BMC_HOST2BMC_Q2 0x30010 +#define ASPEED_PCI_BMC_BMC2HOST_Q1 0x30020 +#define ASPEED_PCI_BMC_BMC2HOST_Q2 0x30030 +#define ASPEED_PCI_BMC_BMC2HOST_STS 0x30040 +#define BMC2HOST_INT_STS_DOORBELL BIT(31) +#define BMC2HOST_ENABLE_INTB BIT(30) +/* */ +#define BMC2HOST_Q1_FULL BIT(27) +#define BMC2HOST_Q1_EMPTY BIT(26) +#define BMC2HOST_Q2_FULL BIT(25) +#define BMC2HOST_Q2_EMPTY BIT(24) +#define BMC2HOST_Q1_FULL_UNMASK BIT(23) +#define BMC2HOST_Q1_EMPTY_UNMASK BIT(22) +#define BMC2HOST_Q2_FULL_UNMASK BIT(21) +#define BMC2HOST_Q2_EMPTY_UNMASK BIT(20) + +#define ASPEED_PCI_BMC_HOST2BMC_STS 0x30044 +#define HOST2BMC_INT_STS_DOORBELL BIT(31) +#define HOST2BMC_ENABLE_INTB BIT(30) +/* */ +#define HOST2BMC_Q1_FULL BIT(27) +#define HOST2BMC_Q1_EMPTY BIT(26) +#define HOST2BMC_Q2_FULL BIT(25) +#define HOST2BMC_Q2_EMPTY BIT(24) +#define HOST2BMC_Q1_FULL_UNMASK BIT(23) +#define HOST2BMC_Q1_EMPTY_UNMASK BIT(22) +#define HOST2BMC_Q2_FULL_UNMASK BIT(21) +#define HOST2BMC_Q2_EMPTY_UNMASK BIT(20) + +struct aspeed_pci_bmc_dev { + struct device *dev; + struct miscdevice miscdev; + + unsigned long mem_bar_base; + unsigned long mem_bar_size; + void __iomem *mem_bar_reg; + + unsigned long message_bar_base; + unsigned long message_bar_size; + void __iomem *msg_bar_reg; + + struct bin_attribute bin0; + struct bin_attribute bin1; + + struct kernfs_node *kn0; + struct kernfs_node *kn1; + + /* Queue waiters for idle engine */ + wait_queue_head_t tx_wait0; + wait_queue_head_t tx_wait1; + wait_queue_head_t rx_wait0; + wait_queue_head_t rx_wait1; + + void __iomem *sio_mbox_reg; + int sio_mbox_irq; + + u8 IntLine; + int legency_irq; +}; + +#define HOST_BMC_QUEUE_SIZE (16 * 4) +#define PCIE_DEVICE_SIO_ADDR (0x2E * 4) +#define BMC_MULTI_MSI 32 + +#define DRIVER_NAME "ASPEED BMC DEVICE" + +static struct rtc_device *rtc; +static int time64_flag = 1; +module_param(time64_flag, int, 0644); + +static struct aspeed_pci_bmc_dev *file_aspeed_bmc_device(struct file *file) +{ + return container_of(file->private_data, struct aspeed_pci_bmc_dev, + miscdev); +} + +static int aspeed_pci_bmc_dev_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct aspeed_pci_bmc_dev *pci_bmc_dev = file_aspeed_bmc_device(file); + unsigned long vsize = vma->vm_end - vma->vm_start; + pgprot_t prot = vma->vm_page_prot; + + if (vma->vm_pgoff + vsize > pci_bmc_dev->mem_bar_base + 0x100000) + return -EINVAL; + + prot = pgprot_noncached(prot); + + if (remap_pfn_range(vma, vma->vm_start, + (pci_bmc_dev->mem_bar_base >> PAGE_SHIFT) + vma->vm_pgoff, + vsize, prot)) + return -EAGAIN; + + return 0; +} + +static const struct file_operations aspeed_pci_bmc_dev_fops = { + .owner = THIS_MODULE, + .mmap = aspeed_pci_bmc_dev_mmap, +}; + + +static irqreturn_t aspeed_pci_host_bmc_device_interrupt(int irq, void *dev_id) +{ + struct aspeed_pci_bmc_dev *pci_bmc_device = dev_id; + u32 bmc2host_q_sts = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS); + + if (bmc2host_q_sts & BMC2HOST_INT_STS_DOORBELL) + writel(BMC2HOST_INT_STS_DOORBELL, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS); + + if (bmc2host_q_sts & BMC2HOST_ENABLE_INTB) + writel(BMC2HOST_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS); + + if (bmc2host_q_sts & BMC2HOST_Q1_FULL) + dev_info(pci_bmc_device->dev, "Q1 Full\n"); + + if (bmc2host_q_sts & BMC2HOST_Q2_FULL) + dev_info(pci_bmc_device->dev, "Q2 Full\n"); + + + //check q1 + if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q1_FULL)) + wake_up_interruptible(&pci_bmc_device->tx_wait0); + + if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) + wake_up_interruptible(&pci_bmc_device->rx_wait0); + //chech q2 + if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL)) + wake_up_interruptible(&pci_bmc_device->tx_wait1); + + if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q2_EMPTY)) + wake_up_interruptible(&pci_bmc_device->rx_wait1); + + return IRQ_HANDLED; + +} + + +static int clear_r_queue1(struct device *dev, int timeout) +{ + u32 value; + unsigned long tick_end = jiffies + timeout * HZ; + struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev); + while (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) { + value = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1); + writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS); + + if (time_after(jiffies, tick_end)) { + return 0; + } + } + return 1; +} + + + +static ssize_t read_8bytes_from_queue1(struct device *dev, time64_t * time_stamp, int timeout) +{ + int i = 0; + u32 * time_buf = (u32*)time_stamp; + struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev); + unsigned long tick_end = jiffies + timeout * HZ; + + while (i < 2) { + if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)) { + time_buf[i++] = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1); + writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS); + } + + if (time_after(jiffies, tick_end)) { + return 0; + } + } + return sizeof(time64_t); +} + +static ssize_t read_queue1(struct device *dev, u32 * data) +{ + struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev); + int ret; + + ret = wait_event_interruptible(pci_bmc_device->rx_wait0, + !(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q1_EMPTY)); + if (ret) + return -EINTR; + + * data = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q1); + writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS); + return sizeof(u32); +} +static ssize_t write_queue1(struct device *dev, u32 data) +{ + struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev); + int ret; + + ret = wait_event_interruptible(pci_bmc_device->tx_wait0, + !(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q1_FULL)); + if (ret) + return -EINTR; + + writel(data, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q1); + //trigger to host + writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS); + + return sizeof(u32); +} + +static ssize_t read_queue2(struct device *dev, u32 * timestamp) +{ + struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev); + int ret; + + ret = wait_event_interruptible(pci_bmc_device->rx_wait1, + !(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_STS) & BMC2HOST_Q2_EMPTY)); + if (ret) + return -EINTR; + + * timestamp = readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_BMC2HOST_Q2); + writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS); + return sizeof(u32); +} +static ssize_t write_queue2(struct device *dev, u32 data) +{ + struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev); + int ret; + + ret = wait_event_interruptible(pci_bmc_device->tx_wait1, + !(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL)); + if (ret) + return -EINTR; + + writel(data, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q2); + //trigger to host + writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS); + + + return sizeof(u32); +} + +static ssize_t write_8bytes_to_queue2(struct device *dev, time64_t * time_stamp) +{ + int i = 0; + u32 * time_buf = (u32*)time_stamp; + struct aspeed_pci_bmc_dev *pci_bmc_device = dev_get_drvdata(dev); + + while (i < 2) { + if (!(readl(pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS) & HOST2BMC_Q2_FULL)) { + writel(time_buf[i++], pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_Q2); + writel(HOST2BMC_INT_STS_DOORBELL | HOST2BMC_ENABLE_INTB, pci_bmc_device->msg_bar_reg + ASPEED_PCI_BMC_HOST2BMC_STS); + + } + } + return sizeof(time64_t); +} + + + +static int astbmc_read_time(struct device *dev, struct rtc_time *dt) +{ + time64_t time_stamp = 0; + u32 tx_cmd = 0x55555555; + + clear_r_queue1(dev, 5); + + write_queue1(dev, tx_cmd); + + read_8bytes_from_queue1(dev, &time_stamp, 5); + + rtc_time64_to_tm(time_stamp, dt); + + return 0; +} + +static int astbmc_set_time(struct device *dev, struct rtc_time *dt) +{ + time64_t time_stamp = 0; + u32 tx_cmd = 0xaaaaaaaa; + + write_queue2(dev, tx_cmd); + + time_stamp = rtc_tm_to_time64(dt); + + write_8bytes_to_queue2(dev, &time_stamp); + + return 0; +} + +static const struct rtc_class_ops astbmc_rtc_ops = { + .read_time = astbmc_read_time, + .set_time = astbmc_set_time, +}; + + +//0-unenabled 1-enabled +static int is_bmc_rtc_device_func_enable(struct device *dev) +{ + time64_t time_stamp = 0; + u32 tx_cmd = 0x55555555; + + clear_r_queue1(dev, 5); + + write_queue1(dev, tx_cmd); + + if (read_8bytes_from_queue1(dev, &time_stamp, 5) == 0) { + pr_info("BMC has not enabled rtc device func!\n"); + return 0; + } + + pr_info("BMC has enabled rtc device func!\n"); + return 1; + +} + + +#define BMC_MSI_IDX_BASE 0 +static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct aspeed_pci_bmc_dev *pci_bmc_dev; + struct device *dev = &pdev->dev; + u16 config_cmd_val; + int nr_entries; + int rc = 0; + + pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq); + + pci_bmc_dev = kzalloc(sizeof(*pci_bmc_dev), GFP_KERNEL); + if (!pci_bmc_dev) { + rc = -ENOMEM; + dev_err(&pdev->dev, "kmalloc() returned NULL memory.\n"); + goto out_err; + } + + rc = pci_enable_device(pdev); + if (rc != 0) { + dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc); + goto out_err; + } + + /* set PCI host mastering */ + pci_set_master(pdev); + + nr_entries = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + if (nr_entries < 0) { + pci_bmc_dev->legency_irq = 1; + pci_read_config_word(pdev, PCI_COMMAND, &config_cmd_val); + config_cmd_val &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word((struct pci_dev *)pdev, PCI_COMMAND, config_cmd_val); + + } else { + pci_bmc_dev->legency_irq = 0; + pci_read_config_word(pdev, PCI_COMMAND, &config_cmd_val); + config_cmd_val |= PCI_COMMAND_INTX_DISABLE; + pci_write_config_word((struct pci_dev *)pdev, PCI_COMMAND, config_cmd_val); + pdev->irq = pci_irq_vector(pdev, BMC_MSI_IDX_BASE); + } + + pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq); + + init_waitqueue_head(&pci_bmc_dev->tx_wait0); + init_waitqueue_head(&pci_bmc_dev->tx_wait1); + init_waitqueue_head(&pci_bmc_dev->rx_wait0); + init_waitqueue_head(&pci_bmc_dev->rx_wait1); + + //Get MEM bar + pci_bmc_dev->mem_bar_base = pci_resource_start(pdev, 0); + pci_bmc_dev->mem_bar_size = pci_resource_len(pdev, 0); + + pr_info("BAR0 I/O Mapped Base Address is: %08lx End %08lx\n", pci_bmc_dev->mem_bar_base, pci_bmc_dev->mem_bar_size); + + pci_bmc_dev->mem_bar_reg = pci_ioremap_bar(pdev, 0); + if (!pci_bmc_dev->mem_bar_reg) { + rc = -ENOMEM; + goto out_free0; + } + + //Get MSG BAR info + pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1); + pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1); + + pr_info("MSG BAR1 Memory Mapped Base Address is: %08lx End %08lx\n", pci_bmc_dev->message_bar_base, pci_bmc_dev->message_bar_size); + + pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1); + if (!pci_bmc_dev->msg_bar_reg) { + rc = -ENOMEM; + goto out_free1; + } + + /* ERRTA40: dummy read */ + (void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg); + + + pci_bmc_dev->miscdev.minor = MISC_DYNAMIC_MINOR; + pci_bmc_dev->miscdev.name = DRIVER_NAME; + pci_bmc_dev->miscdev.fops = &aspeed_pci_bmc_dev_fops; + pci_bmc_dev->miscdev.parent = dev; + + rc = misc_register(&pci_bmc_dev->miscdev); + if (rc) { + pr_err("host bmc register fail %d\n", rc); + goto out_free; + } + + pci_set_drvdata(pdev, pci_bmc_dev); + + rc = request_irq(pdev->irq, aspeed_pci_host_bmc_device_interrupt, IRQF_SHARED, "ASPEED BMC DEVICE", pci_bmc_dev); + if (rc) { + pr_err("host bmc device Unable to get IRQ %d\n", rc); + goto out_unreg; + } + + return 0; + + if (!is_bmc_rtc_device_func_enable(dev)) + return 0; + + //register rtc device + rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + rtc->ops = &astbmc_rtc_ops; + rtc->range_min = RTC_TIMESTAMP_BEGIN_0000; + rtc->range_max = RTC_TIMESTAMP_END_9999; + + devm_rtc_register_device(rtc); + + return 0; + +out_unreg: + misc_deregister(&pci_bmc_dev->miscdev); +out_free1: + pci_release_region(pdev, 1); +out_free0: + pci_release_region(pdev, 0); +out_free: + kfree(pci_bmc_dev); +out_err: + pci_disable_device(pdev); + + return rc; + +} + + + +static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev) +{ + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev); + + free_irq(pdev->irq, pdev); + misc_deregister(&pci_bmc_dev->miscdev); + pci_release_regions(pdev); + kfree(pci_bmc_dev); + pci_disable_device(pdev); +} + +/** + * This table holds the list of (VendorID,DeviceID) supported by this driver + * + */ +static struct pci_device_id aspeed_host_bmc_dev_pci_ids[] = { + { PCI_DEVICE(0x1A03, 0x2402), }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids); + +static struct pci_driver aspeed_host_bmc_dev_driver = { + .name = DRIVER_NAME, + .id_table = aspeed_host_bmc_dev_pci_ids, + .probe = aspeed_pci_host_bmc_device_probe, + .remove = aspeed_pci_host_bmc_device_remove, +}; + +static int __init aspeed_host_bmc_device_init(void) +{ + int ret; + + /* register pci driver */ + ret = pci_register_driver(&aspeed_host_bmc_dev_driver); + if (ret < 0) { + pr_err("pci-driver: can't register pci driver\n"); + return ret; + } + + return 0; + +} + +static void aspeed_host_bmc_device_exit(void) +{ + /* unregister pci driver */ + pci_unregister_driver(&aspeed_host_bmc_dev_driver); +} + +// late_initcall(aspeed_host_bmc_device_init); +module_init(aspeed_host_bmc_device_init); +module_exit(aspeed_host_bmc_device_exit); + +MODULE_AUTHOR("Ryan Chen "); +MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver"); +MODULE_LICENSE("GPL"); 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..f19f053b5404 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -29,9 +29,11 @@ obj-y += renesas/ obj-y += rockchip/ obj-$(CONFIG_SOC_SAMSUNG) += samsung/ obj-y += sifive/ +obj-$(CONFIG_ARCH_SOPHGO) += sophgo/ obj-y += sunxi/ 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 buf[64]; + + 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_name[32]; + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_hwirqs[MAX_IRQ_NUMBER]; + int plic_irqs[MAX_IRQ_NUMBER]; + struct irq_data *plic_irq_datas[MAX_IRQ_NUMBER]; + int tic_to_plic[MAX_IRQ_NUMBER]; // mapping from tic hwirq to plic hwirq +}; + +// workaround for using in other modules +struct top_intc_data *tic_data[TOP_INTC_NUM]; + +struct irq_domain *cdns_pcie_get_parent_irq_domain(int intc_id) +{ + if (intc_id >= TOP_INTC_NUM) + return NULL; + + if (tic_data[intc_id]) + return tic_data[intc_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->param[1] >= data->irq_num) + return -EINVAL; + + *hwirq = fwspec->param[0]; + *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + pr_debug("%s hwirq %d, flag %d\n", __func__, fwspec->param[0], fwspec->param[1]); + 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_plic[hwirq + i] = data->plic_hwirqs[hwirq + 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_plic[hwirq] = data->plic_hwirqs[hwirq]; + } + + pr_debug("%s hwirq %ld, irq %d, plic irq %d, total %d\n", __func__, + hwirq, virq, data->plic_irqs[hwirq], 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_datas[d->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_datas[d->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_datas[d->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_datas[d->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_plic[i] == 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_hwirqs[0]), 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 name[8]; + int irq; + + snprintf(name, ARRAY_SIZE(name), "msi%d", i); + irq = platform_get_irq_byname(pdev, name); + if (irq < 0) + break; + + data->plic_irqs[i] = irq; + data->plic_irq_datas[i] = irq_get_irq_data(irq); + data->plic_hwirqs[i] = data->plic_irq_datas[i]->hwirq; + dev_dbg(&pdev->dev, "%s: plic hwirq %ld, plic irq %d\n", name, + data->plic_hwirqs[i], data->plic_irqs[i]); + } + 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_irqs[i], + top_intc_irq_handler, data); + + if (data->for_msi) { + irq_domain_update_bus_token(data->domain, DOMAIN_BUS_NEXUS); + if (tic_data[intc_id]) + dev_err(&pdev->dev, "tic_data is not empty, %s\n", + dev_name(&tic_data[intc_id]->pdev->dev)); + tic_data[intc_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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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_table[16]; +}; + +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_config[4]; + struct hwmon_channel_info temp_info; + const struct hwmon_channel_info *channel_info[3]; + 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_list[MCU_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_list[i]) == 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 token[16]; + 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); + token[tokenlen] = 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) +{ + buf[0] = 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 ip[4]; + 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", + ip[0], ip[1], ip[2], ip[3]); +} + +static ssize_t brdip_store(struct device *dev, struct device_attribute *attr, + const char *ubuf, size_t len) +{ + u8 ip[4]; + char buf[32]; + 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; + ip[i] = (u8)res; + dev_dbg(dev, "ip[%d] = %d\n", i, ip[i]); + 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 t[2]; + 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", t[0] | (t[1] << 8)); +} + +ssize_t temp_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + s8 t[2]; + 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", t[0]); + return mcu_msg_append(buf, PAGE_SIZE, + "Board temperature: %d Cel\n", t[1]); +} + + +static const char *alert_id2name(const struct mcu_features *features, int id) +{ + if (features->alert_table[id]) + return features->alert_table[id]; + return "Unknown alert"; +} + +ssize_t alert_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int cnt = 0; + int i, err; + u8 t[4]; + 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 = t[0] | (t[1] << 8); + mask = t[2] | (t[3] << 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_table[i] == 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 buf[32]; + u8 t[2]; + 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); + + buf[len] = 0; // zero terminated + err = kstrtoul(buf, 0, &res); + if (err) + return err; + if (res > 0xffff) + return -EINVAL; + + t[0] = res & 0xff; + t[1] = (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 = code[res]; *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 t[2]; + 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)t[0]) | (t[1] << 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_info[0] = HWMON_CHANNEL_INFO(chip, + HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL); + ctx->channel_info[1] = &ctx->temp_info; + + info = &ctx->temp_info; + info->type = hwmon_temp; + info->config = ctx->channel_config; + + ctx->channel_config[0] = HWMON_T_INPUT; + ctx->channel_config[1] = 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 regs[3]; + + /* 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", + regs[0], regs[1], regs[2]); + + 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_list[i].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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 reserved[5]; +} __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 + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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_SYS[COMMONONN] + * 2. set DWC3_GCTL[SOFITPSYNC](done by core.c) + * 3. set GUSB3PIPECTL[SUSPENDEN] (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 "); 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_timeout[LIGHT_TWDSCALE_MIN] +#define LIGHT_WDT_MAX_TIMEOUT wdt_timeout[LIGHT_TWDSCALE_MAX] +#define LIGHT_WDT_TIMEOUT wdt_timeout[3] +#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 reserved[4]; +}_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_timeout[i] >= 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_timeout[light_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,%d]poweroff 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 "); +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 + +/*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 +#include + +#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 +#include +#include +#include +#include +#include + +/* 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 vring[2]; + struct virtqueue *vq[2]; + 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 ivdev[MAX_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_message[MAX_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 reserved[5]; +} __attribute__ ((packed)); + +#endif /* __LINUX_LIGHT_RPMSG_H__*/ + diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index b7246b7171b7..52de73abd9fc 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -51,7 +51,7 @@ atomic_t __kexec_lock = ATOMIC_INIT(0); /* Flag to indicate we are going to kexec a new kernel */ bool kexec_in_progress = false; - +EXPORT_SYMBOL(kexec_in_progress); /* Location of the reserved area for the crash kernel */ struct resource crashk_res = { diff --git a/kernel/panic.c b/kernel/panic.c index ef9f9a4e928d..0506d3ceb06c 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -37,6 +37,7 @@ #include #include #include +#include #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/kernel/sched/fair.c b/kernel/sched/fair.c index 84af50f4285f..e3bbd67beee6 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -10496,6 +10496,9 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env) if (kthread_is_per_cpu(p)) return 0; + if (is_migration_disabled(p)) + return 0; + #ifdef CONFIG_QOS_SCHED_DYNAMIC_AFFINITY set_task_select_cpus(p, NULL, 0); if (!cpumask_test_cpu(env->dst_cpu, p->select_cpus)) { diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index 5e2c2c26b3cc..368c8fc21b1f 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c @@ -78,7 +78,7 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) || !tick_device_is_functional(dev)) { - pr_info("Clockevents: could not switch to one-shot mode:"); + pr_debug("Clockevents: could not switch to one-shot mode:"); if (!dev) { pr_cont(" no tick device\n"); } else { diff --git a/mm/memblock.c b/mm/memblock.c index b46bcb931a2e..285bc9757ec7 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1780,6 +1780,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; @@ -1789,16 +1790,37 @@ 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; } +#ifdef CONFIG_HIGHMEM +phys_addr_t __init_memblock find_max_low_addr(phys_addr_t limit) +{ + phys_addr_t max_low_addr = PHYS_ADDR_MAX; + phys_addr_t max_low_addr_limit; + struct memblock_region *r; + + max_low_addr_limit = memblock_start_of_DRAM() + limit; + + for_each_mem_region(r) { + if ((r->base+r->size) <= max_low_addr_limit) + max_low_addr = r->base + r->size; + else if (r->base < max_low_addr_limit) + max_low_addr = max_low_addr_limit; + else + continue; + } + + return max_low_addr; +} +#endif + void __init memblock_enforce_memory_limit(phys_addr_t limit) { phys_addr_t 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 ef6d06fe0f5b..a6863ba97d00 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/lib/perf/cpumap.c b/tools/lib/perf/cpumap.c index 2a5a29217374..b53c22b909b8 100644 --- a/tools/lib/perf/cpumap.c +++ b/tools/lib/perf/cpumap.c @@ -405,8 +405,8 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig, struct perf_cpu_map *other) { struct perf_cpu *tmp_cpus; - int tmp_len; - int i, j, k; + unsigned int tmp_len; + unsigned int i, j, k; struct perf_cpu_map *merged; if (perf_cpu_map__is_subset(orig, other)) @@ -423,7 +423,7 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig, /* Standard merge algorithm from wikipedia */ i = j = k = 0; - while (i < __perf_cpu_map__nr(orig) && j < __perf_cpu_map__nr(other)) { + while (i < (unsigned int)(__perf_cpu_map__nr(orig)) && j < (unsigned int)(__perf_cpu_map__nr(other))) { if (__perf_cpu_map__cpu(orig, i).cpu <= __perf_cpu_map__cpu(other, j).cpu) { if (__perf_cpu_map__cpu(orig, i).cpu == __perf_cpu_map__cpu(other, j).cpu) j++; @@ -432,10 +432,10 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig, tmp_cpus[k++] = __perf_cpu_map__cpu(other, j++); } - while (i < __perf_cpu_map__nr(orig)) + while (i < (unsigned int)(__perf_cpu_map__nr(orig))) tmp_cpus[k++] = __perf_cpu_map__cpu(orig, i++); - while (j < __perf_cpu_map__nr(other)) + while (j < (unsigned int)(__perf_cpu_map__nr(other))) tmp_cpus[k++] = __perf_cpu_map__cpu(other, j++); assert(k <= tmp_len); 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