Rebase riscv-kernel patch to 6.6.0-28.0.0, and fixed a merge conflicts from
the commit f1e873348141 ("LoongArch: limit min pci msi-x/msi vector number
when request more than 32 vectors")
Signed-off-by: Mingzheng Xing <xingmingzheng@iscas.ac.cn>
33860 lines
1021 KiB
Diff
33860 lines
1021 KiB
Diff
From d3f6927f8d76cb4aec288772970b3380b852aa37 Mon Sep 17 00:00:00 2001
|
|
From: Mingzheng Xing <xingmingzheng@iscas.ac.cn>
|
|
Date: Sun, 26 May 2024 19:38:18 +0800
|
|
Subject: [PATCH] riscv kernel
|
|
|
|
Signed-off-by: Mingzheng Xing <xingmingzheng@iscas.ac.cn>
|
|
---
|
|
.../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 | 177 ++-
|
|
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, 29954 insertions(+), 501 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 <jszhang@kernel.org>
|
|
+
|
|
+select:
|
|
+ properties:
|
|
+ compatible:
|
|
+ contains:
|
|
+ enum:
|
|
+ - thead,th1520-dwmac
|
|
+ required:
|
|
+ - compatible
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ items:
|
|
+ - enum:
|
|
+ - thead,th1520-dwmac
|
|
+ - const: snps,dwmac-3.70a
|
|
+
|
|
+ reg:
|
|
+ maxItems: 1
|
|
+
|
|
+ thead,gmacapb:
|
|
+ $ref: /schemas/types.yaml#/definitions/phandle
|
|
+ description:
|
|
+ The phandle to the syscon node that control ethernet
|
|
+ interface and timing delay.
|
|
+
|
|
+required:
|
|
+ - compatible
|
|
+ - reg
|
|
+ - clocks
|
|
+ - clock-names
|
|
+ - interrupts
|
|
+ - interrupt-names
|
|
+ - phy-mode
|
|
+ - thead,gmacapb
|
|
+
|
|
+allOf:
|
|
+ - $ref: snps,dwmac.yaml#
|
|
+
|
|
+unevaluatedProperties: false
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+ gmac0: ethernet@e7070000 {
|
|
+ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a";
|
|
+ reg = <0xe7070000 0x2000>;
|
|
+ clocks = <&clk 1>, <&clk 2>;
|
|
+ clock-names = "stmmaceth", "pclk";
|
|
+ interrupts = <66>;
|
|
+ interrupt-names = "macirq";
|
|
+ phy-mode = "rgmii-id";
|
|
+ snps,fixed-burst;
|
|
+ snps,axi-config = <&stmmac_axi_setup>;
|
|
+ snps,pbl = <32>;
|
|
+ thead,gmacapb = <&gmacapb_syscon>;
|
|
+ phy-handle = <&phy0>;
|
|
+
|
|
+ mdio {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "snps,dwmac-mdio";
|
|
+
|
|
+ phy0: ethernet-phy@0 {
|
|
+ reg = <0>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
diff --git a/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml
|
|
new file mode 100644
|
|
index 000000000000..b80d0f7b4697
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml
|
|
@@ -0,0 +1,372 @@
|
|
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
+%YAML 1.2
|
|
+---
|
|
+$id: http://devicetree.org/schemas/pinctrl/thead,th1520-pinctrl.yaml#
|
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
+
|
|
+title: T-Head TH1520 SoC pin controller
|
|
+
|
|
+maintainers:
|
|
+ - Emil Renner Berthing <emil.renner.berthing@canonical.com>
|
|
+
|
|
+description: |
|
|
+ Pinmux and pinconf controller in the T-Head TH1520 RISC-V SoC.
|
|
+
|
|
+ The TH1520 has 3 groups of pads each controlled from different memory ranges.
|
|
+ Confusingly the memory ranges are named
|
|
+ PADCTRL_AOSYS -> PAD Group 1
|
|
+ PADCTRL1_APSYS -> PAD Group 2
|
|
+ PADCTRL0_APSYS -> PAD Group 3
|
|
+
|
|
+ Each pad can be muxed individually to up to 6 different functions. For most
|
|
+ pads only a few of those 6 configurations are valid though, and a few pads in
|
|
+ group 1 does not support muxing at all.
|
|
+
|
|
+ Pinconf is fairly regular except for a few pads in group 1 that either can't
|
|
+ be configured or has some special functions. The rest have configurable drive
|
|
+ strength, input enable, schmitt trigger, slew rate, pull-up and pull-down in
|
|
+ addition to a special strong pull up.
|
|
+
|
|
+ Certain pads in group 1 can be muxed to AUDIO_PA0 - AUDIO_PA30 functions and
|
|
+ are then meant to be used by the audio co-processor. Each such pad can then
|
|
+ be further muxed to either audio GPIO or one of 4 functions such as UART, I2C
|
|
+ and I2S. If the audio pad is muxed to one of the 4 functions then pinconf is
|
|
+ also configured in different registers. All of this is done from a different
|
|
+ AUDIO_IOCTRL memory range and is left to the audio co-processor for now.
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ enum:
|
|
+ - thead,th1520-group1-pinctrl
|
|
+ - thead,th1520-group2-pinctrl
|
|
+ - thead,th1520-group3-pinctrl
|
|
+
|
|
+ reg:
|
|
+ maxItems: 1
|
|
+
|
|
+ clocks:
|
|
+ maxItems: 1
|
|
+
|
|
+patternProperties:
|
|
+ '-[0-9]+$':
|
|
+ type: object
|
|
+
|
|
+ additionalProperties: false
|
|
+
|
|
+ patternProperties:
|
|
+ '-pins$':
|
|
+ type: object
|
|
+ $ref: /schemas/pinctrl/pincfg-node.yaml
|
|
+
|
|
+ additionalProperties: false
|
|
+
|
|
+ description:
|
|
+ A pinctrl node should contain at least one subnode describing one
|
|
+ or more pads and their associated pinmux and pinconf settings.
|
|
+
|
|
+ properties:
|
|
+ pins:
|
|
+ $ref: /schemas/pinctrl/pinmux-node.yaml#/properties/pins
|
|
+ description: List of pads that properties in the node apply to.
|
|
+
|
|
+ function:
|
|
+ $ref: /schemas/pinctrl/pinmux-node.yaml#/properties/function
|
|
+ enum: [ gpio, pwm, uart, ir, i2c, spi, qspi, sdio, audio, i2s,
|
|
+ gmac0, gmac1, dpu0, dpu1, isp, hdmi, bootsel, debug,
|
|
+ clock, jtag, iso7816, efuse, reset ]
|
|
+ description: The mux function to select for the given pins.
|
|
+
|
|
+ bias-disable: true
|
|
+
|
|
+ bias-pull-up:
|
|
+ oneOf:
|
|
+ - type: boolean
|
|
+ description: Enable the regular 48kOhm pull-up
|
|
+ - enum: [ 2100, 48000 ]
|
|
+ description: Enable the strong 2.1kOhm pull-up or regular 48kOhm pull-up
|
|
+
|
|
+ bias-pull-down:
|
|
+ oneOf:
|
|
+ - type: boolean
|
|
+ - const: 44000
|
|
+ description: Enable the regular 44kOhm pull-down
|
|
+
|
|
+ drive-strength:
|
|
+ description: Drive strength in mA
|
|
+ enum: [ 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25 ]
|
|
+
|
|
+ input-enable: true
|
|
+
|
|
+ input-disable: true
|
|
+
|
|
+ input-schmitt-enable: true
|
|
+
|
|
+ input-schmitt-disable: true
|
|
+
|
|
+ slew-rate:
|
|
+ maximum: 1
|
|
+
|
|
+ required:
|
|
+ - pins
|
|
+
|
|
+required:
|
|
+ - compatible
|
|
+ - reg
|
|
+ - clocks
|
|
+
|
|
+additionalProperties: false
|
|
+
|
|
+allOf:
|
|
+ - $ref: pinctrl.yaml#
|
|
+ - if:
|
|
+ properties:
|
|
+ compatible:
|
|
+ const: thead,th1520-group1-pinctrl
|
|
+ then:
|
|
+ patternProperties:
|
|
+ '-[0-9]+$':
|
|
+ patternProperties:
|
|
+ '-pins$':
|
|
+ properties:
|
|
+ pins:
|
|
+ items:
|
|
+ enum:
|
|
+ - OSC_CLK_IN
|
|
+ - OSC_CLK_OUT
|
|
+ - SYS_RST_N
|
|
+ - RTC_CLK_IN
|
|
+ - RTC_CLK_OUT
|
|
+ - TEST_MODE
|
|
+ - DEBUG_MODE
|
|
+ - POR_SEL
|
|
+ - I2C_AON_SCL
|
|
+ - I2C_AON_SDA
|
|
+ - CPU_JTG_TCLK
|
|
+ - CPU_JTG_TMS
|
|
+ - CPU_JTG_TDI
|
|
+ - CPU_JTG_TDO
|
|
+ - CPU_JTG_TRST
|
|
+ - AOGPIO_7
|
|
+ - AOGPIO_8
|
|
+ - AOGPIO_9
|
|
+ - AOGPIO_10
|
|
+ - AOGPIO_11
|
|
+ - AOGPIO_12
|
|
+ - AOGPIO_13
|
|
+ - AOGPIO_14
|
|
+ - AOGPIO_15
|
|
+ - AUDIO_PA0
|
|
+ - AUDIO_PA1
|
|
+ - AUDIO_PA2
|
|
+ - AUDIO_PA3
|
|
+ - AUDIO_PA4
|
|
+ - AUDIO_PA5
|
|
+ - AUDIO_PA6
|
|
+ - AUDIO_PA7
|
|
+ - AUDIO_PA8
|
|
+ - AUDIO_PA9
|
|
+ - AUDIO_PA10
|
|
+ - AUDIO_PA11
|
|
+ - AUDIO_PA12
|
|
+ - AUDIO_PA13
|
|
+ - AUDIO_PA14
|
|
+ - AUDIO_PA15
|
|
+ - AUDIO_PA16
|
|
+ - AUDIO_PA17
|
|
+ - AUDIO_PA27
|
|
+ - AUDIO_PA28
|
|
+ - AUDIO_PA29
|
|
+ - AUDIO_PA30
|
|
+ - if:
|
|
+ properties:
|
|
+ compatible:
|
|
+ const: thead,th1520-group2-pinctrl
|
|
+ then:
|
|
+ patternProperties:
|
|
+ '-[0-9]+$':
|
|
+ patternProperties:
|
|
+ '-pins$':
|
|
+ properties:
|
|
+ pins:
|
|
+ items:
|
|
+ enum:
|
|
+ - QSPI1_SCLK
|
|
+ - QSPI1_CSN0
|
|
+ - QSPI1_D0_MOSI
|
|
+ - QSPI1_D1_MISO
|
|
+ - QSPI1_D2_WP
|
|
+ - QSPI1_D3_HOLD
|
|
+ - I2C0_SCL
|
|
+ - I2C0_SDA
|
|
+ - I2C1_SCL
|
|
+ - I2C1_SDA
|
|
+ - UART1_TXD
|
|
+ - UART1_RXD
|
|
+ - UART4_TXD
|
|
+ - UART4_RXD
|
|
+ - UART4_CTSN
|
|
+ - UART4_RTSN
|
|
+ - UART3_TXD
|
|
+ - UART3_RXD
|
|
+ - GPIO0_18
|
|
+ - GPIO0_19
|
|
+ - GPIO0_20
|
|
+ - GPIO0_21
|
|
+ - GPIO0_22
|
|
+ - GPIO0_23
|
|
+ - GPIO0_24
|
|
+ - GPIO0_25
|
|
+ - GPIO0_26
|
|
+ - GPIO0_27
|
|
+ - GPIO0_28
|
|
+ - GPIO0_29
|
|
+ - GPIO0_30
|
|
+ - GPIO0_31
|
|
+ - GPIO1_0
|
|
+ - GPIO1_1
|
|
+ - GPIO1_2
|
|
+ - GPIO1_3
|
|
+ - GPIO1_4
|
|
+ - GPIO1_5
|
|
+ - GPIO1_6
|
|
+ - GPIO1_7
|
|
+ - GPIO1_8
|
|
+ - GPIO1_9
|
|
+ - GPIO1_10
|
|
+ - GPIO1_11
|
|
+ - GPIO1_12
|
|
+ - GPIO1_13
|
|
+ - GPIO1_14
|
|
+ - GPIO1_15
|
|
+ - GPIO1_16
|
|
+ - CLK_OUT_0
|
|
+ - CLK_OUT_1
|
|
+ - CLK_OUT_2
|
|
+ - CLK_OUT_3
|
|
+ - GPIO1_21
|
|
+ - GPIO1_22
|
|
+ - GPIO1_23
|
|
+ - GPIO1_24
|
|
+ - GPIO1_25
|
|
+ - GPIO1_26
|
|
+ - GPIO1_27
|
|
+ - GPIO1_28
|
|
+ - GPIO1_29
|
|
+ - GPIO1_30
|
|
+ - if:
|
|
+ properties:
|
|
+ compatible:
|
|
+ const: thead,th1520-group3-pinctrl
|
|
+ then:
|
|
+ patternProperties:
|
|
+ '-[0-9]+$':
|
|
+ patternProperties:
|
|
+ '-pins$':
|
|
+ properties:
|
|
+ pins:
|
|
+ items:
|
|
+ enum:
|
|
+ - UART0_TXD
|
|
+ - UART0_RXD
|
|
+ - QSPI0_SCLK
|
|
+ - QSPI0_CSN0
|
|
+ - QSPI0_CSN1
|
|
+ - QSPI0_D0_MOSI
|
|
+ - QSPI0_D1_MISO
|
|
+ - QSPI0_D2_WP
|
|
+ - QSPI1_D3_HOLD
|
|
+ - I2C2_SCL
|
|
+ - I2C2_SDA
|
|
+ - I2C3_SCL
|
|
+ - I2C3_SDA
|
|
+ - GPIO2_13
|
|
+ - SPI_SCLK
|
|
+ - SPI_CSN
|
|
+ - SPI_MOSI
|
|
+ - SPI_MISO
|
|
+ - GPIO2_18
|
|
+ - GPIO2_19
|
|
+ - GPIO2_20
|
|
+ - GPIO2_21
|
|
+ - GPIO2_22
|
|
+ - GPIO2_23
|
|
+ - GPIO2_24
|
|
+ - GPIO2_25
|
|
+ - SDIO0_WPRTN
|
|
+ - SDIO0_DETN
|
|
+ - SDIO1_WPRTN
|
|
+ - SDIO1_DETN
|
|
+ - GPIO2_30
|
|
+ - GPIO2_31
|
|
+ - GPIO3_0
|
|
+ - GPIO3_1
|
|
+ - GPIO3_2
|
|
+ - GPIO3_3
|
|
+ - HDMI_SCL
|
|
+ - HDMI_SDA
|
|
+ - HDMI_CEC
|
|
+ - GMAC0_TX_CLK
|
|
+ - GMAC0_RX_CLK
|
|
+ - GMAC0_TXEN
|
|
+ - GMAC0_TXD0
|
|
+ - GMAC0_TXD1
|
|
+ - GMAC0_TXD2
|
|
+ - GMAC0_TXD3
|
|
+ - GMAC0_RXDV
|
|
+ - GMAC0_RXD0
|
|
+ - GMAC0_RXD1
|
|
+ - GMAC0_RXD2
|
|
+ - GMAC0_RXD3
|
|
+ - GMAC0_MDC
|
|
+ - GMAC0_MDIO
|
|
+ - GMAC0_COL
|
|
+ - GMAC0_CRS
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+ padctrl0_apsys: pinctrl@ec007000 {
|
|
+ compatible = "thead,th1520-group3-pinctrl";
|
|
+ reg = <0xec007000 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+
|
|
+ uart0_pins: uart0-0 {
|
|
+ tx-pins {
|
|
+ pins = "UART0_TXD";
|
|
+ function = "uart";
|
|
+ bias-disable;
|
|
+ drive-strength = <3>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ rx-pins {
|
|
+ pins = "UART0_RXD";
|
|
+ function = "uart";
|
|
+ bias-disable;
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ padctrl1_apsys: pinctrl@e7f3c000 {
|
|
+ compatible = "thead,th1520-group2-pinctrl";
|
|
+ reg = <0xe7f3c000 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+
|
|
+ i2c5_pins: i2c5-0 {
|
|
+ i2c-pins {
|
|
+ pins = "QSPI1_CSN0", /* I2C5_SCL */
|
|
+ "QSPI1_D0_MOSI"; /* I2C5_SDA */
|
|
+ function = "i2c";
|
|
+ bias-pull-up = <2100>;
|
|
+ drive-strength = <7>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
diff --git a/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml
|
|
new file mode 100644
|
|
index 000000000000..e75d8e9f24c5
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml
|
|
@@ -0,0 +1,44 @@
|
|
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
+%YAML 1.2
|
|
+---
|
|
+$id: http://devicetree.org/schemas/pwm/thead,th1520-pwm.yaml#
|
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
+
|
|
+title: T-HEAD TH1520 PWM
|
|
+
|
|
+maintainers:
|
|
+ - Jisheng Zhang <jszhang@kernel.org>
|
|
+
|
|
+allOf:
|
|
+ - $ref: pwm.yaml#
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ enum:
|
|
+ - thead,th1520-pwm
|
|
+
|
|
+ reg:
|
|
+ maxItems: 1
|
|
+
|
|
+ clocks:
|
|
+ maxItems: 1
|
|
+
|
|
+ "#pwm-cells":
|
|
+ const: 3
|
|
+
|
|
+required:
|
|
+ - compatible
|
|
+ - reg
|
|
+ - clocks
|
|
+
|
|
+additionalProperties: false
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+
|
|
+ pwm@ec01c000 {
|
|
+ compatible = "thead,th1520-pwm";
|
|
+ reg = <0xec01c000 0x1000>;
|
|
+ clocks = <&clk 1>;
|
|
+ #pwm-cells = <3>;
|
|
+ };
|
|
diff --git a/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml
|
|
new file mode 100644
|
|
index 000000000000..49ea8c6a331f
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml
|
|
@@ -0,0 +1,44 @@
|
|
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
+%YAML 1.2
|
|
+---
|
|
+$id: http://devicetree.org/schemas/reset/thead,th1520-reset.yaml#
|
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
+
|
|
+title: T-HEAD th1520 SoC Reset Controller
|
|
+
|
|
+maintainers:
|
|
+ - Kwanghoon Son <k.son@samsung.com>
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ items:
|
|
+ - const: thead,th1520-reset
|
|
+ - const: syscon
|
|
+
|
|
+ reg:
|
|
+ maxItems: 1
|
|
+
|
|
+ '#reset-cells':
|
|
+ const: 1
|
|
+
|
|
+required:
|
|
+ - compatible
|
|
+ - reg
|
|
+ - '#reset-cells'
|
|
+
|
|
+additionalProperties: false
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+ #include <dt-bindings/reset/thead,th1520-reset.h>
|
|
+
|
|
+ soc {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+
|
|
+ reset-controller@ffef014000 {
|
|
+ compatible = "thead,th1520-reset", "syscon";
|
|
+ reg = <0xff 0xef014000 0x0 0x1000>;
|
|
+ #reset-cells = <1>;
|
|
+ };
|
|
+ };
|
|
diff --git a/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml b/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml
|
|
new file mode 100644
|
|
index 000000000000..afb618eb5013
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml
|
|
@@ -0,0 +1,73 @@
|
|
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
+%YAML 1.2
|
|
+---
|
|
+$id: http://devicetree.org/schemas/usb/thead,th1520-usb.yaml#
|
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
+
|
|
+title: T-HEAD TH1520 DWC3 USB Controller Glue
|
|
+
|
|
+maintainers:
|
|
+ - Jisheng Zhang <jszhang@kernel.org>
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ const: thead,th1520-usb
|
|
+
|
|
+ reg:
|
|
+ maxItems: 1
|
|
+
|
|
+ clocks:
|
|
+ maxItems: 4
|
|
+
|
|
+ clock-names:
|
|
+ items:
|
|
+ - const: ref
|
|
+ - const: bus_early
|
|
+ - const: phy
|
|
+ - const: suspend
|
|
+
|
|
+ ranges: true
|
|
+
|
|
+ '#address-cells':
|
|
+ enum: [ 1, 2 ]
|
|
+
|
|
+ '#size-cells':
|
|
+ enum: [ 1, 2 ]
|
|
+
|
|
+# Required child node:
|
|
+
|
|
+patternProperties:
|
|
+ "^usb@[0-9a-f]+$":
|
|
+ $ref: snps,dwc3.yaml#
|
|
+
|
|
+required:
|
|
+ - compatible
|
|
+ - reg
|
|
+ - clocks
|
|
+ - clock-names
|
|
+ - ranges
|
|
+
|
|
+additionalProperties: false
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+
|
|
+ usb {
|
|
+ compatible = "thead,th1520-usb";
|
|
+ reg = <0xec03f000 0x1000>;
|
|
+ clocks = <&clk 1>,
|
|
+ <&clk 2>,
|
|
+ <&clk 3>,
|
|
+ <&clk 4>;
|
|
+ clock-names = "ref", "bus_early", "phy", "suspend";
|
|
+ ranges;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+
|
|
+ usb@e7040000 {
|
|
+ compatible = "snps,dwc3";
|
|
+ reg = <0xe7040000 0x10000>;
|
|
+ interrupts = <68>;
|
|
+ dr_mode = "host";
|
|
+ };
|
|
+ };
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index 1c70622103e0..e41153dd877b 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -18529,6 +18529,8 @@ M: Fu Wei <wefu@redhat.com>
|
|
L: linux-riscv@lists.infradead.org
|
|
S: Maintained
|
|
F: arch/riscv/boot/dts/thead/
|
|
+F: drivers/pinctrl/pinctrl-th1520.c
|
|
+F: drivers/usb/dwc3/dwc3-thead.c
|
|
|
|
RNBD BLOCK DRIVERS
|
|
M: Md. Haris Iqbal <haris.iqbal@ionos.com>
|
|
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 = <RST_MAX_NUM>;
|
|
+ };
|
|
+
|
|
+ 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 = <SOC_PERIPHERAL_IRQ(320) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ ethernet1: ethernet@f040026000 {
|
|
+ compatible = "bitmain,ethernet";
|
|
+ reg = <0xf0 0x40026000 0x0 0x4000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(356) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ 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 = <SOC_PERIPHERAL_IRQ(358) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ 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 = <SOC_PERIPHERAL_IRQ(360) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ 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 = <SOC_PERIPHERAL_IRQ(332) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ 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 = <SOC_PERIPHERAL_IRQ(333) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ 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 = <MPLL_CLK>;
|
|
+ mode = <NORMAL_MODE>;
|
|
+ subctrl-syscon = <&top_misc>;
|
|
+ clocks = <&cgi>;
|
|
+ clock-output-names = "mpll_clock";
|
|
+ };
|
|
+
|
|
+ fpll: fpll {
|
|
+ compatible = "mango, pll-clock";
|
|
+ #clock-cells = <0>;
|
|
+ id = <FPLL_CLK>;
|
|
+ mode = <NORMAL_MODE>;
|
|
+ subctrl-syscon = <&top_misc>;
|
|
+ clocks = <&cgi>;
|
|
+ clock-output-names = "fpll_clock";
|
|
+ };
|
|
+
|
|
+ dpll0: dpll0 {
|
|
+ compatible = "mango, pll-clock";
|
|
+ #clock-cells = <0>;
|
|
+ id = <DPLL0_CLK>;
|
|
+ mode = <NORMAL_MODE>;
|
|
+ subctrl-syscon = <&top_misc>;
|
|
+ clocks = <&cgi>;
|
|
+ clock-output-names = "dpll0_clock";
|
|
+ };
|
|
+
|
|
+ dpll1: dpll1 {
|
|
+ compatible = "mango, pll-clock";
|
|
+ #clock-cells = <0>;
|
|
+ mode = <NORMAL_MODE>;
|
|
+ subctrl-syscon = <&top_misc>;
|
|
+ clocks = <&cgi>;
|
|
+ id = <DPLL1_CLK>;
|
|
+ clock-output-names = "dpll1_clock";
|
|
+ };
|
|
+
|
|
+ div_clk: div_clk {
|
|
+ compatible = "mango, pll-child-clock";
|
|
+ #clock-cells = <1>;
|
|
+ id = <S0_DIV_CLK_TABLE>;
|
|
+ subctrl-syscon = <&top_misc>;
|
|
+ };
|
|
+
|
|
+ mux_clk: mux_clk {
|
|
+ compatible = "mango, pll-mux-clock";
|
|
+ #clock-cells = <1>;
|
|
+ id = <S0_MUX_CLK_TABLE>;
|
|
+ subctrl-syscon = <&top_misc>;
|
|
+ };
|
|
+
|
|
+ socket0_default_rates {
|
|
+ compatible = "mango, clk-default-rates";
|
|
+ #clock-cells = <1>;
|
|
+ subctrl-syscon = <&top_misc>;
|
|
+ clocks = \
|
|
+ <&mpll>, <&fpll>,
|
|
+
|
|
+ <&div_clk DIV_CLK_FPLL_RP_CPU_NORMAL_1>,
|
|
+ <&div_clk DIV_CLK_FPLL_50M_A53>,
|
|
+ <&div_clk DIV_CLK_FPLL_TOP_RP_CMN_DIV2>,
|
|
+ <&div_clk DIV_CLK_FPLL_UART_500M>,
|
|
+ <&div_clk DIV_CLK_FPLL_AHB_LPC>,
|
|
+ <&div_clk DIV_CLK_FPLL_EFUSE>,
|
|
+ <&div_clk DIV_CLK_FPLL_TX_ETH0>,
|
|
+ <&div_clk DIV_CLK_FPLL_PTP_REF_I_ETH0>,
|
|
+ <&div_clk DIV_CLK_FPLL_REF_ETH0>,
|
|
+ <&div_clk DIV_CLK_FPLL_EMMC>,
|
|
+ <&div_clk DIV_CLK_FPLL_SD>,
|
|
+ <&div_clk DIV_CLK_FPLL_TOP_AXI0>,
|
|
+ <&div_clk DIV_CLK_FPLL_TOP_AXI_HSPERI>,
|
|
+ <&div_clk DIV_CLK_FPLL_AXI_DDR_1>,
|
|
+ <&div_clk DIV_CLK_FPLL_DIV_TIMER1>,
|
|
+ <&div_clk DIV_CLK_FPLL_DIV_TIMER2>,
|
|
+ <&div_clk DIV_CLK_FPLL_DIV_TIMER3>,
|
|
+ <&div_clk DIV_CLK_FPLL_DIV_TIMER4>,
|
|
+ <&div_clk DIV_CLK_FPLL_DIV_TIMER5>,
|
|
+ <&div_clk DIV_CLK_FPLL_DIV_TIMER6>,
|
|
+ <&div_clk DIV_CLK_FPLL_DIV_TIMER7>,
|
|
+ <&div_clk DIV_CLK_FPLL_DIV_TIMER8>,
|
|
+ <&div_clk DIV_CLK_FPLL_100K_EMMC>,
|
|
+ <&div_clk DIV_CLK_FPLL_100K_SD>,
|
|
+ <&div_clk DIV_CLK_FPLL_GPIO_DB>,
|
|
+
|
|
+ <&div_clk DIV_CLK_MPLL_RP_CPU_NORMAL_0>,
|
|
+ <&div_clk DIV_CLK_MPLL_AXI_DDR_0>;
|
|
+
|
|
+ clock-rates = \
|
|
+ <2000000000>, <1000000000>,
|
|
+
|
|
+ <2000000000>, <50000000>,
|
|
+ <1000000000>, <500000000>,
|
|
+ <200000000>, <25000000>,
|
|
+ <125000000>, <50000000>,
|
|
+ <25000000>, <100000000>,
|
|
+ <100000000>, <100000000>,
|
|
+ <250000000>, <1000000000>,
|
|
+ <50000000>, <50000000>,
|
|
+ <50000000>, <50000000>,
|
|
+ <50000000>, <50000000>,
|
|
+ <50000000>, <50000000>,
|
|
+ <100000>, <100000>, <100000>,
|
|
+
|
|
+ <2000000001>, <1000000001>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/sophgo/mango-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 = <MPLL_CLK>;
|
|
+ mode = <NORMAL_MODE>;
|
|
+ subctrl-syscon = <&top1_misc>;
|
|
+ clocks = <&cgi1>;
|
|
+ clock-output-names = "s1_mpll_clock";
|
|
+ };
|
|
+
|
|
+ fpll1: fpll1 {
|
|
+ compatible = "mango, pll-clock";
|
|
+ #clock-cells = <0>;
|
|
+ id = <FPLL_CLK>;
|
|
+ mode = <NORMAL_MODE>;
|
|
+ subctrl-syscon = <&top1_misc>;
|
|
+ clocks = <&cgi1>;
|
|
+ clock-output-names = "s1_fpll_clock";
|
|
+ };
|
|
+
|
|
+ dpll01: dpll01 {
|
|
+ compatible = "mango, pll-clock";
|
|
+ #clock-cells = <0>;
|
|
+ id = <DPLL0_CLK>;
|
|
+ mode = <NORMAL_MODE>;
|
|
+ subctrl-syscon = <&top1_misc>;
|
|
+ clocks = <&cgi1>;
|
|
+ clock-output-names = "s1_dpll0_clock";
|
|
+ };
|
|
+
|
|
+ dpll11: dpll11 {
|
|
+ compatible = "mango, pll-clock";
|
|
+ #clock-cells = <0>;
|
|
+ mode = <NORMAL_MODE>;
|
|
+ subctrl-syscon = <&top1_misc>;
|
|
+ clocks = <&cgi1>;
|
|
+ id = <DPLL1_CLK>;
|
|
+ clock-output-names = "s1_dpll1_clock";
|
|
+ };
|
|
+
|
|
+ s1_div_clk: s1_div_clk {
|
|
+ compatible = "mango, pll-child-clock";
|
|
+ #clock-cells = <1>;
|
|
+ id = <S1_DIV_CLK_TABLE>;
|
|
+ subctrl-syscon = <&top1_misc>;
|
|
+ };
|
|
+
|
|
+ s1_mux_clk: s1_mux_clk {
|
|
+ compatible = "mango, pll-mux-clock";
|
|
+ #clock-cells = <1>;
|
|
+ id = <S1_MUX_CLK_TABLE>;
|
|
+ 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 = <KEY_POWER>;
|
|
+ gpios = <&port0a 22 GPIO_ACTIVE_HIGH>;
|
|
+ linux,input-type = <1>;
|
|
+ debounce-interval = <100>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gpio-restart {
|
|
+ compatible = "gpio-keys";
|
|
+ input-name = "gpio-keys";
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&restart_key>;
|
|
+
|
|
+ restart {
|
|
+ label = "GPIO Key Restart";
|
|
+ linux,code = <KEY_RESTART>;
|
|
+ gpios = <&port0a 23 GPIO_ACTIVE_HIGH>;
|
|
+ linux,input-type = <1>;
|
|
+ debounce-interval = <100>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&tach0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&fan0_acquire>;
|
|
+};
|
|
+
|
|
+&tach1 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&fan1_acquire>;
|
|
+};
|
|
+
|
|
+/ {
|
|
+ pwmfan: pwm-fan {
|
|
+ compatible = "pwm-fan";
|
|
+ pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns
|
|
+ pwm-names = "pwm0","pwm1";
|
|
+ pwm_inuse = "pwm0";
|
|
+ #cooling-cells = <2>;
|
|
+ cooling-levels = <1 1 1 1 1>; //total 255
|
|
+ };
|
|
+
|
|
+ thermal_zones: thermal-zones {
|
|
+ soc {
|
|
+ polling-delay-passive = <1000>; /* milliseconds */
|
|
+ polling-delay = <1000>; /* milliseconds */
|
|
+ thermal-sensors = <&mcu 0>;
|
|
+
|
|
+ trips {
|
|
+ soc_pwmfan_trip1: soc_pwmfan_trip@1 {
|
|
+ temperature = <30000>; /* millicelsius */
|
|
+ hysteresis = <8000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+
|
|
+ soc_pwmfan_trip2: soc_pwmfan_trip@2 {
|
|
+ temperature = <40000>; /* millicelsius */
|
|
+ hysteresis = <12000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+
|
|
+ soc_pwmfan_trip3: soc_pwmfan_trip@3 {
|
|
+ temperature = <50000>; /* millicelsius */
|
|
+ hysteresis = <10000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+
|
|
+ soc_pwmfan_trip4: soc_pwmfan_trip@4 {
|
|
+ temperature = <60000>; /* millicelsius */
|
|
+ hysteresis = <5000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ cooling-maps {
|
|
+ map0 {
|
|
+ trip = <&soc_pwmfan_trip1>;
|
|
+ cooling-device = <&pwmfan 0 1>;
|
|
+ };
|
|
+
|
|
+ map1 {
|
|
+ trip = <&soc_pwmfan_trip2>;
|
|
+ cooling-device = <&pwmfan 1 2>;
|
|
+ };
|
|
+
|
|
+ map2 {
|
|
+ trip = <&soc_pwmfan_trip3>;
|
|
+ cooling-device = <&pwmfan 2 3>;
|
|
+ };
|
|
+
|
|
+ map3 {
|
|
+ trip = <&soc_pwmfan_trip4>;
|
|
+ cooling-device = <&pwmfan 3 4>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ board {
|
|
+ polling-delay-passive = <1000>; /* milliseconds */
|
|
+ polling-delay = <1000>; /* milliseconds */
|
|
+ thermal-sensors = <&mcu 1>;
|
|
+
|
|
+ trips {
|
|
+ board_pwmfan_trip1: board_pwmfan_trip@1 {
|
|
+ temperature = <75000>; /* millicelsius */
|
|
+ hysteresis = <8000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ cooling-maps {
|
|
+ map4 {
|
|
+ trip = <&board_pwmfan_trip1>;
|
|
+ cooling-device = <&pwmfan 3 4>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+};
|
|
+
|
|
+&chosen {
|
|
+ bootargs = "console=ttyS0,115200 console=tty1 earlycon maxcpus=1";
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi
|
|
new file mode 100644
|
|
index 000000000000..e39b3a80bf06
|
|
--- /dev/null
|
|
+++ b/arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi
|
|
@@ -0,0 +1,81 @@
|
|
+#include <dt-bindings/interrupt-controller/irq.h>
|
|
+
|
|
+#define SOC_PERIPHERAL_IRQ(nr) (nr)
|
|
+
|
|
+/ {
|
|
+ pcie@7062000000 {
|
|
+ compatible = "sophgo,cdns-pcie-host";
|
|
+ device_type = "pci";
|
|
+ #address-cells = <3>;
|
|
+ #size-cells = <2>;
|
|
+
|
|
+ bus-range = <0x00 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 = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ //interrupt-names = "msi";
|
|
+ reg = <0x70 0x62000000 0x0 0x02000000>,
|
|
+ <0x48 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 = <SOC_PERIPHERAL_IRQ(346) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ //interrupt-names = "msi";
|
|
+ reg = <0xf0 0x60000000 0x0 0x02000000>,
|
|
+ <0xc0 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 <dt-bindings/interrupt-controller/irq.h>
|
|
+
|
|
+#define SOC_PERIPHERAL_IRQ(nr) (nr)
|
|
+
|
|
+/ {
|
|
+ pcie@7060000000 {
|
|
+ compatible = "sophgo,cdns-pcie-host";
|
|
+ device_type = "pci";
|
|
+ #address-cells = <3>;
|
|
+ #size-cells = <2>;
|
|
+
|
|
+ bus-range = <0x0 0x3f>;
|
|
+ linux,pci-domain = <0>;
|
|
+ cdns,max-outbound-regions = <16>;
|
|
+ cdns,no-bar-match-nbits = <48>;
|
|
+ vendor-id = /bits/ 16 <0x1E30>;
|
|
+ device-id = /bits/ 16 <0x2042>;
|
|
+ pcie-id = /bits/ 16 <0x0>;
|
|
+ link-id = /bits/ 16 <0x0>;
|
|
+ top-intc-used = <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 = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi";
|
|
+ reg = <0x44 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi";
|
|
+ reg = <0x70 0x62000000 0x0 0x02000000>,
|
|
+ <0x48 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 <dt-bindings/interrupt-controller/irq.h>
|
|
+
|
|
+#define SOC_PERIPHERAL_IRQ(nr) (nr)
|
|
+
|
|
+/ {
|
|
+ pcie@7060000000 {
|
|
+ compatible = "sophgo,cdns-pcie-host";
|
|
+ device_type = "pci";
|
|
+ #address-cells = <3>;
|
|
+ #size-cells = <2>;
|
|
+
|
|
+ bus-range = <0x0 0x3f>;
|
|
+ linux,pci-domain = <0>;
|
|
+ cdns,max-outbound-regions = <16>;
|
|
+ cdns,no-bar-match-nbits = <48>;
|
|
+ vendor-id = /bits/ 16 <0x1E30>;
|
|
+ device-id = /bits/ 16 <0x2042>;
|
|
+ pcie-id = /bits/ 16 <0x0>;
|
|
+ link-id = /bits/ 16 <0x0>;
|
|
+ top-intc-used = <0>;
|
|
+ top-intc-id = <0>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi";
|
|
+ reg = <0x70 0x60000000 0x0 0x02000000>,
|
|
+ <0x40 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ //interrupt-names = "msi";
|
|
+ reg = <0x44 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi";
|
|
+ reg = <0x70 0x62000000 0x0 0x02000000>,
|
|
+ <0x48 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 <dt-bindings/interrupt-controller/irq.h>
|
|
+
|
|
+#define SOC_PERIPHERAL_IRQ(nr) (nr)
|
|
+
|
|
+/ {
|
|
+ pcie@7060000000 {
|
|
+ compatible = "sophgo,cdns-pcie-host";
|
|
+ device_type = "pci";
|
|
+ #address-cells = <3>;
|
|
+ #size-cells = <2>;
|
|
+
|
|
+ bus-range = <0x0 0x3f>;
|
|
+ linux,pci-domain = <0>;
|
|
+ cdns,max-outbound-regions = <16>;
|
|
+ cdns,no-bar-match-nbits = <48>;
|
|
+ vendor-id = /bits/ 16 <0x1E30>;
|
|
+ device-id = /bits/ 16 <0x2042>;
|
|
+ pcie-id = /bits/ 16 <0x0>;
|
|
+ link-id = /bits/ 16 <0x0>;
|
|
+ top-intc-used = <0>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi";
|
|
+ reg = <0x70 0x60000000 0x0 0x02000000>,
|
|
+ <0x40 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi";
|
|
+ reg = <0x70 0x62000000 0x0 0x02000000>,
|
|
+ <0x48 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 <dt-bindings/interrupt-controller/irq.h>
|
|
+
|
|
+#define SOC_PERIPHERAL_IRQ(nr) (nr)
|
|
+
|
|
+/ {
|
|
+ pcie@7062000000 {
|
|
+ compatible = "sophgo,cdns-pcie-host";
|
|
+ device_type = "pci";
|
|
+ #address-cells = <3>;
|
|
+ #size-cells = <2>;
|
|
+
|
|
+ bus-range = <0x00 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 <dt-bindings/interrupt-controller/irq.h>
|
|
+
|
|
+#define SOC_PERIPHERAL_IRQ(nr) (nr)
|
|
+
|
|
+/ {
|
|
+ pcie@7060000000 {
|
|
+ compatible = "sophgo,cdns-pcie-host";
|
|
+ device_type = "pci";
|
|
+ #address-cells = <3>;
|
|
+ #size-cells = <2>;
|
|
+
|
|
+ bus-range = <0x0 0x3f>;
|
|
+ linux,pci-domain = <0>;
|
|
+ cdns,max-outbound-regions = <16>;
|
|
+ cdns,no-bar-match-nbits = <48>;
|
|
+ vendor-id = /bits/ 16 <0x1E30>;
|
|
+ device-id = /bits/ 16 <0x2042>;
|
|
+ pcie-id = /bits/ 16 <0x0>;
|
|
+ link-id = /bits/ 16 <0x0>;
|
|
+ top-intc-used = <1>;
|
|
+ top-intc-id = <0>;
|
|
+ msix-supported = <1>;
|
|
+ interrupt-parent = <&intc1>;
|
|
+ //top-intc-used = <0>;
|
|
+ //interrupt-parent = <&intc>;
|
|
+ //interrupts = <SOC_PERIPHERAL_IRQ(122) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ //interrupt-names = "msi";
|
|
+ reg = <0x70 0x60000000 0x0 0x02000000>,
|
|
+ <0x40 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 = <SOC_PERIPHERAL_IRQ(123) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi";
|
|
+ reg = <0x70 0x62000000 0x0 0x02000000>,
|
|
+ <0x48 0x00000000 0x0 0x00001000>;
|
|
+ reg-names = "reg", "cfg";
|
|
+
|
|
+ // IO, check IO_SPACE_LIMIT
|
|
+ // 32bit prefetchable memory
|
|
+ // 32bit non-prefetchable memory
|
|
+ // 64bit prefetchable memory
|
|
+ // 64bit non-prefetchable memory
|
|
+ ranges = <0x01000000 0x0 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 = <KEY_POWER>;
|
|
+ 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 = <KEY_POWER>;
|
|
+ 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 = <KEY_POWER>;
|
|
+ gpios = <&port0a 22 GPIO_ACTIVE_HIGH>;
|
|
+ linux,input-type = <1>;
|
|
+ debounce-interval = <100>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gpio-restart {
|
|
+ compatible = "gpio-keys";
|
|
+ input-name = "gpio-keys";
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&restart_key>;
|
|
+
|
|
+ restart {
|
|
+ label = "GPIO Key Restart";
|
|
+ linux,code = <KEY_RESTART>;
|
|
+ gpios = <&port0a 23 GPIO_ACTIVE_HIGH>;
|
|
+ linux,input-type = <1>;
|
|
+ debounce-interval = <100>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&tach0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&fan0_acquire>;
|
|
+};
|
|
+
|
|
+&tach1 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&fan1_acquire>;
|
|
+};
|
|
+
|
|
+ðernet0 {
|
|
+ max-speed = <1000>;
|
|
+ eth-sophgo-config {
|
|
+ autoneg = "enable";
|
|
+ };
|
|
+};
|
|
+
|
|
+/ {
|
|
+ pwmfan: pwm-fan {
|
|
+ compatible = "pwm-fan";
|
|
+ pwms = <&pwm 0 40000>, <&pwm 1 40000>; // period_ns
|
|
+ pwm-names = "pwm0","pwm1";
|
|
+ pwm_inuse = "pwm0";
|
|
+ #cooling-cells = <2>;
|
|
+ cooling-levels = <153 128 77 26 1>; //total 255
|
|
+ };
|
|
+
|
|
+ thermal_zones: thermal-zones {
|
|
+ soc {
|
|
+ polling-delay-passive = <1000>; /* milliseconds */
|
|
+ polling-delay = <1000>; /* milliseconds */
|
|
+ thermal-sensors = <&mcu 0>;
|
|
+
|
|
+ trips {
|
|
+ soc_pwmfan_trip1: soc_pwmfan_trip@1 {
|
|
+ temperature = <40000>; /* millicelsius */
|
|
+ hysteresis = <8000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+
|
|
+ soc_pwmfan_trip2: soc_pwmfan_trip@2 {
|
|
+ temperature = <58000>; /* millicelsius */
|
|
+ hysteresis = <12000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+
|
|
+ soc_pwmfan_trip3: soc_pwmfan_trip@3 {
|
|
+ temperature = <70000>; /* millicelsius */
|
|
+ hysteresis = <10000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+
|
|
+ soc_pwmfan_trip4: soc_pwmfan_trip@4 {
|
|
+ temperature = <85000>; /* millicelsius */
|
|
+ hysteresis = <5000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ cooling-maps {
|
|
+ map0 {
|
|
+ trip = <&soc_pwmfan_trip1>;
|
|
+ cooling-device = <&pwmfan 0 1>;
|
|
+ };
|
|
+
|
|
+ map1 {
|
|
+ trip = <&soc_pwmfan_trip2>;
|
|
+ cooling-device = <&pwmfan 1 2>;
|
|
+ };
|
|
+
|
|
+ map2 {
|
|
+ trip = <&soc_pwmfan_trip3>;
|
|
+ cooling-device = <&pwmfan 2 3>;
|
|
+ };
|
|
+
|
|
+ map3 {
|
|
+ trip = <&soc_pwmfan_trip4>;
|
|
+ cooling-device = <&pwmfan 3 4>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ board {
|
|
+ polling-delay-passive = <1000>; /* milliseconds */
|
|
+ polling-delay = <1000>; /* milliseconds */
|
|
+ thermal-sensors = <&mcu 1>;
|
|
+
|
|
+ trips {
|
|
+ board_pwmfan_trip1: board_pwmfan_trip@1 {
|
|
+ temperature = <75000>; /* millicelsius */
|
|
+ hysteresis = <8000>; /* millicelsius */
|
|
+ type = "active";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ cooling-maps {
|
|
+ map4 {
|
|
+ trip = <&board_pwmfan_trip1>;
|
|
+ cooling-device = <&pwmfan 3 4>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi b/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi
|
|
new file mode 100644
|
|
index 000000000000..6d364cf6b3c5
|
|
--- /dev/null
|
|
+++ b/arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi
|
|
@@ -0,0 +1,62 @@
|
|
+#include <dt-bindings/interrupt-controller/irq.h>
|
|
+
|
|
+#define SOC_PERIPHERAL_IRQ(nr) (nr)
|
|
+
|
|
+/ {
|
|
+ intc2: top_intc@f030010300 {
|
|
+ compatible = "sophgo,top-intc";
|
|
+ reg = <0xf0 0x300102E0 0x0 0x4>,
|
|
+ <0xf0 0x30010300 0x0 0x4>,
|
|
+ <0xf0 0x30010304 0x0 0x4>;
|
|
+ reg-names = "sta", "set", "clr";
|
|
+ reg-bitwidth = <32>;
|
|
+ top-intc-id = <1>;
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <0x1>; // only applies to child node
|
|
+ for-msi;
|
|
+
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(288) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(289) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(290) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(291) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(292) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(293) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(294) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(295) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(296) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(297) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(298) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(299) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(300) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(301) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(302) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(303) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(304) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(305) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(306) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(307) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(308) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(309) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(310) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(311) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(312) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(313) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(314) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(315) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(316) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(317) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(318) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(319) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi0", "msi1", "msi2", "msi3",
|
|
+ "msi4", "msi5", "msi6", "msi7",
|
|
+ "msi8", "msi9", "msi10", "msi11",
|
|
+ "msi12", "msi13", "msi14", "msi15",
|
|
+ "msi16", "msi17", "msi18", "msi19",
|
|
+ "msi20", "msi21", "msi22", "msi23",
|
|
+ "msi24", "msi25", "msi26", "msi27",
|
|
+ "msi28", "msi29", "msi30", "msi31";
|
|
+
|
|
+ };
|
|
+
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/sophgo/mango-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 = <KEY_POWER>;
|
|
+ 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 <dt-bindings/clock/sophgo.h>
|
|
+#include <dt-bindings/clock/sophgo-mango-clock.h>
|
|
+#include <dt-bindings/gpio/gpio.h>
|
|
+#include <dt-bindings/input/input.h>
|
|
+#include <dt-bindings/reset/sophgo-mango-resets.h>
|
|
+#include <dt-bindings/interrupt-controller/irq.h>
|
|
+
|
|
+#include "mango-cpus-socket0.dtsi"
|
|
+#include "mango-clock-socket0.dtsi"
|
|
+#include "mango-pinctrl.dtsi"
|
|
+
|
|
+#define SOC_PERIPHERAL_IRQ(nr) (nr)
|
|
+
|
|
+/ {
|
|
+ model = "Sophgo Mango";
|
|
+ compatible = "sophgo,mango";
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ dma-noncoherent;
|
|
+
|
|
+ distance-map {
|
|
+ compatible = "numa-distance-map-v1";
|
|
+ distance-matrix = <0 0 10>,
|
|
+ <0 1 15>,
|
|
+ <0 2 25>,
|
|
+ <0 3 30>,
|
|
+ <1 0 15>,
|
|
+ <1 1 10>,
|
|
+ <1 2 30>,
|
|
+ <1 3 25>,
|
|
+ <2 0 25>,
|
|
+ <2 1 30>,
|
|
+ <2 2 10>,
|
|
+ <2 3 15>,
|
|
+ <3 0 30>,
|
|
+ <3 1 25>,
|
|
+ <3 2 15>,
|
|
+ <3 3 10>;
|
|
+ };
|
|
+
|
|
+ pmu {
|
|
+ compatible = "riscv,pmu";
|
|
+ riscv,event-to-mhpmevent =
|
|
+ <0x00003 0x00000000 0x00000010>,
|
|
+ <0x00004 0x00000000 0x00000011>,
|
|
+ <0x00005 0x00000000 0x00000007>,
|
|
+ <0x00006 0x00000000 0x00000006>,
|
|
+ <0x00008 0x00000000 0x00000027>,
|
|
+ <0x00009 0x00000000 0x00000028>,
|
|
+ <0x10000 0x00000000 0x0000000c>,
|
|
+ <0x10001 0x00000000 0x0000000d>,
|
|
+ <0x10002 0x00000000 0x0000000e>,
|
|
+ <0x10003 0x00000000 0x0000000f>,
|
|
+ <0x10008 0x00000000 0x00000001>,
|
|
+ <0x10009 0x00000000 0x00000002>,
|
|
+ <0x10010 0x00000000 0x00000010>,
|
|
+ <0x10011 0x00000000 0x00000011>,
|
|
+ <0x10012 0x00000000 0x00000012>,
|
|
+ <0x10013 0x00000000 0x00000013>,
|
|
+ <0x10019 0x00000000 0x00000004>,
|
|
+ <0x10021 0x00000000 0x00000003>,
|
|
+ <0x10030 0x00000000 0x0000001c>,
|
|
+ <0x10031 0x00000000 0x0000001b>;
|
|
+ riscv,event-to-mhpmcounters =
|
|
+ <0x00003 0x00003 0xfffffff8>,
|
|
+ <0x00004 0x00004 0xfffffff8>,
|
|
+ <0x00005 0x00005 0xfffffff8>,
|
|
+ <0x00006 0x00006 0xfffffff8>,
|
|
+ <0x00007 0x00007 0xfffffff8>,
|
|
+ <0x00008 0x00008 0xfffffff8>,
|
|
+ <0x00009 0x00009 0xfffffff8>,
|
|
+ <0x0000a 0x0000a 0xfffffff8>,
|
|
+ <0x10000 0x10000 0xfffffff8>,
|
|
+ <0x10001 0x10001 0xfffffff8>,
|
|
+ <0x10002 0x10002 0xfffffff8>,
|
|
+ <0x10003 0x10003 0xfffffff8>,
|
|
+ <0x10008 0x10008 0xfffffff8>,
|
|
+ <0x10009 0x10009 0xfffffff8>,
|
|
+ <0x10010 0x10010 0xfffffff8>,
|
|
+ <0x10011 0x10011 0xfffffff8>,
|
|
+ <0x10012 0x10012 0xfffffff8>,
|
|
+ <0x10013 0x10013 0xfffffff8>,
|
|
+ <0x10019 0x10019 0xfffffff8>,
|
|
+ <0x10021 0x10021 0xfffffff8>,
|
|
+ <0x10030 0x10030 0xfffffff8>,
|
|
+ <0x10031 0x10031 0xfffffff8>;
|
|
+ riscv,raw-event-to-mhpmcounters =
|
|
+ <0x00000000 0x00000001 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000002 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000003 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000004 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000005 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000006 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000007 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000008 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000009 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000000a 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000000b 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000000c 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000000d 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000000e 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000000f 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000010 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000011 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000012 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000013 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000014 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000015 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000016 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000017 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000018 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000019 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000001a 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000001b 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000001c 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000001d 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000001e 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000001f 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000020 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000021 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000022 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000023 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000024 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000025 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000026 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000027 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000028 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x00000029 0xffffffff 0xffffffff 0xfffffff8>,
|
|
+ <0x00000000 0x0000002a 0xffffffff 0xffffffff 0xfffffff8>;
|
|
+ };
|
|
+
|
|
+ soc: soc {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ compatible = "simple-bus";
|
|
+ ranges;
|
|
+ dma-ranges = <0x0 0x0 0x0 0x0 0x1f 0x0>;
|
|
+
|
|
+ clint_mswi: clint-mswi@7094000000 {
|
|
+ compatible = "thead,c900-clint-mswi";
|
|
+ reg = <0x00000070 0x94000000 0x00000000 0x00004000>;
|
|
+ interrupts-extended = <
|
|
+ &cpu0_intc 3
|
|
+ &cpu1_intc 3
|
|
+ &cpu2_intc 3
|
|
+ &cpu3_intc 3
|
|
+ &cpu4_intc 3
|
|
+ &cpu5_intc 3
|
|
+ &cpu6_intc 3
|
|
+ &cpu7_intc 3
|
|
+ &cpu8_intc 3
|
|
+ &cpu9_intc 3
|
|
+ &cpu10_intc 3
|
|
+ &cpu11_intc 3
|
|
+ &cpu12_intc 3
|
|
+ &cpu13_intc 3
|
|
+ &cpu14_intc 3
|
|
+ &cpu15_intc 3
|
|
+ &cpu16_intc 3
|
|
+ &cpu17_intc 3
|
|
+ &cpu18_intc 3
|
|
+ &cpu19_intc 3
|
|
+ &cpu20_intc 3
|
|
+ &cpu21_intc 3
|
|
+ &cpu22_intc 3
|
|
+ &cpu23_intc 3
|
|
+ &cpu24_intc 3
|
|
+ &cpu25_intc 3
|
|
+ &cpu26_intc 3
|
|
+ &cpu27_intc 3
|
|
+ &cpu28_intc 3
|
|
+ &cpu29_intc 3
|
|
+ &cpu30_intc 3
|
|
+ &cpu31_intc 3
|
|
+ &cpu32_intc 3
|
|
+ &cpu33_intc 3
|
|
+ &cpu34_intc 3
|
|
+ &cpu35_intc 3
|
|
+ &cpu36_intc 3
|
|
+ &cpu37_intc 3
|
|
+ &cpu38_intc 3
|
|
+ &cpu39_intc 3
|
|
+ &cpu40_intc 3
|
|
+ &cpu41_intc 3
|
|
+ &cpu42_intc 3
|
|
+ &cpu43_intc 3
|
|
+ &cpu44_intc 3
|
|
+ &cpu45_intc 3
|
|
+ &cpu46_intc 3
|
|
+ &cpu47_intc 3
|
|
+ &cpu48_intc 3
|
|
+ &cpu49_intc 3
|
|
+ &cpu50_intc 3
|
|
+ &cpu51_intc 3
|
|
+ &cpu52_intc 3
|
|
+ &cpu53_intc 3
|
|
+ &cpu54_intc 3
|
|
+ &cpu55_intc 3
|
|
+ &cpu56_intc 3
|
|
+ &cpu57_intc 3
|
|
+ &cpu58_intc 3
|
|
+ &cpu59_intc 3
|
|
+ &cpu60_intc 3
|
|
+ &cpu61_intc 3
|
|
+ &cpu62_intc 3
|
|
+ &cpu63_intc 3
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer0: clint-mtimer@70ac000000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu0_intc 7
|
|
+ &cpu1_intc 7
|
|
+ &cpu2_intc 7
|
|
+ &cpu3_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer1: clint-mtimer@70ac010000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu4_intc 7
|
|
+ &cpu5_intc 7
|
|
+ &cpu6_intc 7
|
|
+ &cpu7_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer2: clint-mtimer@70ac020000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu8_intc 7
|
|
+ &cpu9_intc 7
|
|
+ &cpu10_intc 7
|
|
+ &cpu11_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer3: clint-mtimer@70ac030000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu12_intc 7
|
|
+ &cpu13_intc 7
|
|
+ &cpu14_intc 7
|
|
+ &cpu15_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer4: clint-mtimer@70ac040000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu16_intc 7
|
|
+ &cpu17_intc 7
|
|
+ &cpu18_intc 7
|
|
+ &cpu19_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer5: clint-mtimer@70ac050000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu20_intc 7
|
|
+ &cpu21_intc 7
|
|
+ &cpu22_intc 7
|
|
+ &cpu23_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer6: clint-mtimer@70ac060000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu24_intc 7
|
|
+ &cpu25_intc 7
|
|
+ &cpu26_intc 7
|
|
+ &cpu27_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer7: clint-mtimer@70ac070000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu28_intc 7
|
|
+ &cpu29_intc 7
|
|
+ &cpu30_intc 7
|
|
+ &cpu31_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer8: clint-mtimer@70ac080000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu32_intc 7
|
|
+ &cpu33_intc 7
|
|
+ &cpu34_intc 7
|
|
+ &cpu35_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer9: clint-mtimer@70ac090000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu36_intc 7
|
|
+ &cpu37_intc 7
|
|
+ &cpu38_intc 7
|
|
+ &cpu39_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer10: clint-mtimer@70ac0a0000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu40_intc 7
|
|
+ &cpu41_intc 7
|
|
+ &cpu42_intc 7
|
|
+ &cpu43_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer11: clint-mtimer@70ac0b0000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu44_intc 7
|
|
+ &cpu45_intc 7
|
|
+ &cpu46_intc 7
|
|
+ &cpu47_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer12: clint-mtimer@70ac0c0000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu48_intc 7
|
|
+ &cpu49_intc 7
|
|
+ &cpu50_intc 7
|
|
+ &cpu51_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer13: clint-mtimer@70ac0d0000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu52_intc 7
|
|
+ &cpu53_intc 7
|
|
+ &cpu54_intc 7
|
|
+ &cpu55_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer14: clint-mtimer@70ac0e0000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu56_intc 7
|
|
+ &cpu57_intc 7
|
|
+ &cpu58_intc 7
|
|
+ &cpu59_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ clint_mtimer15: clint-mtimer@70ac0f0000 {
|
|
+ compatible = "thead,c900-clint-mtimer";
|
|
+ reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>;
|
|
+ interrupts-extended = <
|
|
+ &cpu60_intc 7
|
|
+ &cpu61_intc 7
|
|
+ &cpu62_intc 7
|
|
+ &cpu63_intc 7
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ intc: interrupt-controller@7090000000 {
|
|
+ #address-cells = <0>;
|
|
+ #interrupt-cells = <2>;
|
|
+ compatible = "thead,c900-plic";
|
|
+ interrupt-controller;
|
|
+ interrupts-extended = <
|
|
+ &cpu0_intc 11 &cpu0_intc 9
|
|
+ &cpu1_intc 11 &cpu1_intc 9
|
|
+ &cpu2_intc 11 &cpu2_intc 9
|
|
+ &cpu3_intc 11 &cpu3_intc 9
|
|
+ &cpu4_intc 11 &cpu4_intc 9
|
|
+ &cpu5_intc 11 &cpu5_intc 9
|
|
+ &cpu6_intc 11 &cpu6_intc 9
|
|
+ &cpu7_intc 11 &cpu7_intc 9
|
|
+ &cpu8_intc 11 &cpu8_intc 9
|
|
+ &cpu9_intc 11 &cpu9_intc 9
|
|
+ &cpu10_intc 11 &cpu10_intc 9
|
|
+ &cpu11_intc 11 &cpu11_intc 9
|
|
+ &cpu12_intc 11 &cpu12_intc 9
|
|
+ &cpu13_intc 11 &cpu13_intc 9
|
|
+ &cpu14_intc 11 &cpu14_intc 9
|
|
+ &cpu15_intc 11 &cpu15_intc 9
|
|
+ &cpu16_intc 11 &cpu16_intc 9
|
|
+ &cpu17_intc 11 &cpu17_intc 9
|
|
+ &cpu18_intc 11 &cpu18_intc 9
|
|
+ &cpu19_intc 11 &cpu19_intc 9
|
|
+ &cpu20_intc 11 &cpu20_intc 9
|
|
+ &cpu21_intc 11 &cpu21_intc 9
|
|
+ &cpu22_intc 11 &cpu22_intc 9
|
|
+ &cpu23_intc 11 &cpu23_intc 9
|
|
+ &cpu24_intc 11 &cpu24_intc 9
|
|
+ &cpu25_intc 11 &cpu25_intc 9
|
|
+ &cpu26_intc 11 &cpu26_intc 9
|
|
+ &cpu27_intc 11 &cpu27_intc 9
|
|
+ &cpu28_intc 11 &cpu28_intc 9
|
|
+ &cpu29_intc 11 &cpu29_intc 9
|
|
+ &cpu30_intc 11 &cpu30_intc 9
|
|
+ &cpu31_intc 11 &cpu31_intc 9
|
|
+ &cpu32_intc 11 &cpu32_intc 9
|
|
+ &cpu33_intc 11 &cpu33_intc 9
|
|
+ &cpu34_intc 11 &cpu34_intc 9
|
|
+ &cpu35_intc 11 &cpu35_intc 9
|
|
+ &cpu36_intc 11 &cpu36_intc 9
|
|
+ &cpu37_intc 11 &cpu37_intc 9
|
|
+ &cpu38_intc 11 &cpu38_intc 9
|
|
+ &cpu39_intc 11 &cpu39_intc 9
|
|
+ &cpu40_intc 11 &cpu40_intc 9
|
|
+ &cpu41_intc 11 &cpu41_intc 9
|
|
+ &cpu42_intc 11 &cpu42_intc 9
|
|
+ &cpu43_intc 11 &cpu43_intc 9
|
|
+ &cpu44_intc 11 &cpu44_intc 9
|
|
+ &cpu45_intc 11 &cpu45_intc 9
|
|
+ &cpu46_intc 11 &cpu46_intc 9
|
|
+ &cpu47_intc 11 &cpu47_intc 9
|
|
+ &cpu48_intc 11 &cpu48_intc 9
|
|
+ &cpu49_intc 11 &cpu49_intc 9
|
|
+ &cpu50_intc 11 &cpu50_intc 9
|
|
+ &cpu51_intc 11 &cpu51_intc 9
|
|
+ &cpu52_intc 11 &cpu52_intc 9
|
|
+ &cpu53_intc 11 &cpu53_intc 9
|
|
+ &cpu54_intc 11 &cpu54_intc 9
|
|
+ &cpu55_intc 11 &cpu55_intc 9
|
|
+ &cpu56_intc 11 &cpu56_intc 9
|
|
+ &cpu57_intc 11 &cpu57_intc 9
|
|
+ &cpu58_intc 11 &cpu58_intc 9
|
|
+ &cpu59_intc 11 &cpu59_intc 9
|
|
+ &cpu60_intc 11 &cpu60_intc 9
|
|
+ &cpu61_intc 11 &cpu61_intc 9
|
|
+ &cpu62_intc 11 &cpu62_intc 9
|
|
+ &cpu63_intc 11 &cpu63_intc 9
|
|
+ >;
|
|
+ reg = <0x00000070 0x90000000 0x00000000 0x04000000>;
|
|
+ reg-names = "control";
|
|
+ riscv,max-priority = <7>;
|
|
+ riscv,ndev = <224>;
|
|
+ };
|
|
+
|
|
+ timer0: dw-apb-timer0@7030003000 {
|
|
+ compatible = "snps,dw-apb-timer";
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ reg = <0x70 0x30003000 0x0 0x14>;
|
|
+ clocks = <&div_clk GATE_CLK_TIMER1>,
|
|
+ <&div_clk GATE_CLK_APB_TIMER>;
|
|
+ clock-names = "timer", "pclk";
|
|
+ clk-drv-rating = <300>;
|
|
+ };
|
|
+
|
|
+ timer1: dw-apb-timer1@7030003014 {
|
|
+ compatible = "snps,dw-apb-timer";
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(100) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ reg = <0x70 0x30003014 0x0 0x10>;
|
|
+ clocks = <&div_clk GATE_CLK_TIMER2>,
|
|
+ <&div_clk GATE_CLK_APB_TIMER>;
|
|
+ clock-names = "timer", "pclk";
|
|
+ clk-drv-rating = <300>;
|
|
+ };
|
|
+
|
|
+ top_misc: top_misc_ctrl@7030010000 {
|
|
+ compatible = "syscon";
|
|
+ reg = <0x70 0x30010000 0x0 0x8000>;
|
|
+ };
|
|
+
|
|
+ rst: reset-controller {
|
|
+ #reset-cells = <1>;
|
|
+ compatible = "bitmain,reset";
|
|
+ subctrl-syscon = <&top_misc>;
|
|
+ top_rst_offset = <0x3000>;
|
|
+ nr_resets = <RST_MAX_NUM>;
|
|
+ };
|
|
+
|
|
+ i2c0: i2c@7030005000 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "snps,designware-i2c";
|
|
+ clocks = <&div_clk GATE_CLK_APB_I2C>;
|
|
+ clock-names = "clk_gate_apb_i2c";
|
|
+ reg = <0x70 0x30005000 0x0 0x1000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(101) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <100000>;
|
|
+ resets = <&rst RST_I2C0>;
|
|
+ reset-names = "i2c0";
|
|
+ };
|
|
+
|
|
+ i2c1: i2c@7030006000 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "snps,designware-i2c";
|
|
+ clocks = <&div_clk GATE_CLK_APB_I2C>;
|
|
+ clock-names = "clk_gate_apb_i2c";
|
|
+ reg = <0x70 0x30006000 0x0 0x1000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(102) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <100000>;
|
|
+ resets = <&rst RST_I2C1>;
|
|
+ reset-names = "i2c1";
|
|
+ };
|
|
+
|
|
+ i2c2: i2c@7030007000 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "snps,designware-i2c";
|
|
+ clocks = <&div_clk GATE_CLK_APB_I2C>;
|
|
+ clock-names = "clk_gate_apb_i2c";
|
|
+ reg = <0x70 0x30007000 0x0 0x1000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(103) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <100000>;
|
|
+ resets = <&rst RST_I2C2>;
|
|
+ reset-names = "i2c2";
|
|
+ };
|
|
+
|
|
+ i2c3: i2c@7030008000 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "snps,designware-i2c";
|
|
+ clocks = <&div_clk GATE_CLK_APB_I2C>;
|
|
+ clock-names = "clk_gate_apb_i2c";
|
|
+ reg = <0x70 0x30008000 0x0 0x1000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(104) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <100000>;
|
|
+ resets = <&rst RST_I2C3>;
|
|
+ reset-names = "i2c3";
|
|
+ };
|
|
+
|
|
+ gpio0: gpio@7030009000 {
|
|
+ compatible = "snps,dw-apb-gpio";
|
|
+ reg = <0x70 0x30009000 0x0 0x400>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ clocks = <&div_clk GATE_CLK_APB_GPIO>,
|
|
+ <&div_clk GATE_CLK_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 = <SOC_PERIPHERAL_IRQ(96) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gpio1: gpio@703000a000 {
|
|
+ compatible = "snps,dw-apb-gpio";
|
|
+ reg = <0x70 0x3000a000 0x0 0x400>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ clocks = <&div_clk GATE_CLK_APB_GPIO>,
|
|
+ <&div_clk GATE_CLK_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 = <SOC_PERIPHERAL_IRQ(97) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gpio2: gpio@703000b000 {
|
|
+ compatible = "snps,dw-apb-gpio";
|
|
+ reg = <0x70 0x3000b000 0x0 0x400>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ clocks = <&div_clk GATE_CLK_APB_GPIO>,
|
|
+ <&div_clk GATE_CLK_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 = <SOC_PERIPHERAL_IRQ(98) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ pwm: pwm@703000C000 {
|
|
+ compatible = "sophgo,sophgo-pwm";
|
|
+ reg = <0x70 0x3000C000 0x0 0x20>;
|
|
+ clocks = <&div_clk GATE_CLK_APB_PWM>;
|
|
+ clock-names = "clk_gate_apb_pwm";
|
|
+ #pwm-cells = <2>;
|
|
+ pwm-num = <2>;
|
|
+ no-polarity;
|
|
+ };
|
|
+
|
|
+ tach0: tach@703000C020 {
|
|
+ compatible = "sophgo,sophgo-tach";
|
|
+ reg = <0x70 0x3000C020 0x0 0x8>;
|
|
+ };
|
|
+
|
|
+ tach1: tach@703000C028 {
|
|
+ compatible = "sophgo,sophgo-tach";
|
|
+ reg = <0x70 0x3000C028 0x0 0x8>;
|
|
+ };
|
|
+
|
|
+ uart0: serial@7040000000 {
|
|
+ compatible = "snps,dw-apb-uart";
|
|
+ reg = <0x00000070 0x40000000 0x00000000 0x00001000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(112) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <500000000>;
|
|
+ clocks = <&div_clk GATE_CLK_UART_500M>,
|
|
+ <&div_clk GATE_CLK_APB_UART>;
|
|
+ clock-names = "baudclk", "apb_pclk";
|
|
+ reg-shift = <2>;
|
|
+ reg-io-width = <4>;
|
|
+ };
|
|
+
|
|
+ uart1: serial@7040001000 {
|
|
+ compatible = "snps,dw-apb-uart";
|
|
+ reg = <0x00000070 0x40001000 0x00000000 0x00001000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(113) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <500000000>;
|
|
+ clocks = <&div_clk GATE_CLK_UART_500M>,
|
|
+ <&div_clk GATE_CLK_APB_UART>;
|
|
+ clock-names = "baudclk", "apb_pclk";
|
|
+ reg-shift = <2>;
|
|
+ reg-io-width = <4>;
|
|
+ };
|
|
+
|
|
+ uart2: serial@7040002000 {
|
|
+ compatible = "snps,dw-apb-uart";
|
|
+ reg = <0x00000070 0x40002000 0x00000000 0x00001000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(114) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <500000000>;
|
|
+ clocks = <&div_clk GATE_CLK_UART_500M>,
|
|
+ <&div_clk GATE_CLK_APB_UART>;
|
|
+ clock-names = "baudclk", "apb_pclk";
|
|
+ reg-shift = <2>;
|
|
+ reg-io-width = <4>;
|
|
+ };
|
|
+
|
|
+ uart3: serial@7040003000 {
|
|
+ compatible = "snps,dw-apb-uart";
|
|
+ reg = <0x00000070 0x40003000 0x00000000 0x00001000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(115) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <500000000>;
|
|
+ clocks = <&div_clk GATE_CLK_UART_500M>,
|
|
+ <&div_clk GATE_CLK_APB_UART>;
|
|
+ clock-names = "baudclk", "apb_pclk";
|
|
+ reg-shift = <2>;
|
|
+ reg-io-width = <4>;
|
|
+ };
|
|
+
|
|
+ emmc: bm-emmc@704002A000 {
|
|
+ compatible = "bitmain,bm-emmc";
|
|
+ reg = <0x70 0x4002A000 0x0 0x1000>;
|
|
+ reg-names = "core_mem";
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(134) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ bus-width = <4>;
|
|
+ non-removable;
|
|
+ no-sdio;
|
|
+ no-sd;
|
|
+ resets = <&rst RST_EMMC>;
|
|
+ reset-names = "emmc";
|
|
+ clocks =
|
|
+ <&div_clk GATE_CLK_EMMC_100M>,
|
|
+ <&div_clk GATE_CLK_AXI_EMMC>,
|
|
+ <&div_clk GATE_CLK_100K_EMMC>;
|
|
+ clock-names =
|
|
+ "clk_gate_emmc",
|
|
+ "clk_gate_axi_emmc",
|
|
+ "clk_gate_100k_emmc";
|
|
+ };
|
|
+
|
|
+ sd: bm-sd@704002B000 {
|
|
+ compatible = "bitmain,bm-sd";
|
|
+ reg = <0x70 0x4002B000 0x0 0x1000>;
|
|
+ reg-names = "core_mem";
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(136) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ bus-width = <4>;
|
|
+ no-sdio;
|
|
+ no-mmc;
|
|
+ resets = <&rst RST_SD>;
|
|
+ reset-names = "sdio";
|
|
+ clocks =
|
|
+ <&div_clk GATE_CLK_SD_100M>,
|
|
+ <&div_clk GATE_CLK_AXI_SD>,
|
|
+ <&div_clk GATE_CLK_100K_SD>;
|
|
+ clock-names =
|
|
+ "clk_gate_sd",
|
|
+ "clk_gate_axi_sd",
|
|
+ "clk_gate_100k_sd";
|
|
+ };
|
|
+
|
|
+ spifmc0: flash-controller@7000180000 {
|
|
+ compatible = "sophgo,spifmc";
|
|
+ reg = <0x70 0x00180000 0x0 0x1000000>;
|
|
+ reg-names = "memory";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(108) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <100000000>;
|
|
+ clocks = <&div_clk GATE_CLK_AHB_SF>;
|
|
+ flash@0 {
|
|
+ reg = <0>;
|
|
+ compatible = "jedec,spi-nor";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ spifmc1: flash-controller@7002180000 {
|
|
+ compatible = "sophgo,spifmc";
|
|
+ reg = <0x70 0x02180000 0x0 0x1000000>;
|
|
+ reg-names = "memory";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(109) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clock-frequency = <100000000>;
|
|
+ clocks = <&div_clk GATE_CLK_AHB_SF>;
|
|
+ flash@0 {
|
|
+ reg = <0>;
|
|
+ compatible = "jedec,spi-nor";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ spi0: spi@7040004000 {
|
|
+ compatible = "snps,dw-apb-ssi";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0x70 0x40004000 0x0 0x1000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(110) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&div_clk GATE_CLK_APB_SPI>,
|
|
+ <&div_clk GATE_CLK_SYSDMA_AXI>;
|
|
+ clock-frequency = <250000000>;
|
|
+ resets = <&rst RST_SPI0>;
|
|
+ reset-names = "spi0";
|
|
+ num-cs = <2>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ spi1: spi@7040005000 {
|
|
+ compatible = "snps,dw-apb-ssi";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0x70 0x40005000 0x0 0x1000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(111) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&div_clk GATE_CLK_APB_SPI>,
|
|
+ <&div_clk GATE_CLK_SYSDMA_AXI>;
|
|
+ clock-frequency = <250000000>;
|
|
+ resets = <&rst RST_SPI1>;
|
|
+ reset-names = "spi1";
|
|
+ num-cs = <2>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ stmmac_axi_setup: stmmac-axi-config {
|
|
+ snps,wr_osr_lmt = <1>;
|
|
+ snps,rd_osr_lmt = <2>;
|
|
+ snps,blen = <4 8 16 0 0 0 0>;
|
|
+ };
|
|
+
|
|
+ mtl_rx_setup: rx-queues-config {
|
|
+ snps,rx-queues-to-use = <8>;
|
|
+ queue0 {};
|
|
+ queue1 {};
|
|
+ queue2 {};
|
|
+ queue3 {};
|
|
+ queue4 {};
|
|
+ queue5 {};
|
|
+ queue6 {};
|
|
+ queue7 {};
|
|
+ };
|
|
+
|
|
+ mtl_tx_setup: tx-queues-config {
|
|
+ snps,tx-queues-to-use = <8>;
|
|
+ queue0 {};
|
|
+ queue1 {};
|
|
+ queue2 {};
|
|
+ queue3 {};
|
|
+ queue4 {};
|
|
+ queue5 {};
|
|
+ queue6 {};
|
|
+ queue7 {};
|
|
+ };
|
|
+
|
|
+ ethernet0: ethernet@7040026000 {
|
|
+ compatible = "bitmain,ethernet";
|
|
+ reg = <0x70 0x40026000 0x0 0x4000>;
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(132) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "macirq";
|
|
+ clock-names = "clk_tx", "gate_clk_tx", "stmmaceth", "ptp_ref", "gate_clk_ref";
|
|
+ clocks = <&div_clk DIV_CLK_FPLL_TX_ETH0>,
|
|
+ <&div_clk GATE_CLK_TX_ETH0>,
|
|
+ <&div_clk GATE_CLK_AXI_ETH0>,
|
|
+ <&div_clk GATE_CLK_PTP_REF_I_ETH0>,
|
|
+ <&div_clk GATE_CLK_REF_ETH0>;
|
|
+
|
|
+ /* no hash filter and perfect filter support */
|
|
+ snps,multicast-filter-bins = <0>;
|
|
+ snps,perfect-filter-entries = <1>;
|
|
+
|
|
+ snps,txpbl = <32>;
|
|
+ snps,rxpbl = <32>;
|
|
+ snps,aal;
|
|
+
|
|
+ snps,axi-config = <&stmmac_axi_setup>;
|
|
+ snps,mtl-rx-config = <&mtl_rx_setup>;
|
|
+ snps,mtl-tx-config = <&mtl_tx_setup>;
|
|
+
|
|
+ phy-mode = "rgmii-txid";
|
|
+ phy-reset-gpios = <&port0a 27 0>;
|
|
+ phy-handle = <&phy0>;
|
|
+ mdio {
|
|
+ #address-cells = <0x1>;
|
|
+ #size-cells = <0x0>;
|
|
+ compatible = "snps,dwmac-mdio";
|
|
+ phy0: phy@0 {
|
|
+ compatible = "ethernet-phy-ieee802.3-c22";
|
|
+ device_type = "ethernet-phy";
|
|
+ reg = <0x0>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ intc1: top_intc@7030010300 {
|
|
+ compatible = "sophgo,top-intc";
|
|
+ reg = <0x70 0x300102E0 0x0 0x4>,
|
|
+ <0x70 0x30010300 0x0 0x4>,
|
|
+ <0x70 0x30010304 0x0 0x4>;
|
|
+ reg-names = "sta", "set", "clr";
|
|
+ reg-bitwidth = <32>;
|
|
+ top_intc_id = <0>;
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <0x1>; // only applies to child node
|
|
+ for-msi;
|
|
+
|
|
+ interrupt-parent = <&intc>;
|
|
+ interrupts = <SOC_PERIPHERAL_IRQ(64) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(65) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(66) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(67) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(68) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(69) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(70) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(71) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(72) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(73) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(74) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(75) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(76) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(77) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(78) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(79) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(80) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(81) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(82) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(83) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(84) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(85) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(86) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(87) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(88) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(89) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(90) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(91) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(92) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(93) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(94) IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <SOC_PERIPHERAL_IRQ(95) IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "msi0", "msi1", "msi2", "msi3",
|
|
+ "msi4", "msi5", "msi6", "msi7",
|
|
+ "msi8", "msi9", "msi10", "msi11",
|
|
+ "msi12", "msi13", "msi14", "msi15",
|
|
+ "msi16", "msi17", "msi18", "msi19",
|
|
+ "msi20", "msi21", "msi22", "msi23",
|
|
+ "msi24", "msi25", "msi26", "msi27",
|
|
+ "msi28", "msi29", "msi30", "msi31";
|
|
+
|
|
+ };
|
|
+
|
|
+ aliases {
|
|
+ serial0 = &uart0;
|
|
+ };
|
|
+
|
|
+ chosen: chosen {
|
|
+ bootargs = "console=ttyS0,115200 earlycon maxcpus=1";
|
|
+ stdout-path = "serial0";
|
|
+ };
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/thead/Makefile b/arch/riscv/boot/dts/thead/Makefile
|
|
index b55a17127c2b..1f14fdaf6add 100644
|
|
--- a/arch/riscv/boot/dts/thead/Makefile
|
|
+++ b/arch/riscv/boot/dts/thead/Makefile
|
|
@@ -1,2 +1,5 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-pi-4a.dtb th1520-beaglev-ahead.dtb
|
|
+dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-pi-4a-16g.dtb
|
|
+dtb-$(CONFIG_ARCH_THEAD) += th1520-lichee-cluster-4a.dtb th1520-lichee-cluster-4a-16g.dtb
|
|
+dtb-$(CONFIG_ARCH_THEAD) += th1520-milkv-meles.dtb th1520-milkv-meles-4g.dtb
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts
|
|
index 70e8042c8304..2c2d43433586 100644
|
|
--- a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts
|
|
+++ b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts
|
|
@@ -7,22 +7,29 @@
|
|
/dts-v1/;
|
|
|
|
#include "th1520.dtsi"
|
|
+#include <dt-bindings/gpio/gpio.h>
|
|
+#include <dt-bindings/leds/common.h>
|
|
|
|
/ {
|
|
model = "BeagleV Ahead";
|
|
compatible = "beagle,beaglev-ahead", "thead,th1520";
|
|
|
|
aliases {
|
|
+ ethernet0 = &gmac0;
|
|
gpio0 = &gpio0;
|
|
gpio1 = &gpio1;
|
|
gpio2 = &gpio2;
|
|
gpio3 = &gpio3;
|
|
+ gpio4 = &gpio4;
|
|
+ gpio5 = &aogpio;
|
|
serial0 = &uart0;
|
|
serial1 = &uart1;
|
|
serial2 = &uart2;
|
|
serial3 = &uart3;
|
|
serial4 = &uart4;
|
|
serial5 = &uart5;
|
|
+ mmc0 = &emmc;
|
|
+ mmc1 = &sdio0;
|
|
};
|
|
|
|
chosen {
|
|
@@ -32,11 +39,46 @@ chosen {
|
|
memory@0 {
|
|
device_type = "memory";
|
|
reg = <0x0 0x00000000 0x1 0x00000000>;
|
|
+ };
|
|
+
|
|
+ leds {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&led_pins>;
|
|
+ compatible = "gpio-leds";
|
|
+
|
|
+ led-1 {
|
|
+ gpios = <&gpio4 8 GPIO_ACTIVE_LOW>;
|
|
+ color = <LED_COLOR_ID_BLUE>;
|
|
+ label = "led1";
|
|
+ };
|
|
+
|
|
+ led-2 {
|
|
+ gpios = <&gpio4 9 GPIO_ACTIVE_LOW>;
|
|
+ color = <LED_COLOR_ID_BLUE>;
|
|
+ label = "led2";
|
|
+ };
|
|
+
|
|
+ led-3 {
|
|
+ gpios = <&gpio4 10 GPIO_ACTIVE_LOW>;
|
|
+ color = <LED_COLOR_ID_BLUE>;
|
|
+ label = "led3";
|
|
+ };
|
|
|
|
+ led-4 {
|
|
+ gpios = <&gpio4 11 GPIO_ACTIVE_LOW>;
|
|
+ color = <LED_COLOR_ID_BLUE>;
|
|
+ label = "led4";
|
|
+ };
|
|
+
|
|
+ led-5 {
|
|
+ gpios = <&gpio4 12 GPIO_ACTIVE_LOW>;
|
|
+ color = <LED_COLOR_ID_BLUE>;
|
|
+ label = "led5";
|
|
+ };
|
|
};
|
|
};
|
|
|
|
-&osc {
|
|
+&osc_24m {
|
|
clock-frequency = <24000000>;
|
|
};
|
|
|
|
@@ -44,10 +86,18 @@ &osc_32k {
|
|
clock-frequency = <32768>;
|
|
};
|
|
|
|
+&aonsys_clk {
|
|
+ clock-frequency = <73728000>;
|
|
+};
|
|
+
|
|
&apb_clk {
|
|
clock-frequency = <62500000>;
|
|
};
|
|
|
|
+&sdhci_clk {
|
|
+ clock-frequency = <198000000>;
|
|
+};
|
|
+
|
|
&uart_sclk {
|
|
clock-frequency = <100000000>;
|
|
};
|
|
@@ -56,6 +106,153 @@ &dmac0 {
|
|
status = "okay";
|
|
};
|
|
|
|
+&gmac_clk {
|
|
+ clock-frequency = <500000000>;
|
|
+};
|
|
+
|
|
+&gmac_axi_clk {
|
|
+ clock-frequency = <100000000>;
|
|
+};
|
|
+
|
|
+&emmc {
|
|
+ bus-width = <8>;
|
|
+ max-frequency = <198000000>;
|
|
+ mmc-hs400-1_8v;
|
|
+ non-removable;
|
|
+ no-sdio;
|
|
+ no-sd;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&gmac0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&gmac0_pins>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&mdio0 {
|
|
+ phy0: ethernet-phy@1 {
|
|
+ reg = <1>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&padctrl_aosys {
|
|
+ led_pins: led-0 {
|
|
+ led-pins {
|
|
+ pins = "AUDIO_PA8", /* GPIO4_8 */
|
|
+ "AUDIO_PA9", /* GPIO4_9 */
|
|
+ "AUDIO_PA10", /* GPIO4_10 */
|
|
+ "AUDIO_PA11", /* GPIO4_11 */
|
|
+ "AUDIO_PA12"; /* GPIO4_12 */
|
|
+ function = "gpio";
|
|
+ bias-disable;
|
|
+ drive-strength = <3>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&padctrl0_apsys {
|
|
+ gmac0_pins: gmac0-0 {
|
|
+ tx-pins {
|
|
+ pins = "GMAC0_TX_CLK",
|
|
+ "GMAC0_TXEN",
|
|
+ "GMAC0_TXD0",
|
|
+ "GMAC0_TXD1",
|
|
+ "GMAC0_TXD2",
|
|
+ "GMAC0_TXD3";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <25>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ rx-pins {
|
|
+ pins = "GMAC0_RX_CLK",
|
|
+ "GMAC0_RXDV",
|
|
+ "GMAC0_RXD0",
|
|
+ "GMAC0_RXD1",
|
|
+ "GMAC0_RXD2",
|
|
+ "GMAC0_RXD3";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ mdc-pins {
|
|
+ pins = "GMAC0_MDC";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <13>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ mdio-pins {
|
|
+ pins = "GMAC0_MDIO";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <13>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ sdio0_pins: sdio0-0 {
|
|
+ detn-pins {
|
|
+ pins = "SDIO0_DETN";
|
|
+ function = "sdio";
|
|
+ bias-disable; /* external pull-up */
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ uart0_pins: uart0-0 {
|
|
+ tx-pins {
|
|
+ pins = "UART0_TXD";
|
|
+ function = "uart";
|
|
+ bias-disable;
|
|
+ drive-strength = <3>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ rx-pins {
|
|
+ pins = "UART0_RXD";
|
|
+ function = "uart";
|
|
+ bias-disable;
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&sdio0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&sdio0_pins>;
|
|
+ bus-width = <4>;
|
|
+ max-frequency = <198000000>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
&uart0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&uart0_pins>;
|
|
status = "okay";
|
|
};
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts
|
|
new file mode 100644
|
|
index 000000000000..c65cd1c83101
|
|
--- /dev/null
|
|
+++ b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts
|
|
@@ -0,0 +1,18 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright (C) 2024 NekoRouter <nekorouter@outlook.com>
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "th1520-lichee-cluster-4a.dts"
|
|
+
|
|
+/ {
|
|
+ model = "Sipeed Lichee Cluster 4A 16G";
|
|
+ compatible = "sipeed,lichee-cluster-4a", "sipeed,lichee-module-4a", "thead,th1520";
|
|
+
|
|
+ memory@0 {
|
|
+ device_type = "memory";
|
|
+ reg = <0x0 0x00000000 0x4 0x00000000>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts
|
|
new file mode 100644
|
|
index 000000000000..f1116426233f
|
|
--- /dev/null
|
|
+++ b/arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts
|
|
@@ -0,0 +1,45 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright (C) 2024 NekoRouter <nekorouter@outlook.com>
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "th1520-lichee-pi-4a.dts"
|
|
+
|
|
+/ {
|
|
+ model = "Sipeed Lichee Cluster 4A";
|
|
+ compatible = "sipeed,lichee-cluster-4a", "sipeed,lichee-module-4a", "thead,th1520";
|
|
+
|
|
+ /delete-node/ regulator-hub_5v;
|
|
+
|
|
+ /delete-node/ regulator-vcc5v_usb;
|
|
+
|
|
+ /delete-node/ regulator-hub_5v;
|
|
+
|
|
+ /delete-node/ regulator-vcc5v_usb;
|
|
+
|
|
+ /delete-node/ wireless-wlan;
|
|
+
|
|
+ /delete-node/ wireless-bluetooth;
|
|
+
|
|
+ /delete-node/ soc_wcn33_en;
|
|
+};
|
|
+
|
|
+&i2c0 {
|
|
+ status = "okay";
|
|
+
|
|
+ /delete-node/ gpio@18;
|
|
+};
|
|
+
|
|
+&i2c3 {
|
|
+ status = "okay";
|
|
+
|
|
+ /delete-node/ gpio@18;
|
|
+};
|
|
+
|
|
+&usb_dwc3 {
|
|
+ /delete-node/ hub@1;
|
|
+
|
|
+ /delete-node/ hub@2;
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi
|
|
index a802ab110429..8e2d281c7dee 100644
|
|
--- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi
|
|
+++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi
|
|
@@ -15,9 +15,33 @@ memory@0 {
|
|
device_type = "memory";
|
|
reg = <0x0 0x00000000 0x2 0x00000000>;
|
|
};
|
|
+
|
|
+ resmem: reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+ //Note: with "no-map" reserv mem not saved in hibernation
|
|
+ rpmsgmem: memory@1E000000 {
|
|
+ reg = <0x0 0x1E000000 0x0 0x10000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ light_rpmsg: light_rpmsg {
|
|
+ compatible = "light,rpmsg-bus", "simple-bus";
|
|
+ memory-region = <&rpmsgmem>;
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+ rpmsg: rpmsg {
|
|
+ vdev-nums = <1>;
|
|
+ reg = <0x0 0x1E000000 0 0x10000>;
|
|
+ compatible = "light,light-rpmsg";
|
|
+ status = "okay";
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
-&osc {
|
|
+&osc_24m {
|
|
clock-frequency = <24000000>;
|
|
};
|
|
|
|
@@ -25,14 +49,139 @@ &osc_32k {
|
|
clock-frequency = <32768>;
|
|
};
|
|
|
|
+&aonsys_clk {
|
|
+ clock-frequency = <73728000>;
|
|
+};
|
|
+
|
|
&apb_clk {
|
|
clock-frequency = <62500000>;
|
|
};
|
|
|
|
+&sdhci_clk {
|
|
+ clock-frequency = <198000000>;
|
|
+};
|
|
+
|
|
&uart_sclk {
|
|
clock-frequency = <100000000>;
|
|
};
|
|
|
|
+&gmac_clk {
|
|
+ clock-frequency = <500000000>;
|
|
+};
|
|
+
|
|
+&gmac_axi_clk {
|
|
+ clock-frequency = <100000000>;
|
|
+};
|
|
+
|
|
&dmac0 {
|
|
status = "okay";
|
|
};
|
|
+
|
|
+&emmc {
|
|
+ bus-width = <8>;
|
|
+ max-frequency = <198000000>;
|
|
+ mmc-hs400-1_8v;
|
|
+ non-removable;
|
|
+ no-sdio;
|
|
+ no-sd;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&padctrl0_apsys {
|
|
+ sdio0_pins: sdio0-0 {
|
|
+ detn-pins {
|
|
+ pins = "SDIO0_DETN";
|
|
+ function = "sdio";
|
|
+ bias-disable; /* external pull-up */
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&sdio0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&sdio0_pins>;
|
|
+ bus-width = <4>;
|
|
+ max-frequency = <198000000>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&cpus {
|
|
+ c910_0: cpu@0 {
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 650000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 800000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ dvdd-supply = <&dvdd_cpu_reg>;
|
|
+ dvddm-supply = <&dvddm_cpu_reg>;
|
|
+ };
|
|
+ c910_1: cpu@1 {
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 650000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 800000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ dvdd-supply = <&dvdd_cpu_reg>;
|
|
+ dvddm-supply = <&dvddm_cpu_reg>;
|
|
+ };
|
|
+ c910_2: cpu@2 {
|
|
+
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 650000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 800000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ dvdd-supply = <&dvdd_cpu_reg>;
|
|
+ dvddm-supply = <&dvddm_cpu_reg>;
|
|
+ };
|
|
+ c910_3: cpu@3 {
|
|
+
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 650000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 800000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ dvdd-supply = <&dvdd_cpu_reg>;
|
|
+ dvddm-supply = <&dvddm_cpu_reg>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts
|
|
new file mode 100644
|
|
index 000000000000..a3a991baf716
|
|
--- /dev/null
|
|
+++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts
|
|
@@ -0,0 +1,18 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright (C) 2023 Han Gao <gaohan@iscas.ac.cn>
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "th1520-lichee-pi-4a.dts"
|
|
+
|
|
+/ {
|
|
+ model = "Sipeed Lichee Pi 4A 16G";
|
|
+ compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520";
|
|
+
|
|
+ memory@0 {
|
|
+ device_type = "memory";
|
|
+ reg = <0x0 0x00000000 0x4 0x00000000>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts
|
|
index 9a3884a73e13..6c0709e5193f 100644
|
|
--- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts
|
|
+++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts
|
|
@@ -4,29 +4,741 @@
|
|
*/
|
|
|
|
#include "th1520-lichee-module-4a.dtsi"
|
|
+#include <dt-bindings/gpio/gpio.h>
|
|
|
|
/ {
|
|
model = "Sipeed Lichee Pi 4A";
|
|
compatible = "sipeed,lichee-pi-4a", "sipeed,lichee-module-4a", "thead,th1520";
|
|
|
|
aliases {
|
|
+ ethernet0 = &gmac0;
|
|
+ ethernet1 = &gmac1;
|
|
gpio0 = &gpio0;
|
|
gpio1 = &gpio1;
|
|
gpio2 = &gpio2;
|
|
gpio3 = &gpio3;
|
|
+ gpio4 = &gpio4;
|
|
+ gpio5 = &aogpio;
|
|
serial0 = &uart0;
|
|
serial1 = &uart1;
|
|
serial2 = &uart2;
|
|
serial3 = &uart3;
|
|
serial4 = &uart4;
|
|
serial5 = &uart5;
|
|
+ i2c0 = &i2c0;
|
|
+ i2c1 = &i2c1;
|
|
+ i2c2 = &i2c2;
|
|
+ i2c3 = &i2c3;
|
|
+ i2c4 = &i2c4;
|
|
+ i2c5 = &audio_i2c0;
|
|
+ i2c6 = &audio_i2c1;
|
|
+ mmc0 = &emmc;
|
|
+ mmc1 = &sdio0;
|
|
};
|
|
|
|
chosen {
|
|
stdout-path = "serial0:115200n8";
|
|
};
|
|
+
|
|
+ fan: pwm-fan {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&fan_pins>;
|
|
+ compatible = "pwm-fan";
|
|
+ #cooling-cells = <2>;
|
|
+ pwms = <&pwm 1 10000000 0>;
|
|
+ cooling-levels = <0 66 196 255>;
|
|
+ };
|
|
+
|
|
+ hub_5v: regulator-hub_5v {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "HUB_5V";
|
|
+ regulator-min-microvolt = <5000000>;
|
|
+ regulator-max-microvolt = <5000000>;
|
|
+ gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ vcc5v_usb: regulator-vcc5v_usb {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "VCC5V_USB";
|
|
+ regulator-min-microvolt = <5000000>;
|
|
+ regulator-max-microvolt = <5000000>;
|
|
+ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ thermal-zones {
|
|
+ cpu-thermal {
|
|
+ polling-delay = <1000>;
|
|
+ polling-delay-passive = <1000>;
|
|
+ thermal-sensors = <&pvt 0>;
|
|
+
|
|
+ trips {
|
|
+ trip_active0: active-0 {
|
|
+ temperature = <39000>;
|
|
+ hysteresis = <5000>;
|
|
+ type = "active";
|
|
+ };
|
|
+
|
|
+ trip_active1: active-1 {
|
|
+ temperature = <50000>;
|
|
+ hysteresis = <5000>;
|
|
+ type = "active";
|
|
+ };
|
|
+
|
|
+ trip_active2: active-2 {
|
|
+ temperature = <60000>;
|
|
+ hysteresis = <5000>;
|
|
+ type = "active";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ cooling-maps {
|
|
+ map-active-0 {
|
|
+ cooling-device = <&fan 1 1>;
|
|
+ trip = <&trip_active0>;
|
|
+ };
|
|
+
|
|
+ map-active-1 {
|
|
+ cooling-device = <&fan 2 2>;
|
|
+ trip = <&trip_active1>;
|
|
+ };
|
|
+
|
|
+ map-active-2 {
|
|
+ cooling-device = <&fan 3 3>;
|
|
+ trip = <&trip_active2>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ hub_5v: regulator-hub_5v {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "HUB_5V";
|
|
+ regulator-min-microvolt = <5000000>;
|
|
+ regulator-max-microvolt = <5000000>;
|
|
+ gpio = <&ioexp3 3 GPIO_ACTIVE_HIGH>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ vcc5v_usb: regulator-vcc5v_usb {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "VCC5V_USB";
|
|
+ regulator-min-microvolt = <5000000>;
|
|
+ regulator-max-microvolt = <5000000>;
|
|
+ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ wcn_wifi: wireless-wlan {
|
|
+ compatible = "wlan-platdata";
|
|
+ clock-names = "clk_wifi";
|
|
+ ref-clock-frequency = <24000000>;
|
|
+ keep_wifi_power_on;
|
|
+ pinctrl-names = "default";
|
|
+ wifi_chip_type = "rtl8723ds";
|
|
+ WIFI,poweren_gpio = <&ioexp2 5 0>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ wcn_bt: wireless-bluetooth {
|
|
+ compatible = "bluetooth-platdata";
|
|
+ pinctrl-names = "default", "rts_gpio";
|
|
+ BT,power_gpio = <&ioexp2 6 0>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ aon: aon {
|
|
+ compatible = "thead,light-aon";
|
|
+ mbox-names = "aon";
|
|
+ mboxes = <&mbox_910t 1 0>;
|
|
+ status = "okay";
|
|
+
|
|
+ pd: light-aon-pd {
|
|
+ compatible = "thead,light-aon-pd";
|
|
+ #power-domain-cells = <1>;
|
|
+ };
|
|
+
|
|
+ soc_aud_3v3_en_reg: soc_aud_3v3_en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_aud_3v3_en";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_aud_1v8_en_reg: soc_aud_1v8_en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_aud_1v8_en";
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd_3v3_en_reg: soc_vdd_3v3_en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_vdd_3v3_en";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ gpio = <&gpio0 30 1>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd33_lcd0_en_reg: soc_lcd0_vdd33_en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_lcd0_vdd33_en";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ gpio = <&ioexp2 5 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_vdd18_lcd0_en_reg: soc_lcd0_vdd18_en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_lcd0_vdd18_en";
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ gpio = <&ioexp2 6 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_vdd5v_se_en_reg: soc_vdd5v_se_en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_vdd5v_se_en";
|
|
+ regulator-min-microvolt = <5000000>;
|
|
+ regulator-max-microvolt = <5000000>;
|
|
+ gpio = <&gpio2 14 1>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_wcn33_en_reg: soc_wcn33_en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_wcn33_en";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ gpio = <&gpio2 29 1>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vbus_en_reg: soc_vbus_en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_vbus_en";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ gpio = <&gpio1 22 1>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+
|
|
+ soc_avdd28_rgb_reg: soc_avdd28_rgb {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_avdd28_rgb";
|
|
+ regulator-min-microvolt = <2800000>;
|
|
+ regulator-max-microvolt = <2800000>;
|
|
+ gpio = <&ioexp2 1 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_dovdd18_rgb_reg: soc_dovdd18_rgb {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_dovdd18_rgb";
|
|
+ regulator-min-microvolt = <2800000>;
|
|
+ regulator-max-microvolt = <2800000>;
|
|
+ gpio = <&ioexp2 2 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_dvdd12_rgb_reg: soc_dvdd12_rgb {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_dvdd12_rgb";
|
|
+ regulator-min-microvolt = <2800000>;
|
|
+ regulator-max-microvolt = <2800000>;
|
|
+ gpio = <&ioexp2 0 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_avdd25_ir_reg: soc_avdd25_ir {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_avdd25_ir";
|
|
+ regulator-min-microvolt = <2500000>;
|
|
+ regulator-max-microvolt = <2500000>;
|
|
+ gpio = <&ioexp2 5 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_dovdd18_ir_reg: soc_dovdd18_ir {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_dovdd18_ir";
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ gpio = <&ioexp2 3 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_dvdd12_ir_reg: soc_dvdd12_ir {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_dvdd12_ir";
|
|
+ regulator-min-microvolt = <1200000>;
|
|
+ regulator-max-microvolt = <1200000>;
|
|
+ gpio = <&ioexp2 4 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_cam2_avdd25_ir_reg: soc_cam2_avdd25_ir {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_cam2_avdd25_ir";
|
|
+ regulator-min-microvolt = <2500000>;
|
|
+ regulator-max-microvolt = <2500000>;
|
|
+ gpio = <&ioexp2 7 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_cam2_dovdd18_ir_reg: soc_cam2_dovdd18_ir {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_cam2_dovdd18_ir";
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ gpio = <&ioexp2 6 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ soc_cam2_dvdd12_ir_reg: soc_cam2_dvdd12_ir {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "soc_cam2_dvdd12_ir";
|
|
+ regulator-min-microvolt = <1200000>;
|
|
+ regulator-max-microvolt = <1200000>;
|
|
+ gpio = <&ioexp2 0 1>;
|
|
+ enable-active-high;
|
|
+ };
|
|
+
|
|
+ aon_reg_dialog: light-dialog-reg {
|
|
+ compatible = "thead,light-dialog-pmic-ant";
|
|
+ status = "okay";
|
|
+
|
|
+ dvdd_cpu_reg: appcpu_dvdd {
|
|
+ regulator-name = "appcpu_dvdd";
|
|
+ regulator-min-microvolt = <300000>;
|
|
+ regulator-max-microvolt = <1570000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ dvddm_cpu_reg: appcpu_dvddm {
|
|
+ regulator-name = "appcpu_dvddm";
|
|
+ regulator-min-microvolt = <300000>;
|
|
+ regulator-max-microvolt = <1570000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dvdd18_aon_reg: soc_dvdd18_aon {
|
|
+ regulator-name = "soc_dvdd18_aon";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_avdd33_usb3_reg: soc_avdd33_usb3 {
|
|
+ regulator-name = "soc_avdd33_usb3";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dvdd08_aon_reg: soc_dvdd08_aon {
|
|
+ regulator-name = "soc_dvdd08_aon";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dvdd08_ddr_reg: soc_dvdd08_ddr {
|
|
+ regulator-name = "soc_dvdd08_ddr";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd_ddr_1v8_reg: soc_vdd_ddr_1v8 {
|
|
+ regulator-name = "soc_vdd_ddr_1v8";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd_ddr_1v1_reg: soc_vdd_ddr_1v1 {
|
|
+ regulator-name = "soc_vdd_ddr_1v1";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd_ddr_0v6_reg: soc_vdd_ddr_0v6 {
|
|
+ regulator-name = "soc_vdd_ddr_0v6";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dvdd18_ap_reg: soc_dvdd18_ap {
|
|
+ regulator-name = "soc_dvdd18_ap";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_avdd08_mipi_hdmi_reg: soc_avdd08_mipi_hdmi {
|
|
+ regulator-name = "soc_avdd08_mipi_hdmi";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_avdd18_mipi_hdmi_reg: soc_avdd18_mipi_hdmi {
|
|
+ regulator-name = "soc_avdd18_mipi_hdmi";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd33_emmc_reg: soc_vdd33_emmc {
|
|
+ regulator-name = "soc_vdd33_emmc";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd18_emmc_reg: soc_vdd18_emmc {
|
|
+ regulator-name = "soc_vdd18_emmc";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dovdd18_scan_reg: soc_dovdd18_scan {
|
|
+ regulator-name = "soc_dovdd18_scan";
|
|
+ regulator-min-microvolt = <900000>;
|
|
+ regulator-max-microvolt = <3600000>;
|
|
+ };
|
|
+
|
|
+ soc_dvdd12_scan_reg: soc_dvdd12_scan {
|
|
+ regulator-name = "soc_dvdd12_scan";
|
|
+ regulator-min-microvolt = <900000>;
|
|
+ regulator-max-microvolt = <3600000>;
|
|
+ };
|
|
+
|
|
+ soc_avdd28_scan_en_reg: soc_avdd28_scan_en {
|
|
+ regulator-name = "soc_avdd28_scan_en";
|
|
+ regulator-min-microvolt = <900000>;
|
|
+ regulator-max-microvolt = <3600000>;
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ c910_cpufreq {
|
|
+ compatible = "thead,light-mpw-cpufreq";
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ test: light-aon-test {
|
|
+ compatible = "thead,light-aon-test";
|
|
+ };
|
|
+ };
|
|
+
|
|
+};
|
|
+
|
|
+&aogpio {
|
|
+ sel-usb-hub-hog {
|
|
+ gpio-hog;
|
|
+ gpios = <4 GPIO_ACTIVE_HIGH>;
|
|
+ output-high;
|
|
+ };
|
|
+};
|
|
+
|
|
+&gmac0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&gmac0_pins>;
|
|
+ phy-handle = <&phy0>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&gmac1 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&gmac1_pins>;
|
|
+ phy-handle = <&phy1>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&i2c0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&i2c0_pins>;
|
|
+ clock-frequency = <100000>;
|
|
+ i2c-sda-hold-time-ns = <300>;
|
|
+ i2c-sda-falling-time-ns = <510>;
|
|
+ i2c-scl-falling-time-ns = <510>;
|
|
+ status = "okay";
|
|
+
|
|
+ ioexp1: gpio@18 {
|
|
+ compatible = "nxp,pca9557";
|
|
+ reg = <0x18>;
|
|
+ gpio-controller;
|
|
+ #gpio-cells = <2>;
|
|
+ gpio-line-names = "cam0_dvdd12",
|
|
+ "cam0_avdd28",
|
|
+ "cam0_dovdd18";
|
|
+ };
|
|
+};
|
|
+
|
|
+&i2c1 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&i2c1_pins>;
|
|
+ clock-frequency = <100000>;
|
|
+ i2c-sda-hold-time-ns = <300>;
|
|
+ i2c-sda-falling-time-ns = <510>;
|
|
+ i2c-scl-falling-time-ns = <510>;
|
|
+ status = "okay";
|
|
+
|
|
+ ioexp2: gpio@18 {
|
|
+ compatible = "nxp,pca9557";
|
|
+ reg = <0x18>;
|
|
+ gpio-controller;
|
|
+ #gpio-cells = <2>;
|
|
+ gpio-line-names = "",
|
|
+ "cam0_reset",
|
|
+ "cam1_reset",
|
|
+ "cam2_reset",
|
|
+ "wl_host_wake",
|
|
+ "bt_resetn",
|
|
+ "",
|
|
+ "bt_host_wake";
|
|
+ };
|
|
+};
|
|
+
|
|
+&i2c3 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&i2c3_pins>;
|
|
+ clock-frequency = <100000>;
|
|
+ i2c-sda-hold-time-ns = <300>;
|
|
+ i2c-sda-falling-time-ns = <510>;
|
|
+ i2c-scl-falling-time-ns = <510>;
|
|
+ status = "okay";
|
|
+
|
|
+ ioexp3: gpio@18 {
|
|
+ compatible = "nxp,pca9557";
|
|
+ reg = <0x18>;
|
|
+ gpio-controller;
|
|
+ #gpio-cells = <2>;
|
|
+ gpio-line-names = "tp0_rst",
|
|
+ "",
|
|
+ "",
|
|
+ "vcc5v_usb",
|
|
+ "vdd28_tp0",
|
|
+ "vdd33_lcd0",
|
|
+ "vdd18_lcd0",
|
|
+ "lcd0_reset";
|
|
+ };
|
|
+};
|
|
+
|
|
+&mdio0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&mdio0_pins>;
|
|
+
|
|
+ phy0: ethernet-phy@1 {
|
|
+ reg = <1>;
|
|
+ };
|
|
+
|
|
+ phy1: ethernet-phy@2 {
|
|
+ reg = <2>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&padctrl0_apsys {
|
|
+ fan_pins: fan-0 {
|
|
+ pwm1-pins {
|
|
+ pins = "GPIO3_3"; /* PWM1 */
|
|
+ function = "pwm";
|
|
+ bias-disable;
|
|
+ drive-strength = <25>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gmac0_pins: gmac0-0 {
|
|
+ tx-pins {
|
|
+ pins = "GMAC0_TX_CLK",
|
|
+ "GMAC0_TXEN",
|
|
+ "GMAC0_TXD0",
|
|
+ "GMAC0_TXD1",
|
|
+ "GMAC0_TXD2",
|
|
+ "GMAC0_TXD3";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <25>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ rx-pins {
|
|
+ pins = "GMAC0_RX_CLK",
|
|
+ "GMAC0_RXDV",
|
|
+ "GMAC0_RXD0",
|
|
+ "GMAC0_RXD1",
|
|
+ "GMAC0_RXD2",
|
|
+ "GMAC0_RXD3";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gmac1_pins: gmac1-0 {
|
|
+ tx-pins {
|
|
+ pins = "GPIO2_18", /* GMAC1_TX_CLK */
|
|
+ "GPIO2_20", /* GMAC1_TXEN */
|
|
+ "GPIO2_21", /* GMAC1_TXD0 */
|
|
+ "GPIO2_22", /* GMAC1_TXD1 */
|
|
+ "GPIO2_23", /* GMAC1_TXD2 */
|
|
+ "GPIO2_24"; /* GMAC1_TXD3 */
|
|
+ function = "gmac1";
|
|
+ bias-disable;
|
|
+ drive-strength = <25>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ rx-pins {
|
|
+ pins = "GPIO2_19", /* GMAC1_RX_CLK */
|
|
+ "GPIO2_25", /* GMAC1_RXDV */
|
|
+ "GPIO2_30", /* GMAC1_RXD0 */
|
|
+ "GPIO2_31", /* GMAC1_RXD1 */
|
|
+ "GPIO3_0", /* GMAC1_RXD2 */
|
|
+ "GPIO3_1"; /* GMAC1_RXD3 */
|
|
+ function = "gmac1";
|
|
+ bias-disable;
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ i2c3_pins: i2c3-0 {
|
|
+ i2c-pins {
|
|
+ pins = "I2C3_SCL", "I2C3_SDA";
|
|
+ function = "i2c";
|
|
+ bias-disable;
|
|
+ drive-strength = <7>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ mdio0_pins: mdio0-0 {
|
|
+ mdc-pins {
|
|
+ pins = "GMAC0_MDC";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <13>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ mdio-pins {
|
|
+ pins = "GMAC0_MDIO";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <13>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ uart0_pins: uart0-0 {
|
|
+ tx-pins {
|
|
+ pins = "UART0_TXD";
|
|
+ function = "uart";
|
|
+ bias-disable;
|
|
+ drive-strength = <3>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ rx-pins {
|
|
+ pins = "UART0_RXD";
|
|
+ function = "uart";
|
|
+ bias-disable;
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&padctrl1_apsys {
|
|
+ i2c0_pins: i2c0-0 {
|
|
+ i2c-pins {
|
|
+ pins = "I2C0_SCL", "I2C0_SDA";
|
|
+ function = "i2c";
|
|
+ bias-disable;
|
|
+ drive-strength = <7>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ i2c1_pins: i2c1-0 {
|
|
+ i2c-pins {
|
|
+ pins = "I2C1_SCL", "I2C1_SDA";
|
|
+ function = "i2c";
|
|
+ bias-disable;
|
|
+ drive-strength = <7>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
&uart0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&uart0_pins>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&usb {
|
|
status = "okay";
|
|
};
|
|
+
|
|
+&usb_dwc3 {
|
|
+ status = "okay";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ hub_2_0: hub@1 {
|
|
+ compatible = "usb2109,2817";
|
|
+ reg = <1>;
|
|
+ peer-hub = <&hub_3_0>;
|
|
+ vdd-supply = <&hub_5v>;
|
|
+ vbus-supply = <&vcc5v_usb>;
|
|
+ };
|
|
+
|
|
+ hub_3_0: hub@2 {
|
|
+ compatible = "usb2109,817";
|
|
+ reg = <2>;
|
|
+ peer-hub = <&hub_2_0>;
|
|
+ vbus-supply = <&vcc5v_usb>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts b/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts
|
|
new file mode 100644
|
|
index 000000000000..5a6baccd1684
|
|
--- /dev/null
|
|
+++ b/arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts
|
|
@@ -0,0 +1,19 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ * Copyright (C) 2024 Milk-V Limited.
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "th1520-milkv-meles.dts"
|
|
+
|
|
+/ {
|
|
+ model = "Milk-V Meles 4G";
|
|
+ compatible = "milkv,meles", "thead,light";
|
|
+
|
|
+ memory@0 {
|
|
+ device_type = "memory";
|
|
+ reg = <0x0 0x00000000 0x1 0x00000000>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts b/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts
|
|
new file mode 100644
|
|
index 000000000000..394385afd53d
|
|
--- /dev/null
|
|
+++ b/arch/riscv/boot/dts/thead/th1520-milkv-meles.dts
|
|
@@ -0,0 +1,441 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ * Copyright (C) 2024 Milk-V Limited.
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "th1520.dtsi"
|
|
+#include <dt-bindings/gpio/gpio.h>
|
|
+
|
|
+/ {
|
|
+ model = "Milk-V Meles";
|
|
+ compatible = "milkv,meles", "thead,th1520";
|
|
+
|
|
+ aliases {
|
|
+ ethernet0 = &gmac0;
|
|
+ gpio0 = &gpio0;
|
|
+ gpio1 = &gpio1;
|
|
+ gpio2 = &gpio2;
|
|
+ gpio3 = &gpio3;
|
|
+ gpio4 = &gpio4;
|
|
+ gpio5 = &aogpio;
|
|
+ serial0 = &uart0;
|
|
+ serial1 = &uart1;
|
|
+ serial2 = &uart2;
|
|
+ serial3 = &uart3;
|
|
+ serial4 = &uart4;
|
|
+ serial5 = &uart5;
|
|
+ };
|
|
+
|
|
+ chosen {
|
|
+ stdout-path = "serial0:115200n8";
|
|
+ };
|
|
+
|
|
+ memory@0 {
|
|
+ device_type = "memory";
|
|
+ reg = <0x0 0x00000000 0x2 0x00000000>;
|
|
+ };
|
|
+
|
|
+ resmem: reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+ //Note: with "no-map" reserv mem not saved in hibernation
|
|
+ rpmsgmem: memory@1E000000 {
|
|
+ reg = <0x0 0x1E000000 0x0 0x10000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ light_rpmsg: light_rpmsg {
|
|
+ compatible = "light,rpmsg-bus", "simple-bus";
|
|
+ memory-region = <&rpmsgmem>;
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+ rpmsg: rpmsg {
|
|
+ vdev-nums = <1>;
|
|
+ reg = <0x0 0x1E000000 0 0x10000>;
|
|
+ compatible = "light,light-rpmsg";
|
|
+ status = "okay";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ aon: aon {
|
|
+ compatible = "thead,light-aon";
|
|
+ mbox-names = "aon";
|
|
+ mboxes = <&mbox_910t 1 0>;
|
|
+ status = "okay";
|
|
+
|
|
+ pd: light-aon-pd {
|
|
+ compatible = "thead,light-aon-pd";
|
|
+ #power-domain-cells = <1>;
|
|
+ };
|
|
+
|
|
+ aon_reg_dialog: light-dialog-reg {
|
|
+ compatible = "thead,light-dialog-pmic-ant";
|
|
+ status = "okay";
|
|
+
|
|
+ dvdd_cpu_reg: appcpu_dvdd {
|
|
+ regulator-name = "appcpu_dvdd";
|
|
+ regulator-min-microvolt = <300000>;
|
|
+ regulator-max-microvolt = <1570000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ dvddm_cpu_reg: appcpu_dvddm {
|
|
+ regulator-name = "appcpu_dvddm";
|
|
+ regulator-min-microvolt = <300000>;
|
|
+ regulator-max-microvolt = <1570000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dvdd18_aon_reg: soc_dvdd18_aon {
|
|
+ regulator-name = "soc_dvdd18_aon";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_avdd33_usb3_reg: soc_avdd33_usb3 {
|
|
+ regulator-name = "soc_avdd33_usb3";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dvdd08_aon_reg: soc_dvdd08_aon {
|
|
+ regulator-name = "soc_dvdd08_aon";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dvdd08_ddr_reg: soc_dvdd08_ddr {
|
|
+ regulator-name = "soc_dvdd08_ddr";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd_ddr_1v8_reg: soc_vdd_ddr_1v8 {
|
|
+ regulator-name = "soc_vdd_ddr_1v8";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd_ddr_1v1_reg: soc_vdd_ddr_1v1 {
|
|
+ regulator-name = "soc_vdd_ddr_1v1";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd_ddr_0v6_reg: soc_vdd_ddr_0v6 {
|
|
+ regulator-name = "soc_vdd_ddr_0v6";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dvdd18_ap_reg: soc_dvdd18_ap {
|
|
+ regulator-name = "soc_dvdd18_ap";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_avdd08_mipi_hdmi_reg: soc_avdd08_mipi_hdmi {
|
|
+ regulator-name = "soc_avdd08_mipi_hdmi";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_avdd18_mipi_hdmi_reg: soc_avdd18_mipi_hdmi {
|
|
+ regulator-name = "soc_avdd18_mipi_hdmi";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd33_emmc_reg: soc_vdd33_emmc {
|
|
+ regulator-name = "soc_vdd33_emmc";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_vdd18_emmc_reg: soc_vdd18_emmc {
|
|
+ regulator-name = "soc_vdd18_emmc";
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ soc_dovdd18_scan_reg: soc_dovdd18_scan {
|
|
+ regulator-name = "soc_dovdd18_scan";
|
|
+ regulator-min-microvolt = <900000>;
|
|
+ regulator-max-microvolt = <3600000>;
|
|
+ };
|
|
+
|
|
+ soc_dvdd12_scan_reg: soc_dvdd12_scan {
|
|
+ regulator-name = "soc_dvdd12_scan";
|
|
+ regulator-min-microvolt = <900000>;
|
|
+ regulator-max-microvolt = <3600000>;
|
|
+ };
|
|
+
|
|
+ soc_avdd28_scan_en_reg: soc_avdd28_scan_en {
|
|
+ regulator-name = "soc_avdd28_scan_en";
|
|
+ regulator-min-microvolt = <900000>;
|
|
+ regulator-max-microvolt = <3600000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ c910_cpufreq {
|
|
+ compatible = "thead,light-mpw-cpufreq";
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ test: light-aon-test {
|
|
+ compatible = "thead,light-aon-test";
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&osc_24m {
|
|
+ clock-frequency = <24000000>;
|
|
+};
|
|
+
|
|
+&osc_32k {
|
|
+ clock-frequency = <32768>;
|
|
+};
|
|
+
|
|
+&aonsys_clk {
|
|
+ clock-frequency = <73728000>;
|
|
+};
|
|
+
|
|
+&apb_clk {
|
|
+ clock-frequency = <62500000>;
|
|
+};
|
|
+
|
|
+&sdhci_clk {
|
|
+ clock-frequency = <198000000>;
|
|
+};
|
|
+
|
|
+&uart_sclk {
|
|
+ clock-frequency = <100000000>;
|
|
+};
|
|
+
|
|
+&gmac_clk {
|
|
+ clock-frequency = <500000000>;
|
|
+};
|
|
+
|
|
+&gmac_axi_clk {
|
|
+ clock-frequency = <100000000>;
|
|
+};
|
|
+
|
|
+&dmac0 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&emmc {
|
|
+ bus-width = <8>;
|
|
+ max-frequency = <198000000>;
|
|
+ mmc-hs400-1_8v;
|
|
+ non-removable;
|
|
+ no-sdio;
|
|
+ no-sd;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&gmac0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&gmac0_pins>;
|
|
+ phy-handle = <&phy0>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&mdio0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&mdio0_pins>;
|
|
+
|
|
+ phy0: ethernet-phy@1 {
|
|
+ reg = <1>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&sdio0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&sdio0_pins>;
|
|
+ bus-width = <4>;
|
|
+ max-frequency = <198000000>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&uart0 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&uart0_pins>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&cpus {
|
|
+ c910_0: cpu@0 {
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 650000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 800000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ dvdd-supply = <&dvdd_cpu_reg>;
|
|
+ dvddm-supply = <&dvddm_cpu_reg>;
|
|
+ };
|
|
+
|
|
+ c910_1: cpu@1 {
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 650000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 800000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ dvdd-supply = <&dvdd_cpu_reg>;
|
|
+ dvddm-supply = <&dvddm_cpu_reg>;
|
|
+ };
|
|
+
|
|
+ c910_2: cpu@2 {
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 650000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 800000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ dvdd-supply = <&dvdd_cpu_reg>;
|
|
+ dvddm-supply = <&dvddm_cpu_reg>;
|
|
+ };
|
|
+
|
|
+ c910_3: cpu@3 {
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 650000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 800000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ dvdd-supply = <&dvdd_cpu_reg>;
|
|
+ dvddm-supply = <&dvddm_cpu_reg>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&padctrl0_apsys {
|
|
+ gmac0_pins: gmac0-0 {
|
|
+ tx-pins {
|
|
+ pins = "GMAC0_TX_CLK",
|
|
+ "GMAC0_TXEN",
|
|
+ "GMAC0_TXD0",
|
|
+ "GMAC0_TXD1",
|
|
+ "GMAC0_TXD2",
|
|
+ "GMAC0_TXD3";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <25>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ rx-pins {
|
|
+ pins = "GMAC0_RX_CLK",
|
|
+ "GMAC0_RXDV",
|
|
+ "GMAC0_RXD0",
|
|
+ "GMAC0_RXD1",
|
|
+ "GMAC0_RXD2",
|
|
+ "GMAC0_RXD3";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ mdio0_pins: mdio0-0 {
|
|
+ mdc-pins {
|
|
+ pins = "GMAC0_MDC";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <13>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ mdio-pins {
|
|
+ pins = "GMAC0_MDIO";
|
|
+ function = "gmac0";
|
|
+ bias-disable;
|
|
+ drive-strength = <13>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ sdio0_pins: sdio0-0 {
|
|
+ detn-pins {
|
|
+ pins = "SDIO0_DETN";
|
|
+ function = "sdio";
|
|
+ bias-disable; /* external pull-up */
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ uart0_pins: uart0-0 {
|
|
+ tx-pins {
|
|
+ pins = "UART0_TXD";
|
|
+ function = "uart";
|
|
+ bias-disable;
|
|
+ drive-strength = <3>;
|
|
+ input-disable;
|
|
+ input-schmitt-disable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+
|
|
+ rx-pins {
|
|
+ pins = "UART0_RXD";
|
|
+ function = "uart";
|
|
+ bias-disable;
|
|
+ drive-strength = <1>;
|
|
+ input-enable;
|
|
+ input-schmitt-enable;
|
|
+ slew-rate = <0>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi
|
|
index ff364709a6df..fab3b5f17f22 100644
|
|
--- a/arch/riscv/boot/dts/thead/th1520.dtsi
|
|
+++ b/arch/riscv/boot/dts/thead/th1520.dtsi
|
|
@@ -5,6 +5,9 @@
|
|
*/
|
|
|
|
#include <dt-bindings/interrupt-controller/irq.h>
|
|
+#include <dt-bindings/clock/light-fm-ap-clock.h>
|
|
+#include <dt-bindings/gpio/gpio.h>
|
|
+#include <dt-bindings/reset/thead,th1520-reset.h>
|
|
|
|
/ {
|
|
compatible = "thead,th1520";
|
|
@@ -29,6 +32,30 @@ c910_0: cpu@0 {
|
|
d-cache-sets = <512>;
|
|
next-level-cache = <&l2_cache>;
|
|
mmu-type = "riscv,sv39";
|
|
+ cpu-freq = "1.848Ghz";
|
|
+ cpu-cacheline = "64Bytes";
|
|
+
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 600000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 750000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ clock-latency = <61036>;
|
|
+ clocks = <&clk C910_CCLK>,
|
|
+ <&clk C910_CCLK_I0>,
|
|
+ <&clk CPU_PLL1_FOUTPOSTDIV>,
|
|
+ <&clk CPU_PLL0_FOUTPOSTDIV>;
|
|
+ clock-names = "c910_cclk", "c910_cclk_i0",
|
|
+ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv";
|
|
|
|
cpu0_intc: interrupt-controller {
|
|
compatible = "riscv,cpu-intc";
|
|
@@ -50,6 +77,30 @@ c910_1: cpu@1 {
|
|
d-cache-sets = <512>;
|
|
next-level-cache = <&l2_cache>;
|
|
mmu-type = "riscv,sv39";
|
|
+ cpu-freq = "1.848Ghz";
|
|
+ cpu-cacheline = "64Bytes";
|
|
+
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 600000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 750000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ clock-latency = <61036>;
|
|
+ clocks = <&clk C910_CCLK>,
|
|
+ <&clk C910_CCLK_I0>,
|
|
+ <&clk CPU_PLL1_FOUTPOSTDIV>,
|
|
+ <&clk CPU_PLL0_FOUTPOSTDIV>;
|
|
+ clock-names = "c910_cclk", "c910_cclk_i0",
|
|
+ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv";
|
|
|
|
cpu1_intc: interrupt-controller {
|
|
compatible = "riscv,cpu-intc";
|
|
@@ -71,6 +122,30 @@ c910_2: cpu@2 {
|
|
d-cache-sets = <512>;
|
|
next-level-cache = <&l2_cache>;
|
|
mmu-type = "riscv,sv39";
|
|
+ cpu-freq = "1.848Ghz";
|
|
+ cpu-cacheline = "64Bytes";
|
|
+
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 600000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 750000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ clock-latency = <61036>;
|
|
+ clocks = <&clk C910_CCLK>,
|
|
+ <&clk C910_CCLK_I0>,
|
|
+ <&clk CPU_PLL1_FOUTPOSTDIV>,
|
|
+ <&clk CPU_PLL0_FOUTPOSTDIV>;
|
|
+ clock-names = "c910_cclk", "c910_cclk_i0",
|
|
+ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv";
|
|
|
|
cpu2_intc: interrupt-controller {
|
|
compatible = "riscv,cpu-intc";
|
|
@@ -92,6 +167,30 @@ c910_3: cpu@3 {
|
|
d-cache-sets = <512>;
|
|
next-level-cache = <&l2_cache>;
|
|
mmu-type = "riscv,sv39";
|
|
+ cpu-freq = "1.848Ghz";
|
|
+ cpu-cacheline = "64Bytes";
|
|
+
|
|
+ operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 600000
|
|
+ 800000 700000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ light,dvddm-operating-points = <
|
|
+ /* kHz uV */
|
|
+ 300000 750000
|
|
+ 800000 800000
|
|
+ 1500000 800000
|
|
+ 1848000 1000000
|
|
+ >;
|
|
+ clock-latency = <61036>;
|
|
+ clocks = <&clk C910_CCLK>,
|
|
+ <&clk C910_CCLK_I0>,
|
|
+ <&clk CPU_PLL1_FOUTPOSTDIV>,
|
|
+ <&clk CPU_PLL0_FOUTPOSTDIV>;
|
|
+ clock-names = "c910_cclk", "c910_cclk_i0",
|
|
+ "cpu_pll1_foutpostdiv", "cpu_pll0_foutpostdiv";
|
|
|
|
cpu3_intc: interrupt-controller {
|
|
compatible = "riscv,cpu-intc";
|
|
@@ -110,15 +209,111 @@ l2_cache: l2-cache {
|
|
};
|
|
};
|
|
|
|
- osc: oscillator {
|
|
+ pmu {
|
|
+ compatible = "riscv,pmu";
|
|
+ riscv,event-to-mhpmcounters =
|
|
+ <0x00003 0x00003 0x0007fff8>,
|
|
+ <0x00004 0x00004 0x0007fff8>,
|
|
+ <0x00005 0x00005 0x0007fff8>,
|
|
+ <0x00006 0x00006 0x0007fff8>,
|
|
+ <0x00007 0x00007 0x0007fff8>,
|
|
+ <0x00008 0x00008 0x0007fff8>,
|
|
+ <0x00009 0x00009 0x0007fff8>,
|
|
+ <0x0000a 0x0000a 0x0007fff8>,
|
|
+ <0x10000 0x10000 0x0007fff8>,
|
|
+ <0x10001 0x10001 0x0007fff8>,
|
|
+ <0x10002 0x10002 0x0007fff8>,
|
|
+ <0x10003 0x10003 0x0007fff8>,
|
|
+ <0x10010 0x10010 0x0007fff8>,
|
|
+ <0x10011 0x10011 0x0007fff8>,
|
|
+ <0x10012 0x10012 0x0007fff8>,
|
|
+ <0x10013 0x10013 0x0007fff8>;
|
|
+ riscv,event-to-mhpmevent =
|
|
+ <0x00003 0x00000000 0x00000001>,
|
|
+ <0x00004 0x00000000 0x00000002>,
|
|
+ <0x00006 0x00000000 0x00000006>,
|
|
+ <0x00005 0x00000000 0x00000007>,
|
|
+ <0x00007 0x00000000 0x00000008>,
|
|
+ <0x00008 0x00000000 0x00000009>,
|
|
+ <0x00009 0x00000000 0x0000000a>,
|
|
+ <0x0000a 0x00000000 0x0000000b>,
|
|
+ <0x10000 0x00000000 0x0000000c>,
|
|
+ <0x10001 0x00000000 0x0000000d>,
|
|
+ <0x10002 0x00000000 0x0000000e>,
|
|
+ <0x10003 0x00000000 0x0000000f>,
|
|
+ <0x10010 0x00000000 0x00000010>,
|
|
+ <0x10011 0x00000000 0x00000011>,
|
|
+ <0x10012 0x00000000 0x00000012>,
|
|
+ <0x10013 0x00000000 0x00000013>;
|
|
+ riscv,raw-event-to-mhpmcounters =
|
|
+ <0x00000000 0x00000001 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000002 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000003 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000004 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000005 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000006 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000007 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000008 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000009 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000000a 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000000b 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000000c 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000000d 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000000e 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000000f 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000010 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000011 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000012 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000013 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000014 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000015 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000016 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000017 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000018 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000019 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000001a 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000001b 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000001c 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000001d 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000001e 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000001f 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000020 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000021 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000022 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000023 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000024 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000025 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000026 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000027 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000028 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x00000029 0xffffffff 0xffffffff 0x0007fff8>,
|
|
+ <0x00000000 0x0000002a 0xffffffff 0xffffffff 0x0007fff8>;
|
|
+ };
|
|
+
|
|
+ osc_32k: clock-osc-32k {
|
|
compatible = "fixed-clock";
|
|
+ #clock-cells = <0>;
|
|
+ clock-frequency = <32768>;
|
|
+ clock-output-names = "osc_32k";
|
|
+ };
|
|
+
|
|
+ osc_24m: clock-osc-24m {
|
|
+ compatible = "fixed-clock";
|
|
+ #clock-cells = <0>;
|
|
+ clock-frequency = <24000000>;
|
|
clock-output-names = "osc_24m";
|
|
+ };
|
|
+
|
|
+ rc_24m: clock-rc-24m {
|
|
+ compatible = "fixed-clock";
|
|
#clock-cells = <0>;
|
|
+ clock-frequency = <24000000>;
|
|
+ clock-output-names = "rc_24m";
|
|
};
|
|
|
|
- osc_32k: 32k-oscillator {
|
|
+ aonsys_clk: aonsys-clk {
|
|
compatible = "fixed-clock";
|
|
- clock-output-names = "osc_32k";
|
|
+ clock-output-names = "aonsys_clk";
|
|
#clock-cells = <0>;
|
|
};
|
|
|
|
@@ -134,6 +329,36 @@ uart_sclk: uart-sclk-clock {
|
|
#clock-cells = <0>;
|
|
};
|
|
|
|
+ sdhci_clk: sdhci-clock {
|
|
+ compatible = "fixed-clock";
|
|
+ clock-frequency = <198000000>;
|
|
+ clock-output-names = "sdhci_clk";
|
|
+ #clock-cells = <0>;
|
|
+ };
|
|
+
|
|
+ gmac_axi_clk: gmac-axi-clock {
|
|
+ compatible = "fixed-clock";
|
|
+ clock-output-names = "gmac_axi_clk";
|
|
+ #clock-cells = <0>;
|
|
+ };
|
|
+
|
|
+ gmac_clk: gmac-clock {
|
|
+ compatible = "fixed-clock";
|
|
+ clock-output-names = "gmac_clk";
|
|
+ #clock-cells = <0>;
|
|
+ };
|
|
+
|
|
+ stmmac_axi_config: stmmac-axi-config {
|
|
+ snps,wr_osr_lmt = <15>;
|
|
+ snps,rd_osr_lmt = <15>;
|
|
+ snps,blen = <0 0 64 32 0 0 0>;
|
|
+ };
|
|
+
|
|
+ aon_iram: aon-iram@ffffef8000 {
|
|
+ compatible = "syscon";
|
|
+ reg = <0xff 0xffef8000 0x0 0x10000>;
|
|
+ };
|
|
+
|
|
soc {
|
|
compatible = "simple-bus";
|
|
interrupt-parent = <&plic>;
|
|
@@ -142,6 +367,41 @@ soc {
|
|
dma-noncoherent;
|
|
ranges;
|
|
|
|
+ cpurst: cpurst {
|
|
+ compatible = "thead,reset-sample";
|
|
+ entry-reg = <0xff 0xff019050>;
|
|
+ entry-cnt = <4>;
|
|
+ control-reg = <0xff 0xff015004>;
|
|
+ control-val = <0x1c>;
|
|
+ csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
|
|
+ };
|
|
+
|
|
+ light_event: light-event {
|
|
+ compatible = "thead,light-event";
|
|
+ aon-iram-regmap = <&aon_iram>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ audio_i2c0: i2c@ffcb01a000 {
|
|
+ compatible = "snps,designware-i2c";
|
|
+ reg = <0xff 0xcb01a000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ interrupts = <182 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ audio_i2c1: i2c@ffcb01b000 {
|
|
+ compatible = "snps,designware-i2c";
|
|
+ reg = <0xff 0xcb01b000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ interrupts = <183 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
plic: interrupt-controller@ffd8000000 {
|
|
compatible = "thead,th1520-plic", "thead,c900-plic";
|
|
reg = <0xff 0xd8000000 0x0 0x01000000>;
|
|
@@ -164,6 +424,50 @@ clint: timer@ffdc000000 {
|
|
<&cpu3_intc 3>, <&cpu3_intc 7>;
|
|
};
|
|
|
|
+ gmac0: ethernet@ffe7070000 {
|
|
+ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a";
|
|
+ reg = <0xff 0xe7070000 0x0 0x2000>;
|
|
+ interrupts = <66 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "macirq";
|
|
+ clocks = <&gmac_clk>, <&gmac_axi_clk>;
|
|
+ clock-names = "stmmaceth", "pclk";
|
|
+ snps,pbl = <32>;
|
|
+ snps,fixed-burst;
|
|
+ snps,multicast-filter-bins = <64>;
|
|
+ snps,perfect-filter-entries = <32>;
|
|
+ snps,axi-config = <&stmmac_axi_config>;
|
|
+ thead,gmacapb = <&gmac0_apb>;
|
|
+ status = "disabled";
|
|
+
|
|
+ mdio0: mdio {
|
|
+ compatible = "snps,dwmac-mdio";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gmac1: ethernet@ffe7060000 {
|
|
+ compatible = "thead,th1520-dwmac", "snps,dwmac-3.70a";
|
|
+ reg = <0xff 0xe7060000 0x0 0x2000>;
|
|
+ interrupts = <67 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "macirq";
|
|
+ clocks = <&gmac_clk>, <&gmac_axi_clk>;
|
|
+ clock-names = "stmmaceth", "pclk";
|
|
+ snps,pbl = <32>;
|
|
+ snps,fixed-burst;
|
|
+ snps,multicast-filter-bins = <64>;
|
|
+ snps,perfect-filter-entries = <32>;
|
|
+ snps,axi-config = <&stmmac_axi_config>;
|
|
+ thead,gmacapb = <&gmac1_apb>;
|
|
+ status = "disabled";
|
|
+
|
|
+ mdio1: mdio {
|
|
+ compatible = "snps,dwmac-mdio";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
uart0: serial@ffe7014000 {
|
|
compatible = "snps,dw-apb-uart";
|
|
reg = <0xff 0xe7014000 0x0 0x100>;
|
|
@@ -194,17 +498,48 @@ uart3: serial@ffe7f04000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
- gpio2: gpio@ffe7f34000 {
|
|
+ i2c0: i2c@ffe7f20000 {
|
|
+ compatible = "snps,designware-i2c";
|
|
+ reg = <0xff 0xe7f20000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ interrupts = <44 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ i2c1: i2c@ffe7f24000 {
|
|
+ compatible = "snps,designware-i2c";
|
|
+ reg = <0xff 0xe7f24000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ interrupts = <45 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ i2c4: i2c@ffe7f28000 {
|
|
+ compatible = "snps,designware-i2c";
|
|
+ reg = <0xff 0xe7f28000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ interrupts = <48 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ gpio@ffe7f34000 {
|
|
compatible = "snps,dw-apb-gpio";
|
|
reg = <0xff 0xe7f34000 0x0 0x1000>;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
- portc: gpio-controller@0 {
|
|
+ gpio2: gpio-controller@0 {
|
|
compatible = "snps,dw-apb-gpio-port";
|
|
gpio-controller;
|
|
#gpio-cells = <2>;
|
|
ngpios = <32>;
|
|
+ gpio-ranges = <&padctrl0_apsys 0 0 32>;
|
|
reg = <0>;
|
|
interrupt-controller;
|
|
#interrupt-cells = <2>;
|
|
@@ -212,17 +547,18 @@ portc: gpio-controller@0 {
|
|
};
|
|
};
|
|
|
|
- gpio3: gpio@ffe7f38000 {
|
|
+ gpio@ffe7f38000 {
|
|
compatible = "snps,dw-apb-gpio";
|
|
reg = <0xff 0xe7f38000 0x0 0x1000>;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
- portd: gpio-controller@0 {
|
|
+ gpio3: gpio-controller@0 {
|
|
compatible = "snps,dw-apb-gpio-port";
|
|
gpio-controller;
|
|
#gpio-cells = <2>;
|
|
- ngpios = <32>;
|
|
+ ngpios = <23>;
|
|
+ gpio-ranges = <&padctrl0_apsys 0 32 23>;
|
|
reg = <0>;
|
|
interrupt-controller;
|
|
#interrupt-cells = <2>;
|
|
@@ -230,17 +566,34 @@ portd: gpio-controller@0 {
|
|
};
|
|
};
|
|
|
|
- gpio0: gpio@ffec005000 {
|
|
+ padctrl1_apsys: pinctrl@ffe7f3c000 {
|
|
+ compatible = "thead,th1520-group2-pinctrl";
|
|
+ reg = <0xff 0xe7f3c000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ };
|
|
+
|
|
+ gmac0_apb: syscon@ffec003000 {
|
|
+ compatible = "thead,th1520-gmac-apb", "syscon";
|
|
+ reg = <0xff 0xec003000 0x0 0x1000>;
|
|
+ };
|
|
+
|
|
+ gmac1_apb: syscon@ffec004000 {
|
|
+ compatible = "thead,th1520-gmac-apb", "syscon";
|
|
+ reg = <0xff 0xec004000 0x0 0x1000>;
|
|
+ };
|
|
+
|
|
+ gpio@ffec005000 {
|
|
compatible = "snps,dw-apb-gpio";
|
|
reg = <0xff 0xec005000 0x0 0x1000>;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
- porta: gpio-controller@0 {
|
|
+ gpio0: gpio-controller@0 {
|
|
compatible = "snps,dw-apb-gpio-port";
|
|
gpio-controller;
|
|
#gpio-cells = <2>;
|
|
ngpios = <32>;
|
|
+ gpio-ranges = <&padctrl1_apsys 0 0 32>;
|
|
reg = <0>;
|
|
interrupt-controller;
|
|
#interrupt-cells = <2>;
|
|
@@ -248,17 +601,18 @@ porta: gpio-controller@0 {
|
|
};
|
|
};
|
|
|
|
- gpio1: gpio@ffec006000 {
|
|
+ gpio@ffec006000 {
|
|
compatible = "snps,dw-apb-gpio";
|
|
reg = <0xff 0xec006000 0x0 0x1000>;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
- portb: gpio-controller@0 {
|
|
+ gpio1: gpio-controller@0 {
|
|
compatible = "snps,dw-apb-gpio-port";
|
|
gpio-controller;
|
|
#gpio-cells = <2>;
|
|
- ngpios = <32>;
|
|
+ ngpios = <31>;
|
|
+ gpio-ranges = <&padctrl1_apsys 0 32 31>;
|
|
reg = <0>;
|
|
interrupt-controller;
|
|
#interrupt-cells = <2>;
|
|
@@ -266,6 +620,22 @@ portb: gpio-controller@0 {
|
|
};
|
|
};
|
|
|
|
+ padctrl0_apsys: pinctrl@ffec007000 {
|
|
+ compatible = "thead,th1520-group3-pinctrl";
|
|
+ reg = <0xff 0xec007000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ };
|
|
+
|
|
+ i2c2: i2c@ffec00c000 {
|
|
+ compatible = "snps,designware-i2c";
|
|
+ reg = <0xff 0xec00c000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
uart2: serial@ffec010000 {
|
|
compatible = "snps,dw-apb-uart";
|
|
reg = <0xff 0xec010000 0x0 0x4000>;
|
|
@@ -276,6 +646,88 @@ uart2: serial@ffec010000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+ i2c3: i2c@ffec014000 {
|
|
+ compatible = "snps,designware-i2c";
|
|
+ reg = <0xff 0xec014000 0x0 0x1000>;
|
|
+ clocks = <&apb_clk>;
|
|
+ interrupts = <47 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ pwm: pwm@ffec01c000 {
|
|
+ compatible = "thead,th1520-pwm";
|
|
+ reg = <0xff 0xec01c000 0x0 0x4000>;
|
|
+ #pwm-cells = <3>;
|
|
+ clocks = <&osc_24m>;
|
|
+ };
|
|
+
|
|
+ audio_mbox: audio_mbox@0xffefc48000 {
|
|
+ compatible = "thead,light-audio-mbox-reg", "syscon";
|
|
+ reg = <0xff 0xefc48000 0x0 0x1000>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ mbox_910t_client1: mbox_910t_client1 {
|
|
+ compatible = "thead,light-mbox-client";
|
|
+ mbox-names = "902";
|
|
+ mboxes = <&mbox_910t 1 0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ mbox_910t_client2: mbox_910t_client2 {
|
|
+ compatible = "thead,light-mbox-client";
|
|
+ mbox-names = "906";
|
|
+ mboxes = <&mbox_910t 2 0>;
|
|
+ audio-mbox-regmap = <&audio_mbox>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ clk: clock-controller@ffef010000 {
|
|
+ compatible = "thead,light-fm-ree-clk";
|
|
+ reg = <0xff 0xef010000 0x0 0x1000>;
|
|
+ #clock-cells = <1>;
|
|
+ clocks = <&osc_32k>, <&osc_24m>, <&rc_24m>;
|
|
+ clock-names = "osc_32k", "osc_24m", "rc_24m";
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ rst: reset-controller@ffef014000 {
|
|
+ compatible = "thead,th1520-reset", "syscon";
|
|
+ reg = <0xff 0xef014000 0x0 0x1000>;
|
|
+ #reset-cells = <1>;
|
|
+ };
|
|
+
|
|
+ sys_reg: sys_reg@ffef010100 {
|
|
+ compatible = "thead,light_sys_reg";
|
|
+ reg = <0xff 0xef010100 0x0 0x100>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ misc_sysreg: misc_sysreg@ffec02c000 {
|
|
+ compatible = "thead,th1520-misc-sysreg", "syscon";
|
|
+ reg = <0xff 0xec02c000 0x0 0x1000>;
|
|
+ };
|
|
+
|
|
+ usb: usb@ffec03f000 {
|
|
+ compatible = "thead,th1520-usb";
|
|
+ reg = <0xff 0xec03f000 0x0 0x1000>;
|
|
+ thead,misc-sysreg = <&misc_sysreg>;
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ usb_dwc3: usb@ffe7040000 {
|
|
+ compatible = "snps,dwc3";
|
|
+ reg = <0xff 0xe7040000 0x0 0x10000>;
|
|
+ interrupts = <68 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ dr_mode = "host";
|
|
+ snps,usb3_lpm_capable;
|
|
+ status = "disabled";
|
|
+ };
|
|
+ };
|
|
+
|
|
dmac0: dma-controller@ffefc00000 {
|
|
compatible = "snps,axi-dma-1.01a";
|
|
reg = <0xff 0xefc00000 0x0 0x1000>;
|
|
@@ -292,6 +744,33 @@ dmac0: dma-controller@ffefc00000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+ emmc: mmc@ffe7080000 {
|
|
+ compatible = "thead,th1520-dwcmshc";
|
|
+ reg = <0xff 0xe7080000 0x0 0x10000>;
|
|
+ interrupts = <62 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&sdhci_clk>;
|
|
+ clock-names = "core";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ sdio0: mmc@ffe7090000 {
|
|
+ compatible = "thead,th1520-dwcmshc";
|
|
+ reg = <0xff 0xe7090000 0x0 0x10000>;
|
|
+ interrupts = <64 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&sdhci_clk>;
|
|
+ clock-names = "core";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ sdio1: mmc@ffe70a0000 {
|
|
+ compatible = "thead,th1520-dwcmshc";
|
|
+ reg = <0xff 0xe70a0000 0x0 0x10000>;
|
|
+ interrupts = <71 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&sdhci_clk>;
|
|
+ clock-names = "core";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
timer0: timer@ffefc32000 {
|
|
compatible = "snps,dw-apb-timer";
|
|
reg = <0xff 0xefc32000 0x0 0x14>;
|
|
@@ -384,17 +863,18 @@ timer7: timer@ffffc3303c {
|
|
status = "disabled";
|
|
};
|
|
|
|
- ao_gpio0: gpio@fffff41000 {
|
|
+ gpio@fffff41000 {
|
|
compatible = "snps,dw-apb-gpio";
|
|
reg = <0xff 0xfff41000 0x0 0x1000>;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
- porte: gpio-controller@0 {
|
|
+ aogpio: gpio-controller@0 {
|
|
compatible = "snps,dw-apb-gpio-port";
|
|
gpio-controller;
|
|
#gpio-cells = <2>;
|
|
- ngpios = <32>;
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&padctrl_aosys 0 9 16>;
|
|
reg = <0>;
|
|
interrupt-controller;
|
|
#interrupt-cells = <2>;
|
|
@@ -402,22 +882,77 @@ porte: gpio-controller@0 {
|
|
};
|
|
};
|
|
|
|
- ao_gpio1: gpio@fffff52000 {
|
|
+ padctrl_aosys: pinctrl@fffff4a000 {
|
|
+ compatible = "thead,th1520-group1-pinctrl";
|
|
+ reg = <0xff 0xfff4a000 0x0 0x2000>;
|
|
+ clocks = <&aonsys_clk>;
|
|
+ };
|
|
+
|
|
+ pvt: pvt@fffff4e000 {
|
|
+ compatible = "moortec,mr75203";
|
|
+ reg = <0xff 0xfff4e000 0x0 0x80>,
|
|
+ <0xff 0xfff4e080 0x0 0x100>,
|
|
+ <0xff 0xfff4e180 0x0 0x680>,
|
|
+ <0xff 0xfff4e800 0x0 0x600>;
|
|
+ reg-names = "common", "ts", "pd", "vm";
|
|
+ clocks = <&aonsys_clk>;
|
|
+ #thermal-sensor-cells = <1>;
|
|
+ };
|
|
+
|
|
+ gpio@fffff52000 {
|
|
compatible = "snps,dw-apb-gpio";
|
|
reg = <0xff 0xfff52000 0x0 0x1000>;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
- portf: gpio-controller@0 {
|
|
+ gpio4: gpio-controller@0 {
|
|
compatible = "snps,dw-apb-gpio-port";
|
|
gpio-controller;
|
|
#gpio-cells = <2>;
|
|
- ngpios = <32>;
|
|
+ ngpios = <23>;
|
|
+ gpio-ranges = <&padctrl_aosys 0 25 22>, <&padctrl_aosys 22 7 1>;
|
|
reg = <0>;
|
|
interrupt-controller;
|
|
#interrupt-cells = <2>;
|
|
interrupts = <55 IRQ_TYPE_LEVEL_HIGH>;
|
|
};
|
|
};
|
|
+
|
|
+ mbox_910t: mbox@ffffc38000 {
|
|
+ compatible = "thead,light-mbox";
|
|
+ reg = <0xff 0xffc38000 0x0 0x4000>,
|
|
+ <0xff 0xffc44000 0x0 0x1000>,
|
|
+ <0xff 0xffc4c000 0x0 0x1000>,
|
|
+ <0xff 0xffc54000 0x0 0x1000>;
|
|
+ reg-names = "local_base", "remote_icu0", "remote_icu1", "remote_icu2";
|
|
+ #interrupt-cells = <2>;
|
|
+ interrupts = <28 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&apb_clk>;
|
|
+ clock-names = "ipg";
|
|
+ icu_cpu_id = <0>;
|
|
+ #mbox-cells = <2>;
|
|
+ };
|
|
+
|
|
+ watchdog0: watchdog@ffefc30000 {
|
|
+ compatible = "snps,dw-wdt";
|
|
+ reg = <0xff 0xefc30000 0x0 0x1000>;
|
|
+ interrupt-parent = <&plic>;
|
|
+ interrupts = <24>;
|
|
+ clocks = <&clk CLKGEN_WDT0_PCLK>;
|
|
+ clock-names = "tclk";
|
|
+ resets = <&rst TH1520_RESET_WDT0>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ watchdog1: watchdog@ffefc31000 {
|
|
+ compatible = "snps,dw-wdt";
|
|
+ reg = <0xff 0xefc31000 0x0 0x1000>;
|
|
+ interrupt-parent = <&plic>;
|
|
+ interrupts = <25>;
|
|
+ clocks = <&clk CLKGEN_WDT1_PCLK>;
|
|
+ clock-names = "tclk";
|
|
+ resets = <&rst TH1520_RESET_WDT1>;
|
|
+ status = "okay";
|
|
+ };
|
|
};
|
|
};
|
|
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
|
|
index ab86ec3b9eab..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 <asm/alternative.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/cpufeature.h>
|
|
+#include <asm/dma-noncoherent.h>
|
|
#include <asm/errata_list.h>
|
|
#include <asm/hwprobe.h>
|
|
+#include <asm/io.h>
|
|
#include <asm/patch.h>
|
|
#include <asm/vendorid_list.h>
|
|
|
|
@@ -33,6 +35,69 @@ static bool errata_probe_pbmt(unsigned int stage,
|
|
return false;
|
|
}
|
|
|
|
+/*
|
|
+ * th.dcache.ipa rs1 (invalidate, physical address)
|
|
+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
|
|
+ * 0000001 01010 rs1 000 00000 0001011
|
|
+ * th.dcache.iva rs1 (invalidate, virtual address)
|
|
+ * 0000001 00110 rs1 000 00000 0001011
|
|
+ *
|
|
+ * th.dcache.cpa rs1 (clean, physical address)
|
|
+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
|
|
+ * 0000001 01001 rs1 000 00000 0001011
|
|
+ * th.dcache.cva rs1 (clean, virtual address)
|
|
+ * 0000001 00101 rs1 000 00000 0001011
|
|
+ *
|
|
+ * th.dcache.cipa rs1 (clean then invalidate, physical address)
|
|
+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
|
|
+ * 0000001 01011 rs1 000 00000 0001011
|
|
+ * th.dcache.civa rs1 (clean then invalidate, virtual address)
|
|
+ * 0000001 00111 rs1 000 00000 0001011
|
|
+ *
|
|
+ * th.sync.s (make sure all cache operations finished)
|
|
+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
|
|
+ * 0000000 11001 00000 000 00000 0001011
|
|
+ */
|
|
+#define THEAD_INVAL_A0 ".long 0x02a5000b"
|
|
+#define THEAD_CLEAN_A0 ".long 0x0295000b"
|
|
+#define THEAD_FLUSH_A0 ".long 0x02b5000b"
|
|
+#define THEAD_SYNC_S ".long 0x0190000b"
|
|
+
|
|
+#define THEAD_CMO_OP(_op, _start, _size, _cachesize) \
|
|
+asm volatile("mv a0, %1\n\t" \
|
|
+ "j 2f\n\t" \
|
|
+ "3:\n\t" \
|
|
+ THEAD_##_op##_A0 "\n\t" \
|
|
+ "add a0, a0, %0\n\t" \
|
|
+ "2:\n\t" \
|
|
+ "bltu a0, %2, 3b\n\t" \
|
|
+ THEAD_SYNC_S \
|
|
+ : : "r"(_cachesize), \
|
|
+ "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \
|
|
+ "r"((unsigned long)(_start) + (_size)) \
|
|
+ : "a0")
|
|
+
|
|
+static void thead_errata_cache_inv(phys_addr_t paddr, size_t size)
|
|
+{
|
|
+ THEAD_CMO_OP(INVAL, paddr, size, riscv_cbom_block_size);
|
|
+}
|
|
+
|
|
+static void thead_errata_cache_wback(phys_addr_t paddr, size_t size)
|
|
+{
|
|
+ THEAD_CMO_OP(CLEAN, paddr, size, riscv_cbom_block_size);
|
|
+}
|
|
+
|
|
+static void thead_errata_cache_wback_inv(phys_addr_t paddr, size_t size)
|
|
+{
|
|
+ THEAD_CMO_OP(FLUSH, paddr, size, riscv_cbom_block_size);
|
|
+}
|
|
+
|
|
+static const struct riscv_nonstd_cache_ops thead_errata_cmo_ops = {
|
|
+ .wback = &thead_errata_cache_wback_inv,
|
|
+ .inv = &thead_errata_cache_inv,
|
|
+ .wback_inv = &thead_errata_cache_wback_inv,
|
|
+};
|
|
+
|
|
static bool errata_probe_cmo(unsigned int stage,
|
|
unsigned long arch_id, unsigned long impid)
|
|
{
|
|
@@ -48,6 +113,7 @@ static bool errata_probe_cmo(unsigned int stage,
|
|
if (stage == RISCV_ALTERNATIVES_BOOT) {
|
|
riscv_cbom_block_size = L1_CACHE_BYTES;
|
|
riscv_noncoherent_supported();
|
|
+ riscv_noncoherent_register_cache_ops(&thead_errata_cmo_ops);
|
|
}
|
|
|
|
return true;
|
|
@@ -77,8 +143,7 @@ static u32 thead_errata_probe(unsigned int stage,
|
|
if (errata_probe_pbmt(stage, archid, impid))
|
|
cpu_req_errata |= BIT(ERRATA_THEAD_PBMT);
|
|
|
|
- if (errata_probe_cmo(stage, archid, impid))
|
|
- cpu_req_errata |= BIT(ERRATA_THEAD_CMO);
|
|
+ errata_probe_cmo(stage, archid, impid);
|
|
|
|
if (errata_probe_pmu(stage, archid, impid))
|
|
cpu_req_errata |= BIT(ERRATA_THEAD_PMU);
|
|
diff --git a/arch/riscv/include/asm/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 <linux/sizes.h>
|
|
#include <linux/pgtable.h>
|
|
#include <asm/page.h>
|
|
+#ifdef CONFIG_HIGHMEM
|
|
+#include <linux/threads.h>
|
|
+#include <asm/kmap_size.h>
|
|
+#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 <asm/kmap_size.h>
|
|
+#include <asm/pgtable.h>
|
|
+#include <asm/fixmap.h>
|
|
+
|
|
+#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 <asm/csr.h>
|
|
|
|
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 <takahiro.akashi@linaro.org>
|
|
+ */
|
|
+#define pr_fmt(fmt) "kexec_file(Image): " fmt
|
|
+
|
|
+#include <linux/err.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/kexec.h>
|
|
+#include <linux/pe.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/verification.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_fdt.h>
|
|
+#include <linux/libfdt.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/memblock.h>
|
|
+#include <linux/types.h>
|
|
+#include <asm/byteorder.h>
|
|
+#include <asm/image.h>
|
|
+
|
|
+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 <linux/kexec.h>
|
|
|
|
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 <asm/delay.h>
|
|
#include <asm/kvm_vcpu_timer.h>
|
|
|
|
+#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..bab2654aae48 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 <asm/highmem.h>
|
|
+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);
|
|
@@ -1268,7 +1429,7 @@ static void __init create_linear_mapping_page_table(void)
|
|
if (end >= __pa(PAGE_OFFSET) + memory_limit)
|
|
end = __pa(PAGE_OFFSET) + memory_limit;
|
|
|
|
- create_linear_mapping_range(start, end, 0);
|
|
+ create_linear_mapping_range(start, end, PMD_SIZE);
|
|
}
|
|
|
|
#ifdef CONFIG_STRICT_KERNEL_RWX
|
|
@@ -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 <linux/pagewalk.h>
|
|
#include <linux/pgtable.h>
|
|
-#include <linux/vmalloc.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/bitops.h>
|
|
#include <asm/set_memory.h>
|
|
@@ -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 <linux/platform_device.h>
|
|
#include "ipmi_si.h"
|
|
#include "ipmi_plat_data.h"
|
|
-
|
|
+#include <linux/pci.h>
|
|
/*
|
|
* 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 <linux/of_device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/log2.h>
|
|
+
|
|
+#include "clk.h"
|
|
+
|
|
+/*
|
|
+ * @hw: handle between common and hardware-specific interfaces
|
|
+ * @reg: register containing divider
|
|
+ * @shift: shift to the divider bit field
|
|
+ * @width: width of the divider bit field
|
|
+ * @initial_val:initial value of the divider
|
|
+ * @table: the div table that the divider supports
|
|
+ * @lock: register lock
|
|
+ */
|
|
+struct mango_clk_divider {
|
|
+ struct clk_hw hw;
|
|
+ void __iomem *reg;
|
|
+ u8 shift;
|
|
+ u8 width;
|
|
+ u8 flags;
|
|
+ u32 initial_val;
|
|
+ const struct clk_div_table *table;
|
|
+ spinlock_t *lock;
|
|
+};
|
|
+
|
|
+static unsigned long mango_clk_divider_recalc_rate(struct clk_hw *hw,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct device_node *node;
|
|
+ struct of_phandle_args clkspec;
|
|
+ int rc, index = 0;
|
|
+ u32 rate;
|
|
+ struct property *prop;
|
|
+ const __be32 *cur;
|
|
+ struct clk *clk;
|
|
+
|
|
+ node = of_find_node_by_name(NULL, "default_rates");
|
|
+
|
|
+ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) {
|
|
+ if (rate) {
|
|
+ rc = of_parse_phandle_with_args(node, "clocks",
|
|
+ "#clock-cells", index, &clkspec);
|
|
+ if (rc < 0) {
|
|
+ /* skip empty (null) phandles */
|
|
+ if (rc == -ENOENT)
|
|
+ continue;
|
|
+ else
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ clk = of_clk_get_from_provider(&clkspec);
|
|
+ if (IS_ERR(clk))
|
|
+ return PTR_ERR(clk);
|
|
+ if (!strcmp(clk_hw_get_name(hw), __clk_get_name(clk)))
|
|
+ return rate;
|
|
+ }
|
|
+ index++;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static long mango_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
|
+ unsigned long *prate)
|
|
+{
|
|
+ return rate;
|
|
+}
|
|
+
|
|
+static int mango_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @hw: ccf use to hook get mango_pll_clock
|
|
+ * @parent_rate: parent rate
|
|
+ *
|
|
+ * The is function will be called through clk_get_rate
|
|
+ * and return current rate after decoding reg value
|
|
+ */
|
|
+static unsigned long mango_clk_pll_recalc_rate(struct clk_hw *hw,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct device_node *node;
|
|
+ struct of_phandle_args clkspec;
|
|
+ int rc, index = 0;
|
|
+ u32 rate;
|
|
+ struct property *prop;
|
|
+ const __be32 *cur;
|
|
+
|
|
+ node = of_find_node_by_name(NULL, "default_rates");
|
|
+
|
|
+ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) {
|
|
+ if (rate) {
|
|
+ rc = of_parse_phandle_with_args(node, "clocks",
|
|
+ "#clock-cells", index, &clkspec);
|
|
+ if (rc < 0) {
|
|
+ /* skip empty (null) phandles */
|
|
+ if (rc == -ENOENT)
|
|
+ continue;
|
|
+ else
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ if (!strncmp(clk_hw_get_name(hw), clkspec.np->name, 4))
|
|
+ return rate;
|
|
+ }
|
|
+ index++;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static long mango_clk_pll_round_rate(struct clk_hw *hw,
|
|
+ unsigned long req_rate, unsigned long *prate)
|
|
+{
|
|
+ return req_rate;
|
|
+}
|
|
+
|
|
+static int mango_clk_pll_determine_rate(struct clk_hw *hw,
|
|
+ struct clk_rate_request *req)
|
|
+{
|
|
+ req->rate = mango_clk_pll_round_rate(hw, min(req->rate, req->max_rate),
|
|
+ &req->best_parent_rate);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mango_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+const struct clk_ops dm_mango_clk_divider_ops = {
|
|
+ .recalc_rate = mango_clk_divider_recalc_rate,
|
|
+ .round_rate = mango_clk_divider_round_rate,
|
|
+ .set_rate = mango_clk_divider_set_rate,
|
|
+};
|
|
+
|
|
+const struct clk_ops dm_mango_clk_divider_ro_ops = {
|
|
+ .recalc_rate = mango_clk_divider_recalc_rate,
|
|
+ .round_rate = mango_clk_divider_round_rate,
|
|
+};
|
|
+
|
|
+const struct clk_ops dm_mango_clk_pll_ops = {
|
|
+ .recalc_rate = mango_clk_pll_recalc_rate,
|
|
+ .round_rate = mango_clk_pll_round_rate,
|
|
+ .determine_rate = mango_clk_pll_determine_rate,
|
|
+ .set_rate = mango_clk_pll_set_rate,
|
|
+};
|
|
+
|
|
+const struct clk_ops dm_mango_clk_pll_ro_ops = {
|
|
+ .recalc_rate = mango_clk_pll_recalc_rate,
|
|
+ .round_rate = mango_clk_pll_round_rate,
|
|
+};
|
|
+
|
|
+struct mux_cb_clk_name {
|
|
+ const char *name;
|
|
+ struct list_head node;
|
|
+};
|
|
+
|
|
+static struct list_head mux_cb_clk_name_list =
|
|
+ LIST_HEAD_INIT(mux_cb_clk_name_list);
|
|
+static int mux_notifier_cb(struct notifier_block *nb,
|
|
+ unsigned long event, void *data)
|
|
+{
|
|
+ int ret = 0;
|
|
+ static unsigned char mux_id = 1;
|
|
+ struct clk_notifier_data *ndata = data;
|
|
+ struct clk_hw *hw = __clk_get_hw(ndata->clk);
|
|
+ const struct clk_ops *ops = &clk_mux_ops;
|
|
+ struct mux_cb_clk_name *cb_lsit;
|
|
+
|
|
+ if (event == PRE_RATE_CHANGE) {
|
|
+ struct clk_hw *hw_p = clk_hw_get_parent(hw);
|
|
+
|
|
+ cb_lsit = kmalloc(sizeof(*cb_lsit), GFP_KERNEL);
|
|
+ if (cb_lsit) {
|
|
+ INIT_LIST_HEAD(&cb_lsit->node);
|
|
+ list_add_tail(&cb_lsit->node, &mux_cb_clk_name_list);
|
|
+ } else {
|
|
+ pr_err("mux cb kmalloc mem fail\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ cb_lsit->name = clk_hw_get_name(hw_p);
|
|
+ mux_id = ops->get_parent(hw);
|
|
+ if (mux_id > 1) {
|
|
+ ret = 1;
|
|
+ goto out;
|
|
+ }
|
|
+ ops->set_parent(hw, !mux_id);
|
|
+ } else if (event == POST_RATE_CHANGE) {
|
|
+ struct clk_hw *hw_p = clk_hw_get_parent(hw);
|
|
+
|
|
+ cb_lsit = list_first_entry_or_null(&mux_cb_clk_name_list,
|
|
+ typeof(*cb_lsit), node);
|
|
+ if (cb_lsit) {
|
|
+ const char *pre_name = cb_lsit->name;
|
|
+
|
|
+ list_del_init(&cb_lsit->node);
|
|
+ kfree(cb_lsit);
|
|
+ if (strcmp(clk_hw_get_name(hw_p), pre_name))
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ops->set_parent(hw, mux_id);
|
|
+ }
|
|
+
|
|
+out:
|
|
+ return notifier_from_errno(ret);
|
|
+}
|
|
+
|
|
+int dm_set_default_clk_rates(struct device_node *node)
|
|
+{
|
|
+ struct of_phandle_args clkspec;
|
|
+ struct property *prop;
|
|
+ const __be32 *cur;
|
|
+ int rc, index = 0;
|
|
+ struct clk *clk;
|
|
+ u32 rate;
|
|
+
|
|
+ of_property_for_each_u32 (node, "clock-rates", prop, cur, rate) {
|
|
+ if (rate) {
|
|
+ rc = of_parse_phandle_with_args(node, "clocks",
|
|
+ "#clock-cells", index, &clkspec);
|
|
+ if (rc < 0) {
|
|
+ /* skip empty (null) phandles */
|
|
+ if (rc == -ENOENT)
|
|
+ continue;
|
|
+ else
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ clk = of_clk_get_from_provider(&clkspec);
|
|
+ if (IS_ERR(clk)) {
|
|
+ pr_warn("clk: couldn't get clock %d for %s\n",
|
|
+ index, node->full_name);
|
|
+ return PTR_ERR(clk);
|
|
+ }
|
|
+
|
|
+ rc = clk_set_rate(clk, rate);
|
|
+ if (rc < 0)
|
|
+ pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
|
|
+ __clk_get_name(clk), rate, rc,
|
|
+ clk_get_rate(clk));
|
|
+ clk_put(clk);
|
|
+ }
|
|
+ index++;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct clk *__register_divider_clks(struct device *dev, const char *name,
|
|
+ const char *parent_name,
|
|
+ unsigned long flags,
|
|
+ void __iomem *reg, u8 shift,
|
|
+ u8 width, u32 initial_val,
|
|
+ u8 clk_divider_flags,
|
|
+ const struct clk_div_table *table,
|
|
+ spinlock_t *lock)
|
|
+{
|
|
+ struct mango_clk_divider *div;
|
|
+ struct clk_hw *hw;
|
|
+ struct clk_init_data init;
|
|
+ int ret;
|
|
+
|
|
+ if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
|
|
+ if (width + shift > 16) {
|
|
+ pr_warn("divider value exceeds LOWORD field\n");
|
|
+ return ERR_PTR(-EINVAL);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* allocate the divider */
|
|
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
|
|
+ if (!div)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ init.name = name;
|
|
+ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
|
|
+ init.ops = &dm_mango_clk_divider_ro_ops;
|
|
+ else
|
|
+ init.ops = &dm_mango_clk_divider_ops;
|
|
+ init.flags = flags;
|
|
+ init.parent_names = (parent_name ? &parent_name : NULL);
|
|
+ init.num_parents = (parent_name ? 1 : 0);
|
|
+
|
|
+ /* struct mango_clk_divider assignments */
|
|
+ div->reg = reg;
|
|
+ div->shift = shift;
|
|
+ div->width = width;
|
|
+ div->flags = clk_divider_flags;
|
|
+ div->lock = lock;
|
|
+ div->hw.init = &init;
|
|
+ div->table = table;
|
|
+ div->initial_val = initial_val;
|
|
+
|
|
+ /* register the clock */
|
|
+ hw = &div->hw;
|
|
+ ret = clk_hw_register(dev, hw);
|
|
+ if (ret) {
|
|
+ kfree(div);
|
|
+ hw = ERR_PTR(ret);
|
|
+ return ERR_PTR(-EBUSY);
|
|
+ }
|
|
+
|
|
+ return hw->clk;
|
|
+}
|
|
+
|
|
+static inline int register_provider_clks
|
|
+(struct device_node *node, struct mango_clk_data *clk_data, int clk_num)
|
|
+{
|
|
+ return of_clk_add_provider(node, of_clk_src_onecell_get,
|
|
+ &clk_data->clk_data);
|
|
+}
|
|
+
|
|
+static int register_gate_clks(struct device *dev, struct mango_clk_data *clk_data)
|
|
+{
|
|
+ struct clk *clk;
|
|
+ const struct mango_clk_table *table = clk_data->table;
|
|
+ const struct mango_gate_clock *gate_clks = table->gate_clks;
|
|
+ void __iomem *base = clk_data->base;
|
|
+ int clk_num = table->gate_clks_num;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < clk_num; i++) {
|
|
+ clk = clk_register_gate(
|
|
+ dev, gate_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 <linux/of_address.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <dt-bindings/clock/sophgo-mango-clock.h>
|
|
+
|
|
+#include "clk.h"
|
|
+
|
|
+/* fixed clocks */
|
|
+struct mango_pll_clock mango_root_pll_clks[] = {
|
|
+ {
|
|
+ .id = FPLL_CLK,
|
|
+ .name = "fpll_clock",
|
|
+ .parent_name = "cgi",
|
|
+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
|
|
+ .ini_flags = MANGO_CLK_RO,
|
|
+ }, {
|
|
+ .id = DPLL0_CLK,
|
|
+ .name = "dpll0_clock",
|
|
+ .parent_name = "cgi",
|
|
+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
|
|
+ .ini_flags = MANGO_CLK_RO,
|
|
+ .status_offset = 0xc0,
|
|
+ .enable_offset = 0xc4,
|
|
+ }, {
|
|
+ .id = DPLL1_CLK,
|
|
+ .name = "dpll1_clock",
|
|
+ .parent_name = "cgi",
|
|
+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
|
|
+ .ini_flags = MANGO_CLK_RO,
|
|
+ .status_offset = 0xc0,
|
|
+ .enable_offset = 0xc4,
|
|
+ }, {
|
|
+ .id = MPLL_CLK,
|
|
+ .name = "mpll_clock",
|
|
+ .parent_name = "cgi",
|
|
+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
|
|
+ .status_offset = 0xc0,
|
|
+ .enable_offset = 0xc4,
|
|
+ },{
|
|
+ .id = FPLL_CLK,
|
|
+ .name = "s1_fpll_clock",
|
|
+ .parent_name = "s1_cgi",
|
|
+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
|
|
+ .ini_flags = MANGO_CLK_RO,
|
|
+ }, {
|
|
+ .id = DPLL0_CLK,
|
|
+ .name = "s1_dpll0_clock",
|
|
+ .parent_name = "s1_cgi",
|
|
+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
|
|
+ .ini_flags = MANGO_CLK_RO,
|
|
+ .status_offset = 0xc0,
|
|
+ .enable_offset = 0xc4,
|
|
+ }, {
|
|
+ .id = DPLL1_CLK,
|
|
+ .name = "s1_dpll1_clock",
|
|
+ .parent_name = "s1_cgi",
|
|
+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
|
|
+ .ini_flags = MANGO_CLK_RO,
|
|
+ .status_offset = 0xc0,
|
|
+ .enable_offset = 0xc4,
|
|
+ }, {
|
|
+ .id = MPLL_CLK,
|
|
+ .name = "s1_mpll_clock",
|
|
+ .parent_name = "s1_cgi",
|
|
+ .flags = CLK_GET_RATE_NOCACHE | CLK_GET_ACCURACY_NOCACHE,
|
|
+ .status_offset = 0xc0,
|
|
+ .enable_offset = 0xc4,
|
|
+ }
|
|
+};
|
|
+
|
|
+/* divider clocks */
|
|
+static const struct mango_divider_clock s0_div_clks[] = {
|
|
+ { DIV_CLK_MPLL_RP_CPU_NORMAL_0, "clk_div_rp_cpu_normal_0", "clk_gate_rp_cpu_normal_div0",
|
|
+ 0, 0x2044, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_MPLL_AXI_DDR_0, "clk_div_axi_ddr_0", "clk_gate_axi_ddr_div0",
|
|
+ 0, 0x20a8, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5},
|
|
+ { DIV_CLK_FPLL_DDR01_1, "clk_div_ddr01_1", "clk_gate_ddr01_div1",
|
|
+ 0, 0x20b0, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
|
|
+ { DIV_CLK_FPLL_DDR23_1, "clk_div_ddr23_1", "clk_gate_ddr23_div1",
|
|
+ 0, 0x20b8, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
|
|
+ { DIV_CLK_FPLL_RP_CPU_NORMAL_1, "clk_div_rp_cpu_normal_1", "clk_gate_rp_cpu_normal_div1",
|
|
+ 0, 0x2040, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_50M_A53, "clk_div_50m_a53", "fpll_clock",
|
|
+ 0, 0x2048, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_TOP_RP_CMN_DIV2, "clk_div_top_rp_cmn_div2", "clk_mux_rp_cpu_normal",
|
|
+ 0, 0x204c, 16, 16, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_UART_500M, "clk_div_uart_500m", "fpll_clock",
|
|
+ 0, 0x2050, 16, 7, CLK_DIVIDER_READ_ONLY, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_AHB_LPC, "clk_div_ahb_lpc", "fpll_clock",
|
|
+ 0, 0x2054, 16, 16, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_EFUSE, "clk_div_efuse", "fpll_clock",
|
|
+ 0, 0x2078, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_TX_ETH0, "clk_div_tx_eth0", "fpll_clock",
|
|
+ 0, 0x2080, 16, 11, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_PTP_REF_I_ETH0, "clk_div_ptp_ref_i_eth0", "fpll_clock",
|
|
+ 0, 0x2084, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_REF_ETH0, "clk_div_ref_eth0", "fpll_clock",
|
|
+ 0, 0x2088, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_EMMC, "clk_div_emmc", "fpll_clock",
|
|
+ 0, 0x208c, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_SD, "clk_div_sd", "fpll_clock",
|
|
+ 0, 0x2094, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_TOP_AXI0, "clk_div_top_axi0", "fpll_clock",
|
|
+ 0, 0x209c, 16, 5, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_TOP_AXI_HSPERI, "clk_div_top_axi_hsperi", "fpll_clock",
|
|
+ 0, 0x20a0, 16, 5, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_AXI_DDR_1, "clk_div_axi_ddr_1", "clk_gate_axi_ddr_div1",
|
|
+ 0, 0x20a4, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, 5},
|
|
+ { DIV_CLK_FPLL_DIV_TIMER1, "clk_div_timer1", "clk_div_50m_a53",
|
|
+ 0, 0x2058, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_DIV_TIMER2, "clk_div_timer2", "clk_div_50m_a53",
|
|
+ 0, 0x205c, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_DIV_TIMER3, "clk_div_timer3", "clk_div_50m_a53",
|
|
+ 0, 0x2060, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_DIV_TIMER4, "clk_div_timer4", "clk_div_50m_a53",
|
|
+ 0, 0x2064, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_DIV_TIMER5, "clk_div_timer5", "clk_div_50m_a53",
|
|
+ 0, 0x2068, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_DIV_TIMER6, "clk_div_timer6", "clk_div_50m_a53",
|
|
+ 0, 0x206c, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_DIV_TIMER7, "clk_div_timer7", "clk_div_50m_a53",
|
|
+ 0, 0x2070, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_DIV_TIMER8, "clk_div_timer8", "clk_div_50m_a53",
|
|
+ 0, 0x2074, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_100K_EMMC, "clk_div_100k_emmc", "clk_div_top_axi0",
|
|
+ 0, 0x2090, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_100K_SD, "clk_div_100k_sd", "clk_div_top_axi0",
|
|
+ 0, 0x2098, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_FPLL_GPIO_DB, "clk_div_gpio_db", "clk_div_top_axi0",
|
|
+ 0, 0x207c, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_REG_VAL, },
|
|
+ { DIV_CLK_DPLL0_DDR01_0, "clk_div_ddr01_0", "clk_gate_ddr01_div0",
|
|
+ 0, 0x20ac, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
|
|
+ { DIV_CLK_DPLL1_DDR23_0, "clk_div_ddr23_0", "clk_gate_ddr23_div0",
|
|
+ 0, 0x20b4, 16, 8, CLK_DIVIDER_ONE_BASED |
|
|
+ CLK_DIVIDER_ALLOW_ZERO, MANGO_CLK_USE_INIT_VAL, },
|
|
+};
|
|
+
|
|
+/* gate clocks */
|
|
+static const struct mango_gate_clock s0_gate_clks[] = {
|
|
+ { GATE_CLK_RP_CPU_NORMAL_DIV0, "clk_gate_rp_cpu_normal_div1", "mpll_clock",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 },
|
|
+ { GATE_CLK_AXI_DDR_DIV0, "clk_gate_axi_ddr_div1", "mpll_clock",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 },
|
|
+ { GATE_CLK_DDR01_DIV0, "clk_gate_ddr01_div0", "fpll_clock",
|
|
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 14, 0 },
|
|
+ { GATE_CLK_DDR23_DIV0, "clk_gate_ddr23_div0", "fpll_clock",
|
|
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 15, 0 },
|
|
+ { GATE_CLK_RP_CPU_NORMAL_DIV1, "clk_gate_rp_cpu_normal_div0", "fpll_clock",
|
|
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2000, 0, 0 },
|
|
+ { GATE_CLK_AXI_DDR_DIV1, "clk_gate_axi_ddr_div0", "fpll_clock",
|
|
+ CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 13, 0 },
|
|
+ { GATE_CLK_DDR01_DIV1, "clk_gate_ddr01_div1", "dpll0_clock",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 14, 0 },
|
|
+ { GATE_CLK_DDR23_DIV1, "clk_gate_ddr23_div1", "dpll1_clock",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 15, 0 },
|
|
+ { GATE_CLK_A53_50M, "clk_gate_a53_50m", "clk_div_50m_a53",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 1, 0 },
|
|
+ { GATE_CLK_TOP_RP_CMN_DIV2, "clk_gate_top_rp_cmn_div2", "clk_gate_rp_cpu_normal",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 2, 0 },
|
|
+ { GATE_CLK_AXI_PCIE0, "clk_gate_axi_pcie0", "clk_gate_rp_cpu_normal",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 8, 0 },
|
|
+ { GATE_CLK_AXI_PCIE1, "clk_gate_axi_pcie1", "clk_gate_rp_cpu_normal",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2004, 9, 0 },
|
|
+ { GATE_CLK_HSDMA, "clk_gate_hsdma", "clk_gate_top_rp_cmn_div2",
|
|
+ CLK_SET_RATE_PARENT, 0x2004, 10, 0 },
|
|
+ { GATE_CLK_EMMC_100M, "clk_gate_emmc", "clk_div_emmc",
|
|
+ CLK_SET_RATE_PARENT, 0x2004, 3, 0 },
|
|
+ { GATE_CLK_SD_100M, "clk_gate_sd", "clk_div_sd",
|
|
+ CLK_SET_RATE_PARENT, 0x2004, 6, 0 },
|
|
+ { GATE_CLK_TX_ETH0, "clk_gate_tx_eth0", "clk_div_tx_eth0",
|
|
+ CLK_SET_RATE_PARENT, 0x2000, 30, 0 },
|
|
+ { GATE_CLK_PTP_REF_I_ETH0, "clk_gate_ptp_ref_i_eth0", "clk_div_ptp_ref_i_eth0",
|
|
+ CLK_SET_RATE_PARENT, 0x2004, 0, 0 },
|
|
+ { GATE_CLK_REF_ETH0, "clk_gate_ref_eth0", "clk_div_ref_eth0",
|
|
+ CLK_SET_RATE_PARENT, 0x2004, 1, 0 },
|
|
+ { GATE_CLK_UART_500M, "clk_gate_uart_500m", "clk_div_uart_500m",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0x2000, 4, 0 },
|
|
+ { GATE_CLK_AHB_LPC, "clk_gate_ahb_lpc", "clk_div_ahb_lpc",
|
|
+ CLK_SET_RATE_PARENT, 0x2000, 7, 0 },
|
|
+ { GATE_CLK_EFUSE, "clk_gate_efuse", "clk_div_efuse",
|
|
+ CLK_SET_RATE_PARENT, 0x2000, 20, 0},
|
|
+ { GATE_CLK_TOP_AXI0, "clk_gate_top_axi0", "clk_div_top_axi0",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 11, 0 },
|
|
+ { GATE_CLK_TOP_AXI_HSPERI, "clk_gate_top_axi_hsperi", "clk_div_top_axi_hsperi",
|
|
+ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0x2004, 12, 0 },
|
|
+ { GATE_CLK_AHB_ROM, "clk_gate_ahb_rom", "clk_gate_top_axi0",
|
|
+ 0, 0x2000, 8, 0 },
|
|
+ { GATE_CLK_AHB_SF, "clk_gate_ahb_sf", "clk_gate_top_axi0",
|
|
+ 0, 0x2000, 9, 0 },
|
|
+ { GATE_CLK_AXI_SRAM, "clk_gate_axi_sram", "clk_gate_top_axi0",
|
|
+ CLK_IGNORE_UNUSED, 0x2000, 10, 0 },
|
|
+ { GATE_CLK_APB_TIMER, "clk_gate_apb_timer", "clk_gate_top_axi0",
|
|
+ CLK_IGNORE_UNUSED, 0x2000, 11, 0 },
|
|
+ { GATE_CLK_APB_EFUSE, "clk_gate_apb_efuse", "clk_gate_top_axi0",
|
|
+ 0, 0x2000, 21, 0 },
|
|
+ { GATE_CLK_APB_GPIO, "clk_gate_apb_gpio", "clk_gate_top_axi0",
|
|
+ 0, 0x2000, 22, 0 },
|
|
+ { GATE_CLK_APB_GPIO_INTR, "clk_gate_apb_gpio_intr", "clk_gate_top_axi0",
|
|
+ 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 <linux/of_device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/log2.h>
|
|
+
|
|
+#include "clk.h"
|
|
+
|
|
+/*
|
|
+ * @hw: handle between common and hardware-specific interfaces
|
|
+ * @reg: register containing divider
|
|
+ * @shift: shift to the divider bit field
|
|
+ * @width: width of the divider bit field
|
|
+ * @initial_val:initial value of the divider
|
|
+ * @table: the div table that the divider supports
|
|
+ * @lock: register lock
|
|
+ */
|
|
+struct mango_clk_divider {
|
|
+ struct clk_hw hw;
|
|
+ void __iomem *reg;
|
|
+ u8 shift;
|
|
+ u8 width;
|
|
+ u8 flags;
|
|
+ u32 initial_val;
|
|
+ const struct clk_div_table *table;
|
|
+ spinlock_t *lock;
|
|
+};
|
|
+
|
|
+static inline int mango_pll_enable(struct regmap *map,
|
|
+ struct mango_pll_clock *pll, bool en)
|
|
+{
|
|
+ unsigned int value;
|
|
+ unsigned long enter;
|
|
+ unsigned int id = pll->id;
|
|
+
|
|
+ if (en) {
|
|
+ /* wait pll lock */
|
|
+ enter = jiffies;
|
|
+ regmap_read(map, pll->status_offset, &value);
|
|
+ while (!((value >> (PLL_STAT_LOCK_OFFSET + id)) & 0x1)) {
|
|
+ regmap_read(map, pll->status_offset, &value);
|
|
+ if (time_after(jiffies, enter + HZ / 10))
|
|
+ pr_warn("%s not locked\n", pll->name);
|
|
+ }
|
|
+ /* wait pll updating */
|
|
+ enter = jiffies;
|
|
+ regmap_read(map, pll->status_offset, &value);
|
|
+ while (((value >> id) & 0x1)) {
|
|
+ regmap_read(map, pll->status_offset, &value);
|
|
+ if (time_after(jiffies, enter + HZ / 10))
|
|
+ pr_warn("%s still updating\n", pll->name);
|
|
+ }
|
|
+ /* enable pll */
|
|
+ regmap_read(map, pll->enable_offset, &value);
|
|
+ regmap_write(map, pll->enable_offset, value | (1 << id));
|
|
+ } else {
|
|
+ /* disable pll */
|
|
+ regmap_read(map, pll->enable_offset, &value);
|
|
+ regmap_write(map, pll->enable_offset, value & (~(1 << id)));
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int mango_pll_write(struct regmap *map, int id, int value)
|
|
+{
|
|
+ return regmap_write(map, PLL_CTRL_OFFSET + (id << 2), value);
|
|
+}
|
|
+
|
|
+static inline int mango_pll_read(struct regmap *map, int id, unsigned int *pvalue)
|
|
+{
|
|
+ return regmap_read(map, PLL_CTRL_OFFSET + (id << 2), pvalue);
|
|
+}
|
|
+
|
|
+static unsigned int _get_table_div(const struct clk_div_table *table,
|
|
+ unsigned int val)
|
|
+{
|
|
+ const struct clk_div_table *clkt;
|
|
+
|
|
+ for (clkt = table; clkt->div; clkt++)
|
|
+ if (clkt->val == val)
|
|
+ return clkt->div;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static unsigned int _get_div(const struct clk_div_table *table,
|
|
+ unsigned int val, unsigned long flags, u8 width)
|
|
+{
|
|
+ if (flags & CLK_DIVIDER_ONE_BASED)
|
|
+ return val;
|
|
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
|
+ return 1 << val;
|
|
+ if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
|
+ return val ? val : div_mask(width) + 1;
|
|
+ if (table)
|
|
+ return _get_table_div(table, val);
|
|
+ return val + 1;
|
|
+}
|
|
+
|
|
+static unsigned long mango_clk_divider_recalc_rate(struct clk_hw *hw,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct mango_clk_divider *divider = to_mango_clk_divider(hw);
|
|
+ unsigned int val;
|
|
+
|
|
+ val = readl(divider->reg) >> divider->shift;
|
|
+ val &= div_mask(divider->width);
|
|
+
|
|
+#ifdef CONFIG_ARCH_BM1880
|
|
+ /* if select divide factor from initial value */
|
|
+ if (!(readl(divider->reg) & BIT(3)))
|
|
+ val = divider->initial_val;
|
|
+#endif
|
|
+
|
|
+ return divider_recalc_rate(hw, parent_rate, val, divider->table,
|
|
+ divider->flags, divider->width);
|
|
+}
|
|
+
|
|
+static long mango_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
|
+ unsigned long *prate)
|
|
+{
|
|
+ int bestdiv;
|
|
+ struct mango_clk_divider *divider = to_mango_clk_divider(hw);
|
|
+
|
|
+ /* if read only, just return current value */
|
|
+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
|
|
+ bestdiv = readl(divider->reg) >> divider->shift;
|
|
+ bestdiv &= div_mask(divider->width);
|
|
+ bestdiv = _get_div(divider->table, bestdiv, divider->flags,
|
|
+ divider->width);
|
|
+ return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
|
|
+ }
|
|
+
|
|
+ return divider_round_rate(hw, rate, prate, divider->table,
|
|
+ divider->width, divider->flags);
|
|
+}
|
|
+
|
|
+static int mango_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ unsigned int value;
|
|
+ unsigned int val;
|
|
+ unsigned long flags = 0;
|
|
+ struct mango_clk_divider *divider = to_mango_clk_divider(hw);
|
|
+
|
|
+ value = divider_get_val(rate, parent_rate, divider->table,
|
|
+ divider->width, divider->flags);
|
|
+
|
|
+ if (divider->lock)
|
|
+ spin_lock_irqsave(divider->lock, flags);
|
|
+ else
|
|
+ __acquire(divider->lock);
|
|
+
|
|
+ /* div assert */
|
|
+ val = readl(divider->reg);
|
|
+ val &= ~0x1;
|
|
+ writel(val, divider->reg);
|
|
+
|
|
+ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
|
|
+ val = div_mask(divider->width) << (divider->shift + 16);
|
|
+ } else {
|
|
+ val = readl(divider->reg);
|
|
+ val &= ~(div_mask(divider->width) << divider->shift);
|
|
+ }
|
|
+
|
|
+ val |= value << divider->shift;
|
|
+ writel(val, divider->reg);
|
|
+
|
|
+ if (!(divider->flags & CLK_DIVIDER_READ_ONLY))
|
|
+ val |= 1 << 3;
|
|
+
|
|
+ /* de-assert */
|
|
+ val |= 1;
|
|
+ writel(val, divider->reg);
|
|
+ if (divider->lock)
|
|
+ spin_unlock_irqrestore(divider->lock, flags);
|
|
+ else
|
|
+ __release(divider->lock);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Below array is the total combination lists of POSTDIV1 and POSTDIV2
|
|
+ * for example:
|
|
+ * postdiv1_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 <linux/regmap.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/clk-provider.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/clkdev.h>
|
|
+
|
|
+#include <dt-bindings/clock/sophgo.h>
|
|
+
|
|
+#define KHZ 1000L
|
|
+#define MHZ (KHZ * KHZ)
|
|
+
|
|
+#define MANGO_CLK_USE_INIT_VAL BIT(0) /* use default value */
|
|
+#define MANGO_CLK_USE_REG_VAL BIT(1) /* use reg divider value */
|
|
+#define MANGO_CLK_RO BIT(2) /* use reg divider value */
|
|
+
|
|
+#define CLK_PLL BIT(0)
|
|
+#define CLK_MUX BIT(1)
|
|
+
|
|
+#define PLL_CTRL_OFFSET 0xE8
|
|
+#define PLL_STAT_LOCK_OFFSET 0x8
|
|
+#define CLK_MODE 0x4
|
|
+#define CLK_MODE_MASK 0x3
|
|
+
|
|
+#define REFDIV_MIN 1
|
|
+#define REFDIV_MAX 64
|
|
+#define FBDIV_MIN 16
|
|
+#define FBDIV_MAX 321
|
|
+
|
|
+#define PLL_FREQ_MIN (16 * MHZ)
|
|
+#define PLL_FREQ_MAX (3200 * MHZ)
|
|
+
|
|
+#define div_mask(width) ((1 << (width)) - 1)
|
|
+#define TOP_PLL_CTRL(fbdiv, p1, p2, refdiv) \
|
|
+ (((fbdiv & 0xfff) << 16) | ((p2 & 0x7) << 12) | ((p1 & 0x7) << 8) | (refdiv & 0x3f))
|
|
+
|
|
+struct mango_pll_ctrl {
|
|
+ unsigned int mode;
|
|
+ unsigned long freq;
|
|
+
|
|
+ unsigned int fbdiv;
|
|
+ unsigned int postdiv1;
|
|
+ unsigned int postdiv2;
|
|
+ unsigned int refdiv;
|
|
+};
|
|
+
|
|
+struct mango_pll_clock {
|
|
+ unsigned int id;
|
|
+ char *name;
|
|
+ const char *parent_name;
|
|
+ unsigned long flags;
|
|
+ struct clk_hw hw;
|
|
+ struct regmap *syscon_top;
|
|
+
|
|
+ /* Below lock used to protect PLL top register during write */
|
|
+ spinlock_t *lock;
|
|
+ u32 ini_flags;
|
|
+
|
|
+ u32 status_offset;
|
|
+ u32 enable_offset;
|
|
+
|
|
+ struct mango_pll_ctrl pctrl_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 <dt-bindings/clock/light-fm-ap-clock.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/types.h>
|
|
+
|
|
+#include "clk.h"
|
|
+
|
|
+static struct clk *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 <lw312886@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light Fullmask clock driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/clk/thead/clk-light-mpw.c b/drivers/clk/thead/clk-light-mpw.c
|
|
new file mode 100644
|
|
index 000000000000..f7356ddf4684
|
|
--- /dev/null
|
|
+++ b/drivers/clk/thead/clk-light-mpw.c
|
|
@@ -0,0 +1,492 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <dt-bindings/clock/light-mpw-clock.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/types.h>
|
|
+
|
|
+#include "clk.h"
|
|
+
|
|
+static struct clk *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 <duanfugang.dfg@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light MPW clock driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/clk/thead/clk.c b/drivers/clk/thead/clk.c
|
|
new file mode 100644
|
|
index 000000000000..2e181a9fd180
|
|
--- /dev/null
|
|
+++ b/drivers/clk/thead/clk.c
|
|
@@ -0,0 +1,739 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+#include <linux/clk.h>
|
|
+#include <linux/clk-provider.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/iopoll.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/spinlock.h>
|
|
+
|
|
+#include "clk.h"
|
|
+
|
|
+#define LIGHT_PLL_CFG0 0x0
|
|
+#define LIGHT_PLL_CFG1 0x04
|
|
+#define LIGHT_PLL_CFG2 0x8
|
|
+#define LIGHT_POSTDIV2_SHIFT 24
|
|
+#define LIGHT_POSTDIV2_MASK GENMASK(26, 24)
|
|
+#define LIGHT_POSTDIV1_SHIFT 20
|
|
+#define LIGHT_POSTDIV1_MASK GENMASK(22, 20)
|
|
+#define LIGHT_FBDIV_SHIFT 8
|
|
+#define LIGHT_FBDIV_MASK GENMASK(19, 8)
|
|
+#define LIGHT_REFDIV_SHIFT 0
|
|
+#define LIGHT_REFDIV_MASK GENMASK(5, 0)
|
|
+#define LIGHT_BYPASS_MASK BIT(30)
|
|
+#define LIGHT_RST_MASK BIT(29)
|
|
+#define LIGHT_DSMPD_MASK BIT(24)
|
|
+#define LIGHT_DACPD_MASK BIT(25)
|
|
+#define LIGHT_FRAC_MASK GENMASK(23, 0)
|
|
+#define LIGHT_FRAC_SHIFT 0
|
|
+#define LIGHT_FRAC_DIV BIT(24)
|
|
+
|
|
+#define LOCK_TIMEOUT_US 10000
|
|
+
|
|
+#define div_mask(d) ((1 << (d->width)) - 1)
|
|
+
|
|
+DEFINE_SPINLOCK(thead_light_clk_lock);
|
|
+
|
|
+enum light_pll_mode {
|
|
+ PLL_MODE_FRAC,
|
|
+ PLL_MODE_INT,
|
|
+};
|
|
+
|
|
+struct clk_lightpll {
|
|
+ struct clk_hw hw;
|
|
+ void __iomem *base;
|
|
+ enum light_pll_clktype clk_type;
|
|
+ enum light_pll_outtype out_type;
|
|
+ enum light_pll_mode pll_mode;
|
|
+ const struct light_pll_rate_table *rate_table;
|
|
+ int rate_count;
|
|
+
|
|
+ u32 cfg0_reg_off;
|
|
+ u32 pll_sts_off;
|
|
+ int pll_lock_bit;
|
|
+
|
|
+ /* Light MPW Aon/ddr pll define bypass:rst bits as: 31:30
|
|
+ * but AP pll define bypass:rst bits as: 30:29
|
|
+ *
|
|
+ * Light Fullmask align these register field define, all pll
|
|
+ * define bypss:rst bits as: 30:29
|
|
+ */
|
|
+ int pll_rst_bit;
|
|
+ int pll_bypass_bit;
|
|
+};
|
|
+
|
|
+struct clk_lightdiv {
|
|
+ struct clk_divider divider;
|
|
+ enum light_div_type div_type;
|
|
+ u16 min_div;
|
|
+ u16 max_div;
|
|
+ u8 sync_en;
|
|
+ const struct clk_ops *ops;
|
|
+};
|
|
+
|
|
+struct clk_lightgate {
|
|
+ struct clk_gate gate;
|
|
+ unsigned int *share_count;
|
|
+ const struct clk_ops *ops;
|
|
+};
|
|
+
|
|
+#define to_clk_lightpll(_hw) container_of(_hw, struct clk_lightpll, hw)
|
|
+
|
|
+void thead_unregister_clocks(struct clk *clks[], unsigned int count)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < count; i++)
|
|
+ clk_unregister(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 <linux/spinlock.h>
|
|
+#include <linux/clk-provider.h>
|
|
+
|
|
+extern spinlock_t thead_light_clk_lock;
|
|
+
|
|
+#define LIGHT_PLL_RATE(_vco, _rate, _r, _b, _f, _p, _k) \
|
|
+ { \
|
|
+ .vco_rate = (_vco), \
|
|
+ .rate = (_rate), \
|
|
+ .refdiv = (_r), \
|
|
+ .fbdiv = (_b), \
|
|
+ .frac = (_f), \
|
|
+ .postdiv1 = (_p), \
|
|
+ .postdiv2 = (_k), \
|
|
+ }
|
|
+
|
|
+enum light_pll_outtype {
|
|
+ LIGHT_PLL_VCO,
|
|
+ LIGHT_PLL_DIV,
|
|
+};
|
|
+
|
|
+enum light_div_type {
|
|
+ MUX_TYPE_DIV,
|
|
+ MUX_TYPE_CDE,
|
|
+};
|
|
+
|
|
+enum light_pll_clktype {
|
|
+ LIGHT_AUDIO_PLL,
|
|
+ LIGHT_SYS_PLL,
|
|
+ LIGHT_CPU_PLL0,
|
|
+ LIGHT_CPU_PLL1,
|
|
+ LIGHT_GMAC_PLL,
|
|
+ LIGHT_VIDEO_PLL,
|
|
+ LIGHT_DDR_PLL,
|
|
+ LIGHT_DPU0_PLL,
|
|
+ LIGHT_DPU1_PLL,
|
|
+};
|
|
+
|
|
+struct light_pll_rate_table {
|
|
+ unsigned long vco_rate;
|
|
+ unsigned long rate;
|
|
+ unsigned int refdiv;
|
|
+ unsigned int fbdiv;
|
|
+ unsigned int frac;
|
|
+ unsigned int postdiv1;
|
|
+ unsigned int postdiv2;
|
|
+};
|
|
+
|
|
+struct light_pll_clk {
|
|
+ enum light_pll_outtype out_type;
|
|
+ enum light_pll_clktype clk_type;
|
|
+ const struct light_pll_rate_table *rate_table;
|
|
+ int rate_count;
|
|
+ int flags;
|
|
+};
|
|
+
|
|
+static inline struct clk *thead_light_clk_fixed_factor(const char *name,
|
|
+ const char *parent, unsigned int mult, unsigned int div)
|
|
+{
|
|
+ return clk_register_fixed_factor(NULL, name, parent,
|
|
+ CLK_SET_RATE_PARENT, mult, div);
|
|
+}
|
|
+
|
|
+struct clk *thead_light_pll(const char *name, const char *parent_name,
|
|
+ void __iomem *base,
|
|
+ const struct light_pll_clk *pll_clk);
|
|
+
|
|
+static inline struct clk *thead_clk_light_gate(const char *name, const char *parent,
|
|
+ void __iomem *reg, u8 shift)
|
|
+{
|
|
+ return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
|
+ shift, 0, &thead_light_clk_lock);
|
|
+}
|
|
+
|
|
+struct clk *thead_clk_light_register_gate_shared(const char *name, const char *parent,
|
|
+ unsigned long flags, void __iomem *reg,
|
|
+ u8 shift, spinlock_t *lock,
|
|
+ unsigned int *share_count);
|
|
+
|
|
+struct clk *thead_clk_light_divider(const char *name, const char *parent,
|
|
+ void __iomem *reg, u8 shift, u8 width,
|
|
+ u8 sync, enum light_div_type div_type,
|
|
+ u16 min, u16 max);
|
|
+
|
|
+void thead_unregister_clocks(struct clk *clks[], unsigned int count);
|
|
+
|
|
+static inline struct clk *thead_clk_fixed(const char *name, unsigned long rate)
|
|
+{
|
|
+ return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
|
|
+}
|
|
+
|
|
+static inline struct clk *thead_clk_light_gate_shared(const char *name, const char *parent,
|
|
+ void __iomem *reg, u8 shift,
|
|
+ unsigned int *share_count)
|
|
+{
|
|
+ return thead_clk_light_register_gate_shared(name, parent, CLK_SET_RATE_PARENT, reg,
|
|
+ shift, &thead_light_clk_lock, share_count);
|
|
+}
|
|
+
|
|
+static inline struct clk *thead_light_clk_mux_flags(const char *name,
|
|
+ void __iomem *reg, u8 shift, u8 width,
|
|
+ const char * const *parents, int num_parents,
|
|
+ unsigned long flags)
|
|
+{
|
|
+ return clk_register_mux(NULL, name, parents, num_parents,
|
|
+ flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0,
|
|
+ &thead_light_clk_lock);
|
|
+}
|
|
+#endif
|
|
diff --git a/drivers/clk/thead/gate/Makefile b/drivers/clk/thead/gate/Makefile
|
|
new file mode 100644
|
|
index 000000000000..b0ad8b2011c0
|
|
--- /dev/null
|
|
+++ b/drivers/clk/thead/gate/Makefile
|
|
@@ -0,0 +1,3 @@
|
|
+# SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+obj-$(CONFIG_CLK_LIGHT_FM) += thead-gate.o visys-gate.o vpsys-gate.o vosys-gate.o dspsys-gate.o
|
|
diff --git a/drivers/clk/thead/gate/clk-gate.h b/drivers/clk/thead/gate/clk-gate.h
|
|
new file mode 100644
|
|
index 000000000000..ebb190374a0e
|
|
--- /dev/null
|
|
+++ b/drivers/clk/thead/gate/clk-gate.h
|
|
@@ -0,0 +1,35 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#ifndef CLK_GATE_H
|
|
+#define CLK_GATE_H
|
|
+
|
|
+#include <linux/clk-provider.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+
|
|
+enum clk_gate_type {
|
|
+ GATE_NOT_SHARED,
|
|
+ GATE_SHARED,
|
|
+};
|
|
+
|
|
+struct thead_clk_gate {
|
|
+ struct clk_hw hw;
|
|
+ struct regmap *regmap;
|
|
+ u32 offset;
|
|
+ u8 bit;
|
|
+ bool shared;
|
|
+ u32 *share_count;
|
|
+};
|
|
+
|
|
+struct clk *thead_gate_clk_register(const char *name,
|
|
+ const char *parent_name,
|
|
+ struct regmap *regmap,
|
|
+ int offset,
|
|
+ u8 bit,
|
|
+ bool shared,
|
|
+ u32 *share_count,
|
|
+ struct device *dev);
|
|
+
|
|
+#endif
|
|
diff --git a/drivers/clk/thead/gate/dspsys-gate.c b/drivers/clk/thead/gate/dspsys-gate.c
|
|
new file mode 100644
|
|
index 000000000000..e68a5d4e6151
|
|
--- /dev/null
|
|
+++ b/drivers/clk/thead/gate/dspsys-gate.c
|
|
@@ -0,0 +1,109 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <dt-bindings/clock/light-dspsys.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/types.h>
|
|
+#include "clk-gate.h"
|
|
+#include "../clk.h"
|
|
+
|
|
+static struct clk *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 <lw312886@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light Fullmask dspsys clock gate provider");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/clk/thead/gate/thead-gate.c b/drivers/clk/thead/gate/thead-gate.c
|
|
new file mode 100644
|
|
index 000000000000..372c11dee1b9
|
|
--- /dev/null
|
|
+++ b/drivers/clk/thead/gate/thead-gate.c
|
|
@@ -0,0 +1,114 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <linux/clk.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/regmap.h>
|
|
+#include "clk-gate.h"
|
|
+
|
|
+#define to_thead_clk_gate(_hw) container_of(_hw, struct thead_clk_gate, hw)
|
|
+
|
|
+static int thead_clk_gate_is_enabled(struct clk_hw *hw)
|
|
+{
|
|
+ struct thead_clk_gate *tcg = to_thead_clk_gate(hw);
|
|
+ u32 val;
|
|
+
|
|
+ regmap_read(tcg->regmap, tcg->offset, &val);
|
|
+
|
|
+ val &= BIT(tcg->bit);
|
|
+
|
|
+ return val != 0;
|
|
+}
|
|
+
|
|
+static void thead_clk_gate_disable(struct clk_hw *hw)
|
|
+{
|
|
+ struct thead_clk_gate *tcg = to_thead_clk_gate(hw);
|
|
+
|
|
+ if (!tcg->shared)
|
|
+ goto out;
|
|
+
|
|
+ if (tcg->share_count) {
|
|
+ if (WARN_ON(*tcg->share_count == 0))
|
|
+ return;
|
|
+ else if (--(*tcg->share_count) > 0) {
|
|
+ pr_info("[%s,%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 <dt-bindings/clock/light-fm-ap-clock.h>
|
|
+#include <dt-bindings/clock/light-visys.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/types.h>
|
|
+#include "clk-gate.h"
|
|
+#include "../clk.h"
|
|
+
|
|
+static struct clk *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 <lw312886@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light Fullmask visys clock gate provider");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/clk/thead/gate/vosys-gate.c b/drivers/clk/thead/gate/vosys-gate.c
|
|
new file mode 100644
|
|
index 000000000000..e53ba1a3e763
|
|
--- /dev/null
|
|
+++ b/drivers/clk/thead/gate/vosys-gate.c
|
|
@@ -0,0 +1,111 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <dt-bindings/clock/light-fm-ap-clock.h>
|
|
+#include <dt-bindings/clock/light-vosys.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/types.h>
|
|
+#include "../clk.h"
|
|
+
|
|
+static struct clk *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 <lw312886@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light Fullmask vosys clock gate provider");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/clk/thead/gate/vpsys-gate.c b/drivers/clk/thead/gate/vpsys-gate.c
|
|
new file mode 100644
|
|
index 000000000000..78613188da70
|
|
--- /dev/null
|
|
+++ b/drivers/clk/thead/gate/vpsys-gate.c
|
|
@@ -0,0 +1,94 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <dt-bindings/clock/light-fm-ap-clock.h>
|
|
+#include <dt-bindings/clock/light-vpsys.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/types.h>
|
|
+#include "../clk.h"
|
|
+
|
|
+static struct clk *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 <lw312886@linux.alibaba.com>");
|
|
+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 <linux/clk.h>
|
|
+#include <linux/cpu.h>
|
|
+#include <linux/cpufreq.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/pm_opp.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/reboot.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+#include <linux/suspend.h>
|
|
+#include <linux/clk-provider.h>
|
|
+#include <linux/smp.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/notifier.h>
|
|
+
|
|
+extern struct atomic_notifier_head panic_notifier_list;
|
|
+
|
|
+static DEFINE_MUTEX(cpufreq_lock);
|
|
+
|
|
+bool cpufreq_denied = false;
|
|
+
|
|
+struct regulator *dvdd_cpu_reg;
|
|
+struct regulator *dvddm_cpu_reg;
|
|
+
|
|
+enum LIGHT_MPW_CPUFREQ_CLKS {
|
|
+ LIGHT_C910_CCLK,
|
|
+ LIGHT_C910_CCLK_I0,
|
|
+ LIGHT_CPU_PLL1_FOUTPOSTDIV,
|
|
+ LIGHT_CPU_PLL0_FOUTPOSTDIV,
|
|
+};
|
|
+
|
|
+#define LIGHT_MPW_CPUFREQ_CLK_NUM 4
|
|
+#define LIGHT_CPUFREQ_THRE 2000000
|
|
+#define LIGHT_C910_BUS_CLK_SYNC BIT(11)
|
|
+#define LIGHT_C910_BUS_CLK_RATIO_MASK 0x700
|
|
+#define LIGHT_C910_BUS_CLK_DIV_RATIO_2 0x100
|
|
+#define LIGHT_C910_BUS_CLK_DIV_RATIO_3 0x200
|
|
+
|
|
+static int num_clks;
|
|
+static struct clk_bulk_data clks[] = {
|
|
+ { .id = "c910_cclk" },
|
|
+ { .id = "c910_cclk_i0" },
|
|
+ { .id = "cpu_pll1_foutpostdiv" },
|
|
+ { .id = "cpu_pll0_foutpostdiv" },
|
|
+};
|
|
+
|
|
+static struct device *cpu_dev;
|
|
+static struct cpufreq_frequency_table *freq_table;
|
|
+static unsigned int max_freq;
|
|
+static unsigned int transition_latency;
|
|
+static void __iomem *ap_sys_reg;
|
|
+static bool light_dvfs_sv = false;
|
|
+
|
|
+static u32 *light_dvddm_volt;
|
|
+static u32 soc_opp_count = 0;
|
|
+
|
|
+static int light_set_target(struct cpufreq_policy *policy, unsigned int index)
|
|
+{
|
|
+ struct dev_pm_opp *opp;
|
|
+ unsigned long freq_hz;
|
|
+ int volt, volt_old;
|
|
+ unsigned int old_freq, new_freq;
|
|
+ int ret;
|
|
+ u32 val;
|
|
+ u32 re_modify_bus_freq = 0;
|
|
+
|
|
+ mutex_lock(&cpufreq_lock);
|
|
+
|
|
+ if (cpufreq_denied) {
|
|
+ dev_emerg(cpu_dev, "Denied to set cpu frequency temporarily on reboot\n");
|
|
+ mutex_unlock(&cpufreq_lock);
|
|
+ return 0;
|
|
+ }
|
|
+ new_freq = freq_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 <duanfugang.dfg@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light cpufreq driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
|
|
index 9cb284a6e7a1..52f07f9c5db7 100644
|
|
--- a/drivers/firmware/Kconfig
|
|
+++ b/drivers/firmware/Kconfig
|
|
@@ -314,5 +314,6 @@ source "drivers/firmware/psci/Kconfig"
|
|
source "drivers/firmware/smccc/Kconfig"
|
|
source "drivers/firmware/tegra/Kconfig"
|
|
source "drivers/firmware/xilinx/Kconfig"
|
|
+source "drivers/firmware/thead/Kconfig"
|
|
|
|
endmenu
|
|
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
|
|
index 28fcddcd688f..a817fe549c9f 100644
|
|
--- a/drivers/firmware/Makefile
|
|
+++ b/drivers/firmware/Makefile
|
|
@@ -38,3 +38,4 @@ obj-y += psci/
|
|
obj-y += smccc/
|
|
obj-y += tegra/
|
|
obj-y += xilinx/
|
|
+obj-y += thead/
|
|
diff --git a/drivers/firmware/thead/Kconfig b/drivers/firmware/thead/Kconfig
|
|
new file mode 100644
|
|
index 000000000000..ad5b82dd51e8
|
|
--- /dev/null
|
|
+++ b/drivers/firmware/thead/Kconfig
|
|
@@ -0,0 +1,18 @@
|
|
+# SPDX-License-Identifier: GPL-2.0-only
|
|
+config LIGHT_AON
|
|
+ bool "Thead Light Aon Protocol driver"
|
|
+ depends on THEAD_LIGHT_MBOX
|
|
+ default y
|
|
+ help
|
|
+ Thead light Aon is a low-level system function which runs a dedicated
|
|
+ thead riscv E902 core to provide power, clock and resource management.
|
|
+
|
|
+ This driver manages the IPC interface between host cpu liks thead
|
|
+ and the Aon firmware running on thead riscv E902 core.
|
|
+
|
|
+config LIGHT_AON_PD
|
|
+ bool "Thead Light Aon Power Domain driver"
|
|
+ depends on LIGHT_AON
|
|
+ select PM_GENERIC_DOMAINS if PM
|
|
+ help
|
|
+ The Aon power domain virtual driver.
|
|
diff --git a/drivers/firmware/thead/Makefile b/drivers/firmware/thead/Makefile
|
|
new file mode 100644
|
|
index 000000000000..6bd2afe817ef
|
|
--- /dev/null
|
|
+++ b/drivers/firmware/thead/Makefile
|
|
@@ -0,0 +1,3 @@
|
|
+# SPDX-License-Identifier: GPL-2.0
|
|
+obj-$(CONFIG_LIGHT_AON) += light_aon.o light_aon_misc.o light_aon_test.o
|
|
+obj-$(CONFIG_LIGHT_AON_PD) += light_aon_pd.o
|
|
diff --git a/drivers/firmware/thead/light_aon.c b/drivers/firmware/thead/light_aon.c
|
|
new file mode 100644
|
|
index 000000000000..5af7de821e76
|
|
--- /dev/null
|
|
+++ b/drivers/firmware/thead/light_aon.c
|
|
@@ -0,0 +1,261 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <linux/err.h>
|
|
+#include <linux/firmware/thead/ipc.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/mailbox_client.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/of_platform.h>
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+/* wait for response for 3000ms instead of 300ms (fix me pls)*/
|
|
+#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000))
|
|
+#define MAX_TX_TIMEOUT (msecs_to_jiffies(500))
|
|
+
|
|
+struct light_aon_chan {
|
|
+ struct light_aon_ipc *aon_ipc;
|
|
+
|
|
+ struct mbox_client cl;
|
|
+ struct mbox_chan *ch;
|
|
+ struct completion tx_done;
|
|
+};
|
|
+
|
|
+struct light_aon_ipc {
|
|
+ struct light_aon_chan chans;
|
|
+ struct device *dev;
|
|
+ struct mutex lock;
|
|
+ struct completion done;
|
|
+ u32 *msg;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * This type is used to indicate error response for most functions.
|
|
+ */
|
|
+enum light_aon_error_codes {
|
|
+ LIGHT_AON_ERR_NONE = 0, /* Success */
|
|
+ LIGHT_AON_ERR_VERSION = 1, /* Incompatible API version */
|
|
+ LIGHT_AON_ERR_CONFIG = 2, /* Configuration error */
|
|
+ LIGHT_AON_ERR_PARM = 3, /* Bad parameter */
|
|
+ LIGHT_AON_ERR_NOACCESS = 4, /* Permission error (no access) */
|
|
+ LIGHT_AON_ERR_LOCKED = 5, /* Permission error (locked) */
|
|
+ LIGHT_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */
|
|
+ LIGHT_AON_ERR_NOTFOUND = 7, /* Not found */
|
|
+ LIGHT_AON_ERR_NOPOWER = 8, /* No power */
|
|
+ LIGHT_AON_ERR_IPC = 9, /* Generic IPC error */
|
|
+ LIGHT_AON_ERR_BUSY = 10, /* Resource is currently busy/active */
|
|
+ LIGHT_AON_ERR_FAIL = 11, /* General I/O failure */
|
|
+ LIGHT_AON_ERR_LAST
|
|
+};
|
|
+
|
|
+static int light_aon_linux_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 <duanfugang.dfg@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light firmware protocol driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/firmware/thead/light_aon_misc.c b/drivers/firmware/thead/light_aon_misc.c
|
|
new file mode 100644
|
|
index 000000000000..3fb689f4b261
|
|
--- /dev/null
|
|
+++ b/drivers/firmware/thead/light_aon_misc.c
|
|
@@ -0,0 +1,74 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <linux/firmware/thead/ipc.h>
|
|
+
|
|
+struct light_aon_msg_req_misc_set_ctrl {
|
|
+ struct light_aon_rpc_msg_hdr hdr;
|
|
+ u32 ctrl;
|
|
+ u32 val;
|
|
+ u16 resource;
|
|
+ u16 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 <dt-bindings/firmware/thead/rsrc.h>
|
|
+#include <linux/ctype.h>
|
|
+#include <linux/debugfs.h>
|
|
+#include <linux/firmware/thead/ipc.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/of_platform.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/pm.h>
|
|
+#include <linux/pm_domain.h>
|
|
+#include <linux/seq_file.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+struct light_aon_msg_req_set_resource_power_mode {
|
|
+ struct light_aon_rpc_msg_hdr hdr;
|
|
+ u16 resource;
|
|
+ u16 mode;
|
|
+ u16 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 <duanfugang.dfg@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light firmware protocol driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/firmware/thead/light_aon_test.c b/drivers/firmware/thead/light_aon_test.c
|
|
new file mode 100644
|
|
index 000000000000..172025430853
|
|
--- /dev/null
|
|
+++ b/drivers/firmware/thead/light_aon_test.c
|
|
@@ -0,0 +1,163 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <linux/debugfs.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/uaccess.h>
|
|
+#include <linux/firmware/thead/ipc.h>
|
|
+
|
|
+#define MBOX_MAX_MSG_LEN 28
|
|
+
|
|
+static struct dentry *root_debugfs_dir;
|
|
+
|
|
+struct light_aon_msg_req_misc_set_ctrl {
|
|
+ struct light_aon_rpc_msg_hdr hdr;
|
|
+ u32 ctrl;
|
|
+ u32 val;
|
|
+ u16 resource;
|
|
+ u16 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 <duanfugang.dfg@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light firmware protocol test driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
|
|
index 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 <asm/neon.h>
|
|
#elif defined(CONFIG_LOONGARCH)
|
|
#include <asm/fpu.h>
|
|
+#elif defined(CONFIG_RISCV)
|
|
+#include <asm/switch_to.h>
|
|
#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 <linux/vga_switcheroo.h>
|
|
#include <linux/mmu_notifier.h>
|
|
#include <linux/pci.h>
|
|
+#include <linux/kexec.h>
|
|
|
|
#include <drm/drm_aperture.h>
|
|
#include <drm/drm_drv.h>
|
|
@@ -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 <linux/debugfs.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/mailbox_client.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/uaccess.h>
|
|
+
|
|
+#define MBOX_MAX_MSG_LEN 28
|
|
+#define WJ_MBOX_SEND_MAX_MESSAGE_LENGTH 28
|
|
+#define HEXDUMP_BYTES_PER_LINE 28
|
|
+#define HEXDUMP_LINE_LEN ((HEXDUMP_BYTES_PER_LINE * 4) + 2)
|
|
+#define HEXDUMP_MAX_LEN (HEXDUMP_LINE_LEN * \
|
|
+ (MBOX_MAX_MSG_LEN / HEXDUMP_BYTES_PER_LINE))
|
|
+
|
|
+static struct dentry *root_debugfs_dir;
|
|
+
|
|
+struct mbox_client_light_device {
|
|
+ struct device *dev;
|
|
+ void __iomem *tx_mmio;
|
|
+ void __iomem *rx_mmio;
|
|
+ struct mbox_chan *tx_channel;
|
|
+ struct mbox_chan *rx_channel;
|
|
+ char *rx_buffer;
|
|
+ char *message;
|
|
+ spinlock_t lock;
|
|
+};
|
|
+
|
|
+static ssize_t mbox_client_light_message_write(struct file *filp,
|
|
+ const char __user *userbuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct mbox_client_light_device *tdev = filp->private_data;
|
|
+ void *data;
|
|
+ int ret;
|
|
+
|
|
+ if (!tdev->tx_channel) {
|
|
+ dev_err(tdev->dev, "Channel cannot do Tx\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (count > WJ_MBOX_SEND_MAX_MESSAGE_LENGTH)
|
|
+ count = WJ_MBOX_SEND_MAX_MESSAGE_LENGTH;
|
|
+
|
|
+ tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
|
|
+ if (!tdev->message)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ ret = copy_from_user(tdev->message, userbuf, count);
|
|
+ if (ret) {
|
|
+ ret = -EFAULT;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ data = tdev->message;
|
|
+ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->message, MBOX_MAX_MSG_LEN, true);
|
|
+
|
|
+ ret = mbox_send_message(tdev->tx_channel, data);
|
|
+ if (ret < 0)
|
|
+ dev_err(tdev->dev, "Failed to send message via mailbox\n");
|
|
+
|
|
+out:
|
|
+ kfree(tdev->message);
|
|
+ return ret < 0 ? ret : count;
|
|
+}
|
|
+
|
|
+static ssize_t mbox_client_light_message_read(struct file *filp,
|
|
+ char __user *userbuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct mbox_client_light_device *tdev = filp->private_data;
|
|
+ unsigned long flags;
|
|
+
|
|
+ print_hex_dump(KERN_INFO, __func__, DUMP_PREFIX_NONE, 16, 1, tdev->rx_buffer, MBOX_MAX_MSG_LEN, true);
|
|
+ spin_lock_irqsave(&tdev->lock, flags);
|
|
+ memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN);
|
|
+ spin_unlock_irqrestore(&tdev->lock, flags);
|
|
+
|
|
+ return MBOX_MAX_MSG_LEN;
|
|
+}
|
|
+
|
|
+static const struct file_operations mbox_client_light_message_ops = {
|
|
+ .write = mbox_client_light_message_write,
|
|
+ .read = mbox_client_light_message_read,
|
|
+ .open = simple_open,
|
|
+ .llseek = generic_file_llseek,
|
|
+};
|
|
+
|
|
+static int index_names = 0;
|
|
+static bool debugfs_dir_created = false;
|
|
+static const char* file_names[] = {"mbox-client0", "mbox-client1"};
|
|
+
|
|
+static int mbox_client_light_add_debugfs(struct platform_device *pdev,
|
|
+ struct mbox_client_light_device *tdev)
|
|
+{
|
|
+ if (!debugfs_initialized())
|
|
+ return 0;
|
|
+
|
|
+ if (index_names > 2) {
|
|
+ dev_err(&pdev->dev, "Max device index is 2\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!debugfs_dir_created) {
|
|
+ root_debugfs_dir = debugfs_create_dir("mailbox",NULL);
|
|
+ if (!root_debugfs_dir) {
|
|
+ dev_err(&pdev->dev,
|
|
+ "Failed to create mailbox debugfs\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ debugfs_dir_created = true;
|
|
+ }
|
|
+
|
|
+ debugfs_create_file(file_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 <linux/clk.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/mailbox_controller.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+/* Status Register */
|
|
+#define LIGHT_MBOX_STA 0x0
|
|
+#define LIGHT_MBOX_CLR 0x4
|
|
+#define LIGHT_MBOX_MASK 0xc
|
|
+
|
|
+/* Transmit/receive data register:
|
|
+ * INFO0 ~ INFO6
|
|
+ */
|
|
+#define LIGHT_MBOX_INFO_NUM 8
|
|
+#define LIGHT_MBOX_DATA_INFO_NUM 7
|
|
+#define LIGHT_MBOX_INFO0 0x14
|
|
+/* Transmit ack register: INFO7 */
|
|
+#define LIGHT_MBOX_INFO7 0x30
|
|
+
|
|
+/* Generate remote icu IRQ Register */
|
|
+#define LIGHT_MBOX_GEN 0x10
|
|
+#define LIGHT_MBOX_GEN_RX_DATA BIT(6)
|
|
+#define LIGHT_MBOX_GEN_TX_ACK BIT(7)
|
|
+
|
|
+#define LIGHT_MBOX_CHAN_RES_SIZE 0x1000
|
|
+#define LIGHT_MBOX_CHANS 4
|
|
+#define LIGHT_MBOX_CHAN_NAME_SIZE 20
|
|
+
|
|
+#define LIGHT_MBOX_ACK_MAGIC 0xdeadbeaf
|
|
+
|
|
+enum light_mbox_chan_type {
|
|
+ LIGHT_MBOX_TYPE_TXRX, /* Tx & Rx chan */
|
|
+ LIGHT_MBOX_TYPE_DB, /* Tx & Rx doorbell */
|
|
+};
|
|
+
|
|
+enum light_mbox_icu_cpu_id {
|
|
+ LIGHT_MBOX_ICU_CPU0, /* 910T */
|
|
+ LIGHT_MBOX_ICU_CPU1, /* 902 */
|
|
+ LIGHT_MBOX_ICU_CPU2, /* 906 */
|
|
+ LIGHT_MBOX_ICU_CPU3, /* 910R */
|
|
+};
|
|
+
|
|
+struct light_mbox_con_priv {
|
|
+ enum light_mbox_icu_cpu_id idx;
|
|
+ enum light_mbox_chan_type type;
|
|
+ void __iomem *comm_local_base;
|
|
+ void __iomem *comm_remote_base;
|
|
+ char irq_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 <duanfugang.dfg@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light mailbox IPC driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
|
|
index 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 <linux/acpi.h>
|
|
+#include <linux/bitfield.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/iopoll.h>
|
|
@@ -35,6 +36,21 @@
|
|
#define DWCMSHC_CARD_IS_EMMC BIT(0)
|
|
#define DWCMSHC_ENHANCED_STROBE BIT(8)
|
|
#define DWCMSHC_EMMC_ATCTRL 0x40
|
|
+/* Tuning and auto-tuning fields in AT_CTRL_R control register */
|
|
+#define AT_CTRL_AT_EN BIT(0) /* autotuning is enabled */
|
|
+#define AT_CTRL_CI_SEL BIT(1) /* interval to drive center phase select */
|
|
+#define AT_CTRL_SWIN_TH_EN BIT(2) /* sampling window threshold enable */
|
|
+#define AT_CTRL_RPT_TUNE_ERR BIT(3) /* enable reporting framing errors */
|
|
+#define AT_CTRL_SW_TUNE_EN BIT(4) /* enable software managed tuning */
|
|
+#define AT_CTRL_WIN_EDGE_SEL_MASK GENMASK(11, 8) /* bits [11:8] */
|
|
+#define AT_CTRL_WIN_EDGE_SEL 0xf /* sampling window edge select */
|
|
+#define AT_CTRL_TUNE_CLK_STOP_EN BIT(16) /* clocks stopped during phase code change */
|
|
+#define AT_CTRL_PRE_CHANGE_DLY_MASK GENMASK(18, 17) /* bits [18:17] */
|
|
+#define AT_CTRL_PRE_CHANGE_DLY 0x1 /* 2-cycle latency */
|
|
+#define AT_CTRL_POST_CHANGE_DLY_MASK GENMASK(20, 19) /* bits [20:19] */
|
|
+#define AT_CTRL_POST_CHANGE_DLY 0x3 /* 4-cycle latency */
|
|
+#define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits [31:24] */
|
|
+#define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */
|
|
|
|
/* Rockchip specific Registers */
|
|
#define DWCMSHC_EMMC_DLL_CTRL 0x800
|
|
@@ -72,6 +88,82 @@
|
|
(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
|
|
#define RK35xx_MAX_CLKS 3
|
|
|
|
+/* PHY register area pointer */
|
|
+#define DWC_MSHC_PTR_PHY_R 0x300
|
|
+
|
|
+/* PHY general configuration */
|
|
+#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00)
|
|
+#define PHY_CNFG_RSTN_DEASSERT 0x1 /* Deassert PHY reset */
|
|
+#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16) /* bits [19:16] */
|
|
+#define PHY_CNFG_PAD_SP 0x0c /* PMOS TX drive strength */
|
|
+#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20) /* bits [23:20] */
|
|
+#define PHY_CNFG_PAD_SN 0x0c /* NMOS TX drive strength */
|
|
+
|
|
+/* PHY command/response pad settings */
|
|
+#define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04)
|
|
+
|
|
+/* PHY data pad settings */
|
|
+#define PHY_DATAPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x06)
|
|
+
|
|
+/* PHY clock pad settings */
|
|
+#define PHY_CLKPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x08)
|
|
+
|
|
+/* PHY strobe pad settings */
|
|
+#define PHY_STBPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0a)
|
|
+
|
|
+/* PHY reset pad settings */
|
|
+#define PHY_RSTNPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0c)
|
|
+
|
|
+/* Bitfields are common for all pad settings */
|
|
+#define PHY_PAD_RXSEL_1V8 0x1 /* Receiver type select for 1.8V */
|
|
+#define PHY_PAD_RXSEL_3V3 0x2 /* Receiver type select for 3.3V */
|
|
+
|
|
+#define PHY_PAD_WEAKPULL_MASK GENMASK(4, 3) /* bits [4:3] */
|
|
+#define PHY_PAD_WEAKPULL_PULLUP 0x1 /* Weak pull up enabled */
|
|
+#define PHY_PAD_WEAKPULL_PULLDOWN 0x2 /* Weak pull down enabled */
|
|
+
|
|
+#define PHY_PAD_TXSLEW_CTRL_P_MASK GENMASK(8, 5) /* bits [8:5] */
|
|
+#define PHY_PAD_TXSLEW_CTRL_P 0x3 /* Slew control for P-Type pad TX */
|
|
+#define PHY_PAD_TXSLEW_CTRL_N_MASK GENMASK(12, 9) /* bits [12:9] */
|
|
+#define PHY_PAD_TXSLEW_CTRL_N 0x3 /* Slew control for N-Type pad TX */
|
|
+
|
|
+/* PHY CLK delay line settings */
|
|
+#define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d)
|
|
+#define PHY_SDCLKDL_CNFG_UPDATE BIT(4) /* set before writing to SDCLKDL_DC */
|
|
+
|
|
+/* PHY CLK delay line delay code */
|
|
+#define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e)
|
|
+#define PHY_SDCLKDL_DC_INITIAL 0x40 /* initial delay code */
|
|
+#define PHY_SDCLKDL_DC_DEFAULT 0x32 /* default delay code */
|
|
+#define PHY_SDCLKDL_DC_HS400 0x18 /* delay code for HS400 mode */
|
|
+
|
|
+/* PHY drift_cclk_rx delay line configuration setting */
|
|
+#define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21)
|
|
+#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2) /* bits [3:2] */
|
|
+#define PHY_ATDL_CNFG_INPSEL 0x3 /* delay line input source */
|
|
+
|
|
+/* PHY DLL control settings */
|
|
+#define PHY_DLL_CTRL_R (DWC_MSHC_PTR_PHY_R + 0x24)
|
|
+#define PHY_DLL_CTRL_DISABLE 0x0 /* PHY DLL is enabled */
|
|
+#define PHY_DLL_CTRL_ENABLE 0x1 /* PHY DLL is disabled */
|
|
+
|
|
+/* PHY DLL configuration register 1 */
|
|
+#define PHY_DLL_CNFG1_R (DWC_MSHC_PTR_PHY_R + 0x25)
|
|
+#define PHY_DLL_CNFG1_SLVDLY_MASK GENMASK(5, 4) /* bits [5:4] */
|
|
+#define PHY_DLL_CNFG1_SLVDLY 0x2 /* DLL slave update delay input */
|
|
+#define PHY_DLL_CNFG1_WAITCYCLE 0x5 /* DLL wait cycle input */
|
|
+
|
|
+/* PHY DLL configuration register 2 */
|
|
+#define PHY_DLL_CNFG2_R (DWC_MSHC_PTR_PHY_R + 0x26)
|
|
+#define PHY_DLL_CNFG2_JUMPSTEP 0xa /* DLL jump step input */
|
|
+
|
|
+/* PHY DLL master and slave delay line configuration settings */
|
|
+#define PHY_DLLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x28)
|
|
+#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5) /* bits [6:5] */
|
|
+#define PHY_DLLDL_CNFG_SLV_INPSEL 0x3 /* clock source select for slave DL */
|
|
+
|
|
+#define FLAG_IO_FIXED_1V8 BIT(0)
|
|
+
|
|
#define BOUNDARY_OK(addr, len) \
|
|
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
|
|
|
|
@@ -92,6 +184,8 @@ struct dwcmshc_priv {
|
|
struct clk *bus_clk;
|
|
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
|
|
void *priv; /* pointer to SoC private stuff */
|
|
+ u16 delay_line;
|
|
+ u16 flags;
|
|
};
|
|
|
|
/*
|
|
@@ -157,6 +251,127 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|
sdhci_request(mmc, mrq);
|
|
}
|
|
|
|
+static void dwcmshc_phy_1_8v_init(struct sdhci_host *host)
|
|
+{
|
|
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
|
+ u32 val;
|
|
+
|
|
+ /* deassert phy reset & set tx drive strength */
|
|
+ val = PHY_CNFG_RSTN_DEASSERT;
|
|
+ val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP);
|
|
+ val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN);
|
|
+ sdhci_writel(host, val, PHY_CNFG_R);
|
|
+
|
|
+ /* disable delay line */
|
|
+ sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R);
|
|
+
|
|
+ /* set delay line */
|
|
+ sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R);
|
|
+ sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R);
|
|
+
|
|
+ /* enable delay lane */
|
|
+ val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
|
|
+ val &= ~(PHY_SDCLKDL_CNFG_UPDATE);
|
|
+ sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
|
|
+
|
|
+ /* configure phy pads */
|
|
+ val = PHY_PAD_RXSEL_1V8;
|
|
+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
|
+ sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
|
|
+ sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
|
|
+ sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
|
|
+
|
|
+ val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
|
+ sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
|
|
+
|
|
+ val = PHY_PAD_RXSEL_1V8;
|
|
+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
|
+ sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
|
|
+
|
|
+ /* enable data strobe mode */
|
|
+ sdhci_writeb(host, FIELD_PREP(PHY_DLLDL_CNFG_SLV_INPSEL_MASK, PHY_DLLDL_CNFG_SLV_INPSEL),
|
|
+ PHY_DLLDL_CNFG_R);
|
|
+
|
|
+ /* enable phy dll */
|
|
+ sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R);
|
|
+}
|
|
+
|
|
+static void dwcmshc_phy_3_3v_init(struct sdhci_host *host)
|
|
+{
|
|
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
|
+ u32 val;
|
|
+
|
|
+ /* deassert phy reset & set tx drive strength */
|
|
+ val = PHY_CNFG_RSTN_DEASSERT;
|
|
+ val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP);
|
|
+ val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN);
|
|
+ sdhci_writel(host, val, PHY_CNFG_R);
|
|
+
|
|
+ /* disable delay line */
|
|
+ sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R);
|
|
+
|
|
+ /* set delay line */
|
|
+ sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R);
|
|
+ sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R);
|
|
+
|
|
+ /* enable delay lane */
|
|
+ val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
|
|
+ val &= ~(PHY_SDCLKDL_CNFG_UPDATE);
|
|
+ sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
|
|
+
|
|
+ /* configure phy pads */
|
|
+ val = PHY_PAD_RXSEL_3V3;
|
|
+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
|
+ sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
|
|
+ sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
|
|
+ sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
|
|
+
|
|
+ val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
|
+ sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
|
|
+
|
|
+ val = PHY_PAD_RXSEL_3V3;
|
|
+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
|
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
|
+ sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
|
|
+
|
|
+ /* enable phy dll */
|
|
+ sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R);
|
|
+}
|
|
+
|
|
+static void th1520_sdhci_set_phy(struct sdhci_host *host)
|
|
+{
|
|
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
|
+ u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
|
|
+ u16 emmc_ctrl;
|
|
+
|
|
+ /* Before power on, set PHY configs */
|
|
+ if (priv->flags & FLAG_IO_FIXED_1V8)
|
|
+ dwcmshc_phy_1_8v_init(host);
|
|
+ else
|
|
+ dwcmshc_phy_3_3v_init(host);
|
|
+
|
|
+ if ((host->mmc->caps2 & emmc_caps) == emmc_caps) {
|
|
+ emmc_ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
|
|
+ emmc_ctrl |= DWCMSHC_CARD_IS_EMMC;
|
|
+ sdhci_writew(host, emmc_ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
|
|
+ }
|
|
+
|
|
+ sdhci_writeb(host, FIELD_PREP(PHY_DLL_CNFG1_SLVDLY_MASK, PHY_DLL_CNFG1_SLVDLY) |
|
|
+ PHY_DLL_CNFG1_WAITCYCLE, PHY_DLL_CNFG1_R);
|
|
+}
|
|
+
|
|
static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
|
|
unsigned int timing)
|
|
{
|
|
@@ -189,9 +404,25 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
|
|
ctrl_2 |= DWCMSHC_CTRL_HS400;
|
|
}
|
|
|
|
+ if (priv->flags & FLAG_IO_FIXED_1V8)
|
|
+ ctrl_2 |= SDHCI_CTRL_VDD_180;
|
|
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
|
}
|
|
|
|
+static void th1520_set_uhs_signaling(struct sdhci_host *host,
|
|
+ unsigned int timing)
|
|
+{
|
|
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
|
+
|
|
+ dwcmshc_set_uhs_signaling(host, timing);
|
|
+ if (timing == MMC_TIMING_MMC_HS400)
|
|
+ priv->delay_line = PHY_SDCLKDL_DC_HS400;
|
|
+ else
|
|
+ sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R);
|
|
+ th1520_sdhci_set_phy(host);
|
|
+}
|
|
+
|
|
static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
|
|
struct mmc_ios *ios)
|
|
{
|
|
@@ -338,6 +569,79 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
|
|
sdhci_reset(host, mask);
|
|
}
|
|
|
|
+static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|
+{
|
|
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
|
+ u32 val = 0;
|
|
+
|
|
+ if (host->flags & SDHCI_HS400_TUNING)
|
|
+ return 0;
|
|
+
|
|
+ sdhci_writeb(host, FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL),
|
|
+ PHY_ATDL_CNFG_R);
|
|
+ val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
|
+
|
|
+ /*
|
|
+ * configure tuning settings:
|
|
+ * - center phase select code driven in block gap interval
|
|
+ * - disable reporting of framing errors
|
|
+ * - disable software managed tuning
|
|
+ * - disable user selection of sampling window edges,
|
|
+ * instead tuning calculated edges are used
|
|
+ */
|
|
+ val &= ~(AT_CTRL_CI_SEL | AT_CTRL_RPT_TUNE_ERR | AT_CTRL_SW_TUNE_EN |
|
|
+ FIELD_PREP(AT_CTRL_WIN_EDGE_SEL_MASK, AT_CTRL_WIN_EDGE_SEL));
|
|
+
|
|
+ /*
|
|
+ * configure tuning settings:
|
|
+ * - enable auto-tuning
|
|
+ * - enable sampling window threshold
|
|
+ * - stop clocks during phase code change
|
|
+ * - set max latency in cycles between tx and rx clocks
|
|
+ * - set max latency in cycles to switch output phase
|
|
+ * - set max sampling window threshold value
|
|
+ */
|
|
+ val |= AT_CTRL_AT_EN | AT_CTRL_SWIN_TH_EN | AT_CTRL_TUNE_CLK_STOP_EN;
|
|
+ val |= FIELD_PREP(AT_CTRL_PRE_CHANGE_DLY_MASK, AT_CTRL_PRE_CHANGE_DLY);
|
|
+ val |= FIELD_PREP(AT_CTRL_POST_CHANGE_DLY_MASK, AT_CTRL_POST_CHANGE_DLY);
|
|
+ val |= FIELD_PREP(AT_CTRL_SWIN_TH_VAL_MASK, AT_CTRL_SWIN_TH_VAL);
|
|
+
|
|
+ sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
|
+ val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
|
+
|
|
+ /* perform tuning */
|
|
+ sdhci_start_tuning(host);
|
|
+ host->tuning_err = __sdhci_execute_tuning(host, opcode);
|
|
+ if (host->tuning_err) {
|
|
+ /* disable auto-tuning upon tuning error */
|
|
+ val &= ~AT_CTRL_AT_EN;
|
|
+ sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
|
+ dev_err(mmc_dev(host->mmc), "tuning failed: %d\n", host->tuning_err);
|
|
+ return -EIO;
|
|
+ }
|
|
+ sdhci_end_tuning(host);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask)
|
|
+{
|
|
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
|
+ u16 ctrl_2;
|
|
+
|
|
+ sdhci_reset(host, mask);
|
|
+
|
|
+ if (priv->flags & FLAG_IO_FIXED_1V8) {
|
|
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
|
+ if (!(ctrl_2 & SDHCI_CTRL_VDD_180)) {
|
|
+ ctrl_2 |= SDHCI_CTRL_VDD_180;
|
|
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
static const struct sdhci_ops sdhci_dwcmshc_ops = {
|
|
.set_clock = sdhci_set_clock,
|
|
.set_bus_width = sdhci_set_bus_width,
|
|
@@ -356,6 +660,17 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
|
|
.adma_write_desc = dwcmshc_adma_write_desc,
|
|
};
|
|
|
|
+static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = {
|
|
+ .set_clock = sdhci_set_clock,
|
|
+ .set_bus_width = sdhci_set_bus_width,
|
|
+ .set_uhs_signaling = th1520_set_uhs_signaling,
|
|
+ .get_max_clock = dwcmshc_get_max_clock,
|
|
+ .reset = th1520_sdhci_reset,
|
|
+ .adma_write_desc = dwcmshc_adma_write_desc,
|
|
+ .voltage_switch = dwcmshc_phy_1_8v_init,
|
|
+ .platform_execute_tuning = &th1520_execute_tuning,
|
|
+};
|
|
+
|
|
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
|
|
.ops = &sdhci_dwcmshc_ops,
|
|
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
|
|
@@ -379,6 +694,12 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
|
|
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
|
};
|
|
|
|
+static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = {
|
|
+ .ops = &sdhci_dwcmshc_th1520_ops,
|
|
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
|
|
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
|
+};
|
|
+
|
|
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
|
|
{
|
|
int err;
|
|
@@ -447,6 +768,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
|
|
.compatible = "snps,dwcmshc-sdhci",
|
|
.data = &sdhci_dwcmshc_pdata,
|
|
},
|
|
+ {
|
|
+ .compatible = "thead,th1520-dwcmshc",
|
|
+ .data = &sdhci_dwcmshc_th1520_pdata,
|
|
+ },
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
|
|
@@ -542,6 +867,30 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
|
goto err_clk;
|
|
}
|
|
|
|
+ if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) {
|
|
+ priv->delay_line = PHY_SDCLKDL_DC_DEFAULT;
|
|
+
|
|
+ if ((device_property_read_bool(dev, "mmc-ddr-1_8v")) |
|
|
+ (device_property_read_bool(dev, "mmc-hs200-1_8v")) |
|
|
+ (device_property_read_bool(dev, "mmc-hs400-1_8v")))
|
|
+ priv->flags |= FLAG_IO_FIXED_1V8;
|
|
+ else
|
|
+ priv->flags &= ~FLAG_IO_FIXED_1V8;
|
|
+
|
|
+ /*
|
|
+ * start_signal_voltage_switch() will try 3.3V first
|
|
+ * then 1.8V. Use SDHCI_SIGNALING_180 rather than
|
|
+ * SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V
|
|
+ * in sdhci_start_signal_voltage_switch().
|
|
+ */
|
|
+ if (priv->flags & FLAG_IO_FIXED_1V8) {
|
|
+ host->flags &= ~SDHCI_SIGNALING_330;
|
|
+ host->flags |= SDHCI_SIGNALING_180;
|
|
+ }
|
|
+
|
|
+ sdhci_enable_v4_mode(host);
|
|
+ }
|
|
+
|
|
#ifdef CONFIG_ACPI
|
|
if (pltfm_data == &sdhci_dwcmshc_bf3_pdata)
|
|
sdhci_enable_v4_mode(host);
|
|
diff --git a/drivers/mmc/host/sdhci-sophgo.c b/drivers/mmc/host/sdhci-sophgo.c
|
|
new file mode 100644
|
|
index 000000000000..8200ccaa68f6
|
|
--- /dev/null
|
|
+++ b/drivers/mmc/host/sdhci-sophgo.c
|
|
@@ -0,0 +1,619 @@
|
|
+/*
|
|
+ * Sophgo SDHCI Platform driver
|
|
+ *
|
|
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 and
|
|
+ * only version 2 as published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/mmc/mmc.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/reset.h>
|
|
+#include "sdhci-pltfm.h"
|
|
+#include "sdhci-sophgo.h"
|
|
+
|
|
+#define DRIVER_NAME "bm"
|
|
+
|
|
+#define BM_SDHCI_VENDOR_OFFSET 0x500
|
|
+#define BM_SDHCI_VENDOR_MSHC_CTRL_R (BM_SDHCI_VENDOR_OFFSET + 0x8)
|
|
+#define BM_SDHCI_VENDOR_A_CTRL_R (BM_SDHCI_VENDOR_OFFSET + 0x40)
|
|
+#define BM_SDHCI_VENDOR_A_STAT_R (BM_SDHCI_VENDOR_OFFSET + 0x44)
|
|
+
|
|
+static void bm_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
|
|
+{
|
|
+ sdhci_writel(host, 0x0, BM_SDHCI_VENDOR_MSHC_CTRL_R);
|
|
+ sdhci_writel(host, 0x18, BM_SDHCI_VENDOR_A_CTRL_R);
|
|
+ sdhci_writel(host, tap, BM_SDHCI_VENDOR_A_STAT_R);
|
|
+}
|
|
+
|
|
+static int sdhci_bm_execute_software_tuning(struct sdhci_host *host, u32 opcode)
|
|
+{
|
|
+ unsigned int maxwidth = 0;
|
|
+ unsigned int tuntap;
|
|
+ struct {
|
|
+ unsigned int start;
|
|
+ unsigned int end;
|
|
+ unsigned int width;
|
|
+ } 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 <linux/module.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/mmc/mmc.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+/*register macro */
|
|
+#define P_VENDOR_SPECIFIC_AREA 0xE8
|
|
+#define P_VENDOR2_SPECIFIC_AREA 0xEA
|
|
+#define VENDOR_EMMC_CTRL 0x2C
|
|
+#define SW_RST_R 0x2F
|
|
+#define SDHCI_NORMAL_INT_STATUS 0x30
|
|
+#define SDHCI_ERR_INT_STATUS 0x32
|
|
+#define SDHCI_ERR_INT_STATUS_EN 0x36
|
|
+#define SDHCI_HOST_CTRL2_R 0x3E
|
|
+#define SDHCI_MSHC_CTRL 0x508
|
|
+#define SDHCI_AT_CTRL 0x540
|
|
+#define SDHCI_AT_STAT 0x544
|
|
+
|
|
+/* PHY register */
|
|
+#define SDHCI_PHY_R_OFFSET 0x300
|
|
+
|
|
+#define SDHCI_P_PHY_CNFG (SDHCI_PHY_R_OFFSET + 0x00)
|
|
+#define SDHCI_P_CMDPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x04)
|
|
+#define SDHCI_P_DATPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x06)
|
|
+#define SDHCI_P_CLKPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x08)
|
|
+#define SDHCI_P_STBPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0A)
|
|
+#define SDHCI_P_RSTNPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0C)
|
|
+#define SDHCI_P_PADTEST_CNFG (SDHCI_PHY_R_OFFSET + 0x0E)
|
|
+#define SDHCI_P_PADTEST_OUT (SDHCI_PHY_R_OFFSET + 0x10)
|
|
+#define SDHCI_P_PADTEST_IN (SDHCI_PHY_R_OFFSET + 0x12)
|
|
+#define SDHCI_P_COMMDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1C)
|
|
+#define SDHCI_P_SDCLKDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1D)
|
|
+#define SDHCI_P_SDCLKDL_DC (SDHCI_PHY_R_OFFSET + 0x1E)
|
|
+#define SDHCI_P_SMPLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x20)
|
|
+#define SDHCI_P_ATDL_CNFG (SDHCI_PHY_R_OFFSET + 0x21)
|
|
+#define SDHCI_P_DLL_CTRL (SDHCI_PHY_R_OFFSET + 0x24)
|
|
+#define SDHCI_P_DLL_CNFG1 (SDHCI_PHY_R_OFFSET + 0x25)
|
|
+#define SDHCI_P_DLL_CNFG2 (SDHCI_PHY_R_OFFSET + 0x26)
|
|
+#define SDHCI_P_DLLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x28)
|
|
+#define SDHCI_P_DLL_OFFST (SDHCI_PHY_R_OFFSET + 0x29)
|
|
+#define SDHCI_P_DLLMST_TSTDC (SDHCI_PHY_R_OFFSET + 0x2A)
|
|
+#define SDHCI_P_DLLLBT_CNFG (SDHCI_PHY_R_OFFSET + 0x2C)
|
|
+#define SDHCI_P_DLL_STATUS (SDHCI_PHY_R_OFFSET + 0x2E)
|
|
+#define SDHCI_P_DLLDBG_MLKDC (SDHCI_PHY_R_OFFSET + 0x30)
|
|
+#define SDHCI_P_DLLDBG_SLKDC (SDHCI_PHY_R_OFFSET + 0x32)
|
|
+
|
|
+#define PHY_CNFG_PHY_RSTN 0
|
|
+#define PHY_CNFG_PHY_PWRGOOD 1
|
|
+#define PHY_CNFG_PAD_SP 16
|
|
+#define PHY_CNFG_PAD_SP_MSK 0xf
|
|
+#define PHY_CNFG_PAD_SN 20
|
|
+#define PHY_CNFG_PAD_SN_MSK 0xf
|
|
+
|
|
+#define PAD_CNFG_RXSEL 0
|
|
+#define PAD_CNFG_RXSEL_MSK 0x7
|
|
+#define PAD_CNFG_WEAKPULL_EN 3
|
|
+#define PAD_CNFG_WEAKPULL_EN_MSK 0x3
|
|
+#define PAD_CNFG_TXSLEW_CTRL_P 5
|
|
+#define PAD_CNFG_TXSLEW_CTRL_P_MSK 0xf
|
|
+#define PAD_CNFG_TXSLEW_CTRL_N 9
|
|
+#define PAD_CNFG_TXSLEW_CTRL_N_MSK 0xf
|
|
+
|
|
+#define COMMDL_CNFG_DLSTEP_SEL 0
|
|
+#define COMMDL_CNFG_DLOUT_EN 1
|
|
+
|
|
+#define SDCLKDL_CNFG_EXTDLY_EN 0
|
|
+#define SDCLKDL_CNFG_BYPASS_EN 1
|
|
+#define SDCLKDL_CNFG_INPSEL_CNFG 2
|
|
+#define SDCLKDL_CNFG_INPSEL_CNFG_MSK 0x3
|
|
+#define SDCLKDL_CNFG_UPDATE_DC 4
|
|
+
|
|
+#define SMPLDL_CNFG_EXTDLY_EN 0
|
|
+#define SMPLDL_CNFG_BYPASS_EN 1
|
|
+#define SMPLDL_CNFG_INPSEL_CNFG 2
|
|
+#define SMPLDL_CNFG_INPSEL_CNFG_MSK 0x3
|
|
+#define SMPLDL_CNFG_INPSEL_OVERRIDE 4
|
|
+
|
|
+#define ATDL_CNFG_EXTDLY_EN 0
|
|
+#define ATDL_CNFG_BYPASS_EN 1
|
|
+#define ATDL_CNFG_INPSEL_CNFG 2
|
|
+#define ATDL_CNFG_INPSEL_CNFG_MSK 0x3
|
|
+
|
|
+#define MAX_TUNING_STEP 128
|
|
+
|
|
+struct sdhci_bm_host {
|
|
+ struct platform_device *pdev;
|
|
+ void __iomem *core_mem; /* bm SDCC mapped address */
|
|
+ struct clk *clk; /* main SD/MMC bus clock */
|
|
+ struct clk *clk100k;
|
|
+ struct clk *clkaxi;
|
|
+ struct mmc_host *mmc;
|
|
+ struct reset_control *reset;
|
|
+
|
|
+ struct reset_control *clk_rst_axi_emmc_ctrl;
|
|
+ struct reset_control *clk_rst_emmc_ctrl;
|
|
+ struct reset_control *clk_rst_100k_emmc_ctrl;
|
|
+};
|
|
+
|
|
+int bm_sdhci_phy_init(struct sdhci_host *host);
|
|
+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
|
|
+#endif
|
|
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
|
|
index ff41aa56564e..526df8063579 100644
|
|
--- a/drivers/mmc/host/sdhci.c
|
|
+++ b/drivers/mmc/host/sdhci.c
|
|
@@ -49,7 +49,9 @@ static unsigned int debug_quirks2;
|
|
|
|
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
|
|
|
|
+#ifndef CONFIG_ARCH_SOPHGO
|
|
static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
|
|
+#endif
|
|
|
|
void sdhci_dumpregs(struct sdhci_host *host)
|
|
{
|
|
@@ -1627,7 +1629,11 @@ static void sdhci_finish_data(struct sdhci_host *host)
|
|
__sdhci_finish_data(host, false);
|
|
}
|
|
|
|
+#ifndef CONFIG_ARCH_SOPHGO
|
|
static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
|
|
+#else
|
|
+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
|
|
+#endif
|
|
{
|
|
int flags;
|
|
u32 mask;
|
|
@@ -1717,6 +1723,9 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
|
|
|
|
return true;
|
|
}
|
|
+#ifdef CONFIG_ARCH_SOPHGO
|
|
+EXPORT_SYMBOL_GPL(sdhci_send_command);
|
|
+#endif
|
|
|
|
static bool sdhci_present_error(struct sdhci_host *host,
|
|
struct mmc_command *cmd, bool present)
|
|
@@ -2841,7 +2850,7 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
|
|
}
|
|
EXPORT_SYMBOL_GPL(sdhci_send_tuning);
|
|
|
|
-static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|
+int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|
{
|
|
int i;
|
|
|
|
@@ -2879,6 +2888,7 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|
sdhci_reset_tuning(host);
|
|
return -EAGAIN;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(__sdhci_execute_tuning);
|
|
|
|
int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|
{
|
|
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
|
|
index f219bdea8f28..149e699aac92 100644
|
|
--- a/drivers/mmc/host/sdhci.h
|
|
+++ b/drivers/mmc/host/sdhci.h
|
|
@@ -793,6 +793,7 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width);
|
|
void sdhci_reset(struct sdhci_host *host, u8 mask);
|
|
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
|
|
int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
|
|
+int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode);
|
|
void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
|
|
int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
|
|
struct mmc_ios *ios);
|
|
@@ -823,5 +824,8 @@ void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode);
|
|
void sdhci_switch_external_dma(struct sdhci_host *host, bool en);
|
|
void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable);
|
|
void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
|
|
+#ifdef CONFIG_ARCH_SOPHGO
|
|
+bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
|
|
+#endif
|
|
|
|
#endif /* __SDHCI_HW_H */
|
|
diff --git a/drivers/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 <linux/iopoll.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/mtd/mtd.h>
|
|
+#include <linux/mtd/spi-nor.h>
|
|
+
|
|
+/* 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 <linux/stmmac.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/phy.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/of_net.h>
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/io.h>
|
|
+
|
|
+#include "stmmac_platform.h"
|
|
+
|
|
+struct bm_mac {
|
|
+ struct device *dev;
|
|
+ struct reset_control *rst;
|
|
+ struct clk *clk_tx;
|
|
+ struct clk *gate_clk_tx;
|
|
+ struct clk *gate_clk_ref;
|
|
+ struct gpio_desc *reset;
|
|
+};
|
|
+
|
|
+static u64 bm_dma_mask = DMA_BIT_MASK(40);
|
|
+
|
|
+static int bm_eth_reset_phy(struct platform_device *pdev)
|
|
+{
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
+ int phy_reset_gpio;
|
|
+
|
|
+ if (!np)
|
|
+ return 0;
|
|
+
|
|
+ phy_reset_gpio = of_get_named_gpio(np, "phy-reset-gpios", 0);
|
|
+
|
|
+ if (phy_reset_gpio < 0)
|
|
+ return 0;
|
|
+
|
|
+ if (gpio_request(phy_reset_gpio, "eth-phy-reset"))
|
|
+ return 0;
|
|
+
|
|
+ /* RESET_PU */
|
|
+ gpio_direction_output(phy_reset_gpio, 0);
|
|
+ mdelay(100);
|
|
+
|
|
+ gpio_direction_output(phy_reset_gpio, 1);
|
|
+ /* RC charging time */
|
|
+ mdelay(100);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void bm_mac_fix_speed(void *priv, unsigned int speed, unsigned int mode)
|
|
+{
|
|
+ struct bm_mac *bsp_priv = priv;
|
|
+ unsigned long rate = 125000000;
|
|
+ bool needs_calibration = false;
|
|
+ int err;
|
|
+
|
|
+ switch (speed) {
|
|
+ case SPEED_1000:
|
|
+ needs_calibration = true;
|
|
+ rate = 125000000;
|
|
+ break;
|
|
+
|
|
+ case SPEED_100:
|
|
+ needs_calibration = true;
|
|
+ rate = 25000000;
|
|
+ break;
|
|
+
|
|
+ case SPEED_10:
|
|
+ needs_calibration = true;
|
|
+ rate = 2500000;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ dev_err(bsp_priv->dev, "invalid speed %u\n", speed);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (needs_calibration) {
|
|
+ err = clk_set_rate(bsp_priv->clk_tx, rate);
|
|
+ if (err < 0)
|
|
+ dev_err(bsp_priv->dev, "failed to set TX rate: %d\n"
|
|
+ , err);
|
|
+ }
|
|
+}
|
|
+
|
|
+void bm_dwmac_exit(struct platform_device *pdev, void *priv)
|
|
+{
|
|
+ struct bm_mac *bsp_priv = priv;
|
|
+
|
|
+ clk_disable_unprepare(bsp_priv->gate_clk_tx);
|
|
+ clk_disable_unprepare(bsp_priv->gate_clk_ref);
|
|
+}
|
|
+
|
|
+static int bm_validate_ucast_entries(struct device *dev, int ucast_entries)
|
|
+{
|
|
+ int x = ucast_entries;
|
|
+
|
|
+ switch (x) {
|
|
+ case 1 ... 32:
|
|
+ case 64:
|
|
+ case 128:
|
|
+ break;
|
|
+ default:
|
|
+ x = 1;
|
|
+ dev_info(dev, "Unicast table entries set to unexpected value %d\n",
|
|
+ ucast_entries);
|
|
+ break;
|
|
+ }
|
|
+ return x;
|
|
+}
|
|
+
|
|
+static int bm_validate_mcast_bins(struct device *dev, int mcast_bins)
|
|
+{
|
|
+ int x = mcast_bins;
|
|
+
|
|
+ switch (x) {
|
|
+ case HASH_TABLE_SIZE:
|
|
+ case 128:
|
|
+ case 256:
|
|
+ break;
|
|
+ default:
|
|
+ x = 0;
|
|
+ dev_info(dev, "Hash table entries set to unexpected value %d\n",
|
|
+ mcast_bins);
|
|
+ break;
|
|
+ }
|
|
+ return x;
|
|
+}
|
|
+
|
|
+static void bm_dwmac_probe_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat)
|
|
+{
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
+
|
|
+ of_property_read_u32(np, "snps,multicast-filter-bins", &plat->multicast_filter_bins);
|
|
+ of_property_read_u32(np, "snps,perfect-filter-entries", &plat->unicast_filter_entries);
|
|
+ plat->unicast_filter_entries = bm_validate_ucast_entries(&pdev->dev,
|
|
+ plat->unicast_filter_entries);
|
|
+ plat->multicast_filter_bins = bm_validate_mcast_bins(&pdev->dev,
|
|
+ plat->multicast_filter_bins);
|
|
+ plat->flags |= (STMMAC_FLAG_TSO_EN);
|
|
+ plat->has_gmac4 = 1;
|
|
+ plat->has_gmac = 0;
|
|
+ plat->pmt = 0;
|
|
+}
|
|
+
|
|
+static int bm_dwmac_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct plat_stmmacenet_data *plat_dat;
|
|
+ struct stmmac_resources stmmac_res;
|
|
+ struct bm_mac *bsp_priv = NULL;
|
|
+ struct phy_device *phydev = NULL;
|
|
+ struct stmmac_priv *priv = NULL;
|
|
+ struct net_device *ndev = NULL;
|
|
+ int ret;
|
|
+
|
|
+ pdev->dev.dma_mask = &bm_dma_mask;
|
|
+ pdev->dev.coherent_dma_mask = bm_dma_mask;
|
|
+
|
|
+ bm_eth_reset_phy(pdev);
|
|
+
|
|
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
|
|
+ if (IS_ERR(plat_dat))
|
|
+ return PTR_ERR(plat_dat);
|
|
+
|
|
+ bm_dwmac_probe_config_dt(pdev, plat_dat);
|
|
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
|
+ if (ret)
|
|
+ goto err_remove_config_dt;
|
|
+
|
|
+ bsp_priv = devm_kzalloc(&pdev->dev, sizeof(*bsp_priv), GFP_KERNEL);
|
|
+ if (!bsp_priv)
|
|
+ return PTR_ERR(bsp_priv);
|
|
+
|
|
+ bsp_priv->dev = &pdev->dev;
|
|
+
|
|
+ /* clock setup */
|
|
+ bsp_priv->clk_tx = devm_clk_get(&pdev->dev,
|
|
+ "clk_tx");
|
|
+ if (IS_ERR(bsp_priv->clk_tx))
|
|
+ dev_warn(&pdev->dev, "Cannot get mac tx clock!\n");
|
|
+ else
|
|
+ plat_dat->fix_mac_speed = bm_mac_fix_speed;
|
|
+
|
|
+ bsp_priv->gate_clk_tx = devm_clk_get(&pdev->dev, "gate_clk_tx");
|
|
+ if (IS_ERR(bsp_priv->gate_clk_tx))
|
|
+ dev_warn(&pdev->dev, "Cannot get mac tx gating clock!\n");
|
|
+ else
|
|
+ clk_prepare_enable(bsp_priv->gate_clk_tx);
|
|
+
|
|
+ bsp_priv->gate_clk_ref = devm_clk_get(&pdev->dev, "gate_clk_ref");
|
|
+ if (IS_ERR(bsp_priv->gate_clk_ref))
|
|
+ dev_warn(&pdev->dev, "Cannot get mac ref gating clock!\n");
|
|
+ else
|
|
+ clk_prepare_enable(bsp_priv->gate_clk_ref);
|
|
+
|
|
+ plat_dat->bsp_priv = bsp_priv;
|
|
+ plat_dat->exit = bm_dwmac_exit;
|
|
+
|
|
+ ndev = dev_get_drvdata(&pdev->dev);
|
|
+ priv = netdev_priv(ndev);
|
|
+ phydev = mdiobus_get_phy(priv->mii, 0);
|
|
+ if (phydev == NULL) {
|
|
+ dev_err(&pdev->dev, "Can not get phy in addr 0\n");
|
|
+ goto err_remove_config_dt;
|
|
+ }
|
|
+
|
|
+ /* set green LED0 active for transmit, yellow LED1 for link*/
|
|
+ ret = phy_write_paged(phydev, 0, 0x1f, 0xd04);
|
|
+ if (ret < 0)
|
|
+ dev_err(&pdev->dev, "Can not select page 0xd04\n");
|
|
+ ret = phy_write_paged(phydev, 0xd04, 0x10, 0x617f);
|
|
+ if (ret < 0)
|
|
+ dev_err(&pdev->dev, "Can not alter LED Configuration\n");
|
|
+ /* disable eee LED function */
|
|
+ ret = phy_write_paged(phydev, 0xd04, 0x11, 0x0);
|
|
+ if (ret < 0)
|
|
+ dev_err(&pdev->dev, "Can not disable EEE Configuration\n");
|
|
+ ret = phy_write_paged(phydev, 0, 0x1f, 0);
|
|
+ if (ret < 0)
|
|
+ dev_err(&pdev->dev, "Can not select page 0\n");
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_remove_config_dt:
|
|
+ stmmac_remove_config_dt(pdev, plat_dat);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct of_device_id bm_dwmac_match[] = {
|
|
+ { .compatible = "bitmain,ethernet" },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, bm_dwmac_match);
|
|
+
|
|
+static struct platform_driver bm_dwmac_driver = {
|
|
+ .probe = bm_dwmac_probe,
|
|
+ .remove_new = stmmac_pltfr_remove,
|
|
+ .driver = {
|
|
+ .name = "bm-dwmac",
|
|
+ .pm = &stmmac_pltfr_pm_ops,
|
|
+ .of_match_table = bm_dwmac_match,
|
|
+ },
|
|
+};
|
|
+module_platform_driver(bm_dwmac_driver);
|
|
+
|
|
+MODULE_AUTHOR("Wei Huang<wei.huang01@bitmain.com>");
|
|
+MODULE_DESCRIPTION("Bitmain DWMAC specific glue layer");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
|
|
new file mode 100644
|
|
index 000000000000..fec27f78a417
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
|
|
@@ -0,0 +1,289 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * T-HEAD DWMAC platform driver
|
|
+ *
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/bitfield.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_net.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/regmap.h>
|
|
+
|
|
+#include "stmmac_platform.h"
|
|
+
|
|
+#define GMAC_CLK_EN 0x00
|
|
+#define GMAC_TX_CLK_EN BIT(1)
|
|
+#define GMAC_TX_CLK_N_EN BIT(2)
|
|
+#define GMAC_TX_CLK_OUT_EN BIT(3)
|
|
+#define GMAC_RX_CLK_EN BIT(4)
|
|
+#define GMAC_RX_CLK_N_EN BIT(5)
|
|
+#define GMAC_EPHY_REF_CLK_EN BIT(6)
|
|
+#define GMAC_RXCLK_DELAY_CTRL 0x04
|
|
+#define GMAC_RXCLK_BYPASS BIT(15)
|
|
+#define GMAC_RXCLK_INVERT BIT(14)
|
|
+#define GMAC_RXCLK_DELAY_MASK GENMASK(4, 0)
|
|
+#define GMAC_RXCLK_DELAY_VAL(x) FIELD_PREP(GMAC_RXCLK_DELAY_MASK, (x))
|
|
+#define GMAC_TXCLK_DELAY_CTRL 0x08
|
|
+#define GMAC_TXCLK_BYPASS BIT(15)
|
|
+#define GMAC_TXCLK_INVERT BIT(14)
|
|
+#define GMAC_TXCLK_DELAY_MASK GENMASK(4, 0)
|
|
+#define GMAC_TXCLK_DELAY_VAL(x) FIELD_PREP(GMAC_RXCLK_DELAY_MASK, (x))
|
|
+#define GMAC_PLLCLK_DIV 0x0c
|
|
+#define GMAC_PLLCLK_DIV_EN BIT(31)
|
|
+#define GMAC_PLLCLK_DIV_MASK GENMASK(7, 0)
|
|
+#define GMAC_PLLCLK_DIV_NUM(x) FIELD_PREP(GMAC_PLLCLK_DIV_MASK, (x))
|
|
+#define GMAC_GTXCLK_SEL 0x18
|
|
+#define GMAC_GTXCLK_SEL_PLL BIT(0)
|
|
+#define GMAC_INTF_CTRL 0x1c
|
|
+#define PHY_INTF_MASK BIT(0)
|
|
+#define PHY_INTF_RGMII FIELD_PREP(PHY_INTF_MASK, 1)
|
|
+#define PHY_INTF_MII_GMII FIELD_PREP(PHY_INTF_MASK, 0)
|
|
+#define GMAC_TXCLK_OEN 0x20
|
|
+#define TXCLK_DIR_MASK BIT(0)
|
|
+#define TXCLK_DIR_OUTPUT FIELD_PREP(TXCLK_DIR_MASK, 0)
|
|
+#define TXCLK_DIR_INPUT FIELD_PREP(TXCLK_DIR_MASK, 1)
|
|
+
|
|
+#define GMAC_GMII_RGMII_RATE 125000000
|
|
+#define GMAC_MII_RATE 25000000
|
|
+
|
|
+struct thead_dwmac {
|
|
+ struct plat_stmmacenet_data *plat;
|
|
+ struct regmap *apb_regmap;
|
|
+ struct device *dev;
|
|
+ u32 rx_delay;
|
|
+ u32 tx_delay;
|
|
+};
|
|
+
|
|
+static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat)
|
|
+{
|
|
+ struct thead_dwmac *dwmac = plat->bsp_priv;
|
|
+ u32 phyif;
|
|
+
|
|
+ switch (plat->mac_interface) {
|
|
+ case PHY_INTERFACE_MODE_MII:
|
|
+ phyif = PHY_INTF_MII_GMII;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
+ phyif = PHY_INTF_RGMII;
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(dwmac->dev, "unsupported phy interface %d\n",
|
|
+ plat->mac_interface);
|
|
+ return -EINVAL;
|
|
+ };
|
|
+
|
|
+ regmap_write(dwmac->apb_regmap, GMAC_INTF_CTRL, phyif);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat)
|
|
+{
|
|
+ struct thead_dwmac *dwmac = plat->bsp_priv;
|
|
+ u32 txclk_dir;
|
|
+
|
|
+ switch (plat->mac_interface) {
|
|
+ case PHY_INTERFACE_MODE_MII:
|
|
+ txclk_dir = TXCLK_DIR_INPUT;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
+ txclk_dir = TXCLK_DIR_OUTPUT;
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(dwmac->dev, "unsupported phy interface %d\n",
|
|
+ plat->mac_interface);
|
|
+ return -EINVAL;
|
|
+ };
|
|
+
|
|
+ regmap_write(dwmac->apb_regmap, GMAC_TXCLK_OEN, txclk_dir);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)
|
|
+{
|
|
+ struct thead_dwmac *dwmac = priv;
|
|
+ struct plat_stmmacenet_data *plat = dwmac->plat;
|
|
+ unsigned long rate;
|
|
+ u32 div;
|
|
+
|
|
+ switch (plat->mac_interface) {
|
|
+ /* For MII, rxc/txc is provided by phy */
|
|
+ case PHY_INTERFACE_MODE_MII:
|
|
+ return;
|
|
+
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
+ rate = clk_get_rate(plat->stmmac_clk);
|
|
+ if (!rate || rate % GMAC_GMII_RGMII_RATE != 0 ||
|
|
+ rate % GMAC_MII_RATE != 0) {
|
|
+ dev_err(dwmac->dev, "invalid gmac rate %ld\n", rate);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV, GMAC_PLLCLK_DIV_EN, 0);
|
|
+
|
|
+ switch (speed) {
|
|
+ case SPEED_1000:
|
|
+ div = rate / GMAC_GMII_RGMII_RATE;
|
|
+ break;
|
|
+ case SPEED_100:
|
|
+ div = rate / GMAC_MII_RATE;
|
|
+ break;
|
|
+ case SPEED_10:
|
|
+ div = rate * 10 / GMAC_MII_RATE;
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(dwmac->dev, "invalid speed %u\n", speed);
|
|
+ return;
|
|
+ }
|
|
+ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV,
|
|
+ GMAC_PLLCLK_DIV_MASK, GMAC_PLLCLK_DIV_NUM(div));
|
|
+
|
|
+ regmap_update_bits(dwmac->apb_regmap, GMAC_PLLCLK_DIV,
|
|
+ GMAC_PLLCLK_DIV_EN, GMAC_PLLCLK_DIV_EN);
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(dwmac->dev, "unsupported phy interface %d\n",
|
|
+ plat->mac_interface);
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat)
|
|
+{
|
|
+ struct thead_dwmac *dwmac = plat->bsp_priv;
|
|
+ u32 reg;
|
|
+
|
|
+ switch (plat->mac_interface) {
|
|
+ case PHY_INTERFACE_MODE_MII:
|
|
+ reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN;
|
|
+ break;
|
|
+
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
+ /* use pll */
|
|
+ regmap_write(dwmac->apb_regmap, GMAC_GTXCLK_SEL, GMAC_GTXCLK_SEL_PLL);
|
|
+
|
|
+ reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN |
|
|
+ GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ dev_err(dwmac->dev, "unsupported phy interface %d\n",
|
|
+ plat->mac_interface);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ regmap_write(dwmac->apb_regmap, GMAC_CLK_EN, reg);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int thead_dwmac_init(struct platform_device *pdev,
|
|
+ struct plat_stmmacenet_data *plat)
|
|
+{
|
|
+ struct thead_dwmac *dwmac = plat->bsp_priv;
|
|
+ int ret;
|
|
+
|
|
+ ret = thead_dwmac_set_phy_if(plat);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = thead_dwmac_set_txclk_dir(plat);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ regmap_write(dwmac->apb_regmap, GMAC_RXCLK_DELAY_CTRL,
|
|
+ GMAC_RXCLK_DELAY_VAL(dwmac->rx_delay));
|
|
+ regmap_write(dwmac->apb_regmap, GMAC_TXCLK_DELAY_CTRL,
|
|
+ GMAC_TXCLK_DELAY_VAL(dwmac->tx_delay));
|
|
+
|
|
+ thead_dwmac_fix_speed(dwmac, SPEED_1000, 0);
|
|
+
|
|
+ return thead_dwmac_enable_clk(plat);
|
|
+}
|
|
+
|
|
+static int thead_dwmac_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct plat_stmmacenet_data *plat;
|
|
+ struct stmmac_resources stmmac_res;
|
|
+ struct thead_dwmac *dwmac;
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
+ u32 delay_ps;
|
|
+ int ret;
|
|
+
|
|
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
|
+ if (ret)
|
|
+ return dev_err_probe(&pdev->dev, ret,
|
|
+ "failed to get resources\n");
|
|
+
|
|
+ plat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
|
|
+ if (IS_ERR(plat))
|
|
+ return dev_err_probe(&pdev->dev, PTR_ERR(plat),
|
|
+ "dt configuration failed\n");
|
|
+
|
|
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
|
|
+ if (!dwmac)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ if (!of_property_read_u32(np, "rx-internal-delay-ps", &delay_ps))
|
|
+ dwmac->rx_delay = delay_ps;
|
|
+ if (!of_property_read_u32(np, "tx-internal-delay-ps", &delay_ps))
|
|
+ dwmac->tx_delay = delay_ps;
|
|
+
|
|
+ dwmac->apb_regmap = syscon_regmap_lookup_by_phandle(np, "thead,gmacapb");
|
|
+ if (IS_ERR(dwmac->apb_regmap))
|
|
+ return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->apb_regmap),
|
|
+ "Failed to get gmac apb syscon\n");
|
|
+
|
|
+ dwmac->dev = &pdev->dev;
|
|
+ dwmac->plat = plat;
|
|
+ plat->bsp_priv = dwmac;
|
|
+ plat->fix_mac_speed = thead_dwmac_fix_speed;
|
|
+
|
|
+ ret = thead_dwmac_init(pdev, plat);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return stmmac_dvr_probe(&pdev->dev, plat, &stmmac_res);
|
|
+}
|
|
+
|
|
+static const struct of_device_id thead_dwmac_match[] = {
|
|
+ { .compatible = "thead,th1520-dwmac" },
|
|
+ { }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, thead_dwmac_match);
|
|
+
|
|
+static struct platform_driver thead_dwmac_driver = {
|
|
+ .probe = thead_dwmac_probe,
|
|
+ .remove_new = stmmac_pltfr_remove,
|
|
+ .driver = {
|
|
+ .name = "thead-dwmac",
|
|
+ .pm = &stmmac_pltfr_pm_ops,
|
|
+ .of_match_table = thead_dwmac_match,
|
|
+ },
|
|
+};
|
|
+module_platform_driver(thead_dwmac_driver);
|
|
+
|
|
+MODULE_AUTHOR("T-HEAD");
|
|
+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
|
|
+MODULE_DESCRIPTION("T-HEAD dwmac platform driver");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
|
|
index 291d12711363..25c768d5afb4 100644
|
|
--- a/drivers/pci/controller/cadence/Kconfig
|
|
+++ b/drivers/pci/controller/cadence/Kconfig
|
|
@@ -42,6 +42,17 @@ config PCIE_CADENCE_PLAT_EP
|
|
endpoint mode. This PCIe controller may be embedded into many
|
|
different vendors SoCs.
|
|
|
|
+config PCIE_CADENCE_SOPHGO
|
|
+ bool "Cadence Sophgo PCIe Host controller"
|
|
+ depends on OF
|
|
+ select IRQ_DOMAIN
|
|
+ select PCIE_CADENCE
|
|
+ help
|
|
+ Say Y here if you want to support the Cadence PCIe controller in host mode
|
|
+ for Sophgo SoCs. this PCIe controller is from cadence, integrated into the
|
|
+ Sophgo SoCs. PCIe is one of subsystems, it is choisable, Don't be
|
|
+ care of this if it is not used in your systems.
|
|
+
|
|
config PCI_J721E
|
|
bool
|
|
|
|
diff --git a/drivers/pci/controller/cadence/Makefile b/drivers/pci/controller/cadence/Makefile
|
|
index 9bac5fb2f13d..edac7c5e94a3 100644
|
|
--- a/drivers/pci/controller/cadence/Makefile
|
|
+++ b/drivers/pci/controller/cadence/Makefile
|
|
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
|
|
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
|
|
obj-$(CONFIG_PCIE_CADENCE_PLAT) += pcie-cadence-plat.o
|
|
obj-$(CONFIG_PCI_J721E) += pci-j721e.o
|
|
+obj-$(CONFIG_PCIE_CADENCE_SOPHGO) += pcie-cadence-sophgo.o
|
|
diff --git a/drivers/pci/controller/cadence/pcie-cadence-sophgo.c b/drivers/pci/controller/cadence/pcie-cadence-sophgo.c
|
|
new file mode 100644
|
|
index 000000000000..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 <cyrille.pitchen@free-electrons.com>
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/of_pci.h>
|
|
+#include <linux/msi.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/irqdomain.h>
|
|
+#include <linux/irqchip/chained_irq.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/pm_runtime.h>
|
|
+
|
|
+#include "pcie-cadence.h"
|
|
+#include "pcie-cadence-sophgo.h"
|
|
+
|
|
+#define MAX_MSI_IRQS 512
|
|
+#define MAX_MSI_IRQS_PER_CTRL 1
|
|
+#define MAX_MSI_CTRLS (MAX_MSI_IRQS / MAX_MSI_IRQS_PER_CTRL)
|
|
+#define MSI_DEF_NUM_VECTORS 512
|
|
+#define BYTE_NUM_PER_MSI_VEC 4
|
|
+
|
|
+// mango sideband signals
|
|
+#define CDNS_PCIE_CFG_MANGO_APB 0x1800000
|
|
+#define CDNS_PCIE_IRS_REG0400 0x0400
|
|
+#define CDNS_PCIE_IRS_REG0404 0x0404
|
|
+#define CDNS_PCIE_IRS_REG0418 0x0418
|
|
+#define CDNS_PCIE_IRS_REG041C 0x041C
|
|
+#define CDNS_PCIE_IRS_REG0804 0x0804
|
|
+#define CDNS_PCIE_IRS_REG080C 0x080C
|
|
+#define CDNS_PCIE_IRS_REG0810 0x0810
|
|
+#define CDNS_PCIE_IRS_REG085C 0x085C
|
|
+#define CDNS_PCIE_IRS_REG0860 0x0860
|
|
+#define CDNS_PCIE_IRS_REG0864 0x0864
|
|
+#define CDNS_PCIE_IRS_REG0868 0x0868
|
|
+#define CDNS_PCIE_IRS_REG086C 0x086C
|
|
+
|
|
+#define CDNS_PCIE_IRS_REG0804_CLR_LINK0_MSI_IN_BIT 2
|
|
+#define CDNS_PCIE_IRS_REG0804_CLR_LINK1_MSI_IN_BIT 3
|
|
+#define CDNS_PCIE_IRS_REG0810_ST_LINK0_MSI_IN_BIT 2
|
|
+#define CDNS_PCIE_IRS_REG0810_ST_LINK1_MSI_IN_BIT 3
|
|
+
|
|
+#define CDNS_PLAT_CPU_TO_BUS_ADDR 0xCFFFFFFFFF
|
|
+
|
|
+struct cdns_pcie_database {
|
|
+ void __iomem *pcie_reg_base;
|
|
+};
|
|
+
|
|
+static struct cdns_pcie_database cdns_pcie_db;
|
|
+
|
|
+static inline void cdns_pcie_rp_writel(struct cdns_pcie *pcie,
|
|
+ u32 reg, u32 value)
|
|
+{
|
|
+ writel(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
|
|
+}
|
|
+
|
|
+static inline u32 cdns_pcie_rp_readl(struct cdns_pcie *pcie,
|
|
+ u32 reg)
|
|
+{
|
|
+ return readl(pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * struct cdns_mango_pcie_rc - private data for this PCIe Root Complex driver
|
|
+ * @pcie: Cadence PCIe controller
|
|
+ * @dev: pointer to PCIe device
|
|
+ * @cfg_res: start/end offsets in the physical system memory to map PCI
|
|
+ * configuration space accesses
|
|
+ * @bus_range: first/last buses behind the PCIe host controller
|
|
+ * @cfg_base: IO mapped window to access the PCI configuration space of a
|
|
+ * single function at a time
|
|
+ * @max_regions: maximum number of regions supported by the hardware
|
|
+ * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
|
|
+ * translation (nbits sets into the "no BAR match" register)
|
|
+ * @vendor_id: PCI vendor ID
|
|
+ * @device_id: PCI device ID
|
|
+ */
|
|
+struct cdns_mango_pcie_rc {
|
|
+ struct cdns_pcie pcie;
|
|
+ struct device *dev;
|
|
+ struct resource *cfg_res;
|
|
+ struct resource *bus_range;
|
|
+ void __iomem *cfg_base;
|
|
+ u32 max_regions;
|
|
+ u32 no_bar_nbits;
|
|
+ u16 vendor_id;
|
|
+ u16 device_id;
|
|
+ u16 pcie_id;
|
|
+ u16 link_id;
|
|
+ u32 top_intc_used;
|
|
+ u32 msix_supported;
|
|
+ struct irq_domain *msi_domain;
|
|
+ int msi_irq;
|
|
+ struct irq_domain *irq_domain;
|
|
+ dma_addr_t msi_data;
|
|
+ void *msi_page;
|
|
+ struct irq_chip *msi_irq_chip;
|
|
+ u32 num_vectors;
|
|
+ u32 num_applied_vecs;
|
|
+ u32 irq_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 <emil.renner.berthing@canonical.com>
|
|
+ */
|
|
+
|
|
+#include <linux/bits.h>
|
|
+#include <linux/cleanup.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/mod_devicetable.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/seq_file.h>
|
|
+#include <linux/spinlock.h>
|
|
+
|
|
+#include <linux/pinctrl/pinconf.h>
|
|
+#include <linux/pinctrl/pinconf-generic.h>
|
|
+#include <linux/pinctrl/pinctrl.h>
|
|
+#include <linux/pinctrl/pinmux.h>
|
|
+
|
|
+#include "core.h"
|
|
+#include "pinmux.h"
|
|
+#include "pinconf.h"
|
|
+
|
|
+#define TH1520_PADCFG_IE BIT(9)
|
|
+#define TH1520_PADCFG_SL BIT(8)
|
|
+#define TH1520_PADCFG_ST BIT(7)
|
|
+#define TH1520_PADCFG_SPU BIT(6)
|
|
+#define TH1520_PADCFG_PS BIT(5)
|
|
+#define TH1520_PADCFG_PE BIT(4)
|
|
+#define TH1520_PADCFG_BIAS (TH1520_PADCFG_SPU | TH1520_PADCFG_PS | TH1520_PADCFG_PE)
|
|
+#define TH1520_PADCFG_DS GENMASK(3, 0)
|
|
+
|
|
+#define TH1520_PULL_DOWN_OHM 44000 /* typ. 44kOhm */
|
|
+#define TH1520_PULL_UP_OHM 48000 /* typ. 48kOhm */
|
|
+#define TH1520_PULL_STRONG_OHM 2100 /* typ. 2.1kOhm */
|
|
+
|
|
+#define TH1520_PAD_NO_PADCFG BIT(30)
|
|
+#define TH1520_PAD_MUXDATA GENMASK(29, 0)
|
|
+
|
|
+struct th1520_pad_group {
|
|
+ const char *name;
|
|
+ const struct pinctrl_pin_desc *pins;
|
|
+ unsigned int npins;
|
|
+};
|
|
+
|
|
+struct th1520_pinctrl {
|
|
+ struct pinctrl_desc desc;
|
|
+ struct mutex mutex; /* serialize adding functions */
|
|
+ raw_spinlock_t lock; /* serialize register access */
|
|
+ void __iomem *base;
|
|
+ struct pinctrl_dev *pctl;
|
|
+};
|
|
+
|
|
+static void __iomem *th1520_padcfg(struct th1520_pinctrl *thp,
|
|
+ unsigned int pin)
|
|
+{
|
|
+ return thp->base + 4 * (pin / 2);
|
|
+}
|
|
+
|
|
+static unsigned int th1520_padcfg_shift(unsigned int pin)
|
|
+{
|
|
+ return 16 * (pin & BIT(0));
|
|
+}
|
|
+
|
|
+static void __iomem *th1520_muxcfg(struct th1520_pinctrl *thp,
|
|
+ unsigned int pin)
|
|
+{
|
|
+ return thp->base + 0x400 + 4 * (pin / 8);
|
|
+}
|
|
+
|
|
+static unsigned int th1520_muxcfg_shift(unsigned int pin)
|
|
+{
|
|
+ return 4 * (pin & GENMASK(2, 0));
|
|
+}
|
|
+
|
|
+enum th1520_muxtype {
|
|
+ TH1520_MUX_____,
|
|
+ TH1520_MUX_GPIO,
|
|
+ TH1520_MUX_PWM,
|
|
+ TH1520_MUX_UART,
|
|
+ TH1520_MUX_IR,
|
|
+ TH1520_MUX_I2C,
|
|
+ TH1520_MUX_SPI,
|
|
+ TH1520_MUX_QSPI,
|
|
+ TH1520_MUX_SDIO,
|
|
+ TH1520_MUX_AUD,
|
|
+ TH1520_MUX_I2S,
|
|
+ TH1520_MUX_MAC0,
|
|
+ TH1520_MUX_MAC1,
|
|
+ TH1520_MUX_DPU0,
|
|
+ TH1520_MUX_DPU1,
|
|
+ TH1520_MUX_ISP,
|
|
+ TH1520_MUX_HDMI,
|
|
+ TH1520_MUX_BSEL,
|
|
+ TH1520_MUX_DBG,
|
|
+ TH1520_MUX_CLK,
|
|
+ TH1520_MUX_JTAG,
|
|
+ TH1520_MUX_ISO,
|
|
+ TH1520_MUX_FUSE,
|
|
+ TH1520_MUX_RST,
|
|
+};
|
|
+
|
|
+static const char *const th1520_muxtype_string[] = {
|
|
+ [TH1520_MUX_GPIO] = "gpio",
|
|
+ [TH1520_MUX_PWM] = "pwm",
|
|
+ [TH1520_MUX_UART] = "uart",
|
|
+ [TH1520_MUX_IR] = "ir",
|
|
+ [TH1520_MUX_I2C] = "i2c",
|
|
+ [TH1520_MUX_SPI] = "spi",
|
|
+ [TH1520_MUX_QSPI] = "qspi",
|
|
+ [TH1520_MUX_SDIO] = "sdio",
|
|
+ [TH1520_MUX_AUD] = "audio",
|
|
+ [TH1520_MUX_I2S] = "i2s",
|
|
+ [TH1520_MUX_MAC0] = "gmac0",
|
|
+ [TH1520_MUX_MAC1] = "gmac1",
|
|
+ [TH1520_MUX_DPU0] = "dpu0",
|
|
+ [TH1520_MUX_DPU1] = "dpu1",
|
|
+ [TH1520_MUX_ISP] = "isp",
|
|
+ [TH1520_MUX_HDMI] = "hdmi",
|
|
+ [TH1520_MUX_BSEL] = "bootsel",
|
|
+ [TH1520_MUX_DBG] = "debug",
|
|
+ [TH1520_MUX_CLK] = "clock",
|
|
+ [TH1520_MUX_JTAG] = "jtag",
|
|
+ [TH1520_MUX_ISO] = "iso7816",
|
|
+ [TH1520_MUX_FUSE] = "efuse",
|
|
+ [TH1520_MUX_RST] = "reset",
|
|
+};
|
|
+
|
|
+static enum th1520_muxtype th1520_muxtype_get(const char *str)
|
|
+{
|
|
+ enum th1520_muxtype mt;
|
|
+
|
|
+ for (mt = TH1520_MUX_GPIO; mt < ARRAY_SIZE(th1520_muxtype_string); mt++) {
|
|
+ if (!strcmp(str, th1520_muxtype_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 <emil.renner.berthing@canonical.com>");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/pinctrl/sophgo/Makefile b/drivers/pinctrl/sophgo/Makefile
|
|
new file mode 100644
|
|
index 000000000000..2f2cd0d5a99d
|
|
--- /dev/null
|
|
+++ b/drivers/pinctrl/sophgo/Makefile
|
|
@@ -0,0 +1,2 @@
|
|
+obj-$(CONFIG_ARCH_SOPHGO) += pinctrl-sophgo.o
|
|
+obj-$(CONFIG_ARCH_SOPHGO) += pinctrl-mango.o
|
|
diff --git a/drivers/pinctrl/sophgo/pinctrl-mango.c b/drivers/pinctrl/sophgo/pinctrl-mango.c
|
|
new file mode 100644
|
|
index 000000000000..8e7bd08a73db
|
|
--- /dev/null
|
|
+++ b/drivers/pinctrl/sophgo/pinctrl-mango.c
|
|
@@ -0,0 +1,453 @@
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/pinctrl/pinctrl.h>
|
|
+#include <linux/pinctrl/pinmux.h>
|
|
+#include <linux/pinctrl/pinconf.h>
|
|
+#include <linux/pinctrl/pinconf-generic.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/of.h>
|
|
+
|
|
+#include "../pinctrl-utils.h"
|
|
+#include "pinctrl-sophgo.h"
|
|
+
|
|
+#define DRV_PINCTRL_NAME "mango_pinctrl"
|
|
+#define DRV_PINMUX_NAME "mango_pinmux"
|
|
+
|
|
+#define FUNCTION(fname, gname, fmode) \
|
|
+ { \
|
|
+ .name = #fname, \
|
|
+ .groups = gname##_group, \
|
|
+ .num_groups = ARRAY_SIZE(gname##_group), \
|
|
+ .mode = fmode, \
|
|
+ }
|
|
+
|
|
+#define PIN_GROUP(gname) \
|
|
+ { \
|
|
+ .name = #gname "_grp", \
|
|
+ .pins = gname##_pins, \
|
|
+ .num_pins = ARRAY_SIZE(gname##_pins), \
|
|
+ }
|
|
+
|
|
+static const struct pinctrl_pin_desc mango_pins[] = {
|
|
+ PINCTRL_PIN(0, "MIO0"),
|
|
+ PINCTRL_PIN(1, "MIO1"),
|
|
+ PINCTRL_PIN(2, "MIO2"),
|
|
+ PINCTRL_PIN(3, "MIO3"),
|
|
+ PINCTRL_PIN(4, "MIO4"),
|
|
+ PINCTRL_PIN(5, "MIO5"),
|
|
+ PINCTRL_PIN(6, "MIO6"),
|
|
+ PINCTRL_PIN(7, "MIO7"),
|
|
+ PINCTRL_PIN(8, "MIO8"),
|
|
+ PINCTRL_PIN(9, "MIO9"),
|
|
+ PINCTRL_PIN(10, "MIO10"),
|
|
+ PINCTRL_PIN(11, "MIO11"),
|
|
+ PINCTRL_PIN(12, "MIO12"),
|
|
+ PINCTRL_PIN(13, "MIO13"),
|
|
+ PINCTRL_PIN(14, "MIO14"),
|
|
+ PINCTRL_PIN(15, "MIO15"),
|
|
+ PINCTRL_PIN(16, "MIO16"),
|
|
+ PINCTRL_PIN(17, "MIO17"),
|
|
+ PINCTRL_PIN(18, "MIO18"),
|
|
+ PINCTRL_PIN(19, "MIO19"),
|
|
+ PINCTRL_PIN(20, "MIO20"),
|
|
+ PINCTRL_PIN(21, "MIO21"),
|
|
+ PINCTRL_PIN(22, "MIO22"),
|
|
+ PINCTRL_PIN(23, "MIO23"),
|
|
+ PINCTRL_PIN(24, "MIO24"),
|
|
+ PINCTRL_PIN(25, "MIO25"),
|
|
+ PINCTRL_PIN(26, "MIO26"),
|
|
+ PINCTRL_PIN(27, "MIO27"),
|
|
+ PINCTRL_PIN(28, "MIO28"),
|
|
+ PINCTRL_PIN(29, "MIO29"),
|
|
+ PINCTRL_PIN(30, "MIO30"),
|
|
+ PINCTRL_PIN(31, "MIO31"),
|
|
+ PINCTRL_PIN(32, "MIO32"),
|
|
+ PINCTRL_PIN(33, "MIO33"),
|
|
+ PINCTRL_PIN(34, "MIO34"),
|
|
+ PINCTRL_PIN(35, "MIO35"),
|
|
+ PINCTRL_PIN(36, "MIO36"),
|
|
+ PINCTRL_PIN(37, "MIO37"),
|
|
+ PINCTRL_PIN(38, "MIO38"),
|
|
+ PINCTRL_PIN(39, "MIO39"),
|
|
+ PINCTRL_PIN(40, "MIO40"),
|
|
+ PINCTRL_PIN(41, "MIO41"),
|
|
+ PINCTRL_PIN(42, "MIO42"),
|
|
+ PINCTRL_PIN(43, "MIO43"),
|
|
+ PINCTRL_PIN(44, "MIO44"),
|
|
+ PINCTRL_PIN(45, "MIO45"),
|
|
+ PINCTRL_PIN(46, "MIO46"),
|
|
+ PINCTRL_PIN(47, "MIO47"),
|
|
+ PINCTRL_PIN(48, "MIO48"),
|
|
+ PINCTRL_PIN(49, "MIO49"),
|
|
+ PINCTRL_PIN(50, "MIO50"),
|
|
+ PINCTRL_PIN(51, "MIO51"),
|
|
+ PINCTRL_PIN(52, "MIO52"),
|
|
+ PINCTRL_PIN(53, "MIO53"),
|
|
+ PINCTRL_PIN(54, "MIO54"),
|
|
+ PINCTRL_PIN(55, "MIO55"),
|
|
+ PINCTRL_PIN(56, "MIO56"),
|
|
+ PINCTRL_PIN(57, "MIO57"),
|
|
+ PINCTRL_PIN(58, "MIO58"),
|
|
+ PINCTRL_PIN(59, "MIO59"),
|
|
+ PINCTRL_PIN(60, "MIO60"),
|
|
+ PINCTRL_PIN(61, "MIO61"),
|
|
+ PINCTRL_PIN(62, "MIO62"),
|
|
+ PINCTRL_PIN(63, "MIO63"),
|
|
+ PINCTRL_PIN(64, "MIO64"),
|
|
+ PINCTRL_PIN(65, "MIO65"),
|
|
+ PINCTRL_PIN(66, "MIO66"),
|
|
+ PINCTRL_PIN(67, "MIO67"),
|
|
+ PINCTRL_PIN(68, "MIO68"),
|
|
+ PINCTRL_PIN(69, "MIO69"),
|
|
+ PINCTRL_PIN(70, "MIO70"),
|
|
+ PINCTRL_PIN(71, "MIO71"),
|
|
+ PINCTRL_PIN(72, "MIO72"),
|
|
+ PINCTRL_PIN(73, "MIO73"),
|
|
+ PINCTRL_PIN(74, "MIO74"),
|
|
+ PINCTRL_PIN(75, "MIO75"),
|
|
+ PINCTRL_PIN(76, "MIO76"),
|
|
+ PINCTRL_PIN(77, "MIO77"),
|
|
+ PINCTRL_PIN(78, "MIO78"),
|
|
+ PINCTRL_PIN(79, "MIO79"),
|
|
+ PINCTRL_PIN(80, "MIO80"),
|
|
+ PINCTRL_PIN(81, "MIO81"),
|
|
+ PINCTRL_PIN(82, "MIO82"),
|
|
+ PINCTRL_PIN(83, "MIO83"),
|
|
+ PINCTRL_PIN(84, "MIO84"),
|
|
+ PINCTRL_PIN(85, "MIO85"),
|
|
+ PINCTRL_PIN(86, "MIO86"),
|
|
+ PINCTRL_PIN(87, "MIO87"),
|
|
+ PINCTRL_PIN(88, "MIO88"),
|
|
+ PINCTRL_PIN(89, "MIO89"),
|
|
+ PINCTRL_PIN(90, "MIO90"),
|
|
+ PINCTRL_PIN(91, "MIO91"),
|
|
+ PINCTRL_PIN(92, "MIO92"),
|
|
+ PINCTRL_PIN(93, "MIO93"),
|
|
+ PINCTRL_PIN(94, "MIO94"),
|
|
+ PINCTRL_PIN(95, "MIO95"),
|
|
+ PINCTRL_PIN(96, "MIO96"),
|
|
+ PINCTRL_PIN(97, "MIO97"),
|
|
+ PINCTRL_PIN(98, "MIO98"),
|
|
+ PINCTRL_PIN(99, "MIO99"),
|
|
+ PINCTRL_PIN(100, "MIO100"),
|
|
+ PINCTRL_PIN(101, "MIO101"),
|
|
+ PINCTRL_PIN(102, "MIO102"),
|
|
+ PINCTRL_PIN(103, "MIO103"),
|
|
+ PINCTRL_PIN(104, "MIO104"),
|
|
+ PINCTRL_PIN(105, "MIO105"),
|
|
+ PINCTRL_PIN(106, "MIO106"),
|
|
+ PINCTRL_PIN(107, "MIO107"),
|
|
+ PINCTRL_PIN(108, "MIO108"),
|
|
+ PINCTRL_PIN(109, "MIO109"),
|
|
+ PINCTRL_PIN(110, "MIO110"),
|
|
+ PINCTRL_PIN(111, "MIO111"),
|
|
+ PINCTRL_PIN(112, "MIO112"),
|
|
+ PINCTRL_PIN(113, "MIO113"),
|
|
+ PINCTRL_PIN(114, "MIO114"),
|
|
+ PINCTRL_PIN(115, "MIO115"),
|
|
+ PINCTRL_PIN(116, "MIO116"),
|
|
+ PINCTRL_PIN(117, "MIO117"),
|
|
+ PINCTRL_PIN(118, "MIO118"),
|
|
+ PINCTRL_PIN(119, "MIO119"),
|
|
+ PINCTRL_PIN(120, "MIO120"),
|
|
+ PINCTRL_PIN(121, "MIO121"),
|
|
+ PINCTRL_PIN(122, "MIO122"),
|
|
+ PINCTRL_PIN(123, "MIO123"),
|
|
+ PINCTRL_PIN(124, "MIO124"),
|
|
+ PINCTRL_PIN(125, "MIO125"),
|
|
+ PINCTRL_PIN(126, "MIO126"),
|
|
+ PINCTRL_PIN(127, "MIO127"),
|
|
+ PINCTRL_PIN(128, "MIO128"),
|
|
+ PINCTRL_PIN(129, "MIO129"),
|
|
+ PINCTRL_PIN(130, "MIO130"),
|
|
+ PINCTRL_PIN(131, "MIO131"),
|
|
+ PINCTRL_PIN(132, "MIO132"),
|
|
+ PINCTRL_PIN(133, "MIO133"),
|
|
+ PINCTRL_PIN(134, "MIO134"),
|
|
+ PINCTRL_PIN(135, "MIO135"),
|
|
+ PINCTRL_PIN(136, "MIO136"),
|
|
+ PINCTRL_PIN(137, "MIO137"),
|
|
+ PINCTRL_PIN(138, "MIO138"),
|
|
+ PINCTRL_PIN(139, "MIO139"),
|
|
+ PINCTRL_PIN(140, "MIO140"),
|
|
+ PINCTRL_PIN(141, "MIO141"),
|
|
+ PINCTRL_PIN(142, "MIO142"),
|
|
+ PINCTRL_PIN(143, "MIO143"),
|
|
+ PINCTRL_PIN(144, "MIO144"),
|
|
+ PINCTRL_PIN(145, "MIO145"),
|
|
+ PINCTRL_PIN(146, "MIO146"),
|
|
+ PINCTRL_PIN(147, "MIO147"),
|
|
+ PINCTRL_PIN(148, "MIO148"),
|
|
+ PINCTRL_PIN(149, "MIO149"),
|
|
+ PINCTRL_PIN(150, "MIO150"),
|
|
+ PINCTRL_PIN(151, "MIO151"),
|
|
+ PINCTRL_PIN(152, "MIO152"),
|
|
+ PINCTRL_PIN(153, "MIO153"),
|
|
+ PINCTRL_PIN(154, "MIO154"),
|
|
+ PINCTRL_PIN(155, "MIO155"),
|
|
+ PINCTRL_PIN(156, "MIO156"),
|
|
+};
|
|
+
|
|
+static const unsigned int lpc_pins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
|
+static const unsigned int pcie_pins[] = {13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
|
|
+static const unsigned int spif_pins[] = {25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40};
|
|
+static const unsigned int emmc_pins[] = {41, 42, 43, 44};
|
|
+static const unsigned int sdio_pins[] = {45, 46, 47, 48};
|
|
+static const unsigned int eth0_pins[] = {49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64};
|
|
+static const unsigned int pwm0_pins[] = {65};
|
|
+static const unsigned int pwm1_pins[] = {66};
|
|
+static const unsigned int pwm2_pins[] = {67};
|
|
+static const unsigned int pwm3_pins[] = {68};
|
|
+static const unsigned int fan0_pins[] = {69};
|
|
+static const unsigned int fan1_pins[] = {70};
|
|
+static const unsigned int fan2_pins[] = {71};
|
|
+static const unsigned int fan3_pins[] = {72};
|
|
+static const unsigned int i2c0_pins[] = {73, 74};
|
|
+static const unsigned int i2c1_pins[] = {75, 76};
|
|
+static const unsigned int i2c2_pins[] = {77, 78};
|
|
+static const unsigned int i2c3_pins[] = {79, 80};
|
|
+static const unsigned int uart0_pins[] = {81, 82, 83, 84};
|
|
+static const unsigned int uart1_pins[] = {85, 86, 87, 88};
|
|
+static const unsigned int uart2_pins[] = {89, 90, 91, 92};
|
|
+static const unsigned int uart3_pins[] = {93, 94, 95, 96};
|
|
+static const unsigned int spi0_pins[] = {97, 98, 99, 100, 101};
|
|
+static const unsigned int spi1_pins[] = {102, 103, 104, 105, 106};
|
|
+static const unsigned int jtag0_pins[] = {107, 108, 109, 110, 111, 112};
|
|
+static const unsigned int jtag1_pins[] = {113, 114, 115, 116, 117, 118};
|
|
+static const unsigned int jtag2_pins[] = {119, 120, 121, 122, 123, 124};
|
|
+static const unsigned int gpio0_pins[] = {125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,\
|
|
+ 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,\
|
|
+ 151, 152, 153};
|
|
+static const unsigned int dbgi2c_pins[] = {154, 155, 156};
|
|
+
|
|
+static const char * const lpc_group[] = {"lpc_grp"};
|
|
+static const char * const pcie_group[] = {"pcie_grp"};
|
|
+static const char * const spif_group[] = {"spif_grp"};
|
|
+static const char * const emmc_group[] = {"emmc_grp"};
|
|
+static const char * const sdio_group[] = {"sdio_grp"};
|
|
+static const char * const eth0_group[] = {"eth0_grp"};
|
|
+static const char * const pwm0_group[] = {"pwm0_grp"};
|
|
+static const char * const pwm1_group[] = {"pwm1_grp"};
|
|
+static const char * const pwm2_group[] = {"pwm2_grp"};
|
|
+static const char * const pwm3_group[] = {"pwm3_grp"};
|
|
+static const char * const fan0_group[] = {"fan0_grp"};
|
|
+static const char * const fan1_group[] = {"fan1_grp"};
|
|
+static const char * const fan2_group[] = {"fan2_grp"};
|
|
+static const char * const fan3_group[] = {"fan3_grp"};
|
|
+static const char * const i2c0_group[] = {"i2c0_grp"};
|
|
+static const char * const i2c1_group[] = {"i2c1_grp"};
|
|
+static const char * const i2c2_group[] = {"i2c2_grp"};
|
|
+static const char * const i2c3_group[] = {"i2c3_grp"};
|
|
+static const char * const uart0_group[] = {"uart0_grp"};
|
|
+static const char * const uart1_group[] = {"uart1_grp"};
|
|
+static const char * const uart2_group[] = {"uart2_grp"};
|
|
+static const char * const uart3_group[] = {"uart3_grp"};
|
|
+static const char * const spi0_group[] = {"spi0_grp"};
|
|
+static const char * const spi1_group[] = {"spi1_grp"};
|
|
+static const char * const jtag0_group[] = {"jtag0_grp"};
|
|
+static const char * const jtag1_group[] = {"jtag1_grp"};
|
|
+static const char * const jtag2_group[] = {"jtag2_grp"};
|
|
+static const char * const gpio0_group[] = {"gpio0_grp"};
|
|
+static const char * const dbgi2c_group[] = {"dbgi2c_grp"};
|
|
+
|
|
+static struct mango_group mango_groups[] = {
|
|
+ PIN_GROUP(lpc),
|
|
+ PIN_GROUP(pcie),
|
|
+ PIN_GROUP(spif),
|
|
+ PIN_GROUP(emmc),
|
|
+ PIN_GROUP(sdio),
|
|
+ PIN_GROUP(eth0),
|
|
+ PIN_GROUP(pwm0),
|
|
+ PIN_GROUP(pwm1),
|
|
+ PIN_GROUP(pwm2),
|
|
+ PIN_GROUP(pwm3),
|
|
+ PIN_GROUP(fan0),
|
|
+ PIN_GROUP(fan1),
|
|
+ PIN_GROUP(fan2),
|
|
+ PIN_GROUP(fan3),
|
|
+ PIN_GROUP(i2c0),
|
|
+ PIN_GROUP(i2c1),
|
|
+ PIN_GROUP(i2c2),
|
|
+ PIN_GROUP(i2c3),
|
|
+ PIN_GROUP(uart0),
|
|
+ PIN_GROUP(uart1),
|
|
+ PIN_GROUP(uart2),
|
|
+ PIN_GROUP(uart3),
|
|
+ PIN_GROUP(spi0),
|
|
+ PIN_GROUP(spi1),
|
|
+ PIN_GROUP(jtag0),
|
|
+ PIN_GROUP(jtag1),
|
|
+ PIN_GROUP(jtag2),
|
|
+ PIN_GROUP(gpio0),
|
|
+ PIN_GROUP(dbgi2c),
|
|
+};
|
|
+
|
|
+static const struct mango_pmx_func mango_funcs[] = {
|
|
+ FUNCTION(lpc_a, lpc, FUNC_MODE0),
|
|
+ FUNCTION(lpc_r, lpc, FUNC_MODE1),
|
|
+ FUNCTION(pcie_a, pcie, FUNC_MODE0),
|
|
+ FUNCTION(pcie_r, pcie, FUNC_MODE1),
|
|
+ FUNCTION(spif_a, spif, FUNC_MODE0),
|
|
+ FUNCTION(spif_r, spif, FUNC_MODE1),
|
|
+ FUNCTION(emmc_a, emmc, FUNC_MODE0),
|
|
+ FUNCTION(emmc_r, emmc, FUNC_MODE1),
|
|
+ FUNCTION(sdio_a, sdio, FUNC_MODE0),
|
|
+ FUNCTION(sdio_r, sdio, FUNC_MODE1),
|
|
+ FUNCTION(eth0_a, eth0, FUNC_MODE1),
|
|
+ FUNCTION(eth0_r, eth0, FUNC_MODE0),
|
|
+ FUNCTION(pwm0_a, pwm0, FUNC_MODE0),
|
|
+ FUNCTION(pwm0_r, pwm0, FUNC_MODE1),
|
|
+ FUNCTION(pwm1_a, pwm1, FUNC_MODE0),
|
|
+ FUNCTION(pwm1_r, pwm1, FUNC_MODE1),
|
|
+ FUNCTION(pwm2_a, pwm2, FUNC_MODE0),
|
|
+ FUNCTION(pwm2_r, pwm2, FUNC_MODE1),
|
|
+ FUNCTION(pwm3_a, pwm3, FUNC_MODE0),
|
|
+ FUNCTION(pwm3_r, pwm3, FUNC_MODE1),
|
|
+ FUNCTION(fan0_a, fan0, FUNC_MODE1),
|
|
+ FUNCTION(fan0_r, fan0, FUNC_MODE0),
|
|
+ FUNCTION(fan1_a, fan1, FUNC_MODE1),
|
|
+ FUNCTION(fan1_r, fan1, FUNC_MODE0),
|
|
+ FUNCTION(fan2_a, fan2, FUNC_MODE1),
|
|
+ FUNCTION(fan2_r, fan2, FUNC_MODE0),
|
|
+ FUNCTION(fan3_a, fan3, FUNC_MODE1),
|
|
+ FUNCTION(fan3_r, fan3, FUNC_MODE0),
|
|
+ FUNCTION(i2c0_a, i2c0, FUNC_MODE0),
|
|
+ FUNCTION(i2c0_r, i2c0, FUNC_MODE1),
|
|
+ FUNCTION(i2c1_a, i2c1, FUNC_MODE0),
|
|
+ FUNCTION(i2c1_r, i2c1, FUNC_MODE1),
|
|
+ FUNCTION(i2c2_a, i2c2, FUNC_MODE1),
|
|
+ FUNCTION(i2c2_r, i2c2, FUNC_MODE0),
|
|
+ FUNCTION(i2c3_a, i2c3, FUNC_MODE1),
|
|
+ FUNCTION(i2c3_r, i2c3, FUNC_MODE0),
|
|
+ FUNCTION(uart0_a, uart0, FUNC_MODE0),
|
|
+ FUNCTION(uart0_r, uart0, FUNC_MODE1),
|
|
+ FUNCTION(uart1_a, uart1, FUNC_MODE0),
|
|
+ FUNCTION(uart1_r, uart1, FUNC_MODE1),
|
|
+ FUNCTION(uart2_a, uart2, FUNC_MODE1),
|
|
+ FUNCTION(uart2_r, uart2, FUNC_MODE0),
|
|
+ FUNCTION(uart3_a, uart3, FUNC_MODE1),
|
|
+ FUNCTION(uart3_r, uart3, FUNC_MODE0),
|
|
+ FUNCTION(spi0_a, spi0, FUNC_MODE1),
|
|
+ FUNCTION(spi0_r, spi0, FUNC_MODE0),
|
|
+ FUNCTION(spi1_a, spi1, FUNC_MODE0),
|
|
+ FUNCTION(spi1_r, spi1, FUNC_MODE1),
|
|
+ FUNCTION(jtag0_a, jtag0, FUNC_MODE0),
|
|
+ FUNCTION(jtag0_r, jtag0, FUNC_MODE1),
|
|
+ FUNCTION(jtag1_a, jtag1, FUNC_MODE1),
|
|
+ FUNCTION(jtag1_r, jtag1, FUNC_MODE0),
|
|
+ FUNCTION(jtag2_a, jtag2, FUNC_MODE1),
|
|
+ FUNCTION(jtag2_r, jtag2, FUNC_MODE0),
|
|
+ FUNCTION(gpio0_a, gpio0, FUNC_MODE1),
|
|
+ FUNCTION(gpio0_r, gpio0, FUNC_MODE0),
|
|
+ FUNCTION(dbgi2c_a, dbgi2c, FUNC_MODE0),
|
|
+ FUNCTION(dbgi2c_r, dbgi2c, FUNC_MODE1),
|
|
+};
|
|
+
|
|
+static struct device_attribute lpc_attr = __ATTR(lpc, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute pcie_attr = __ATTR(pcie, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute spif_attr = __ATTR(spif, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute emmc_attr = __ATTR(emmc, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute sdio_attr = __ATTR(sdio, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute eth0_attr = __ATTR(eth0, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute pwm0_attr = __ATTR(pwm0, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute pwm1_attr = __ATTR(pwm1, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute pwm2_attr = __ATTR(pwm2, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute pwm3_attr = __ATTR(pwm3, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute fan0_attr = __ATTR(fan0, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute fan1_attr = __ATTR(fan1, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute fan2_attr = __ATTR(fan2, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute fan3_attr = __ATTR(fan3, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute i2c0_attr = __ATTR(i2c0, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute i2c1_attr = __ATTR(i2c1, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute i2c2_attr = __ATTR(i2c2, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute i2c3_attr = __ATTR(i2c3, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute uart0_attr = __ATTR(uart0, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute uart1_attr = __ATTR(uart1, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute uart2_attr = __ATTR(uart2, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute uart3_attr = __ATTR(uart3, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute spi0_attr = __ATTR(spi0, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute spi1_attr = __ATTR(spi1, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute jtag0_attr = __ATTR(jtag0, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute jtag1_attr = __ATTR(jtag1, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute jtag2_attr = __ATTR(jtag2, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute gpio0_attr = __ATTR(gpio0, 0664, pinmux_show, pinmux_store);
|
|
+static struct device_attribute dbgi2c_attr = __ATTR(dbgi2c, 0664, pinmux_show, pinmux_store);
|
|
+
|
|
+
|
|
+static struct attribute *pinmux_attrs[] = {
|
|
+ &lpc_attr.attr,
|
|
+ &pcie_attr.attr,
|
|
+ &spif_attr.attr,
|
|
+ &emmc_attr.attr,
|
|
+ &sdio_attr.attr,
|
|
+ ð0_attr.attr,
|
|
+ &pwm0_attr.attr,
|
|
+ &pwm1_attr.attr,
|
|
+ &pwm2_attr.attr,
|
|
+ &pwm3_attr.attr,
|
|
+ &fan0_attr.attr,
|
|
+ &fan1_attr.attr,
|
|
+ &fan2_attr.attr,
|
|
+ &fan3_attr.attr,
|
|
+ &i2c0_attr.attr,
|
|
+ &i2c1_attr.attr,
|
|
+ &i2c2_attr.attr,
|
|
+ &i2c3_attr.attr,
|
|
+ &uart0_attr.attr,
|
|
+ &uart1_attr.attr,
|
|
+ &uart2_attr.attr,
|
|
+ &uart3_attr.attr,
|
|
+ &spi0_attr.attr,
|
|
+ &spi1_attr.attr,
|
|
+ &jtag0_attr.attr,
|
|
+ &jtag1_attr.attr,
|
|
+ &jtag2_attr.attr,
|
|
+ &gpio0_attr.attr,
|
|
+ &dbgi2c_attr.attr,
|
|
+ NULL,
|
|
+};
|
|
+ATTRIBUTE_GROUPS(pinmux);
|
|
+
|
|
+static struct class pinmux_class = {
|
|
+ .name = "pinmux",
|
|
+ .dev_groups = pinmux_groups,
|
|
+};
|
|
+
|
|
+static struct mango_soc_pinctrl_data mango_pinctrl_data = {
|
|
+ .pins = mango_pins,
|
|
+ .npins = ARRAY_SIZE(mango_pins),
|
|
+ .groups = mango_groups,
|
|
+ .groups_count = ARRAY_SIZE(mango_groups),
|
|
+ .functions = mango_funcs,
|
|
+ .functions_count = ARRAY_SIZE(mango_funcs),
|
|
+ .p_class = &pinmux_class,
|
|
+};
|
|
+
|
|
+static const struct of_device_id mango_pinctrl_of_table[] = {
|
|
+ {
|
|
+ .compatible = "sophgo, pinctrl-mango",
|
|
+ .data = &mango_pinctrl_data,
|
|
+ },
|
|
+ {}
|
|
+};
|
|
+
|
|
+static int mango_pinctrl_probe(struct platform_device *pdev)
|
|
+{
|
|
+ return sophgo_pinctrl_probe(pdev);
|
|
+}
|
|
+
|
|
+static struct platform_driver mango_pinctrl_driver = {
|
|
+ .probe = mango_pinctrl_probe,
|
|
+ .driver = {
|
|
+ .name = DRV_PINCTRL_NAME,
|
|
+ .of_match_table = of_match_ptr(mango_pinctrl_of_table),
|
|
+ },
|
|
+};
|
|
+
|
|
+static int __init mango_pinctrl_init(void)
|
|
+{
|
|
+ return platform_driver_register(&mango_pinctrl_driver);
|
|
+}
|
|
+postcore_initcall(mango_pinctrl_init);
|
|
diff --git a/drivers/pinctrl/sophgo/pinctrl-sophgo.c b/drivers/pinctrl/sophgo/pinctrl-sophgo.c
|
|
new file mode 100644
|
|
index 000000000000..0862177d4144
|
|
--- /dev/null
|
|
+++ b/drivers/pinctrl/sophgo/pinctrl-sophgo.c
|
|
@@ -0,0 +1,292 @@
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/regmap.h>
|
|
+
|
|
+#include "pinctrl-sophgo.h"
|
|
+
|
|
+
|
|
+static int mango_get_groups(struct pinctrl_dev *pctldev, unsigned int selector,
|
|
+ const char * const **groups,
|
|
+ unsigned int * const num_groups);
|
|
+
|
|
+static struct mango_soc_pinctrl_data *get_pinmux_data(struct pinctrl_dev *pctldev)
|
|
+{
|
|
+ struct mango_pinctrl *mangopctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
+
|
|
+ return mangopctrl->data;
|
|
+}
|
|
+
|
|
+static int mango_get_functions_count(struct pinctrl_dev *pctldev)
|
|
+{
|
|
+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
|
|
+
|
|
+ return data->functions_count;
|
|
+}
|
|
+
|
|
+static const char *mango_get_fname(struct pinctrl_dev *pctldev,
|
|
+ unsigned int selector)
|
|
+{
|
|
+ struct mango_soc_pinctrl_data *data = get_pinmux_data(pctldev);
|
|
+
|
|
+ return data->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 <linux/pinctrl/pinctrl.h>
|
|
+#include <linux/pinctrl/pinmux.h>
|
|
+#include <linux/pinctrl/pinconf.h>
|
|
+#include <linux/pinctrl/pinconf-generic.h>
|
|
+#include "../pinctrl-utils.h"
|
|
+#include "../core.h"
|
|
+
|
|
+enum FUNC_MODE {
|
|
+ FUNC_MODE0,
|
|
+ FUNC_MODE1,
|
|
+ FUNC_MODE2,
|
|
+ FUNC_MODE3,
|
|
+ FUNC_MASK,
|
|
+};
|
|
+
|
|
+struct mango_pinctrl {
|
|
+ struct device *dev;
|
|
+ struct pinctrl_dev *pctl;
|
|
+ u32 top_pinctl_offset;
|
|
+ struct regmap *syscon_pinctl;
|
|
+ void *data;
|
|
+};
|
|
+
|
|
+struct mango_group {
|
|
+ const char *name;
|
|
+ const unsigned int *pins;
|
|
+ const unsigned int num_pins;
|
|
+ int cur_func_idx;
|
|
+ struct mango_pmx_func *funcs;
|
|
+};
|
|
+
|
|
+struct mango_pmx_func {
|
|
+ const char *name;
|
|
+ const char * const *groups;
|
|
+ unsigned int num_groups;
|
|
+ enum FUNC_MODE mode;
|
|
+};
|
|
+
|
|
+struct mango_soc_pinmux_info {
|
|
+ const char 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 <ben@simtec.co.uk>, <ben-linux@fluff.org>
|
|
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
|
|
+ *
|
|
+ * PWM driver for Samsung SoCs
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License.
|
|
+ */
|
|
+
|
|
+#include <linux/bitops.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/export.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/pwm.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+
|
|
+
|
|
+#define REG_HLPERIOD 0x0
|
|
+#define REG_PERIOD 0x4
|
|
+#define REG_GROUP 0x8
|
|
+#define REG_POLARITY 0x20
|
|
+
|
|
+
|
|
+/**
|
|
+ * struct sophgo_pwm_channel - private data of PWM channel
|
|
+ * @period_ns: current period in nanoseconds programmed to the hardware
|
|
+ * @duty_ns: current duty time in nanoseconds programmed to the hardware
|
|
+ * @tin_ns: time of one timer tick in nanoseconds with current timer rate
|
|
+ */
|
|
+struct sophgo_pwm_channel {
|
|
+ u32 period;
|
|
+ u32 hlperiod;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct sophgo_pwm_chip - private data of PWM chip
|
|
+ * @chip: generic PWM chip
|
|
+ * @variant: local copy of hardware variant data
|
|
+ * @inverter_mask: inverter status for all channels - one bit per channel
|
|
+ * @base: base address of mapped PWM registers
|
|
+ * @base_clk: base clock used to drive the timers
|
|
+ * @tclk0: external clock 0 (can be ERR_PTR if not present)
|
|
+ * @tclk1: external clock 1 (can be ERR_PTR if not present)
|
|
+ */
|
|
+struct sophgo_pwm_chip {
|
|
+ struct pwm_chip chip;
|
|
+ void __iomem *base;
|
|
+ struct clk *base_clk;
|
|
+ u8 polarity_mask;
|
|
+ bool no_polarity;
|
|
+};
|
|
+
|
|
+
|
|
+static inline
|
|
+struct sophgo_pwm_chip *to_sophgo_pwm_chip(struct pwm_chip *chip)
|
|
+{
|
|
+ return container_of(chip, struct sophgo_pwm_chip, chip);
|
|
+}
|
|
+
|
|
+static int pwm_sophgo_request(struct pwm_chip *chip, struct pwm_device *pwm_dev)
|
|
+{
|
|
+ struct sophgo_pwm_channel *channel;
|
|
+
|
|
+ channel = kzalloc(sizeof(*channel), GFP_KERNEL);
|
|
+ if (!channel)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ return pwm_set_chip_data(pwm_dev, channel);
|
|
+}
|
|
+
|
|
+static void pwm_sophgo_free(struct pwm_chip *chip, struct pwm_device *pwm_dev)
|
|
+{
|
|
+ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev);
|
|
+
|
|
+ pwm_set_chip_data(pwm_dev, NULL);
|
|
+ kfree(channel);
|
|
+}
|
|
+
|
|
+static int pwm_sophgo_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
|
|
+ int duty_ns, int period_ns)
|
|
+{
|
|
+ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip);
|
|
+ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev);
|
|
+ u64 cycles;
|
|
+
|
|
+ cycles = clk_get_rate(our_chip->base_clk);
|
|
+ cycles *= period_ns;
|
|
+ do_div(cycles, NSEC_PER_SEC);
|
|
+
|
|
+ channel->period = cycles;
|
|
+ cycles = cycles * duty_ns;
|
|
+ do_div(cycles, period_ns);
|
|
+ channel->hlperiod = channel->period - cycles;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pwm_sophgo_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev)
|
|
+{
|
|
+ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip);
|
|
+ struct sophgo_pwm_channel *channel = pwm_get_chip_data(pwm_dev);
|
|
+
|
|
+ writel(channel->period, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_PERIOD);
|
|
+ writel(channel->hlperiod, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_HLPERIOD);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void pwm_sophgo_disable(struct pwm_chip *chip,
|
|
+ struct pwm_device *pwm_dev)
|
|
+{
|
|
+ struct sophgo_pwm_chip *our_chip = to_sophgo_pwm_chip(chip);
|
|
+
|
|
+ writel(0, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_PERIOD);
|
|
+ writel(0, our_chip->base + REG_GROUP * pwm_dev->hwpwm + REG_HLPERIOD);
|
|
+}
|
|
+
|
|
+static int pwm_sophgo_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
+ const struct pwm_state *state)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ bool enabled = pwm->state.enabled;
|
|
+
|
|
+ if (state->polarity != pwm->state.polarity && pwm->state.enabled) {
|
|
+ pwm_sophgo_disable(chip, pwm);
|
|
+ enabled = false;
|
|
+ }
|
|
+
|
|
+ if (!state->enabled) {
|
|
+ if (enabled)
|
|
+ pwm_sophgo_disable(chip, pwm);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ret = pwm_sophgo_config(chip, pwm, state->duty_cycle, state->period);
|
|
+ if (ret) {
|
|
+ dev_err(chip->dev, "pwm apply err\n");
|
|
+ return ret;
|
|
+ }
|
|
+ dev_dbg(chip->dev, "%s tate->enabled =%d\n", __func__, state->enabled);
|
|
+ if (state->enabled)
|
|
+ ret = pwm_sophgo_enable(chip, pwm);
|
|
+ else
|
|
+ pwm_sophgo_disable(chip, pwm);
|
|
+
|
|
+ if (ret) {
|
|
+ dev_err(chip->dev, "pwm apply failed\n");
|
|
+ return ret;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct pwm_ops pwm_sophgo_ops = {
|
|
+ .request = pwm_sophgo_request,
|
|
+ .free = pwm_sophgo_free,
|
|
+ .apply = pwm_sophgo_apply,
|
|
+ .owner = THIS_MODULE,
|
|
+};
|
|
+
|
|
+static const struct of_device_id sophgo_pwm_match[] = {
|
|
+ { .compatible = "sophgo,sophgo-pwm" },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, sophgo_pwm_match);
|
|
+
|
|
+static int pwm_sophgo_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct sophgo_pwm_chip *chip;
|
|
+ struct resource *res;
|
|
+ int ret;
|
|
+
|
|
+ pr_info("%s\n", __func__);
|
|
+
|
|
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
|
+ if (chip == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ chip->chip.dev = &pdev->dev;
|
|
+ chip->chip.ops = &pwm_sophgo_ops;
|
|
+ chip->chip.base = -1;
|
|
+ chip->polarity_mask = 0;
|
|
+
|
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
+ chip->base = devm_ioremap_resource(&pdev->dev, res);
|
|
+ if (IS_ERR(chip->base))
|
|
+ return PTR_ERR(chip->base);
|
|
+
|
|
+ chip->base_clk = devm_clk_get(&pdev->dev, NULL);
|
|
+ if (IS_ERR(chip->base_clk)) {
|
|
+ dev_err(dev, "failed to get pwm source clk\n");
|
|
+ return PTR_ERR(chip->base_clk);
|
|
+ }
|
|
+
|
|
+ ret = clk_prepare_enable(chip->base_clk);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to enable base clock\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ //pwm-num default is 4, compatible with sg2042
|
|
+ if (of_property_read_bool(pdev->dev.of_node, "pwm-num"))
|
|
+ device_property_read_u32(&pdev->dev, "pwm-num", &chip->chip.npwm);
|
|
+ else
|
|
+ chip->chip.npwm = 4;
|
|
+
|
|
+ //no_polarity default is false(have polarity) , compatible with sg2042
|
|
+ if (of_property_read_bool(pdev->dev.of_node, "no-polarity"))
|
|
+ chip->no_polarity = true;
|
|
+ else
|
|
+ chip->no_polarity = false;
|
|
+ pr_debug("chip->chip.npwm =%d chip->no_polarity=%d\n", chip->chip.npwm, chip->no_polarity);
|
|
+
|
|
+ platform_set_drvdata(pdev, chip);
|
|
+
|
|
+ ret = pwmchip_add(&chip->chip);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "failed to register PWM chip\n");
|
|
+ clk_disable_unprepare(chip->base_clk);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pwm_sophgo_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct sophgo_pwm_chip *chip = platform_get_drvdata(pdev);
|
|
+
|
|
+ pwmchip_remove(&chip->chip);
|
|
+
|
|
+ clk_disable_unprepare(chip->base_clk);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
+static int pwm_sophgo_suspend(struct device *dev)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pwm_sophgo_resume(struct device *dev)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static SIMPLE_DEV_PM_OPS(pwm_sophgo_pm_ops, pwm_sophgo_suspend,
|
|
+ pwm_sophgo_resume);
|
|
+
|
|
+static struct platform_driver pwm_sophgo_driver = {
|
|
+ .driver = {
|
|
+ .name = "sophgo-pwm",
|
|
+ .pm = &pwm_sophgo_pm_ops,
|
|
+ .of_match_table = of_match_ptr(sophgo_pwm_match),
|
|
+ },
|
|
+ .probe = pwm_sophgo_probe,
|
|
+ .remove = pwm_sophgo_remove,
|
|
+};
|
|
+module_platform_driver(pwm_sophgo_driver);
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_AUTHOR("chunzhi.lin");
|
|
+MODULE_DESCRIPTION("Sophgo PWM driver");
|
|
diff --git a/drivers/pwm/pwm-thead.c b/drivers/pwm/pwm-thead.c
|
|
new file mode 100644
|
|
index 000000000000..3b4772c3b8ca
|
|
--- /dev/null
|
|
+++ b/drivers/pwm/pwm-thead.c
|
|
@@ -0,0 +1,269 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * T-HEAD PWM driver
|
|
+ *
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
|
|
+ *
|
|
+ * Limitations:
|
|
+ * - The THEAD_PWM_CTRL_START bit is only effective when 0 -> 1, which is used
|
|
+ * to start the channel, 1 -> 0 doesn't change anything. so 0 % duty cycle
|
|
+ * is used to "disable" the channel.
|
|
+ * - The THEAD_PWM_CTRL_START bit is automatically cleared once PWM channel is
|
|
+ * started.
|
|
+ * - The THEAD_PWM_CFG_UPDATE atomically updates and only updates period and duty.
|
|
+ * - To update period and duty, THEAD_PWM_CFG_UPDATE needs to go through 0 -> 1
|
|
+ * step, I.E if THEAD_PWM_CFG_UPDATE is already 1, it's necessary to clear it
|
|
+ * to 0 beforehand.
|
|
+ * - Polarity can only be changed if never started before.
|
|
+ */
|
|
+
|
|
+#include <linux/bitfield.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/mod_devicetable.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/pm_runtime.h>
|
|
+#include <linux/pwm.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+#define THEAD_PWM_MAX_NUM 6
|
|
+#define THEAD_PWM_MAX_PERIOD GENMASK(31, 0)
|
|
+#define THEAD_PWM_MAX_DUTY GENMASK(31, 0)
|
|
+
|
|
+#define THEAD_PWM_CHN_BASE(n) ((n) * 0x20)
|
|
+#define THEAD_PWM_CTRL(n) (THEAD_PWM_CHN_BASE(n) + 0x00)
|
|
+#define THEAD_PWM_CTRL_START BIT(0)
|
|
+#define THEAD_PWM_CTRL_SOFT_RST BIT(1)
|
|
+#define THEAD_PWM_CTRL_CFG_UPDATE BIT(2)
|
|
+#define THEAD_PWM_CTRL_INTEN BIT(3)
|
|
+#define THEAD_PWM_CTRL_MODE GENMASK(5, 4)
|
|
+#define THEAD_PWM_CTRL_MODE_CONTINUOUS FIELD_PREP(THEAD_PWM_CTRL_MODE, 2)
|
|
+#define THEAD_PWM_CTRL_EVTRIG GENMASK(7, 6)
|
|
+#define THEAD_PWM_CTRL_FPOUT BIT(8)
|
|
+#define THEAD_PWM_CTRL_INFACTOUT BIT(9)
|
|
+#define THEAD_PWM_RPT(n) (THEAD_PWM_CHN_BASE(n) + 0x04)
|
|
+#define THEAD_PWM_PER(n) (THEAD_PWM_CHN_BASE(n) + 0x08)
|
|
+#define THEAD_PWM_FP(n) (THEAD_PWM_CHN_BASE(n) + 0x0c)
|
|
+#define THEAD_PWM_STATUS(n) (THEAD_PWM_CHN_BASE(n) + 0x10)
|
|
+#define THEAD_PWM_STATUS_CYCLE GENMASK(7, 0)
|
|
+
|
|
+struct thead_pwm_chip {
|
|
+ struct pwm_chip chip;
|
|
+ void __iomem *mmio_base;
|
|
+ struct clk *clk;
|
|
+ u8 channel_ever_started;
|
|
+};
|
|
+
|
|
+static inline struct thead_pwm_chip *thead_pwm_from_chip(struct pwm_chip *chip)
|
|
+{
|
|
+ return container_of(chip, struct thead_pwm_chip, chip);
|
|
+}
|
|
+
|
|
+static int thead_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
+ const struct pwm_state *state)
|
|
+{
|
|
+ struct thead_pwm_chip *priv = thead_pwm_from_chip(chip);
|
|
+ u32 val = THEAD_PWM_CTRL_INFACTOUT | THEAD_PWM_CTRL_FPOUT | THEAD_PWM_CTRL_MODE_CONTINUOUS;
|
|
+ u64 period_cycle, duty_cycle, rate;
|
|
+ int ret;
|
|
+
|
|
+ /* if ever started, can't change the polarity */
|
|
+ if ((priv->channel_ever_started & (1 << pwm->hwpwm)) &&
|
|
+ state->polarity != pwm->state.polarity)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!state->enabled) {
|
|
+ if (pwm->state.enabled) {
|
|
+ val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
|
|
+ val &= ~THEAD_PWM_CTRL_CFG_UPDATE;
|
|
+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
|
|
+
|
|
+ writel(0, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm));
|
|
+
|
|
+ val |= THEAD_PWM_CTRL_CFG_UPDATE;
|
|
+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
|
|
+ pm_runtime_put_sync(chip->dev);
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!pwm->state.enabled) {
|
|
+ ret = pm_runtime_resume_and_get(chip->dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (state->polarity == PWM_POLARITY_INVERSED)
|
|
+ val &= ~THEAD_PWM_CTRL_FPOUT;
|
|
+
|
|
+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
|
|
+
|
|
+ rate = clk_get_rate(priv->clk);
|
|
+ /*
|
|
+ * The following calculations might overflow if clk is bigger
|
|
+ * than 1 GHz. In practise it's 24MHz, so this limitation
|
|
+ * is only theoretic.
|
|
+ */
|
|
+ if (rate > NSEC_PER_SEC)
|
|
+ return -EINVAL;
|
|
+
|
|
+ period_cycle = mul_u64_u64_div_u64(rate, state->period, NSEC_PER_SEC);
|
|
+ if (period_cycle > THEAD_PWM_MAX_PERIOD)
|
|
+ period_cycle = THEAD_PWM_MAX_PERIOD;
|
|
+ /*
|
|
+ * With limitation above we have period_cycle <= THEAD_PWM_MAX_PERIOD,
|
|
+ * so this cannot overflow.
|
|
+ */
|
|
+ writel(period_cycle, priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm));
|
|
+
|
|
+ duty_cycle = mul_u64_u64_div_u64(rate, state->duty_cycle, NSEC_PER_SEC);
|
|
+ if (duty_cycle > THEAD_PWM_MAX_DUTY)
|
|
+ duty_cycle = THEAD_PWM_MAX_DUTY;
|
|
+ /*
|
|
+ * With limitation above we have duty_cycle <= THEAD_PWM_MAX_DUTY,
|
|
+ * so this cannot overflow.
|
|
+ */
|
|
+ writel(duty_cycle, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm));
|
|
+
|
|
+ val |= THEAD_PWM_CTRL_CFG_UPDATE;
|
|
+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
|
|
+
|
|
+ if (!pwm->state.enabled) {
|
|
+ val |= THEAD_PWM_CTRL_START;
|
|
+ writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
|
|
+ priv->channel_ever_started |= 1 << pwm->hwpwm;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int thead_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
+ struct pwm_state *state)
|
|
+{
|
|
+ struct thead_pwm_chip *priv = thead_pwm_from_chip(chip);
|
|
+ u64 rate = clk_get_rate(priv->clk);
|
|
+ u32 val;
|
|
+ int ret;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(chip->dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
|
|
+ if (val & THEAD_PWM_CTRL_FPOUT)
|
|
+ state->polarity = PWM_POLARITY_NORMAL;
|
|
+ else
|
|
+ state->polarity = PWM_POLARITY_INVERSED;
|
|
+
|
|
+ val = readl(priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm));
|
|
+ /*
|
|
+ * val 32 bits, multiply NSEC_PER_SEC, won't overflow.
|
|
+ */
|
|
+ state->period = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate);
|
|
+
|
|
+ val = readl(priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm));
|
|
+ state->enabled = !!val;
|
|
+ /*
|
|
+ * val 32 bits, multiply NSEC_PER_SEC, won't overflow.
|
|
+ */
|
|
+ state->duty_cycle = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate);
|
|
+
|
|
+ pm_runtime_put_sync(chip->dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct pwm_ops thead_pwm_ops = {
|
|
+ .apply = thead_pwm_apply,
|
|
+ .get_state = thead_pwm_get_state,
|
|
+};
|
|
+
|
|
+static int __maybe_unused thead_pwm_runtime_suspend(struct device *dev)
|
|
+{
|
|
+ struct thead_pwm_chip *priv = dev_get_drvdata(dev);
|
|
+
|
|
+ clk_disable_unprepare(priv->clk);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused thead_pwm_runtime_resume(struct device *dev)
|
|
+{
|
|
+ struct thead_pwm_chip *priv = dev_get_drvdata(dev);
|
|
+ int ret;
|
|
+
|
|
+ ret = clk_prepare_enable(priv->clk);
|
|
+ if (ret)
|
|
+ dev_err(dev, "failed to enable pwm clock(%pe)\n", ERR_PTR(ret));
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int thead_pwm_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct thead_pwm_chip *priv;
|
|
+ int ret, i;
|
|
+ u32 val;
|
|
+
|
|
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ platform_set_drvdata(pdev, priv);
|
|
+
|
|
+ priv->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
|
+ if (IS_ERR(priv->mmio_base))
|
|
+ return PTR_ERR(priv->mmio_base);
|
|
+
|
|
+ priv->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
|
+ if (IS_ERR(priv->clk))
|
|
+ return PTR_ERR(priv->clk);
|
|
+
|
|
+ priv->chip.ops = &thead_pwm_ops;
|
|
+ priv->chip.dev = &pdev->dev;
|
|
+ priv->chip.npwm = THEAD_PWM_MAX_NUM;
|
|
+
|
|
+ /* check whether PWM is ever started or not */
|
|
+ for (i = 0; i < priv->chip.npwm; i++) {
|
|
+ val = readl(priv->mmio_base + THEAD_PWM_FP(i));
|
|
+ if (val)
|
|
+ priv->channel_ever_started |= 1 << i;
|
|
+ }
|
|
+
|
|
+ ret = devm_pwmchip_add(&pdev->dev, &priv->chip);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ devm_pm_runtime_enable(&pdev->dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct of_device_id thead_pwm_dt_ids[] = {
|
|
+ {.compatible = "thead,th1520-pwm",},
|
|
+ {/* sentinel */}
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, thead_pwm_dt_ids);
|
|
+
|
|
+static const struct dev_pm_ops thead_pwm_pm_ops = {
|
|
+ SET_RUNTIME_PM_OPS(thead_pwm_runtime_suspend, thead_pwm_runtime_resume, NULL)
|
|
+};
|
|
+
|
|
+static struct platform_driver thead_pwm_driver = {
|
|
+ .driver = {
|
|
+ .name = "thead-pwm",
|
|
+ .of_match_table = thead_pwm_dt_ids,
|
|
+ .pm = &thead_pwm_pm_ops,
|
|
+ },
|
|
+ .probe = thead_pwm_probe,
|
|
+};
|
|
+module_platform_driver(thead_pwm_driver);
|
|
+
|
|
+MODULE_AUTHOR("Wei Liu <lw312886@linux.alibaba.com>");
|
|
+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
|
|
+MODULE_DESCRIPTION("T-HEAD pwm driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
|
|
index 965d4f0c18a6..8a2c579c783c 100644
|
|
--- a/drivers/regulator/Kconfig
|
|
+++ b/drivers/regulator/Kconfig
|
|
@@ -1663,4 +1663,13 @@ config REGULATOR_QCOM_LABIBB
|
|
boost regulator and IBB can be used as a negative boost regulator
|
|
for LCD display panel.
|
|
|
|
+config REGULATOR_LIGHT_AON
|
|
+ tristate "Thead Light Aon regulator"
|
|
+ depends on LIGHT_AON
|
|
+ default y
|
|
+ help
|
|
+ This driver provides support for the thead light virtal regulators that
|
|
+ inmplemented on Light Aon system.
|
|
+
|
|
+
|
|
endif
|
|
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
|
|
index 23074714a81a..aa1d8ca59499 100644
|
|
--- a/drivers/regulator/Makefile
|
|
+++ b/drivers/regulator/Makefile
|
|
@@ -195,5 +195,6 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
|
|
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
|
|
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
|
|
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
|
|
+obj-$(CONFIG_REGULATOR_LIGHT_AON) += light-regulator-aon.o
|
|
|
|
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
|
|
diff --git a/drivers/regulator/light-regulator-aon.c b/drivers/regulator/light-regulator-aon.c
|
|
new file mode 100644
|
|
index 000000000000..d30cb956145b
|
|
--- /dev/null
|
|
+++ b/drivers/regulator/light-regulator-aon.c
|
|
@@ -0,0 +1,888 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <linux/debugfs.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/regulator/driver.h>
|
|
+#include <linux/regulator/machine.h>
|
|
+#include <linux/regulator/of_regulator.h>
|
|
+#include <linux/regulator/machine.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/uaccess.h>
|
|
+#include <linux/firmware/thead/ipc.h>
|
|
+
|
|
+#define MBOX_MAX_MSG_LEN 28
|
|
+
|
|
+#define CONFIG_AON_REG_DEBUG 1
|
|
+
|
|
+struct rpc_msg_regu_vol_set {
|
|
+ u16 regu_id; ///< virtual regu id
|
|
+ u16 is_dual_rail; ///< whether this regu has dual rails
|
|
+ u32 dc1; ///< voltage uinit in uv for single rail or first rail of dual rail
|
|
+ u32 dc2; ///< voltage uinit in uv for second rail of dual rail,ignore it if "is_dual_rail" is false
|
|
+ u16 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 <duanfugang.dfg@linux.alibaba.com>");
|
|
+MODULE_AUTHOR("linghui.zlh <linghui.zlh@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("Thead Light Aon regulator virtual driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
|
|
index ccd59ddd7610..ec69e6bbba6e 100644
|
|
--- a/drivers/reset/Kconfig
|
|
+++ b/drivers/reset/Kconfig
|
|
@@ -253,6 +253,16 @@ config RESET_SUNXI
|
|
help
|
|
This enables the reset driver for Allwinner SoCs.
|
|
|
|
+config RESET_TH1520
|
|
+ bool "TH1520 Reset Driver"
|
|
+ depends on (ARCH_THEAD || COMPILE_TEST) && OF
|
|
+ select MFD_SYSCON
|
|
+ default ARCH_THEAD
|
|
+ help
|
|
+ Support for the T-HEAD 1520 RISC-V SoC reset controller.
|
|
+ Say Y if you want to control reset signals provided by this
|
|
+ controller.
|
|
+
|
|
config RESET_TI_SCI
|
|
tristate "TI System Control Interface (TI-SCI) reset driver"
|
|
depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n)
|
|
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
|
|
index 8270da8a4baa..ca0abdce468d 100644
|
|
--- a/drivers/reset/Makefile
|
|
+++ b/drivers/reset/Makefile
|
|
@@ -33,6 +33,8 @@ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
|
|
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
|
|
obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
|
|
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
|
|
+obj-$(CONFIG_ARCH_SOPHGO) += reset-sophgo.o
|
|
+obj-$(CONFIG_RESET_TH1520) += reset-th1520.o
|
|
obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
|
|
obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o
|
|
obj-$(CONFIG_RESET_TI_TPS380X) += reset-tps380x.o
|
|
diff --git a/drivers/reset/reset-sophgo.c b/drivers/reset/reset-sophgo.c
|
|
new file mode 100644
|
|
index 000000000000..3c46a43e24ba
|
|
--- /dev/null
|
|
+++ b/drivers/reset/reset-sophgo.c
|
|
@@ -0,0 +1,163 @@
|
|
+/*
|
|
+ * Sophgo SoCs Reset Controller driver
|
|
+ *
|
|
+ * Copyright (c) 2018 Bitmain Ltd.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include <linux/err.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/reset-controller.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/regmap.h>
|
|
+
|
|
+#define BITS_PER_REG 32
|
|
+
|
|
+struct bm_reset_data {
|
|
+ spinlock_t lock;
|
|
+ void __iomem *membase;
|
|
+ struct reset_controller_dev rcdev;
|
|
+ struct regmap *syscon_rst;
|
|
+ u32 top_rst_offset;
|
|
+};
|
|
+
|
|
+static int bm_reset_assert(struct reset_controller_dev *rcdev,
|
|
+ unsigned long id)
|
|
+{
|
|
+ struct bm_reset_data *data = container_of(rcdev,
|
|
+ struct bm_reset_data,
|
|
+ rcdev);
|
|
+ int bank = id / BITS_PER_REG;
|
|
+ int offset = id % BITS_PER_REG;
|
|
+ unsigned long flags;
|
|
+ u32 reg;
|
|
+
|
|
+ spin_lock_irqsave(&data->lock, flags);
|
|
+
|
|
+ regmap_read(data->syscon_rst, data->top_rst_offset + (bank * 4),
|
|
+ ®);
|
|
+ regmap_write(data->syscon_rst, data->top_rst_offset + (bank * 4),
|
|
+ reg & ~BIT(offset));
|
|
+
|
|
+ spin_unlock_irqrestore(&data->lock, flags);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bm_reset_deassert(struct reset_controller_dev *rcdev,
|
|
+ unsigned long id)
|
|
+{
|
|
+ struct bm_reset_data *data = container_of(rcdev,
|
|
+ struct bm_reset_data,
|
|
+ rcdev);
|
|
+ int bank = id / BITS_PER_REG;
|
|
+ int offset = id % BITS_PER_REG;
|
|
+ unsigned long flags;
|
|
+ u32 reg;
|
|
+
|
|
+ spin_lock_irqsave(&data->lock, flags);
|
|
+
|
|
+ regmap_read(data->syscon_rst, data->top_rst_offset + (bank * 4),
|
|
+ ®);
|
|
+ regmap_write(data->syscon_rst, data->top_rst_offset + (bank * 4),
|
|
+ reg | BIT(offset));
|
|
+
|
|
+ spin_unlock_irqrestore(&data->lock, flags);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct reset_control_ops bm_reset_ops = {
|
|
+ .assert = bm_reset_assert,
|
|
+ .deassert = bm_reset_deassert,
|
|
+};
|
|
+
|
|
+static const struct of_device_id bm_reset_dt_ids[] = {
|
|
+ { .compatible = "bitmain,reset", },
|
|
+ { /* sentinel */ },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, bm_reset_dt_ids);
|
|
+
|
|
+static int bm_reset_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct bm_reset_data *data;
|
|
+ int ret = 0;
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct device_node *np = dev->of_node, *np_top;
|
|
+ static struct regmap *syscon;
|
|
+
|
|
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
|
+ if (!data)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ np_top = of_parse_phandle(np, "subctrl-syscon", 0);
|
|
+ if (!np_top) {
|
|
+ dev_err(dev, "%s can't get subctrl-syscon node\n", __func__);
|
|
+ goto out_free_devm;
|
|
+ }
|
|
+
|
|
+ syscon = syscon_node_to_regmap(np_top);
|
|
+ if (IS_ERR(syscon)) {
|
|
+ dev_err(dev, "cannot get regmap\n");
|
|
+ goto out_free_devm;
|
|
+ }
|
|
+
|
|
+ data->syscon_rst = syscon;
|
|
+ ret = device_property_read_u32(&pdev->dev, "top_rst_offset",
|
|
+ &data->top_rst_offset);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "cannot get top_rst_offset\n");
|
|
+ goto out_free_devm;
|
|
+ }
|
|
+
|
|
+ ret = device_property_read_u32(&pdev->dev, "nr_resets",
|
|
+ &data->rcdev.nr_resets);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "cannot get nr_resets\n");
|
|
+ goto out_free_devm;
|
|
+ }
|
|
+
|
|
+ spin_lock_init(&data->lock);
|
|
+
|
|
+ data->rcdev.owner = THIS_MODULE;
|
|
+ data->rcdev.ops = &bm_reset_ops;
|
|
+ data->rcdev.of_node = pdev->dev.of_node;
|
|
+
|
|
+ ret = devm_reset_controller_register(&pdev->dev, &data->rcdev);
|
|
+ if (!ret)
|
|
+ return 0;
|
|
+
|
|
+out_free_devm:
|
|
+ devm_kfree(&pdev->dev, data);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static struct platform_driver bm_reset_driver = {
|
|
+ .probe = bm_reset_probe,
|
|
+ .driver = {
|
|
+ .name = "bm-reset",
|
|
+ .of_match_table = bm_reset_dt_ids,
|
|
+ },
|
|
+};
|
|
+
|
|
+static int __init bm_reset_init(void)
|
|
+{
|
|
+ return platform_driver_register(&bm_reset_driver);
|
|
+}
|
|
+postcore_initcall(bm_reset_init);
|
|
+
|
|
+MODULE_AUTHOR("Wei Huang<wei.huang01@bitmain.com>");
|
|
+MODULE_DESCRIPTION("Bitmain SoC Reset Controoler Driver");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/reset/reset-th1520.c b/drivers/reset/reset-th1520.c
|
|
new file mode 100644
|
|
index 000000000000..5a89d201fc0c
|
|
--- /dev/null
|
|
+++ b/drivers/reset/reset-th1520.c
|
|
@@ -0,0 +1,109 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/reset-controller.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <dt-bindings/reset/thead,th1520-reset.h>
|
|
+
|
|
+struct th1520_rst_signal {
|
|
+ unsigned int offset, bit;
|
|
+};
|
|
+
|
|
+struct th1520_rst {
|
|
+ struct reset_controller_dev rcdev;
|
|
+ struct regmap *regmap;
|
|
+ const struct th1520_rst_signal *signals;
|
|
+};
|
|
+
|
|
+enum th1520_rst_registers {
|
|
+ RST_WDT0 = 0x0034,
|
|
+ RST_WDT1 = 0x0038,
|
|
+};
|
|
+
|
|
+static int th1520_reset_update(struct th1520_rst *rst, unsigned long id,
|
|
+ unsigned int value)
|
|
+{
|
|
+ const struct th1520_rst_signal *signal = &rst->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 <linux/clk.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/notifier.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_irq.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/rpmsg.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/virtio.h>
|
|
+#include <linux/virtio_config.h>
|
|
+#include <linux/virtio_ids.h>
|
|
+#include <linux/virtio_ring.h>
|
|
+#include <linux/light_rpmsg.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/debugfs.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/mailbox_client.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/uaccess.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/light_rpmsg.h>
|
|
+
|
|
+#define MBOX_MAX_MSG_LEN 28
|
|
+#define WJ_MBOX_SEND_MAX_MESSAGE_LENGTH 28
|
|
+#define HEXDUMP_BYTES_PER_LINE 28
|
|
+#define HEXDUMP_LINE_LEN ((HEXDUMP_BYTES_PER_LINE * 4) + 2)
|
|
+#define HEXDUMP_MAX_LEN (HEXDUMP_LINE_LEN * \
|
|
+ (MBOX_MAX_MSG_LEN / HEXDUMP_BYTES_PER_LINE))
|
|
+
|
|
+//extern struct light_rpmsg_vproc *pri_rpdev;
|
|
+static struct dentry *root_debugfs_dir;
|
|
+
|
|
+struct mbox_client_light_device {
|
|
+ struct device *dev;
|
|
+ void __iomem *tx_mmio;
|
|
+ void __iomem *rx_mmio;
|
|
+ struct mbox_chan *tx_channel;
|
|
+ struct mbox_chan *rx_channel;
|
|
+ char *rx_buffer;
|
|
+ struct regmap *audio_mbox_regmap;
|
|
+ char *message;
|
|
+ spinlock_t lock;
|
|
+};
|
|
+
|
|
+struct mbox_client_light_device *tdev_priv;
|
|
+
|
|
+static volatile uint32_t *p_mbox_reg;
|
|
+static volatile uint32_t *p_mbox_reg1;
|
|
+static volatile uint32_t *p_mbox_reg2;
|
|
+
|
|
+/*
|
|
+ * For now, allocate 256 buffers of 512 bytes for each side. each buffer
|
|
+ * will then have 16B for the msg header and 496B for the payload.
|
|
+ * This will require a total space of 256KB for the buffers themselves, and
|
|
+ * 3 pages for every vring (the size of the vring depends on the number of
|
|
+ * buffers it supports).
|
|
+ */
|
|
+#define RPMSG_NUM_BUFS (512)
|
|
+//#define RPMSG_BUF_SIZE (512)
|
|
+//#define RPMSG_BUFS_SPACE (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
|
|
+
|
|
+/*
|
|
+ * The alignment between the consumer and producer parts of the vring.
|
|
+ * Note: this is part of the "wire" protocol. If you change this, you need
|
|
+ * to update your BIOS image as well
|
|
+ */
|
|
+#define RPMSG_VRING_ALIGN (4096)
|
|
+
|
|
+/* With 256 buffers, our vring will occupy 3 pages */
|
|
+#define RPMSG_RING_SIZE ((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \
|
|
+ RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE)
|
|
+
|
|
+#define to_light_virdev(vd) container_of(vd, struct light_virdev, vdev)
|
|
+#define to_light_rpdev(vd, id) container_of(vd, struct light_rpmsg_vproc, 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 <ravi23ganiga@gmail.com>
|
|
+ */
|
|
+
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/rtc.h>
|
|
+#include <linux/spi/spi.h>
|
|
+#include <linux/bcd.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/version.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/pci.h>
|
|
+#include <linux/file.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/wait.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/miscdevice.h>
|
|
+#include <linux/serial_core.h>
|
|
+#include <linux/serial_8250.h>
|
|
+#include <linux/jiffies.h>
|
|
+
|
|
+/* 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 <ryan_chen@aspeedtech.com>");
|
|
+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 <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/netlink.h>
|
|
+#include <net/sock.h>
|
|
+
|
|
+#define DEV_NAME "sophgo-tach"
|
|
+#define MHZ 1000000
|
|
+#define USER_PORT 100
|
|
+#define USER_MSG 30
|
|
+
|
|
+struct fan_state {
|
|
+ unsigned int freq_num;
|
|
+ bool enable;
|
|
+};
|
|
+
|
|
+struct sophgo_fan_speed_device {
|
|
+ struct device *dev;
|
|
+ struct device *parent;
|
|
+ struct class *class;
|
|
+ dev_t devno;
|
|
+ u32 __iomem *regs;
|
|
+ struct delayed_work poll_queue;
|
|
+ struct fan_state fan_state;
|
|
+ struct mutex enable_lock;
|
|
+ struct mutex freqnum_lock;
|
|
+};
|
|
+
|
|
+static int fan_index;
|
|
+static struct class *sophgo_fan_speed_class;
|
|
+static struct sock *nl_fd;
|
|
+
|
|
+static int send_msg(char *pbuf, uint16_t len)
|
|
+{
|
|
+ struct sk_buff *nl_skb;
|
|
+ struct nlmsghdr *nlh;
|
|
+ int ret = 0;
|
|
+
|
|
+ //alloc a new netlink message
|
|
+ nl_skb = nlmsg_new(len, GFP_ATOMIC);
|
|
+ if (!nl_skb) {
|
|
+ pr_err("sophgo_fan_speed, netlink alloc skb error!\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ //add a new netlink message to skb
|
|
+ nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0);
|
|
+ if (nlh == NULL) {
|
|
+ pr_err("sophgo_fan_speed, nlmsg_put error!\n");
|
|
+ nlmsg_free(nl_skb);
|
|
+ return -EFAULT;
|
|
+ }
|
|
+
|
|
+ memcpy(nlmsg_data(nlh), pbuf, len);
|
|
+ ret = netlink_unicast(nl_fd, nl_skb, USER_PORT, MSG_DONTWAIT);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void recv_cb(struct sk_buff *skb)
|
|
+{
|
|
+ struct nlmsghdr *nlh = NULL;
|
|
+ void *data = NULL;
|
|
+
|
|
+ if (skb->len >= nlmsg_total_size(0)) {
|
|
+ nlh = nlmsg_hdr(skb);
|
|
+ data = nlmsg_data(nlh);
|
|
+ if (data) {
|
|
+ pr_info("sophgo_fan_speed, kernel receive data: %s\n", (int8_t *)data);
|
|
+ send_msg(data, nlmsg_len(nlh));
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+struct netlink_kernel_cfg cfg = {
|
|
+ .input = recv_cb,
|
|
+};
|
|
+
|
|
+static void fan_speed_check(struct work_struct *work)
|
|
+{
|
|
+ struct sophgo_fan_speed_device *sophgo_fan = container_of(work,
|
|
+ struct sophgo_fan_speed_device, poll_queue.work);
|
|
+ int speed, ret = 0;
|
|
+ char 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 <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_platform.h>
|
|
+#include <linux/of_pci.h>
|
|
+#include <linux/msi.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/irqdomain.h>
|
|
+#include <linux/irqchip/chained_irq.h>
|
|
+
|
|
+#define MAX_IRQ_NUMBER 32
|
|
+#define TOP_INTC_NUM 2
|
|
+/*
|
|
+ * here we assume all plic hwirq and tic hwirq should
|
|
+ * be contiguous.
|
|
+ * topc_intc hwirq is index of bitmap (both software and
|
|
+ * hardware), and starts from 0.
|
|
+ * so we use tic hwirq as index to get plic hwirq and its
|
|
+ * irq data.
|
|
+ * when used as a msi parent, tic hwirq is written to Top
|
|
+ * reg for triggering irq by a PCIe device.
|
|
+ *
|
|
+ * now we pre-requested plic interrupt, but may try request
|
|
+ * plic interrupt when needed, like gicp_irq_domain_alloc.
|
|
+ */
|
|
+struct top_intc_data {
|
|
+ struct platform_device *pdev;
|
|
+ int irq_num;
|
|
+ struct irq_domain *domain;
|
|
+ struct irq_chip *chip;
|
|
+ int for_msi;
|
|
+ int reg_bitwidth;
|
|
+
|
|
+ DECLARE_BITMAP(irq_bitmap, MAX_IRQ_NUMBER);
|
|
+ spinlock_t lock;
|
|
+
|
|
+ void __iomem *reg_sta;
|
|
+ void __iomem *reg_set;
|
|
+ void __iomem *reg_clr;
|
|
+
|
|
+ phys_addr_t reg_set_phys;
|
|
+
|
|
+ irq_hw_number_t plic_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 <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/nvmem-consumer.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/hwmon.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+/* fixed MCU registers */
|
|
+#define MCU_REG_BOARD_TYPE 0x00
|
|
+#define MCU_REG_VERSION 0x01
|
|
+#define MCU_REG_SOC_TEMP 0x04
|
|
+#define MCU_REG_BOARD_TEMP 0x05
|
|
+#define MCU_REG_PWROFF_REASON1 0x06
|
|
+#define MCU_REG_PWROFF_REASON2 0x07
|
|
+
|
|
+#define MCU_REG_CRITICAL_ACTIONS 0x65
|
|
+#define MCU_REG_CRITICAL_TEMP 0x66
|
|
+#define MCU_REG_REPOWERON_TEMP 0x67
|
|
+#define MCU_REG_KEEP_DDR_POWERON 0x68
|
|
+
|
|
+#define MCU_CRITICAL_ACTION_POWEROFF 0x2
|
|
+#define MCU_CRITICAL_ACTION_REBOOT 0X1
|
|
+
|
|
+#define MANGO_BOARD_TYPE_MASK 1 << 7
|
|
+
|
|
+#ifndef assert
|
|
+#define assert(exp) WARN_ON(!(exp))
|
|
+#endif
|
|
+
|
|
+struct mcu_features {
|
|
+ u8 id;
|
|
+ char *proj;
|
|
+ char *soc;
|
|
+ char *chip;
|
|
+
|
|
+ int board_type;
|
|
+ int mcu_ver;
|
|
+ int pcb_ver;
|
|
+ int soc_tmp;
|
|
+ int board_tmp;
|
|
+ int alert_status;
|
|
+ int alert_mask;
|
|
+ int rst_cnt;
|
|
+ int uptime;
|
|
+ int lock;
|
|
+ int power;
|
|
+ int power_tpu;
|
|
+ int brd_id;
|
|
+ int brd_ip;
|
|
+
|
|
+ int critical_action;
|
|
+ int critical_temp;
|
|
+ int repoweron_temp;
|
|
+ int keep_ddr_poweron;
|
|
+
|
|
+ char *alert_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 <linux/kernel.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/miscdevice.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/firmware/thead/ipc.h>
|
|
+#include <linux/firmware/thead/light_event.h>
|
|
+
|
|
+/*
|
|
+ * AON SRAM total size is 0x10000, reserve 0x100 for event.
|
|
+ * Notice: c902 *.ld also need resize.
|
|
+ * -------------- 0xff_ffef8000
|
|
+ * | |
|
|
+ * | |
|
|
+ * | |
|
|
+ * | c902 |
|
|
+ * | |
|
|
+ * | |
|
|
+ * | |
|
|
+ * -------------- 0xff_fff07f00
|
|
+ * | reserve |
|
|
+ * | |
|
|
+ * --------------
|
|
+ */
|
|
+#define LIGHT_AON_SRAM_LEN 0x10000
|
|
+#define LIGHT_AON_SRAM_RESERV (LIGHT_AON_SRAM_LEN - 0x100)
|
|
+#define LIGHT_EVENT_OFFSET (LIGHT_AON_SRAM_RESERV + 0x10)
|
|
+#define LIGHT_EVENT_CHECK (LIGHT_EVENT_OFFSET + 0x4)
|
|
+
|
|
+#define LIGHT_EVENT_MAGIC 0x5A5A5A5A
|
|
+
|
|
+struct light_aon_msg_event_ctrl {
|
|
+ struct light_aon_rpc_msg_hdr hdr;
|
|
+ u32 reserve_offset;
|
|
+ u32 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 <jszhang@kernel.org>
|
|
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
|
+ */
|
|
+
|
|
+#include <linux/io.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_platform.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/regmap.h>
|
|
+
|
|
+#include "core.h"
|
|
+
|
|
+#define USB_SSP_EN 0x34
|
|
+#define REF_SSP_EN BIT(0)
|
|
+#define USB_SYS 0x3c
|
|
+#define COMMONONN BIT(0)
|
|
+
|
|
+#define USB3_DRD_SWRST 0x14
|
|
+#define USB3_DRD_PRST BIT(0)
|
|
+#define USB3_DRD_PHYRST BIT(1)
|
|
+#define USB3_DRD_VCCRST BIT(2)
|
|
+#define USB3_DRD_RSTMASK (USB3_DRD_PRST | USB3_DRD_PHYRST | USB3_DRD_VCCRST)
|
|
+
|
|
+struct dwc3_thead {
|
|
+ void __iomem *base;
|
|
+ struct regmap *misc_sysreg;
|
|
+ struct regulator *vbus;
|
|
+};
|
|
+
|
|
+static void dwc3_thead_optimize_power(struct dwc3_thead *thead)
|
|
+{
|
|
+ u32 val;
|
|
+
|
|
+ /* config usb top within USB ctrl & PHY reset */
|
|
+ regmap_update_bits(thead->misc_sysreg, USB3_DRD_SWRST,
|
|
+ USB3_DRD_RSTMASK, USB3_DRD_PRST);
|
|
+
|
|
+ /*
|
|
+ * dwc reg also need to be configed to save power
|
|
+ * 1. set USB_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 <jszhang@kernel.org>");
|
|
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
|
|
index 751458959411..b26aac73333a 100644
|
|
--- a/drivers/watchdog/Kconfig
|
|
+++ b/drivers/watchdog/Kconfig
|
|
@@ -2044,6 +2044,20 @@ config STARFIVE_WATCHDOG
|
|
Say Y here to support the watchdog of StarFive JH7100 and JH7110
|
|
SoC. This driver can also be built as a module if choose M.
|
|
|
|
+config LIGHT_PMIC_WATCHDOG
|
|
+ tristate "THEAD Light pmic watchdog"
|
|
+ depends on THEAD_LIGHT_MBOX
|
|
+ select WATCHDOG_CORE
|
|
+ help
|
|
+ This is the driver for the hardware watchdog on Light Board. This watchdog
|
|
+ simply watches your kernel to make sure it doesn't freeze, and if
|
|
+ it does, it reboots your computer after a certain amount of time.
|
|
+
|
|
+ To compile this driver as a module, choose M here: the
|
|
+ module will be called acquirewdt.
|
|
+
|
|
+ Most people will say N.
|
|
+
|
|
# S390 Architecture
|
|
|
|
config DIAG288_WATCHDOG
|
|
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
|
|
index 7eab9de311cb..5c36e33f8b6e 100644
|
|
--- a/drivers/watchdog/Makefile
|
|
+++ b/drivers/watchdog/Makefile
|
|
@@ -196,6 +196,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
|
|
|
|
# RISC-V Architecture
|
|
obj-$(CONFIG_STARFIVE_WATCHDOG) += starfive-wdt.o
|
|
+obj-$(CONFIG_LIGHT_PMIC_WATCHDOG) += light_wdt.o
|
|
|
|
# S390 Architecture
|
|
obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o
|
|
diff --git a/drivers/watchdog/light_wdt.c b/drivers/watchdog/light_wdt.c
|
|
new file mode 100644
|
|
index 000000000000..d5fa5f77cec1
|
|
--- /dev/null
|
|
+++ b/drivers/watchdog/light_wdt.c
|
|
@@ -0,0 +1,376 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#include <linux/clk.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/moduleparam.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/watchdog.h>
|
|
+#include <linux/firmware/thead/ipc.h>
|
|
+#include <linux/firmware/thead/light_event.h>
|
|
+
|
|
+#define DRV_NAME "light-wdt"
|
|
+
|
|
+/*
|
|
+ * Watchdog selector to timeout in seconds.
|
|
+ * 0: WDT disabled;
|
|
+ * others: timeout = 2048 ms * 2^(TWDSCALE-1).
|
|
+ */
|
|
+static const unsigned int wdt_timeout[] = {8, 16, 32,128};
|
|
+#define LIGHT_TWDSCALE_DISABLE 0
|
|
+#define LIGHT_TWDSCALE_MIN 1
|
|
+#define LIGHT_TWDSCALE_MAX (ARRAY_SIZE(wdt_timeout) - 1)
|
|
+#define LIGHT_WDT_MIN_TIMEOUT wdt_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 <lw312886@linux.alibaba.com>");
|
|
+MODULE_DESCRIPTION("PMIC Watchdog Driver for Light");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/include/dt-bindings/clock/light-dspsys.h b/include/dt-bindings/clock/light-dspsys.h
|
|
new file mode 100644
|
|
index 000000000000..6473e12623c6
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/light-dspsys.h
|
|
@@ -0,0 +1,25 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#ifndef _LIGHT_DSPSYS_H
|
|
+#define _LIGHT_DSPSYS_H
|
|
+
|
|
+#define CLKGEN_DSP0_PCLK 0
|
|
+#define CLKGEN_DSP0_CCLK 1
|
|
+#define CLKGEN_DSP1_PCLK 2
|
|
+#define CLKGEN_DSP1_CCLK 3
|
|
+#define CLKGEN_X2X_X4_DSPSLV_DSP0_ACLK_M 4
|
|
+#define CLKGEN_X2X_X4_DSPSLV_DSP1_ACLK_M 5
|
|
+#define CLKGEN_AXI4_DSPSYS_SLV_ACLK 6
|
|
+#define CLKGEN_AXI4_DSPSYS_ACLK 7
|
|
+#define CLKGEN_IOPMP_DSP0_PCLK 8
|
|
+#define CLKGEN_IOPMP_DSP1_PCLK 9
|
|
+#define CLKGEN_AXI4_DSPSYS_SLV_PCLK 10
|
|
+#define CLKGEN_AXI4_DSPSYS_PCLK 11
|
|
+#define CLKGEN_X2X_DSP0_ACLK_S 12
|
|
+#define CLKGEN_X2X_DSP2_ACLK_S 13
|
|
+#define LIGHT_CLKGEN_DSPSYS_CLK_END 14
|
|
+
|
|
+#endif
|
|
diff --git a/include/dt-bindings/clock/light-fm-ap-clock.h b/include/dt-bindings/clock/light-fm-ap-clock.h
|
|
new file mode 100644
|
|
index 000000000000..8bb23b690f98
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/light-fm-ap-clock.h
|
|
@@ -0,0 +1,513 @@
|
|
+#ifndef _APSYS_CLKGEN_H
|
|
+#define _APSYS_CLKGEN_H
|
|
+
|
|
+#define C910_CCLK_I0 0
|
|
+#define AXI4_CPUSYS1_ACLK 1
|
|
+#define CLKGEN_GPIO2_DBCLK 2
|
|
+#define CLKGEN_MBOX0_PCLK 3
|
|
+#define CLKGEN_GMAC0_CCLK 4
|
|
+#define CLKGEN_SPI_PCLK 5
|
|
+#define CLKGEN_CLK_OUT_1_CLK 6
|
|
+#define PAD_RTC_CLK 7
|
|
+#define CLKGEN_SPINLOCK_HCLK 8
|
|
+#define CLKGEN_QSPI1_PCLK 9
|
|
+#define CLKGEN_HDMI_ISCAN_CK_REF_CLK 10
|
|
+#define CLKGEN_IOPMP_AON_PCLK 11
|
|
+#define CLKGEN_ISP_RY_ACLK 12
|
|
+#define CLKGEN_MIPIDSI0_SCANRXCLKESC 13
|
|
+#define CLKGEN_EIP120SII_HCLK 14
|
|
+#define CLKGEN_MIPI_CSI0_PIXCLK 15
|
|
+#define CLKGEN_SRAM_AXI_ACLK_3 16
|
|
+#define CLKGEN_PERISYS_AHB_HCLK 17
|
|
+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK0_CLK 18
|
|
+#define CLKGEN_QSPI0_SSI_CLK 19
|
|
+#define CLKGEN_DW200_ACLK 20
|
|
+#define CLKGEN_IOPMP_EIP120SIII_PCLK 21
|
|
+#define VISYS_MIPI_CSI2_CFGCLK 22
|
|
+#define CLKGEN_APB3_CPUSYS_HCLK 23
|
|
+#define CLKGEN_PERISYS_APB1_HCLK 24
|
|
+#define CLKGEN_GPU_CORE_CLK 25
|
|
+#define CLKGEN_USB3_DRD_ACLK 26
|
|
+#define CLKGEN_VISYS_ACLK 27
|
|
+#define CLKGEN_USB3_DRD_CTRL_REF_CLK 28
|
|
+#define CLKGEN_TEE_DMAC_ACLK 29
|
|
+#define CLKGEN_AUDIO_SUBSYS_ACLK_CP2AP 30
|
|
+#define CLKGEN_SRAM_AXI_ACLK_2 31
|
|
+#define CLKGEN_IOPMP_VOSYS_GPU_PCLK 32
|
|
+#define CLKGEN_CFG2TEE_X2H_ACLK 33
|
|
+#define CLKGEN_SRAM_AXI_ACLK_1 34
|
|
+#define MISC_SDIO0_OSC_CLK 35
|
|
+#define CLKGEN_SDIO0_ACLK 36
|
|
+#define CLKGEN_MIPI_DSI1_CFGCLK 37
|
|
+#define APB3_CPUSYS_PCLK 38
|
|
+#define CLKGEN_TEE_DMAC_HCLK 39
|
|
+#define VOSYS_DPU0_PIXELCLK 40
|
|
+#define CLKGEN_CPU2CFG_X2H_MHCLK 41
|
|
+#define CLKGEN_VPSYS_ACLK 42
|
|
+#define CLKGEN_MIPIDSI1_SCANRXCLKESC 43
|
|
+#define CLKGEN_MISC2VP_X2X_ACLK_S 44
|
|
+#define CLKGEN_MIPI_CSI_SCANBYTECLK 45
|
|
+#define CLKGEN_APB3_TEESYS_HCLK 46
|
|
+#define VENC_CCLK 47
|
|
+#define VPSYS_VDEC_CCLK 48
|
|
+#define CLKGEN_MIPI_CSI0_CFG_CLK 49
|
|
+#define CLKGEN_MISCSYS_BUS_CLK 50
|
|
+#define CLKGEN_DPU_HCLK 51
|
|
+#define CLKGEN_UART1_SCLK 52
|
|
+#define GMAC_PLL_FOUTPOSTDIV 53
|
|
+#define MISC_BUS_CLK 54
|
|
+#define CLKGEN_USB3_DRD_SPDCLK 55
|
|
+#define CLKGEN_MIPI_CSI2_CFG_CLK 56
|
|
+#define CLKGEN_TOP_AXI4S_ACLK 57
|
|
+#define CLKGEN_IOPMP_EIP120SII_ACLK 58
|
|
+#define CORE_CLK 59
|
|
+#define CLKGEN_VPSYS_FCE_ACLK 60
|
|
+#define CLKGEN_I2C3_PCLK 61
|
|
+#define DPU1_PLL_DIV_CLK 62
|
|
+#define CLKGEN_USB3_DRD_PHY_REF_CLK 63
|
|
+#define CLKGEN_AON2CPU_A2X_ACLK 64
|
|
+#define CLKGEN_QSPI1_SSI_CLK 65
|
|
+#define CLKGEN_DPU_CCLK 66
|
|
+#define VISYS_MASTER_BUS_ACLK 67
|
|
+#define CLKGEN_PERI_I2S_SRC_CLK_0 68
|
|
+#define VOSYS_ACLK_M 69
|
|
+#define TEESYS_I0_HCLK 70
|
|
+#define CLKGEN_MIPI_DSI1_REFCLK 71
|
|
+#define CLKGEN_MIPI_DSI0_PCLK 72
|
|
+#define CLKGEN_VOSYS_ACLK_S 73
|
|
+#define CLKGEN_CPU2VP_X2P_PCLK 74
|
|
+#define CLKGEN_X2X_CPUSYS_ACLK_S 75
|
|
+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK1_CLK 76
|
|
+#define CLKGEN_IOPMP_VOSYS_DPU1_PCLK 77
|
|
+#define CLKGEN_MISC2VP_X2X_ACLK_M 78
|
|
+#define CLKGEN_WDT0_PCLK 79
|
|
+#define VOSYS_MIPIDSI0_SCANTXCLKESC 80
|
|
+#define VISYS_MIPI_CSI1_CFGCLK 81
|
|
+#define AHB2_CPUSYS_HCLK 82
|
|
+#define CLKGEN_SDIO1_HCLK 83
|
|
+#define CLKGEN_SDIO0_HCLK 84
|
|
+#define CLKGEN_CLK_OUT_3_CLK 85
|
|
+#define CLKGEN_GMAC_AXI_ACLK 86
|
|
+#define GMAC_CCLK 87
|
|
+#define CLKGEN_VIPRE_PCLK 88
|
|
+#define CLKGEN_HDMI_ISCAN_TX_CK_OUT2_CLK 89
|
|
+#define CLKGEN_MIPIDSI1_SCANTXCLKESC 90
|
|
+#define CLKGEN_VISYS_SLAVE_HCLK 91
|
|
+#define VOSYS_HDMI_ISCAN_TX_CK_OUT1_CLK 92
|
|
+#define CLKGEN_X2X_CPUSYS_ACLK_M 93
|
|
+#define CLKGEN_CPU2CFG_X2X_ACLK_S 94
|
|
+#define C910_OSC_CLK 95
|
|
+#define CLKGEN_X2H_DPU1_ACLK 96
|
|
+#define CLKGEN_I2C4_PCLK 97
|
|
+#define CLKGEN_GMAC0_ACLK 98
|
|
+#define MISC_USB3_PHY_REF_CLK 99
|
|
+#define VOSYS_MIPIDSI0_CFG_CLK 100
|
|
+#define CLKGEN_VPSYS_VDEC_CCLK 101
|
|
+#define VOSYS_MIPIDSI1_CFG_CLK 102
|
|
+#define CLKGEN_I2S_PCLK 103
|
|
+#define CLKGEN_DMAC_CPUSYS_ACLK 104
|
|
+#define VISYS_DW200_CLK_DWE 105
|
|
+#define CLKGEN_OCRAM_HCLK 106
|
|
+#define CLKGEN_EFUSE_PCLK 107
|
|
+#define CLKGEN_X2H_DPU_ACLK 108
|
|
+#define CLKGEN_IOPMP_SDIO0_ACLK 109
|
|
+#define VOSYS_DPU1_PIXELCLK 110
|
|
+#define CPU_PLL1_FOUT4 111
|
|
+#define CLKGEN_GPIO2_PCLK 112
|
|
+#define CLKGEN_GMAC1_CCLK 113
|
|
+#define CPU_PLL1_FOUTPOSTDIV 114
|
|
+#define VOSYS_HDMI_ISCAN_40M_CLK 115
|
|
+#define CLKGEN_VOSYS_X2X_ACLK_S 116
|
|
+#define CLKGEN_PERISYS_APB2_HCLK 117
|
|
+#define VOSYS_OSC_CLK_MUX_I2S_CLK_OCCBUF 118
|
|
+#define CLKGEN_HDMI_CEC_CLK 119
|
|
+#define CLKGEN_X2P_X4_VOSYS_PCLK 120
|
|
+#define CLKGEN_VOSYS_ACLK_M 121
|
|
+#define CLKGEN_EMMC_SDIO_REF_CLK 122
|
|
+#define CLKGEN_IOPMP_EMMC_ACLK 123
|
|
+#define VIDEO_PLL_FOUTVCO 124
|
|
+#define CLKGEN_HDMI_ISCAN_CKO_WORD_CLK 125
|
|
+#define CLKGEN_IOPMP_VOSYS_DPU_PCLK 126
|
|
+#define CLKGEN_AXI4_VISYS3_ACLK 127
|
|
+#define CLKGEN_VISYS_SYSREG_PCLK 128
|
|
+#define CLKGEN_MIPIDSI0_SCANTXCLKESC 129
|
|
+#define CLKGEN_HDMI_ISCAN_TX_CK_OUT1_CLK 130
|
|
+#define CLKGEN_IOPMP_EIP120SIII_ACLK 131
|
|
+#define CLKGEN_EIP120SII_ACLK 132
|
|
+#define CLKGEN_MBOX2_PCLK 133
|
|
+#define CLKGEN_AXI4_VISYS1_ACLK 134
|
|
+#define CLKGEN_UART1_PCLK 135
|
|
+#define CLK_OUT_3 136
|
|
+#define CLKGEN_UART5_SCLK 137
|
|
+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK2_CLK 138
|
|
+#define CLKGEN_MBOX3_PCLK 139
|
|
+#define QSPI1_SSI_CLK 140
|
|
+#define CLKGEN_I2C1_PCLK 141
|
|
+#define CLKGEN_HDMI_I2S_CLK 142
|
|
+#define CLKGEN_AXI4_CPUSYS2_PCLK 143
|
|
+#define CLKGEN_CFG2TEE_X2H_MHCLK 144
|
|
+#define CLKGEN_C910_CPU_CLK 145
|
|
+#define VOSYS_HDMI_ISCAN_TX_CK_OUT2_CLK 146
|
|
+#define CLKGEN_HDMI_PCLK 147
|
|
+#define CLKGEN_IOPMP_EIP120SII_PCLK 148
|
|
+#define CLKGEN_MISCSYS_AXI_PCLK 149
|
|
+#define CLKGEN_EIP120SI_ACLK 150
|
|
+#define TEESYS_I1_HCLK 151
|
|
+#define PERISYS_APB_PCLK 152
|
|
+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK0_DIV2_CLK 153
|
|
+#define CLKGEN_TIMER0_CCLK 154
|
|
+#define CLKGEN_IOPMP_USB3_ACLK 155
|
|
+#define CLKGEN_UART2_PCLK 156
|
|
+#define CLK_OUT_4 157
|
|
+#define AXI4_CPUSYS2_ACLK 158
|
|
+#define CLKGEN_AUDIO_SUBSYS_ACLK_AP2CP 159
|
|
+#define CLKGEN_I2C3_IC_CLK 160
|
|
+#define CLKGEN_IOPMP_GPU_ACLK 161
|
|
+#define CLKGEN_TIMER1_CCLK 162
|
|
+#define VOSYS_I2S_CLK 163
|
|
+#define CLKGEN_I2C5_IC_CLK 164
|
|
+#define VOSYS_OSC_CLK_MUX_I2S_CLK 165
|
|
+#define CLKGEN_DDR_SUBSYS_ACLK_0 166
|
|
+#define CLKGEN_TIMER1_PCLK 167
|
|
+#define CLKGEN_I2C1_IC_CLK 168
|
|
+#define CLKGEN_I2S_SRC_CLK 169
|
|
+#define VISYS_DW200_CLK_VSE 170
|
|
+#define CLKGEN_MIPIDSI1_PIXCLK 171
|
|
+#define VOSYS_RTC_CLK 172
|
|
+#define CLK_OUT_1 173
|
|
+#define CLKGEN_PERISYS_APB4_HCLK 174
|
|
+#define MISC_USB3_CTRL_REF_CLK 175
|
|
+#define CLKGEN_TEE_SYSREG_PCLK 176
|
|
+#define CLKGEN_MISCSYS_AXI_ACLK 177
|
|
+#define CLKGEN_MIPIDSI1_SCANCLK 178
|
|
+#define CLKGEN_GPIO3_DBCLK 179
|
|
+#define CLKGEN_HDMI_ISCAN_40M_CLK 180
|
|
+#define CLKGEN_PERI2PERI1_APB_HCLK 181
|
|
+#define CLKGEN_GMAC0_HCLK 182
|
|
+#define CLKGEN_DDR_SUBSYS_PCLK 183
|
|
+#define VOSYS_PCLK 184
|
|
+#define CLKGEN_MIPIDSI1_SCANBYTECLK 185
|
|
+#define CLKGEN_VPSYS_G2D_ACLK 186
|
|
+#define CLKGEN_EIP150B_HCLK 187
|
|
+#define CLKGEN_UART4_SCLK 188
|
|
+#define DPU1_PLL_TEST_CLK 189
|
|
+#define CLKGEN_VOSYS_X2X_ACLK_M 190
|
|
+#define CLKGEN_IOPMP_EIP120SI_ACLK 191
|
|
+#define CLKGEN_CLK_OUT_4_CLK 192
|
|
+#define CLKGEN_GPIO0_FPCLK 193
|
|
+#define PAD_OSC_CLK 194
|
|
+#define CLKGEN_C910_BUS_CLK_NO_ICG 195
|
|
+#define CLKGEN_TIMER0_PCLK 196
|
|
+#define CLKGEN_AHB2_CPUSYS_HCLK 197
|
|
+#define EMMC_SDIO_REF_CLK 198
|
|
+#define CLKGEN_IOPMP_CHIP_DBG_PCLK 199
|
|
+#define CLKGEN_BMU_C910_PCLK 200
|
|
+#define CLKGEN_IOPMP_DPU1_ACLK 201
|
|
+#define CLKGEN_PADCTRL0_APSYS_PCLK 202
|
|
+#define MISC_SDIO1_OSC_CLK 203
|
|
+#define CLKGEN_C910_OSC_CLK 204
|
|
+#define VISYS_ISP_RY_CCLK 205
|
|
+#define CLKGEN_VPSYS_PCLK 206
|
|
+#define VISYS_MIPI_CSI0_PIXELCLK 207
|
|
+#define NPU_CCLK 208
|
|
+#define CLKGEN_AXI4_TEESYS_ACLK 209
|
|
+#define PERI2SYS_APB_PCLK 210
|
|
+#define CLKGEN_IOPMP_GMAC0_PCLK 211
|
|
+#define CLKGEN_VPSYS_G2D_PCLK 212
|
|
+#define CLKGEN_EMMC_ACLK 213
|
|
+#define CLKGEN_UART3_SCLK 214
|
|
+#define AONSYS_BUS_CLK 215
|
|
+#define DPU0_PLL_FOUT4 216
|
|
+#define VOSYS_MIPIDSI1_SCANCLK 217
|
|
+#define CLKGEN_UART4_PCLK 218
|
|
+#define CLKGEN_HDMI_ISCAN_SCL 219
|
|
+#define CLKGEN_MIPI_CSI1_PIXCLK 220
|
|
+#define CLKGEN_APSYS_CLKGEN_PCLK 221
|
|
+#define CLKGEN_GPU_TIMER_REFCLK 222
|
|
+#define GMAC_PLL_FOUT1PH0 223
|
|
+#define VOSYS_MIPIDSI1_SCANBYTECLK 224
|
|
+#define CLKGEN_GPIO3_FPCLK 225
|
|
+#define CLKGEN_SDIO1_OSC_CLK 226
|
|
+#define CLKGEN_GPIO3_PCLK 227
|
|
+#define CLKGEN_VPSYS_AXI_ACLK 228
|
|
+#define CLKGEN_HDMI_ISCAN_TX_CK_20B_CLK 229
|
|
+#define CLKGEN_VOSYSREG_PCLK 230
|
|
+#define VIDEO_PLL_TEST_CLK 231
|
|
+#define CLKGEN_MBOX1_PCLK 232
|
|
+#define CLKGEN_I2C2_IC_CLK 233
|
|
+#define VOSYS_MIPIDSI0_PLL_SCANCLK 234
|
|
+#define VOSYS_MIPIDSI1_SCANTXCLKESC 235
|
|
+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK1_DIV2_CLK 236
|
|
+#define CLKGEN_UART2_SCLK 237
|
|
+#define MISC_TEESYS_PCLK 238
|
|
+#define AUDIO_PLL_TEST_CLK 239
|
|
+#define CLKGEN_DPU_PIXELCLK1 240
|
|
+#define CLKGEN_IOPMP_TEEDMAC_PCLK 241
|
|
+#define CLKGEN_TOP_APB_SX_PCLK 242
|
|
+#define CLKGEN_I2C4_IC_CLK 243
|
|
+#define GMAC_PLL_TEST_CLK 244
|
|
+#define CLKGEN_HDMI_JTAG_TCLK 245
|
|
+#define VISYS_MIPI_CSI0_CFGCLK 246
|
|
+#define CLKGEN_CPU2AON_X2H_ACLK 247
|
|
+#define VOSYS_HDMI_ISCAN_TX_CK_OUT0_CLK 248
|
|
+#define QSPI_SSI_CLK 249
|
|
+#define VOSYS_DPU_CCLK 250
|
|
+#define CLKGEN_CPU2VI_X2H_MHCLK 251
|
|
+#define CLKGEN_MIPI_DSI0_REFCLK 252
|
|
+#define CLKGEN_DSPSYS_HCLK 253
|
|
+#define CLKGEN_IOPMP_AUD_PCLK 254
|
|
+#define CLKGEN_PERI2PERI1_APB_PCLK 255
|
|
+#define CFG_AXI_ACLK 256
|
|
+#define VPSYS_FCE_CCLK 257
|
|
+#define CLKGEN_HDMI_ISCAN_CLK 258
|
|
+#define CPU_PLL0_TEST_CLK 259
|
|
+#define CLKGEN_CPU2PERI_X2H_MHCLK 260
|
|
+#define VISYS_ACLK_M 261
|
|
+#define VOSYS_HDMI_JTAG_TCLK 262
|
|
+#define CLKGEN_IOPMP_AUD_ACLK 263
|
|
+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK1_DIV2_CLK 264
|
|
+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK1_CLK 265
|
|
+#define VOSYS_MIPIDSI0_REFCLK 266
|
|
+#define CLKGEN_VISYS_ACLK_M 267
|
|
+#define VOSYS_MIPIDSI0_SCANRXCLKESC 268
|
|
+#define CLKGEN_SDIO1_ACLK 269
|
|
+#define CFG_APB_PCLK 270
|
|
+#define CLKGEN_PADCTRL1_APSYS_PCLK 271
|
|
+#define VOSYS_MIPIDSI0_SCANCLK 272
|
|
+#define CLKGEN_I2C0_IC_CLK 273
|
|
+#define CLKGEN_VPSYS_APB_PCLK 274
|
|
+#define CLKGEN_VPSYS_VENC_CCLK 275
|
|
+#define CLKGEN_AXI4_CFG_BUS_ACLK 276
|
|
+#define CLKGEN_MIPIDSI0_SCANBYTECLK 277
|
|
+#define GPIO3_DBCLK 278
|
|
+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK0_CLK 279
|
|
+#define CLKGEN_UART5_PCLK 280
|
|
+#define DPU0_PLL_FOUTPOSTDIV_ICG 281
|
|
+#define CPU_PLL0_FOUT4 282
|
|
+#define CLKGEN_GPIO2_FPCLK 283
|
|
+#define CLKGEN_DPU_ACLK 284
|
|
+#define CLKGEN_AXI4_CPUSYS2_ACLK 285
|
|
+#define CLKGEN_DSPSYS_PCLK 286
|
|
+#define TEE_PLL_FOUTPOSTDIV 287
|
|
+#define TIMER_CCLK 288
|
|
+#define VOSYS_MIPIDSI1_PLL_SCANCLK 289
|
|
+#define CLKGEN_GMAC_AXI_PCLK 290
|
|
+#define CLKGEN_USB3_DRD_PCLK 291
|
|
+#define CLKGEN_AXI4_CPUSYS1_PCLK 292
|
|
+#define VOSYS_ACLK 293
|
|
+#define CLKGEN_IOPMP_EIP120SI_PCLK 294
|
|
+#define VOSYS_HDMI_ISCAN_TMDSCLKIN_CLK 295
|
|
+#define VOSYS_HDMI_ISCAN_CKO_WORD_CLK 296
|
|
+#define CLKGEN_NPUSYS_AXI_ACLK 297
|
|
+#define CLKGEN_IOPMP_SDIO0_PCLK 298
|
|
+#define CLKGEN_DW200_HCLK 299
|
|
+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK2_CLK 300
|
|
+#define CLKGEN_UART0_PCLK 301
|
|
+#define CLKGEN_CLK_OUT_2_CLK 302
|
|
+#define CLKGEN_GPIO0_PCLK 303
|
|
+#define CLKGEN_EMMC_OSC_CLK 304
|
|
+#define VPSYS_APB_PCLK 305
|
|
+#define CLKGEN_HDMI_PIXCLK 306
|
|
+#define CLKGEN_IOPMP_TEEDMAC_ACLK 307
|
|
+#define AUDIO_PLL_FOUT4 308
|
|
+#define CLKGEN_MIPI_CSI2_PCLK 309
|
|
+#define CLKGEN_MIPI_DSI1_PCLK 310
|
|
+#define CLKGEN_MIPI_DSI0_CFGCLK 311
|
|
+#define VISYS_ISP0_CLK 312
|
|
+#define VISYS_ISP1_CLK 313
|
|
+#define MISC_EMMC_OSC_CLK 314
|
|
+#define DPU0_PLL_FOUTPOSTDIV 315
|
|
+#define VISYS_AHB_HCLK 316
|
|
+#define CLKGEN_IOPMP_SDIO1_ACLK 317
|
|
+#define CLKGEN_EMMC_HCLK 318
|
|
+#define I2S_CLK 319
|
|
+#define CLKGEN_CPU2PERI_X2H_ACLK 320
|
|
+#define VPSYS_AXI_ACLK 321
|
|
+#define CLKGEN_IOPMP_SDIO1_PCLK 322
|
|
+#define CLKGEN_EIP120SIII_HCLK 323
|
|
+#define CLKGEN_BMU_C910_ACLK 324
|
|
+#define CLKGEN_IOPMP_DMAC_CPUSYS_PCLK 325
|
|
+#define GPIO2_DBCLK 326
|
|
+#define CHIP_DBG_CCLK 327
|
|
+#define CLKGEN_MISCSYS_TEE_CCLK 328
|
|
+#define CLKGEN_I2C5_PCLK 329
|
|
+#define CLKGEN_X2H_CPUSYS_MHCLK 330
|
|
+#define CLKGEN_PWM_CCLK 331
|
|
+#define DPU0_PLL_TEST_CLK 332
|
|
+#define CLKGEN_VISYS_PCLK 333
|
|
+#define MISC_TEESYS_HCLK 334
|
|
+#define SPI_SSI_CLK 335
|
|
+#define CLKGEN_PWM_PCLK 336
|
|
+#define VOSYS_MIPIDSI1_SCANRXCLKESC 337
|
|
+#define QSPI0_SSI_CLK 338
|
|
+#define CLKGEN_HDMI_ISCAN_TMDSCLKIN_CLK 339
|
|
+#define CLKGEN_SPI_SSI_CLK 340
|
|
+#define VIDEO_PLL_FOUT4 341
|
|
+#define CLKGEN_IOPMP_GMAC0_ACLK 342
|
|
+#define CLKGEN_VIPRE_ACLK 343
|
|
+#define MISC_OSC_CLK_DIV24 344
|
|
+#define CLKGEN_ISP_VENC_SHAKE_PCLK 345
|
|
+#define CLKGEN_HDMI_ISCAN_TX_CK_OUT0_CLK 346
|
|
+#define CLKGEN_VPSYS_G2D_CCLK 347
|
|
+#define CLKGEN_CPU2CFG_X2X_ACLK_M 348
|
|
+#define CLKGEN_GMAC1_PCLK 349
|
|
+#define CLKGEN_MIPIDSI0_PLL_SCANCLK 350
|
|
+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK0_DIV2_CLK 351
|
|
+#define TEE_PLL_FOUT4 352
|
|
+#define PERISYS_AHB_HCLK 353
|
|
+#define VIDEO_PLL_FOUT1PH0 354
|
|
+#define CLKGEN_MIPIDSI0_PIXCLK 355
|
|
+#define CLKGEN_PERI_I2S_SRC_CLK_1 356
|
|
+#define CLKGEN_MIPI_CSI0_PCLK 357
|
|
+#define CLKGEN_DDR_SUBSYS_ACLK_1 358
|
|
+#define CLKGEN_GMAC0_PCLK 359
|
|
+#define CLK_OUT_2 360
|
|
+#define CLKGEN_EIP120SIII_ACLK 361
|
|
+#define AONSYS_HCLK 362
|
|
+#define CLKGEN_ISP0_CLK 363
|
|
+#define CLKGEN_C910_BROM_HCLK 364
|
|
+#define DPU1_PLL_FOUT4 365
|
|
+#define PERI_I2S_SRC_CLK 366
|
|
+#define CPU_PLL1_TEST_CLK 367
|
|
+#define CLKGEN_DDR_SUBSYS_ACLK_2 368
|
|
+#define CLKGEN_MIPIDSI0_SCANCLK 369
|
|
+#define I2C_IC_CLK 370
|
|
+#define CLKGEN_DPU_PIXELCLK0 371
|
|
+#define CLKGEN_GPIO1_DBCLK 372
|
|
+#define CLKGEN_C910_TOP_DS_PCLK 373
|
|
+#define CLKGEN_DSPSYS_ACLK_M 374
|
|
+#define CLKGEN_AON2CPU_A2X_HCLK 375
|
|
+#define VOSYS_HDMI_ISCAN_CK_REF_CLK 376
|
|
+#define CLKGEN_IOPMP_EMMC_PCLK 377
|
|
+#define NPU_CORE_CLK 378
|
|
+#define CLKGEN_IOPMP_USB3_PCLK 379
|
|
+#define VPSYS_PCLK 380
|
|
+#define VIDEO_PLL_FOUTPOSTDIV 381
|
|
+#define CLKGEN_CPU2VP_X2P_ACLK 382
|
|
+#define CLKGEN_APB_CPU2CFG_HCLK 383
|
|
+#define VOSYS_OSC_CLK_MUX_CEC_CLK_OCCBUF 384
|
|
+#define CLKGEN_GPIO1_PCLK 385
|
|
+#define CLKGEN_APSYS_SYSREG_PCLK 386
|
|
+#define CLKGEN_VISYS_HCLK 387
|
|
+#define CLKGEN_MIPI_CSI1_PCLK 388
|
|
+#define CLKGEN_AHB2_TEESYS_HCLK 389
|
|
+#define CLKGEN_DDR_SUBSYS_ACLK_4 390
|
|
+#define SYS_PLL_TEST_CLK 391
|
|
+#define VISYS_MIPI_CSI_SCANCLK 392
|
|
+#define CPU_PLL0_FOUTPOSTDIV 393
|
|
+#define CLKGEN_UART3_PCLK 394
|
|
+#define CLKGEN_X2H_CPUSYS_ACLK 395
|
|
+#define CLKGEN_MIPI_CSI1_CFG_CLK 396
|
|
+#define CLKGEN_HDMI_ISCAN_RX_WORD_CLK2_DIV2_CLK 397
|
|
+#define CLKGEN_MISCSYS_APB_HCLK 398
|
|
+#define CLKGEN_CPU2CFG_X2H_ACLK 399
|
|
+#define CLKGEN_MIPI_CSI2_FPCLK 400
|
|
+#define CLKGEN_ISP_RY_CCLK 401
|
|
+#define CLKGEN_X2P_VOSYS_ACLK 402
|
|
+#define CLKGEN_VIPRE_PIXELCLK 403
|
|
+#define VOSYS_GPU_TIMER_REFCLK 404
|
|
+#define VOSYS_OSC_CLK_MUX_CEC_CLK 405
|
|
+#define CLKGEN_APSYS_RSTGEN_PCLK 406
|
|
+#define VOSYS_HDMI_ISCAN_SCL 407
|
|
+#define CLKGEN_ISP_RY_HCLK 408
|
|
+#define VOSYS_OSC_CLK 409
|
|
+#define VISYS_PCLK 410
|
|
+#define CLKGEN_AXI4_VO_ACLK 411
|
|
+#define CLKGEN_MIPIDSI1_PLL_SCANCLK 412
|
|
+#define GPIO1_DBCLK 413
|
|
+#define CLKGEN_AXI4_VISYS2_ACLK 414
|
|
+#define CLKGEN_EIP120SI_HCLK 415
|
|
+#define CLKGEN_IOPMP_CHIP_DBG_ACLK 416
|
|
+#define VOSYS_HDMI_ISCAN_TX_CK_20B_CLK 417
|
|
+#define VOSYS_MIPIDSI1_REFCLK 418
|
|
+#define CLKGEN_CHIP_DBG_ACLK 419
|
|
+#define VOSYS_CFG_ACLK 420
|
|
+#define CLKGEN_VOSYS_AXI_ACLK 421
|
|
+#define CPU_BUS_DFTCLK 422
|
|
+#define VOSYS_HDMI_ISCAN_CLK 423
|
|
+#define VISYS_SLAVE_BUS_HCLK 424
|
|
+#define CLKGEN_VPSYS_VDEC_PCLK 425
|
|
+#define GMAC_PLL_FOUT4 426
|
|
+#define CLKGEN_QSPI0_PCLK 427
|
|
+#define CLKGEN_ISP1_CLK 428
|
|
+#define CLKGEN_MIPI_CSI0_FPCLK 429
|
|
+#define CLKGEN_ISP0_ACLK 430
|
|
+#define CLKGEN_CPU2VI_X2H_ACLK 431
|
|
+#define C910_CCLK 432
|
|
+#define CLKGEN_DW200_CLK_VSE 433
|
|
+#define CLKGEN_AXI4_CPUSYS1_ACLK 434
|
|
+#define CLKGEN_GPU_CFG_ACLK 435
|
|
+#define CLKGEN_GPIO1_FPCLK 436
|
|
+#define CLKGEN_SRAM_AXI_ACLK_0 437
|
|
+#define CLKGEN_I2C2_PCLK 438
|
|
+#define CLKGEN_IOPMP_GMAC1_PCLK 439
|
|
+#define CLKGEN_ISP0_S_HCLK 440
|
|
+#define GPIO0_DBCLK 441
|
|
+#define CLKGEN_AXI4_VO_CFG_ACLK 442
|
|
+#define CLKGEN_NPU_CORE_CLK 443
|
|
+#define DPU0_PLL_DIV_CLK 444
|
|
+#define VOSYS_MIPIDSI0_SCANBYTECLK 445
|
|
+#define CLKGEN_CHIP_DBG_CCLK 446
|
|
+#define CLKGEN_DMAC_CPUSYS_HCLK 447
|
|
+#define CLKGEN_IOPMP_DPU_ACLK 448
|
|
+#define CLKGEN_DDR_SUBSYS_ACLK_3 449
|
|
+#define CLK_100M 450
|
|
+#define CLKGEN_DSMART_PCLK 451
|
|
+#define CLKGEN_DW200_CLK_DWE 452
|
|
+#define VPSYS_G2D_CCLK 453
|
|
+#define CLKGEN_WDT1_PCLK 454
|
|
+#define DPU1_PLL_FOUTPOSTDIV 455
|
|
+#define CLKGEN_IOPMP_GMAC1_ACLK 456
|
|
+#define CLKGEN_VPSYS_FCE_PCLK 457
|
|
+#define CLKGEN_MIPI_CSI_SCANCLK 458
|
|
+#define CLKGEN_MIPI_CSI2_PIXCLK 459
|
|
+#define CLKGEN_I2C0_PCLK 460
|
|
+#define VOSYS_HDMI_ISCAN_RX_WORD_CLK2_DIV2_CLK 461
|
|
+#define CLKGEN_HDMI_SFR_CLK 462
|
|
+#define TEE_PLL_TEST_CLK 463
|
|
+#define CLKGEN_IOPMP_DMAC_CPUSYS_ACLK 464
|
|
+#define CLKGEN_ISP_PIXELCLK 465
|
|
+#define CLKGEN_MIPI_CSI1_FPCLK 466
|
|
+#define SYS_PLL_FOUT4 467
|
|
+#define CLKGEN_AXI4_VO_PCLK 468
|
|
+#define CLKGEN_UART0_SCLK 469
|
|
+#define CLKGEN_CPU2AON_X2H_MHCLK 470
|
|
+#define VISYS_MIPI_CSI_SCANBYTECLK 471
|
|
+#define UART_SCLK 472
|
|
+#define CLKGEN_IOPMP_AON_ACLK 473
|
|
+#define CLKGEN_VPSYS_VDEC_ACLK 474
|
|
+#define CLKGEN_GMAC1_HCLK 475
|
|
+#define CLKGEN_ISP_VENC_SHAKE_ACLK 476
|
|
+#define TEESYS_HCLK 477
|
|
+#define PWM_CCLK 478
|
|
+#define CLKGEN_GPIO0_DBCLK 479
|
|
+#define CLKGEN_SDIO0_OSC_CLK 480
|
|
+#define CLKGEN_GMAC1_ACLK 481
|
|
+#define VPSYS_ACLK 482
|
|
+
|
|
+#define AHB2_CPUSYS_HCLK_OUT_DIV 483
|
|
+#define APB3_CPUSYS_PCLK_DIV 484
|
|
+#define CFG_AXI_ACLK_OUT_DIV 485
|
|
+#define PERISYS_AHB_HCLK_OUT_DIV 486
|
|
+#define CLK_OUT_1_OUT_DIV 487
|
|
+#define CLK_OUT_2_OUT_DIV 488
|
|
+#define CLK_OUT_3_OUT_DIV 489
|
|
+#define CLK_OUT_4_OUT_DIV 490
|
|
+#define NPU_CCLK_OUT_DIV 491
|
|
+#define CFG_APB_PCLK_OUT_DIV 492
|
|
+#define CPU_PLL0_BYPASS 493
|
|
+#define CPU_PLL1_BYPASS 494
|
|
+#define GMAC_PLL_BYPASS 495
|
|
+#define VIDEO_PLL_BYPASS 496
|
|
+#define TEE_PLL_BYPASS 497
|
|
+#define DPU0_PLL_BYPASS 498
|
|
+#define DPU1_PLL_BYPASS 499
|
|
+
|
|
+#define CLK_DUMMY 500
|
|
+#define OSC_32K 501
|
|
+#define OSC_24M 502
|
|
+#define RC_24M 503
|
|
+
|
|
+#define CLK_END 504
|
|
+
|
|
+#endif
|
|
diff --git a/include/dt-bindings/clock/light-mpw-clock.h b/include/dt-bindings/clock/light-mpw-clock.h
|
|
new file mode 100644
|
|
index 000000000000..46c2a052a9d2
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/light-mpw-clock.h
|
|
@@ -0,0 +1,222 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#ifndef __DT_BINDINGS_CLOCK_LIGHT_H
|
|
+#define __DT_BINDINGS_CLOCK_LIGHT_H
|
|
+
|
|
+#define LIGHT_CLK_DUMMY 0
|
|
+#define LIGHT_CLK_32K 1
|
|
+#define LIGHT_CLK_24M 2
|
|
+#define LIGHT_RC_24M 3
|
|
+
|
|
+#define LIGHT_VIDEO_PLL_FOUTVCO 4
|
|
+#define LIGHT_VIDEO_PLL_FOUTPOSTDIV 5
|
|
+#define LIGHT_VIDEO_PLL_FOUT4 6
|
|
+#define LIGHT_VIDEO_PLL_BYPASS 7
|
|
+
|
|
+#define LIGHT_GMAC_PLL_FOUTVCO 8
|
|
+#define LIGHT_GMAC_PLL_FOUTPOSTDIV 9
|
|
+#define LIGHT_GMAC_PLL_FOUT1PH0 10
|
|
+#define LIGHT_GMAC_PLL_FOUT4 11
|
|
+#define LIGHT_GMAC_PLL_BYPASS 12
|
|
+
|
|
+#define LIGHT_AUDIO_PLL_FOUTVCO 13
|
|
+#define LIGHT_AUDIO_PLL_FOUTPOSTDIV 14
|
|
+#define LIGHT_AUDIO_PLL_FOUT3 15
|
|
+#define LIGHT_AUDIO_PLL_BYPASS 16
|
|
+
|
|
+#define LIGHT_SYS_PLL_FOUTVCO 17
|
|
+#define LIGHT_SYS_PLL_FOUTPOSTDIV 18
|
|
+#define LIGHT_SYS_PLL_FOUT4 19
|
|
+#define LIGHT_SYS_PLL_BYPASS 20
|
|
+
|
|
+#define LIGHT_CPU_PLL0_FOUTVCO 21
|
|
+#define LIGHT_CPU_PLL0_FOUTPOSTDIV 22
|
|
+#define LIGHT_CPU_PLL0_FOUT4 23
|
|
+#define LIGHT_CPU_PLL0_BYPASS 24
|
|
+
|
|
+#define LIGHT_CPU_PLL1_FOUTVCO 25
|
|
+#define LIGHT_CPU_PLL1_FOUTPOSTDIV 26
|
|
+#define LIGHT_CPU_PLL1_FOUT4 27
|
|
+#define LIGHT_CPU_PLL1_BYPASS 28
|
|
+
|
|
+#define LIGHT_DDR_PLL_FOUTVCO 29
|
|
+#define LIGHT_DDR_PLL_FOUTPOSTDIV 30
|
|
+#define LIGHT_DDR_PLL_FOUT4 31
|
|
+#define LIGHT_DDR_PLL_BYPASS 32
|
|
+
|
|
+#define LIGHT_AONSYS_CLK_SWITCH_0 33
|
|
+#define LIGHT_AONSYS_CLK_SWITCH_1 34
|
|
+#define LIGHT_AONSYS_CLK 35
|
|
+#define LIGHT_SHARE_SRAM_CLK 36
|
|
+#define LIGHT_CLKGEN_RTC_PCLK 37
|
|
+#define LIGHT_CLKGEN_AOGPIO_PCLK 38
|
|
+#define LIGHT_CLKGEN_AOI2C_PCLK 39
|
|
+#define LIGHT_CLKGEN_PVTC_PCLK 40
|
|
+#define LIGHT_CLKGEN_AOAHB_HCLK 41
|
|
+#define LIGHT_CLKGEN_AOSRAM_HCLK 42
|
|
+#define LIGHT_CLKGEN_AOAPB_HCLK 43
|
|
+#define LIGHT_CLKGEN_AOPAD_PCLK 44
|
|
+#define LIGHT_CLKGEN_AOTIMER_PCLK 45
|
|
+#define LIGHT_CLKGEN_AOTIMER_CCLK 46
|
|
+#define LIGHT_CLKGEN_SRAM_AXI_ACLK 47
|
|
+#define LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_S 48
|
|
+#define LIGHT_CLKGEN_AOGPIO_DBCLK 49
|
|
+
|
|
+#define LIGHT_GMAC_CORECLK 50
|
|
+#define LIGHT_OSC_CLK_DIV24 51
|
|
+#define LIGHT_GMAC_PLL_FOUTVCO_DIV5 52
|
|
+#define LIGHT_C910_CCLK_I0 53
|
|
+#define LIGHT_C910_CCLK 54
|
|
+#define LIGHT_CPUSYS_AHB_HCLK 55
|
|
+#define LIGHT_CPUSYS_CFG_AXI_ACLK 56
|
|
+#define LIGHT_PERISYS_AHB_HCLK 57
|
|
+#define LIGHT_CLK_OUT_1 58
|
|
+#define LIGHT_CLK_OUT_2 59
|
|
+#define LIGHT_CLK_OUT_3 60
|
|
+#define LIGHT_CLK_OUT_4 61
|
|
+#define LIGHT_CPUSYS_AHB_HCLK_DIV 62
|
|
+#define LIGHT_APB3_CPUSYS_PCLK 63
|
|
+#define LIGHT_CPUSYS_SUB_AXI_ACLK 64
|
|
+#define LIGHT_CPUSYS_CFG_AXI_ACLK_DIV 65
|
|
+#define LIGHT_TEESYS_HCLK 66
|
|
+#define LIGHT_DMAC_1_CLK 67
|
|
+#define LIGHT_DMAC_2_CLK 68
|
|
+#define LIGHT_DMAC_3_CLK 69
|
|
+#define LIGHT_AXI_PORT4_CLK 70
|
|
+#define LIGHT_PERISYS_AHB_HCLK_DIV 71
|
|
+#define LIGHT_PERISYS_APB_PCLK 72
|
|
+#define LIGHT_CLK_OUT_1_DIV 73
|
|
+#define LIGHT_CLK_OUT_2_DIV 74
|
|
+#define LIGHT_CLK_OUT_3_DIV 75
|
|
+#define LIGHT_CLK_OUT_4_DIV 76
|
|
+#define LIGHT_CLKGEN_PERISYS_AXI_ACLK 77
|
|
+#define LIGHT_CLKGEN_PERISYS_AHB_HCLK 78
|
|
+#define LIGHT_CLKGEN_PERISYS_APB1_HCLK 79
|
|
+#define LIGHT_CLKGEN_PERISYS_APB2_HCLK 80
|
|
+#define LIGHT_CLKGEN_USB3_DRD_PHY_REF_CLK 81
|
|
+#define LIGHT_CLKGEN_USB3_DRD_CTRL_REF_CLK 82
|
|
+#define LIGHT_CLKGEN_USB3_DRD_SPDCLK 83
|
|
+#define LIGHT_CLKGEN_USB3_DRD_ACLK 84
|
|
+#define LIGHT_CLKGEN_EMMC1_X2X_ACLK 85
|
|
+#define LIGHT_CLKGEN_EMMC0_X2X_ACLK 86
|
|
+#define LIGHT_CLKGEN_EMMC0_HCLK 87
|
|
+#define LIGHT_CLKGEN_EMMC1_HCLK 88
|
|
+#define LIGHT_CLKGEN_GMAC_ACLK 89
|
|
+#define LIGHT_CLKGEN_PWM_PCLK 90
|
|
+#define LIGHT_CLKGEN_QSPI0_PCLK 91
|
|
+#define LIGHT_CLKGEN_QSPI1_PCLK 92
|
|
+#define LIGHT_CLKGEN_SPI_PCLK 93
|
|
+#define LIGHT_CLKGEN_UART0_PCLK 94
|
|
+#define LIGHT_CLKGEN_UART1_PCLK 95
|
|
+#define LIGHT_CLKGEN_UART2_PCLK 96
|
|
+#define LIGHT_CLKGEN_UART3_PCLK 97
|
|
+#define LIGHT_CLKGEN_UART4_PCLK 98
|
|
+#define LIGHT_CLKGEN_UART5_PCLK 99
|
|
+#define LIGHT_CLKGEN_GPIO0_PCLK 100
|
|
+#define LIGHT_CLKGEN_GPIO1_PCLK 101
|
|
+#define LIGHT_CLKGEN_GPIO2_PCLK 102
|
|
+#define LIGHT_CLKGEN_I2C0_IC_CLK 103
|
|
+#define LIGHT_CLKGEN_I2C1_IC_CLK 104
|
|
+#define LIGHT_CLKGEN_I2C2_IC_CLK 105
|
|
+#define LIGHT_CLKGEN_I2C3_IC_CLK 106
|
|
+#define LIGHT_CLKGEN_I2C4_IC_CLK 107
|
|
+#define LIGHT_CLKGEN_I2C5_IC_CLK 108
|
|
+#define LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_M 109
|
|
+#define LIGHT_CLKGEN_AXI_DUMMY_SLV_4_ACLK 110
|
|
+#define LIGHT_CLKGEN_AXI_DUMMY_SLV_3_ACLK 111
|
|
+#define LIGHT_CLKGEN_AXI_DUMMY_SLV_2_ACLK 112
|
|
+#define LIGHT_CLKGEN_AXI_DUMMY_SLV_1_ACLK 113
|
|
+#define LIGHT_CLKGEN_APB_CPU2FG_HCLK 114
|
|
+#define LIGHT_CLKGEN_AON2CPU_A2X_ACLK 115
|
|
+#define LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_M 116
|
|
+#define LIGHT_CLKGEN_CPU2RAM_X2X_ACLK_M 117
|
|
+#define LIGHT_CLKGEN_AXI4_CPUSYS2_ACLK 118
|
|
+#define LIGHT_CLKGEN_X2X_CPUSYS_ACLK_M 119
|
|
+#define LIGHT_CLKGEN_CHIP_DBG_ACLK 120
|
|
+#define LIGHT_CLKGEN_AXI4_CFG_BUS_ACLK 121
|
|
+#define LIGHT_CLKGEN_X2H_CPUSYS_ACLK 122
|
|
+#define LIGHT_CLKGEN_CPU2TEE_X2H_ACLK 123
|
|
+#define LIGHT_CLKGEN_CPU2AON_X2H_ACLK 124
|
|
+#define LIGHT_CLKGEN_CPU2CFG_X2H_ACLK 125
|
|
+#define LIGHT_CLKGEN_CPU2PERI_X2H_MHCLK 126
|
|
+#define LIGHT_CLKGEN_AHB2_CPUSYS_HCLK 127
|
|
+#define LIGHT_CLKGEN_APB3_CPUSYS_HCLK 128
|
|
+#define LIGHT_CLKGEN_C910_BROM_HCLK 129
|
|
+#define LIGHT_CLKGEN_DMAC_ACLK 130
|
|
+#define LIGHT_CLKGEN_MBOX0_PCLK 131
|
|
+#define LIGHT_CLKGEN_MBOX1_PCLK 132
|
|
+#define LIGHT_CLKGEN_MBOX2_PCLK 133
|
|
+#define LIGHT_CLKGEN_MBOX3_PCLK 134
|
|
+#define LIGHT_CLKGEN_WDT0_PCLK 135
|
|
+#define LIGHT_CLKGEN_WDT1_PCLK 136
|
|
+#define LIGHT_CLKGEN_TIMER0_CCLK 137
|
|
+#define LIGHT_CLKGEN_TIMER1_CCLK 138
|
|
+#define LIGHT_CLKGEN_TRNG_RB_HCLK 139
|
|
+#define LIGHT_CLKGEN_ADC_PCLK 140
|
|
+#define LIGHT_CLKGEN_AXI_ACLK_4 141
|
|
+#define LIGHT_CLKGEN_AXI_ACLK_3 142
|
|
+#define LIGHT_CLKGEN_AXI_ACLK_2 143
|
|
+#define LIGHT_CLKGEN_AXI_ACLK_1 145
|
|
+#define LIGHT_CLKGEN_AXI_ACLK_0 146
|
|
+#define LIGHT_CLKGEN_DMAC_1_ACLK 147
|
|
+#define LIGHT_CLKGEN_DMAC_2_ACLK 148
|
|
+#define LIGHT_CLKGEN_DMAC_3_ACLK 149
|
|
+#define LIGHT_CLKGEN_SRAM_AXI_PCLK 150
|
|
+#define LIGHT_CLKGEN_AHB2_TEESYS_HCLK 151
|
|
+#define LIGHT_CLKGEN_EFUSE_MPW_PCLK 152
|
|
+#define LIGHT_CLKGEN_CLK_OUT_4_CLK 153
|
|
+#define LIGHT_CLKGEN_CLK_OUT_3_CLK 154
|
|
+#define LIGHT_CLKGEN_CLK_OUT_2_CLK 155
|
|
+#define LIGHT_CLKGEN_CLK_OUT_1_CLK 156
|
|
+#define LIGHT_CLKGEN_DDR_APB_PCLK 157
|
|
+#define LIGHT_CLKGEN_PADCTRL_APSYS_PCLK 158
|
|
+#define LIGHT_CLKGEN_CHIP_DBG_CCLK 159
|
|
+#define LIGHT_CHIP_DBG_CCLK 160
|
|
+#define LIGHT_AXI_ACLK 161
|
|
+
|
|
+#define LIGHT_CLKGEN_CPU2CFG_X2X_ACLK_S 162
|
|
+#define LIGHT_CLKGEN_CPU2CFG_X2H_ACLK_S 163
|
|
+#define LIGHT_CLKGEN_AON2CPU_A2X_HCLK 164
|
|
+#define LIGHT_CLKGEN_DMAC_HCLK 165
|
|
+#define LIGHT_CLKGEN_X2H_CPUSYS_MHCLK 166
|
|
+#define LIGHT_CLKGEN_CPU2TEE_X2H_MHCLK 167
|
|
+#define LIGHT_CLKGEN_CPU2AON_X2H_MHCLK 168
|
|
+#define LIGHT_AXI_HCLK 169
|
|
+#define LIGHT_CLKGEN_CPU2CFG_X2H_MHCLK 170
|
|
+#define LIGHT_CLKGEN_TIMER0_PCLK 171
|
|
+#define LIGHT_CLKGEN_TIMER1_PCLK 172
|
|
+#define LIGHT_CLKGEN_PERI2DDR_X2X_ACLK_S 173
|
|
+#define LIGHT_CLKGEN_USB3_DRD_PCLK 174
|
|
+#define LIGHT_CLKGEN_GMAC_HCLK 175
|
|
+#define LIGHT_CLKGEN_GMAC_PCLK 176
|
|
+#define LIGHT_CLKGEN_GMAC_CCLK 177
|
|
+#define LIGHT_CLKGEN_EMMC0_ACLK 178
|
|
+#define LIGHT_CLKGEN_EMMC0_REF_CLK 179
|
|
+#define LIGHT_CLKGEN_EMMC0_OSC_CLK 180
|
|
+#define LIGHT_CLKGEN_EMMC1_ACLK 181
|
|
+#define LIGHT_CLKGEN_EMMC1_REF_CLK 182
|
|
+#define LIGHT_CLKGEN_EMMC1_OSC_CLK 183
|
|
+#define LIGHT_CLKGEN_PWM_CCLK 184
|
|
+#define LIGHT_CLKGEN_QSPI0_SSI_CLK 185
|
|
+#define LIGHT_CLKGEN_QSPI1_SSI_CLK 186
|
|
+#define LIGHT_CLKGEN_SPI_SSI_CLK 187
|
|
+#define LIGHT_CLKGEN_GPIO0_DBCLK 188
|
|
+#define LIGHT_CLKGEN_GPIO1_DBCLK 189
|
|
+#define LIGHT_CLKGEN_GPIO2_DBCLK 190
|
|
+#define LIGHT_CLKGEN_DMAC_1_HCLK 191
|
|
+#define LIGHT_CLKGEN_DMAC_2_HCLK 192
|
|
+#define LIGHT_CLKGEN_DMAC_3_HCLK 193
|
|
+#define LIGHT_EMMC_CLK_DIV 194
|
|
+#define LIGHT_EMMC0_OSC_CLK 195
|
|
+#define LIGHT_EMMC1_OSC_CLK 196
|
|
+#define LIGHT_PWM_CCLK 197
|
|
+#define LIGHT_USB3_PHY_REF_CLK 198
|
|
+#define LIGHT_SPI_CLK 199
|
|
+#define LIGHT_GPIO_DBCLK 200
|
|
+#define LIGHT_X2H_HCLK 201
|
|
+
|
|
+#define LIGHT_CLK_END 202
|
|
+#endif
|
|
diff --git a/include/dt-bindings/clock/light-visys.h b/include/dt-bindings/clock/light-visys.h
|
|
new file mode 100644
|
|
index 000000000000..53fed0bfb624
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/light-visys.h
|
|
@@ -0,0 +1,54 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#ifndef _LIGHT_VISYS_H
|
|
+#define _LIGHT_VISYS_H
|
|
+
|
|
+#define LIGHT_CLKGEN_VISYS_ACLK 0
|
|
+#define LIGHT_CLKGEN_DW200_ACLK 1
|
|
+#define LIGHT_CLKGEN_AXI4_VISYS1_ACLK 2
|
|
+#define LIGHT_CLKGEN_AXI4_VISYS2_ACLK 3
|
|
+#define LIGHT_CLKGEN_AXI4_VISYS3_ACLK 4
|
|
+#define LIGHT_CLKGEN_ISP0_ACLK 5
|
|
+#define LIGHT_CLKGEN_ISP_RY_ACLK 6
|
|
+#define LIGHT_CLKGEN_ISP_VENC_SHAKE_ACLK 7
|
|
+#define LIGHT_CLKGEN_VIPRE_ACLK 8
|
|
+#define LIGHT_CLKGEN_VISYS_SLAVE_HCLK 9
|
|
+#define LIGHT_CLKGEN_ISP0_S_HCLK 10
|
|
+#define LIGHT_CLKGEN_DW200_HCLK 11
|
|
+#define LIGHT_CLKGEN_ISP_RY_HCLK 12
|
|
+#define LIGHT_CLKGEN_MIPI_CSI0_PCLK 13
|
|
+#define LIGHT_CLKGEN_MIPI_CSI0_FPCLK 14
|
|
+#define LIGHT_CLKGEN_MIPI_CSI1_PCLK 15
|
|
+#define LIGHT_CLKGEN_MIPI_CSI1_FPCLK 16
|
|
+#define LIGHT_CLKGEN_MIPI_CSI2_PCLK 17
|
|
+#define LIGHT_CLKGEN_MIPI_CSI2_FPCLK 18
|
|
+#define LIGHT_CLKGEN_VIPRE_PCLK 19
|
|
+#define LIGHT_CLKGEN_VISYS_PCLK 20
|
|
+#define LIGHT_CLKGEN_VISYS_SYSREG_PCLK 21
|
|
+#define LIGHT_CLKGEN_ISP_VENC_SHAKE_PCLK 22
|
|
+#define LIGHT_CLKGEN_MIPI_CSI0_PIXCLK 23
|
|
+#define LIGHT_CLKGEN_MIPI_CSI1_PIXCLK 24
|
|
+#define LIGHT_CLKGEN_MIPI_CSI2_PIXCLK 25
|
|
+#define LIGHT_CLKGEN_VIPRE_PIXELCLK 26
|
|
+#define LIGHT_CLKGEN_ISP_PIXELCLK 27
|
|
+#define LIGHT_CLKGEN_MIPI_CSI0_CFG_CLK 28
|
|
+#define LIGHT_CLKGEN_MIPI_CSI1_CFG_CLK 29
|
|
+#define LIGHT_CLKGEN_MIPI_CSI2_CFG_CLK 30
|
|
+#define LIGHT_CLKGEN_DW200_CLK_VSE 31
|
|
+#define LIGHT_CLKGEN_DW200_CLK_DWE 32
|
|
+#define LIGHT_CLKGEN_ISP0_CLK 33
|
|
+#define LIGHT_CLKGEN_ISP1_CLK 34
|
|
+#define LIGHT_CLKGEN_ISP_RY_CCLK 35
|
|
+#define LIGHT_CLKGEN_MIPI_CSI_SCANBYTECLK 36
|
|
+#define LIGHT_CLKGEN_MIPI_CSI_SCANCLK 37
|
|
+#define LIGHT_CLKGEN_ISP1_PIXELCLK 38
|
|
+#define LIGHT_CLKGEN_ISP0_PIXELCLK 39
|
|
+#define LIGHT_CLKGEN_ISP1_HCLK 40
|
|
+#define LIGHT_CLKGEN_ISP0_HCLK 41
|
|
+#define LIGHT_CLKGEN_ISP1_ACLK 42
|
|
+#define LIGHT_CLKGEN_VISYS_CLK_END 43
|
|
+
|
|
+#endif
|
|
diff --git a/include/dt-bindings/clock/light-vosys.h b/include/dt-bindings/clock/light-vosys.h
|
|
new file mode 100644
|
|
index 000000000000..dbdd7fa7016b
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/light-vosys.h
|
|
@@ -0,0 +1,41 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#ifndef LIGHT_VOSYS_H
|
|
+#define LIGHT_VOSYS_H
|
|
+
|
|
+#define LIGHT_CLKGEN_AXI4_VO_PCLK 0
|
|
+#define LIGHT_CLKGEN_IOPMP_VOSYS_DPU_PCLK 1
|
|
+#define LIGHT_CLKGEN_IOPMP_VOSYS_DPU1_PCLK 2
|
|
+#define LIGHT_CLKGEN_IOPMP_VOSYS_GPU_PCLK 3
|
|
+#define LIGHT_CLKGEN_HDMI_PCLK 4
|
|
+#define LIGHT_CLKGEN_MIPIDSI0_PCLK 5
|
|
+#define LIGHT_CLKGEN_MIPIDSI1_PCLK 6
|
|
+#define LIGHT_CLKGEN_AXI4_VO_ACLK 7
|
|
+#define LIGHT_CLKGEN_IOPMP_GPU_ACLK 8
|
|
+#define LIGHT_CLKGEN_IOPMP_DPU_ACLK 9
|
|
+#define LIGHT_CLKGEN_IOPMP_DPU1_ACLK 10
|
|
+#define LIGHT_CLKGEN_X2H_DPU_ACLK 11
|
|
+#define LIGHT_CLKGEN_X2H_DPU1_ACLK 12
|
|
+#define LIGHT_CLKGEN_MIPIDSI0_PIXCLK 13
|
|
+#define LIGHT_CLKGEN_HDMI_PIXCLK 14
|
|
+#define LIGHT_CLKGEN_MIPIDSI1_PIXCLK 15
|
|
+#define LIGHT_CLKGEN_HDMI_SFR_CLK 16
|
|
+#define LIGHT_CLKGEN_HDMI_CEC_CLK 17
|
|
+#define LIGHT_CLKGEN_HDMI_I2S_CLK 18
|
|
+#define LIGHT_CLKGEN_MIPIDSI0_CFG_CLK 19
|
|
+#define LIGHT_CLKGEN_MIPIDSI1_CFG_CLK 20
|
|
+#define LIGHT_CLKGEN_MIPIDSI0_REFCLK 21
|
|
+#define LIGHT_CLKGEN_MIPIDSI1_REFCLK 22
|
|
+#define LIGHT_CLKGEN_GPU_CORE_CLK 23
|
|
+#define LIGHT_CLKGEN_GPU_CFG_ACLK 24
|
|
+#define LIGHT_CLKGEN_DPU_HCLK 25
|
|
+#define LIGHT_CLKGEN_DPU_ACLK 26
|
|
+#define LIGHT_CLKGEN_DPU_CCLK 27
|
|
+#define LIGHT_CLKGEN_DPU_PIXCLK0 28
|
|
+#define LIGHT_CLKGEN_DPU_PIXCLK1 29
|
|
+#define LIGHT_CLKGEN_VOSYS_CLK_END 30
|
|
+
|
|
+#endif
|
|
diff --git a/include/dt-bindings/clock/light-vpsys.h b/include/dt-bindings/clock/light-vpsys.h
|
|
new file mode 100644
|
|
index 000000000000..188aaa6cc435
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/light-vpsys.h
|
|
@@ -0,0 +1,24 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#ifndef _LIGHT_VPSYS_H
|
|
+#define _LIGHT_VPSYS_H
|
|
+
|
|
+#define LIGHT_VPSYS_G2D_PCLK 0
|
|
+#define LIGHT_VPSYS_G2D_ACLK 1
|
|
+#define LIGHT_VPSYS_G2D_CCLK 2
|
|
+#define LIGHT_VPSYS_FCE_PCLK 3
|
|
+#define LIGHT_VPSYS_FCE_ACLK 4
|
|
+#define LIGHT_VPSYS_VDEC_PCLK 5
|
|
+#define LIGHT_VPSYS_VDEC_ACLK 6
|
|
+#define LIGHT_VPSYS_VDEC_CCLK 7
|
|
+#define LIGHT_VPSYS_AXI_ACLK 8
|
|
+#define LIGHT_VPSYS_VENC_CCLK 9
|
|
+#define LIGHT_VPSYS_VENC_PCLK 10
|
|
+#define LIGHT_VPSYS_VENC_ACLK 11
|
|
+#define LIGHT_VPSYS_CLK_END 12
|
|
+
|
|
+#endif
|
|
+
|
|
diff --git a/include/dt-bindings/clock/sophgo-mango-clock.h b/include/dt-bindings/clock/sophgo-mango-clock.h
|
|
new file mode 100644
|
|
index 000000000000..aaed4ad27dc1
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/sophgo-mango-clock.h
|
|
@@ -0,0 +1,165 @@
|
|
+#ifndef __SOPHGO_MANGO_CLOCK__
|
|
+#define __SOPHGO_MANGO_CLOCK__
|
|
+
|
|
+#include <dt-bindings/clock/sophgo.h>
|
|
+
|
|
+/*div clock*/
|
|
+#define DIV_CLK_MPLL_RP_CPU_NORMAL_0 0
|
|
+#define DIV_CLK_MPLL_AXI_DDR_0 1
|
|
+#define DIV_CLK_FPLL_DDR01_1 2
|
|
+#define DIV_CLK_FPLL_DDR23_1 3
|
|
+#define DIV_CLK_FPLL_RP_CPU_NORMAL_1 4
|
|
+#define DIV_CLK_FPLL_50M_A53 5
|
|
+#define DIV_CLK_FPLL_TOP_RP_CMN_DIV2 6
|
|
+#define DIV_CLK_FPLL_UART_500M 7
|
|
+#define DIV_CLK_FPLL_AHB_LPC 8
|
|
+#define DIV_CLK_FPLL_EFUSE 9
|
|
+#define DIV_CLK_FPLL_TX_ETH0 10
|
|
+#define DIV_CLK_FPLL_PTP_REF_I_ETH0 11
|
|
+#define DIV_CLK_FPLL_REF_ETH0 12
|
|
+#define DIV_CLK_FPLL_EMMC 13
|
|
+#define DIV_CLK_FPLL_SD 14
|
|
+#define DIV_CLK_FPLL_TOP_AXI0 15
|
|
+#define DIV_CLK_FPLL_TOP_AXI_HSPERI 16
|
|
+#define DIV_CLK_FPLL_AXI_DDR_1 17
|
|
+#define DIV_CLK_FPLL_DIV_TIMER1 18
|
|
+#define DIV_CLK_FPLL_DIV_TIMER2 19
|
|
+#define DIV_CLK_FPLL_DIV_TIMER3 20
|
|
+#define DIV_CLK_FPLL_DIV_TIMER4 21
|
|
+#define DIV_CLK_FPLL_DIV_TIMER5 22
|
|
+#define DIV_CLK_FPLL_DIV_TIMER6 23
|
|
+#define DIV_CLK_FPLL_DIV_TIMER7 24
|
|
+#define DIV_CLK_FPLL_DIV_TIMER8 25
|
|
+#define DIV_CLK_FPLL_100K_EMMC 26
|
|
+#define DIV_CLK_FPLL_100K_SD 27
|
|
+#define DIV_CLK_FPLL_GPIO_DB 28
|
|
+#define DIV_CLK_DPLL0_DDR01_0 29
|
|
+#define DIV_CLK_DPLL1_DDR23_0 30
|
|
+
|
|
+/* MPLL */
|
|
+#define GATE_CLK_RP_CPU_NORMAL_DIV0 31
|
|
+#define GATE_CLK_AXI_DDR_DIV0 32
|
|
+
|
|
+/* FPLL */
|
|
+#define GATE_CLK_RP_CPU_NORMAL_DIV1 33
|
|
+#define GATE_CLK_A53_50M 34
|
|
+#define GATE_CLK_TOP_RP_CMN_DIV2 35
|
|
+#define GATE_CLK_HSDMA 36
|
|
+#define GATE_CLK_EMMC_100M 37
|
|
+#define GATE_CLK_SD_100M 38
|
|
+#define GATE_CLK_TX_ETH0 39
|
|
+#define GATE_CLK_PTP_REF_I_ETH0 40
|
|
+#define GATE_CLK_REF_ETH0 41
|
|
+#define GATE_CLK_UART_500M 42
|
|
+#define GATE_CLK_EFUSE 43
|
|
+
|
|
+#define GATE_CLK_AHB_LPC 44
|
|
+#define GATE_CLK_AHB_ROM 45
|
|
+#define GATE_CLK_AHB_SF 46
|
|
+
|
|
+#define GATE_CLK_APB_UART 47
|
|
+#define GATE_CLK_APB_TIMER 48
|
|
+#define GATE_CLK_APB_EFUSE 49
|
|
+#define GATE_CLK_APB_GPIO 50
|
|
+#define GATE_CLK_APB_GPIO_INTR 51
|
|
+#define GATE_CLK_APB_SPI 52
|
|
+#define GATE_CLK_APB_I2C 53
|
|
+#define GATE_CLK_APB_WDT 54
|
|
+#define GATE_CLK_APB_PWM 55
|
|
+#define GATE_CLK_APB_RTC 56
|
|
+
|
|
+#define GATE_CLK_AXI_PCIE0 57
|
|
+#define GATE_CLK_AXI_PCIE1 58
|
|
+#define GATE_CLK_SYSDMA_AXI 59
|
|
+#define GATE_CLK_AXI_DBG_I2C 60
|
|
+#define GATE_CLK_AXI_SRAM 61
|
|
+#define GATE_CLK_AXI_ETH0 62
|
|
+#define GATE_CLK_AXI_EMMC 63
|
|
+#define GATE_CLK_AXI_SD 64
|
|
+#define GATE_CLK_TOP_AXI0 65
|
|
+#define GATE_CLK_TOP_AXI_HSPERI 66
|
|
+
|
|
+#define GATE_CLK_TIMER1 67
|
|
+#define GATE_CLK_TIMER2 68
|
|
+#define GATE_CLK_TIMER3 69
|
|
+#define GATE_CLK_TIMER4 70
|
|
+#define GATE_CLK_TIMER5 71
|
|
+#define GATE_CLK_TIMER6 72
|
|
+#define GATE_CLK_TIMER7 73
|
|
+#define GATE_CLK_TIMER8 74
|
|
+#define GATE_CLK_100K_EMMC 75
|
|
+#define GATE_CLK_100K_SD 76
|
|
+#define GATE_CLK_GPIO_DB 77
|
|
+
|
|
+#define GATE_CLK_AXI_DDR_DIV1 78
|
|
+#define GATE_CLK_DDR01_DIV1 79
|
|
+#define GATE_CLK_DDR23_DIV1 80
|
|
+/* DPLL0 */
|
|
+#define GATE_CLK_DDR01_DIV0 81
|
|
+/* DPLL1 */
|
|
+#define GATE_CLK_DDR23_DIV0 82
|
|
+
|
|
+#define GATE_CLK_DDR01 83
|
|
+#define GATE_CLK_DDR23 84
|
|
+#define GATE_CLK_RP_CPU_NORMAL 85
|
|
+#define GATE_CLK_AXI_DDR 86
|
|
+#define GATE_CLK_RXU0 87
|
|
+#define GATE_CLK_RXU1 88
|
|
+#define GATE_CLK_RXU2 89
|
|
+#define GATE_CLK_RXU3 90
|
|
+#define GATE_CLK_RXU4 91
|
|
+#define GATE_CLK_RXU5 92
|
|
+#define GATE_CLK_RXU6 93
|
|
+#define GATE_CLK_RXU7 94
|
|
+#define GATE_CLK_RXU8 95
|
|
+#define GATE_CLK_RXU9 96
|
|
+#define GATE_CLK_RXU10 97
|
|
+#define GATE_CLK_RXU11 98
|
|
+#define GATE_CLK_RXU12 99
|
|
+#define GATE_CLK_RXU13 100
|
|
+#define GATE_CLK_RXU14 101
|
|
+#define GATE_CLK_RXU15 102
|
|
+#define GATE_CLK_RXU16 103
|
|
+#define GATE_CLK_RXU17 104
|
|
+#define GATE_CLK_RXU18 105
|
|
+#define GATE_CLK_RXU19 106
|
|
+#define GATE_CLK_RXU20 107
|
|
+#define GATE_CLK_RXU21 108
|
|
+#define GATE_CLK_RXU22 109
|
|
+#define GATE_CLK_RXU23 110
|
|
+#define GATE_CLK_RXU24 111
|
|
+#define GATE_CLK_RXU25 112
|
|
+#define GATE_CLK_RXU26 113
|
|
+#define GATE_CLK_RXU27 114
|
|
+#define GATE_CLK_RXU28 115
|
|
+#define GATE_CLK_RXU29 116
|
|
+#define GATE_CLK_RXU30 117
|
|
+#define GATE_CLK_RXU31 118
|
|
+#define GATE_CLK_MP0 119
|
|
+#define GATE_CLK_MP1 120
|
|
+#define GATE_CLK_MP2 121
|
|
+#define GATE_CLK_MP3 122
|
|
+#define GATE_CLK_MP4 123
|
|
+#define GATE_CLK_MP5 124
|
|
+#define GATE_CLK_MP6 125
|
|
+#define GATE_CLK_MP7 126
|
|
+#define GATE_CLK_MP8 127
|
|
+#define GATE_CLK_MP9 128
|
|
+#define GATE_CLK_MP10 129
|
|
+#define GATE_CLK_MP11 130
|
|
+#define GATE_CLK_MP12 131
|
|
+#define GATE_CLK_MP13 132
|
|
+#define GATE_CLK_MP14 133
|
|
+#define GATE_CLK_MP15 134
|
|
+
|
|
+/* MUX */
|
|
+#define MUX_CLK_DDR01 0
|
|
+#define MUX_CLK_DDR23 1
|
|
+#define MUX_CLK_RP_CPU_NORMAL 2
|
|
+#define MUX_CLK_AXI_DDR 3
|
|
+
|
|
+#define S0_DIV_CLK_TABLE 0
|
|
+#define S1_DIV_CLK_TABLE 1
|
|
+#define S0_MUX_CLK_TABLE 2
|
|
+#define S1_MUX_CLK_TABLE 3
|
|
+#endif
|
|
diff --git a/include/dt-bindings/clock/sophgo.h b/include/dt-bindings/clock/sophgo.h
|
|
new file mode 100644
|
|
index 000000000000..5584243f9135
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/clock/sophgo.h
|
|
@@ -0,0 +1,15 @@
|
|
+#ifndef __SOPHGO_CLK__
|
|
+#define __SOPHGO_CLK__
|
|
+
|
|
+//PLL ID
|
|
+#define MPLL_CLK 0
|
|
+#define FPLL_CLK 3
|
|
+#define DPLL0_CLK 4
|
|
+#define DPLL1_CLK 5
|
|
+
|
|
+//clock mode
|
|
+#define NORMAL_MODE 0
|
|
+#define FAST_MODE 1
|
|
+#define SAFE_MODE 2
|
|
+#define BYPASS_MODE 3
|
|
+#endif
|
|
diff --git a/include/dt-bindings/firmware/thead/rsrc.h b/include/dt-bindings/firmware/thead/rsrc.h
|
|
new file mode 100644
|
|
index 000000000000..8cee0fcaeb74
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/firmware/thead/rsrc.h
|
|
@@ -0,0 +1,17 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#ifndef __DT_BINDINGS_RSCRC_LIGHT_H
|
|
+#define __DT_BINDINGS_RSCRC_LIGHT_H
|
|
+
|
|
+#define LIGHT_AON_AUDIO_PD 0
|
|
+#define LIGHT_AON_VDEC_PD 1
|
|
+#define LIGHT_AON_NPU_PD 2
|
|
+#define LIGHT_AON_VENC_PD 3
|
|
+#define LIGHT_AON_GPU_PD 4
|
|
+#define LIGHT_AON_DSP0_PD 5
|
|
+#define LIGHT_AON_DSP1_PD 6
|
|
+
|
|
+#endif
|
|
diff --git a/include/dt-bindings/reset/sophgo-mango-resets.h b/include/dt-bindings/reset/sophgo-mango-resets.h
|
|
new file mode 100644
|
|
index 000000000000..9ff8ca4c3d67
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/reset/sophgo-mango-resets.h
|
|
@@ -0,0 +1,96 @@
|
|
+/*
|
|
+ * Sophgo SoCs Reset definitions
|
|
+ *
|
|
+ * Copyright (c) 2018 Bitmain Ltd.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#ifndef _DT_BINDINGS_RST_MANGO_H_
|
|
+#define _DT_BINDINGS_RST_MANGO_H_
|
|
+
|
|
+#define RST_MAIN_AP 0
|
|
+#define RST_RISCV_CPU 1
|
|
+#define RST_RISCV_LOW_SPEED_LOGIC 2
|
|
+#define RST_RISCV_CMN 3
|
|
+#define RST_HSDMA 4
|
|
+#define RST_SYSDMA 5
|
|
+#define RST_EFUSE0 6
|
|
+#define RST_EFUSE1 7
|
|
+#define RST_RTC 8
|
|
+#define RST_TIMER 9
|
|
+#define RST_WDT 10
|
|
+#define RST_AHB_ROM0 11
|
|
+#define RST_AHB_ROM1 12
|
|
+#define RST_I2C0 13
|
|
+#define RST_I2C1 14
|
|
+#define RST_I2C2 15
|
|
+#define RST_I2C3 16
|
|
+#define RST_GPIO0 17
|
|
+#define RST_GPIO1 18
|
|
+#define RST_GPIO2 19
|
|
+#define RST_PWM 20
|
|
+#define RST_AXI_SRAM0 21
|
|
+#define RST_AXI_SRAM1 22
|
|
+#define RST_SF0 23
|
|
+#define RST_SF1 24
|
|
+#define RST_LPC 25
|
|
+#define RST_ETH0 26
|
|
+#define RST_EMMC 27
|
|
+#define RST_SD 28
|
|
+#define RST_UART0 29
|
|
+#define RST_UART1 30
|
|
+#define RST_UART2 31
|
|
+
|
|
+#define RST_UART3 32
|
|
+#define RST_SPI0 33
|
|
+#define RST_SPI1 34
|
|
+#define RST_DBG_I2C 35
|
|
+#define RST_PCIE0 36
|
|
+#define RST_PCIE1 37
|
|
+#define RST_DDR0 38
|
|
+#define RST_DDR1 39
|
|
+#define RST_DDR2 40
|
|
+#define RST_DDR3 41
|
|
+#define RST_FAU0 42
|
|
+#define RST_FAU1 43
|
|
+#define RST_FAU2 44
|
|
+#define RST_RXU0 45
|
|
+#define RST_RXU1 46
|
|
+#define RST_RXU2 47
|
|
+#define RST_RXU3 48
|
|
+#define RST_RXU4 49
|
|
+#define RST_RXU5 50
|
|
+#define RST_RXU6 51
|
|
+#define RST_RXU7 52
|
|
+#define RST_RXU8 53
|
|
+#define RST_RXU9 54
|
|
+#define RST_RXU10 55
|
|
+#define RST_RXU11 56
|
|
+#define RST_RXU12 57
|
|
+#define RST_RXU13 58
|
|
+#define RST_RXU14 59
|
|
+#define RST_RXU15 60
|
|
+#define RST_RXU16 61
|
|
+#define RST_RXU17 62
|
|
+#define RST_RXU18 63
|
|
+#define RST_RXU19 64
|
|
+#define RST_RXU20 65
|
|
+#define RST_RXU21 66
|
|
+#define RST_RXU22 67
|
|
+#define RST_RXU23 68
|
|
+#define RST_RXU24 69
|
|
+#define RST_RXU25 70
|
|
+#define RST_RXU26 71
|
|
+#define RST_RXU27 72
|
|
+#define RST_RXU28 73
|
|
+#define RST_RXU29 74
|
|
+#define RST_RXU30 75
|
|
+#define RST_RXU31 76
|
|
+
|
|
+#define RST_MAX_NUM (RST_RXU31+1)
|
|
+
|
|
+#endif
|
|
diff --git a/include/dt-bindings/reset/thead,th1520-reset.h b/include/dt-bindings/reset/thead,th1520-reset.h
|
|
new file mode 100644
|
|
index 000000000000..ec10751814e5
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/reset/thead,th1520-reset.h
|
|
@@ -0,0 +1,9 @@
|
|
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
|
|
+
|
|
+#ifndef DT_BINDING_RESET_TH1520_H
|
|
+#define DT_BINDING_RESET_TH1520_H
|
|
+
|
|
+#define TH1520_RESET_WDT0 0
|
|
+#define TH1520_RESET_WDT1 1
|
|
+
|
|
+#endif
|
|
diff --git a/include/linux/firmware/thead/ipc.h b/include/linux/firmware/thead/ipc.h
|
|
new file mode 100644
|
|
index 000000000000..dfda60e76725
|
|
--- /dev/null
|
|
+++ b/include/linux/firmware/thead/ipc.h
|
|
@@ -0,0 +1,74 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+#ifndef _SC_IPC_H
|
|
+#define _SC_IPC_H
|
|
+
|
|
+#include <linux/device.h>
|
|
+#include <linux/types.h>
|
|
+
|
|
+#define AON_RPC_MSG_MAGIC (0xef)
|
|
+#define LIGHT_AON_RPC_VERSION 1
|
|
+#define LIGHT_AON_RPC_MSG_NUM 7
|
|
+
|
|
+struct light_aon_ipc;
|
|
+
|
|
+enum light_aon_rpc_svc {
|
|
+ LIGHT_AON_RPC_SVC_UNKNOWN = 0,
|
|
+ LIGHT_AON_RPC_SVC_RETURN = 1,
|
|
+ LIGHT_AON_RPC_SVC_PM = 2,
|
|
+ LIGHT_AON_RPC_SVC_MISC = 3,
|
|
+ LIGHT_AON_RPC_SVC_AVFS = 4,
|
|
+};
|
|
+
|
|
+enum light_aon_misc_func {
|
|
+ LIGHT_AON_MISC_FUNC_UNKNOWN = 0,
|
|
+ LIGHT_AON_MISC_FUNC_SET_CONTROL = 1,
|
|
+ LIGHT_AON_MISC_FUNC_GET_CONTROL = 2,
|
|
+ LIGHT_AON_MISC_FUNC_WDG_START = 3,
|
|
+ LIGHT_AON_MISC_FUNC_WDG_STOP = 4,
|
|
+ LIGHT_AON_MISC_FUNC_WDG_PING = 5,
|
|
+ LIGHT_AON_MISC_FUNC_WDG_TIMEOUTSET = 6,
|
|
+ LIGHT_AON_MISC_FUNC_WDG_RESTART = 7,
|
|
+ LIGHT_AON_MISC_FUNC_WDG_GET_STATE = 8,
|
|
+ LIGHT_AON_MISC_FUNC_WDG_POWER_OFF = 9,
|
|
+ LIGHT_AON_MISC_FUNC_AON_WDT_ON = 10,
|
|
+ LIGHT_AON_MISC_FUNC_AON_WDT_OFF = 11,
|
|
+ LIGHT_AON_MISC_FUNC_AON_RESERVE_MEM = 12,
|
|
+ LIGHT_AON_MISC_FUNC_REQUIRE_STR = 13,
|
|
+ LIGHT_AON_MISC_FUNC_RESUME_STR = 14,
|
|
+ LIGHT_AON_MISC_FUNC_REQUIRE_STD = 15,
|
|
+ LIGHT_AON_MISC_FUNC_CPUHP = 16,
|
|
+};
|
|
+
|
|
+enum light_aon_pm_func {
|
|
+ LIGHT_AON_PM_FUNC_UNKNOWN = 0,
|
|
+ LIGHT_AON_PM_FUNC_SET_RESOURCE_REGULATOR = 1,
|
|
+ LIGHT_AON_PM_FUNC_GET_RESOURCE_REGULATOR = 2,
|
|
+ LIGHT_AON_PM_FUNC_SET_RESOURCE_POWER_MODE = 3,
|
|
+ LIGHT_AON_PM_FUNC_PWR_SET = 4,
|
|
+ LIGHT_AON_PM_FUNC_PWR_GET = 5,
|
|
+};
|
|
+
|
|
+struct light_aon_rpc_msg_hdr {
|
|
+ uint8_t ver; ///< version of msg hdr
|
|
+ uint8_t size; ///< msg size ,uinit in bytes,the size includes rpc msg header self.
|
|
+ uint8_t svc; ///< rpc main service id
|
|
+ uint8_t func; ///< rpc sub func id of specific service, sent by caller
|
|
+} __packed __aligned(4);
|
|
+
|
|
+/*
|
|
+ * Defines for SC PM Power Mode
|
|
+ */
|
|
+#define LIGHT_AON_PM_PW_MODE_OFF 0 /* Power off */
|
|
+#define LIGHT_AON_PM_PW_MODE_STBY 1 /* Power in standby */
|
|
+#define LIGHT_AON_PM_PW_MODE_LP 2 /* Power in low-power */
|
|
+#define LIGHT_AON_PM_PW_MODE_ON 3 /* Power on */
|
|
+
|
|
+int light_aon_call_rpc(struct light_aon_ipc *ipc, void *msg, bool have_resp);
|
|
+int light_aon_get_handle(struct light_aon_ipc **ipc);
|
|
+int light_aon_misc_set_control(struct light_aon_ipc *ipc, u16 resource, u32 ctrl, u32 val);
|
|
+int light_aon_misc_get_control(struct light_aon_ipc *ipc, u16 resource, u32 ctrl, u32 *val);
|
|
+#endif /* _SC_IPC_H */
|
|
diff --git a/include/linux/firmware/thead/light_event.h b/include/linux/firmware/thead/light_event.h
|
|
new file mode 100644
|
|
index 000000000000..a4f99d41c2d1
|
|
--- /dev/null
|
|
+++ b/include/linux/firmware/thead/light_event.h
|
|
@@ -0,0 +1,35 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
|
+#ifndef _LIGHT_EVENT_H
|
|
+#define _LIGHT_EVENT_H
|
|
+
|
|
+enum light_rebootmode_index {
|
|
+ /* C902 event rebootmode */
|
|
+ LIGHT_EVENT_PMIC_RESET = 0x0,
|
|
+ LIGHT_EVENT_PMIC_ONKEY,
|
|
+ LIGHT_EVENT_PMIC_POWERUP,
|
|
+
|
|
+ /* C910 event rebootmode */
|
|
+ LIGHT_EVENT_SW_REBOOT = 0x20,
|
|
+ LIGHT_EVENT_SW_WATCHDOG,
|
|
+ LIGHT_EVENT_SW_PANIC,
|
|
+ LIGHT_EVENT_SW_HANG,
|
|
+ LIGHT_EVENT_MAX,
|
|
+};
|
|
+
|
|
+#if IS_ENABLED(CONFIG_LIGHT_REBOOTMODE)
|
|
+extern int light_event_set_rebootmode(enum light_rebootmode_index mode);
|
|
+extern int light_event_get_rebootmode(enum light_rebootmode_index *mode);
|
|
+#else
|
|
+static int light_event_set_rebootmode(enum light_rebootmode_index mode)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+static int light_event_get_rebootmode(enum light_rebootmode_index *mode)
|
|
+{
|
|
+ *mode = LIGHT_EVENT_MAX;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif
|
|
diff --git a/include/linux/light_rpmsg.h b/include/linux/light_rpmsg.h
|
|
new file mode 100644
|
|
index 000000000000..8930845604a0
|
|
--- /dev/null
|
|
+++ b/include/linux/light_rpmsg.h
|
|
@@ -0,0 +1,92 @@
|
|
+/*
|
|
+ * Copyright (C) 2023 Alibaba Group Holding Limited.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * The code contained herein is licensed under the GNU Lesser General
|
|
+ * Public License. You may obtain a copy of the GNU Lesser General
|
|
+ * Public License Version 2.1 or later at the following locations:
|
|
+ *
|
|
+ * http://www.opensource.org/licenses/lgpl-license.html
|
|
+ * http://www.gnu.org/copyleft/lgpl.html
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * @file linux/light_rpmsg.h
|
|
+ *
|
|
+ * @brief Global header file for imx RPMSG
|
|
+ *
|
|
+ * @ingroup RPMSG
|
|
+ */
|
|
+#ifndef __LINUX_LIGHT_RPMSG_H__
|
|
+#define __LINUX_LIGHT_RPMSG_H__
|
|
+
|
|
+#include <linux/rpmsg.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/virtio.h>
|
|
+#include <linux/virtio_config.h>
|
|
+#include <linux/virtio_ids.h>
|
|
+#include <linux/virtio_ring.h>
|
|
+
|
|
+/* Category define */
|
|
+#define LIGHT_RMPSG_LIFECYCLE 1
|
|
+#define LIGHT_RPMSG_PMIC 2
|
|
+#define LIGHT_RPMSG_AUDIO 3
|
|
+#define LIGHT_RPMSG_KEY 4
|
|
+#define LIGHT_RPMSG_GPIO 5
|
|
+#define LIGHT_RPMSG_RTC 6
|
|
+#define LIGHT_RPMSG_SENSOR 7
|
|
+/* rpmsg version */
|
|
+#define LIGHT_RMPSG_MAJOR 1
|
|
+#define LIGHT_RMPSG_MINOR 0
|
|
+
|
|
+enum light_rpmsg_variants {
|
|
+ LIGHTA,
|
|
+ LIGHTB,
|
|
+ LIGHT_RPMSG,
|
|
+};
|
|
+
|
|
+struct light_virdev {
|
|
+ struct virtio_device vdev;
|
|
+ unsigned int 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 <linux/context_tracking.h>
|
|
#include <trace/events/error_report.h>
|
|
#include <asm/sections.h>
|
|
+#include <linux/firmware/thead/light_event.h>
|
|
|
|
#define PANIC_TIMER_STEP 100
|
|
#define PANIC_BLINK_SPD 18
|
|
@@ -281,6 +282,11 @@ void panic(const char *fmt, ...)
|
|
int state = 0;
|
|
int old_cpu, this_cpu;
|
|
bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers;
|
|
+ enum light_rebootmode_index mode;
|
|
+
|
|
+ if (!light_event_get_rebootmode(&mode) &&
|
|
+ mode != LIGHT_EVENT_SW_WATCHDOG)
|
|
+ light_event_set_rebootmode(LIGHT_EVENT_SW_PANIC);
|
|
|
|
if (panic_on_warn) {
|
|
/*
|
|
diff --git a/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
|
|
|