summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--0001-riscv-kernel.patch33850
-rw-r--r--0002-cpupower-clang-compile-support.patch49
-rw-r--r--0003-x86_energy_perf_policy-clang-compile-support.patch24
-rw-r--r--0004-turbostat-clang-compile-support.patch24
-rw-r--r--0005-haoc-kernel.patch13472
-rw-r--r--cpupower.config3
-rw-r--r--cpupower.service13
-rw-r--r--haoc-kernel.spec10943
-rw-r--r--mkgrub-menu-aarch64.sh98
-rw-r--r--sign-modules25
-rw-r--r--sources2
-rw-r--r--x509.genkey16
13 files changed, 58521 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..fe53b91 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/extra_certificates
+/kernel.tar.xz
diff --git a/0001-riscv-kernel.patch b/0001-riscv-kernel.patch
new file mode 100644
index 0000000..33cbd32
--- /dev/null
+++ b/0001-riscv-kernel.patch
@@ -0,0 +1,33850 @@
+From 9d1e1ac5c1d745bc8108246848152902fd539f26 Mon Sep 17 00:00:00 2001
+From: Mingzheng Xing <xingmingzheng@iscas.ac.cn>
+Date: Wed, 5 Jun 2024 22:39:47 +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 | 175 ++-
+ arch/riscv/mm/pageattr.c | 275 +---
+ drivers/base/arch_numa.c | 4 +
+ drivers/char/ipmi/ipmi_si_hardcode.c | 26 +-
+ drivers/char/ipmi/ipmi_si_intf.c | 3 +-
+ drivers/char/ipmi/ipmi_si_pci.c | 6 +
+ drivers/clk/Kconfig | 1 +
+ drivers/clk/Makefile | 2 +
+ drivers/clk/sophgo/Makefile | 3 +
+ drivers/clk/sophgo/clk-dummy.c | 600 +++++++++
+ drivers/clk/sophgo/clk-mango.c | 977 ++++++++++++++
+ drivers/clk/sophgo/clk.c | 883 +++++++++++++
+ drivers/clk/sophgo/clk.h | 152 +++
+ drivers/clk/thead/Kconfig | 19 +
+ drivers/clk/thead/Makefile | 8 +
+ drivers/clk/thead/clk-light-fm.c | 646 +++++++++
+ drivers/clk/thead/clk-light-mpw.c | 492 +++++++
+ drivers/clk/thead/clk.c | 739 +++++++++++
+ drivers/clk/thead/clk.h | 117 ++
+ drivers/clk/thead/gate/Makefile | 3 +
+ drivers/clk/thead/gate/clk-gate.h | 35 +
+ drivers/clk/thead/gate/dspsys-gate.c | 109 ++
+ drivers/clk/thead/gate/thead-gate.c | 114 ++
+ drivers/clk/thead/gate/visys-gate.c | 144 +++
+ drivers/clk/thead/gate/vosys-gate.c | 111 ++
+ drivers/clk/thead/gate/vpsys-gate.c | 94 ++
+ drivers/clocksource/dw_apb_timer_of.c | 24 +
+ drivers/cpufreq/Kconfig | 10 +
+ drivers/cpufreq/Makefile | 1 +
+ drivers/cpufreq/light-mpw-cpufreq.c | 491 +++++++
+ drivers/firmware/Kconfig | 1 +
+ drivers/firmware/Makefile | 1 +
+ drivers/firmware/thead/Kconfig | 18 +
+ drivers/firmware/thead/Makefile | 3 +
+ drivers/firmware/thead/light_aon.c | 261 ++++
+ drivers/firmware/thead/light_aon_misc.c | 74 ++
+ drivers/firmware/thead/light_aon_pd.c | 417 ++++++
+ drivers/firmware/thead/light_aon_test.c | 163 +++
+ drivers/gpio/gpio-dwapb.c | 15 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 +
+ drivers/gpu/drm/amd/display/Kconfig | 1 +
+ .../gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 6 +-
+ drivers/gpu/drm/amd/display/dc/dml/Makefile | 6 +
+ drivers/gpu/drm/drm_gem_vram_helper.c | 2 +-
+ drivers/gpu/drm/radeon/radeon_drv.c | 7 +-
+ drivers/gpu/drm/radeon/radeon_irq_kms.c | 2 +
+ drivers/gpu/drm/ttm/ttm_bo_util.c | 5 +-
+ drivers/gpu/drm/ttm/ttm_module.c | 3 +-
+ drivers/gpu/drm/ttm/ttm_resource.c | 7 +-
+ drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
+ drivers/mailbox/Kconfig | 8 +
+ drivers/mailbox/Makefile | 3 +
+ drivers/mailbox/light-mailbox-client.c | 242 ++++
+ drivers/mailbox/light-mailbox.c | 507 ++++++++
+ drivers/mmc/host/Kconfig | 14 +
+ drivers/mmc/host/Makefile | 1 +
+ drivers/mmc/host/sdhci-of-dwcmshc.c | 349 +++++
+ drivers/mmc/host/sdhci-sophgo.c | 619 +++++++++
+ drivers/mmc/host/sdhci-sophgo.h | 121 ++
+ drivers/mmc/host/sdhci.c | 12 +-
+ drivers/mmc/host/sdhci.h | 4 +
+ drivers/mtd/spi-nor/controllers/Kconfig | 11 +
+ drivers/mtd/spi-nor/controllers/Makefile | 1 +
+ .../mtd/spi-nor/controllers/sophgo-spifmc.c | 445 +++++++
+ drivers/mtd/spi-nor/gigadevice.c | 14 +
+ drivers/net/ethernet/intel/i40e/i40e_common.c | 3 +-
+ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 2 +-
+ drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 +
+ drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +
+ .../ethernet/stmicro/stmmac/dwmac-sophgo.c | 268 ++++
+ .../net/ethernet/stmicro/stmmac/dwmac-thead.c | 289 +++++
+ drivers/pci/controller/cadence/Kconfig | 11 +
+ drivers/pci/controller/cadence/Makefile | 1 +
+ .../controller/cadence/pcie-cadence-sophgo.c | 972 ++++++++++++++
+ .../controller/cadence/pcie-cadence-sophgo.h | 17 +
+ drivers/pci/msi/msi.c | 97 +-
+ drivers/pci/pcie/portdrv.c | 2 +-
+ drivers/pinctrl/Kconfig | 11 +-
+ drivers/pinctrl/Makefile | 2 +
+ drivers/pinctrl/pinctrl-th1520.c | 860 ++++++++++++
+ drivers/pinctrl/sophgo/Makefile | 2 +
+ drivers/pinctrl/sophgo/pinctrl-mango.c | 453 +++++++
+ drivers/pinctrl/sophgo/pinctrl-sophgo.c | 292 +++++
+ drivers/pinctrl/sophgo/pinctrl-sophgo.h | 70 +
+ drivers/pwm/Kconfig | 11 +
+ drivers/pwm/Makefile | 2 +
+ drivers/pwm/pwm-sophgo.c | 276 ++++
+ drivers/pwm/pwm-thead.c | 269 ++++
+ drivers/regulator/Kconfig | 9 +
+ drivers/regulator/Makefile | 1 +
+ drivers/regulator/light-regulator-aon.c | 888 +++++++++++++
+ drivers/reset/Kconfig | 10 +
+ drivers/reset/Makefile | 2 +
+ drivers/reset/reset-sophgo.c | 163 +++
+ drivers/reset/reset-th1520.c | 109 ++
+ drivers/rpmsg/Kconfig | 4 +
+ drivers/rpmsg/Makefile | 1 +
+ drivers/rpmsg/light_rpmsg.c | 864 +++++++++++++
+ drivers/rtc/Kconfig | 6 +
+ drivers/rtc/Makefile | 1 +
+ drivers/rtc/rtc-astbmc.c | 535 ++++++++
+ drivers/soc/Kconfig | 1 +
+ drivers/soc/Makefile | 2 +
+ drivers/soc/sophgo/Makefile | 3 +
+ drivers/soc/sophgo/tach/sophgo-tach.c | 330 +++++
+ drivers/soc/sophgo/top/top_intc.c | 412 ++++++
+ drivers/soc/sophgo/umcu/mcu.c | 1144 ++++++++++++++++
+ drivers/soc/thead/Kconfig | 10 +
+ drivers/soc/thead/Makefile | 2 +
+ drivers/soc/thead/light_event.c | 279 ++++
+ drivers/usb/dwc3/Kconfig | 20 +
+ drivers/usb/dwc3/Makefile | 2 +
+ drivers/usb/dwc3/dwc3-thead.c | 112 ++
+ drivers/watchdog/Kconfig | 14 +
+ drivers/watchdog/Makefile | 1 +
+ drivers/watchdog/light_wdt.c | 376 ++++++
+ include/dt-bindings/clock/light-dspsys.h | 25 +
+ include/dt-bindings/clock/light-fm-ap-clock.h | 513 ++++++++
+ include/dt-bindings/clock/light-mpw-clock.h | 222 ++++
+ include/dt-bindings/clock/light-visys.h | 54 +
+ include/dt-bindings/clock/light-vosys.h | 41 +
+ include/dt-bindings/clock/light-vpsys.h | 24 +
+ .../dt-bindings/clock/sophgo-mango-clock.h | 165 +++
+ include/dt-bindings/clock/sophgo.h | 15 +
+ include/dt-bindings/firmware/thead/rsrc.h | 17 +
+ .../dt-bindings/reset/sophgo-mango-resets.h | 96 ++
+ .../dt-bindings/reset/thead,th1520-reset.h | 9 +
+ include/linux/firmware/thead/ipc.h | 74 ++
+ include/linux/firmware/thead/light_event.h | 35 +
+ include/linux/light_rpmsg.h | 92 ++
+ kernel/kexec_core.c | 2 +-
+ kernel/panic.c | 6 +
+ kernel/sched/fair.c | 3 +
+ kernel/time/tick-oneshot.c | 2 +-
+ mm/memblock.c | 28 +-
+ scripts/package/builddeb | 2 +-
+ sound/pci/hda/hda_intel.c | 5 +-
+ tools/lib/perf/cpumap.c | 10 +-
+ tools/perf/pmu-events/arch/riscv/mapfile.csv | 1 +
+ .../arch/riscv/thead/c900-legacy/cache.json | 67 +
+ .../riscv/thead/c900-legacy/firmware.json | 68 +
+ .../riscv/thead/c900-legacy/instruction.json | 72 ++
+ .../riscv/thead/c900-legacy/microarch.json | 80 ++
+ 211 files changed, 29953 insertions(+), 500 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/net/thead,dwmac.yaml
+ create mode 100644 Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml
+ create mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml
+ create mode 100644 Documentation/devicetree/bindings/reset/thead,th1520-reset.yaml
+ create mode 100644 Documentation/devicetree/bindings/usb/thead,th1520-usb.yaml
+ create mode 100644 arch/riscv/Makefile.isa
+ create mode 100644 arch/riscv/boot/dts/sophgo/Makefile
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-2sockets.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-clock-socket0.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-clock-socket1.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-cpus-socket0.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-cpus-socket1.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-milkv-pioneer.dts
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-2rc.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-3rc-capricorn.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-3rc-v2.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-3rc.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-4rc-v2.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-pcie-4rc.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-pinctrl.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-capricorn.dts
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-pisces.dts
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-x4evb.dts
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-sophgo-x8evb.dts
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-top-intc2.dtsi
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango-yixin-s2110.dts
+ create mode 100644 arch/riscv/boot/dts/sophgo/mango.dtsi
+ create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a-16g.dts
+ create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-cluster-4a.dts
+ create mode 100644 arch/riscv/boot/dts/thead/th1520-lichee-pi-4a-16g.dts
+ create mode 100644 arch/riscv/boot/dts/thead/th1520-milkv-meles-4g.dts
+ create mode 100644 arch/riscv/boot/dts/thead/th1520-milkv-meles.dts
+ create mode 100644 arch/riscv/include/asm/highmem.h
+ create mode 100644 arch/riscv/kernel/image_kexec.c
+ create mode 100644 drivers/clk/sophgo/Makefile
+ create mode 100644 drivers/clk/sophgo/clk-dummy.c
+ create mode 100644 drivers/clk/sophgo/clk-mango.c
+ create mode 100644 drivers/clk/sophgo/clk.c
+ create mode 100644 drivers/clk/sophgo/clk.h
+ create mode 100644 drivers/clk/thead/Kconfig
+ create mode 100644 drivers/clk/thead/Makefile
+ create mode 100644 drivers/clk/thead/clk-light-fm.c
+ create mode 100644 drivers/clk/thead/clk-light-mpw.c
+ create mode 100644 drivers/clk/thead/clk.c
+ create mode 100644 drivers/clk/thead/clk.h
+ create mode 100644 drivers/clk/thead/gate/Makefile
+ create mode 100644 drivers/clk/thead/gate/clk-gate.h
+ create mode 100644 drivers/clk/thead/gate/dspsys-gate.c
+ create mode 100644 drivers/clk/thead/gate/thead-gate.c
+ create mode 100644 drivers/clk/thead/gate/visys-gate.c
+ create mode 100644 drivers/clk/thead/gate/vosys-gate.c
+ create mode 100644 drivers/clk/thead/gate/vpsys-gate.c
+ create mode 100644 drivers/cpufreq/light-mpw-cpufreq.c
+ create mode 100644 drivers/firmware/thead/Kconfig
+ create mode 100644 drivers/firmware/thead/Makefile
+ create mode 100644 drivers/firmware/thead/light_aon.c
+ create mode 100644 drivers/firmware/thead/light_aon_misc.c
+ create mode 100644 drivers/firmware/thead/light_aon_pd.c
+ create mode 100644 drivers/firmware/thead/light_aon_test.c
+ create mode 100644 drivers/mailbox/light-mailbox-client.c
+ create mode 100644 drivers/mailbox/light-mailbox.c
+ create mode 100644 drivers/mmc/host/sdhci-sophgo.c
+ create mode 100644 drivers/mmc/host/sdhci-sophgo.h
+ create mode 100644 drivers/mtd/spi-nor/controllers/sophgo-spifmc.c
+ create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c
+ create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
+ create mode 100644 drivers/pci/controller/cadence/pcie-cadence-sophgo.c
+ create mode 100644 drivers/pci/controller/cadence/pcie-cadence-sophgo.h
+ create mode 100644 drivers/pinctrl/pinctrl-th1520.c
+ create mode 100644 drivers/pinctrl/sophgo/Makefile
+ create mode 100644 drivers/pinctrl/sophgo/pinctrl-mango.c
+ create mode 100644 drivers/pinctrl/sophgo/pinctrl-sophgo.c
+ create mode 100644 drivers/pinctrl/sophgo/pinctrl-sophgo.h
+ create mode 100644 drivers/pwm/pwm-sophgo.c
+ create mode 100644 drivers/pwm/pwm-thead.c
+ create mode 100644 drivers/regulator/light-regulator-aon.c
+ create mode 100644 drivers/reset/reset-sophgo.c
+ create mode 100644 drivers/reset/reset-th1520.c
+ create mode 100644 drivers/rpmsg/light_rpmsg.c
+ create mode 100644 drivers/rtc/rtc-astbmc.c
+ create mode 100644 drivers/soc/sophgo/Makefile
+ create mode 100644 drivers/soc/sophgo/tach/sophgo-tach.c
+ create mode 100644 drivers/soc/sophgo/top/top_intc.c
+ create mode 100644 drivers/soc/sophgo/umcu/mcu.c
+ create mode 100644 drivers/soc/thead/Kconfig
+ create mode 100644 drivers/soc/thead/Makefile
+ create mode 100644 drivers/soc/thead/light_event.c
+ create mode 100644 drivers/usb/dwc3/dwc3-thead.c
+ create mode 100644 drivers/watchdog/light_wdt.c
+ create mode 100644 include/dt-bindings/clock/light-dspsys.h
+ create mode 100644 include/dt-bindings/clock/light-fm-ap-clock.h
+ create mode 100644 include/dt-bindings/clock/light-mpw-clock.h
+ create mode 100644 include/dt-bindings/clock/light-visys.h
+ create mode 100644 include/dt-bindings/clock/light-vosys.h
+ create mode 100644 include/dt-bindings/clock/light-vpsys.h
+ create mode 100644 include/dt-bindings/clock/sophgo-mango-clock.h
+ create mode 100644 include/dt-bindings/clock/sophgo.h
+ create mode 100644 include/dt-bindings/firmware/thead/rsrc.h
+ create mode 100644 include/dt-bindings/reset/sophgo-mango-resets.h
+ create mode 100644 include/dt-bindings/reset/thead,th1520-reset.h
+ create mode 100644 include/linux/firmware/thead/ipc.h
+ create mode 100644 include/linux/firmware/thead/light_event.h
+ create mode 100644 include/linux/light_rpmsg.h
+ create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json
+ create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json
+ create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json
+ create mode 100644 tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json
+
+diff --git a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
+index eefe7b345286..ab2afc0e4153 100644
+--- a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
++++ b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
+@@ -65,6 +65,8 @@ patternProperties:
+ minItems: 1
+ maxItems: 32
+
++ gpio-ranges: true
++
+ ngpios:
+ default: 32
+ minimum: 1
+diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
+index a43eb837f8da..42804d955293 100644
+--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
++++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
+@@ -19,6 +19,7 @@ properties:
+ - rockchip,rk3568-dwcmshc
+ - rockchip,rk3588-dwcmshc
+ - snps,dwcmshc-sdhci
++ - thead,th1520-dwcmshc
+
+ reg:
+ maxItems: 1
+diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
+index 5c2769dc689a..eeed9d2b940e 100644
+--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
++++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
+@@ -96,6 +96,7 @@ properties:
+ - snps,dwxgmac
+ - snps,dwxgmac-2.10
+ - starfive,jh7110-dwmac
++ - thead,th1520-dwmac
+
+ reg:
+ minItems: 1
+@@ -591,6 +592,7 @@ allOf:
+ - qcom,sa8775p-ethqos
+ - qcom,sc8280xp-ethqos
+ - snps,dwmac-3.50a
++ - snps,dwmac-3.70a
+ - snps,dwmac-4.10a
+ - snps,dwmac-4.20a
+ - snps,dwmac-5.20
+diff --git a/Documentation/devicetree/bindings/net/thead,dwmac.yaml b/Documentation/devicetree/bindings/net/thead,dwmac.yaml
+new file mode 100644
+index 000000000000..bf8ec8ca2753
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/thead,dwmac.yaml
+@@ -0,0 +1,77 @@
++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/net/thead,dwmac.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: T-HEAD DWMAC Ethernet controller
++
++maintainers:
++ - Jisheng Zhang <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 = &ethernet0;
++ ethernet1 = &ethernet1;
++ };
++};
+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";
++ };
++};
++
++&ethernet0 {
++ 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";
++ };
++};
++
++&ethernet0 {
++ 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>;
++};
++
++&ethernet0 {
++ 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>;
++};
++
++&ethernet0 {
++ 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";
++ };
++};
++
++&ethernet0 {
++ 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(&gt->nsec_mult, &gt->nsec_shift);
++#else
+ riscv_cs_get_mult_shift(&gt->nsec_mult, &gt->nsec_shift);
++#endif
+ gt->time_delta = -get_cycles64();
+ }
+diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
+index ec02ea86aa39..0980d6c683ad 100644
+--- a/arch/riscv/mm/init.c
++++ b/arch/riscv/mm/init.c
+@@ -36,6 +36,11 @@
+
+ #include "../kernel/head.h"
+
++#ifdef CONFIG_HIGHMEM
++#include <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);
+@@ -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,
++ &eth0_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, &regval);
++ 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, &regval);
++ 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 = &regu_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 = &regus_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),
++ &reg);
++ 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),
++ &reg);
++ 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
+
diff --git a/0002-cpupower-clang-compile-support.patch b/0002-cpupower-clang-compile-support.patch
new file mode 100644
index 0000000..1363e9b
--- /dev/null
+++ b/0002-cpupower-clang-compile-support.patch
@@ -0,0 +1,49 @@
+From 6289f9462859513b4fa3137faf0332b84e46558a Mon Sep 17 00:00:00 2001
+From: liyunfei <liyunfei33@huawei.com>
+Date: Mon, 28 Aug 2023 10:55:20 +0800
+Subject: [PATCH] cpupower clang compile support
+
+Modified Makefile with tools/scripts/Makefile.include for clang compile and clang cross compile support.
+---
+ tools/power/cpupower/Makefile | 17 ++---------------
+ 1 file changed, 2 insertions(+), 15 deletions(-)
+
+diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
+index 59bfa05..1e606a4 100644
+--- a/tools/power/cpupower/Makefile
++++ b/tools/power/cpupower/Makefile
+@@ -8,16 +8,7 @@
+ # Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com>
+ #
+ OUTPUT=./
+-ifeq ("$(origin O)", "command line")
+- OUTPUT := $(O)/
+-endif
+-
+-ifneq ($(OUTPUT),)
+-# check that the output directory actually exists
+-OUTDIR := $(shell cd $(OUTPUT) && pwd)
+-$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
+-endif
+-
++include ../../scripts/Makefile.include
+
+ # --- CONFIGURATION BEGIN ---
+
+@@ -86,12 +77,8 @@ INSTALL_SCRIPT = ${INSTALL} -m 644
+ # to something more interesting, like "arm-linux-". If you want
+ # to compile vs uClibc, that can be done here as well.
+ CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc-
+-CC = $(CROSS)gcc
+-LD = $(CROSS)gcc
+-AR = $(CROSS)ar
+-STRIP = $(CROSS)strip
++CROSS_COMPILE ?= $(CROSS)
+ RANLIB = $(CROSS)ranlib
+-HOSTCC = gcc
+ MKDIR = mkdir
+
+ # 64bit library detection
+--
+2.28.0.windows.1
+
diff --git a/0003-x86_energy_perf_policy-clang-compile-support.patch b/0003-x86_energy_perf_policy-clang-compile-support.patch
new file mode 100644
index 0000000..2384105
--- /dev/null
+++ b/0003-x86_energy_perf_policy-clang-compile-support.patch
@@ -0,0 +1,24 @@
+From 55391ef2c74c32675038a7eb9c81769eba4622f6 Mon Sep 17 00:00:00 2001
+From: liyunfei <liyunfei33@huawei.com>
+Date: Mon, 28 Aug 2023 11:06:32 +0800
+Subject: [PATCH] x86_energy_perf_policy clang compile support
+
+Modified Makefile with tools/scripts/Makefile.include for clang compile and clang cross compile support.
+---
+ tools/power/x86/x86_energy_perf_policy/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile
+index 666b325..c61227b 100644
+--- a/tools/power/x86/x86_energy_perf_policy/Makefile
++++ b/tools/power/x86/x86_energy_perf_policy/Makefile
+@@ -1,5 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
+-CC = $(CROSS_COMPILE)gcc
++include ../../../scripts/Makefile.include
+ BUILD_OUTPUT := $(CURDIR)
+ PREFIX := /usr
+ DESTDIR :=
+--
+2.28.0.windows.1
+
diff --git a/0004-turbostat-clang-compile-support.patch b/0004-turbostat-clang-compile-support.patch
new file mode 100644
index 0000000..d21c9ef
--- /dev/null
+++ b/0004-turbostat-clang-compile-support.patch
@@ -0,0 +1,24 @@
+From bddde6f3d75afb734862150e2fb80af9cf3e00f9 Mon Sep 17 00:00:00 2001
+From: liyunfei <liyunfei33@huawei.com>
+Date: Mon, 28 Aug 2023 11:09:03 +0800
+Subject: [PATCH] turbostat clang compile support
+
+Modified Makefile with tools/scripts/Makefile.include for clang compile and clang cross compile support.
+---
+ tools/power/x86/turbostat/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile
+index 92e139b..f4de368 100644
+--- a/tools/power/x86/turbostat/Makefile
++++ b/tools/power/x86/turbostat/Makefile
+@@ -1,5 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
+-CC = $(CROSS_COMPILE)gcc
++include ../../../scripts/Makefile.include
+ BUILD_OUTPUT := $(CURDIR)
+ PREFIX ?= /usr
+ DESTDIR ?=
+--
+2.28.0.windows.1
+
diff --git a/0005-haoc-kernel.patch b/0005-haoc-kernel.patch
new file mode 100644
index 0000000..2d9484f
--- /dev/null
+++ b/0005-haoc-kernel.patch
@@ -0,0 +1,13472 @@
+From 099672494b5fbd626031f313bbdbc42d1eb3f02d Mon Sep 17 00:00:00 2001
+From: liuzh <liuzhh@zgclab.edu.cn>
+Date: Wed, 22 May 2024 16:36:55 +0800
+Subject: [PATCH] Squashed commit of the following:
+
+commit 909ad06b3bf629d9af4e143347c1d1ef8a3a5808
+Author: liuzh <liuzhh@zgclab.edu.cn>
+Date: Wed May 22 16:23:13 2024 +0800
+
+ fix mte_sync_tags() parameters after rebase to 6.6.0-27.0.0.
+
+commit 1cbf51371b0539a45f816419b2da82cf36162b4a
+Author: ljl <ljl2013@163.com>
+Date: Mon Mar 25 08:01:32 2024 +0000
+
+ IEE SI: Removed redundant codes.
+
+commit 0178bfc79ad1769a36f4165348a671d2182cff55
+Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
+Date: Mon Mar 25 11:01:11 2024 +0800
+
+ Fix bugs on qemu when opening CONFIG_CREDP.
+
+commit 8e714f6e8f2ace5a6fc900b4bce6b03c83c41870
+Author: ljl <ljl2013@163.com>
+Date: Thu Mar 21 04:44:26 2024 +0000
+
+ IEE SI: Remove PAN operations as BTLB BUG is already fixed.
+
+commit 7b5fc74cb99e377d3bc59da81612cd6f3dd8a4d8
+Author: ljl <lvjinglin2013@163.com>
+Date: Wed Mar 20 18:31:47 2024 +0800
+
+ IEE SI: Migration of iee rwx gate.
+
+commit aad2c7e89c9c4ad8ff0fb3ee53cd1b974144a283
+Author: liuzh <liuzhh@zgclab.edu.cn>
+Date: Mon Mar 18 15:32:43 2024 +0800
+
+ modify slub.c set_track_prepare()
+
+commit 7452bac06ec09bf8321dfdbfb8b6a429d2cd8637
+Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
+Date: Thu Mar 21 11:26:19 2024 +0800
+
+ Set pgd of lm Privileged.
+
+commit 33934cfc3eed798a3a687bf86c6bd92697e68ba9
+Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
+Date: Tue Mar 19 17:14:32 2024 +0800
+
+ Delete some redundant code and put trans_pgd into IEE.
+
+commit 2bfe9008a72f8b8ac237bc7a5f99f9d40e84c247
+Author: zhangshiyang17@mails.ucas.ac.cn <zhangshiyang17@mails.ucas.ac.cn>
+Date: Mon Mar 18 11:47:50 2024 +0000
+
+ Fix bugs on physical when opening CONFIG_IEE and CONFIG_PTP.
+
+commit dafa2df600757511ce3e8f178e05e28adabdf39b
+Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
+Date: Mon Mar 18 10:40:42 2024 +0800
+
+ Fix bugs on qemu when opening CONFIG_IEE and CONFIG_PTP.
+
+commit 9231a9f6b34c62090b5f202c9c64a52bfdac7a73
+Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
+Date: Thu Mar 14 16:34:53 2024 +0800
+
+ Fix compiling bugs of CONFIG_PTP.
+
+commit 6469df3bcce32896c2cb297d3cd7ead82c33f35d
+Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
+Date: Thu Mar 14 11:10:00 2024 +0800
+
+ Fix bugs on qemu when opening CONFIG_IEE and CONFIG_INTERRUPTABLE.
+
+commit 5f1773dada622a3514c9ed6aa72dd50e918f2664
+Author: zhangsy <zhangshiyang17@mails.ucas.ac.cn>
+Date: Wed Mar 13 17:31:39 2024 +0800
+
+ Fix bugs on qemu when opening CONFIG_IEE.
+
+commit 73f433a093fa84cffa5e11e86bed6f17c9b30a39
+Author: liuzh <liuzhh@zgclab.edu.cn>
+Date: Tue Mar 12 15:32:29 2024 +0800
+
+ fix the map of IEE_SI_TEXT.
+
+commit 9b92deb4b2338093d9b04f4b81f162855b31c983
+Author: liuzh <liuzhh@zgclab.edu.cn>
+Date: Sun Mar 10 16:11:13 2024 +0800
+
+ modified to be able to compile.
+ can start the kernel with qemu and successfully reach `start_kernel()`.
+
+commit e892ec4790d72e9433b48b0221e7e6dc4c361dd9
+Author: liuzh <liuzhh@zgclab.edu.cn>
+Date: Thu Mar 7 14:27:45 2024 +0800
+
+ fix some conflicts
+
+commit fdec7e39345e81e867e01258487f88801b790b02
+Author: liuzh <liuzhh@zgclab.edu.cn>
+Date: Wed Mar 6 12:31:11 2024 +0800
+
+ migrate openeuler-commit code. (need some fix before compiling)
+---
+ Makefile | 3 +-
+ arch/arm64/Kconfig | 18 +
+ arch/arm64/include/asm/assembler.h | 67 +
+ arch/arm64/include/asm/daifflags.h | 16 +
+ arch/arm64/include/asm/efi.h | 4 +
+ arch/arm64/include/asm/fixmap.h | 3 +
+ arch/arm64/include/asm/hw_breakpoint.h | 12 +
+ arch/arm64/include/asm/iee-access.h | 36 +
+ arch/arm64/include/asm/iee-cred.h | 150 ++
+ arch/arm64/include/asm/iee-def.h | 74 +
+ arch/arm64/include/asm/iee-si.h | 64 +
+ arch/arm64/include/asm/iee-slab.h | 23 +
+ arch/arm64/include/asm/iee-token.h | 40 +
+ arch/arm64/include/asm/iee.h | 10 +
+ arch/arm64/include/asm/kernel-pgtable.h | 21 +
+ arch/arm64/include/asm/koi.h | 335 +++++
+ arch/arm64/include/asm/memory.h | 24 +
+ arch/arm64/include/asm/mmu_context.h | 20 +
+ arch/arm64/include/asm/pgalloc.h | 4 +
+ arch/arm64/include/asm/pgtable-hwdef.h | 11 +
+ arch/arm64/include/asm/pgtable.h | 304 +++-
+ arch/arm64/include/asm/pointer_auth.h | 5 +
+ arch/arm64/include/asm/sysreg.h | 58 +
+ arch/arm64/include/asm/tlb.h | 9 +
+ arch/arm64/include/asm/tlbflush.h | 58 +-
+ arch/arm64/kernel/Makefile | 2 +
+ arch/arm64/kernel/armv8_deprecated.c | 16 +
+ arch/arm64/kernel/asm-offsets.c | 11 +
+ arch/arm64/kernel/cpu_errata.c | 12 +
+ arch/arm64/kernel/cpufeature.c | 79 +
+ arch/arm64/kernel/debug-monitors.c | 4 +
+ arch/arm64/kernel/entry-common.c | 4 +
+ arch/arm64/kernel/entry.S | 611 ++++++++
+ arch/arm64/kernel/fpsimd.c | 4 +
+ arch/arm64/kernel/head.S | 56 +
+ arch/arm64/kernel/hibernate.c | 14 +
+ arch/arm64/kernel/hw_breakpoint.c | 99 ++
+ arch/arm64/kernel/iee/Makefile | 1 +
+ arch/arm64/kernel/iee/iee-func.c | 187 +++
+ arch/arm64/kernel/iee/iee-gate.S | 174 +++
+ arch/arm64/kernel/iee/iee.c | 1360 +++++++++++++++++
+ arch/arm64/kernel/koi/Makefile | 1 +
+ arch/arm64/kernel/koi/koi.c | 1327 +++++++++++++++++
+ arch/arm64/kernel/mte.c | 5 +
+ arch/arm64/kernel/process.c | 19 +-
+ arch/arm64/kernel/proton-pack.c | 8 +
+ arch/arm64/kernel/setup.c | 33 +
+ arch/arm64/kernel/traps.c | 26 +
+ arch/arm64/kernel/vmlinux.lds.S | 61 +
+ arch/arm64/mm/context.c | 91 +-
+ arch/arm64/mm/fault.c | 9 +
+ arch/arm64/mm/fixmap.c | 74 +-
+ arch/arm64/mm/init.c | 34 +
+ arch/arm64/mm/mmu.c | 1780 +++++++++++++++++++----
+ arch/arm64/mm/pgd.c | 39 +
+ arch/arm64/mm/proc.S | 28 +
+ arch/arm64/mm/trans_pgd.c | 46 +
+ drivers/firmware/efi/arm-runtime.c | 4 +
+ drivers/firmware/efi/memmap.c | 20 +
+ drivers/tty/serial/earlycon.c | 4 +
+ drivers/usb/early/ehci-dbgp.c | 4 +
+ fs/coredump.c | 8 +
+ fs/exec.c | 20 +
+ fs/nfs/flexfilelayout/flexfilelayout.c | 9 +
+ fs/nfs/nfs4idmap.c | 9 +
+ fs/nfsd/auth.c | 38 +
+ fs/nfsd/nfs4callback.c | 12 +-
+ fs/nfsd/nfs4recover.c | 9 +
+ fs/nfsd/nfsfh.c | 9 +
+ fs/open.c | 26 +
+ fs/overlayfs/dir.c | 9 +
+ fs/overlayfs/super.c | 12 +
+ fs/smb/client/cifs_spnego.c | 9 +
+ fs/smb/client/cifsacl.c | 9 +
+ include/asm-generic/early_ioremap.h | 3 +
+ include/asm-generic/fixmap.h | 18 +
+ include/asm-generic/pgalloc.h | 54 +
+ include/asm-generic/vmlinux.lds.h | 24 +-
+ include/linux/cred.h | 45 +-
+ include/linux/efi.h | 9 +
+ include/linux/iee-func.h | 27 +
+ include/linux/module.h | 1 +
+ include/linux/sched.h | 19 +
+ init/main.c | 28 +-
+ kernel/cred.c | 182 +++
+ kernel/exit.c | 8 +
+ kernel/fork.c | 316 ++--
+ kernel/groups.c | 7 +
+ kernel/kthread.c | 13 +
+ kernel/smpboot.c | 9 +
+ kernel/sys.c | 107 ++
+ kernel/umh.c | 10 +
+ kernel/user_namespace.c | 18 +
+ mm/Kconfig | 12 +
+ mm/damon/ops-common.c | 1 +
+ mm/debug_vm_pgtable.c | 24 +
+ mm/early_ioremap.c | 57 +
+ mm/huge_memory.c | 30 +-
+ mm/init-mm.c | 17 +
+ mm/memory.c | 14 +
+ mm/slub.c | 198 ++-
+ mm/sparse-vmemmap.c | 21 +
+ mm/vmalloc.c | 2 +-
+ net/dns_resolver/dns_key.c | 9 +
+ security/commoncap.c | 169 +++
+ security/keys/keyctl.c | 23 +
+ security/keys/process_keys.c | 53 +
+ security/security.c | 15 +
+ 109 files changed, 8945 insertions(+), 397 deletions(-)
+ create mode 100644 arch/arm64/include/asm/iee-access.h
+ create mode 100644 arch/arm64/include/asm/iee-cred.h
+ create mode 100644 arch/arm64/include/asm/iee-def.h
+ create mode 100644 arch/arm64/include/asm/iee-si.h
+ create mode 100644 arch/arm64/include/asm/iee-slab.h
+ create mode 100644 arch/arm64/include/asm/iee-token.h
+ create mode 100644 arch/arm64/include/asm/iee.h
+ create mode 100644 arch/arm64/include/asm/koi.h
+ create mode 100644 arch/arm64/kernel/iee/Makefile
+ create mode 100644 arch/arm64/kernel/iee/iee-func.c
+ create mode 100644 arch/arm64/kernel/iee/iee-gate.S
+ create mode 100644 arch/arm64/kernel/iee/iee.c
+ create mode 100644 arch/arm64/kernel/koi/Makefile
+ create mode 100644 arch/arm64/kernel/koi/koi.c
+ create mode 100644 include/linux/iee-func.h
+
+diff --git a/Makefile b/Makefile
+index 8e6d9b894b1e..20c367b5957d 100644
+--- a/Makefile
++++ b/Makefile
+@@ -554,7 +554,7 @@ LINUXINCLUDE := \
+ -I$(objtree)/include \
+ $(USERINCLUDE)
+
+-KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE
++KBUILD_AFLAGS := -D__ASSEMBLY__ -fno-PIE -march=armv8.1-a
+
+ KBUILD_CFLAGS :=
+ KBUILD_CFLAGS += -std=gnu11
+@@ -563,6 +563,7 @@ KBUILD_CFLAGS += -funsigned-char
+ KBUILD_CFLAGS += -fno-common
+ KBUILD_CFLAGS += -fno-PIE
+ KBUILD_CFLAGS += -fno-strict-aliasing
++KBUILD_CFLAGS += -march=armv8.1-a
+
+ KBUILD_CPPFLAGS := -D__KERNEL__
+ KBUILD_RUSTFLAGS := $(rust_common_flags) \
+diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
+index 2a875546bdc7..7448afc90c0a 100644
+--- a/arch/arm64/Kconfig
++++ b/arch/arm64/Kconfig
+@@ -1730,6 +1730,24 @@ config UNMAP_KERNEL_AT_EL0
+
+ If unsure, say Y.
+
++# Config for iee
++config IEE
++ depends on ARM64
++ depends on ARM64_PAN
++ depends on ARM64_VA_BITS_48
++ depends on ARM64_4K_PAGES
++ def_bool y
++
++# Config for support of interruption of iee
++config IEE_INTERRUPTABLE
++ depends on IEE
++ def_bool n
++
++# Config for credentials isolation
++config CREDP
++ depends on IEE
++ def_bool y
++
+ config MITIGATE_SPECTRE_BRANCH_HISTORY
+ bool "Mitigate Spectre style attacks against branch history" if EXPERT
+ default y
+diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
+index 38b23786aeb4..6af10d509c2e 100644
+--- a/arch/arm64/include/asm/assembler.h
++++ b/arch/arm64/include/asm/assembler.h
+@@ -26,6 +26,41 @@
+ #include <asm/ptrace.h>
+ #include <asm/thread_info.h>
+
++#ifdef CONFIG_IEE
++ .macro iee_si_restore_daif, flags:req
++ msr daifclr, #0xf
++ tbnz \flags, #6, 114221f
++ tbnz \flags, #7, 114210f
++ tbnz \flags, #8, 114100f
++ msr daifset, #0b000
++ b 114514f
++114221:
++ tbnz \flags, #7, 114211f
++ tbnz \flags, #8, 114101f
++ msr daifset, #0b001
++ b 114514f
++114211:
++ tbnz \flags, #8, 114111f
++ msr daifset, #0b011
++ b 114514f
++114210:
++ tbnz \flags, #8, 114110f
++ msr daifset, #0b010
++ b 114514f
++114100:
++ msr daifset, #0b100
++ b 114514f
++114101:
++ msr daifset, #0b101
++ b 114514f
++114110:
++ msr daifset, #0b110
++ b 114514f
++114111:
++ msr daifset, #0b111
++114514:
++ .endm
++#endif
+ /*
+ * Provide a wxN alias for each wN register so what we can paste a xN
+ * reference after a 'w' to obtain the 32-bit version.
+@@ -52,7 +87,11 @@ alternative_else_nop_endif
+
+ .macro disable_daif
+ disable_allint
++// #ifdef CONFIG_IEE
++// msr daifset, #0x7
++// #else
+ msr daifset, #0xf
++// #endif
+ .endm
+
+ .macro enable_daif
+@@ -69,7 +108,11 @@ alternative_else_nop_endif
+ .endm
+
+ .macro restore_irq, flags
++// #ifdef CONFIG_IEE
++// iee_si_restore_daif \flags
++// #else
+ msr daif, \flags
++// #endif
+ .endm
+
+ .macro enable_dbg
+@@ -77,20 +120,44 @@ alternative_else_nop_endif
+ .endm
+
+ .macro disable_step_tsk, flgs, tmp
++// #ifdef CONFIG_IEE
++// 1145:
++// tbz \flgs, #TIF_SINGLESTEP, 9990f
++// mrs \tmp, mdscr_el1
++// bic \tmp, \tmp, #DBG_MDSCR_SS
++// orr \tmp, \tmp, #DBG_MDSCR_MDE
++// msr mdscr_el1, \tmp
++// isb // Synchronise with enable_dbg
++// mrs \tmp, mdscr_el1
++// tbz \tmp, #15, 1145b
++// #else
+ tbz \flgs, #TIF_SINGLESTEP, 9990f
+ mrs \tmp, mdscr_el1
+ bic \tmp, \tmp, #DBG_MDSCR_SS
+ msr mdscr_el1, \tmp
+ isb // Synchronise with enable_dbg
++// #endif
+ 9990:
+ .endm
+
+ /* call with daif masked */
+ .macro enable_step_tsk, flgs, tmp
++// #ifdef CONFIG_IEE
++// 1146:
++// tbz \flgs, #TIF_SINGLESTEP, 9990f
++// mrs \tmp, mdscr_el1
++// orr \tmp, \tmp, #DBG_MDSCR_SS
++// orr \tmp, \tmp, #DBG_MDSCR_MDE
++// msr mdscr_el1, \tmp
++// isb // Synchronise with enable_dbg
++// mrs \tmp, mdscr_el1
++// tbz \tmp, #15, 1146b
++// #else
+ tbz \flgs, #TIF_SINGLESTEP, 9990f
+ mrs \tmp, mdscr_el1
+ orr \tmp, \tmp, #DBG_MDSCR_SS
+ msr mdscr_el1, \tmp
++// #endif
+ 9990:
+ .endm
+
+diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h
+index 2417cc6b1631..cb5b4c2e03b8 100644
+--- a/arch/arm64/include/asm/daifflags.h
++++ b/arch/arm64/include/asm/daifflags.h
+@@ -26,11 +26,19 @@ static inline void local_daif_mask(void)
+ (read_sysreg_s(SYS_ICC_PMR_EL1) == (GIC_PRIO_IRQOFF |
+ GIC_PRIO_PSR_I_SET)));
+
++// #ifdef CONFIG_IEE
++// asm volatile(
++// "msr daifset, #0x7 // local_daif_mask\n"
++// :
++// :
++// : "memory");
++// #else
+ asm volatile(
+ "msr daifset, #0xf // local_daif_mask\n"
+ :
+ :
+ : "memory");
++// #endif
+
+ /* Don't really care for a dsb here, we don't intend to enable IRQs */
+ if (system_uses_irq_prio_masking())
+@@ -118,7 +126,11 @@ static inline void local_daif_restore(unsigned long flags)
+ gic_write_pmr(pmr);
+ }
+
++// #ifdef CONFIG_IEE
++// iee_si_write_daif(flags);
++// #else
+ write_sysreg(flags, daif);
++// #endif
+
+ /* If we can take asynchronous errors we can take NMIs */
+ if (system_uses_nmi()) {
+@@ -151,7 +163,11 @@ static inline void local_daif_inherit(struct pt_regs *regs)
+ * system_has_prio_mask_debugging() won't restore the I bit if it can
+ * use the pmr instead.
+ */
++// #ifdef CONFIG_IEE
++// iee_si_write_daif(flags);
++// #else
+ write_sysreg(flags, daif);
++// #endif
+
+ /* The ALLINT field is at the same position in pstate and ALLINT */
+ if (system_uses_nmi()) {
+diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
+index bcd5622aa096..76c4bd6c2b20 100644
+--- a/arch/arm64/include/asm/efi.h
++++ b/arch/arm64/include/asm/efi.h
+@@ -58,7 +58,11 @@ void arch_efi_call_virt_teardown(void);
+ #define arch_efi_save_flags(state_flags) \
+ ((void)((state_flags) = read_sysreg(daif)))
+
++// #ifdef CONFIG_IEE
++// #define arch_efi_restore_flags(state_flags) iee_si_write_daif(state_flags)
++// #else
+ #define arch_efi_restore_flags(state_flags) write_sysreg(state_flags, daif)
++// #endif
+
+
+ /* arch specific definitions used by the stub code */
+diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
+index 58c294a96676..095a0731dce3 100644
+--- a/arch/arm64/include/asm/fixmap.h
++++ b/arch/arm64/include/asm/fixmap.h
+@@ -108,6 +108,9 @@ void __init fixmap_copy(pgd_t *pgdir);
+ #define __late_clear_fixmap(idx) __set_fixmap((idx), 0, FIXMAP_PAGE_CLEAR)
+
+ extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
++#ifdef CONFIG_PTP
++extern void __iee_set_fixmap_pre_init(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
++#endif
+
+ #include <asm-generic/fixmap.h>
+
+diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h
+index 84055329cd8b..f72d89bb9a32 100644
+--- a/arch/arm64/include/asm/hw_breakpoint.h
++++ b/arch/arm64/include/asm/hw_breakpoint.h
+@@ -104,6 +104,18 @@ static inline void decode_ctrl_reg(u32 reg,
+ write_sysreg(VAL, dbg##REG##N##_el1);\
+ } while (0)
+
++#ifdef CONFIG_IEE
++#define IEE_SI_AARCH64_DBG_READ(N, REG, VAL) do{\
++ VAL = this_cpu_read(iee_si_user_##REG##N);\
++} while (0)
++
++#define IEE_SI_AARCH64_DBG_WRITE(N, REG, VAL) do{\
++ u64 __val = (u64)(VAL); \
++ this_cpu_write(iee_si_user_##REG##N, __val);\
++ iee_rwx_gate_entry(IEE_WRITE_AFSR0);\
++} while (0)
++#endif
++
+ struct task_struct;
+ struct notifier_block;
+ struct perf_event_attr;
+diff --git a/arch/arm64/include/asm/iee-access.h b/arch/arm64/include/asm/iee-access.h
+new file mode 100644
+index 000000000000..79604c21a510
+--- /dev/null
++++ b/arch/arm64/include/asm/iee-access.h
+@@ -0,0 +1,36 @@
++#ifndef _LINUX_IEE_ACCESS_H
++#define _LINUX_IEE_ACCESS_H
++
++#include <asm/iee-def.h>
++#include <asm/iee-slab.h>
++
++extern unsigned long long iee_rw_gate(int flag, ...);
++
++#ifdef CONFIG_IEE
++void iee_write_in_byte(void *ptr, u64 data, int length)
++{
++ iee_rw_gate(IEE_WRITE_IN_BYTE, ptr, data, length);
++}
++
++void iee_memset(void *ptr, int data, size_t n)
++{
++ iee_rw_gate(IEE_MEMSET, ptr, data, n);
++}
++
++void iee_set_track(struct track *ptr, struct track *data)
++{
++ iee_rw_gate(IEE_OP_SET_TRACK, ptr, data);
++}
++
++void iee_set_freeptr(freeptr_t *pptr, freeptr_t ptr)
++{
++ iee_rw_gate(IEE_OP_SET_FREEPTR, pptr, ptr);
++}
++
++void iee_write_entry_task(struct task_struct *tsk)
++{
++ iee_rw_gate(IEE_WRITE_ENTRY_TASK, tsk);
++}
++#endif
++
++#endif
+\ No newline at end of file
+diff --git a/arch/arm64/include/asm/iee-cred.h b/arch/arm64/include/asm/iee-cred.h
+new file mode 100644
+index 000000000000..b8c3bb53f98a
+--- /dev/null
++++ b/arch/arm64/include/asm/iee-cred.h
+@@ -0,0 +1,150 @@
++#ifndef _LINUX_IEE_CRED_H
++#define _LINUX_IEE_CRED_H
++
++#include <linux/cred.h>
++#include <asm/iee-def.h>
++
++extern unsigned long long iee_rw_gate(int flag, ...);
++
++#ifdef CONFIG_CREDP
++static void __maybe_unused iee_copy_cred(const struct cred *old, struct cred *new)
++{
++ iee_rw_gate(IEE_OP_COPY_CRED,old,new);
++}
++
++static void __maybe_unused iee_set_cred_uid(struct cred *cred, kuid_t uid)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_UID,cred,uid);
++}
++
++static void __maybe_unused iee_set_cred_gid(struct cred *cred, kgid_t gid)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_GID,cred,gid);
++}
++
++static void __maybe_unused iee_set_cred_suid(struct cred *cred, kuid_t suid)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_SUID,cred,suid);
++}
++
++static void __maybe_unused iee_set_cred_sgid(struct cred *cred, kgid_t sgid)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_SGID,cred,sgid);
++}
++
++static void __maybe_unused iee_set_cred_euid(struct cred *cred, kuid_t euid)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_EUID,cred,euid);
++}
++
++static void __maybe_unused iee_set_cred_egid(struct cred *cred, kgid_t egid)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_EGID,cred,egid);
++}
++
++static void __maybe_unused iee_set_cred_fsuid(struct cred *cred, kuid_t fsuid)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_FSUID,cred,fsuid);
++}
++
++static void __maybe_unused iee_set_cred_fsgid(struct cred *cred, kgid_t fsgid)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_FSGID,cred,fsgid);
++}
++
++static void __maybe_unused iee_set_cred_user(struct cred *cred, struct user_struct *user)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_USER,cred,user);
++}
++
++static void __maybe_unused iee_set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_USER_NS,cred,user_ns);
++}
++
++static void __maybe_unused iee_set_cred_ucounts(struct cred *cred, struct ucounts *ucounts)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_UCOUNTS,cred,ucounts);
++}
++
++static void __maybe_unused iee_set_cred_group_info(struct cred *cred, struct group_info *group_info)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_GROUP_INFO,cred,group_info);
++}
++
++static void __maybe_unused iee_set_cred_securebits(struct cred *cred, unsigned securebits)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_SECUREBITS,cred,securebits);
++}
++
++static void __maybe_unused iee_set_cred_cap_inheritable(struct cred *cred, kernel_cap_t cap_inheritable)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_CAP_INHER,cred,cap_inheritable);
++}
++
++static void __maybe_unused iee_set_cred_cap_permitted(struct cred *cred, kernel_cap_t cap_permitted)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_CAP_PERM,cred,cap_permitted);
++}
++
++static void __maybe_unused iee_set_cred_cap_effective(struct cred *cred, kernel_cap_t cap_effective)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_CAP_EFFECT,cred,cap_effective);
++}
++
++static void __maybe_unused iee_set_cred_cap_bset(struct cred *cred, kernel_cap_t cap_bset)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_CAP_BSET,cred,cap_bset);
++}
++
++static void __maybe_unused iee_set_cred_cap_ambient(struct cred *cred, kernel_cap_t cap_ambient)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_CAP_AMBIENT,cred,cap_ambient);
++}
++
++#ifdef CONFIG_KEYS
++static void __maybe_unused iee_set_cred_jit_keyring(struct cred *cred, unsigned char jit_keyring)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_JIT_KEYRING,cred,jit_keyring);
++}
++
++static void __maybe_unused iee_set_cred_session_keyring(struct cred *cred, struct key *session_keyring)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_SESS_KEYRING,cred,session_keyring);
++}
++
++static void __maybe_unused iee_set_cred_process_keyring(struct cred *cred, struct key *process_keyring)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_PROC_KEYRING,cred,process_keyring);
++}
++
++static void __maybe_unused iee_set_cred_thread_keyring(struct cred *cred, struct key *thread_keyring)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_THREAD_KEYRING,cred,thread_keyring);
++}
++
++static void __maybe_unused iee_set_cred_request_key_auth(struct cred *cred, struct key *request_key_auth)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_REQ_KEYRING,cred,request_key_auth);
++}
++#endif
++
++static void __maybe_unused iee_set_cred_atomic_set_usage(struct cred *cred, int i)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_ATSET_USAGE,cred,i);
++}
++
++#ifdef CONFIG_SECURITY
++static void __maybe_unused iee_set_cred_security(struct cred *cred, void *security)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_SECURITY,cred,security);
++}
++#endif
++
++static void __maybe_unused iee_set_cred_rcu(struct cred *cred, struct rcu_head *rcu)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_RCU,cred,rcu);
++}
++#endif
++
++#endif
+\ No newline at end of file
+diff --git a/arch/arm64/include/asm/iee-def.h b/arch/arm64/include/asm/iee-def.h
+new file mode 100644
+index 000000000000..76e59259e4d1
+--- /dev/null
++++ b/arch/arm64/include/asm/iee-def.h
+@@ -0,0 +1,74 @@
++// Function Identifiers with Parameters Description
++
++#define IEE_WRITE_IN_BYTE 0 // Parameters: void *ptr, __u64 data, int length
++#define IEE_OP_SET_PTE 1 // Parameters: pte_t *ptep, pte_t pte
++#define IEE_OP_SET_PMD 2 // Parameters: pmd_t *pmdp, pmd_t pmd
++#define IEE_OP_SET_PUD 3 // Parameters: pud_t *pudp, pud_t pud
++#define IEE_OP_SET_P4D 4 // Parameters: p4d_t *p4dp, p4d_t p4d
++#define IEE_OP_SET_BM_PTE 5 // Parameters: pte_t *ptep, pte_t pte
++#define IEE_OP_SET_SWAPPER_PGD 6 // Parameters: pgd_t *pgdp, pgd_t pgd
++#define IEE_OP_SET_TRAMP_PGD 7 // Parameters: pgd_t *pgdp, pgd_t pgd
++#define IEE_OP_SET_CMPXCHG 8 // Parameters: pte_t *ptep, pteval_t old_pteval, pteval_t new_pteval
++#define IEE_OP_SET_XCHG 9 // Parameters: pte_t *ptep, pteval_t pteval
++#define IEE_OP_COPY_CRED 10 // Parameters: struct cred *old, struct cred *new
++#define IEE_OP_SET_CRED_UID 11 // Parameters: struct cred *cred, kuid_t uid
++#define IEE_OP_SET_CRED_GID 12 // Parameters: struct cred *cred, kgid_t gid
++#define IEE_OP_SET_CRED_SUID 13 // Parameters: struct cred *cred, kuid_t suid
++#define IEE_OP_SET_CRED_SGID 14 // Parameters: struct cred *cred, kgid_t sgid
++#define IEE_OP_SET_CRED_EUID 15 // Parameters: struct cred *cred, kuid_t euid
++#define IEE_OP_SET_CRED_EGID 16 // Parameters: struct cred *cred, kgid_t egid
++#define IEE_OP_SET_CRED_FSUID 17 // Parameters: struct cred *cred, kuid_t fsuid
++#define IEE_OP_SET_CRED_FSGID 18 // Parameters: struct cred *cred, kgid_t fsgid
++#define IEE_OP_SET_CRED_USER 19 // Parameters: struct cred *cred, struct user_struct *user
++#define IEE_OP_SET_CRED_USER_NS 20 // Parameters: struct cred *cred, struct user_namespace *user_ns
++#define IEE_OP_SET_CRED_GROUP_INFO 21 // Parameters: struct cred *cred, struct group_info *group_info
++#define IEE_OP_SET_CRED_SECUREBITS 22 // Parameters: struct cred *cred, unsigned securebits
++#define IEE_OP_SET_CRED_CAP_INHER 23 // Parameters: struct cred *cred, kernel_cap_t cap_inheritable
++#define IEE_OP_SET_CRED_CAP_PERM 24 // Parameters: struct cred *cred, kernel_cap_t cap_permitted
++#define IEE_OP_SET_CRED_CAP_EFFECT 25 // Parameters: struct cred *cred, kernel_cap_t cap_effective
++#define IEE_OP_SET_CRED_CAP_BSET 26 // Parameters: struct cred *cred, kernel_cap_t cap_bset
++#define IEE_OP_SET_CRED_CAP_AMBIENT 27 // Parameters: struct cred *cred, kernel_cap_t cap_ambient
++#define IEE_OP_SET_CRED_JIT_KEYRING 28 // Parameters: struct cred *cred, unsigned char jit_keyring
++#define IEE_OP_SET_CRED_SESS_KEYRING 29 // Parameters: struct cred *cred, struct key *session_keyring
++#define IEE_OP_SET_CRED_PROC_KEYRING 30 // Parameters: struct cred *cred, struct key *process_keyring
++#define IEE_OP_SET_CRED_THREAD_KEYRING 31 // Parameters: struct cred *cred, struct key *thread_keyring
++#define IEE_OP_SET_CRED_REQ_KEYRING 32 // Parameters: struct cred *cred, struct key *request_key_auth
++#define IEE_OP_SET_CRED_NON_RCU 33 // Parameters: struct cred *cred, int non_rcu
++#define IEE_OP_SET_CRED_ATSET_USAGE 34 // Parameters: struct cred *cred, int i
++#define IEE_OP_SET_CRED_ATOP_USAGE 35 // Parameters: struct cred *cred, int flag
++#define IEE_OP_SET_CRED_SECURITY 36 // Parameters: struct cred *cred, void *security
++#define IEE_OP_SET_CRED_RCU 37 // Parameters: struct cred *cred, struct rcu_head *rcu
++#define IEE_MEMSET 38 // Parameters: void *ptr, int data, size_t n
++#define IEE_OP_SET_TRACK 39 // Parameters: struct track *ptr, struct track *data
++#define IEE_OP_SET_FREEPTR 40 // Parameters: void **pptr, void *ptr
++#define IEE_OP_SET_PTE_U 41 // Parameters: pte_t *ptep, pte_t pte
++#define IEE_OP_SET_PTE_P 42 // Parameters: pte_t *ptep, pte_t pte
++#define IEE_SET_TOKEN_MM 43 // Parameters: struct task_token *token, struct mm_struct *mm
++#define IEE_SET_TOKEN_PGD 44 // Parameters: struct task_token *token, pgd_t *pgd
++#define IEE_INIT_TOKEN 45 // Parameters: struct task_struct *tsk, void *kernel_stack, void *iee_stack
++#define IEE_FREE_TOKEN 46 // Parameters: struct task_struct *tsk
++#define IEE_READ_TOKEN_STACK 47 // Parameters: struct task_struct *tsk
++#define IEE_WRITE_ENTRY_TASK 48 // Parameters: struct task_struct *tsk
++#define IEE_OP_SET_CRED_UCOUNTS 49 // Parameters: struct cred *cred, struct ucounts *ucounts
++#ifdef CONFIG_KOI
++#define IEE_READ_KOI_STACK 50 // Parameters: struct task_struct *tsk
++#define IEE_WRITE_KOI_STACK 51 // Parameters: struct task_struct *tsk, unsigned long koi_stack
++#define IEE_READ_TOKEN_TTBR1 52 // Parameters: struct task_struct *tsk
++#define IEE_WRITE_TOKEN_TTBR1 53 // Parameters: struct task_struct *tsk, unsigned long current_ttbr1
++#define IEE_READ_KOI_KERNEL_STACK 54 // Parameters: struct task_struct *tsk
++#define IEE_WRITE_KOI_KERNEL_STACK 55 // Parameters: struct task_struct *tsk, unsigned long kernel_stack
++#define IEE_READ_KOI_STACK_BASE 56 // Parameters: struct task_struct *tsk
++#define IEE_WRITE_KOI_STACK_BASE 57 // Parameters: struct task_struct *tsk, unsigned long koi_stack_base
++#endif
++
++/* Add new IEE ops here */
++
++#define AT_ADD 1
++#define AT_INC_NOT_ZERO 2
++#define AT_SUB_AND_TEST 3
++/* Atomic ops for atomic_t */
++
++#ifdef CONFIG_KOI
++#define IEE_SWITCH_TO_KERNEL 7
++#define IEE_SWITCH_TO_KOI 8
++#endif
+\ No newline at end of file
+diff --git a/arch/arm64/include/asm/iee-si.h b/arch/arm64/include/asm/iee-si.h
+new file mode 100644
+index 000000000000..e67d81db66a5
+--- /dev/null
++++ b/arch/arm64/include/asm/iee-si.h
+@@ -0,0 +1,64 @@
++#ifndef _LINUX_IEE_SI_H
++#define _LINUX_IEE_SI_H
++
++#include <asm/sysreg.h>
++#define __iee_si_code __section(".iee.si_text")
++#define __iee_si_data __section(".iee.si_data")
++
++/* Used for copying globals that iee rwx gate needs. */
++extern unsigned long iee_base_idmap_pg_dir;
++extern unsigned long iee_base_reserved_pg_dir;
++extern unsigned long iee_base__bp_harden_el1_vectors;
++extern bool iee_init_done;
++extern unsigned long iee_si_tcr;
++
++/* The following are __init functions used for iee si initialization. */
++extern void iee_si_prepare_data(void);
++
++extern unsigned long __iee_si_start[];
++// Handler function for sensitive inst
++u64 iee_si_handler(int flag, ...);
++/*
++ * TODO: scan a page to check whether it contains sensitive instructions
++ * return 1 when finding sensitive inst, 0 on safe page.
++ */
++extern int iee_si_scan_page(unsigned long addr);
++
++
++#define DBG_MDSCR_SS (1 << 0)
++#define DBG_MDSCR_MDE (1 << 15)
++
++#define IEE_SI_TEST 0
++#define IEE_WRITE_SCTLR 1
++#define IEE_WRITE_TTBR0 2
++#define IEE_WRITE_VBAR 3
++#define IEE_WRITE_TCR 4
++#define IEE_WRITE_MDSCR 5
++#define IEE_CONTEXT_SWITCH 6
++// #define IEE_WRITE_AFSR0 10
++/* Provide ttbr1 switch gate for KOI */
++#ifdef CONFIG_KOI
++#define IEE_SWITCH_TO_KERNEL 7
++#define IEE_SWITCH_TO_KOI 8
++#endif
++/* MASK modify-permitted bits on IEE protected sys registers */
++#define IEE_SCTLR_MASK (SCTLR_EL1_CP15BEN | SCTLR_EL1_SED | SCTLR_EL1_UCT | SCTLR_EL1_UCI |\
++ SCTLR_EL1_BT0 | SCTLR_EL1_BT1 | SCTLR_EL1_TCF0_MASK | SCTLR_ELx_DSSBS |\
++ SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA | SCTLR_ELx_ENDB|\
++ SCTLR_EL1_SPINTMASK | SCTLR_EL1_NMI | SCTLR_EL1_TIDCP | SCTLR_EL1_MSCEn|\
++ SCTLR_ELx_ENTP2 | SCTLR_EL1_TCF_MASK)
++#define IEE_TTBR0_MASK ~0
++#define IEE_TTBR1_MASK ~0
++#define IEE_TCR_MASK (TCR_HD | TCR_T0SZ_MASK | TCR_E0PD1)
++#define IEE_MDSCR_MASK (DBG_MDSCR_SS | DBG_MDSCR_MDE)
++
++#define IEE_DBGBCR_BT 0b0000 << 20
++#define IEE_DBGBCR_SSC 0b00 << 14
++#define IEE_DBGBCR_HMC 0b1 << 13
++#define IEE_DBGBCR_BAS 0b1111 << 5
++#define IEE_DBGBCR_PMC 0b11 << 1
++#define IEE_DBGBCR_E 0b1
++#define IEE_DBGBCR IEE_DBGBCR_BT | IEE_DBGBCR_SSC | IEE_DBGBCR_HMC | IEE_DBGBCR_BAS \
++ | IEE_DBGBCR_PMC | IEE_DBGBCR_E
++
++#endif
+\ No newline at end of file
+diff --git a/arch/arm64/include/asm/iee-slab.h b/arch/arm64/include/asm/iee-slab.h
+new file mode 100644
+index 000000000000..4f3c17c7da00
+--- /dev/null
++++ b/arch/arm64/include/asm/iee-slab.h
+@@ -0,0 +1,23 @@
++#ifndef _LINUX_IEE_SLAB_H
++#define _LINUX_IEE_SLAB_H
++/*
++ * Tracking user of a slab.
++ */
++#include <linux/stackdepot.h>
++
++#define TRACK_ADDRS_COUNT 16
++struct track {
++ unsigned long addr; /* Called from address */
++#ifdef CONFIG_STACKDEPOT
++ depot_stack_handle_t handle;
++#endif
++ int cpu; /* Was running on cpu */
++ int pid; /* Pid context */
++ unsigned long when; /* When did the operation occur */
++};
++
++enum track_item { TRACK_ALLOC, TRACK_FREE };
++
++typedef struct { unsigned long v; } freeptr_t;
++
++#endif
+\ No newline at end of file
+diff --git a/arch/arm64/include/asm/iee-token.h b/arch/arm64/include/asm/iee-token.h
+new file mode 100644
+index 000000000000..152474e1a187
+--- /dev/null
++++ b/arch/arm64/include/asm/iee-token.h
+@@ -0,0 +1,40 @@
++#ifndef _LINUX_IEE_TOKEN_H
++#define _LINUX_IEE_TOKEN_H
++
++#include <asm/iee-def.h>
++
++extern unsigned long long iee_rw_gate(int flag, ...);
++struct task_token;
++struct task_struct;
++struct mm_struct;
++
++#ifdef CONFIG_IEE
++void iee_set_token_mm(struct task_struct *tsk, struct mm_struct *mm)
++{
++ iee_rw_gate(IEE_SET_TOKEN_MM, tsk, mm);
++}
++
++void iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd)
++{
++ iee_rw_gate(IEE_SET_TOKEN_PGD, tsk, pgd);
++}
++
++void iee_init_token(struct task_struct *tsk, void *kernel_stack, void *iee_stack)
++{
++ iee_rw_gate(IEE_INIT_TOKEN, tsk, kernel_stack, iee_stack);
++}
++
++void iee_free_token(struct task_struct *tsk)
++{
++ iee_rw_gate(IEE_FREE_TOKEN, tsk);
++}
++
++unsigned long iee_read_token_stack(struct task_struct *tsk)
++{
++ unsigned long ret;
++ ret = iee_rw_gate(IEE_READ_TOKEN_STACK, tsk);
++ return ret;
++}
++#endif
++
++#endif
+\ No newline at end of file
+diff --git a/arch/arm64/include/asm/iee.h b/arch/arm64/include/asm/iee.h
+new file mode 100644
+index 000000000000..598f6d0b2626
+--- /dev/null
++++ b/arch/arm64/include/asm/iee.h
+@@ -0,0 +1,10 @@
++#ifndef _LINUX_IEE_H
++#define _LINUX_IEE_H
++#define __iee_code __section(".iee.text")
++#define __iee_header __section(".iee.text.header")
++
++u64 iee_dispatch(int flag, ...);
++
++#include <asm/iee-def.h>
++
++#endif
+diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
+index 85d26143faa5..e7a3081ce285 100644
+--- a/arch/arm64/include/asm/kernel-pgtable.h
++++ b/arch/arm64/include/asm/kernel-pgtable.h
+@@ -118,4 +118,25 @@
+ #define SWAPPER_RX_MMUFLAGS (SWAPPER_RW_MMUFLAGS | PTE_RDONLY)
+ #endif
+
++#ifdef CONFIG_IEE
++
++#ifdef CONFIG_ARM64_4K_PAGES // zgcXXX: it has been deleted in 6.6.
++#define ARM64_SWAPPER_USES_SECTION_MAPS 1
++#else
++#define ARM64_SWAPPER_USES_SECTION_MAPS 0
++#endif
++
++#define SWAPPER_MM_MMUFLAGS (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS) // zgcXXX: warning: 6.6 delete this macro. should delete this line later.
++
++#define SWAPPER_PTE_FLAGS_IDMAP (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED | PTE_RDONLY)
++#define SWAPPER_PMD_FLAGS_IDMAP (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S | PMD_SECT_RDONLY)
++
++#if ARM64_SWAPPER_USES_SECTION_MAPS
++#define SWAPPER_MM_MMUFLAGS_IDMAP (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS_IDMAP)
++#else
++#define SWAPPER_MM_MMUFLAGS_IDMAP (PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS_IDMAP)
++#endif
++
++#endif
++
+ #endif /* __ASM_KERNEL_PGTABLE_H */
+diff --git a/arch/arm64/include/asm/koi.h b/arch/arm64/include/asm/koi.h
+new file mode 100644
+index 000000000000..48d9a1378a1d
+--- /dev/null
++++ b/arch/arm64/include/asm/koi.h
+@@ -0,0 +1,335 @@
++#include "linux/mm.h"
++#include "asm/current.h"
++#include "asm/pgtable-hwdef.h"
++#include "asm/pgtable-types.h"
++#include "asm/pgtable.h"
++#include "linux/mm_types.h"
++#include "linux/pgtable.h"
++#include "linux/printk.h"
++#include "linux/slab.h"
++#include "linux/string.h"
++#include <linux/sched.h>
++#include "linux/hashtable.h"
++#include "linux/module.h"
++#include "linux/vmalloc.h"
++#include "stacktrace.h"
++#include "asm/mmu.h"
++#ifdef CONFIG_IEE
++#include "asm/iee-si.h"
++#include "asm/iee-def.h"
++#endif
++
++#define HASH_TABLE_BIT 10
++#define HASH_TABLE_LEN (1 << HASH_TABLE_BIT)
++#define HASH_KEY_MASK ((1 << HASH_TABLE_BIT) - 1)
++
++#define MAX_VAR_NAME 64
++#define DRIVER_ISOLATION_VAR_ARRAY_SIZE 32
++#define DRIVER_ISOLATION_MAX_VAL 256
++
++extern struct hlist_head koi_mem_htbl[1024];
++extern spinlock_t koi_mem_htbl_spin_lock;
++extern unsigned long koi_swapper_ttbr1;
++extern s64 koi_offset;
++
++#ifdef CONFIG_IEE
++extern unsigned long long iee_rw_gate(int flag, ...);
++#endif
++
++DECLARE_PER_CPU(unsigned long[PAGE_SIZE / sizeof(unsigned long)],
++ koi_irq_current_ttbr1);
++
++/**
++* struct koi_mem_hash_node -
++*@mod:pointer to driver module
++*@mem_list_head:free memory list head
++*@ko_mm: mm_struct in each driver
++*@pgdp:entry to Page Global Directory :pgd
++*@node:hash linked list node
++*@addr_htbl[1 << (HASH_TABLE_BIT)]:
++*@rcu:
++*/
++struct koi_mem_hash_node {
++ struct module *mod;
++ struct list_head mem_list_head;
++ struct mm_struct *ko_mm;
++ pgd_t *pgdp;
++ unsigned long ko_ttbr1;
++ struct hlist_node node;
++ struct hlist_head addr_htbl[1 << (HASH_TABLE_BIT)];
++ struct rcu_head rcu;
++ // used to protect free mem list
++ spinlock_t spin_lock;
++ // used to protect addr hashtable
++ spinlock_t addr_htbl_spin_lock;
++};
++//describe the global shared var
++struct shared_variable_descriptor {
++ unsigned int id;
++ unsigned int type;
++ char name[MAX_VAR_NAME];
++ unsigned long offset;
++ unsigned int size;
++ unsigned int self_ptr_ids[DRIVER_ISOLATION_VAR_ARRAY_SIZE];
++};
++
++int koi_do_switch_to_kernel_pgtbl(void);
++
++int koi_copy_pagetable(struct mm_struct *ko_mm, pgd_t *koi_pg_dir,
++ unsigned long addr, unsigned long end);
++
++void koi_create_pagetable(struct module *mod);
++
++void koi_map_kostack(struct module *mod);
++unsigned long koi_mem_alloc(struct module *mod, unsigned long orig_addr,
++ unsigned long size);
++void koi_mem_free(struct module *mod, unsigned long addr, unsigned long size,
++ bool is_const, int count, ...);
++void *koi_mem_lookup(struct module *mod, unsigned long addr);
++void koi_mem_free_callback(struct module *mod, unsigned long addr,
++ unsigned long size, void (*func)(void *));
++void koi_map_mem(struct module *mod, unsigned long addr, unsigned long size);
++void koi_mem_free_to_user(struct module *mod, unsigned long addr,
++ unsigned long size);
++
++unsigned long koi_ttbr_ctor(struct module *mod);
++extern void koi_do_switch_to_kernel_stack(void);
++extern void koi_do_switch_to_ko_stack(void);
++
++#define switch_pgtable(ttbr1) \
++ do { \
++ write_sysreg(ttbr1, ttbr1_el1); \
++ isb(); \
++ asm volatile(ALTERNATIVE("nop; nop; nop", \
++ "ic iallu; dsb nsh; isb", \
++ ARM64_WORKAROUND_CAVIUM_27456)); \
++ } while (0);
++
++#ifndef CONFIG_IEE
++#define koi_switch_to_ko() \
++ do { \
++ unsigned long flags, ko_ttbr1, cur_sp; \
++ unsigned long *ptr; \
++ struct task_token *token; \
++ asm volatile("mrs %0, daif\n" \
++ "msr daifset, #2\n" \
++ "isb\n" \
++ "mov %1, sp\n" \
++ : "=r"(flags), "=r"(cur_sp) \
++ :); \
++ if (!on_irq_stack(cur_sp, NULL)) { \
++ koi_do_switch_to_ko_stack(); \
++ ko_ttbr1 = koi_ttbr_ctor(THIS_MODULE); \
++ token = (struct task_token *)((unsigned long)current + \
++ koi_offset); \
++ token->current_ttbr1 = ko_ttbr1 & (~TTBR_ASID_MASK); \
++ } else { \
++ ko_ttbr1 = koi_ttbr_ctor(THIS_MODULE); \
++ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, \
++ __kern_my_cpu_offset()); \
++ *ptr = ko_ttbr1 & ~(TTBR_ASID_MASK); \
++ } \
++ switch_pgtable(ko_ttbr1); \
++ asm volatile("msr daif, %0\n" \
++ "isb\n" \
++ : \
++ : "r"(flags)); \
++ } while (0);
++
++#define koi_switch_to_kernel() \
++ do { \
++ unsigned long cur_sp, flags, asid; \
++ unsigned long *ptr; \
++ struct task_token *token; \
++ asm volatile("mrs %0, daif\n" \
++ "msr daifset, #2\n" \
++ "isb\n" \
++ "mov %1, sp\n" \
++ "mov %2, ttbr0_el1\n" \
++ : "=r"(flags), "=r"(cur_sp), "=r"(asid) \
++ :); \
++ asid &= ~USER_ASID_FLAG; \
++ asid &= TTBR_ASID_MASK; \
++ switch_pgtable(koi_swapper_ttbr1); \
++ if (!on_irq_stack(cur_sp, NULL)) { \
++ token = (struct task_token *)((unsigned long)current + \
++ koi_offset); \
++ token->current_ttbr1 = koi_swapper_ttbr1; \
++ koi_do_switch_to_kernel_stack(); \
++ } else { \
++ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, \
++ __kern_my_cpu_offset()); \
++ *ptr = koi_swapper_ttbr1; \
++ } \
++ asm volatile("msr daif, %0\n" \
++ "isb\n" \
++ : \
++ : "r"(flags)); \
++ } while (0);
++#else
++#define koi_switch_to_ko() \
++ do { \
++ unsigned long cur_sp, flags, ko_ttbr1; \
++ unsigned long *ptr; \
++ asm volatile("mrs %0, daif\n" \
++ "msr daifset, #2\n" \
++ "isb\n" \
++ "mov %1, sp\n" \
++ : "=r"(flags), "=r"(cur_sp) \
++ :); \
++ if (!on_irq_stack(cur_sp, NULL)) { \
++ koi_do_switch_to_ko_stack(); \
++ ko_ttbr1 = koi_ttbr_ctor(THIS_MODULE); \
++ iee_rw_gate(IEE_WRITE_TOKEN_TTBR1, current, \
++ ko_ttbr1 &(~TTBR_ASID_MASK)); \
++ } else { \
++ ko_ttbr1 = koi_ttbr_ctor(THIS_MODULE); \
++ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, \
++ __kern_my_cpu_offset()); \
++ *ptr = ko_ttbr1 & (~TTBR_ASID_MASK); \
++ } \
++ iee_rwx_gate_entry(IEE_SWITCH_TO_KOI, ko_ttbr1); \
++ asm volatile("msr daif, %0\n" \
++ "isb\n" \
++ : \
++ : "r"(flags)); \
++ } while (0);
++
++#define koi_switch_to_kernel() \
++ do { \
++ unsigned long flags, cur_sp; \
++ unsigned long *ptr; \
++ asm volatile("mrs %0, daif\n" \
++ "msr daifset, #2\n" \
++ "isb\n" \
++ "mov %1, sp\n" \
++ : "=r"(flags), "=r"(cur_sp) \
++ :); \
++ iee_rwx_gate_entry(IEE_SWITCH_TO_KERNEL); \
++ if (!on_irq_stack(cur_sp, NULL)) { \
++ iee_rw_gate(IEE_WRITE_TOKEN_TTBR1, current, \
++ koi_swapper_ttbr1); \
++ koi_do_switch_to_kernel_stack(); \
++ } else { \
++ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, \
++ __kern_my_cpu_offset()); \
++ *ptr = koi_swapper_ttbr1; \
++ } \
++ asm volatile("msr daif, %0\n" \
++ "isb\n" \
++ : \
++ : "r"(flags)); \
++ } while (0);
++#endif
++//kzalloc function in driver space
++static __maybe_unused noinline void *
++koi_kzalloc_wrapper(struct module *mod, size_t size, gfp_t flags)
++{
++ int cnt = (size + PAGE_SIZE - 1) / PAGE_SIZE;
++ void *addr;
++ struct koi_mem_hash_node *target = NULL;
++ koi_switch_to_kernel();
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk("mem node for module: %s not found\n", mod->name);
++ return NULL;
++ }
++
++ addr = kzalloc(size, flags);
++ koi_copy_pagetable(target->ko_mm, target->pgdp, (unsigned long)addr,
++ (unsigned long)addr + PAGE_SIZE * cnt);
++ koi_switch_to_ko();
++ return addr;
++}
++//kmalloc function in driver space
++static __maybe_unused __always_inline void *
++koi_kmalloc_wrapper(struct module *mod, size_t size, gfp_t flags)
++{
++ int cnt = (size + PAGE_SIZE - 1) / PAGE_SIZE;
++ void *addr;
++ struct koi_mem_hash_node *target = NULL;
++ koi_switch_to_kernel();
++
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk("mem node for module: %s not found\n", mod->name);
++ return 0;
++ }
++
++ addr = kmalloc(cnt * PAGE_SIZE, flags);
++ koi_copy_pagetable(target->ko_mm, target->pgdp, (unsigned long)addr,
++ (unsigned long)addr + PAGE_SIZE * cnt);
++ koi_switch_to_ko();
++ return (void *)addr;
++}
++//vmalloc function in driver space
++static __maybe_unused void *koi_vmalloc_wrapper(struct module *mod,
++ unsigned long size)
++{
++ int cnt = (size + PAGE_SIZE - 1) / PAGE_SIZE;
++ void *addr;
++ struct koi_mem_hash_node *target = NULL;
++ koi_switch_to_kernel();
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk("mem node for module: %s not found\n", mod->name);
++ koi_switch_to_ko();
++ return 0;
++ }
++ addr = vmalloc(cnt * PAGE_SIZE);
++ koi_copy_pagetable(target->ko_mm, target->pgdp, (unsigned long)addr,
++ (unsigned long)addr + PAGE_SIZE * cnt);
++ koi_switch_to_ko();
++ return addr;
++}
++//kmalloc_array function in driver space
++static __maybe_unused void *koi_kmalloc_array_wrapper(struct module *mod,
++ size_t n, size_t size,
++ gfp_t flags)
++{
++ int kpage;
++ void *addr;
++ struct koi_mem_hash_node *target = NULL;
++ koi_switch_to_kernel();
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk("mem node for module: %s not found\n", mod->name);
++ koi_switch_to_ko();
++ return 0;
++ }
++ kpage = (n * size + PAGE_SIZE - 1) / PAGE_SIZE;
++ n = (kpage * PAGE_SIZE) / size;
++ addr = kmalloc_array(n, size, flags);
++ koi_copy_pagetable(target->ko_mm, target->pgdp, (unsigned long)addr,
++ (unsigned long)addr + PAGE_SIZE * kpage);
++ koi_switch_to_ko();
++ return addr;
++}
+\ No newline at end of file
+diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
+index fde4186cc387..6309e5514a16 100644
+--- a/arch/arm64/include/asm/memory.h
++++ b/arch/arm64/include/asm/memory.h
+@@ -190,6 +190,13 @@ extern u64 vabits_actual;
+ #endif
+
+ extern s64 memstart_addr;
++
++#if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++extern s64 memstart_addr_init;
++extern s64 iee_offset;
++#define LOGICAL_RANDOM (long long int)((long unsigned int)__va(memstart_addr_init) & (~PAGE_OFFSET))
++#endif
++
+ /* PHYS_OFFSET - the physical address of the start of memory. */
+ #define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
+
+@@ -310,6 +317,23 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x);
+ #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
+ #define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset))
+
++#ifdef CONFIG_KOI
++#define KOI_OFFSET ((unsigned long)BIT(vabits_actual - 2))
++#endif
++
++#ifdef CONFIG_IEE
++#ifdef CONFIG_IEE_OFFSET
++#define IEE_OFFSET ((CONFIG_IEE_OFFSET) - LOGICAL_RANDOM)
++#else
++#define IEE_OFFSET (((unsigned long)BIT(vabits_actual - 2)) - LOGICAL_RANDOM)
++#endif
++#define __phys_to_iee(x) (__phys_to_virt(x) + IEE_OFFSET)
++#define SET_UPAGE(x) __pgprot(pgprot_val(x) | PTE_USER)
++#define SET_PPAGE(x) __pgprot(pgprot_val(x) & (~PTE_USER))
++#define SET_INVALID(x) __pgprot(pgprot_val(x) & (~PTE_VALID))
++#define SET_NG(x) __pgprot(pgprot_val(x) | PTE_NG)
++#endif
++
+ /*
+ * Convert a page to/from a physical address
+ */
+diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
+index a6fb325424e7..cca5994dabfb 100644
+--- a/arch/arm64/include/asm/mmu_context.h
++++ b/arch/arm64/include/asm/mmu_context.h
+@@ -24,6 +24,9 @@
+ #include <asm/cputype.h>
+ #include <asm/sysreg.h>
+ #include <asm/tlbflush.h>
++#ifdef CONFIG_IEE
++#define INIT_ASID 0x2
++#endif
+
+ extern bool rodata_full;
+
+@@ -43,7 +46,12 @@ static inline void cpu_set_reserved_ttbr0_nosync(void)
+ {
+ unsigned long ttbr = phys_to_ttbr(__pa_symbol(reserved_pg_dir));
+
++#ifdef CONFIG_IEE
++ ttbr |= FIELD_PREP(TTBR_ASID_MASK, 1);
++ iee_rwx_gate_entry(IEE_WRITE_ttbr0_el1, ttbr);
++#else
+ write_sysreg(ttbr, ttbr0_el1);
++#endif
+ }
+
+ static inline void cpu_set_reserved_ttbr0(void)
+@@ -79,7 +87,11 @@ static inline void __cpu_set_tcr_t0sz(unsigned long t0sz)
+
+ tcr &= ~TCR_T0SZ_MASK;
+ tcr |= t0sz << TCR_T0SZ_OFFSET;
++#ifdef CONFIG_IEE
++ iee_rwx_gate_entry(IEE_WRITE_tcr_el1, tcr);
++#else
+ write_sysreg(tcr, tcr_el1);
++#endif
+ isb();
+ }
+
+@@ -144,7 +156,11 @@ static inline void cpu_install_ttbr0(phys_addr_t ttbr0, unsigned long t0sz)
+ __cpu_set_tcr_t0sz(t0sz);
+
+ /* avoid cpu_switch_mm() and its SW-PAN and CNP interactions */
++ #ifdef CONFIG_IEE
++ iee_rwx_gate_entry(IEE_WRITE_ttbr0_el1, ttbr0);
++ #else
+ write_sysreg(ttbr0, ttbr0_el1);
++ #endif
+ isb();
+ }
+
+@@ -174,6 +190,10 @@ static inline void cpu_replace_ttbr1(pgd_t *pgdp, pgd_t *idmap)
+ ttbr1 |= TTBR_CNP_BIT;
+ }
+
++ #ifdef CONFIG_IEE
++ ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, ASID(current->active_mm));
++ #endif
++
+ replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
+
+ __cpu_install_idmap(idmap);
+diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
+index 237224484d0f..4e3304da8421 100644
+--- a/arch/arm64/include/asm/pgalloc.h
++++ b/arch/arm64/include/asm/pgalloc.h
+@@ -63,6 +63,10 @@ static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
+ extern pgd_t *pgd_alloc(struct mm_struct *mm);
+ extern void pgd_free(struct mm_struct *mm, pgd_t *pgdp);
+
++#ifdef CONFIG_KOI
++pgd_t *koi_pgd_alloc(void);
++#endif
++
+ static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t ptep,
+ pmdval_t prot)
+ {
+diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
+index e4944d517c99..7f60e568c964 100644
+--- a/arch/arm64/include/asm/pgtable-hwdef.h
++++ b/arch/arm64/include/asm/pgtable-hwdef.h
+@@ -84,6 +84,13 @@
+ #define CONT_PMD_SIZE (CONT_PMDS * PMD_SIZE)
+ #define CONT_PMD_MASK (~(CONT_PMD_SIZE - 1))
+
++#ifdef CONFIG_IEE
++#define PGD_APT_RO (_AT(pudval_t, 1) << 62)
++#endif
++#define PGD_APT (_AT(pudval_t, 1) << 61)
++#define PGD_PXN (_AT(pudval_t, 1) << 59)
++#define PGD_UXN (_AT(pudval_t, 1) << 60)
++
+ /*
+ * Hardware page table definitions.
+ *
+@@ -285,6 +292,10 @@
+ #define TCR_TCMA0 (UL(1) << 57)
+ #define TCR_TCMA1 (UL(1) << 58)
+
++#ifdef CONFIG_IEE
++#define TCR_HPD1 (UL(1) << 42)
++#endif
++
+ /*
+ * TTBR.
+ */
+diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
+index 8d68d00de0a4..6f8d5b85bfd7 100644
+--- a/arch/arm64/include/asm/pgtable.h
++++ b/arch/arm64/include/asm/pgtable.h
+@@ -34,6 +34,9 @@
+ #include <linux/mm_types.h>
+ #include <linux/sched.h>
+ #include <linux/page_table_check.h>
++#ifdef CONFIG_PTP
++#include <asm/iee.h>
++#endif
+
+ #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
+@@ -156,6 +159,30 @@ static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
+ #define pud_access_permitted(pud, write) \
+ (pte_access_permitted(pud_pte(pud), (write)))
+
++#ifdef CONFIG_PTP
++static inline bool in_tramp_pgdir(void *addr);
++extern unsigned long long iee_rw_gate(int flag, ...);
++
++static void iee_set_tramp_pgd_pre_init(pgd_t *pgdp, pgd_t pgd)
++{
++ iee_rw_gate(IEE_OP_SET_TRAMP_PGD, pgdp, pgd);
++}
++
++static noinline pteval_t iee_set_xchg_relaxed(pte_t *ptep, pteval_t pteval)
++{
++ pteval_t ret;
++ ret = iee_rw_gate(IEE_OP_SET_XCHG, ptep, pteval);
++ return (pteval_t)ret;
++}
++
++static noinline pteval_t iee_set_cmpxchg_relaxed(pte_t *ptep, pteval_t old_pteval, pteval_t new_pteval)
++{
++ pteval_t ret;
++ ret = iee_rw_gate(IEE_OP_SET_CMPXCHG, ptep, old_pteval, new_pteval);
++ return (pteval_t)ret;
++}
++#endif
++
+ static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
+ {
+ pte_val(pte) &= ~pgprot_val(prot);
+@@ -262,6 +289,64 @@ static inline pte_t pte_mkdevmap(pte_t pte)
+
+ static inline void __set_pte(pte_t *ptep, pte_t pte)
+ {
++#ifdef CONFIG_KOI
++ if (!pte_none(pte)) {
++ pte = __pte(pte_val(pte) | PTE_NG);
++ }
++#endif
++#ifdef CONFIG_PTP
++ iee_rw_gate(IEE_OP_SET_PTE, ptep, pte);
++ dsb(ishst);
++ isb();
++#else
++ WRITE_ONCE(*ptep, pte);
++
++ /*
++ * Only if the new pte is valid and kernel, otherwise TLB maintenance
++ * or update_mmu_cache() have the necessary barriers.
++ */
++ if (pte_valid_not_user(pte)) {
++ dsb(ishst);
++ isb();
++ }
++#endif
++}
++
++
++#ifdef CONFIG_PTP
++static inline void iee_set_bm_pte(pte_t *ptep, pte_t pte)
++{
++ // If it is pre init, write once.
++ // Else, write once will cause exception. So it is safe.
++ unsigned long flags;
++ unsigned long res;
++ local_irq_save(flags);
++ asm volatile("at s1e1r, %0"::"r"(__phys_to_iee(__pa_symbol(ptep))));
++ isb();
++ res = read_sysreg(par_el1);
++ local_irq_restore(flags);
++ if(res & 0x1)
++ WRITE_ONCE(*ptep,pte);
++ else
++ iee_rw_gate(IEE_OP_SET_BM_PTE, ptep, pte);
++
++ /*
++ * Only if the new pte is valid and kernel, otherwise TLB maintenance
++ * or update_mmu_cache() have the necessary barriers.
++ */
++ if (pte_valid_not_user(pte)) {
++ dsb(ishst);
++ isb();
++ }
++}
++
++static inline void iee_set_fixmap_pte_pre_init(pte_t *ptep, pte_t pte)
++{
++#ifdef CONFIG_KOI
++ if (!pte_none(pte)) {
++ pte = __pte(pte_val(pte) | PTE_NG);
++ }
++#endif
+ WRITE_ONCE(*ptep, pte);
+
+ /*
+@@ -273,6 +358,7 @@ static inline void __set_pte(pte_t *ptep, pte_t pte)
+ isb();
+ }
+ }
++#endif
+
+ static inline pte_t __ptep_get(pte_t *ptep)
+ {
+@@ -546,6 +632,95 @@ static inline void __set_pte_at(struct mm_struct *mm,
+ __set_pte(ptep, pte);
+ }
+
++#ifdef CONFIG_IEE
++static inline void iee_set_pte_upage(pte_t *ptep, pte_t pte)
++{
++#ifdef CONFIG_PTP
++ iee_rw_gate(IEE_OP_SET_PTE_U, ptep, pte);
++ dsb(ishst);
++ isb();
++#else
++ WRITE_ONCE(*ptep, pte);
++ if (pte_valid_not_user(pte)) {
++ dsb(ishst);
++ isb();
++ }
++#endif
++}
++
++static inline void iee_set_pte_ppage(pte_t *ptep, pte_t pte)
++{
++#ifdef CONFIG_PTP
++ iee_rw_gate(IEE_OP_SET_PTE_P, ptep, pte);
++#else
++ WRITE_ONCE(*ptep, pte);
++#endif
++ if (pte_valid_not_user(pte)) {
++ dsb(ishst);
++ isb();
++ }
++}
++#endif
++
++#ifdef CONFIG_PTP
++static inline void set_pmd(pmd_t *pmdp, pmd_t pmd);
++static inline void __set_pmd_at(struct mm_struct *mm, unsigned long addr,
++ pmd_t *pmdp, pmd_t pmd)
++{
++ if (pte_present(pmd_pte(pmd)) && pte_user_exec(pmd_pte(pmd)) && !pte_special(pmd_pte(pmd)))
++ __sync_icache_dcache(pmd_pte(pmd));
++
++ /*
++ * If the PTE would provide user space access to the tags associated
++ * with it then ensure that the MTE tags are synchronised. Although
++ * pte_access_permitted() returns false for exec only mappings, they
++ * don't expose tags (instruction fetches don't check tags).
++ */
++ if (system_supports_mte() && pte_access_permitted(pmd_pte(pmd), false) &&
++ !pte_special(pmd_pte(pmd)) && pte_tagged(pmd_pte(pmd)))
++ mte_sync_tags(pmd_pte(pmd), PMD_SIZE >> PAGE_SHIFT);
++
++ __check_safe_pte_update(mm, (pte_t *)pmdp, pmd_pte(pmd));
++
++ set_pmd(pmdp, pmd);
++}
++
++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_pmd_at(mm, addr, pmdp, pmd);
++}
++
++static inline void set_pud(pud_t *pudp, pud_t pud);
++static inline void __set_pud_at(struct mm_struct *mm, unsigned long addr,
++ pud_t *pudp, pud_t pud)
++{
++ if (pte_present(pud_pte(pud)) && pte_user_exec(pud_pte(pud)) && !pte_special(pud_pte(pud)))
++ __sync_icache_dcache(pud_pte(pud));
++
++ /*
++ * If the PTE would provide user space access to the tags associated
++ * with it then ensure that the MTE tags are synchronised. Although
++ * pte_access_permitted() returns false for exec only mappings, they
++ * don't expose tags (instruction fetches don't check tags).
++ */
++ if (system_supports_mte() && pte_access_permitted(pud_pte(pud), false) &&
++ !pte_special(pud_pte(pud)) && pte_tagged(pud_pte(pud)))
++ mte_sync_tags(pud_pte(pud), PUD_SIZE >> PAGE_SHIFT);
++
++ __check_safe_pte_update(mm, (pte_t *)pudp, pud_pte(pud));
++
++ set_pud(pudp, pud);
++}
++
++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_pud_at(mm, addr, pudp, pud);
++}
++#else
+ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp, pmd_t pmd)
+ {
+@@ -561,7 +736,7 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
+ return __set_pte_at(mm, addr, (pte_t *)pudp, pud_pte(pud),
+ PUD_SIZE >> PAGE_SHIFT);
+ }
+-
++#endif
+ #define __p4d_to_phys(p4d) __pte_to_phys(p4d_pte(p4d))
+ #define __phys_to_p4d_val(phys) __phys_to_pte_val(phys)
+
+@@ -640,7 +815,14 @@ static inline bool in_swapper_pgdir(void *addr)
+ ((unsigned long)swapper_pg_dir & PAGE_MASK);
+ }
+
+-static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
++#ifdef CONFIG_PTP
++static inline bool in_tramp_pgdir(void *addr)
++{
++ return ((unsigned long)addr & PAGE_MASK) ==
++ ((unsigned long)tramp_pg_dir & PAGE_MASK);
++}
++
++static inline void iee_set_fixmap_pmd_pre_init(pmd_t *pmdp, pmd_t pmd)
+ {
+ #ifdef __PAGETABLE_PMD_FOLDED
+ if (in_swapper_pgdir(pmdp)) {
+@@ -648,7 +830,6 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
+ return;
+ }
+ #endif /* __PAGETABLE_PMD_FOLDED */
+-
+ WRITE_ONCE(*pmdp, pmd);
+
+ if (pmd_valid(pmd)) {
+@@ -656,6 +837,32 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
+ isb();
+ }
+ }
++#endif
++
++static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
++{
++#ifdef __PAGETABLE_PMD_FOLDED
++ if (in_swapper_pgdir(pmdp)) {
++ set_swapper_pgd((pgd_t *)pmdp, __pgd(pmd_val(pmd)));
++ return;
++ }
++#endif /* __PAGETABLE_PMD_FOLDED */
++#ifdef CONFIG_KOI
++ pmdval_t val = pmd_val(pmd);
++ if (pmd_valid(pmd) && !(val & PMD_TABLE_BIT)) {
++ pmd = __pmd(val | PMD_SECT_NG);
++ }
++#endif
++#ifdef CONFIG_PTP
++ iee_rw_gate(IEE_OP_SET_PMD, pmdp, pmd);
++#else
++ WRITE_ONCE(*pmdp, pmd);
++#endif
++ if (pmd_valid(pmd)) {
++ dsb(ishst);
++ isb();
++ }
++}
+
+ static inline void pmd_clear(pmd_t *pmdp)
+ {
+@@ -675,6 +882,12 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
+ /* Find an entry in the third-level page table. */
+ #define pte_offset_phys(dir,addr) (pmd_page_paddr(READ_ONCE(*(dir))) + pte_index(addr) * sizeof(pte_t))
+
++#ifdef CONFIG_PTP
++#define pte_set_fixmap_init(addr) ((pte_t *)iee_set_fixmap_offset_pre_init(FIX_PTE, addr))
++#define pte_set_fixmap_offset_init(pmd, addr) pte_set_fixmap_init(pte_offset_phys(pmd, addr))
++#define pte_clear_fixmap_init() clear_fixmap_init(FIX_PTE)
++#endif
++
+ #define pte_set_fixmap(addr) ((pte_t *)set_fixmap_offset(FIX_PTE, addr))
+ #define pte_set_fixmap_offset(pmd, addr) pte_set_fixmap(pte_offset_phys(pmd, addr))
+ #define pte_clear_fixmap() clear_fixmap(FIX_PTE)
+@@ -703,7 +916,9 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
+ #define pud_user(pud) pte_user(pud_pte(pud))
+ #define pud_user_exec(pud) pte_user_exec(pud_pte(pud))
+
+-static inline void set_pud(pud_t *pudp, pud_t pud)
++
++#ifdef CONFIG_PTP
++static inline void iee_set_fixmap_pud_pre_init(pud_t *pudp, pud_t pud)
+ {
+ #ifdef __PAGETABLE_PUD_FOLDED
+ if (in_swapper_pgdir(pudp)) {
+@@ -711,7 +926,6 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
+ return;
+ }
+ #endif /* __PAGETABLE_PUD_FOLDED */
+-
+ WRITE_ONCE(*pudp, pud);
+
+ if (pud_valid(pud)) {
+@@ -719,6 +933,33 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
+ isb();
+ }
+ }
++#endif
++
++static inline void set_pud(pud_t *pudp, pud_t pud)
++{
++#ifdef __PAGETABLE_PUD_FOLDED
++ if (in_swapper_pgdir(pudp)) {
++ set_swapper_pgd((pgd_t *)pudp, __pgd(pud_val(pud)));
++ return;
++ }
++#endif /* __PAGETABLE_PUD_FOLDED */
++#ifdef CONFIG_KOI
++ pudval_t val = pud_val(pud);
++ if (pud_valid(pud) && !(val & PUD_TABLE_BIT)) {
++ // There is no PUD_SEC_NG, so we use PMD_SECT_NG instead.
++ pud = __pud(val | PMD_SECT_NG);
++ }
++#endif
++#ifdef CONFIG_PTP
++ iee_rw_gate(IEE_OP_SET_PUD, pudp, pud);
++#else
++ WRITE_ONCE(*pudp, pud);
++#endif
++ if (pud_valid(pud)) {
++ dsb(ishst);
++ isb();
++ }
++}
+
+ static inline void pud_clear(pud_t *pudp)
+ {
+@@ -738,6 +979,12 @@ static inline pmd_t *pud_pgtable(pud_t pud)
+ /* Find an entry in the second-level page table. */
+ #define pmd_offset_phys(dir, addr) (pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t))
+
++#ifdef CONFIG_PTP
++#define pmd_set_fixmap_init(addr) ((pmd_t *)iee_set_fixmap_offset_pre_init(FIX_PMD, addr))
++#define pmd_set_fixmap_offset_init(pud, addr) pmd_set_fixmap_init(pmd_offset_phys(pud, addr))
++#define pmd_clear_fixmap_init() clear_fixmap_init(FIX_PMD)
++#endif
++
+ #define pmd_set_fixmap(addr) ((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
+ #define pmd_set_fixmap_offset(pud, addr) pmd_set_fixmap(pmd_offset_phys(pud, addr))
+ #define pmd_clear_fixmap() clear_fixmap(FIX_PMD)
+@@ -769,15 +1016,26 @@ static inline pmd_t *pud_pgtable(pud_t pud)
+ #define p4d_none(p4d) (!p4d_val(p4d))
+ #define p4d_bad(p4d) (!(p4d_val(p4d) & 2))
+ #define p4d_present(p4d) (p4d_val(p4d))
++#define p4d_valid(p4d) pte_valid(p4d_pte(p4d))
+
+ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
+ {
+- if (in_swapper_pgdir(p4dp)) {
++ if (in_swapper_pgdir(p4dp))
++ {
+ set_swapper_pgd((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
+ return;
+ }
+
++#ifdef CONFIG_PTP
++ if(in_tramp_pgdir(p4dp))
++ {
++ iee_set_tramp_pgd_pre_init((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
++ return;
++ }
++ iee_rw_gate(IEE_OP_SET_P4D, p4dp, p4d);
++#else
+ WRITE_ONCE(*p4dp, p4d);
++#endif
+ dsb(ishst);
+ isb();
+ }
+@@ -800,6 +1058,12 @@ static inline pud_t *p4d_pgtable(p4d_t p4d)
+ /* Find an entry in the first-level page table. */
+ #define pud_offset_phys(dir, addr) (p4d_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
+
++#ifdef CONFIG_PTP
++#define pud_set_fixmap_init(addr) ((pud_t *)iee_set_fixmap_offset_pre_init(FIX_PUD, addr))
++#define pud_set_fixmap_offset_init(p4d, addr) pud_set_fixmap_init(pud_offset_phys(p4d, addr))
++#define pud_clear_fixmap_init() clear_fixmap_init(FIX_PUD)
++#endif
++
+ #define pud_set_fixmap(addr) ((pud_t *)set_fixmap_offset(FIX_PUD, addr))
+ #define pud_set_fixmap_offset(p4d, addr) pud_set_fixmap(pud_offset_phys(p4d, addr))
+ #define pud_clear_fixmap() clear_fixmap(FIX_PUD)
+@@ -826,6 +1090,10 @@ static inline pud_t *p4d_pgtable(p4d_t p4d)
+ #define pgd_ERROR(e) \
+ pr_err("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e))
+
++#ifdef CONFIG_PTP
++#define pgd_set_fixmap_init(addr) ((pgd_t *)iee_set_fixmap_offset_pre_init(FIX_PGD, addr))
++#define pgd_clear_fixmap_init() clear_fixmap_init(FIX_PGD)
++#endif
+ #define pgd_set_fixmap(addr) ((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
+ #define pgd_clear_fixmap() clear_fixmap(FIX_PGD)
+
+@@ -912,8 +1180,13 @@ static inline int __ptep_test_and_clear_young(struct vm_area_struct *vma,
+ do {
+ old_pte = pte;
+ pte = pte_mkold(pte);
++ #ifdef CONFIG_PTP
++ pte_val(pte) = iee_set_cmpxchg_relaxed(ptep,
++ pte_val(old_pte), pte_val(pte));
++ #else
+ pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
+ pte_val(old_pte), pte_val(pte));
++ #endif
+ } while (pte_val(pte) != pte_val(old_pte));
+
+ return pte_young(pte);
+@@ -952,8 +1225,12 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
+ static inline pte_t __ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+ {
++ #ifdef CONFIG_PTP
++ pteval_t pteval= iee_set_xchg_relaxed((pte_t *)&pte_val(*ptep), (pteval_t)0);
++ pte_t pte = __pte(pteval);
++ #else
+ pte_t pte = __pte(xchg_relaxed(&pte_val(*ptep), 0));
+-
++ #endif
+ page_table_check_pte_clear(mm, pte);
+
+ return pte;
+@@ -995,7 +1272,12 @@ static inline pte_t __get_and_clear_full_ptes(struct mm_struct *mm,
+ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
+ unsigned long address, pmd_t *pmdp)
+ {
++ #ifdef CONFIG_PTP
++ pteval_t pteval= iee_set_xchg_relaxed((pte_t *)&pmd_val(*pmdp), (pteval_t)0);
++ pmd_t pmd = __pmd(pteval);
++ #else
+ pmd_t pmd = __pmd(xchg_relaxed(&pmd_val(*pmdp), 0));
++ #endif
+
+ page_table_check_pmd_clear(mm, pmd);
+
+@@ -1012,8 +1294,12 @@ static inline void ___ptep_set_wrprotect(struct mm_struct *mm,
+ do {
+ old_pte = pte;
+ pte = pte_wrprotect(pte);
++ #ifdef CONFIG_PTP
++ pte_val(pte) = iee_set_cmpxchg_relaxed(ptep,pte_val(old_pte), pte_val(pte));
++ #else
+ pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
+ pte_val(old_pte), pte_val(pte));
++ #endif
+ } while (pte_val(pte) != pte_val(old_pte));
+ }
+
+@@ -1049,7 +1335,11 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp, pmd_t pmd)
+ {
+ page_table_check_pmd_set(vma->vm_mm, pmdp, pmd);
++ #ifdef CONFIG_PTP
++ return __pmd((pmdval_t)iee_set_xchg_relaxed((pte_t *)&pmd_val(*pmdp), (pmdval_t)pmd_val(pmd)));
++ #else
+ return __pmd(xchg_relaxed(&pmd_val(*pmdp), pmd_val(pmd)));
++ #endif
+ }
+ #endif
+
+diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h
+index d2e0306e65d3..8352e92d4536 100644
+--- a/arch/arm64/include/asm/pointer_auth.h
++++ b/arch/arm64/include/asm/pointer_auth.h
+@@ -108,8 +108,13 @@ static __always_inline void ptrauth_enable(void)
+ {
+ if (!system_supports_address_auth())
+ return;
++ #ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, 0, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB |
++ SCTLR_ELx_ENDA | SCTLR_ELx_ENDB));
++ #else
+ sysreg_clear_set(sctlr_el1, 0, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB |
+ SCTLR_ELx_ENDA | SCTLR_ELx_ENDB));
++ #endif
+ isb();
+ }
+
+diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
+index 42358b8d678e..1e2d11e57fe3 100644
+--- a/arch/arm64/include/asm/sysreg.h
++++ b/arch/arm64/include/asm/sysreg.h
+@@ -1116,6 +1116,64 @@
+ write_sysreg_s(__scs_new, sysreg); \
+ } while (0)
+
++
++#ifdef CONFIG_IEE
++
++#define SYS_TCR_IEE_SI TCR_HPD1 | TCR_A1
++
++extern void iee_rwx_gate_entry(int flag, ...);
++#define IEE_SI_TEST 0
++#define IEE_WRITE_sctlr_el1 1
++#define IEE_WRITE_ttbr0_el1 2
++#define IEE_WRITE_vbar_el1 3
++#define IEE_WRITE_tcr_el1 4
++#define IEE_WRITE_mdscr_el1 5
++#define IEE_WRITE_AFSR0 10
++
++#define sysreg_clear_set_iee_si(sysreg, clear, set) do { \
++ u64 __scs_val = read_sysreg(sysreg); \
++ u64 __scs_new = (__scs_val & ~(u64)(clear)) | (set); \
++ if (__scs_new != __scs_val) \
++ iee_rwx_gate_entry(IEE_WRITE_##sysreg, __scs_new); \
++} while (0)
++
++#define IEE_SI_WRITE_DAIF_SEL "msr daifclr, #0xf\n\t" \
++ "tbnz %x0, #6, 114221f\n\t" \
++ "tbnz %x0, #7, 114210f\n\t" \
++ "tbnz %x0, #8, 114100f\n\t" \
++ "msr daifset, #0b000\n\t" \
++ "b 114514f\n\t" \
++"114221:\n\t" \
++ "tbnz %x0, #7, 114211f\n\t" \
++ "tbnz %x0, #8, 114101f\n\t" \
++ "msr daifset, #0b001\n\t" \
++ "b 114514f\n\t" \
++"114211:\n\t" \
++ "tbnz %x0, #8, 114111f\n\t" \
++ "msr daifset, #0b011\n\t" \
++ "b 114514f\n\t" \
++"114210:\n\t" \
++ "tbnz %x0, #8, 114110f\n\t" \
++ "msr daifset, #0b010\n\t" \
++ "b 114514f\n\t" \
++"114100:\n\t" \
++ "msr daifset, #0b100\n\t" \
++ "b 114514f\n\t" \
++"114101:\n\t" \
++ "msr daifset, #0b101\n\t" \
++ "b 114514f\n\t" \
++"114110:\n\t" \
++ "msr daifset, #0b110\n\t" \
++ "b 114514f\n\t" \
++"114111:\n\t" \
++ "msr daifset, #0b111\n\t" \
++"114514:\n\t"
++
++#define iee_si_write_daif(v) do { \
++ u64 __val = (u64)(v); \
++ asm volatile(IEE_SI_WRITE_DAIF_SEL: : "rZ" (__val));} while (0)
++#endif
++
+ #define read_sysreg_par() ({ \
+ u64 par; \
+ asm(ALTERNATIVE("nop", "dmb sy", ARM64_WORKAROUND_1508412)); \
+diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
+index 2c29239d05c3..955f99317790 100644
+--- a/arch/arm64/include/asm/tlb.h
++++ b/arch/arm64/include/asm/tlb.h
+@@ -11,8 +11,17 @@
+ #include <linux/pagemap.h>
+ #include <linux/swap.h>
+
++#ifdef CONFIG_PTP
++#include <linux/iee-func.h>
++#endif
++
+ static inline void __tlb_remove_table(void *_table)
+ {
++#ifdef CONFIG_PTP
++ unsigned long iee_addr = __phys_to_iee(page_to_phys((struct page *)_table));
++ set_iee_page_invalid(iee_addr);
++ iee_set_logical_mem_rw((unsigned long)page_address((struct page *)_table));
++#endif
+ free_page_and_swap_cache((struct page *)_table);
+ }
+
+diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
+index 831c314d75ff..7775628528c6 100644
+--- a/arch/arm64/include/asm/tlbflush.h
++++ b/arch/arm64/include/asm/tlbflush.h
+@@ -49,6 +49,7 @@
+
+ #define __tlbi(op, ...) __TLBI_N(op, ##__VA_ARGS__, 1, 0)
+
++
+ #define __tlbi_user(op, arg) do { \
+ if (arm64_kernel_unmapped_at_el0()) \
+ __tlbi(op, (arg) | USER_ASID_FLAG); \
+@@ -258,6 +259,10 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
+ asid = __TLBI_VADDR(0, ASID(mm));
+ __tlbi(aside1is, asid);
+ __tlbi_user(aside1is, asid);
++ #if defined(CONFIG_IEE) || defined (CONFIG_KOI)
++ if (!arm64_kernel_unmapped_at_el0())
++ __tlbi(aside1is, asid | USER_ASID_FLAG);
++ #endif
+ dsb(ish);
+ mmu_notifier_arch_invalidate_secondary_tlbs(mm, 0, -1UL);
+ }
+@@ -273,6 +278,10 @@ static inline void __flush_tlb_page_nosync(struct mm_struct *mm,
+ __tlbi_user(vale1is, addr);
+ mmu_notifier_arch_invalidate_secondary_tlbs(mm, uaddr & PAGE_MASK,
+ (uaddr & PAGE_MASK) + PAGE_SIZE);
++ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++ if (!arm64_kernel_unmapped_at_el0())
++ __tlbi(vale1is, addr | USER_ASID_FLAG);
++ #endif
+ }
+
+ static inline void flush_tlb_page_nosync(struct vm_area_struct *vma,
+@@ -366,6 +375,45 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
+ * 2. If there is 1 page remaining, flush it through non-range operations. Range
+ * operations can only span an even number of pages.
+ */
++#if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++#define __flush_tlb_range_op(op, start, pages, stride, \
++ asid, tlb_level, tlbi_user) \
++do { \
++ int num = 0; \
++ int scale = 0; \
++ unsigned long addr; \
++ \
++ while (pages > 0) { \
++ if (!system_supports_tlb_range() || \
++ pages % 2 == 1) { \
++ addr = __TLBI_VADDR(start, asid); \
++ __tlbi_level(op, addr, tlb_level); \
++ if (!arm64_kernel_unmapped_at_el0()) /* added for IEE */ \
++ __tlbi_level(op, addr | USER_ASID_FLAG, tlb_level); \
++ if (tlbi_user) \
++ __tlbi_user_level(op, addr, tlb_level); \
++ start += stride; \
++ pages -= stride >> PAGE_SHIFT; \
++ continue; \
++ } \
++ \
++ num = __TLBI_RANGE_NUM(pages, scale); \
++ if (num >= 0) { \
++ addr = __TLBI_VADDR_RANGE(start, asid, scale, \
++ num, tlb_level); \
++ __tlbi(r##op, addr); \
++ if (!arm64_kernel_unmapped_at_el0()) /* added for IEE */ \
++ __tlbi(r##op, addr | USER_ASID_FLAG); \
++ if (tlbi_user) \
++ __tlbi_user(r##op, addr); \
++ start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
++ pages -= __TLBI_RANGE_PAGES(num, scale); \
++ } \
++ scale++; \
++ } \
++} while (0)
++
++#else
+ #define __flush_tlb_range_op(op, start, pages, stride, \
+ asid, tlb_level, tlbi_user) \
+ do { \
+@@ -399,6 +447,8 @@ do { \
+ } \
+ } while (0)
+
++#endif //if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++
+ #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
+ __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false)
+
+@@ -467,7 +517,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
+ return;
+ }
+
+- start = __TLBI_VADDR(start, 0);
++ start = __TLBI_VADDR(start, 0);
+ end = __TLBI_VADDR(end, 0);
+
+ dsb(ishst);
+@@ -483,9 +533,9 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
+ */
+ static inline void __flush_tlb_kernel_pgtable(unsigned long kaddr)
+ {
+- unsigned long addr = __TLBI_VADDR(kaddr, 0);
+-
+- dsb(ishst);
++ unsigned long addr = __TLBI_VADDR(kaddr, 0);
++
++ dsb(ishst);
+ __tlbi(vaae1is, addr);
+ dsb(ish);
+ isb();
+diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
+index 21ef9c21a400..44eb76cc54d7 100644
+--- a/arch/arm64/kernel/Makefile
++++ b/arch/arm64/kernel/Makefile
+@@ -36,6 +36,8 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
+ syscall.o proton-pack.o idreg-override.o idle.o \
+ patching.o
+
++obj-y += iee/
++obj-$(CONFIG_KOI) += koi/
+ obj-$(CONFIG_AARCH32_EL0) += binfmt_elf32.o sys32.o signal32.o \
+ sys_compat.o
+ obj-$(CONFIG_AARCH32_EL0) += sigreturn32.o
+diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
+index fd0f291e215e..c008e46b5fc0 100644
+--- a/arch/arm64/kernel/armv8_deprecated.c
++++ b/arch/arm64/kernel/armv8_deprecated.c
+@@ -306,11 +306,19 @@ static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
+
+ static int cp15_barrier_set_hw_mode(bool enable)
+ {
++#ifdef CONFIG_IEE
++ if (enable)
++ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_CP15BEN);
++ else
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_CP15BEN, 0);
++ return 0;
++#else
+ if (enable)
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_CP15BEN);
+ else
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_CP15BEN, 0);
+ return 0;
++#endif
+ }
+
+ static bool try_emulate_cp15_barrier(struct pt_regs *regs, u32 insn)
+@@ -341,11 +349,19 @@ static int setend_set_hw_mode(bool enable)
+ if (!cpu_supports_mixed_endian_el0())
+ return -EINVAL;
+
++#ifdef CONFIG_IEE
++ if (enable)
++ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_CP15BEN);
++ else
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_CP15BEN, 0);
++ return 0;
++#else
+ if (enable)
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_SED, 0);
+ else
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_SED);
+ return 0;
++#endif
+ }
+
+ static int __a32_setend_handler(struct pt_regs *regs, u32 big_endian)
+diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
+index e997ad275afb..e105f633355a 100644
+--- a/arch/arm64/kernel/asm-offsets.c
++++ b/arch/arm64/kernel/asm-offsets.c
+@@ -97,6 +97,17 @@ int main(void)
+ DEFINE(FREGS_DIRECT_TRAMP, offsetof(struct ftrace_regs, direct_tramp));
+ #endif
+ DEFINE(FREGS_SIZE, sizeof(struct ftrace_regs));
++#ifdef CONFIG_IEE
++ DEFINE(iee_from_token_offset, offsetof(struct task_token, iee_stack));
++ DEFINE(kernel_from_token_offset, offsetof(struct task_token, kernel_stack));
++ DEFINE(mm_from_task_offset, offsetof(struct task_struct, mm));
++#endif
++#ifdef CONFIG_KOI
++ DEFINE(koi_kernel_from_token_offset, offsetof(struct task_token, koi_kernel_stack));
++ DEFINE(koi_from_token_offset, offsetof(struct task_token, koi_stack));
++ DEFINE(ttbr1_from_token_offset, offsetof(struct task_token, current_ttbr1));
++ DEFINE(koi_stack_base_from_token_offset, offsetof(struct task_token, koi_stack_base));
++#endif
+ BLANK();
+ #endif
+ #ifdef CONFIG_AARCH32_EL0
+diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
+index 46813132a09f..412006aa323c 100644
+--- a/arch/arm64/kernel/cpu_errata.c
++++ b/arch/arm64/kernel/cpu_errata.c
+@@ -80,7 +80,11 @@ hisilicon_1980005_enable(const struct arm64_cpu_capabilities *__unused)
+ __set_bit(ARM64_HAS_CACHE_IDC, system_cpucaps);
+ arm64_ftr_reg_ctrel0.sys_val |= BIT(CTR_EL0_IDC_SHIFT);
+ arm64_ftr_reg_ctrel0.strict_mask &= ~BIT(CTR_EL0_IDC_SHIFT);
++#ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_UCT, 0);
++#else
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
++#endif
+ }
+ #endif
+
+@@ -132,7 +136,11 @@ cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
+ enable_uct_trap = true;
+
+ if (enable_uct_trap)
++#ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_UCT, 0);
++#else
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
++#endif
+ }
+
+ #ifdef CONFIG_ARM64_ERRATUM_1463225
+@@ -147,7 +155,11 @@ has_cortex_a76_erratum_1463225(const struct arm64_cpu_capabilities *entry,
+ static void __maybe_unused
+ cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused)
+ {
++#ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_UCI, 0);
++#else
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCI, 0);
++#endif
+ }
+
+ #ifdef CONFIG_HISILICON_ERRATUM_HIP08_RU_PREFETCH
+diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
+index 74e445251b51..ebc1e776b175 100644
+--- a/arch/arm64/kernel/cpufeature.c
++++ b/arch/arm64/kernel/cpufeature.c
+@@ -94,6 +94,10 @@
+ #include <asm/vectors.h>
+ #include <asm/virt.h>
+
++#ifdef CONFIG_IEE
++#include <asm/iee-si.h>
++#endif
++
+ /* Kernel representation of AT_HWCAP and AT_HWCAP2 */
+ static DECLARE_BITMAP(elf_hwcap, MAX_CPU_FEATURES) __read_mostly;
+
+@@ -1612,7 +1616,11 @@ static void cpu_emulate_effective_ctr(const struct arm64_cpu_capabilities *__unu
+ * value.
+ */
+ if (!(read_cpuid_cachetype() & BIT(CTR_EL0_IDC_SHIFT)))
++#ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_UCT, 0);
++#else
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
++#endif
+ }
+
+ static bool has_cache_dic(const struct arm64_cpu_capabilities *entry,
+@@ -1873,7 +1881,11 @@ static inline void __cpu_enable_hw_dbm(void)
+ {
+ u64 tcr = read_sysreg(tcr_el1) | TCR_HD;
+
++#ifdef CONFIG_IEE
++ iee_rwx_gate_entry(IEE_WRITE_tcr_el1, tcr);
++#else
+ write_sysreg(tcr, tcr_el1);
++#endif
+ isb();
+ local_flush_tlb_all();
+ }
+@@ -2056,7 +2068,9 @@ static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
+ */
+ WARN_ON_ONCE(in_interrupt());
+
++ #ifndef CONFIG_IEE
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_SPAN, 0);
++ #endif
+ set_pstate_pan(1);
+ }
+ #endif /* CONFIG_ARM64_PAN */
+@@ -2121,7 +2135,11 @@ static bool has_generic_auth(const struct arm64_cpu_capabilities *entry,
+ static void cpu_enable_e0pd(struct arm64_cpu_capabilities const *cap)
+ {
+ if (this_cpu_has_cap(ARM64_HAS_E0PD))
++#ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(tcr_el1, 0, TCR_E0PD1);
++#else
+ sysreg_clear_set(tcr_el1, 0, TCR_E0PD1);
++#endif
+ }
+ #endif /* CONFIG_ARM64_E0PD */
+
+@@ -2214,7 +2232,11 @@ static void nmi_enable(const struct arm64_cpu_capabilities *__unused)
+ * avoid leaving things masked.
+ */
+ _allint_clear();
++ #ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_SPINTMASK, SCTLR_EL1_NMI);
++ #else
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_SPINTMASK, SCTLR_EL1_NMI);
++ #endif
+ isb();
+ }
+ #endif
+@@ -2229,7 +2251,11 @@ static void bti_enable(const struct arm64_cpu_capabilities *__unused)
+ * So, be strict and forbid other BRs using other registers to
+ * jump onto a PACIxSP instruction:
+ */
++#ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_BT0 | SCTLR_EL1_BT1);
++#else
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_BT0 | SCTLR_EL1_BT1);
++#endif
+ isb();
+ }
+ #endif /* CONFIG_ARM64_BTI */
+@@ -2237,7 +2263,11 @@ static void bti_enable(const struct arm64_cpu_capabilities *__unused)
+ #ifdef CONFIG_ARM64_MTE
+ static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap)
+ {
++ #ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_ELx_ATA | SCTLR_EL1_ATA0);
++ #else
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_ATA | SCTLR_EL1_ATA0);
++ #endif
+
+ mte_cpu_setup();
+
+@@ -2271,7 +2301,11 @@ static bool is_kvm_protected_mode(const struct arm64_cpu_capabilities *entry, in
+
+ static void cpu_trap_el0_impdef(const struct arm64_cpu_capabilities *__unused)
+ {
++ #ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_TIDCP);
++ #else
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_TIDCP);
++ #endif
+ }
+
+ static void cpu_enable_dit(const struct arm64_cpu_capabilities *__unused)
+@@ -2281,7 +2315,11 @@ static void cpu_enable_dit(const struct arm64_cpu_capabilities *__unused)
+
+ static void cpu_enable_mops(const struct arm64_cpu_capabilities *__unused)
+ {
++ #ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_EL1_MSCEn);
++ #else
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_MSCEn);
++ #endif
+ }
+
+ /* Internal helper functions to match cpu capability type */
+@@ -3475,6 +3513,43 @@ static void __init setup_system_capabilities(void)
+ enable_cpu_capabilities(SCOPE_ALL & ~SCOPE_BOOT_CPU);
+ }
+
++#ifdef CONFIG_IEE
++
++static void iee_si_test_end(void)
++{
++ pr_info("IEE: testing iee_exec_entry sctlr...\n");
++ iee_rwx_gate_entry(IEE_WRITE_SCTLR, read_sysreg(sctlr_el1)& ~SCTLR_ELx_M);
++ pr_info("IEE: testing iee_exec_entry ttbr0_el1...\n");
++ iee_rwx_gate_entry(IEE_WRITE_TTBR0, read_sysreg(ttbr0_el1));
++ pr_info("IEE: testing iee_exec_entry vbar...\n");
++ iee_rwx_gate_entry(IEE_WRITE_VBAR, read_sysreg(vbar_el1));
++ pr_info("IEE: testing iee_exec_entry tcr...\n");
++ iee_rwx_gate_entry(IEE_WRITE_TCR, read_sysreg(tcr_el1));
++ // pr_info("IEE: testing iee_exec_entry mdscr...\n");
++ // iee_rwx_gate_entry(IEE_WRITE_MDSCR, read_sysreg(mdscr_el1));
++ // pr_info("IEE: testing iee_exec_entry afsr0...\n");
++ // iee_rwx_gate_entry(IEE_WRITE_AFSR0);
++ #ifdef CONFIG_KOI
++ write_sysreg(read_sysreg(ttbr0_el1)+0x3000000000000, ttbr0_el1);
++ pr_info("IEE: current TTBR1_EL1:%llx, TTBR0:%llx\n", read_sysreg(ttbr1_el1), read_sysreg(ttbr0_el1));
++ pr_info("IEE: testing iee_exec_entry switch to koi...\n");
++ iee_rwx_gate_entry(IEE_SWITCH_TO_KOI, phys_to_ttbr(__pa_symbol(swapper_pg_dir)));
++ pr_info("IEE: current TTBR1_EL1:%llx, TTBR0:%llx\n", read_sysreg(ttbr1_el1), read_sysreg(ttbr0_el1));
++ pr_info("IEE: testing iee_exec_entry switch to kernel...\n");
++ iee_rwx_gate_entry(IEE_SWITCH_TO_KERNEL);
++ #endif
++}
++
++/* Finish iee rwx gate initializations. */
++static void __init iee_si_init_done(void)
++{
++ // Prepare data for iee rwx gate
++ iee_si_prepare_data();
++ // All initialization is done. Do some simple tests.
++ iee_si_test_end();
++}
++#endif
++
+ void __init setup_cpu_features(void)
+ {
+ u32 cwg;
+@@ -3502,6 +3577,10 @@ void __init setup_cpu_features(void)
+ if (!cwg)
+ pr_warn("No Cache Writeback Granule information, assuming %d\n",
+ ARCH_DMA_MINALIGN);
++
++ #ifdef CONFIG_IEE
++ iee_si_init_done();
++ #endif
+ }
+
+ static int enable_mismatched_32bit_el0(unsigned int cpu)
+diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
+index 745aefddd9a3..265417e0ad81 100644
+--- a/arch/arm64/kernel/debug-monitors.c
++++ b/arch/arm64/kernel/debug-monitors.c
+@@ -36,10 +36,14 @@ u8 debug_monitors_arch(void)
+ */
+ static void mdscr_write(u32 mdscr)
+ {
++// #ifdef CONFIG_IEE
++// iee_rwx_gate_entry(IEE_WRITE_mdscr_el1, mdscr);
++// #else
+ unsigned long flags;
+ flags = local_daif_save();
+ write_sysreg(mdscr, mdscr_el1);
+ local_daif_restore(flags);
++// #endif
+ }
+ NOKPROBE_SYMBOL(mdscr_write);
+
+diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
+index 08274e4317b2..0d259e355c90 100644
+--- a/arch/arm64/kernel/entry-common.c
++++ b/arch/arm64/kernel/entry-common.c
+@@ -156,7 +156,11 @@ asmlinkage void noinstr asm_exit_to_user_mode(struct pt_regs *regs)
+ * mode. Before this function is called it is not safe to call regular kernel
+ * code, instrumentable code, or any code which may trigger an exception.
+ */
++#ifdef CONFIG_IEE
++void noinstr arm64_enter_nmi(struct pt_regs *regs)
++#else
+ static void noinstr arm64_enter_nmi(struct pt_regs *regs)
++#endif
+ {
+ regs->lockdep_hardirqs = lockdep_hardirqs_enabled();
+
+diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
+index 7fcbee0f6c0e..dee813ee6aad 100644
+--- a/arch/arm64/kernel/entry.S
++++ b/arch/arm64/kernel/entry.S
+@@ -29,12 +29,391 @@
+ #include <asm/asm-uaccess.h>
+ #include <asm/unistd.h>
+
++#ifdef CONFIG_IEE
++#include <asm/iee-def.h>
++
++#define BAD_SP_EL0 0
++#define BAD_ELR_EL1 1
++#define BAD_TCR_EL1 2
++#define BAD_IEE_SI 4
++#endif
++
+ .macro clear_gp_regs
+ .irp n,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29
+ mov x\n, xzr
+ .endr
+ .endm
+
++#ifdef CONFIG_KOI
++#ifdef CONFIG_IEE
++/*
++ * This function is used to switch to ko stack in glue code
++ */
++SYM_FUNC_START(koi_do_switch_to_ko_stack)
++ sub sp, sp, #48
++ stp x29, x30, [sp]
++ str x2, [sp, #16]
++ stp x0, x1, [sp, #32]
++
++ // iee_rw_gate(IEE_WRITE_KERNEL_STACK, current, sp)
++ mov x0, #IEE_WRITE_KOI_KERNEL_STACK
++ mrs x1, sp_el0
++ add x2, sp, #48
++
++ bl iee_rw_gate
++
++ // iee_rw_gate(IEE_READ_KOI_STACK, current)
++ mov x0, #IEE_READ_KOI_STACK
++ mrs x1, sp_el0
++ bl iee_rw_gate
++
++ ldp x29, x30, [sp]
++ ldr x2, [sp, #16]
++ add x1, sp, #32
++ mov sp, x0
++ ldp x0, x1, [x1]
++
++ isb
++ ret
++SYM_FUNC_END(koi_do_switch_to_ko_stack)
++
++/*
++ * This fucntion is used to switch to kernel stack in glue code
++ */
++SYM_FUNC_START(koi_do_switch_to_kernel_stack)
++ sub sp, sp, #48
++ stp x29, x30, [sp]
++ str x2, [sp, #16]
++ stp x0, x1, [sp, #32]
++ // iee_rw_gate(IEE_WRITE_KOI_STACK, current, sp)
++ mov x0, #IEE_WRITE_KOI_STACK
++ mrs x1, sp_el0
++ add x2, sp, #48
++ bl iee_rw_gate
++
++ // iee_rw_gate(IEE_READ_KOI_KERNEL_STACK, current)
++ mov x0, #IEE_READ_KOI_KERNEL_STACK
++ mrs x1, sp_el0
++ bl iee_rw_gate
++
++ ldp x29, x30, [sp]
++ ldr x2, [sp, #16]
++ add x1, sp, #32
++ mov sp, x0
++ ldp x0, x1, [x1]
++ isb
++ ret
++SYM_FUNC_END(koi_do_switch_to_kernel_stack)
++
++/*
++ * Before switch to ko's pgtable, we must switch current stack to ko's stack.
++ * We have stored registers to kernel stack, and we need to restore them from ko's stack after switching,
++ * so we need to copy from kernel stack to ko stack
++ * the memory region to copy is [sp, stack_top)
++ * void koi_switch_to_ko_stack(void);
++ */
++SYM_FUNC_START(koi_switch_to_ko_stack)
++ mrs x17, pan
++ msr pan, 0x0
++
++ sub sp, sp, #32
++ str x17, [sp, #16]
++ stp x30, x29, [sp]
++
++ // current sp stores in x1
++ add x1, x1, #176
++ // current sp_el0 stores in x0
++ bl _iee_write_koi_kernel_stack
++
++ mrs x0, sp_el0
++ bl _iee_read_koi_stack
++
++ ldr x17, [sp, #16]
++ ldp x30, x29, [sp]
++ add sp, sp, #32
++
++ msr pan, x17
++
++ sub x0, x0, #176
++ mov x1, sp
++ mov x2, #176
++
++ // memcpy(current->driver_stack, current->kernel_stack, 176)
++ mov x16, lr
++ bl memcpy
++ mov lr, x16
++
++ mov sp, x0
++ isb
++ ret
++SYM_FUNC_END(koi_switch_to_ko_stack)
++
++SYM_FUNC_START(koi_switch_to_kernel_stack)
++ /*
++ * current sp belongs to driver stack, and the bottom 160 bytes saves registers when exception occurred,
++ * so we should add 160 to current sp, and store it in task_struct
++ * also, fetch kernel sp from task_struct, copy the bottom 160 bytes from driver stack to kernel stack
++ */
++ mrs x17, pan
++ msr pan, 0x0
++
++ sub sp, sp, #32
++ stp x30, x29, [sp]
++ str x17, [sp, #16]
++
++ mrs x0, sp_el0
++ add x1, sp, #192
++ bl _iee_write_koi_stack
++
++ mrs x0, sp_el0
++ bl _iee_read_koi_kernel_stack
++
++ ldr x17, [sp, #16]
++ ldp x30, x29, [sp]
++ add sp, sp, #32
++
++ msr pan, x17
++
++ // x0 = kernel_stack
++ sub x0, x0, #160
++ mov x1, sp
++ // x2 = 160
++ mov x2, #160
++
++ mov x16, lr
++ bl memcpy
++ mov lr, x16
++
++ mov sp, x0
++ isb
++ ret
++SYM_FUNC_END(koi_switch_to_kernel_stack)
++#else
++/*
++ * This function is used to switch to ko stack in glue code
++ */
++SYM_FUNC_START(koi_do_switch_to_ko_stack)
++ sub sp, sp, #16
++ stp x16, x17, [sp]
++ mrs x17, sp_el0
++ adrp x16, koi_offset
++ ldr x16, [x16, #:lo12:koi_offset]
++ add x17, x17, x16
++ add x16, sp, #16
++ str x16, [x17, #koi_kernel_from_token_offset]
++ ldr x16, [x17, #koi_from_token_offset]
++ mov x17, sp
++ mov sp, x16
++ ldp x16, x17, [x17]
++ isb
++ ret
++SYM_FUNC_END(koi_do_switch_to_ko_stack)
++
++/*
++ * This fucntion is used to switch to kernel stack in glue code
++ */
++SYM_FUNC_START(koi_do_switch_to_kernel_stack)
++ sub sp, sp, #16
++ stp x16, x17, [sp]
++ mrs x17, sp_el0
++ adrp x16, koi_offset
++ ldr x16, [x16, #:lo12:koi_offset]
++ add x17, x17, x16
++ add x16, sp, #16
++ str x16, [x17, #koi_from_token_offset]
++ ldr x16, [x17, #koi_kernel_from_token_offset]
++ mov x17, sp
++ mov sp, x16
++ ldp x16, x17, [x17]
++ isb
++ ret
++SYM_FUNC_END(koi_do_switch_to_kernel_stack)
++
++/*
++ * Before switch to ko's pgtable, we must switch current stack to ko's stack.
++ * We have stored registers to kernel stack, and we need to restore them from ko's stack after switching,
++ * so we need to copy from kernel stack to ko stack
++ * the memory region to copy is [sp, stack_top)
++ * void koi_switch_to_ko_stack(unsigned long stack_top);
++ */
++SYM_FUNC_START(koi_switch_to_ko_stack)
++ // current sp stores in x1
++ add x3, x1, #176
++ adrp x4, koi_offset
++ ldr x4, [x4, #:lo12:koi_offset]
++ add x4, x0, x4
++ // current sp_el0 stores in x0
++ str x3, [x4, #koi_kernel_from_token_offset]
++ ldr x0, [x4, #koi_from_token_offset]
++ sub x0, x0, #176
++ mov x2, #176
++
++ // memcpy(current->driver_stack, current->kernel_stack, 176)
++ mov x16, lr
++ bl memcpy
++ mov lr, x16
++
++ mov sp, x0
++ isb
++ ret
++SYM_FUNC_END(koi_switch_to_ko_stack)
++
++SYM_FUNC_START(koi_switch_to_kernel_stack)
++ /*
++ * current sp belongs to driver stack, and the bottom 176 bytes saves registers when exception occurred,
++ * so we should add 176 to current sp, and store it in task_struct
++ * also, fetch kernel sp from task_struct, copy the bottom 176 bytes from driver stack to kernel stack
++ */
++ mov x1, sp
++ add x3, sp, #160
++
++ mrs x16, sp_el0
++ adrp x2, koi_offset
++ ldr x2, [x2, #:lo12:koi_offset]
++ add x16, x16, x2
++ str x3, [x16, #koi_from_token_offset]
++ // sp points to kernel_stack
++ ldr x0, [x16, #koi_kernel_from_token_offset]
++
++ // x0 = kernel_stack
++ sub x0, x0, #160
++ // x2 = 160
++ mov x2, #160
++ mov x16, lr
++ // memcpy(kernel_stack, driver_stack, 160)
++ bl memcpy
++ mov lr, x16
++ mov sp, x0
++ isb
++ ret
++SYM_FUNC_END(koi_switch_to_kernel_stack)
++#endif
++
++SYM_FUNC_START(koi_switch_to_ko_pgtbl)
++ stp x0, x1, [sp, #16 * 1]
++ stp x2, x3, [sp, #16 * 2]
++ stp x4, x5, [sp, #16 * 3]
++ stp x6, x7, [sp, #16 * 4]
++ stp x8, x9, [sp, #16 * 5]
++ stp x10, x11, [sp, #16 * 6]
++ stp x12, x13, [sp, #16 * 7]
++ stp x14, x15, [sp, #16 * 8]
++ stp x16, x17, [sp, #16 * 9]
++ stp x18, x30, [sp, #16 * 10]
++
++ adrp x0, koi_swapper_ttbr1
++ ldr x0, [x0, #:lo12:koi_swapper_ttbr1]
++ cbz x0, 0f
++ bl koi_do_switch_to_ko_pgtbl
++ // if x0 == 0, don't need to switch pgtable and stack, jump to 0
++ cbz x0, 0f
++ mov x19, x0
++ // if current on task's kernel stack, switch to ko stack
++ mrs x0, sp_el0
++ mov x1, sp
++ ldr x2, [x0, TSK_STACK]
++ eor x2, x2, x1
++ and x2, x2, #~(THREAD_SIZE - 1)
++ cbnz x2, 1f
++
++ bl koi_switch_to_ko_stack
++1:
++#ifndef CONFIG_IEE
++ msr ttbr1_el1, x19
++ isb
++ nop
++ nop
++ nop
++#else
++ mov x0, #IEE_SWITCH_TO_KOI
++ mov x1, x19
++ bl iee_rwx_gate_entry
++#endif
++0:
++
++ ldp x0, x1, [sp, #16 * 1]
++ ldp x2, x3, [sp, #16 * 2]
++ ldp x4, x5, [sp, #16 * 3]
++ ldp x6, x7, [sp, #16 * 4]
++ ldp x8, x9, [sp, #16 * 5]
++ ldp x10, x11, [sp, #16 * 6]
++ ldp x12, x13, [sp, #16 * 7]
++ ldp x14, x15, [sp, #16 * 8]
++ ldp x16, x17, [sp, #16 * 9]
++ ldp x18, x30, [sp, #16 * 10]
++ ret
++SYM_FUNC_END(koi_switch_to_ko_pgtbl)
++
++.pushsection ".koi.text", "ax"
++SYM_FUNC_START(koi_switch_to_kernel_pgtbl)
++ sub sp, sp, #160
++ stp x0, x1, [sp, #16 * 0]
++ stp x2, x3, [sp, #16 * 1]
++ stp x4, x5, [sp, #16 * 2]
++ stp x6, x7, [sp, #16 * 3]
++ stp x8, x9, [sp, #16 * 4]
++ stp x10, x11, [sp, #16 * 5]
++
++ stp x12, x13, [sp, #16 * 6]
++ stp x14, x15, [sp, #16 * 7]
++ stp x16, x17, [sp, #16 * 8]
++ stp x18, x30, [sp, #16 * 9]
++ // check whether paging init finished
++ adrp x0, koi_swapper_ttbr1
++ ldr x0, [x0, #:lo12:koi_swapper_ttbr1]
++ cbz x0, 0f
++
++ bl koi_do_switch_to_kernel_pgtbl
++ /*
++ * koi_do_switch_to_kernel_pgtbl return 0 indicates
++ * that when exception occurred, the isolated ko is executing under koi pgtbl,
++ * so we need to switch stack to kernel stack after switch pgtbl back to koi_swapper_ttbr1.
++ */
++ cbz x0, 0f
++#ifndef CONFIG_IEE
++ mrs x0, sp_el0
++ adrp x1, koi_offset
++ ldr x1, [x1, #:lo12:koi_offset]
++ add x0, x0, x1
++ mov x16, sp
++ ldr x17, [x0, koi_stack_base_from_token_offset]
++ eor x17, x17, x16
++ and x17, x17, #~(THREAD_SIZE - 1)
++ cbnz x17, 0f
++#else
++ // save current pan
++ mrs x17, pan
++ // disable pan
++ msr pan, 0x0
++ mrs x0, sp_el0
++ bl _iee_read_koi_stack_base
++ // restore pan
++ msr pan, x17
++
++ mov x16, sp
++ eor x0, x0, x16
++ and x0, x0, #~(THREAD_SIZE - 1)
++ cbnz x0, 0f
++#endif
++ bl koi_switch_to_kernel_stack
++0:
++
++ ldp x0, x1, [sp, #16 * 0]
++ ldp x2, x3, [sp, #16 * 1]
++ ldp x4, x5, [sp, #16 * 2]
++ ldp x6, x7, [sp, #16 * 3]
++ ldp x8, x9, [sp, #16 * 4]
++ ldp x10, x11, [sp, #16 * 5]
++ ldp x12, x13, [sp, #16 * 6]
++ ldp x14, x15, [sp, #16 * 7]
++ ldp x16, x17, [sp, #16 * 8]
++ ldp x18, x30, [sp, #16 * 9]
++ add sp, sp, #160
++ ret
++SYM_FUNC_END(koi_switch_to_kernel_pgtbl)
++.popsection
++#endif
++
+ .macro kernel_ventry, el:req, ht:req, regsize:req, label:req
+ .align 7
+ .Lventry_start\@:
+@@ -151,6 +530,17 @@ alternative_else_nop_endif
+ #endif
+ .endm
+
++#ifdef CONFIG_IEE
++// SP_EL0 check failed.
++SYM_FUNC_START_LOCAL(sp_el0_check_failed)
++ mov x0, sp
++ mov x1, #BAD_SP_EL0
++ mrs x2, esr_el1
++ bl iee_bad_mode
++ ASM_BUG()
++SYM_FUNC_END(sp_el0_check_failed)
++#endif
++
+ /* Clear the MTE asynchronous tag check faults */
+ .macro clear_mte_async_tcf thread_sctlr
+ #ifdef CONFIG_ARM64_MTE
+@@ -224,6 +614,14 @@ alternative_cb_end
+ ldr_this_cpu tsk, __entry_task, x20
+ msr sp_el0, tsk
+
++#ifdef CONFIG_IEE
++ // tsk check.
++ ldr_this_cpu x19, __entry_task, x20
++ mrs x20, sp_el0
++ cmp x19, x20
++ b.ne sp_el0_check_failed
++#endif
++
+ /*
+ * Ensure MDSCR_EL1.SS is clear, since we can unmask debug exceptions
+ * when scheduling.
+@@ -276,6 +674,13 @@ alternative_else_nop_endif
+
+ scs_load_current
+ .else
++#ifdef CONFIG_IEE
++ // tsk check.
++ ldr_this_cpu x19, __entry_task, x20
++ mrs x20, sp_el0
++ cmp x19, x20
++ b.ne sp_el0_check_failed
++#endif
+ add x21, sp, #PT_REGS_SIZE
+ get_current_task tsk
+ .endif /* \el == 0 */
+@@ -333,9 +738,11 @@ alternative_else_nop_endif
+ .endm
+
+ .macro kernel_exit, el
++ #ifndef CONFIG_IEE
+ .if \el != 0
+ disable_daif
+ .endif
++ #endif
+
+ #ifdef CONFIG_ARM64_PSEUDO_NMI
+ alternative_if_not ARM64_HAS_GIC_PRIO_MASKING
+@@ -411,6 +818,41 @@ alternative_else_nop_endif
+
+ msr elr_el1, x21 // set up the return data
+ msr spsr_el1, x22
++
++#ifdef CONFIG_IEE
++
++ .if \el == 0
++
++ #ifndef CONFIG_UNMAP_KERNEL_AT_EL0
++ // SET hpd1 = 0 start
++ mrs x0, tcr_el1
++ and x0, x0, #0xFFFFFBFFFFFFFFFF
++ and x0, x0, #0xFFFFFFFFFFBFFFFF
++ msr tcr_el1, x0
++ // SET hpd1 = 0 end
++
++ disable_daif
++
++ // Check ELR_EL1
++ mrs x0, elr_el1
++ lsr x0, x0, #48
++ tst x0, #0xffff
++ b.ne 5f
++ #endif
++
++ .endif
++
++#else
++#ifdef CONFIG_KOI
++ .if \el==0
++ mrs x0, tcr_el1
++ and x0, x0, #0xFFFFFFFFFFBFFFFF
++ msr tcr_el1,x0
++ .endif
++#endif
++
++#endif
++
+ ldp x0, x1, [sp, #16 * 0]
+ ldp x2, x3, [sp, #16 * 1]
+ ldp x4, x5, [sp, #16 * 2]
+@@ -569,12 +1011,167 @@ SYM_CODE_START_LOCAL(__bad_stack)
+ SYM_CODE_END(__bad_stack)
+ #endif /* CONFIG_VMAP_STACK */
+
++/*
++ * iee exception entry
++ */
++ .macro iee_exception_entry, el
++
++ /* Check whether exception is permmited. */
++ ldr x1, =__iee_si_no_irq
++ cmp x1, x22
++ b.hi 1148f
++ ldr x1, =__iee_si_end
++ cmp x1, x22
++ b.lo 1148f
++ /* ELR check fail */
++ mov x0, sp
++ mov x1, #BAD_IEE_SI
++ mrs x2, esr_el1
++ bl iee_bad_mode
++ ASM_BUG()
++1148:
++
++ /* el0 set hpds */
++ .if \el == 0
++
++ #ifndef CONFIG_UNMAP_KERNEL_AT_EL0
++ /* SET hpd1 = 1 start */
++ mrs x0, tcr_el1
++ orr x0, x0, #0x0000040000000000
++ orr x0, x0, #0x0000000000400000
++ msr tcr_el1, x0
++ /* SET hpd1 = 1 end */
++
++ disable_daif
++
++ /* Check TCR_EL1 */
++ mrs x0, tcr_el1
++ tst x0, #0x0000040000000000
++ b.eq 5f
++ tst x0, #0x0000000000400000
++ b.ne 6f
++
++5:
++ /* TCR_EL1 check fail */
++ mov x0, sp
++ mov x1, #BAD_TCR_EL1
++ mrs x2, esr_el1
++ bl iee_bad_mode
++ ASM_BUG()
++
++6:
++ nop
++ #endif
++
++ .else
++#ifdef CONFIG_IEE_INTERRUPTABLE
++ /* el1 save elr_el1 and set pan */
++ /* Check ELR_EL1 */
++ ldr x1, =__iee_code_start
++ cmp x1, x22
++ b.hi 7f
++ ldr x1, =__iee_code_end
++ cmp x1, x22
++ b.lo 7f
++ /* Exception from iee code */
++ /* Switch to kernel stack */
++ mrs x0, sp_el0 /* x0 -> task_struct(VA) */
++ adrp x2, iee_offset
++ ldr x2, [x2, #:lo12:iee_offset]
++ add x1, x0, x2 /* x1 -> task_token(IEE) */
++ // store iee stack
++ mov x3, sp
++ str x3, [x1, #iee_from_token_offset]
++ // load kernel stack
++ ldr x3, [x1, #kernel_from_token_offset]
++ mov sp, x3
++ sub sp, sp, #PT_REGS_SIZE
++ /* Enable PAN */
++ msr pan, #0x1
++
++7:
++ /* Exception from kernel code */
++ mov x0, #0x0
++ mov x1, #0x0
++ mov x2, #0x0
++ mov x3, #0x0
++#endif
++ .endif
++ .endm
++
++/*
++ * iee exception exit
++ */
++ .macro iee_exception_exit, el
++ // Disable daif
++ disable_daif
++
++ .if \el == 1
++#ifdef CONFIG_IEE_INTERRUPTABLE
++ /* el1 pop elr_el1 and set pan */
++ /* Check ELR_EL1 */
++ ldr x1, =__iee_code_start
++ cmp x1, x22
++ b.hi 9f
++ ldr x1, =__iee_code_end
++ cmp x1, x22
++ b.lo 9f
++ /* Eret iee code */
++ /* Disable PAN */
++ msr pan, #0x0
++ /* Switch to iee stack */
++ add sp, sp, #PT_REGS_SIZE
++ mrs x0, sp_el0 /* x0 -> task_struct */
++ adrp x2, iee_offset
++ ldr x2, [x2, #:lo12:iee_offset]
++ add x1, x0, x2 /* x1 -> task_token(IEE) */
++ // store kernel stack
++ mov x3, sp
++ str x3, [x1, #kernel_from_token_offset]
++ // load iee stack
++ ldr x2, [x1, #iee_from_token_offset]
++ mov sp, x2
++ /* Load ELR_EL1 from iee stack */
++ ldr x21, [sp, #S_PC]
++ /* Check the modify of ELR_EL1 */
++ cmp x21, x22
++ b.ne 8f
++ /* ELR_EL1 not modified */
++ b 9f
++
++8:
++ // ELR_EL1 modified
++ mov x0, sp
++ mov x1, #BAD_ELR_EL1
++ mrs x2, esr_el1
++ bl iee_bad_mode
++ ASM_BUG()
++
++9:
++ // Eret kernel code
++ mov x0, #0x0
++ mov x1, #0x0
++ mov x2, #0x0
++ mov x3, #0x0
++#endif
++ .endif
++ .endm
+
+ .macro entry_handler el:req, ht:req, regsize:req, label:req
+ SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label)
+ kernel_entry \el, \regsize
++
++ #ifdef CONFIG_IEE
++ iee_exception_entry \el
++ #endif
++
+ mov x0, sp
+ bl el\el\ht\()_\regsize\()_\label\()_handler
++
++ #ifdef CONFIG_IEE
++ iee_exception_exit \el
++ #endif
++
+ .if \el == 0
+ b ret_to_user
+ .else
+@@ -844,6 +1441,13 @@ SYM_FUNC_START(cpu_switch_to)
+ ldr lr, [x8]
+ mov sp, x9
+ msr sp_el0, x1
++#ifdef CONFIG_IEE
++ // tsk check.
++ ldr_this_cpu x8, __entry_task, x9
++ mrs x9, sp_el0
++ cmp x8, x9
++ b.ne sp_el0_check_failed
++#endif
+ ptrauth_keys_install_kernel x1, x8, x9, x10
+ scs_save x0
+ scs_load_current
+@@ -1033,6 +1637,13 @@ SYM_CODE_START(__sdei_asm_handler)
+ mrs x28, sp_el0
+ ldr_this_cpu dst=x0, sym=__entry_task, tmp=x1
+ msr sp_el0, x0
++#ifdef CONFIG_IEE
++ // tsk check.
++ ldr_this_cpu x0, __entry_task, x1
++ mrs x1, sp_el0
++ cmp x0, x1
++ b.ne sp_el0_check_failed
++#endif
+
+ /* If we interrupted the kernel point to the previous stack/frame. */
+ and x0, x3, #0xc
+diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
+index 5cdfcc9e3e54..c0af965bd92e 100644
+--- a/arch/arm64/kernel/fpsimd.c
++++ b/arch/arm64/kernel/fpsimd.c
+@@ -1309,7 +1309,11 @@ void sme_kernel_enable(const struct arm64_cpu_capabilities *__always_unused p)
+ isb();
+
+ /* Allow EL0 to access TPIDR2 */
++ #ifdef CONFIG_IEE
++ iee_rwx_gate_entry(IEE_WRITE_sctlr_el1, read_sysreg(SCTLR_EL1) | SCTLR_ELx_ENTP2);
++ #else
+ write_sysreg(read_sysreg(SCTLR_EL1) | SCTLR_ELx_ENTP2, SCTLR_EL1);
++ #endif
+ isb();
+ }
+
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index 6517bf2644a0..5c75e069d877 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -464,6 +464,42 @@ SYM_FUNC_END(create_kernel_mapping)
+ set_this_cpu_offset \tmp1
+ .endm
+
++#ifdef CONFIG_IEE
++ .macro init_cpu_task_checked tsk, tmp1, tmp2
++ msr sp_el0, \tsk
++ // tsk check.
++ adrp x29, __per_cpu_offset
++ mrs \tmp1, sp_el0
++ ldr \tmp2, [\tmp1, #TSK_TI_CPU] /* cpu number */
++1:
++ cmp \tmp2, #0
++ b.eq 2f
++ add x29, x29, #8
++ sub \tmp2, \tmp2, #1
++ b 1b
++2:
++ ldr \tmp2, [x29, #:lo12:__per_cpu_offset] /* cpu offset */
++ adr_l x29, __entry_task
++ ldr x29, [x29, \tmp2]
++ cmp x29, \tmp1
++ b.ne sp_el0_check_failed
++
++ ldr \tmp1, [\tsk, #TSK_STACK]
++ add sp, \tmp1, #THREAD_SIZE
++ sub sp, sp, #PT_REGS_SIZE
++
++ stp xzr, xzr, [sp, #S_STACKFRAME]
++ add x29, sp, #S_STACKFRAME
++
++ scs_load_current
++
++ adr_l \tmp1, __per_cpu_offset
++ ldr w\tmp2, [\tsk, #TSK_TI_CPU]
++ ldr \tmp1, [\tmp1, \tmp2, lsl #3]
++ set_this_cpu_offset \tmp1
++ .endm
++#endif
++
+ /*
+ * The following fragment of code is executed with the MMU enabled.
+ *
+@@ -661,6 +697,18 @@ SYM_FUNC_START_LOCAL(secondary_startup)
+ SYM_FUNC_END(secondary_startup)
+
+ .text
++#ifdef CONFIG_IEE
++// SP_EL0 check failed.
++SYM_FUNC_START_LOCAL(sp_el0_check_failed)
++ 1:
++ nop
++ nop
++ nop
++ nop
++ b 1f
++SYM_FUNC_END(sp_el0_check_failed)
++#endif
++
+ SYM_FUNC_START_LOCAL(__secondary_switched)
+ mov x0, x20
+ bl set_cpu_boot_mode_flag
+@@ -677,7 +725,11 @@ SYM_FUNC_START_LOCAL(__secondary_switched)
+ ldr x2, [x0, #CPU_BOOT_TASK]
+ cbz x2, __secondary_too_slow
+
++#ifdef CONFIG_IEE
++ init_cpu_task_checked x2, x1, x3
++#else
+ init_cpu_task x2, x1, x3
++#endif
+
+ #ifdef CONFIG_ARM64_PTR_AUTH
+ ptrauth_keys_init_cpu x2, x3, x4, x5
+@@ -746,6 +798,10 @@ SYM_FUNC_START(__enable_mmu)
+ cmp x3, #ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX
+ b.gt __no_granule_support
+ phys_to_ttbr x2, x2
++#ifdef CONFIG_IEE
++ mov x3, #1
++ bfi x2, x3, #48, #16 // ASID 1 is used by IEE rwx gate.
++#endif
+ msr ttbr0_el1, x2 // load TTBR0
+ load_ttbr1 x1, x1, x3
+
+diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
+index 02870beb271e..1c14428a3ed4 100644
+--- a/arch/arm64/kernel/hibernate.c
++++ b/arch/arm64/kernel/hibernate.c
+@@ -34,6 +34,10 @@
+ #include <asm/trans_pgd.h>
+ #include <asm/virt.h>
+
++#ifdef CONFIG_PTP
++#include <linux/iee-func.h>
++#endif
++
+ /*
+ * Hibernate core relies on this value being 0 on resume, and marks it
+ * __nosavedata assuming it will keep the resume kernel's '0' value. This
+@@ -197,12 +201,22 @@ static int create_safe_exec_page(void *src_start, size_t length,
+ phys_addr_t trans_ttbr0;
+ unsigned long t0sz;
+ int rc;
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
+
+ if (!page)
+ return -ENOMEM;
+
+ memcpy(page, src_start, length);
+ caches_clean_inval_pou((unsigned long)page, (unsigned long)page + length);
++
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(page_address(page)));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)page_address(page));
++ #endif
++
+ rc = trans_pgd_idmap_page(&trans_info, &trans_ttbr0, &t0sz, page);
+ if (rc)
+ return rc;
+diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
+index d39a8787edf2..b5ac4b7670bc 100644
+--- a/arch/arm64/kernel/hw_breakpoint.c
++++ b/arch/arm64/kernel/hw_breakpoint.c
+@@ -26,6 +26,10 @@
+ #include <asm/cputype.h>
+ #include <asm/system_misc.h>
+
++#ifdef CONFIG_IEE
++#include <asm/iee-si.h>
++#endif
++
+ /* Breakpoint currently in use for each BRP. */
+ static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
+
+@@ -102,13 +106,68 @@ int hw_breakpoint_slots(int type)
+ WRITE_WB_REG_CASE(OFF, 14, REG, VAL); \
+ WRITE_WB_REG_CASE(OFF, 15, REG, VAL)
+
++#ifdef CONFIG_IEE
++
++#define IEE_SI_READ_WB_REG_CASE(OFF, N, REG, VAL) \
++ case (OFF + N): \
++ IEE_SI_AARCH64_DBG_READ(N, REG, VAL); \
++ break
++
++#define IEE_SI_WRITE_WB_REG_CASE(OFF, N, REG, VAL) \
++ case (OFF + N): \
++ IEE_SI_AARCH64_DBG_WRITE(N, REG, VAL); \
++ break
++
++#define IEE_SI_GEN_READ_REG_CASES(OFF, REG, VAL) \
++ IEE_SI_READ_WB_REG_CASE(OFF, 0, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 1, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 2, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 3, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 4, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 5, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 6, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 7, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 8, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 9, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 10, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 11, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 12, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 13, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 14, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 15, REG, VAL)
++
++#define IEE_SI_GEN_WRITE_REG_CASES(OFF, REG, VAL) \
++ IEE_SI_WRITE_WB_REG_CASE(OFF, 0, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 1, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 2, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 3, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 4, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 5, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 6, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 7, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 8, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 9, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 10, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 11, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 12, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 13, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 14, REG, VAL); \
++ WRITE_WB_REG_CASE(OFF, 15, REG, VAL)
++
++#endif
++
+ static u64 read_wb_reg(int reg, int n)
+ {
+ u64 val = 0;
+
+ switch (reg + n) {
++// #ifdef CONFIG_IEE
++// IEE_SI_GEN_READ_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
++// IEE_SI_GEN_READ_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
++// #else
+ GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
+ GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
++// #endif
+ GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val);
+ GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val);
+ default:
+@@ -122,8 +181,13 @@ NOKPROBE_SYMBOL(read_wb_reg);
+ static void write_wb_reg(int reg, int n, u64 val)
+ {
+ switch (reg + n) {
++// #ifdef CONFIG_IEE
++// IEE_SI_GEN_WRITE_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
++// IEE_SI_GEN_WRITE_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
++// #else
+ GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val);
+ GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val);
++// #endif
+ GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val);
+ GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val);
+ default:
+@@ -171,6 +235,10 @@ static int is_a32_compat_bp(struct perf_event *bp)
+ return tsk && is_a32_compat_thread(task_thread_info(tsk));
+ }
+
++#ifdef CONFIG_IEE
++int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
++#endif
++
+ /**
+ * hw_breakpoint_slot_setup - Find and setup a perf slot according to
+ * operations
+@@ -191,6 +259,37 @@ static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
+ {
+ int i;
+ struct perf_event **slot;
++// reserve hw breakpoint 0 for iee rwx gate in kernel sapce.
++// #ifdef CONFIG_IEE
++// struct arch_hw_breakpoint *info = counter_arch_bp(bp);
++// if (arch_check_bp_in_kernelspace(info)){
++// for (i = 1; i < max_slots; ++i) { // search from hw breakpoint 1
++// slot = &slots[i];
++// switch (ops) {
++// case HW_BREAKPOINT_INSTALL:
++// if (!*slot) {
++// *slot = bp;
++// return i;
++// }
++// break;
++// case HW_BREAKPOINT_UNINSTALL:
++// if (*slot == bp) {
++// *slot = NULL;
++// return i;
++// }
++// break;
++// case HW_BREAKPOINT_RESTORE:
++// if (*slot == bp)
++// return i;
++// break;
++// default:
++// pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
++// return -EINVAL;
++// }
++// }
++// return -ENOSPC;
++// }
++// #endif
+
+ for (i = 0; i < max_slots; ++i) {
+ slot = &slots[i];
+diff --git a/arch/arm64/kernel/iee/Makefile b/arch/arm64/kernel/iee/Makefile
+new file mode 100644
+index 000000000000..123c68c5cc4e
+--- /dev/null
++++ b/arch/arm64/kernel/iee/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_IEE) += iee.o iee-gate.o iee-func.o
+\ No newline at end of file
+diff --git a/arch/arm64/kernel/iee/iee-func.c b/arch/arm64/kernel/iee/iee-func.c
+new file mode 100644
+index 000000000000..7764dbd41555
+--- /dev/null
++++ b/arch/arm64/kernel/iee/iee-func.c
+@@ -0,0 +1,187 @@
++#include "asm/pgtable.h"
++#include <linux/memory.h>
++#include <linux/mm.h>
++#include <asm/tlb.h>
++#include <asm/tlbflush.h>
++#include <asm/pgalloc.h>
++
++void set_iee_page_valid(unsigned long addr)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
++
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++
++ pud_t *pudp = pud_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_offset(pudp, addr);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++ pte_t pte = READ_ONCE(*ptep);
++
++ if((addr < (PAGE_OFFSET + IEE_OFFSET)) | (addr > (PAGE_OFFSET + BIT(vabits_actual - 1))))
++ return;
++
++ pte = __pte(pte_val(pte) | 0x1);
++ set_pte(ptep, pte);
++ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
++ isb();
++}
++
++void set_iee_page_invalid(unsigned long addr)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
++
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++
++ pud_t *pudp = pud_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_offset(pudp, addr);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++ pte_t pte = READ_ONCE(*ptep);
++
++ if((addr < (PAGE_OFFSET + IEE_OFFSET)) | (addr > (PAGE_OFFSET + BIT(vabits_actual - 1))))
++ return;
++
++ pte = __pte(pte_val(pte) & ~0x1);
++ set_pte(ptep, pte);
++ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
++ isb();
++}
++
++void iee_set_logical_mem_ro(unsigned long addr)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
++
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++
++ pud_t *pudp = pud_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_offset(pudp, addr);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++ pte_t pte = READ_ONCE(*ptep);
++
++ if(addr < PAGE_OFFSET)
++ return;
++
++ pte = __pte((pte_val(pte) | PTE_RDONLY) & ~PTE_DBM);
++ set_pte(ptep, pte);
++ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
++ isb();
++}
++
++void iee_set_logical_mem_rw(unsigned long addr)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
++
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++
++ pud_t *pudp = pud_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_offset(pudp, addr);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++ pte_t pte = READ_ONCE(*ptep);
++
++ if((addr < PAGE_OFFSET) | (addr > (PAGE_OFFSET + BIT(vabits_actual - 2))))
++ return;
++
++ pte = __pte(pte_val(pte) | PTE_DBM);
++ set_pte(ptep, pte);
++ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
++ isb();
++}
++
++void iee_set_token_page_valid(void *token, void *new)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token);
++
++ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token);
++
++ pud_t *pudp = pud_offset(p4dp, (unsigned long)token);
++
++ pmd_t *pmdp = pmd_offset(pudp, (unsigned long)token);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, (unsigned long)token);
++ pte_t pte = READ_ONCE(*ptep);
++ pte = __pte(((pte_val(pte) | 0x1) & ~PTE_ADDR_MASK) | __phys_to_pte_val(__pa(new)));
++ set_pte(ptep, pte);
++ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token+PAGE_SIZE));
++ isb();
++}
++
++void iee_set_token_page_invalid(void *token)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token);
++
++ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token);
++
++ pud_t *pudp = pud_offset(p4dp, (unsigned long)token);
++
++ pmd_t *pmdp = pmd_offset(pudp, (unsigned long)token);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, (unsigned long)token);
++ pte_t pte = READ_ONCE(*ptep);
++ pte = __pte(((pte_val(pte) & ~((unsigned long)0x1)) & ~PTE_ADDR_MASK) | __phys_to_pte_val(__pa(token - IEE_OFFSET)));
++ set_pte(ptep, pte);
++ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token+PAGE_SIZE));
++ isb();
++}
++
++void iee_set_kernel_ppage(unsigned long addr)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
++
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++
++ pud_t *pudp = pud_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_offset(pudp, addr);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++
++ int i;
++ for(i = 0; i < 4; i++)
++ {
++ pte_t pte = READ_ONCE(*ptep);
++ pte = __pte(pte_val(pte) & ~PTE_USER & ~PTE_NG);
++ iee_set_pte_ppage(ptep, pte);
++ ptep++;
++ }
++ flush_tlb_kernel_range(addr, addr+4*PAGE_SIZE);
++ isb();
++}
++
++void iee_set_kernel_upage(unsigned long addr)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
++
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++ p4d_t p4d = READ_ONCE(*p4dp);
++
++ pud_t *pudp = pud_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_offset(pudp, addr);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++
++ int i;
++ for(i = 0; i < 4; i++)
++ {
++ pte_t pte = READ_ONCE(*ptep);
++ pte = __pte(pte_val(pte) | PTE_USER | PTE_NG);
++ iee_set_pte_upage(ptep, pte);
++ ptep++;
++ }
++ flush_tlb_kernel_range(addr, addr+4*PAGE_SIZE);
++ isb();
++}
+\ No newline at end of file
+diff --git a/arch/arm64/kernel/iee/iee-gate.S b/arch/arm64/kernel/iee/iee-gate.S
+new file mode 100644
+index 000000000000..6de99a018bde
+--- /dev/null
++++ b/arch/arm64/kernel/iee/iee-gate.S
+@@ -0,0 +1,174 @@
++#include <asm/asm-offsets.h>
++#include <linux/linkage.h>
++#include <asm/bug.h>
++#include <asm-generic/export.h>
++
++#ifdef CONFIG_IEE
++
++SYM_FUNC_START(iee_rw_gate)
++ /* save daif, close irq */
++ mrs x13, daif
++ msr daifset, #0x2
++ isb
++ /* save lr */
++ sub sp, sp, #16
++ stp x29, x30, [sp]
++ bl iee_protected_rw_gate
++ /* restore lr */
++ ldp x29, x30, [sp]
++ add sp, sp, #16
++ /* restore daif */
++ msr daif, x13
++ ret
++SYM_FUNC_END(iee_rw_gate)
++#if defined(CONFIG_CREDP) || defined(CONFIG_KOI)
++EXPORT_SYMBOL(iee_rw_gate)
++#endif
++
++ .pushsection ".iee.text.header", "ax"
++
++SYM_FUNC_START(iee_protected_rw_gate)
++ mrs x9, pan
++ /* disable PAN */
++ msr pan, #0x0
++ /* switch to iee stack */
++ mrs x9, sp_el0 /* x9 -> task_struct */
++ adrp x12, iee_offset
++ ldr x12, [x12, #:lo12:iee_offset]
++ add x11, x9, x12 /* x11 -> task_token(IEE) */
++ // store kernel stack
++ mov x10, sp
++ str x10, [x11, #kernel_from_token_offset]
++ // load iee stack
++ ldr x10, [x11, #iee_from_token_offset]
++ mov sp, x10
++#ifdef CONFIG_IEE_INTERRUPTABLE
++ isb
++ /* restore daif */
++ msr daif, x13
++ sub sp, sp, #16
++ stp x29, x30, [sp]
++#else
++ sub sp, sp, #16
++ stp x13, x30, [sp]
++#endif
++ /* call iee func */
++ bl iee_dispatch
++#ifdef CONFIG_IEE_INTERRUPTABLE
++ ldp x29, x30, [sp]
++ add sp, sp, #16
++ /* store and disable daif */
++ mrs x13, daif
++ msr daifset, #0x2
++ isb
++#else
++ ldp x13, x30, [sp]
++ add sp, sp, #16
++#endif
++ /* switch to kernel stack */
++ mrs x9, sp_el0 /* x9 -> task_struct(VA) */
++ adrp x12, iee_offset
++ ldr x12, [x12, #:lo12:iee_offset]
++ add x11, x9, x12 /* x11 -> task_token(IEE) */
++ // store iee stack
++ mov x10, sp
++ str x10, [x11, #iee_from_token_offset]
++ // load kernel stack
++ ldr x10, [x11, #kernel_from_token_offset]
++ mov sp, x10
++ /* enable PAN */
++ msr pan, #0x1
++ ret
++SYM_FUNC_END(iee_protected_rw_gate)
++
++ .popsection
++
++#include <asm/asm-bug.h>
++#define BAD_IEE 4
++#define BAD_IEE_SI 5
++
++#define SYS_TCR_EL1_HPD1 0x40000000000
++#define SYS_TCR_EL1_A1 0x400000
++
++ .pushsection ".iee.exec_entry", "ax"
++
++SYM_FUNC_START(iee_rwx_gate_entry)
++ /* Disable irq first. */
++ mrs x15, daif // use x15 to restore daif
++ msr DAIFSet, #0xf
++ isb
++
++ /* Set HPD1 = 0 to exec follwing codes in U RWX page */
++ mrs x9, tcr_el1
++ bic x9, x9, #SYS_TCR_EL1_HPD1
++ bic x9, x9, #SYS_TCR_EL1_A1
++ msr tcr_el1, x9
++ isb
++
++ b iee_rwx_gate_tramp
++SYM_FUNC_END(iee_rwx_gate_entry)
++ .popsection
++
++ .pushsection ".iee.si_text", "awx"
++
++SYM_FUNC_START(iee_rwx_gate_tramp)
++ /* Check tcr val. */
++ mrs x10, tcr_el1
++ adrp x12, iee_si_tcr // tcr val shall be const after init
++ ldr x12, [x12, #:lo12:iee_si_tcr]
++ cbz x12, 1f
++ cmp x12, x10
++ b.ne 3f
++1:
++ mov x13, sp
++ /* If iee hasn't been initialized, skip stack switch. */
++ ldr x11, =iee_init_done
++ ldr x10, [x11]
++ cbz x10, 2f
++
++ /* Switch to iee stack */
++ mrs x9, sp_el0 // x9 -> task_struct
++ adrp x12, iee_offset
++ ldr x12, [x12, #:lo12:iee_offset]
++ add x11, x9, x12 // x11 -> task_token(IEE)
++ // load iee stack
++ ldr x10, [x11, #iee_from_token_offset]
++ mov sp, x10
++
++ /* x15 stores daif and x13 stores previous sp */
++2:
++ stp x15, x13, [sp, #-32]!
++ stp x29, x30, [sp, #16]
++ bl iee_si_handler // enter actual handler
++ ldp x29, x30, [sp, #16]
++
++ b iee_rwx_gate_exit // jump to iee exit
++3:
++ mov x0, sp
++ mov x1, #BAD_IEE_SI
++ mrs x2, esr_el1
++ bl iee_bad_mode
++ ASM_BUG()
++SYM_FUNC_END(iee_rwx_gate_tramp)
++
++ .popsection
++
++ .pushsection ".iee.exec_exit", "ax"
++
++SYM_FUNC_START(iee_rwx_gate_exit)
++ ldp x15, x13, [sp], #32
++ mov sp, x13 // switch to kernel stack
++ mrs x9, tcr_el1
++ orr x9, x9, #SYS_TCR_EL1_HPD1
++ orr x9, x9, #SYS_TCR_EL1_A1
++ msr tcr_el1, x9
++/* --------Page boundary-------- */
++ isb
++ msr daif, x15
++ isb
++ ret
++SYM_FUNC_END(iee_rwx_gate_exit)
++
++ .popsection
++
++#endif
+diff --git a/arch/arm64/kernel/iee/iee.c b/arch/arm64/kernel/iee/iee.c
+new file mode 100644
+index 000000000000..6b9f7d40df67
+--- /dev/null
++++ b/arch/arm64/kernel/iee/iee.c
+@@ -0,0 +1,1360 @@
++#include "linux/sched.h"
++#include <linux/stdarg.h>
++#include <asm/pgtable-types.h>
++#include <asm/iee.h>
++#include <asm/iee-si.h>
++#include <asm/sysreg.h>
++#include <linux/pgtable.h>
++#include <linux/cred.h>
++#include <asm/iee-slab.h>
++#include <asm/percpu.h>
++
++#ifdef CONFIG_IEE
++extern struct cred init_cred;
++extern s64 memstart_addr;
++
++void __iee_code _iee_set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
++void __iee_code _iee_set_tramp_pgd_pre_init(pgd_t *pgdp, pgd_t pgd);
++void __iee_code _iee_set_pte(pte_t *ptep, pte_t pte);
++void __iee_code _iee_set_pmd(pmd_t *pmdp, pmd_t pmd);
++void __iee_code _iee_set_pud(pud_t *pudp, pud_t pud);
++void __iee_code _iee_set_p4d(p4d_t *p4dp, p4d_t p4d);
++void __iee_code _iee_set_bm_pte(pte_t *ptep, pte_t pte);
++pteval_t __iee_code _iee_set_xchg_relaxed(pte_t *ptep, pteval_t pteval);
++pteval_t __iee_code _iee_set_cmpxchg_relaxed(pte_t *ptep, pteval_t old_pteval, pteval_t new_pteval);
++void __iee_code _iee_write_in_byte(void *ptr, __u64 data, int length);
++void __iee_code _iee_set_cred_uid(struct cred *cred, kuid_t uid);
++void __iee_code _iee_set_cred_gid(struct cred *cred, kgid_t gid);
++void __iee_code _iee_copy_cred(struct cred *old, struct cred *new);
++void __iee_code _iee_set_cred_suid(struct cred *cred, kuid_t suid);
++void __iee_code _iee_set_cred_sgid(struct cred *cred, kgid_t sgid);
++void __iee_code _iee_set_cred_euid(struct cred *cred, kuid_t euid);
++void __iee_code _iee_set_cred_egid(struct cred *cred, kgid_t egid);
++void __iee_code _iee_set_cred_fsuid(struct cred *cred, kuid_t fsuid);
++void __iee_code _iee_set_cred_fsgid(struct cred *cred, kgid_t fsgid);
++void __iee_code _iee_set_cred_user(struct cred *cred, struct user_struct *user);
++void __iee_code _iee_set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns);
++void __iee_code _iee_set_cred_ucounts(struct cred *cred, struct ucounts *ucounts);
++void __iee_code _iee_set_cred_group_info(struct cred *cred, struct group_info *group_info);
++void __iee_code _iee_set_cred_securebits(struct cred *cred, unsigned securebits);
++void __iee_code _iee_set_cred_cap_inheritable(struct cred *cred, kernel_cap_t cap_inheritable);
++void __iee_code _iee_set_cred_cap_permitted(struct cred *cred, kernel_cap_t cap_permitted);
++void __iee_code _iee_set_cred_cap_effective(struct cred *cred, kernel_cap_t cap_effective);
++void __iee_code _iee_set_cred_cap_bset(struct cred *cred, kernel_cap_t cap_bset);
++void __iee_code _iee_set_cred_cap_ambient(struct cred *cred, kernel_cap_t cap_ambient);
++void __iee_code _iee_set_cred_jit_keyring(struct cred *cred, unsigned char jit_keyring);
++void __iee_code _iee_set_cred_session_keyring(struct cred *cred, struct key *session_keyring);
++void __iee_code _iee_set_cred_process_keyring(struct cred *cred, struct key *process_keyring);
++void __iee_code _iee_set_cred_thread_keyring(struct cred *cred, struct key *thread_keyring);
++void __iee_code _iee_set_cred_request_key_auth(struct cred *cred, struct key *request_key_auth);
++void __iee_code _iee_set_cred_non_rcu(struct cred *cred, int non_rcu);
++void __iee_code _iee_set_cred_atomic_set_usage(struct cred *cred, int i);
++bool __iee_code _iee_set_cred_atomic_op_usage(struct cred *cred, int flag, int nr);
++void __iee_code _iee_set_cred_security(struct cred *cred, void *security);
++void __iee_code _iee_set_cred_rcu(struct cred *cred, struct rcu_head *rcu);
++void __iee_code _iee_memset(void *ptr, int data, size_t n);
++void __iee_code _iee_set_track(struct track *ptr, struct track *data);
++void __iee_code _iee_set_freeptr(freeptr_t *pptr, freeptr_t ptr);
++void __iee_code _iee_set_pte_upage(pte_t *ptep, pte_t pte);
++void __iee_code _iee_set_pte_ppage(pte_t *ptep, pte_t pte);
++void __iee_code _iee_set_token_mm(struct task_struct *tsk, struct mm_struct *mm);
++void __iee_code _iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd);
++void __iee_code _iee_init_token(struct task_struct *tsk, void *kernel_stack, void *iee_stack);
++void __iee_code _iee_free_token(struct task_struct *tsk);
++unsigned long __iee_code _iee_read_token_stack(struct task_struct *tsk);
++void __iee_code _iee_write_entry_task(struct task_struct *tsk);
++#ifdef CONFIG_KOI
++unsigned long __iee_code _iee_read_koi_stack(struct task_struct *tsk);
++void __iee_code _iee_write_koi_stack(struct task_struct *tsk, unsigned long koi_stack);
++unsigned long __iee_code _iee_read_token_ttbr1(struct task_struct *tsk);
++void __iee_code _iee_write_token_ttbr1(struct task_struct *tsk, unsigned long current_ttbr1);
++unsigned long __iee_code _iee_read_koi_kernel_stack(struct task_struct *tsk);
++void __iee_code _iee_write_koi_kernel_stack(struct task_struct *tsk, unsigned long kernel_stack);
++unsigned long __iee_code _iee_read_koi_stack_base(struct task_struct *tsk);
++void __iee_code _iee_write_koi_stack_base(struct task_struct *tsk, unsigned long koi_stack_base);
++#endif
++
++/* wrapper functions */
++void __iee_code iee_wrapper_write_in_byte(va_list args) {
++ void *ptr = va_arg(args, void *);
++ __u64 data = va_arg(args, __u64);
++ int length = va_arg(args, int);
++ _iee_write_in_byte(ptr, data, length);
++}
++
++void __iee_code iee_wrapper_set_pte(va_list args) {
++ pte_t *ptep = va_arg(args, pte_t *);
++ pte_t pte = va_arg(args, pte_t);
++ _iee_set_pte(ptep, pte);
++}
++
++void __iee_code iee_wrapper_set_pmd(va_list args) {
++ pmd_t *pmdp = va_arg(args, pmd_t *);
++ pmd_t pmd = va_arg(args, pmd_t);
++ _iee_set_pmd(pmdp, pmd);
++}
++
++void __iee_code iee_wrapper_set_p4d(va_list args) {
++ p4d_t *p4dp = va_arg(args, p4d_t *);
++ p4d_t p4d = va_arg(args, p4d_t);
++ _iee_set_p4d(p4dp, p4d);
++}
++
++void __iee_code iee_wrapper_set_pud(va_list args) {
++ pud_t *pudp = va_arg(args, pud_t *);
++ pud_t pud = va_arg(args, pud_t);
++ _iee_set_pud(pudp, pud);
++}
++
++void __iee_code iee_wrapper_set_bm_pte(va_list args) {
++ pte_t *ptep = va_arg(args, pte_t *);
++ pte_t pte = va_arg(args, pte_t);
++ _iee_set_bm_pte(ptep, pte);
++}
++
++void __iee_code iee_wrapper_set_swapper_pgd(va_list args) {
++ pgd_t *pgdp = va_arg(args, pgd_t *);
++ pgd_t pgd = va_arg(args, pgd_t);
++ _iee_set_swapper_pgd(pgdp, pgd);
++}
++
++void __iee_code iee_wrapper_set_tramp_pgd(va_list args) {
++ pgd_t *pgdp = va_arg(args, pgd_t *);
++ pgd_t pgd = va_arg(args, pgd_t);
++ _iee_set_tramp_pgd_pre_init(pgdp, pgd);
++}
++
++pteval_t __iee_code iee_wrapper_set_xchg(va_list args) {
++ pteval_t ret;
++ pte_t *ptep = va_arg(args, pte_t *);
++ pteval_t pteval = va_arg(args, pteval_t);
++ ret = _iee_set_xchg_relaxed(ptep, pteval);
++ return (u64)ret;
++}
++
++pteval_t __iee_code iee_wrapper_set_cmpxchg(va_list args) {
++ pteval_t ret;
++ pte_t *ptep = va_arg(args, pte_t *);
++ pteval_t old_pteval = va_arg(args, pteval_t);
++ pteval_t new_pteval = va_arg(args, pteval_t);
++ ret = _iee_set_cmpxchg_relaxed(ptep, old_pteval, new_pteval);
++ return (u64)ret;
++}
++
++void __iee_code iee_wrapper_set_cred_uid(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kuid_t uid = va_arg(args, kuid_t);
++ _iee_set_cred_uid(cred, uid);
++}
++
++void __iee_code iee_wrapper_set_cred_gid(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kgid_t gid = va_arg(args, kgid_t);
++ _iee_set_cred_gid(cred, gid);
++}
++
++void __iee_code iee_wrapper_copy_cred(va_list args) {
++ struct cred *old = va_arg(args, struct cred *);
++ struct cred *new = va_arg(args, struct cred *);
++ _iee_copy_cred(old, new);
++}
++
++void __iee_code iee_wrapper_set_cred_suid(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kuid_t suid = va_arg(args, kuid_t);
++ _iee_set_cred_suid(cred, suid);
++}
++
++void __iee_code iee_wrapper_set_cred_sgid(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kgid_t sgid = va_arg(args, kgid_t);
++ _iee_set_cred_sgid(cred, sgid);
++}
++
++void __iee_code iee_wrapper_set_cred_euid(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kuid_t euid = va_arg(args, kuid_t);
++ _iee_set_cred_euid(cred, euid);
++}
++
++void __iee_code iee_wrapper_set_cred_egid(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kgid_t egid = va_arg(args, kgid_t);
++ _iee_set_cred_egid(cred, egid);
++}
++
++void __iee_code iee_wrapper_set_cred_fsuid(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kuid_t fsuid = va_arg(args, kuid_t);
++ _iee_set_cred_fsuid(cred, fsuid);
++}
++
++void __iee_code iee_wrapper_set_cred_fsgid(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kgid_t fsgid = va_arg(args, kgid_t);
++ _iee_set_cred_fsgid(cred, fsgid);
++}
++
++void __iee_code iee_wrapper_set_cred_user(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct user_struct *user = va_arg(args, struct user_struct *);
++ _iee_set_cred_user(cred, user);
++}
++
++void __iee_code iee_wrapper_set_cred_user_ns(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct user_namespace *user_ns = va_arg(args, struct user_namespace *);
++ _iee_set_cred_user_ns(cred, user_ns);
++}
++
++void __iee_code iee_wrapper_set_cred_ucounts(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct ucounts *ucounts = va_arg(args, struct ucounts *);
++ _iee_set_cred_ucounts(cred, ucounts);
++}
++
++void __iee_code iee_wrapper_set_cred_group_info(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct group_info *group_info = va_arg(args, struct group_info *);
++ _iee_set_cred_group_info(cred, group_info);
++}
++
++void __iee_code iee_wrapper_set_cred_securebits(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ unsigned securebits = va_arg(args, unsigned);
++ _iee_set_cred_securebits(cred, securebits);
++}
++
++void __iee_code iee_wrapper_set_cred_cap_inheritable(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kernel_cap_t cap_inheritable = va_arg(args, kernel_cap_t);
++ _iee_set_cred_cap_inheritable(cred, cap_inheritable);
++}
++
++void __iee_code iee_wrapper_set_cred_cap_permitted(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kernel_cap_t cap_permitted = va_arg(args, kernel_cap_t);
++ _iee_set_cred_cap_permitted(cred, cap_permitted);
++}
++
++void __iee_code iee_wrapper_set_cred_cap_effective(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kernel_cap_t cap_effective = va_arg(args, kernel_cap_t);
++ _iee_set_cred_cap_effective(cred, cap_effective);
++}
++
++void __iee_code iee_wrapper_set_cred_cap_bset(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kernel_cap_t cap_bset = va_arg(args, kernel_cap_t);
++ _iee_set_cred_cap_bset(cred, cap_bset);
++}
++
++void __iee_code iee_wrapper_set_cred_cap_ambient(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ kernel_cap_t cap_ambient = va_arg(args, kernel_cap_t);
++ _iee_set_cred_cap_ambient(cred, cap_ambient);
++}
++
++void __iee_code iee_wrapper_set_cred_jit_keyring(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ unsigned long jit_keyring = va_arg(args, unsigned long);
++ _iee_set_cred_jit_keyring(cred, (unsigned char)jit_keyring);
++}
++
++void __iee_code iee_wrapper_set_cred_session_keyring(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct key *session_keyring = va_arg(args, struct key *);
++ _iee_set_cred_session_keyring(cred, session_keyring);
++}
++
++void __iee_code iee_wrapper_set_cred_process_keyring(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct key *process_keyring = va_arg(args, struct key *);
++ _iee_set_cred_process_keyring(cred, process_keyring);
++}
++
++void __iee_code iee_wrapper_set_cred_thread_keyring(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct key *thread_keyring = va_arg(args, struct key *);
++ _iee_set_cred_thread_keyring(cred, thread_keyring);
++}
++
++void __iee_code iee_wrapper_set_cred_request_key_auth(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct key *request_key_auth = va_arg(args, struct key *);
++ _iee_set_cred_request_key_auth(cred, request_key_auth);
++}
++
++void __iee_code iee_wrapper_set_cred_non_rcu(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ int non_rcu = va_arg(args, int);
++ _iee_set_cred_non_rcu(cred, non_rcu);
++}
++
++void __iee_code iee_wrapper_set_cred_atomic_set_usage(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ int i = va_arg(args, int);
++ _iee_set_cred_atomic_set_usage(cred, i);
++}
++
++u64 __iee_code iee_wrapper_set_cred_atomic_op_usage(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ int flag = va_arg(args, int);
++ int nr = va_arg(args, int);
++ return (u64)_iee_set_cred_atomic_op_usage(cred, flag, nr);
++}
++
++void __iee_code iee_wrapper_set_cred_security(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ void *security = va_arg(args, void *);
++ _iee_set_cred_security(cred, security);
++}
++
++void __iee_code iee_wrapper_set_cred_rcu(va_list args) {
++ struct cred *cred = va_arg(args, struct cred *);
++ struct rcu_head *rcu = va_arg(args, struct rcu_head *);
++ _iee_set_cred_rcu(cred, rcu);
++}
++
++void __iee_code iee_wrapper_memset(va_list args) {
++ void *ptr = va_arg(args, void *);
++ int data = va_arg(args, int);
++ size_t n = va_arg(args, size_t);
++ _iee_memset(ptr, data, n);
++}
++
++void __iee_code iee_wrapper_set_track(va_list args) {
++ struct track *ptr = va_arg(args, struct track *);
++ struct track *data = va_arg(args, struct track *);
++ _iee_set_track(ptr, data);
++}
++
++void __iee_code iee_wrapper_set_freeptr(va_list args) {
++ freeptr_t *pptr = va_arg(args, freeptr_t *);
++ freeptr_t ptr = va_arg(args, freeptr_t);
++ _iee_set_freeptr(pptr, ptr);
++}
++
++void __iee_code iee_wrapper_set_pte_upage(va_list args) {
++ pte_t *ptep = va_arg(args, pte_t *);
++ pte_t pte = va_arg(args, pte_t);
++ _iee_set_pte_upage(ptep, pte);
++}
++
++void __iee_code iee_wrapper_set_pte_ppage(va_list args) {
++ pte_t *ptep = va_arg(args, pte_t *);
++ pte_t pte = va_arg(args, pte_t);
++ _iee_set_pte_ppage(ptep, pte);
++}
++
++void __iee_code iee_wrapper_set_token_mm(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ struct mm_struct *mm = va_arg(args, struct mm_struct *);
++ _iee_set_token_mm(tsk, mm);
++}
++
++void __iee_code iee_wrapper_set_token_pgd(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ pgd_t *pgd = va_arg(args, pgd_t *);
++ _iee_set_token_pgd(tsk, pgd);
++}
++
++void __iee_code iee_wrapper_init_token(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ void *kernel_stack = va_arg(args, void *);
++ void *iee_stack = va_arg(args, void *);
++ _iee_init_token(tsk, kernel_stack, iee_stack);
++}
++
++void __iee_code iee_wrapper_free_token(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ _iee_free_token(tsk);
++}
++
++u64 __iee_code iee_wrapper_read_token_stack(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ return (u64)_iee_read_token_stack(tsk);
++}
++
++void __iee_code iee_wrapper_write_entry_task(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ _iee_write_entry_task(tsk);
++}
++
++#ifdef CONFIG_KOI
++u64 __iee_code iee_wrapper_read_koi_stack(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ return (u64)_iee_read_koi_stack(tsk);
++}
++
++void __iee_code iee_wrapper_write_koi_stack(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ unsigned long koi_stack = va_arg(args, unsigned long);
++ _iee_write_koi_stack(tsk, koi_stack);
++}
++
++u64 __iee_code iee_wrapper_read_token_ttbr1(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ return (u64)_iee_read_token_ttbr1(tsk);
++}
++
++void __iee_code iee_wrapper_write_token_ttbr1(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ unsigned long current_ttbr1 = va_arg(args, unsigned long);
++ _iee_write_token_ttbr1(tsk, current_ttbr1);
++}
++
++u64 __iee_code iee_wrapper_read_koi_kernel_stack(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ return (u64)_iee_read_koi_kernel_stack(tsk);
++}
++
++void __iee_code iee_wrapper_write_koi_kernel_stack(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ unsigned long kernel_stack = va_arg(args, unsigned long);
++ _iee_write_koi_kernel_stack(tsk, kernel_stack);
++}
++
++u64 __iee_code iee_wrapper_read_koi_stack_base(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ return (u64)_iee_read_koi_stack_base(tsk);
++}
++
++void __iee_code iee_wrapper_write_koi_stack_base(va_list args) {
++ struct task_struct *tsk = va_arg(args, struct task_struct *);
++ unsigned long koi_stack_base = va_arg(args, unsigned long);
++ _iee_write_koi_stack_base(tsk, koi_stack_base);
++}
++#endif
++// Define the function pointer type for wrapper functions.
++// Each function pointer conforms to a standardized calling convention
++// using a variable argument list (va_list) as its parameter.
++// This allows dynamic invocation of different functions with various arguments.
++typedef void (*iee_wrapper_func)(va_list args);
++iee_wrapper_func iee_wrappers[] = {
++ iee_wrapper_write_in_byte,
++ iee_wrapper_set_pte,
++ iee_wrapper_set_pmd,
++ iee_wrapper_set_pud,
++ iee_wrapper_set_p4d,
++ iee_wrapper_set_bm_pte,
++ iee_wrapper_set_swapper_pgd,
++ iee_wrapper_set_tramp_pgd,
++ (iee_wrapper_func)iee_wrapper_set_cmpxchg,
++ (iee_wrapper_func)iee_wrapper_set_xchg,
++ iee_wrapper_copy_cred,
++ iee_wrapper_set_cred_uid,
++ iee_wrapper_set_cred_gid,
++ iee_wrapper_set_cred_suid,
++ iee_wrapper_set_cred_sgid,
++ iee_wrapper_set_cred_euid,
++ iee_wrapper_set_cred_egid,
++ iee_wrapper_set_cred_fsuid,
++ iee_wrapper_set_cred_fsgid,
++ iee_wrapper_set_cred_user,
++ iee_wrapper_set_cred_user_ns,
++ iee_wrapper_set_cred_group_info,
++ iee_wrapper_set_cred_securebits,
++ iee_wrapper_set_cred_cap_inheritable,
++ iee_wrapper_set_cred_cap_permitted,
++ iee_wrapper_set_cred_cap_effective,
++ iee_wrapper_set_cred_cap_bset,
++ iee_wrapper_set_cred_cap_ambient,
++ iee_wrapper_set_cred_jit_keyring,
++ iee_wrapper_set_cred_session_keyring,
++ iee_wrapper_set_cred_process_keyring,
++ iee_wrapper_set_cred_thread_keyring,
++ iee_wrapper_set_cred_request_key_auth,
++ iee_wrapper_set_cred_non_rcu,
++ iee_wrapper_set_cred_atomic_set_usage,
++ (iee_wrapper_func)iee_wrapper_set_cred_atomic_op_usage,
++ iee_wrapper_set_cred_security,
++ iee_wrapper_set_cred_rcu,
++ iee_wrapper_memset,
++ iee_wrapper_set_track,
++ iee_wrapper_set_freeptr,
++ iee_wrapper_set_pte_upage,
++ iee_wrapper_set_pte_ppage,
++ iee_wrapper_set_token_mm,
++ iee_wrapper_set_token_pgd,
++ iee_wrapper_init_token,
++ iee_wrapper_free_token,
++ (iee_wrapper_func)iee_wrapper_read_token_stack,
++ iee_wrapper_write_entry_task,
++ iee_wrapper_set_cred_ucounts,
++#ifdef CONFIG_KOI
++ (iee_wrapper_func)iee_wrapper_read_koi_stack,
++ iee_wrapper_write_koi_stack,
++ (iee_wrapper_func)iee_wrapper_read_token_ttbr1,
++ iee_wrapper_write_token_ttbr1,
++ (iee_wrapper_func)iee_wrapper_read_koi_kernel_stack,
++ iee_wrapper_write_koi_kernel_stack,
++ (iee_wrapper_func)iee_wrapper_read_koi_stack_base,
++ iee_wrapper_write_koi_stack_base
++#endif
++};
++
++u64 __iee_code iee_dispatch(int flag, ...){
++ va_list pArgs;
++
++ va_start(pArgs, flag);
++
++ switch(flag)
++ {
++ case IEE_OP_SET_CMPXCHG:
++ {
++ pteval_t ret = iee_wrapper_set_cmpxchg(pArgs);
++ va_end(pArgs);
++ return (u64)ret;
++ }
++ case IEE_OP_SET_XCHG:
++ {
++ pteval_t ret = iee_wrapper_set_xchg(pArgs);
++ va_end(pArgs);
++ return (u64)ret;
++ }
++ case IEE_OP_SET_CRED_ATOP_USAGE:
++ {
++ u64 ret = iee_wrapper_set_cred_atomic_op_usage(pArgs);
++ va_end(pArgs);
++ return ret;
++ }
++ case IEE_READ_TOKEN_STACK:
++ {
++ u64 ret = iee_wrapper_read_token_stack(pArgs);
++ va_end(pArgs);
++ return ret;
++ }
++#ifdef CONFIG_KOI
++ case IEE_READ_KOI_STACK:
++ {
++ u64 ret = iee_wrapper_read_koi_stack(pArgs);
++ va_end(pArgs);
++ return ret;
++ }
++ case IEE_READ_TOKEN_TTBR1:
++ {
++ u64 ret = iee_wrapper_read_token_ttbr1(pArgs);
++ va_end(pArgs);
++ return ret;
++ }
++ case IEE_READ_KOI_KERNEL_STACK:
++ {
++ u64 ret = iee_wrapper_read_koi_kernel_stack(pArgs);
++ va_end(pArgs);
++ return ret;
++ }
++ case IEE_READ_KOI_STACK_BASE:
++ {
++ u64 ret = iee_wrapper_read_koi_stack_base(pArgs);
++ va_end(pArgs);
++ return ret;
++ }
++#endif
++ default:
++ {
++ #ifndef CONFIG_KOI
++ if((flag < IEE_WRITE_IN_BYTE) | (flag > IEE_OP_SET_CRED_UCOUNTS))
++ panic("Invalid iee flag.\n");
++ #else
++ if((flag < IEE_WRITE_IN_BYTE) | (flag > IEE_WRITE_KOI_STACK_BASE))
++ panic("Invalid iee flag.\n");
++ #endif
++ iee_wrappers[flag](pArgs);
++ break;
++ }
++ }
++
++ va_end(pArgs);
++ return 0;
++}
++
++#ifdef CONFIG_KOI
++unsigned long __iee_code _iee_read_koi_stack(struct task_struct *tsk)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ return (unsigned long)token->koi_stack;
++}
++
++void __iee_code _iee_write_koi_stack(struct task_struct *tsk, unsigned long koi_stack)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ token->koi_stack = koi_stack;
++}
++
++unsigned long __iee_code _iee_read_token_ttbr1(struct task_struct *tsk)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ return token->current_ttbr1;
++}
++
++void __iee_code _iee_write_token_ttbr1(struct task_struct *tsk, unsigned long current_ttbr1)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ token->current_ttbr1 = current_ttbr1;
++}
++
++unsigned long __iee_code _iee_read_koi_kernel_stack(struct task_struct *tsk)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ return token->koi_kernel_stack;
++}
++
++void __iee_code _iee_write_koi_kernel_stack(struct task_struct *tsk, unsigned long kernel_stack)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ token->koi_kernel_stack = kernel_stack;
++}
++
++unsigned long __iee_code _iee_read_koi_stack_base(struct task_struct *tsk)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ return (unsigned long)token->koi_stack_base;
++}
++
++void __iee_code _iee_write_koi_stack_base(struct task_struct *tsk, unsigned long koi_stack_base)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ token->koi_stack_base = koi_stack_base;
++}
++#endif
++
++// Protect the __entry_task.
++__attribute__((aligned(PAGE_SIZE))) DECLARE_PER_CPU(struct task_struct *[PAGE_SIZE/sizeof(struct task_struct *)], __entry_task);
++void __iee_code _iee_write_entry_task(struct task_struct *tsk)
++{
++ // Add check of tsk.
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++
++ unsigned long flags;
++ unsigned long res;
++ struct task_struct **entry_addr;
++ local_irq_save(flags);
++ asm volatile("at s1e1r, %0"::"r"(token));
++ isb();
++ res = read_sysreg(par_el1);
++ local_irq_restore(flags);
++
++ // If it is logical map, that means it is not a token.
++ if(__phys_to_iee(res & PTE_ADDR_MASK) == (((unsigned long)token) & PTE_ADDR_MASK))
++ panic("Trying to forge a token.\n");
++
++ if(!token->valid)
++ panic("Trying to write a wrong task into __entry_task.\n");
++ entry_addr = (struct task_struct **)__phys_to_iee(__pa(SHIFT_PERCPU_PTR(__entry_task,__kern_my_cpu_offset())));
++ *entry_addr = tsk;
++}
++
++unsigned long __iee_code _iee_read_token_stack(struct task_struct *tsk)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ return (unsigned long)token->iee_stack;
++}
++
++void __iee_code _iee_free_token(struct task_struct *tsk)
++{
++ _iee_memset(tsk, 0, sizeof(struct task_token));
++}
++
++#ifdef CONFIG_KOI
++extern unsigned long koi_swapper_ttbr1;
++#endif
++void __iee_code _iee_init_token(struct task_struct *tsk, void *kernel_stack, void *iee_stack)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ token->kernel_stack = kernel_stack;
++ token->iee_stack = iee_stack;
++ token->valid = true;
++#ifdef CONFIG_KOI
++ token->koi_kernel_stack = NULL;
++ token->koi_stack = NULL;
++ token->koi_stack_base = NULL;
++ token->current_ttbr1 = 0;
++#endif
++}
++
++void __iee_code _iee_set_token_mm(struct task_struct *tsk, struct mm_struct *mm)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ token->mm = mm;
++}
++
++void __iee_code _iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd)
++{
++ struct task_token *token = (struct task_token *)__phys_to_iee(__pa(tsk));
++ token->pgd = pgd;
++}
++
++void __iee_code _iee_set_freeptr(freeptr_t *pptr, freeptr_t ptr)
++{
++ pptr = (freeptr_t *)__phys_to_iee(__pa(pptr));
++ *pptr = ptr;
++}
++
++#pragma GCC push_options
++#pragma GCC optimize("O0")
++void __iee_code _iee_memset(void *ptr, int data, size_t n)
++{
++ char *_ptr = (char *)__phys_to_iee(__pa(ptr));
++
++ while (n--)
++ *_ptr++ = data;
++}
++
++void __iee_code _iee_memcpy(void *dst, void *src, size_t n)
++{
++ char *_dst = (char *)__phys_to_iee(__pa(dst));
++ char *_src = (char *)src;
++
++ while(n--)
++ *_dst++ = *_src++;
++}
++#pragma GCC pop_options
++
++void __iee_code _iee_set_track(struct track *ptr, struct track *data)
++{
++ _iee_memcpy(ptr, data, sizeof(struct track));
++}
++
++void __iee_code _iee_set_cred_rcu(struct cred *cred, struct rcu_head *rcu)
++{
++ if(cred == &init_cred)
++ cred = (struct cred *)__phys_to_iee(__pa_symbol(cred));
++ else
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ #ifdef CONFIG_CREDP
++ *((struct rcu_head **)(&(cred->rcu.func))) = rcu;
++ #endif
++}
++
++void __iee_code _iee_set_cred_security(struct cred *cred, void *security)
++{
++ if(cred == &init_cred)
++ cred = (struct cred *)__phys_to_iee(__pa_symbol(cred));
++ else
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->security = security;
++}
++
++bool __iee_code _iee_set_cred_atomic_op_usage(struct cred *cred, int flag, int nr)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ switch (flag)
++ {
++ case AT_ADD: {
++ atomic_long_add(nr, &cred->usage);
++ return 0;
++ }
++ case AT_INC_NOT_ZERO: {
++ return atomic_long_inc_not_zero(&cred->usage);
++ }
++ case AT_SUB_AND_TEST: {
++ return atomic_long_sub_and_test(nr, &cred->usage);
++ }
++ }
++ return 0;
++}
++
++void __iee_code _iee_set_cred_atomic_set_usage(struct cred *cred, int i)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ atomic_long_set(&cred->usage,i);
++}
++
++void __iee_code _iee_set_cred_non_rcu(struct cred *cred, int non_rcu)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->non_rcu = non_rcu;
++}
++
++void __iee_code _iee_set_cred_session_keyring(struct cred *cred, struct key *session_keyring)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->session_keyring = session_keyring;
++}
++
++void __iee_code _iee_set_cred_process_keyring(struct cred *cred, struct key *process_keyring)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->process_keyring = process_keyring;
++}
++
++void __iee_code _iee_set_cred_thread_keyring(struct cred *cred, struct key *thread_keyring)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->thread_keyring = thread_keyring;
++}
++
++void __iee_code _iee_set_cred_request_key_auth(struct cred *cred, struct key *request_key_auth)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->request_key_auth = request_key_auth;
++}
++
++void __iee_code _iee_set_cred_jit_keyring(struct cred *cred, unsigned char jit_keyring)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->jit_keyring = jit_keyring;
++}
++
++void __iee_code _iee_set_cred_cap_inheritable(struct cred *cred, kernel_cap_t cap_inheritable)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->cap_inheritable = cap_inheritable;
++}
++
++void __iee_code _iee_set_cred_cap_permitted(struct cred *cred, kernel_cap_t cap_permitted)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->cap_permitted = cap_permitted;
++}
++
++void __iee_code _iee_set_cred_cap_effective(struct cred *cred, kernel_cap_t cap_effective)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->cap_effective = cap_effective;
++}
++
++void __iee_code _iee_set_cred_cap_bset(struct cred *cred, kernel_cap_t cap_bset)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->cap_bset = cap_bset;
++}
++
++void __iee_code _iee_set_cred_cap_ambient(struct cred *cred, kernel_cap_t cap_ambient)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->cap_ambient = cap_ambient;
++}
++
++void __iee_code _iee_set_cred_securebits(struct cred *cred, unsigned securebits)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->securebits = securebits;
++}
++
++void __iee_code _iee_set_cred_group_info(struct cred *cred, struct group_info *group_info)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->group_info = group_info;
++}
++
++void __iee_code _iee_set_cred_ucounts(struct cred *cred, struct ucounts *ucounts)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->ucounts = ucounts;
++}
++
++void __iee_code _iee_set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->user_ns = user_ns;
++}
++
++void __iee_code _iee_set_cred_user(struct cred *cred, struct user_struct *user)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->user = user;
++}
++
++void __iee_code _iee_set_cred_fsgid(struct cred *cred, kgid_t fsgid)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->fsgid = fsgid;
++}
++
++void __iee_code _iee_set_cred_fsuid(struct cred *cred, kuid_t fsuid)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->fsuid = fsuid;
++}
++
++void __iee_code _iee_set_cred_egid(struct cred *cred, kgid_t egid)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->egid = egid;
++}
++
++void __iee_code _iee_set_cred_euid(struct cred *cred, kuid_t euid)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->euid = euid;
++}
++
++void __iee_code _iee_set_cred_sgid(struct cred *cred, kgid_t sgid)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->sgid = sgid;
++}
++
++void __iee_code _iee_set_cred_suid(struct cred *cred, kuid_t suid)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->suid = suid;
++}
++
++void __iee_code _iee_copy_cred(struct cred *old, struct cred *new)
++{
++ #ifdef CONFIG_CREDP
++ struct rcu_head *rcu = (struct rcu_head *)(new->rcu.func);
++ struct cred *_new = (struct cred *)__phys_to_iee(__pa(new));
++ _iee_memcpy(new,old,sizeof(struct cred));
++ *(struct rcu_head **)(&(_new->rcu.func)) = rcu;
++ *(struct rcu_head *)(_new->rcu.func) = *(struct rcu_head *)(old->rcu.func);
++ #endif
++}
++
++void __iee_code _iee_set_cred_gid(struct cred *cred, kgid_t gid)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->gid = gid;
++}
++
++void __iee_code _iee_set_cred_uid(struct cred *cred, kuid_t uid)
++{
++ cred = (struct cred *)__phys_to_iee(__pa(cred));
++ cred->uid = uid;
++}
++
++void __iee_code _iee_write_in_byte(void *ptr, __u64 data, int length)
++{
++ ptr = (void *)__phys_to_iee(__pa(ptr));
++ switch(length) {
++ case 8: {
++ *(__u64 *)ptr = data;
++ break;
++ }
++ case 4: {
++ *(__u32 *)ptr = (__u32)data;
++ break;
++ }
++ case 2: {
++ *(__u16 *)ptr = (__u16)data;
++ break;
++ }
++ case 1: {
++ *(__u8 *)ptr = (__u8)data;
++ break;
++ }
++ }
++}
++
++pteval_t __iee_code _iee_set_xchg_relaxed(pte_t *ptep, pteval_t pteval)
++{
++ pteval_t ret = xchg_relaxed((pteval_t *)(__phys_to_iee(__pa(ptep))), pteval);
++ return ret;
++}
++
++pteval_t __iee_code _iee_set_cmpxchg_relaxed(pte_t *ptep, pteval_t old_pteval, pteval_t new_pteval)
++{
++ pteval_t pteval = cmpxchg_relaxed((pteval_t *)(__phys_to_iee(__pa(ptep))), old_pteval, new_pteval);
++ return pteval;
++}
++
++/* Check if addr is allocated in IEE page */
++static inline bool check_addr_in_iee_valid(unsigned long addr)
++{
++ unsigned long flags;
++ unsigned long res;
++ local_irq_save(flags);
++ asm volatile("at s1e1r, %0"::"r"(addr));
++ isb();
++ res = read_sysreg(par_el1);
++ local_irq_restore(flags);
++
++ // If it is not logical map, that means it is a token.
++ if(__phys_to_iee(res & PTE_ADDR_MASK) != addr)
++ return false;
++
++ return !(res & 0x1);
++}
++
++void __iee_code _iee_set_tramp_pgd_pre_init(pgd_t *pgdp, pgd_t pgd)
++{
++ WRITE_ONCE(*((pgd_t *)(__phys_to_iee(__pa_symbol(pgdp)))), pgd);
++}
++
++void __iee_code _iee_set_swapper_pgd(pgd_t *pgdp, pgd_t pgd)
++{
++ if(!(pgd_val(pgd) & PMD_SECT_VALID))
++ {
++ WRITE_ONCE(*((pgd_t *)(__phys_to_iee(__pa_symbol(pgdp)))), pgd);
++ return;
++ }
++
++ if ((pgd_val(pgd) & PMD_TABLE_BIT) && !check_addr_in_iee_valid(__phys_to_iee(__pgd_to_phys(pgd))))
++ panic("You can't use non-iee-pgtable\n");
++
++ if((pgdp >= pgd_offset_pgd((pgd_t *)swapper_pg_dir, PAGE_OFFSET + BIT(vabits_actual - 2))) && (pgdp < pgd_offset_pgd((pgd_t *)swapper_pg_dir, PAGE_OFFSET + BIT(vabits_actual - 1))) && !(pgd_val(pgd) & PGD_APT))
++ panic("Set IEE pgd U page.\n");
++
++ WRITE_ONCE(*((pgd_t *)(__phys_to_iee(__pa_symbol(pgdp)))), pgd);
++}
++
++void __iee_code _iee_set_p4d(p4d_t *p4dp, p4d_t p4d)
++{
++ if(!(p4d_val(p4d) & PMD_SECT_VALID))
++ {
++ WRITE_ONCE(*((p4d_t *)(__phys_to_iee(__pa(p4dp)))), p4d);
++ return;
++ }
++
++ if ((p4d_val(p4d) & PMD_TABLE_BIT) && !check_addr_in_iee_valid(__phys_to_iee(__p4d_to_phys(p4d))))
++ panic("You can't use non-iee-pgtable\n");
++
++ WRITE_ONCE(*((p4d_t *)(__phys_to_iee(__pa(p4dp)))), p4d);
++}
++
++void __iee_code _iee_set_pud(pud_t *pudp, pud_t pud)
++{
++ if(!(pud_val(pud) & PMD_SECT_VALID))
++ {
++ WRITE_ONCE(*((pud_t *)(__phys_to_iee(__pa(pudp)))), pud);
++ return;
++ }
++
++ if ((pud_val(pud) & PMD_TABLE_BIT) && !check_addr_in_iee_valid(__phys_to_iee(__pud_to_phys(pud))))
++ panic("You can't use non-iee-pgtable\n");
++
++ WRITE_ONCE(*((pud_t *)(__phys_to_iee(__pa(pudp)))), pud);
++}
++
++// Return true if the modify does not break DEP.
++static inline bool check_pmd_dep(char *addr, pmd_t pmd)
++{
++ // DEP for kernel code and readonly data
++ // _text: .text start addr, __init_begin: .rodata end addr
++ if (addr >= _stext && addr < _etext)
++ {
++ if ((PTE_WRITE & pmd_val(pmd)) || // DBM == 1 --> writable
++ !(PTE_RDONLY & pmd_val(pmd))) // DBM == 0 && AP[2] = 0 --> writable
++ {
++ panic("Can't make kernel's text/readonly page as writable!\n"
++ "addr = 0x%16llx, pmd_val = 0x%16llx",
++ (u64)addr, pmd_val(pmd));
++ }
++ }
++ return true;
++}
++
++// Return true if the pmd table is a part of kernel page table.
++// TODO : Optimize to get lower overhead.
++static inline bool is_kernel_pmd_table(pmd_t *pmdp, pmd_t pmd)
++{
++ int i = 0,j = 0;
++ for(i = 0; i < PAGE_SIZE/sizeof(pgd_t); i++)
++ {
++ pgd_t *pgdp = (pgd_t *)swapper_pg_dir + i;
++ if((pgd_val(*pgdp) & PMD_SECT_VALID) && (pgd_val(*pgdp) & PMD_TABLE_BIT))
++ {
++ for(j = 0; j < PAGE_SIZE/sizeof(pud_t); j++)
++ {
++ pud_t *pudp = (pud_t *)__va(__pgd_to_phys(*pgdp)) + i;
++ if((pud_val(*pudp) & PMD_SECT_VALID) && (pud_val(*pudp) & PMD_TABLE_BIT))
++ {
++ pmd_t *current_pmdp = __va(__pud_to_phys(*pudp));
++ if((unsigned long)current_pmdp == ((unsigned long)pmdp & PAGE_MASK))
++ return true;
++ }
++ }
++ }
++ }
++ return false;
++}
++
++// Return true if it is mapped to a physical range containing IEE page.
++// TODO : Optimize to get lower overhead.
++static inline bool check_addr_range_in_iee_valid(pmd_t pmd)
++{
++ int i = 0;
++ unsigned long addr = __phys_to_iee(__pmd_to_phys(pmd));
++ for(i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++)
++ {
++ if(check_addr_in_iee_valid(addr + PAGE_SIZE * i))
++ return true;
++ }
++ return false;
++}
++
++void __iee_code _iee_set_pmd(pmd_t *pmdp, pmd_t pmd)
++{
++ char * addr = (char *)__phys_to_kimg(__pmd_to_phys(pmd));
++
++ if(!(pmd_val(pmd) & PMD_SECT_VALID))
++ {
++ WRITE_ONCE(*((pmd_t *)(__phys_to_iee(__pa(pmdp)))), pmd);
++ return;
++ }
++
++ // Check if the pte table is legally allocated.
++ if ((pmd_val(pmd) & PMD_TABLE_BIT) && !check_addr_in_iee_valid(__phys_to_iee(__pmd_to_phys(pmd))))
++ panic("You can't use non-iee-pgtable\n");
++
++ // Avoid mapping a huge pmd as U page.
++ if(!(pmd_val(pmd) & PMD_TABLE_BIT) && (pmd_val(pmd) & PMD_SECT_USER) && is_kernel_pmd_table(pmdp, pmd))
++ panic("Set a block descriptor in kernel space U page.\n");
++
++ // Avoid mapping a huge pmd to IEE physical page.
++ if(!(pmd_val(pmd) & PMD_TABLE_BIT) && check_addr_range_in_iee_valid(pmd))
++ panic("Mapping IEE physical page to a huge pmd.\n");
++
++ if(!check_pmd_dep(addr, pmd))
++ return;
++
++ WRITE_ONCE(*((pmd_t *)(__phys_to_iee(__pa(pmdp)))), pmd);
++}
++
++// Return true if the pte table is a part of kernel page table.
++// TODO : Optimize to get lower overhead.
++static inline bool is_kernel_pte_table(pte_t *ptep, pte_t pte)
++{
++ return false;
++}
++
++// Return true if it does not change the privilage or add new U page in kernel.
++static inline bool check_privilage_safe(pte_t *ptep, pte_t pte)
++{
++ if(!(pte_val(pte) & PTE_VALID))
++ return true;
++
++ if((pte_val(*ptep) & PTE_VALID))
++ {
++ if((pte_val(*ptep) & PTE_USER) != (pte_val(pte) & PTE_USER))
++ panic("Incorrectly change privilage.\n");
++ }
++ else
++ {
++ if((pte_val(pte) & PTE_USER) && is_kernel_pte_table(ptep, pte))
++ panic("Add new U page in kernel space.\n");
++ }
++ return true;
++}
++
++// TODO : When adding a new executable page, check it for DEP.
++static inline bool safely_adding_new_exec_page(pte_t *ptep, pte_t pte)
++{
++ return true;
++}
++
++// Return true if it is only changing prot of a pte.
++static inline bool is_changing_pte_prot(pte_t *ptep, pte_t pte)
++{
++ if(((pte_val(*ptep) ^ pte_val(pte)) & PTE_ADDR_MASK) == 0)
++ return true;
++ else
++ return false;
++}
++
++// Return true if the modify does not break DEP.
++static inline bool check_pte_dep(char *addr, pte_t pte)
++{
++ // DEP for kernel code and readonly data
++ // _text: .text start addr, __init_begin: .rodata end addr
++ if (addr >= _stext && addr < _etext)
++ {
++ if ((PTE_WRITE & pte_val(pte)) // DBM == 1 --> writable
++ || !(PTE_RDONLY & pte_val(pte))) // DBM == 0 && AP[2] = 0 --> writable
++ {
++ panic("Can't make kernel's text/readonly page as writable!\n"
++ "addr = 0x%16llx, pte_val = 0x%16llx",
++ (u64)addr, pte_val(pte));
++ }
++ }
++ return true;
++}
++
++void __iee_code _iee_set_pte(pte_t *ptep, pte_t pte)
++{
++ char * addr = (char *)__phys_to_kimg(__pte_to_phys(pte));
++
++ if(!(pte_val(pte) & PTE_VALID))
++ {
++ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
++ return;
++ }
++
++ // Avoid modify privilage unsafely.
++ if(!check_privilage_safe(ptep, pte))
++ panic("You are modify privilage unsafely.\n");
++
++ // Avoid mapping a new executable page.
++ if(!safely_adding_new_exec_page(ptep, pte))
++ panic("You are adding a new executable page unsafely.\n");
++
++ // Avoid mapping a new VA to IEE PA.
++ if(!is_changing_pte_prot(ptep, pte) &&
++ check_addr_in_iee_valid(__phys_to_iee(__pte_to_phys(pte))))
++ panic("You are remmaping IEE page to other VA.\n");
++
++ // Avoid mapping a writable VA to kernel code PA.
++ if(!check_pte_dep(addr, pte))
++ return;
++
++ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
++}
++
++// Return true if it only sets U page and modify NG.
++static inline bool is_setting_upage(pte_t *ptep, pte_t pte)
++{
++ if(((pte_val(*ptep) ^ pte_val(pte)) & ~(PTE_USER | PTE_NG)) != 0)
++ panic("Incorrectly setting U page.\n");
++ if((pte_val(pte) & PTE_USER) != PTE_USER)
++ panic("Using error interface to set P page.\n");
++ return true;
++}
++
++void __iee_code _iee_set_pte_upage(pte_t *ptep, pte_t pte)
++{
++ // Check if it only change the prot.
++ if(!is_setting_upage(ptep,pte))
++ panic("Incorrectly setting U page.\n");
++
++ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
++}
++
++// Return true if it only sets P page and modify NG.
++static inline bool is_setting_ppage(pte_t *ptep, pte_t pte)
++{
++ if(((pte_val(*ptep) ^ pte_val(pte)) & ~(PTE_USER | PTE_NG)) != 0)
++ panic("Incorrectly setting P page.\n");
++ if((pte_val(pte) & PTE_USER) != 0)
++ panic("Using error interface to set U page.\n");
++ return true;
++}
++
++void __iee_code _iee_set_pte_ppage(pte_t *ptep, pte_t pte)
++{
++ // Check if it only change the prot.
++ if(!is_setting_ppage(ptep,pte))
++ panic("Incorrectly setting P page.\n");
++
++ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
++}
++
++void __iee_code _iee_set_bm_pte(pte_t *ptep, pte_t pte)
++{
++ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa_symbol(ptep)))), pte);
++}
++
++/* Data in iee_si_base is visible to all pgd while iee_si_data is private. */
++unsigned long iee_base_idmap_pg_dir __iee_si_data;
++unsigned long iee_base_reserved_pg_dir __iee_si_data;
++unsigned long iee_base__bp_harden_el1_vectors __iee_si_data;
++bool iee_init_done __iee_si_data;
++unsigned long iee_si_tcr __iee_si_data;
++
++static u64 __iee_si_code inline iee_si_mask(unsigned long mask, unsigned long new_val, unsigned long old_val)
++{
++ return (new_val & mask) | (old_val & ~mask);
++}
++/*
++ * handler function for requests of executing sensitive instrutions.
++ */
++u64 __iee_si_code iee_si_handler(int flag, ...)
++{
++ va_list pArgs;
++ u64 old_val, new_val;
++
++ // BUG_ON(flag > IEE_WRITE_MDSCR);
++ va_start(pArgs, flag);
++ switch (flag) {
++ case IEE_SI_TEST:
++ break;
++ case IEE_WRITE_SCTLR: {
++ old_val = read_sysreg(sctlr_el1);
++ new_val = va_arg(pArgs, u64);
++ new_val = iee_si_mask(IEE_SCTLR_MASK, new_val, old_val);
++ write_sysreg(new_val, sctlr_el1);
++ break;
++ }
++ case IEE_WRITE_TTBR0:
++ case IEE_CONTEXT_SWITCH: {
++ u64 new_asid, new_phys, old_phys, token_phys;
++ struct task_struct *tsk;
++ struct task_token *token;
++ new_val = va_arg(pArgs, u64);
++ new_phys = (new_val & PAGE_MASK) & ~TTBR_ASID_MASK;
++ new_asid = new_val >> 48;
++
++ // Check ASID first
++ if (new_phys == iee_base_reserved_pg_dir){
++ if (new_asid != 1)
++ panic("IEE SI warning: reserved_pg_dir ASID invalid: %llx:%llx", new_asid, new_val);
++ }
++ // Already reserved asid 1 for iee rwx gate.
++ else if (new_asid == 0){
++ new_val |= FIELD_PREP(TTBR_ASID_MASK, 1);
++ printk("IEE SI: Modify ASID of %llx to 1.", new_val);
++ }
++ // TO DO: operations to protect idmap_pg_dir
++ else if (new_phys == iee_base_idmap_pg_dir)
++ {
++ // printk("IEE SI: switch to idmap_pg_dir.);
++ }
++ else if (new_asid % 2 ==0)
++ panic("IEE SI warning: TTBR0 ASID invalid: %llx:%llx", new_asid, new_val);
++
++ /* Skip verification if iee hasn't been initialized. */
++ if (iee_init_done){
++ // Verify current sp_el0 with iee token info
++ asm volatile("mrs %x0, sp_el0":"=r"(tsk));
++ token = (struct task_token *)__phys_to_iee(__pa(tsk));
++
++ /*
++ * token->pgd != NULL means it is a user task, then we need to check whether current ttbr0 is correct.
++ */
++ if (token->pgd){
++ old_val = read_sysreg(ttbr0_el1);
++ // When TTBR0 is reserved_pg_dir then no checking is available.
++ if (old_val != iee_base_reserved_pg_dir){
++ old_phys = (old_val & PAGE_MASK) & ~TTBR_ASID_MASK;
++ token_phys = __pa(token->pgd);
++ if (old_phys != token_phys)
++ panic("IEE SI warning: Pgd set error. old ttbr0:%lx, token ttbr0:%lx, token pgd:%lx",
++ (unsigned long)old_phys, (unsigned long)token_phys, (unsigned long)(token->pgd));
++ }
++ }
++ }
++ // all checks are done.
++ write_sysreg(new_val, ttbr0_el1);
++
++ // SET ASID in TTBR1 when context switch
++ if (flag == IEE_CONTEXT_SWITCH){
++ new_val = (read_sysreg(ttbr1_el1) & ~TTBR_ASID_MASK) | FIELD_PREP(TTBR_ASID_MASK, new_asid-1);
++ write_sysreg(new_val, ttbr1_el1);
++ }
++ break;
++ }
++ case IEE_WRITE_VBAR: {
++ u64 el1_vector;
++ new_val = va_arg(pArgs, u64);
++ el1_vector = iee_base__bp_harden_el1_vectors;
++ if(new_val == el1_vector || new_val == el1_vector+SZ_2K ||
++ new_val == el1_vector+SZ_2K*2 || new_val == el1_vector+SZ_2K*3)
++ write_sysreg(new_val, vbar_el1);
++ break;
++ }
++ case IEE_WRITE_TCR: {
++ old_val = read_sysreg(tcr_el1);
++ new_val = va_arg(pArgs, u64);
++ new_val = iee_si_mask(IEE_TCR_MASK, new_val, old_val);
++ write_sysreg(new_val, tcr_el1);
++ break;
++ }
++ case IEE_WRITE_MDSCR: {
++ old_val = read_sysreg(mdscr_el1);
++ new_val = va_arg(pArgs, u64);
++ new_val = iee_si_mask(IEE_MDSCR_MASK, new_val, old_val);
++ write_sysreg(new_val, mdscr_el1);
++ break;
++ }
++ }
++ va_end(pArgs);
++ return 0;
++}
++/*
++ * TODO: scan a page to check whether it contains sensitive instructions
++ * return 1 when finding sensitive inst, 0 on safe page.
++ */
++int iee_si_scan_page(unsigned long addr);
++#endif
+\ No newline at end of file
+diff --git a/arch/arm64/kernel/koi/Makefile b/arch/arm64/kernel/koi/Makefile
+new file mode 100644
+index 000000000000..9be8710b714a
+--- /dev/null
++++ b/arch/arm64/kernel/koi/Makefile
+@@ -0,0 +1 @@
++obj-y += koi.o
+\ No newline at end of file
+diff --git a/arch/arm64/kernel/koi/koi.c b/arch/arm64/kernel/koi/koi.c
+new file mode 100644
+index 000000000000..716ba16ab358
+--- /dev/null
++++ b/arch/arm64/kernel/koi/koi.c
+@@ -0,0 +1,1327 @@
++#include "asm/koi.h"
++#include "linux/compiler_attributes.h"
++#include "linux/compiler_types.h"
++#include "asm/barrier.h"
++#include "asm-generic/bug.h"
++#include "asm-generic/errno-base.h"
++#include "asm-generic/memory_model.h"
++#include "asm-generic/pgtable-nop4d.h"
++#include "asm-generic/rwonce.h"
++#include "asm/pgalloc.h"
++#include "asm/memory.h"
++#include "linux/bitfield.h"
++#include "linux/compiler.h"
++#include "linux/types.h"
++#include "linux/spinlock.h"
++#include "linux/spinlock_types.h"
++#include "linux/kernel.h"
++#include "linux/rculist.h"
++#include "linux/rcupdate.h"
++#include "linux/list.h"
++#include "asm/current.h"
++#include "linux/compiler_types.h"
++#include "asm-generic/barrier.h"
++#include "asm-generic/rwonce.h"
++#include "asm-generic/pgalloc.h"
++#include "asm/cpufeature.h"
++#include "asm/kvm_hyp.h"
++#include "asm/mmu.h"
++#include "asm/mmu_context.h"
++#include "asm/page-def.h"
++#include "asm/pgalloc.h"
++#include "asm/pgtable-hwdef.h"
++#include "asm/pgtable-types.h"
++#include "asm/pgtable.h"
++#include "asm/string.h"
++#include "asm/sysreg.h"
++#include "linux/bitfield.h"
++#include "linux/compiler.h"
++#include "linux/export.h"
++#include "linux/gfp.h"
++#include "linux/huge_mm.h"
++#include "linux/kallsyms.h"
++#include "linux/kconfig.h"
++#include "linux/kern_levels.h"
++#include "linux/kernel.h"
++#include "linux/list.h"
++#include "linux/lockdep.h"
++#include "linux/mm.h"
++#include "linux/mm_types.h"
++#include "linux/pgtable.h"
++#include "linux/printk.h"
++#include "linux/rculist.h"
++#include "linux/rcupdate.h"
++#include "linux/rmap.h"
++#include "linux/sched.h"
++#include "linux/stddef.h"
++#include "linux/string.h"
++#include "linux/swap.h"
++#include "linux/swapops.h"
++#include "linux/types.h"
++#include "linux/slab.h"
++#include "linux/string.h"
++#include "linux/hashtable.h"
++
++#define __koi_code __section(".koi.text")
++#define __koi_data __section(".data..koi")
++
++extern unsigned long __koi_code_start[];
++extern unsigned long __koi_code_end[];
++extern unsigned long __koi_data_start[];
++extern unsigned long __koi_data_end[];
++#ifdef CONFIG_IEE
++extern unsigned long __iee_si_base_start[];
++extern unsigned long __iee_exec_entry_start[];
++extern unsigned long __iee_exec_entry_end[];
++#endif
++
++__koi_data unsigned long koi_swapper_ttbr1 = 0;
++EXPORT_SYMBOL(koi_swapper_ttbr1);
++#define KOI_SWAPPER_MASK 0x0000fffffffffff0
++
++__attribute__((aligned(PAGE_SIZE)))
++DEFINE_PER_CPU(unsigned long[PAGE_SIZE / sizeof(unsigned long)],
++ koi_irq_current_ttbr1);
++EXPORT_SYMBOL(koi_irq_current_ttbr1);
++
++extern void koi_switch_to_ko_stack(unsigned long stack_top);
++extern void init_ko_mm(struct mm_struct *ko_mm, pgd_t *pgdp);
++extern void koi_check_and_switch_context(struct mm_struct *mm);
++extern int koi_add_page_mapping(unsigned long dst, unsigned long src);
++extern unsigned long _iee_read_token_ttbr1(struct task_struct *tsk);
++/**
++*struct koi_mem_list - maintain a linked list of free memory in the kernel
++*@addr: stating address of this memory
++*@size: the size of the memory
++*@list: the head of the koi_mem_list
++*@rcu: for rcu
++*/
++struct koi_mem_list {
++ unsigned long addr;
++ unsigned long size;
++ struct list_head list;
++ struct rcu_head rcu;
++};
++//mapping parameter pointer to copy
++struct koi_addr_map {
++ unsigned long buffer_addr;
++ unsigned long orig_addr;
++ int offset;
++ struct hlist_node node;
++ struct rcu_head rcu;
++};
++
++DEFINE_HASHTABLE(koi_mem_htbl, HASH_TABLE_BIT);
++EXPORT_SYMBOL(koi_mem_htbl);
++DEFINE_SPINLOCK(koi_mem_htbl_spin_lock);
++EXPORT_SYMBOL(koi_mem_htbl_spin_lock);
++
++EXPORT_SYMBOL(koi_do_switch_to_ko_stack);
++EXPORT_SYMBOL(koi_do_switch_to_kernel_stack);
++
++extern unsigned long long iee_rw_gate(int flag, ...);
++
++/**
++* koi_ttbr_ctor - return ttbr1 for the given driver module
++*/
++unsigned long koi_ttbr_ctor(struct module *mod)
++{
++ struct koi_mem_hash_node *ko;
++ struct mm_struct *ko_mm;
++ unsigned long ttbr1;
++ unsigned long asid;
++ int bkt;
++ rcu_read_lock();
++ hash_for_each_rcu (koi_mem_htbl, bkt, ko, node) {
++ if (ko->mod == mod) {
++ ko_mm = ko->ko_mm;
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (!ko_mm) {
++ printk(KERN_ERR "cannot found module %s in koi_mem_htbl",
++ mod->name);
++ return 0;
++ }
++ asm volatile("mrs %0, ttbr0_el1\n":"=r"(asid):);
++ asid &= TTBR_ASID_MASK;
++ ttbr1 = ko->ko_ttbr1 | asid;
++ // koi_check_and_switch_context(ko_mm);
++ // asid = ASID(ko_mm);
++ // ttbr1 = ko->ko_ttbr1 | FIELD_PREP(TTBR_ASID_MASK, asid);
++ return ttbr1;
++}
++EXPORT_SYMBOL(koi_ttbr_ctor);
++//release the hash node
++static __maybe_unused void koi_mem_hash_node_free(struct rcu_head *rcu)
++{
++ struct koi_mem_hash_node *node =
++ container_of(rcu, struct koi_mem_hash_node, rcu);
++ kfree(node);
++}
++//release free memory linked list nodes
++static void koi_mem_node_free(struct rcu_head *rcu)
++{
++ struct koi_mem_list *mem_node =
++ container_of(rcu, struct koi_mem_list, rcu);
++ kfree(mem_node);
++}
++//release the node in koi_addr_map
++static void koi_addr_map_node_free(struct rcu_head *rcu)
++{
++ struct koi_addr_map *addr_map_node =
++ container_of(rcu, struct koi_addr_map, rcu);
++ kfree(addr_map_node);
++}
++
++#ifndef CONFIG_IEE
++/*
++ * This function is used to switch to ko's pgtable.
++ */
++__koi_code noinline unsigned long koi_do_switch_to_ko_pgtbl(void)
++{
++ struct koi_mem_hash_node *ko;
++ // struct mm_struct *ko_mm;
++ unsigned long addr;
++ unsigned long ttbr1, asid;
++ unsigned long *ptr;
++ struct task_token *token_addr =
++ (struct task_token *)((unsigned long)current +
++ (unsigned long)koi_offset);
++ int bkt;
++ asm volatile(" mrs %0, elr_el1\n" : "=r"(addr));
++ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, __kern_my_cpu_offset());
++ rcu_read_lock();
++ hash_for_each_rcu (koi_mem_htbl, bkt, ko, node) {
++ if (ko->mod->init_layout.base != NULL) {
++ if (addr >= (unsigned long)ko->mod->init_layout.base &&
++ addr < (unsigned long)(ko->mod->init_layout.base +
++ ko->mod->init_layout.size)) {
++ if (token_addr->current_ttbr1 == ko->ko_ttbr1 ||
++ *ptr == ko->ko_ttbr1) {
++ // ko_mm = ko->ko_mm;
++ // koi_check_and_switch_context(ko_mm);
++ // asid = ASID(ko_mm);
++ // ttbr1 = ko->ko_ttbr1;
++ // ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
++ asm volatile("mrs %0, ttbr0_el1\n":"=r"(asid):);
++ asid &= TTBR_ASID_MASK;
++ ttbr1 = ko->ko_ttbr1 | asid;
++ rcu_read_unlock();
++ return ttbr1;
++ }
++ rcu_read_unlock();
++ return 0;
++ }
++ }
++ if (addr >= (unsigned long)ko->mod->core_layout.base &&
++ addr < (unsigned long)ko->mod->core_layout.base +
++ ko->mod->core_layout.size) {
++ if (token_addr->current_ttbr1 == ko->ko_ttbr1 ||
++ *ptr == ko->ko_ttbr1) {
++ // ko_mm = ko->ko_mm;
++ // koi_check_and_switch_context(ko_mm);
++ // asid = ASID(ko_mm);
++ // ttbr1 = ko->ko_ttbr1;
++ // ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
++ asm volatile("mrs %0, ttbr0_el1\n":"=r"(asid):);
++ asid &= TTBR_ASID_MASK;
++ ttbr1 = ko->ko_ttbr1 | asid;
++ rcu_read_unlock();
++ return ttbr1;
++ }
++ rcu_read_unlock();
++ return 0;
++ }
++ }
++ rcu_read_unlock();
++ return 0;
++}
++/**
++* koi_do_switch_to_kernel_pgtbl - switch to kernel pagetable
++*/
++__koi_code noinline int koi_do_switch_to_kernel_pgtbl(void)
++{
++ unsigned long curr_ttbr1, asid;
++ // if (!cpu_online(smp_processor_id()))
++ // return 0;
++ asm volatile(" mrs %0, ttbr1_el1\n" : "=r"(curr_ttbr1));
++ if ((curr_ttbr1 & KOI_SWAPPER_MASK) ==
++ (koi_swapper_ttbr1 & KOI_SWAPPER_MASK)) {
++ return 0;
++ }
++ if (((curr_ttbr1 & TTBR_ASID_MASK) >> 48) <= 1) {
++ return 0;
++ }
++ asm volatile("mrs %0, ttbr0_el1\n":"=r"(asid):);
++ asid &= ~USER_ASID_FLAG;
++ asid &= TTBR_ASID_MASK;
++ write_sysreg(koi_swapper_ttbr1 | asid, ttbr1_el1);
++ isb();
++ asm volatile(ALTERNATIVE("nop; nop; nop", "ic iallu; dsb nsh; isb",
++ ARM64_WORKAROUND_CAVIUM_27456));
++ return 1;
++}
++#else
++__koi_code noinline unsigned long koi_do_switch_to_ko_pgtbl(void)
++{
++ struct koi_mem_hash_node *ko;
++ struct mm_struct *ko_mm;
++ unsigned long addr, ttbr1, asid, pan_flag, current_ttbr1;
++ unsigned long *ptr;
++ int bkt;
++ asm volatile("mrs %0, pan\n"
++ "msr pan, 0x0\n"
++ : "=r"(pan_flag)
++ :);
++ current_ttbr1 = _iee_read_token_ttbr1(current);
++ asm volatile("msr pan, %0\n" : : "r"(pan_flag));
++ ptr = SHIFT_PERCPU_PTR(koi_irq_current_ttbr1, __kern_my_cpu_offset());
++ if (current_ttbr1 == 0 && *ptr == 0)
++ return 0;
++ asm volatile(" mrs %0, elr_el1\n" : "=r"(addr));
++ rcu_read_lock();
++ hash_for_each_rcu (koi_mem_htbl, bkt, ko, node) {
++ if (ko->mod->init_layout.base != NULL) {
++ if (addr >= (unsigned long)ko->mod->init_layout.base &&
++ addr < (unsigned long)(ko->mod->init_layout.base +
++ ko->mod->init_layout.size)) {
++ rcu_read_unlock();
++ if (current_ttbr1 == ko->ko_ttbr1 || *ptr == ko->ko_ttbr1) {
++ // ko_mm = ko->ko_mm;
++ // koi_check_and_switch_context(ko_mm);
++ // asid = ASID(ko_mm);
++ // ttbr1 = ko->ko_ttbr1;
++ // ttbr1 |= FIELD_PREP(TTBR_ASID_MASK,
++ // asid);
++ return ko->ko_ttbr1;
++ }
++ return 0;
++ }
++ }
++ if (addr >= (unsigned long)ko->mod->core_layout.base &&
++ addr < (unsigned long)ko->mod->core_layout.base +
++ ko->mod->core_layout.size) {
++ rcu_read_unlock();
++ if (current_ttbr1 == ko->ko_ttbr1 || *ptr == ko->ko_ttbr1) {
++ // ko_mm = ko->ko_mm;
++ // koi_check_and_switch_context(ko_mm);
++ // asid = ASID(ko_mm);
++ // ttbr1 = ko->ko_ttbr1;
++ // ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
++ return ko->ko_ttbr1;
++ }
++ return 0;
++ }
++ }
++ rcu_read_unlock();
++ return 0;
++}
++
++__koi_code noinline int koi_do_switch_to_kernel_pgtbl(void)
++{
++ unsigned long curr_ttbr1;
++ // if (!cpu_online(smp_processor_id()))
++ // return 0;
++ asm volatile(" mrs %0, ttbr1_el1\n" : "=r"(curr_ttbr1));
++ if ((curr_ttbr1 & KOI_SWAPPER_MASK) ==
++ (koi_swapper_ttbr1 & KOI_SWAPPER_MASK)) {
++ return 0;
++ }
++ if (((curr_ttbr1 & TTBR_ASID_MASK) >> 48) <= 1) {
++ return 0;
++ }
++ iee_rwx_gate_entry(IEE_SWITCH_TO_KERNEL);
++ return 1;
++}
++#endif
++/**
++* koi_save_ttbr - save ttbr of each driver module
++* @mod: driver module
++* @pgdp:pointer to driver module top page table,pgd
++*/
++static void koi_save_ttbr(struct module *mod, pgd_t *pgdp,
++ struct koi_mem_hash_node *node)
++{
++ phys_addr_t ttbr1 = phys_to_ttbr(virt_to_phys(pgdp));
++ if (system_supports_cnp())
++ ttbr1 |= TTBR_CNP_BIT;
++ node->ko_ttbr1 = ttbr1;
++}
++/**
++*kio_normal_page - to obtain the pointer of the corresponding struct page structure
++*from a given page table entry(pte)
++*/
++struct page *koi_normal_page(pte_t pte)
++{
++ unsigned long pfn = pte_pfn(pte);
++
++ if (IS_ENABLED(CONFIG_ARCH_HAS_PTE_SPECIAL)) {
++ if (likely(!pte_special(pte)))
++ goto check_pfn;
++ if (is_zero_pfn(pfn)) {
++ printk(KERN_ERR "zero pfn found! pte=0x%16lx\n", pte);
++ return NULL;
++ }
++ if (pte_devmap(pte)) {
++ printk(KERN_ERR "pte for dev found! pte=0x%16lx\n",
++ pte);
++ return NULL;
++ }
++ return NULL;
++ }
++
++check_pfn:
++ return pfn_to_page(pfn);
++}
++
++/**
++ * Copy one pte. Returns 0 if succeeded, or -EAGAIN if one preallocated page
++ * is required to copy this pte.
++*/
++static inline int koi_copy_present_pte(pte_t *dst_pte, pte_t *src_pte,
++ unsigned long addr,
++ struct page **prealloc)
++{
++ pte_t pte = *src_pte;
++ struct page *page;
++
++ page = koi_normal_page(pte);
++ if (!page) {
++ printk(KERN_ERR "pte_page unavailable. Impossible.....\n");
++ return -1;
++ }
++
++ set_pte(dst_pte, pte);
++ return 0;
++}
++/**
++* copy huge pmd from kernel space to driver space.
++*/
++static int koi_copy_huge_pmd(struct mm_struct *ko_mm, pmd_t *dst_pmd,
++ pmd_t *src_pmd, unsigned long addr)
++{
++ spinlock_t *src_ptl;
++ pmd_t pmd;
++ int ret = -ENOMEM;
++
++ src_ptl = pmd_lockptr(&init_mm, src_pmd);
++ spin_lock_bh(src_ptl);
++
++ ret = -EAGAIN;
++ pmd = *src_pmd;
++
++ set_pte((pte_t *)dst_pmd, pmd_pte(pmd));
++ ret = 0;
++ spin_unlock_bh(src_ptl);
++ return ret;
++}
++
++int __koi_pte_alloc(struct mm_struct *mm, pmd_t *pmd)
++{
++ spinlock_t *ptl;
++ pgtable_t new = pte_alloc_one(mm);
++ if (!new)
++ return -ENOMEM;
++
++ /*
++ * Ensure all pte setup (eg. pte page lock and page clearing) are
++ * visible before the pte is made visible to other CPUs by being
++ * put into page tables.
++ *
++ * The other side of the story is the pointer chasing in the page
++ * table walking code (when walking the page table without locking;
++ * ie. most of the time). Fortunately, these data accesses consist
++ * of a chain of data-dependent loads, meaning most CPUs (alpha
++ * being the notable exception) will already guarantee loads are
++ * seen in-order. See the alpha page table accessors for the
++ * smp_rmb() barriers in page table walking code.
++ */
++ smp_wmb(); /* Could be smp_wmb__xxx(before|after)_spin_lock */
++
++ ptl = pmd_lockptr(mm, pmd);
++ spin_lock_bh(ptl);
++ if (likely(pmd_none(*pmd))) { /* Has another populated it ? */
++ #ifdef CONFIG_PTP
++ pte_t *pte = (pte_t *)page_address(new);
++ unsigned long iee_addr = __phys_to_iee(__pa(pte));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)pte);
++ #endif
++ mm_inc_nr_ptes(mm);
++ pmd_populate(mm, pmd, new);
++ new = NULL;
++ }
++ spin_unlock_bh(ptl);
++ if (new)
++ pte_free(mm, new);
++ return 0;
++}
++
++#define koi_pte_alloc(mm, pmd) (unlikely(pmd_none(*(pmd))) && __koi_pte_alloc(mm, pmd))
++
++#define koi_pte_offset_map_lock(mm, pmd, address, ptlp) \
++({ \
++ spinlock_t *__ptl = pte_lockptr(mm, pmd); \
++ pte_t *__pte = pte_offset_map(pmd, address); \
++ *(ptlp) = __ptl; \
++ spin_lock_bh(__ptl); \
++ __pte; \
++})
++
++#define koi_pte_alloc_map_lock(mm, pmd, address, ptlp) \
++ (koi_pte_alloc(mm, pmd) ? \
++ NULL : koi_pte_offset_map_lock(mm, pmd, address, ptlp))
++
++/**
++*koi_copy_pte_range - copy pte from kernel space to driver space
++*/
++static int koi_copy_pte_range(struct mm_struct *ko_mm, pmd_t *dst_pmd,
++ pmd_t *src_pmd, unsigned long addr,
++ unsigned long end)
++{
++ pte_t *src_pte, *dst_pte;
++ spinlock_t *src_ptl, *dst_ptl;
++ int ret = 0;
++ struct page *prealloc = NULL;
++again:
++ dst_pte = koi_pte_alloc_map_lock(ko_mm, dst_pmd, addr, &dst_ptl);
++ if (!dst_pte) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ src_pte = pte_offset_map(src_pmd, addr);
++ src_ptl = pte_lockptr(&init_mm, src_pmd);
++ spin_lock_bh(src_ptl);
++ arch_enter_lazy_mmu_mode();
++
++ do {
++ if (pte_none(*src_pte))
++ continue;
++ if (unlikely(!pte_present(*src_pte))) {
++ continue;
++ }
++ /* koi_copy_present_pte() will clear `*prealloc` if consumed */
++ ret = koi_copy_present_pte(dst_pte, src_pte, addr, &prealloc);
++ if (unlikely(ret == -EAGAIN))
++ break;
++ if (unlikely(prealloc)) {
++ put_page(prealloc);
++ prealloc = NULL;
++ }
++ } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
++ arch_leave_lazy_mmu_mode();
++ spin_unlock_bh(src_ptl);
++ spin_unlock_bh(dst_ptl);
++
++ if (ret) {
++ WARN_ON_ONCE(ret != -EAGAIN);
++ ret = 0;
++ }
++ if (addr != end)
++ goto again;
++out:
++ if (unlikely(prealloc))
++ put_page(prealloc);
++ return ret;
++}
++
++int __koi_pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
++{
++ spinlock_t *ptl;
++ pmd_t *new = pmd_alloc_one(mm, address);
++ if (!new)
++ return -ENOMEM;
++
++ smp_wmb(); /* See comment in __pte_alloc */
++
++ ptl = pud_lockptr(mm, pud);
++ spin_lock_bh(ptl);
++ if (!pud_present(*pud)) {
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr = __phys_to_iee(__pa(new));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)new);
++ #endif
++ mm_inc_nr_pmds(mm);
++ pud_populate(mm, pud, new);
++ } else /* Another has populated it */
++ pmd_free(mm, new);
++ spin_unlock_bh(ptl);
++ return 0;
++}
++
++static inline pmd_t *koi_pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
++{
++ return (unlikely(pud_none(*pud)) && __koi_pmd_alloc(mm, pud, address))?
++ NULL: pmd_offset(pud, address);
++}
++
++/**
++*kio_copy_pmd_range - copy pmd from kernel to driver space
++*/
++static inline int koi_copy_pmd_range(struct mm_struct *ko_mm, pud_t *dst_pud,
++ pud_t *src_pud, unsigned long addr,
++ unsigned long end)
++{
++ pmd_t *src_pmd, *dst_pmd;
++ unsigned long next;
++ int err;
++
++ dst_pmd = koi_pmd_alloc(ko_mm, dst_pud, addr);
++ if (!dst_pmd) {
++ return -ENOMEM;
++ }
++ src_pmd = pmd_offset(src_pud, addr);
++ do {
++ next = pmd_addr_end(addr, end);
++ // CONFIG_TRANSPARENT_HUGEPAGE is enabled, so we must add copy_huge_pmd
++ if (is_swap_pmd(*src_pmd) || pmd_trans_huge(*src_pmd) ||
++ (pmd_devmap(*src_pmd))) {
++ err = koi_copy_huge_pmd(ko_mm, dst_pmd, src_pmd, addr);
++ if (err == -ENOMEM)
++ return -ENOMEM;
++ if (!err)
++ continue;
++ }
++ if (pmd_none_or_clear_bad(src_pmd)) {
++ continue;
++ }
++ if (koi_copy_pte_range(ko_mm, dst_pmd, src_pmd, addr, next))
++ return -ENOMEM;
++ } while (dst_pmd++, src_pmd++, addr = next, addr != end);
++ return 0;
++}
++
++int __koi_pud_alloc(struct mm_struct *mm, p4d_t *p4d, unsigned long address)
++{
++ pud_t *new = pud_alloc_one(mm, address);
++ if (!new)
++ return -ENOMEM;
++
++ smp_wmb(); /* See comment in __pte_alloc */
++
++ spin_lock_bh(&mm->page_table_lock);
++ if (!p4d_present(*p4d)) {
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr = __phys_to_iee(__pa(new));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)new);
++ #endif
++ mm_inc_nr_puds(mm);
++ p4d_populate(mm, p4d, new);
++ } else /* Another has populated it */
++ pud_free(mm, new);
++ spin_unlock_bh(&mm->page_table_lock);
++ return 0;
++}
++
++static inline pud_t *koi_pud_alloc(struct mm_struct *mm, p4d_t *p4d,
++ unsigned long address)
++{
++ return (unlikely(p4d_none(*p4d)) && __koi_pud_alloc(mm, p4d, address)) ?
++ NULL : pud_offset(p4d, address);
++}
++
++/**
++*koi_copy_pud_range - copy pud from kernel to driver
++*/
++static inline int koi_copy_pud_range(struct mm_struct *ko_mm, p4d_t *dst_p4d,
++ p4d_t *src_p4d, unsigned long addr,
++ unsigned long end)
++{
++ pud_t *src_pud, *dst_pud;
++ unsigned long next;
++ dst_pud = koi_pud_alloc(ko_mm, dst_p4d, addr);
++ if (!dst_pud)
++ return -ENOMEM;
++ src_pud = pud_offset(src_p4d, addr);
++ do {
++ next = pud_addr_end(addr, end);
++ if (pud_trans_huge(*src_pud) || pud_devmap(*src_pud)) {
++ continue;
++ /* fall through */
++ }
++ if (pud_none_or_clear_bad(src_pud))
++ continue;
++ if (koi_copy_pmd_range(ko_mm, dst_pud, src_pud, addr, next))
++ return -ENOMEM;
++ } while (dst_pud++, src_pud++, addr = next, addr != end);
++ return 0;
++}
++
++/**
++* koi_copy_p4d_range - map the kernel pagetable to the driver space level by level
++* @ko_mm: the mm_struct of driver module
++* @dst_pgd: destination pgd
++* @src_pgd: source pgd
++* @addr: the start of address
++* @end: the end of address
++*/
++static inline int koi_copy_p4d_range(struct mm_struct *ko_mm, pgd_t *dst_pgd,
++ pgd_t *src_pgd, unsigned long addr,
++ unsigned long end)
++{
++ p4d_t *src_p4d, *dst_p4d;
++ unsigned long next;
++ dst_p4d = p4d_alloc(ko_mm, dst_pgd, addr);
++ if (!dst_p4d)
++ return -ENOMEM;
++ src_p4d = p4d_offset(src_pgd, addr);
++ do {
++ next = p4d_addr_end(addr, end);
++ if (p4d_none_or_clear_bad(src_p4d))
++ continue;
++ if (koi_copy_pud_range(ko_mm, dst_p4d, src_p4d, addr, next)) {
++ return -ENOMEM;
++ }
++ } while (dst_p4d++, src_p4d++, addr = next, addr != end);
++ return 0;
++}
++
++/**
++*int koi_copy_pagetable - map the address range from "addr" to "end" to the driver pagetable
++*@ko_mm: the mm_struct of the driver module
++*@koi_pg_dir: koi_pg_dir, related to the driver module, the entry for driver pagetable
++*@addr: the starting address of mapping zone
++*@end: the end address of mapping zone
++*/
++int koi_copy_pagetable(struct mm_struct *ko_mm, pgd_t *koi_pg_dir,
++ unsigned long addr, unsigned long end)
++{
++ int ret = 0;
++ unsigned long next;
++
++ pgd_t *src_pgd, *dst_pgd;
++
++ src_pgd = pgd_offset_pgd(swapper_pg_dir, addr);
++ dst_pgd = pgd_offset_pgd(koi_pg_dir, addr);
++ do {
++ next = pgd_addr_end(addr, end);
++ if (pgd_none_or_clear_bad(src_pgd))
++ continue;
++ if (unlikely(koi_copy_p4d_range(ko_mm, dst_pgd, src_pgd, addr,
++ next))) {
++ ret = -ENOMEM;
++ break;
++ }
++ } while (dst_pgd++, src_pgd++, addr = next, addr != end);
++
++ return ret;
++}
++
++void koi_set_rdonly(unsigned long addr, pgd_t *pgdir)
++{
++ p4d_t *p4dp;
++ pud_t *pudp;
++ pmd_t *pmdp;
++ pte_t *ptep;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
++ if (pgd_none(*pgdp) || pgd_bad(*pgdp)) {
++ return;
++ }
++
++ p4dp = p4d_offset(pgdp, addr);
++ if (p4d_none(*p4dp) || p4d_bad(*p4dp)) {
++ return;
++ }
++
++ pudp = pud_offset(p4dp, addr);
++ if (pud_none(*pudp) || pud_bad(*pudp)) {
++ return;
++ }
++ pmdp = pmd_offset(pudp, addr);
++ if (pmd_none(*pmdp) || pmd_bad(*pmdp)) {
++ return;
++ }
++
++ ptep = pte_offset_kernel(pmdp, addr);
++ if (pte_none(*ptep)) {
++ printk(KERN_ERR "ptep 0x%llx not available\n", ptep);
++ return;
++ }
++ set_pte(ptep, __pte(pte_val(*ptep) | PTE_RDONLY));
++ printk(KERN_ERR "set_readonly successfully\n");
++ return;
++}
++
++/**
++* koi_create_pagetable - create pagetable for driver
++* @mod: driver module
++* 1.create a new koi_mem_hash_node new_node
++* 2.create page table return the pgd address, init the new_node->pgdp
++* 3.create and init the new_node->ko_mm
++* 4.map swapper_ttbr1 to the newly created pagetable
++* 5.map the interrupt vector table to the newly created pagetable
++* 6.map the init_layout of the module
++* 7.map the core_layout of the module
++* 8.map switch_to_kernel_pgtable into driver view
++* 9.map share memory
++*/
++void koi_create_pagetable(struct module *mod)
++{
++ int ret = 0, cpu;
++ unsigned long vbar, addr, ttbr1;
++ pgd_t *pgdp;
++ unsigned long *ptr;
++ struct koi_mem_list *new_mem_node;
++ struct koi_mem_hash_node *new_node =
++ kzalloc(sizeof(struct koi_mem_hash_node), GFP_KERNEL);
++ if (!new_node) {
++ printk(KERN_ERR "NULL new_node\n");
++ return;
++ };
++ if (koi_swapper_ttbr1 == 0) {
++ pgdp = lm_alias(swapper_pg_dir);
++ ttbr1 = phys_to_ttbr(virt_to_phys(pgdp));
++ if (system_supports_cnp() &&
++ !WARN_ON(pgdp != lm_alias(swapper_pg_dir)))
++ ttbr1 |= TTBR_CNP_BIT;
++#ifdef CONFIG_IEE
++ ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, 1);
++#endif
++ koi_swapper_ttbr1 = ttbr1;
++ // __WRITE_ONCE(koi_swapper_ttbr1, ttbr1);
++ // koi_set_rdonly(&koi_swapper_ttbr1, swapper_pg_dir);
++ }
++ new_node->pgdp = koi_pgd_alloc();
++ new_node->ko_mm =
++ kzalloc(sizeof(struct mm_struct) +
++ sizeof(unsigned long) * BITS_TO_LONGS(NR_CPUS),
++ GFP_KERNEL);
++ init_ko_mm(new_node->ko_mm, new_node->pgdp);
++ new_node->mod = mod;
++ koi_save_ttbr(mod, new_node->pgdp, new_node);
++ printk(KERN_ERR "copying koi_data, start=0x%16llx, end=0x%16llx\n",
++ (unsigned long)__koi_data_start, (unsigned long)__koi_data_end);
++ // copy koi_swapper_ttbr1, which records page dir base for kernel view
++ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
++ (unsigned long)__koi_data_start,
++ (unsigned long)__koi_data_end);
++ asm volatile("mrs %0, VBAR_EL1\n" : "=r"(vbar) :);
++
++ // copy interrupt vectors
++ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp, vbar & PAGE_MASK,
++ (vbar + PAGE_SIZE) & PAGE_MASK);
++
++ // copy module init_layout, which contains init data and text in driver
++ ret = koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
++ (unsigned long)mod->init_layout.base,
++ (unsigned long)mod->init_layout.base +
++ mod->init_layout.size);
++ if (ret != 0)
++ printk(KERN_ERR
++ "\033[33mError occur when copying init_layout, Eno:%d\033[0m\n",
++ ret);
++
++ // copy module core_layout, which contains non-init data and text in driver
++ ret = koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
++ (unsigned long)mod->core_layout.base,
++ (unsigned long)mod->core_layout.base +
++ mod->core_layout.size);
++ if (ret != 0)
++ printk(KERN_ERR
++ "\033[33mError occur when copying core_layout, Eno: %d\033[0m\n",
++ ret);
++
++ // mapping switch_to_kernel_pgtable into driver view, which is used to switch to kernel view when entering INT
++ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
++ (unsigned long)__koi_code_start,
++ (unsigned long)__koi_code_end);
++
++ for_each_possible_cpu (cpu) {
++ ptr = per_cpu(irq_stack_ptr, cpu);
++ printk(KERN_ERR
++ "\033[33mirq_stack_ptr on cpu %d addr=0x%16llx, end=0x%16llx\033[0m\n",
++ cpu, (unsigned long)ptr,
++ (unsigned long)ptr + IRQ_STACK_SIZE);
++ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
++ (unsigned long)ptr,
++ (unsigned long)ptr + IRQ_STACK_SIZE);
++ }
++
++ for_each_possible_cpu (cpu) {
++ ptr = per_cpu(koi_irq_current_ttbr1, cpu);
++ printk(KERN_ERR
++ "\033[33mirq_current_ptr on cpu %d addr=0x%16llx, end=0x%16llx\033[0m\n",
++ cpu, (unsigned long)ptr, (unsigned long)ptr + PAGE_SIZE);
++ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
++ (unsigned long)ptr,
++ (unsigned long)ptr + PAGE_SIZE);
++ }
++
++#ifdef CONFIG_IEE
++ // mapping iee_rwx_gate_entry and iee_si_base to ko's pagetable
++ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp,
++ (unsigned long)__iee_si_base_start,
++ (unsigned long)__iee_exec_entry_end);
++#endif
++
++ // alloc 16KB memory for new ko, and add it into hashtable
++ addr = (unsigned long)kmalloc(THREAD_SIZE, GFP_KERNEL);
++ if ((void *)addr == NULL) {
++ printk(KERN_ERR "alloc buffer error\n");
++ }
++ koi_copy_pagetable(new_node->ko_mm, new_node->pgdp, addr,
++ addr + THREAD_SIZE);
++
++ new_mem_node = kmalloc(sizeof(struct koi_mem_list), GFP_KERNEL);
++ if (new_mem_node == NULL) {
++ printk(KERN_ERR "alloc new_mem_node error\n");
++ }
++ new_mem_node->addr = addr;
++ new_mem_node->size = THREAD_SIZE;
++
++ new_node->mem_list_head =
++ (struct list_head)LIST_HEAD_INIT(new_node->mem_list_head);
++ hash_init(new_node->addr_htbl);
++ spin_lock_init(&new_node->addr_htbl_spin_lock);
++ spin_lock_init(&new_node->spin_lock);
++
++ spin_lock(&new_node->spin_lock);
++ list_add_rcu(&new_mem_node->list, &new_node->mem_list_head);
++ spin_unlock(&new_node->spin_lock);
++
++ spin_lock(&koi_mem_htbl_spin_lock);
++ hash_add_rcu(koi_mem_htbl, &new_node->node,
++ (unsigned long)new_node->mod);
++ spin_unlock(&koi_mem_htbl_spin_lock);
++}
++/**
++* koi_mem_alloc
++*@mod: driver module
++*@orig_addr: the starting address of the parameter in kernel
++*@size: the size of the parameter
++*/
++unsigned long koi_mem_alloc(struct module *mod, unsigned long orig_addr,
++ unsigned long size)
++{
++ struct koi_mem_hash_node *target = NULL;
++ struct koi_mem_list *mem_node;
++ struct koi_addr_map *new_addr_node;
++ unsigned long addr = 0, flags;
++ struct koi_mem_list *new_mem_node;
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk(KERN_ERR "mem node for module: %s not found\n",
++ mod->name);
++ return 0;
++ }
++ spin_lock_irqsave(&target->spin_lock, flags);
++ list_for_each_entry_rcu (mem_node, &target->mem_list_head, list) {
++ if (mem_node->size >= size) {
++ addr = mem_node->addr;
++ mem_node->size -= size;
++ if (mem_node->size == 0) {
++ list_del_rcu(&mem_node->list);
++ } else {
++ new_mem_node =
++ kmalloc(sizeof(struct koi_mem_list),
++ GFP_ATOMIC);
++ new_mem_node->addr = addr + size;
++ new_mem_node->size = mem_node->size;
++ list_replace_rcu(&mem_node->list,
++ &new_mem_node->list);
++ }
++ call_rcu(&mem_node->rcu, koi_mem_node_free);
++ }
++ }
++ spin_unlock_irqrestore(&target->spin_lock, flags);
++ if (!addr) {
++ addr = (unsigned long)kmalloc(THREAD_SIZE, GFP_KERNEL);
++ if ((void *)addr == NULL) {
++ return 0;
++ }
++ koi_copy_pagetable(target->ko_mm, target->pgdp, addr,
++ addr + THREAD_SIZE);
++ mem_node = kmalloc(sizeof(struct koi_mem_list), GFP_KERNEL);
++ if (!mem_node) {
++ printk(KERN_ERR "NULL mem_node\n");
++ }
++ if (size > THREAD_SIZE) {
++ return 0;
++ }
++ mem_node->addr = addr + size;
++ mem_node->size = THREAD_SIZE - size;
++ spin_lock_irqsave(&target->spin_lock, flags);
++ list_add_tail_rcu(&mem_node->list, &target->mem_list_head);
++ spin_unlock_irqrestore(&target->spin_lock, flags);
++ }
++
++ new_addr_node = kzalloc(sizeof(struct koi_addr_map), GFP_KERNEL);
++ new_addr_node->buffer_addr = addr;
++ new_addr_node->orig_addr = orig_addr;
++ spin_lock_irqsave(&target->addr_htbl_spin_lock, flags);
++ hash_add_rcu(target->addr_htbl, &new_addr_node->node,
++ new_addr_node->buffer_addr);
++ spin_unlock_irqrestore(&target->addr_htbl_spin_lock, flags);
++ return addr;
++}
++EXPORT_SYMBOL(koi_mem_alloc);
++// find the parameter pointer corresponding to the copy
++noinline void *koi_mem_lookup(struct module *mod, unsigned long addr)
++{
++ struct koi_mem_hash_node *target = NULL;
++ struct koi_addr_map *addr_map_node;
++ unsigned long orig_addr = addr;
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk(KERN_ERR "mem node for module: %s not found\n",
++ mod->name);
++ return NULL;
++ }
++
++ rcu_read_lock();
++ hash_for_each_possible_rcu (target->addr_htbl, addr_map_node, node,
++ orig_addr) {
++ if (addr_map_node->buffer_addr == addr) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (addr_map_node) {
++ return (void *)(addr_map_node->orig_addr);
++ } else {
++ return NULL;
++ }
++}
++EXPORT_SYMBOL(koi_mem_lookup);
++/**
++* kio_mem_free - recycle a copy of the copied parameters and synchronize the parameters
++* @mod: driver module
++* @addr: the starting addr of parameter
++* @size: the size of the parameter
++* @is_const: const pointers or not
++* @count: contry the number of parameters
++*/
++noinline void koi_mem_free(struct module *mod, unsigned long addr,
++ unsigned long size, bool is_const, int count, ...)
++{
++ struct koi_mem_hash_node *target = NULL;
++ struct koi_mem_list *mem_node;
++ struct list_head *pos = NULL;
++ struct koi_addr_map *addr_map_node;
++ unsigned long orig_size = size;
++ unsigned long orig_addr = addr;
++ va_list valist;
++ int i;
++ unsigned int offset;
++ unsigned long flags;
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk(KERN_ERR "mem node for module: %s not found\n",
++ mod->name);
++ return;
++ }
++
++ rcu_read_lock();
++ hash_for_each_possible_rcu (target->addr_htbl, addr_map_node, node,
++ orig_addr) {
++ if (addr_map_node->buffer_addr == orig_addr) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ va_start(valist, count);
++ for (i = 0; i < count; i++) {
++ offset = va_arg(valist, int);
++ *(unsigned long *)(addr_map_node->buffer_addr + offset) =
++ *(unsigned long *)(addr_map_node->orig_addr + offset);
++ }
++ va_end(valist);
++ memcpy((void *)addr_map_node->orig_addr,
++ (void *)addr_map_node->buffer_addr, orig_size);
++
++ spin_lock_irqsave(&target->addr_htbl_spin_lock, flags);
++ hlist_del_init_rcu(&addr_map_node->node);
++ call_rcu(&addr_map_node->rcu, koi_addr_map_node_free);
++ spin_unlock_irqrestore(&target->addr_htbl_spin_lock, flags);
++
++ spin_lock_irqsave(&target->spin_lock, flags);
++ list_for_each_entry_rcu (mem_node, &target->mem_list_head, list) {
++ if (mem_node->addr + mem_node->size == addr) {
++ pos = mem_node->list.prev;
++ addr = mem_node->addr;
++ size += mem_node->size;
++ list_del_rcu(&mem_node->list);
++ call_rcu(&mem_node->rcu, koi_mem_node_free);
++ } else if (addr + size == mem_node->addr) {
++ if (!pos)
++ pos = mem_node->list.prev;
++ size += mem_node->size;
++ list_del_rcu(&mem_node->list);
++ call_rcu(&mem_node->rcu, koi_mem_node_free);
++ } else if (addr + size < mem_node->addr) {
++ if (!pos)
++ pos = mem_node->list.prev;
++ break;
++ }
++ }
++ mem_node = kzalloc(sizeof(struct koi_mem_list), GFP_ATOMIC);
++ mem_node->addr = addr;
++ mem_node->size = size;
++ if (pos)
++ list_add_rcu(&mem_node->list, pos);
++ else
++ list_add_tail_rcu(&mem_node->list, &target->mem_list_head);
++ spin_unlock_irqrestore(&target->spin_lock, flags);
++}
++EXPORT_SYMBOL(koi_mem_free);
++/**
++* koi_mem_free_callback - used to recycle the copy of parameter.
++*@addr: the address of the parameter
++*@(*func)(void*): callback func, used to release the copy of the parameter pointer
++*/
++noinline void koi_mem_free_callback(struct module *mod, unsigned long addr,
++ unsigned long size, void (*func)(void *))
++{
++ struct koi_mem_hash_node *target = NULL;
++ struct koi_mem_list *mem_node;
++ struct list_head *pos = NULL;
++ struct koi_addr_map *addr_map_node;
++ unsigned long flags;
++ unsigned long orig_size = size;
++ unsigned long orig_addr = addr;
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk("mem node for module: %s not found\n", mod->name);
++ return;
++ }
++
++ rcu_read_lock();
++ hash_for_each_possible_rcu (target->addr_htbl, addr_map_node, node,
++ orig_addr) {
++ if (addr_map_node->buffer_addr == orig_addr) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (addr_map_node != NULL) {
++ memcpy((void *)addr_map_node->orig_addr,
++ (void *)addr_map_node->buffer_addr, orig_size);
++ func((void *)addr_map_node->orig_addr);
++ } else {
++ printk("Cannot find addr_map_node in addr_htbl, maybe addr is in kernel space!!\n");
++ func((void *)orig_addr);
++ }
++
++ spin_lock_irqsave(&target->addr_htbl_spin_lock, flags);
++ if (addr_map_node != NULL) {
++ hlist_del_init_rcu(&addr_map_node->node);
++ call_rcu(&addr_map_node->rcu, koi_addr_map_node_free);
++ }
++ spin_unlock_irqrestore(&target->addr_htbl_spin_lock, flags);
++ spin_lock_irqsave(&target->spin_lock, flags);
++ list_for_each_entry_rcu (mem_node, &target->mem_list_head, list) {
++ if (mem_node->addr + mem_node->size == addr) {
++ pos = mem_node->list.prev;
++ addr = mem_node->addr;
++ size += mem_node->size;
++ list_del_rcu(&mem_node->list);
++ call_rcu(&mem_node->rcu, koi_mem_node_free);
++ } else if (addr + size == mem_node->addr) {
++ if (!pos)
++ pos = mem_node->list.prev;
++ size += mem_node->size;
++ list_del_rcu(&mem_node->list);
++ call_rcu(&mem_node->rcu, koi_mem_node_free);
++ } else if (addr + size < mem_node->addr) {
++ if (!pos)
++ pos = mem_node->list.prev;
++ break;
++ }
++ }
++ mem_node = kzalloc(sizeof(struct koi_mem_list), GFP_ATOMIC);
++ mem_node->addr = addr;
++ mem_node->size = size;
++ if (pos)
++ list_add_rcu(&mem_node->list, pos);
++ else
++ list_add_tail_rcu(&mem_node->list, &target->mem_list_head);
++ spin_unlock_irqrestore(&target->spin_lock, flags);
++}
++EXPORT_SYMBOL(koi_mem_free_callback);
++
++void koi_map_mem(struct module *mod, unsigned long addr, unsigned long size)
++{
++ struct koi_mem_hash_node *target = NULL;
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod)
++ break;
++ }
++ rcu_read_unlock();
++
++ if (target == NULL) {
++ printk(KERN_ERR "mem node for module: %s not found\n",
++ mod->name);
++ return;
++ }
++ koi_copy_pagetable(target->ko_mm, target->pgdp, addr & PAGE_MASK,
++ (addr + size + PAGE_SIZE) & PAGE_MASK);
++}
++EXPORT_SYMBOL(koi_map_mem);
++/**
++* koi_mem_free_to_user - function 'copy_to_user' in driver space
++*/
++void koi_mem_free_to_user(struct module *mod, unsigned long addr,
++ unsigned long size)
++{
++ struct koi_mem_hash_node *target = NULL;
++ struct koi_mem_list *mem_node;
++ struct list_head *pos = NULL;
++ struct koi_addr_map *addr_map_node;
++ unsigned long flags;
++ unsigned long orig_size = size;
++ unsigned long orig_addr = addr;
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk(KERN_ERR "mem node for module: %s not found\n",
++ mod->name);
++ return;
++ }
++
++ rcu_read_lock();
++ hash_for_each_possible_rcu (target->addr_htbl, addr_map_node, node,
++ orig_addr) {
++ if (addr_map_node->buffer_addr == orig_addr) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (copy_to_user((void *)addr_map_node->orig_addr,
++ (void *)addr_map_node->buffer_addr, orig_size)) {
++ return;
++ }
++
++ spin_lock_irqsave(&target->addr_htbl_spin_lock, flags);
++ hlist_del_init_rcu(&addr_map_node->node);
++ call_rcu(&addr_map_node->rcu, koi_addr_map_node_free);
++ spin_unlock_irqrestore(&target->addr_htbl_spin_lock, flags);
++ spin_lock_irqsave(&target->spin_lock, flags);
++ list_for_each_entry_rcu (mem_node, &target->mem_list_head, list) {
++ if (mem_node->addr + mem_node->size == addr) {
++ pos = mem_node->list.prev;
++ addr = mem_node->addr;
++ size += mem_node->size;
++ list_del_rcu(&mem_node->list);
++ call_rcu(&mem_node->rcu, koi_mem_node_free);
++ } else if (addr + size == mem_node->addr) {
++ if (!pos)
++ pos = mem_node->list.prev;
++ size += mem_node->size;
++ list_del_rcu(&mem_node->list);
++ call_rcu(&mem_node->rcu, koi_mem_node_free);
++ } else if (addr + size < mem_node->addr) {
++ if (!pos)
++ pos = mem_node->list.prev;
++ break;
++ }
++ }
++ mem_node = kzalloc(sizeof(struct koi_mem_list), GFP_ATOMIC);
++ mem_node->addr = addr;
++ mem_node->size = size;
++ if (pos)
++ list_add_rcu(&mem_node->list, pos);
++ else
++ list_add_tail_rcu(&mem_node->list, &target->mem_list_head);
++ spin_unlock_irqrestore(&target->spin_lock, flags);
++}
++EXPORT_SYMBOL(koi_mem_free_to_user);
++// map the driver stack to kernel
++void koi_map_kostack(struct module *mod)
++{
++ struct koi_mem_hash_node *target = NULL;
++ void *koi_stack;
++ unsigned long cur_sp;
++ asm volatile("mov %0, sp\n" : "=r"(cur_sp) :);
++ if (on_irq_stack(cur_sp, NULL)) {
++ return;
++ }
++#ifndef CONFIG_IEE
++ unsigned long res, alloc_token;
++ struct task_token *token_addr =
++ (struct task_token *)((unsigned long)current +
++ (unsigned long)koi_offset);
++ if (token_addr->koi_stack_base != NULL)
++ return;
++#else
++ koi_stack = iee_rw_gate(IEE_READ_KOI_STACK, current);
++ if (koi_stack != NULL)
++ return;
++#endif
++ koi_stack =
++ (void *)__get_free_pages(THREADINFO_GFP & ~__GFP_ACCOUNT, 3);
++ free_pages(koi_stack + 4 * PAGE_SIZE, 2);
++ printk(KERN_ERR "alloc dstack start=0x%16llx, end=0x%16llx\n",
++ koi_stack, koi_stack + THREAD_SIZE);
++#ifndef CONFIG_IEE
++ token_addr->koi_stack =
++ (struct pt_regs *)(THREAD_SIZE + (unsigned long)koi_stack) - 1;
++ token_addr->koi_stack_base = koi_stack;
++#else
++ iee_rw_gate(
++ IEE_WRITE_KOI_STACK, current,
++ (unsigned long)((struct pt_regs *)(THREAD_SIZE +
++ (unsigned long)koi_stack) -
++ 1));
++ iee_rw_gate(IEE_WRITE_KOI_STACK_BASE, current,
++ (unsigned long)koi_stack);
++#endif
++ rcu_read_lock();
++ hash_for_each_possible_rcu (koi_mem_htbl, target, node,
++ (unsigned long)mod) {
++ if (target->mod == mod) {
++ break;
++ }
++ }
++ rcu_read_unlock();
++ if (target == NULL) {
++ printk(KERN_ERR "mem node for module: %s not found\n",
++ mod->name);
++ return;
++ }
++ koi_copy_pagetable(target->ko_mm, target->pgdp,
++ (unsigned long)koi_stack,
++ (unsigned long)koi_stack + THREAD_SIZE);
++ printk(KERN_ERR "create ko stack: 0x%16llx\n",
++ (unsigned long)koi_stack);
++}
++EXPORT_SYMBOL(koi_map_kostack);
+\ No newline at end of file
+diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
+index cea96ee75d22..cbddc8e464e4 100644
+--- a/arch/arm64/kernel/mte.c
++++ b/arch/arm64/kernel/mte.c
+@@ -79,8 +79,13 @@ int memcmp_pages(struct page *page1, struct page *page2)
+ static inline void __mte_enable_kernel(const char *mode, unsigned long tcf)
+ {
+ /* Enable MTE Sync Mode for EL1. */
++#ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_TCF_MASK,
++ SYS_FIELD_PREP(SCTLR_EL1, TCF, tcf));
++#else
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF_MASK,
+ SYS_FIELD_PREP(SCTLR_EL1, TCF, tcf));
++#endif
+ isb();
+
+ pr_info_once("MTE: enabled in %s mode at EL1\n", mode);
+diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
+index 068e5bb2661b..c98bc1a24fc7 100644
+--- a/arch/arm64/kernel/process.c
++++ b/arch/arm64/kernel/process.c
+@@ -467,11 +467,24 @@ static void ssbs_thread_switch(struct task_struct *next)
+ * This is *only* for exception entry from EL0, and is not valid until we
+ * __switch_to() a user task.
+ */
++#ifdef CONFIG_IEE
++// Put __entry_task in a isolated page to protect it.
++__attribute__((aligned(PAGE_SIZE))) DEFINE_PER_CPU(struct task_struct *[PAGE_SIZE/sizeof(struct task_struct *)], __entry_task);
++extern void iee_write_entry_task(struct task_struct *tsk);
++#else
+ DEFINE_PER_CPU(struct task_struct *, __entry_task);
++#endif
+
+ static void entry_task_switch(struct task_struct *next)
+ {
++ #ifdef CONFIG_IEE
++ if(next == &init_task)
++ iee_write_entry_task((struct task_struct *)__va(__pa_symbol(next)));
++ else
++ iee_write_entry_task(next);
++ #else
+ __this_cpu_write(__entry_task, next);
++ #endif
+ }
+
+ /*
+@@ -506,11 +519,15 @@ static void erratum_1418040_new_exec(void)
+ */
+ void update_sctlr_el1(u64 sctlr)
+ {
+- /*
++ /*
+ * EnIA must not be cleared while in the kernel as this is necessary for
+ * in-kernel PAC. It will be cleared on kernel exit if needed.
+ */
++ #ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_USER_MASK & ~SCTLR_ELx_ENIA, sctlr);
++ #else
+ sysreg_clear_set(sctlr_el1, SCTLR_USER_MASK & ~SCTLR_ELx_ENIA, sctlr);
++ #endif
+
+ /* ISB required for the kernel uaccess routines when setting TCF0. */
+ isb();
+diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
+index 58a97861bfc5..c7839247327d 100644
+--- a/arch/arm64/kernel/proton-pack.c
++++ b/arch/arm64/kernel/proton-pack.c
+@@ -551,7 +551,11 @@ static enum mitigation_state spectre_v4_enable_hw_mitigation(void)
+ return state;
+
+ if (spectre_v4_mitigations_off()) {
++#ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, 0, SCTLR_ELx_DSSBS);
++#else
+ sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_DSSBS);
++#endif
+ set_pstate_ssbs(1);
+ return SPECTRE_VULNERABLE;
+ }
+@@ -975,7 +979,11 @@ static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot)
+ if (arm64_kernel_unmapped_at_el0())
+ return;
+
++#ifdef CONFIG_IEE
++ iee_rwx_gate_entry(IEE_WRITE_vbar_el1, v);
++#else
+ write_sysreg(v, vbar_el1);
++#endif
+ isb();
+ }
+
+diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
+index 95cb22c083c8..df73a583a733 100644
+--- a/arch/arm64/kernel/setup.c
++++ b/arch/arm64/kernel/setup.c
+@@ -33,6 +33,11 @@
+ #include <linux/scs.h>
+ #include <linux/mm.h>
+
++#ifdef CONFIG_IEE
++#include <linux/iee-func.h>
++#include <asm/iee-si.h>
++#endif
++
+ #include <asm/acpi.h>
+ #include <asm/fixmap.h>
+ #include <asm/cpu.h>
+@@ -335,10 +340,30 @@ u64 cpu_logical_map(unsigned int cpu)
+ return __cpu_logical_map[cpu];
+ }
+
++#ifdef CONFIG_IEE
++/* used for secure modification of vbar*/
++extern char __bp_harden_el1_vectors[];
++/* prepare iee rwx gate for senario of ttbr1=init_pg_dir */
++static void __init iee_si_init_early(void)
++{
++ /* prepare data used for iee rwx gate. */
++ iee_base_idmap_pg_dir = phys_to_ttbr(__pa_symbol(idmap_pg_dir));
++ iee_base_reserved_pg_dir = phys_to_ttbr(__pa_symbol(reserved_pg_dir))
++ | FIELD_PREP(TTBR_ASID_MASK, 1);
++ iee_base__bp_harden_el1_vectors = (unsigned long)__bp_harden_el1_vectors;
++ iee_si_tcr = 0;
++}
++#endif
++
+ void __init __no_sanitize_address setup_arch(char **cmdline_p)
+ {
+ setup_initial_init_mm(_stext, _etext, _edata, _end);
+
++ #ifdef CONFIG_IEE
++ init_new_context(&init_task, &init_mm);
++ atomic64_set(&init_mm.context.id, (1UL << get_cpu_asid_bits()) | INIT_ASID);
++ #endif
++
+ *cmdline_p = boot_command_line;
+
+ kaslr_init();
+@@ -371,6 +396,14 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
+ */
+ local_daif_restore(DAIF_PROCCTX_NOIRQ);
+
++#ifdef CONFIG_IEE
++ /*
++ * Map iee si codes to init_pg_dir to run the following
++ * cpu_uninstall_idmap() which writes ttbr0.
++ */
++ iee_si_init_early();
++#endif
++
+ /*
+ * TTBR0 is only used for the identity mapping at this stage. Make it
+ * point to zero page to avoid speculatively fetching new entries.
+diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
+index b7b7afb4a8c7..168a9390d6e9 100644
+--- a/arch/arm64/kernel/traps.c
++++ b/arch/arm64/kernel/traps.c
+@@ -902,6 +902,32 @@ const char *esr_get_class_string(unsigned long esr)
+ return esr_class_str[ESR_ELx_EC(esr)];
+ }
+
++#ifdef CONFIG_IEE
++extern void arm64_enter_nmi(struct pt_regs *regs);
++static const char *handler[]= {
++ "SP_EL0",
++ "ELR_EL1",
++ "TCR_EL1",
++ "TTBR0 ASID"
++ "IEE_SI"
++};
++
++asmlinkage void notrace iee_bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
++{
++ arm64_enter_nmi(regs);
++
++ console_verbose();
++
++ pr_crit("IEE : Bad mode in %s check detected on CPU%d, code 0x%08x -- %s\n",
++ handler[reason], smp_processor_id(), esr,
++ esr_get_class_string(esr));
++
++ __show_regs(regs);
++ local_daif_mask();
++ panic("bad mode");
++}
++#endif
++
+ /*
+ * bad_el0_sync handles unexpected, but potentially recoverable synchronous
+ * exceptions taken from EL0.
+diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
+index 3cd7e76cc562..287eaba7a15b 100644
+--- a/arch/arm64/kernel/vmlinux.lds.S
++++ b/arch/arm64/kernel/vmlinux.lds.S
+@@ -134,6 +134,52 @@ jiffies = jiffies_64;
+ #define UNWIND_DATA_SECTIONS
+ #endif
+
++#ifdef CONFIG_IEE
++#define IEE_TEXT \
++ . = ALIGN(PAGE_SIZE); \
++ __iee_code_start = .; \
++ *(.iee.text.header) \
++ *(.iee.text) \
++ . = ALIGN(PAGE_SIZE); \
++ __iee_code_end = .;
++#else
++#define IEE_TEXT
++#endif
++
++#ifdef CONFIG_IEE
++#define IEE_SI_TEXT \
++ . = ALIGN(PAGE_SIZE); \
++ __iee_si_data_start = .; \
++ *(.iee.si_data) \
++ . = ALIGN(PAGE_SIZE); \
++ __iee_exec_entry_start = .; \
++ __iee_si_no_irq = . + (16); \
++ *(.iee.exec_entry) \
++ . = ALIGN(PAGE_SIZE); \
++ __iee_si_start = .; \
++ *(.iee.si_text) \
++ . = ALIGN(PAGE_SIZE); \
++ . += PAGE_SIZE - (24); \
++ __iee_si_end = . + (24); \
++ __iee_exec_exit = .; \
++ *(.iee.exec_exit) \
++ . = ALIGN(PAGE_SIZE);
++
++#else
++#define IEE_SI_TEXT
++#endif
++
++#ifdef CONFIG_KOI
++#define KOI_TEXT \
++ . = ALIGN(PAGE_SIZE); \
++ __koi_code_start = .; \
++ *(.koi.text) \
++ . = ALIGN(PAGE_SIZE); \
++ __koi_code_end = .;
++#else
++#define KOI_TEXT
++#endif
++
+ /*
+ * The size of the PE/COFF section that covers the kernel image, which
+ * runs from _stext to _edata, must be a round multiple of the PE/COFF
+@@ -176,10 +222,13 @@ SECTIONS
+ SOFTIRQENTRY_TEXT
+ ENTRY_TEXT
+ TEXT_TEXT
++ IEE_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ HYPERVISOR_TEXT
++ IEE_SI_TEXT
++ KOI_TEXT
+ *(.gnu.warning)
+ }
+
+@@ -318,6 +367,18 @@ SECTIONS
+ . += INIT_DIR_SIZE;
+ init_pg_end = .;
+
++ #ifdef CONFIG_IEE
++ . = ALIGN(PAGE_SIZE*8);
++ init_iee_stack_begin = .;
++ . += PAGE_SIZE*4;
++ init_iee_stack_end = .;
++
++ . = ALIGN(PAGE_SIZE);
++ init_iee_si_stack_begin = .;
++ . += PAGE_SIZE*4;
++ init_iee_si_stack_end = .;
++ #endif
++
+ . = ALIGN(SEGMENT_ALIGN);
+ __pecoff_data_size = ABSOLUTE(. - __initdata_begin);
+ _end = .;
+diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
+index 188197590fc9..97e1f86046cf 100644
+--- a/arch/arm64/mm/context.c
++++ b/arch/arm64/mm/context.c
+@@ -17,6 +17,10 @@
+ #include <asm/smp.h>
+ #include <asm/tlbflush.h>
+
++#ifdef CONFIG_IEE
++#include <asm/iee-si.h>
++#endif
++
+ static u32 asid_bits;
+ static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
+
+@@ -39,7 +43,11 @@ static unsigned long *pinned_asid_map;
+ #define asid2ctxid(asid, genid) ((asid) | (genid))
+
+ /* Get the ASIDBits supported by the current CPU */
++#ifdef CONFIG_IEE
++u32 get_cpu_asid_bits(void)
++#else
+ static u32 get_cpu_asid_bits(void)
++#endif
+ {
+ u32 asid;
+ int fld = cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR0_EL1),
+@@ -212,6 +220,38 @@ static u64 new_context(struct mm_struct *mm)
+ return asid2ctxid(asid, generation);
+ }
+
++#ifdef CONFIG_KOI
++/*
++ * This function is used to check and allocate ASID for ko's pgd
++ * The mm MUST point to the isolated kos' mm_struct, other behaviours are undefined.
++ */
++void koi_check_and_switch_context(struct mm_struct *mm) {
++ u64 asid = atomic64_read(&mm->context.id);
++ u64 old_active_asid;
++ unsigned long flags;
++ unsigned int cpu;
++
++ old_active_asid = atomic64_read(this_cpu_ptr(&active_asids));
++ if (old_active_asid && asid_gen_match(asid) && atomic64_cmpxchg_relaxed(this_cpu_ptr(&active_asids), old_active_asid, asid)) {
++ return;
++ }
++
++ raw_spin_lock_irqsave(&cpu_asid_lock, flags);
++ asid = atomic64_read(&mm->context.id);
++ if (!asid_gen_match(asid)) {
++ asid = new_context(mm);
++ atomic64_set(&mm->context.id, asid);
++ }
++
++ cpu = smp_processor_id();
++ if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending))
++ local_flush_tlb_all();
++
++ atomic64_set(this_cpu_ptr(&active_asids), asid);
++ raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
++}
++#endif
++
+ void check_and_switch_context(struct mm_struct *mm)
+ {
+ unsigned long flags;
+@@ -348,7 +388,9 @@ asmlinkage void post_ttbr_update_workaround(void)
+
+ void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm)
+ {
++ #ifndef CONFIG_IEE
+ unsigned long ttbr1 = read_sysreg(ttbr1_el1);
++ #endif
+ unsigned long asid = ASID(mm);
+ unsigned long ttbr0 = phys_to_ttbr(pgd_phys);
+
+@@ -360,14 +402,28 @@ void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm)
+ if (IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN))
+ ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid);
+
+- /* Set ASID in TTBR1 since TCR.A1 is set */
++ #ifdef CONFIG_IEE
++ ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid+1);
++ iee_rwx_gate_entry(IEE_CONTEXT_SWITCH, ttbr0);
++ // TODO : if defined CONFIG_IEE and defined CONFIG_KOI
++ #else
++ /* Set ASID in TTBR0 since TCR.A1 is set 0*/
++
++ #ifdef CONFIG_KOI
++ ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid+1);
++ ttbr1 &= ~TTBR_ASID_MASK;
++ ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
++ #else
+ ttbr1 &= ~TTBR_ASID_MASK;
+ ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
+-
++
++ #endif
+ cpu_set_reserved_ttbr0_nosync();
+ write_sysreg(ttbr1, ttbr1_el1);
+ write_sysreg(ttbr0, ttbr0_el1);
+ isb();
++ #endif
++
+ post_ttbr_update_workaround();
+ }
+
+@@ -375,11 +431,21 @@ static int asids_update_limit(void)
+ {
+ unsigned long num_available_asids = NUM_USER_ASIDS;
+
+- if (arm64_kernel_unmapped_at_el0()) {
+- num_available_asids /= 2;
+- if (pinned_asid_map)
+- set_kpti_asid_bits(pinned_asid_map);
+- }
++ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++ num_available_asids /= 2;
++ if (pinned_asid_map) {
++ unsigned int len = BITS_TO_LONGS(NUM_USER_ASIDS) * sizeof(unsigned long);
++ memset(pinned_asid_map, 0xaa, len);
++ __set_bit(INIT_ASID, pinned_asid_map);
++ }
++ #else
++ if (arm64_kernel_unmapped_at_el0()) {
++ num_available_asids /= 2;
++ if (pinned_asid_map)
++ set_kpti_asid_bits(pinned_asid_map);
++ }
++ #endif
++
+ /*
+ * Expect allocation after rollover to fail if we don't have at least
+ * one more ASID than CPUs. ASID #0 is reserved for init_mm.
+@@ -400,6 +466,10 @@ arch_initcall(asids_update_limit);
+
+ static int asids_init(void)
+ {
++ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++ unsigned int len;
++ #endif
++
+ asid_bits = get_cpu_asid_bits();
+ atomic64_set(&asid_generation, ASID_FIRST_VERSION);
+ asid_map = bitmap_zalloc(NUM_USER_ASIDS, GFP_KERNEL);
+@@ -410,6 +480,11 @@ static int asids_init(void)
+ pinned_asid_map = bitmap_zalloc(NUM_USER_ASIDS, GFP_KERNEL);
+ nr_pinned_asids = 0;
+
++ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++ len = BITS_TO_LONGS(NUM_USER_ASIDS) * sizeof(unsigned long);
++ memset(asid_map, 0xaa, len);
++ __set_bit(INIT_ASID, asid_map);
++ #else
+ /*
+ * We cannot call set_reserved_asid_bits() here because CPU
+ * caps are not finalized yet, so it is safer to assume KPTI
+@@ -417,6 +492,8 @@ static int asids_init(void)
+ */
+ if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0))
+ set_kpti_asid_bits(asid_map);
++ #endif
++
+ return 0;
+ }
+ early_initcall(asids_init);
+diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
+index 4ea07caba71c..de1d57c2b30f 100644
+--- a/arch/arm64/mm/fault.c
++++ b/arch/arm64/mm/fault.c
+@@ -261,7 +261,11 @@ int __ptep_set_access_flags(struct vm_area_struct *vma,
+ pteval ^= PTE_RDONLY;
+ pteval |= pte_val(entry);
+ pteval ^= PTE_RDONLY;
++ #ifdef CONFIG_PTP
++ pteval = iee_set_cmpxchg_relaxed(ptep, old_pteval, pteval);
++ #else
+ pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval, pteval);
++ #endif
+ } while (pteval != old_pteval);
+
+ /* Invalidate a stale read-only entry */
+@@ -376,8 +380,13 @@ static void do_tag_recovery(unsigned long addr, unsigned long esr,
+ * It will be done lazily on the other CPUs when they will hit a
+ * tag fault.
+ */
++ #ifdef CONFIG_IEE
++ sysreg_clear_set_iee_si(sctlr_el1, SCTLR_EL1_TCF_MASK,
++ SYS_FIELD_PREP_ENUM(SCTLR_EL1, TCF, NONE));
++ #else
+ sysreg_clear_set(sctlr_el1, SCTLR_EL1_TCF_MASK,
+ SYS_FIELD_PREP_ENUM(SCTLR_EL1, TCF, NONE));
++ #endif
+ isb();
+ }
+
+diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
+index bfc02568805a..580ecb596d2d 100644
+--- a/arch/arm64/mm/fixmap.c
++++ b/arch/arm64/mm/fixmap.c
+@@ -32,6 +32,22 @@ static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __page_aligned_bss;
+ static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
+ static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
+
++#ifdef CONFIG_IEE
++void *bm_pte_addr = (void *)bm_pte;
++void *bm_pmd_addr = (void *)bm_pmd;
++void *bm_pud_addr = (void *)bm_pud;
++#endif
++
++#ifdef CONFIG_PTP
++extern void __iee_p4d_populate_pre_init(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot);
++extern void __iee_pud_populate_pre_init(pud_t *pudp, phys_addr_t pmdp, pudval_t prot);
++extern void __iee_pmd_populate_pre_init(pmd_t *pmdp, phys_addr_t ptep,
++ pmdval_t prot);
++
++extern void iee_set_p4d_pre_init(p4d_t *p4dp, p4d_t p4d);
++#define set_pgd_init(pgdptr, pgdval) iee_set_p4d_pre_init((p4d_t *)(pgdptr), (p4d_t) { pgdval })
++#endif
++
+ static inline pte_t *fixmap_pte(unsigned long addr)
+ {
+ return &bm_pte[BM_PTE_TABLE_IDX(addr)][pte_index(addr)];
+@@ -44,7 +60,11 @@ static void __init early_fixmap_init_pte(pmd_t *pmdp, unsigned long addr)
+
+ if (pmd_none(pmd)) {
+ ptep = bm_pte[BM_PTE_TABLE_IDX(addr)];
++ #ifdef CONFIG_PTP
++ __iee_pmd_populate_pre_init(pmdp, __pa_symbol(ptep), PMD_TYPE_TABLE);
++ #else
+ __pmd_populate(pmdp, __pa_symbol(ptep), PMD_TYPE_TABLE);
++ #endif
+ }
+ }
+
+@@ -55,8 +75,13 @@ static void __init early_fixmap_init_pmd(pud_t *pudp, unsigned long addr,
+ pud_t pud = READ_ONCE(*pudp);
+ pmd_t *pmdp;
+
+- if (pud_none(pud))
++ if (pud_none(pud)) {
++ #ifdef CONFIG_PTP
++ __iee_pud_populate_pre_init(pudp, __pa_symbol(bm_pmd), PUD_TYPE_TABLE);
++ #else
+ __pud_populate(pudp, __pa_symbol(bm_pmd), PUD_TYPE_TABLE);
++ #endif
++ }
+
+ pmdp = pmd_offset_kimg(pudp, addr);
+ do {
+@@ -82,8 +107,13 @@ static void __init early_fixmap_init_pud(p4d_t *p4dp, unsigned long addr,
+ BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
+ }
+
+- if (p4d_none(p4d))
++ if (p4d_none(p4d)) {
++ #ifdef CONFIG_PTP
++ __iee_p4d_populate_pre_init(p4dp, __pa_symbol(bm_pud), P4D_TYPE_TABLE);
++ #else
+ __p4d_populate(p4dp, __pa_symbol(bm_pud), P4D_TYPE_TABLE);
++ #endif
++ }
+
+ pudp = pud_offset_kimg(p4dp, addr);
+ early_fixmap_init_pmd(pudp, addr, end);
+@@ -106,6 +136,27 @@ void __init early_fixmap_init(void)
+ early_fixmap_init_pud(p4dp, addr, end);
+ }
+
++#ifdef CONFIG_PTP
++extern void iee_set_pte_pre_init(pte_t *ptep, pte_t pte);
++void __iee_set_fixmap_pre_init(enum fixed_addresses idx,
++ phys_addr_t phys, pgprot_t flags)
++{
++ unsigned long addr = __fix_to_virt(idx);
++ pte_t *ptep;
++
++ BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
++
++ ptep = fixmap_pte(addr);
++
++ if (pgprot_val(flags)) {
++ iee_set_pte_pre_init(ptep, pfn_pte(phys >> PAGE_SHIFT, flags));
++ } else {
++ iee_set_pte_pre_init(ptep, __pte(0));
++ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
++ }
++}
++#endif
++
+ /*
+ * Unusually, this is also called in IRQ context (ghes_iounmap_irq) so if we
+ * ever need to use IPIs for TLB broadcasting, then we're in trouble here.
+@@ -121,9 +172,17 @@ void __set_fixmap(enum fixed_addresses idx,
+ ptep = fixmap_pte(addr);
+
+ if (pgprot_val(flags)) {
++ #ifdef CONFIG_PTP
++ iee_set_bm_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags));
++ #else
+ __set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags));
++ #endif
+ } else {
++ #ifdef CONFIG_PTP
++ iee_set_bm_pte(ptep, __pte(0));
++ #else
+ __pte_clear(&init_mm, addr, ptep);
++ #endif
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
+ }
+ }
+@@ -179,8 +238,13 @@ void __init fixmap_copy(pgd_t *pgdir)
+ * live in the carveout for the swapper_pg_dir. We can simply
+ * re-use the existing dir for the fixmap.
+ */
++ #ifdef CONFIG_PTP
++ set_pgd_init(pgd_offset_pgd(pgdir, FIXADDR_TOT_START),
++ READ_ONCE(*pgd_offset_k(FIXADDR_TOT_START)));
++ #else
+ set_pgd(pgd_offset_pgd(pgdir, FIXADDR_TOT_START),
+ READ_ONCE(*pgd_offset_k(FIXADDR_TOT_START)));
++ #endif
+ } else if (CONFIG_PGTABLE_LEVELS > 3) {
+ pgd_t *bm_pgdp;
+ p4d_t *bm_p4dp;
+@@ -194,9 +258,15 @@ void __init fixmap_copy(pgd_t *pgdir)
+ BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
+ bm_pgdp = pgd_offset_pgd(pgdir, FIXADDR_TOT_START);
+ bm_p4dp = p4d_offset(bm_pgdp, FIXADDR_TOT_START);
++ #ifdef CONFIG_PTP
++ bm_pudp = pud_set_fixmap_offset_init(bm_p4dp, FIXADDR_TOT_START);
++ __iee_pud_populate_pre_init(bm_pudp, __pa(lm_alias(bm_pmd)), PMD_TYPE_TABLE);
++ pud_clear_fixmap_init();
++ #else
+ bm_pudp = pud_set_fixmap_offset(bm_p4dp, FIXADDR_TOT_START);
+ pud_populate(&init_mm, bm_pudp, lm_alias(bm_pmd));
+ pud_clear_fixmap();
++ #endif
+ } else {
+ BUG();
+ }
+diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
+index 8c8d7653ba84..4190f5c10d68 100644
+--- a/arch/arm64/mm/init.c
++++ b/arch/arm64/mm/init.c
+@@ -55,8 +55,19 @@
+ * that cannot be mistaken for a real physical address.
+ */
+ s64 memstart_addr __ro_after_init = -1;
++#if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++s64 memstart_addr_init __ro_after_init = -1;
++#endif
++#ifdef CONFIG_KOI
++s64 koi_offset __ro_after_init = -1;
++EXPORT_SYMBOL(koi_offset);
++#endif
++#ifdef CONFIG_IEE
++s64 iee_offset __ro_after_init = -1;
++#endif
+ EXPORT_SYMBOL(memstart_addr);
+
++
+ /*
+ * If the corresponding config options are enabled, we create both ZONE_DMA
+ * and ZONE_DMA32. By default ZONE_DMA covers the 32-bit addressable memory
+@@ -421,7 +432,11 @@ early_param("memmap", parse_memmap_opt);
+
+ void __init arm64_memblock_init(void)
+ {
++ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++ s64 linear_region_size = BIT(vabits_actual - 2);
++ #else
+ s64 linear_region_size = PAGE_END - _PAGE_OFFSET(vabits_actual);
++ #endif
+
+ /*
+ * Corner case: 52-bit VA capable systems running KVM in nVHE mode may
+@@ -438,13 +453,24 @@ void __init arm64_memblock_init(void)
+ }
+
+ /* Remove memory above our supported physical address size */
++ #ifdef CONFIG_IEE
++ // If config iee, phys size can not be above 0x400000000000
++ if(__pa_symbol(_end) > BIT_ULL(vabits_actual - 2))
++ panic("Image on too high phys mem.\n");
++ else
++ memblock_remove(BIT_ULL(vabits_actual - 2), ULLONG_MAX);
++ #else
+ memblock_remove(1ULL << PHYS_MASK_SHIFT, ULLONG_MAX);
++ #endif
+
+ /*
+ * Select a suitable value for the base of physical memory.
+ */
+ memstart_addr = round_down(memblock_start_of_DRAM(),
+ ARM64_MEMSTART_ALIGN);
++ #if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++ memstart_addr_init = memstart_addr;
++ #endif
+
+ if ((memblock_end_of_DRAM() - memstart_addr) > linear_region_size)
+ pr_warn("Memory doesn't fit in the linear mapping, VA_BITS too small\n");
+@@ -531,6 +557,14 @@ void __init arm64_memblock_init(void)
+ ((range * memstart_offset_seed) >> 16);
+ }
+ }
++
++ #ifdef CONFIG_KOI
++ koi_offset = memstart_addr - memstart_addr_init + KOI_OFFSET;
++ #endif
++ #ifdef CONFIG_IEE
++ iee_offset = memstart_addr - memstart_addr_init + ((unsigned long)BIT(vabits_actual - 2));
++ #endif
++ //printk(KERN_ERR "koi_offset: 0x%16llx\n", koi_offset);
+
+ /*
+ * Register the kernel text, kernel data, initrd, and initial
+diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
+index 4142a75a414e..094f3798441d 100644
+--- a/arch/arm64/mm/mmu.c
++++ b/arch/arm64/mm/mmu.c
+@@ -6,6 +6,7 @@
+ * Copyright (C) 2012 ARM Ltd.
+ */
+
++#include "asm/pgtable.h"
+ #include <linux/cache.h>
+ #include <linux/export.h>
+ #include <linux/kernel.h>
+@@ -40,6 +41,11 @@
+ #include <asm/tlbflush.h>
+ #include <asm/pgalloc.h>
+ #include <asm/kfence.h>
++#ifdef CONFIG_IEE
++#include <linux/iee-func.h>
++#include <asm/iee.h>
++#include <asm/iee-si.h>
++#endif
+
+ #define NO_BLOCK_MAPPINGS BIT(0)
+ #define NO_CONT_MAPPINGS BIT(1)
+@@ -76,8 +82,282 @@ EXPORT_SYMBOL(empty_zero_page);
+ static DEFINE_SPINLOCK(swapper_pgdir_lock);
+ static DEFINE_MUTEX(fixmap_lock);
+
++#ifdef CONFIG_IEE
++extern struct cred init_cred;
++
++extern unsigned long init_iee_stack_begin[];
++extern unsigned long init_iee_stack_end[];
++extern unsigned long __iee_si_data_start[];
++extern unsigned long __iee_exec_entry_start[];
++extern unsigned long __iee_si_start[];
++extern unsigned long __iee_si_end[];
++
++extern void *bm_pte_addr;
++extern void *bm_pmd_addr;
++extern void *bm_pud_addr;
++
++#ifdef CONFIG_PTP
++
++/* Funcs to set pgtable before iee initialized. */
++static void iee_set_swapper_pgd_pre_init(pgd_t *pgdp, pgd_t pgd)
++{
++ pgd_t *fixmap_pgdp;
++
++ spin_lock(&swapper_pgdir_lock);
++ fixmap_pgdp = pgd_set_fixmap_init(__pa_symbol(pgdp));
++ WRITE_ONCE(*fixmap_pgdp, pgd);
++ /*
++ * We need dsb(ishst) here to ensure the page-table-walker sees
++ * our new entry before set_p?d() returns. The fixmap's
++ * flush_tlb_kernel_range() via clear_fixmap() does this for us.
++ */
++ pgd_clear_fixmap_init();
++ spin_unlock(&swapper_pgdir_lock);
++}
++
++void iee_set_p4d_pre_init(p4d_t *p4dp, p4d_t p4d)
++{
++ if (in_swapper_pgdir(p4dp)) {
++ iee_set_swapper_pgd_pre_init((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
++ return;
++ }
++
++ WRITE_ONCE(*p4dp, p4d);
++ dsb(ishst);
++ isb();
++}
++
++static inline void iee_set_pud_pre_init(pud_t *pudp, pud_t pud)
++{
++#ifdef __PAGETABLE_PUD_FOLDED
++ if (in_swapper_pgdir(pudp)) {
++ iee_set_swapper_pgd_pre_init((pgd_t *)pudp, __pgd(pud_val(pud)));
++ return;
++ }
++#endif /* __PAGETABLE_PUD_FOLDED */
++#ifdef CONFIG_KOI
++ pudval_t val = pud_val(pud);
++ if (pud_valid(pud) && !(val & PUD_TABLE_BIT)) {
++ // There is no PUD_SEC_NG, so we use PMD_SECT_NG instead.
++ pud = __pud(val | PMD_SECT_NG);
++ }
++#endif
++ WRITE_ONCE(*pudp, pud);
++
++ if (pud_valid(pud)) {
++ dsb(ishst);
++ isb();
++ }
++}
++
++static inline void iee_set_pmd_pre_init(pmd_t *pmdp, pmd_t pmd)
++{
++#ifdef __PAGETABLE_PMD_FOLDED
++ if (in_swapper_pgdir(pmdp)) {
++ iee_set_swapper_pgd_pre_init((pgd_t *)pmdp, __pgd(pmd_val(pmd)));
++ return;
++ }
++#endif /* __PAGETABLE_PMD_FOLDED */
++#ifdef CONFIG_KOI
++ pmdval_t val = pmd_val(pmd);
++ if (pmd_valid(pmd) && !(val & PMD_TABLE_BIT)) {
++ pmd = __pmd(val | PMD_SECT_NG);
++ }
++#endif
++ WRITE_ONCE(*pmdp, pmd);
++
++ if (pmd_valid(pmd)) {
++ dsb(ishst);
++ isb();
++ }
++}
++
++
++void __iee_p4d_populate_pre_init(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
++{
++ iee_set_p4d_pre_init(p4dp, __p4d(__phys_to_p4d_val(pudp) | prot));
++}
++
++void __iee_pud_populate_pre_init(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
++{
++ iee_set_pud_pre_init(pudp, __pud(__phys_to_pud_val(pmdp) | prot));
++}
++
++void __iee_pmd_populate_pre_init(pmd_t *pmdp, phys_addr_t ptep,
++ pmdval_t prot)
++{
++ iee_set_pmd_pre_init(pmdp, __pmd(__phys_to_pmd_val(ptep) | prot));
++}
++
++/* Funcs to set fixmap before iee initialized. */
++bool pgattr_change_is_safe(u64 old, u64 new);
++static int iee_pud_set_huge_fixmap(pud_t *pudp, phys_addr_t phys, pgprot_t prot)
++{
++ pud_t new_pud = pfn_pud(__phys_to_pfn(phys), mk_pud_sect_prot(prot));
++
++ /* Only allow permission changes for now */
++ if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pudp)),
++ pud_val(new_pud)))
++ return 0;
++
++ VM_BUG_ON(phys & ~PUD_MASK);
++ iee_set_fixmap_pud_pre_init(pudp, new_pud);
++ return 1;
++}
++
++static int iee_pmd_set_huge_fixmap(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot)
++{
++ pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), mk_pmd_sect_prot(prot));
++
++ /* Only allow permission changes for now */
++ if (!pgattr_change_is_safe(READ_ONCE(pmd_val(*pmdp)),
++ pmd_val(new_pmd)))
++ return 0;
++
++ VM_BUG_ON(phys & ~PMD_MASK);
++ iee_set_fixmap_pmd_pre_init(pmdp, new_pmd);
++ return 1;
++}
++
++static inline void __iee_pmd_populate_fixmap(pmd_t *pmdp, phys_addr_t ptep,
++ pmdval_t prot)
++{
++ iee_set_fixmap_pmd_pre_init(pmdp, __pmd(__phys_to_pmd_val(ptep) | prot));
++}
++
++static inline void __iee_pud_populate_fixmap(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
++{
++ iee_set_fixmap_pud_pre_init(pudp, __pud(__phys_to_pud_val(pmdp) | prot));
++}
++#endif /* END CONFIG_PTP*/
++
++void iee_set_pte_pre_init(pte_t *ptep, pte_t pte)
++{
++#ifdef CONFIG_KOI
++ if (!pte_none(pte)) {
++ pte = __pte(pte_val(pte) | PTE_NG);
++ }
++#endif
++ WRITE_ONCE(*ptep, pte);
++
++ /*
++ * Only if the new pte is valid and kernel, otherwise TLB maintenance
++ * or update_mmu_cache() have the necessary barriers.
++ */
++ if (pte_valid_not_user(pte)) {
++ dsb(ishst);
++ isb();
++ }
++}
++
++static void __init iee_set_token_page_valid_pre_init(void *token, void *new)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token);
++
++ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token);
++
++ pud_t *pudp = pud_offset(p4dp, (unsigned long)token);
++
++ pmd_t *pmdp = pmd_offset(pudp, (unsigned long)token);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, (unsigned long)token);
++ pte_t pte = READ_ONCE(*ptep);
++ pte = __pte(((pte_val(pte) | 0x1) & ~PTE_ADDR_MASK) | __phys_to_pte_val(__pa(new)));
++ iee_set_pte_pre_init(ptep, pte);
++ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token+PAGE_SIZE));
++ isb();
++}
++#endif /* END CONFIG_IEE*/
++
++#if defined(CONFIG_KOI) && !defined(CONFIG_IEE)
++int koi_add_page_mapping(unsigned long dst, unsigned long src)
++{
++ pgd_t *src_pgdp, *dst_pgdp;
++ p4d_t *src_p4dp, *dst_p4dp;
++ pud_t *src_pudp, *dst_pudp;
++ pmd_t *src_pmdp, *dst_pmdp;
++ pte_t *src_ptep, *dst_ptep;
++
++ src_pgdp = pgd_offset_pgd(swapper_pg_dir, src);
++ dst_pgdp = pgd_offset_pgd(swapper_pg_dir, dst);
++
++ src_p4dp = p4d_offset(src_pgdp, src);
++ dst_p4dp = p4d_alloc(&init_mm, dst_pgdp, dst);
++ if (!dst_p4dp) {
++ return -ENOMEM;
++ }
++ src_pudp = pud_offset(src_p4dp, src);
++ dst_pudp = pud_alloc(&init_mm, dst_p4dp, dst);
++ if (!dst_pudp) {
++ return -ENOMEM;
++ }
++ if (pud_val(*src_pudp) & PMD_TABLE_BIT) {
++ src_pmdp = pmd_offset(src_pudp, src);
++ dst_pmdp = pmd_alloc(&init_mm, dst_pudp, dst);
++ if (!dst_pmdp) {
++ return -ENOMEM;
++ }
++ if (pmd_val(*src_pmdp) & PMD_TABLE_BIT) {
++ src_ptep = pte_offset_kernel(src_pmdp, src);
++ dst_ptep = pte_alloc_map(&init_mm, dst_pmdp, dst);
++ set_pte(dst_ptep, *src_ptep);
++ } else {
++ set_pte((pte_t *)dst_pmdp, pmd_pte(*src_pmdp));
++ }
++ } else {
++ set_pte((pte_t *)dst_pudp, pud_pte(*src_pudp));
++ }
++
++
++ flush_tlb_kernel_range(dst, dst+PAGE_SIZE);
++ isb();
++ return 0;
++}
++
++void koi_remove_page_mapping(unsigned long addr) {
++ pgd_t *src_pgdp;
++ p4d_t *src_p4dp;
++ pud_t *src_pudp;
++ pmd_t *src_pmdp;
++ pte_t *src_ptep;
++
++ src_pgdp = pgd_offset_pgd(swapper_pg_dir, addr);
++ if (pgd_none(*src_pgdp) || pgd_bad(*src_pgdp))
++ return;
++ src_p4dp = p4d_offset(src_pgdp, addr);
++ if (p4d_none(*src_p4dp) || p4d_bad(*src_p4dp))
++ return;
++ src_pudp = pud_offset(src_p4dp, addr);
++ if (pud_none(*src_pudp))
++ return;
++ if (pud_val(*src_pudp) & PMD_TABLE_BIT) {
++ src_pmdp = pmd_offset(src_pudp, addr);
++ if (pmd_none(*src_pmdp))
++ return;
++ if (pmd_val(*src_pmdp) & PMD_TABLE_BIT) {
++ src_ptep = pte_offset_kernel(src_pmdp, addr);
++ if(!pte_none(*src_ptep))
++ pte_clear(&init_mm, addr, src_ptep);
++ } else {
++ pmd_clear(src_pmdp);
++ }
++ } else {
++ pud_clear(src_pudp);
++ }
++
++ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
++ isb();
++}
++#endif
++
+ void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd)
+ {
++ #ifdef CONFIG_PTP
++ spin_lock(&swapper_pgdir_lock);
++ iee_rw_gate(IEE_OP_SET_SWAPPER_PGD, pgdp, pgd);
++ spin_unlock(&swapper_pgdir_lock);
++ #else
+ pgd_t *fixmap_pgdp;
+
+ spin_lock(&swapper_pgdir_lock);
+@@ -90,6 +370,7 @@ void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd)
+ */
+ pgd_clear_fixmap();
+ spin_unlock(&swapper_pgdir_lock);
++ #endif
+ }
+
+ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+@@ -118,7 +399,11 @@ static phys_addr_t __init early_pgtable_alloc(int shift)
+ * slot will be free, so we can (ab)use the FIX_PTE slot to initialise
+ * any level of table.
+ */
++ #ifdef CONFIG_PTP
++ ptr = pte_set_fixmap_init(phys);
++ #else
+ ptr = pte_set_fixmap(phys);
++ #endif
+
+ memset(ptr, 0, PAGE_SIZE);
+
+@@ -126,11 +411,16 @@ static phys_addr_t __init early_pgtable_alloc(int shift)
+ * Implicit barriers also ensure the zeroed page is visible to the page
+ * table walker
+ */
++ #ifdef CONFIG_PTP
++ pte_clear_fixmap_init();
++ #else
+ pte_clear_fixmap();
++ #endif
+
+ return phys;
+ }
+
++
+ bool pgattr_change_is_safe(u64 old, u64 new)
+ {
+ /*
+@@ -178,7 +468,11 @@ static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,
+ do {
+ pte_t old_pte = __ptep_get(ptep);
+
++ #ifdef CONFIG_PTP
++ iee_set_fixmap_pte_pre_init(ptep, pfn_pte(__phys_to_pfn(phys), prot));
++ #else
+ __set_pte(ptep, pfn_pte(__phys_to_pfn(phys), prot));
++ #endif
+
+ /*
+ * After the PTE entry has been populated once, we
+@@ -211,7 +505,11 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
+ pmdval |= PMD_TABLE_PXN;
+ BUG_ON(!pgtable_alloc);
+ pte_phys = pgtable_alloc(PAGE_SHIFT);
++ #ifdef CONFIG_PTP
++ __iee_pmd_populate_fixmap(pmdp, pte_phys, pmdval);
++ #else
+ __pmd_populate(pmdp, pte_phys, pmdval);
++ #endif
+ pmd = READ_ONCE(*pmdp);
+ }
+ BUG_ON(pmd_bad(pmd));
+@@ -248,7 +546,11 @@ static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
+ /* try section mapping first */
+ if (((addr | next | phys) & ~PMD_MASK) == 0 &&
+ (flags & NO_BLOCK_MAPPINGS) == 0) {
++ #ifdef CONFIG_PTP
++ iee_pmd_set_huge_fixmap(pmdp, phys, prot);
++ #else
+ pmd_set_huge(pmdp, phys, prot);
++ #endif
+
+ /*
+ * After the PMD entry has been populated once, we
+@@ -289,7 +591,11 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
+ pudval |= PUD_TABLE_PXN;
+ BUG_ON(!pgtable_alloc);
+ pmd_phys = pgtable_alloc(PMD_SHIFT);
+- __pud_populate(pudp, pmd_phys, pudval);
++ #ifdef CONFIG_PTP
++ __iee_pud_populate_fixmap(pudp, pmd_phys, PUD_TYPE_TABLE);
++ #else
++ __pud_populate(pudp, pmd_phys, PUD_TYPE_TABLE);
++ #endif
+ pud = READ_ONCE(*pudp);
+ }
+ BUG_ON(pud_bad(pud));
+@@ -345,7 +651,11 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,
+ if (pud_sect_supported() &&
+ ((addr | next | phys) & ~PUD_MASK) == 0 &&
+ (flags & NO_BLOCK_MAPPINGS) == 0) {
++ #ifdef CONFIG_PTP
++ iee_pud_set_huge_fixmap(pudp, phys, prot);
++ #else
+ pud_set_huge(pudp, phys, prot);
++ #endif
+
+ /*
+ * After the PUD entry has been populated once, we
+@@ -374,6 +684,10 @@ static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys,
+ {
+ unsigned long addr, end, next;
+ pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);
++ #ifdef CONFIG_IEE
++ p4d_t *p4dp;
++ p4d_t p4d;
++ #endif
+
+ /*
+ * If the virtual and physical address don't have the same offset
+@@ -390,10 +704,14 @@ static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys,
+ next = pgd_addr_end(addr, end);
+ alloc_init_pud(pgdp, addr, next, phys, prot, pgtable_alloc,
+ flags);
++ #ifdef CONFIG_IEE
++ p4dp = p4d_offset(pgdp, addr);
++ p4d = READ_ONCE(*p4dp);
++ __p4d_populate(p4dp, __p4d_to_phys(p4d), (PGD_APT | PUD_TYPE_TABLE));
++ #endif
+ phys += next - addr;
+ } while (pgdp++, addr = next, addr != end);
+ }
+-
+ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
+ unsigned long virt, phys_addr_t size,
+ pgprot_t prot,
+@@ -413,162 +731,844 @@ void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt,
+ phys_addr_t (*pgtable_alloc)(int), int flags);
+ #endif
+
+-static phys_addr_t __pgd_pgtable_alloc(int shift)
++#ifdef CONFIG_PTP
++static int __init iee_pud_set_huge_pre_init(pud_t *pudp, phys_addr_t phys, pgprot_t prot)
+ {
+- void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL);
+- BUG_ON(!ptr);
++ pud_t new_pud = pfn_pud(__phys_to_pfn(phys), mk_pud_sect_prot(prot));
+
+- /* Ensure the zeroed page is visible to the page table walker */
+- dsb(ishst);
+- return __pa(ptr);
++ /* Only allow permission changes for now */
++ if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pudp)),
++ pud_val(new_pud)))
++ return 0;
++
++ VM_BUG_ON(phys & ~PUD_MASK);
++ iee_set_pud_pre_init(pudp, new_pud);
++ return 1;
+ }
+
+-static phys_addr_t pgd_pgtable_alloc(int shift)
++static int __init iee_pmd_set_huge_pre_init(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot)
+ {
+- phys_addr_t pa = __pgd_pgtable_alloc(shift);
+- struct ptdesc *ptdesc = page_ptdesc(phys_to_page(pa));
+-
+- /*
+- * Call proper page table ctor in case later we need to
+- * call core mm functions like apply_to_page_range() on
+- * this pre-allocated page table.
+- *
+- * We don't select ARCH_ENABLE_SPLIT_PMD_PTLOCK if pmd is
+- * folded, and if so pagetable_pte_ctor() becomes nop.
+- */
+- if (shift == PAGE_SHIFT)
+- BUG_ON(!pagetable_pte_ctor(ptdesc));
+- else if (shift == PMD_SHIFT)
+- BUG_ON(!pagetable_pmd_ctor(ptdesc));
++ pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), mk_pmd_sect_prot(prot));
+
+- return pa;
+-}
++ /* Only allow permission changes for now */
++ if (!pgattr_change_is_safe(READ_ONCE(pmd_val(*pmdp)),
++ pmd_val(new_pmd)))
++ return 0;
+
+-/*
+- * This function can only be used to modify existing table entries,
+- * without allocating new levels of table. Note that this permits the
+- * creation of new section or page entries.
+- */
+-void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
+- phys_addr_t size, pgprot_t prot)
+-{
+- if (virt < PAGE_OFFSET) {
+- pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
+- &phys, virt);
+- return;
+- }
+- __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
+- NO_CONT_MAPPINGS);
++ VM_BUG_ON(phys & ~PMD_MASK);
++ iee_set_pmd_pre_init(pmdp, new_pmd);
++ return 1;
+ }
+
+-void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
+- unsigned long virt, phys_addr_t size,
+- pgprot_t prot, bool page_mappings_only)
++static __init void iee_init_pte_pre_init(pmd_t *pmdp, unsigned long addr, unsigned long end,
++ phys_addr_t phys, pgprot_t prot)
+ {
+- int flags = 0;
+-
+- BUG_ON(mm == &init_mm);
++ pte_t *ptep;
+
+- if (page_mappings_only)
+- flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
++ ptep = pte_set_fixmap_offset_init(pmdp, addr);
++ do {
++ pte_t old_pte = READ_ONCE(*ptep);
+
+- __create_pgd_mapping(mm->pgd, phys, virt, size, prot,
+- pgd_pgtable_alloc, flags);
+-}
++ iee_set_pte_pre_init(ptep, pfn_pte(__phys_to_pfn(phys), prot));
+
+-static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
+- phys_addr_t size, pgprot_t prot)
+-{
+- if (virt < PAGE_OFFSET) {
+- pr_warn("BUG: not updating mapping for %pa at 0x%016lx - outside kernel range\n",
+- &phys, virt);
+- return;
+- }
++ /*
++ * After the PTE entry has been populated once, we
++ * only allow updates to the permission attributes.
++ */
++ BUG_ON(!pgattr_change_is_safe(pte_val(old_pte),
++ READ_ONCE(pte_val(*ptep))));
+
+- __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
+- NO_CONT_MAPPINGS);
++ phys += PAGE_SIZE;
++ } while (ptep++, addr += PAGE_SIZE, addr != end);
+
+- /* flush the TLBs after updating live kernel mappings */
+- flush_tlb_kernel_range(virt, virt + size);
++ pte_clear_fixmap_init();
+ }
+
+-static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start,
+- phys_addr_t end, pgprot_t prot, int flags)
++static __init void iee_alloc_init_cont_pte_pre_init(pmd_t *pmdp, unsigned long addr,
++ unsigned long end, phys_addr_t phys,
++ pgprot_t prot,
++ phys_addr_t (*pgtable_alloc)(int),
++ int flags)
+ {
+- __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start,
+- prot, early_pgtable_alloc, flags);
+-}
++ unsigned long next;
++ pmd_t pmd = READ_ONCE(*pmdp);
+
+-void __init mark_linear_text_alias_ro(void)
+-{
+- /*
+- * Remove the write permissions from the linear alias of .text/.rodata
+- */
+- update_mapping_prot(__pa_symbol(_stext), (unsigned long)lm_alias(_stext),
+- (unsigned long)__init_begin - (unsigned long)_stext,
+- PAGE_KERNEL_RO);
+-}
++ BUG_ON(pmd_sect(pmd));
++ if (pmd_none(pmd)) {
++ pmdval_t pmdval = PMD_TYPE_TABLE | PMD_TABLE_UXN;
++ phys_addr_t pte_phys;
+
+-#ifdef CONFIG_KFENCE
++ if (flags & NO_EXEC_MAPPINGS)
++ pmdval |= PMD_TABLE_PXN;
++ BUG_ON(!pgtable_alloc);
++ pte_phys = pgtable_alloc(PAGE_SHIFT);
++ __iee_pmd_populate_pre_init(pmdp, pte_phys, pmdval);
++ pmd = READ_ONCE(*pmdp);
++ }
++ BUG_ON(pmd_bad(pmd));
+
+-bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL;
++ do {
++ pgprot_t __prot = prot;
+
+-/* early_param() will be parsed before map_mem() below. */
+-static int __init parse_kfence_early_init(char *arg)
+-{
+- int val;
++ next = pte_cont_addr_end(addr, end);
+
+- if (get_option(&arg, &val))
+- kfence_early_init = !!val;
++ /* use a contiguous mapping if the range is suitably aligned */
++ if ((((addr | next | phys) & ~CONT_PTE_MASK) == 0) &&
++ (flags & NO_CONT_MAPPINGS) == 0)
++ __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
+
+-#if IS_ENABLED(CONFIG_KFENCE_MUST_EARLY_INIT)
+- kfence_must_early_init = (val == -1) ? true : false;
+-#endif
++ iee_init_pte_pre_init(pmdp, addr, next, phys, __prot);
+
+- return 0;
++ phys += next - addr;
++ } while (addr = next, addr != end);
+ }
+-early_param("kfence.sample_interval", parse_kfence_early_init);
+
+-static phys_addr_t __init arm64_kfence_alloc_pool(void)
++static __init void iee_init_pmd_pre_init(pud_t *pudp, unsigned long addr, unsigned long end,
++ phys_addr_t phys, pgprot_t prot,
++ phys_addr_t (*pgtable_alloc)(int), int flags)
+ {
+- phys_addr_t kfence_pool;
++ unsigned long next;
++ pmd_t *pmdp;
+
+- if (!kfence_early_init)
+- return 0;
++ pmdp = pmd_set_fixmap_offset_init(pudp, addr);
++ do {
++ pmd_t old_pmd = READ_ONCE(*pmdp);
+
+- kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE);
+- if (!kfence_pool) {
+- pr_err("failed to allocate kfence pool\n");
+- kfence_early_init = false;
+- return 0;
+- }
++ next = pmd_addr_end(addr, end);
+
+- /* Temporarily mark as NOMAP. */
+- memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE);
++ /* try section mapping first */
++ if (((addr | next | phys) & ~PMD_MASK) == 0 &&
++ (flags & NO_BLOCK_MAPPINGS) == 0) {
++ iee_pmd_set_huge_pre_init(pmdp, phys, prot);
++
++ /*
++ * After the PMD entry has been populated once, we
++ * only allow updates to the permission attributes.
++ */
++ BUG_ON(!pgattr_change_is_safe(pmd_val(old_pmd),
++ READ_ONCE(pmd_val(*pmdp))));
++ } else {
++ iee_alloc_init_cont_pte_pre_init(pmdp, addr, next, phys, prot,
++ pgtable_alloc, flags);
++
++ BUG_ON(pmd_val(old_pmd) != 0 &&
++ pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp)));
++ }
++ phys += next - addr;
++ } while (pmdp++, addr = next, addr != end);
++
++ pmd_clear_fixmap_init();
++}
++
++static __init void iee_alloc_init_cont_pmd_pre_init(pud_t *pudp, unsigned long addr,
++ unsigned long end, phys_addr_t phys,
++ pgprot_t prot,
++ phys_addr_t (*pgtable_alloc)(int), int flags)
++{
++ unsigned long next;
++ pud_t pud = READ_ONCE(*pudp);
++
++ /*
++ * Check for initial section mappings in the pgd/pud.
++ */
++ BUG_ON(pud_sect(pud));
++ if (pud_none(pud)) {
++ pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_UXN;
++ phys_addr_t pmd_phys;
++
++ if (flags & NO_EXEC_MAPPINGS)
++ pudval |= PUD_TABLE_PXN;
++ BUG_ON(!pgtable_alloc);
++ pmd_phys = pgtable_alloc(PMD_SHIFT);
++ __iee_pud_populate_pre_init(pudp, pmd_phys, pudval);
++ pud = READ_ONCE(*pudp);
++ }
++ BUG_ON(pud_bad(pud));
++
++ do {
++ pgprot_t __prot = prot;
++
++ next = pmd_cont_addr_end(addr, end);
++
++ /* use a contiguous mapping if the range is suitably aligned */
++ if ((((addr | next | phys) & ~CONT_PMD_MASK) == 0) &&
++ (flags & NO_CONT_MAPPINGS) == 0)
++ __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
++
++ iee_init_pmd_pre_init(pudp, addr, next, phys, __prot, pgtable_alloc, flags);
++
++ phys += next - addr;
++ } while (addr = next, addr != end);
++}
++
++static __init void iee_alloc_init_pud_pre_init(pgd_t *pgdp, unsigned long addr, unsigned long end,
++ phys_addr_t phys, pgprot_t prot,
++ phys_addr_t (*pgtable_alloc)(int),
++ int flags)
++{
++ unsigned long next;
++ pud_t *pudp;
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++ p4d_t p4d = READ_ONCE(*p4dp);
++
++ if (p4d_none(p4d)) {
++ p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_UXN;
++ phys_addr_t pud_phys;
++
++ if (flags & NO_EXEC_MAPPINGS)
++ p4dval |= P4D_TABLE_PXN;
++ BUG_ON(!pgtable_alloc);
++ pud_phys = pgtable_alloc(PUD_SHIFT);
++ __iee_p4d_populate_pre_init(p4dp, pud_phys, p4dval);
++ p4d = READ_ONCE(*p4dp);
++ }
++ BUG_ON(p4d_bad(p4d));
++
++ pudp = pud_set_fixmap_offset_init(p4dp, addr);
++ do {
++ pud_t old_pud = READ_ONCE(*pudp);
++
++ next = pud_addr_end(addr, end);
++
++ /*
++ * For 4K granule only, attempt to put down a 1GB block
++ */
++ if (pud_sect_supported() &&
++ ((addr | next | phys) & ~PUD_MASK) == 0 &&
++ (flags & NO_BLOCK_MAPPINGS) == 0) {
++ iee_pud_set_huge_pre_init(pudp, phys, prot);
++
++ /*
++ * After the PUD entry has been populated once, we
++ * only allow updates to the permission attributes.
++ */
++ BUG_ON(!pgattr_change_is_safe(pud_val(old_pud),
++ READ_ONCE(pud_val(*pudp))));
++ } else {
++ iee_alloc_init_cont_pmd_pre_init(pudp, addr, next, phys, prot,
++ pgtable_alloc, flags);
++
++ BUG_ON(pud_val(old_pud) != 0 &&
++ pud_val(old_pud) != READ_ONCE(pud_val(*pudp)));
++ }
++ phys += next - addr;
++ } while (pudp++, addr = next, addr != end);
++
++ pud_clear_fixmap_init();
++}
++
++static __init void __iee_create_pgd_mapping_locked_pre_init(pgd_t *pgdir, phys_addr_t phys,
++ unsigned long virt, phys_addr_t size,
++ pgprot_t prot,
++ phys_addr_t (*pgtable_alloc)(int),
++ int flags)
++{
++ unsigned long addr, end, next;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);
++ p4d_t *p4dp;
++ p4d_t p4d;
++
++ /*
++ * If the virtual and physical address don't have the same offset
++ * within a page, we cannot map the region as the caller expects.
++ */
++ if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
++ return;
++
++ phys &= PAGE_MASK;
++ addr = virt & PAGE_MASK;
++ end = PAGE_ALIGN(virt + size);
++
++ do {
++ next = pgd_addr_end(addr, end);
++ iee_alloc_init_pud_pre_init(pgdp, addr, next, phys, prot, pgtable_alloc,
++ flags);
++ p4dp = p4d_offset(pgdp, addr);
++ p4d = READ_ONCE(*p4dp);
++ __iee_p4d_populate_pre_init(p4dp, __p4d_to_phys(p4d), (PGD_APT | PUD_TYPE_TABLE));
++ phys += next - addr;
++ } while (pgdp++, addr = next, addr != end);
++}
++
++static __init void __iee_create_pgd_mapping_pre_init(pgd_t *pgdir, phys_addr_t phys,
++ unsigned long virt, phys_addr_t size,
++ pgprot_t prot,
++ phys_addr_t (*pgtable_alloc)(int),
++ int flags)
++{
++ mutex_lock(&fixmap_lock);
++ __iee_create_pgd_mapping_locked_pre_init(pgdir, phys, virt, size, prot,
++ pgtable_alloc, flags);
++ mutex_unlock(&fixmap_lock);
++}
++#endif
++
++static phys_addr_t __pgd_pgtable_alloc(int shift)
++{
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
++ void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL);
++ BUG_ON(!ptr);
++
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(ptr));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)ptr);
++ #endif
++
++ /* Ensure the zeroed page is visible to the page table walker */
++ dsb(ishst);
++ return __pa(ptr);
++}
++
++static phys_addr_t pgd_pgtable_alloc(int shift)
++{
++ phys_addr_t pa = __pgd_pgtable_alloc(shift);
++ struct ptdesc *ptdesc = page_ptdesc(phys_to_page(pa));
++
++ /*
++ * Call proper page table ctor in case later we need to
++ * call core mm functions like apply_to_page_range() on
++ * this pre-allocated page table.
++ *
++ * We don't select ARCH_ENABLE_SPLIT_PMD_PTLOCK if pmd is
++ * folded, and if so pagetable_pte_ctor() becomes nop.
++ */
++ if (shift == PAGE_SHIFT)
++ BUG_ON(!pagetable_pte_ctor(ptdesc));
++ else if (shift == PMD_SHIFT)
++ BUG_ON(!pagetable_pmd_ctor(ptdesc));
++
++ return pa;
++}
++
++/*
++ * This function can only be used to modify existing table entries,
++ * without allocating new levels of table. Note that this permits the
++ * creation of new section or page entries.
++ */
++void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
++ phys_addr_t size, pgprot_t prot)
++{
++ if (virt < PAGE_OFFSET) {
++ pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
++ &phys, virt);
++ return;
++ }
++
++ #ifdef CONFIG_PTP
++ __iee_create_pgd_mapping_pre_init(init_mm.pgd, phys, virt, size, prot, NULL,
++ NO_CONT_MAPPINGS);
++ #else
++ __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
++ NO_CONT_MAPPINGS);
++ #endif
++}
++
++void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
++ unsigned long virt, phys_addr_t size,
++ pgprot_t prot, bool page_mappings_only)
++{
++ int flags = 0;
++
++ BUG_ON(mm == &init_mm);
++
++ if (page_mappings_only)
++ flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
++
++ __create_pgd_mapping(mm->pgd, phys, virt, size, prot,
++ pgd_pgtable_alloc, flags);
++}
++
++static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
++ phys_addr_t size, pgprot_t prot)
++{
++ if (virt < PAGE_OFFSET) {
++ pr_warn("BUG: not updating mapping for %pa at 0x%016lx - outside kernel range\n",
++ &phys, virt);
++ return;
++ }
++
++ __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL,
++ NO_CONT_MAPPINGS);
++
++ /* flush the TLBs after updating live kernel mappings */
++ flush_tlb_kernel_range(virt, virt + size);
++}
++
++static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start,
++ phys_addr_t end, pgprot_t prot, int flags)
++{
++ #ifdef CONFIG_PTP
++ __iee_create_pgd_mapping_pre_init(pgdp, start, __phys_to_virt(start), end - start,
++ prot, early_pgtable_alloc, flags);
++ #else
++ __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start,
++ prot, early_pgtable_alloc, flags);
++ #endif
++}
++
++void __init mark_linear_text_alias_ro(void)
++{
++ /*
++ * Remove the write permissions from the linear alias of .text/.rodata
++ */
++ update_mapping_prot(__pa_symbol(_stext), (unsigned long)lm_alias(_stext),
++ (unsigned long)__init_begin - (unsigned long)_stext,
++ PAGE_KERNEL_RO);
++}
++
++#ifdef CONFIG_KFENCE
++
++bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL;
++
++/* early_param() will be parsed before map_mem() below. */
++static int __init parse_kfence_early_init(char *arg)
++{
++ int val;
++
++ if (get_option(&arg, &val))
++ kfence_early_init = !!val;
++
++#if IS_ENABLED(CONFIG_KFENCE_MUST_EARLY_INIT)
++ kfence_must_early_init = (val == -1) ? true : false;
++#endif
++
++ return 0;
++}
++early_param("kfence.sample_interval", parse_kfence_early_init);
++
++static phys_addr_t __init arm64_kfence_alloc_pool(void)
++{
++ phys_addr_t kfence_pool;
++
++ if (!kfence_early_init)
++ return 0;
++
++ kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE);
++ if (!kfence_pool) {
++ pr_err("failed to allocate kfence pool\n");
++ kfence_early_init = false;
++ return 0;
++ }
++
++ /* Temporarily mark as NOMAP. */
++ memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE);
++
++ return kfence_pool;
++}
++
++static void __init arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp)
++{
++ if (!kfence_pool)
++ return;
++
++ /* KFENCE pool needs page-level mapping. */
++ __map_memblock(pgdp, kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
++ pgprot_tagged(PAGE_KERNEL),
++ NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
++ memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE);
++ __kfence_pool = phys_to_virt(kfence_pool);
++}
++#else /* CONFIG_KFENCE */
++
++static inline phys_addr_t arm64_kfence_alloc_pool(void) { return 0; }
++static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp) { }
++
++#endif /* CONFIG_KFENCE */
++
++static void __init map_mem(pgd_t *pgdp)
++{
++ static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
++ phys_addr_t kernel_start = __pa_symbol(_stext);
++ phys_addr_t kernel_end = __pa_symbol(__init_begin);
++ phys_addr_t start, end;
++ phys_addr_t early_kfence_pool;
++ int flags = NO_EXEC_MAPPINGS;
++ u64 i;
++
++ /*
++ * Setting hierarchical PXNTable attributes on table entries covering
++ * the linear region is only possible if it is guaranteed that no table
++ * entries at any level are being shared between the linear region and
++ * the vmalloc region. Check whether this is true for the PGD level, in
++ * which case it is guaranteed to be true for all other levels as well.
++ */
++ BUILD_BUG_ON(pgd_index(direct_map_end - 1) == pgd_index(direct_map_end));
++
++ early_kfence_pool = arm64_kfence_alloc_pool();
++
++ if (can_set_direct_map())
++ flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
++
++ #ifdef CONFIG_IEE
++ flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
++ #endif
++ /*
++ * Take care not to create a writable alias for the
++ * read-only text and rodata sections of the kernel image.
++ * So temporarily mark them as NOMAP to skip mappings in
++ * the following for-loop
++ */
++ memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
++
++ /* map all the memory banks */
++ for_each_mem_range(i, &start, &end) {
++ if (start >= end)
++ break;
++ /*
++ * The linear map must allow allocation tags reading/writing
++ * if MTE is present. Otherwise, it has the same attributes as
++ * PAGE_KERNEL.
++ */
++ __map_memblock(pgdp, start, end, pgprot_tagged(PAGE_KERNEL),
++ flags);
++ }
+
+- return kfence_pool;
++ /*
++ * Map the linear alias of the [_stext, __init_begin) interval
++ * as non-executable now, and remove the write permission in
++ * mark_linear_text_alias_ro() below (which will be called after
++ * alternative patching has completed). This makes the contents
++ * of the region accessible to subsystems such as hibernate,
++ * but protects it from inadvertent modification or execution.
++ * Note that contiguous mappings cannot be remapped in this way,
++ * so we should avoid them here.
++ */
++ #ifdef CONFIG_IEE
++ __map_memblock(pgdp, kernel_start, kernel_end,
++ PAGE_KERNEL, flags);
++ #else
++ __map_memblock(pgdp, kernel_start, kernel_end,
++ PAGE_KERNEL, NO_CONT_MAPPINGS);
++ #endif
++ memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
++ arm64_kfence_map_pool(early_kfence_pool, pgdp);
++}
++
++void mark_rodata_ro(void)
++{
++ unsigned long section_size;
++
++ /*
++ * mark .rodata as read only. Use __init_begin rather than __end_rodata
++ * to cover NOTES and EXCEPTION_TABLE.
++ */
++ section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
++ update_mapping_prot(__pa_symbol(__start_rodata), (unsigned long)__start_rodata,
++ section_size, PAGE_KERNEL_RO);
++
++ debug_checkwx();
++}
++
++static void __init map_kernel_segment(pgd_t *pgdp, void *va_start, void *va_end,
++ pgprot_t prot, struct vm_struct *vma,
++ int flags, unsigned long vm_flags)
++{
++ phys_addr_t pa_start = __pa_symbol(va_start);
++ unsigned long size = va_end - va_start;
++
++ BUG_ON(!PAGE_ALIGNED(pa_start));
++ BUG_ON(!PAGE_ALIGNED(size));
++
++ #ifdef CONFIG_PTP
++ __iee_create_pgd_mapping_pre_init(pgdp, pa_start, (unsigned long)va_start, size, prot,
++ early_pgtable_alloc, flags);
++ #else
++ __create_pgd_mapping(pgdp, pa_start, (unsigned long)va_start, size, prot,
++ early_pgtable_alloc, flags);
++ #endif
++
++ if (!(vm_flags & VM_NO_GUARD))
++ size += PAGE_SIZE;
++
++ vma->addr = va_start;
++ vma->phys_addr = pa_start;
++ vma->size = size;
++ vma->flags = VM_MAP | vm_flags;
++ vma->caller = __builtin_return_address(0);
++
++ vm_area_add_early(vma);
++}
++
++static pgprot_t kernel_exec_prot(void)
++{
++ return rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
++}
++
++#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++static int __init map_entry_trampoline(void)
++{
++ int i;
++
++ pgprot_t prot = kernel_exec_prot();
++ phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
++
++ /* The trampoline is always mapped and can therefore be global */
++ pgprot_val(prot) &= ~PTE_NG;
++
++ /* Map only the text into the trampoline page table */
++ memset(tramp_pg_dir, 0, PGD_SIZE);
++ #ifdef CONFIG_PTP
++ iee_set_logical_mem_ro((unsigned long)tramp_pg_dir);
++ #endif
++ __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS,
++ entry_tramp_text_size(), prot,
++ __pgd_pgtable_alloc, NO_BLOCK_MAPPINGS);
++
++ /* Map both the text and data into the kernel page table */
++ for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++)
++ __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
++ pa_start + i * PAGE_SIZE, prot);
++
++ if (IS_ENABLED(CONFIG_RELOCATABLE))
++ __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
++ pa_start + i * PAGE_SIZE, PAGE_KERNEL_RO);
++
++ return 0;
++}
++core_initcall(map_entry_trampoline);
++#endif
++
++/*
++ * Open coded check for BTI, only for use to determine configuration
++ * for early mappings for before the cpufeature code has run.
++ */
++static bool arm64_early_this_cpu_has_bti(void)
++{
++ u64 pfr1;
++
++ if (!IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
++ return false;
++
++ pfr1 = __read_sysreg_by_encoding(SYS_ID_AA64PFR1_EL1);
++ return cpuid_feature_extract_unsigned_field(pfr1,
++ ID_AA64PFR1_EL1_BT_SHIFT);
++}
++
++#ifdef CONFIG_IEE
++/* Set PMD APTable of iee si codes as (1,1) to revert it to ROX P pages when HPD1=0. */
++static void __init iee_si_set_pmd_APtable(unsigned long addr, pgd_t *pgdir)
++{
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
++
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++
++ #ifdef CONFIG_PTP
++ pud_t *pudp = pud_set_fixmap_offset_init(p4dp, addr);
++
++ pmd_t *pmdp = pmd_set_fixmap_offset_init(pudp, addr);
++
++ pmd_t pmd = READ_ONCE(*pmdp);
++
++ __iee_pmd_populate_pre_init(pmdp, __pmd_to_phys(pmd), PGD_APT_RO | PGD_APT | PMD_TYPE_TABLE);
++
++ pud_clear_fixmap_init();
++ pmd_clear_fixmap_init();
++ #else
++ pud_t *pudp = pud_set_fixmap_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_set_fixmap_offset(pudp, addr);
++
++ pmd_t pmd = READ_ONCE(*pmdp);
++
++ __pmd_populate(pmdp, __pmd_to_phys(pmd), PGD_APT_RO | PGD_APT | PMD_TYPE_TABLE);
++
++ pud_clear_fixmap();
++ pmd_clear_fixmap();
++ #endif
++}
++/* Set PMD APTable of iee si codes as (1,1) to revert it to ROX P pages when HPD1=0. */
++static void __init mark_iee_si_pmd_APtable(pgd_t *pgdir)
++{
++ unsigned long addr = (unsigned long)__iee_si_start;
++ iee_si_set_pmd_APtable(addr, pgdir);
++ // iee rwx gate exit may be mapped by another pmd.
++ iee_si_set_pmd_APtable(addr + PAGE_SIZE, pgdir);
++}
++#endif
++
++/*
++ * Create fine-grained mappings for the kernel.
++ */
++static void __init map_kernel(pgd_t *pgdp)
++{
++ static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext,
++ vmlinux_initdata, vmlinux_data;
++
++ #ifdef CONFIG_IEE
++ static struct vm_struct vmlinux_iee_code, vmlinux_iee_data, vmlinux_iee_gate, vmlinux_text_end;
++ #endif
++
++ /*
++ * External debuggers may need to write directly to the text
++ * mapping to install SW breakpoints. Allow this (only) when
++ * explicitly requested with rodata=off.
++ */
++ pgprot_t text_prot = kernel_exec_prot();
++
++ /*
++ * If we have a CPU that supports BTI and a kernel built for
++ * BTI then mark the kernel executable text as guarded pages
++ * now so we don't have to rewrite the page tables later.
++ */
++ if (arm64_early_this_cpu_has_bti())
++ text_prot = __pgprot_modify(text_prot, PTE_GP, PTE_GP);
++
++ /*
++ * Only rodata will be remapped with different permissions later on,
++ * all other segments are allowed to use contiguous mappings.
++ */
++ #ifdef CONFIG_IEE
++ map_kernel_segment(pgdp, _stext, __iee_si_data_start, text_prot, &vmlinux_text,
++ 0, VM_NO_GUARD);
++ /* Set iee si data RW. */
++ map_kernel_segment(pgdp, __iee_si_data_start, __iee_exec_entry_start, SET_NG(PAGE_KERNEL),
++ &vmlinux_iee_data, NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, VM_NO_GUARD);
++ /* Set iee entry codes NG. */
++ map_kernel_segment(pgdp, __iee_exec_entry_start, __iee_si_start, SET_NG(text_prot), &vmlinux_iee_gate,
++ NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, VM_NO_GUARD);
++ /* Map __iee_si_start - __iee_si_end as U RWX pages and set PMD APTABLE = (1,1). */
++ map_kernel_segment(pgdp, __iee_si_start, __iee_si_end, SET_NG((PAGE_KERNEL_EXEC)),
++ &vmlinux_iee_code, NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, VM_NO_GUARD);
++ mark_iee_si_pmd_APtable(pgdp);
++
++ map_kernel_segment(pgdp, __iee_si_end, _etext, text_prot, &vmlinux_text_end, 0,
++ VM_NO_GUARD);
++
++ map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL,
++ &vmlinux_rodata, NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, VM_NO_GUARD);
++ map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot,
++ &vmlinux_inittext, 0, VM_NO_GUARD);
++ map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL,
++ &vmlinux_initdata, 0, VM_NO_GUARD);
++ map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, NO_CONT_MAPPINGS | NO_BLOCK_MAPPINGS, 0);
++ #else
++ map_kernel_segment(pgdp, _stext, _etext, text_prot, &vmlinux_text, 0,
++ VM_NO_GUARD);
++ map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL,
++ &vmlinux_rodata, NO_CONT_MAPPINGS, VM_NO_GUARD);
++ map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot,
++ &vmlinux_inittext, 0, VM_NO_GUARD);
++ map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL,
++ &vmlinux_initdata, 0, VM_NO_GUARD);
++ map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0);
++ #endif
++
++
++ fixmap_copy(pgdp);
++ kasan_copy_shadow(pgdp);
++}
++
++static void __init create_idmap(void)
++{
++ u64 start = __pa_symbol(__idmap_text_start);
++ u64 size = __pa_symbol(__idmap_text_end) - start;
++ pgd_t *pgd = idmap_pg_dir;
++ u64 pgd_phys;
++
++ /* check if we need an additional level of translation */
++ if (VA_BITS < 48 && idmap_t0sz < (64 - VA_BITS_MIN)) {
++ pgd_phys = early_pgtable_alloc(PAGE_SHIFT);
++ set_pgd(&idmap_pg_dir[start >> VA_BITS],
++ __pgd(pgd_phys | P4D_TYPE_TABLE));
++ pgd = __va(pgd_phys);
++ }
++ #ifdef CONFIG_PTP
++ __iee_create_pgd_mapping_pre_init(pgd, start, start, size, PAGE_KERNEL_ROX,
++ early_pgtable_alloc, 0);
++ #else
++ __create_pgd_mapping(pgd, start, start, size, PAGE_KERNEL_ROX,
++ early_pgtable_alloc, 0);
++ #endif
++
++ if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) {
++ extern u32 __idmap_kpti_flag;
++ u64 pa = __pa_symbol(&__idmap_kpti_flag);
++
++ /*
++ * The KPTI G-to-nG conversion code needs a read-write mapping
++ * of its synchronization flag in the ID map.
++ */
++ #ifdef CONFIG_PTP
++ __iee_create_pgd_mapping_pre_init(pgd, pa, pa, sizeof(u32), PAGE_KERNEL,
++ early_pgtable_alloc, 0);
++ #else
++ __create_pgd_mapping(pgd, pa, pa, sizeof(u32), PAGE_KERNEL,
++ early_pgtable_alloc, 0);
++ #endif
++ }
++}
++
++#ifdef CONFIG_IEE
++static void __create_pgd_mapping_for_iee_locked(pgd_t *pgdir, phys_addr_t phys,
++ unsigned long virt, phys_addr_t size,
++ pgprot_t prot,
++ phys_addr_t (*pgtable_alloc)(int),
++ int flags)
++{
++ unsigned long addr, end, next;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);
++ p4d_t *p4dp;
++ p4d_t p4d;
++
++ /*
++ * If the virtual and physical address don't have the same offset
++ * within a page, we cannot map the region as the caller expects.
++ */
++ if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
++ return;
++
++ phys &= PAGE_MASK;
++ addr = virt & PAGE_MASK;
++ end = PAGE_ALIGN(virt + size);
++
++ do {
++ next = pgd_addr_end(addr, end);
++ #ifdef CONFIG_PTP
++ iee_alloc_init_pud_pre_init(pgdp, addr, next, phys, prot, pgtable_alloc,
++ flags);
++ #else
++ alloc_init_pud(pgdp, addr, next, phys, prot, pgtable_alloc,
++ flags);
++ #endif
++ p4dp = p4d_offset(pgdp, addr);
++ p4d = READ_ONCE(*p4dp);
++ #ifdef CONFIG_PTP
++ __iee_p4d_populate_pre_init(p4dp, __p4d_to_phys(p4d), (PGD_APT | PGD_PXN | PGD_UXN | PUD_TYPE_TABLE));
++ #else
++ __p4d_populate(p4dp, __p4d_to_phys(p4d), (PGD_APT | PGD_PXN | PGD_UXN | PUD_TYPE_TABLE));
++ #endif
++ phys += next - addr;
++ } while (pgdp++, addr = next, addr != end);
++}
++
++static void __create_pgd_mapping_for_iee(pgd_t *pgdir, phys_addr_t phys,
++ unsigned long virt, phys_addr_t size,
++ pgprot_t prot,
++ phys_addr_t (*pgtable_alloc)(int),
++ int flags)
++{
++ mutex_lock(&fixmap_lock);
++ __create_pgd_mapping_for_iee_locked(pgdir, phys, virt, size, prot,
++ pgtable_alloc, flags);
++ mutex_unlock(&fixmap_lock);
+ }
+
+-static void __init arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp)
++static void __init __map_memblock_for_iee(pgd_t *pgdp, phys_addr_t start,
++ phys_addr_t end, pgprot_t prot, int flags)
+ {
+- if (!kfence_pool)
+- return;
+-
+- /* KFENCE pool needs page-level mapping. */
+- __map_memblock(pgdp, kfence_pool, kfence_pool + KFENCE_POOL_SIZE,
+- pgprot_tagged(PAGE_KERNEL),
+- NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
+- memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE);
+- __kfence_pool = phys_to_virt(kfence_pool);
++ #ifdef CONFIG_PTP
++ __create_pgd_mapping_for_iee(pgdp, start, __phys_to_iee(start), end - start,
++ prot, early_pgtable_alloc, flags);
++ #else
++ __create_pgd_mapping_for_iee(pgdp, start, __phys_to_iee(start), end - start,
++ prot, early_pgtable_alloc, flags);
++ #endif
+ }
+-#else /* CONFIG_KFENCE */
+
+-static inline phys_addr_t arm64_kfence_alloc_pool(void) { return 0; }
+-static inline void arm64_kfence_map_pool(phys_addr_t kfence_pool, pgd_t *pgdp) { }
+-
+-#endif /* CONFIG_KFENCE */
+-
+-static void __init map_mem(pgd_t *pgdp)
++static void __init map_iee(pgd_t *pgdp)
+ {
+ static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
+ phys_addr_t kernel_start = __pa_symbol(_stext);
+@@ -578,6 +1578,8 @@ static void __init map_mem(pgd_t *pgdp)
+ int flags = NO_EXEC_MAPPINGS;
+ u64 i;
+
++ flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
++
+ /*
+ * Setting hierarchical PXNTable attributes on table entries covering
+ * the linear region is only possible if it is guaranteed that no table
+@@ -589,9 +1591,6 @@ static void __init map_mem(pgd_t *pgdp)
+
+ early_kfence_pool = arm64_kfence_alloc_pool();
+
+- if (can_set_direct_map())
+- flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
+-
+ /*
+ * Take care not to create a writable alias for the
+ * read-only text and rodata sections of the kernel image.
+@@ -609,12 +1608,11 @@ static void __init map_mem(pgd_t *pgdp)
+ * if MTE is present. Otherwise, it has the same attributes as
+ * PAGE_KERNEL.
+ */
+- __map_memblock(pgdp, start, end, pgprot_tagged(PAGE_KERNEL),
+- flags);
++ __map_memblock_for_iee(pgdp, start, end, SET_NG(SET_INVALID(SET_UPAGE(PAGE_KERNEL))), flags);
+ }
+
+ /*
+- * Map the linear alias of the [_stext, __init_begin) interval
++ * Map the linear alias of the [_text, __init_begin) interval
+ * as non-executable now, and remove the write permission in
+ * mark_linear_text_alias_ro() below (which will be called after
+ * alternative patching has completed). This makes the contents
+@@ -623,178 +1621,384 @@ static void __init map_mem(pgd_t *pgdp)
+ * Note that contiguous mappings cannot be remapped in this way,
+ * so we should avoid them here.
+ */
+- __map_memblock(pgdp, kernel_start, kernel_end,
+- PAGE_KERNEL, NO_CONT_MAPPINGS);
++ __map_memblock_for_iee(pgdp, kernel_start, kernel_end,
++ SET_NG(SET_INVALID(SET_UPAGE(PAGE_KERNEL))), flags);
+ memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
+ arm64_kfence_map_pool(early_kfence_pool, pgdp);
+ }
+
+-void mark_rodata_ro(void)
++/*
++ * Change page access permission, whereas not handling huge pages.
++ * Only used on IEE init functions.
++ */
++static void __init iee_si_set_page_attr(unsigned long addr, pteval_t attr)
+ {
+- unsigned long section_size;
++ unsigned long flag;
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
+
+- /*
+- * mark .rodata as read only. Use __init_begin rather than __end_rodata
+- * to cover NOTES and EXCEPTION_TABLE.
+- */
+- section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
+- update_mapping_prot(__pa_symbol(__start_rodata), (unsigned long)__start_rodata,
+- section_size, PAGE_KERNEL_RO);
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
+
+- debug_checkwx();
++ pud_t *pudp = pud_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_offset(pudp, addr);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++ pte_t pte = READ_ONCE(*ptep);
++
++ if(attr & PTE_RDONLY)
++ pte = __pte((pte_val(pte) | PTE_RDONLY) & ~PTE_DBM);
++ pte = __pte(pte_val(pte) | attr);
++ #ifdef CONFIG_PTP
++ // Write pgtable in IEE directly.
++ flag = local_daif_save();
++ asm volatile ("msr pan, #0");
++ WRITE_ONCE(*((pte_t *)(__phys_to_iee(__pa(ptep)))), pte);
++ asm volatile ("msr pan, #1");
++ local_daif_restore(flag);
++ #else
++ WRITE_ONCE(*ptep, pte);
++ #endif
++}
++
++/* Prepare data used for iee rwx gates. These data are setted only once. */
++void __init iee_si_prepare_data(void)
++{
++ unsigned long va;
++ // Record current TCR val after system init.
++ iee_si_tcr = read_sysreg(tcr_el1) & ~(SYS_TCR_IEE_SI);
++ // Mark iee data as RO and move it to iee after setting up.
++ va = (unsigned long)__iee_si_data_start;
++ iee_si_set_page_attr(va, PTE_RDONLY);
++ iee_si_set_page_attr(lm_alias(va)+iee_offset, 0x1 | PTE_RDONLY);
++ // Set iee sensitive inst code page U RWX here to hide it from kernel.
++ va = (unsigned long)__iee_si_start;
++ iee_si_set_page_attr(va, PTE_USER);
++ va = (unsigned long)__iee_si_start + PAGE_SIZE;
++ iee_si_set_page_attr(va, PTE_USER);
++ flush_tlb_all();
+ }
+
+-static void __init map_kernel_segment(pgd_t *pgdp, void *va_start, void *va_end,
+- pgprot_t prot, struct vm_struct *vma,
+- int flags, unsigned long vm_flags)
++#endif
++
++#ifdef CONFIG_PTP
++// Attention : Using set_xxx without adding offset.
++static void __init set_iee_valid_pre_init(unsigned long addr)
+ {
+- phys_addr_t pa_start = __pa_symbol(va_start);
+- unsigned long size = va_end - va_start;
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
+
+- BUG_ON(!PAGE_ALIGNED(pa_start));
+- BUG_ON(!PAGE_ALIGNED(size));
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
+
+- __create_pgd_mapping(pgdp, pa_start, (unsigned long)va_start, size, prot,
+- early_pgtable_alloc, flags);
++ pud_t *pudp = pud_offset(p4dp, addr);
+
+- if (!(vm_flags & VM_NO_GUARD))
+- size += PAGE_SIZE;
++ pmd_t *pmdp = pmd_offset(pudp, addr);
+
+- vma->addr = va_start;
+- vma->phys_addr = pa_start;
+- vma->size = size;
+- vma->flags = VM_MAP | vm_flags;
+- vma->caller = __builtin_return_address(0);
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++ pte_t pte = READ_ONCE(*ptep);
+
+- vm_area_add_early(vma);
++ if((addr < (PAGE_OFFSET + IEE_OFFSET)) | (addr > (PAGE_OFFSET + BIT(vabits_actual - 1))))
++ return;
++
++ pte = __pte(pte_val(pte) | 0x1);
++ iee_set_pte_pre_init(ptep, pte);
++ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
++ isb();
+ }
+
+-static pgprot_t kernel_exec_prot(void)
++static void __init move_pte_table_into_iee(pmd_t *pmdp, unsigned long addr, unsigned long end)
+ {
+- return rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
++ pmd_t pmd = READ_ONCE(*pmdp);
++ unsigned long iee_addr = __phys_to_iee(__pmd_to_phys(pmd));
++ set_iee_valid_pre_init(iee_addr);
+ }
+
+-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+-static int __init map_entry_trampoline(void)
++static void __init move_pmd_table_into_iee(pud_t *pudp, unsigned long addr, unsigned long end)
+ {
+- int i;
++ unsigned long next;
++ pud_t pud = READ_ONCE(*pudp);
++ pmd_t *pmdp;
++ pmd_t pmd;
++ unsigned long iee_addr = __phys_to_iee(__pud_to_phys(pud));
++ set_iee_valid_pre_init(iee_addr);
+
+- pgprot_t prot = kernel_exec_prot();
+- phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
++ pmdp = pmd_offset(pudp, addr);
++ do {
++ next = pmd_addr_end(addr, end);
++ pmd = READ_ONCE(*pmdp);
++ if((pmd_val(pmd) & PMD_TABLE_BIT) == 0)
++ {
++ continue;
++ }
++ else
++ {
++ move_pte_table_into_iee(pmdp, addr, next);
++ }
++ } while (pmdp++, addr = next, addr != end);
++}
+
+- /* The trampoline is always mapped and can therefore be global */
+- pgprot_val(prot) &= ~PTE_NG;
++static void __init move_pud_table_into_iee(pgd_t *pgdp, unsigned long addr, unsigned long end)
++{
++ unsigned long next;
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++ p4d_t p4d = READ_ONCE(*p4dp);
++ pud_t *pudp;
++ pud_t pud;
++ unsigned long iee_addr = __phys_to_iee(__p4d_to_phys(p4d));
++ set_iee_valid_pre_init(iee_addr);
+
+- /* Map only the text into the trampoline page table */
+- memset(tramp_pg_dir, 0, PGD_SIZE);
+- __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS,
+- entry_tramp_text_size(), prot,
+- __pgd_pgtable_alloc, NO_BLOCK_MAPPINGS);
++ pudp = pud_offset(p4dp, addr);
++ do {
++ next = pud_addr_end(addr, end);
++ pud = READ_ONCE(*pudp);
++ if ((pud_val(pud) & PUD_TABLE_BIT) == 0)
++ {
++ continue;
++ }
++ else
++ {
++ move_pmd_table_into_iee(pudp, addr, next);
++ }
++ } while (pudp++, addr = next, addr != end);
++}
+
+- /* Map both the text and data into the kernel page table */
+- for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++)
+- __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
+- pa_start + i * PAGE_SIZE, prot);
++static void __init init_iee_for_one_region(pgd_t *pgdir, unsigned long va_start, unsigned long va_end)
++{
++ unsigned long addr, end, next;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, va_start);
+
+- if (IS_ENABLED(CONFIG_RELOCATABLE))
+- __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
+- pa_start + i * PAGE_SIZE, PAGE_KERNEL_RO);
++ addr = va_start & PAGE_MASK;
++ end = PAGE_ALIGN(va_end);
+
+- return 0;
++ do {
++ next = pgd_addr_end(addr, end);
++ move_pud_table_into_iee(pgdp, addr, next);
++ } while (pgdp++, addr = next, addr != end);
+ }
+-core_initcall(map_entry_trampoline);
+-#endif
+
+-/*
+- * Open coded check for BTI, only for use to determine configuration
+- * for early mappings for before the cpufeature code has run.
+- */
+-static bool arm64_early_this_cpu_has_bti(void)
++static void __init init_iee(void)
+ {
+- u64 pfr1;
++ unsigned long iee_addr;
++ phys_addr_t start, end;
++ u64 i;
++ pgd_t *pgdp;
++
++ #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ // handling 1-level tramp page table tramp_pg_dir
++ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(tramp_pg_dir));
++ set_iee_valid_pre_init(iee_addr);
++ #endif
++ // handling 1-level page table swapper_pg_dir
++ pgdp = swapper_pg_dir;
++ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(swapper_pg_dir));
++ set_iee_valid_pre_init(iee_addr);
++ // handling 2/3/4-level page table for kernel
++ init_iee_for_one_region(pgdp, (unsigned long)_text, (unsigned long)_etext);
++ init_iee_for_one_region(pgdp, (unsigned long)__start_rodata, (unsigned long)__inittext_begin);
++ init_iee_for_one_region(pgdp, (unsigned long)__inittext_begin, (unsigned long)__inittext_end);
++ init_iee_for_one_region(pgdp, (unsigned long)__initdata_begin, (unsigned long)__initdata_end);
++ init_iee_for_one_region(pgdp, (unsigned long)_data, (unsigned long)_end);
++ // handling 2/3/4-level page table for fixmap i.e. remap bm_xxx
++ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(bm_pte_addr));
++ set_iee_valid_pre_init(iee_addr);
++ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(bm_pmd_addr));
++ set_iee_valid_pre_init(iee_addr);
++ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(bm_pud_addr));
++ set_iee_valid_pre_init(iee_addr);
++ // handling 2/3/4-level page table for logical mem and iee
++ for_each_mem_range(i, &start, &end) {
++ if (start >= end)
++ break;
++ /*
++ * The linear map must allow allocation tags reading/writing
++ * if MTE is present. Otherwise, it has the same attributes as
++ * PAGE_KERNEL.
++ */
++ init_iee_for_one_region(pgdp, (unsigned long)__va(start), (unsigned long)__va(end));
++ init_iee_for_one_region(pgdp, (unsigned long)__phys_to_iee(start), (unsigned long)__phys_to_iee(end));
++ }
++}
+
+- if (!IS_ENABLED(CONFIG_ARM64_BTI_KERNEL))
+- return false;
++static void iee_set_kernel_upage_pre_init(unsigned long addr)
++{
++ pgd_t *pgdir = swapper_pg_dir;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr);
+
+- pfr1 = __read_sysreg_by_encoding(SYS_ID_AA64PFR1_EL1);
+- return cpuid_feature_extract_unsigned_field(pfr1,
+- ID_AA64PFR1_EL1_BT_SHIFT);
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++ p4d_t p4d = READ_ONCE(*p4dp);
++
++ pud_t *pudp = pud_offset(p4dp, addr);
++
++ pmd_t *pmdp = pmd_offset(pudp, addr);
++
++ pte_t *ptep = pte_offset_kernel(pmdp, addr);
++
++ int i;
++ for(i = 0; i < 4; i++)
++ {
++ pte_t pte = READ_ONCE(*ptep);
++ pte = __pte(pte_val(pte) | PTE_USER | PTE_NG);
++ iee_set_pte_pre_init(ptep, pte);
++ ptep++;
++ }
++ flush_tlb_kernel_range(addr, addr+4*PAGE_SIZE);
++ isb();
+ }
+
+-/*
+- * Create fine-grained mappings for the kernel.
+- */
+-static void __init map_kernel(pgd_t *pgdp)
++static void __init iee_set_pte_table_ro(pmd_t *pmdp, unsigned long addr, unsigned long end)
+ {
+- static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext,
+- vmlinux_initdata, vmlinux_data;
++ pmd_t pmd = READ_ONCE(*pmdp);
++ unsigned long logical_addr = (unsigned long)__va(__pmd_to_phys(pmd));
++ iee_set_logical_mem_ro(logical_addr);
++}
+
+- /*
+- * External debuggers may need to write directly to the text
+- * mapping to install SW breakpoints. Allow this (only) when
+- * explicitly requested with rodata=off.
+- */
+- pgprot_t text_prot = kernel_exec_prot();
++static void __init iee_set_pmd_table_ro(pud_t *pudp, unsigned long addr, unsigned long end)
++{
++ unsigned long next;
++ pud_t pud = READ_ONCE(*pudp);
++ pmd_t *pmdp;
++ pmd_t pmd;
++ unsigned long logical_addr = (unsigned long)__va(__pud_to_phys(pud));
++ iee_set_logical_mem_ro(logical_addr);
+
+- /*
+- * If we have a CPU that supports BTI and a kernel built for
+- * BTI then mark the kernel executable text as guarded pages
+- * now so we don't have to rewrite the page tables later.
+- */
+- if (arm64_early_this_cpu_has_bti())
+- text_prot = __pgprot_modify(text_prot, PTE_GP, PTE_GP);
++ pmdp = pmd_offset(pudp, addr);
++ do {
++ next = pmd_addr_end(addr, end);
++ pmd = READ_ONCE(*pmdp);
++ if((pmd_val(pmd) & PMD_TABLE_BIT) == 0)
++ {
++ continue;
++ }
++ else
++ {
++ iee_set_pte_table_ro(pmdp, addr, next);
++ }
++ } while (pmdp++, addr = next, addr != end);
++}
+
+- /*
+- * Only rodata will be remapped with different permissions later on,
+- * all other segments are allowed to use contiguous mappings.
+- */
+- map_kernel_segment(pgdp, _stext, _etext, text_prot, &vmlinux_text, 0,
+- VM_NO_GUARD);
+- map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL,
+- &vmlinux_rodata, NO_CONT_MAPPINGS, VM_NO_GUARD);
+- map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot,
+- &vmlinux_inittext, 0, VM_NO_GUARD);
+- map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL,
+- &vmlinux_initdata, 0, VM_NO_GUARD);
+- map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0);
++static void __init iee_set_pud_table_ro(pgd_t *pgdp, unsigned long addr, unsigned long end)
++{
++ unsigned long next;
++ p4d_t *p4dp = p4d_offset(pgdp, addr);
++ p4d_t p4d = READ_ONCE(*p4dp);
++ pud_t *pudp;
++ pud_t pud;
++ unsigned long logical_addr = (unsigned long)__va(__p4d_to_phys(p4d));
++ iee_set_logical_mem_ro(logical_addr);
+
+- fixmap_copy(pgdp);
+- kasan_copy_shadow(pgdp);
++ pudp = pud_offset(p4dp, addr);
++ do {
++ next = pud_addr_end(addr, end);
++ pud = READ_ONCE(*pudp);
++ if ((pud_val(pud) & PUD_TABLE_BIT) == 0)
++ {
++ continue;
++ }
++ else
++ {
++ iee_set_pmd_table_ro(pudp, addr, next);
++ }
++ } while (pudp++, addr = next, addr != end);
+ }
+
+-static void __init create_idmap(void)
++static void __init iee_mark_pgtable_for_one_region_ro(pgd_t *pgdir, unsigned long va_start, unsigned long va_end)
+ {
+- u64 start = __pa_symbol(__idmap_text_start);
+- u64 size = __pa_symbol(__idmap_text_end) - start;
+- pgd_t *pgd = idmap_pg_dir;
+- u64 pgd_phys;
++ unsigned long addr, end, next;
++ pgd_t *pgdp = pgd_offset_pgd(pgdir, va_start);
+
+- /* check if we need an additional level of translation */
+- if (VA_BITS < 48 && idmap_t0sz < (64 - VA_BITS_MIN)) {
+- pgd_phys = early_pgtable_alloc(PAGE_SHIFT);
+- set_pgd(&idmap_pg_dir[start >> VA_BITS],
+- __pgd(pgd_phys | P4D_TYPE_TABLE));
+- pgd = __va(pgd_phys);
+- }
+- __create_pgd_mapping(pgd, start, start, size, PAGE_KERNEL_ROX,
+- early_pgtable_alloc, 0);
++ addr = va_start & PAGE_MASK;
++ end = PAGE_ALIGN(va_end);
+
+- if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) {
+- extern u32 __idmap_kpti_flag;
+- u64 pa = __pa_symbol(&__idmap_kpti_flag);
++ do {
++ next = pgd_addr_end(addr, end);
++ iee_set_pud_table_ro(pgdp, addr, next);
++ } while (pgdp++, addr = next, addr != end);
++}
+
++static void __init iee_mark_all_lm_pgtable_ro(void)
++{
++ unsigned long logical_addr;
++ phys_addr_t start, end;
++ u64 i;
++ pgd_t *pgdp;
++
++ // handling static allocated page table
++ #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
++ // handling 1-level tramp page table tramp_pg_dir
++ logical_addr = (unsigned long)__va(__pa_symbol(tramp_pg_dir));
++ iee_set_logical_mem_ro(logical_addr);
++ #endif
++ // handling 1-level page table swapper_pg_dir
++ pgdp = swapper_pg_dir;
++ iee_set_logical_mem_ro((unsigned long)swapper_pg_dir);
++ logical_addr = (unsigned long)__va(__pa_symbol(swapper_pg_dir));
++ iee_set_logical_mem_ro(logical_addr);
++
++ // handling 2/3/4-level page table for kernel
++ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)_text, (unsigned long)_etext);
++ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__start_rodata, (unsigned long)__inittext_begin);
++ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__inittext_begin, (unsigned long)__inittext_end);
++ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__initdata_begin, (unsigned long)__initdata_end);
++ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)_data, (unsigned long)_end);
++
++ // handling 2/3/4-level page table for fixmap i.e. remap bm_xxx
++ logical_addr = (unsigned long)__va(__pa_symbol(bm_pte_addr));
++ iee_set_logical_mem_ro(logical_addr);
++
++ iee_set_logical_mem_ro((unsigned long)bm_pmd_addr);
++ logical_addr = (unsigned long)__va(__pa_symbol(bm_pmd_addr));
++ iee_set_logical_mem_ro(logical_addr);
++
++ iee_set_logical_mem_ro((unsigned long)bm_pud_addr);
++ logical_addr = (unsigned long)__va(__pa_symbol(bm_pud_addr));
++ iee_set_logical_mem_ro(logical_addr);
++
++ // handling 2/3/4-level page table for logical mem and iee
++ for_each_mem_range(i, &start, &end) {
++ if (start >= end)
++ break;
+ /*
+- * The KPTI G-to-nG conversion code needs a read-write mapping
+- * of its synchronization flag in the ID map.
++ * The linear map must allow allocation tags reading/writing
++ * if MTE is present. Otherwise, it has the same attributes as
++ * PAGE_KERNEL.
+ */
+- __create_pgd_mapping(pgd, pa, pa, sizeof(u32), PAGE_KERNEL,
+- early_pgtable_alloc, 0);
++ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__va(start), (unsigned long)__va(end));
++ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__phys_to_iee(start), (unsigned long)__phys_to_iee(end));
+ }
+ }
++#endif
++
++#ifdef CONFIG_KOI
++extern s64 koi_offset;
++#endif
+
+ void __init paging_init(void)
+ {
++ #ifdef CONFIG_IEE
++ unsigned long SP_EL0;
++ void *new;
++ void *init_token;
++ struct task_token *token;
++ unsigned long tcr;
++
++ // Check if cpu has PAN and HPDS.
++ if(!cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR1_EL1),
++ ID_AA64MMFR1_EL1_PAN_SHIFT))
++ panic("Architecture doesn't support PAN, please disable CONFIG_IEE.\n");
++
++ if(!cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR1_EL1),
++ ID_AA64MMFR1_EL1_HPDS_SHIFT))
++ panic("Architecture doesn't support HPDS, please disable CONFIG_IEE.\n");
++ #endif
++
++ // Avoid using iee code to modify pgtable before iee initialized.
++ #ifdef CONFIG_PTP
++ pgd_t *pgdp = pgd_set_fixmap_init(__pa_symbol(swapper_pg_dir));
++ #else
+ pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));
++ #endif
++
++
+ extern pgd_t init_idmap_pg_dir[];
+
+ idmap_t0sz = 63UL - __fls(__pa_symbol(_end) | GENMASK(VA_BITS_MIN - 1, 0));
+@@ -802,7 +2006,17 @@ void __init paging_init(void)
+ map_kernel(pgdp);
+ map_mem(pgdp);
+
++ // Map the whole physical mem into IEE, but set invalid.
++ #ifdef CONFIG_IEE
++ map_iee(pgdp);
++ #endif
++
++ // Avoid using iee code to modify pgtable before iee initialized.
++ #ifdef CONFIG_PTP
++ pgd_clear_fixmap_init();
++ #else
+ pgd_clear_fixmap();
++ #endif
+
+ cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_idmap_pg_dir);
+ init_mm.pgd = swapper_pg_dir;
+@@ -813,6 +2027,80 @@ void __init paging_init(void)
+ memblock_allow_resize();
+
+ create_idmap();
++
++ #ifdef CONFIG_IEE
++ // test iee_exec_entry
++ iee_rwx_gate_entry(IEE_SI_TEST);
++ // Initialize init iee stack.
++ #ifdef CONFIG_PTP
++ iee_set_kernel_upage_pre_init((unsigned long)init_iee_stack_begin);
++ iee_set_kernel_upage_pre_init((unsigned long)__va(__pa_symbol(init_iee_stack_begin)));
++ #else
++ iee_set_kernel_upage((unsigned long)init_iee_stack_begin);
++ iee_set_kernel_upage((unsigned long)__va(__pa_symbol(init_iee_stack_begin)));
++ #endif
++ #endif
++
++ // Init token for init_task.
++ #ifdef CONFIG_IEE
++ // Change SP_EL0 from Image VA to Logical VA.
++ SP_EL0 = (unsigned long)__va(__pa_symbol(&init_task));
++ write_sysreg(SP_EL0, sp_el0);
++ init_task.cpus_ptr = &(((struct task_struct *)(__va(__pa_symbol(&init_task))))->cpus_mask);
++ init_task.children.prev = (__va(__pa_symbol(init_task.children.prev)));
++ init_task.children.next = (__va(__pa_symbol(init_task.children.next)));
++ // Set init_task into __entry_task before per_cpu init.
++ *(struct task_struct **)__entry_task = __va(__pa_symbol(&init_task));
++ // Alloc a page for init_token.
++ new = __va(early_pgtable_alloc(0));
++ init_token = (void *)__phys_to_iee(__pa_symbol(&init_task));
++ #ifdef CONFIG_PTP
++ iee_set_token_page_valid_pre_init(init_token, new);
++ #else
++ iee_set_token_page_valid(init_token, new);
++ #endif
++ // Use lm to write token before IEE initialized.
++ token = (struct task_token *)((unsigned long)new + (((unsigned long)&init_task) & ~PAGE_MASK));
++ token->mm = &init_mm;
++ token->pgd = NULL;
++ token->iee_stack = (void *)init_iee_stack_end;
++ token->valid = true;
++ #endif
++
++ #ifdef CONFIG_PTP
++ // Map the existing pgtable into IEE, set valid.
++ init_iee();
++ #endif
++
++ #ifdef CONFIG_IEE
++ sysreg_clear_set(sctlr_el1, 0, SCTLR_EL1_SPAN);
++ #endif
++
++ #ifdef CONFIG_PTP
++ // IEE ready.
++ // Pgtable writing before uses logical memory and after uses IEE memory.
++
++ // Set the logical va of existing pgtable readonly.
++ iee_mark_all_lm_pgtable_ro();
++ #endif
++
++ // Set the init token readonly.
++ #ifdef CONFIG_IEE
++ set_iee_page_valid(__phys_to_iee(__pa(new)));
++ iee_set_logical_mem_ro((unsigned long)new);
++
++ // Set HPD1 as 1.
++ tcr = read_sysreg(tcr_el1);
++ tcr |= ((unsigned long)0x1 << 42);
++ write_sysreg(tcr, tcr_el1);
++ isb();
++
++ // Flush tlb to enable IEE.
++ flush_tlb_all();
++
++ // mark that iee is prepared.
++ iee_init_done = true;
++ #endif
+ }
+
+ #ifdef CONFIG_MEMORY_HOTPLUG
+diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c
+index 4a64089e5771..894bda11c389 100644
+--- a/arch/arm64/mm/pgd.c
++++ b/arch/arm64/mm/pgd.c
+@@ -15,14 +15,44 @@
+ #include <asm/page.h>
+ #include <asm/tlbflush.h>
+
++#ifdef CONFIG_PTP
++#include <linux/iee-func.h>
++#endif
++
+ static struct kmem_cache *pgd_cache __ro_after_init;
+
++#ifdef CONFIG_KOI
++pgd_t *koi_pgd_alloc(void)
++{
++ pgd_t *pgd;
++#ifdef CONFIG_PTP
++ pgd = (pgd_t *)__get_free_page(GFP_PGTABLE_KERNEL);
++ unsigned long iee_addr = __phys_to_iee(__pa(pgd));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)pgd);
++#else
++ pgd = (pgd_t *)__get_free_page(GFP_PGTABLE_KERNEL);
++#endif
++ return pgd;
++}
++#endif
++
+ pgd_t *pgd_alloc(struct mm_struct *mm)
+ {
+ gfp_t gfp = GFP_PGTABLE_USER;
+
+ if (PGD_SIZE == PAGE_SIZE)
++#ifdef CONFIG_PTP
++ {
++ pgd_t* new = (pgd_t *)__get_free_page(gfp);
++ unsigned long iee_addr = __phys_to_iee(__pa(new));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)new);
++ return new;
++ }
++#else
+ return (pgd_t *)__get_free_page(gfp);
++#endif
+ else
+ return kmem_cache_alloc(pgd_cache, gfp);
+ }
+@@ -30,7 +60,16 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
+ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+ {
+ if (PGD_SIZE == PAGE_SIZE)
++#ifdef CONFIG_PTP
++ {
++ unsigned long iee_addr = __phys_to_iee(__pa(pgd));
++ set_iee_page_invalid(iee_addr);
++ iee_set_logical_mem_rw((unsigned long)pgd);
++ free_page((unsigned long)pgd);
++ }
++#else
+ free_page((unsigned long)pgd);
++#endif
+ else
+ kmem_cache_free(pgd_cache, pgd);
+ }
+diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
+index 14fdf645edc8..230b2b883a51 100644
+--- a/arch/arm64/mm/proc.S
++++ b/arch/arm64/mm/proc.S
+@@ -22,6 +22,8 @@
+ #include <asm/smp.h>
+ #include <asm/sysreg.h>
+
++
++
+ #ifdef CONFIG_ARM64_64K_PAGES
+ #define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K
+ #elif defined(CONFIG_ARM64_16K_PAGES)
+@@ -105,6 +107,19 @@ SYM_FUNC_START(cpu_do_suspend)
+ ret
+ SYM_FUNC_END(cpu_do_suspend)
+
++
++#ifdef CONFIG_IEE
++// SP_EL0 check failed.
++SYM_FUNC_START_LOCAL(sp_el0_check_failed)
++1:
++ nop
++ nop
++ nop
++ nop
++ b 1f
++SYM_FUNC_END(sp_el0_check_failed)
++#endif
++
+ /**
+ * cpu_do_resume - restore CPU register context
+ *
+@@ -148,6 +163,13 @@ SYM_FUNC_START(cpu_do_resume)
+ msr sctlr_el1, x12
+ set_this_cpu_offset x13
+ msr sp_el0, x14
++#ifdef CONFIG_IEE
++ // tsk check.
++ ldr_this_cpu x2, __entry_task, x3
++ mrs x3, sp_el0
++ cmp x2, x3
++ b.ne sp_el0_check_failed
++#endif
+ /*
+ * Restore oslsr_el1 by writing oslar_el1
+ */
+@@ -190,6 +212,7 @@ SYM_TYPED_FUNC_START(idmap_cpu_replace_ttbr1)
+ __idmap_cpu_set_reserved_ttbr1 x1, x3
+
+ offset_ttbr1 x0, x3
++
+ msr ttbr1_el1, x0
+ isb
+
+@@ -452,6 +475,11 @@ SYM_FUNC_START(__cpu_setup)
+ orr tcr, tcr, #TCR_HA // hardware Access flag update
+ 1:
+ #endif /* CONFIG_ARM64_HW_AFDBM */
++
++#ifdef CONFIG_IEE
++ orr tcr, tcr, #TCR_HPD1 // Hierarchical permission disables
++#endif
++
+ msr mair_el1, mair
+ msr tcr_el1, tcr
+
+diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
+index 5139a28130c0..15d2a3faa048 100644
+--- a/arch/arm64/mm/trans_pgd.c
++++ b/arch/arm64/mm/trans_pgd.c
+@@ -25,6 +25,9 @@
+ #include <linux/mm.h>
+ #include <linux/mmzone.h>
+ #include <linux/kfence.h>
++#ifdef CONFIG_PTP
++#include <linux/iee-func.h>
++#endif
+
+ static void *trans_alloc(struct trans_pgd_info *info)
+ {
+@@ -65,10 +68,18 @@ static int copy_pte(struct trans_pgd_info *info, pmd_t *dst_pmdp,
+ pte_t *src_ptep;
+ pte_t *dst_ptep;
+ unsigned long addr = start;
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
+
+ dst_ptep = trans_alloc(info);
+ if (!dst_ptep)
+ return -ENOMEM;
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(dst_ptep));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)dst_ptep);
++ #endif
+ pmd_populate_kernel(NULL, dst_pmdp, dst_ptep);
+ dst_ptep = pte_offset_kernel(dst_pmdp, start);
+
+@@ -87,11 +98,19 @@ static int copy_pmd(struct trans_pgd_info *info, pud_t *dst_pudp,
+ pmd_t *dst_pmdp;
+ unsigned long next;
+ unsigned long addr = start;
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
+
+ if (pud_none(READ_ONCE(*dst_pudp))) {
+ dst_pmdp = trans_alloc(info);
+ if (!dst_pmdp)
+ return -ENOMEM;
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(dst_pmdp));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)dst_pmdp);
++ #endif
+ pud_populate(NULL, dst_pudp, dst_pmdp);
+ }
+ dst_pmdp = pmd_offset(dst_pudp, start);
+@@ -123,11 +142,19 @@ static int copy_pud(struct trans_pgd_info *info, p4d_t *dst_p4dp,
+ pud_t *src_pudp;
+ unsigned long next;
+ unsigned long addr = start;
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
+
+ if (p4d_none(READ_ONCE(*dst_p4dp))) {
+ dst_pudp = trans_alloc(info);
+ if (!dst_pudp)
+ return -ENOMEM;
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(dst_pudp));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)dst_pudp);
++ #endif
+ p4d_populate(NULL, dst_p4dp, dst_pudp);
+ }
+ dst_pudp = pud_offset(dst_p4dp, start);
+@@ -212,6 +239,12 @@ int trans_pgd_create_copy(struct trans_pgd_info *info, pgd_t **dst_pgdp,
+ return -ENOMEM;
+ }
+
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr = __phys_to_iee(__pa(trans_pgd));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)trans_pgd);
++ #endif
++
+ rc = copy_page_tables(info, trans_pgd, start, end);
+ if (!rc)
+ *dst_pgdp = trans_pgd;
+@@ -238,6 +271,9 @@ int trans_pgd_idmap_page(struct trans_pgd_info *info, phys_addr_t *trans_ttbr0,
+ int bits_mapped = PAGE_SHIFT - 4;
+ unsigned long level_mask, prev_level_entry, *levels[4];
+ int this_level, index, level_lsb, level_msb;
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
+
+ dst_addr &= PAGE_MASK;
+ prev_level_entry = pte_val(pfn_pte(pfn, PAGE_KERNEL_ROX));
+@@ -247,12 +283,22 @@ int trans_pgd_idmap_page(struct trans_pgd_info *info, phys_addr_t *trans_ttbr0,
+ if (!levels[this_level])
+ return -ENOMEM;
+
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(levels[this_level]));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)levels[this_level]);
++ #endif
++
+ level_lsb = ARM64_HW_PGTABLE_LEVEL_SHIFT(this_level);
+ level_msb = min(level_lsb + bits_mapped, max_msb);
+ level_mask = GENMASK_ULL(level_msb, level_lsb);
+
+ index = (dst_addr & level_mask) >> level_lsb;
++ #ifdef CONFIG_PTP
++ set_pte((pte_t *)(levels[this_level] + index), __pte(prev_level_entry));
++ #else
+ *(levels[this_level] + index) = prev_level_entry;
++ #endif
+
+ pfn = virt_to_pfn(levels[this_level]);
+ prev_level_entry = pte_val(pfn_pte(pfn,
+diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
+index 83092d93f36a..fb12e7d0660a 100644
+--- a/drivers/firmware/efi/arm-runtime.c
++++ b/drivers/firmware/efi/arm-runtime.c
+@@ -94,7 +94,11 @@ static int __init arm_enable_runtime_services(void)
+ return 0;
+ }
+
++ #ifdef CONFIG_PTP
++ efi_memmap_unmap_after_init();
++ #else
+ efi_memmap_unmap();
++ #endif
+
+ mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
+
+diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
+index a1180461a445..4c64b6f15717 100644
+--- a/drivers/firmware/efi/memmap.c
++++ b/drivers/firmware/efi/memmap.c
+@@ -105,6 +105,26 @@ void __init efi_memmap_unmap(void)
+ clear_bit(EFI_MEMMAP, &efi.flags);
+ }
+
++#ifdef CONFIG_PTP
++void __init efi_memmap_unmap_after_init(void)
++{
++ if (!efi_enabled(EFI_MEMMAP))
++ return;
++
++ if (!(efi.memmap.flags & EFI_MEMMAP_LATE)) {
++ unsigned long size;
++
++ size = efi.memmap.desc_size * efi.memmap.nr_map;
++ early_iounmap_after_init((__force void __iomem *)efi.memmap.map, size);
++ } else {
++ memunmap(efi.memmap.map);
++ }
++
++ efi.memmap.map = NULL;
++ clear_bit(EFI_MEMMAP, &efi.flags);
++}
++#endif
++
+ /**
+ * efi_memmap_init_late - Map efi.memmap with memremap()
+ * @phys_addr: Physical address of the new EFI memory map
+diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
+index a5fbb6ed38ae..81428783b9da 100644
+--- a/drivers/tty/serial/earlycon.c
++++ b/drivers/tty/serial/earlycon.c
+@@ -40,7 +40,11 @@ static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size)
+ {
+ void __iomem *base;
+ #ifdef CONFIG_FIX_EARLYCON_MEM
++ #ifdef CONFIG_PTP
++ __iee_set_fixmap_pre_init(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK, FIXMAP_PAGE_IO);
++ #else
+ set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
++ #endif
+ base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
+ base += paddr & ~PAGE_MASK;
+ #else
+diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
+index 45b42d8f6453..b71072d6957e 100644
+--- a/drivers/usb/early/ehci-dbgp.c
++++ b/drivers/usb/early/ehci-dbgp.c
+@@ -879,7 +879,11 @@ int __init early_dbgp_init(char *s)
+ * FIXME I don't have the bar size so just guess PAGE_SIZE is more
+ * than enough. 1K is the biggest I have seen.
+ */
++ #ifdef CONFIG_PTP
++ __iee_set_fixmap_pre_init(FIX_DBGP_BASE, bar_val & PAGE_MASK, FIXMAP_PAGE_NOCACHE);
++ #else
+ set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
++ #endif
+ ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
+ ehci_bar += bar_val & ~PAGE_MASK;
+ dbgp_printk("ehci_bar: %p\n", ehci_bar);
+diff --git a/fs/coredump.c b/fs/coredump.c
+index 9d235fa14ab9..72be355903ca 100644
+--- a/fs/coredump.c
++++ b/fs/coredump.c
+@@ -53,6 +53,10 @@
+
+ #include <trace/events/sched.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ static bool dump_vma_snapshot(struct coredump_params *cprm);
+ static void free_vma_snapshot(struct coredump_params *cprm);
+
+@@ -564,7 +568,11 @@ void do_coredump(const kernel_siginfo_t *siginfo)
+ */
+ if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) {
+ /* Setuid core dump mode */
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(cred,GLOBAL_ROOT_UID);
++ #else
+ cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */
++ #endif
+ need_suid_safe = true;
+ }
+
+diff --git a/fs/exec.c b/fs/exec.c
+index 04fb89656cc3..3689c5f008ba 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -76,6 +76,14 @@
+
+ #include <trace/events/sched.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
++#ifdef CONFIG_IEE
++#include <asm/iee-token.h>
++#endif
++
+ static int bprm_creds_from_file(struct linux_binprm *bprm);
+
+ int suid_dumpable = 0;
+@@ -1005,6 +1013,10 @@ static int exec_mmap(struct mm_struct *mm)
+ if (!IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM))
+ local_irq_enable();
+ activate_mm(active_mm, mm);
++ #ifdef CONFIG_IEE
++ iee_set_token_mm(tsk, mm);
++ iee_set_token_pgd(tsk, mm->pgd);
++ #endif
+ if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM))
+ local_irq_enable();
+ lru_gen_add_mm(mm);
+@@ -1618,12 +1630,20 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
+
+ if (mode & S_ISUID) {
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
++ #ifdef CONFIG_CREDP
++ iee_set_cred_euid(bprm->cred, vfsuid_into_kuid(vfsuid));
++ #else
+ bprm->cred->euid = vfsuid_into_kuid(vfsuid);
++ #endif
+ }
+
+ if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
++ #ifdef CONFIG_CREDP
++ iee_set_cred_egid(bprm->cred, vfsgid_into_kgid(vfsgid));
++ #else
+ bprm->cred->egid = vfsgid_into_kgid(vfsgid);
++ #endif
+ }
+ }
+
+diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
+index 3e724cb7ef01..e32e136e4271 100644
+--- a/fs/nfs/flexfilelayout/flexfilelayout.c
++++ b/fs/nfs/flexfilelayout/flexfilelayout.c
+@@ -15,6 +15,10 @@
+
+ #include <linux/sunrpc/metrics.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ #include "flexfilelayout.h"
+ #include "../nfs4session.h"
+ #include "../nfs4idmap.h"
+@@ -502,8 +506,13 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
+ rc = -ENOMEM;
+ if (!kcred)
+ goto out_err_free;
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(kcred,uid);
++ iee_set_cred_fsgid(kcred,gid);
++ #else
+ kcred->fsuid = uid;
+ kcred->fsgid = gid;
++ #endif
+ cred = RCU_INITIALIZER(kcred);
+
+ if (lgr->range.iomode == IOMODE_READ)
+diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
+index 25a7c771cfd8..b15ab8e33e0e 100644
+--- a/fs/nfs/nfs4idmap.c
++++ b/fs/nfs/nfs4idmap.c
+@@ -48,6 +48,10 @@
+ #include <linux/module.h>
+ #include <linux/user_namespace.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ #include "internal.h"
+ #include "netns.h"
+ #include "nfs4idmap.h"
+@@ -226,8 +230,13 @@ int nfs_idmap_init(void)
+ goto failed_reg_legacy;
+
+ set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_thread_keyring(cred,keyring);
++ iee_set_cred_jit_keyring(cred,KEY_REQKEY_DEFL_THREAD_KEYRING);
++ #else
+ cred->thread_keyring = keyring;
+ cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
++ #endif
+ id_resolver_cache = cred;
+ return 0;
+
+diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
+index e6beaaf4f170..e89385fd81f1 100644
+--- a/fs/nfsd/auth.c
++++ b/fs/nfsd/auth.c
+@@ -2,6 +2,9 @@
+ /* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */
+
+ #include <linux/sched.h>
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
+ #include "nfsd.h"
+ #include "auth.h"
+
+@@ -32,22 +35,40 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
+ if (!new)
+ return -ENOMEM;
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,rqstp->rq_cred.cr_uid);
++ iee_set_cred_fsgid(new,rqstp->rq_cred.cr_gid);
++ #else
+ new->fsuid = rqstp->rq_cred.cr_uid;
+ new->fsgid = rqstp->rq_cred.cr_gid;
++ #endif
+
+ rqgi = rqstp->rq_cred.cr_group_info;
+
+ if (flags & NFSEXP_ALLSQUASH) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,exp->ex_anon_uid);
++ iee_set_cred_fsgid(new,exp->ex_anon_gid);
++ #else
+ new->fsuid = exp->ex_anon_uid;
+ new->fsgid = exp->ex_anon_gid;
++ #endif
+ gi = groups_alloc(0);
+ if (!gi)
+ goto oom;
+ } else if (flags & NFSEXP_ROOTSQUASH) {
+ if (uid_eq(new->fsuid, GLOBAL_ROOT_UID))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,exp->ex_anon_uid);
++ #else
+ new->fsuid = exp->ex_anon_uid;
++ #endif
+ if (gid_eq(new->fsgid, GLOBAL_ROOT_GID))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsgid(new,exp->ex_anon_gid);
++ #else
+ new->fsgid = exp->ex_anon_gid;
++ #endif
+
+ gi = groups_alloc(rqgi->ngroups);
+ if (!gi)
+@@ -67,18 +88,35 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
+ }
+
+ if (uid_eq(new->fsuid, INVALID_UID))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,exp->ex_anon_uid);
++ #else
+ new->fsuid = exp->ex_anon_uid;
++ #endif
+ if (gid_eq(new->fsgid, INVALID_GID))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsgid(new,exp->ex_anon_gid);
++ #else
+ new->fsgid = exp->ex_anon_gid;
++ #endif
+
+ set_groups(new, gi);
+ put_group_info(gi);
+
+ if (!uid_eq(new->fsuid, GLOBAL_ROOT_UID))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,cap_drop_nfsd_set(new->cap_effective));
++ #else
+ new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
++ #endif
+ else
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,cap_raise_nfsd_set(new->cap_effective,
++ new->cap_permitted));
++ #else
+ new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
+ new->cap_permitted);
++ #endif
+ put_cred(override_creds(new));
+ put_cred(new);
+ return 0;
+diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
+index 4039ffcf90ba..6e0dfa01e01e 100644
+--- a/fs/nfsd/nfs4callback.c
++++ b/fs/nfsd/nfs4callback.c
+@@ -41,6 +41,9 @@
+ #include "trace.h"
+ #include "xdr4cb.h"
+ #include "xdr4.h"
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
+
+ #define NFSDDBG_FACILITY NFSDDBG_PROC
+
+@@ -946,8 +949,13 @@ static const struct cred *get_backchannel_cred(struct nfs4_client *clp, struct r
+ if (!kcred)
+ return NULL;
+
+- kcred->fsuid = ses->se_cb_sec.uid;
+- kcred->fsgid = ses->se_cb_sec.gid;
++ #ifdef CONFIG_CREDP
++ iee_set_cred_uid(kcred,ses->se_cb_sec.uid);
++ iee_set_cred_gid(kcred,ses->se_cb_sec.gid);
++ #else
++ kcred->uid = ses->se_cb_sec.uid;
++ kcred->gid = ses->se_cb_sec.gid;
++ #endif
+ return kcred;
+ }
+ }
+diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
+index 3509e73abe1f..798fe0352841 100644
+--- a/fs/nfsd/nfs4recover.c
++++ b/fs/nfsd/nfs4recover.c
+@@ -44,6 +44,10 @@
+ #include <linux/sunrpc/clnt.h>
+ #include <linux/nfsd/cld.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ #include "nfsd.h"
+ #include "state.h"
+ #include "vfs.h"
+@@ -78,8 +82,13 @@ nfs4_save_creds(const struct cred **original_creds)
+ if (!new)
+ return -ENOMEM;
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,GLOBAL_ROOT_UID);
++ iee_set_cred_fsgid(new,GLOBAL_ROOT_GID);
++ #else
+ new->fsuid = GLOBAL_ROOT_UID;
+ new->fsgid = GLOBAL_ROOT_GID;
++ #endif
+ *original_creds = override_creds(new);
+ put_cred(new);
+ return 0;
+diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
+index 355bf0db3235..6cb276dde4e9 100644
+--- a/fs/nfsd/nfsfh.c
++++ b/fs/nfsd/nfsfh.c
+@@ -16,6 +16,10 @@
+ #include "auth.h"
+ #include "trace.h"
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ #define NFSDDBG_FACILITY NFSDDBG_FH
+
+
+@@ -223,9 +227,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
+ error = nfserrno(-ENOMEM);
+ goto out;
+ }
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,cap_raise_nfsd_set(new->cap_effective,
++ new->cap_permitted));
++ #else
+ new->cap_effective =
+ cap_raise_nfsd_set(new->cap_effective,
+ new->cap_permitted);
++ #endif
+ put_cred(override_creds(new));
+ put_cred(new);
+ } else {
+diff --git a/fs/open.c b/fs/open.c
+index 54723fceb776..d83901dc50ff 100644
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -35,6 +35,11 @@
+ #include <linux/mnt_idmapping.h>
+ #include <linux/filelock.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
++
+ #include "internal.h"
+
+ int do_truncate(struct mnt_idmap *idmap, struct dentry *dentry,
+@@ -414,17 +419,34 @@ static const struct cred *access_override_creds(void)
+ * routine.
+ */
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(override_cred,override_cred->uid);
++ iee_set_cred_fsgid(override_cred,override_cred->gid);
++ #else
+ override_cred->fsuid = override_cred->uid;
+ override_cred->fsgid = override_cred->gid;
++ #endif
+
+ if (!issecure(SECURE_NO_SETUID_FIXUP)) {
+ /* Clear the capabilities if we switch to a non-root user */
+ kuid_t root_uid = make_kuid(override_cred->user_ns, 0);
+ if (!uid_eq(override_cred->uid, root_uid))
++ #ifdef CONFIG_CREDP
++ do {
++ kernel_cap_t tmp_cap = override_cred->cap_effective;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_effective(override_cred, tmp_cap);
++ } while (0);
++ #else
+ cap_clear(override_cred->cap_effective);
++ #endif
+ else
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(override_cred,override_cred->cap_permitted);
++ #else
+ override_cred->cap_effective =
+ override_cred->cap_permitted;
++ #endif
+ }
+
+ /*
+@@ -444,7 +466,11 @@ static const struct cred *access_override_creds(void)
+ * expecting RCU freeing. But normal thread-synchronous
+ * cred accesses will keep things non-RCY.
+ */
++ #ifdef CONFIG_CREDP
++ iee_set_cred_non_rcu(override_cred,1);
++ #else
+ override_cred->non_rcu = 1;
++ #endif
+
+ old_cred = override_creds(override_cred);
+
+diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
+index 033fc0458a3d..2afa31ead2b5 100644
+--- a/fs/overlayfs/dir.c
++++ b/fs/overlayfs/dir.c
+@@ -16,6 +16,10 @@
+ #include <linux/ratelimit.h>
+ #include "overlayfs.h"
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ static unsigned short ovl_redirect_max = 256;
+ module_param_named(redirect_max, ovl_redirect_max, ushort, 0644);
+ MODULE_PARM_DESC(redirect_max,
+@@ -593,8 +597,13 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
+ * create a new inode, so just use the ovl mounter's
+ * fs{u,g}id.
+ */
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(override_cred,inode->i_uid);
++ iee_set_cred_fsgid(override_cred,inode->i_gid);
++ #else
+ override_cred->fsuid = inode->i_uid;
+ override_cred->fsgid = inode->i_gid;
++ #endif
+ err = security_dentry_create_files_as(dentry,
+ attr->mode, &dentry->d_name, old_cred,
+ override_cred);
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+index 2c056d737c27..9ede99ddb04b 100644
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -21,6 +21,10 @@
+ #include "overlayfs.h"
+ #include "params.h"
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
+ MODULE_DESCRIPTION("Overlay filesystem");
+ MODULE_LICENSE("GPL");
+@@ -1485,7 +1489,15 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
+ sb->s_export_op = &ovl_export_fid_operations;
+
+ /* Never override disk quota limits or use reserved space */
++ #ifdef CONFIG_CREDP
++ {
++ kernel_cap_t tmp = cred->cap_effective;
++ cap_lower(tmp, CAP_SYS_RESOURCE);
++ iee_set_cred_cap_effective(cred, tmp);
++ }
++ #else
+ cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
++ #endif
+
+ sb->s_magic = OVERLAYFS_SUPER_MAGIC;
+ sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers :
+diff --git a/fs/smb/client/cifs_spnego.c b/fs/smb/client/cifs_spnego.c
+index af7849e5974f..4ac2f0e65955 100644
+--- a/fs/smb/client/cifs_spnego.c
++++ b/fs/smb/client/cifs_spnego.c
+@@ -18,6 +18,10 @@
+ #include "cifs_spnego.h"
+ #include "cifs_debug.h"
+ #include "cifsproto.h"
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ static const struct cred *spnego_cred;
+
+ /* create a new cifs key */
+@@ -212,8 +216,13 @@ init_cifs_spnego(void)
+ * the results it looks up
+ */
+ set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_thread_keyring(cred,keyring);
++ iee_set_cred_jit_keyring(cred,KEY_REQKEY_DEFL_THREAD_KEYRING);
++ #else
+ cred->thread_keyring = keyring;
+ cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
++ #endif
+ spnego_cred = cred;
+
+ cifs_dbg(FYI, "cifs spnego keyring: %d\n", key_serial(keyring));
+diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
+index f5b6df82e857..9f0ff045836d 100644
+--- a/fs/smb/client/cifsacl.c
++++ b/fs/smb/client/cifsacl.c
+@@ -26,6 +26,10 @@
+ #include "cifs_fs_sb.h"
+ #include "cifs_unicode.h"
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ /* security id for everyone/world system group */
+ static const struct cifs_sid sid_everyone = {
+ 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
+@@ -491,8 +495,13 @@ init_cifs_idmap(void)
+ /* instruct request_key() to use this special keyring as a cache for
+ * the results it looks up */
+ set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_thread_keyring(cred,keyring);
++ iee_set_cred_jit_keyring(cred,KEY_REQKEY_DEFL_THREAD_KEYRING);
++ #else
+ cred->thread_keyring = keyring;
+ cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
++ #endif
+ root_cred = cred;
+
+ cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
+diff --git a/include/asm-generic/early_ioremap.h b/include/asm-generic/early_ioremap.h
+index 9d0479f50f97..f501e0f965f8 100644
+--- a/include/asm-generic/early_ioremap.h
++++ b/include/asm-generic/early_ioremap.h
+@@ -17,6 +17,9 @@ extern void *early_memremap_ro(resource_size_t phys_addr,
+ extern void *early_memremap_prot(resource_size_t phys_addr,
+ unsigned long size, unsigned long prot_val);
+ extern void early_iounmap(void __iomem *addr, unsigned long size);
++#ifdef CONFIG_PTP
++extern void early_iounmap_after_init(void __iomem *addr, unsigned long size);
++#endif
+ extern void early_memunmap(void *addr, unsigned long size);
+
+ #if defined(CONFIG_GENERIC_EARLY_IOREMAP) && defined(CONFIG_MMU)
+diff --git a/include/asm-generic/fixmap.h b/include/asm-generic/fixmap.h
+index 8cc7b09c1bc7..83158589a545 100644
+--- a/include/asm-generic/fixmap.h
++++ b/include/asm-generic/fixmap.h
+@@ -70,6 +70,24 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
+ __set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR)
+ #endif
+
++#ifdef CONFIG_PTP
++#ifndef clear_fixmap_init
++#define clear_fixmap_init(idx) \
++ __iee_set_fixmap_pre_init(idx, 0, FIXMAP_PAGE_CLEAR)
++#endif
++
++#define __iee_set_fixmap_offset_pre_init(idx, phys, flags) \
++({ \
++ unsigned long ________addr; \
++ __iee_set_fixmap_pre_init(idx, phys, flags); \
++ ________addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1)); \
++ ________addr; \
++})
++
++#define iee_set_fixmap_offset_pre_init(idx, phys) \
++ __iee_set_fixmap_offset_pre_init(idx, phys, FIXMAP_PAGE_NORMAL)
++#endif
++
+ /* Return a pointer with offset calculated */
+ #define __set_fixmap_offset(idx, phys, flags) \
+ ({ \
+diff --git a/include/asm-generic/pgalloc.h b/include/asm-generic/pgalloc.h
+index c75d4a753849..506ff9662e02 100644
+--- a/include/asm-generic/pgalloc.h
++++ b/include/asm-generic/pgalloc.h
+@@ -7,6 +7,10 @@
+ #define GFP_PGTABLE_KERNEL (GFP_KERNEL | __GFP_ZERO)
+ #define GFP_PGTABLE_USER (GFP_PGTABLE_KERNEL | __GFP_ACCOUNT)
+
++#ifdef CONFIG_PTP
++#include <linux/iee-func.h>
++#endif
++
+ /**
+ * __pte_alloc_one_kernel - allocate memory for a PTE-level kernel page table
+ * @mm: the mm_struct of the current context
+@@ -23,6 +27,13 @@ static inline pte_t *__pte_alloc_one_kernel(struct mm_struct *mm)
+
+ if (!ptdesc)
+ return NULL;
++
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr = __phys_to_iee(__pa(ptdesc_address(ptdesc)));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)ptdesc_address(ptdesc));
++ #endif
++
+ return ptdesc_address(ptdesc);
+ }
+
+@@ -46,6 +57,11 @@ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
+ */
+ static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+ {
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr = __phys_to_iee(__pa(pte));
++ set_iee_page_invalid(iee_addr);
++ iee_set_logical_mem_rw((unsigned long)pte);
++ #endif
+ pagetable_free(virt_to_ptdesc(pte));
+ }
+
+@@ -73,6 +89,13 @@ static inline pgtable_t __pte_alloc_one(struct mm_struct *mm, gfp_t gfp)
+ return NULL;
+ }
+
++ #ifdef CONFIG_PTP
++ pte_t *pte = (pte_t *)page_address(ptdesc_page(ptdesc));
++ unsigned long iee_addr = __phys_to_iee(__pa(pte));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)pte);
++ #endif
++
+ return ptdesc_page(ptdesc);
+ }
+
+@@ -103,9 +126,20 @@ static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
+ */
+ static inline void pte_free(struct mm_struct *mm, struct page *pte_page)
+ {
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
++
+ struct ptdesc *ptdesc = page_ptdesc(pte_page);
+
+ pagetable_pte_dtor(ptdesc);
++
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(page_address(pte_page)));
++ set_iee_page_invalid(iee_addr);
++ iee_set_logical_mem_rw((unsigned long)page_address(pte_page));
++ #endif
++
+ pagetable_free(ptdesc);
+ }
+
+@@ -145,10 +179,21 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+ #ifndef __HAVE_ARCH_PMD_FREE
+ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+ {
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
++
+ struct ptdesc *ptdesc = virt_to_ptdesc(pmd);
+
+ BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
+ pagetable_pmd_dtor(ptdesc);
++
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(pmd));
++ set_iee_page_invalid(iee_addr);
++ iee_set_logical_mem_rw((unsigned long)pmd);
++ #endif
++
+ pagetable_free(ptdesc);
+ }
+ #endif
+@@ -190,7 +235,16 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
+
+ static inline void __pud_free(struct mm_struct *mm, pud_t *pud)
+ {
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
++
+ BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(pud));
++ set_iee_page_invalid(iee_addr);
++ iee_set_logical_mem_rw((unsigned long)pud);
++ #endif
+ pagetable_free(virt_to_ptdesc(pud));
+ }
+
+diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
+index 200853042fc7..9d733afced53 100644
+--- a/include/asm-generic/vmlinux.lds.h
++++ b/include/asm-generic/vmlinux.lds.h
+@@ -346,6 +346,17 @@
+ KEEP(*(.dtb.init.rodata)) \
+ __dtb_end = .;
+
++#ifdef CONFIG_KOI
++#define KOI_DATA() \
++ . = ALIGN(PAGE_SIZE); \
++ __koi_data_start = .; \
++ *(.data..koi) \
++ . = ALIGN(PAGE_SIZE); \
++ __koi_data_end = .;
++#else
++#define KOI_DATA()
++#endif
++
+ /*
+ * .data section
+ */
+@@ -370,8 +381,8 @@
+ BRANCH_PROFILE() \
+ TRACE_PRINTKS() \
+ BPF_RAW_TP() \
+- TRACEPOINT_STR()
+-
++ TRACEPOINT_STR() \
++ KOI_DATA()
+ /*
+ * Data section helpers
+ */
+@@ -1093,6 +1104,14 @@
+ * They will fit only a subset of the architectures
+ */
+
++#ifdef CONFIG_CREDP
++ #define CRED_DATA \
++ . = ALIGN(PAGE_SIZE); \
++ *(.iee.cred) \
++ . = ALIGN(PAGE_SIZE);
++#else
++ #define CRED_DATA
++#endif
+
+ /*
+ * Writeable data.
+@@ -1110,6 +1129,7 @@
+ . = ALIGN(PAGE_SIZE); \
+ .data : AT(ADDR(.data) - LOAD_OFFSET) { \
+ INIT_TASK_DATA(inittask) \
++ CRED_DATA \
+ NOSAVE_DATA \
+ PAGE_ALIGNED_DATA(pagealigned) \
+ CACHELINE_ALIGNED_DATA(cacheline) \
+diff --git a/include/linux/cred.h b/include/linux/cred.h
+index e01c6d094a30..cceb4842b619 100644
+--- a/include/linux/cred.h
++++ b/include/linux/cred.h
+@@ -18,6 +18,10 @@
+ #include <linux/sched/user.h>
+ #include <linux/kabi.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-def.h>
++#endif
++
+ struct cred;
+ struct inode;
+
+@@ -153,6 +157,22 @@ struct cred {
+ KABI_RESERVE(4)
+ } __randomize_layout;
+
++#ifdef CONFIG_CREDP
++extern unsigned long long iee_rw_gate(int flag, ...);
++static void iee_set_cred_non_rcu(struct cred *cred, int non_rcu)
++{
++ iee_rw_gate(IEE_OP_SET_CRED_NON_RCU,cred,non_rcu);
++ *(int *)(&(((struct rcu_head *)(cred->rcu.func))->next)) = non_rcu;
++}
++
++static bool noinline iee_set_cred_atomic_op_usage(struct cred *cred, int flag, int nr)
++{
++ bool ret;
++ ret = iee_rw_gate(IEE_OP_SET_CRED_ATOP_USAGE,cred,flag,nr);
++ return ret;
++}
++#endif
++
+ extern void __put_cred(struct cred *);
+ extern void exit_creds(struct task_struct *);
+ extern int copy_creds(struct task_struct *, unsigned long);
+@@ -189,7 +209,11 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
+ */
+ static inline struct cred *get_new_cred_many(struct cred *cred, int nr)
+ {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_atomic_op_usage(cred, AT_ADD, nr);
++ #else
+ atomic_long_add(nr, &cred->usage);
++ #endif
+ return cred;
+ }
+
+@@ -202,7 +226,7 @@ static inline struct cred *get_new_cred_many(struct cred *cred, int nr)
+ */
+ static inline struct cred *get_new_cred(struct cred *cred)
+ {
+- return get_new_cred_many(cred, 1);
++ return get_new_cred_many(cred, 1); // XXXzgc atomic_inc -> get_new_cred_many
+ }
+
+ /**
+@@ -224,7 +248,11 @@ static inline const struct cred *get_cred_many(const struct cred *cred, int nr)
+ struct cred *nonconst_cred = (struct cred *) cred;
+ if (!cred)
+ return cred;
++ #ifdef CONFIG_CREDP
++ iee_set_cred_non_rcu(nonconst_cred,0);
++ #else
+ nonconst_cred->non_rcu = 0;
++ #endif
+ return get_new_cred_many(nonconst_cred, nr);
+ }
+
+@@ -247,9 +275,19 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred)
+ struct cred *nonconst_cred = (struct cred *) cred;
+ if (!cred)
+ return NULL;
++ #ifdef CONFIG_CREDP
++ if (!iee_set_cred_atomic_op_usage(nonconst_cred,AT_INC_NOT_ZERO,0))
++ return NULL;
++ #else
+ if (!atomic_long_inc_not_zero(&nonconst_cred->usage))
+ return NULL;
++ #endif
++
++ #ifdef CONFIG_CREDP
++ iee_set_cred_non_rcu(nonconst_cred,0);
++ #else
+ nonconst_cred->non_rcu = 0;
++ #endif
+ return cred;
+ }
+
+@@ -270,8 +308,13 @@ static inline void put_cred_many(const struct cred *_cred, int nr)
+ struct cred *cred = (struct cred *) _cred;
+
+ if (cred) {
++ #ifdef CONFIG_CREDP
++ if (iee_set_cred_atomic_op_usage(cred,AT_SUB_AND_TEST,nr))
++ __put_cred(cred);
++ #else
+ if (atomic_long_sub_and_test(nr, &cred->usage))
+ __put_cred(cred);
++ #endif
+ }
+ }
+
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 9ed79128458c..970cc4f7068b 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -740,6 +740,15 @@ extern int __init __efi_memmap_init(struct efi_memory_map_data *data);
+ extern int __init efi_memmap_init_early(struct efi_memory_map_data *data);
+ extern int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size);
+ extern void __init efi_memmap_unmap(void);
++#ifdef CONFIG_PTP
++extern void __init efi_memmap_unmap_after_init(void);
++#endif
++extern int __init efi_memmap_install(struct efi_memory_map_data *data);
++extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
++ struct range *range);
++extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
++ void *buf, struct efi_mem_range *mem);
++extern void __init efi_print_memmap(void);
+
+ #ifdef CONFIG_EFI_ESRT
+ extern void __init efi_esrt_init(void);
+diff --git a/include/linux/iee-func.h b/include/linux/iee-func.h
+new file mode 100644
+index 000000000000..79171de67c2a
+--- /dev/null
++++ b/include/linux/iee-func.h
+@@ -0,0 +1,27 @@
++#ifndef _LINUX_IEE_FUNC_H
++#define _LINUX_IEE_FUNC_H
++
++#ifdef CONFIG_IEE
++// Declare the __entry_task.
++__attribute__((aligned(PAGE_SIZE))) DECLARE_PER_CPU(struct task_struct *[PAGE_SIZE/sizeof(struct task_struct *)], __entry_task);
++
++extern unsigned long long iee_rw_gate(int flag, ...);
++extern u32 get_cpu_asid_bits(void);
++extern unsigned long arm64_mm_context_get(struct mm_struct *mm);
++extern void set_iee_page_valid(unsigned long addr);
++extern void set_iee_page_invalid(unsigned long addr);
++extern void iee_set_logical_mem_ro(unsigned long addr);
++extern void iee_set_logical_mem_rw(unsigned long addr);
++extern void iee_set_token_mm(struct task_struct *tsk, struct mm_struct *mm);
++extern void iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd);
++extern void iee_init_token(struct task_struct *tsk, void *kernel_stack, void *iee_stack);
++extern void iee_free_token(struct task_struct *tsk);
++extern unsigned long iee_read_token_stack(struct task_struct *tsk);
++extern void iee_set_token_page_valid(void *token, void *new);
++extern void iee_set_token_page_invalid(void *token);
++extern void iee_set_kernel_ppage(unsigned long addr);
++extern void iee_set_kernel_upage(unsigned long addr);
++extern void iee_write_in_byte(void *ptr, u64 data, int length);
++#endif
++
++#endif
+\ No newline at end of file
+diff --git a/include/linux/module.h b/include/linux/module.h
+index 4db2878d9e42..ef8d51994017 100644
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -606,6 +606,7 @@ struct module {
+ KABI_RESERVE(2)
+ KABI_RESERVE(3)
+ KABI_RESERVE(4)
++
+ } ____cacheline_aligned __randomize_layout;
+ #ifndef MODULE_ARCH_INIT
+ #define MODULE_ARCH_INIT {}
+diff --git a/include/linux/sched.h b/include/linux/sched.h
+index f40411aa7b70..297becfbc8e3 100644
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -773,6 +773,24 @@ struct task_struct_resvd {
+ struct task_struct *task;
+ };
+
++#if defined(CONFIG_IEE) || defined(CONFIG_KOI)
++struct task_token {
++#ifdef CONFIG_IEE
++ struct mm_struct *mm; /* VA */
++ pgd_t *pgd; /* Logical VA */
++ void *iee_stack; /* VA */
++ bool valid;
++ void *kernel_stack; /* VA */
++#endif
++#ifdef CONFIG_KOI
++ void *koi_kernel_stack; /* VA */
++ void *koi_stack; /* VA */
++ void *koi_stack_base; /* VA */
++ unsigned long current_ttbr1;
++#endif
++};
++#endif
++
+ struct task_struct {
+ #ifdef CONFIG_THREAD_INFO_IN_TASK
+ /*
+@@ -795,6 +813,7 @@ struct task_struct {
+ randomized_struct_fields_start
+
+ void *stack;
++
+ refcount_t usage;
+ /* Per task flags (PF_*), defined further below: */
+ unsigned int flags;
+diff --git a/init/main.c b/init/main.c
+index 803332dd3d90..0f8d6e2744c2 100644
+--- a/init/main.c
++++ b/init/main.c
+@@ -102,6 +102,12 @@
+ #include <linux/randomize_kstack.h>
+ #include <net/net_namespace.h>
+
++#ifdef CONFIG_IEE
++#include <linux/iee-func.h>
++#include <asm/iee-si.h>
++#include <linux/stop_machine.h>
++#endif
++
+ #include <asm/io.h>
+ #include <asm/setup.h>
+ #include <asm/sections.h>
+@@ -112,6 +118,10 @@
+
+ #include <kunit/test.h>
+
++#ifdef CONFIG_PTP
++extern void *bm_pte_addr;
++#endif
++
+ static int kernel_init(void *);
+
+ /*
+@@ -880,6 +890,9 @@ void start_kernel(void)
+ {
+ char *command_line;
+ char *after_dashes;
++ #ifdef CONFIG_IEE
++ unsigned int cpu;
++ #endif
+
+ set_task_stack_end_magic(&init_task);
+ smp_setup_processor_id();
+@@ -904,6 +917,16 @@ void start_kernel(void)
+ setup_command_line(command_line);
+ setup_nr_cpu_ids();
+ setup_per_cpu_areas();
++ #ifdef CONFIG_IEE
++ for_each_possible_cpu(cpu)
++ {
++ // Map the __entry_task to IEE.
++ set_iee_page_valid((unsigned long)__phys_to_iee(__pa(SHIFT_PERCPU_PTR(__entry_task,__per_cpu_offset[cpu]))));
++ // Set the __entry_task of cpu 0 readonly in lm.
++ if(cpu == smp_processor_id())
++ iee_set_logical_mem_ro((unsigned long)SHIFT_PERCPU_PTR(__entry_task,__per_cpu_offset[cpu]));
++ }
++ #endif
+ smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
+ boot_cpu_hotplug_init();
+
+@@ -1446,6 +1469,9 @@ static int __ref kernel_init(void *unused)
+ wait_for_completion(&kthreadd_done);
+
+ kernel_init_freeable();
++ #ifdef CONFIG_PTP
++ iee_set_logical_mem_ro((unsigned long)bm_pte_addr);
++ #endif
+ /* need to finish all async __init code before freeing the memory */
+ async_synchronize_full();
+
+@@ -1462,7 +1488,7 @@ static int __ref kernel_init(void *unused)
+ * to finalize PTI.
+ */
+ pti_finalize();
+-
++
+ system_state = SYSTEM_RUNNING;
+ numa_default_policy();
+
+diff --git a/kernel/cred.c b/kernel/cred.c
+index c033a201c808..2e44530976d5 100644
+--- a/kernel/cred.c
++++ b/kernel/cred.c
+@@ -20,6 +20,11 @@
+ #include <linux/cn_proc.h>
+ #include <linux/uidgid.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#include <linux/iee-func.h>
++#endif
++
+ #if 0
+ #define kdebug(FMT, ...) \
+ printk("[%-5.5s%5u] " FMT "\n", \
+@@ -34,6 +39,9 @@ do { \
+ #endif
+
+ static struct kmem_cache *cred_jar;
++#ifdef CONFIG_CREDP
++static struct kmem_cache *rcu_jar;
++#endif
+
+ /* init to 2 - one for init_task, one to ensure it is never freed */
+ static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) };
+@@ -41,6 +49,32 @@ static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) };
+ /*
+ * The initial credentials for the initial task
+ */
++#ifdef CONFIG_CREDP
++struct cred init_cred __section(".iee.cred") = {
++ .usage = ATOMIC_INIT(4),
++#ifdef CONFIG_DEBUG_CREDENTIALS
++ .subscribers = ATOMIC_INIT(2),
++ .magic = CRED_MAGIC,
++#endif
++ .uid = GLOBAL_ROOT_UID,
++ .gid = GLOBAL_ROOT_GID,
++ .suid = GLOBAL_ROOT_UID,
++ .sgid = GLOBAL_ROOT_GID,
++ .euid = GLOBAL_ROOT_UID,
++ .egid = GLOBAL_ROOT_GID,
++ .fsuid = GLOBAL_ROOT_UID,
++ .fsgid = GLOBAL_ROOT_GID,
++ .securebits = SECUREBITS_DEFAULT,
++ .cap_inheritable = CAP_EMPTY_SET,
++ .cap_permitted = CAP_FULL_SET,
++ .cap_effective = CAP_FULL_SET,
++ .cap_bset = CAP_FULL_SET,
++ .user = INIT_USER,
++ .user_ns = &init_user_ns,
++ .group_info = &init_groups,
++ .ucounts = &init_ucounts,
++};
++#else
+ struct cred init_cred = {
+ .usage = ATOMIC_INIT(4),
+ .uid = GLOBAL_ROOT_UID,
+@@ -61,13 +95,43 @@ struct cred init_cred = {
+ .group_info = &init_groups,
+ .ucounts = &init_ucounts,
+ };
++#endif
++
++static inline void set_cred_subscribers(struct cred *cred, int n)
++{
++#ifdef CONFIG_DEBUG_CREDENTIALS
++ atomic_set(&cred->subscribers, n);
++#endif
++}
++
++static inline int read_cred_subscribers(const struct cred *cred)
++{
++#ifdef CONFIG_DEBUG_CREDENTIALS
++ return atomic_read(&cred->subscribers);
++#else
++ return 0;
++#endif
++}
++
++static inline void alter_cred_subscribers(const struct cred *_cred, int n)
++{
++#ifdef CONFIG_DEBUG_CREDENTIALS
++ struct cred *cred = (struct cred *) _cred;
++
++ atomic_add(n, &cred->subscribers);
++#endif
++}
+
+ /*
+ * The RCU callback to actually dispose of a set of credentials
+ */
+ static void put_cred_rcu(struct rcu_head *rcu)
+ {
++ #ifdef CONFIG_CREDP
++ struct cred *cred = *(struct cred **)(rcu + 1);
++ #else
+ struct cred *cred = container_of(rcu, struct cred, rcu);
++ #endif
+
+ kdebug("put_cred_rcu(%p)", cred);
+
+@@ -86,6 +150,9 @@ static void put_cred_rcu(struct rcu_head *rcu)
+ if (cred->ucounts)
+ put_ucounts(cred->ucounts);
+ put_user_ns(cred->user_ns);
++ #ifdef CONFIG_CREDP
++ kmem_cache_free(rcu_jar, (struct rcu_head *)(cred->rcu.func));
++ #endif
+ kmem_cache_free(cred_jar, cred);
+ }
+
+@@ -104,10 +171,22 @@ void __put_cred(struct cred *cred)
+ BUG_ON(cred == current->cred);
+ BUG_ON(cred == current->real_cred);
+
++ #ifdef CONFIG_CREDP
++ if (*(int *)(&(((struct rcu_head *)(cred->rcu.func))->next)))
++ #else
+ if (cred->non_rcu)
++ #endif
++ #ifdef CONFIG_CREDP
++ put_cred_rcu((struct rcu_head *)(cred->rcu.func));
++ #else
+ put_cred_rcu(&cred->rcu);
++ #endif
+ else
++ #ifdef CONFIG_CREDP
++ call_rcu((struct rcu_head *)(cred->rcu.func), put_cred_rcu);
++ #else
+ call_rcu(&cred->rcu, put_cred_rcu);
++ #endif
+ }
+ EXPORT_SYMBOL(__put_cred);
+
+@@ -178,7 +257,18 @@ struct cred *cred_alloc_blank(void)
+ if (!new)
+ return NULL;
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_rcu(new,kmem_cache_zalloc(rcu_jar, GFP_KERNEL));
++ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new;
++ iee_set_cred_atomic_set_usage(new,1);
++ #else
+ atomic_long_set(&new->usage, 1);
++ #endif
++
++ #ifdef CONFIG_DEBUG_CREDENTIALS
++ new->magic = CRED_MAGIC;
++ #endif
++
+ if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0)
+ goto error;
+
+@@ -213,13 +303,25 @@ struct cred *prepare_creds(void)
+ if (!new)
+ return NULL;
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_rcu(new,kmem_cache_alloc(rcu_jar, GFP_KERNEL));
++ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new;
++ #endif
++
+ kdebug("prepare_creds() alloc %p", new);
+
+ old = task->cred;
++ #ifdef CONFIG_CREDP
++ iee_copy_cred(old,new);
++
++ iee_set_cred_non_rcu(new,0);
++ iee_set_cred_atomic_set_usage(new,1);
++ #else
+ memcpy(new, old, sizeof(struct cred));
+
+ new->non_rcu = 0;
+ atomic_long_set(&new->usage, 1);
++ #endif
+ get_group_info(new->group_info);
+ get_uid(new->user);
+ get_user_ns(new->user_ns);
+@@ -232,10 +334,18 @@ struct cred *prepare_creds(void)
+ #endif
+
+ #ifdef CONFIG_SECURITY
++#ifdef CONFIG_CREDP
++ iee_set_cred_security(new,NULL);
++#else
+ new->security = NULL;
++#endif
+ #endif
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_ucounts(new, get_ucounts(new->ucounts));
++ #else
+ new->ucounts = get_ucounts(new->ucounts);
++ #endif
+ if (!new->ucounts)
+ goto error;
+
+@@ -265,15 +375,30 @@ struct cred *prepare_exec_creds(void)
+ #ifdef CONFIG_KEYS
+ /* newly exec'd tasks don't get a thread keyring */
+ key_put(new->thread_keyring);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_thread_keyring(new,NULL);
++ #else
+ new->thread_keyring = NULL;
++ #endif
+
+ /* inherit the session keyring; new process keyring */
+ key_put(new->process_keyring);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_process_keyring(new,NULL);
++ #else
+ new->process_keyring = NULL;
++ #endif
+ #endif
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,new->euid);
++ iee_set_cred_suid(new,new->euid);
++ iee_set_cred_fsgid(new,new->egid);
++ iee_set_cred_sgid(new,new->egid);
++ #else
+ new->suid = new->fsuid = new->euid;
+ new->sgid = new->fsgid = new->egid;
++ #endif
+
+ return new;
+ }
+@@ -327,7 +452,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
+ * had one */
+ if (new->thread_keyring) {
+ key_put(new->thread_keyring);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_thread_keyring(new,NULL);
++ #else
+ new->thread_keyring = NULL;
++ #endif
+ if (clone_flags & CLONE_THREAD)
+ install_thread_keyring_to_cred(new);
+ }
+@@ -337,7 +466,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
+ */
+ if (!(clone_flags & CLONE_THREAD)) {
+ key_put(new->process_keyring);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_process_keyring(new,NULL);
++ #else
+ new->process_keyring = NULL;
++ #endif
+ }
+ #endif
+
+@@ -594,7 +727,11 @@ int set_cred_ucounts(struct cred *new)
+ if (!(new_ucounts = alloc_ucounts(new->user_ns, new->uid)))
+ return -EAGAIN;
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_ucounts(new, new_ucounts);
++ #else
+ new->ucounts = new_ucounts;
++ #endif
+ put_ucounts(old_ucounts);
+
+ return 0;
+@@ -606,8 +743,21 @@ int set_cred_ucounts(struct cred *new)
+ void __init cred_init(void)
+ {
+ /* allocate a slab in which we can store credentials */
++ #ifdef CONFIG_CREDP
+ cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0,
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT|SLAB_RED_ZONE, NULL);
++ rcu_jar = kmem_cache_create("rcu_jar", sizeof(struct rcu_head) + sizeof(struct cred *), 0,
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
++ // Map init_cred
++ *((struct rcu_head **)(&(init_cred.rcu.func))) = (struct rcu_head *)kmem_cache_zalloc(rcu_jar, GFP_KERNEL);
++ *(struct cred **)(((struct rcu_head *)(init_cred.rcu.func)) + 1) = &init_cred;
++ set_iee_page_valid(__phys_to_iee(__pa_symbol(&init_cred)));
++ iee_set_logical_mem_ro((unsigned long)&init_cred);
++ iee_set_logical_mem_ro((unsigned long)__va(__pa_symbol(&init_cred)));
++ #else
++ cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0,
++ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL);
++ #endif
+ }
+
+ /**
+@@ -638,29 +788,56 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
+ if (!new)
+ return NULL;
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_rcu(new,kmem_cache_alloc(rcu_jar, GFP_KERNEL));
++ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new;
++ #endif
++
+ kdebug("prepare_kernel_cred() alloc %p", new);
+
+ old = get_task_cred(daemon);
+
++ #ifdef CONFIG_CREDP
++ iee_copy_cred(old,new);
++ iee_set_cred_non_rcu(new,0);
++ iee_set_cred_atomic_set_usage(new,1);
++ #else
+ *new = *old;
+ new->non_rcu = 0;
+ atomic_long_set(&new->usage, 1);
++ #endif
+ get_uid(new->user);
+ get_user_ns(new->user_ns);
+ get_group_info(new->group_info);
+
+ #ifdef CONFIG_KEYS
++#ifdef CONFIG_CREDP
++ iee_set_cred_session_keyring(new,NULL);
++ iee_set_cred_process_keyring(new,NULL);
++ iee_set_cred_thread_keyring(new,NULL);
++ iee_set_cred_request_key_auth(new,NULL);
++ iee_set_cred_jit_keyring(new,KEY_REQKEY_DEFL_THREAD_KEYRING);
++#else
+ new->session_keyring = NULL;
+ new->process_keyring = NULL;
+ new->thread_keyring = NULL;
+ new->request_key_auth = NULL;
+ new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
+ #endif
++#endif
+
+ #ifdef CONFIG_SECURITY
++#ifdef CONFIG_CREDP
++ iee_set_cred_security(new,NULL);
++#else
+ new->security = NULL;
+ #endif
++#endif
++ #ifdef CONFIG_CREDP
++ iee_set_cred_ucounts(new, get_ucounts(new->ucounts));
++ #else
+ new->ucounts = get_ucounts(new->ucounts);
++ #endif
+ if (!new->ucounts)
+ goto error;
+
+@@ -727,8 +904,13 @@ int set_create_files_as(struct cred *new, struct inode *inode)
+ {
+ if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+ return -EINVAL;
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,inode->i_uid);
++ iee_set_cred_fsgid(new,inode->i_gid);
++ #else
+ new->fsuid = inode->i_uid;
+ new->fsgid = inode->i_gid;
++ #endif
+ return security_kernel_create_files_as(new, inode);
+ }
+ EXPORT_SYMBOL(set_create_files_as);
+diff --git a/kernel/exit.c b/kernel/exit.c
+index 21a59a6e1f2e..d21a109f0497 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -74,6 +74,10 @@
+ #include <asm/unistd.h>
+ #include <asm/mmu_context.h>
+
++#ifdef CONFIG_IEE
++#include <linux/iee-func.h>
++#endif
++
+ /*
+ * The default value should be high enough to not crash a system that randomly
+ * crashes its kernel from time to time, but low enough to at least not permit
+@@ -558,6 +562,10 @@ static void exit_mm(void)
+ smp_mb__after_spinlock();
+ local_irq_disable();
+ current->mm = NULL;
++ #ifdef CONFIG_IEE
++ iee_set_token_mm(current, NULL);
++ iee_set_token_pgd(current, NULL);
++ #endif
+ membarrier_update_current_mm(NULL);
+ enter_lazy_tlb(mm, current);
+ local_irq_enable();
+diff --git a/kernel/fork.c b/kernel/fork.c
+index e033388b11bd..c93e18a4f0b3 100644
+--- a/kernel/fork.c
++++ b/kernel/fork.c
+@@ -115,6 +115,10 @@
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/task.h>
+
++#ifdef CONFIG_IEE
++#include <linux/iee-func.h>
++#endif
++
+ /*
+ * Minimum number of threads to boot the kernel
+ */
+@@ -128,14 +132,14 @@
+ /*
+ * Protected counters by write_lock_irq(&tasklist_lock)
+ */
+-unsigned long total_forks; /* Handle normal Linux uptimes. */
+-int nr_threads; /* The idle threads do not count.. */
++unsigned long total_forks; /* Handle normal Linux uptimes. */
++int nr_threads; /* The idle threads do not count.. */
+
+-static int max_threads; /* tunable limit on nr_threads */
++static int max_threads; /* tunable limit on nr_threads */
+
+-#define NAMED_ARRAY_INDEX(x) [x] = __stringify(x)
++#define NAMED_ARRAY_INDEX(x) [x] = __stringify(x)
+
+-static const char * const resident_page_types[] = {
++static const char *const resident_page_types[] = {
+ NAMED_ARRAY_INDEX(MM_FILEPAGES),
+ NAMED_ARRAY_INDEX(MM_ANONPAGES),
+ NAMED_ARRAY_INDEX(MM_SWAPENTS),
+@@ -144,7 +148,7 @@ static const char * const resident_page_types[] = {
+
+ DEFINE_PER_CPU(unsigned long, process_counts) = 0;
+
+-__cacheline_aligned DEFINE_RWLOCK(tasklist_lock); /* outer */
++__cacheline_aligned DEFINE_RWLOCK(tasklist_lock); /* outer */
+
+ #ifdef CONFIG_PROVE_RCU
+ int lockdep_tasklist_lock_is_held(void)
+@@ -159,7 +163,7 @@ int nr_processes(void)
+ int cpu;
+ int total = 0;
+
+- for_each_possible_cpu(cpu)
++ for_each_possible_cpu (cpu)
+ total += per_cpu(process_counts, cpu);
+
+ return total;
+@@ -190,7 +194,7 @@ static inline void free_task_struct(struct task_struct *tsk)
+ * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
+ * kmemcache based allocator.
+ */
+-# if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)
++#if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)
+
+ # ifdef CONFIG_VMAP_STACK
+ /*
+@@ -311,8 +315,8 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
+ * so memcg accounting is performed manually on assigning/releasing
+ * stacks to tasks. Drop __GFP_ACCOUNT.
+ */
+- stack = __vmalloc_node_range(THREAD_SIZE, THREAD_ALIGN,
+- VMALLOC_START, VMALLOC_END,
++ stack = __vmalloc_node_range(THREAD_SIZE, THREAD_ALIGN, VMALLOC_START,
++ VMALLOC_END,
+ THREADINFO_GFP & ~__GFP_ACCOUNT,
+ PAGE_KERNEL,
+ 0, node, __builtin_return_address(0));
+@@ -410,9 +414,10 @@ static void free_thread_stack(struct task_struct *tsk)
+
+ void thread_stack_cache_init(void)
+ {
+- thread_stack_cache = kmem_cache_create_usercopy("thread_stack",
+- THREAD_SIZE, THREAD_SIZE, 0, 0,
+- THREAD_SIZE, NULL);
++ thread_stack_cache =
++ kmem_cache_create_usercopy("thread_stack", THREAD_SIZE,
++ THREAD_SIZE, 0, 0, THREAD_SIZE,
++ NULL);
+ BUG_ON(thread_stack_cache == NULL);
+ }
+
+@@ -502,7 +507,8 @@ struct vm_area_struct *vm_area_alloc(struct mm_struct *mm)
+
+ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
+ {
+- struct vm_area_struct *new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
++ struct vm_area_struct *new =
++ kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
+
+ if (!new)
+ return NULL;
+@@ -602,8 +608,15 @@ void put_task_stack(struct task_struct *tsk)
+ }
+ #endif
+
++#ifdef CONFIG_KOI
++extern s64 koi_offset;
++#endif
++
+ void free_task(struct task_struct *tsk)
+ {
++ #ifdef CONFIG_IEE
++ void *iee_stack;
++ #endif
+ #ifdef CONFIG_SECCOMP
+ WARN_ON_ONCE(tsk->seccomp.filter);
+ #endif
+@@ -633,6 +646,45 @@ void free_task(struct task_struct *tsk)
+ if (dynamic_affinity_enabled())
+ sched_prefer_cpus_free(tsk);
+ #endif
++#ifdef CONFIG_IEE
++ // Free iee stack.
++ iee_stack = (void *)iee_read_token_stack(tsk);
++ if (iee_stack) {
++ iee_set_kernel_ppage(
++ (unsigned long)(iee_stack - PAGE_SIZE * 4));
++ free_pages((unsigned long)(iee_stack - PAGE_SIZE * 4), 3);
++ }
++ // Free task_token.
++ // Empty the token
++ iee_free_token(tsk);
++
++#ifdef CONFIG_KOI
++ // Free koi stack.
++ unsigned long koi_stack = iee_rw_gate(IEE_READ_KOI_STACK_BASE, current);
++ if (koi_stack != 0)
++ free_pages(koi_stack, 2);
++#endif
++#else
++#ifdef CONFIG_KOI
++// free koi stack
++ struct task_token *token = (struct task_token *)((unsigned long)current + koi_offset);
++ unsigned long flags;
++ local_irq_save(flags);
++ asm volatile(
++ "at s1e1r, %0\n"
++ "isb\n"
++ :
++ :"r"(token));
++ unsigned long res = read_sysreg(par_el1);
++ local_irq_restore(flags);
++ if (!(res & 0x1)) {
++ unsigned long koi_stack = token->koi_stack_base;
++ if (koi_stack != 0)
++ free_pages(koi_stack, 2);
++ }
++#endif
++#endif
++
+ #ifdef CONFIG_QOS_SCHED_SMART_GRID
+ if (smart_grid_enabled())
+ sched_grid_qos_free(tsk);
+@@ -657,7 +709,7 @@ static void dup_mm_exe_file(struct mm_struct *mm, struct mm_struct *oldmm)
+
+ #ifdef CONFIG_MMU
+ static __latent_entropy int dup_mmap(struct mm_struct *mm,
+- struct mm_struct *oldmm)
++ struct mm_struct *oldmm)
+ {
+ struct vm_area_struct *mpnt, *tmp;
+ int retval;
+@@ -773,7 +825,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
+ flush_dcache_mmap_lock(mapping);
+ /* insert tmp into the share list, just after mpnt */
+ vma_interval_tree_insert_after(tmp, mpnt,
+- &mapping->i_mmap);
++ &mapping->i_mmap);
+ flush_dcache_mmap_unlock(mapping);
+ i_mmap_unlock_write(mapping);
+ }
+@@ -842,7 +894,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
+ mmap_write_unlock(oldmm);
+ return 0;
+ }
+-#define mm_alloc_pgd(mm) (0)
++#define mm_alloc_pgd(mm) (0)
+ #define mm_free_pgd(mm)
+ #endif /* CONFIG_MMU */
+
+@@ -850,20 +902,22 @@ static void check_mm(struct mm_struct *mm)
+ {
+ int i;
+
+- BUILD_BUG_ON_MSG(ARRAY_SIZE(resident_page_types) != NR_MM_COUNTERS,
+- "Please make sure 'struct resident_page_types[]' is updated as well");
++ BUILD_BUG_ON_MSG(
++ ARRAY_SIZE(resident_page_types) != NR_MM_COUNTERS,
++ "Please make sure 'struct resident_page_types[]' is updated as well");
+
+ for (i = 0; i < NR_MM_COUNTERS; i++) {
+ long x = mm_counter_sum(mm, i);
+
+ if (unlikely(x))
+- pr_alert("BUG: Bad rss-counter state mm:%p type:%s val:%ld\n",
+- mm, resident_page_types[i], x);
++ pr_alert(
++ "BUG: Bad rss-counter state mm:%p type:%s val:%ld\n",
++ mm, resident_page_types[i], x);
+ }
+
+ if (mm_pgtables_bytes(mm))
+ pr_alert("BUG: non-zero pgtables_bytes on freeing mm: %ld\n",
+- mm_pgtables_bytes(mm));
++ mm_pgtables_bytes(mm));
+
+ #if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
+ VM_BUG_ON_MM(mm->pmd_huge_pte, mm);
+@@ -1014,14 +1068,6 @@ void __put_task_struct(struct task_struct *tsk)
+ }
+ EXPORT_SYMBOL_GPL(__put_task_struct);
+
+-void __put_task_struct_rcu_cb(struct rcu_head *rhp)
+-{
+- struct task_struct *task = container_of(rhp, struct task_struct, rcu);
+-
+- __put_task_struct(task);
+-}
+-EXPORT_SYMBOL_GPL(__put_task_struct_rcu_cb);
+-
+ void __init __weak arch_task_cache_init(void) { }
+
+ /*
+@@ -1039,8 +1085,8 @@ static void set_max_threads(unsigned int max_threads_suggested)
+ if (fls64(nr_pages) + fls64(PAGE_SIZE) > 64)
+ threads = MAX_THREADS;
+ else
+- threads = div64_u64((u64) nr_pages * (u64) PAGE_SIZE,
+- (u64) THREAD_SIZE * 8UL);
++ threads = div64_u64((u64)nr_pages * (u64)PAGE_SIZE,
++ (u64)THREAD_SIZE * 8UL);
+
+ if (threads > max_threads_suggested)
+ threads = max_threads_suggested;
+@@ -1075,17 +1121,24 @@ void __init fork_init(void)
+ int i;
+ #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
+ #ifndef ARCH_MIN_TASKALIGN
+-#define ARCH_MIN_TASKALIGN 0
++#define ARCH_MIN_TASKALIGN 0
+ #endif
+ int align = max_t(int, L1_CACHE_BYTES, ARCH_MIN_TASKALIGN);
+ unsigned long useroffset, usersize;
+
+ /* create a slab on which task_structs can be allocated */
+ task_struct_whitelist(&useroffset, &usersize);
++ #ifdef CONFIG_IEE
+ task_struct_cachep = kmem_cache_create_usercopy("task_struct",
+ arch_task_struct_size, align,
+- SLAB_PANIC|SLAB_ACCOUNT,
++ SLAB_PANIC|SLAB_ACCOUNT|SLAB_RED_ZONE,
+ useroffset, usersize, NULL);
++ #else
++ task_struct_cachep =
++ kmem_cache_create_usercopy("task_struct", arch_task_struct_size,
++ align, SLAB_PANIC | SLAB_ACCOUNT,
++ useroffset, usersize, NULL);
++ #endif
+ #endif
+
+ /* do the arch specific task caches init */
+@@ -1093,8 +1146,8 @@ void __init fork_init(void)
+
+ set_max_threads(MAX_THREADS);
+
+- init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
+- init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
++ init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads / 2;
++ init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads / 2;
+ init_task.signal->rlim[RLIMIT_SIGPENDING] =
+ init_task.signal->rlim[RLIMIT_NPROC];
+
+@@ -1107,8 +1160,8 @@ void __init fork_init(void)
+ set_userns_rlimit_max(&init_user_ns, UCOUNT_RLIMIT_MEMLOCK, RLIM_INFINITY);
+
+ #ifdef CONFIG_VMAP_STACK
+- cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache",
+- NULL, free_vm_stack_cache);
++ cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "fork:vm_stack_cache", NULL,
++ free_vm_stack_cache);
+ #endif
+
+ scs_init();
+@@ -1118,7 +1171,7 @@ void __init fork_init(void)
+ }
+
+ int __weak arch_dup_task_struct(struct task_struct *dst,
+- struct task_struct *src)
++ struct task_struct *src)
+ {
+ *dst = *src;
+ return 0;
+@@ -1129,14 +1182,14 @@ void set_task_stack_end_magic(struct task_struct *tsk)
+ unsigned long *stackend;
+
+ stackend = end_of_stack(tsk);
+- *stackend = STACK_END_MAGIC; /* for overflow detection */
++ *stackend = STACK_END_MAGIC; /* for overflow detection */
+ }
+
+ static bool dup_resvd_task_struct(struct task_struct *dst,
+ struct task_struct *orig, int node)
+ {
+- dst->_resvd = kzalloc_node(sizeof(struct task_struct_resvd),
+- GFP_KERNEL, node);
++ dst->_resvd = kzalloc_node(sizeof(struct task_struct_resvd), GFP_KERNEL,
++ node);
+ if (!dst->_resvd)
+ return false;
+
+@@ -1309,7 +1362,7 @@ static void mm_init_uprobes_state(struct mm_struct *mm)
+ }
+
+ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
+- struct user_namespace *user_ns)
++ struct user_namespace *user_ns)
+ {
+ mt_init_flags(&mm->mm_mt, MM_MT_FLAGS);
+ mt_set_external_lock(&mm->mm_mt, &mm->mmap_lock);
+@@ -1425,8 +1478,8 @@ EXPORT_SYMBOL_GPL(mmput);
+ #ifdef CONFIG_MMU
+ static void mmput_async_fn(struct work_struct *work)
+ {
+- struct mm_struct *mm = container_of(work, struct mm_struct,
+- async_put_work);
++ struct mm_struct *mm =
++ container_of(work, struct mm_struct, async_put_work);
+
+ __mmput(mm);
+ }
+@@ -1602,13 +1655,12 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
+ struct mm_struct *mm;
+ int err;
+
+- err = down_read_killable(&task->signal->exec_update_lock);
++ err = down_read_killable(&task->signal->exec_update_lock);
+ if (err)
+ return ERR_PTR(err);
+
+ mm = get_task_mm(task);
+- if (mm && mm != current->mm &&
+- !ptrace_may_access(task, mode)) {
++ if (mm && mm != current->mm && !ptrace_may_access(task, mode)) {
+ mmput(mm);
+ mm = ERR_PTR(-EACCES);
+ }
+@@ -1631,7 +1683,7 @@ static void complete_vfork_done(struct task_struct *tsk)
+ }
+
+ static int wait_for_vfork_done(struct task_struct *child,
+- struct completion *vfork)
++ struct completion *vfork)
+ {
+ unsigned int state = TASK_UNINTERRUPTIBLE|TASK_KILLABLE|TASK_FREEZABLE;
+ int killed;
+@@ -1682,8 +1734,8 @@ static void mm_release(struct task_struct *tsk, struct mm_struct *mm)
+ * not set up a proper pointer then tough luck.
+ */
+ put_user(0, tsk->clear_child_tid);
+- do_futex(tsk->clear_child_tid, FUTEX_WAKE,
+- 1, NULL, NULL, 0, 0);
++ do_futex(tsk->clear_child_tid, FUTEX_WAKE, 1, NULL,
++ NULL, 0, 0);
+ }
+ tsk->clear_child_tid = NULL;
+ }
+@@ -1767,6 +1819,10 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
+ #endif
+
+ tsk->mm = NULL;
++#ifdef CONFIG_IEE
++ iee_set_token_mm(tsk, NULL);
++ iee_set_token_pgd(tsk, NULL);
++#endif
+ tsk->active_mm = NULL;
+
+ /*
+@@ -1798,6 +1854,10 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
+ }
+
+ tsk->mm = mm;
++#ifdef CONFIG_IEE
++ iee_set_token_mm(tsk, mm);
++ iee_set_token_pgd(tsk, mm->pgd);
++#endif
+ tsk->active_mm = mm;
+ sched_mm_cid_fork(tsk);
+ return 0;
+@@ -2015,8 +2075,8 @@ static inline void init_task_pid_links(struct task_struct *task)
+ INIT_HLIST_NODE(&task->pid_links[type]);
+ }
+
+-static inline void
+-init_task_pid(struct task_struct *task, enum pid_type type, struct pid *pid)
++static inline void init_task_pid(struct task_struct *task, enum pid_type type,
++ struct pid *pid)
+ {
+ if (type == PIDTYPE_PID)
+ task->thread_pid = pid;
+@@ -2277,6 +2337,12 @@ static void copy_oom_score_adj(u64 clone_flags, struct task_struct *tsk)
+ mutex_unlock(&oom_adj_mutex);
+ }
+
++#if defined(CONFIG_KOI) && !defined(CONFIG_IEE)
++extern s64 koi_offset;
++extern int koi_add_page_mapping(unsigned long dst, unsigned long src);
++#endif
++
++
+ #ifdef CONFIG_RV
+ static void rv_task_fork(struct task_struct *p)
+ {
+@@ -2309,15 +2375,21 @@ __latent_entropy struct task_struct *copy_process(
+ struct file *pidfile = NULL;
+ const u64 clone_flags = args->flags;
+ struct nsproxy *nsp = current->nsproxy;
++ #ifdef CONFIG_IEE
++ gfp_t gfp;
++ void *pstack;
++ #endif
+
+ /*
+ * Don't allow sharing the root directory with processes in a different
+ * namespace
+ */
+- if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
++ if ((clone_flags & (CLONE_NEWNS | CLONE_FS)) ==
++ (CLONE_NEWNS | CLONE_FS))
+ return ERR_PTR(-EINVAL);
+
+- if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))
++ if ((clone_flags & (CLONE_NEWUSER | CLONE_FS)) ==
++ (CLONE_NEWUSER | CLONE_FS))
+ return ERR_PTR(-EINVAL);
+
+ /*
+@@ -2342,7 +2414,7 @@ __latent_entropy struct task_struct *copy_process(
+ * from creating siblings.
+ */
+ if ((clone_flags & CLONE_PARENT) &&
+- current->signal->flags & SIGNAL_UNKILLABLE)
++ current->signal->flags & SIGNAL_UNKILLABLE)
+ return ERR_PTR(-EINVAL);
+
+ /*
+@@ -2387,6 +2459,15 @@ __latent_entropy struct task_struct *copy_process(
+ p = dup_task_struct(current, node);
+ if (!p)
+ goto fork_out;
++ #ifdef CONFIG_IEE
++ // Alloc iee stack.
++ gfp = GFP_KERNEL;
++ pstack = (void *)__get_free_pages(gfp, 3);
++ iee_set_kernel_upage((unsigned long)pstack);
++ // Init token.
++ iee_init_token(p, NULL, pstack + PAGE_SIZE * 4);
++ #endif
++
+ p->flags &= ~PF_KTHREAD;
+ if (args->kthread)
+ p->flags |= PF_KTHREAD;
+@@ -2408,7 +2489,8 @@ __latent_entropy struct task_struct *copy_process(
+ /*
+ * Clear TID on mm_release()?
+ */
+- p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? args->child_tid : NULL;
++ p->clear_child_tid =
++ (clone_flags & CLONE_CHILD_CLEARTID) ? args->child_tid : NULL;
+
+ ftrace_graph_init_task(p);
+
+@@ -2519,10 +2601,10 @@ __latent_entropy struct task_struct *copy_process(
+ #endif
+ #ifdef CONFIG_TRACE_IRQFLAGS
+ memset(&p->irqtrace, 0, sizeof(p->irqtrace));
+- p->irqtrace.hardirq_disable_ip = _THIS_IP_;
+- p->irqtrace.softirq_enable_ip = _THIS_IP_;
+- p->softirqs_enabled = 1;
+- p->softirq_context = 0;
++ p->irqtrace.hardirq_disable_ip = _THIS_IP_;
++ p->irqtrace.softirq_enable_ip = _THIS_IP_;
++ p->softirqs_enabled = 1;
++ p->softirq_context = 0;
+ #endif
+
+ p->pagefault_disabled = 0;
+@@ -2535,8 +2617,8 @@ __latent_entropy struct task_struct *copy_process(
+ p->blocked_on = NULL; /* not blocked yet */
+ #endif
+ #ifdef CONFIG_BCACHE
+- p->sequential_io = 0;
+- p->sequential_io_avg = 0;
++ p->sequential_io = 0;
++ p->sequential_io_avg = 0;
+ #endif
+ #ifdef CONFIG_BPF_SYSCALL
+ RCU_INIT_POINTER(p->bpf_storage, NULL);
+@@ -2623,7 +2705,7 @@ __latent_entropy struct task_struct *copy_process(
+ /*
+ * sigaltstack should be cleared when sharing the same VM
+ */
+- if ((clone_flags & (CLONE_VM|CLONE_VFORK)) == CLONE_VM)
++ if ((clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM)
+ sas_ss_reset(p);
+
+ /*
+@@ -2702,7 +2784,7 @@ __latent_entropy struct task_struct *copy_process(
+ write_lock_irq(&tasklist_lock);
+
+ /* CLONE_PARENT re-uses the old parent */
+- if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) {
++ if (clone_flags & (CLONE_PARENT | CLONE_THREAD)) {
+ p->real_parent = current->real_parent;
+ p->parent_exec_id = current->parent_exec_id;
+ if (clone_flags & CLONE_THREAD)
+@@ -2766,8 +2848,9 @@ __latent_entropy struct task_struct *copy_process(
+ * tasklist_lock with adding child to the process tree
+ * for propagate_has_child_subreaper optimization.
+ */
+- p->signal->has_child_subreaper = p->real_parent->signal->has_child_subreaper ||
+- p->real_parent->signal->is_child_subreaper;
++ p->signal->has_child_subreaper =
++ p->real_parent->signal->has_child_subreaper ||
++ p->real_parent->signal->is_child_subreaper;
+ list_add_tail(&p->sibling, &p->real_parent->children);
+ list_add_tail_rcu(&p->tasks, &init_task.tasks);
+ attach_pid(p, PIDTYPE_TGID);
+@@ -2918,8 +3001,8 @@ struct task_struct * __init fork_idle(int cpu)
+ */
+ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node)
+ {
+- unsigned long flags = CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|
+- CLONE_IO;
++ unsigned long flags = CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
++ CLONE_THREAD | CLONE_IO;
+ struct kernel_clone_args args = {
+ .flags = ((lower_32_bits(flags) | CLONE_VM |
+ CLONE_UNTRACED) & ~CSIGNAL),
+@@ -3083,8 +3166,8 @@ SYSCALL_DEFINE0(fork)
+ SYSCALL_DEFINE0(vfork)
+ {
+ struct kernel_clone_args args = {
+- .flags = CLONE_VFORK | CLONE_VM,
+- .exit_signal = SIGCHLD,
++ .flags = CLONE_VFORK | CLONE_VM,
++ .exit_signal = SIGCHLD,
+ };
+
+ return kernel_clone(&args);
+@@ -3094,35 +3177,30 @@ SYSCALL_DEFINE0(vfork)
+ #ifdef __ARCH_WANT_SYS_CLONE
+ #ifdef CONFIG_CLONE_BACKWARDS
+ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
+- int __user *, parent_tidptr,
+- unsigned long, tls,
+- int __user *, child_tidptr)
++ int __user *, parent_tidptr, unsigned long, tls, int __user *,
++ child_tidptr)
+ #elif defined(CONFIG_CLONE_BACKWARDS2)
+ SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,
+- int __user *, parent_tidptr,
+- int __user *, child_tidptr,
+- unsigned long, tls)
+-#elif defined(CONFIG_CLONE_BACKWARDS3)
+-SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,
+- int, stack_size,
+- int __user *, parent_tidptr,
+- int __user *, child_tidptr,
++ int __user *, parent_tidptr, int __user *, child_tidptr,
+ unsigned long, tls)
++#elif defined(CONFIG_CLONE_BACKWARDS3)
++SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp, int,
++ stack_size, int __user *, parent_tidptr, int __user *,
++ child_tidptr, unsigned long, tls)
+ #else
+ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
+- int __user *, parent_tidptr,
+- int __user *, child_tidptr,
+- unsigned long, tls)
++ int __user *, parent_tidptr, int __user *, child_tidptr,
++ unsigned long, tls)
+ #endif
+ {
+ struct kernel_clone_args args = {
+- .flags = (lower_32_bits(clone_flags) & ~CSIGNAL),
+- .pidfd = parent_tidptr,
+- .child_tid = child_tidptr,
+- .parent_tid = parent_tidptr,
+- .exit_signal = (lower_32_bits(clone_flags) & CSIGNAL),
+- .stack = newsp,
+- .tls = tls,
++ .flags = (lower_32_bits(clone_flags) & ~CSIGNAL),
++ .pidfd = parent_tidptr,
++ .child_tid = child_tidptr,
++ .parent_tid = parent_tidptr,
++ .exit_signal = (lower_32_bits(clone_flags) & CSIGNAL),
++ .stack = newsp,
++ .tls = tls,
+ };
+
+ return kernel_clone(&args);
+@@ -3178,21 +3256,21 @@ noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
+ return -EINVAL;
+
+ *kargs = (struct kernel_clone_args){
+- .flags = args.flags,
+- .pidfd = u64_to_user_ptr(args.pidfd),
+- .child_tid = u64_to_user_ptr(args.child_tid),
+- .parent_tid = u64_to_user_ptr(args.parent_tid),
+- .exit_signal = args.exit_signal,
+- .stack = args.stack,
+- .stack_size = args.stack_size,
+- .tls = args.tls,
+- .set_tid_size = args.set_tid_size,
+- .cgroup = args.cgroup,
++ .flags = args.flags,
++ .pidfd = u64_to_user_ptr(args.pidfd),
++ .child_tid = u64_to_user_ptr(args.child_tid),
++ .parent_tid = u64_to_user_ptr(args.parent_tid),
++ .exit_signal = args.exit_signal,
++ .stack = args.stack,
++ .stack_size = args.stack_size,
++ .tls = args.tls,
++ .set_tid_size = args.set_tid_size,
++ .cgroup = args.cgroup,
+ };
+
+ if (args.set_tid &&
+- copy_from_user(kset_tid, u64_to_user_ptr(args.set_tid),
+- (kargs->set_tid_size * sizeof(pid_t))))
++ copy_from_user(kset_tid, u64_to_user_ptr(args.set_tid),
++ (kargs->set_tid_size * sizeof(pid_t))))
+ return -EFAULT;
+
+ kargs->set_tid = kset_tid;
+@@ -3287,7 +3365,8 @@ SYSCALL_DEFINE2(clone3, struct clone_args __user *, uargs, size_t, size)
+ }
+ #endif
+
+-void walk_process_tree(struct task_struct *top, proc_visitor visitor, void *data)
++void walk_process_tree(struct task_struct *top, proc_visitor visitor,
++ void *data)
+ {
+ struct task_struct *leader, *parent, *child;
+ int res;
+@@ -3295,8 +3374,8 @@ void walk_process_tree(struct task_struct *top, proc_visitor visitor, void *data
+ read_lock(&tasklist_lock);
+ leader = top = top->group_leader;
+ down:
+- for_each_thread(leader, parent) {
+- list_for_each_entry(child, &parent->children, sibling) {
++ for_each_thread (leader, parent) {
++ list_for_each_entry (child, &parent->children, sibling) {
+ res = visitor(child, data);
+ if (res) {
+ if (res < 0)
+@@ -3304,8 +3383,7 @@ void walk_process_tree(struct task_struct *top, proc_visitor visitor, void *data
+ leader = child;
+ goto down;
+ }
+-up:
+- ;
++ up:;
+ }
+ }
+
+@@ -3382,11 +3460,11 @@ void __init proc_caches_init(void)
+ */
+ static int check_unshare_flags(unsigned long unshare_flags)
+ {
+- if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
+- CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
+- CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET|
+- CLONE_NEWUSER|CLONE_NEWPID|CLONE_NEWCGROUP|
+- CLONE_NEWTIME))
++ if (unshare_flags &
++ ~(CLONE_THREAD | CLONE_FS | CLONE_NEWNS | CLONE_SIGHAND | CLONE_VM |
++ CLONE_FILES | CLONE_SYSVSEM | CLONE_NEWUTS | CLONE_NEWIPC |
++ CLONE_NEWNET | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWCGROUP |
++ CLONE_NEWTIME))
+ return -EINVAL;
+ /*
+ * Not implemented, but pretend it works if there is nothing
+@@ -3497,7 +3575,7 @@ int ksys_unshare(unsigned long unshare_flags)
+ * to a new ipc namespace, the semaphore arrays from the old
+ * namespace are unreachable.
+ */
+- if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM))
++ if (unshare_flags & (CLONE_NEWIPC | CLONE_SYSVSEM))
+ do_sysvsem = 1;
+ err = unshare_fs(unshare_flags, &new_fs);
+ if (err)
+@@ -3508,8 +3586,8 @@ int ksys_unshare(unsigned long unshare_flags)
+ err = unshare_userns(unshare_flags, &new_cred);
+ if (err)
+ goto bad_unshare_cleanup_fd;
+- err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy,
+- new_cred, new_fs);
++ err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, new_cred,
++ new_fs);
+ if (err)
+ goto bad_unshare_cleanup_cred;
+
+@@ -3606,8 +3684,8 @@ int unshare_files(void)
+ return 0;
+ }
+
+-int sysctl_max_threads(struct ctl_table *table, int write,
+- void *buffer, size_t *lenp, loff_t *ppos)
++int sysctl_max_threads(struct ctl_table *table, int write, void *buffer,
++ size_t *lenp, loff_t *ppos)
+ {
+ struct ctl_table t;
+ int ret;
+diff --git a/kernel/groups.c b/kernel/groups.c
+index 9b43da22647d..8045812e8a3c 100644
+--- a/kernel/groups.c
++++ b/kernel/groups.c
+@@ -11,6 +11,9 @@
+ #include <linux/user_namespace.h>
+ #include <linux/vmalloc.h>
+ #include <linux/uaccess.h>
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
+
+ struct group_info *groups_alloc(int gidsetsize)
+ {
+@@ -119,7 +122,11 @@ void set_groups(struct cred *new, struct group_info *group_info)
+ {
+ put_group_info(new->group_info);
+ get_group_info(group_info);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_group_info(new,group_info);
++ #else
+ new->group_info = group_info;
++ #endif
+ }
+
+ EXPORT_SYMBOL(set_groups);
+diff --git a/kernel/kthread.c b/kernel/kthread.c
+index 1eea53050bab..317eac6eb2f2 100644
+--- a/kernel/kthread.c
++++ b/kernel/kthread.c
+@@ -30,6 +30,10 @@
+ #include <linux/sched/isolation.h>
+ #include <trace/events/sched.h>
+
++#ifdef CONFIG_IEE
++#include <linux/iee-func.h>
++#endif
++
+
+ static DEFINE_SPINLOCK(kthread_create_lock);
+ static LIST_HEAD(kthread_create_list);
+@@ -1429,6 +1433,10 @@ void kthread_use_mm(struct mm_struct *mm)
+ tsk->active_mm = mm;
+ tsk->mm = mm;
+ membarrier_update_current_mm(mm);
++ #ifdef CONFIG_IEE
++ iee_set_token_mm(tsk, mm);
++ iee_set_token_pgd(tsk, mm->pgd);
++ #endif
+ switch_mm_irqs_off(active_mm, mm, tsk);
+ local_irq_enable();
+ task_unlock(tsk);
+@@ -1473,7 +1481,12 @@ void kthread_unuse_mm(struct mm_struct *mm)
+ local_irq_disable();
+ tsk->mm = NULL;
+ membarrier_update_current_mm(NULL);
++ #ifdef CONFIG_IEE
++ iee_set_token_mm(tsk, mm);
++ iee_set_token_pgd(tsk, NULL);
++ #endif
+ mmgrab_lazy_tlb(mm);
++
+ /* active_mm is still 'mm' */
+ enter_lazy_tlb(mm, tsk);
+ local_irq_enable();
+diff --git a/kernel/smpboot.c b/kernel/smpboot.c
+index f47d8f375946..60c7d365c0e1 100644
+--- a/kernel/smpboot.c
++++ b/kernel/smpboot.c
+@@ -16,6 +16,10 @@
+ #include <linux/kthread.h>
+ #include <linux/smpboot.h>
+
++#ifdef CONFIG_IEE
++#include <linux/iee-func.h>
++#endif
++
+ #include "smpboot.h"
+
+ #ifdef CONFIG_SMP
+@@ -57,6 +61,11 @@ static __always_inline void idle_init(unsigned int cpu)
+ pr_err("SMP: fork_idle() failed for CPU %u\n", cpu);
+ else
+ per_cpu(idle_threads, cpu) = tsk;
++ #ifdef CONFIG_IEE
++ // Set the secondary __entry_task.
++ *(struct task_struct **)SHIFT_PERCPU_PTR(__entry_task,__per_cpu_offset[cpu]) = tsk;
++ iee_set_logical_mem_ro((unsigned long)SHIFT_PERCPU_PTR(__entry_task,__per_cpu_offset[cpu]));
++ #endif
+ }
+ }
+
+diff --git a/kernel/sys.c b/kernel/sys.c
+index 44b575990333..fbc47f83af50 100644
+--- a/kernel/sys.c
++++ b/kernel/sys.c
+@@ -75,6 +75,10 @@
+ #include <asm/io.h>
+ #include <asm/unistd.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ #include "uid16.h"
+
+ #ifndef SET_UNALIGN_CTL
+@@ -395,7 +399,11 @@ long __sys_setregid(gid_t rgid, gid_t egid)
+ if (gid_eq(old->gid, krgid) ||
+ gid_eq(old->egid, krgid) ||
+ ns_capable_setid(old->user_ns, CAP_SETGID))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_gid(new,krgid);
++ #else
+ new->gid = krgid;
++ #endif
+ else
+ goto error;
+ }
+@@ -404,15 +412,27 @@ long __sys_setregid(gid_t rgid, gid_t egid)
+ gid_eq(old->egid, kegid) ||
+ gid_eq(old->sgid, kegid) ||
+ ns_capable_setid(old->user_ns, CAP_SETGID))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_egid(new,kegid);
++ #else
+ new->egid = kegid;
++ #endif
+ else
+ goto error;
+ }
+
+ if (rgid != (gid_t) -1 ||
+ (egid != (gid_t) -1 && !gid_eq(kegid, old->gid)))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_sgid(new,new->egid);
++ #else
+ new->sgid = new->egid;
++ #endif
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsgid(new,new->egid);
++ #else
+ new->fsgid = new->egid;
++ #endif
+
+ retval = security_task_fix_setgid(new, old, LSM_SETID_RE);
+ if (retval < 0)
+@@ -454,9 +474,25 @@ long __sys_setgid(gid_t gid)
+
+ retval = -EPERM;
+ if (ns_capable_setid(old->user_ns, CAP_SETGID))
++ #ifdef CONFIG_CREDP
++ {
++ iee_set_cred_fsgid(new,kgid);
++ iee_set_cred_sgid(new,kgid);
++ iee_set_cred_egid(new,kgid);
++ iee_set_cred_gid(new,kgid);
++ }
++ #else
+ new->gid = new->egid = new->sgid = new->fsgid = kgid;
++ #endif
+ else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
++ #ifdef CONFIG_CREDP
++ {
++ iee_set_cred_fsgid(new,kgid);
++ iee_set_cred_egid(new,kgid);
++ }
++ #else
+ new->egid = new->fsgid = kgid;
++ #endif
+ else
+ goto error;
+
+@@ -488,7 +524,11 @@ static int set_user(struct cred *new)
+ return -EAGAIN;
+
+ free_uid(new->user);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_user(new,new_user);
++ #else
+ new->user = new_user;
++ #endif
+ return 0;
+ }
+
+@@ -549,7 +589,11 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
+
+ retval = -EPERM;
+ if (ruid != (uid_t) -1) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_uid(new,kruid);
++ #else
+ new->uid = kruid;
++ #endif
+ if (!uid_eq(old->uid, kruid) &&
+ !uid_eq(old->euid, kruid) &&
+ !ns_capable_setid(old->user_ns, CAP_SETUID))
+@@ -557,7 +601,11 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
+ }
+
+ if (euid != (uid_t) -1) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_euid(new,keuid);
++ #else
+ new->euid = keuid;
++ #endif
+ if (!uid_eq(old->uid, keuid) &&
+ !uid_eq(old->euid, keuid) &&
+ !uid_eq(old->suid, keuid) &&
+@@ -572,8 +620,16 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
+ }
+ if (ruid != (uid_t) -1 ||
+ (euid != (uid_t) -1 && !uid_eq(keuid, old->uid)))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_suid(new,new->euid);
++ #else
+ new->suid = new->euid;
++ #endif
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,new->euid);
++ #else
+ new->fsuid = new->euid;
++ #endif
+
+ retval = security_task_fix_setuid(new, old, LSM_SETID_RE);
+ if (retval < 0)
+@@ -626,7 +682,12 @@ long __sys_setuid(uid_t uid)
+
+ retval = -EPERM;
+ if (ns_capable_setid(old->user_ns, CAP_SETUID)) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_uid(new,kuid);
++ iee_set_cred_suid(new,kuid);
++ #else
+ new->suid = new->uid = kuid;
++ #endif
+ if (!uid_eq(kuid, old->uid)) {
+ retval = set_user(new);
+ if (retval < 0)
+@@ -636,7 +697,12 @@ long __sys_setuid(uid_t uid)
+ goto error;
+ }
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_euid(new,kuid);
++ iee_set_cred_fsuid(new,kuid);
++ #else
+ new->fsuid = new->euid = kuid;
++ #endif
+
+ retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
+ if (retval < 0)
+@@ -710,7 +776,11 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+ return -ENOMEM;
+
+ if (ruid != (uid_t) -1) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_uid(new,kruid);
++ #else
+ new->uid = kruid;
++ #endif
+ if (!uid_eq(kruid, old->uid)) {
+ retval = set_user(new);
+ if (retval < 0)
+@@ -718,10 +788,22 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+ }
+ }
+ if (euid != (uid_t) -1)
++ #ifdef CONFIG_CREDP
++ iee_set_cred_euid(new,keuid);
++ #else
+ new->euid = keuid;
++ #endif
+ if (suid != (uid_t) -1)
++ #ifdef CONFIG_CREDP
++ iee_set_cred_suid(new,ksuid);
++ #else
+ new->suid = ksuid;
++ #endif
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,new->euid);
++ #else
+ new->fsuid = new->euid;
++ #endif
+
+ retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
+ if (retval < 0)
+@@ -810,12 +892,29 @@ long __sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+ return -ENOMEM;
+
+ if (rgid != (gid_t) -1)
++ #ifdef CONFIG_CREDP
++ iee_set_cred_gid(new,krgid);
++ #else
+ new->gid = krgid;
++ #endif
+ if (egid != (gid_t) -1)
++ #ifdef CONFIG_CREDP
++ iee_set_cred_egid(new,kegid);
++ #else
+ new->egid = kegid;
++ #endif
+ if (sgid != (gid_t) -1)
++ #ifdef CONFIG_CREDP
++ iee_set_cred_sgid(new,ksgid);
++ #else
+ new->sgid = ksgid;
++ #endif
++
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsgid(new,new->egid);
++ #else
+ new->fsgid = new->egid;
++ #endif
+
+ retval = security_task_fix_setgid(new, old, LSM_SETID_RES);
+ if (retval < 0)
+@@ -882,7 +981,11 @@ long __sys_setfsuid(uid_t uid)
+ uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
+ ns_capable_setid(old->user_ns, CAP_SETUID)) {
+ if (!uid_eq(kuid, old->fsuid)) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,kuid);
++ #else
+ new->fsuid = kuid;
++ #endif
+ if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
+ goto change_okay;
+ }
+@@ -926,7 +1029,11 @@ long __sys_setfsgid(gid_t gid)
+ gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
+ ns_capable_setid(old->user_ns, CAP_SETGID)) {
+ if (!gid_eq(kgid, old->fsgid)) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsgid(new,kgid);
++ #else
+ new->fsgid = kgid;
++ #endif
+ if (security_task_fix_setgid(new,old,LSM_SETID_FS) == 0)
+ goto change_okay;
+ }
+diff --git a/kernel/umh.c b/kernel/umh.c
+index 1b13c5d34624..32f5c88e10bf 100644
+--- a/kernel/umh.c
++++ b/kernel/umh.c
+@@ -32,6 +32,10 @@
+
+ #include <trace/events/module.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
+ static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
+ static DEFINE_SPINLOCK(umh_sysctl_lock);
+@@ -91,9 +95,15 @@ static int call_usermodehelper_exec_async(void *data)
+ goto out;
+
+ spin_lock(&umh_sysctl_lock);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_bset(new,cap_intersect(usermodehelper_bset, new->cap_bset));
++ iee_set_cred_cap_inheritable(new,cap_intersect(usermodehelper_inheritable,
++ new->cap_inheritable));
++ #else
+ new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
+ new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
+ new->cap_inheritable);
++ #endif
+ spin_unlock(&umh_sysctl_lock);
+
+ if (sub_info->init) {
+diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
+index 1d8e47bed3f1..9f1921025539 100644
+--- a/kernel/user_namespace.c
++++ b/kernel/user_namespace.c
+@@ -22,6 +22,10 @@
+ #include <linux/bsearch.h>
+ #include <linux/sort.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ static struct kmem_cache *user_ns_cachep __read_mostly;
+ static DEFINE_MUTEX(userns_state_mutex);
+
+@@ -45,6 +49,19 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
+ /* Start with the same capabilities as init but useless for doing
+ * anything as the capabilities are bound to the new user namespace.
+ */
++ #ifdef CONFIG_CREDP
++ iee_set_cred_securebits(cred,SECUREBITS_DEFAULT);
++ iee_set_cred_cap_inheritable(cred,CAP_EMPTY_SET);
++ iee_set_cred_cap_permitted(cred,CAP_FULL_SET);
++ iee_set_cred_cap_effective(cred,CAP_FULL_SET);
++ iee_set_cred_cap_ambient(cred,CAP_EMPTY_SET);
++ iee_set_cred_cap_bset(cred,CAP_FULL_SET);
++#ifdef CONFIG_KEYS
++ key_put(cred->request_key_auth);
++ iee_set_cred_request_key_auth(cred,NULL);
++#endif
++ iee_set_cred_user_ns(cred,user_ns);
++ #else
+ cred->securebits = SECUREBITS_DEFAULT;
+ cred->cap_inheritable = CAP_EMPTY_SET;
+ cred->cap_permitted = CAP_FULL_SET;
+@@ -57,6 +74,7 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
+ #endif
+ /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
+ cred->user_ns = user_ns;
++ #endif
+ }
+
+ static unsigned long enforced_nproc_rlimit(void)
+diff --git a/mm/Kconfig b/mm/Kconfig
+index 45d4139c959c..eb9d41768c15 100644
+--- a/mm/Kconfig
++++ b/mm/Kconfig
+@@ -530,6 +530,18 @@ config NUMA_KEEP_MEMINFO
+ config MEMORY_ISOLATION
+ bool
+
++# Config for kernel module isolation
++config KOI
++ depends on ARM64
++ depends on ARM64_VA_BITS_48
++ depends on ARM64_4K_PAGES
++ def_bool n
++
++# Configs for pgtable isolation
++config PTP
++ depends on IEE
++ def_bool y
++
+ # IORESOURCE_SYSTEM_RAM regions in the kernel resource tree that are marked
+ # IORESOURCE_EXCLUSIVE cannot be mapped to user space, for example, via
+ # /dev/mem.
+diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
+index d25d99cb5f2b..2ea51f559d4e 100644
+--- a/mm/damon/ops-common.c
++++ b/mm/damon/ops-common.c
+@@ -44,6 +44,7 @@ void damon_ptep_mkold(pte_t *pte, struct vm_area_struct *vma, unsigned long addr
+ if (!folio)
+ return;
+
++
+ if (ptep_clear_young_notify(vma, addr, pte))
+ folio_set_young(folio);
+
+diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
+index 13f0d1192707..60dc95c5b286 100644
+--- a/mm/debug_vm_pgtable.c
++++ b/mm/debug_vm_pgtable.c
+@@ -452,7 +452,11 @@ static void __init pmd_huge_tests(struct pgtable_debug_args *args)
+ * X86 defined pmd_set_huge() verifies that the given
+ * PMD is not a populated non-leaf entry.
+ */
++ #ifdef CONFIG_PTP
++ set_pmd(args->pmdp, __pmd(0));
++ #else
+ WRITE_ONCE(*args->pmdp, __pmd(0));
++ #endif
+ WARN_ON(!pmd_set_huge(args->pmdp, __pfn_to_phys(args->fixed_pmd_pfn), args->page_prot));
+ WARN_ON(!pmd_clear_huge(args->pmdp));
+ pmd = READ_ONCE(*args->pmdp);
+@@ -472,7 +476,11 @@ static void __init pud_huge_tests(struct pgtable_debug_args *args)
+ * X86 defined pud_set_huge() verifies that the given
+ * PUD is not a populated non-leaf entry.
+ */
++ #ifdef CONFIG_PTP
++ set_pud(args->pudp, __pud(0));
++ #else
+ WRITE_ONCE(*args->pudp, __pud(0));
++ #endif
+ WARN_ON(!pud_set_huge(args->pudp, __pfn_to_phys(args->fixed_pud_pfn), args->page_prot));
+ WARN_ON(!pud_clear_huge(args->pudp));
+ pud = READ_ONCE(*args->pudp);
+@@ -511,7 +519,11 @@ static void __init pud_clear_tests(struct pgtable_debug_args *args)
+
+ pr_debug("Validating PUD clear\n");
+ pud = __pud(pud_val(pud) | RANDOM_ORVALUE);
++ #ifdef CONFIG_PTP
++ set_pud(args->pudp, pud);
++ #else
+ WRITE_ONCE(*args->pudp, pud);
++ #endif
+ pud_clear(args->pudp);
+ pud = READ_ONCE(*args->pudp);
+ WARN_ON(!pud_none(pud));
+@@ -548,7 +560,11 @@ static void __init p4d_clear_tests(struct pgtable_debug_args *args)
+
+ pr_debug("Validating P4D clear\n");
+ p4d = __p4d(p4d_val(p4d) | RANDOM_ORVALUE);
++ #ifdef CONFIG_PTP
++ set_p4d(args->p4dp, p4d);
++ #else
+ WRITE_ONCE(*args->p4dp, p4d);
++ #endif
+ p4d_clear(args->p4dp);
+ p4d = READ_ONCE(*args->p4dp);
+ WARN_ON(!p4d_none(p4d));
+@@ -582,7 +598,11 @@ static void __init pgd_clear_tests(struct pgtable_debug_args *args)
+
+ pr_debug("Validating PGD clear\n");
+ pgd = __pgd(pgd_val(pgd) | RANDOM_ORVALUE);
++ #ifdef CONFIG_PTP
++ set_pgd(args->pgdp, pgd);
++ #else
+ WRITE_ONCE(*args->pgdp, pgd);
++ #endif
+ pgd_clear(args->pgdp);
+ pgd = READ_ONCE(*args->pgdp);
+ WARN_ON(!pgd_none(pgd));
+@@ -650,7 +670,11 @@ static void __init pmd_clear_tests(struct pgtable_debug_args *args)
+
+ pr_debug("Validating PMD clear\n");
+ pmd = __pmd(pmd_val(pmd) | RANDOM_ORVALUE);
++ #ifdef CONFIG_PTP
++ set_pmd(args->pmdp, pmd);
++ #else
+ WRITE_ONCE(*args->pmdp, pmd);
++ #endif
+ pmd_clear(args->pmdp);
+ pmd = READ_ONCE(*args->pmdp);
+ WARN_ON(!pmd_none(pmd));
+diff --git a/mm/early_ioremap.c b/mm/early_ioremap.c
+index ce06b2884789..a039c7a50ec5 100644
+--- a/mm/early_ioremap.c
++++ b/mm/early_ioremap.c
+@@ -147,7 +147,11 @@ __early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot)
+ if (after_paging_init)
+ __late_set_fixmap(idx, phys_addr, prot);
+ else
++ #ifdef CONFIG_PTP
++ __iee_set_fixmap_pre_init(idx, phys_addr, prot);
++ #else
+ __early_set_fixmap(idx, phys_addr, prot);
++ #endif
+ phys_addr += PAGE_SIZE;
+ --idx;
+ --nrpages;
+@@ -199,13 +203,66 @@ void __init early_iounmap(void __iomem *addr, unsigned long size)
+ if (after_paging_init)
+ __late_clear_fixmap(idx);
+ else
++ #ifdef CONFIG_PTP
++ __iee_set_fixmap_pre_init(idx, 0, FIXMAP_PAGE_CLEAR);
++ #else
+ __early_set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR);
++ #endif
+ --idx;
+ --nrpages;
+ }
+ prev_map[slot] = NULL;
+ }
+
++#ifdef CONFIG_PTP
++void __init early_iounmap_after_init(void __iomem *addr, unsigned long size)
++{
++ unsigned long virt_addr;
++ unsigned long offset;
++ unsigned int nrpages;
++ enum fixed_addresses idx;
++ int i, slot;
++
++ slot = -1;
++ for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
++ if (prev_map[i] == addr) {
++ slot = i;
++ break;
++ }
++ }
++
++ if (WARN(slot < 0, "early_iounmap(%p, %08lx) not found slot\n",
++ addr, size))
++ return;
++
++ if (WARN(prev_size[slot] != size,
++ "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n",
++ addr, size, slot, prev_size[slot]))
++ return;
++
++ WARN(early_ioremap_debug, "early_iounmap(%p, %08lx) [%d]\n",
++ addr, size, slot);
++
++ virt_addr = (unsigned long)addr;
++ if (WARN_ON(virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)))
++ return;
++
++ offset = offset_in_page(virt_addr);
++ nrpages = PAGE_ALIGN(offset + size) >> PAGE_SHIFT;
++
++ idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
++ while (nrpages > 0) {
++ if (after_paging_init)
++ __late_clear_fixmap(idx);
++ else
++ __early_set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR);
++ --idx;
++ --nrpages;
++ }
++ prev_map[slot] = NULL;
++}
++#endif
++
+ /* Remap an IO device */
+ void __init __iomem *
+ early_ioremap(resource_size_t phys_addr, unsigned long size)
+diff --git a/mm/huge_memory.c b/mm/huge_memory.c
+index 763bb25e4f99..80bb2c0abeda 100644
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -39,6 +39,10 @@
+ #include <linux/memory-tiers.h>
+ #include <linux/compat.h>
+
++#ifdef CONFIG_PTP
++#include <linux/iee-func.h>
++#endif
++
+ #include <asm/tlb.h>
+ #include <asm/pgalloc.h>
+ #include "internal.h"
+@@ -2489,6 +2493,10 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
+ unsigned long addr;
+ pte_t *pte;
+ int i;
++ #ifdef CONFIG_PTP
++ pte_t *ptep;
++ unsigned long iee_addr;
++ #endif
+
+ /*
+ * Leave pmd empty until pte is filled note that it is fine to delay
+@@ -2501,7 +2509,14 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
+ old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);
+
+ pgtable = pgtable_trans_huge_withdraw(mm, pmd);
+- pmd_populate(mm, &_pmd, pgtable);
++ #ifdef CONFIG_PTP
++ ptep = (pte_t *)page_address(pgtable);
++ iee_addr = __phys_to_iee(__pa(ptep));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)ptep);
++ #endif
++ //pmd_populate(mm, &_pmd, pgtable);
++ _pmd = __pmd(__phys_to_pmd_val(page_to_phys(pgtable)) | PMD_TYPE_TABLE);
+
+ pte = pte_offset_map(&_pmd, haddr);
+ VM_BUG_ON(!pte);
+@@ -2534,6 +2549,10 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
+ unsigned long addr;
+ pte_t *pte;
+ int i;
++ #ifdef CONFIG_PTP
++ pte_t *ptep;
++ unsigned long iee_addr;
++ #endif
+
+ VM_BUG_ON(haddr & ~HPAGE_PMD_MASK);
+ VM_BUG_ON_VMA(vma->vm_start > haddr, vma);
+@@ -2671,7 +2690,14 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
+ * This's critical for some architectures (Power).
+ */
+ pgtable = pgtable_trans_huge_withdraw(mm, pmd);
+- pmd_populate(mm, &_pmd, pgtable);
++ #ifdef CONFIG_PTP
++ ptep = (pte_t *)page_to_virt(pgtable);
++ iee_addr = __phys_to_iee(__pa(ptep));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)ptep);
++ #endif
++ //pmd_populate(mm, &_pmd, pgtable);
++ _pmd = __pmd(__phys_to_pmd_val(page_to_phys(pgtable)) | PMD_TYPE_TABLE);
+
+ pte = pte_offset_map(&_pmd, haddr);
+ VM_BUG_ON(!pte);
+diff --git a/mm/init-mm.c b/mm/init-mm.c
+index 24c809379274..07d060fca6f0 100644
+--- a/mm/init-mm.c
++++ b/mm/init-mm.c
+@@ -55,3 +55,20 @@ void setup_initial_init_mm(void *start_code, void *end_code,
+ init_mm.end_data = (unsigned long)end_data;
+ init_mm.brk = (unsigned long)brk;
+ }
++
++#ifdef CONFIG_KOI
++/*
++ * This is used to init ko_mm when creating pgtable for a ko to be isolated
++ * the ko_mm belongs to a specific ko, pgdp is allocated by koi_pgd_alloc
++ */
++void init_ko_mm(struct mm_struct *ko_mm, pgd_t *pgdp) {
++ ko_mm->mm_rb = RB_ROOT;
++ ko_mm->pgd = pgdp;
++ ko_mm->mm_users = (atomic_t)ATOMIC_INIT(2);
++ ko_mm->mm_count = (atomic_t)ATOMIC_INIT(1);
++ ko_mm->mmap_lock = (struct rw_semaphore)__RWSEM_INITIALIZER(ko_mm->mmap_lock);
++ ko_mm->page_table_lock = __SPIN_LOCK_UNLOCKED(ko_mm.page_table_lock);
++ ko_mm->arg_lock = __SPIN_LOCK_UNLOCKED(ko_mm->arg_lock);
++ ko_mm->mmlist = (struct list_head)LIST_HEAD_INIT(ko_mm->mmlist);
++}
++#endif
+diff --git a/mm/memory.c b/mm/memory.c
+index 4ef917a182f9..28da89a19e30 100644
+--- a/mm/memory.c
++++ b/mm/memory.c
+@@ -80,6 +80,10 @@
+ #include <linux/userswap.h>
+ #include <linux/dynamic_pool.h>
+
++#ifdef CONFIG_PTP
++#include <linux/iee-func.h>
++#endif
++
+ #include <trace/events/kmem.h>
+
+ #include <asm/io.h>
+@@ -5872,6 +5876,11 @@ int __pud_alloc(struct mm_struct *mm, p4d_t *p4d, unsigned long address)
+
+ spin_lock(&mm->page_table_lock);
+ if (!p4d_present(*p4d)) {
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr = __phys_to_iee(__pa(new));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)new);
++ #endif
+ mm_inc_nr_puds(mm);
+ smp_wmb(); /* See comment in pmd_install() */
+ p4d_populate(mm, p4d, new);
+@@ -5896,6 +5905,11 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
+
+ ptl = pud_lock(mm, pud);
+ if (!pud_present(*pud)) {
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr = __phys_to_iee(__pa(new));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)new);
++ #endif
+ mm_inc_nr_pmds(mm);
+ smp_wmb(); /* See comment in pmd_install() */
+ pud_populate(mm, pud, new);
+diff --git a/mm/slub.c b/mm/slub.c
+index ee3e32cdb7fd..20a45a7feed5 100644
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -42,6 +42,11 @@
+ #include <kunit/test-bug.h>
+ #include <linux/sort.h>
+
++#ifdef CONFIG_IEE
++#include <linux/iee-func.h>
++#include <asm/iee-access.h>
++#endif
++
+ #include <linux/debugfs.h>
+ #include <trace/events/kmem.h>
+
+@@ -317,6 +322,7 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
+ /*
+ * Tracking user of a slab.
+ */
++#ifndef CONFIG_IEE
+ #define TRACK_ADDRS_COUNT 16
+ struct track {
+ unsigned long addr; /* Called from address */
+@@ -329,6 +335,7 @@ struct track {
+ };
+
+ enum track_item { TRACK_ALLOC, TRACK_FREE };
++#endif
+
+ #ifdef SLAB_SUPPORTS_SYSFS
+ static int sysfs_slab_add(struct kmem_cache *);
+@@ -379,7 +386,9 @@ static struct workqueue_struct *flushwq;
+ * freeptr_t represents a SLUB freelist pointer, which might be encoded
+ * and not dereferenceable if CONFIG_SLAB_FREELIST_HARDENED is enabled.
+ */
++#ifndef CONFIG_IEE
+ typedef struct { unsigned long v; } freeptr_t;
++#endif
+
+ /*
+ * Returns freelist pointer (ptr). With hardening, this is obfuscated
+@@ -464,7 +473,14 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
+ #endif
+
+ freeptr_addr = (unsigned long)kasan_reset_tag((void *)freeptr_addr);
++ #ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ iee_set_freeptr((freeptr_t *)freeptr_addr, freelist_ptr_encode(s, fp, freeptr_addr));
++ else
++ *(freeptr_t *)freeptr_addr = freelist_ptr_encode(s, fp, freeptr_addr);
++ #else
+ *(freeptr_t *)freeptr_addr = freelist_ptr_encode(s, fp, freeptr_addr);
++ #endif
+ }
+
+ /* Loop over all objects in a slab */
+@@ -809,7 +825,34 @@ static void set_track_update(struct kmem_cache *s, void *object,
+ depot_stack_handle_t handle)
+ {
+ struct track *p = get_track(s, object, alloc);
++#ifdef CONFIG_IEE
++ struct track tmp;
++#endif
+
++#ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ {
++ tmp = *p;
++ #ifdef CONFIG_STACKDEPOT
++ tmp.handle = handle;
++ #endif
++ tmp.addr = addr;
++ tmp.cpu = smp_processor_id();
++ tmp.pid = current->pid;
++ tmp.when = jiffies;
++ iee_set_track(p,&tmp);
++ }
++ else
++ {
++ #ifdef CONFIG_STACKDEPOT
++ p->handle = handle;
++ #endif
++ p->addr = addr;
++ p->cpu = smp_processor_id();
++ p->pid = current->pid;
++ p->when = jiffies;
++ }
++#else
+ #ifdef CONFIG_STACKDEPOT
+ p->handle = handle;
+ #endif
+@@ -817,6 +860,7 @@ static void set_track_update(struct kmem_cache *s, void *object,
+ p->cpu = smp_processor_id();
+ p->pid = current->pid;
+ p->when = jiffies;
++#endif
+ }
+
+ static __always_inline void set_track(struct kmem_cache *s, void *object,
+@@ -835,7 +879,14 @@ static void init_tracking(struct kmem_cache *s, void *object)
+ return;
+
+ p = get_track(s, object, TRACK_ALLOC);
++ #ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ iee_memset(p, 0, 2*sizeof(struct track));
++ else
++ memset(p, 0, 2*sizeof(struct track));
++ #else
+ memset(p, 0, 2*sizeof(struct track));
++ #endif
+ }
+
+ static void print_track(const char *s, struct track *t, unsigned long pr_time)
+@@ -1045,7 +1096,14 @@ static void init_object(struct kmem_cache *s, void *object, u8 val)
+ unsigned int poison_size = s->object_size;
+
+ if (s->flags & SLAB_RED_ZONE) {
++ #ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ iee_memset(p - s->red_left_pad, val, s->red_left_pad);
++ else
++ memset(p - s->red_left_pad, val, s->red_left_pad);
++ #else
+ memset(p - s->red_left_pad, val, s->red_left_pad);
++ #endif
+
+ if (slub_debug_orig_size(s) && val == SLUB_RED_ACTIVE) {
+ /*
+@@ -1058,12 +1116,34 @@ static void init_object(struct kmem_cache *s, void *object, u8 val)
+ }
+
+ if (s->flags & __OBJECT_POISON) {
++ #ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ {
++ iee_memset(p, POISON_FREE, poison_size - 1);
++ iee_memset(&p[poison_size - 1], POISON_END, 1);
++ }
++ else
++ {
++ memset(p, POISON_FREE, poison_size - 1);
++ p[poison_size - 1] = POISON_END;
++ }
++ #else
+ memset(p, POISON_FREE, poison_size - 1);
+ p[poison_size - 1] = POISON_END;
++ #endif
+ }
+
+- if (s->flags & SLAB_RED_ZONE)
++ if (s->flags & SLAB_RED_ZONE) {
++ #ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ iee_memset(p + poison_size, val, s->inuse - poison_size);
++ else
++ memset(p + poison_size, val, s->inuse - poison_size);
++ #else
+ memset(p + poison_size, val, s->inuse - poison_size);
++ #endif
++
++ }
+ }
+
+ static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
+@@ -1433,7 +1513,14 @@ void setup_slab_debug(struct kmem_cache *s, struct slab *slab, void *addr)
+ return;
+
+ metadata_access_enable();
++ #ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ iee_memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab));
++ else
++ memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab));
++ #else
+ memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab));
++ #endif
+ metadata_access_disable();
+ }
+
+@@ -2015,6 +2102,9 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
+ void *start, *p, *next;
+ int idx;
+ bool shuffle;
++ #ifdef CONFIG_IEE
++ unsigned int order;
++ #endif
+
+ flags &= gfp_allowed_mask;
+
+@@ -2029,6 +2119,9 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
+ alloc_gfp = (alloc_gfp | __GFP_NOMEMALLOC) & ~__GFP_RECLAIM;
+
+ slab = alloc_slab_page(alloc_gfp, node, oo);
++ #ifdef CONFIG_IEE
++ order = oo_order(oo);
++ #endif
+ if (unlikely(!slab)) {
+ oo = s->min;
+ alloc_gfp = flags;
+@@ -2037,6 +2130,9 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
+ * Try a lower order alloc if possible
+ */
+ slab = alloc_slab_page(alloc_gfp, node, oo);
++ #ifdef CONFIG_IEE
++ order = oo_order(oo);
++ #endif
+ if (unlikely(!slab))
+ return NULL;
+ stat(s, ORDER_FALLBACK);
+@@ -2046,6 +2142,45 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
+ slab->inuse = 0;
+ slab->frozen = 0;
+
++ #ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ {
++ int i;
++ for(i = 0; i < (0x1 << order); i++)
++ {
++ unsigned long iee_addr = __phys_to_iee(page_to_phys(folio_page(slab_folio(slab), i)));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)page_address(folio_page(slab_folio(slab), i)));
++ }
++ }
++
++ // If the page belongs to a task_struct, alloc token for it and set iee&lm va.
++ if(strcmp(s->name, "task_struct") == 0)
++ {
++ int i;
++ for(i = 0; i < (0x1 << order); i++)
++ {
++ void *token_addr = (void *)__phys_to_iee(page_to_phys(folio_page(slab_folio(slab), i)));
++ // Get lm va of the page.
++ void *alloc_token = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
++ iee_set_token_page_valid(token_addr, alloc_token);
++ set_iee_page_valid(__phys_to_iee(__pa(alloc_token)));
++ iee_set_logical_mem_ro((unsigned long)alloc_token);
++ }
++ }
++ #else
++ #ifdef CONFIG_KOI
++ if (strcmp(s->name, "task_struct") == 0) {
++ int i;
++ for (i = 0; i < (0x1 << order); i++) {
++ void *token_addr = __phys_to_virt(page_to_phys(page + i)) + koi_offset;
++ void *alloc_token = __get_free_page(GFP_KERNEL | __GFP_ZERO);
++ koi_add_page_mapping(token_addr, alloc_token);
++ }
++ }
++ #endif
++ #endif
++
+ account_slab(slab, oo_order(oo), s, flags);
+
+ slab->slab_cache = s;
+@@ -2098,6 +2233,67 @@ static void __free_slab(struct kmem_cache *s, struct slab *slab)
+ __folio_clear_slab(folio);
+ mm_account_reclaimed_pages(pages);
+ unaccount_slab(slab, order, s);
++
++ #ifdef CONFIG_IEE
++ if(IS_ENABLED(CONFIG_CREDP) && strcmp(s->name, "cred_jar") == 0)
++ {
++ int i;
++ for(i = 0; i < (0x1 << order); i++)
++ {
++ unsigned long iee_addr = __phys_to_iee(page_to_phys(folio_page(folio, i)));
++ set_iee_page_invalid(iee_addr);
++ iee_set_logical_mem_rw((unsigned long)page_address(folio_page(folio, i)));
++ }
++ }
++ // If the page containing this token is empty, free it and restore iee&lm va.
++ if(strcmp(s->name, "task_struct") == 0)
++ {
++ int i;
++ for(i = 0; i < (0x1 << order); i++)
++ {
++ void *token_addr = (void *)__phys_to_iee(page_to_phys(folio_page(folio, i)));
++ unsigned long flags;
++ unsigned long res;
++ local_irq_save(flags);
++ asm volatile("at s1e1r, %0"::"r"(token_addr));
++ isb();
++ res = read_sysreg(par_el1);
++ local_irq_restore(flags);
++ if(!(res & 0x1))
++ {
++ // Get lm va of the page.
++ void *token_page = __va(res & PTE_ADDR_MASK);
++ iee_set_token_page_invalid(token_addr);
++ set_iee_page_invalid(__phys_to_iee(__pa(token_page)));
++ iee_set_logical_mem_rw((unsigned long)token_page);
++ free_page((unsigned long)token_page);
++ }
++ }
++ }
++ #else
++ #ifdef CONFIG_KOI
++ if(strcmp(s->name, "task_struct") == 0)
++ {
++ int i;
++ for(i = 0; i < (0x1 << order); i++)
++ {
++ void *token_addr = __phys_to_virt(page_to_phys(page + i)) + koi_offset;
++ unsigned long flags;
++ local_irq_save(flags);
++ asm volatile("at s1e1r, %0"::"r"(token_addr));
++ isb();
++ unsigned long res = read_sysreg(par_el1);
++ local_irq_restore(flags);
++ if(!(res & 0x1))
++ {
++ koi_remove_page_mapping(token_addr);
++ free_page(__va(res & PTE_ADDR_MASK));
++ }
++ }
++ }
++ #endif
++ #endif
++
+ __free_pages(&folio->page, order);
+ }
+
+diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
+index a2cbe44c48e1..7cf05d293312 100644
+--- a/mm/sparse-vmemmap.c
++++ b/mm/sparse-vmemmap.c
+@@ -28,6 +28,10 @@
+ #include <linux/vmalloc.h>
+ #include <linux/sched.h>
+
++#ifdef CONFIG_PTP
++#include <linux/iee-func.h>
++#endif
++
+ #include <asm/dma.h>
+ #include <asm/pgalloc.h>
+
+@@ -146,6 +150,9 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node,
+ struct page *reuse)
+ {
+ pte_t *pte = pte_offset_kernel(pmd, addr);
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
+ if (pte_none(ptep_get(pte))) {
+ pte_t entry;
+ void *p;
+@@ -167,6 +174,11 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node,
+ get_page(reuse);
+ p = page_to_virt(reuse);
+ }
++#ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(p));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)p);
++#endif
+ entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL);
+ set_pte_at(&init_mm, addr, pte, entry);
+ }
+@@ -176,11 +188,20 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node,
+ static void * __meminit vmemmap_alloc_block_zero(unsigned long size, int node)
+ {
+ void *p = vmemmap_alloc_block(size, node);
++ #ifdef CONFIG_PTP
++ unsigned long iee_addr;
++ #endif
+
+ if (!p)
+ return NULL;
+ memset(p, 0, size);
+
++ #ifdef CONFIG_PTP
++ iee_addr = __phys_to_iee(__pa(p));
++ set_iee_page_valid(iee_addr);
++ iee_set_logical_mem_ro((unsigned long)p);
++ #endif
++
+ return p;
+ }
+
+diff --git a/mm/vmalloc.c b/mm/vmalloc.c
+index e6058942a084..27a006728009 100644
+--- a/mm/vmalloc.c
++++ b/mm/vmalloc.c
+@@ -3431,7 +3431,7 @@ static int vmap_pfn_apply(pte_t *pte, unsigned long addr, void *private)
+
+ if (WARN_ON_ONCE(pfn_valid(pfn)))
+ return -EINVAL;
+-
++
+ ptent = pte_mkspecial(pfn_pte(pfn, data->prot));
+ set_pte_at(&init_mm, addr, pte, ptent);
+
+diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
+index c42ddd85ff1f..4714b4f2be08 100644
+--- a/net/dns_resolver/dns_key.c
++++ b/net/dns_resolver/dns_key.c
+@@ -34,6 +34,10 @@
+ #include <keys/user-type.h>
+ #include "internal.h"
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ MODULE_DESCRIPTION("DNS Resolver");
+ MODULE_AUTHOR("Wang Lei");
+ MODULE_LICENSE("GPL");
+@@ -365,8 +369,13 @@ static int __init init_dns_resolver(void)
+ /* instruct request_key() to use this special keyring as a cache for
+ * the results it looks up */
+ set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_thread_keyring(cred,keyring);
++ iee_set_cred_jit_keyring(cred,KEY_REQKEY_DEFL_THREAD_KEYRING);
++ #else
+ cred->thread_keyring = keyring;
+ cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
++ #endif
+ dns_resolver_cache = cred;
+
+ kdebug("DNS resolver keyring: %d\n", key_serial(keyring));
+diff --git a/security/commoncap.c b/security/commoncap.c
+index bc0521104197..d7d3b7cc13e8 100644
+--- a/security/commoncap.c
++++ b/security/commoncap.c
+@@ -26,6 +26,10 @@
+ #include <linux/personality.h>
+ #include <linux/mnt_idmapping.h>
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ /*
+ * If a non-root user executes a setuid-root binary in
+ * !secure(SECURE_NOROOT) mode, then we raise capabilities.
+@@ -266,6 +270,15 @@ int cap_capset(struct cred *new,
+ if (!cap_issubset(*effective, *permitted))
+ return -EPERM;
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,*effective);
++ iee_set_cred_cap_inheritable(new,*inheritable);
++ iee_set_cred_cap_permitted(new,*permitted);
++
++ iee_set_cred_cap_ambient(new,cap_intersect(new->cap_ambient,
++ cap_intersect(*permitted,
++ *inheritable)));
++ #else
+ new->cap_effective = *effective;
+ new->cap_inheritable = *inheritable;
+ new->cap_permitted = *permitted;
+@@ -277,6 +290,7 @@ int cap_capset(struct cred *new,
+ new->cap_ambient = cap_intersect(new->cap_ambient,
+ cap_intersect(*permitted,
+ *inheritable));
++ #endif
+ if (WARN_ON(!cap_ambient_invariant_ok(new)))
+ return -EINVAL;
+ return 0;
+@@ -601,9 +615,16 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
+ * pP' = (X & fP) | (pI & fI)
+ * The addition of pA' is handled later.
+ */
++#ifdef CONFIG_CREDP
++ kernel_cap_t temp = new->cap_permitted;
++ temp.val = (new->cap_bset.val & caps->permitted.val) |
++ (new->cap_inheritable.val & caps->inheritable.val);
++ iee_set_cred_cap_permitted(new,temp);
++#else
+ new->cap_permitted.val =
+ (new->cap_bset.val & caps->permitted.val) |
+ (new->cap_inheritable.val & caps->inheritable.val);
++#endif
+
+ if (caps->permitted.val & ~new->cap_permitted.val)
+ /* insufficient to execute correctly */
+@@ -726,7 +747,15 @@ static int get_file_caps(struct linux_binprm *bprm, struct file *file,
+ int rc = 0;
+ struct cpu_vfs_cap_data vcaps;
+
++ #ifdef CONFIG_CREDP
++ do {
++ kernel_cap_t tmp_cap = bprm->cred->cap_permitted;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_permitted(bprm->cred, tmp_cap);
++ } while (0);
++ #else
+ cap_clear(bprm->cred->cap_permitted);
++ #endif
+
+ if (!file_caps_enabled)
+ return 0;
+@@ -757,7 +786,15 @@ static int get_file_caps(struct linux_binprm *bprm, struct file *file,
+
+ out:
+ if (rc)
++ #ifdef CONFIG_CREDP
++ do {
++ kernel_cap_t tmp_cap = bprm->cred->cap_permitted;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_permitted(bprm->cred, tmp_cap);
++ } while (0);
++ #else
+ cap_clear(bprm->cred->cap_permitted);
++ #endif
+
+ return rc;
+ }
+@@ -809,8 +846,13 @@ static void handle_privileged_root(struct linux_binprm *bprm, bool has_fcap,
+ */
+ if (__is_eff(root_uid, new) || __is_real(root_uid, new)) {
+ /* pP' = (cap_bset & ~0) | (pI & ~0) */
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_permitted(new,cap_combine(old->cap_bset,
++ old->cap_inheritable));
++ #else
+ new->cap_permitted = cap_combine(old->cap_bset,
+ old->cap_inheritable);
++ #endif
+ }
+ /*
+ * If only the real uid is 0, we do not set the effective bit.
+@@ -919,34 +961,71 @@ int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file)
+ /* downgrade; they get no more than they had, and maybe less */
+ if (!ns_capable(new->user_ns, CAP_SETUID) ||
+ (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_euid(new,new->uid);
++ iee_set_cred_egid(new,new->gid);
++ #else
+ new->euid = new->uid;
+ new->egid = new->gid;
++ #endif
+ }
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_permitted(new,cap_intersect(new->cap_permitted,
++ old->cap_permitted));
++ #else
+ new->cap_permitted = cap_intersect(new->cap_permitted,
+ old->cap_permitted);
++ #endif
+ }
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_fsuid(new,new->euid);
++ iee_set_cred_suid(new,new->euid);
++ iee_set_cred_fsgid(new,new->egid);
++ iee_set_cred_sgid(new,new->egid);
++ #else
+ new->suid = new->fsuid = new->euid;
+ new->sgid = new->fsgid = new->egid;
++ #endif
+
+ /* File caps or setid cancels ambient. */
+ if (has_fcap || is_setid)
++ #ifdef CONFIG_CREDP
++ do {
++ kernel_cap_t tmp_cap = new->cap_ambient;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_ambient(new, tmp_cap);
++ } while (0);
++ #else
+ cap_clear(new->cap_ambient);
++ #endif
+
+ /*
+ * Now that we've computed pA', update pP' to give:
+ * pP' = (X & fP) | (pI & fI) | pA'
+ */
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_permitted(new,cap_combine(new->cap_permitted, new->cap_ambient));
++ #else
+ new->cap_permitted = cap_combine(new->cap_permitted, new->cap_ambient);
++ #endif
+
+ /*
+ * Set pE' = (fE ? pP' : pA'). Because pA' is zero if fE is set,
+ * this is the same as pE' = (fE ? pP' : 0) | pA'.
+ */
+ if (effective)
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,new->cap_permitted);
++ #else
+ new->cap_effective = new->cap_permitted;
++ #endif
+ else
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,new->cap_ambient);
++ #else
+ new->cap_effective = new->cap_ambient;
++ #endif
+
+ if (WARN_ON(!cap_ambient_invariant_ok(new)))
+ return -EPERM;
+@@ -957,7 +1036,11 @@ int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file)
+ return ret;
+ }
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_securebits(new,new->securebits & ~issecure_mask(SECURE_KEEP_CAPS));
++ #else
+ new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
++ #endif
+
+ if (WARN_ON(!cap_ambient_invariant_ok(new)))
+ return -EPERM;
+@@ -1092,8 +1175,21 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
+ !uid_eq(new->euid, root_uid) &&
+ !uid_eq(new->suid, root_uid))) {
+ if (!issecure(SECURE_KEEP_CAPS)) {
++ #ifdef CONFIG_CREDP
++ do {
++ kernel_cap_t tmp_cap = new->cap_permitted;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_permitted(new, tmp_cap);
++ } while (0);
++ do {
++ kernel_cap_t tmp_cap = new->cap_effective;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_effective(new, tmp_cap);
++ } while (0);
++ #else
+ cap_clear(new->cap_permitted);
+ cap_clear(new->cap_effective);
++ #endif
+ }
+
+ /*
+@@ -1101,12 +1197,32 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
+ * by exec to drop capabilities. We should make sure that
+ * this remains the case.
+ */
++ #ifdef CONFIG_CREDP
++ do {
++ kernel_cap_t tmp_cap = new->cap_ambient;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_ambient(new, tmp_cap);
++ } while (0);
++ #else
+ cap_clear(new->cap_ambient);
++ #endif
+ }
+ if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid))
++ #ifdef CONFIG_CREDP
++ do {
++ kernel_cap_t tmp_cap = new->cap_effective;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_effective(new, tmp_cap);
++ } while (0);
++ #else
+ cap_clear(new->cap_effective);
++ #endif
+ if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,new->cap_permitted);
++ #else
+ new->cap_effective = new->cap_permitted;
++ #endif
+ }
+
+ /**
+@@ -1142,13 +1258,22 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
+ if (!issecure(SECURE_NO_SETUID_FIXUP)) {
+ kuid_t root_uid = make_kuid(old->user_ns, 0);
+ if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,cap_drop_fs_set(new->cap_effective));
++ #else
+ new->cap_effective =
+ cap_drop_fs_set(new->cap_effective);
++ #endif
+
+ if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid))
++ #ifdef CONFIG_CREDP
++ iee_set_cred_cap_effective(new,cap_raise_fs_set(new->cap_effective,
++ new->cap_permitted));
++ #else
+ new->cap_effective =
+ cap_raise_fs_set(new->cap_effective,
+ new->cap_permitted);
++ #endif
+ }
+ break;
+
+@@ -1243,7 +1368,15 @@ static int cap_prctl_drop(unsigned long cap)
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
++ #ifdef CONFIG_CREDP
++ {
++ kernel_cap_t tmp = new->cap_bset;
++ cap_lower(tmp, cap);
++ iee_set_cred_cap_bset(new, tmp);
++ }
++ #else
+ cap_lower(new->cap_bset, cap);
++ #endif
+ return commit_creds(new);
+ }
+
+@@ -1319,7 +1452,11 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
++ #ifdef CONFIG_CREDP
++ iee_set_cred_securebits(new,arg2);
++ #else
+ new->securebits = arg2;
++ #endif
+ return commit_creds(new);
+
+ case PR_GET_SECUREBITS:
+@@ -1338,9 +1475,17 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+ if (!new)
+ return -ENOMEM;
+ if (arg2)
++ #ifdef CONFIG_CREDP
++ iee_set_cred_securebits(new,new->securebits | issecure_mask(SECURE_KEEP_CAPS));
++ #else
+ new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
++ #endif
+ else
++ #ifdef CONFIG_CREDP
++ iee_set_cred_securebits(new,new->securebits & ~issecure_mask(SECURE_KEEP_CAPS));
++ #else
+ new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
++ #endif
+ return commit_creds(new);
+
+ case PR_CAP_AMBIENT:
+@@ -1351,7 +1496,15 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
++ #ifdef CONFIG_CREDP
++ do {
++ kernel_cap_t tmp_cap = new->cap_ambient;
++ tmp_cap.val = 0;
++ iee_set_cred_cap_ambient(new, tmp_cap);
++ } while (0);
++ #else
+ cap_clear(new->cap_ambient);
++ #endif
+ return commit_creds(new);
+ }
+
+@@ -1375,9 +1528,25 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+ if (!new)
+ return -ENOMEM;
+ if (arg2 == PR_CAP_AMBIENT_RAISE)
++ #ifdef CONFIG_CREDP
++ {
++ kernel_cap_t tmp = new->cap_ambient;
++ cap_raise(tmp, arg3);
++ iee_set_cred_cap_ambient(new, tmp);
++ }
++ #else
+ cap_raise(new->cap_ambient, arg3);
++ #endif
+ else
++ #ifdef CONFIG_CREDP
++ {
++ kernel_cap_t tmp = new->cap_ambient;
++ cap_lower(tmp, arg3);
++ iee_set_cred_cap_ambient(new, tmp);
++ }
++ #else
+ cap_lower(new->cap_ambient, arg3);
++ #endif
+ return commit_creds(new);
+ }
+
+diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
+index 19be69fa4d05..6cb164dfc19b 100644
+--- a/security/keys/keyctl.c
++++ b/security/keys/keyctl.c
+@@ -23,6 +23,9 @@
+ #include <linux/uaccess.h>
+ #include <keys/request_key_auth-type.h>
+ #include "internal.h"
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
+
+ #define KEY_MAX_DESC_SIZE 4096
+
+@@ -1155,7 +1158,11 @@ static int keyctl_change_reqkey_auth(struct key *key)
+ return -ENOMEM;
+
+ key_put(new->request_key_auth);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_request_key_auth(new,key_get(key));
++ #else
+ new->request_key_auth = key_get(key);
++ #endif
+
+ return commit_creds(new);
+ }
+@@ -1432,7 +1439,11 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
+ }
+
+ set:
++ #ifdef CONFIG_CREDP
++ iee_set_cred_jit_keyring(new,reqkey_defl);
++ #else
+ new->jit_keyring = reqkey_defl;
++ #endif
+ commit_creds(new);
+ return old_setting;
+ error:
+@@ -1644,9 +1655,17 @@ long keyctl_session_to_parent(void)
+ cred = cred_alloc_blank();
+ if (!cred)
+ goto error_keyring;
++ #ifdef CONFIG_CREDP
++ newwork = (struct rcu_head *)(cred->rcu.func);
++ #else
+ newwork = &cred->rcu;
++ #endif
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_session_keyring(cred,key_ref_to_ptr(keyring_r));
++ #else
+ cred->session_keyring = key_ref_to_ptr(keyring_r);
++ #endif
+ keyring_r = NULL;
+ init_task_work(newwork, key_change_session_keyring);
+
+@@ -1705,7 +1724,11 @@ long keyctl_session_to_parent(void)
+ write_unlock_irq(&tasklist_lock);
+ rcu_read_unlock();
+ if (oldwork)
++ #ifdef CONFIG_CREDP
++ put_cred(*(struct cred **)(oldwork + 1));
++ #else
+ put_cred(container_of(oldwork, struct cred, rcu));
++ #endif
+ if (newwork)
+ put_cred(cred);
+ return ret;
+diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
+index b5d5333ab330..aaa2a2347d84 100644
+--- a/security/keys/process_keys.c
++++ b/security/keys/process_keys.c
+@@ -19,6 +19,10 @@
+ #include <keys/request_key_auth-type.h>
+ #include "internal.h"
+
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
++
+ /* Session keyring create vs join semaphore */
+ static DEFINE_MUTEX(key_session_mutex);
+
+@@ -232,7 +236,11 @@ int install_thread_keyring_to_cred(struct cred *new)
+ if (IS_ERR(keyring))
+ return PTR_ERR(keyring);
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_thread_keyring(new,keyring);
++ #else
+ new->thread_keyring = keyring;
++ #endif
+ return 0;
+ }
+
+@@ -279,7 +287,11 @@ int install_process_keyring_to_cred(struct cred *new)
+ if (IS_ERR(keyring))
+ return PTR_ERR(keyring);
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_process_keyring(new,keyring);
++ #else
+ new->process_keyring = keyring;
++ #endif
+ return 0;
+ }
+
+@@ -338,7 +350,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
+
+ /* install the keyring */
+ old = cred->session_keyring;
++ #ifdef CONFIG_CREDP
++ iee_set_cred_session_keyring(cred,keyring);
++ #else
+ cred->session_keyring = keyring;
++ #endif
+
+ if (old)
+ key_put(old);
+@@ -911,7 +927,11 @@ long join_session_keyring(const char *name)
+ void key_change_session_keyring(struct callback_head *twork)
+ {
+ const struct cred *old = current_cred();
++ #ifdef CONFIG_CREDP
++ struct cred *new = *(struct cred **)(twork + 1);
++ #else
+ struct cred *new = container_of(twork, struct cred, rcu);
++ #endif
+
+ if (unlikely(current->flags & PF_EXITING)) {
+ put_cred(new);
+@@ -925,6 +945,38 @@ void key_change_session_keyring(struct callback_head *twork)
+ return;
+ }
+
++ /* If get_ucounts fails more bits are needed in the refcount */
++ if (unlikely(!get_ucounts(old->ucounts))) {
++ WARN_ONCE(1, "In %s get_ucounts failed\n", __func__);
++ put_cred(new);
++ return;
++ }
++
++ #ifdef CONFIG_CREDP
++ iee_set_cred_uid(new,old-> uid);
++ iee_set_cred_euid(new,old-> euid);
++ iee_set_cred_suid(new,old-> suid);
++ iee_set_cred_fsuid(new,old->fsuid);
++ iee_set_cred_gid(new,old-> gid);
++ iee_set_cred_egid(new,old-> egid);
++ iee_set_cred_sgid(new,old-> sgid);
++ iee_set_cred_fsgid(new,old->fsgid);
++ iee_set_cred_user(new,get_uid(old->user));
++ iee_set_cred_ucounts(new, old->ucounts);
++ iee_set_cred_user_ns(new,get_user_ns(old->user_ns));
++ iee_set_cred_group_info(new,get_group_info(old->group_info));
++
++ iee_set_cred_securebits(new,old->securebits);
++ iee_set_cred_cap_inheritable(new,old->cap_inheritable);
++ iee_set_cred_cap_permitted(new,old->cap_permitted);
++ iee_set_cred_cap_effective(new,old->cap_effective);
++ iee_set_cred_cap_ambient(new,old->cap_ambient);
++ iee_set_cred_cap_bset(new,old->cap_bset);
++
++ iee_set_cred_jit_keyring(new,old->jit_keyring);
++ iee_set_cred_thread_keyring(new,key_get(old->thread_keyring));
++ iee_set_cred_process_keyring(new,key_get(old->process_keyring));
++ #else
+ new-> uid = old-> uid;
+ new-> euid = old-> euid;
+ new-> suid = old-> suid;
+@@ -948,6 +1000,7 @@ void key_change_session_keyring(struct callback_head *twork)
+ new->jit_keyring = old->jit_keyring;
+ new->thread_keyring = key_get(old->thread_keyring);
+ new->process_keyring = key_get(old->process_keyring);
++ #endif
+
+ security_transfer_creds(new, old);
+
+diff --git a/security/security.c b/security/security.c
+index 407b51719f79..74ffd7ea3f37 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -30,6 +30,9 @@
+ #include <linux/string.h>
+ #include <linux/msg.h>
+ #include <net/flow.h>
++#ifdef CONFIG_CREDP
++#include <asm/iee-cred.h>
++#endif
+
+ /* How many LSMs were built into the kernel? */
+ #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
+@@ -570,11 +573,19 @@ EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
+ static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+ {
+ if (blob_sizes.lbs_cred == 0) {
++ #ifdef CONFIG_CREDP
++ iee_set_cred_security(cred,NULL);
++ #else
+ cred->security = NULL;
++ #endif
+ return 0;
+ }
+
++ #ifdef CONFIG_CREDP
++ iee_set_cred_security(cred,kzalloc(blob_sizes.lbs_cred, gfp));
++ #else
+ cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
++ #endif
+ if (cred->security == NULL)
+ return -ENOMEM;
+ return 0;
+@@ -2950,7 +2961,11 @@ void security_cred_free(struct cred *cred)
+ call_void_hook(cred_free, cred);
+
+ kfree(cred->security);
++ #ifdef CONFIG_CREDP
++ iee_set_cred_security(cred,NULL);
++ #else
+ cred->security = NULL;
++ #endif
+ }
+
+ /**
+--
+2.34.1
+
diff --git a/cpupower.config b/cpupower.config
new file mode 100644
index 0000000..8629a4a
--- /dev/null
+++ b/cpupower.config
@@ -0,0 +1,3 @@
+# See 'cpupower help' and cpupower(1) for more info
+CPUPOWER_START_OPTS="frequency-set -g performance"
+CPUPOWER_STOP_OPTS="frequency-set -g ondemand"
diff --git a/cpupower.service b/cpupower.service
new file mode 100644
index 0000000..5f10ab7
--- /dev/null
+++ b/cpupower.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Configure CPU power related settings
+After=syslog.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+EnvironmentFile=/etc/sysconfig/cpupower
+ExecStart=/usr/bin/cpupower $CPUPOWER_START_OPTS
+ExecStop=/usr/bin/cpupower $CPUPOWER_STOP_OPTS
+
+[Install]
+WantedBy=multi-user.target
diff --git a/haoc-kernel.spec b/haoc-kernel.spec
new file mode 100644
index 0000000..f1a9242
--- /dev/null
+++ b/haoc-kernel.spec
@@ -0,0 +1,10943 @@
+%define with_signmodules 1
+%define with_kabichk 0
+
+# Default without toolchain_clang
+%bcond_with toolchain_clang
+
+%if %{with toolchain_clang}
+%global toolchain clang
+%endif
+
+%bcond_with clang_lto
+
+%if %{with clang_lto} && "%{toolchain}" != "clang"
+{error:clang_lto requires --with toolchain_clang}
+%endif
+
+%define modsign_cmd %{SOURCE10}
+
+%if 0%{?openEuler_sign_rsa}
+# Use the open-source signature when the EBS permission is insufficient.
+# Now only the admin user in EBS can send the signature request. But the
+# user triggering the acces control build task and the personal build
+# task is non-admin. Inorder to avoid build failures caused by failed
+# signing, use the open-source signature.
+# The flag_openEuler_has_sign_perm used in the rpm execution phase
+# The openEuler_has_sign_perm used in the rpm execution phase
+
+%define openEuler_check_EBS_perm openEuler_has_sign_perm=0 \
+echo "" >> test_openEuler_sign.ko \
+sh /usr/lib/rpm/brp-ebs-sign --module test_openEuler_sign.ko || \
+[ $? -ne 2 ] && openEuler_has_sign_perm=1 \
+%global flag_openEuler_has_sign_perm $openEuler_has_sign_perm \
+rm -f test_openEuler_sign.ko test_openEuler_sign.ko.sig
+%endif
+
+%global Arch $(echo %{_host_cpu} | sed -e s/i.86/x86/ -e s/x86_64/x86/ -e s/aarch64.*/arm64/ -e s/riscv.*/riscv/ -e s/powerpc64le/powerpc/ -e s/loongarch64/loongarch/)
+
+%global KernelVer %{version}-%{release}.%{_target_cpu}
+%global debuginfodir /usr/lib/debug
+
+%global upstream_version 6.6
+%global upstream_sublevel 0
+%global devel_release 27
+%global maintenance_release .0.0
+%global pkg_release .32
+
+%global openeuler_lts 1
+%global openeuler_major 2403
+%global openeuler_minor 0
+
+#
+# Support input parameter to overwrite the preceding version numbers.
+#
+
+%bcond_with openeuler_version
+
+%if %{with openeuler_version}
+%global openeuler_lts %{?_openeuler_lts} %{?!_openeuler_lts: 0}
+%global openeuler_major %{?_openeuler_major} %{?!_openeuler_major: 0}
+%global openeuler_minor %{?_openeuler_minor} %{?!_openeuler_minor: 0}
+%endif
+
+%define with_debuginfo 1
+# Do not recompute the build-id of vmlinux in find-debuginfo.sh
+%global _missing_build_ids_terminate_build 1
+%global _no_recompute_build_ids 1
+%undefine _include_minidebuginfo
+%undefine _include_gdb_index
+%undefine _unique_build_ids
+
+%define with_source 1
+
+%define with_python2 0
+
+# failed if there is new config options
+%define listnewconfig_fail 0
+
+%ifarch aarch64
+%define with_64kb %{?_with_64kb: 1} %{?!_with_64kb: 0}
+%if %{with_64kb}
+%global package64kb -64kb
+%endif
+%else
+%define with_64kb 0
+%endif
+
+#default is enabled. You can disable it with --without option
+%define with_perf %{?_without_perf: 0} %{?!_without_perf: 1}
+
+Name: haoc-kernel
+Version: 6.6.0
+Release: %{devel_release}%{?maintenance_release}%{?pkg_release}
+Summary: Linux Kernel
+License: GPLv2
+URL: http://www.kernel.org/
+Source0: kernel.tar.xz
+Source10: sign-modules
+Source11: x509.genkey
+Source12: extra_certificates
+
+%if 0%{?openEuler_sign_rsa}
+Source15: openeuler_kernel_cert.cer
+Source16: sign-modules-openeuler
+%endif
+
+%if 0%{?with_kabichk}
+Source18: check-kabi
+Source20: Module.kabi_aarch64
+Source21: Module.kabi_x86_64
+%endif
+
+Source200: mkgrub-menu-aarch64.sh
+
+Source2000: cpupower.service
+Source2001: cpupower.config
+
+%if 0%{?with_patch}
+Source9000: apply-patches
+Source9001: guards
+Source9002: series.conf
+Source9998: patches.tar.bz2
+%endif
+
+Patch0001: 0001-riscv-kernel.patch
+Patch0002: 0002-cpupower-clang-compile-support.patch
+Patch0003: 0003-x86_energy_perf_policy-clang-compile-support.patch
+Patch0004: 0004-turbostat-clang-compile-support.patch
+Patch0005: 0005-haoc-kernel.patch
+
+#BuildRequires:
+BuildRequires: module-init-tools, patch >= 2.5.4, bash >= 2.03, tar
+BuildRequires: bzip2, xz, findutils, gzip, m4, perl, make >= 3.78, diffutils, gawk
+BuildRequires: libcap-devel, libcap-ng-devel, rsync
+BuildRequires: gcc >= 3.4.2, binutils >= 2.12
+BuildRequires: hostname, net-tools, bc
+BuildRequires: xmlto, asciidoc
+BuildRequires: openssl-devel openssl
+BuildRequires: hmaccalc
+BuildRequires: ncurses-devel
+#BuildRequires: pesign >= 0.109-4
+BuildRequires: elfutils-libelf-devel
+BuildRequires: rpm >= 4.14.2
+#BuildRequires: sparse >= 0.4.1
+%if 0%{?with_python2}
+BuildRequires: python-devel
+%endif
+
+BuildRequires: elfutils-devel zlib-devel binutils-devel newt-devel perl(ExtUtils::Embed) bison
+BuildRequires: audit-libs-devel libpfm-devel libtraceevent-devel
+BuildRequires: pciutils-devel gettext
+BuildRequires: rpm-build, elfutils
+BuildRequires: numactl-devel python3-devel glibc-static python3-docutils
+BuildRequires: perl-generators perl(Carp) libunwind-devel gtk2-devel libbabeltrace-devel java-1.8.0-openjdk java-1.8.0-openjdk-devel perl-devel
+
+AutoReq: no
+AutoProv: yes
+
+Conflicts: device-mapper-libs < 1.02.63-2 e2fsprogs < 1.37-4 initscripts < 7.23 iptables < 1.3.2-1
+Conflicts: ipw2200-firmware < 2.4 isdn4k-utils < 3.2-32 iwl4965-firmware < 228.57.2 jfsutils < 1.1.7-2
+Conflicts: mdadm < 3.2.1-5 nfs-utils < 1.0.7-12 oprofile < 0.9.1-2 ppp < 2.4.3-3 procps < 3.2.5-6.3
+Conflicts: reiserfs-utils < 3.6.19-2 selinux-policy-targeted < 1.25.3-14 squashfs-tools < 4.0
+Conflicts: udev < 063-6 util-linux < 2.12 wireless-tools < 29-3 xfsprogs < 2.6.13-4
+
+Provides: kernel-%{_target_cpu} = %{version}-%{release} kernel-drm = 4.3.0 kernel-drm-nouveau = 16 kernel-modeset = 1
+Provides: kernel-uname-r = %{KernelVer} kernel=%{KernelVer}
+
+Requires: dracut >= 001-7 grubby >= 8.28-2 initscripts >= 8.11.1-1 linux-firmware >= 20100806-2 module-init-tools >= 3.16-2
+
+ExclusiveArch: noarch aarch64 i686 x86_64 riscv64 ppc64le loongarch64
+ExclusiveOS: Linux
+
+%if %{with_perf}
+BuildRequires: flex xz-devel libzstd-devel
+BuildRequires: java-devel
+%ifarch aarch64
+BuildRequires: OpenCSD
+%endif
+%endif
+
+BuildRequires: dwarves
+BuildRequires: clang >= 10.0.0
+BuildRequires: llvm
+BuildRequires: llvm-devel
+%if %{with clang_lto}
+BuildRequires: lld
+%endif
+
+%description
+The Linux Kernel, the operating system core itself.
+
+%package headers
+Summary: Header files for the Linux kernel for use by glibc
+Obsoletes: glibc-kernheaders < 3.0-46
+Provides: glibc-kernheaders = 3.0-46
+%description headers
+Kernel-headers includes the C header files that specify the interface
+between the Linux kernel and userspace libraries and programs. The
+header files define structures and constants that are needed for
+building most standard programs and are also needed for rebuilding the
+glibc package.
+
+
+%package devel
+Summary: Development package for building kernel modules to match the %{KernelVer} kernel
+AutoReqProv: no
+Provides: kernel-devel-uname-r = %{KernelVer}
+Provides: kernel-devel-%{_target_cpu} = %{version}-%{release}
+Requires: perl findutils
+
+%description devel
+This package provides kernel headers and makefiles sufficient to build modules
+against the %{KernelVer} kernel package.
+
+%package tools
+Summary: Assortment of tools for the Linux kernel
+Provides: %{name}-tools-libs
+Obsoletes: %{name}-tools-libs
+Provides: cpufreq-utils = 1:009-0.6.p1
+Provides: cpufrequtils = 1:009-0.6.p1
+Obsoletes: cpufreq-utils < 1:009-0.6.p1
+Obsoletes: cpufrequtils < 1:009-0.6.p1
+Obsoletes: cpuspeed < 1:1.5-16
+%description tools
+This package contains the tools/ directory from the kernel source
+and the supporting documentation.
+
+%package tools-devel
+Summary: Assortment of tools for the Linux kernel
+Requires: %{name}-tools = %{version}-%{release}
+Requires: %{name}-tools-libs = %{version}-%{release}
+Provides: %{name}-tools-libs-devel = %{version}-%{release}
+Obsoletes: %{name}-tools-libs-devel
+%description tools-devel
+This package contains the development files for the tools/ directory from
+the kernel source.
+
+%if %{with_perf}
+%package -n perf
+Summary: Performance monitoring for the Linux kernel
+%description -n perf
+This package contains the perf tool, which enables performance monitoring
+of the Linux kernel.
+
+%if 0%{?with_python2}
+%package -n python2-perf
+Provides: python-perf = %{version}-%{release}
+Obsoletes: python-perf
+Summary: Python bindings for apps which will manipulate perf events
+
+%description -n python2-perf
+A Python module that permits applications written in the Python programming
+language to use the interface to manipulate perf events.
+%endif
+
+%package -n python3-perf
+Summary: Python bindings for apps which will manipulate perf events
+%description -n python3-perf
+A Python module that permits applications written in the Python programming
+language to use the interface to manipulate perf events.
+# with_perf
+%endif
+
+%package -n bpftool
+Summary: Inspection and simple manipulation of eBPF programs and maps
+%description -n bpftool
+This package contains the bpftool, which allows inspection and simple
+manipulation of eBPF programs and maps.
+
+%package source
+Summary: the kernel source
+%description source
+This package contains vaious source files from the kernel.
+
+%if 0%{?with_debuginfo}
+%define _debuginfo_template %{nil}
+%define _debuginfo_subpackages 0
+
+%define debuginfo_template(n:) \
+%package -n %{-n*}-debuginfo\
+Summary: Debug information for package %{-n*}\
+Group: Development/Debug\
+AutoReq: 0\
+AutoProv: 1\
+%description -n %{-n*}-debuginfo\
+This package provides debug information for package %{-n*}.\
+Debug information is useful when developing applications that use this\
+package or when debugging this package.\
+%{nil}
+
+%debuginfo_template -n kernel
+%files -n kernel-debuginfo -f kernel-debugfiles.list -f debugfiles.list
+%{expand:%%global _find_debuginfo_opts %{?_find_debuginfo_opts} --keep-section '.BTF' -p '.*/%{KernelVer}/.*|.*/vmlinux|XXX' -o kernel-debugfiles.list}
+
+%debuginfo_template -n bpftool
+%files -n bpftool-debuginfo -f bpftool-debugfiles.list
+%{expand:%%global _find_debuginfo_opts %{?_find_debuginfo_opts} -p '.*%{_sbindir}/bpftool.*(\.debug)?|XXX' -o bpftool-debugfiles.list}
+
+%debuginfo_template -n kernel-tools
+%files -n kernel-tools-debuginfo -f kernel-tools-debugfiles.list
+%{expand:%%global _find_debuginfo_opts %{?_find_debuginfo_opts} -p '.*%{_bindir}/centrino-decode.*(\.debug)?|.*%{_bindir}/powernow-k8-decode.*(\.debug)?|.*%{_bindir}/cpupower.*(\.debug)?|.*%{_libdir}/libcpupower.*|.*%{_libdir}/libcpupower.*|.*%{_bindir}/turbostat.(\.debug)?|.*%{_bindir}/.*gpio.*(\.debug)?|.*%{_bindir}/.*iio.*(\.debug)?|.*%{_bindir}/tmon.*(.debug)?|XXX' -o kernel-tools-debugfiles.list}
+
+%if %{with_perf}
+%debuginfo_template -n perf
+%files -n perf-debuginfo -f perf-debugfiles.list
+%{expand:%%global _find_debuginfo_opts %{?_find_debuginfo_opts} -p '.*%{_bindir}/perf.*(\.debug)?|.*%{_libexecdir}/perf-core/.*|.*%{_libdir}/traceevent/.*|XXX' -o perf-debugfiles.list}
+
+%if 0%{?with_python2}
+%debuginfo_template -n python2-perf
+%files -n python2-perf-debuginfo -f python2-perf-debugfiles.list
+%{expand:%%global _find_debuginfo_opts %{?_find_debuginfo_opts} -p '.*%{python2_sitearch}/perf.*(.debug)?|XXX' -o python2-perf-debugfiles.list}
+%endif
+
+%debuginfo_template -n python3-perf
+%files -n python3-perf-debuginfo -f python3-perf-debugfiles.list
+%{expand:%%global _find_debuginfo_opts %{?_find_debuginfo_opts} -p '.*%{python3_sitearch}/perf.*(.debug)?|XXX' -o python3-perf-debugfiles.list}
+#with_perf
+%endif
+
+%endif
+
+%prep
+%setup -q -n kernel-%{version} -c
+
+%if 0%{?with_patch}
+tar -xjf %{SOURCE9998}
+%endif
+
+mv kernel linux-%{KernelVer}
+cd linux-%{KernelVer}
+
+%if 0%{?with_patch}
+cp %{SOURCE9000} .
+cp %{SOURCE9001} .
+cp %{SOURCE9002} .
+
+if [ ! -d patches ];then
+ mv ../patches .
+fi
+
+Applypatches()
+{
+ set -e
+ set -o pipefail
+ local SERIESCONF=$1
+ local PATCH_DIR=$2
+ sed -i '/^#/d' $SERIESCONF
+ sed -i '/^[\s]*$/d' $SERIESCONF
+ (
+ echo "trap 'echo \"*** patch \$_ failed ***\"' ERR"
+ echo "set -ex"
+ cat $SERIESCONF | \
+ sed "s!^!patch -s -F0 -E -p1 --no-backup-if-mismatch -i $PATCH_DIR/!" \
+ ) | sh
+}
+
+Applypatches series.conf %{_builddir}/kernel-%{version}/linux-%{KernelVer}
+%endif
+
+# haoc-kernel patch
+%patch0005 -p1
+
+# riscv-kernel patch
+%ifarch riscv64
+%patch0001 -p1
+%endif
+
+%if "%toolchain" == "clang"
+%patch0002 -p1
+%patch0003 -p1
+%patch0004 -p1
+%endif
+
+find . \( -name "*.orig" -o -name "*~" \) -exec rm -f {} \; >/dev/null
+find . -name .gitignore -exec rm -f {} \; >/dev/null
+
+%if 0%{?with_signmodules}
+ cp %{SOURCE11} certs/.
+%endif
+
+%if 0%{?with_source}
+# Copy directory backup for kernel-source
+cp -a ../linux-%{KernelVer} ../linux-%{KernelVer}-source
+find ../linux-%{KernelVer}-source -type f -name "\.*" -exec rm -rf {} \; >/dev/null
+%endif
+
+cp -a tools/perf tools/python3-perf
+
+%build
+cd linux-%{KernelVer}
+
+perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = -%{release}.%{_target_cpu}/" Makefile
+perl -p -i -e "s/^OPENEULER_LTS.*/OPENEULER_LTS = %{openeuler_lts}/" Makefile.oever
+perl -p -i -e "s/^OPENEULER_MAJOR.*/OPENEULER_MAJOR = %{openeuler_major}/" Makefile.oever
+perl -p -i -e "s/^OPENEULER_MINOR.*/OPENEULER_MINOR = %{openeuler_minor}/" Makefile.oever
+perl -p -i -e "s/^OPENEULER_RELEASE.*/OPENEULER_RELEASE = \"%{release}\"/" Makefile.oever
+
+## make linux
+make mrproper %{_smp_mflags}
+
+%if %{with_64kb}
+sed -i arch/arm64/configs/openeuler_defconfig -e 's/^CONFIG_ARM64_4K_PAGES.*/CONFIG_ARM64_64K_PAGES=y/'
+sed -i arch/arm64/configs/openeuler_defconfig -e 's/^CONFIG_ARM64_PA_BITS=.*/CONFIG_ARM64_PA_BITS=52/'
+sed -i arch/arm64/configs/openeuler_defconfig -e 's/^CONFIG_ARM64_PA_BITS_.*/CONFIG_ARM64_PA_BITS_52=y/'
+sed -i arch/arm64/configs/openeuler_defconfig -e 's/^CONFIG_ARM64_VA_BITS=.*/CONFIG_ARM64_VA_BITS=52/'
+sed -i arch/arm64/configs/openeuler_defconfig -e 's/^CONFIG_ARM64_VA_BITS_.*/CONFIG_ARM64_VA_BITS_52=y/'
+%endif
+
+%if "%toolchain" == "clang"
+
+%ifarch s390x ppc64le
+%global llvm_ias 0
+%else
+%global llvm_ias 1
+%endif
+
+%global clang_make_opts HOSTCC=clang CC=clang LLVM_IAS=%{llvm_ias}
+
+%if %{with clang_lto}
+%global clang_make_opts %{clang_make_opts} HOSTLD=ld.lld LD=ld.lld AR=llvm-ar NM=llvm-nm HOSTAR=llvm-ar HOSTNM=llvm-nm
+%endif
+
+%endif
+
+%global make %{__make} %{?clang_make_opts} HOSTCFLAGS="%{?build_cflags}" HOSTLDFLAGS="%{?build_ldflags}"
+
+%ifarch loongarch64
+
+%if 0%{with_signmodules}
+echo "CONFIG_MODULE_SIG=y" >>arch/loongarch/configs/loongson3_defconfig
+%endif
+
+%if 0%{with_debuginfo}
+echo "CONFIG_DEBUG_INFO=y" >>arch/loongarch/configs/loongson3_defconfig
+%endif
+
+make ARCH=%{Arch} loongson3_defconfig
+
+%else
+%{make} ARCH=%{Arch} openeuler_defconfig
+%endif
+
+%if %{with clang_lto}
+scripts/config -e LTO_CLANG_FULL
+sed -i 's/# CONFIG_LTO_CLANG_FULL is not set/CONFIG_LTO_CLANG_FULL=y/' .config
+sed -i 's/CONFIG_LTO_NONE=y/# CONFIG_LTO_NONE is not set/' .config
+%endif
+
+%if 0%{?openEuler_sign_rsa}
+ %{openEuler_check_EBS_perm}
+ if [ $openEuler_has_sign_perm -eq 1 ]; then
+ cp %{SOURCE15} ./certs/openeuler-cert.pem
+ # close kernel native signature
+ sed -i 's/CONFIG_MODULE_SIG_KEY=.*$/CONFIG_MODULE_SIG_KEY=""/g' .config
+ sed -i 's/CONFIG_SYSTEM_TRUSTED_KEYS=.*$/CONFIG_SYSTEM_TRUSTED_KEYS="certs\/openeuler-cert.pem"/g' .config
+ sed -i 's/CONFIG_MODULE_SIG_ALL=y$/CONFIG_MODULE_SIG_ALL=n/g' .config
+ fi
+%endif
+
+TargetImage=$(basename $(make -s image_name))
+
+%{make} ARCH=%{Arch} $TargetImage %{?_smp_mflags}
+%{make} ARCH=%{Arch} modules %{?_smp_mflags}
+
+%if 0%{?with_kabichk}
+ chmod 0755 %{SOURCE18}
+ if [ -e $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu} ]; then
+ %{SOURCE18} -k $RPM_SOURCE_DIR/Module.kabi_%{_target_cpu} -s Module.symvers || exit 1
+ else
+ echo "**** NOTE: Cannot find reference Module.kabi file. ****"
+ fi
+%endif
+
+# aarch64 make dtbs
+%ifarch aarch64 riscv64
+ %{make} ARCH=%{Arch} dtbs
+%endif
+
+## make tools
+%if %{with_perf}
+# perf
+%ifarch aarch64
+# aarch64 make perf with CORESIGHT=1
+%global perf_make \
+ make %{?clang_make_opts} EXTRA_LDFLAGS="%[ "%{toolchain}" == "clang" ? "-z now" : "" ]" EXTRA_CFLAGS="%[ "%{toolchain}" == "clang" ? "" : "-Wl,-z,now" ] -g -Wall -fstack-protector-strong -fPIC" EXTRA_PERFLIBS="-fpie -pie" %{?_smp_mflags} -s V=1 WERROR=0 NO_LIBUNWIND=1 HAVE_CPLUS_DEMANGLE=1 NO_GTK2=1 NO_LIBNUMA=1 NO_STRLCPY=1 CORESIGHT=1 prefix=%{_prefix}
+%else
+%global perf_make \
+ make %{?clang_make_opts} EXTRA_LDFLAGS="%[ "%{toolchain}" == "clang" ? "-z now" : "" ]" EXTRA_CFLAGS="%[ "%{toolchain}" == "clang" ? "" : "-Wl,-z,now" ] -g -Wall -fstack-protector-strong -fPIC" EXTRA_PERFLIBS="-fpie -pie" %{?_smp_mflags} -s V=1 WERROR=0 NO_LIBUNWIND=1 HAVE_CPLUS_DEMANGLE=1 NO_GTK2=1 NO_LIBNUMA=1 NO_STRLCPY=1 prefix=%{_prefix}
+%endif
+%if 0%{?with_python2}
+%global perf_python2 -C tools/perf PYTHON=%{__python2}
+%global perf_python3 -C tools/python3-perf PYTHON=%{__python3}
+%else
+%global perf_python3 -C tools/perf PYTHON=%{__python3}
+%endif
+
+chmod +x tools/perf/check-headers.sh
+# perf
+%if 0%{?with_python2}
+%{perf_make} %{perf_python2} all
+%endif
+
+# make sure check-headers.sh is executable
+chmod +x tools/python3-perf/check-headers.sh
+%{perf_make} %{perf_python3} all
+
+pushd tools/perf/Documentation/
+%{make} %{?_smp_mflags} man
+popd
+%endif
+
+# bpftool
+pushd tools/bpf/bpftool
+%{make}
+popd
+
+# cpupower
+chmod +x tools/power/cpupower/utils/version-gen.sh
+%{make} %{?_smp_mflags} -C tools/power/cpupower CPUFREQ_BENCH=false
+%ifarch %{ix86}
+ pushd tools/power/cpupower/debug/i386
+ %{make} %{?_smp_mflags} centrino-decode powernow-k8-decode
+ popd
+%endif
+%ifarch x86_64
+ pushd tools/power/cpupower/debug/x86_64
+ %{make} %{?_smp_mflags} centrino-decode powernow-k8-decode
+ popd
+%endif
+%ifarch %{ix86} x86_64
+ pushd tools/power/x86/x86_energy_perf_policy/
+ %{make}
+ popd
+ pushd tools/power/x86/turbostat
+ %{make}
+ popd
+%endif
+# thermal
+pushd tools/thermal/tmon/
+%{make}
+popd
+# iio
+pushd tools/iio/
+%{make}
+popd
+# gpio
+pushd tools/gpio/
+%{make}
+popd
+# kvm
+pushd tools/kvm/kvm_stat/
+%{make} %{?_smp_mflags} man
+popd
+# libbpf.a and bpf_helper_defs.h
+pushd tools/lib/bpf
+%{make}
+popd
+# netacc
+pushd tools/netacc
+%{make} BPFTOOL=../../tools/bpf/bpftool/bpftool
+popd
+
+%install
+%if 0%{?with_source}
+ %define _python_bytecompile_errors_terminate_build 0
+ mkdir -p $RPM_BUILD_ROOT/usr/src/
+ mv linux-%{KernelVer}-source $RPM_BUILD_ROOT/usr/src/linux-%{KernelVer}
+ cp linux-%{KernelVer}/.config $RPM_BUILD_ROOT/usr/src/linux-%{KernelVer}/
+%endif
+
+cd linux-%{KernelVer}
+
+## install linux
+
+# deal with kernel-source, now we don't need kernel-source
+#mkdir $RPM_BUILD_ROOT/usr/src/linux-%{KernelVer}
+#tar cf - --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git --exclude=.tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude=.config.old --exclude=.missing-syscalls.d --exclude=patches . | tar xf - -C %{buildroot}/usr/src/linux-%{KernelVer}
+
+mkdir -p $RPM_BUILD_ROOT/boot
+dd if=/dev/zero of=$RPM_BUILD_ROOT/boot/initramfs-%{KernelVer}.img bs=1M count=20
+
+%ifarch loongarch64
+strip -s vmlinux -o vmlinux.elf
+install -m 755 vmlinux.elf $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}
+%else
+install -m 755 $(make -s image_name) $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}
+%endif
+
+%if 0%{?openEuler_sign_rsa}
+ %{openEuler_check_EBS_perm}
+ if [ $openEuler_has_sign_perm -eq 1 ]; then
+ echo "start sign"
+ %ifarch %arm aarch64
+ gunzip -c $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}>$RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi
+ sh /usr/lib/rpm/brp-ebs-sign --efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi
+ mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi.sig $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi
+ mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip.efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip
+ gzip -c $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip>$RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}
+ rm -f $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.unzip
+ %endif
+ %ifarch x86_64
+ mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer} $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi
+ sh /usr/lib/rpm/brp-ebs-sign --efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi
+ mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi.sig $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi
+ mv $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}.efi $RPM_BUILD_ROOT/boot/vmlinuz-%{KernelVer}
+ %endif
+ fi
+%endif
+
+pushd $RPM_BUILD_ROOT/boot
+sha512hmac ./vmlinuz-%{KernelVer} >./.vmlinuz-%{KernelVer}.hmac
+popd
+
+install -m 644 .config $RPM_BUILD_ROOT/boot/config-%{KernelVer}
+install -m 644 System.map $RPM_BUILD_ROOT/boot/System.map-%{KernelVer}
+
+gzip -c9 < Module.symvers > $RPM_BUILD_ROOT/boot/symvers-%{KernelVer}.gz
+
+mkdir -p $RPM_BUILD_ROOT%{_sbindir}
+install -m 755 %{SOURCE200} $RPM_BUILD_ROOT%{_sbindir}/mkgrub-menu-%{version}-%{devel_release}%{?maintenance_release}%{?pkg_release}.sh
+
+
+%if 0%{?with_debuginfo}
+ mkdir -p $RPM_BUILD_ROOT%{debuginfodir}/lib/modules/%{KernelVer}
+ cp vmlinux $RPM_BUILD_ROOT%{debuginfodir}/lib/modules/%{KernelVer}
+%endif
+
+# deal with module, if not kdump
+%{make} ARCH=%{Arch} INSTALL_MOD_PATH=$RPM_BUILD_ROOT modules_install KERNELRELEASE=%{KernelVer} mod-fw=
+######## to collect ko to module.filelist about netwoking. block. drm. modesetting ###############
+pushd $RPM_BUILD_ROOT/lib/modules/%{KernelVer}
+find -type f -name "*.ko" >modnames
+
+# mark modules executable so that strip-to-file can strip them
+xargs --no-run-if-empty chmod u+x < modnames
+
+# Generate a list of modules for block and networking.
+
+grep -F /drivers/ modnames | xargs --no-run-if-empty nm -upA |
+sed -n 's,^.*/\([^/]*\.ko\): *U \(.*\)$,\1 \2,p' > drivers.undef
+
+collect_modules_list()
+{
+ sed -r -n -e "s/^([^ ]+) \\.?($2)\$/\\1/p" drivers.undef |
+ LC_ALL=C sort -u > modules.$1
+ if [ ! -z "$3" ]; then
+ sed -r -e "/^($3)\$/d" -i modules.$1
+ fi
+}
+
+collect_modules_list networking \
+ 'register_netdev|ieee80211_register_hw|usbnet_probe|phy_driver_register|rt2x00(pci|usb)_probe|register_netdevice'
+collect_modules_list block \
+ 'ata_scsi_ioctl|scsi_add_host|scsi_add_host_with_dma|blk_alloc_queue|blk_init_queue|register_mtd_blktrans|scsi_esp_register|scsi_register_device_handler|blk_queue_physical_block_size|ahci_platform_get_resources' 'pktcdvd.ko|dm-mod.ko'
+collect_modules_list drm \
+ 'drm_open|drm_init'
+collect_modules_list modesetting \
+ 'drm_crtc_init'
+
+# detect missing or incorrect license tags
+rm -f modinfo
+while read i
+do
+ echo -n "$i " >> modinfo
+ /sbin/modinfo -l $i >> modinfo
+done < modnames
+
+grep -E -v \
+ 'GPL( v2)?$|Dual BSD/GPL$|Dual MPL/GPL$|GPL and additional rights$' \
+ modinfo && exit 1
+
+rm -f modinfo modnames drivers.undef
+
+for i in alias alias.bin builtin.bin ccwmap dep dep.bin ieee1394map inputmap isapnpmap ofmap pcimap seriomap symbols symbols.bin usbmap
+do
+ rm -f $RPM_BUILD_ROOT/lib/modules/$KernelVer/modules.$i
+done
+popd
+# modsign module ko;need after find-debuginfo,strip
+%define __modsign_install_post \
+ if [ "%{with_signmodules}" -eq "1" ];then \
+ cp certs/signing_key.pem . \
+ cp certs/signing_key.x509 . \
+ chmod 0755 %{modsign_cmd} \
+ %{modsign_cmd} $RPM_BUILD_ROOT/lib/modules/%{KernelVer} || exit 1 \
+ fi \
+ find $RPM_BUILD_ROOT/lib/modules/ -type f -name '*.ko' | xargs -n1 -P`nproc --all` xz; \
+%{nil}
+
+%if 0%{?openEuler_sign_rsa}
+%define __modsign_install_post \
+ if [ "%{with_signmodules}" -eq "1" ];then \
+ if [ %flag_openEuler_has_sign_perm -eq 1 ]; then \
+ sh %{SOURCE16} $RPM_BUILD_ROOT/lib/modules/%{KernelVer} || exit 1 \
+ else \
+ cp certs/signing_key.pem . \
+ cp certs/signing_key.x509 . \
+ chmod 0755 %{modsign_cmd} \
+ %{modsign_cmd} $RPM_BUILD_ROOT/lib/modules/%{KernelVer} || exit 1 \
+ fi \
+ fi \
+ find $RPM_BUILD_ROOT/lib/modules/ -type f -name '*.ko' | xargs -n1 -P`nproc --all` xz; \
+%{nil}
+%endif
+
+# deal with header
+%{make} ARCH=%{Arch} INSTALL_HDR_PATH=$RPM_BUILD_ROOT/usr KBUILD_SRC= headers_install
+find $RPM_BUILD_ROOT/usr/include -name "\.*" -exec rm -rf {} \;
+
+# dtbs install
+%ifarch aarch64 riscv64
+ mkdir -p $RPM_BUILD_ROOT/boot/dtb-%{KernelVer}
+ install -m 644 $(find arch/%{Arch}/boot -name "*.dtb") $RPM_BUILD_ROOT/boot/dtb-%{KernelVer}/
+ rm -f $(find arch/$Arch/boot -name "*.dtb")
+%endif
+
+# deal with vdso
+%ifnarch ppc64le
+%{make} -s ARCH=%{Arch} INSTALL_MOD_PATH=$RPM_BUILD_ROOT vdso_install KERNELRELEASE=%{KernelVer}
+%endif
+if [ ! -s ldconfig-kernel.conf ]; then
+ echo "# Placeholder file, no vDSO hwcap entries used in this kernel." >ldconfig-kernel.conf
+fi
+install -D -m 444 ldconfig-kernel.conf $RPM_BUILD_ROOT/etc/ld.so.conf.d/kernel-%{KernelVer}.conf
+
+# deal with /lib/module/ path- sub path: build source kernel
+rm -f $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build
+rm -f $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/source
+mkdir -p $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build
+mkdir -p $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/extra
+mkdir -p $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/updates
+mkdir -p $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/weak-updates
+############ to do collect devel file #########
+# 1. Makefile And Kconfig, .config sysmbol
+# 2. scrpits dir
+# 3. .h file
+find -type f \( -name "Makefile*" -o -name "Kconfig*" \) -exec cp --parents {} $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build \;
+for f in Module.symvers System.map Module.markers .config;do
+ test -f $f || continue
+ cp $f $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build
+done
+
+cp -a scripts $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build
+if [ -d arch/%{Arch}/scripts ]; then
+ cp -a arch/%{Arch}/scripts $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/arch/%{_arch} || :
+fi
+if [ -f arch/%{Arch}/*lds ]; then
+ cp -a arch/%{Arch}/*lds $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/arch/%{_arch}/ || :
+fi
+find $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/scripts/ -name "*.o" -exec rm -rf {} \;
+
+if [ -d arch/%{Arch}/include ]; then
+ cp -a --parents arch/%{Arch}/include $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/
+fi
+cp -a include $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include
+
+if [ -f arch/%{Arch}/kernel/module.lds ]; then
+ cp -a --parents arch/%{Arch}/kernel/module.lds $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/
+fi
+
+# module.lds is moved to scripts by commit 596b0474d3d9 in linux 5.10.
+if [ -f scripts/module.lds ]; then
+ cp -a --parents scripts/module.lds $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/
+fi
+
+%ifarch aarch64
+ cp -a --parents arch/arm/include/asm $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/
+%endif
+
+# copy objtool for kernel-devel (needed for building external modules)
+if grep -q CONFIG_OBJTOOL=y .config; then
+ mkdir -p $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/tools/objtool
+ cp -a tools/objtool/objtool $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/tools/objtool
+fi
+
+# Make sure the Makefile and version.h have a matching timestamp so that
+# external modules can be built
+touch -r $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/Makefile $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include/generated/uapi/linux/version.h
+touch -r $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/.config $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include/generated/autoconf.h
+# for make prepare
+if [ ! -f $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include/config/auto.conf ];then
+ cp .config $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build/include/config/auto.conf
+fi
+
+mkdir -p %{buildroot}/usr/src/kernels
+mv $RPM_BUILD_ROOT/lib/modules/%{KernelVer}/build $RPM_BUILD_ROOT/usr/src/kernels/%{KernelVer}
+
+find $RPM_BUILD_ROOT/usr/src/kernels/%{KernelVer} -name ".*.cmd" -exec rm -f {} \;
+
+pushd $RPM_BUILD_ROOT/lib/modules/%{KernelVer}
+ln -sf /usr/src/kernels/%{KernelVer} build
+ln -sf build source
+popd
+
+
+# deal with doc , now we don't need
+
+
+# deal with kernel abi whitelists. now we don't need
+
+
+## install tools
+%if %{with_perf}
+# perf
+# perf tool binary and supporting scripts/binaries
+%if 0%{?with_python2}
+%{perf_make} %{perf_python2} DESTDIR=%{buildroot} lib=%{_lib} install-bin
+%else
+%{perf_make} %{perf_python3} DESTDIR=%{buildroot} lib=%{_lib} install-bin
+%endif
+# remove the 'trace' symlink.
+rm -f %{buildroot}%{_bindir}/trace
+
+# remove examples
+rm -rf %{buildroot}/usr/lib/perf/examples
+# remove the stray header file that somehow got packaged in examples
+rm -rf %{buildroot}/usr/lib/perf/include/bpf/
+
+# python-perf extension
+%{perf_make} %{perf_python3} DESTDIR=%{buildroot} install-python_ext
+%if 0%{?with_python2}
+%{perf_make} %{perf_python2} DESTDIR=%{buildroot} install-python_ext
+%endif
+
+# perf man pages (note: implicit rpm magic compresses them later)
+install -d %{buildroot}/%{_mandir}/man1
+install -pm0644 tools/kvm/kvm_stat/kvm_stat.1 %{buildroot}/%{_mandir}/man1/
+install -pm0644 tools/perf/Documentation/*.1 %{buildroot}/%{_mandir}/man1/
+%endif
+
+# bpftool
+pushd tools/bpf/bpftool
+%{make} DESTDIR=%{buildroot} prefix=%{_prefix} bash_compdir=%{_sysconfdir}/bash_completion.d/ mandir=%{_mandir} install doc-install
+popd
+
+# resolve_btfids
+mkdir -p %{buildroot}/usr/src/kernels/%{KernelVer}/tools/bpf/resolve_btfids
+cp tools/bpf/resolve_btfids/resolve_btfids %{buildroot}/usr/src/kernels/%{KernelVer}/tools/bpf/resolve_btfids
+
+# cpupower
+%{make} -C tools/power/cpupower DESTDIR=%{buildroot} libdir=%{_libdir} mandir=%{_mandir} CPUFREQ_BENCH=false install
+rm -f %{buildroot}%{_libdir}/*.{a,la}
+%find_lang cpupower
+mv cpupower.lang ../
+%ifarch %{ix86}
+ pushd tools/power/cpupower/debug/i386
+ install -m755 centrino-decode %{buildroot}%{_bindir}/centrino-decode
+ install -m755 powernow-k8-decode %{buildroot}%{_bindir}/powernow-k8-decode
+ popd
+%endif
+%ifarch x86_64
+ pushd tools/power/cpupower/debug/x86_64
+ install -m755 centrino-decode %{buildroot}%{_bindir}/centrino-decode
+ install -m755 powernow-k8-decode %{buildroot}%{_bindir}/powernow-k8-decode
+ popd
+%endif
+chmod 0755 %{buildroot}%{_libdir}/libcpupower.so*
+mkdir -p %{buildroot}%{_unitdir} %{buildroot}%{_sysconfdir}/sysconfig
+install -m644 %{SOURCE2000} %{buildroot}%{_unitdir}/cpupower.service
+install -m644 %{SOURCE2001} %{buildroot}%{_sysconfdir}/sysconfig/cpupower
+%ifarch %{ix86} x86_64
+ mkdir -p %{buildroot}%{_mandir}/man8
+ pushd tools/power/x86/x86_energy_perf_policy
+ %{make} DESTDIR=%{buildroot} install
+ popd
+ pushd tools/power/x86/turbostat
+ %{make} DESTDIR=%{buildroot} install
+ popd
+%endif
+# thermal
+pushd tools/thermal/tmon
+%{make} INSTALL_ROOT=%{buildroot} install
+popd
+# iio
+pushd tools/iio
+%{make} DESTDIR=%{buildroot} install
+popd
+# gpio
+pushd tools/gpio
+%{make} DESTDIR=%{buildroot} install
+popd
+# kvm
+pushd tools/kvm/kvm_stat
+%{make} INSTALL_ROOT=%{buildroot} install-tools
+popd
+# netacc
+pushd tools/netacc
+%{make} INSTALL_ROOT=%{buildroot} install
+popd
+
+%define __spec_install_post\
+%{?__debug_package:%{__debug_install_post}}\
+%{__arch_install_post}\
+%{__os_install_post}\
+%{__modsign_install_post}\
+%{nil}
+
+%post
+%{_sbindir}/new-kernel-pkg --package kernel --install %{KernelVer} || exit $?
+
+%preun
+if [ `uname -i` == "aarch64" ] &&
+ [ -f /boot/EFI/grub2/grub.cfg ]; then
+ /usr/bin/sh %{_sbindir}/mkgrub-menu-%{version}-%{devel_release}%{?maintenance_release}%{?pkg_release}.sh %{version}-%{release}.aarch64 /boot/EFI/grub2/grub.cfg remove
+fi
+
+%postun
+%{_sbindir}/new-kernel-pkg --rminitrd --rmmoddep --remove %{KernelVer} || exit $?
+if [ -x %{_sbindir}/weak-modules ]
+then
+ %{_sbindir}/weak-modules --remove-kernel %{KernelVer} || exit $?
+fi
+
+# remove empty directory
+if [ -d /lib/modules/%{KernelVer} ] && [ "`ls -A /lib/modules/%{KernelVer}`" = "" ]; then
+ rm -rf /lib/modules/%{KernelVer}
+fi
+if [ `uname -i` == "loongarch64" ];then
+ [ -f /etc/grub2.cfg ] && GRUB_CFG=`readlink -f /etc/grub2.cfg`
+ [ "x${GRUB_CFG}" == "x" ] && [ -f /etc/grub2-efi.cfg ] && GRUB_CFG=`readlink -f /etc/grub2-efi.cfg`
+ [ "x${GRUB_CFG}" == "x" ] && [ -f /boot/efi/EFI/openEuler/grub.cfg ] && GRUB_CFG=/boot/efi/EFI/openEuler/grub.cfg
+ [ "x${GRUB_CFG}" != "x" ] && grub2-mkconfig -o ${GRUB_CFG}
+fi
+
+%posttrans
+%{_sbindir}/new-kernel-pkg --package kernel --mkinitrd --dracut --depmod --update %{KernelVer} || exit $?
+%{_sbindir}/new-kernel-pkg --package kernel --rpmposttrans %{KernelVer} || exit $?
+if [ `uname -i` == "aarch64" ] &&
+ [ -f /boot/EFI/grub2/grub.cfg ]; then
+ /usr/bin/sh %{_sbindir}/mkgrub-menu-%{version}-%{devel_release}%{?maintenance_release}%{?pkg_release}.sh %{version}-%{release}.aarch64 /boot/EFI/grub2/grub.cfg update
+fi
+if [ `uname -i` == "loongarch64" ];then
+ [ -f /etc/grub2.cfg ] && GRUB_CFG=`readlink -f /etc/grub2.cfg`
+ [ "x${GRUB_CFG}" == "x" ] && [ -f /etc/grub2-efi.cfg ] && GRUB_CFG=`readlink -f /etc/grub2-efi.cfg`
+ [ "x${GRUB_CFG}" == "x" ] && [ -f /boot/efi/EFI/openEuler/grub.cfg ] && GRUB_CFG=/boot/efi/EFI/openEuler/grub.cfg
+ [ "x${GRUB_CFG}" != "x" ] && grub2-mkconfig -o ${GRUB_CFG}
+ grubby --set-default=/boot/vmlinuz-%{KernelVer}
+fi
+if [ -x %{_sbindir}/weak-modules ]
+then
+ %{_sbindir}/weak-modules --add-kernel %{KernelVer} || exit $?
+fi
+%{_sbindir}/new-kernel-pkg --package kernel --mkinitrd --dracut --depmod --update %{KernelVer} || exit $?
+%{_sbindir}/new-kernel-pkg --package kernel --rpmposttrans %{KernelVer} || exit $?
+
+%post devel
+if [ -f /etc/sysconfig/kernel ]
+then
+ . /etc/sysconfig/kernel || exit $?
+fi
+if [ "$HARDLINK" != "no" -a -x /usr/sbin/hardlink ]
+then
+ (cd /usr/src/kernels/%{KernelVer} &&
+ /usr/bin/find . -type f | while read f; do
+ hardlink -c /usr/src/kernels/*.oe*.*/$f $f
+ done)
+fi
+
+%post -n %{name}-tools
+/sbin/ldconfig
+%systemd_post cpupower.service
+
+%preun -n %{name}-tools
+%systemd_preun cpupower.service
+
+%postun -n %{name}-tools
+/sbin/ldconfig
+%systemd_postun cpupower.service
+
+%files
+%defattr (-, root, root)
+%doc
+/boot/config-*
+%ifarch aarch64 riscv64
+/boot/dtb-*
+%endif
+/boot/symvers-*
+/boot/System.map-*
+/boot/vmlinuz-*
+%ghost /boot/initramfs-%{KernelVer}.img
+/boot/.vmlinuz-*.hmac
+/etc/ld.so.conf.d/*
+/lib/modules/%{KernelVer}/
+%exclude /lib/modules/%{KernelVer}/source
+%exclude /lib/modules/%{KernelVer}/build
+%{_sbindir}/mkgrub-menu*.sh
+
+%files devel
+%defattr (-, root, root)
+%doc
+/lib/modules/%{KernelVer}/source
+/lib/modules/%{KernelVer}/build
+/usr/src/kernels/%{KernelVer}
+
+%files headers
+%defattr (-, root, root)
+/usr/include/*
+%exclude %{_includedir}/cpufreq.h
+%exclude %{_includedir}/cpuidle.h
+
+%if %{with_perf}
+%files -n perf
+%{_bindir}/perf
+%{_libdir}/libperf-jvmti.so
+%{_libexecdir}/perf-core
+%{_datadir}/perf-core/
+%{_mandir}/man[1-8]/perf*
+%{_sysconfdir}/bash_completion.d/perf
+%doc linux-%{KernelVer}/tools/perf/Documentation/examples.txt
+%dir %{_datadir}/doc/perf-tip
+%{_datadir}/doc/perf-tip/*
+%license linux-%{KernelVer}/COPYING
+
+%if 0%{?with_python2}
+%files -n python2-perf
+%license linux-%{KernelVer}/COPYING
+%{python2_sitearch}/*
+%endif
+
+%files -n python3-perf
+%license linux-%{KernelVer}/COPYING
+%{python3_sitearch}/*
+%endif
+
+%files -n %{name}-tools -f cpupower.lang
+%{_bindir}/cpupower
+%ifarch %{ix86} x86_64
+%{_bindir}/centrino-decode
+%{_bindir}/powernow-k8-decode
+%endif
+%{_unitdir}/cpupower.service
+%{_datadir}/bash-completion/completions/cpupower
+%{_mandir}/man[1-8]/cpupower*
+%config(noreplace) %{_sysconfdir}/sysconfig/cpupower
+%ifarch %{ix86} x86_64
+%{_bindir}/x86_energy_perf_policy
+%{_mandir}/man8/x86_energy_perf_policy*
+%{_bindir}/turbostat
+%{_mandir}/man8/turbostat*
+%endif
+%{_bindir}/tmon
+%{_bindir}/iio_event_monitor
+%{_bindir}/iio_generic_buffer
+%{_bindir}/lsiio
+%{_bindir}/lsgpio
+%{_bindir}/gpio-hammer
+%{_bindir}/gpio-event-mon
+%{_bindir}/gpio-watch
+%{_mandir}/man1/kvm_stat*
+%{_bindir}/kvm_stat
+%{_sbindir}/net-acc
+%{_sbindir}/tuned_acc/netacc
+%{_libdir}/libcpupower.so.1
+%{_libdir}/libcpupower.so.0.0.1
+%license linux-%{KernelVer}/COPYING
+
+%files -n %{name}-tools-devel
+%{_libdir}/libcpupower.so
+%{_includedir}/cpufreq.h
+%{_includedir}/cpuidle.h
+
+%files -n bpftool
+%{_sbindir}/bpftool
+%{_sysconfdir}/bash_completion.d/bpftool
+%{_mandir}/man8/bpftool-cgroup.8.gz
+%{_mandir}/man8/bpftool-map.8.gz
+%{_mandir}/man8/bpftool-prog.8.gz
+%{_mandir}/man8/bpftool-perf.8.gz
+%{_mandir}/man8/bpftool.8.gz
+%{_mandir}/man8/bpftool-btf.8.gz
+%{_mandir}/man8/bpftool-feature.8.gz
+%{_mandir}/man8/bpftool-gen.8.gz
+%{_mandir}/man8/bpftool-iter.8.gz
+%{_mandir}/man8/bpftool-link.8.gz
+%{_mandir}/man8/bpftool-net.8.gz
+%{_mandir}/man8/bpftool-struct_ops.8.gz
+%license linux-%{KernelVer}/COPYING
+
+%if 0%{?with_source}
+%files source
+%defattr(-,root,root)
+/usr/src/linux-%{KernelVer}/*
+/usr/src/linux-%{KernelVer}/.config
+%endif
+
+%changelog
+* Thu May 23 2024 Liu Zhehui <liuzhh@zgclab.edu.cn> - 6.6.0-27.0.0.32
+- update HAOC patch and spec for 6.6.0-27.0.0
+* Sat May 18 2024 ZhangPeng <zhangpeng362@huawei.com> - 6.6.0-27.0.0.31
+- !7527 ext4 iomap performance optimize
+- ext4: fallback to generic_perform_write once iov_iter_count <= PAGE_SIZE
+- iomap: export __iomap_write_{begin|end}
+- !7530 mm: more thp control for large folio
+- mm: correct the docs for thp_fault_alloc and thp_fault_fallback
+- mm: add docs for per-order mTHP counters and transhuge_page ABI
+- mm: add per-order mTHP anon_swpout and anon_swpout_fallback counters
+- mm: add per-order mTHP anon_fault_alloc and anon_fault_fallback counters
+- mm: add control to allow specified high-order pages stored on PCP list
+- mm: huge_memory: add thp mapping align control
+- mm: huge_memory: add folio_get_unmapped_area()
+- mm: filemap: make mTHP configurable for exec mapping
+- mm/filemap: Allow arch to request folio size for exec memory
+- mm/memcontrol: remove __mod_lruvec_page_state()
+- mm/khugepaged: use a folio more in collapse_file()
+- mm: remove inc/dec lruvec page state functions
+- !7521 v2 Avoiding false sharing in field access of tk_core
+- openeuler_defconfig: Enable CONFIG_ARCH_LLC_128_LINE_SIZE for Hisilicon platforms
+- timekeeping: Avoiding false sharing in field access of tk_core
+- !7182 v3 mm: mglru: reuse some legacy trace
+- mm: multi-gen LRU: reuse some legacy trace events
+- mm, vmscan: remove ISOLATE_UNMAPPED
+- trace-vmscan-postprocess: sync with tracepoints updates
+- !7219 Hygon model 6h L3 PMU event duplicate creating issue fix
+- perf/x86/uncore: Create L3 event strictly to the CPU vendor
+- !7474 sched/fair: set burst to zero when cfs bandwidth is cancelled
+- sched/fair: set burst to zero when set max to cpu.max
+- sched/fair: limit burst to zero when cfs bandwidth is toggled off
+- !7475 Makefile.oever: add OPENEULER_RELEASE for version.h
+- Makefile.oever: add OPENEULER_RELEASE for version.h
+- !6241 add pmu support for loongarch kvm
+- LoongArch: KVM: Add PMU support
+- !5654 [OLK-6.6] USB: UAS: return ENODEV when submit urbs fail with device not attached
+- USB: UAS: return ENODEV when submit urbs fail with device not attached
+- !5218 [OLK-6.6] Add HGSC_CERT_IMPORT ioctl interface for Hygon CPUs.
+- crypto: ccp: Implement CSV_HGSC_CERT_IMPORT ioctl command
+- crypto: ccp: Move the fixup code for Hygon psp to Hygon specific files
+- crypto: ccp: Bind specific sp_dev_vdata for Hygon secure processor
+- crypto: ccp: Introduce hygon specific interface to support driver
+- !6311 v2 ima: Avoid blocking in RCU read-side critical section
+- ima: Avoid blocking in RCU read-side critical section
+- !6837 fs: sysfs: Fix reference leak in sysfs_break_active_protection()
+- fs: sysfs: Fix reference leak in sysfs_break_active_protection()
+- !5644 [OLK-6.6] x86/mce: Set bios_cmci_threshold for CMCI threshold
+- x86/mce: Set bios_cmci_threshold for CMCI threshold
+- !7454 add new kvm_type for Confidential VMs
+- kvm: add macro CONFIG_CVM_HOST to defconfig
+- kvm: add new kvm_type for cvm
+- !7405 v2 mm: prepare to support weighted interleaving mempolicy
+- mm: prepare to support weighted interleaving mempolicy
+- !7370 v2 sched: smart_grid: silence complier error
+- sched: smart_grid: silence complier error
+- !7227 arm64: arm_pmuv3: Correctly extract and check the PMUVer
+- arm64: arm_pmuv3: Correctly extract and check the PMUVer
+- !5291 [OLK-6.6] iommu/dma: Fix not fully traversing iova reservations issue
+- iommu/dma: Fix not fully traversing iova reservations issue
+- !6774 [OLK-6.6] merge upstream 4 wangxun related patches to fix i2c bug
+- Revert "net: txgbe: fix clk_name exceed MAX_DEV_ID limits"
+- Revert "net: txgbe: fix i2c dev name cannot match clkdev"
+- net: wangxun: add ethtool_ops for channel number
+- clkdev: Update clkdev id usage to allow for longer names
+- !7206 v2 sched: programmable: Allow set tag for pid 1.
+- sched: programmable: Allow set tag for pid 1.
+
+* Sat May 11 2024 ZhangPeng <zhangpeng362@huawei.com> - 6.6.0-26.0.0.30
+- !7198 v2 mm: prepare more high-order pages on pcplist
+- mm: prepare more high-order pages to be stored on the per-cpu lists
+- mm: page_alloc: use the correct THP order for THP PCP
+- !7196 v3 Backport folio feature and bugfix
+- mm: madvise: avoid split during MADV_PAGEOUT and MADV_COLD
+- mm: vmscan: avoid split during shrink_folio_list()
+- mm: swap: allow storage of all mTHP orders
+- mm: swap: update get_swap_pages() to take folio order
+- mm: swap: simplify struct percpu_cluster
+- mm: swap: free_swap_and_cache_nr() as batched free_swap_and_cache()
+- mm: swap: remove CLUSTER_FLAG_HUGE from swap_cluster_info:flags
+- mm/madvise: don't forget to leave lazy MMU mode in madvise_cold_or_pageout_pte_range()
+- mm/madvise: add cond_resched() in madvise_cold_or_pageout_pte_range()
+- mm: support multi-size THP numa balancing
+- mm: factor out the numa mapping rebuilding into a new helper
+- mm: alloc_anon_folio: avoid doing vma_thp_gfp_mask in fallback cases
+- huge_memory.c: document huge page splitting rules more thoroughly
+- mm: convert folio_estimated_sharers() to folio_likely_mapped_shared()
+- mm/migrate: split source folio if it is on deferred split list
+- mm: hold PTL from the first PTE while reclaiming a large folio
+- madvise:madvise_cold_or_pageout_pte_range(): allow split while folio_estimated_sharers = 0
+- mm/filemap: don't decrease mmap_miss when folio has workingset flag
+- mm/readahead: break read-ahead loop if filemap_add_folio return -ENOMEM
+- arm64: mm: swap: support THP_SWAP on hardware with MTE
+- mm: remove PageAnonExclusive assertions in unuse_pte()
+- mm: remove struct page from get_shadow_from_swap_cache
+- selftests: mm: fix unused and uninitialized variable warning
+- XArray: set the marks correctly when splitting an entry
+- mm/huge_memory: check new folio order when split a folio
+- mm: huge_memory: enable debugfs to split huge pages to any order
+- mm: thp: split huge page to any lower order pages
+- mm: page_owner: add support for splitting to any order in split page_owner
+- mm: memcg: make memcg huge page split support any order split
+- mm/page_owner: use order instead of nr in split_page_owner()
+- mm/memcg: use order instead of nr in split_page_memcg()
+- mm: support order-1 folios in the page cache
+- mm/huge_memory: only split PMD mapping when necessary in unmap_folio()
+- selftests/mm: split_huge_page_test: conform test to TAP format output
+- mm: huge_memory: use more folio api in __split_huge_page_tail()
+- mm/vmalloc: fix return value of vb_alloc if size is 0
+- mm: use memalloc_nofs_save() in page_cache_ra_order()
+- mm: madvise: pageout: ignore references rather than clearing young
+- mm: ratelimit stat flush from workingset shrinker
+- mm, oom:dump_tasks add rss detailed information printing
+- arm64/mm: improve comment in contpte_ptep_get_lockless()
+- arm64/mm: export contpte symbols only to GPL users
+- mm: page_alloc: enforce minimum zone size to do high atomic reserves
+- mm: page_alloc: correct high atomic reserve calculations
+- mm: fix draining remote pageset
+- !7190 entry: inline syscall enter/exit functions
+- entry: Move syscall_enter_from_user_mode() to header file
+- entry: Move enter_from_user_mode() to header file
+- entry: Move exit to usermode functions to header file
+- !7130 v2 openeuler_defconfig: update oedefconfig for the minimum set
+- openeuler_defconfig: update oedefconfig for the minimum set
+- !7141 spi: hisi-kunpeng: Add validation for the minimum value of speed_hz
+- spi: hisi-kunpeng: Add validation for the minimum value of speed_hz
+- spi: Add verification for the max_frequency provided by the firmware
+- !7136 Fix failed in acpi_gpiochip_find() by adding parent node match
+- gpiolib: acpi: Fix failed in acpi_gpiochip_find() by adding parent node match
+- !6778 v2 Fix two soc bugs of hip09
+- irqchip: gicv3: Add workaround for hip09 erratum 162200806
+- irqchip: gicv3: Add workaround for hip09 erratum 162200803
+- !7165 v2 tick/broadcast-hrtimer: Prevent the timer device on broadcast duty CPU from being disabled
+- tick/broadcast-hrtimer: Prevent the timer device on broadcast duty CPU from being disabled
+- !7184 v3 md: do not delete safemode_timer in mddev_suspend
+- md: do not delete safemode_timer in mddev_suspend
+- !7131 net: hns3: Fix ROH mac address initialization.
+- net: hns3: Fix ROH mac address initialization.
+- !7126 net: hns3: some bugfixes for hns3 driver
+- net: hns3: fix kernel crash when devlink reload during initialization
+- net: hns3: direct return when receive a unknown mailbox message
+- net: hns3: release PTP resources if pf initialization failed
+- net: hns3: change type of numa_node_mask as nodemask_t
+- net: hns3: using cpumask_copy when set value to cpumask_t
+- net: hns3: set irq affinity directly
+- net: hns3: use appropriate barrier function after setting a bit value
+- net: hns3: don't need to check an unsigned number is less than 0
+- net: hns3: add
+- net: hns3: using user configure after hardware reset
+- net: hns3: add cond_resched() to hns3 ring buffer init process
+- net: hns3: fix kernel crash problem in concurrent scenario
+- net: hns3: fix port vlan filter not disabled issue
+- net: hns3: revert "net: hns3: fix port vlan filter not disabled problem in dynamic vlan mode"
+- !7159 【OLK 6.6】 backport some mailist patches for perf
+- drivers/perf: hisi: hns3: Actually use devm_add_action_or_reset()
+- drivers/perf: hisi: hns3: Fix out-of-bound access when valid event group
+- drivers/perf: hisi_pcie: Fix out-of-bound access when valid event group
+- !7068 kernfs: RCU protect kernfs_nodes and avoid kernfs_idr_lock in kernfs_find_and_get_node_by_id()
+- kernfs: RCU protect kernfs_nodes and avoid kernfs_idr_lock in kernfs_find_and_get_node_by_id()
+- !7153 Backports for OLK-6.6
+- netfilter: br_netfilter: skip conntrack input hook for promisc packets
+- netfilter: bridge: confirm multicast packets before passing them up the stack
+- !7069 ext4: fix uninitialized ratelimit_state->lock access in __ext4_fill_super()
+- ext4: fix uninitialized ratelimit_state->lock access in __ext4_fill_super()
+- !7075 RDMA/hns: Some bugfixes and cleanups
+- RDMA/hns: Fix soft lockup under heavy CEQE load
+- RDMA/hns: Fix sleeping in spin_lock critical section
+- RDMA/hns: Fix Use-After-Free of rsv_qp
+- RDMA/hns: Fix a missing check of atomic wr length
+- !3184 [OLK-6.6] add support for Zhaoxin ZXPAUSE instruction
+- x86/delay: add support for Zhaoxin ZXPAUSE instruction
+- !7078 v2 Backport four conflict stable patch
+- mm: turn folio_test_hugetlb into a PageType
+- mm/hugetlb: fix missing hugetlb_lock for resv uncharge
+- fork: defer linking file vma until vma is fully initialized
+- mm, treewide: introduce NR_PAGE_ORDERS
+- !7067 crypto: hisilicon fix some issues
+- uacce: fix for cdev memory leak
+- crypto: hisilicon/qm - adjust the internal processing sequence of the vf enable and disable
+- crypto: hisilicon/zip - optimize the address offset of the reg query function
+- !4084 riscv64: initial LIVEPATCH_WO_FTRACE support
+- riscv64: add initial livepatch support
+- livepatch: add arch hook before doing klp_resolve_symbols
+- !6868 irqchip/loongson-pch-pic: Update interrupt registration policy
+- irqchip/loongson-pch-pic: Update interrupt registration policy
+- !6004 [OLK-6.6] fix bug:ethtool -S and ethtool -x/X for mucse rnpm drvier
+- mucse: ethtool -S and ethtool -x/X for mucse rnpm drvier
+
+ at the end when print msg
+* Sat May 11 2024 Mingzheng Xing <xingmingzheng@iscas.ac.cn> - 6.6.0-25.0.0.29
+- Add riscv-kernel patch, which adds support for sg2042 and th1520 RISC-V SoCs.
+- This patch only applies to the RISC-V architecture, the related commit list:
+-
+- th1520: riscv: config: Enable th1520 support
+- riscv: thead: Use the wback_inv instead of wback_only
+- riscv: errata: thead: use pa based instructions for CMO
+- riscv: errata: thead: use riscv_nonstd_cache_ops for CMO
+- Revert "riscv: errata: thead: use riscv_nonstd_cache_ops for CMO"
+- Revert "riscv: errata: thead: use pa based instructions for CMO"
+- riscv: mm: fix NOCACHE_THEAD does not set bit[61] correctly
+- riscv: mm: update T-Head memory type definitions
+- Revert "sg2042: riscv: changing T-Head PBMT attributes"
+- riscv: remove compression for riscv Image
+- th1520: cpufreq: correct typo in config name
+- th1520: riscv: dts: thead: Add Milk-V Meles board
+- th1520: cpufreq: light-mpw-cpufreq: fix -Wunused-variable in panic_cpufreq_notifier_call
+- th1520: cpufreq: light-mpw-cpufreq: fix cpu_pll1 already disabled warning
+- riscv: Add th1520-lichee-cluster-4a dts support (8G/16G)
+- riscv: dts: th1520-beaglev-ahead: add alias for emmc & sd
+- riscv: dts: th1520-lichee-pi-4a: add alias for emmc & sd
+- riscv: dts: lpi4a 16g support
+- th1520: perf vendor events riscv: add T-HEAD C9xx JSON file
+- th1520: riscv: dts: thead: Add PMU event node
+- riscv: pinctrl: th1520: fix build
+- riscv: dts: th1520: lpi4a: add rpmsg node
+- riscv: dts: th1520: add mbox client node
+- riscv: rpmsg: mailbox-client: sync thead sdk 1.4.2
+- riscv: panic: add thead sdk quirks
+- riscv: dts: add watchdog node
+- th1520: riscv: dts: Add th1520 reset device tree
+- th1520: reset: Add th1520 reset driver support
+- th1520: dt-bindings: reset: Document th1520 reset control
+- riscv: light_wdt: update sdk 1.4.2
+- th1520_light_event: update sdk 1.4.2
+- th1520_aon: update sdk 1.4.2
+- th1520: fix compile th1520-beaglev-ahead error
+- th1520: add TH1520 cpu frequency driver
+- th1520: riscv: errata: thead: use pa based instructions for CMO
+- th1520: riscv: errata: thead: use riscv_nonstd_cache_ops for CMO
+- riscv: dts: thead: Add TH1520 CPU reset node
+- th1520: riscv: dts: thead: Enable Lichee Pi 4A USB
+- th1520: riscv: dts: thead: Add Lichee Pi 4A IO expansions
+- th1520: riscv: dts: thead: Add TH1520 USB nodes
+- th1520: riscv: dts: thead: Add TH1520 I2C nodes
+- th1520: usb: dwc3: add T-HEAD TH1520 usb driver
+- th1520: dt-bindings: usb: Add T-HEAD TH1520 USB controller
+- th1520: riscv: dts: thead: Add BeagleV Ahead SDIO0 pins
+- th1520: riscv: dts: thead: Add Lichee Pi 4A SDIO0 pins
+- th1520: riscv: dts: thead: Add TH1520 ethernet nodes
+- th1520: net: stmmac: add glue layer for T-HEAD TH1520 SoC
+- th1520: dt-bindings: net: add T-HEAD dwmac support
+- th1520: dt-bindings: net: snps,dwmac: allow dwmac-3.70a to set pbl properties
+- th1520: riscv: dts: thead: Enable Lichee Pi 4A PWM fan
+- th1520: riscv: dts: thead: Add TH1520 PVT node
+- th1520: riscv: dts: thead: Add TH1520 PWM node
+- th1520: pwm: add T-HEAD PWM driver
+- th1520: dt-bindings: pwm: Add T-HEAD PWM controller
+- th1520: gpio: dwapb: Use generic request, free and set_config
+- riscv: dts: thead: Enable LicheePi 4A eMMC and microSD
+- riscv: dts: thead: Enable BeagleV Ahead eMMC and microSD
+- riscv: dts: thead: Add TH1520 mmc controllers and sdhci clock
+- riscv: defconfig: Enable mmc and dma drivers for T-Head TH1520
+- mmc: sdhci-of-dwcmshc: Add support for T-Head TH1520
+- mmc: sdhci: add __sdhci_execute_tuning() to header
+- dt-bindings: mmc: sdhci-of-dwcmhsc: Add T-Head TH1520 support
+- th1520: riscv: dtb: thead: Add BeagleV Ahead LEDs
+- th1520: riscv: dts: thead: Add TH1520 pinctrl settings for UART0
+- th1520: riscv: dts: thead: Adjust TH1520 GPIO labels
+- th1520: riscv: dts: thead: Add TH1520 GPIO ranges
+- th1520: riscv: dts: thead: Add TH1520 pin control nodes
+- th1520: pinctrl: Add driver for the T-Head TH1520 SoC
+- th1520: dt-bindings: pinctrl: Add thead,th1520-pinctrl bindings
+- th1520: dt-bindings: gpio: dwapb: allow gpio-ranges
+- sg2042: riscv: config: Enable sg2042 support
+- sg2042: riscv: changing T-Head PBMT attributes
+- sg2042: kconfig: Enable DW_APB_TIMER_OF in ARCH_SOPHGO
+- sg2042: pcie contronller msi-x whitelist add device_id
+- sg2042: nvidia hda: force msi
+- sg2042: radeon hack: force 64-bit msi to fit top intc
+- sg2042: amdgpu: disable rebar
+- sg2042: ttm: disallow cached mapping
+- sg2042: mango pci hack: broadcast when no MSI source known
+- sg2042: riscv: dts: separate sg2042 mtime and mtimecmp to fit aclint format
+- sg2042: dt-bindings: timer: thead,c900-aclint-mtimer: separate mtime and mtimecmp regs
+- sg2042: riscv: dts: modify the PCIe range
+- sg2042: drivers: clk: turn off non-essential clocks by default
+- sg2042: drivers: clk: Avoid the problem of serial port garbled characters
+- sg2042: mm: Modify __find_max_addr for memory hole
+- sg2042: riscv: dts: Add timer apb clock
+- sg2042: riscv: dts: Remove cma node
+- sg2042: riscv: dts: Add uart apb clock and remove sysdma clock
+- sg2042: riscv: dts: Move memory node from dts to zsbl
+- sg2042: riscv: dts: Reduce bootargs
+- sg2042: riscv: dts: Configure external interrupt in m mode
+- sg2042: rebase: v6.6-rc1: Fix some compile warnings
+- sg2042: riscv: dts: Remove nvme paremeter in bootargs
+- sg2042: riscv: dtsi: confirm correspondence between PMU events and IDs
+- sg2042: driver: pcie: support msix for top intr
+- sg2042: driver: mmc: add config for MMC_SDHCI_SOPHGO
+- sg2042: riscv: Kconfig: Set vector as default no
+- sg2042: driver: soc: Add sophgo sg2042 soc support
+- sg2042: driver: net: Add sophgo sg2042 soc support
+- sg2042: driver: mmc: Add sophgo sg2042 soc support
+- sg2042: driver: pcie: Add sophgo sg2042 soc support
+- sg2042: driver: reset: Add sophgo sg2042 soc support
+- sg2042: driver: pinctrl: Add sophgo sg2042 soc support
+- sg2042: driver: clk: Add sophgo sg2042 soc support
+- sg2042: riscv: dts: Add sophgo sg2042 soc support
+- sg2042: riscv: defconfig: enable SOPHGO SoC
+- sg2042: riscv: dts: sophgo: add Milk-V Pioneer board device tree
+- sg2042: riscv: dts: add initial Sophgo SG2042 SoC device tree
+- sg2042: dt-bindings: interrupt-controller: Add Sophgo sg2042 CLINT mswi
+- sg2042: dt-bindings: timer: Add Sophgo sg2042 CLINT timer
+- sg2042: dt-bindings: interrupt-controller: Add Sophgo SG2042 PLIC
+- sg2042: dt-bindings: riscv: Add T-HEAD C920 compatibles
+- sg2042: dt-bindings: riscv: add sophgo sg2042 bindings
+- sg2042: dt-bindings: vendor-prefixes: add milkv/sophgo
+- sg2042: riscv: Add SOPHGO SOC family Kconfig support
+
+* Thu May 09 2024 ZhangPeng <zhangpeng362@huawei.com> - 6.6.0-25.0.0.28
+- !6930 fix general protection fault in update_cpumask
+- cgroup/cpuset: fix general protection fault in update_cpumask
+- !6905 v2 arm64: mmap: disable align larger anonymous mappings on THP boundaries
+- arm64: mmap: disable align larger anonymous mappings on THP boundaries
+- !7015 Fixes and cleanups to fs-writeback
+- fs/writeback: remove unnecessary return in writeback_inodes_sb
+- fs/writeback: correct comment of __wakeup_flusher_threads_bdi
+- fs/writeback: only calculate dirtied_before when b_io is empty
+- fs/writeback: remove unused parameter wb of finish_writeback_work
+- fs/writeback: bail out if there is no more inodes for IO and queued once
+- fs/writeback: avoid to writeback non-expired inode in kupdate writeback
+- !6581 LoongArch: fix KASLR can not be disabled by nokaslr when boot from old BPI
+- LoongArch: fix KASLR can not be disabled by nokaslr when boot from old BPI
+- !6483 LoongArch: fix boot error caused by ioremap_page_range error
+- LoongArch: fix boot error caused by ioremap_page_range error
+- !6759 net: hns3: backport some maillist patches
+- net: hns3: move constants from hclge_debugfs.h to hclge_debugfs.c
+- net: hns3: dump more reg info based on ras mod
+- net: hns3: add command queue trace for hns3
+- net: hns3: add support to query scc version by devlink info
+- net: hns3: revert "net: hns3: dump more reg info based on ras mod"
+- net: hns3: revert "net: hns3: add command queue trace for hns3"
+- net: hns3: revert "net: hns3: add support to query scc version by devlink info"
+- !7011 v3 bugfix patches from OLK-5.10
+- x86/quirks: Add parameter to clear MSIs early on boot
+- x86/PCI: Export find_cap() to be used in early PCI code
+- !6844 block: fix deadlock between bd_link_disk_holder and partition scan
+- block: fix deadlock between bd_link_disk_holder and partition scan
+- !5879 [OLK-6.6] Fix 'duplicate symbol rnp10_netdev_ops' error for RNPGBE driver with x86_64-allyesconfig
+- RNPGBE: NET: Fix 'duplicate symbol rnp10_netdev_ops' errors
+- !5836 [OLK-6.6] Fix "'snprintf' output between 10 and 37 bytes into a destination of size 24" warning for RNP driver with loongarch-allmodconfig
+- RNP: NET: Fix "'snprintf' output between 10 and 37 bytes into a destination of size 24" wanrings
+
+* Wed May 08 2024 ZhangPeng <zhangpeng362@huawei.com> - 6.6.0-24.0.0.27
+- !6824 Introduce CONFIG_ARCH_CUSTOM_NUMA_DISTANCE
+- config: enable COBFIG_ARCH_CUSTOM_NUMA_DISTANCE for arm64
+- arm64/numa: Support node_reclaim_distance adjust for arch
+- !6877 maple_tree: avoid checking other gaps after getting the largest gap
+- maple_tree: avoid checking other gaps after getting the largest gap
+- !6859 [openEuler-24.03-LTS][linux-6.6.y sync] Backport 6.6.23-6.6.30 LTS Patches
+- x86: update openeuler_defconfig for x86_64
+- bounds: Use the right number of bits for power-of-two CONFIG_NR_CPUS
+- net/mlx5e: Advertise mlx5 ethernet driver updates sk_buff md_dst for MACsec
+- macsec: Detect if Rx skb is macsec-related for offloading devices that update md_dst
+- macsec: Enable devices to advertise whether they update sk_buff md_dst during offloads
+- Revert "riscv: kdump: fix crashkernel reserving problem on RISC-V"
+- ovl: fix memory leak in ovl_parse_param()
+- phy: qcom: qmp-combo: fix VCO div offset on v5_5nm and v6
+- i2c: smbus: fix NULL function pointer dereference
+- sched/eevdf: Prevent vlag from going out of bounds in reweight_eevdf()
+- sched/eevdf: Fix miscalculation in reweight_entity() when se is not curr
+- sched/eevdf: Always update V if se->on_rq when reweighting
+- phy: ti: tusb1210: Resolve charger-det crash if charger psy is unregistered
+- riscv: Fix loading 64-bit NOMMU kernels past the start of RAM
+- riscv: Fix TASK_SIZE on 64-bit NOMMU
+- riscv: fix VMALLOC_START definition
+- dmaengine: idxd: Fix oops during rmmod on single-CPU platforms
+- dma: xilinx_dpdma: Fix locking
+- dmaengine: idxd: Convert spinlock to mutex to lock evl workqueue
+- phy: qcom: m31: match requested regulator name with dt schema
+- phy: rockchip: naneng-combphy: Fix mux on rk3588
+- phy: rockchip-snps-pcie3: fix clearing PHP_GRF_PCIESEL_CON bits
+- phy: rockchip-snps-pcie3: fix bifurcation on rk3588
+- phy: freescale: imx8m-pcie: fix pcie link-up instability
+- phy: marvell: a3700-comphy: Fix hardcoded array size
+- phy: marvell: a3700-comphy: Fix out of bounds read
+- soundwire: amd: fix for wake interrupt handling for clockstop mode
+- idma64: Don't try to serve interrupts when device is powered off
+- dmaengine: tegra186: Fix residual calculation
+- dmaengine: owl: fix register access functions
+- x86/tdx: Preserve shared bit on mprotect()
+- phy: qcom: qmp-combo: Fix VCO div offset on v3
+- phy: qcom: qmp-combo: Fix register base for QSERDES_DP_PHY_MODE
+- mtd: diskonchip: work around ubsan link failure
+- udp: preserve the connected status if only UDP cmsg
+- fbdev: fix incorrect address computation in deferred IO
+- stackdepot: respect __GFP_NOLOCKDEP allocation flag
+- net: b44: set pause params only when interface is up
+- ethernet: Add helper for assigning packet type when dest address does not match device address
+- ACPI: CPPC: Fix access width used for PCC registers
+- ACPI: CPPC: Fix bit_offset shift in MASK_VAL() macro
+- ACPI: CPPC: Use access_width over bit_width for system memory accesses
+- irqchip/gic-v3-its: Prevent double free on error
+- drm/amdgpu: Fix leak when GPU memory allocation fails
+- drm/amdgpu: Assign correct bits for SDMA HDP flush
+- drm/amdgpu/sdma5.2: use legacy HDP flush for SDMA2/3
+- arm64: dts: rockchip: enable internal pull-up for Q7_THRM# on RK3399 Puma
+- arm64: dts: qcom: sm8450: Fix the msi-map entries
+- arm64: dts: qcom: sc8280xp: add missing PCIe minimum OPP
+- LoongArch: Fix access error when read fault on a write-only VMA
+- LoongArch: Fix callchain parse error with kernel tracepoint events
+- cpu: Re-enable CPU mitigations by default for !X86 architectures
+- btrfs: fix information leak in btrfs_ioctl_logical_to_ino()
+- btrfs: scrub: run relocation repair when/only needed
+- btrfs: fix wrong block_start calculation for btrfs_drop_extent_map_range()
+- btrfs: fallback if compressed IO fails for ENOSPC
+- HID: i2c-hid: remove I2C_HID_READ_PENDING flag to prevent lock-up
+- smb3: fix lock ordering potential deadlock in cifs_sync_mid_result
+- smb3: missing lock when picking channel
+- smb: client: Fix struct_group() usage in __packed structs
+- mm: support page_mapcount() on page_has_type() pages
+- mm: create FOLIO_FLAG_FALSE and FOLIO_TYPE_OPS macros
+- mmc: sdhci-msm: pervent access to suspended controller
+- mtd: rawnand: qcom: Fix broken OP_RESET_DEVICE command in qcom_misc_cmd_type_exec()
+- Bluetooth: qca: fix NULL-deref on non-serdev setup
+- Bluetooth: qca: fix NULL-deref on non-serdev suspend
+- Bluetooth: btusb: Add Realtek RTL8852BE support ID 0x0bda:0x4853
+- Bluetooth: Fix type of len in {l2cap,sco}_sock_getsockopt_old()
+- rust: remove `params` from `module` macro example
+- kbuild: rust: force `alloc` extern to allow "empty" Rust files
+- kbuild: rust: remove unneeded `@rustc_cfg` to avoid ICE
+- rust: make mutually exclusive with CFI_CLANG
+- rust: init: remove impl Zeroable for Infallible
+- rust: don't select CONSTRUCTORS
+- x86/cpu: Fix check for RDPKRU in __show_regs()
+- selftests/seccomp: Handle EINVAL on unshare(CLONE_NEWPID)
+- selftests/seccomp: Change the syscall used in KILL_THREAD test
+- selftests/seccomp: user_notification_addfd check nextfd is available
+- Squashfs: check the inode number is not the invalid value of zero
+- squashfs: convert to new timestamp accessors
+- drm/amdgpu: fix visible VRAM handling during faults
+- drm/amdgpu: add shared fdinfo stats
+- drm: add drm_gem_object_is_shared_for_memory_stats() helper
+- mm/madvise: make MADV_POPULATE_(READ|WRITE) handle VM_FAULT_RETRY properly
+- mm/gup: explicitly define and check internal GUP flags, disallow FOLL_TOUCH
+- KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL at "RESET"
+- KVM: x86/pmu: Zero out PMU metadata on AMD if PMU is disabled
+- af_unix: Suppress false-positive lockdep splat for spin_lock() in __unix_gc().
+- tls: fix lockless read of strp->msg_ready in ->poll
+- net: ethernet: ti: am65-cpts: Fix PTPv1 message type on TX packets
+- ice: fix LAG and VF lock dependency in ice_reset_vf()
+- iavf: Fix TC config comparison with existing adapter TC config
+- i40e: Report MFS in decimal base instead of hex
+- i40e: Do not use WQ_MEM_RECLAIM flag for workqueue
+- net: ti: icssg-prueth: Fix signedness bug in prueth_init_rx_chns()
+- net: phy: dp83869: Fix MII mode failure
+- netfilter: nf_tables: honor table dormant flag from netdev release event path
+- ARM: dts: imx6ull-tarragon: fix USB over-current polarity
+- eth: bnxt: fix counting packets discarded due to OOM and netpoll
+- mlxsw: spectrum_acl_tcam: Fix memory leak when canceling rehash work
+- mlxsw: spectrum_acl_tcam: Fix incorrect list API usage
+- mlxsw: spectrum_acl_tcam: Fix warning during rehash
+- mlxsw: spectrum_acl_tcam: Fix memory leak during rehash
+- mlxsw: spectrum_acl_tcam: Rate limit error message
+- mlxsw: spectrum_acl_tcam: Fix possible use-after-free during rehash
+- mlxsw: spectrum_acl_tcam: Fix possible use-after-free during activity update
+- mlxsw: spectrum_acl_tcam: Fix race during rehash delayed work
+- mlxsw: spectrum_acl_tcam: Fix race in region ID allocation
+- mlxsw: Use refcount_t for reference counting
+- net: openvswitch: Fix Use-After-Free in ovs_ct_exit
+- ipvs: Fix checksumming on GSO of SCTP packets
+- Bluetooth: qca: set power_ctrl_enabled on NULL returned by gpiod_get_optional()
+- Bluetooth: hci_sync: Using hci_cmd_sync_submit when removing Adv Monitor
+- Bluetooth: btusb: mediatek: Fix double free of skb in coredump
+- Bluetooth: MGMT: Fix failing to MGMT_OP_ADD_UUID/MGMT_OP_REMOVE_UUID
+- Bluetooth: hci_event: Fix sending HCI_OP_READ_ENC_KEY_SIZE
+- Bluetooth: btusb: Fix triggering coredump implementation for QCA
+- gpio: tegra186: Fix tegra186_gpio_is_accessible() check
+- net: phy: mediatek-ge-soc: follow netdev LED trigger semantics
+- net: gtp: Fix Use-After-Free in gtp_dellink
+- net: usb: ax88179_178a: stop lying about skb->truesize
+- ipv4: check for NULL idev in ip_route_use_hint()
+- net: fix sk_memory_allocated_{add|sub} vs softirqs
+- net: make SK_MEMORY_PCPU_RESERV tunable
+- tools: ynl: don't ignore errors in NLMSG_DONE messages
+- ax25: Fix netdev refcount issue
+- NFC: trf7970a: disable all regulators on removal
+- net: dsa: mv88e6xx: fix supported_interfaces setup in mv88e6250_phylink_get_caps()
+- cxl/core: Fix potential payload size confusion in cxl_mem_get_poison()
+- bnxt_en: Fix the PCI-AER routines
+- bnxt_en: refactor reset close code
+- bridge/br_netlink.c: no need to return void function
+- icmp: prevent possible NULL dereferences from icmp_build_probe()
+- ARM: dts: microchip: at91-sama7g5ek: Replace regulator-suspend-voltage with the valid property
+- mlxsw: core_env: Fix driver initialization with old firmware
+- mlxsw: core: Unregister EMAD trap using FORWARD action
+- net: bcmasp: fix memory leak when bringing down interface
+- vxlan: drop packets from invalid src-address
+- net: libwx: fix alloc msix vectors failed
+- wifi: mac80211: fix unaligned le16 access
+- wifi: mac80211: remove link before AP
+- wifi: mac80211_hwsim: init peer measurement result
+- drm/gma500: Remove lid code
+- wifi: iwlwifi: mvm: return uid from iwl_mvm_build_scan_cmd
+- wifi: iwlwifi: mvm: remove old PASN station when adding a new one
+- wifi: mac80211: split mesh fast tx cache into local/proxied/forwarded
+- wifi: mac80211: clean up assignments to pointer cache.
+- ARC: [plat-hsdk]: Remove misplaced interrupt-cells property
+- gpio: tangier: Use correct type for the IRQ chip data
+- arm64: dts: qcom: sc8180x: Fix ss_phy_irq for secondary USB controller
+- arm64: dts: rockchip: regulator for sd needs to be always on for BPI-R2Pro
+- arm64: dts: mediatek: mt2712: fix validation errors
+- arm64: dts: mediatek: mt7986: prefix BPI-R3 cooling maps with "map-"
+- arm64: dts: mediatek: mt7986: drop invalid thermal block clock
+- arm64: dts: mediatek: mt7986: reorder nodes
+- arm64: dts: mediatek: mt7986: drop "#reset-cells" from Ethernet controller
+- arm64: dts: mediatek: mt7986: drop invalid properties from ethsys
+- arm64: dts: mediatek: mt7986: reorder properties
+- arm64: dts: mediatek: mt7622: drop "reset-names" from thermal block
+- arm64: dts: mediatek: mt7622: fix ethernet controller "compatible"
+- arm64: dts: mediatek: mt7622: fix IR nodename
+- arm64: dts: mediatek: mt7622: fix clock controllers
+- arm64: dts: mediatek: mt8183-kukui: Use default min voltage for MT6358
+- arm64: dts: mediatek: mt8195-cherry: Update min voltage constraint for MT6315
+- arm64: dts: mediatek: mt8192-asurada: Update min voltage constraint for MT6315
+- arm64: dts: mediatek: cherry: Describe CPU supplies
+- arm64: dts: mediatek: cherry: Add platform thermal configuration
+- arm64: dts: mediatek: mt8195: Add missing gce-client-reg to mutex1
+- arm64: dts: mediatek: mt8195: Add missing gce-client-reg to mutex
+- arm64: dts: mediatek: mt8195: Add missing gce-client-reg to vpp/vdosys
+- arm64: dts: mediatek: mt8192: Add missing gce-client-reg to mutex
+- arm64: dts: mediatek: mt8183: Add power-domains properity to mfgcfg
+- arm64: dts: rockchip: Remove unsupported node from the Pinebook Pro dts
+- arm64: dts: rockchip: enable internal pull-up on PCIE_WAKE# for RK3399 Puma
+- arm64: dts: rockchip: fix alphabetical ordering RK3399 puma
+- arm64: dts: rockchip: enable internal pull-up on Q7_USB_ID for RK3399 Puma
+- arm64: dts: rockchip: set PHY address of MT7531 switch to 0x1f
+- HID: logitech-dj: allow mice to use all types of reports
+- HID: intel-ish-hid: ipc: Fix dev_err usage with uninitialized dev->devc
+- cifs: reinstate original behavior again for forceuid/forcegid
+- smb: client: fix rename(2) regression against samba
+- cifs: Fix reacquisition of volume cookie on still-live connection
+- selftests: kselftest: Fix build failure with NOLIBC
+- thunderbolt: Reset only non-USB4 host routers in resume
+- PCI/ASPM: Fix deadlock when enabling ASPM
+- ksmbd: common: use struct_group_attr instead of struct_group for network_open_info
+- ksmbd: clear RENAME_NOREPLACE before calling vfs_rename
+- ksmbd: validate request buffer size in smb2_allocate_rsp_buf()
+- ksmbd: fix slab-out-of-bounds in smb2_allocate_rsp_buf
+- powerpc/ftrace: Ignore ftrace locations in exit text sections
+- virtio_net: Do not send RSS key if it is not supported
+- net: dsa: mt7530: fix enabling EEE on MT7531 switch on all boards
+- net: dsa: mt7530: fix improper frames on all 25MHz and 40MHz XTAL MT7530
+- nilfs2: fix OOB in nilfs_set_de_type
+- bootconfig: use memblock_free_late to free xbc memory to buddy
+- nouveau: fix instmem race condition around ptr stores
+- drm/vmwgfx: Fix crtc's atomic check conditional
+- drm/vmwgfx: Sort primary plane formats by order of preference
+- drm/vmwgfx: Fix prime import/export
+- drm/amdgpu: remove invalid resource->start check v2
+- drm/amdkfd: Fix memory leak in create_process failure
+- drm/amdgpu: validate the parameters of bo mapping operations more clearly
+- fuse: fix leaked ENOSYS error on first statx call
+- mm/shmem: inline shmem_is_huge() for disabled transparent hugepages
+- mm/memory-failure: fix deadlock when hugetlb_optimize_vmemmap is enabled
+- mm,swapops: update check in is_pfn_swap_entry for hwpoison entries
+- mm/userfaultfd: allow hugetlb change protection upon poison entry
+- init/main.c: Fix potential static_command_line memory overflow
+- arm64: hibernate: Fix level3 translation fault in swsusp_save()
+- arm64/head: Disable MMU at EL2 before clearing HCR_EL2.E2H
+- KVM: x86/mmu: Write-protect L2 SPTEs in TDP MMU when clearing dirty status
+- KVM: x86/pmu: Do not mask LVTPC when handling a PMI on AMD platforms
+- KVM: x86/pmu: Disable support for adaptive PEBS
+- KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel compatible
+- sched: Add missing memory barrier in switch_mm_cid
+- fs: sysfs: Fix reference leak in sysfs_break_active_protection()
+- speakup: Avoid crash on very long word
+- mei: me: disable RPL-S on SPS and IGN firmwares
+- usb: gadget: f_ncm: Fix UAF ncm object at re-bind after usb ep transport error
+- usb: Disable USB3 LPM at shutdown
+- usb: dwc2: host: Fix dereference issue in DDMA completion flow.
+- Revert "usb: cdc-wdm: close race between read and workqueue"
+- USB: serial: option: add Telit FN920C04 rmnet compositions
+- USB: serial: option: add Rolling RW101-GL and RW135-GL support
+- USB: serial: option: support Quectel EM060K sub-models
+- USB: serial: option: add Lonsung U8300/U9300 product
+- USB: serial: option: add support for Fibocom FM650/FG650
+- USB: serial: option: add Fibocom FM135-GL variants
+- serial: core: Fix missing shutdown and startup for serial base port
+- serial: core: Clearing the circular buffer before NULLifying it
+- serial: stm32: Reset .throttled state in .startup()
+- serial: stm32: Return IRQ_NONE in the ISR if no handling happend
+- serial/pmac_zilog: Remove flawed mitigation for rx irq flood
+- serial: mxs-auart: add spinlock around changing cts state
+- comedi: vmk80xx: fix incomplete endpoint checking
+- thunderbolt: Fix wake configurations after device unplug
+- thunderbolt: Avoid notify PM core about runtime PM resume
+- binder: check offset alignment in binder_get_object()
+- ALSA: hda/realtek - Enable audio jacks of Haier Boyue G42 with ALC269VC
+- ALSA: hda/realtek: Add quirks for Huawei Matebook D14 NBLB-WAX9N
+- ALSA: hda/tas2781: Add new vendor_id and subsystem_id to support ThinkPad ICE-1
+- ALSA: hda/tas2781: correct the register for pow calibrated data
+- ALSA: seq: ump: Fix conversion from MIDI2 to MIDI1 UMP messages
+- net/mlx5: E-switch, store eswitch pointer before registering devlink_param
+- x86/cpufeatures: Fix dependencies for GFNI, VAES, and VPCLMULQDQ
+- x86/bugs: Fix BHI retpoline check
+- clk: mediatek: Do a runtime PM get on controllers during probe
+- clk: Get runtime PM before walking tree for clk_summary
+- clk: Show active consumers of clocks in debugfs
+- clk: Get runtime PM before walking tree during disable_unused
+- clk: Initialize struct clk_core kref earlier
+- clk: Remove prepare_lock hold assertion in __clk_release()
+- interconnect: Don't access req_list while it's being manipulated
+- platform/x86/amd/pmc: Extend Framework 13 quirk to more BIOSes
+- usb: new quirk to reduce the SET_ADDRESS request timeout
+- usb: xhci: Add timeout argument in address_device USB HCD callback
+- drm: panel-orientation-quirks: Add quirk for Lenovo Legion Go
+- ALSA: scarlett2: Rename scarlett_gen2 to scarlett2
+- PCI: Simplify pcie_capability_clear_and_set_word() to ..._clear_word()
+- PCI/DPC: Use FIELD_GET()
+- ALSA: scarlett2: Add Focusrite Clarett 2Pre and 4Pre USB support
+- ALSA: scarlett2: Add Focusrite Clarett+ 2Pre and 4Pre support
+- ALSA: scarlett2: Add correct product series name to messages
+- ALSA: scarlett2: Default mixer driver to enabled
+- thunderbolt: Reset topology created by the boot firmware
+- thunderbolt: Make tb_switch_reset() support Thunderbolt 2, 3 and USB4 routers
+- thunderbolt: Introduce tb_path_deactivate_hop()
+- thunderbolt: Introduce tb_port_reset()
+- ASoC: ti: Convert Pandora ASoC to GPIO descriptors
+- ALSA: scarlett2: Add support for Clarett 8Pre USB
+- ALSA: scarlett2: Move USB IDs out from device_info struct
+- drm/radeon: make -fstrict-flex-arrays=3 happy
+- drm/panel: visionox-rm69299: don't unregister DSI device
+- drm: nv04: Fix out of bounds access
+- s390/cio: fix race condition during online processing
+- s390/qdio: handle deferred cc1
+- perf lock contention: Add a missing NULL check
+- RDMA/mlx5: Fix port number for counter query in multi-port configuration
+- RDMA/cm: Print the old state when cm_destroy_id gets timeout
+- RDMA/rxe: Fix the problem "mutex_destroy missing"
+- drm/i915/mst: Limit MST+DSC to TGL+
+- net: ethernet: ti: am65-cpsw-nuss: cleanup DMA Channels before using them
+- net: ethernet: mtk_eth_soc: fix WED + wifi reset
+- gpiolib: swnode: Remove wrong header inclusion
+- s390/ism: Properly fix receive message buffer allocation
+- net: dsa: mt7530: fix port mirroring for MT7988 SoC switch
+- net: dsa: mt7530: fix mirroring frames received on local port
+- tun: limit printing rate when illegal packet received by tun dev
+- ice: Fix checking for unsupported keys on non-tunnel device
+- ice: tc: allow zero flags in parsing tc flower
+- ice: tc: check src_vsi in case of traffic from VF
+- net: stmmac: Fix IP-cores specific MAC capabilities
+- net: stmmac: Fix max-speed being ignored on queue re-init
+- net: stmmac: Apply half-duplex-less constraint for DW QoS Eth only
+- octeontx2-pf: fix FLOW_DIS_IS_FRAGMENT implementation
+- net: change maximum number of UDP segments to 128
+- net/mlx5e: Prevent deadlock while disabling aRFS
+- net/mlx5: Lag, restore buckets number to default after hash LAG deactivation
+- net: sparx5: flower: fix fragment flags handling
+- af_unix: Don't peek OOB data without MSG_OOB.
+- af_unix: Call manage_oob() for every skb in unix_stream_read_generic().
+- netfilter: flowtable: incorrect pppoe tuple
+- netfilter: flowtable: validate pppoe header
+- netfilter: nft_set_pipapo: do not free live element
+- netfilter: nf_tables: Fix potential data-race in __nft_obj_type_get()
+- netfilter: nf_tables: Fix potential data-race in __nft_expr_type_get()
+- scsi: ufs: qcom: Add missing interconnect bandwidth values for Gear 5
+- arm64: tlb: Fix TLBI RANGE operand
+- arm64/mm: Modify range-based tlbi to decrement scale
+- net: usb: ax88179_178a: avoid writing the mac address before first reading
+- scsi: core: Fix handling of SCMD_FAIL_IF_RECOVERING
+- random: handle creditable entropy from atomic process context
+- selftests/ftrace: Limit length in subsystem-enable tests
+- SUNRPC: Fix rpcgss_context trace event acceptor field
+- drm/i915/vma: Fix UAF on destroy against retire race
+- io_uring: Fix io_cqring_wait() not restoring sigmask on get_timespec64() failure
+- media: videobuf2: request more buffers for vb2_read
+- drm/msm/dpu: populate SSPP scaler block version
+- selftests: timers: Fix posix_timers ksft_print_msg() warning
+- ceph: redirty page before returning AOP_WRITEPAGE_ACTIVATE
+- ceph: rename _to_client() to _to_fs_client()
+- ceph: pass the mdsc to several helpers
+- drm/amd/display: Do not recursively call manual trigger programming
+- selftests/timers/posix_timers: Reimplement check_timer_distribution()
+- selftests: timers: Convert posix_timers test to generate KTAP output
+- drm/i915: Disable live M/N updates when using bigjoiner
+- drm/i915: Adjust seamless_m_n flag behaviour
+- drm/i915: Enable VRR later during fastsets
+- drm/i915: Extract intel_crtc_vblank_evade_scanlines()
+- drm/i915: Change intel_pipe_update_{start,end}() calling convention
+- drm/i915/cdclk: Fix voltage_level programming edge case
+- drm/i915/mst: Reject FEC+MST on ICL
+- drm/i915: Fix FEC pipe A vs. DDI A mixup
+- smb: client: refresh referral without acquiring refpath_lock
+- smb: client: guarantee refcounted children from parent session
+- smb3: show beginning time for per share stats
+- smb: client: fix UAF in smb2_reconnect_server()
+- smb: client: remove extra @chan_count check in __cifs_put_smb_ses()
+- drm/amd/display: fix disable otg wa logic in DCN316
+- drm/amd/display: Set VSC SDP Colorimetry same way for MST and SST
+- drm/amd/display: Program VSC SDP colorimetry for all DP sinks >= 1.4
+- drm/amdgpu: fix incorrect number of active RBs for gfx11
+- drm/amdgpu: always force full reset for SOC21
+- drm/amdgpu: Reset dGPU if suspend got aborted
+- drm/i915: Disable port sync when bigjoiner is used
+- drm/i915/cdclk: Fix CDCLK programming order when pipes are active
+- x86/bugs: Replace CONFIG_SPECTRE_BHI_{ON,OFF} with CONFIG_MITIGATION_SPECTRE_BHI
+- x86/bugs: Remove CONFIG_BHI_MITIGATION_AUTO and spectre_bhi=auto
+- x86/bugs: Clarify that syscall hardening isn't a BHI mitigation
+- x86/bugs: Fix BHI handling of RRSBA
+- x86/bugs: Rename various 'ia32_cap' variables to 'x86_arch_cap_msr'
+- x86/bugs: Cache the value of MSR_IA32_ARCH_CAPABILITIES
+- x86/bugs: Fix BHI documentation
+- x86/bugs: Fix return type of spectre_bhi_state()
+- irqflags: Explicitly ignore lockdep_hrtimer_exit() argument
+- x86/apic: Force native_apic_mem_read() to use the MOV instruction
+- selftests: timers: Fix abs() warning in posix_timers test
+- x86/cpu: Actually turn off mitigations by default for SPECULATION_MITIGATIONS=n
+- perf/x86: Fix out of range data
+- vhost: Add smp_rmb() in vhost_enable_notify()
+- vhost: Add smp_rmb() in vhost_vq_avail_empty()
+- arm64: dts: imx8-ss-dma: fix spi lpcg indices
+- arm64: dts: imx8-ss-lsio: fix pwm lpcg indices
+- arm64: dts: imx8-ss-conn: fix usb lpcg indices
+- arm64: dts: imx8-ss-dma: fix adc lpcg indices
+- arm64: dts: imx8-ss-dma: fix can lpcg indices
+- arm64: dts: imx8qm-ss-dma: fix can lpcg indices
+- drm/client: Fully protect modes[] with dev->mode_config.mutex
+- drm/panfrost: Fix the error path in panfrost_mmu_map_fault_addr()
+- drm/ast: Fix soft lockup
+- drm/amdkfd: Reset GPU on queue preemption failure
+- drm/i915/vrr: Disable VRR when using bigjoiner
+- drm/vmwgfx: Enable DMA mappings with SEV
+- accel/ivpu: Fix deadlock in context_xa
+- scsi: sg: Avoid race in error handling & drop bogus warn
+- scsi: sg: Avoid sg device teardown race
+- kprobes: Fix possible use-after-free issue on kprobe registration
+- io_uring/net: restore msg_control on sendzc retry
+- btrfs: qgroup: convert PREALLOC to PERTRANS after record_root_in_trans
+- btrfs: record delayed inode root in transaction
+- btrfs: qgroup: fix qgroup prealloc rsv leak in subvolume operations
+- btrfs: qgroup: correctly model root qgroup rsv in convert
+- selftests: mptcp: use += operator to append strings
+- iommu/vt-d: Allocate local memory for page request queue
+- iommu/vt-d: Fix wrong use of pasid config
+- tracing: hide unused ftrace_event_id_fops
+- net: ena: Set tx_info->xdpf value to NULL
+- net: ena: Use tx_ring instead of xdp_ring for XDP channel TX
+- net: ena: Pass ena_adapter instead of net_device to ena_xmit_common()
+- net: ena: Move XDP code to its new files
+- net: ena: Fix incorrect descriptor free behavior
+- net: ena: Wrong missing IO completions check order
+- net: ena: Fix potential sign extension issue
+- af_unix: Fix garbage collector racing against connect()
+- af_unix: Do not use atomic ops for unix_sk(sk)->inflight.
+- net: dsa: mt7530: trap link-local frames regardless of ST Port State
+- Revert "s390/ism: fix receive message buffer allocation"
+- net: sparx5: fix wrong config being used when reconfiguring PCS
+- net/mlx5e: Do not produce metadata freelist entries in Tx port ts WQE xmit
+- net/mlx5e: HTB, Fix inconsistencies with QoS SQs number
+- net/mlx5e: Fix mlx5e_priv_init() cleanup flow
+- net/mlx5: Correctly compare pkt reformat ids
+- net/mlx5: Properly link new fs rules into the tree
+- net/mlx5: offset comp irq index in name by one
+- net/mlx5: Register devlink first under devlink lock
+- net/mlx5: SF, Stop waiting for FW as teardown was called
+- netfilter: complete validation of user input
+- Bluetooth: l2cap: Don't double set the HCI_CONN_MGMT_CONNECTED bit
+- Bluetooth: SCO: Fix not validating setsockopt user input
+- Bluetooth: hci_sync: Fix using the same interval and window for Coded PHY
+- Bluetooth: hci_sync: Use QoS to determine which PHY to scan
+- Bluetooth: ISO: Don't reject BT_ISO_QOS if parameters are unset
+- Bluetooth: ISO: Align broadcast sync_timeout with connection timeout
+- ipv6: fix race condition between ipv6_get_ifaddr and ipv6_del_addr
+- ipv4/route: avoid unused-but-set-variable warning
+- ipv6: fib: hide unused 'pn' variable
+- octeontx2-af: Fix NIX SQ mode and BP config
+- af_unix: Clear stale u->oob_skb.
+- net: ks8851: Handle softirqs at the end of IRQ thread to fix hang
+- net: ks8851: Inline ks8851_rx_skb()
+- bnxt_en: Reset PTP tx_avail after possible firmware reset
+- bnxt_en: Fix error recovery for RoCE ulp client
+- bnxt_en: Fix possible memory leak in bnxt_rdma_aux_device_init()
+- s390/ism: fix receive message buffer allocation
+- geneve: fix header validation in geneve[6]_xmit_skb
+- block: fix q->blkg_list corruption during disk rebind
+- octeontx2-pf: Fix transmit scheduler resource leak
+- xsk: validate user input for XDP_{UMEM|COMPLETION}_FILL_RING
+- u64_stats: fix u64_stats_init() for lockdep when used repeatedly in one file
+- net: openvswitch: fix unwanted error log on timeout policy probing
+- scsi: qla2xxx: Fix off by one in qla_edif_app_getstats()
+- nouveau: fix function cast warning
+- Revert "drm/qxl: simplify qxl_fence_wait"
+- cxl/core: Fix initialization of mbox_cmd.size_out in get event
+- arm64: dts: imx8-ss-conn: fix usdhc wrong lpcg clock order
+- drm/msm/dpu: don't allow overriding data from catalog
+- cxl/core/regs: Fix usage of map->reg_type in cxl_decode_regblock() before assigned
+- cxl/mem: Fix for the index of Clear Event Record Handle
+- firmware: arm_scmi: Make raw debugfs entries non-seekable
+- ARM: OMAP2+: fix USB regression on Nokia N8x0
+- mmc: omap: restore original power up/down steps
+- mmc: omap: fix deferred probe
+- mmc: omap: fix broken slot switch lookup
+- ARM: OMAP2+: fix N810 MMC gpiod table
+- ARM: OMAP2+: fix bogus MMC GPIO labels on Nokia N8x0
+- media: cec: core: remove length check of Timer Status
+- PM: s2idle: Make sure CPUs will wakeup directly on resume
+- ACPI: scan: Do not increase dep_unmet for already met dependencies
+- platform/chrome: cros_ec_uart: properly fix race condition
+- drm/amd/pm: fixes a random hang in S4 for SMU v13.0.4/11
+- Bluetooth: Fix memory leak in hci_req_sync_complete()
+- ring-buffer: Only update pages_touched when a new page is touched
+- raid1: fix use-after-free for original bio in raid1_write_request()
+- ARM: dts: imx7s-warp: Pass OV2680 link-frequencies
+- batman-adv: Avoid infinite loop trying to resize local TT
+- ata: libata-scsi: Fix ata_scsi_dev_rescan() error path
+- ata: libata-core: Allow command duration limits detection for ACS-4 drives
+- smb3: fix Open files on server counter going negative
+- drm: Check polling initialized before enabling in drm_helper_probe_single_connector_modes
+- Revert "drm/amd/amdgpu: Fix potential ioremap() memory leaks in amdgpu_device_init()"
+- VMCI: Fix possible memcpy() run-time warning in vmci_datagram_invoke_guest_handler()
+- net: mpls: error out if inner headers are not set
+- Bluetooth: btintel: Fixe build regression
+- platform/x86: intel-vbtn: Update tablet mode switch at end of probe
+- randomize_kstack: Improve entropy diffusion
+- media: mediatek: vcodec: adding lock to protect encoder context list
+- media: mediatek: vcodec: adding lock to protect decoder context list
+- media: mediatek: vcodec: Fix oops when HEVC init fails
+- selftests: mptcp: display simult in extra_msg
+- gcc-plugins/stackleak: Avoid .head.text section
+- ALSA: hda/realtek: Add quirks for some Clevo laptops
+- fbmon: prevent division by zero in fb_videomode_from_videomode()
+- drivers/nvme: Add quirks for device 126f:2262
+- modpost: fix null pointer dereference
+- io_uring: clear opcode specific data for an early failure
+- fbdev: viafb: fix typo in hw_bitblt_1 and hw_bitblt_2
+- x86/xen: attempt to inflate the memory balloon on PVH
+- ASoC: soc-core.c: Skip dummy codec when adding platforms
+- thermal/of: Assume polling-delay(-passive) 0 when absent
+- ASoC: amd: yc: Fix non-functional mic on ASUS M7600RE
+- usb: sl811-hcd: only defined function checkdone if QUIRK2 is defined
+- usb: typec: tcpci: add generic tcpci fallback compatible
+- thunderbolt: Keep the domain powered when USB4 port is in redrive mode
+- usb: typec: ucsi: Limit read size on v1.2
+- usb: gadget: uvc: mark incomplete frames with UVC_STREAM_ERR
+- bus: mhi: host: Add MHI_PM_SYS_ERR_FAIL state
+- tools: iio: replace seekdir() in iio_generic_buffer
+- ring-buffer: use READ_ONCE() to read cpu_buffer->commit_page in concurrent environment
+- Input: xpad - add support for Snakebyte GAMEPADs
+- ktest: force $buildonly = 1 for 'make_warnings_file' test type
+- ALSA: hda/realtek: Add quirk for Lenovo Yoga 9 14IMH9
+- platform/x86: touchscreen_dmi: Add an extra entry for a variant of the Chuwi Vi8 tablet
+- Input: allocate keycode for Display refresh rate toggle
+- Input: imagis - use FIELD_GET where applicable
+- RDMA/cm: add timeout to cm_destroy_id wait
+- block: prevent division by zero in blk_rq_stat_sum()
+- input/touchscreen: imagis: Correct the maximum touch area value
+- libperf evlist: Avoid out-of-bounds access
+- Revert "ACPI: PM: Block ASUS B1400CEAE from suspend to idle by default"
+- PCI: Disable D3cold on Asus B1400 PCI-NVMe bridge
+- SUNRPC: increase size of rpc_wait_queue.qlen from unsigned short to unsigned int
+- drm: Check output polling initialized before disabling
+- drm/amd/amdgpu: Fix potential ioremap() memory leaks in amdgpu_device_init()
+- HID: input: avoid polling stylus battery on Chromebook Pompom
+- i2c: designware: Fix RX FIFO depth define on Wangxun 10Gb NIC
+- accel/habanalabs: increase HL_MAX_STR to 64 bytes to avoid warnings
+- drm/amd/display: Fix nanosec stat overflow
+- ext4: forbid commit inconsistent quota data when errors=remount-ro
+- ext4: add a hint for block bitmap corrupt state in mb_groups
+- ASoC: Intel: avs: Populate board selection with new I2S entries
+- ALSA: firewire-lib: handle quirk to calculate payload quadlets as data block counter
+- media: sta2x11: fix irq handler cast
+- Julia Lawall reported this null pointer dereference, this should fix it.
+- rcu-tasks: Repair RCU Tasks Trace quiescence check
+- rcu/nocb: Fix WARN_ON_ONCE() in the rcu_nocb_bypass_lock()
+- ASoC: Intel: common: DMI remap for rebranded Intel NUC M15 (LAPRC710) laptops
+- isofs: handle CDs with bad root inode but good Joliet root directory
+- scsi: lpfc: Fix possible memory leak in lpfc_rcv_padisc()
+- sysv: don't call sb_bread() with pointers_lock held
+- pinctrl: renesas: checker: Limit cfg reg enum checks to provided IDs
+- drm/ttm: return ENOSPC from ttm_bo_mem_space v3
+- ASoC: SOF: amd: Optimize quirk for Valve Galileo
+- drm: panel-orientation-quirks: Add quirk for GPD Win Mini
+- Input: synaptics-rmi4 - fail probing if memory allocation for "phys" fails
+- drm/vc4: don't check if plane->state->fb == state->fb
+- Bluetooth: Add new quirk for broken read key length on ATS2851
+- Bluetooth: btmtk: Add MODULE_FIRMWARE() for MT7922
+- Bluetooth: btintel: Fix null ptr deref in btintel_read_version
+- net/smc: reduce rtnl pressure in smc_pnet_create_pnetids_list()
+- ice: use relative VSI index for VFs instead of PF VSI number
+- btrfs: send: handle path ref underflow in header iterate_inode_ref()
+- btrfs: export: handle invalid inode or root reference in btrfs_get_parent()
+- btrfs: handle chunk tree lookup error in btrfs_relocate_sys_chunks()
+- wifi: cfg80211: check A-MSDU format more carefully
+- wifi: iwlwifi: Add missing MODULE_FIRMWARE() for *.pnvm
+- overflow: Allow non-type arg to type_max() and type_min()
+- cpufreq: Don't unregister cpufreq cooling on CPU hotplug
+- wifi: ath11k: decrease MHI channel buffer length to 8KB
+- dma-direct: Leak pages on dma_set_decrypted() failure
+- net: pcs: xpcs: Return EINVAL in the internal methods
+- tools/power x86_energy_perf_policy: Fix file leak in get_pkg_num()
+- pstore/zone: Add a null pointer check to the psz_kmsg_read
+- ACPI: x86: Move acpi_quirk_skip_serdev_enumeration() out of CONFIG_X86_ANDROID_TABLETS
+- wifi: mt76: mt7996: add locking for accessing mapped registers
+- wifi: mt76: mt7996: disable AMSDU for non-data frames
+- wifi: mt76: mt7915: add locking for accessing mapped registers
+- wifi: brcmfmac: Add DMI nvram filename quirk for ACEPC W5 Pro
+- firmware: tegra: bpmp: Return directly after a failed kzalloc() in get_filename()
+- net: skbuff: add overflow debug check to pull/push helpers
+- ionic: set adminq irq affinity
+- pmdomain: imx8mp-blk-ctrl: imx8mp_blk: Add fdcc clock to hdmimix domain
+- pmdomain: ti: Add a null pointer check to the omap_prm_domain_init
+- net: add netdev_lockdep_set_classes() to virtual drivers
+- arm64: dts: rockchip: fix rk3399 hdmi ports node
+- arm64: dts: rockchip: fix rk3328 hdmi ports node
+- ARM: dts: rockchip: fix rk322x hdmi ports node
+- ARM: dts: rockchip: fix rk3288 hdmi ports node
+- cpuidle: Avoid potential overflow in integer multiplication
+- panic: Flush kernel log buffer at the end
+- printk: For @suppress_panic_printk check for other CPU in panic
+- wifi: iwlwifi: pcie: Add the PCI device id for new hardware
+- VMCI: Fix memcpy() run-time warning in dg_dispatch_as_host()
+- wifi: rtw89: pci: enlarge RX DMA buffer to consider size of RX descriptor
+- net: phy: phy_device: Prevent nullptr exceptions on ISR
+- net: stmmac: dwmac-starfive: Add support for JH7100 SoC
+- bnx2x: Fix firmware version string character counts
+- wifi: rtw89: fix null pointer access when abort scan
+- wifi: ath9k: fix LNA selection in ath_ant_try_scan()
+- amdkfd: use calloc instead of kzalloc to avoid integer overflow
+- x86: set SPECTRE_BHI_ON as default
+- KVM: x86: Add BHI_NO
+- x86/bhi: Mitigate KVM by default
+- x86/bhi: Add BHI mitigation knob
+- x86/bhi: Enumerate Branch History Injection (BHI) bug
+- x86/bhi: Define SPEC_CTRL_BHI_DIS_S
+- x86/bhi: Add support for clearing branch history at syscall entry
+- x86/syscall: Don't force use of indirect calls for system calls
+- x86/bugs: Change commas to semicolons in 'spectre_v2' sysfs file
+- x86/boot: Move mem_encrypt= parsing to the decompressor
+- x86/efistub: Remap kernel text read-only before dropping NX attribute
+- x86/sev: Move early startup code into .head.text section
+- x86/sme: Move early SME kernel encryption handling into .head.text
+- efi/libstub: Add generic support for parsing mem_encrypt=
+- x86/head/64: Move the __head definition to <asm/init.h>
+- bpf: put uprobe link's path and task in release callback
+- mptcp: don't account accept() of non-MPC client as fallback to TCP
+- mptcp: don't overwrite sock_ops in mptcp_is_tcpsk()
+- selftests: mptcp: connect: fix shellcheck warnings
+- of: module: prevent NULL pointer dereference in vsnprintf()
+- Revert "x86/mpparse: Register APIC address only once"
+- drm/i915/gt: Enable only one CCS for compute workload
+- drm/i915/gt: Do not generate the command streamer for all the CCS
+- drm/i915/gt: Disable HW load balancing for CCS
+- smb: client: fix potential UAF in cifs_signal_cifsd_for_reconnect()
+- smb: client: fix potential UAF in smb2_is_network_name_deleted()
+- smb: client: fix potential UAF in is_valid_oplock_break()
+- smb: client: fix potential UAF in smb2_is_valid_lease_break()
+- smb: client: fix potential UAF in smb2_is_valid_oplock_break()
+- smb: client: fix potential UAF in cifs_dump_full_key()
+- smb: client: fix potential UAF in cifs_stats_proc_show()
+- smb: client: fix potential UAF in cifs_stats_proc_write()
+- smb: client: fix potential UAF in cifs_debug_files_proc_show()
+- smb3: retrying on failed server close
+- smb: client: serialise cifs_construct_tcon() with cifs_mount_mutex
+- smb: client: handle DFS tcons in cifs_construct_tcon()
+- riscv: process: Fix kernel gp leakage
+- riscv: Fix spurious errors from __get/put_kernel_nofault
+- s390/entry: align system call table on 8 bytes
+- selftests/mm: include strings.h for ffsl
+- mm/secretmem: fix GUP-fast succeeding on secretmem folios
+- arm64/ptrace: Use saved floating point state type to determine SVE layout
+- perf/x86/intel/ds: Don't clear ->pebs_data_cfg for the last PEBS event
+- x86/coco: Require seeding RNG with RDRAND on CoCo systems
+- x86/mce: Make sure to grab mce_sysfs_mutex in set_bank()
+- x86/mm/pat: fix VM_PAT handling in COW mappings
+- of: dynamic: Synchronize of_changeset_destroy() with the devlink removals
+- driver core: Introduce device_link_wait_removal()
+- io_uring/kbuf: hold io_buffer_list reference over mmap
+- io_uring: use private workqueue for exit work
+- io_uring/kbuf: protect io_buffer_list teardown with a reference
+- io_uring/kbuf: get rid of bl->is_ready
+- io_uring/kbuf: get rid of lower BGID lists
+- ALSA: hda/realtek: Update Panasonic CF-SZ6 quirk to support headset with microphone
+- ALSA: hda/realtek - Fix inactive headset mic jack
+- ksmbd: do not set SMB2_GLOBAL_CAP_ENCRYPTION for SMB 3.1.1
+- ksmbd: validate payload size in ipc response
+- ksmbd: don't send oplock break if rename fails
+- gpio: cdev: fix missed label sanitizing in debounce_setup()
+- gpio: cdev: check for NULL labels when sanitizing them for irqs
+- x86/retpoline: Add NOENDBR annotation to the SRSO dummy return thunk
+- ice: fix typo in assignment
+- nfsd: hold a lighter-weight client reference over CB_RECALL_ANY
+- riscv: Disable preemption when using patch_map()
+- ASoC: SOF: amd: fix for false dsp interrupts
+- ata: sata_mv: Fix PCI device ID table declaration compilation warning
+- spi: mchp-pci1xxx: Fix a possible null pointer dereference in pci1xxx_spi_probe
+- cifs: Fix caching to try to do open O_WRONLY as rdwr on server
+- Revert "ALSA: emu10k1: fix synthesizer sample playback position and caching"
+- scsi: mylex: Fix sysfs buffer lengths
+- ata: sata_sx4: fix pdc20621_get_from_dimm() on 64-bit
+- regmap: maple: Fix uninitialized symbol 'ret' warnings
+- ASoC: amd: acp: fix for acp_init function error handling
+- spi: s3c64xx: Use DMA mode from fifo size
+- spi: s3c64xx: determine the fifo depth only once
+- spi: s3c64xx: allow full FIFO masks
+- spi: s3c64xx: define a magic value
+- spi: s3c64xx: remove else after return
+- spi: s3c64xx: explicitly include <linux/bits.h>
+- spi: s3c64xx: sort headers alphabetically
+- spi: s3c64xx: Extract FIFO depth calculation to a dedicated macro
+- ASoC: ops: Fix wraparound for mask in snd_soc_get_volsw
+- ASoC: rt722-sdca-sdw: fix locking sequence
+- ASoC: rt712-sdca-sdw: fix locking sequence
+- ASoC: rt711-sdw: fix locking sequence
+- ASoC: rt711-sdca: fix locking sequence
+- ASoC: rt5682-sdw: fix locking sequence
+- drm/prime: Unbreak virtgpu dma-buf export
+- nouveau/uvmm: fix addr/range calcs for remap operations
+- drm/panfrost: fix power transition timeout warnings
+- ALSA: hda: cs35l56: Add ACPI device match tables
+- regmap: maple: Fix cache corruption in regcache_maple_drop()
+- RISC-V: Update AT_VECTOR_SIZE_ARCH for new AT_MINSIGSTKSZ
+- drivers/perf: riscv: Disable PERF_SAMPLE_BRANCH_* while not supported
+- ASoC: wm_adsp: Fix missing mutex_lock in wm_adsp_write_ctl()
+- 9p: Fix read/write debug statements to report server reply
+- fs/pipe: Fix lockdep false-positive in watchqueue pipe_write()
+- KVM: SVM: Add support for allowing zero SEV ASIDs
+- KVM: SVM: Use unsigned integers when dealing with ASIDs
+- net: ravb: Always update error counters
+- net: ravb: Always process TX descriptor ring
+- net: ravb: Let IP-specific receive function to interrogate descriptors
+- e1000e: move force SMBUS from enable ulp function to avoid PHY loss issue
+- e1000e: Minor flow correction in e1000_shutdown function
+- e1000e: Workaround for sporadic MDI error on Meteor Lake systems
+- intel: legacy: field get conversion
+- intel: add bit macro includes where needed
+- i40e: Remove circular header dependencies and fix headers
+- i40e: Split i40e_osdep.h
+- i40e: Move memory allocation structures to i40e_alloc.h
+- i40e: Simplify memory allocation functions
+- virtchnl: Add header dependencies
+- i40e: Refactor I40E_MDIO_CLAUSE* macros
+- i40e: Remove back pointer from i40e_hw structure
+- i40e: Enforce software interrupt during busy-poll exit
+- i40e: Remove _t suffix from enum type names
+- drm/amd: Flush GFXOFF requests in prepare stage
+- drm/amd: Add concept of running prepare_suspend() sequence for IP blocks
+- drm/amd: Evict resources during PM ops prepare() callback
+- drm/amd/display: Prevent crash when disable stream
+- drm/amd/display: Fix DPSTREAM CLK on and off sequence
+- usb: typec: ucsi: Fix race between typec_switch and role_switch
+- i40e: fix vf may be used uninitialized in this function warning
+- i40e: fix i40e_count_filters() to count only active/new filters
+- octeontx2-af: Add array index check
+- octeontx2-pf: check negative error code in otx2_open()
+- octeontx2-af: Fix issue with loading coalesced KPU profiles
+- udp: prevent local UDP tunnel packets from being GROed
+- udp: do not transition UDP GRO fraglist partial checksums to unnecessary
+- udp: do not accept non-tunnel GSO skbs landing in a tunnel
+- r8169: skip DASH fw status checks when DASH is disabled
+- mlxbf_gige: stop interface during shutdown
+- ipv6: Fix infinite recursion in fib6_dump_done().
+- ax25: fix use-after-free bugs caused by ax25_ds_del_timer
+- tcp: Fix bind() regression for v6-only wildcard and v4(-mapped-v6) non-wildcard addresses.
+- selftests: reuseaddr_conflict: add missing new line at the end of the output
+- erspan: make sure erspan_base_hdr is present in skb->head
+- i40e: Fix VF MAC filter removal
+- ice: fix enabling RX VLAN filtering
+- gro: fix ownership transfer
+- selftests: net: gro fwd: update vxlan GRO test expectations
+- net: dsa: mv88e6xxx: fix usable ports on 88e6020
+- net: phy: micrel: Fix potential null pointer dereference
+- net: fec: Set mac_managed_pm during probe
+- net: txgbe: fix i2c dev name cannot match clkdev
+- net: phy: micrel: lan8814: Fix when enabling/disabling 1-step timestamping
+- net: stmmac: fix rx queue priority assignment
+- net/sched: fix lockdep splat in qdisc_tree_reduce_backlog()
+- net: dsa: sja1105: Fix parameters order in sja1110_pcs_mdio_write_c45()
+- net/sched: act_skbmod: prevent kernel-infoleak
+- KVM: arm64: Ensure target address is granule-aligned for range TLBI
+- x86/retpoline: Do the necessary fixup to the Zen3/4 srso return thunk for !SRSO
+- bpf, sockmap: Prevent lock inversion deadlock in map delete elem
+- vboxsf: Avoid an spurious warning if load_nls_xxx() fails
+- netfilter: validate user input for expected length
+- netfilter: nf_tables: discard table flag update with pending basechain deletion
+- netfilter: nf_tables: Fix potential data-race in __nft_flowtable_type_get()
+- netfilter: nf_tables: flush pending destroy work before exit_net release
+- netfilter: nf_tables: reject new basechain after table flag update
+- x86/bugs: Fix the SRSO mitigation on Zen3/4
+- x86/nospec: Refactor UNTRAIN_RET[_*]
+- x86/srso: Disentangle rethunk-dependent options
+- x86/srso: Improve i-cache locality for alias mitigation
+- vsock/virtio: fix packet delivery to tap device
+- net: mana: Fix Rx DMA datasize and skb_over_panic
+- net: usb: ax88179_178a: avoid the interface always configured as random address
+- net/rds: fix possible cp null dereference
+- xen-netfront: Add missing skb_mark_for_recycle
+- selftests: mptcp: join: fix dev in check_endpoint
+- netfilter: nf_tables: release mutex after nft_gc_seq_end from abort path
+- netfilter: nf_tables: release batch on table validation from abort path
+- Bluetooth: Fix TOCTOU in HCI debugfs implementation
+- Bluetooth: hci_event: set the conn encrypted before conn establishes
+- Bluetooth: add quirk for broken address properties
+- Bluetooth: qca: fix device-address endianness
+- arm64: dts: qcom: sc7180-trogdor: mark bluetooth address as broken
+- Revert "Bluetooth: hci_qca: Set BDA quirk bit if fwnode exists in DT"
+- x86/bpf: Fix IP after emitting call depth accounting
+- r8169: fix issue caused by buggy BIOS on certain boards with RTL8168d
+- selinux: avoid dereference of garbage after mount failure
+- KVM: arm64: Fix host-programmed guest events in nVHE
+- RISC-V: KVM: Fix APLIC in_clrip[x] read emulation
+- RISC-V: KVM: Fix APLIC setipnum_le/be write emulation
+- gpio: cdev: sanitize the label before requesting the interrupt
+- modpost: do not make find_tosym() return NULL
+- btrfs: fix race when detecting delalloc ranges during fiemap
+- btrfs: ensure fiemap doesn't race with writes when FIEMAP_FLAG_SYNC is given
+- Revert "x86/mm/ident_map: Use gbpages only where full GB page should be mapped."
+- mm/treewide: replace pud_large() with pud_leaf()
+- dm integrity: fix out-of-range warning
+- drm/i915/mtl: Update workaround 14018575942
+- drm/i915/xelpg: Extend some workarounds/tuning to gfx version 12.74
+- drm/i915/mtl: Update workaround 14016712196
+- drm/i915: Replace several IS_METEORLAKE with proper IP version checks
+- drm/i915: Eliminate IS_MTL_GRAPHICS_STEP
+- drm/i915/xelpg: Call Xe_LPG workaround functions based on IP version
+- drm/i915: Consolidate condition for Wa_22011802037
+- drm/i915: Tidy workaround definitions
+- drm/i915/dg2: Drop pre-production GT workarounds
+- inet: inet_defrag: prevent sk release while still in use
+- Octeontx2-af: fix pause frame configuration in GMP mode
+- net: lan743x: Add set RFE read fifo threshold for PCI1x1x chips
+- net: bcmasp: Bring up unimac after PHY link up
+- netfilter: nf_tables: skip netdev hook unregistration if table is dormant
+- netfilter: nf_tables: reject table flag and netdev basechain updates
+- netfilter: nf_tables: reject destroy command to remove basechain hooks
+- cifs: Fix duplicate fscache cookie warnings
+- bpf: Protect against int overflow for stack access size
+- mlxbf_gige: call request_irq() after NAPI initialized
+- tls: get psock ref after taking rxlock to avoid leak
+- tls: adjust recv return with async crypto and failed copy to userspace
+- tls: recv: process_rx_list shouldn't use an offset with kvec
+- net: hns3: mark unexcuted loopback test result as UNEXECUTED
+- net: hns3: fix kernel crash when devlink reload during pf initialization
+- net: hns3: fix index limit to support all queue stats
+- ACPICA: debugger: check status of acpi_evaluate_object() in acpi_db_walk_for_fields()
+- selftests: vxlan_mdb: Fix failures with old libnet
+- net: wwan: t7xx: Split 64bit accesses to fix alignment issues
+- tcp: properly terminate timers for kernel sockets
+- net: hsr: hsr_slave: Fix the promiscuous mode in offload mode
+- s390/qeth: handle deferred cc1
+- igc: Remove stale comment about Tx timestamping
+- ixgbe: avoid sleeping allocation in ixgbe_ipsec_vf_add_sa()
+- ice: fix memory corruption bug with suspend and rebuild
+- ice: realloc VSI stats arrays
+- ice: Refactor FW data type and fix bitmap casting issue
+- ALSA: hda: cs35l56: Set the init_done flag before component_add()
+- wifi: iwlwifi: mvm: include link ID when releasing frames
+- wifi: iwlwifi: disable multi rx queue for 9000
+- wifi: iwlwifi: mvm: rfi: fix potential response leaks
+- mlxbf_gige: stop PHY during open() error paths
+- tools: ynl: fix setting presence bits in simple nests
+- nfc: nci: Fix uninit-value in nci_dev_up and nci_ntf_packet
+- arm64: bpf: fix 32bit unconditional bswap
+- dma-buf: Fix NULL pointer dereference in sanitycheck()
+- bpf, arm64: fix bug in BPF_LDX_MEMSX
+- s390/bpf: Fix bpf_plt pointer arithmetic
+- scripts/bpf_doc: Use silent mode when exec make cmd
+- drm/i915: Pre-populate the cursor physical dma address
+- drm/i915/display: Use i915_gem_object_get_dma_address to get dma address
+- Revert "workqueue.c: Increase workqueue name length"
+- Revert "workqueue: Move pwq->max_active to wq->max_active"
+- Revert "workqueue: Factor out pwq_is_empty()"
+- Revert "workqueue: Replace pwq_activate_inactive_work() with [__]pwq_activate_work()"
+- Revert "workqueue: Move nr_active handling into helpers"
+- Revert "workqueue: Make wq_adjust_max_active() round-robin pwqs while activating"
+- Revert "workqueue: Introduce struct wq_node_nr_active"
+- Revert "workqueue: Shorten events_freezable_power_efficient name"
+- drm/amdgpu: fix use-after-free bug
+- tools/resolve_btfids: fix build with musl libc
+- x86/sev: Skip ROM range scans and validation for SEV-SNP guests
+- scsi: lpfc: Correct size for wqe for memset()
+- scsi: lpfc: Correct size for cmdwqe/rspwqe for memset()
+- usb: dwc3: pci: Drop duplicate ID
+- Revert "x86/bugs: Use fixed addressing for VERW operand"
+- x86/bugs: Use fixed addressing for VERW operand
+- scsi: qla2xxx: Delay I/O Abort on PCI error
+- scsi: qla2xxx: Change debug message during driver unload
+- scsi: qla2xxx: Fix double free of fcport
+- scsi: qla2xxx: Fix double free of the ha->vp_map pointer
+- scsi: qla2xxx: Fix command flush on cable pull
+- scsi: qla2xxx: NVME|FCP prefer flag not being honored
+- scsi: qla2xxx: Update manufacturer detail
+- scsi: qla2xxx: Split FCE|EFT trace control
+- scsi: qla2xxx: Fix N2N stuck connection
+- scsi: qla2xxx: Prevent command send on chip reset
+- usb: typec: ucsi: Clear UCSI_CCI_RESET_COMPLETE before reset
+- usb: typec: ucsi_acpi: Refactor and fix DELL quirk
+- usb: typec: ucsi: Ack unsupported commands
+- usb: typec: ucsi: Clear EVENT_PENDING under PPM lock
+- usb: typec: Return size of buffer if pd_set operation succeeds
+- usb: udc: remove warning when queue disabled ep
+- usb: dwc2: gadget: LPM flow fix
+- usb: dwc2: gadget: Fix exiting from clock gating
+- usb: dwc2: host: Fix ISOC flow in DDMA mode
+- usb: dwc2: host: Fix hibernation flow
+- usb: dwc2: host: Fix remote wakeup from hibernation
+- USB: core: Fix deadlock in port "disable" sysfs attribute
+- USB: core: Add hub_get() and hub_put() routines
+- USB: core: Fix deadlock in usb_deauthorize_interface()
+- usb: dwc3: Properly set system wakeup
+- staging: vc04_services: fix information leak in create_component()
+- staging: vc04_services: changen strncpy() to strscpy_pad()
+- scsi: core: Fix unremoved procfs host directory regression
+- scsi: sd: Fix TCG OPAL unlock on system resume
+- vfio/pds: Make sure migration file isn't accessed after reset
+- drm/amd/display: Clear OPTC mem select on disable
+- drm/amd/display: Disconnect phantom pipe OPP from OPTC being disabled
+- drm/amd/display: Fix hang/underflow when transitioning to ODM4:1
+- USB: UAS: return ENODEV when submit urbs fail with device not attached
+- usb: cdc-wdm: close race between read and workqueue
+- Revert "usb: phy: generic: Get the vbus supply"
+- mtd: spinand: Add support for 5-byte IDs
+- Bluetooth: hci_sync: Fix not checking error on hci_cmd_sync_cancel_sync
+- drm/i915/gt: Reset queue_priority_hint on parking
+- drm/i915: Do not match JSL in ehl_combo_pll_div_frac_wa_needed()
+- drm/i915/dsi: Go back to the previous INIT_OTP/DISPLAY_ON order, mostly
+- drm/i915/bios: Tolerate devdata==NULL in intel_bios_encoder_supports_dp_dual_mode()
+- drm/i915/hwmon: Fix locking inversion in sysfs getter
+- drm/amdgpu: fix deadlock while reading mqd from debugfs
+- drm/amdkfd: fix TLB flush after unmap for GFX9.4.2
+- drm/vmwgfx: Create debugfs ttm_resource_manager entry only if needed
+- net: ll_temac: platform_get_resource replaced by wrong function
+- nouveau/dmem: handle kcalloc() allocation failure
+- thermal: devfreq_cooling: Fix perf state when calculate dfc res_util
+- block: Do not force full zone append completion in req_bio_endio()
+- sdhci-of-dwcmshc: disable PM runtime in dwcmshc_remove()
+- mmc: core: Avoid negative index with array access
+- mmc: core: Initialize mmc_blk_ioc_data
+- mmc: sdhci-omap: re-tuning is needed after a pm transition to support emmc HS200 mode
+- selftests/mm: fix ARM related issue with fork after pthread_create
+- selftests/mm: sigbus-wp test requires UFFD_FEATURE_WP_HUGETLBFS_SHMEM
+- mm: cachestat: fix two shmem bugs
+- hexagon: vmlinux.lds.S: handle attributes section
+- exec: Fix NOMMU linux_binprm::exec in transfer_args_to_stack()
+- Revert "drm/amd/display: Fix sending VSC (+ colorimetry) packets for DP/eDP displays without PSR"
+- wifi: iwlwifi: fw: don't always use FW dump trig
+- wifi: iwlwifi: mvm: disable MLO for the time being
+- wifi: cfg80211: add a flag to disable wireless extensions
+- wifi: mac80211: check/clear fast rx for non-4addr sta VLAN changes
+- btrfs: zoned: use zone aware sb location for scrub
+- btrfs: zoned: don't skip block groups with 100% zone unusable
+- btrfs: fix race in read_extent_buffer_pages()
+- tmpfs: fix race on handling dquot rbtree
+- ARM: prctl: reject PR_SET_MDWE on pre-ARMv6
+- prctl: generalize PR_SET_MDWE support check to be per-arch
+- x86/efistub: Reinstate soft limit for initrd loading
+- x86/efistub: Add missing boot_params for mixed mode compat entry
+- init: open /initrd.image with O_LARGEFILE
+- ALSA: hda/tas2781: add locks to kcontrols
+- ALSA: hda/tas2781: remove digital gain kcontrol
+- perf top: Use evsel's cpus to replace user_requested_cpus
+- selftests/mm: Fix build with _FORTIFY_SOURCE
+- selftests/mm: gup_test: conform test to TAP format output
+- pwm: img: fix pwm clock lookup
+- efi: fix panic in kdump kernel
+- x86/fpu: Keep xfd_state in sync with MSR_IA32_XFD
+- x86/mpparse: Register APIC address only once
+- kprobes/x86: Use copy_from_kernel_nofault() to read from unsafe address
+- irqchip/renesas-rzg2l: Prevent spurious interrupts when setting trigger type
+- irqchip/renesas-rzg2l: Rename rzg2l_irq_eoi()
+- irqchip/renesas-rzg2l: Rename rzg2l_tint_eoi()
+- irqchip/renesas-rzg2l: Add macro to retrieve TITSR register offset based on register's index
+- irqchip/renesas-rzg2l: Flush posted write in irq_eoi()
+- irqchip/renesas-rzg2l: Implement restriction when writing ISCR register
+- printk: Update @console_may_schedule in console_trylock_spinning()
+- iommu/dma: Force swiotlb_max_mapping_size on an untrusted device
+- swiotlb: Fix alignment checks when both allocation and DMA masks are present
+- swiotlb: Honour dma_alloc_coherent() alignment in swiotlb_alloc()
+- swiotlb: Fix double-allocation of slots due to broken alignment handling
+- entry: Respect changes to system call number by trace_sys_enter()
+- ARM: 9359/1: flush: check if the folio is reserved for no-mapping addresses
+- ARM: 9352/1: iwmmxt: Remove support for PJ4/PJ4B cores
+- clocksource/drivers/arm_global_timer: Fix maximum prescaler value
+- x86/sev: Fix position dependent variable references in startup code
+- x86/Kconfig: Remove CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT
+- vfio/fsl-mc: Block calling interrupt handler without trigger
+- vfio/platform: Create persistent IRQ handlers
+- vfio/pci: Create persistent INTx handler
+- vfio: Introduce interface to flush virqfd inject workqueue
+- btrfs: fix deadlock with fiemap and extent locking
+- xfs: remove conditional building of rt geometry validator functions
+- xfs: reset XFS_ATTR_INCOMPLETE filter on node removal
+- xfs: update dir3 leaf block metadata after swap
+- xfs: ensure logflagsp is initialized in xfs_bmap_del_extent_real
+- xfs: short circuit xfs_growfs_data_private() if delta is zero
+- xfs: initialise di_crc in xfs_log_dinode
+- xfs: add missing nrext64 inode flag check to scrub
+- xfs: force all buffers to be written during btree bulk load
+- xfs: fix an off-by-one error in xreap_agextent_binval
+- xfs: recompute growfsrtfree transaction reservation while growing rt volume
+- xfs: remove unused fields from struct xbtree_ifakeroot
+- xfs: make xchk_iget safer in the presence of corrupt inode btrees
+- xfs: don't allow overly small or large realtime volumes
+- xfs: fix 32-bit truncation in xfs_compute_rextslog
+- xfs: make rextslog computation consistent with mkfs
+- xfs: transfer recovered intent item ownership in ->iop_recover
+- xfs: pass the xfs_defer_pending object to iop_recover
+- xfs: use xfs_defer_pending objects to recover intent items
+- xfs: don't leak recovered attri intent items
+- xfs: consider minlen sized extents in xfs_rtallocate_extent_block
+- xfs: convert rt bitmap extent lengths to xfs_rtbxlen_t
+- xfs: move the xfs_rtbitmap.c declarations to xfs_rtbitmap.h
+- wifi: rtw88: 8821cu: Fix connection failure
+- wifi: iwlwifi: pcie: fix RB status reading
+- ASoC: amd: yc: Revert "Fix non-functional mic on Lenovo 21J2"
+- x86/efistub: Call mixed mode boot services on the firmware's stack
+- drm/amd/display: handle range offsets in VRR ranges
+- drm/i915: Don't explode when the dig port we don't have an AUX CH
+- iio: imu: inv_mpu6050: fix FIFO parsing when empty
+- iio: imu: inv_mpu6050: fix frequency setting when chip is off
+- i2c: i801: Avoid potential double call to gpiod_remove_lookup_table
+- iio: accel: adxl367: fix I2C FIFO data register
+- iio: accel: adxl367: fix DEVID read after reset
+- arm64: dts: qcom: sc8280xp-x13s: limit pcie4 link speed
+- mm, vmscan: prevent infinite loop for costly GFP_NOIO | __GFP_RETRY_MAYFAIL allocations
+- ARM: imx_v6_v7_defconfig: Restore CONFIG_BACKLIGHT_CLASS_DEVICE
+- tee: optee: Fix kernel panic caused by incorrect error handling
+- ALSA: hda/realtek: fix mute/micmute LEDs for HP EliteBook
+- ALSA: hda/realtek - Add Headset Mic supported Acer NB platform
+- fs/aio: Check IOCB_AIO_RW before the struct aio_kiocb conversion
+- Revert "tty: serial: simplify qcom_geni_serial_send_chunk_fifo()"
+- vt: fix unicode buffer corruption when deleting characters
+- mei: me: add arrow lake point H DID
+- mei: me: add arrow lake point S DID
+- serial: port: Don't suspend if the port is still busy
+- misc: fastrpc: Pass proper arguments to scm call
+- misc: lis3lv02d_i2c: Fix regulators getting en-/dis-abled twice on suspend/resume
+- tty: serial: fsl_lpuart: avoid idle preamble pending if CTS is enabled
+- xhci: Fix failure to detect ring expansion need.
+- usb: port: Don't try to peer unused USB ports based on location
+- usb: gadget: ncm: Fix handling of zero block length packets
+- usb: typec: altmodes/displayport: create sysfs nodes as driver's default device attribute group
+- USB: usb-storage: Prevent divide-by-0 error in isd200_ata_command
+- ALSA: hda/realtek - Fix headset Mic no show at resume back for Lenovo ALC897 platform
+- drm/i915: Check before removing mm notifier
+- tty: serial: imx: Fix broken RS485
+- drm/amdgpu/pm: Fix the error of pwm1_enable setting
+- tracing: Use .flush() call to wake up readers
+- SEV: disable SEV-ES DebugSwap by default
+- KVM: SVM: Flush pages under kvm->lock to fix UAF in svm_register_enc_region()
+- KVM: x86: Mark target gfn of emulated atomic instruction as dirty
+- firewire: ohci: prevent leak of left-over IRQ on unbind
+- init/Kconfig: lower GCC version check for -Warray-bounds
+- Input: xpad - add additional HyperX Controller Identifiers
+- cgroup/cpuset: Fix retval in update_cpumask()
+- usb: typec: tpcm: Fix PORT_RESET behavior for self powered devices
+- selftests: mptcp: diag: return KSFT_FAIL not test_cnt
+- mm, mmap: fix vma_merge() case 7 with vma_ops->close
+- xfrm: Avoid clang fortify warning in copy_to_user_tmpl()
+- crypto: sun8i-ce - Fix use after free in unprepare
+- crypto: rk3288 - Fix use after free in unprepare
+- drm/nouveau: fix stale locked mutex in nouveau_gem_ioctl_pushbuf
+- nouveau: lock the client object tree.
+- Drivers: hv: vmbus: Calculate ring buffer size for more efficient use of memory
+- netfilter: nf_tables: reject constant set with timeout
+- netfilter: nf_tables: disallow anonymous set with timeout flag
+- netfilter: nf_tables: mark set as dead when unbinding anonymous set with timeout
+- net: fix IPSTATS_MIB_OUTPKGS increment in OutForwDatagrams.
+- drm/amd/display: Use freesync when `DRM_EDID_FEATURE_CONTINUOUS_FREQ` found
+- workqueue: Shorten events_freezable_power_efficient name
+- drm/bridge: lt8912b: do not return negative values from .get_modes()
+- drm/bridge: lt8912b: clear the EDID property on failures
+- drm/bridge: lt8912b: use drm_bridge_edid_read()
+- drm/bridge: add ->edid_read hook and drm_bridge_edid_read()
+- drm/ttm: Make sure the mapped tt pages are decrypted when needed
+- wifi: brcmfmac: Demote vendor-specific attach/detach messages to info
+- wifi: brcmfmac: cfg80211: Use WSEC to set SAE password
+- wifi: brcmfmac: add per-vendor feature detection callback
+- x86/pm: Work around false positive kmemleak report in msr_build_context()
+- dm snapshot: fix lockup in dm_exception_table_exit
+- drm/amd/display: Fix noise issue on HDMI AV mute
+- drm/amd/display: Return the correct HDCP error code
+- drm/amdgpu: amdgpu_ttm_gart_bind set gtt bound flag
+- ahci: asm1064: asm1166: don't limit reported ports
+- ahci: asm1064: correct count of reported ports
+- wireguard: selftests: set RISCV_ISA_FALLBACK on riscv{32,64}
+- wireguard: netlink: access device through ctx instead of peer
+- wireguard: netlink: check for dangling peer via is_dead instead of empty list
+- LoongArch/crypto: Clean up useless assignment operations
+- LoongArch: Define the __io_aw() hook as mmiowb()
+- LoongArch: Change __my_cpu_offset definition to avoid mis-optimization
+- virtio: reenable config if freezing device failed
+- cxl/trace: Properly initialize cxl_poison region name
+- net: hns3: tracing: fix hclgevf trace event strings
+- drm/i915: Add missing ; to __assign_str() macros in tracepoint code
+- NFSD: Fix nfsd_clid_class use of __string_len() macro
+- net: esp: fix bad handling of pages from page_pool
+- x86/CPU/AMD: Update the Zenbleed microcode revisions
+- cpufreq: dt: always allocate zeroed cpumask
+- mtd: rawnand: Constrain even more when continuous reads are enabled
+- mtd: rawnand: Fix and simplify again the continuous read derivations
+- cifs: open_cached_dir(): add FILE_READ_EA to desired access
+- cifs: reduce warning log level for server not advertising interfaces
+- cifs: make cifs_chan_update_iface() a void function
+- cifs: delete unnecessary NULL checks in cifs_chan_update_iface()
+- cifs: do not let cifs_chan_update_iface deallocate channels
+- cifs: make sure server interfaces are requested only for SMB3+
+- cifs: add xid to query server interface call
+- nilfs2: prevent kernel bug at submit_bh_wbc()
+- nilfs2: fix failure to detect DAT corruption in btree and direct mappings
+- f2fs: truncate page cache before clearing flags when aborting atomic write
+- f2fs: mark inode dirty for FI_ATOMIC_COMMITTED flag
+- Revert "block/mq-deadline: use correct way to throttling write requests"
+- memtest: use {READ,WRITE}_ONCE in memory scanning
+- drm/vc4: hdmi: do not return negative values from .get_modes()
+- drm/imx/ipuv3: do not return negative values from .get_modes()
+- drm/exynos: do not return negative values from .get_modes()
+- drm/panel: do not return negative error codes from drm_panel_get_modes()
+- drm/probe-helper: warn about negative .get_modes()
+- s390/zcrypt: fix reference counting on zcrypt card objects
+- soc: fsl: qbman: Use raw spinlock for cgr_lock
+- soc: fsl: qbman: Always disable interrupts when taking cgr_lock
+- dlm: fix user space lkb refcounting
+- ring-buffer: Use wait_event_interruptible() in ring_buffer_wait()
+- ring-buffer: Fix full_waiters_pending in poll
+- ring-buffer: Fix resetting of shortest_full
+- ring-buffer: Do not set shortest_full when full target is hit
+- ring-buffer: Fix waking up ring buffer readers
+- io_uring: clean rings on NO_MMAP alloc fail
+- platform/x86/intel/tpmi: Change vsec offset to u64
+- ksmbd: retrieve number of blocks using vfs_getattr in set_file_allocation_info
+- ksmbd: replace generic_fillattr with vfs_getattr
+- server: convert to new timestamp accessors
+- vfio/platform: Disable virqfds on cleanup
+- vfio/pci: Lock external INTx masking ops
+- vfio/pci: Disable auto-enable of exclusive INTx IRQ
+- thermal/drivers/mediatek: Fix control buffer enablement on MT7896
+- cifs: allow changing password during remount
+- cifs: prevent updating file size from server if we have a read/write lease
+- smb: client: stop revalidating reparse points unnecessarily
+- PCI: hv: Fix ring buffer size calculation
+- PCI: dwc: endpoint: Fix advertised resizable BAR size
+- PCI: qcom: Enable BDF to SID translation properly
+- kbuild: Move -Wenum-{compare-conditional,enum-conversion} into W=1
+- NFS: Read unlock folio on nfs_page_create_from_folio() error
+- nfs: fix UAF in direct writes
+- sparc32: Fix parport build with sparc32
+- io_uring: fix mshot io-wq checks
+- io_uring/net: correctly handle multishot recvmsg retry setup
+- PCI/AER: Block runtime suspend when handling errors
+- speakup: Fix 8bit characters from direct synth
+- usb: gadget: tegra-xudc: Fix USB3 PHY retrieval logic
+- phy: tegra: xusb: Add API to retrieve the port number of phy
+- slimbus: core: Remove usage of the deprecated ida_simple_xx() API
+- nvmem: meson-efuse: fix function pointer type mismatch
+- ext4: fix corruption during on-line resize
+- hwmon: (amc6821) add of_match table
+- landlock: Warn once if a Landlock action is requested while disabled
+- drm/etnaviv: Restore some id values
+- leds: trigger: netdev: Fix kernel panic on interface rename trig notify
+- Bluetooth: btnxpuart: Fix btnxpuart_close
+- mmc: core: Fix switch on gp3 partition
+- mm: swap: fix race between free_swap_and_cache() and swapoff()
+- mac802154: fix llsec key resources release in mac802154_llsec_key_del
+- block: Fix page refcounts for unaligned buffers in __bio_release_pages()
+- powerpc: xor_vmx: Add '-mhard-float' to CFLAGS
+- dm-raid: fix lockdep waring in "pers->hot_add_disk"
+- PCI/DPC: Quirk PIO log size for Intel Raptor Lake Root Ports
+- PCI/PM: Drain runtime-idle callbacks before driver removal
+- wifi: rtw88: Add missing VID/PIDs for 8811CU and 8821CU
+- btrfs: fix off-by-one chunk length calculation at contains_pending_extent()
+- btrfs: qgroup: always free reserved space for extent records
+- serial: Lock console when calling into driver before registration
+- serial: core: only stop transmit when HW fifo is empty
+- usb: dwc3-am62: Disable wakeup at remove
+- usb: dwc3-am62: fix module unload/reload behavior
+- usb: typec: ucsi: Clean up UCSI_CABLE_PROP macros
+- fuse: don't unhash root
+- fuse: fix root lookup with nonzero generation
+- fuse: replace remaining make_bad_inode() with fuse_make_bad()
+- mmc: tmio: avoid concurrent runs of mmc_request_done()
+- PM: sleep: wakeirq: fix wake irq warning in system suspend
+- USB: serial: cp210x: add pid/vid for TDK NC0110013M and MM0110113M
+- KVM: x86/xen: inject vCPU upcall vector when local APIC is enabled
+- USB: serial: option: add MeiG Smart SLM320 product
+- USB: serial: cp210x: add ID for MGP Instruments PDS100
+- USB: serial: add device ID for VeriFone adapter
+- USB: serial: ftdi_sio: add support for GMC Z216C Adapter IR-USB
+- powerpc/fsl: Fix mfpmr build errors with newer binutils
+- usb: xhci: Add error handling in xhci_map_urb_for_dma
+- clk: qcom: mmcc-msm8974: fix terminating of frequency table arrays
+- clk: qcom: mmcc-apq8084: fix terminating of frequency table arrays
+- clk: qcom: gcc-ipq9574: fix terminating of frequency table arrays
+- clk: qcom: gcc-ipq8074: fix terminating of frequency table arrays
+- clk: qcom: gcc-ipq6018: fix terminating of frequency table arrays
+- clk: qcom: gcc-ipq5018: fix terminating of frequency table arrays
+- vfio/pds: Always clear the save/restore FDs on reset
+- PM: suspend: Set mem_sleep_current during kernel command line setup
+- cpufreq: Limit resolving a frequency to policy min/max
+- docs: Restore "smart quotes" for quotes
+- iio: adc: rockchip_saradc: use mask for write_enable bitfield
+- iio: adc: rockchip_saradc: fix bitmask for channels on SARADCv2
+- md/raid5: fix atomicity violation in raid5_cache_count
+- parisc: Strip upper 32 bit of sum in csum_ipv6_magic for 64-bit builds
+- parisc: Fix csum_ipv6_magic on 64-bit systems
+- parisc: Fix csum_ipv6_magic on 32-bit systems
+- parisc: Fix ip_fast_csum
+- parisc: Avoid clobbering the C/B bits in the PSW with tophys and tovirt macros
+- parisc/unaligned: Rewrite 64-bit inline assembly of emulate_ldd()
+- x86/nmi: Fix the inverse "in NMI handler" check
+- md/md-bitmap: fix incorrect usage for sb_index
+- mtd: rawnand: meson: fix scrambling mode value in command macro
+- ubi: correct the calculation of fastmap size
+- ubifs: Set page uptodate in the correct place
+- fuse: fix VM_MAYSHARE and direct_io_allow_mmap
+- fat: fix uninitialized field in nostale filehandles
+- bounds: support non-power-of-two CONFIG_NR_CPUS
+- kasan/test: avoid gcc warning for intentional overflow
+- block: Clear zone limits for a non-zoned stacked queue
+- ext4: correct best extent lstart adjustment logic
+- selftests/mqueue: Set timeout to 180 seconds
+- sparc: vDSO: fix return value of __setup handler
+- sparc64: NMI watchdog: fix return value of __setup handler
+- powerpc/smp: Increase nr_cpu_ids to include the boot CPU
+- powerpc/smp: Adjust nr_cpu_ids to cover all threads of a core
+- powercap: intel_rapl_tpmi: Fix System Domain probing
+- powercap: intel_rapl_tpmi: Fix a register bug
+- powercap: intel_rapl: Fix locking in TPMI RAPL
+- sched: Simplify tg_set_cfs_bandwidth()
+- powercap: intel_rapl: Fix a NULL pointer dereference
+- thermal/intel: Fix intel_tcc_get_temp() to support negative CPU temperature
+- cpufreq: amd-pstate: Fix min_perf assignment in amd_pstate_adjust_perf()
+- arm64: dts: qcom: sm8550-mtp: correct WCD9385 TX port mapping
+- arm64: dts: qcom: sm8550-qrd: correct WCD9385 TX port mapping
+- KVM: Always flush async #PF workqueue when vCPU is being destroyed
+- media: nxp: imx8-isi: Mark all crossbar sink pads as MUST_CONNECT
+- media: mc: Expand MUST_CONNECT flag to always require an enabled link
+- media: mc: Rename pad variable to clarify intent
+- media: mc: Add num_links flag to media_pad
+- media: nxp: imx8-isi: Check whether crossbar pad is non-NULL before access
+- media: mc: Fix flags handling when creating pad links
+- media: mc: Add local pad to pipeline regardless of the link state
+- media: xc4000: Fix atomicity violation in xc4000_get_frequency
+- pci_iounmap(): Fix MMIO mapping leak
+- drm/vmwgfx: Fix the lifetime of the bo cursor memory
+- serial: max310x: fix NULL pointer dereference in I2C instantiation
+- drm/vmwgfx: Fix possible null pointer derefence with invalid contexts
+- arm: dts: marvell: Fix maxium->maxim typo in brownstone dts
+- smack: Handle SMACK64TRANSMUTE in smack_inode_setsecurity()
+- smack: Set SMACK64TRANSMUTE only for dirs in smack_inode_setxattr()
+- clk: qcom: gcc-sdm845: Add soft dependency on rpmhpd
+- remoteproc: virtio: Fix wdg cannot recovery remote processor
+- arm64: dts: qcom: sc7280: Add additional MSI interrupts
+- media: staging: ipu3-imgu: Set fields before media_entity_pads_init()
+- wifi: brcmfmac: avoid invalid list operation when vendor attach fails
+- wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach
+- drm/vmwgfx: Unmap the surface before resetting it on a plane state
+- KVM: x86: Use a switch statement and macros in __feature_translate()
+- KVM: x86: Advertise CPUID.(EAX=7,ECX=2):EDX[5:0] to userspace
+- x86/efistub: Don't clear BSS twice in mixed mode
+- x86/efistub: Clear decompressor BSS in native EFI entrypoint
+- dm-integrity: align the outgoing bio in integrity_recheck
+- dm io: Support IO priority
+- selftests: forwarding: Fix ping failure due to short timeout
+- spi: spi-mt65xx: Fix NULL pointer access in interrupt handler
+- netfilter: nf_tables: Fix a memory leak in nf_tables_updchain
+- net: dsa: mt7530: fix handling of all link-local frames
+- net: dsa: mt7530: fix link-local frames that ingress vlan filtering ports
+- bpf: report RCU QS in cpumap kthread
+- net: report RCU QS on threaded NAPI repolling
+- rcu: add a helper to report consolidated flavor QS
+- netfilter: nf_tables: do not compare internal table flags on updates
+- netfilter: nft_set_pipapo: release elements in clone only from destroy path
+- octeontx2-af: Use separate handlers for interrupts
+- octeontx2-pf: Send UP messages to VF only when VF is up.
+- octeontx2-pf: Use default max_active works instead of one
+- octeontx2-pf: Wait till detach_resources msg is complete
+- octeontx2: Detect the mbox up or down message via register
+- devlink: fix port new reply cmd type
+- net/bnx2x: Prevent access to a freed page in page_pool
+- dm-integrity: fix a memory leak when rechecking the data
+- net: phy: fix phy_read_poll_timeout argument type in genphy_loopback
+- ceph: stop copying to iter at EOF on sync reads
+- ipv4: raw: Fix sending packets from raw sockets via IPsec tunnels
+- hsr: Handle failures in module init
+- rds: introduce acquire/release ordering in acquire/release_in_xmit()
+- wireguard: receive: annotate data-race around receiving_counter.counter
+- virtio: packed: fix unmap leak for indirect desc table
+- vdpa/mlx5: Allow CVQ size changes
+- vdpa_sim: reset must not run
+- drm: Fix drm_fixp2int_round() making it add 0.5
+- spi: spi-imx: fix off-by-one in mx51 CPU mode burst length
+- net: dsa: mt7530: prevent possible incorrect XTAL frequency selection
+- net: veth: do not manipulate GRO when using XDP
+- xfrm: Allow UDP encapsulation only in offload modes
+- packet: annotate data-races around ignore_outgoing
+- xen/events: increment refcnt only if event channel is refcounted
+- xen/evtchn: avoid WARN() when unbinding an event channel
+- riscv: Fix compilation error with FAST_GUP and rv32
+- io_uring: fix poll_remove stalled req completion
+- net: ethernet: mtk_eth_soc: fix PPE hanging issue
+- net: mediatek: mtk_eth_soc: clear MAC_MCR_FORCE_LINK only when MAC is up
+- nvme: fix reconnection fail due to reserved tag allocation
+- net: txgbe: fix clk_name exceed MAX_DEV_ID limits
+- hsr: Fix uninit-value access in hsr_get_node()
+- vmxnet3: Fix missing reserved tailroom
+- tcp: Fix refcnt handling in __inet_hash_connect().
+- io_uring: Fix release of pinned pages when __io_uaddr_map fails
+- cpufreq: Fix per-policy boost behavior on SoCs using cpufreq_boost_set_sw()
+- soc: fsl: dpio: fix kcalloc() argument order
+- net/sched: taprio: proper TCA_TAPRIO_TC_ENTRY_INDEX check
+- s390/vtime: fix average steal time calculation
+- octeontx2-af: Use matching wake_up API variant in CGX command interface
+- rds: tcp: Fix use-after-free of net in reqsk_timer_handler().
+- tcp: Fix NEW_SYN_RECV handling in inet_twsk_purge()
+- nouveau: reset the bo resource bus info after an eviction
+- ASoC: rockchip: i2s-tdm: Fix inaccurate sampling rates
+- spi: lpspi: Avoid potential use-after-free in probe()
+- io_uring: don't save/restore iowait state
+- thermal/drivers/qoriq: Fix getting tmu range
+- thermal/drivers/mediatek/lvts_thermal: Fix a memory leak in an error handling path
+- ASoC: tlv320adc3xxx: Don't strip remove function when driver is builtin
+- x86/hyperv: Use per cpu initial stack for vtl context
+- usb: gadget: net2272: Use irqflags in the call to net2272_probe_fin
+- staging: greybus: fix get_channel_from_mode() failure path
+- serial: 8250_exar: Don't remove GPIO device on suspend
+- rtc: mt6397: select IRQ_DOMAIN instead of depending on it
+- bus: mhi: ep: check the correct variable in mhi_ep_register_controller()
+- iio: gts-helper: Fix division loop
+- kconfig: fix infinite loop when expanding a macro at the end of file
+- coresight: etm4x: Set skip_power_up in etm4_init_arch_data function
+- coresight: Fix issue where a source device's helpers aren't disabled
+- arm64: dts: broadcom: bcmbca: bcm4908: drop invalid switch cells
+- tty: serial: samsung: fix tx_empty() to return TIOCSER_TEMT
+- serial: max310x: fix syntax error in IRQ error message
+- tty: vt: fix 20 vs 0x20 typo in EScsiignore
+- usb: phy: generic: Get the vbus supply
+- iio: pressure: mprls0025pa fix off-by-one enum
+- remoteproc: stm32: Fix incorrect type assignment returned by stm32_rproc_get_loaded_rsc_tablef
+- remoteproc: stm32: Fix incorrect type in assignment for va
+- mei: gsc_proxy: match component when GSC is on different bus
+- comedi: comedi_test: Prevent timers rescheduling during deletion
+- io_uring/net: correct the type of variable
+- afs: Revert "afs: Hide silly-rename files from userspace"
+- f2fs: zone: fix to remove pow2 check condition for zoned block device
+- f2fs: compress: fix reserve_cblocks counting error when out of space
+- f2fs: compress: relocate some judgments in f2fs_reserve_compress_blocks
+- NFSv4.1/pnfs: fix NFS with TLS in pnfs
+- NFS: Fix an off by one in root_nfs_cat()
+- NFS: Fix nfs_netfs_issue_read() xarray locking for writeback interrupt
+- Input: iqs7222 - add support for IQS7222D v1.1 and v1.2
+- RDMA/mana_ib: Fix bug in creation of dma regions
+- f2fs: ro: compress: fix to avoid caching unaligned extent
+- f2fs: fix to use correct segment type in f2fs_allocate_data_block()
+- watchdog: stm32_iwdg: initialize default timeout
+- watchdog: starfive: Check pm_runtime_enabled() before decrementing usage counter
+- f2fs: check number of blocks in a current section
+- f2fs: compress: fix to check compress flag w/ .i_sem lock
+- NFSv4.2: fix listxattr maximum XDR buffer size
+- NFSv4.2: fix nfs4_listxattr kernel BUG at mm/usercopy.c:102
+- net: sunrpc: Fix an off by one in rpc_sockaddr2uaddr()
+- f2fs: compress: fix to check zstd compress level correctly in mount option
+- f2fs: fix to create selinux label during whiteout initialization
+- scsi: bfa: Fix function pointer type mismatch for hcb_qe->cbfn
+- RDMA/rtrs-clt: Check strnlen return len in sysfs mpath_policy_store()
+- RDMA/device: Fix a race between mad_client and cm_client init
+- i3c: dw: Disable IBI IRQ depends on hot-join and SIR enabling
+- scsi: csiostor: Avoid function pointer casts
+- f2fs: fix to avoid potential panic during recovery
+- f2fs: compress: fix to cover f2fs_disable_compressed_file() w/ i_sem
+- f2fs: zone: fix to wait completion of last bio in zone correctly
+- f2fs: fix to remove unnecessary f2fs_bug_on() to avoid panic
+- f2fs: compress: fix to avoid inconsistence bewteen i_blocks and dnode
+- f2fs: update blkaddr in __set_data_blkaddr() for cleanup
+- f2fs: introduce get_dnode_addr() to clean up codes
+- f2fs: delete obsolete FI_DROP_CACHE
+- f2fs: delete obsolete FI_FIRST_BLOCK_WRITTEN
+- f2fs: compress: fix to check unreleased compressed cluster
+- f2fs: compress: fix to cover normal cluster write with cp_rwsem
+- f2fs: compress: fix to guarantee persisting compressed blocks by CP
+- RDMA/srpt: Do not register event handler until srpt device is fully setup
+- RDMA/irdma: Remove duplicate assignment
+- ALSA: usb-audio: Stop parsing channels bits when all channels are found.
+- ALSA: hda/tas2781: restore power state after system_resume
+- ALSA: hda/tas2781: configure the amp after firmware load
+- ALSA: hda/tas2781: do not call pm_runtime_force_* in system_resume/suspend
+- ALSA: hda/tas2781: add ptrs to calibration functions
+- ALSA: hda/tas2781: do not reset cur_* values in runtime_suspend
+- ALSA: hda/tas2781: add lock to system_suspend
+- ALSA: hda/tas2781: use dev_dbg in system_resume
+- ALSA: hda/realtek: fix ALC285 issues on HP Envy x360 laptops
+- cifs: Fix writeback data corruption
+- cifs: Don't use certain unnecessary folio_*() functions
+- smb: do not test the return value of folio_start_writeback()
+- PCI: brcmstb: Fix broken brcm_pcie_mdio_write() polling
+- clk: zynq: Prevent null pointer dereference caused by kmalloc failure
+- clk: Fix clk_core_get NULL dereference
+- sparc32: Fix section mismatch in leon_pci_grpci
+- backlight: lp8788: Fully initialize backlight_properties during probe
+- backlight: lm3639: Fully initialize backlight_properties during probe
+- backlight: da9052: Fully initialize backlight_properties during probe
+- backlight: lm3630a: Don't set bl->props.brightness in get_brightness
+- backlight: lm3630a: Initialize backlight_properties on init
+- backlight: ktz8866: Correct the check for of_property_read_u32
+- leds: sgm3140: Add missing timer cleanup and flash gpio control
+- leds: aw2013: Unlock mutex before destroying it
+- powerpc/embedded6xx: Fix no previous prototype for avr_uart_send() etc.
+- mfd: cs42l43: Fix wrong GPIO_FN_SEL and SPI_CLK_CONFIG1 defaults
+- modules: wait do_free_init correctly
+- drm/msm/dpu: add division of drm_display_mode's hskew parameter
+- clk: qcom: gcc-ipq5018: fix register offset for GCC_UBI0_AXI_ARES reset
+- clk: qcom: gcc-ipq5018: fix 'halt_reg' offset of 'gcc_pcie1_pipe_clk'
+- clk: qcom: gcc-ipq5018: fix 'enable_reg' offset of 'gcc_gmac0_sys_clk'
+- powerpc/hv-gpci: Fix the H_GET_PERF_COUNTER_INFO hcall return value checks
+- powerpc/pseries: Fix potential memleak in papr_get_attr()
+- mfd: cs42l43: Fix wrong register defaults
+- drm/mediatek: Fix a null pointer crash in mtk_drm_crtc_finish_page_flip
+- gpio: nomadik: fix offset bug in nmk_pmx_set()
+- drm/amd/pm: Fix esm reg mask use to get pcie speed
+- drm/tests: helpers: Include missing drm_drv header
+- arm64: ftrace: Don't forbid CALL_OPS+CC_OPTIMIZE_FOR_SIZE with Clang
+- media: mediatek: vcodec: avoid -Wcast-function-type-strict warning
+- media: ttpci: fix two memleaks in budget_av_attach
+- media: go7007: fix a memleak in go7007_load_encoder
+- media: dvb-frontends: avoid stack overflow warnings with clang
+- drm/amdgpu: Fix missing break in ATOM_ARG_IMM Case of atom_get_src_int()
+- HID: amd_sfh: Avoid disabling the interrupt
+- HID: amd_sfh: Update HPD sensor structure elements
+- perf pmu: Fix a potential memory leak in perf_pmu__lookup()
+- ASoC: meson: axg-tdm-interface: add frame rate constraint
+- ASoC: meson: axg-tdm-interface: fix mclk setup without mclk-fs
+- mtd: rawnand: lpc32xx_mlc: fix irq handler prototype
+- mtd: maps: physmap-core: fix flash size larger than 32-bit
+- clk: imx: imx8mp: Fix SAI_MCLK_SEL definition
+- drm/tidss: Fix sync-lost issue with two displays
+- drm/tidss: Fix initial plane zpos values
+- crypto: jitter - fix CRYPTO_JITTERENTROPY help text
+- crypto: ccp - Avoid discarding errors in psp_send_platform_access_msg()
+- crypto: arm/sha - fix function cast warnings
+- perf print-events: make is_event_supported() more robust
+- mfd: altera-sysmgr: Call of_node_put() only when of_parse_phandle() takes a ref
+- mfd: syscon: Call of_node_put() only when of_parse_phandle() takes a ref
+- media: i2c: imx290: Fix IMX920 typo
+- media: ivsc: csi: Swap SINK and SOURCE pads
+- drm/tegra: put drm_gem_object ref on error in tegra_fb_create
+- clk: mediatek: mt7981-topckgen: flag SGM_REG_SEL as critical
+- clk: mediatek: mt8183: Correct parent of CLK_INFRA_SSPM_32K_SELF
+- clk: mediatek: mt7622-apmixedsys: Fix an error handling path in clk_mt8135_apmixed_probe()
+- clk: mediatek: mt8135: Fix an error handling path in clk_mt8135_apmixed_probe()
+- clk: hisilicon: hi3559a: Fix an erroneous devm_kfree()
+- clk: hisilicon: hi3519: Release the correct number of gates in hi3519_clk_unregister()
+- pinctrl: renesas: Allow the compiler to optimize away sh_pfc_pm
+- PCI: Mark 3ware-9650SE Root Port Extended Tags as broken
+- drm/mediatek: dsi: Fix DSI RGB666 formats and definitions
+- drm/panel: boe-tv101wum-nl6: make use of prepare_prev_first
+- drm/amd/display: Add 'replay' NULL check in 'edp_set_replay_allow_active()'
+- clk: qcom: dispcc-sdm845: Adjust internal GDSC wait times
+- media: pvrusb2: fix pvr2_stream_callback casts
+- media: pvrusb2: remove redundant NULL check
+- media: go7007: add check of return value of go7007_read_addr()
+- media: imx: csc/scaler: fix v4l2_ctrl_handler memory leak
+- media: sun8i-di: Fix chroma difference threshold
+- media: sun8i-di: Fix power on/off sequences
+- media: sun8i-di: Fix coefficient writes
+- media: cedrus: h265: Fix configuring bitstream size
+- NTB: fix possible name leak in ntb_register_device()
+- drm: ci: use clk_ignore_unused for apq8016
+- ASoC: SOF: Add some bounds checking to firmware data
+- powerpc: Force inlining of arch_vmap_p{u/m}d_supported()
+- ASoC: meson: t9015: fix function pointer type mismatch
+- ASoC: meson: aiu: fix function pointer type mismatch
+- perf metric: Don't remove scale from counts
+- perf stat: Avoid metric-only segv
+- perf expr: Fix "has_event" function for metric style events
+- ALSA: seq: fix function cast warnings
+- clk: renesas: r8a779f0: Correct PFC/GPIO parent clock
+- clk: renesas: r8a779g0: Correct PFC/GPIO parent clocks
+- drm/amd/display: fix NULL checks for adev->dm.dc in amdgpu_dm_fini()
+- drm/radeon/ni: Fix wrong firmware size logging in ni_init_microcode()
+- drm/msm/dpu: Only enable DSC_MODE_MULTIPLEX if dsc_merge is enabled
+- drm/msm/dpu: fix the programming of INTF_CFG2_DATA_HCTL_EN
+- dt-bindings: msm: qcom, mdss: Include ommited fam-b compatible
+- perf srcline: Add missed addr2line closes
+- perf thread_map: Free strlist on normal path in thread_map__new_by_tid_str()
+- drivers/ps3: select VIDEO to provide cmdline functions
+- crypto: xilinx - call finalize with bh disabled
+- PCI: switchtec: Fix an error handling path in switchtec_pci_probe()
+- PCI/P2PDMA: Fix a sleeping issue in a RCU read section
+- quota: Properly annotate i_dquot arrays with __rcu
+- quota: Fix rcu annotations of inode dquot pointers
+- clk: qcom: reset: Ensure write completion on reset de/assertion
+- clk: qcom: reset: Commonize the de/assert functions
+- drm/amdgpu: Fix potential out-of-bounds access in 'amdgpu_discovery_reg_base_init()'
+- pinctrl: mediatek: Drop bogus slew rate register range for MT8192
+- pinctrl: mediatek: Drop bogus slew rate register range for MT8186
+- media: edia: dvbdev: fix a use-after-free
+- mtd: spinand: esmt: Extend IDs to 5 bytes
+- media: v4l2-mem2mem: fix a memleak in v4l2_m2m_register_entity
+- media: v4l2-tpg: fix some memleaks in tpg_alloc
+- media: em28xx: annotate unchecked call to media_device_register()
+- clk: meson: Add missing clocks to axg_clk_regmaps
+- perf bpf: Clean up the generated/copied vmlinux.h
+- perf evsel: Fix duplicate initialization of data->id in evsel__parse_sample()
+- media: v4l2: cci: print leading 0 on error
+- clk: samsung: exynos850: Propagate SPI IPCLK rate change
+- pinctrl: renesas: r8a779g0: Add missing SCIF_CLK2 pin group/function
+- drm/vmwgfx: Fix vmw_du_get_cursor_mob fencing of newly-created MOBs
+- ASoC: sh: rz-ssi: Fix error message print
+- drm/amd/display: Fix potential NULL pointer dereferences in 'dcn10_set_output_transfer_func()'
+- perf pmu: Treat the msr pmu as software
+- drm/amd/display: Fix a potential buffer overflow in 'dp_dsc_clock_en_read()'
+- HID: lenovo: Add middleclick_workaround sysfs knob for cptkbd
+- perf record: Check conflict between '--timestamp-filename' option and pipe mode before recording
+- perf top: Uniform the event name for the hybrid machine
+- perf record: Fix possible incorrect free in record__switch_output()
+- PCI/DPC: Print all TLP Prefixes, not just the first
+- media: cadence: csi2rx: use match fwnode for media link
+- media: tc358743: register v4l2 async device only after successful setup
+- dmaengine: tegra210-adma: Update dependency to ARCH_TEGRA
+- ASoC: SOF: amd: Fix memory leak in amd_sof_acp_probe()
+- ASoC: amd: acp: Add missing error handling in sof-mach
+- drm/lima: fix a memleak in lima_heap_alloc
+- drm/panel-edp: use put_sync in unprepare
+- drm/rockchip: lvds: do not print scary message when probing defer
+- drm/rockchip: lvds: do not overwrite error code
+- drm/vmwgfx: fix a memleak in vmw_gmrid_man_get_node
+- drm/vkms: Avoid reading beyond LUT array
+- drm: Don't treat 0 as -1 in drm_fixp2int_ceil
+- drm/rockchip: inno_hdmi: Fix video timing
+- drm/tegra: output: Fix missing i2c_put_adapter() in the error handling paths of tegra_output_probe()
+- drm/tegra: rgb: Fix missing clk_put() in the error handling paths of tegra_dc_rgb_probe()
+- drm/tegra: rgb: Fix some error handling paths in tegra_dc_rgb_probe()
+- drm/tegra: hdmi: Fix some error handling paths in tegra_hdmi_probe()
+- drm/tegra: dsi: Fix missing pm_runtime_disable() in the error handling path of tegra_dsi_probe()
+- drm/tegra: dsi: Fix some error handling paths in tegra_dsi_probe()
+- drm/tegra: dpaux: Fix PM disable depth imbalance in tegra_dpaux_probe
+- drm/tegra: dsi: Add missing check for of_find_device_by_node
+- dm: call the resume method on internal suspend
+- dm raid: fix false positive for requeue needed during reshape
+- bpf: hardcode BPF_PROG_PACK_SIZE to 2MB * num_possible_nodes()
+- nfp: flower: handle acti_netdevs allocation failure
+- net/x25: fix incorrect parameter validation in the x25_getsockopt() function
+- net: kcm: fix incorrect parameter validation in the kcm_getsockopt) function
+- udp: fix incorrect parameter validation in the udp_lib_getsockopt() function
+- l2tp: fix incorrect parameter validation in the pppol2tp_getsockopt() function
+- ipmr: fix incorrect parameter validation in the ip_mroute_getsockopt() function
+- tcp: fix incorrect parameter validation in the do_tcp_getsockopt() function
+- OPP: debugfs: Fix warning around icc_get_name()
+- erofs: fix lockdep false positives on initializing erofs_pseudo_mnt
+- net: phy: dp83822: Fix RGMII TX delay configuration
+- Bluetooth: Fix eir name length
+- net: phy: fix phy_get_internal_delay accessing an empty array
+- net: ip_tunnel: make sure to pull inner header in ip_tunnel_rcv()
+- ipv6: fib6_rules: flush route cache when rule is changed
+- iommu: Fix compilation without CONFIG_IOMMU_INTEL
+- bpf: Fix stackmap overflow check on 32-bit arches
+- bpf: Fix hashtab overflow check on 32-bit arches
+- bpf: Fix DEVMAP_HASH overflow check on 32-bit arches
+- s390/cache: prevent rebuild of shared_cpu_list
+- Bluetooth: fix use-after-free in accessing skb after sending it
+- Bluetooth: af_bluetooth: Fix deadlock
+- Bluetooth: btusb: Fix memory leak
+- Bluetooth: msft: Fix memory leak
+- Bluetooth: msft: __hci_cmd_sync() doesn't return NULL
+- Bluetooth: hci_core: Fix possible buffer overflow
+- Bluetooth: btrtl: fix out of bounds memory access
+- Bluetooth: hci_h5: Add ability to allocate memory for private data
+- Bluetooth: hci_sync: Fix overwriting request callback
+- Bluetooth: hci_core: Cancel request on command timeout
+- Bluetooth: hci_qca: don't use IS_ERR_OR_NULL() with gpiod_get_optional()
+- Bluetooth: hci_event: Fix not indicating new connection for BIG Sync
+- Bluetooth: Remove BT_HS
+- Bluetooth: Remove superfluous call to hci_conn_check_pending()
+- Bluetooth: mgmt: Remove leftover queuing of power_off work
+- Bluetooth: Remove HCI_POWER_OFF_TIMEOUT
+- ice: fix stats being updated by way too large values
+- igb: Fix missing time sync events
+- igc: Fix missing time sync events
+- iommu/vt-d: Don't issue ATS Invalidation request when device is disconnected
+- PCI: Make pci_dev_is_disconnected() helper public for other drivers
+- wifi: brcm80211: handle pmk_op allocation failure
+- wifi: rtw88: 8821c: Fix false alarm count
+- wifi: rtw88: 8821c: Fix beacon loss and disconnect
+- wifi: rtw88: 8821cu: Fix firmware upload fail
+- ACPI: CPPC: enable AMD CPPC V2 support for family 17h processors
+- mmc: wmt-sdmmc: remove an incorrect release_mem_region() call in the .remove function
+- arm64: dts: qcom: sm8550: Fix SPMI channels size
+- SUNRPC: fix some memleaks in gssx_dec_option_array
+- SUNRPC: fix a memleak in gss_import_v2_context
+- x86, relocs: Ignore relocations in .notes section
+- objtool: Fix UNWIND_HINT_{SAVE,RESTORE} across basic blocks
+- arm64: dts: rockchip: drop rockchip,trcm-sync-tx-only from rk3588 i2s
+- arm64: dts: rockchip: fix reset-names for rk356x i2s2 controller
+- arm64: dts: rockchip: add missing interrupt-names for rk356x vdpu
+- ACPI: scan: Fix device check notification handling
+- ACPI: resource: Add MAIBENBEN X577 to irq1_edge_low_force_override
+- ACPI: resource: Do IRQ override on Lunnen Ground laptops
+- ACPI: resource: Add Infinity laptops to irq1_edge_low_force_override
+- arm64: dts: marvell: reorder crypto interrupts on Armada SoCs
+- gpiolib: Pass consumer device through to core in devm_fwnode_gpiod_get_index()
+- regulator: userspace-consumer: add module device table
+- arm64: dts: imx8mp-evk: Fix hdmi@3d node
+- arm64: dts: imx8mp: Set SPI NOR to max 40 MHz on Data Modul i.MX8M Plus eDM SBC
+- ARM: dts: imx6dl-yapp4: Move the internal switch PHYs under the switch node
+- ARM: dts: imx6dl-yapp4: Fix typo in the QCA switch register address
+- arm64: dts: allwinner: h6: Add RX DMA channel for SPDIF
+- pstore: inode: Only d_invalidate() is needed
+- pstore: inode: Convert mutex usage to guard(mutex)
+- net: mctp: copy skb ext data when fragmenting
+- arm64: dts: renesas: r8a779g0: Correct avb[01] reg sizes
+- arm64: dts: renesas: r8a779a0: Correct avb[01] reg sizes
+- arm64: dts: renesas: rzg2l: Add missing interrupts to IRQC nodes
+- wifi: mt76: mt792x: fix a potential loading failure of the 6Ghz channel config from ACPI
+- wifi: mt76: mt7921e: fix use-after-free in free_irq()
+- wifi: mt76: mt792x: fix ethtool warning
+- wifi: mt76: mt7996: fix HIF_TXD_V2_1 value
+- wifi: mt76: mt7996: fix efuse reading issue
+- wifi: mt76: mt7996: fix HE beamformer phy cap for station vif
+- wifi: mt76: mt7996: fix incorrect interpretation of EHT MCS caps
+- wifi: mt76: mt7996: fix TWT issues
+- memory: tegra: Correct DLA client names
+- ARM: dts: arm: realview: Fix development chip ROM compatible value
+- wifi: wilc1000: revert reset line logic flip
+- arm64: dts: ti: k3-am62p: Fix memory ranges for DMSS
+- firmware: arm_scmi: Fix double free in SMC transport cleanup path
+- arm64: dts: ti: Add common1 register space for AM62x SoC
+- arm64: dts: ti: Add common1 register space for AM65x SoC
+- arm64: dts: mt8195-cherry-tomato: change watchdog reset boot flow
+- arm64: dts: ti: k3-am64-main: Fix ITAP/OTAP values for MMC
+- arm64: dts: ti: k3-am64: Enable SDHCI nodes at the board level
+- arm64: dts: ti: k3-am642-sk: Add boot phase tags marking
+- arm64: dts: ti: k3-am642-evm: Add boot phase tags marking
+- arm64: dts: ti: k3-j784s4-evm: Remove Pinmux for CTS and RTS in wkup_uart0
+- arm64: dts: ti: k3-j721s2-common-proc-board: Remove Pinmux for CTS and RTS in wkup_uart0
+- arm64: dts: ti: k3-j7200-common-proc-board: Remove clock-frequency from mcu_uart0
+- arm64: dts: ti: k3-j7200-common-proc-board: Modify Pinmux for wkup_uart0 and mcu_uart0
+- net: ena: Remove ena_select_queue
+- powercap: dtpm_cpu: Fix error check against freq_qos_add_request()
+- arm64: dts: qcom: sm8150: correct PCIe wake-gpios
+- arm64: dts: qcom: sm8150: use 'gpios' suffix for PCI GPIOs
+- arm64: dts: qcom: sdm845-db845c: correct PCIe wake-gpios
+- wifi: brcmsmac: avoid function pointer casts
+- iommu/amd: Mark interrupt as managed
+- bus: tegra-aconnect: Update dependency to ARCH_TEGRA
+- arm64: dts: ti: k3-am62-main: disable usb lpm
+- wifi: wilc1000: prevent use-after-free on vif when cleaning up all interfaces
+- cpufreq: qcom-hw: add CONFIG_COMMON_CLK dependency
+- arm64: dts: mediatek: mt8186: Add missing xhci clock to usb controllers
+- arm64: dts: mediatek: mt8186: Add missing clocks to ssusb power domains
+- ARM: dts: qcom: msm8974: correct qfprom node size
+- soc: qcom: llcc: Check return value on Broadcast_OR reg read
+- arm64: dts: qcom: sdm845: Use the Low Power Island CX/MX for SLPI
+- bpf: Mark bpf_spin_{lock,unlock}() helpers with notrace correctly
+- wifi: iwlwifi: mvm: Fix the listener MAC filter flags
+- can: m_can: Start/Cancel polling timer together with interrupts
+- arm64: dts: mediatek: mt7622: add missing "device_type" to memory nodes
+- arm64: dts: mediatek: mt8186: fix VENC power domain clocks
+- arm64: dts: mediatek: mt8192: fix vencoder clock name
+- arm64: dts: mediatek: mt8192-asurada: Remove CrosEC base detection node
+- arm64: dts: mediatek: mt7986: add "#reset-cells" to infracfg
+- arm64: dts: mediatek: mt7986: drop "#clock-cells" from PWM
+- arm64: dts: mediatek: mt7986: fix SPI nodename
+- arm64: dts: mediatek: mt7986: fix SPI bus width properties
+- arm64: dts: mediatek: mt7986: drop crypto's unneeded/invalid clock name
+- arm64: dts: mediatek: mt7986: fix reference to PWM in fan node
+- arm64: dts: mt8183: Move CrosEC base detection node to kukui-based DTs
+- ipv6: mcast: remove one synchronize_net() barrier in ipv6_mc_down()
+- selftests: forwarding: Add missing multicast routing config entries
+- selftests: forwarding: Add missing config entries
+- s390/vdso: drop '-fPIC' from LDFLAGS
+- s390/pai: fix attr_event_free upper limit for pai device drivers
+- wifi: iwlwifi: mvm: don't set replay counters to 0xff
+- wifi: iwlwifi: mvm: don't set the MFP flag for the GTK
+- wifi: iwlwifi: mvm: fix erroneous queue index mask
+- wifi: iwlwifi: support EHT for WH
+- tools/resolve_btfids: Fix cross-compilation to non-host endianness
+- tools/resolve_btfids: Refactor set sorting with types from btf_ids.h
+- pwm: sti: Fix capture for st,pwm-num-chan < st,capture-num-chan
+- printk: Disable passing console lock owner completely during panic()
+- wifi: ath12k: fix incorrect logic of calculating vdev_stats_id
+- arm64: dts: qcom: sm6115: declare VLS CLAMP register for USB3 PHY
+- arm64: dts: qcom: qcm2290: declare VLS CLAMP register for USB3 PHY
+- wifi: wfx: fix memory leak when starting AP
+- libbpf: Use OPTS_SET() macro in bpf_xdp_query()
+- wifi: libertas: fix some memleaks in lbs_allocate_cmd_buffer()
+- wifi: ath11k: initialize rx_mcs_80 and rx_mcs_160 before use
+- arm64: dts: ti: k3-j784s4: Fix power domain for VTM node
+- arm64: dts: ti: k3-j721s2: Fix power domain for VTM node
+- net: blackhole_dev: fix build warning for ethh set but not used
+- pwm: atmel-hlcdc: Fix clock imbalance related to suspend support
+- arm64: dts: imx8mm-venice-gw71xx: fix USB OTG VBUS
+- gpio: vf610: allow disabling the vf610 driver
+- wifi: iwlwifi: read BIOS PNVM only for non-Intel SKU
+- wifi: iwlwifi: mvm: fix the TLC command after ADD_STA
+- wifi: iwlwifi: mvm: d3: fix IPN byte order
+- wifi: iwlwifi: fix EWRD table validity check
+- wifi: iwlwifi: mvm: initialize rates in FW earlier
+- wifi: iwlwifi: acpi: fix WPFC reading
+- wifi: iwlwifi: dbg-tlv: ensure NUL termination
+- wifi: iwlwifi: mvm: report beacon protection failures
+- wifi: ath12k: fix fetching MCBC flag for QCN9274
+- wifi: ath12k: Update Qualcomm Innovation Center, Inc. copyrights
+- wifi: ath11k: change to move WMI_VDEV_PARAM_SET_HEMU_MODE before WMI_PEER_ASSOC_CMDID
+- wifi: ath9k: delay all of ath9k_wmi_event_tasklet() until init is complete
+- libbpf: Add missing LIBBPF_API annotation to libbpf_set_memlock_rlim API
+- arm64: dts: imx8mm-kontron: Fix interrupt for RTC on OSM-S i.MX8MM module
+- arm64: dts: imx8mm-kontron: Disable pull resistors for SD card signals on BL board
+- arm64: dts: imx8mm-kontron: Disable pull resistors for SD card signals on BL OSM-S board
+- arm64: dts: imx8mm-kontron: Disable pullups for onboard UART signals on BL board
+- arm64: dts: imx8mm-kontron: Disable pullups for onboard UART signals on BL OSM-S board
+- arm64: dts: imx8mm-kontron: Disable pullups for I2C signals on SL/BL i.MX8MM
+- arm64: dts: imx8mm-kontron: Disable pullups for I2C signals on OSM-S i.MX8MM
+- selftests/bpf: Disable IPv6 for lwt_redirect test
+- arm64: dts: renesas: r8a779g0: Add missing SCIF_CLK2
+- arm64: dts: renesas: r8a779g0: Restore sort order
+- arm64: dts: qcom: sa8540p: Drop gfx.lvl as power-domain for gpucc
+- pmdomain: qcom: rpmhpd: Drop SA8540P gfx.lvl
+- libbpf: Fix faccessat() usage on Android
+- cpufreq: mediatek-hw: Don't error out if supply is not found
+- arm64: dts: qcom: sdm845-oneplus-common: improve DAI node naming
+- soc: qcom: socinfo: rename PM2250 to PM4125
+- arm64: dts: qcom: sm8450: Add missing interconnects to serial
+- af_unix: Annotate data-race of gc_in_progress in wait_for_unix_gc().
+- selftests/bpf: Wait for the netstamp_needed_key static key to be turned on
+- selftests/bpf: Fix the flaky tc_redirect_dtime test
+- selftests/bpf: Add netkit to tc_redirect selftest
+- selftests/bpf: De-veth-ize the tc_redirect test case
+- wifi: ath12k: Fix issues in channel list update
+- selftest/bpf: Add map_in_maps with BPF_MAP_TYPE_PERF_EVENT_ARRAY values
+- libbpf: Apply map_set_def_max_entries() for inner_maps on creation
+- selftests/bpf: Fix potential premature unload in bpf_testmod
+- bpftool: Silence build warning about calloc()
+- inet_diag: annotate data-races around inet_diag_table[]
+- sock_diag: annotate data-races around sock_diag_handlers[family]
+- cpufreq: mediatek-hw: Wait for CPU supplies before probing
+- cpufreq: brcmstb-avs-cpufreq: add check for cpufreq_cpu_get's return value
+- arm64: dts: qcom: sc8180x: Shrink aoss_qmp register space size
+- arm64: dts: qcom: sc8180x: Require LOW_SVS vote for MMCX if DISPCC is on
+- arm64: dts: qcom: sc8180x: Don't hold MDP core clock at FMAX
+- arm64: dts: qcom: sc8180x: Fix eDP PHY power-domains
+- arm64: dts: qcom: sc8180x: Add missing CPU off state
+- arm64: dts: qcom: sc8180x: Fix up big CPU idle state entry latency
+- arm64: dts: qcom: sc8180x: Hook up VDD_CX as GCC parent domain
+- ARM: dts: renesas: r8a73a4: Fix external clocks and clock rate
+- wifi: mwifiex: debugfs: Drop unnecessary error check for debugfs_create_dir()
+- wifi: wilc1000: fix multi-vif management when deleting a vif
+- wifi: wilc1000: do not realloc workqueue everytime an interface is added
+- wifi: rtl8xxxu: add cancel_work_sync() for c2hcmd_work
+- wifi: wilc1000: fix RCU usage in connect path
+- wifi: wilc1000: fix declarations ordering
+- wifi: b43: Disable QoS for bcm4331
+- wifi: b43: Stop correct queue in DMA worker when QoS is disabled
+- wifi: b43: Stop/wake correct queue in PIO Tx path when QoS is disabled
+- wifi: b43: Stop/wake correct queue in DMA Tx path when QoS is disabled
+- wifi: ath10k: fix NULL pointer dereference in ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev()
+- timekeeping: Fix cross-timestamp interpolation for non-x86
+- timekeeping: Fix cross-timestamp interpolation corner case decision
+- timekeeping: Fix cross-timestamp interpolation on counter wrap
+- x86/sme: Fix memory encryption setting if enabled by default and not overridden
+- x86/mm: Ensure input to pfn_to_kaddr() is treated as a 64-bit type
+- aoe: fix the potential use-after-free problem in aoecmd_cfg_pkts
+- io_uring/net: fix overflow check in io_recvmsg_mshot_prep()
+- io_uring/net: move receive multishot out of the generic msghdr path
+- io_uring/net: unify how recvmsg and sendmsg copy in the msghdr
+- rtc: test: Fix invalid format specifier.
+- time: test: Fix incorrect format specifier
+- lib: memcpy_kunit: Fix an invalid format specifier in an assertion msg
+- lib/cmdline: Fix an invalid format specifier in an assertion msg
+- kunit: test: Log the correct filter string in executor_test
+- ovl: Always reject mounting over case-insensitive directories
+- ovl: add support for appending lowerdirs one by one
+- ovl: refactor layer parsing helpers
+- ovl: store and show the user provided lowerdir mount option
+- ovl: remove unused code in lowerdir param parsing
+- md: Don't clear MD_CLOSING when the raid is about to stop
+- fs/select: rework stack allocation hack for clang
+- rcu/exp: Handle RCU expedited grace period kworker allocation failure
+- rcu/exp: Fix RCU expedited parallel grace period kworker allocation failure recovery
+- s390/dasd: fix double module refcount decrement
+- s390/dasd: Use dev_*() for device log messages
+- io_uring: remove unconditional looping in local task_work handling
+- io_uring: remove looping around handling traditional task_work
+- fs: Fix rw_hint validation
+- workqueue: Introduce struct wq_node_nr_active
+- workqueue: Make wq_adjust_max_active() round-robin pwqs while activating
+- workqueue: Move nr_active handling into helpers
+- workqueue: Replace pwq_activate_inactive_work() with [__]pwq_activate_work()
+- workqueue: Factor out pwq_is_empty()
+- workqueue: Move pwq->max_active to wq->max_active
+- workqueue.c: Increase workqueue name length
+- ASoC: wm8962: Fix up incorrect error message in wm8962_set_fll
+- ASoC: wm8962: Enable both SPKOUTR_ENA and SPKOUTL_ENA in mono mode
+- ASoC: wm8962: Enable oscillator if selecting WM8962_FLL_OSC
+- Input: gpio_keys_polled - suppress deferred probe error for gpio
+- xfrm: set skb control buffer based on packet offload as well
+- xfrm: fix xfrm child route lookup for packet offload
+- ASoC: amd: yc: Add HP Pavilion Aero Laptop 13-be2xxx(8BD6) into DMI quirk table
+- x86/hyperv: Allow 15-bit APIC IDs for VTL platforms
+- ASoC: Intel: bytcr_rt5640: Add an extra entry for the Chuwi Vi8 tablet
+- arm64: tegra: Set the correct PHY mode for MGBE
+- perf: RISCV: Fix panic on pmu overflow handler
+- firewire: core: use long bus reset on gap count error
+- Bluetooth: mgmt: Fix limited discoverable off timeout
+- ASoC: amd: yc: Fix non-functional mic on Lenovo 21J2
+- drm/amdgpu: Enable gpu reset for S3 abort cases on Raven series
+- ALSA: hda/realtek - ALC285 reduce pop noise from Headphone port
+- scsi: mpt3sas: Prevent sending diag_reset when the controller is ready
+- ASoC: amd: yc: Add Lenovo ThinkBook 21J0 into DMI quirk table
+- drm/ttm/tests: depend on UML || COMPILE_TEST
+- wifi: mac80211: only call drv_sta_rc_update for uploaded stations
+- net: smsc95xx: add support for SYS TEC USB-SPEmodule1
+- regulator: max5970: Fix regulator child node name
+- ARM: dts: renesas: rcar-gen2: Add missing #interrupt-cells to DA9063 nodes
+- arm64: dts: qcom: Fix interrupt-map cell sizes
+- arm: dts: Fix dtc interrupt_map warnings
+- arm64: dts: Fix dtc interrupt_provider warnings
+- arm: dts: Fix dtc interrupt_provider warnings
+- dm-verity, dm-crypt: align "struct bvec_iter" correctly
+- platform/x86: x86-android-tablets: Fix acer_b1_750_goodix_gpios name
+- perf: CXL: fix CPMU filter value mask length
+- cxl/region: Allow out of order assembly of autodiscovered regions
+- cxl/region: Handle endpoint decoders in cxl_region_find_decoder()
+- block: sed-opal: handle empty atoms when parsing response
+- parisc/ftrace: add missing CONFIG_DYNAMIC_FTRACE check
+- net/iucv: fix the allocation size of iucv_path_table array
+- x86/mm: Disallow vsyscall page read for copy_from_kernel_nofault()
+- x86/mm: Move is_vsyscall_vaddr() into asm/vsyscall.h
+- riscv: dts: sifive: add missing #interrupt-cells to pmic
+- ARM: dts: rockchip: Drop interrupts property from pwm-rockchip nodes
+- RDMA/mlx5: Relax DEVX access upon modify commands
+- RDMA/mlx5: Fix fortify source warning while accessing Eth segment
+- arm64: dts: rockchip: mark system power controller on rk3588-evb1
+- soc: microchip: Fix POLARFIRE_SOC_SYS_CTRL input prompt
+- arm64/sve: Lower the maximum allocation for the SVE ptrace regset
+- gen_compile_commands: fix invalid escape sequence warning
+- ASoC: SOF: ipc4-pcm: Workaround for crashed firmware on system suspend
+- HID: multitouch: Add required quirk for Synaptics 0xcddc device
+- MIPS: Clear Cause.BD in instruction_pointer_set
+- x86/xen: Add some null pointer checking to smp.c
+- ASoC: amd: yc: Fix non-functional mic on Lenovo 82UU
+- regmap: kunit: Ensure that changed bytes are actually different
+- spi: intel-pci: Add support for Lunar Lake-M SPI serial flash
+- ASoC: rt5645: Make LattePanda board DMI match more precise
+- selftests: tls: use exact comparison in recv_partial
+- selftests: openvswitch: Add validation for the recursion test
+- perf/arm-cmn: Workaround AmpereOneX errata AC04_MESH_1 (incorrect child count)
+- wifi: iwlwifi: mvm: use correct address 3 in A-MSDU
+- ASoC: cs42l43: Handle error from devm_pm_runtime_enable
+- media: rkisp1: Fix IRQ handling due to shared interrupts
+- soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free
+- io_uring: drop any code related to SCM_RIGHTS
+- io_uring/unix: drop usage of io_uring socket
+- platform/x86: p2sb: On Goldmont only cache P2SB and SPI devfn BAR
+- !6730 quota: Fix potential NULL pointer dereference
+- quota: Fix potential NULL pointer dereference
+- !6782 i2c: hisi: Add I2C controller reset and initialization proccess in bus recovery action
+- i2c: hisi: Correct the description comment for PIN_MUX METHOD
+- i2c: hisi: Add I2C controller reset and initialization proccess in bus recovery action
+- !6760 spi: hisi-kunpeng: Delete the dump interface of data registers in debugfs
+- spi: hisi-kunpeng: Delete the dump interface of data registers in debugfs
+- !3176 [OLK-6.6] Turning off Zhaoxin ahci controller runtime pm
+- Turning off Zhaoxin ahci controller runtime pm
+- !6403 iommu/arm-smmu-v3: fix using uninitialized or unchecked symbol
+- iommu/arm-smmu-v3: fix using uninitialized or unchecked symbol
+- !6479 do_sys_name_to_handle(): use kzalloc() to fix kernel-infoleak
+- do_sys_name_to_handle(): use kzalloc() to fix kernel-infoleak
+- !6005 [OLK-6.6]Add Yunsilicon eth driver and rdma driver
+- drivers: support for xsc drivers from Yunsilicon Technology
+- !6595 A Solution to Re-enable hugetlb vmemmap optimize on ARM64
+- arm64: update openeuler_defconfig for HVO enable
+- arm64: mm: Re-enable OPTIMIZE_HUGETLB_VMEMMAP
+- arm64: mm: HVO: support BBM of vmemmap pgtable safely
+- mm: HVO: introduce helper function to update and flush pgtable
+- !6731 [OLK-6.6] watchdog: Fix call trace when failed to initialize sdei
+- watchdog: Fix call trace when failed to initialize sdei
+- !6651 [OLK - 6.6]net: hns3: add support for Hisilicon ptp sync device
+- net: hns3: add support for Hisilicon ptp sync device
+- !6385 ipvlan: Fix warning while IPVLAN_L2E disabled
+- ipvlan: Fix warning while IPVLAN_L2E disabled
+- !6409 [OLK-6.6] irqchip: gic-v3: Collection table support muti pages
+- irqchip: gic-v3: Collection table support muti pages
+- !6735 v2 SUNRPC: Fix a slow server-side memory leak with RPC-over-TCP
+- SUNRPC: Fix a slow server-side memory leak with RPC-over-TCP
+- !6590 v6 Introduce BPF_READAHEAD option for optimizing read performance
+- arch: Add BPF_READAHEAD config options for supported architectures
+- mm, fs: Add BPF_READAHEAD build option for bpf readhead
+- !6681 v2 btrfs: fix data races when accessing the reserved amount of block reserves
+- btrfs: fix data races when accessing the reserved amount of block reserves
+
+* Sun Apr 28 2024 ZhangPeng <zhangpeng362@huawei.com> - 6.6.0-23.0.0.26
+- !6306 【OLK-6.6】fix compiling problem in bzwx N5/N6 series NIC drivers
+- drivers: fix compiling problem in bzwx N5/N6 series NIC drivers
+- !6692 ipvlan: enable CONFIG_IPVLAN_L2E option in openeuler config
+- ipvlan: enable CONFIG_IPVLAN_L2E option in openeuler config
+- !6632 ext4: use iomap for regular file's buffered IO path and enable large foilo
+- ext4: add mount option for buffered IO iomap path
+- ext4: don't mark IOMAP_F_DIRTY for buffer write
+- ext4: enable large folio for regular file with iomap buffered IO path
+- filemap: support disable large folios on active inode
+- ext4: partial enable iomap for regular file's buffered IO path
+- ext4: fall back to buffer_head path for defrag
+- ext4: writeback partial blocks before zeroing out range
+- ext4: implement zero_range iomap path
+- ext4: implement mmap iomap path
+- ext4: implement writeback iomap path
+- ext4: implement buffered write iomap path
+- ext4: implement buffered read iomap path
+- ext4: add a new iomap aops for regular file's buffered IO path
+- ext4: introduce seq counter for the extent status entry
+- ext4: factor out ext4_map_create_blocks() to allocate new blocks
+- ext4: use reserved metadata blocks when splitting extent on endio
+- ext4: make ext4_da_map_blocks() buffer_head unaware
+- ext4: make ext4_insert_delayed_block() insert multi-blocks
+- ext4: factor out check for whether a cluster is allocated
+- ext4: make ext4_da_reserve_space() reserve multi-clusters
+- ext4: make ext4_es_insert_delayed_block() insert multi-blocks
+- ext4: drop iblock parameter
+- ext4: trim delalloc extent
+- ext4: check the extent status again before inserting delalloc block
+- ext4: factor out a common helper to query extent map
+- ext4: make ext4_set_iomap() recognize IOMAP_DELALLOC map type
+- ext4: make ext4_map_blocks() distinguish delalloc only extent
+- ext4: add a hole extent entry in cache after punch
+- ext4: convert to exclusive lock while inserting delalloc extents
+- ext4: refactor ext4_da_map_blocks()
+- iomap: do some small logical cleanup in buffered write
+- iomap: make iomap_write_end() return a boolean
+- iomap: use a new variable to handle the written bytes in iomap_write_iter()
+- iomap: don't increase i_size if it's not a write operation
+- iomap: drop the write failure handles when unsharing and zeroing
+- xfs: convert delayed extents to unwritten when zeroing post eof blocks
+- xfs: make xfs_bmapi_convert_delalloc() to allocate the target offset
+- xfs: make the seq argument to xfs_bmapi_convert_delalloc() optional
+- xfs: match lock mode in xfs_buffered_write_iomap_begin()
+- iomap: add pos and dirty_len into trace_iomap_writepage_map
+- iomap: pass the length of the dirty region to ->map_blocks
+- iomap: map multiple blocks at a time
+- iomap: submit ioends immediately
+- iomap: factor out a iomap_writepage_map_block helper
+- iomap: only call mapping_set_error once for each failed bio
+- iomap: don't chain bios
+- iomap: move the iomap_sector sector calculation out of iomap_add_to_ioend
+- iomap: clean up the iomap_alloc_ioend calling convention
+- iomap: move all remaining per-folio logic into iomap_writepage_map
+- iomap: factor out a iomap_writepage_handle_eof helper
+- iomap: move the PF_MEMALLOC check to iomap_writepages
+- iomap: move the io_folios field out of struct iomap_ioend
+- iomap: treat inline data in iomap_writepage_map as an I/O error
+- iomap: clear the per-folio dirty bits on all writeback failures
+- !6625 v2 perf data convert: Fix segfault when converting to json when cpu_desc isn't set
+- perf data convert: Fix segfault when converting to json when cpu_desc isn't set
+- !6647 infiniband/hw/hiroce3: Add Huawei Intelligent Network Card RDMA Driver
+- infiniband/hw/hiroce3: Add Huawei Intelligent Network Card RDMA Driver
+- net/ethernet/huawei/hinic3: Add the CQM on which the RDMA depends
+- !6624 hisi-acc-vfio-pci:add DFX for acc migration driver
+- hisi_acc_vfio_pci: add exception error handling
+- hisi-acc-vfio-pci:add DFX for acc migration driver
+- !6658 sched: disable sched_autogroup by default
+- sched: disable sched_autogroup by default
+- !6626 Backport page fault and fork optimization
+- mm: swapfile: check usable swap device in __folio_throttle_swaprate()
+- mm/filemap: optimize filemap folio adding
+- lib/xarray: introduce a new helper xas_get_order
+- lib/xarray: introduce a new helper xas_get_order
+- mm/filemap: clean up hugetlb exclusion code
+- mm/filemap: return early if failed to allocate memory for split
+- mm: memory: check userfaultfd_wp() in vmf_orig_pte_uffd_wp()
+- !6179 crypto: hisilicon - fixed some code security review issues
+- crypto: hisilicon/debugfs - Resolve the problem of applying for redundant space in sq dump
+- crypto: hisilicon/sec - Fix memory leak for sec resource release
+- crypto: hisilicon - Adjust debugfs creation and release order
+- crypto: hisilicon/qm - Add the default processing branch
+- crypto: hisilicon/debugfs - Fix the processing logic issue in the debugfs creation
+- crypto: hisilicon/sgl - Delete redundant parameter verification
+- crypto: hisilicon/debugfs - Fix debugfs uninit process issue
+- crypto: hisilicon/sec - Add the condition for configuring the sriov function
+- crypto: hisilicon/zip - fix the missing CRYPTO_ALG_ASYNC in cra_flags
+- !6400 btrfs: fix data race at btrfs_use_block_rsv() when accessing block reserve
+- btrfs: fix data race at btrfs_use_block_rsv() when accessing block reserve
+- !6444 Fix CVE-2024-26869
+- f2fs: fix to truncate meta inode pages forcely
+- f2fs: introduce f2fs_invalidate_internal_cache() for cleanup
+- !6585 ACPI: processor_idle: Fix memory leak in acpi_processor_power_exit()
+- ACPI: processor_idle: Fix memory leak in acpi_processor_power_exit()
+- !6251 ubi: Check for too small LEB size in VTBL code
+- ubi: Check for too small LEB size in VTBL code
+- !6418 media: pvrusb2: fix uaf in pvr2_context_set_notify
+- media: pvrusb2: fix uaf in pvr2_context_set_notify
+
+* Wed Apr 24 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-22.0.0.25
+- !6467 RDMA/hns: Some bugfixes and cleanups
+- RDMA/hns: Fix incorrect variable usage in scc_attr_is_visible()
+- RDMA/hns: Fix null pointer when alloc_scc_param() fails
+- RDMA/hns: Fix scc_param delay_work to execute after sysfs shutdown
+- RDMA/hns: Add mutex_destroy() to destroy the mutex
+- RDMA/hns: Fix a potential Sleep-in-Atomic-Context
+- !6468 v2 scsi: fnic: Move fnic_fnic_flush_tx() to a work queue
+- scsi: fnic: Move fnic_fnic_flush_tx() to a work queue
+- !6439 v3 m: convert mm's rss stats to use atomic mode
+- mm: convert mm's rss stats to use atomic mode
+- percpu_counter: introduce atomic mode for percpu_counter
+- !6424 mm/migrate: correct nr_failed in migrate_pages_sync()
+- mm/migrate: add nr_split to trace_mm_migrate_pages stats.
+- mm/migrate: correct nr_failed in migrate_pages_sync()
+- !6390 nfs: fix panic when nfs4_ff_layout_prepare_ds() fails
+- nfs: fix panic when nfs4_ff_layout_prepare_ds() fails
+- !5482 [OLK-6.6] crypto: update zhaoxin-aes for __pcpu_unique_paes_last_cword
+- crypto: update zhaoxin-aes for __pcpu_unique_paes_last_cword
+- !3171 [OLK-6.6] ata: libata: disabling PhyRdy Change Interrupt based on actual LPM capability
+- ata: libata: disabling PhyRdy Change Interrupt based on actual LPM capability
+- !6443 f2fs: fix NULL pointer dereference in f2fs_submit_page_write()
+- f2fs: fix NULL pointer dereference in f2fs_submit_page_write()
+- !6261 RDMA/hns: Some bugfixes and cleanups
+- RDMA/hns: Modify the print level of CQE error
+- RDMA/hns: Add mutex_destroy()
+- RDMA/hns: Fix GMV table pagesize
+- RDMA/hns: Fix mismatch exception rollback
+- RDMA/hns: Fix UAF for cq async event
+- RDMA/hns: Fix deadlock on SRQ async events.
+- RDMA/hns: Remove unused parameters and variables
+- RDMA/hns: Use macro instead of magic number
+- RDMA/hns: Fix return value in hns_roce_map_mr_sg
+- !6265 tpm_tis: Avoid warning splat at shutdown
+- tpm,tpm_tis: Avoid warning splat at shutdown
+- !6402 bpf: Add missing BPF_LINK_TYPE invocations
+- bpf: Add missing BPF_LINK_TYPE invocations
+- !6256 [OLK-6.6] bugfix from upstream v6.9 for AMD EPYC perf
+- perf/x86/amd/core: Define a proper ref-cycles event for Zen 4 and later
+- perf/x86/amd/core: Update and fix stalled-cycles-* events for Zen 2 and later
+- perf/x86/amd/lbr: Use freeze based on availability
+- !6134 v3 rootfs: Fix support for rootfstype= when root= is given
+- rootfs: Fix support for rootfstype= when root= is given
+
+* Tue Apr 23 2024 Hongchen Zhang <zhanghongchen@loongson.cn> - 6.6.0-21.0.0.24
+- add LoongArch support
+
+* Tue Apr 23 2024 Hongchen Zhang <zhanghongchen@loongson.cn> - 6.6.0-21.0.0.23
+- exclude cpufreq.h and cpuidle.h from kernel-headers package
+
+* Sat Apr 20 2024 ZhangPeng <zhangpeng362@huawei.com> - 6.6.0-21.0.0.22
+- !6201 v2 mm: some optimization about hugetlb and thp
+- mm: filemap: try to enable THP for exec mapping
+- mm/khugepaged: keep mm in mm_slot without MMF_DISABLE_THP check
+- mm/khugepaged: bypassing unnecessary scans with MMF_DISABLE_THP check
+- mm: mmap: no need to call khugepaged_enter_vma() for stack
+- mm: remove VM_EXEC requirement for THP eligibility
+- mm: thp_get_unmapped_area must honour topdown preference
+- mm: huge_memory: don't force huge page alignment on 32 bit
+- mm: mmap: map MAP_STACK to VM_NOHUGEPAGE
+- mm: align larger anonymous mappings on THP boundaries
+- fs/hugetlbfs/inode.c: mm/memory-failure.c: fix hugetlbfs hwpoison handling
+- mm/hugetlb: have CONFIG_HUGETLB_PAGE select CONFIG_XARRAY_MULTI
+- mm/filemap: remove hugetlb special casing in filemap.c
+- mm/filemap: clarify filemap_fault() comments for not uptodate case
+- mm: huge_memory: batch tlb flush when splitting a pte-mapped THP
+- !6230 xarray: inline xas_descend to improve performance
+- xarray: inline xas_descend to improve performance
+- !5891 Fix several compilation warnings for hinic driver
+- net/hinic: Fix several compilation warnings with aarch64-openEuler-linux toolchain
+- !6244 arm64: enable CONFIG_ARM64_MPAM in openeuler_defconfig
+- arm64: enable CONFIG_ARM64_MPAM in openeuler_defconfig
+- !6105 fix some issues for arm64 machine check safe
+- ACPI: APEI: handle synchronous exceptions in task work to send correct SIGBUS si_code
+- mm: memory-failure: move return value documentation to function declaration
+- ACPI: APEI: send SIGBUS to current task if synchronous memory error not recovered
+- arm64: add machine check safe sysctl interface
+- arm64: introduce copy_mc_to_kernel() implementation
+- arm64: support copy_mc_[user]_highpage()
+- arm64: Get rid of ARM64_HAS_NO_HW_PREFETCH
+- mm/hwpoison: return -EFAULT when copy fail in copy_mc_[user]_highpage()
+- arm64: add support for ARCH_HAS_COPY_MC
+- Revert "arm64: add support for machine check error safe"
+- Revert "arm64: add uaccess to machine check safe"
+- Revert "mm/hwpoison: return -EFAULT when copy fail in copy_mc_[user]_highpage()"
+- Revert "arm64: support copy_mc_[user]_highpage()"
+- Revert "arm64: introduce copy_mc_to_kernel() implementation"
+- Revert "arm64: add machine check safe sysctl interface"
+- Revert "kasan: fix the compilation error for memcpy_mcs()"
+
+* Tue Apr 16 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-20.0.0.21
+- !6048 improve 3SNIC 910/920/930 NIC driver
+- improve 3SNIC 910/920/930 NIC driver
+- !5815 v2 Support NMI in the virtual machine
+- KVM: arm64: vgic-v3: Handle traps of ICV_NMIAR1_EL1
+- arm64: Decouple KVM from CONFIG_ARM64_NMI
+- KVM: arm64: Handle traps of ALLINT
+- KVM: arm64: Allow GICv3.3 NMI if the host supports it
+- KVM: arm64: vgic-v3: Don't inject an NMI if the vcpu doesn't have FEAT_NMI
+- KVM: arm64: Don't trap ALLINT accesses if the vcpu has FEAT_NMI
+- KVM: arm64: Allow userspace to control ID_AA64PFR1_EL1.NMI
+- KVM: arm64: vgic-debug: Add the NMI field to the debug output
+- KVM: arm64: vgic-v3: Add userspace selection for GICv3.3 NMI
+- KVM: arm64: vgic-v3: Add support for GIC{D,R}_INMIR registers
+- KVM: arm64: vgic-v3: Use the NMI attribute as part of the AP-list sorting
+- KVM: arm64: vgic-v4: Propagate the NMI state into the GICv4.1 VSGI configuration
+- KVM: arm64: vgic-v3: Make NMI priority RES0
+- KVM: arm64: vgic-v3: Allow the NMI state to make it into the LRs
+- KVM: arm64: vgic-v3: Upgrade AP1Rn to 64bit.
+- !5752 【OLK-6.6】Add Chengdu BeiZhongWangXin Technology N5/N6 Series Network Card Driver
+- drivers: add Chengdu BeiZhongWangXin Technology N5/N6 Series Network Card Driver
+- !5730 [OLK-6.6] Fix warnings for RNPGBEVF driver
+- RNPGBEVF: NET: Fix wanrings
+- !5726 [OLK-6.6] Fix warnings for RNPVF driver
+- RNPVF: NET: Fix wanrings
+- !5854 [OLK-6.6] Make Cluster Scheduling Configurable
+- scheduler: Disable cluster scheduling by default
+- scheduler: Add boot time enabling/disabling of cluster scheduling
+- scheduler: Add runtime knob sysctl_sched_cluster
+- scheduler: Create SDTL_SKIP flag to skip topology level
+- !6068 mm: batch mm counter updating in filemap_map_pages()
+- mm: filemap: batch mm counter updating in filemap_map_pages()
+- mm: move mm counter updating out of set_pte_range()
+- !5931 irqchip/gicv3-its: Add workaround for hip09 ITS erratum 162100801
+- irqchip/gicv3-its: Add workaround for hip09 ITS erratum 162100801
+- !5678 v2 KVM: arm64: Translate logic cluster id to physical cluster id when updating lsudvmbm
+- KVM: arm64: Translate logic cluster id to physical cluster id when updating lsudvmbm
+- !5972 Perf-related bugfix
+- docs: perf: Fix build warning of hisi-pcie-pmu.rst
+- drivers/perf: hisi_pcie: Merge find_related_event() and get_event_idx()
+- drivers/perf: hisi_pcie: Relax the check on related events
+- drivers/perf: hisi_pcie: Check the target filter properly
+- drivers/perf: hisi_pcie: Add more events for counting TLP bandwidth
+- drivers/perf: hisi_pcie: Fix incorrect counting under metric mode
+- drivers/perf: hisi_pcie: Introduce hisi_pcie_pmu_get_event_ctrl_val()
+- drivers/perf: hisi_pcie: Rename hisi_pcie_pmu_{config,clear}_filter()
+- drivers/perf: hisi: Enable HiSilicon Erratum 162700402 quirk for HIP09
+- docs: perf: Update usage for target filter of hisi-pcie-pmu
+- !6063 RDMA/hns: Some bugfixes and cleanups
+- RDMA/hns: Fix long waiting cmd event when reset
+- RDMA/hns: Fix the overflow risk of hem_list_calc_ba_range()
+- RDMA/hns: Fix simultaneous reset and resource deregistration
+- RDMA/hns: Fix cpu stuck by printings during reset
+- RDMA/hns: Fix missing capacities in query_device()
+- RDMA/hns: Fix missing resetting notify
+- RDMA/hns: Remove extra blank line in get_sge_num_from_max_inl_data()
+- RDMA/hns: Use complete parentheses in macros
+- RDMA/hns: fix iommu_map_sg() failed when MR bigger than 4G
+- !6069 RDMA/hns: support roh
+- RDMA/hns: Support RDMA_CM in ROH mode
+- RDMA/hns: Support for ROH
+- RDMA/hns: Add new device ID
+- !6008 locking/osq_lock: Avoid false sharing in optimistic_spin_node
+- locking/osq_lock: Avoid false sharing in optimistic_spin_node
+- !5774 irqdomain: Fix driver re-inserting failures when IRQs not being freed
+- irqdomain: Fix driver re-inserting failures when IRQs not being freed
+- !5709 【OLK-6.6】configs: arm64: Enable CONFIG_DLM
+- configs: arm64: Enable CONFIG_DLM
+- !5971 RDMA/hns: Support hns roce DCA mode
+- RDMA/hns: Fix DCA's dependence on ib_uverbs
+- RDMA/hns: Fixes concurrent ressetting and post_recv in DCA mode
+- RDMA/hns: Optimize user DCA perfermance by sharing DCA status
+- RDMA/hns: Add debugfs support for DCA
+- RDMA/hns: Add DCA support for kernel space
+- RDMA/hns: Add method to query WQE buffer's address
+- RDMA/hns: Add method to detach WQE buffer
+- RDMA/hns: Setup the configuration of WQE addressing to QPC
+- RDMA/hns: Add method for attaching WQE buffer
+- RDMA/hns: Configure DCA mode for the userspace QP
+- RDMA/hns: Add method for shrinking DCA memory pool
+- RDMA/hns: Introduce DCA for RC QP
+
+* Fri Apr 12 2024 Jin Lun <jinlun@huawei.com> - 6.6.0-19.0.0.20
+- Remove PGP certificates.
+- Optimize the signing process, if the project has no permission
+ to send sign request, use the kernel native signing.
+
+* Wed Apr 10 2024 ZhangPeng <zhangpeng362@huawei.com> - 6.6.0-19.0.0.19
+- !5877 optimize eevdf scheduler
+- sched/eevdf: Skip eligibility check for current entity during wakeup preemption
+- sched/eevdf: O(1) fastpath for task selection
+- sched/eevdf: Sort the rbtree by virtual deadline
+- !5922 Some fixes and cleanups for SAS
+- Revert "scsi: hisi_sas: Disable SATA disk phy for severe I_T nexus reset failure"
+- scsi: hisi_sas: Add slave_destroy interface for v3 hw
+- scsi: hisi_sas: Modify the deadline for ata_wait_after_reset()
+- scsi: libsas: Allocation SMP request is aligned to ARCH_DMA_MINALIGN
+- scsi: libsas: Add a helper sas_get_sas_addr_and_dev_type()
+- scsi: libsas: Fix disk not being scanned in after being removed
+- scsi: hisi_sas: Remove redundant checks for automatic debugfs dump
+- scsi: hisi_sas: Check usage count only when the runtime PM status is RPM_SUSPENDING
+- scsi: hisi_sas: Handle the NCQ error returned by D2H frame
+- scsi: hisi_sas: Remove hisi_hba->timer for v3 hw
+- scsi: hisi_sas: Check whether debugfs is enabled before removing or releasing it
+- scsi: hisi_sas: Fix a deadlock issue related to automatic dump
+- scsi: hisi_sas: Allocate DFX memory during dump trigger
+- scsi: hisi_sas: Directly call register snapshot instead of using workqueue
+- !5546 support 3snic NIC
+- support 3SNIC 910/920/930 NIC
+- !5869 KVM: arm64: vgic-its: use vgic_get_irq_kref() before vgic_put_irq()
+- KVM: arm64: vgic-its: use vgic_get_irq_kref() before vgic_put_irq()
+- !5878 ima:Dont check xattr when loading digest lists
+- ima:Dont check xattr when loading digest lists
+- !5800 firmware: arm_sdei: Move sdei_cpuhp_up/down() before lockup_detector_online_cpu()
+- firmware: arm_sdei: Move sdei_cpuhp_up/down() before lockup_detector_online_cpu()
+- !3175 [OLK-6.6] x86/tsc: Make cur->adjusted values in package#1 to be the same
+- x86/tsc: Make cur->adjusted values in package#1 to be the same
+- !5022 [devel-6.6] perf/x86/zhaoxin/uncore: Add KX-7000 support
+- perf/x86/zhaoxin/uncore: Add KX-7000 support
+- !5652 [OLK-6.6] i2c: zhaoxin: update support for Zhaoxin I2C controller
+- i2c: zhaoxin: update support for Zhaoxin I2C controller
+- !4475 [OLK-6.6] Update zhaoxin cputemp driver with using the same MSR uniformly
+- Update zhaoxin cputemp driver with using the same MSR uniformly
+- !5813 [intel]OLK-tdx-guest-configs-6.6
+- Enable Intel TDX guest as kernel module
+- !5723 vfio/migration: some bugfix
+- hisi_acc_vfio_pci: obtain the mailbox configuration at one time
+- vfio/migration: remove unused local variable
+- vfio/migration: bugfix cache write-back issue
+- vfio/migration: add eq and aeq interruption restore
+- vfio/migration: bugfix some driver code
+- vfio/migration: added map length page alignment
+- !5707 [OLK-6.6] Fix warnings for RNPGBE driver
+- RNPGBE: NET: Fix wanrings
+- !5659 [OLK-6.6] Fix warnings for RNP driver
+- RNP: Fix warnings
+
+* Mon Apr 08 2024 Ren Zhijie <zhijie.ren@shingroup.cn> - 6.6.0-18.0.0.18
+- add support for arch ppc64le
+
+* Mon Apr 08 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-18.0.0.17
+- !5768 resctrl: fix undefined reference to lockdep_is_cpus_held()
+- fs/resctrl: Move rdtgroup_setup_default() out of init.text section
+- resctrl: fix undefined reference to lockdep_is_cpus_held()
+- !5769 Revert "KVM: arm64: Disable MPAM visibility by default, and handle traps"
+- Revert "KVM: arm64: Disable MPAM visibility by default, and handle traps"
+- !5744 Backport maple_tree: iterator state changes
+- lib/maple_tree.c: fix build error due to hotfix alteration
+- maple_tree: mtree_range_walk() clean up
+- maple_tree: don't find node end in mtree_lookup_walk()
+- maple_tree: use maple state end for write operations
+- maple_tree: remove mas_searchable()
+- maple_tree: separate ma_state node from status
+- maple_tree: clean up inlines for some functions
+- maple_tree: use cached node end in mas_destroy()
+- maple_tree: use cached node end in mas_next()
+- maple_tree: add end of node tracking to the maple state
+- maple_tree: move debug check to __mas_set_range()
+- maple_tree: make mas_erase() more robust
+- maple_tree: remove unnecessary default labels from switch statements
+- !5725 ALSA: sh: aica: reorder cleanup operations to avoid UAF bugs
+- ALSA: sh: aica: reorder cleanup operations to avoid UAF bugs
+
+* Sun Apr 07 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-17.0.0.16
+- !5695 v2 Disable OLK-6.6 configs
+- arm64: configs: Disable PROBE_EVENTS_BTF_ARGS
+- x86: configs: Disable PROBE_EVENTS_BTF_ARGS
+- x86: configs: Disable X86_KERNEL_IBT
+- x86: configs: Disable CRASH_HOTPLUG
+- !5733 fix port vlan filter not disabled problem in dynamic vlan mode
+- net: hns3: fix port vlan filter not disabled problem in dynamic vlan mode
+- !5734 arch/mm/fault: accelerate pagefault when badaccess
+- x86: mm: accelerate pagefault when badaccess
+- arm64: mm: accelerate pagefault when VM_FAULT_BADACCESS
+- !5657 Backport slub performance optimization
+- mm/slub: remove unused parameter in next_freelist_entry()
+- mm/slub: remove full list manipulation for non-debug slab
+- mm/slub: directly load freelist from cpu partial slab in the likely case
+- slub: Update frozen slabs documentations in the source
+- slub: Rename all *unfreeze_partials* functions to *put_partials*
+- slub: Optimize deactivate_slab()
+- slub: Delay freezing of partial slabs
+- slub: Introduce freeze_slab()
+- slub: Prepare __slab_free() for unfrozen partial slab out of node partial list
+- slub: Keep track of whether slub is on the per-node partial list
+- slub: Change get_partial() interfaces to return slab
+- slub: Reflow ___slab_alloc()
+- !5699 sr9800: Add check for usbnet_get_endpoints
+- sr9800: Add check for usbnet_get_endpoints
+
+* Tue Apr 02 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-16.0.0.15
+- !5647 hisilicon - some bugfix and cleanup
+- crypto: hisilicon/sec2: fix memory use-after-free issue
+- crypto: hisilicon/qm - hardware error does not reset during binding/unbinding
+- crypto: hisilicon/qm - check device status before sending mailbox
+- crypto: hisilicon/qm - mask error bit before flr
+- crypto: hisilicon/qm - fix the pf2vf timeout when global reset
+- crypto: hisilicon/qm - obtain the mailbox configuration at one time
+- crypto: hisilicon/hpre - mask cluster timeout error
+- crypto: hisilicon/qm - disable same error report before resetting
+- crypto: hisilicon/qm - modify interrupt processing resource application
+- crypto: hisilicon/qm - reset device before enabling it
+- openeuler_defconfig: enable HISI_ACC_VFIO_PCI=m
+- Revert "openeuler_defconfig: enable HISI_ACC_VFIO_PCI=m"
+- !5509 ext4: Validate inode pa before using preallocation blocks
+- ext4: Validate inode pa before using preallocation blocks
+- !5630 scsi: sd: try more retries of START_STOP when resuming scsi device
+- scsi: sd: try more retries of START_STOP when resuming scsi device
+- !5561 roh: backport roh driver feature support
+- roh/hns3: Fix the processing flow of ROH CMDq during the reset process.
+- roh/core: Synchronously update the mac address of the vlan device when configuring the vlan device ip
+- roh/hns3: Fix ROH multi-BD cmdq issue
+- roh/hns3: Add support for roh dfx(debugfs)
+- roh/hns3: Add support for roh reset
+- roh/core: Add support for inetaddr notifier in roh/core
+- roh/hns3: Add support for roh abnormal interruption
+- roh/core: Add roh device sysfs node
+- roh/hns3: Add ROH cmdq interface support
+- roh/hns3: Add ROH hns3 driver and register a ROH device
+- roh/core: Add ROH device driver
+- net: hns3: add support for ROH reset
+- net: hns3: intercept invalid MAC address setting in ROH
+- !5703 openeuler_defconfig: Disable CONFIG_PREEMPT_DYNAMIC for x86
+- openeuler_defconfig: Disable CONFIG_PREEMPT_DYNAMIC for x86
+- !5513 [OLK-6.6] SCSI: SSSRAID: Support 3SNIC 3S5XX serial RAID/HBA controllers
+- SCSI: SSSRAID: Support 3SNIC 3S5XX serial RAID/HBA controllers
+- !5582 [OLK-6.6]Open CONFIG_LZ4_COMPRESS option for x86_64 architecture
+- Open CONFIG_LZ4_COMPRESS option for x86_64 architecture
+- !5688 v3 Optimize compaction
+- mm/compaction: optimize >0 order folio compaction with free page split.
+- mm/compaction: add support for >0 order folio memory compaction.
+- mm/compaction: enable compacting >0 order folios.
+- mm/page_alloc: remove unused fpi_flags in free_pages_prepare()
+- mm/compaction: introduce NR_PAGE_ORDERS and MAX_PAGE_ORDER
+- mm: compaction: limit the suitable target page order to be less than cc->order
+- mm: compaction: update the cc->nr_migratepages when allocating or freeing the freepages
+- mm: compaction: avoid fast_isolate_freepages blindly choose improper pageblock
+- mm: add page_rmappable_folio() wrapper
+- mm: page_alloc: check the order of compound page even when the order is zero
+- mm/compaction: factor out code to test if we should run compaction for target order
+- mm/compaction: improve comment of is_via_compact_memory
+- mm/compaction: remove repeat compact_blockskip_flush check in reset_isolation_suitable
+- mm/compaction: correctly return failure with bogus compound_order in strict mode
+- mm/compaction: call list_is_{first}/{last} more intuitively in move_freelist_{head}/{tail}
+- mm/compaction: use correct list in move_freelist_{head}/{tail}
+- !5655 add steal time software breakpoint pv ipi support for loongarch kvm
+- LoongArch: Add steal time support in guest side
+- LoongArch: KVM: Add steal time support in kvm side
+- irqchip/loongson-eiointc: Add virt extension support
+- LoongArch: KVM: Add software breakpoint support
+- Documentation: KVM: Add hypercall for LoongArch
+- LoongArch: Add pv ipi support on guest kernel side
+- LoongArch: KVM: Add pv ipi support on kvm side
+- LoongArch: KVM: Add vcpu search support from physical cpuid
+- LoongArch: KVM: Add cpucfg area for kvm hypervisor
+- LoongArch: KVM: Add hypercall instruction emulation support
+- LoongArch/smp: Refine some ipi functions on LoongArch platform
+- !5653 arm64: Enable hardware NMI for perf events NMI
+- arm64: Enable hardware NMI for perf events NMI
+- !5667 configs: arm64: Enable CONFIG_ACPI_AGDI and CONFIG_ACPI_FFH
+- configs: arm64: Enable CONFIG_ACPI_AGDI and CONFIG_ACPI_FFH
+- !5669 disable CONFIG_CMDLINE_FROM_BOOTLOADER CONFIG_INITRAMFS_PRESERVE_MTIME in 6.6
+- configs: disable CONFIG_CMDLINE_FROM_BOOTLOADER CONFIG_INITRAMFS_PRESERVE_MTIME in 6.6
+- !5663 arm64: transparent contiguous PTEs for user mappings
+- arm64: configs: enable ARM64_CONTPTE
+- tools/mm: add thpmaps script to dump THP usage info
+- mm: make folio_pte_batch available outside of mm/memory.c
+- arm64/mm: automatically fold contpte mappings
+- arm64/mm: __always_inline to improve fork() perf
+- arm64/mm: implement pte_batch_hint()
+- mm: add pte_batch_hint() to reduce scanning in folio_pte_batch()
+- arm64/mm: implement new [get_and_]clear_full_ptes() batch APIs
+- arm64/mm: implement new wrprotect_ptes() batch API
+- arm64/mm: wire up PTE_CONT for user mappings
+- arm64/mm: dplit __flush_tlb_range() to elide trailing DSB
+- arm64/mm: new ptep layer to manage contig bit
+- arm64/mm: convert ptep_clear() to ptep_get_and_clear()
+- arm64/mm: convert set_pte_at() to set_ptes(..., 1)
+- arm64/mm: convert READ_ONCE(*ptep) to ptep_get(ptep)
+- mm: tidy up pte_next_pfn() definition
+- x86/mm: convert pte_next_pfn() to pte_advance_pfn()
+- arm64/mm: convert pte_next_pfn() to pte_advance_pfn()
+- mm: introduce pte_advance_pfn() and use for pte_next_pfn()
+- mm: thp: batch-collapse PMD with set_ptes()
+- mm: clarify the spec for set_ptes()
+- mm: memory: move mem_cgroup_charge() into alloc_anon_folio()
+- mm: memory: use folio_prealloc() in wp_page_copy()
+- mm: memory: use a folio in do_cow_fault()
+- mm: memory: rename page_copy_prealloc() to folio_prealloc()
+- !5662 v4 Introduce dynamic pool feature part 2
+- mm/dynamic_pool: Wrap some core functions with dpool prefix
+- mm/dynamic_pool: disable irq for dynamic_pool lock
+- mm/dynamic_pool: don't set subpool for page from dynamic pool
+- mm/dynamic_pool: skip unexpected migration
+- mm/mem_reliable: Fallback to dpool if reliable memory is not enough
+- mm/mem_reliable: Treat page from dhugetlb pool as unreliable page
+- mm/dynamic_pool: Stop alloc reliable page from dynamic pool
+- !5621 irqchip/gic-v3: Fix a system stall when using pseudo NMI with CONFIG_ARM64_NMI closed
+- irqchip/gic-v3: Fix a system stall when using pseudo NMI with CONFIG_ARM64_NMI closed
+- !5656 v3 mm: backport fork/unmap/zap optimize
+- mm/memory: fix missing pte marker for !page on pte zaps
+- mm/memory: optimize unmap/zap with PTE-mapped THP
+- mm/mmu_gather: improve cond_resched() handling with large folios and expensive page freeing
+- mm/mmu_gather: add __tlb_remove_folio_pages()
+- mm/mmu_gather: add tlb_remove_tlb_entries()
+- mm/mmu_gather: define ENCODED_PAGE_FLAG_DELAY_RMAP
+- mm/mmu_gather: pass "delay_rmap" instead of encoded page to __tlb_remove_page_size()
+- mm/memory: factor out zapping folio pte into zap_present_folio_pte()
+- mm/memory: further separate anon and pagecache folio handling in zap_present_pte()
+- mm/memory: handle !page case in zap_present_pte() separately
+- mm/memory: factor out zapping of present pte into zap_present_pte()
+- mm/memory: ignore writable bit in folio_pte_batch()
+- mm/memory: ignore dirty/accessed/soft-dirty bits in folio_pte_batch()
+- mm/memory: optimize fork() with PTE-mapped THP
+- mm/memory: pass PTE to copy_present_pte()
+- mm/memory: factor out copying the actual PTE in copy_present_pte()
+- powerpc/mm: use pte_next_pfn() in set_ptes()
+- arm/mm: use pte_next_pfn() in set_ptes()
+- mm/pgtable: make pte_next_pfn() independent of set_ptes()
+- sparc/pgtable: define PFN_PTE_SHIFT
+- s390/pgtable: define PFN_PTE_SHIFT
+- riscv/pgtable: define PFN_PTE_SHIFT
+- powerpc/pgtable: define PFN_PTE_SHIFT
+- nios2/pgtable: define PFN_PTE_SHIFT
+- arm/pgtable: define PFN_PTE_SHIFT
+- arm64/mm: make set_ptes() robust when OAs cross 48-bit boundary
+- arm64: Mark the 'addr' argument to set_ptes() and __set_pte_at() as unused
+- arm64/mm: Hoist synchronization out of set_ptes() loop
+- mm: convert mm_counter_file() to take a folio
+- mm: convert mm_counter() to take a folio
+- mm: convert to should_zap_page() to should_zap_folio()
+- mm: use pfn_swap_entry_folio() in copy_nonpresent_pte()
+- mm: use pfn_swap_entry_to_folio() in zap_huge_pmd()
+- mm: use pfn_swap_entry_folio() in __split_huge_pmd_locked()
+- s390: use pfn_swap_entry_folio() in ptep_zap_swap_entry()
+- mprotect: use pfn_swap_entry_folio
+- mm: add pfn_swap_entry_folio()
+
+* Tue Apr 2 2024 Jin Lun <jinlun@huawei.com> - 6.6.0-15.0.0.14
+- Support generating moudle/kernel signature with openEuler signature platform
+
+* Sat Mar 30 2024 Liu Jian <liujian56@huawei.com> - 6.6.0-15.0.0.13
+- And net-acc tool to kernel-tools.
+
+* Fri Mar 29 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-15.0.0.12
+- !5470 [OLK-6.6] Add support for Mucse Virtual Function Network Adapter(N500/n210)
+- drivers: initial support for rnpgbevf drivers from Mucse Technology
+- !3164 [OLK-6.6] Fix CRC32C instruction low performance issue
+- crypto: x86/crc32c-intel - Don't match some Zhaoxin CPUs
+- !5547 Synchronizing upstream patch
+- LoongArch: KVM: Set reserved bits as zero in CPUCFG
+- LoongArch: KVM: Do not restart SW timer when it is expired
+- LoongArch: KVM: Start SW timer only when vcpu is blocking
+- irqchip/loongson-eiointc: Remove explicit interrupt affinity restore on resume
+- irqchip/loongson-eiointc: Skip handling if there is no pending irq
+- !3182 [OLK-6.6] Add support for Zhaoxin GMI SM2 Secure Hash algorithm
+- configs: add CONFIG_CRYPTO_SM2_ZHAOXIN_GMI to m
+- Add support for Zhaoxin GMI SM2 Secure Hash algorithm
+- !5578 SCSI: hisi_raid: support SPxxx serial RAID/HBA controllers
+- SCSI: hisi_raid: support SPxxx serial RAID/HBA controllers
+- !5641 userfaultfd: early return in dup_userfaultfd()
+- userfaultfd: early return in dup_userfaultfd()
+- !5629 v3 Mitigate a vmap lock contention
+- mm: vmalloc: refactor vmalloc_dump_obj() function
+- mm: vmalloc: improve description of vmap node layer
+- mm: vmalloc: add a shrinker to drain vmap pools
+- mm: vmalloc: set nr_nodes based on CPUs in a system
+- mm: vmalloc: support multiple nodes in vmallocinfo
+- mm: vmalloc: support multiple nodes in vread_iter
+- mm: vmalloc: add a scan area of VA only once
+- mm: vmalloc: offload free_vmap_area_lock lock
+- mm: vmalloc: remove global purge_vmap_area_root rb-tree
+- mm/vmalloc: remove vmap_area_list
+- mm: vmalloc: remove global vmap_area_root rb-tree
+- mm: vmalloc: move vmap_init_free_space() down in vmalloc.c
+- mm: vmalloc: rename adjust_va_to_fit_type() function
+- mm: vmalloc: add va_alloc() helper
+- mm: Introduce vmap_page_range() to map pages in PCI address space
+- mm: Introduce VM_SPARSE kind and vm_area_[un]map_pages().
+- mm: Enforce VM_IOREMAP flag and range in ioremap_page_range.
+- mm/vmalloc: fix the unchecked dereference warning in vread_iter()
+- !5609 Adding Huawei BMA driver
+- configs: add config BMA to config files
+- Huawei BMA: Adding Huawei BMA driver: cdev_veth_drv
+- Huawei BMA: Adding Huawei BMA driver: host_kbox_drv
+- Huawei BMA: Adding Huawei BMA driver: host_veth_drv
+- Huawei BMA: Adding Huawei BMA driver: host_cdev_drv
+- Huawei BMA: Adding Huawei BMA driver: host_edma_drv
+- !5613 mm: backport rmap interface overhaul
+- mm/memory: fix folio_set_dirty() vs. folio_mark_dirty() in zap_pte_range()
+- mm/huge_memory: fix folio_set_dirty() vs. folio_mark_dirty()
+- mm/rmap: silence VM_WARN_ON_FOLIO() in __folio_rmap_sanity_checks()
+- mm: remove one last reference to page_add_*_rmap()
+- mm/rmap: rename COMPOUND_MAPPED to ENTIRELY_MAPPED
+- mm: convert page_try_share_anon_rmap() to folio_try_share_anon_rmap_[pte|pmd]()
+- mm/rmap: remove page_try_dup_anon_rmap()
+- mm/memory: page_try_dup_anon_rmap() -> folio_try_dup_anon_rmap_pte()
+- mm/huge_memory: page_try_dup_anon_rmap() -> folio_try_dup_anon_rmap_pmd()
+- mm/rmap: introduce folio_try_dup_anon_rmap_[pte|ptes|pmd]()
+- mm/rmap: convert page_dup_file_rmap() to folio_dup_file_rmap_[pte|ptes|pmd]()
+- mm/rmap: remove page_remove_rmap()
+- Documentation: stop referring to page_remove_rmap()
+- mm: userswap: page_remove_rmap() -> folio_remove_rmap_pte()
+- mm/rmap: page_remove_rmap() -> folio_remove_rmap_pte()
+- mm/migrate_device: page_remove_rmap() -> folio_remove_rmap_pte()
+- mm/memory: page_remove_rmap() -> folio_remove_rmap_pte()
+- mm/ksm: page_remove_rmap() -> folio_remove_rmap_pte()
+- mm/khugepaged: page_remove_rmap() -> folio_remove_rmap_pte()
+- mm/huge_memory: page_remove_rmap() -> folio_remove_rmap_pmd()
+- kernel/events/uprobes: page_remove_rmap() -> folio_remove_rmap_pte()
+- mm/rmap: introduce folio_remove_rmap_[pte|ptes|pmd]()
+- mm/rmap: remove RMAP_COMPOUND
+- mm/rmap: remove page_add_anon_rmap()
+- mm/memory: page_add_anon_rmap() -> folio_add_anon_rmap_pte()
+- mm/swapfile: page_add_anon_rmap() -> folio_add_anon_rmap_pte()
+- mm/ksm: page_add_anon_rmap() -> folio_add_anon_rmap_pte()
+- mm/migrate: page_add_anon_rmap() -> folio_add_anon_rmap_pte()
+- mm/huge_memory: page_add_anon_rmap() -> folio_add_anon_rmap_pmd()
+- mm/huge_memory: batch rmap operations in __split_huge_pmd_locked()
+- mm/rmap: introduce folio_add_anon_rmap_[pte|ptes|pmd]()
+- mm/rmap: factor out adding folio mappings into __folio_add_rmap()
+- mm/rmap: remove page_add_file_rmap()
+- mm/userfaultfd: page_add_file_rmap() -> folio_add_file_rmap_pte()
+- mm/migrate: page_add_file_rmap() -> folio_add_file_rmap_pte()
+- mm/huge_memory: page_add_file_rmap() -> folio_add_file_rmap_pmd()
+- mm/memory: page_add_file_rmap() -> folio_add_file_rmap_[pte|pmd]()
+- mm/rmap: convert folio_add_file_rmap_range() into folio_add_file_rmap_[pte|ptes|pmd]()
+- mm/rmap: add hugetlb sanity checks for anon rmap handling
+- mm/rmap: introduce and use hugetlb_try_share_anon_rmap()
+- mm/rmap: introduce and use hugetlb_try_dup_anon_rmap()
+- mm/rmap: introduce and use hugetlb_add_file_rmap()
+- mm/rmap: introduce and use hugetlb_remove_rmap()
+- mm/rmap: rename hugepage_add* to hugetlb_add*
+- mm/khugepaged: convert collapse_pte_mapped_thp() to use folios
+- mm/khugepaged: convert alloc_charge_hpage() to use folios
+- mm/khugepaged: convert is_refcount_suitable() to use folios
+- mm/khugepaged: convert hpage_collapse_scan_pmd() to use folios
+- mm/khugepaged: convert __collapse_huge_page_isolate() to use folios
+- !5543 v2 locking/qspinlock: Add CNA support for ARM64
+- config/arm64: Enable numa aware qspinlock by default
+- locking/qspinlock: Add CNA support for ARM64 without pvspinlock
+- !5555 v2 ACPI/arm64: add support for virtual cpu hotplug
+- arm64/psci: Add undefined error message printing for psci_x_cpu_on
+- cpumask: Add enabled cpumask for present CPUs that can be brought online
+- ACPI: Add _OSC bits to advertise OS support for toggling CPU present/enabled
+- arm64: document virtual CPU hotplug's expectations
+- ACPI: processor: Only call arch_unregister_cpu() if HOTPLUG_CPU is selected
+- ACPI: add support to register CPUs based on the _STA enabled bit
+- arm64: psci: Ignore DENIED CPUs
+- irqchip/gic-v3: Add support for ACPI's disabled but 'online capable' CPUs
+- irqchip/gic-v3: Don't return errors from gic_acpi_match_gicc()
+- ACPICA: Add new MADT GICC flags fields
+- arm64: acpi: Move get_cpu_for_acpi_id() to a header
+- ACPI: Warn when the present bit changes but the feature is not enabled
+- ACPI: Check _STA present bit before making CPUs not present
+- ACPI: convert acpi_processor_post_eject() to use IS_ENABLED()
+- ACPI: Add post_eject to struct acpi_scan_handler for cpu hotplug
+- ACPI: Rename acpi_processor_hotadd_init and remove pre-processor guards
+- ACPI: Move acpi_bus_trim_one() before acpi_scan_hot_remove()
+- ACPI: Rename ACPI_HOTPLUG_CPU to include 'present'
+- ACPI: processor: Register all CPUs from acpi_processor_get_info()
+- ACPI: processor: Register CPUs that are online, but not described in the DSDT
+- ACPI: processor: Add support for processors described as container packages
+- ACPI: Only enumerate enabled (or functional) devices
+- !5461 [OLK-6.6] Add support for Mucse Virtual Function Network Adapter(N10)
+- drivers: initial support for rnpvf drivers from Mucse Technology
+- !5526 Intel: Backport QuickAssist Technology(QAT) in-tree driver
+- Enable Intel QAT_4XXX as kernel module
+- crypto: qat - make ring to service map common for QAT GEN4
+- crypto: qat - fix ring to service map for dcc in 420xx
+- crypto: qat - fix ring to service map for dcc in 4xxx
+- crypto: qat - fix comment structure
+- crypto: qat - remove unnecessary description from comment
+- crypto: qat - remove double initialization of value
+- crypto: qat - avoid division by zero
+- crypto: qat - removed unused macro in adf_cnv_dbgfs.c
+- crypto: qat - remove unused macros in qat_comp_alg.c
+- crypto: qat - uninitialized variable in adf_hb_error_inject_write()
+- Documentation: qat: fix auto_reset section
+- crypto: qat - resolve race condition during AER recovery
+- crypto: qat - change SLAs cleanup flow at shutdown
+- crypto: qat - improve aer error reset handling
+- crypto: qat - limit heartbeat notifications
+- crypto: qat - add auto reset on error
+- crypto: qat - add fatal error notification
+- crypto: qat - re-enable sriov after pf reset
+- crypto: qat - update PFVF protocol for recovery
+- crypto: qat - disable arbitration before reset
+- crypto: qat - add fatal error notify method
+- crypto: qat - add heartbeat error simulator
+- crypto: qat - use kcalloc_node() instead of kzalloc_node()
+- crypto: qat - avoid memcpy() overflow warning
+- crypto: qat - fix arbiter mapping generation algorithm for QAT 402xx
+- crypto: qat - generate dynamically arbiter mappings
+- crypto: qat - add support for ring pair level telemetry
+- crypto: qat - add support for device telemetry
+- crypto: qat - add admin msgs for telemetry
+- crypto: qat - include pci.h for GET_DEV()
+- crypto: qat - add support for 420xx devices
+- crypto: qat - move fw config related structures
+- crypto: qat - relocate portions of qat_4xxx code
+- crypto: qat - change signature of uof_get_num_objs()
+- crypto: qat - relocate and rename get_service_enabled()
+- crypto: qat - add NULL pointer check
+- crypto: qat - fix mutex ordering in adf_rl
+- crypto: qat - fix error path in add_update_sla()
+- crypto: qat - add sysfs_added flag for rate limiting
+- crypto: qat - add sysfs_added flag for ras
+- crypto: qat - prevent underflow in rp2srv_store()
+- units: add missing header
+- seq_file: add helper macro to define attribute for rw file
+- crypto: qat - move adf_cfg_services
+- crypto: qat - add num_rps sysfs attribute
+- crypto: qat - add rp2svc sysfs attribute
+- crypto: qat - add rate limiting sysfs interface
+- crypto: qat - add rate limiting feature to qat_4xxx
+- crypto: qat - add retrieval of fw capabilities
+- crypto: qat - add bits.h to icp_qat_hw.h
+- units: Add BYTES_PER_*BIT
+- crypto: qat - move admin api
+- crypto: qat - count QAT GEN4 errors
+- crypto: qat - add error counters
+- crypto: qat - add handling of errors from ERRSOU3 for QAT GEN4
+- crypto: qat - add adf_get_aram_base() helper function
+- crypto: qat - add handling of compression related errors for QAT GEN4
+- crypto: qat - add handling of errors from ERRSOU2 for QAT GEN4
+- crypto: qat - add reporting of errors from ERRSOU1 for QAT GEN4
+- crypto: qat - add reporting of correctable errors for QAT GEN4
+- crypto: qat - add infrastructure for error reporting
+- crypto: qat - add cnv_errors debugfs file
+- crypto: qat - add pm_status debugfs file
+- crypto: qat - refactor included headers
+- crypto: qat - add namespace to driver
+- crypto: qat - Remove zlib-deflate
+- crypto: qat - Annotate struct adf_fw_counters with __counted_by
+- crypto: qat - do not shadow error code
+- crypto: qat - refactor deprecated strncpy
+- crypto: qat - Use list_for_each_entry() helper
+- Documentation: ABI: debugfs-driver-qat: fix fw_counters path
+
+* Thu Mar 28 2024 Bing Xia <xiabing12@h-partners.com> - 6.6.0-14.0.0.11
+- perf: add CoreSight trace component support on aarch64 platform
+
+* Wed Mar 27 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-14.0.0.10
+- !5524 [OLK-6.6] fix 0day bugs reported by CI robot for Mont-TSSE
+- fix 0 day bugs for Mont-TSSE Driver
+- !5284 [OLK-6.6] fs/address_space: move i_mmap_rwsem to mitigate a false sharing with i_mmap.
+- fs/address_space: move i_mmap_rwsem to mitigate a false sharing with i_mmap.
+- !5280 Add Huawei Intelligent Network Card Driver: hinic3
+- net/hinic3: add huawei/hinic3 driver
+- !5179 Update Huawei Intelligent Network Card Driver: hinic
+- net/hinic: Update Huawei Intelligent Network Card Driver: hinic
+- !5523 enable openeuler_defconfig HISI_ACC_VFIO_PCI=m
+- openeuler_defconfig: enable HISI_ACC_VFIO_PCI=m
+- !5529 arch/powerpc: open BTF relevant configs in openuler defconfig
+- arch/powerpc: open BTF relevant configs in openuler defconfig
+- !5541 RDMA/hns: Backport bugfixes
+- RDMA/hns: Refactor hns_roce_alloc_ucontext()
+- RDMA/hns: Fix missing reset notification by user space driver
+- RDMA/hns: Kernel notify usr space to stop ring db
+- RDMA/hns: Support flexible wqe buffer page size
+- !5464 net: hns3: backport some driver feature enhancement
+- net: hns3: default select PAGE_POOL_STATS
+- net: hns3: support set/get VxLAN rule of rx flow director by ethtool
+- net: ethtool: add VxLAN to the NFC API
+- net: hns3: add support for ROH ras
+- net: hns3: fix bug for init roh client instance
+- net: hns3: HNAE3 framework add support for ROH client
+- net: hns3: add support handling tx dhcp packets for ROH
+- net: hns3: support arp proxy
+- net: hns3: add arp proxy switch in ethtool
+- net: hns3: support tc limit rate
+- net: hns3: support tc command with max rate parameter
+- net: hns3: add ROH MAC type definitions and support query MAC type
+- net: hns3: Add support for some CMIS transceiver modules
+- net: sfp: Synchronize some CMIS transceiver modules from ethtool
+- net: hns3: add command queue trace for hns3
+- net: hns3: dump more reg info based on ras mod
+- net: hns3: add support for page_pool_get_stats
+- net: hns3: add support to query scc version by devlink info
+- net: hns3: correct the logic of hclge_sync_vf_qb_mode()
+- net: hns3: add support for FD counter
+- net: hns3: allocate fd counter for queue bonding
+- net: hns3: refactor the debugfs for dumping FD tcam
+- net: hns3: add queue bonding mode support for VF
+- net: hns3: add support for queue bonding mode of flow director
+- !5426 BTC's bugfix for openeuler OLK-6.6
+- ipmi: Add erratum 162102203 config to enable workaround for SMS message processing timeout
+- ipmi: Errata workaround to prevent SMS message processing timeout
+- !5049 [OLK-6.6]Add pcie acs and no-bus-reset quirk for mucse Nics
+- Add pcie acs and no-bus-reset quirk for mucse Nics
+- !5354 iommu/arm-smmu-v3: Disable ECMDQ before reset
+- iommu/arm-smmu-v3: Disable ECMDQ before reset
+- !5061 [OLK-6.6] riscv: Update openeuler_defconfig to support sg2042 SoC
+- riscv: Update openeuler_defconfig to support sg2042 SoC
+- !5427 crypto/trng: Remove the automatic loading of the hisi_trng driver
+- crypto/trng: Remove the automatic loading of the hisi_trng driver
+- crypto: hisilicon/trng - use %u to print u32 variables
+- !5492 Backport Introduce __mt_dup() to improve the performance of fork()
+- fork: use __mt_dup() to duplicate maple tree in dup_mmap()
+- maple_tree: preserve the tree attributes when destroying maple tree
+- maple_tree: update check_forking() and bench_forking()
+- maple_tree: skip other tests when BENCH is enabled
+- maple_tree: update the documentation of maple tree
+- maple_tree: add test for mtree_dup()
+- radix tree test suite: align kmem_cache_alloc_bulk() with kernel behavior.
+- maple_tree: introduce interfaces __mt_dup() and mtree_dup()
+- maple_tree: introduce {mtree,mas}_lock_nested()
+- maple_tree: add mt_free_one() and mt_attr() helpers
+- radix tree test suite: fix allocation calculation in kmem_cache_alloc_bulk()
+- !5334 v4 iommu/iova: avoid softlockup in fq_flush_timeout
+- iommu/iova: avoid softlockup in fq_flush_timeout
+- !5412 [OLK-6.6] perf/x86/amd: Miscellaneous fixes
+- perf vendor events amd: Fix Zen 4 cache latency events
+- perf/x86/amd/lbr: Discard erroneous branch entries
+- perf/x86/amd/core: Avoid register reset when CPU is dead
+- !5376 Bluetooth: rfcomm: Fix null-ptr-deref in rfcomm_check_security
+- Bluetooth: rfcomm: Fix null-ptr-deref in rfcomm_check_security
+
+* Fri Mar 22 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-13.0.0.9
+- !5424 block: Fix iterating over an empty bio with bio_for_each_folio_all
+- block: Fix iterating over an empty bio with bio_for_each_folio_all
+- !5425 nbd: always initialize struct msghdr completely
+- nbd: always initialize struct msghdr completely
+- !5255 CVE-2024-26627
+- scsi: core: Move scsi_host_busy() out of host lock if it is for per-command
+- scsi: core: Move scsi_host_busy() out of host lock for waking up EH handler
+- !5221 powerpc/mm: Fix null-pointer dereference in pgtable_cache_add
+- powerpc/mm: Fix null-pointer dereference in pgtable_cache_add
+- !5045 [OLK-6.6] Add support for Mont-TSSE firmware update and fix 0day bugs
+- add firmware update function for Mont-TSSE
+- fix 0day bugs for Mont-TSSE in CI test
+- !5363 [OLK-6.6] ima: Support modsig verify using trusted keys
+- ima: Enable modsig appraisal by default
+- ima: Support modsig verify using trusted keys
+- !5369 Backport 6.6.9-6.6.22 LTS
+- KVM/x86: Export RFDS_NO and RFDS_CLEAR to guests
+- x86/rfds: Mitigate Register File Data Sampling (RFDS)
+- Documentation/hw-vuln: Add documentation for RFDS
+- x86/mmio: Disable KVM mitigation when X86_FEATURE_CLEAR_CPU_BUF is set
+- selftests: mptcp: decrease BW in simult flows
+- readahead: avoid multiple marked readahead pages
+- KVM: s390: vsie: fix race during shadow creation
+- KVM: s390: add stat counter for shadow gmap events
+- net: pds_core: Fix possible double free in error handling path
+- netrom: Fix data-races around sysctl_net_busy_read
+- netrom: Fix a data-race around sysctl_netrom_link_fails_count
+- netrom: Fix a data-race around sysctl_netrom_routing_control
+- netrom: Fix a data-race around sysctl_netrom_transport_no_activity_timeout
+- netrom: Fix a data-race around sysctl_netrom_transport_requested_window_size
+- netrom: Fix a data-race around sysctl_netrom_transport_busy_delay
+- netrom: Fix a data-race around sysctl_netrom_transport_acknowledge_delay
+- netrom: Fix a data-race around sysctl_netrom_transport_maximum_tries
+- netrom: Fix a data-race around sysctl_netrom_transport_timeout
+- netrom: Fix data-races around sysctl_netrom_network_ttl_initialiser
+- netrom: Fix a data-race around sysctl_netrom_obsolescence_count_initialiser
+- netrom: Fix a data-race around sysctl_netrom_default_path_quality
+- erofs: apply proper VMA alignment for memory mapped files on THP
+- netfilter: nf_conntrack_h323: Add protection for bmp length out of range
+- netfilter: nft_ct: fix l3num expectations with inet pseudo family
+- net/rds: fix WARNING in rds_conn_connect_if_down
+- net: dsa: microchip: fix register write order in ksz8_ind_write8()
+- cpumap: Zero-initialise xdp_rxq_info struct before running XDP program
+- selftests/bpf: Fix up xdp bonding test wrt feature flags
+- xdp, bonding: Fix feature flags when there are no slave devs anymore
+- bpf: check bpf_func_state->callback_depth when pruning states
+- net/ipv6: avoid possible UAF in ip6_route_mpath_notify()
+- igc: avoid returning frame twice in XDP_REDIRECT
+- net: ice: Fix potential NULL pointer dereference in ice_bridge_setlink()
+- ice: virtchnl: stop pretending to support RSS over AQ or registers
+- net: sparx5: Fix use after free inside sparx5_del_mact_entry
+- geneve: make sure to pull inner header in geneve_rx()
+- tracing/net_sched: Fix tracepoints that save qdisc_dev() as a string
+- net/mlx5e: Switch to using _bh variant of of spinlock API in port timestamping NAPI poll context
+- net/mlx5e: Use a memory barrier to enforce PTP WQ xmit submission tracking occurs after populating the metadata_map
+- net/mlx5e: Fix MACsec state loss upon state update in offload path
+- net/mlx5e: Change the warning when ignore_flow_level is not supported
+- net/mlx5: Check capability for fw_reset
+- net/mlx5: E-switch, Change flow rule destination checking
+- Revert "net/mlx5e: Check the number of elements before walk TC rhashtable"
+- Revert "net/mlx5: Block entering switchdev mode with ns inconsistency"
+- ice: reorder disabling IRQ and NAPI in ice_qp_dis
+- i40e: disable NAPI right after disabling irqs when handling xsk_pool
+- ixgbe: {dis, en}able irqs in ixgbe_txrx_ring_{dis, en}able
+- net: lan78xx: fix runtime PM count underflow on link stop
+- xfrm: Pass UDP encapsulation in TX packet offload
+- mm/vmscan: fix a bug calling wakeup_kswapd() with a wrong zone index
+- ceph: switch to corrected encoding of max_xattr_size in mdsmap
+- dmaengine: fsl-edma: correct max_segment_size setting
+- dmaengine: fsl-edma: utilize common dt-binding header file
+- dt-bindings: dma: fsl-edma: Add fsl-edma.h to prevent hardcoding in dts
+- drm/nouveau: don't fini scheduler before entity flush
+- selftests: mptcp: rm subflow with v4/v4mapped addr
+- selftests: mptcp: add mptcp_lib_is_v6
+- selftests: mptcp: update userspace pm test helpers
+- selftests: mptcp: add chk_subflows_total helper
+- selftests: mptcp: add evts_get_info helper
+- KVM/VMX: Move VERW closer to VMentry for MDS mitigation
+- KVM/VMX: Use BT+JNC, i.e. EFLAGS.CF to select VMRESUME vs. VMLAUNCH
+- x86/bugs: Use ALTERNATIVE() instead of mds_user_clear static key
+- x86/entry_32: Add VERW just before userspace transition
+- x86/entry_64: Add VERW just before userspace transition
+- block: define bvec_iter as __packed __aligned(4)
+- gpio: fix resource unwinding order in error path
+- gpiolib: Fix the error path order in gpiochip_add_data_with_key()
+- gpio: 74x164: Enable output pins after registers are reset
+- powerpc/rtas: use correct function name for resetting TCE tables
+- powerpc/pseries/iommu: IOMMU table is not initialized for kdump over SR-IOV
+- dmaengine: idxd: Ensure safe user copy of completion record
+- dmaengine: idxd: Remove shadow Event Log head stored in idxd
+- phy: freescale: phy-fsl-imx8-mipi-dphy: Fix alias name to use dashes
+- dmaengine: dw-edma: eDMA: Add sync read before starting the DMA transfer in remote setup
+- dmaengine: dw-edma: HDMA: Add sync read before starting the DMA transfer in remote setup
+- dmaengine: dw-edma: Add HDMA remote interrupt configuration
+- dmaengine: dw-edma: HDMA_V0_REMOTEL_STOP_INT_EN typo fix
+- dmaengine: dw-edma: Fix wrong interrupt bit set for HDMA
+- dmaengine: dw-edma: Fix the ch_count hdma callback
+- ASoC: cs35l56: fix reversed if statement in cs35l56_dspwait_asp1tx_put()
+- af_unix: Drop oob_skb ref before purging queue in GC.
+- af_unix: Fix task hung while purging oob_skb in GC.
+- NFS: Fix data corruption caused by congestion.
+- mptcp: fix possible deadlock in subflow diag
+- mptcp: fix double-free on socket dismantle
+- mptcp: fix potential wake-up event loss
+- mptcp: fix snd_wnd initialization for passive socket
+- selftests: mptcp: join: add ss mptcp support check
+- mptcp: push at DSS boundaries
+- mptcp: avoid printing warning once on client side
+- mptcp: map v4 address to v6 when destroying subflow
+- x86/cpu/intel: Detect TME keyid bits before setting MTRR mask registers
+- x86/e820: Don't reserve SETUP_RNG_SEED in e820
+- mm/debug_vm_pgtable: fix BUG_ON with pud advanced test
+- pmdomain: qcom: rpmhpd: Fix enabled_corner aggregation
+- efivarfs: Request at most 512 bytes for variable names
+- kbuild: Add -Wa,--fatal-warnings to as-instr invocation
+- riscv: add CALLER_ADDRx support
+- RISC-V: Drop invalid test from CONFIG_AS_HAS_OPTION_ARCH
+- mmc: sdhci-xenon: fix PHY init clock stability
+- mmc: sdhci-xenon: add timeout for PHY init complete
+- mmc: core: Fix eMMC initialization with 1-bit bus connection
+- mmc: mmci: stm32: fix DMA API overlapping mappings warning
+- dmaengine: fsl-qdma: init irq after reg initialization
+- dmaengine: fsl-edma: correct calculation of 'nbytes' in multi-fifo scenario
+- dmaengine: ptdma: use consistent DMA masks
+- crypto: arm64/neonbs - fix out-of-bounds access on short input
+- dmaengine: fsl-qdma: fix SoC may hang on 16 byte unaligned read
+- soc: qcom: pmic_glink: Fix boot when QRTR=m
+- drm/amd/display: Add monitor patch for specific eDP
+- drm/buddy: fix range bias
+- Revert "drm/amd/pm: resolve reboot exception for si oland"
+- btrfs: send: don't issue unnecessary zero writes for trailing hole
+- btrfs: dev-replace: properly validate device names
+- btrfs: fix double free of anonymous device after snapshot creation failure
+- wifi: nl80211: reject iftype change with mesh ID change
+- mtd: rawnand: marvell: fix layouts
+- gtp: fix use-after-free and null-ptr-deref in gtp_newlink()
+- landlock: Fix asymmetric private inodes referring
+- Bluetooth: hci_bcm4377: do not mark valid bd_addr as invalid
+- ALSA: hda/realtek: Add special fixup for Lenovo 14IRP8
+- ALSA: hda/realtek: fix mute/micmute LED For HP mt440
+- ALSA: hda/realtek: Enable Mute LED on HP 840 G8 (MB 8AB8)
+- ALSA: hda/realtek: tas2781: enable subwoofer volume control
+- ALSA: ump: Fix the discard error code from snd_ump_legacy_open()
+- ALSA: firewire-lib: fix to check cycle continuity
+- tomoyo: fix UAF write bug in tomoyo_write_control()
+- of: property: fw_devlink: Fix stupid bug in remote-endpoint parsing
+- btrfs: fix race between ordered extent completion and fiemap
+- riscv: Sparse-Memory/vmemmap out-of-bounds fix
+- riscv: Fix pte_leaf_size() for NAPOT
+- Revert "riscv: mm: support Svnapot in huge vmap"
+- drivers: perf: ctr_get_width function for legacy is not defined
+- drivers: perf: added capabilities for legacy PMU
+- afs: Fix endless loop in directory parsing
+- fbcon: always restore the old font data in fbcon_do_set_font()
+- drm/tegra: Remove existing framebuffer only if we support display
+- RISC-V: Ignore V from the riscv,isa DT property on older T-Head CPUs
+- ASoC: soc-card: Fix missing locking in snd_soc_card_get_kcontrol()
+- ASoC: cs35l56: Fix deadlock in ASP1 mixer register initialization
+- ASoC: cs35l56: Fix misuse of wm_adsp 'part' string for silicon revision
+- ASoC: cs35l56: Fix for initializing ASP1 mixer registers
+- ASoC: cs35l56: Don't add the same register patch multiple times
+- ASoC: cs35l56: cs35l56_component_remove() must clean up wm_adsp
+- ASoC: cs35l56: cs35l56_component_remove() must clear cs35l56->component
+- riscv: Fix build error if !CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
+- ASoC: qcom: Fix uninitialized pointer dmactl
+- ASoC: qcom: convert not to use asoc_xxx()
+- ASoC: soc.h: convert asoc_xxx() to snd_soc_xxx()
+- ALSA: Drop leftover snd-rtctimer stuff from Makefile
+- ASoC: cs35l56: Must clear HALO_STATE before issuing SYSTEM_RESET
+- power: supply: bq27xxx-i2c: Do not free non existing IRQ
+- efi/capsule-loader: fix incorrect allocation size
+- tls: fix use-after-free on failed backlog decryption
+- tls: separate no-async decryption request handling from async
+- tls: fix peeking with sync+async decryption
+- tls: decrement decrypt_pending if no async completion will be called
+- net: hsr: Use correct offset for HSR TLV values in supervisory HSR frames
+- igb: extend PTP timestamp adjustments to i211
+- rtnetlink: fix error logic of IFLA_BRIDGE_FLAGS writing back
+- tools: ynl: fix handling of multiple mcast groups
+- netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate()
+- Bluetooth: qca: Fix triggering coredump implementation
+- Bluetooth: hci_qca: Set BDA quirk bit if fwnode exists in DT
+- Bluetooth: qca: Fix wrong event type for patch config command
+- Bluetooth: Enforce validation on max value of connection interval
+- Bluetooth: hci_event: Fix handling of HCI_EV_IO_CAPA_REQUEST
+- Bluetooth: hci_event: Fix wrongly recorded wakeup BD_ADDR
+- Bluetooth: hci_sync: Fix accept_list when attempting to suspend
+- Bluetooth: Avoid potential use-after-free in hci_error_reset
+- Bluetooth: hci_sync: Check the correct flag before starting a scan
+- stmmac: Clear variable when destroying workqueue
+- uapi: in6: replace temporary label with rfc9486
+- net: lan78xx: fix "softirq work is pending" error
+- net: usb: dm9601: fix wrong return value in dm9601_mdio_read
+- veth: try harder when allocating queue memory
+- lan78xx: enable auto speed configuration for LAN7850 if no EEPROM is detected
+- ipv6: fix potential "struct net" leak in inet6_rtm_getaddr()
+- net: veth: clear GRO when clearing XDP even when down
+- cpufreq: intel_pstate: fix pstate limits enforcement for adjust_perf call back
+- tun: Fix xdp_rxq_info's queue_index when detaching
+- net: dpaa: fman_memac: accept phy-interface-type = "10gbase-r" in the device tree
+- net: mctp: take ownership of skb in mctp_local_output
+- net: ip_tunnel: prevent perpetual headroom growth
+- netlink: add nla be16/32 types to minlen array
+- netlink: Fix kernel-infoleak-after-free in __skb_datagram_iter
+- spi: cadence-qspi: fix pointer reference in runtime PM hooks
+- mtd: spinand: gigadevice: Fix the get ecc status issue
+- ublk: move ublk_cancel_dev() out of ub->mutex
+- ksmbd: fix wrong allocation size update in smb2_open()
+- ASoC: cs35l34: Fix GPIO name and drop legacy include
+- fs/ntfs3: fix build without CONFIG_NTFS3_LZX_XPRESS
+- ahci: Extend ASM1061 43-bit DMA address quirk to other ASM106x parts
+- ata: ahci: add identifiers for ASM2116 series adapters
+- mptcp: add needs_id for netlink appending addr
+- mptcp: userspace pm send RM_ADDR for ID 0
+- selftests: mptcp: add mptcp_lib_get_counter
+- selftests: mptcp: join: stop transfer when check is done (part 2)
+- mm: zswap: fix missing folio cleanup in writeback race path
+- mm/zswap: invalidate duplicate entry when !zswap_enabled
+- selftests: mptcp: join: stop transfer when check is done (part 1)
+- i2c: imx: when being a target, mark the last read as processed
+- drm/amd/display: Fix memory leak in dm_sw_fini()
+- drm/syncobj: handle NULL fence in syncobj_eventfd_entry_func
+- drm/syncobj: call drm_syncobj_fence_add_wait when WAIT_AVAILABLE flag is set
+- net: phy: realtek: Fix rtl8211f_config_init() for RTL8211F(D)(I)-VD-CG PHY
+- Fix write to cloned skb in ipv6_hop_ioam()
+- phonet/pep: fix racy skb_queue_empty() use
+- phonet: take correct lock to peek at the RX queue
+- net: sparx5: Add spinlock for frame transmission from CPU
+- net/sched: flower: Add lock protection when remove filter handle
+- devlink: fix port dump cmd type
+- tools: ynl: don't leak mcast_groups on init error
+- tools: ynl: make sure we always pass yarg to mnl_cb_run
+- net: mctp: put sock on tag allocation failure
+- netfilter: nf_tables: use kzalloc for hook allocation
+- netfilter: nf_tables: register hooks last when adding new chain/flowtable
+- netfilter: nft_flow_offload: release dst in case direct xmit path is used
+- netfilter: nft_flow_offload: reset dst in route object after setting up flow
+- netfilter: nf_tables: set dormant flag on hook register failure
+- tls: don't skip over different type records from the rx_list
+- tls: stop recv() if initial process_rx_list gave us non-DATA
+- tls: break out of main loop when PEEK gets a non-data record
+- hwmon: (nct6775) Fix access to temperature configuration registers
+- cache: ax45mp_cache: Align end size to cache boundary in ax45mp_dma_cache_wback()
+- bpf, sockmap: Fix NULL pointer dereference in sk_psock_verdict_data_ready()
+- s390: use the correct count for __iowrite64_copy()
+- net: ipa: don't overrun IPA suspend interrupt registers
+- octeontx2-af: Consider the action set by PF
+- drm/i915/tv: Fix TV mode
+- platform/x86: thinkpad_acpi: Only update profile if successfully converted
+- arm64/sme: Restore SMCR_EL1.EZT0 on exit from suspend
+- arm64/sme: Restore SME registers on exit from suspend
+- arp: Prevent overflow in arp_req_get().
+- devlink: fix possible use-after-free and memory leaks in devlink_init()
+- ipv6: sr: fix possible use-after-free and null-ptr-deref
+- afs: Increase buffer size in afs_update_volume_status()
+- parisc: Fix stack unwinder
+- bpf: Fix racing between bpf_timer_cancel_and_free and bpf_timer_cancel
+- ata: ahci_ceva: fix error handling for Xilinx GT PHY support
+- selftests: bonding: set active slave to primary eth1 specifically
+- powerpc/pseries/iommu: DLPAR add doesn't completely initialize pci_controller
+- net: bcmasp: Sanity check is off by one
+- net: bcmasp: Indicate MAC is in charge of PHY PM
+- ipv6: properly combine dev_base_seq and ipv6.dev_addr_genid
+- ipv4: properly combine dev_base_seq and ipv4.dev_addr_genid
+- net: stmmac: Fix incorrect dereference in interrupt handlers
+- x86/numa: Fix the sort compare func used in numa_fill_memblks()
+- x86/numa: Fix the address overlap check in numa_fill_memblks()
+- nouveau: fix function cast warnings
+- net/sched: act_mirred: don't override retval if we already lost the skb
+- net/sched: act_mirred: use the backlog for mirred ingress
+- net/sched: act_mirred: Create function tcf_mirred_to_dev and improve readability
+- dccp/tcp: Unhash sk from ehash for tb2 alloc failure after check_estalblished().
+- net: bridge: switchdev: Ensure deferred event delivery on unoffload
+- net: bridge: switchdev: Skip MDB replays of deferred events on offload
+- scsi: jazz_esp: Only build if SCSI core is builtin
+- scsi: smartpqi: Fix disable_managed_interrupts
+- bpf, scripts: Correct GPL license name
+- RDMA/srpt: fix function pointer cast warnings
+- xsk: Add truesize to skb_add_rx_frag().
+- arm64: dts: rockchip: Correct Indiedroid Nova GPIO Names
+- arm64: dts: rockchip: set num-cs property for spi on px30
+- RDMA/qedr: Fix qedr_create_user_qp error flow
+- bus: imx-weim: fix valid range check
+- arm64: dts: tqma8mpql: fix audio codec iov-supply
+- RDMA/srpt: Support specifying the srpt_service_guid parameter
+- RDMA/irdma: Add AE for too many RNRS
+- RDMA/irdma: Set the CQ read threshold for GEN 1
+- RDMA/irdma: Validate max_send_wr and max_recv_wr
+- RDMA/irdma: Fix KASAN issue with tasklet
+- arm64: dts: imx8mp: Disable UART4 by default on Data Modul i.MX8M Plus eDM SBC
+- IB/mlx5: Don't expose debugfs entries for RRoCE general parameters if not supported
+- RDMA/bnxt_re: Add a missing check in bnxt_qplib_query_srq
+- RDMA/bnxt_re: Return error for SRQ resize
+- IB/hfi1: Fix a memleak in init_credit_return
+- bpf: Derive source IP addr via bpf_*_fib_lookup()
+- xen/events: fix error code in xen_bind_pirq_msi_to_irq()
+- Revert "drm/amd/display: increased min_dcfclk_mhz and min_fclk_mhz"
+- drm/amd/display: Fix buffer overflow in 'get_host_router_total_dp_tunnel_bw()'
+- drm/amd/display: Avoid enum conversion warning
+- smb3: add missing null server pointer check
+- selftests: mptcp: diag: unique 'cestab' subtest names
+- selftests: mptcp: diag: unique 'in use' subtest names
+- selftests: mptcp: diag: fix bash warnings on older kernels
+- selftests: mptcp: diag: check CURRESTAB counters
+- selftests: mptcp: pm nl: avoid error msg on older kernels
+- selftests: mptcp: pm nl: also list skipped tests
+- selftests: mptcp: simult flows: fix some subtest names
+- selftests: mptcp: userspace_pm: unique subtest names
+- mptcp: fix duplicate subflow creation
+- mptcp: fix data races on remote_id
+- mptcp: fix data races on local_id
+- mptcp: fix lockless access in subflow ULP diag
+- mptcp: add needs_id for userspace appending addr
+- usb: roles: don't get/set_role() when usb_role_switch is unregistered
+- usb: roles: fix NULL pointer issue when put module's reference
+- usb: gadget: omap_udc: fix USB gadget regression on Palm TE
+- usb: gadget: ncm: Avoid dropping datagrams of properly parsed NTBs
+- usb: cdns3: fix memory double free when handle zero packet
+- usb: cdns3: fixed memory use after free at cdns3_gadget_ep_disable()
+- usb: cdnsp: fixed issue with incorrect detecting CDNSP family controllers
+- usb: cdnsp: blocked some cdns3 specific code
+- usb: dwc3: gadget: Don't disconnect if not started
+- serial: amba-pl011: Fix DMA transmission in RS485 mode
+- serial: stm32: do not always set SER_RS485_RX_DURING_TX if RS485 is enabled
+- Revert "usb: typec: tcpm: reset counter when enter into unattached state after try role"
+- erofs: fix refcount on the metabuf used for inode lookup
+- dm-integrity, dm-verity: reduce stack usage for recheck
+- ARM: ep93xx: Add terminator to gpiod_lookup_table
+- l2tp: pass correct message length to ip6_append_data
+- PCI/MSI: Prevent MSI hardware interrupt number truncation
+- irqchip/sifive-plic: Enable interrupt if needed before EOI
+- irqchip/gic-v3-its: Do not assume vPE tables are preallocated
+- irqchip/mbigen: Don't use bus_get_dev_root() to find the parent
+- crypto: virtio/akcipher - Fix stack overflow on memcpy
+- gtp: fix use-after-free and null-ptr-deref in gtp_genl_dump_pdp()
+- accel/ivpu: Don't enable any tiles by default on VPU40xx
+- KVM: arm64: vgic-its: Test for valid IRQ in its_sync_lpi_pending_table()
+- KVM: arm64: vgic-its: Test for valid IRQ in MOVALL handler
+- md: Fix missing release of 'active_io' for flush
+- sparc: Fix undefined reference to fb_is_primary_device
+- platform/x86: touchscreen_dmi: Allow partial (prefix) matches for ACPI names
+- platform/x86: intel-vbtn: Stop calling "VBDL" from notify_handler
+- mm/damon/reclaim: fix quota stauts loss due to online tunings
+- mm: memcontrol: clarify swapaccount=0 deprecation warning
+- mm/damon/lru_sort: fix quota status loss due to online tunings
+- mm/swap: fix race when skipping swapcache
+- selftests/mm: uffd-unit-test check if huge page size is 0
+- scsi: core: Consult supported VPD page list prior to fetching page
+- scsi: target: pscsi: Fix bio_put() for error case
+- scsi: sd: usb_storage: uas: Access media prior to querying device properties
+- cxl/acpi: Fix load failures due to single window creation failure
+- dm-verity: recheck the hash after a failure
+- dm-crypt: don't modify the data when using authenticated encryption
+- dm-integrity: recheck the integrity tag after a failure
+- Revert "parisc: Only list existing CPUs in cpu_possible_mask"
+- dm-crypt: recheck the integrity tag after a failure
+- lib/Kconfig.debug: TEST_IOV_ITER depends on MMU
+- fs/aio: Restrict kiocb_set_cancel_fn() to I/O submitted via libaio
+- ata: libata-core: Do not try to set sleeping devices to standby
+- s390/cio: fix invalid -EBUSY on ccw_device_start
+- drm/amd/display: adjust few initialization order in dm
+- drm/meson: Don't remove bridges which are created by other drivers
+- drm/ttm: Fix an invalid freeing on already freed page in error path
+- btrfs: defrag: avoid unnecessary defrag caused by incorrect extent size
+- LoongArch: Update cpu_sibling_map when disabling nonboot CPUs
+- LoongArch: Disable IRQ before init_fn() for nonboot CPUs
+- LoongArch: Call early_init_fdt_scan_reserved_mem() earlier
+- docs: Instruct LaTeX to cope with deeper nesting
+- x86/bugs: Add asm helpers for executing VERW
+- IB/hfi1: Fix sdma.h tx->num_descs off-by-one error
+- xen/events: close evtchn after mapping cleanup
+- xen/events: modify internal [un]bind interfaces
+- xen/events: drop xen_allocate_irqs_dynamic()
+- xen/events: remove some simple helpers from events_base.c
+- xen/events: reduce externally visible helper functions
+- xen: evtchn: Allow shared registration of IRQ handers
+- drm/amd/display: fixed integer types and null check locations
+- drm/amd/display: Request usb4 bw for mst streams
+- drm/amd/display: Add dpia display mode validation logic
+- mptcp: corner case locking for rx path fields initialization
+- mptcp: fix more tx path fields initialization
+- mptcp: use mptcp_set_state
+- mptcp: add CurrEstab MIB counter support
+- smb3: clarify mount warning
+- cifs: handle cases where multiple sessions share connection
+- cifs: change tcon status when need_reconnect is set on it
+- virtio-blk: Ensure no requests in virtqueues before deleting vqs.
+- smb: client: set correct d_type for reparse points under DFS mounts
+- drm/amdgpu: Fix HDP flush for VFs on nbio v7.9
+- drm/amdgpu: Fix shared buff copy to user
+- drm/amdgpu: reset gpu for s3 suspend abort case
+- drm/amdgpu: skip to program GFXDEC registers for suspend abort
+- libceph: fail sparse-read if the data length doesn't match
+- firewire: core: send bus reset promptly on gap count error
+- accel/ivpu/40xx: Stop passing SKU boot parameters to FW
+- accel/ivpu: Disable d3hot_delay on all NPU generations
+- accel/ivpu: Force snooping for MMU writes
+- LoongArch: vDSO: Disable UBSAN instrumentation
+- LoongArch: Change acpi_core_pic[NR_CPUS] to acpi_core_pic[MAX_CORE_PIC]
+- LoongArch: Select HAVE_ARCH_SECCOMP to use the common SECCOMP menu
+- LoongArch: Select ARCH_ENABLE_THP_MIGRATION instead of redefining it
+- scsi: ufs: core: Remove the ufshcd_release() in ufshcd_err_handling_prepare()
+- scsi: ufs: core: Fix shift issue in ufshcd_clear_cmd()
+- scsi: lpfc: Use unsigned type for num_sge
+- hwmon: (coretemp) Enlarge per package core count limit
+- efi: Don't add memblocks for soft-reserved memory
+- efi: runtime: Fix potential overflow of soft-reserved region size
+- wifi: iwlwifi: do not announce EPCS support
+- wifi: mac80211: accept broadcast probe responses on 6 GHz
+- wifi: mac80211: adding missing drv_mgd_complete_tx() call
+- wifi: mac80211: set station RX-NSS on reconfig
+- fs/ntfs3: Fix oob in ntfs_listxattr
+- fs/ntfs3: Update inode->i_size after success write into compressed file
+- fs/ntfs3: Fixed overflow check in mi_enum_attr()
+- fs/ntfs3: Correct function is_rst_area_valid
+- fs/ntfs3: Use i_size_read and i_size_write
+- fs/ntfs3: Prevent generic message "attempt to access beyond end of device"
+- fs/ntfs3: use non-movable memory for ntfs3 MFT buffer cache
+- fs/ntfs3: Use kvfree to free memory allocated by kvmalloc
+- fs/ntfs3: Disable ATTR_LIST_ENTRY size check
+- fs/ntfs3: Add NULL ptr dereference checking at the end of attr_allocate_frame()
+- fs/ntfs3: ntfs3_forced_shutdown use int instead of bool
+- fs/ntfs3: Implement super_operations::shutdown
+- fs/ntfs3: Drop suid and sgid bits as a part of fpunch
+- fs/ntfs3: Add file_modified
+- fs/ntfs3: Fix detected field-spanning write (size 8) of single field "le->name"
+- fs/ntfs3: Fix multithreaded stress test
+- fs/ntfs3: Reduce stack usage
+- fs/ntfs3: Print warning while fixing hard links count
+- fs/ntfs3: Correct hard links updating when dealing with DOS names
+- fs/ntfs3: Improve ntfs_dir_count
+- fs/ntfs3: Modified fix directory element type detection
+- fs/ntfs3: Improve alternative boot processing
+- Input: i8042 - add Fujitsu Lifebook U728 to i8042 quirk table
+- ext4: correct the hole length returned by ext4_map_blocks()
+- smb: client: increase number of PDUs allowed in a compound request
+- cifs: do not search for channel if server is terminating
+- nvmet-fc: take ref count on tgtport before delete assoc
+- nvmet-fc: avoid deadlock on delete association path
+- nvmet-fc: abort command when there is no binding
+- nvmet-fc: hold reference on hostport match
+- nvmet-fc: defer cleanup using RCU properly
+- nvmet-fc: release reference on target port
+- nvmet-fcloop: swap the list_add_tail arguments
+- nvme-fc: do not wait in vain when unloading module
+- ALSA: usb-audio: Ignore clock selector errors for single connection
+- ASoC: wm_adsp: Don't overwrite fwf_name with the default
+- cifs: make sure that channel scaling is done only once
+- drm/amd/display: increased min_dcfclk_mhz and min_fclk_mhz
+- drm/amdkfd: Use correct drm device for cgroup permission check
+- netfilter: conntrack: check SCTP_CID_SHUTDOWN_ACK for vtag setting in sctp_new
+- misc: open-dice: Fix spurious lockdep warning
+- Input: xpad - add Lenovo Legion Go controllers
+- spi: sh-msiof: avoid integer overflow in constants
+- regulator (max5970): Fix IRQ handler
+- ASoC: sunxi: sun4i-spdif: Add support for Allwinner H616
+- ALSA: usb-audio: Check presence of valid altsetting control
+- usb: ucsi_acpi: Quirk to ack a connector change ack cmd
+- nvmet-tcp: fix nvme tcp ida memory leak
+- HID: nvidia-shield: Add missing null pointer checks to LED initialization
+- ALSA: hda: Increase default bdl_pos_adj for Apollo Lake
+- ALSA: hda: Replace numeric device IDs with constant values
+- HID: logitech-hidpp: add support for Logitech G Pro X Superlight 2
+- regulator: pwm-regulator: Add validity checks in continuous .get_voltage
+- ASoC: amd: acp: Add check for cpu dai link initialization
+- dmaengine: ti: edma: Add some null pointer checks to the edma_probe
+- Input: goodix - accept ACPI resources with gpio_count == 3 && gpio_int_idx == 0
+- ext4: avoid allocating blocks from corrupted group in ext4_mb_find_by_goal()
+- ext4: avoid allocating blocks from corrupted group in ext4_mb_try_best_found()
+- ext4: avoid dividing by 0 in mb_update_avg_fragment_size() when block bitmap corrupt
+- platform/x86: touchscreen_dmi: Add info for the TECLAST X16 Plus tablet
+- MIPS: reserve exception vector space ONLY ONCE
+- ARM: dts: Fix TPM schema violations
+- ahci: add 43-bit DMA address quirk for ASMedia ASM1061 controllers
+- spi: cs42l43: Handle error from devm_pm_runtime_enable
+- aoe: avoid potential deadlock at set_capacity
+- ahci: asm1166: correct count of reported ports
+- cifs: helper function to check replayable error codes
+- cifs: translate network errors on send to -ECONNABORTED
+- cifs: cifs_pick_channel should try selecting active channels
+- smb: Work around Clang __bdos() type confusion
+- block: Fix WARNING in _copy_from_iter
+- spi: intel-pci: Add support for Arrow Lake SPI serial flash
+- platform/mellanox: mlxbf-tmfifo: Drop Tx network packet when Tx TmFIFO is full
+- fbdev: sis: Error out if pixclock equals zero
+- fbdev: savage: Error out if pixclock equals zero
+- wifi: mac80211: fix race condition on enabling fast-xmit
+- wifi: cfg80211: fix missing interfaces when dumping
+- dmaengine: dw-edma: increase size of 'name' in debugfs code
+- dmaengine: fsl-qdma: increase size of 'irq_name'
+- dmaengine: shdma: increase size of 'dev_id'
+- cifs: open_cached_dir should not rely on primary channel
+- scsi: target: core: Add TMF to tmr_list handling
+- tools: selftests: riscv: Fix compile warnings in mm tests
+- tools: selftests: riscv: Fix compile warnings in vector tests
+- scsi: smartpqi: Fix logical volume rescan race condition
+- scsi: smartpqi: Add new controller PCI IDs
+- dmaengine: apple-admac: Keep upper bits of REG_BUS_WIDTH
+- riscv/efistub: Ensure GP-relative addressing is not used
+- PCI: dwc: Fix a 64bit bug in dw_pcie_ep_raise_msix_irq()
+- sched/rt: Disallow writing invalid values to sched_rt_period_us
+- tracing: Fix a NULL vs IS_ERR() bug in event_subsystem_dir()
+- tracing: Make system_callback() function static
+- Documentation/arch/ia64/features.rst: fix kernel-feat directive
+- nilfs2: fix potential bug in end_buffer_async_write
+- of: property: Add in-ports/out-ports support to of_graph_get_port_parent()
+- sched/membarrier: reduce the ability to hammer on sys_membarrier
+- x86/efistub: Use 1:1 file:memory mapping for PE/COFF .compat section
+- x86/boot: Increase section and file alignment to 4k/512
+- x86/boot: Split off PE/COFF .data section
+- x86/boot: Drop PE/COFF .reloc section
+- x86/boot: Construct PE/COFF .text section from assembler
+- x86/boot: Derive file size from _edata symbol
+- x86/boot: Define setup size in linker script
+- x86/boot: Set EFI handover offset directly in header asm
+- x86/boot: Grab kernel_info offset from zoffset header directly
+- x86/boot: Drop references to startup_64
+- x86/boot: Drop redundant code setting the root device
+- x86/boot: Omit compression buffer from PE/COFF image memory footprint
+- x86/boot: Remove the 'bugger off' message
+- x86/efi: Drop alignment flags from PE section headers
+- x86/efi: Disregard setup header of loaded image
+- x86/efi: Drop EFI stub .bss from .data section
+- nfsd: don't take fi_lock in nfsd_break_deleg_cb()
+- eventfs: Keep all directory links at 1
+- eventfs: Remove fsnotify*() functions from lookup()
+- eventfs: Restructure eventfs_inode structure to be more condensed
+- eventfs: Warn if an eventfs_inode is freed without is_freed being set
+- eventfs: Get rid of dentry pointers without refcounts
+- eventfs: Clean up dentry ops and add revalidate function
+- eventfs: Remove unused d_parent pointer field
+- tracefs: dentry lookup crapectomy
+- tracefs: Avoid using the ei->dentry pointer unnecessarily
+- eventfs: Initialize the tracefs inode properly
+- tracefs: Zero out the tracefs_inode when allocating it
+- tracefs: remove stale update_gid code
+- eventfs: Save directory inodes in the eventfs_inode structure
+- eventfs: Use kcalloc() instead of kzalloc()
+- eventfs: Do not create dentries nor inodes in iterate_shared
+- eventfs: Have the inodes all for files and directories all be the same
+- eventfs: Shortcut eventfs_iterate() by skipping entries already read
+- eventfs: Read ei->entries before ei->children in eventfs_iterate()
+- eventfs: Do ctx->pos update for all iterations in eventfs_iterate()
+- eventfs: Have eventfs_iterate() stop immediately if ei->is_freed is set
+- tracefs/eventfs: Use root and instance inodes as default ownership
+- eventfs: Stop using dcache_readdir() for getdents()
+- eventfs: Remove "lookup" parameter from create_dir/file_dentry()
+- eventfs: Fix bitwise fields for "is_events"
+- tracefs: Check for dentry->d_inode exists in set_gid()
+- eventfs: Fix file and directory uid and gid ownership
+- eventfs: Have event files and directories default to parent uid and gid
+- eventfs: Fix events beyond NAME_MAX blocking tasks
+- eventfs: Make sure that parent->d_inode is locked in creating files/dirs
+- eventfs: Do not allow NULL parent to eventfs_start_creating()
+- eventfs: Move taking of inode_lock into dcache_dir_open_wrapper()
+- eventfs: Use GFP_NOFS for allocation when eventfs_mutex is held
+- eventfs: Do not invalidate dentry in create_file/dir_dentry()
+- eventfs: Remove expectation that ei->is_freed means ei->dentry == NULL
+- eventfs: Use simple_recursive_removal() to clean up dentries
+- eventfs: Remove special processing of dput() of events directory
+- eventfs: Delete eventfs_inode when the last dentry is freed
+- eventfs: Hold eventfs_mutex when calling callback functions
+- eventfs: Save ownership and mode
+- eventfs: Test for ei->is_freed when accessing ei->dentry
+- eventfs: Have a free_ei() that just frees the eventfs_inode
+- eventfs: Remove "is_freed" union with rcu head
+- eventfs: Fix kerneldoc of eventfs_remove_rec()
+- eventfs: Remove extra dget() in eventfs_create_events_dir()
+- eventfs: Fix typo in eventfs_inode union comment
+- eventfs: Fix WARN_ON() in create_file_dentry()
+- tracefs/eventfs: Modify mismatched function name
+- eventfs: Fix failure path in eventfs_create_events_dir()
+- eventfs: Use ERR_CAST() in eventfs_create_events_dir()
+- eventfs: Use eventfs_remove_events_dir()
+- eventfs: Remove eventfs_file and just use eventfs_inode
+- Revert "eventfs: Remove "is_freed" union with rcu head"
+- Revert "eventfs: Save ownership and mode"
+- Revert "eventfs: Delete eventfs_inode when the last dentry is freed"
+- Revert "eventfs: Use simple_recursive_removal() to clean up dentries"
+- Revert "eventfs: Check for NULL ef in eventfs_set_attr()"
+- Revert "eventfs: Do not allow NULL parent to eventfs_start_creating()"
+- parisc: Fix random data corruption from exception handler
+- netfilter: ipset: Missing gc cancellations fixed
+- netfilter: ipset: fix performance regression in swap operation
+- block: fix partial zone append completion handling in req_bio_endio()
+- tracing: Inform kmemleak of saved_cmdlines allocation
+- tracing: Fix HAVE_DYNAMIC_FTRACE_WITH_REGS ifdef
+- fs/proc: do_task_stat: move thread_group_cputime_adjusted() outside of lock_task_sighand()
+- pmdomain: core: Move the unused cleanup to a _sync initcall
+- can: j1939: Fix UAF in j1939_sk_match_filter during setsockopt(SO_J1939_FILTER)
+- can: j1939: prevent deadlock by changing j1939_socks_lock to rwlock
+- can: netlink: Fix TDCO calculation using the old data bittiming
+- of: property: fix typo in io-channels
+- docs: kernel_feat.py: fix build error for missing files
+- blk-wbt: Fix detection of dirty-throttled tasks
+- LoongArch: Fix earlycon parameter if KASAN enabled
+- mm: hugetlb pages should not be reserved by shmat() if SHM_NORESERVE
+- ceph: prevent use-after-free in encode_cap_msg()
+- hv_netvsc: Register VF in netvsc_probe if NET_DEVICE_REGISTER missed
+- net: stmmac: protect updates of 64-bit statistics counters
+- pmdomain: renesas: r8a77980-sysc: CR7 must be always on
+- net: ethernet: ti: cpsw_new: enable mac_managed_pm to fix mdio
+- s390/qeth: Fix potential loss of L3-IP@ in case of network issues
+- net: ethernet: ti: cpsw: enable mac_managed_pm to fix mdio
+- fs: relax mount_setattr() permission checks
+- tools/rtla: Fix Makefile compiler options for clang
+- tools/rtla: Fix uninitialized bucket/data->bucket_size warning
+- tools/rtla: Exit with EXIT_SUCCESS when help is invoked
+- tools/rtla: Fix clang warning about mount_point var size
+- tools/rtla: Replace setting prio with nice for SCHED_OTHER
+- tools/rtla: Remove unused sched_getattr() function
+- tools/rv: Fix Makefile compiler options for clang
+- tools/rv: Fix curr_reactor uninitialized variable
+- ASoC: amd: yc: Add DMI quirk for Lenovo Ideapad Pro 5 16ARP8
+- ASoC: tas2781: add module parameter to tascodec_init()
+- ASoC: SOF: IPC3: fix message bounds on ipc ops
+- arm64: Subscribe Microsoft Azure Cobalt 100 to ARM Neoverse N2 errata
+- arm64/signal: Don't assume that TIF_SVE means we saved SVE state
+- mmc: sdhci-pci-o2micro: Fix a warm reboot issue that disk can't be detected by BIOS
+- zonefs: Improve error handling
+- KVM: arm64: Fix circular locking dependency
+- smb: Fix regression in writes when non-standard maximum write size negotiated
+- smb: client: set correct id, uid and cruid for multiuser automounts
+- thunderbolt: Fix setting the CNS bit in ROUTER_CS_5
+- irqchip/gic-v3-its: Fix GICv4.1 VPE affinity update
+- irqchip/gic-v3-its: Restore quirk probing for ACPI-based systems
+- irqchip/irq-brcmstb-l2: Add write memory barrier before exit
+- wifi: iwlwifi: mvm: fix a crash when we run out of stations
+- wifi: mac80211: reload info pointer in ieee80211_tx_dequeue()
+- wifi: cfg80211: fix wiphy delayed work queueing
+- wifi: iwlwifi: fix double-free bug
+- nfp: flower: prevent re-adding mac index for bonded port
+- nfp: enable NETDEV_XDP_ACT_REDIRECT feature flag
+- nfp: use correct macro for LengthSelect in BAR config
+- crypto: algif_hash - Remove bogus SGL free on zero-length error path
+- crypto: ccp - Fix null pointer dereference in __sev_platform_shutdown_locked
+- nilfs2: fix hang in nilfs_lookup_dirty_data_buffers()
+- nilfs2: fix data corruption in dsync block recovery for small block sizes
+- ALSA: hda/realtek: add IDs for Dell dual spk platform
+- ALSA: hda/conexant: Add quirk for SWS JS201D
+- ALSA: hda/realtek: fix mute/micmute LED For HP mt645
+- mmc: slot-gpio: Allow non-sleeping GPIO ro
+- io_uring/net: fix multishot accept overflow handling
+- x86/mm/ident_map: Use gbpages only where full GB page should be mapped.
+- KVM: x86/pmu: Fix type length error when reading pmu->fixed_ctr_ctrl
+- KVM: x86: make KVM_REQ_NMI request iff NMI pending for vcpu
+- x86/Kconfig: Transmeta Crusoe is CPU family 5, not 6
+- serial: mxs-auart: fix tx
+- serial: core: introduce uart_port_tx_flags()
+- powerpc/pseries: fix accuracy of stolen time
+- powerpc/cputable: Add missing PPC_FEATURE_BOOKE on PPC64 Book-E
+- powerpc/64: Set task pt_regs->link to the LR value on scv entry
+- ftrace: Fix DIRECT_CALLS to use SAVE_REGS by default
+- serial: max310x: prevent infinite while() loop in port startup
+- serial: max310x: fail probe if clock crystal is unstable
+- serial: max310x: improve crystal stable clock detection
+- serial: max310x: set default value when reading clock ready bit
+- nfp: flower: fix hardware offload for the transfer layer port
+- nfp: flower: add hardware offload check for post ct entry
+- net: dsa: mv88e6xxx: Fix failed probe due to unsupported C45 reads
+- ring-buffer: Clean ring_buffer_poll_wait() error return
+- hv_netvsc: Fix race condition between netvsc_probe and netvsc_remove
+- drm/amd/display: Preserve original aspect ratio in create stream
+- drm/amd/display: Increase frame-larger-than for all display_mode_vba files
+- drm/amd/display: Fix MST Null Ptr for RV
+- drm/amdgpu/soc21: update VCN 4 max HEVC encoding resolution
+- drm/prime: Support page array >= 4GB
+- drm/amd/display: Add align done check
+- drm/msm: Wire up tlb ops
+- ksmbd: free aux buffer if ksmbd_iov_pin_rsp_read fails
+- media: rc: bpf attach/detach requires write permission
+- pmdomain: mediatek: fix race conditions with genpd
+- iio: pressure: bmp280: Add missing bmp085 to SPI id table
+- iio: imu: bno055: serdev requires REGMAP
+- iio: imu: adis: ensure proper DMA alignment
+- iio: adc: ad_sigma_delta: ensure proper DMA alignment
+- iio: accel: bma400: Fix a compilation problem
+- iio: commom: st_sensors: ensure proper DMA alignment
+- iio: core: fix memleak in iio_device_register_sysfs
+- iio: magnetometer: rm3100: add boundary check for the value read from RM3100_REG_TMRC
+- staging: iio: ad5933: fix type mismatch regression
+- tracing/probes: Fix to search structure fields correctly
+- tracing/probes: Fix to set arg size and fmt after setting type from BTF
+- tracing/probes: Fix to show a parse error for bad type for $comm
+- tracing/synthetic: Fix trace_string() return value
+- tracing: Fix wasted memory in saved_cmdlines logic
+- tracing/timerlat: Move hrtimer_init to timerlat_fd open()
+- ext4: avoid bb_free and bb_fragments inconsistency in mb_free_blocks()
+- ext4: fix double-free of blocks due to wrong extents moved_len
+- misc: fastrpc: Mark all sessions as invalid in cb_remove
+- binder: signal epoll threads of self-work
+- ALSA: hda/realtek: fix mute/micmute LEDs for HP ZBook Power
+- ALSA: hda/cs8409: Suppress vmaster control for Dolphin models
+- ASoC: codecs: wcd938x: handle deferred probe
+- ALSA: hda/realtek - Add speaker pin verbtable for Dell dual speaker platform
+- ALSA: hda/realtek: Enable headset mic on Vaio VJFE-ADL
+- usb: typec: tpcm: Fix issues with power being removed during reset
+- modpost: Add '.ltext' and '.ltext.*' to TEXT_SECTIONS
+- linux/init: remove __memexit* annotations
+- um: Fix adding '-no-pie' for clang
+- xen-netback: properly sync TX responses
+- parisc: BTLB: Fix crash when setting up BTLB at CPU bringup
+- net: stmmac: do not clear TBS enable bit on link up/down
+- net: hsr: remove WARN_ONCE() in send_hsr_supervision_frame()
+- nfc: nci: free rx_data_reassembly skb on NCI device cleanup
+- kbuild: Fix changing ELF file type for output of gen_btf for big endian
+- ALSA: hda/realtek: Apply headset jack quirk for non-bass alc287 thinkpads
+- firewire: core: correct documentation of fw_csr_string() kernel API
+- lsm: fix the logic in security_inode_getsecctx()
+- lsm: fix default return value of the socket_getpeersec_*() hooks
+- drm/amd: Don't init MEC2 firmware when it fails to load
+- drm/amdgpu: Reset IH OVERFLOW_CLEAR bit
+- drm/virtio: Set segment size for virtio_gpu device
+- connector/cn_proc: revert "connector: Fix proc_event_num_listeners count not cleared"
+- Revert "drm/msm/gpu: Push gpu lock down past runpm"
+- Revert "drm/amd: flush any delayed gfxoff on suspend entry"
+- scsi: Revert "scsi: fcoe: Fix potential deadlock on &fip->ctlr_lock"
+- media: Revert "media: rkisp1: Drop IRQF_SHARED"
+- Revert "powerpc/pseries/iommu: Fix iommu initialisation during DLPAR add"
+- mptcp: really cope with fastopen race
+- mptcp: check addrs list in userspace_pm_get_local_id
+- mptcp: fix rcv space initialization
+- mptcp: drop the push_pending field
+- selftests: mptcp: add mptcp_lib_kill_wait
+- selftests: mptcp: allow changing subtests prefix
+- selftests: mptcp: increase timeout to 30 min
+- selftests: mptcp: add missing kconfig for NF Mangle
+- selftests: mptcp: add missing kconfig for NF Filter in v6
+- selftests: mptcp: add missing kconfig for NF Filter
+- mptcp: fix data re-injection from stale subflow
+- kallsyms: ignore ARMv4 thunks along with others
+- modpost: trim leading spaces when processing source files list
+- i2c: i801: Fix block process call transactions
+- i2c: pasemi: split driver into two separate modules
+- powerpc/kasan: Limit KASAN thread size increase to 32KB
+- irqchip/gic-v3-its: Handle non-coherent GICv4 redistributors
+- i2c: qcom-geni: Correct I2C TRE sequence
+- cifs: fix underflow in parse_server_interfaces()
+- iio: adc: ad4130: only set GPIO_CTRL if pin is unused
+- iio: adc: ad4130: zero-initialize clock init data
+- PCI: Fix active state requirement in PME polling
+- Revert "kobject: Remove redundant checks for whether ktype is NULL"
+- powerpc/kasan: Fix addr error caused by page alignment
+- powerpc/6xx: set High BAT Enable flag on G2_LE cores
+- powerpc/pseries/iommu: Fix iommu initialisation during DLPAR add
+- driver core: fw_devlink: Improve detection of overlapping cycles
+- media: ir_toy: fix a memleak in irtoy_tx
+- interconnect: qcom: sm8550: Enable sync_state
+- interconnect: qcom: sc8180x: Mark CO0 BCM keepalive
+- usb: dwc3: gadget: Fix NULL pointer dereference in dwc3_gadget_suspend
+- usb: core: Prevent null pointer dereference in update_port_device_state
+- usb: chipidea: core: handle power lost in workqueue
+- usb: f_mass_storage: forbid async queue when shutdown happen
+- USB: hub: check for alternate port before enabling A_ALT_HNP_SUPPORT
+- usb: ucsi_acpi: Fix command completion handling
+- usb: ulpi: Fix debugfs directory leak
+- usb: ucsi: Add missing ppm_lock
+- iio: hid-sensor-als: Return 0 for HID_USAGE_SENSOR_TIME_TIMESTAMP
+- HID: wacom: Do not register input devices until after hid_hw_start
+- HID: wacom: generic: Avoid reporting a serial of '0' to userspace
+- HID: i2c-hid-of: fix NULL-deref on failed power up
+- HID: bpf: actually free hdev memory after attaching a HID-BPF program
+- HID: bpf: remove double fdget()
+- ALSA: hda/realtek: Enable Mute LED on HP Laptop 14-fq0xxx
+- ALSA: hda/realtek: Fix the external mic not being recognised for Acer Swift 1 SF114-32
+- parisc: Prevent hung tasks when printing inventory on serial console
+- ASoC: amd: yc: Add DMI quirk for MSI Bravo 15 C7VF
+- dm-crypt, dm-verity: disable tasklets
+- nouveau: offload fence uevents work to workqueue
+- scsi: storvsc: Fix ring buffer size calculation
+- selftests: mm: fix map_hugetlb failure on 64K page size systems
+- selftests/mm: Update va_high_addr_switch.sh to check CPU for la57 flag
+- mm/writeback: fix possible divide-by-zero in wb_dirty_limits(), again
+- selftests/mm: switch to bash from sh
+- tracing/trigger: Fix to return error if failed to alloc snapshot
+- scs: add CONFIG_MMU dependency for vfree_atomic()
+- selftests/mm: ksm_tests should only MADV_HUGEPAGE valid memory
+- userfaultfd: fix mmap_changing checking in mfill_atomic_hugetlb
+- i40e: Fix waiting for queues of all VSIs to be disabled
+- i40e: Do not allow untrusted VF to remove administratively set MAC
+- mm/memory: Use exception ip to search exception tables
+- ptrace: Introduce exception_ip arch hook
+- MIPS: Add 'memory' clobber to csum_ipv6_magic() inline assembler
+- nouveau/svm: fix kvcalloc() argument order
+- net: sysfs: Fix /sys/class/net/<iface> path for statistics
+- ASoC: rt5645: Fix deadlock in rt5645_jack_detect_work()
+- spi: ppc4xx: Drop write-only variable
+- net: tls: fix returned read length with async decrypt
+- net: tls: fix use-after-free with partial reads and async decrypt
+- net: tls: handle backlogging of crypto requests
+- tls: fix race between tx work scheduling and socket close
+- tls: fix race between async notify and socket close
+- net: tls: factor out tls_*crypt_async_wait()
+- tls: extract context alloc/initialization out of tls_set_sw_offload
+- lan966x: Fix crash when adding interface under a lag
+- net: openvswitch: limit the number of recursions from action sets
+- selftests: forwarding: Fix bridge locked port test flakiness
+- selftests: forwarding: Suppress grep warnings
+- selftests: bridge_mdb: Use MDB get instead of dump
+- selftests: forwarding: Fix bridge MDB test flakiness
+- selftests: forwarding: Fix layer 2 miss test flakiness
+- selftests: net: Fix bridge backup port test flakiness
+- selftests/net: convert test_bridge_backup_port.sh to run it in unique namespace
+- perf: CXL: fix mismatched cpmu event opcode
+- ALSA: hda/cs35l56: select intended config FW_CS_DSP
+- of: property: Improve finding the supplier of a remote-endpoint property
+- of: property: Improve finding the consumer of a remote-endpoint property
+- devlink: Fix command annotation documentation
+- bonding: do not report NETDEV_XDP_ACT_XSK_ZEROCOPY
+- net/handshake: Fix handshake_req_destroy_test1
+- ASoC: SOF: ipc3-topology: Fix pipeline tear down logic
+- wifi: iwlwifi: uninitialized variable in iwl_acpi_get_ppag_table()
+- wifi: iwlwifi: Fix some error codes
+- KVM: selftests: Fix a semaphore imbalance in the dirty ring logging test
+- spi: imx: fix the burst length at DMA mode and CPU mode
+- drm/msm/gem: Fix double resv lock aquire
+- of: unittest: Fix compile in the non-dynamic case
+- KVM: selftests: Avoid infinite loop in hyperv_features when invtsc is missing
+- KVM: selftests: Delete superfluous, unused "stage" variable in AMX test
+- selftests/landlock: Fix fs_test build with old libc
+- driver core: Fix device_link_flag_is_sync_state_only()
+- btrfs: don't drop extent_map for free space inode on write error
+- btrfs: reject encoded write if inode has nodatasum flag set
+- btrfs: don't reserve space for checksums when writing to nocow files
+- btrfs: send: return EOPNOTSUPP on unknown flags
+- btrfs: forbid deleting live subvol qgroup
+- btrfs: do not ASSERT() if the newly created subvolume already got read
+- btrfs: forbid creating subvol qgroups
+- btrfs: do not delete unused block group if it may be used soon
+- btrfs: add and use helper to check if block group is used
+- update workarounds for gcc "asm goto" issue
+- work around gcc bugs with 'asm goto' with outputs
+- netfilter: nft_set_rbtree: skip end interval element from gc
+- net: stmmac: xgmac: fix a typo of register name in DPP safety handling
+- ALSA: usb-audio: Sort quirk table entries
+- net: stmmac: xgmac: use #define for string constants
+- io_uring/net: limit inline multishot retries
+- io_uring/poll: add requeue return code from poll multishot handling
+- io_uring/net: un-indent mshot retry path in io_recv_finish()
+- io_uring/poll: move poll execution helpers higher up
+- io_uring/net: fix sr->len for IORING_OP_RECV with MSG_WAITALL and buffers
+- media: solo6x10: replace max(a, min(b, c)) by clamp(b, a, c)
+- Revert "ASoC: amd: Add new dmi entries for acp5x platform"
+- Input: atkbd - skip ATKBD_CMD_SETLEDS when skipping ATKBD_CMD_GETID
+- Input: i8042 - fix strange behavior of touchpad on Clevo NS70PU
+- hrtimer: Report offline hrtimer enqueue
+- usb: dwc3: pci: add support for the Intel Arrow Lake-H
+- xhci: handle isoc Babble and Buffer Overrun events properly
+- xhci: process isoc TD properly when there was a transaction error mid TD.
+- usb: host: xhci-plat: Add support for XHCI_SG_TRB_CACHE_SIZE_QUIRK
+- usb: dwc3: host: Set XHCI_SG_TRB_CACHE_SIZE_QUIRK
+- x86/lib: Revert to _ASM_EXTABLE_UA() for {get,put}_user() fixups
+- Revert "usb: typec: tcpm: fix cc role at port reset"
+- USB: serial: cp210x: add ID for IMST iM871A-USB
+- USB: serial: option: add Fibocom FM101-GL variant
+- USB: serial: qcserial: add new usb-id for Dell Wireless DW5826e
+- ALSA: usb-audio: add quirk for RODE NT-USB+
+- ALSA: usb-audio: Add a quirk for Yamaha YIT-W12TX transmitter
+- ALSA: usb-audio: Add delay quirk for MOTU M Series 2nd revision
+- blk-iocost: Fix an UBSAN shift-out-of-bounds warning
+- riscv: declare overflow_stack as exported from traps.c
+- riscv: Fix arch_hugetlb_migration_supported() for NAPOT
+- libceph: just wait for more data to be available on the socket
+- libceph: rename read_sparse_msg_*() to read_partial_sparse_msg_*()
+- riscv: Flush the tlb when a page directory is freed
+- scsi: core: Move scsi_host_busy() out of host lock if it is for per-command
+- riscv: Fix hugetlb_mask_last_page() when NAPOT is enabled
+- riscv: Fix set_huge_pte_at() for NAPOT mapping
+- riscv: mm: execute local TLB flush after populating vmemmap
+- mm: Introduce flush_cache_vmap_early()
+- riscv: Improve flush_tlb_kernel_range()
+- riscv: Make __flush_tlb_range() loop over pte instead of flushing the whole tlb
+- riscv: Improve tlb_flush()
+- fs/ntfs3: Fix an NULL dereference bug
+- netfilter: nft_set_pipapo: remove scratch_aligned pointer
+- netfilter: nft_set_pipapo: add helper to release pcpu scratch area
+- netfilter: nft_set_pipapo: store index in scratch maps
+- netfilter: nft_ct: reject direction for ct id
+- drm/amd/display: Implement bounds check for stream encoder creation in DCN301
+- drm/amd/display: Add NULL test for 'timing generator' in 'dcn21_set_pipe()'
+- drm/amd/display: Fix 'panel_cntl' could be null in 'dcn21_set_backlight_level()'
+- netfilter: nft_compat: restrict match/target protocol to u16
+- netfilter: nft_compat: reject unused compat flag
+- netfilter: nft_compat: narrow down revision to unsigned 8-bits
+- selftests: cmsg_ipv6: repeat the exact packet
+- ppp_async: limit MRU to 64K
+- af_unix: Call kfree_skb() for dead unix_(sk)->oob_skb in GC.
+- tipc: Check the bearer type before calling tipc_udp_nl_bearer_add()
+- selftests: net: let big_tcp test cope with slow env
+- rxrpc: Fix counting of new acks and nacks
+- rxrpc: Fix response to PING RESPONSE ACKs to a dead call
+- rxrpc: Fix delayed ACKs to not set the reference serial number
+- rxrpc: Fix generation of serial numbers to skip zero
+- drm/i915/gvt: Fix uninitialized variable in handle_mmio()
+- inet: read sk->sk_family once in inet_recv_error()
+- hwmon: (coretemp) Fix bogus core_id to attr name mapping
+- hwmon: (coretemp) Fix out-of-bounds memory access
+- hwmon: (aspeed-pwm-tacho) mutex for tach reading
+- octeontx2-pf: Fix a memleak otx2_sq_init
+- atm: idt77252: fix a memleak in open_card_ubr0
+- tunnels: fix out of bounds access when building IPv6 PMTU error
+- tsnep: Fix mapping for zero copy XDP_TX action
+- selftests: net: avoid just another constant wait
+- selftests: net: fix tcp listener handling in pmtu.sh
+- selftests/net: change shebang to bash to support "source"
+- selftests/net: convert pmtu.sh to run it in unique namespace
+- selftests/net: convert unicast_extensions.sh to run it in unique namespace
+- selftests: net: cut more slack for gro fwd tests.
+- net: atlantic: Fix DMA mapping for PTP hwts ring
+- netdevsim: avoid potential loop in nsim_dev_trap_report_work()
+- wifi: brcmfmac: Adjust n_channels usage for __counted_by
+- wifi: iwlwifi: exit eSR only after the FW does
+- wifi: mac80211: fix waiting for beacons logic
+- wifi: mac80211: fix RCU use in TDLS fast-xmit
+- net: stmmac: xgmac: fix handling of DPP safety error for DMA channels
+- x86/efistub: Avoid placing the kernel below LOAD_PHYSICAL_ADDR
+- x86/efistub: Give up if memory attribute protocol returns an error
+- drm/msm/dpu: check for valid hw_pp in dpu_encoder_helper_phys_cleanup
+- drm/msm/dp: return correct Colorimetry for DP_TEST_DYNAMIC_RANGE_CEA case
+- drm/msms/dp: fixed link clock divider bits be over written in BPC unknown case
+- xfs: respect the stable writes flag on the RT device
+- xfs: clean up FS_XFLAG_REALTIME handling in xfs_ioctl_setattr_xflags
+- xfs: dquot recovery does not validate the recovered dquot
+- xfs: clean up dqblk extraction
+- xfs: inode recovery does not validate the recovered inode
+- xfs: fix again select in kconfig XFS_ONLINE_SCRUB_STATS
+- xfs: fix internal error from AGFL exhaustion
+- xfs: up(ic_sema) if flushing data device fails
+- xfs: only remap the written blocks in xfs_reflink_end_cow_extent
+- xfs: allow read IO and FICLONE to run concurrently
+- xfs: handle nimaps=0 from xfs_bmapi_write in xfs_alloc_file_space
+- xfs: introduce protection for drop nlink
+- xfs: make sure maxlen is still congruent with prod when rounding down
+- xfs: fix units conversion error in xfs_bmap_del_extent_delay
+- xfs: rt stubs should return negative errnos when rt disabled
+- xfs: prevent rt growfs when quota is enabled
+- xfs: hoist freeing of rt data fork extent mappings
+- xfs: bump max fsgeom struct version
+- MAINTAINERS: add Catherine as xfs maintainer for 6.6.y
+- rust: upgrade to Rust 1.73.0
+- rust: print: use explicit link in documentation
+- rust: task: remove redundant explicit link
+- rust: upgrade to Rust 1.72.1
+- rust: arc: add explicit `drop()` around `Box::from_raw()`
+- cifs: failure to add channel on iface should bump up weight
+- cifs: avoid redundant calls to disable multichannel
+- phy: ti: phy-omap-usb2: Fix NULL pointer dereference for SRP
+- dmaengine: fix is_slave_direction() return false when DMA_DEV_TO_DEV
+- perf evlist: Fix evlist__new_default() for > 1 core PMU
+- phy: renesas: rcar-gen3-usb2: Fix returning wrong error code
+- dmaengine: fsl-qdma: Fix a memory leak related to the queue command DMA
+- dmaengine: fsl-qdma: Fix a memory leak related to the status queue DMA
+- dmaengine: ti: k3-udma: Report short packet errors
+- dmaengine: fsl-dpaa2-qdma: Fix the size of dma pools
+- pds_core: Prevent health thread from running during reset/remove
+- drm/amdgpu: Fix missing error code in 'gmc_v6/7/8/9_0_hw_init()'
+- ASoC: codecs: wsa883x: fix PA volume control
+- ASoC: codecs: lpass-wsa-macro: fix compander volume hack
+- ASoC: codecs: wcd938x: fix headphones volume controls
+- ASoC: qcom: sc8280xp: limit speaker volumes
+- bonding: remove print in bond_verify_device_path
+- selftests/bpf: Remove flaky test_btf_id test
+- LoongArch/smp: Call rcutree_report_cpu_starting() at tlb_init()
+- drm/msm/dsi: Enable runtime PM
+- Revert "drm/amd/display: Disable PSR-SU on Parade 0803 TCON again"
+- mm, kmsan: fix infinite recursion due to RCU critical section
+- arm64: irq: set the correct node for shadow call stack
+- selftests: net: enable some more knobs
+- selftests: net: add missing config for NF_TARGET_TTL
+- selftests: bonding: Check initial state
+- selftests: team: Add missing config options
+- net: sysfs: Fix /sys/class/net/<iface> path
+- octeontx2-pf: Remove xdp queues on program detach
+- selftests: net: don't access /dev/stdout in pmtu.sh
+- selftests: net: fix available tunnels detection
+- selftests: net: add missing config for pmtu.sh tests
+- selftests: net: add missing config for nftables-backed iptables
+- pds_core: Rework teardown/setup flow to be more common
+- pds_core: Clear BARs on reset
+- pds_core: Prevent race issues involving the adminq
+- pds_core: implement pci reset handlers
+- pds_core: Use struct pdsc for the pdsc_adminq_isr private data
+- pds_core: Cancel AQ work on teardown
+- af_unix: fix lockdep positive in sk_diag_dump_icons()
+- net: ipv4: fix a memleak in ip_setup_cork
+- netfilter: nft_ct: sanitize layer 3 and 4 protocol number in custom expectations
+- netfilter: nf_log: replace BUG_ON by WARN_ON_ONCE when putting logger
+- netfilter: nf_tables: restrict tunnel object to NFPROTO_NETDEV
+- netfilter: conntrack: correct window scaling with retransmitted SYN
+- selftests: net: add missing config for GENEVE
+- devlink: Fix referring to hw_addr attribute during state validation
+- bridge: mcast: fix disabled snooping after long uptime
+- selftests: net: Add missing matchall classifier
+- llc: call sock_orphan() at release time
+- ipv6: Ensure natural alignment of const ipv6 loopback and router addresses
+- net: dsa: qca8k: fix illegal usage of GPIO
+- ixgbe: Fix an error handling path in ixgbe_read_iosf_sb_reg_x550()
+- ixgbe: Refactor overtemp event handling
+- ixgbe: Refactor returning internal error codes
+- e1000e: correct maximum frequency adjustment values
+- tcp: add sanity checks to rx zerocopy
+- net: lan966x: Fix port configuration when using SGMII interface
+- ipmr: fix kernel panic when forwarding mcast packets
+- net: dsa: mt7530: fix 10M/100M speed on MT7988 switch
+- ip6_tunnel: make sure to pull inner header in __ip6_tnl_rcv()
+- selftests: net: give more time for GRO aggregation
+- selftests: net: add missing required classifier
+- selftests: net: add missing config for big tcp tests
+- net: phy: mediatek-ge-soc: sync driver with MediaTek SDK
+- net: ethernet: mtk_eth_soc: set DMA coherent mask to get PPE working
+- gve: Fix skb truesize underestimation
+- selftests: net: explicitly wait for listener ready
+- selftests: net: remove dependency on ebpf tests
+- HID: hidraw: fix a problem of memory leak in hidraw_release()
+- scsi: core: Move scsi_host_busy() out of host lock for waking up EH handler
+- regulator: ti-abb: don't use devm_platform_ioremap_resource_byname for shared interrupt register
+- kunit: run test suites only after module initialization completes
+- scsi: isci: Fix an error code problem in isci_io_request_build()
+- riscv: Fix build error on rv32 + XIP
+- drm/amdkfd: only flush mes process context if mes support is there
+- drm: using mul_u32_u32() requires linux/math64.h
+- wifi: cfg80211: fix RCU dereference in __cfg80211_bss_update
+- perf: Fix the nr_addr_filters fix
+- i2c: rk3x: Adjust mask/value offset for i2c2 on rv1126
+- drm/amdkfd: Fix 'node' NULL check in 'svm_range_get_range_boundaries()'
+- drm/amdgpu: Release 'adev->pm.fw' before return in 'amdgpu_device_need_post()'
+- drm/amdgpu: Fix with right return code '-EIO' in 'amdgpu_gmc_vram_checking()'
+- drm/amd/powerplay: Fix kzalloc parameter 'ATOM_Tonga_PPM_Table' in 'get_platform_power_management_table()'
+- drm/amdgpu: fix avg vs input power reporting on smu7
+- ceph: fix invalid pointer access if get_quota_realm return ERR_PTR
+- ceph: reinitialize mds feature bit even when session in open
+- virtio_net: Fix "‘%d’ directive writing between 1 and 11 bytes into a region of size 10" warnings
+- drm/amdkfd: Fix lock dependency warning with srcu
+- drm/amdkfd: Fix lock dependency warning
+- libsubcmd: Fix memory leak in uniq()
+- misc: lis3lv02d_i2c: Add missing setting of the reg_ctrl callback
+- usb: xhci-plat: fix usb disconnect issue after s4
+- 9p: Fix initialisation of netfs_inode for 9p
+- PCI/AER: Decode Requester ID when no error info found
+- PCI: Fix 64GT/s effective data rate calculation
+- spmi: mediatek: Fix UAF on device remove
+- fs/kernfs/dir: obey S_ISGID
+- tty: allow TIOCSLCKTRMIOS with CAP_CHECKPOINT_RESTORE
+- selftests/sgx: Fix linker script asserts
+- usb: hub: Add quirk to decrease IN-ep poll interval for Microchip USB491x hub
+- usb: hub: Replace hardcoded quirk value with BIT() macro
+- extcon: fix possible name leak in extcon_dev_register()
+- perf cs-etm: Bump minimum OpenCSD version to ensure a bugfix is present
+- PCI: switchtec: Fix stdev_release() crash after surprise hot remove
+- PCI: Only override AMD USB controller if required
+- mailbox: arm_mhuv2: Fix a bug for mhuv2_sender_interrupt
+- mfd: ti_am335x_tscadc: Fix TI SoC dependencies
+- xen/gntdev: Fix the abuse of underlying struct page in DMA-buf import
+- riscv: Make XIP bootable again
+- i3c: master: cdns: Update maximum prescaler value for i2c clock
+- um: time-travel: fix time corruption
+- um: net: Fix return type of uml_net_start_xmit()
+- um: Don't use vfprintf() for os_info()
+- um: Fix naming clash between UML and scheduler
+- leds: trigger: panic: Don't register panic notifier if creating the trigger failed
+- pinctrl: baytrail: Fix types of config value in byt_pin_config_set()
+- ALSA: hda/conexant: Fix headset auto detect fail in cx8070 and SN6140
+- drm/amdgpu: apply the RV2 system aperture fix to RN/CZN as well
+- drm/amdkfd: Fix iterator used outside loop in 'kfd_add_peer_prop()'
+- drm/amdgpu: Drop 'fence' check in 'to_amdgpu_amdkfd_fence()'
+- drm/amdgpu: Fix '*fw' from request_firmware() not released in 'amdgpu_ucode_request()'
+- Re-revert "drm/amd/display: Enable Replay for static screen use cases"
+- drm/amdgpu: Let KFD sync with VM fences
+- drm/amd/display: Fix minor issues in BW Allocation Phase2
+- drm/amdgpu: Fix ecc irq enable/disable unpaired
+- clk: imx: clk-imx8qxp: fix LVDS bypass, pixel and phy clocks
+- drm/amd/display: Only clear symclk otg flag for HDMI
+- drm/amd/display: make flip_timestamp_in_us a 64-bit variable
+- accel/habanalabs: add support for Gaudi2C device
+- watchdog: it87_wdt: Keep WDTCTRL bit 3 unmodified for IT8784/IT8786
+- watchdog: starfive: add lock annotations to fix context imbalances
+- clk: mmp: pxa168: Fix memory leak in pxa168_clk_init()
+- clk: hi3620: Fix memory leak in hi3620_mmc_clk_init()
+- drm/amdgpu: fix ftrace event amdgpu_bo_move always move on same heap
+- drm/msm/dpu: fix writeback programming for YUV cases
+- drm/msm/dpu: Ratelimit framedone timeout msgs
+- drm/msm/dpu: enable writeback on SM8450
+- drm/msm/dpu: enable writeback on SM8350
+- drm/amdkfd: fix mes set shader debugger process management
+- drm/amd/display: Force p-state disallow if leaving no plane config
+- drm/amd/display: For prefetch mode > 0, extend prefetch if possible
+- media: i2c: imx335: Fix hblank min/max values
+- media: ddbridge: fix an error code problem in ddb_probe
+- media: amphion: remove mutext lock in condition of wait_event
+- IB/ipoib: Fix mcast list locking
+- drm/exynos: Call drm_atomic_helper_shutdown() at shutdown/unbind time
+- hwmon: (hp-wmi-sensors) Fix failure to load on EliteDesk 800 G6
+- hwmon: (nct6775) Fix fan speed set failure in automatic mode
+- media: rkisp1: resizer: Stop manual allocation of v4l2_subdev_state
+- media: rkisp1: Fix IRQ disable race issue
+- media: rkisp1: Store IRQ lines
+- media: rkisp1: Fix IRQ handler return values
+- media: rkisp1: Drop IRQF_SHARED
+- media: uvcvideo: Fix power line control for SunplusIT camera
+- media: uvcvideo: Fix power line control for a Chicony camera
+- drm/msm/dp: Add DisplayPort controller for SM8650
+- ALSA: hda: intel-dspcfg: add filters for ARL-S and ARL
+- ALSA: hda: Intel: add HDA_ARL PCI ID support
+- PCI: add INTEL_HDA_ARL to pci_ids.h
+- media: rockchip: rga: fix swizzling for RGB formats
+- media: stk1160: Fixed high volume of stk1160_dbg messages
+- drm/mipi-dsi: Fix detach call without attach
+- drm/framebuffer: Fix use of uninitialized variable
+- drm/drm_file: fix use of uninitialized variable
+- drm/amd/display: Fix MST PBN/X.Y value calculations
+- ASoC: amd: Add new dmi entries for acp5x platform
+- f2fs: fix write pointers on zoned device after roll forward
+- drm/amd/display: Fix tiled display misalignment
+- drm/bridge: anx7625: Fix Set HPD irq detect window to 2ms
+- drm/panel-edp: Add override_edid_mode quirk for generic edp
+- RDMA/IPoIB: Fix error code return in ipoib_mcast_join
+- reiserfs: Avoid touching renamed directory if parent does not change
+- fast_dput(): handle underflows gracefully
+- ASoC: doc: Fix undefined SND_SOC_DAPM_NOPM argument
+- ALSA: hda: Refer to correct stream index at loops
+- f2fs: fix to check return value of f2fs_reserve_new_block()
+- net: dsa: qca8k: put MDIO bus OF node on qca8k_mdio_register() failure
+- net: kcm: fix direct access to bv_len
+- octeontx2-af: Fix max NPC MCAM entry check while validating ref_entry
+- i40e: Fix VF disable behavior to block all traffic
+- arm64: dts: sprd: Change UMS512 idle-state nodename to match bindings
+- arm64: dts: sprd: Add clock reference for pll2 on UMS512
+- bridge: cfm: fix enum typo in br_cc_ccm_tx_parse
+- net/smc: disable SEID on non-s390 archs where virtual ISM may be used
+- Bluetooth: L2CAP: Fix possible multiple reject send
+- Bluetooth: hci_sync: fix BR/EDR wakeup bug
+- Bluetooth: ISO: Avoid creating child socket if PA sync is terminating
+- Bluetooth: qca: Set both WIDEBAND_SPEECH and LE_STATES quirks for QCA2066
+- wifi: cfg80211: free beacon_ies when overridden from hidden BSS
+- wifi: rtlwifi: rtl8723{be,ae}: using calculate_bit_shift()
+- libbpf: Fix NULL pointer dereference in bpf_object__collect_prog_relos
+- wifi: rtw89: coex: Fix wrong Wi-Fi role info and FDDT parameter members
+- wifi: rtl8xxxu: Add additional USB IDs for RTL8192EU devices
+- arm64: dts: amlogic: fix format for s4 uart node
+- ice: fix pre-shifted bit usage
+- arm64: dts: qcom: Fix coresight warnings in in-ports and out-ports
+- arm64: dts: qcom: msm8998: Fix 'out-ports' is a required property
+- arm64: dts: qcom: msm8996: Fix 'in-ports' is a required property
+- block: prevent an integer overflow in bvec_try_merge_hw_page
+- net: dsa: mv88e6xxx: Fix mv88e6352_serdes_get_stats error path
+- net: atlantic: eliminate double free in error handling logic
+- ice: fix ICE_AQ_VSI_Q_OPT_RSS_* register values
+- scsi: hisi_sas: Set .phy_attached before notifing phyup event HISI_PHYE_PHY_UP_PM
+- scsi: lpfc: Move determination of vmid_flag after VMID reinitialization completes
+- scsi: lpfc: Reinitialize an NPIV's VMID data structures after FDISC
+- ARM: dts: imx23/28: Fix the DMA controller node name
+- ARM: dts: imx23-sansa: Use preferred i2c-gpios properties
+- ARM: dts: imx27-apf27dev: Fix LED name
+- ARM: dts: imx25/27: Pass timing0
+- ARM: dts: imx25: Fix the iim compatible string
+- selftests/bpf: fix compiler warnings in RELEASE=1 mode
+- arm64: zynqmp: Fix clock node name in kv260 cards
+- arm64: zynqmp: Move fixed clock to / for kv260
+- block/rnbd-srv: Check for unlikely string overflow
+- ionic: bypass firmware cmds when stuck in reset
+- ionic: pass opcode to devcmd_wait
+- net: phy: at803x: fix passing the wrong reference for config_intr
+- ARM: dts: imx1: Fix sram node
+- ARM: dts: imx27: Fix sram node
+- ARM: dts: imx: Use flash@0,0 pattern
+- ARM: dts: imx25/27-eukrea: Fix RTC node name
+- ARM: dts: rockchip: fix rk3036 hdmi ports node
+- wifi: ath12k: fix the issue that the multicast/broadcast indicator is not read correctly for WCN7850
+- bpf: Set uattr->batch.count as zero before batched update or deletion
+- wifi: mt76: mt7996: add PCI IDs for mt7992
+- wifi: mt76: connac: fix EHT phy mode check
+- arm64: dts: qcom: sm8350: Fix remoteproc interrupt type
+- arm64: dts: qcom: sm8450: fix soundwire controllers node name
+- arm64: dts: qcom: sm8550: fix soundwire controllers node name
+- net: mvmdio: Avoid excessive sleeps in polled mode
+- minmax: relax check to allow comparison between unsigned arguments and signed constants
+- minmax: allow comparisons of 'int' against 'unsigned char/short'
+- minmax: fix indentation of __cmp_once() and __clamp_once()
+- minmax: allow min()/max()/clamp() if the arguments have the same signedness.
+- minmax: add umin(a, b) and umax(a, b)
+- minmax: fix header inclusions
+- minmax: deduplicate __unconst_integer_typeof()
+- scsi: libfc: Fix up timeout error in fc_fcp_rec_error()
+- scsi: libfc: Don't schedule abort twice
+- wifi: ath12k: fix and enable AP mode for WCN7850
+- bpf: Set need_defer as false when clearing fd array during map free
+- bpf: Check rcu_read_lock_trace_held() before calling bpf map helpers
+- wifi: rtw89: fix misbehavior of TX beacon in concurrent mode
+- wifi: ath11k: fix race due to setting ATH11K_FLAG_EXT_IRQ_ENABLED too early
+- wifi: ath9k: Fix potential array-index-out-of-bounds read in ath9k_htc_txstatus()
+- bpf: Fix a few selftest failures due to llvm18 change
+- ARM: dts: imx7s: Fix nand-controller #size-cells
+- ARM: dts: imx7s: Fix lcdif compatible
+- ARM: dts: imx7d: Fix coresight funnel ports
+- scsi: arcmsr: Support new PCI device IDs 1883 and 1886
+- scsi: mpi3mr: Add PCI checks where SAS5116 diverges from SAS4116
+- scsi: mpi3mr: Add support for SAS5116 PCI IDs
+- net: usb: ax88179_178a: avoid two consecutive device resets
+- bonding: return -ENOMEM instead of BUG in alb_upper_dev_walk
+- PCI: Add no PM reset quirk for NVIDIA Spectrum devices
+- net: phy: micrel: fix ts_info value in case of no phc
+- ARM: dts: samsung: s5pv210: fix camera unit addresses/ranges
+- ARM: dts: samsung: exynos4: fix camera unit addresses/ranges
+- scsi: lpfc: Fix possible file string name overflow when updating firmware
+- soc: xilinx: fix unhandled SGI warning message
+- soc: xilinx: Fix for call trace due to the usage of smp_processor_id()
+- ARM: dts: qcom: msm8660: fix PMIC node labels
+- ARM: dts: qcom: mdm9615: fix PMIC node labels
+- ARM: dts: qcom: strip prefix from PMIC files
+- selftests/bpf: Fix issues in setup_classid_environment()
+- wifi: rt2x00: correct wrong BBP register in RxDCOC calibration
+- selftests/bpf: Fix pyperf180 compilation failure with clang18
+- libbpf: Fix potential uninitialized tail padding with LIBBPF_OPTS_RESET
+- selftests/bpf: satisfy compiler by having explicit return in btf test
+- selftests/bpf: fix RELEASE=1 build for tc_opts
+- wifi: rt2x00: restart beacon queue when hardware reset
+- wifi: rtw89: fix timeout calculation in rtw89_roc_end()
+- ext4: avoid online resizing failures due to oversized flex bg
+- ext4: remove unnecessary check from alloc_flex_gd()
+- ext4: unify the type of flexbg_size to unsigned int
+- ext4: fix inconsistent between segment fstrim and full fstrim
+- ecryptfs: Reject casefold directory inodes
+- smb: client: fix hardlinking of reparse points
+- smb: client: fix renaming of reparse points
+- ext4: treat end of range as exclusive in ext4_zero_range()
+- SUNRPC: Fix a suspicious RCU usage warning
+- sysctl: Fix out of bounds access for empty sysctl registers
+- KVM: s390: fix setting of fpc register
+- s390/ptrace: handle setting of fpc register correctly
+- s390/vfio-ap: fix sysfs status attribute for AP queue devices
+- arch: consolidate arch_irq_work_raise prototypes
+- s390/boot: always align vmalloc area on segment boundary
+- jfs: fix array-index-out-of-bounds in diNewExt
+- rxrpc_find_service_conn_rcu: fix the usage of read_seqbegin_or_lock()
+- afs: fix the usage of read_seqbegin_or_lock() in afs_find_server*()
+- afs: fix the usage of read_seqbegin_or_lock() in afs_lookup_volume_rcu()
+- crypto: stm32/crc32 - fix parsing list of devices
+- erofs: fix ztailpacking for subpage compressed blocks
+- crypto: octeontx2 - Fix cptvf driver cleanup
+- crypto: starfive - Fix dev_err_probe return error
+- erofs: fix up compacted indexes for block size < 4096
+- pstore/ram: Fix crash when setting number of cpus to an odd number
+- crypto: p10-aes-gcm - Avoid -Wstringop-overflow warnings
+- hwrng: starfive - Fix dev_err_probe return error
+- jfs: fix uaf in jfs_evict_inode
+- jfs: fix array-index-out-of-bounds in dbAdjTree
+- jfs: fix slab-out-of-bounds Read in dtSearch
+- UBSAN: array-index-out-of-bounds in dtSplitRoot
+- FS:JFS:UBSAN:array-index-out-of-bounds in dbAdjTree
+- thermal: core: Fix thermal zone suspend-resume synchronization
+- ACPI: APEI: set memory failure flags as MF_ACTION_REQUIRED on synchronous events
+- PM / devfreq: Synchronize devfreq_monitor_[start/stop]
+- kunit: tool: fix parsing of test attributes
+- ACPI: NUMA: Fix the logic of getting the fake_pxm value
+- selftests/nolibc: fix testcase status alignment
+- ACPI: extlog: fix NULL pointer dereference check
+- PNP: ACPI: fix fortify warning
+- ACPI: video: Add quirk for the Colorful X15 AT 23 Laptop
+- audit: Send netlink ACK before setting connection in auditd_set
+- regulator: core: Only increment use_count when enable_count changes
+- debugobjects: Stop accessing objects after releasing hash bucket lock
+- perf/core: Fix narrow startup race when creating the perf nr_addr_filters sysfs file
+- x86/mce: Mark fatal MCE's page as poison to avoid panic in the kdump kernel
+- powerpc: pmd_move_must_withdraw() is only needed for CONFIG_TRANSPARENT_HUGEPAGE
+- x86/boot: Ignore NMIs during very early boot
+- powerpc/64s: Fix CONFIG_NUMA=n build due to create_section_mapping()
+- powerpc/mm: Fix build failures due to arch_reserved_kernel_pages()
+- powerpc: Fix build error due to is_valid_bugaddr()
+- drivers/perf: pmuv3: don't expose SW_INCR event in sysfs
+- arm64: irq: set the correct node for VMAP stack
+- powerpc/mm: Fix null-pointer dereference in pgtable_cache_add
+- asm-generic: make sparse happy with odd-sized put_unaligned_*()
+- Documentation/sphinx: fix Python string escapes
+- thermal: trip: Drop lockdep assertion from thermal_zone_trip_id()
+- serial: core: fix kernel-doc for uart_port_unlock_irqrestore()
+- x86/entry/ia32: Ensure s32 is sign extended to s64
+- tick/sched: Preserve number of idle sleeps across CPU hotplug events
+- clocksource: Skip watchdog check for large watchdog intervals
+- genirq: Initialize resend_node hlist for all interrupt descriptors
+- mips: Call lose_fpu(0) before initializing fcr31 in mips_set_personality_nan
+- cxl/region:Fix overflow issue in alloc_hpa()
+- drm: bridge: samsung-dsim: Don't use FORCE_STOP_STATE
+- MIPS: lantiq: register smp_ops on non-smp platforms
+- spi: fix finalize message on error return
+- cifs: fix stray unlock in cifs_chan_skip_or_disable
+- spi: spi-cadence: Reverse the order of interleaved write and read operations
+- spi: bcm-qspi: fix SFDP BFPT read by usig mspi read
+- cpufreq/amd-pstate: Fix setting scaling max/min freq values
+- drm/bridge: anx7625: Ensure bridge is suspended in disable()
+- block: Move checking GENHD_FL_NO_PART to bdev_add_partition()
+- spi: intel-pci: Remove Meteor Lake-S SoC PCI ID from the list
+- ARM: dts: exynos4212-tab3: add samsung,invert-vclk flag to fimd
+- gpio: eic-sprd: Clear interrupt after set the interrupt type
+- firmware: arm_scmi: Use xa_insert() when saving raw queues
+- firmware: arm_scmi: Use xa_insert() to store opps
+- drm/exynos: gsc: minor fix for loop iteration in gsc_runtime_resume
+- drm/exynos: fix accidental on-stack copy of exynos_drm_plane
+- memblock: fix crash when reserved memory is not added to memory
+- drm/bridge: parade-ps8640: Make sure we drop the AUX mutex in the error case
+- drm/bridge: parade-ps8640: Ensure bridge is suspended in .post_disable()
+- drm/bridge: sii902x: Fix audio codec unregistration
+- drm/bridge: sii902x: Fix probing race issue
+- drm/panel: samsung-s6d7aa0: drop DRM_BUS_FLAG_DE_HIGH for lsl080al02
+- drm: panel-simple: add missing bus flags for Tianma tm070jvhg[30/33]
+- drm/bridge: parade-ps8640: Wait for HPD when doing an AUX transfer
+- drm/amdgpu/gfx11: set UNORD_DISPATCH in compute MQDs
+- drm/amdgpu/gfx10: set UNORD_DISPATCH in compute MQDs
+- drm/panel-edp: drm/panel-edp: Fix AUO B116XTN02 name
+- drm/panel-edp: drm/panel-edp: Fix AUO B116XAK01 name and timing
+- drm/panel-edp: Add AUO B116XTN02, BOE NT116WHM-N21,836X2, NV116WHM-N49 V8.0
+- drm/i915/psr: Only allow PSR in LPSP mode on HSW non-ULT
+- drm/i915/lnl: Remove watchdog timers for PSR
+- btrfs: zoned: optimize hint byte for zoned allocator
+- btrfs: zoned: factor out prepare_allocation_zoned()
+- serial: sc16is7xx: fix unconditional activation of THRI interrupt
+- serial: sc16is7xx: Use port lock wrappers
+- serial: core: Provide port lock wrappers
+- mm: migrate: fix getting incorrect page mapping during page migration
+- mm: migrate: record the mlocked page status to remove unnecessary lru drain
+- thermal: gov_power_allocator: avoid inability to reset a cdev
+- thermal: core: Store trip pointer in struct thermal_instance
+- thermal: trip: Drop redundant trips check from for_each_thermal_trip()
+- media: i2c: imx290: Properly encode registers as little-endian
+- media: v4l2-cci: Add support for little-endian encoded registers
+- media: v4l: cci: Add macros to obtain register width and address
+- media: v4l: cci: Include linux/bits.h
+- pipe: wakeup wr_wait after setting max_usage
+- fs/pipe: move check to pipe_has_watch_queue()
+- thermal: intel: hfi: Add syscore callbacks for system-wide PM
+- thermal: intel: hfi: Disable an HFI instance when all its CPUs go offline
+- thermal: intel: hfi: Refactor enabling code into helper functions
+- net/bpf: Avoid unused "sin_addr_len" warning when CONFIG_CGROUP_BPF is not set
+- drm/amd/display: Fix uninitialized variable usage in core_link_ 'read_dpcd() & write_dpcd()' functions
+- drm/amdgpu/pm: Fix the power source flag error
+- drm/amd/display: Fix late derefrence 'dsc' check in 'link_set_dsc_pps_packet()'
+- drm/amd/display: Align the returned error code with legacy DP
+- drm/amd/display: Port DENTIST hang and TDR fixes to OTG disable W/A
+- drm/amd/display: Fix variable deferencing before NULL check in edp_setup_replay()
+- drm/amdgpu: correct the cu count for gfx v11
+- drm/bridge: nxp-ptn3460: simplify some error checking
+- Revert "drm/amd/display: fix bandwidth validation failure on DCN 2.1"
+- drm/amd/display: Disable PSR-SU on Parade 0803 TCON again
+- drm/amd/display: fix bandwidth validation failure on DCN 2.1
+- drm: Allow drivers to indicate the damage helpers to ignore damage clips
+- drm/virtio: Disable damage clipping if FB changed since last page-flip
+- drm: Disable the cursor plane on atomic contexts with virtualized drivers
+- drm/tidss: Fix atomic_flush check
+- drm: Fix TODO list mentioning non-KMS drivers
+- drm/bridge: nxp-ptn3460: fix i2c_master_send() error checking
+- drm: Don't unref the same fb many times by mistake due to deadlock handling
+- Revert "drm/i915/dsi: Do display on sequence later on icl+"
+- cpufreq: intel_pstate: Refine computation of P-state for given frequency
+- gpiolib: acpi: Ignore touchpad wakeup on GPD G1619-04
+- xfs: read only mounts with fsopen mount API are busted
+- drm/amdgpu: Fix the null pointer when load rlc firmware
+- Revert "drivers/firmware: Move sysfb_init() from device_initcall to subsys_initcall_sync"
+- firmware: arm_scmi: Check mailbox/SMT channel for consistency
+- ksmbd: fix global oob in ksmbd_nl_policy
+- platform/x86: p2sb: Allow p2sb_bar() calls during PCI device probe
+- platform/x86: intel-uncore-freq: Fix types in sysfs callbacks
+- netfilter: nf_tables: reject QUEUE/DROP verdict parameters
+- netfilter: nft_chain_filter: handle NETDEV_UNREGISTER for inet/ingress basechain
+- hv_netvsc: Calculate correct ring size when PAGE_SIZE is not 4 Kbytes
+- nfsd: fix RELEASE_LOCKOWNER
+- wifi: iwlwifi: fix a memory corruption
+- exec: Fix error handling in begin_new_exec()
+- rbd: don't move requests to the running list on errors
+- btrfs: don't abort filesystem when attempting to snapshot deleted subvolume
+- btrfs: defrag: reject unknown flags of btrfs_ioctl_defrag_range_args
+- btrfs: don't warn if discard range is not aligned to sector
+- btrfs: tree-checker: fix inline ref size in error messages
+- btrfs: ref-verify: free ref cache before clearing mount opt
+- btrfs: avoid copying BTRFS_ROOT_SUBVOL_DEAD flag to snapshot of subvolume being deleted
+- btrfs: zoned: fix lock ordering in btrfs_zone_activate()
+- tsnep: Fix XDP_RING_NEED_WAKEUP for empty fill ring
+- tsnep: Remove FCS for XDP data path
+- net: fec: fix the unhandled context fault from smmu
+- selftests: bonding: do not test arp/ns target with mode balance-alb/tlb
+- fjes: fix memleaks in fjes_hw_setup
+- i40e: update xdp_rxq_info::frag_size for ZC enabled Rx queue
+- i40e: set xdp_rxq_info::frag_size
+- xdp: reflect tail increase for MEM_TYPE_XSK_BUFF_POOL
+- ice: update xdp_rxq_info::frag_size for ZC enabled Rx queue
+- intel: xsk: initialize skb_frag_t::bv_offset in ZC drivers
+- ice: remove redundant xdp_rxq_info registration
+- i40e: handle multi-buffer packets that are shrunk by xdp prog
+- ice: work on pre-XDP prog frag count
+- xsk: fix usage of multi-buffer BPF helpers for ZC XDP
+- bpf: Add bpf_sock_addr_set_sun_path() to allow writing unix sockaddr from bpf
+- bpf: Propagate modified uaddrlen from cgroup sockaddr programs
+- xsk: make xsk_buff_pool responsible for clearing xdp_buff::flags
+- xsk: recycle buffer in case Rx queue was full
+- selftests: netdevsim: fix the udp_tunnel_nic test
+- selftests: net: fix rps_default_mask with >32 CPUs
+- net: mvpp2: clear BM pool before initialization
+- net: stmmac: Wait a bit for the reset to take effect
+- netfilter: nf_tables: validate NFPROTO_* family
+- netfilter: nf_tables: restrict anonymous set and map names to 16 bytes
+- netfilter: nft_limit: reject configurations that cause integer overflow
+- rcu: Defer RCU kthreads wakeup when CPU is dying
+- net/mlx5e: fix a potential double-free in fs_any_create_groups
+- net/mlx5e: fix a double-free in arfs_create_groups
+- net/mlx5e: Ignore IPsec replay window values on sender side
+- net/mlx5e: Allow software parsing when IPsec crypto is enabled
+- net/mlx5: Use mlx5 device constant for selecting CQ period mode for ASO
+- net/mlx5: DR, Can't go to uplink vport on RX rule
+- net/mlx5: DR, Use the right GVMI number for drop action
+- net/mlx5: Bridge, fix multicast packets sent to uplink
+- net/mlx5: Bridge, Enable mcast in smfs steering mode
+- net/mlx5: Fix a WARN upon a callback command failure
+- net/mlx5e: Fix peer flow lists handling
+- net/mlx5e: Fix operation precedence bug in port timestamping napi_poll context
+- net/sched: flower: Fix chain template offload
+- selftests: fill in some missing configs for net
+- ipv6: init the accept_queue's spinlocks in inet6_create
+- netlink: fix potential sleeping issue in mqueue_flush_file
+- selftest: Don't reuse port for SO_INCOMING_CPU test.
+- tcp: Add memory barrier to tcp_push()
+- afs: Hide silly-rename files from userspace
+- tracing: Ensure visibility when inserting an element into tracing_map
+- netfs, fscache: Prevent Oops in fscache_put_cache()
+- net/rds: Fix UBSAN: array-index-out-of-bounds in rds_cmsg_recv
+- net: micrel: Fix PTP frame parsing for lan8814
+- tun: add missing rx stats accounting in tun_xdp_act
+- tun: fix missing dropped counter in tun_xdp_act
+- net: fix removing a namespace with conflicting altnames
+- udp: fix busy polling
+- llc: Drop support for ETH_P_TR_802_2.
+- llc: make llc_ui_sendmsg() more robust against bonding changes
+- vlan: skip nested type that is not IFLA_VLAN_QOS_MAPPING
+- bnxt_en: Prevent kernel warning when running offline self test
+- bnxt_en: Wait for FLR to complete during probe
+- tcp: make sure init the accept_queue's spinlocks once
+- selftests: bonding: Increase timeout to 1200s
+- net/smc: fix illegal rmb_desc access in SMC-D connection dump
+- wifi: mac80211: fix potential sta-link leak
+- SUNRPC: use request size to initialize bio_vec in svc_udp_sendto()
+- cifs: after disabling multichannel, mark tcon for reconnect
+- cifs: fix a pending undercount of srv_count
+- cifs: fix lock ordering while disabling multichannel
+- Revert "drm/amd: Enable PCIe PME from D3"
+- selftests/bpf: check if max number of bpf_loop iterations is tracked
+- bpf: keep track of max number of bpf_loop callback iterations
+- selftests/bpf: test widening for iterating callbacks
+- bpf: widening for callback iterators
+- selftests/bpf: tests for iterating callbacks
+- bpf: verify callbacks as if they are called unknown number of times
+- bpf: extract setup_func_entry() utility function
+- bpf: extract __check_reg_arg() utility function
+- selftests/bpf: track string payload offset as scalar in strobemeta
+- selftests/bpf: track tcp payload offset as scalar in xdp_synproxy
+- bpf: print full verifier states on infinite loop detection
+- selftests/bpf: test if state loops are detected in a tricky case
+- bpf: correct loop detection for iterators convergence
+- selftests/bpf: tests with delayed read/precision makrs in loop body
+- bpf: exact states comparison for iterator convergence checks
+- bpf: extract same_callsites() as utility function
+- bpf: move explored_state() closer to the beginning of verifier.c
+- dt-bindings: net: snps,dwmac: Tx coe unsupported
+- ksmbd: Add missing set_freezable() for freezable kthread
+- ksmbd: send lease break notification on FILE_RENAME_INFORMATION
+- ksmbd: don't increment epoch if current state and request state are same
+- ksmbd: fix potential circular locking issue in smb2_set_ea()
+- ksmbd: set v2 lease version on lease upgrade
+- serial: Do not hold the port lock when setting rx-during-tx GPIO
+- mm: page_alloc: unreserve highatomic page blocks before oom
+- LoongArch/smp: Call rcutree_report_cpu_starting() earlier
+- serial: sc16is7xx: improve do/while loop in sc16is7xx_irq()
+- serial: sc16is7xx: remove obsolete loop in sc16is7xx_port_irq()
+- serial: sc16is7xx: fix invalid sc16is7xx_lines bitfield in case of probe error
+- serial: sc16is7xx: convert from _raw_ to _noinc_ regmap functions for FIFO
+- serial: sc16is7xx: change EFR lock to operate on each channels
+- serial: sc16is7xx: remove unused line structure member
+- serial: sc16is7xx: remove global regmap from struct sc16is7xx_port
+- serial: sc16is7xx: remove wasteful static buffer in sc16is7xx_regmap_name()
+- serial: sc16is7xx: improve regmap debugfs by using one regmap per port
+- rename(): fix the locking of subdirectories
+- mm/sparsemem: fix race in accessing memory_section->usage
+- mm/rmap: fix misplaced parenthesis of a likely()
+- selftests: mm: hugepage-vmemmap fails on 64K page size systems
+- kexec: do syscore_shutdown() in kernel_kexec
+- ubifs: ubifs_symlink: Fix memleak of inode->i_link in error path
+- nouveau/vmm: don't set addr on the fail path to avoid warning
+- rtc: Extend timeout for waiting for UIP to clear to 1s
+- rtc: Add support for configuring the UIP timeout for RTC reads
+- rtc: mc146818-lib: Adjust failure return code for mc146818_get_time()
+- rtc: Adjust failure return code for cmos_set_alarm()
+- rtc: cmos: Use ACPI alarm for non-Intel x86 systems too
+- arm64: entry: fix ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD
+- arm64/sme: Always exit sme_alloc() early with existing storage
+- arm64: errata: Add Cortex-A510 speculative unprivileged load workaround
+- arm64: Rename ARM64_WORKAROUND_2966298
+- riscv: mm: Fixup compat mode boot failure
+- riscv: mm: Fixup compat arch_get_mmap_end
+- media: mtk-jpeg: Fix use after free bug due to error path handling in mtk_jpeg_dec_device_run
+- media: mtk-jpeg: Fix timeout schedule error in mtk_jpegdec_worker.
+- media: i2c: st-mipid02: correct format propagation
+- mmc: mmc_spi: remove custom DMA mapped buffers
+- mmc: core: Use mrq.sbc in close-ended ffu
+- media: videobuf2-dma-sg: fix vmap callback
+- scripts/get_abi: fix source path leak
+- docs: kernel_abi.py: fix command injection
+- dlm: use kernel_connect() and kernel_bind()
+- lsm: new security_file_ioctl_compat() hook
+- ARM: dts: qcom: sdx55: fix USB SS wakeup
+- arm64: dts: qcom: sdm670: fix USB SS wakeup
+- arm64: dts: qcom: sdm670: fix USB DP/DM HS PHY interrupts
+- arm64: dts: qcom: sc8180x: fix USB SS wakeup
+- arm64: dts: qcom: sc8180x: fix USB DP/DM HS PHY interrupts
+- arm64: dts: qcom: sm8150: fix USB SS wakeup
+- arm64: dts: qcom: sm8150: fix USB DP/DM HS PHY interrupts
+- arm64: dts: qcom: sdm845: fix USB SS wakeup
+- arm64: dts: qcom: sdm845: fix USB DP/DM HS PHY interrupts
+- ARM: dts: qcom: sdx55: fix USB DP/DM HS PHY interrupts
+- arm64: dts: qcom: Add missing vio-supply for AW2013
+- arm64: dts: qcom: sc7280: fix usb_1 wakeup interrupt types
+- arm64: dts: qcom: sc8180x: fix USB wakeup interrupt types
+- arm64: dts: qcom: sm8150: fix USB wakeup interrupt types
+- arm64: dts: qcom: sdm670: fix USB wakeup interrupt types
+- arm64: dts: qcom: sdm845: fix USB wakeup interrupt types
+- arm64: dts: qcom: sc7180: fix USB wakeup interrupt types
+- arm64: dts: qcom: msm8939: Make blsp_dma controlled-remotely
+- arm64: dts: qcom: msm8916: Make blsp_dma controlled-remotely
+- arm64: dts: rockchip: Fix rk3588 USB power-domain clocks
+- arm64: dts: rockchip: configure eth pad driver strength for orangepi r1 plus lts
+- arm64: dts: sprd: fix the cpu node for UMS512
+- ARM: dts: qcom: sdx55: fix pdc '#interrupt-cells'
+- ARM: dts: samsung: exynos4210-i9100: Unconditionally enable LDO12
+- ARM: dts: qcom: sdx55: fix USB wakeup interrupt types
+- arm64: dts: qcom: sc8280xp-crd: fix eDP phy compatible
+- ARM: dts: imx6q-apalis: add can power-up delay on ixora board
+- parisc/power: Fix power soft-off button emulation on qemu
+- parisc/firmware: Fix F-extend for PDC addresses
+- bus: mhi: host: Add spinlock to protect WP access when queueing TREs
+- bus: mhi: host: Drop chan lock before queuing buffers
+- bus: mhi: host: Add alignment check for event ring read pointer
+- mips: Fix max_mapnr being uninitialized on early stages
+- nbd: always initialize struct msghdr completely
+- s390/vfio-ap: do not reset queue removed from host config
+- s390/vfio-ap: reset queues associated with adapter for queue unbound from driver
+- s390/vfio-ap: reset queues filtered from the guest's AP config
+- s390/vfio-ap: let on_scan_complete() callback filter matrix and update guest's APCB
+- s390/vfio-ap: loop over the shadow APCB when filtering guest's AP configuration
+- soc: fsl: cpm1: qmc: Fix rx channel reset
+- soc: fsl: cpm1: qmc: Fix __iomem addresses declaration
+- soc: fsl: cpm1: tsa: Fix __iomem addresses declaration
+- media: ov01a10: Enable runtime PM before registering async sub-device
+- media: ov13b10: Enable runtime PM before registering async sub-device
+- media: ov9734: Enable runtime PM before registering async sub-device
+- rpmsg: virtio: Free driver_override when rpmsg_remove()
+- media: imx355: Enable runtime PM before registering async sub-device
+- soc: qcom: pmic_glink_altmode: fix port sanity check
+- mtd: rawnand: Clarify conditions to enable continuous reads
+- mtd: rawnand: Prevent sequential reads with on-die ECC engines
+- mtd: rawnand: Fix core interference with sequential reads
+- mtd: rawnand: Prevent crossing LUN boundaries during sequential reads
+- mtd: maps: vmu-flash: Fix the (mtd core) switch to ref counters
+- PM / devfreq: Fix buffer overflow in trans_stat_show
+- s390/vfio-ap: unpin pages on gisc registration failure
+- crypto: s390/aes - Fix buffer overread in CTR mode
+- hwrng: core - Fix page fault dead lock on mmap-ed hwrng
+- PM: hibernate: Enforce ordering during image compression/decompression
+- crypto: api - Disallow identical driver names
+- crypto: lib/mpi - Fix unexpected pointer access in mpi_ec_init
+- btrfs: sysfs: validate scrub_speed_max value
+- OPP: Pass rounded rate to _set_opp()
+- arm64: properly install vmlinuz.efi
+- PM: sleep: Fix possible deadlocks in core system-wide PM code
+- async: Introduce async_schedule_dev_nocall()
+- async: Split async_schedule_node_domain()
+- ext4: allow for the last group to be marked as trimmed
+- powerpc/ps3_defconfig: Disable PPC64_BIG_ENDIAN_ELF_ABI_V2
+- cifs: update iface_last_update on each query-and-update
+- cifs: handle servers that still advertise multichannel after disabling
+- cifs: reconnect worker should take reference on server struct unconditionally
+- Revert "cifs: reconnect work should have reference on server struct"
+- cifs: handle when server stops supporting multichannel
+- cifs: handle when server starts supporting multichannel
+- cifs: reconnect work should have reference on server struct
+- cifs: handle cases where a channel is closed
+- smb: client: fix parsing of SMB3.1.1 POSIX create context
+- sh: ecovec24: Rename missed backlight field from fbdev to dev
+- scsi: core: Kick the requeue list after inserting when flushing
+- riscv: Fix an off-by-one in get_early_cmdline()
+- scsi: ufs: core: Remove the ufshcd_hba_exit() call from ufshcd_async_scan()
+- dmaengine: idxd: Move dma_free_coherent() out of spinlocked context
+- dmaengine: fix NULL pointer in channel unregistration function
+- dmaengine: fsl-edma: fix eDMAv4 channel allocation issue
+- iio: adc: ad7091r: Enable internal vref if external vref is not supplied
+- iio: adc: ad7091r: Allow users to configure device events
+- iio: adc: ad7091r: Set alert bit in config register
+- net: stmmac: Prevent DSA tags from breaking COE
+- net: stmmac: Tx coe sw fallback
+- soundwire: fix initializing sysfs for same devices on different buses
+- soundwire: bus: introduce controller_id
+- serial: core: set missing supported flag for RX during TX GPIO
+- serial: core: Simplify uart_get_rs485_mode()
+- docs: kernel_feat.py: fix potential command injection
+- docs: sparse: add sparse.rst to toctree
+- docs: sparse: move TW sparse.txt to TW dev-tools
+- Revert "Revert "md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d""
+- arm64: dts: armada-3720-turris-mox: set irq type for RTC
+- Revert "KEYS: encrypted: Add check for strsep"
+- riscv: Fix wrong usage of lm_alias() when splitting a huge linear mapping
+- i2c: s3c24xx: fix transferring more than one message in polling mode
+- i2c: s3c24xx: fix read transfers in polling mode
+- ipv6: mcast: fix data-race in ipv6_mc_down / mld_ifc_work
+- selftests: mlxsw: qos_pfc: Adjust the test to support 8 lanes
+- mlxsw: spectrum_router: Register netdevice notifier before nexthop
+- mlxsw: spectrum_acl_tcam: Fix stack corruption
+- mlxsw: spectrum_acl_tcam: Fix NULL pointer dereference in error path
+- mlxsw: spectrum_acl_erp: Fix error flow of pool allocation failure
+- loop: fix the the direct I/O support check when used on top of block devices
+- ethtool: netlink: Add missing ethnl_ops_begin/complete
+- arm64/ptrace: Don't flush ZA/ZT storage when writing ZA via ptrace
+- kdb: Fix a potential buffer overflow in kdb_local()
+- io_uring: adjust defer tw counting
+- ipvs: avoid stat macros calls from preemptible context
+- netfilter: nf_tables: reject NFT_SET_CONCAT with not field length description
+- netfilter: nf_tables: skip dead set elements in netlink dump
+- netfilter: nf_tables: do not allow mismatch field size and set key length
+- netfilter: bridge: replace physindev with physinif in nf_bridge_info
+- netfilter: propagate net to nf_bridge_get_physindev
+- netfilter: nf_queue: remove excess nf_bridge variable
+- netfilter: nfnetlink_log: use proper helper for fetching physinif
+- netfilter: nft_limit: do not ignore unsupported flags
+- netfilter: nf_tables: reject invalid set policy
+- net: netdevsim: don't try to destroy PHC on VFs
+- mptcp: relax check on MPC passive fallback
+- LoongArch: BPF: Prevent out-of-bounds memory access
+- net: dsa: vsc73xx: Add null pointer check to vsc73xx_gpio_probe
+- bpf: Reject variable offset alu on PTR_TO_FLOW_KEYS
+- net: stmmac: ethtool: Fixed calltrace caused by unbalanced disable_irq_wake calls
+- selftests: bonding: Change script interpreter
+- drm/amdgpu: fall back to INPUT power for AVG power via INFO IOCTL
+- drm/amdkfd: fixes for HMM mem allocation
+- ASoC: SOF: ipc4-loader: remove the CPC check warnings
+- gpio: mlxbf3: add an error code check in mlxbf3_gpio_probe
+- dt-bindings: gpio: xilinx: Fix node address in gpio
+- net: ravb: Fix dma_addr_t truncation in error case
+- net: tls, fix WARNIING in __sk_msg_free
+- bpf: Avoid iter->offset making backward progress in bpf_iter_udp
+- bpf: iter_udp: Retry with a larger batch size without going back to the previous bucket
+- net: netdev_queue: netdev_txq_completed_mb(): fix wake condition
+- net: add more sanity check in virtio_net_hdr_to_skb()
+- udp: annotate data-races around up->pending
+- net: stmmac: Fix ethool link settings ops for integrated PCS
+- block: ensure we hold a queue reference when using queue limits
+- mptcp: refine opt_mp_capable determination
+- mptcp: use OPTION_MPTCP_MPJ_SYN in subflow_check_req()
+- mptcp: use OPTION_MPTCP_MPJ_SYNACK in subflow_finish_connect()
+- mptcp: strict validation before using mp_opt->hmac
+- mptcp: mptcp_parse_option() fix for MPTCPOPT_MP_JOIN
+- ALSA: hda: Properly setup HDMI stream
+- net: phy: micrel: populate .soft_reset for KSZ9131
+- net: micrel: Fix PTP frame parsing for lan8841
+- amt: do not use overwrapped cb area
+- net: ethernet: ti: am65-cpsw: Fix max mtu to fit ethernet frames
+- octeontx2-af: CN10KB: Fix FIFO length calculation for RPM2
+- rxrpc: Fix use of Don't Fragment flag
+- net: qualcomm: rmnet: fix global oob in rmnet_policy
+- s390/pci: fix max size calculation in zpci_memcpy_toio()
+- ASoC: mediatek: sof-common: Add NULL check for normal_link string
+- PCI: mediatek-gen3: Fix translation window size calculation
+- PCI: keystone: Fix race condition when initializing PHYs
+- nvmet-tcp: Fix the H2C expected PDU len calculation
+- nvme: trace: avoid memcpy overflow warning
+- nvmet: re-fix tracing strncpy() warning
+- hisi_acc_vfio_pci: Update migration data pointer correctly on saving/resume
+- spi: coldfire-qspi: Remove an erroneous clk_disable_unprepare() from the remove function
+- cxl/port: Fix missing target list lock
+- perf db-export: Fix missing reference count get in call_path_from_sample()
+- serial: apbuart: fix console prompt on qemu
+- serial: imx: Correct clock error message in function probe()
+- usb: xhci-mtk: fix a short packet issue of gen1 isoc-in transfer
+- apparmor: avoid crash when parsed profile name is empty
+- apparmor: fix possible memory leak in unpack_trans_table
+- cxl/region: fix x9 interleave typo
+- perf stat: Fix hard coded LL miss units
+- perf env: Avoid recursively taking env->bpf_progs.lock
+- nvmet-tcp: fix a crash in nvmet_req_complete()
+- nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length
+- apparmor: Fix ref count leak in task_kill
+- vdpa: Fix an error handling path in eni_vdpa_probe()
+- power: supply: Fix null pointer dereference in smb2_probe
+- usb: gadget: webcam: Make g_webcam loadable again
+- spmi: mtk-pmif: Serialize PMIF status check and command submission
+- usb: cdc-acm: return correct error code on unsupported break
+- tty: use 'if' in send_break() instead of 'goto'
+- tty: don't check for signal_pending() in send_break()
+- tty: early return from send_break() on TTY_DRIVER_HARDWARE_BREAK
+- PCI: epf-mhi: Fix the DMA data direction of dma_unmap_single()
+- bus: mhi: ep: Pass mhi_ep_buf_info struct to read/write APIs
+- bus: mhi: ep: Use slab allocator where applicable
+- bus: mhi: ep: Do not allocate event ring element on stack
+- perf unwind-libunwind: Fix base address for .eh_frame
+- perf unwind-libdw: Handle JIT-generated DSOs properly
+- perf genelf: Set ELF program header addresses properly
+- perf header: Fix one memory leakage in perf_event__fprintf_event_update()
+- iio: adc: ad9467: fix scale setting
+- iio: adc: ad9467: add mutex to struct ad9467_state
+- iio: adc: ad9467: don't ignore error codes
+- iio: adc: ad9467: fix reset gpio handling
+- selftests/sgx: Skip non X86_64 platform
+- selftests/sgx: Include memory clobber for inline asm in test enclave
+- selftests/sgx: Fix uninitialized pointer dereferences in encl_get_entry
+- selftests/sgx: Fix uninitialized pointer dereference in error path
+- serial: imx: fix tx statemachine deadlock
+- software node: Let args be NULL in software_node_get_reference_args
+- acpi: property: Let args be NULL in __acpi_node_get_property_reference
+- base/node.c: initialize the accessor list before registering
+- perf stat: Exit perf stat if parse groups fails
+- perf mem: Fix error on hybrid related to availability of mem event in a PMU
+- perf vendor events arm64 AmpereOne: Rename BPU_FLUSH_MEM_FAULT to GPC_FLUSH_MEM_FAULT
+- vfio/pds: Fix calculations in pds_vfio_dirty_sync
+- perf test record user-regs: Fix mask for vg register
+- libapi: Add missing linux/types.h header to get the __u64 type on io.h
+- perf header: Fix segfault on build_mem_topology() error path
+- perf test: Remove atomics from test_loop to avoid test failures
+- power: supply: bq256xx: fix some problem in bq256xx_hw_init
+- power: supply: cw2015: correct time_to_empty units in sysfs
+- MIPS: Alchemy: Fix an out-of-bound access in db1550_dev_setup()
+- MIPS: Alchemy: Fix an out-of-bound access in db1200_dev_setup()
+- riscv: Fixed wrong register in XIP_FIXUP_FLASH_OFFSET macro
+- riscv: Fix set_direct_map_default_noflush() to reset _PAGE_EXEC
+- riscv: Fix set_memory_XX() and set_direct_map_XX() by splitting huge linear mappings
+- riscv: Fix module_alloc() that did not reset the linear mapping permissions
+- riscv: Check if the code to patch lies in the exit section
+- um: virt-pci: fix platform map offset
+- mips: Fix incorrect max_low_pfn adjustment
+- mips: dmi: Fix early remap on MIPS32
+- srcu: Use try-lock lockdep annotation for NMI-safe access.
+- mfd: intel-lpss: Fix the fractional clock divider flags
+- mfd: tps6594: Add null pointer check to tps6594_device_init()
+- leds: aw200xx: Fix write to DIM parameter
+- leds: aw2013: Select missing dependency REGMAP_I2C
+- mfd: syscon: Fix null pointer dereference in of_syscon_register()
+- mfd: cs42l43: Correct SoundWire port list
+- mfd: rk8xx: fixup devices registration with PLATFORM_DEVID_AUTO
+- ARM: 9330/1: davinci: also select PINCTRL
+- serial: sc16is7xx: set safe default SPI clock frequency
+- serial: sc16is7xx: add check for unsupported SPI modes during probe
+- HID: wacom: Correct behavior when processing some confidence == false touches
+- HID: sensor-hub: Enable hid core report processing for all devices
+- iio: adc: ad7091r: Pass iio_dev to event handler
+- KVM: x86/pmu: Reset the PMU, i.e. stop counters, before refreshing
+- KVM: x86/pmu: Move PMU reset logic to common x86 code
+- KVM: arm64: vgic-its: Avoid potential UAF in LPI translation cache
+- x86/kvm: Do not try to disable kvmclock if it was not enabled
+- PCI: mediatek: Clear interrupt status before dispatching handler
+- PCI: dwc: endpoint: Fix dw_pcie_ep_raise_msix_irq() alignment support
+- x86/pci: Reserve ECAM if BIOS didn't include it in PNP0C02 _CRS
+- PCI/P2PDMA: Remove reference to pci_p2pdma_map_sg()
+- cxl/port: Fix decoder initialization when nr_targets > interleave_ways
+- Revert "nSVM: Check for reserved encodings of TLB_CONTROL in nested VMCB"
+- Revert "net: rtnetlink: Enslave device before bringing it up"
+- net: stmmac: fix ethtool per-queue statistics
+- wifi: mwifiex: fix uninitialized firmware_stat
+- wifi: mwifiex: configure BSSID consistently when starting AP
+- wifi: mwifiex: add extra delay for firmware ready
+- wifi: rtlwifi: Convert LNKCTL change to PCIe cap RMW accessors
+- wifi: rtlwifi: Remove bogus and dangerous ASPM disable/enable code
+- wifi: mt76: fix broken precal loading from MTD for mt7915
+- iommu/arm-smmu-qcom: Add missing GMU entry to match table
+- bpf: Fix re-attachment branch in bpf_tracing_prog_attach
+- Bluetooth: Fix atomicity violation in {min,max}_key_size_set
+- md/raid1: Use blk_opf_t for read and write operations
+- pwm: Fix out-of-bounds access in of_pwm_single_xlate()
+- pwm: jz4740: Don't use dev_err_probe() in .request()
+- netfilter: nf_tables: check if catch-all set element is active in next generation
+- block: Fix iterating over an empty bio with bio_for_each_folio_all
+- block: Remove special-casing of compound pages
+- drm/amd: Enable PCIe PME from D3
+- scsi: mpi3mr: Block PEL Enable Command on Controller Reset and Unrecoverable State
+- scsi: mpi3mr: Clean up block devices post controller reset
+- scsi: mpi3mr: Refresh sdev queue depth after controller reset
+- scsi: target: core: add missing file_{start,end}_write()
+- scsi: ufs: core: Simplify power management during async scan
+- fbdev: flush deferred IO before closing
+- fbdev: flush deferred work in fb_deferred_io_fsync()
+- fbdev/acornfb: Fix name of fb_ops initializer macro
+- io_uring: ensure local task_work is run on wait timeout
+- io_uring/rw: ensure io->bytes_done is always initialized
+- io_uring: don't check iopoll if request completes
+- LoongArch: Fix and simplify fcsr initialization on execve()
+- ceph: select FS_ENCRYPTION_ALGS if FS_ENCRYPTION
+- ksmbd: only v2 leases handle the directory
+- ksmbd: fix UAF issue in ksmbd_tcp_new_connection()
+- ksmbd: validate mech token in session setup
+- ALSA: hda/realtek: Enable headset mic on Lenovo M70 Gen5
+- ALSA: hda/realtek: Enable mute/micmute LEDs and limit mic boost on HP ZBook
+- ALSA: hda/relatek: Enable Mute LED on HP Laptop 15s-fq2xxx
+- ALSA: oxygen: Fix right channel of capture volume mixer
+- serial: omap: do not override settings for RS485 support
+- serial: 8250_exar: Set missing rs485_supported flag
+- serial: imx: Ensure that imx_uart_rs485_config() is called with enabled clock
+- serial: core, imx: do not set RS485 enabled if it is not supported
+- serial: 8250_bcm2835aux: Restore clock error handling
+- serial: core: make sure RS485 cannot be enabled when it is not supported
+- serial: core: fix sanitizing check for RTS settings
+- dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp-phy: fix path to header
+- usb: mon: Fix atomicity violation in mon_bin_vma_fault
+- usb: typec: class: fix typec_altmode_put_partner to put plugs
+- Revert "usb: typec: class: fix typec_altmode_put_partner to put plugs"
+- usb: cdns3: Fix uvc fail when DMA cross 4k boundery since sg enabled
+- usb: cdns3: fix iso transfer error when mult is not zero
+- usb: cdns3: fix uvc failure work since sg support enabled
+- usb: chipidea: wait controller resume finished for wakeup irq
+- Revert "usb: dwc3: don't reset device side if dwc3 was configured as host-only"
+- Revert "usb: dwc3: Soft reset phy on probe for host"
+- usb: dwc3: gadget: Queue PM runtime idle on disconnect event
+- usb: dwc3: gadget: Handle EP0 request dequeuing properly
+- usb: dwc: ep0: Update request status in dwc3_ep0_stall_restart
+- usb: phy: mxs: remove CONFIG_USB_OTG condition for mxs_phy_is_otg_host()
+- Revert "usb: gadget: f_uvc: change endpoint allocation in uvc_function_bind()"
+- tick-sched: Fix idle and iowait sleeptime accounting vs CPU hotplug
+- powerpc/64s: Increase default stack size to 32KB
+- clocksource/drivers/timer-ti-dm: Fix make W=n kerneldoc warnings
+- binder: fix race between mmput() and do_exit()
+- xen-netback: don't produce zero-size SKB frags
+- Revert "drm/amdkfd: Relocate TBA/TMA to opposite side of VM hole"
+- rust: Ignore preserve-most functions
+- Input: atkbd - use ab83 as id when skipping the getid command
+- mips/smp: Call rcutree_report_cpu_starting() earlier
+- binder: fix unused alloc->free_async_space
+- binder: fix async space check for 0-sized buffers
+- keys, dns: Fix size check of V1 server-list header
+- selftests/bpf: Add assert for user stacks in test_task_stack
+- Revert "kernfs: convert kernfs_idr_lock to an irq safe raw spinlock"
+- kernfs: convert kernfs_idr_lock to an irq safe raw spinlock
+- class: fix use-after-free in class_register()
+- of: unittest: Fix of_count_phandle_with_args() expected value message
+- fbdev: imxfb: fix left margin setting
+- of: Fix double free in of_parse_phandle_with_args_map
+- ksmbd: validate the zero field of packet header
+- kselftest/alsa - conf: Stringify the printed errno in sysfs_get()
+- kselftest/alsa - mixer-test: Fix the print format specifier warning
+- kselftest/alsa - mixer-test: fix the number of parameters to ksft_exit_fail_msg()
+- drm/amd/display: avoid stringop-overflow warnings for dp_decide_lane_settings()
+- drm/amd/pm/smu7: fix a memleak in smu7_hwmgr_backend_init
+- drm/amdkfd: Confirm list is non-empty before utilizing list_first_entry in kfd_topology.c
+- IB/iser: Prevent invalidating wrong MR
+- gpio: sysfs: drop the mention of gpiochip_find() from sysfs code
+- gpiolib: provide gpio_device_find()
+- gpiolib: make gpio_device_get() and gpio_device_put() public
+- drm/amdkfd: Fix type of 'dbg_flags' in 'struct kfd_process'
+- mmc: sdhci_omap: Fix TI SoC dependencies
+- mmc: sdhci_am654: Fix TI SoC dependencies
+- ALSA: scarlett2: Add clamp() in scarlett2_mixer_ctl_put()
+- ALSA: scarlett2: Add missing error checks to *_ctl_get()
+- ALSA: scarlett2: Allow passing any output to line_out_remap()
+- ALSA: scarlett2: Add missing error check to scarlett2_usb_set_config()
+- ALSA: scarlett2: Add missing error check to scarlett2_config_save()
+- ASoC: rt5645: Drop double EF20 entry from dmi_platform_data[]
+- pwm: stm32: Fix enable count for clk in .probe()
+- pwm: stm32: Use hweight32 in stm32_pwm_detect_channels
+- clk: fixed-rate: fix clk_hw_register_fixed_rate_with_accuracy_parent_hw
+- clk: qcom: dispcc-sm8550: Update disp PLL settings
+- clk: qcom: gcc-sm8550: Mark RCGs shared where applicable
+- clk: qcom: gcc-sm8550: use collapse-voting for PCIe GDSCs
+- clk: qcom: gcc-sm8550: Mark the PCIe GDSCs votable
+- clk: qcom: gcc-sm8550: Add the missing RETAIN_FF_ENABLE GDSC flag
+- accel/habanalabs: fix information leak in sec_attest_info()
+- drm/mediatek: dp: Add phy_mtk_dp module as pre-dependency
+- ASoC: tas2781: add support for FW version 0x0503
+- ASoC: amd: vangogh: Drop conflicting ACPI-based probing
+- clk: si5341: fix an error code problem in si5341_output_clk_set_rate
+- clk: rs9: Fix DIF OEn bit placement on 9FGV0241
+- watchdog: rti_wdt: Drop runtime pm reference count when watchdog is unused
+- watchdog: bcm2835_wdt: Fix WDIOC_SETTIMEOUT handling
+- watchdog/hpwdt: Only claim UNKNOWN NMI if from iLO
+- watchdog: set cdev owner before adding
+- drivers: clk: zynqmp: update divider round rate logic
+- drivers: clk: zynqmp: calculate closest mux rate
+- clk: sp7021: fix return value check in sp7021_clk_probe()
+- clk: qcom: videocc-sm8150: Add missing PLL config property
+- clk: qcom: videocc-sm8150: Update the videocc resets
+- dt-bindings: clock: Update the videocc resets for sm8150
+- f2fs: fix to check return value of f2fs_recover_xattr_data
+- drm/amd/pm: fix a double-free in amdgpu_parse_extended_power_table
+- gpu/drm/radeon: fix two memleaks in radeon_vm_init
+- drivers/amd/pm: fix a use-after-free in kv_parse_power_table
+- drm/amd/pm: fix a double-free in si_dpm_init
+- drm/amdgpu/debugfs: fix error code when smc register accessors are NULL
+- drm/mediatek: Fix underrun in VDO1 when switches off the layer
+- drm/mediatek: Remove the redundant driver data for DPI
+- drm/mediatek: Return error if MDP RDMA failed to enable the clock
+- drm/msm/dpu: Drop enable and frame_count parameters from dpu_hw_setup_misr()
+- drm/msm/dpu: Set input_sel bit for INTF
+- clk: renesas: rzg2l: Check reset monitor registers
+- clk: renesas: rzg2l-cpg: Reuse code in rzg2l_cpg_reset()
+- media: dvb-frontends: m88ds3103: Fix a memory leak in an error handling path of m88ds3103_probe()
+- media: dvbdev: drop refcount on error path in dvb_device_open()
+- f2fs: fix to update iostat correctly in f2fs_filemap_fault()
+- f2fs: fix to check compress file in f2fs_move_file_range()
+- f2fs: fix to wait on block writeback for post_read case
+- drm/panel: st7701: Fix AVCL calculation
+- drm/msm/adreno: Fix A680 chip id
+- media: rkisp1: Fix media device memory leak
+- media: dt-bindings: media: rkisp1: Fix the port description for the parallel interface
+- media: imx-mipi-csis: Drop extra clock enable at probe()
+- media: imx-mipi-csis: Fix clock handling in remove()
+- media: bttv: add back vbi hack
+- media: bttv: start_streaming should return a proper error code
+- clk: qcom: gpucc-sm8150: Update the gpu_cc_pll1 config
+- media: cx231xx: fix a memleak in cx231xx_init_isoc
+- drm/bridge: tc358767: Fix return value on error case
+- drm/bridge: cdns-mhdp8546: Fix use of uninitialized variable
+- drm/radeon/trinity_dpm: fix a memleak in trinity_parse_power_table
+- drm/radeon/dpm: fix a memleak in sumo_parse_power_table
+- drm/msm/dpu: correct clk bit for WB2 block
+- drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq
+- ASoC: SOF: topology: Use partial match for disconnecting DAI link and DAI widget
+- ASoC: Intel: sof_sdw_rt_sdca_jack_common: ctx->headset_codec_dev = NULL
+- ASoC: Intel: glk_rt5682_max98357a: fix board id mismatch
+- media: v4l: async: Fix duplicated list deletion
+- drm/drv: propagate errors from drm_modeset_register_all()
+- drm/msm/dsi: Use pm_runtime_resume_and_get to prevent refcnt leaks
+- drm/msm/dpu: Add missing safe_lut_tbl in sc8180x catalog
+- drm/msm/mdp4: flush vblank event on disable
+- ASoC: cs35l33: Fix GPIO name and drop legacy include
+- drm/imx/lcdc: Fix double-free of driver data
+- drm/tidss: Fix dss reset
+- drm/tidss: Check for K2G in in dispc_softreset()
+- drm/tidss: Return error value from from softreset
+- drm/tidss: Move reset to the end of dispc_init()
+- drm/radeon: check return value of radeon_ring_lock()
+- drm/radeon/r100: Fix integer overflow issues in r100_cs_track_check()
+- drm/radeon/r600_cs: Fix possible int overflows in r600_cs_check_reg()
+- drm/bridge: Fix typo in post_disable() description
+- media: amphion: Fix VPU core alias name
+- media: rkvdec: Hook the (TRY_)DECODER_CMD stateless ioctls
+- media: verisilicon: Hook the (TRY_)DECODER_CMD stateless ioctls
+- media: visl: Hook the (TRY_)DECODER_CMD stateless ioctls
+- media: mtk-jpeg: Remove cancel worker in mtk_jpeg_remove to avoid the crash of multi-core JPEG devices
+- media: pvrusb2: fix use after free on context disconnection
+- drm/tilcdc: Fix irq free on unload
+- drm/bridge: tpd12s015: Drop buggy __exit annotation for remove function
+- drm/nouveau/fence:: fix warning directly dereferencing a rcu pointer
+- drm/panel-elida-kd35t133: hold panel in reset for unprepare
+- drm/panel: nv3051d: Hold panel in reset for unprepare
+- RDMA/usnic: Silence uninitialized symbol smatch warnings
+- drm/panfrost: Really power off GPU cores in panfrost_gpu_power_off()
+- drm/dp_mst: Fix fractional DSC bpp handling
+- Revert "drm/omapdrm: Annotate dma-fence critical section in commit path"
+- Revert "drm/tidss: Annotate dma-fence critical section in commit path"
+- ARM: davinci: always select CONFIG_CPU_ARM926T
+- ip6_tunnel: fix NEXTHDR_FRAGMENT handling in ip6_tnl_parse_tlv_enc_lim()
+- rxrpc: Fix skbuff cleanup of call's recvmsg_queue and rx_oos_queue
+- mlxbf_gige: Enable the GigE port in mlxbf_gige_open
+- mlxbf_gige: Fix intermittent no ip issue
+- net/sched: act_ct: fix skb leak and crash on ooo frags
+- blk-cgroup: fix rcu lockdep warning in blkg_lookup()
+- sctp: fix busy polling
+- sctp: support MSG_ERRQUEUE flag in recvmsg()
+- bpf: sockmap, fix proto update hook to avoid dup calls
+- wifi: cfg80211: parse all ML elements in an ML probe response
+- wifi: cfg80211: correct comment about MLD ID
+- arm64: dts: rockchip: Fix led pinctrl of lubancat 1
+- null_blk: don't cap max_hw_sectors to BLK_DEF_MAX_SECTORS
+- Bluetooth: btmtkuart: fix recv_buf() return value
+- Bluetooth: btnxpuart: fix recv_buf() return value
+- Bluetooth: Fix bogus check for re-auth no supported with non-ssp
+- netfilter: nf_tables: validate chain type update if available
+- netfilter: nf_tables: mark newset as dead on transaction abort
+- wifi: iwlwifi: assign phy_ctxt before eSR activation
+- wifi: iwlwifi: fix out of bound copy_from_user
+- wifi: iwlwifi: mvm: send TX path flush in rfkill
+- wifi: iwlwifi: mvm: set siso/mimo chains to 1 in FW SMPS request
+- wifi: rtlwifi: rtl8192se: using calculate_bit_shift()
+- wifi: rtlwifi: rtl8192ee: using calculate_bit_shift()
+- wifi: rtlwifi: rtl8192de: using calculate_bit_shift()
+- wifi: rtlwifi: rtl8192ce: using calculate_bit_shift()
+- wifi: rtlwifi: rtl8192cu: using calculate_bit_shift()
+- wifi: rtlwifi: rtl8192c: using calculate_bit_shift()
+- wifi: rtlwifi: rtl8188ee: phy: using calculate_bit_shift()
+- wifi: rtlwifi: add calculate_bit_shift()
+- bpf: Use c->unit_size to select target cache during free
+- bpf: Use pcpu_alloc_size() in bpf_mem_free{_rcu}()
+- bpf: Re-enable unit_size checking for global per-cpu allocator
+- arm64: dts: qcom: sc8180x: Fix up PCIe nodes
+- arm64: dts: qcom: sc8180x: switch PCIe QMP PHY to new style of bindings
+- arm64: dts: qcom: sc8180x: Mark PCIe hosts cache-coherent
+- arm64: dts: qcom: sm8550: Update idle state time requirements
+- arm64: dts: qcom: sm8550: Separate out X3 idle state
+- arm64: dts: qcom: ipq6018: fix clock rates for GCC_USB0_MOCK_UTMI_CLK
+- arm64: dts: qcom: sc7280: Mark SDHCI hosts as cache-coherent
+- soc: qcom: llcc: Fix LLCC_TRP_ATTR2_CFGn offset
+- arm64: dts: qcom: sm8150-hdk: fix SS USB regulators
+- arm64: dts: qcom: sm8150: make dispcc cast minimal vote on MMCX
+- arm64: dts: qcom: sm6375: Hook up MPM
+- arm64: dts: qcom: sm6375: fix USB wakeup interrupt types
+- soc: qcom: llcc: Fix dis_cap_alloc and retain_on_pc configuration
+- arm64: dts: qcom: acer-aspire1: Correct audio codec definition
+- bpf: Limit the number of kprobes when attaching program to multiple kprobes
+- bpf: Limit the number of uprobes when attaching program to multiple uprobes
+- dma-mapping: clear dev->dma_mem to NULL after freeing it
+- virtio/vsock: send credit update during setting SO_RCVLOWAT
+- virtio/vsock: fix logic which reduces credit update messages
+- ipmr: support IP_PKTINFO on cache report IGMP msg
+- selftests/net: fix grep checking for fib_nexthop_multiprefix
+- bpf: Fix a race condition between btf_put() and map_free()
+- ARM: dts: stm32: don't mix SCMI and non-SCMI board compatibles
+- scsi: hisi_sas: Correct the number of global debugfs registers
+- scsi: hisi_sas: Rollback some operations if FLR failed
+- scsi: hisi_sas: Check before using pointer variables
+- scsi: hisi_sas: Replace with standard error code return value
+- scsi: ufs: qcom: Fix the return value when platform_get_resource_byname() fails
+- scsi: ufs: qcom: Fix the return value of ufs_qcom_ice_program_key()
+- arm64: dts: imx8mm: Reduce GPU to nominal speed
+- arm64: dts: renesas: white-hawk-cpu: Fix missing serial console pin control
+- arm64: dts: xilinx: Apply overlays to base dtbs
+- selftests/bpf: Relax time_tai test for equal timestamps in tai_forward
+- wifi: iwlwifi: don't support triggered EHT CQI feedback
+- wifi: mt76: mt7921: fix country count limitation for CLC
+- arm64: dts: mediatek: mt8186: fix address warning for ADSP mailboxes
+- arm64: dts: mediatek: mt8186: Fix alias prefix for ovl_2l0
+- arm64: dts: mediatek: mt8195: revise VDOSYS RDMA node name
+- arm64: dts: mediatek: mt8183: correct MDP3 DMA-related nodes
+- dt-bindings: media: mediatek: mdp3: correct RDMA and WROT node with generic names
+- bpf: Fix accesses to uninit stack slots
+- bpf: Guard stack limits against 32bit overflow
+- arm64: dts: hisilicon: hikey970-pmic: fix regulator cells properties
+- bpf: Fix verification of indirect var-off stack access
+- wifi: mt76: mt7921s: fix workqueue problem causes STA association fail
+- wifi: mt76: mt7915: also MT7981 is 3T3R but nss2 on 5 GHz band
+- wifi: mt76: mt7915: fix EEPROM offset of TSSI flag on MT7981
+- wifi: mt76: mt7996: fix rate usage of inband discovery frames
+- wifi: mt76: mt7996: fix the size of struct bss_rate_tlv
+- wifi: mt76: mt7915: fallback to non-wed mode if platform_get_resource fails in mt7915_mmio_wed_init()
+- wifi: mt76: fix typo in mt76_get_of_eeprom_from_nvmem function
+- arm64: dts: qcom: sm8550: fix USB wakeup interrupt types
+- arm64: dts: qcom: sc7280: fix usb_2 wakeup interrupt types
+- arm64: dts: qcom: sa8775p: fix USB wakeup interrupt types
+- arm64: dts: qcom: sc7280: Mark Adreno SMMU as DMA coherent
+- arm64: dts: qcom: sc7280: Fix up GPU SIDs
+- arm64: dts: qcom: sm8350: Fix DMA0 address
+- arm64: dts: qcom: sm6125: add interrupts to DWC3 USB controller
+- arm64: dts: qcom: sdm845-db845c: correct LED panic indicator
+- arm64: dts: qcom: qrb5165-rb5: correct LED panic indicator
+- arm64: dts: qcom: qrb2210-rb1: use USB host mode
+- arm64: dts: qcom: qrb2210-rb1: Hook up USB3
+- scsi: fnic: Return error if vmalloc() failed
+- bpf: fix check for attempt to corrupt spilled pointer
+- selftests/net: specify the interface when do arping
+- bpf: Defer the free of inner map when necessary
+- bpf: Add map and need_defer parameters to .map_fd_put_ptr()
+- arm64: dts: qcom: sm6350: Make watchdog bark interrupt edge triggered
+- arm64: dts: qcom: sc8280xp: Make watchdog bark interrupt edge triggered
+- arm64: dts: qcom: sa8775p: Make watchdog bark interrupt edge triggered
+- arm64: dts: qcom: sm8250: Make watchdog bark interrupt edge triggered
+- arm64: dts: qcom: sm8150: Make watchdog bark interrupt edge triggered
+- arm64: dts: qcom: sdm845: Make watchdog bark interrupt edge triggered
+- arm64: dts: qcom: sc7280: Make watchdog bark interrupt edge triggered
+- arm64: dts: qcom: sc7280: Mark some nodes as 'reserved'
+- arm64: dts: qcom: sc7180: Make watchdog bark interrupt edge triggered
+- arm64: dts: qcom: sm8550: correct TX Soundwire clock
+- arm64: dts: qcom: sm8450: correct TX Soundwire clock
+- arm64: dts: qcom: sc8180x-primus: Fix HALL_INT polarity
+- dt-bindings: arm: qcom: Fix html link
+- ARM: dts: qcom: sdx65: correct SPMI node name
+- ARM: dts: qcom: sdx65: correct PCIe EP phy-names
+- bpf: enforce precision of R0 on callback return
+- selftests/bpf: Fix erroneous bitmask operation
+- wifi: rtw88: sdio: Honor the host max_req_size in the RX path
+- arm64: dts: ti: iot2050: Re-add aliases
+- arm64: dts: ti: k3-am65-main: Fix DSS irq trigger type
+- arm64: dts: ti: k3-am62a-main: Fix GPIO pin count in DT nodes
+- wifi: rtlwifi: rtl8821ae: phy: fix an undefined bitwise shift behavior
+- scsi: bfa: Use the proper data type for BLIST flags
+- firmware: ti_sci: Fix an off-by-one in ti_sci_debugfs_create()
+- net/ncsi: Fix netlink major/minor version numbers
+- ARM: dts: qcom: apq8064: correct XOADC register address
+- wifi: libertas: stop selecting wext
+- wifi: ath11k: Defer on rproc_get failure
+- bpf: Add crosstask check to __bpf_get_stack
+- bpf, lpm: Fix check prefixlen before walking trie
+- wifi: rtw88: fix RX filter in FIF_ALLMULTI flag
+- wifi: plfxlc: check for allocation failure in plfxlc_usb_wreq_async()
+- ARM: dts: qcom: msm8226: provide dsi phy clocks to mmcc
+- arm64: dts: qcom: sc8280xp-x13s: add missing camera LED pin config
+- arm64: dts: qcom: sc8280xp-x13s: Use the correct DP PHY compatible
+- arm64: dts: qcom: qrb4210-rb2: don't force usb peripheral mode
+- asm-generic: Fix 32 bit __generic_cmpxchg_local
+- pNFS: Fix the pnfs block driver's calculation of layoutget size
+- SUNRPC: fix _xprt_switch_find_current_entry logic
+- NFSv4.1/pnfs: Ensure we handle the error NFS4ERR_RETURNCONFLICT
+- NFS: Use parent's objective cred in nfs_access_login_time()
+- blocklayoutdriver: Fix reference leak of pnfs_device_node
+- csky: fix arch_jump_label_transform_static override
+- crypto: scomp - fix req->dst buffer overflow
+- crypto: sahara - do not resize req->src when doing hash operations
+- crypto: sahara - fix processing hash requests with req->nbytes < sg->length
+- crypto: sahara - improve error handling in sahara_sha_process()
+- crypto: sahara - fix wait_for_completion_timeout() error handling
+- crypto: sahara - fix ahash reqsize
+- crypto: sahara - handle zero-length aes requests
+- crypto: sahara - avoid skcipher fallback code duplication
+- crypto: virtio - Wait for tasklet to complete on device remove
+- dlm: fix format seq ops type 4
+- gfs2: fix kernel BUG in gfs2_quota_cleanup
+- fs: indicate request originates from old mount API
+- erofs: fix memory leak on short-lived bounced pages
+- pstore: ram_core: fix possible overflow in persistent_ram_init_ecc()
+- crypto: sahara - fix error handling in sahara_hw_descriptor_create()
+- crypto: sahara - fix processing requests with cryptlen < sg->length
+- crypto: sahara - fix ahash selftest failure
+- crypto: sahara - fix cbc selftest failure
+- crypto: sahara - remove FLAGS_NEW_KEY logic
+- crypto: safexcel - Add error handling for dma_map_sg() calls
+- crypto: af_alg - Disallow multiple in-flight AIO requests
+- crypto: ccp - fix memleak in ccp_init_dm_workarea
+- crypto: sa2ul - Return crypto_aead_setkey to transfer the error
+- crypto: virtio - Handle dataq logic with tasklet
+- crypto: jh7110 - Correct deferred probe return
+- crypto: rsa - add a check for allocation failure
+- selinux: Fix error priority for bind with AF_UNSPEC on PF_INET6 socket
+- drivers/thermal/loongson2_thermal: Fix incorrect PTR_ERR() judgment
+- cpuidle: haltpoll: Do not enable interrupts when entering idle
+- kunit: debugfs: Fix unchecked dereference in debugfs_print_results()
+- thermal: core: Fix NULL pointer dereference in zone registration error path
+- ACPI: extlog: Clear Extended Error Log status when RAS_CEC handled the error
+- ACPI: LPSS: Fix the fractional clock divider flags
+- spi: sh-msiof: Enforce fixed DTDL for R-Car H3
+- efivarfs: Free s_fs_info on unmount
+- calipso: fix memory leak in netlbl_calipso_add_pass()
+- cpufreq: scmi: process the result of devm_of_clk_add_hw_provider()
+- platform/x86/intel/vsec: Fix xa_alloc memory leak
+- spi: cadence-quadspi: add missing clk_disable_unprepare() in cqspi_probe()
+- KEYS: encrypted: Add check for strsep
+- ACPI: LPIT: Avoid u32 multiplication overflow
+- ACPI: video: check for error while searching for backlight device parent
+- mtd: rawnand: Increment IFC_TIMEOUT_MSECS for nand controller response
+- spi: spi-zynqmp-gqspi: fix driver kconfig dependencies
+- perf/x86/intel/uncore: Fix NULL pointer dereference issue in upi_fill_topology()
+- sched/fair: Update min_vruntime for reweight_entity() correctly
+- powerpc/imc-pmu: Add a null pointer check in update_events_in_group()
+- powerpc/powernv: Add a null pointer check in opal_powercap_init()
+- powerpc/powernv: Add a null pointer check in opal_event_init()
+- powerpc/powernv: Add a null pointer check to scom_debug_init_one()
+- powerpc/rtas: Avoid warning on invalid token argument to sys_rtas()
+- powerpc/hv-gpci: Add return value check in affinity_domain_via_partition_show function
+- selftests/powerpc: Fix error handling in FPU/VMX preemption tests
+- KVM: PPC: Book3S HV: Handle pending exceptions on guest entry with MSR_EE
+- KVM: PPC: Book3S HV: Introduce low level MSR accessor
+- KVM: PPC: Book3S HV: Use accessors for VCPU registers
+- drivers/perf: hisi: Fix some event id for HiSilicon UC pmu
+- perf/arm-cmn: Fix HN-F class_occup_id events
+- powerpc/pseries/memhp: Fix access beyond end of drmem array
+- powerpc/44x: select I2C for CURRITUCK
+- x86: Fix CPUIDLE_FLAG_IRQ_ENABLE leaking timer reprogram
+- powerpc: add crtsavres.o to always-y instead of extra-y
+- EDAC/thunderx: Fix possible out-of-bounds string access
+- x86/mce/inject: Clear test status value
+- x86/lib: Fix overflow when counting digits
+- mm/memory_hotplug: fix memmap_on_memory sysfs value retrieval
+- scripts/decode_stacktrace.sh: optionally use LLVM utilities
+- coresight: etm4x: Fix width of CCITMIN field
+- PCI: Add ACS quirk for more Zhaoxin Root Ports
+- leds: ledtrig-tty: Free allocated ttyname buffer on deactivate
+- parport: parport_serial: Add Brainboxes device IDs and geometry
+- parport: parport_serial: Add Brainboxes BAR details
+- uio: Fix use-after-free in uio_open
+- binder: fix comment on binder_alloc_new_buf() return value
+- binder: fix trivial typo of binder_free_buf_locked()
+- binder: fix use-after-free in shinker's callback
+- binder: use EPOLLERR from eventpoll.h
+- ksmbd: free ppace array on error in parse_dacl
+- ksmbd: don't allow O_TRUNC open on read-only share
+- drm/amd/display: Pass pwrseq inst for backlight and ABM
+- ASoC: SOF: Intel: hda-codec: Delay the codec device registration
+- bus: moxtet: Add spi device table
+- bus: moxtet: Mark the irq as shared
+- ACPI: resource: Add another DMI match for the TongFang GMxXGxx
+- ALSA: hda/realtek: Fix mute and mic-mute LEDs for HP Envy X360 13-ay0xxx
+- drm/crtc: fix uninitialized variable use
+- x86/csum: clean up `csum_partial' further
+- x86/csum: Remove unnecessary odd handling
+- ARM: sun9i: smp: fix return code check of of_property_match_string
+- connector: Fix proc_event_num_listeners count not cleared
+- net: qrtr: ns: Return 0 if server port is not present
+- nfc: Do not send datagram if socket state isn't LLCP_BOUND
+- virtio_blk: fix snprintf truncation compiler warning
+- ida: Fix crash in ida_free when the bitmap is empty
+- posix-timers: Get rid of [COMPAT_]SYS_NI() uses
+- pinctrl: cy8c95x0: Fix get_pincfg
+- pinctrl: cy8c95x0: Fix regression
+- pinctrl: cy8c95x0: Fix typo
+- drm/amd/display: get dprefclk ss info from integration info table
+- drm/amd/display: Add case for dcn35 to support usb4 dmub hpd event
+- drm/amdkfd: svm range always mapped flag not working on APU
+- i2c: rk3x: fix potential spinlock recursion on poll
+- smb: client: fix potential OOB in smb2_dump_detail()
+- HID: nintendo: Prevent divide-by-zero on code
+- dm audit: fix Kconfig so DM_AUDIT depends on BLK_DEV_DM
+- ALSA: hda/realtek: Add quirks for ASUS Zenbook 2022 Models
+- ASoC: Intel: bytcr_rt5640: Add new swapped-speakers quirk
+- ASoC: Intel: bytcr_rt5640: Add quirk for the Medion Lifetab S10346
+- platform/x86/amd/pmc: Disable keyboard wakeup on AMD Framework 13
+- platform/x86/amd/pmc: Move keyboard wakeup disablement detection to pmc-quirks
+- platform/x86/amd/pmc: Only run IRQ1 firmware version check on Cezanne
+- platform/x86/amd/pmc: Move platform defines to header
+- platform/x86: thinkpad_acpi: fix for incorrect fan reporting on some ThinkPad systems
+- HID: nintendo: fix initializer element is not constant error
+- kselftest: alsa: fixed a print formatting warning
+- driver core: Add a guard() definition for the device_lock()
+- Input: xpad - add Razer Wolverine V2 support
+- wifi: iwlwifi: pcie: avoid a NULL pointer dereference
+- ARC: fix smatch warning
+- ARC: fix spare error
+- s390/scm: fix virtual vs physical address confusion
+- ASoC: cs35l45: Prevents spinning during runtime suspend
+- ASoC: cs35l45: Prevent IRQ handling when suspending/resuming
+- ASoC: cs35l45: Use modern pm_ops
+- pinctrl: amd: Mask non-wake source pins with interrupt enabled at suspend
+- Input: i8042 - add nomux quirk for Acer P459-G2-M
+- Input: atkbd - skip ATKBD_CMD_GETID in translated mode
+- reset: hisilicon: hi6220: fix Wvoid-pointer-to-enum-cast warning
+- Input: psmouse - enable Synaptics InterTouch for ThinkPad L14 G1
+- ring-buffer: Do not record in NMI if the arch does not support cmpxchg in NMI
+- tracing: Fix uaf issue when open the hist or hist_debug file
+- MIPS: dts: loongson: drop incorrect dwmac fallback compatible
+- stmmac: dwmac-loongson: drop useless check for compatible fallback
+- tracing: Add size check when printing trace_marker output
+- tracing: Have large events show up as '[LINE TOO BIG]' instead of nothing
+- jbd2: fix soft lockup in journal_finish_inode_data_buffers()
+- efi/loongarch: Use load address to calculate kernel entry address
+- platform/x86: intel-vbtn: Fix missing tablet-mode-switch events
+- neighbour: Don't let neigh_forced_gc() disable preemption for long
+- drm/crtc: Fix uninit-value bug in drm_mode_setcrtc
+- jbd2: increase the journal IO's priority
+- jbd2: correct the printing of write_flags in jbd2_write_superblock()
+- soundwire: intel_ace2x: fix AC timing setting for ACE2.x
+- clk: rockchip: rk3128: Fix HCLK_OTG gate register
+- clk: rockchip: rk3568: Add PLL rate for 292.5MHz
+- LoongArch: Preserve syscall nr across execve()
+- LoongArch: Set unwind stack type to unknown rather than set error flag
+- LoongArch: Apply dynamic relocations for LLD
+- hwmon: (corsair-psu) Fix probe when built-in
+- ALSA: pcmtest: stop timer before buffer is released
+- drm/exynos: fix a wrong error checking
+- drm/exynos: fix a potential error pointer dereference
+- drm/amdgpu: Add NULL checks for function pointers
+- drm/amd/display: Add monitor patch for specific eDP
+- arm64: dts: rockchip: Fix PCI node addresses on rk3399-gru
+- nvme: fix deadlock between reset and scan
+- nvme: prevent potential spectre v1 gadget
+- nvme-ioctl: move capable() admin check to the end
+- nvme: ensure reset state check ordering
+- nvme: introduce helper function to get ctrl state
+- ASoC: da7219: Support low DC impedance headset
+- net/tg3: fix race condition in tg3_reset_task()
+- pds_vdpa: set features order
+- pds_vdpa: clear config callback when status goes to 0
+- pds_vdpa: fix up format-truncation complaint
+- ASoC: SOF: ipc4-topology: Correct data structures for the GAIN module
+- ASoC: SOF: ipc4-topology: Correct data structures for the SRC module
+- ASoC: hdac_hda: Conditionally register dais for HDMI and Analog
+- ASoC: amd: yc: Add DMI entry to support System76 Pangolin 13
+- nouveau/tu102: flush all pdbs on vmm flush
+- ASoC: SOF: sof-audio: Modify logic for enabling/disabling topology cores
+- ASoC: SOF: ipc4-topology: Add core_mask in struct snd_sof_pipeline
+- ASoC: Intel: skl_hda_dsp_generic: Drop HDMI routes when HDMI is not available
+- ASoC: fsl_xcvr: refine the requested phy clock frequency
+- ASoC: rt5650: add mutex to avoid the jack detection failure
+- ASoC: fsl_xcvr: Enable 2 * TX bit clock for spdif only case
+- ASoC: cs43130: Fix incorrect frame delay configuration
+- ASoC: cs43130: Fix the position of const qualifier
+- ASoC: Intel: Skylake: mem leak in skl register function
+- ASoC: SOF: topology: Fix mem leak in sof_dai_load()
+- ASoC: nau8822: Fix incorrect type in assignment and cast to restricted __be16
+- ASoC: Intel: Skylake: Fix mem leak in few functions
+- arm64: dts: rockchip: fix rk356x pcie msg interrupt name
+- ASoC: wm8974: Correct boost mixer inputs
+- ASoC: amd: yc: Add HP 255 G10 into quirk table
+- nvme-core: check for too small lba shift
+- blk-mq: don't count completed flush data request as inflight in case of quiesce
+- smb: client, common: fix fortify warnings
+- drm/amdgpu: Use another offset for GC 9.4.3 remap
+- drm/amdkfd: Free gang_ctx_bo and wptr_bo in pqm_uninit
+- drm/amdgpu: Fix cat debugfs amdgpu_regs_didt causes kernel null pointer
+- drm/amd/display: update dcn315 lpddr pstate latency
+- drm/amdkfd: Use common function for IP version check
+- drm/amdgpu: Do not issue gpu reset from nbio v7_9 bif interrupt
+- block: warn once for each partition in bio_check_ro()
+- io_uring: use fget/fput consistently
+- nvme-core: fix a memory leak in nvme_ns_info_from_identify()
+- ALSA: hda: intel-nhlt: Ignore vbps when looking for DMIC 32 bps format
+- debugfs: fix automount d_fsdata usage
+- wifi: mac80211: handle 320 MHz in ieee80211_ht_cap_ie_to_sta_ht_cap
+- wifi: avoid offset calculation on NULL pointer
+- wifi: cfg80211: lock wiphy mutex for rfkill poll
+- mptcp: fix uninit-value in mptcp_incoming_options
+- ALSA: hda - Fix speaker and headset mic pin config for CHUWI CoreBook XPro
+- pinctrl: lochnagar: Don't build on MIPS
+- pinctrl: s32cc: Avoid possible string truncation
+- nfsd: drop the nfsd_put helper
+- media: qcom: camss: Comment CSID dt_id field
+- cxl/memdev: Hold region_rwsem during inject and clear poison ops
+- cxl/hdm: Fix a benign lockdep splat
+- cxl: Add cxl_num_decoders_committed() usage to cxl_test
+- mmc: sdhci-sprd: Fix eMMC init failure after hw reset
+- mmc: core: Cancel delayed work before releasing host
+- mmc: rpmb: fixes pause retune on all RPMB partitions.
+- mmc: meson-mx-sdhc: Fix initialization frozen issue
+- drm/amd/display: Fix sending VSC (+ colorimetry) packets for DP/eDP displays without PSR
+- drm/amd/display: add nv12 bounding box
+- drm/amdgpu: skip gpu_info fw loading on navi12
+- mm: fix unmap_mapping_range high bits shift bug
+- i2c: core: Fix atomic xfer check for non-preempt config
+- x86/kprobes: fix incorrect return address calculation in kprobe_emulate_call_indirect
+- firewire: ohci: suppress unexpected system reboot in AMD Ryzen machines and ASM108x/VT630x PCIe cards
+- mm/mglru: skip special VMAs in lru_gen_look_around()
+- net: constify sk_dst_get() and __sk_dst_get() argument
+- cxl/pmu: Ensure put_device on pmu devices
+- net: prevent mss overflow in skb_segment()
+- powerpc/pseries/vas: Migration suspend waits for no in-progress open windows
+- RISCV: KVM: update external interrupt atomically for IMSIC swfile
+- dmaengine: fsl-edma: fix wrong pointer check in fsl_edma3_attach_pd()
+- dmaengine: idxd: Protect int_handle field in hw descriptor
+- drm/amd/display: Increase frame warning limit with KASAN or KCSAN in dml
+- kernel/resource: Increment by align value in get_free_mem_region()
+- cxl/core: Always hold region_rwsem while reading poison lists
+- cxl: Add cxl_decoders_committed() helper
+- drm/amd/display: Increase num voltage states to 40
+- drm/i915: Call intel_pre_plane_updates() also for pipes getting enabled
+- clk: rockchip: rk3128: Fix SCLK_SDMMC's clock name
+- clk: rockchip: rk3128: Fix aclk_peri_src's parent
+- phy: sunplus: return negative error code in sp_usb_phy_probe
+- phy: mediatek: mipi: mt8183: fix minimal supported frequency
+- iio: imu: adis16475: use bit numbers in assign_bit()
+- dmaengine: fsl-edma: Add judgment on enabling round robin arbitration
+- dmaengine: fsl-edma: Do not suspend and resume the masked dma channel when the system is sleeping
+- dmaengine: ti: k3-psil-am62a: Fix SPI PDMA data
+- dmaengine: ti: k3-psil-am62: Fix SPI PDMA data
+- phy: ti: gmii-sel: Fix register offset when parent is not a syscon node
+- KVM: s390: vsie: fix wrong VIR 37 when MSO is used
+- riscv: don't probe unaligned access speed if already done
+- rcu/tasks-trace: Handle new PF_IDLE semantics
+- rcu/tasks: Handle new PF_IDLE semantics
+- rcu: Introduce rcu_cpu_online()
+- rcu: Break rcu_node_0 --> &rq->__lock order
+- ACPI: thermal: Fix acpi_thermal_unregister_thermal_zone() cleanup
+- RDMA/mlx5: Fix mkey cache WQ flush
+- clk: si521xx: Increase stack based print buffer size in probe
+- vfio/mtty: Overhaul mtty interrupt handling
+- crypto: qat - fix double free during reset
+- crypto: xts - use 'spawn' for underlying single-block cipher
+- bpftool: Align output skeleton ELF code
+- bpftool: Fix -Wcast-qual warning
+- tcp: derive delack_max from rto_min
+- media: qcom: camss: Fix genpd cleanup
+- media: qcom: camss: Fix V4L2 async notifier error path
+- xsk: add multi-buffer support for sockets sharing umem
+- mm/memory-failure: pass the folio and the page to collect_procs()
+- mm: convert DAX lock/unlock page to lock/unlock folio
+- net: Implement missing SO_TIMESTAMPING_NEW cmsg support
+- bnxt_en: Remove mis-applied code from bnxt_cfg_ntp_filters()
+- net: ravb: Wait for operating mode to be applied
+- asix: Add check for usbnet_get_endpoints
+- octeontx2-af: Re-enable MAC TX in otx2_stop processing
+- octeontx2-af: Always configure NIX TX link credits based on max frame size
+- net/smc: fix invalid link access in dumping SMC-R connections
+- net/qla3xxx: fix potential memleak in ql_alloc_buffer_queues
+- virtio_net: fix missing dma unmap for resize
+- virtio_net: avoid data-races on dev->stats fields
+- apparmor: Fix move_mount mediation by detecting if source is detached
+- igc: Fix hicredit calculation
+- i40e: Restore VF MSI-X state during PCI reset
+- ASoC: meson: g12a-tohdmitx: Fix event generation for S/PDIF mux
+- ASoC: meson: g12a-toacodec: Fix event generation
+- ASoC: meson: g12a-tohdmitx: Validate written enum values
+- ASoC: meson: g12a-toacodec: Validate written enum values
+- i40e: fix use-after-free in i40e_aqc_add_filters()
+- net: Save and restore msg_namelen in sock_sendmsg
+- netfilter: nft_immediate: drop chain reference counter on error
+- netfilter: nf_nat: fix action not being set for all ct states
+- net: bcmgenet: Fix FCS generation for fragmented skbuffs
+- sfc: fix a double-free bug in efx_probe_filters
+- ARM: sun9i: smp: Fix array-index-out-of-bounds read in sunxi_mc_smp_init
+- selftests: bonding: do not set port down when adding to bond
+- net: Implement missing getsockopt(SO_TIMESTAMPING_NEW)
+- r8169: Fix PCI error on system resume
+- net: sched: em_text: fix possible memory leak in em_text_destroy()
+- mlxbf_gige: fix receive packet race condition
+- ASoC: mediatek: mt8186: fix AUD_PAD_TOP register and offset
+- ASoC: fsl_rpmsg: Fix error handler with pm_runtime_enable
+- igc: Check VLAN EtherType mask
+- igc: Check VLAN TCI mask
+- igc: Report VLAN EtherType matching back to user
+- i40e: Fix filter input checks to prevent config with invalid values
+- ice: Shut down VSI with "link-down-on-close" enabled
+- ice: Fix link_down_on_close message
+- drm/i915/perf: Update handling of MMIO triggered reports
+- drm/i915/dp: Fix passing the correct DPCD_REV for drm_dp_set_phy_test_pattern
+- octeontx2-af: Fix marking couple of structure as __packed
+- nfc: llcp_core: Hold a ref to llcp_local->dev when holding a ref to llcp_local
+- netfilter: nf_tables: set transport offset from mac header for netdev/egress
+- drm/bridge: ps8640: Fix size mismatch warning w/ len
+- drm/bridge: ti-sn65dsi86: Never store more than msg->size bytes in AUX xfer
+- drm/bridge: parade-ps8640: Never store more than msg->size bytes in AUX xfer
+- wifi: iwlwifi: pcie: don't synchronize IRQs from IRQ
+- accel/qaic: Implement quirk for SOC_HW_VERSION
+- accel/qaic: Fix GEM import path code
+- KVM: x86/pmu: fix masking logic for MSR_CORE_PERF_GLOBAL_CTRL
+- cifs: do not depend on release_iface for maintaining iface_list
+- cifs: cifs_chan_is_iface_active should be called with chan_lock held
+- drm/mgag200: Fix gamma lut not initialized for G200ER, G200EV, G200SE
+- Revert "PCI/ASPM: Remove pcie_aspm_pm_state_change()"
+- mptcp: prevent tcp diag from closing listener subflows
+- drm/amd/display: pbn_div need be updated for hotplug event
+- ALSA: hda/realtek: Fix mute and mic-mute LEDs for HP ProBook 440 G6
+- ALSA: hda/realtek: fix mute/micmute LEDs for a HP ZBook
+- ALSA: hda/realtek: enable SND_PCI_QUIRK for hp pavilion 14-ec1xxx series
+- ALSA: hda/tas2781: remove sound controls in unbind
+- ALSA: hda/tas2781: move set_drv_data outside tasdevice_init
+- ALSA: hda/tas2781: do not use regcache
+- keys, dns: Fix missing size check of V1 server-list header
+- Revert "platform/x86: p2sb: Allow p2sb_bar() calls during PCI device probe"
+- netfilter: nf_tables: skip set commit for deleted/destroyed sets
+- wifi: nl80211: fix deadlock in nl80211_set_cqm_rssi (6.6.x)
+- wifi: cfg80211: fix CQM for non-range use
+- tracing: Fix blocked reader of snapshot buffer
+- ftrace: Fix modification of direct_function hash while in use
+- ring-buffer: Fix wake ups when buffer_percent is set to 100
+- Revert "nvme-fc: fix race between error recovery and creating association"
+- mm/memory-failure: check the mapcount of the precise page
+- mm/memory-failure: cast index to loff_t before shifting it
+- mm: migrate high-order folios in swap cache correctly
+- mm/filemap: avoid buffered read/write race to read inconsistent data
+- selftests: secretmem: floor the memory size to the multiple of page_size
+- maple_tree: do not preallocate nodes for slot stores
+- platform/x86: p2sb: Allow p2sb_bar() calls during PCI device probe
+- platform/x86/intel/pmc: Move GBE LTR ignore to suspend callback
+- platform/x86/intel/pmc: Allow reenabling LTRs
+- platform/x86/intel/pmc: Add suspend callback
+- block: renumber QUEUE_FLAG_HW_WC
+- mptcp: fix inconsistent state on fastopen race
+- mptcp: fix possible NULL pointer dereference on close
+- mptcp: refactor sndbuf auto-tuning
+- linux/export: Ensure natural alignment of kcrctab array
+- linux/export: Fix alignment for 64-bit ksymtab entries
+- kexec: select CRYPTO from KEXEC_FILE instead of depending on it
+- kexec: fix KEXEC_FILE dependencies
+- virtio_ring: fix syncs DMA memory with different direction
+- fs: cifs: Fix atime update check
+- client: convert to new timestamp accessors
+- fs: new accessor methods for atime and mtime
+- ksmbd: avoid duplicate opinfo_put() call on error of smb21_lease_break_ack()
+- ksmbd: lazy v2 lease break on smb2_write()
+- ksmbd: send v2 lease break notification for directory
+- ksmbd: downgrade RWH lease caching state to RH for directory
+- ksmbd: set v2 lease capability
+- ksmbd: set epoch in create context v2 lease
+- ksmbd: don't update ->op_state as OPLOCK_STATE_NONE on error
+- ksmbd: move setting SMB2_FLAGS_ASYNC_COMMAND and AsyncId
+- ksmbd: release interim response after sending status pending response
+- ksmbd: move oplock handling after unlock parent dir
+- ksmbd: separately allocate ci per dentry
+- ksmbd: prevent memory leak on error return
+- ksmbd: fix kernel-doc comment of ksmbd_vfs_kern_path_locked()
+- ksmbd: no need to wait for binded connection termination at logoff
+- ksmbd: add support for surrogate pair conversion
+- ksmbd: fix missing RDMA-capable flag for IPoIB device in ksmbd_rdma_capable_netdev()
+- ksmbd: fix kernel-doc comment of ksmbd_vfs_setxattr()
+- ksmbd: reorganize ksmbd_iov_pin_rsp()
+- ksmbd: Remove unused field in ksmbd_user struct
+- spi: cadence: revert "Add SPI transfer delays"
+- x86/smpboot/64: Handle X2APIC BIOS inconsistency gracefully
+- x86/alternatives: Disable interrupts and sync when optimizing NOPs in place
+- x86/alternatives: Sync core before enabling interrupts
+- KVM: arm64: vgic: Force vcpu vgic teardown on vcpu destroy
+- KVM: arm64: vgic: Add a non-locking primitive for kvm_vgic_vcpu_destroy()
+- KVM: arm64: vgic: Simplify kvm_vgic_destroy()
+- thunderbolt: Fix memory leak in margining_port_remove()
+- lib/vsprintf: Fix %pfwf when current node refcount == 0
+- gpio: dwapb: mask/unmask IRQ when disable/enale it
+- bus: ti-sysc: Flush posted write only after srst_udelay
+- pinctrl: starfive: jh7100: ignore disabled device tree nodes
+- pinctrl: starfive: jh7110: ignore disabled device tree nodes
+- selftests: mptcp: join: fix subflow_send_ack lookup
+- dm-integrity: don't modify bio's immutable bio_vec in integrity_metadata()
+- tracing / synthetic: Disable events after testing in synth_event_gen_test_init()
+- scsi: core: Always send batch on reset or error handling command
+- Revert "scsi: aacraid: Reply queue mapping to CPUs based on IRQ affinity"
+- nvmem: brcm_nvram: store a copy of NVRAM content
+- spi: atmel: Fix clock issue when using devices with different polarities
+- spi: atmel: Prevent spi transfers from being killed
+- spi: atmel: Do not cancel a transfer upon any signal
+- ring-buffer: Fix slowpath of interrupted event
+- ring-buffer: Remove useless update to write_stamp in rb_try_to_discard()
+- ring-buffer: Fix 32-bit rb_time_read() race with rb_time_cmpxchg()
+- 9p: prevent read overrun in protocol dump tracepoint
+- drm/i915/dmc: Don't enable any pipe DMC events
+- drm/i915: Reject async flips with bigjoiner
+- smb: client: fix OOB in smbCalcSize()
+- smb: client: fix OOB in SMB2_query_info_init()
+- smb: client: fix potential OOB in cifs_dump_detail()
+- smb: client: fix OOB in cifsd when receiving compounded resps
+- nfsd: call nfsd_last_thread() before final nfsd_put()
+- dt-bindings: nvmem: mxs-ocotp: Document fsl,ocotp
+- net: stmmac: fix incorrect flag check in timestamp interrupt
+- net: avoid build bug in skb extension length calculation
+- net: ks8851: Fix TX stall caused by TX buffer overrun
+- net: rfkill: gpio: set GPIO direction
+- net: 9p: avoid freeing uninit memory in p9pdu_vreadf
+- Input: soc_button_array - add mapping for airplane mode button
+- net: usb: ax88179_178a: avoid failed operations when device is disconnected
+- usb: fotg210-hcd: delete an incorrect bounds test
+- usb: typec: ucsi: fix gpio-based orientation detection
+- Bluetooth: Add more enc key size check
+- Bluetooth: MGMT/SMP: Fix address type when using SMP over BREDR/LE
+- Bluetooth: L2CAP: Send reject on command corrupted request
+- Bluetooth: af_bluetooth: Fix Use-After-Free in bt_sock_recvmsg
+- Bluetooth: hci_event: Fix not checking if HCI_OP_INQUIRY has been sent
+- ASoC: tas2781: check the validity of prm_no/cfg_no
+- ALSA: hda/realtek: Add quirk for ASUS ROG GV302XA
+- ALSA: hda/tas2781: select program 0, conf 0 by default
+- USB: serial: option: add Quectel RM500Q R13 firmware support
+- USB: serial: option: add Foxconn T99W265 with new baseline
+- USB: serial: option: add Quectel EG912Y module support
+- USB: serial: ftdi_sio: update Actisense PIDs constant names
+- wifi: cfg80211: fix certs build to not depend on file order
+- wifi: cfg80211: Add my certificate
+- wifi: mt76: fix crash with WED rx support enabled
+- usb-storage: Add quirk for incorrect WP on Kingston DT Ultimate 3.0 G3
+- ARM: dts: Fix occasional boot hang for am3 usb
+- ALSA: usb-audio: Increase delay in MOTU M quirk
+- iio: triggered-buffer: prevent possible freeing of wrong buffer
+- iio: tmag5273: fix temperature offset
+- iio: adc: ti_am335x_adc: Fix return value check of tiadc_request_dma()
+- iio: imu: adis16475: add spi_device_id table
+- iio: common: ms_sensors: ms_sensors_i2c: fix humidity conversion time table
+- iio: adc: imx93: add four channels for imx93 adc
+- iio: kx022a: Fix acceleration value scaling
+- scsi: ufs: core: Let the sq_lock protect sq_tail_slot access
+- scsi: ufs: qcom: Return ufs_qcom_clk_scale_*() errors in ufs_qcom_clk_scale_notify()
+- scsi: bnx2fc: Fix skb double free in bnx2fc_rcv()
+- iio: adc: meson: add separate config for axg SoC family
+- Input: ipaq-micro-keys - add error handling for devm_kmemdup
+- interconnect: qcom: sm8250: Enable sync_state
+- iio: imu: inv_mpu6050: fix an error code problem in inv_mpu6050_read_raw
+- interconnect: Treat xlate() returning NULL node as an error
+- nvme-pci: fix sleeping function called from interrupt context
+- gpiolib: cdev: add gpio_device locking wrapper around gpio_ioctl()
+- pinctrl: at91-pio4: use dedicated lock class for IRQ
+- x86/xen: add CPU dependencies for 32-bit build
+- i2c: aspeed: Handle the coalesced stop conditions with the start conditions.
+- drm/amdgpu: re-create idle bo's PTE during VM state machine reset
+- i2c: qcom-geni: fix missing clk_disable_unprepare() and geni_se_resources_off()
+- ASoC: fsl_sai: Fix channel swap issue on i.MX8MP
+- ASoC: hdmi-codec: fix missing report for jack initial status
+- drm/i915/mtl: Fix HDMI/DP PLL clock selection
+- drm/i915/hwmon: Fix static analysis tool reported issues
+- afs: Fix use-after-free due to get/remove race in volume tree
+- afs: Fix overwriting of result of DNS query
+- keys, dns: Allow key types (eg. DNS) to be reclaimed immediately on expiry
+- net: check dev->gso_max_size in gso_features_check()
+- net/ipv6: Revert remove expired routes with a separated list of routes
+- net: ethernet: mtk_wed: fix possible NULL pointer dereference in mtk_wed_wo_queue_tx_clean()
+- afs: Fix dynamic root lookup DNS check
+- afs: Fix the dynamic root's d_delete to always delete unused dentries
+- net: check vlan filter feature in vlan_vids_add_by_dev() and vlan_vids_del_by_dev()
+- net: mana: select PAGE_POOL
+- ice: Fix PF with enabled XDP going no-carrier after reset
+- ice: alter feature support check for SRIOV and LAG
+- ice: stop trashing VF VSI aggregator node ID information
+- net: phy: skip LED triggers on PHYs on SFP modules
+- bnxt_en: do not map packet buffers twice
+- Bluetooth: hci_core: Fix hci_conn_hash_lookup_cis
+- Bluetooth: hci_event: shut up a false-positive warning
+- Bluetooth: Fix deadlock in vhci_send_frame
+- Bluetooth: Fix not notifying when connection encryption changes
+- net/rose: fix races in rose_kill_by_device()
+- ethernet: atheros: fix a memleak in atl1e_setup_ring_resources
+- net: sched: ife: fix potential use-after-free
+- net: Return error from sk_stream_wait_connect() if sk_wait_event() fails
+- octeontx2-pf: Fix graceful exit during PFC configuration failure
+- net: mscc: ocelot: fix pMAC TX RMON stats for bucket 256-511 and above
+- net: mscc: ocelot: fix eMAC TX RMON stats for bucket 256-511 and above
+- net/mlx5e: Correct snprintf truncation handling for fw_version buffer used by representors
+- net/mlx5e: Correct snprintf truncation handling for fw_version buffer
+- net/mlx5e: Fix error codes in alloc_branch_attr()
+- net/mlx5e: Fix error code in mlx5e_tc_action_miss_mapping_get()
+- net/mlx5: Refactor mlx5_flow_destination->rep pointer to vport num
+- net/mlx5: Fix fw tracer first block check
+- net/mlx5e: XDP, Drop fragmented packets larger than MTU size
+- net/mlx5e: Decrease num_block_tc when unblock tc offload
+- net/mlx5e: Fix overrun reported by coverity
+- net/mlx5e: fix a potential double-free in fs_udp_create_groups
+- net/mlx5e: Fix a race in command alloc flow
+- net/mlx5e: Fix slab-out-of-bounds in mlx5_query_nic_vport_mac_list()
+- Revert "net/mlx5e: fix double free of encap_header"
+- Revert "net/mlx5e: fix double free of encap_header in update funcs"
+- bpf: syzkaller found null ptr deref in unix_bpf proto add
+- ice: fix theoretical out-of-bounds access in ethtool link modes
+- wifi: mac80211: mesh_plink: fix matches_local logic
+- wifi: mac80211: mesh: check element parsing succeeded
+- wifi: mac80211: check defragmentation succeeded
+- wifi: mac80211: don't re-add debugfs during reconfig
+- wifi: mac80211: check if the existing link config remains unchanged
+- wifi: iwlwifi: pcie: add another missing bh-disable for rxq->lock
+- wifi: ieee80211: don't require protected vendor action frames
+- SUNRPC: Revert 5f7fc5d69f6e92ec0b38774c387f5cf7812c5806
+- platform/x86/intel/pmc: Fix hang in pmc_core_send_ltr_ignore()
+- s390/vx: fix save/restore of fpu kernel context
+- reset: Fix crash when freeing non-existent optional resets
+- ARM: OMAP2+: Fix null pointer dereference and memory leak in omap_soc_device_init
+- ARM: dts: dra7: Fix DRA7 L3 NoC node register size
+- arm64: dts: allwinner: h616: update emac for Orange Pi Zero 3
+- spi: spi-imx: correctly configure burst length when using dma
+- drm: Fix FD ownership check in drm_master_check_perm()
+- drm: Update file owner during use
+- drm/i915/edp: don't write to DP_LINK_BW_SET when using rate select
+- drm/i915: Introduce crtc_state->enhanced_framing
+- drm/i915: Fix FEC state dump
+- drm/amd/display: fix hw rotated modes when PSR-SU is enabled
+- btrfs: free qgroup pertrans reserve on transaction abort
+- btrfs: qgroup: use qgroup_iterator in qgroup_convert_meta()
+- btrfs: qgroup: iterate qgroups without memory allocation for qgroup_reserve()
+- mm/damon/core: make damon_start() waits until kdamond_fn() starts
+- mm/damon/core: use number of passed access sampling as a timer
+- bpf: Fix prog_array_map_poke_run map poke update
+- !5451 arm64: Delete macro in the scsnp feature
+- arm64: Delete macro in the scsnp feature
+- !5037 [OLK-6.6] Add support for Mucse Network Adapter(N500/N210)
+- drivers: initial support for rnpgbe drivers from Mucse Technology
+- !4782 [OLK-6.6] Add drivers support for Mucse Network Adapter rnpm (N10/N400)
+- drivers: initial support for rnpm drivers from Mucse Technology
+- !5340 CVE-2023-52593
+- wifi: wfx: fix possible NULL pointer dereference in wfx_set_mfp_ap()
+- !5341 powerpc/lib: Validate size for vector operations
+- powerpc/lib: Validate size for vector operations
+- !5346 v2 s390/vfio-ap: always filter entire AP matrix
+- s390/vfio-ap: always filter entire AP matrix
+- !5248 mm: cachestat: fix folio read-after-free in cache walk
+- mm: cachestat: fix folio read-after-free in cache walk
+- !5212 [OLK-6.6] Support PSPCCP/NTBCCP identification for Hygon 2th and 3th CPU
+- crypto: ccp: Add Hygon CSV support
+- crypto: ccp: Fixup the capability of Hygon PSP during initialization
+- !5318 Backport 6.6.8 LTS Patches
+- RDMA/mlx5: Change the key being sent for MPV device affiliation
+- x86/speculation, objtool: Use absolute relocations for annotations
+- ring-buffer: Have rb_time_cmpxchg() set the msb counter too
+- ring-buffer: Do not try to put back write_stamp
+- ring-buffer: Fix a race in rb_time_cmpxchg() for 32 bit archs
+- ring-buffer: Fix writing to the buffer with max_data_size
+- ring-buffer: Have saved event hold the entire event
+- ring-buffer: Do not update before stamp when switching sub-buffers
+- tracing: Update snapshot buffer on resize if it is allocated
+- ring-buffer: Fix memory leak of free page
+- smb: client: fix OOB in smb2_query_reparse_point()
+- smb: client: fix NULL deref in asn1_ber_decoder()
+- smb: client: fix potential OOBs in smb2_parse_contexts()
+- drm/i915: Fix remapped stride with CCS on ADL+
+- drm/i915: Fix intel_atomic_setup_scalers() plane_state handling
+- drm/i915: Fix ADL+ tiled plane stride when the POT stride is smaller than the original
+- drm/amd/display: Disable PSR-SU on Parade 0803 TCON again
+- drm/amd/display: Restore guard against default backlight value < 1 nit
+- drm/edid: also call add modes in EDID connector update fallback
+- drm/amdgpu: fix tear down order in amdgpu_vm_pt_free
+- btrfs: don't clear qgroup reserved bit in release_folio
+- btrfs: fix qgroup_free_reserved_data int overflow
+- btrfs: free qgroup reserve when ORDERED_IOERR is set
+- kexec: drop dependency on ARCH_SUPPORTS_KEXEC from CRASH_DUMP
+- mm/shmem: fix race in shmem_undo_range w/THP
+- mm/mglru: reclaim offlined memcgs harder
+- mm/mglru: respect min_ttl_ms with memcgs
+- mm/mglru: try to stop at high watermarks
+- mm/mglru: fix underprotected page cache
+- dmaengine: fsl-edma: fix DMA channel leak in eDMAv4
+- dmaengine: stm32-dma: avoid bitfield overflow assertion
+- drm/mediatek: Fix access violation in mtk_drm_crtc_dma_dev_get
+- drm/amdgpu/sdma5.2: add begin/end_use ring callbacks
+- team: Fix use-after-free when an option instance allocation fails
+- arm64: mm: Always make sw-dirty PTEs hw-dirty in pte_modify
+- Revert "selftests: error out if kernel header files are not yet built"
+- ext4: prevent the normalized size from exceeding EXT_MAX_BLOCKS
+- soundwire: stream: fix NULL pointer dereference for multi_link
+- cxl/hdm: Fix dpa translation locking
+- btrfs: do not allow non subvolume root targets for snapshot
+- perf: Fix perf_event_validate_size() lockdep splat
+- HID: hid-asus: add const to read-only outgoing usb buffer
+- arm64: add dependency between vmlinuz.efi and Image
+- smb: client: set correct file type from NFS reparse points
+- smb: client: introduce ->parse_reparse_point()
+- smb: client: implement ->query_reparse_point() for SMB1
+- net: usb: qmi_wwan: claim interface 4 for ZTE MF290
+- eventfs: Do not allow NULL parent to eventfs_start_creating()
+- asm-generic: qspinlock: fix queued_spin_value_unlocked() implementation
+- scripts/checkstack.pl: match all stack sizes for s390
+- nfc: virtual_ncidev: Add variable to check if ndev is running
+- HID: multitouch: Add quirk for HONOR GLO-GXXX touchpad
+- HID: hid-asus: reset the backlight brightness level on resume
+- HID: add ALWAYS_POLL quirk for Apple kb
+- HID: glorious: fix Glorious Model I HID report
+- HID: apple: add Jamesdonkey and A3R to non-apple keyboards list
+- HID: mcp2221: Allow IO to start during probe
+- HID: mcp2221: Set driver data before I2C adapter add
+- platform/x86: intel_telemetry: Fix kernel doc descriptions
+- LoongArch: Mark {dmw,tlb}_virt_to_page() exports as non-GPL
+- LoongArch: Silence the boot warning about 'nokaslr'
+- LoongArch: Record pc instead of offset in la_abs relocation
+- LoongArch: Add dependency between vmlinuz.efi and vmlinux.efi
+- selftests/bpf: fix bpf_loop_bench for new callback verification scheme
+- nvme: catch errors from nvme_configure_metadata()
+- nvme-auth: set explanation code for failure2 msgs
+- bcache: avoid NULL checking to c->root in run_cache_set()
+- bcache: add code comments for bch_btree_node_get() and __bch_btree_node_alloc()
+- bcache: remove redundant assignment to variable cur_idx
+- bcache: avoid oversize memory allocation by small stripe_size
+- blk-throttle: fix lockdep warning of "cgroup_mutex or RCU read lock required!"
+- rxrpc: Fix some minor issues with bundle tracing
+- stmmac: dwmac-loongson: Add architecture dependency
+- usb: aqc111: check packet for fixup for true limit
+- x86/hyperv: Fix the detection of E820_TYPE_PRAM in a Gen2 VM
+- selftests/mm: cow: print ksft header before printing anything else
+- drm/i915: Use internal class when counting engine resets
+- drm/i915/selftests: Fix engine reset count storage for multi-tile
+- accel/ivpu/37xx: Fix interrupt_clear_with_0 WA initialization
+- accel/ivpu: Print information about used workarounds
+- drm/mediatek: Add spinlock for setting vblank event in atomic_begin
+- drm/mediatek: fix kernel oops if no crtc is found
+- PCI: vmd: Fix potential deadlock when enabling ASPM
+- ksmbd: fix wrong name of SMB2_CREATE_ALLOCATION_SIZE
+- PCI/ASPM: Add pci_enable_link_state_locked()
+- PCI: loongson: Limit MRRS to 256
+- Revert "PCI: acpiphp: Reassign resources on bridge if necessary"
+- ALSA: hda/tas2781: reset the amp before component_add
+- ALSA: hda/tas2781: call cleanup functions only once
+- ALSA: hda/tas2781: handle missing EFI calibration data
+- ALSA: hda/tas2781: leave hda_component in usable state
+- ALSA: hda/realtek: Apply mute LED quirk for HP15-db
+- ALSA: hda/hdmi: add force-connect quirks for ASUSTeK Z170 variants
+- ALSA: hda/hdmi: add force-connect quirk for NUC5CPYB
+- io_uring/cmd: fix breakage in SOCKET_URING_OP_SIOC* implementation
+- fuse: dax: set fc->dax to NULL in fuse_dax_conn_free()
+- fuse: disable FOPEN_PARALLEL_DIRECT_WRITES with FUSE_DIRECT_IO_ALLOW_MMAP
+- fuse: share lookup state between submount and its parent
+- fuse: Rename DIRECT_IO_RELAX to DIRECT_IO_ALLOW_MMAP
+- HID: Add quirk for Labtec/ODDOR/aikeec handbrake
+- HID: i2c-hid: Add IDEA5002 to i2c_hid_acpi_blacklist[]
+- net: atlantic: fix double free in ring reinit logic
+- appletalk: Fix Use-After-Free in atalk_ioctl
+- net: stmmac: Handle disabled MDIO busses from devicetree
+- net: stmmac: dwmac-qcom-ethqos: Fix drops in 10M SGMII RX
+- dpaa2-switch: do not ask for MDB, VLAN and FDB replay
+- dpaa2-switch: fix size of the dma_unmap
+- vsock/virtio: Fix unsigned integer wrap around in virtio_transport_has_space()
+- sign-file: Fix incorrect return values check
+- stmmac: dwmac-loongson: Make sure MDIO is initialized before use
+- net: ena: Fix XDP redirection error
+- net: ena: Fix DMA syncing in XDP path when SWIOTLB is on
+- net: ena: Fix xdp drops handling due to multibuf packets
+- net: ena: Destroy correct number of xdp queues upon failure
+- net: Remove acked SYN flag from packet in the transmit queue correctly
+- qed: Fix a potential use-after-free in qed_cxt_tables_alloc
+- iavf: Fix iavf_shutdown to call iavf_remove instead iavf_close
+- iavf: Handle ntuple on/off based on new state machines for flow director
+- iavf: Introduce new state machines for flow director
+- net/rose: Fix Use-After-Free in rose_ioctl
+- atm: Fix Use-After-Free in do_vcc_ioctl
+- octeontx2-af: Fix pause frame configuration
+- octeontx2-af: Update RSS algorithm index
+- octeontx2-pf: Fix promisc mcam entry action
+- octeon_ep: explicitly test for firmware ready value
+- net/sched: act_ct: Take per-cb reference to tcf_ct_flow_table
+- octeontx2-af: fix a use-after-free in rvu_nix_register_reporters
+- net: fec: correct queue selection
+- atm: solos-pci: Fix potential deadlock on &tx_queue_lock
+- atm: solos-pci: Fix potential deadlock on &cli_queue_lock
+- bnxt_en: Fix HWTSTAMP_FILTER_ALL packet timestamp logic
+- bnxt_en: Fix wrong return value check in bnxt_close_nic()
+- bnxt_en: Fix skb recycling logic in bnxt_deliver_skb()
+- bnxt_en: Clear resource reservation during resume
+- qca_spi: Fix reset behavior
+- qca_debug: Fix ethtool -G iface tx behavior
+- qca_debug: Prevent crash on TX ring changes
+- net: ipv6: support reporting otherwise unknown prefix flags in RTM_NEWPREFIX
+- net/mlx5: Fix a NULL vs IS_ERR() check
+- net/mlx5e: Check netdev pointer before checking its net ns
+- net/mlx5: Nack sync reset request when HotPlug is enabled
+- net/mlx5e: TC, Don't offload post action rule if not supported
+- net/mlx5e: Fix possible deadlock on mlx5e_tx_timeout_work
+- net/mlx5e: Disable IPsec offload support if not FW steering
+- RDMA/mlx5: Send events from IB driver about device affiliation state
+- net/mlx5e: Check the number of elements before walk TC rhashtable
+- net/mlx5e: Reduce eswitch mode_lock protection context
+- net/mlx5e: Tidy up IPsec NAT-T SA discovery
+- net/mlx5e: Unify esw and normal IPsec status table creation/destruction
+- net/mlx5e: Ensure that IPsec sequence packet number starts from 1
+- net/mlx5e: Honor user choice of IPsec replay window size
+- HID: lenovo: Restrict detection of patched firmware only to USB cptkbd
+- afs: Fix refcount underflow from error handling race
+- efi/x86: Avoid physical KASLR on older Dell systems
+- ksmbd: fix memory leak in smb2_lock()
+- ext4: fix warning in ext4_dio_write_end_io()
+- r8152: add vendor/device ID pair for ASUS USB-C2500
+- !5239 crypto: hisilicon support no-sva feature
+- crypto: hisilicon/qm - register to UACCE subsystem in UACCE_MODE_NOIOMMU mode
+- crypto: hisilicon/qm - get the type of iommu
+- uacce: support UACCE_MODE_NOIOMMU mode
+- !5256 net: hns3: some bugfix for the HNS3 ethernet driver
+- net: hns3: add checking for vf id of mailbox
+- net: hns3: fix port duplex configure error in IMP reset
+- net: hns3: fix reset timeout under full functions and queues
+- net: hns3: fix delete tc fail issue
+- net: hns3: fix kernel crash when 1588 is received on HIP08 devices
+- net: hns3: Disable SerDes serial loopback for HiLink H60
+- net: hns3: add new 200G link modes for hisilicon device
+- net: hns3: fix wrong judgment condition issue
+- !5250 f2fs: fix to tag gcing flag on page during block migration
+- f2fs: fix to tag gcing flag on page during block migration
+- !5249 btrfs: scrub: avoid use-after-free when chunk length is not 64K aligned
+- btrfs: scrub: avoid use-after-free when chunk length is not 64K aligned
+- !5244 ceph: fix deadlock or deadcode of misusing dget()
+- ceph: fix deadlock or deadcode of misusing dget()
+- !5180 RDMA/hns: Support hns RoCE Bonding
+- RDMA/hns: Fix the concurrency error between bond and reset.
+- RDMA/hns: Fix the device loss after unbinding RoCE bond resource slave
+- RDMA/hns: Fix wild pointer error of RoCE bonding when rmmod hns3
+- RDMA/hns: Support reset recovery for RoCE bonding
+- RDMA/hns: Add functions to obtain netdev and bus_num from an hr_dev
+- RDMA/hns: Support dispatching IB event for RoCE bonding
+- RDMA/hns: Set IB port state depending on upper device for RoCE bonding
+- RDMA/hns: Support RoCE bonding
+
+* Thu Mar 14 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-12.0.0.8
+- !5174 [OLK-6.6][sync from OLK-5.10] Introduce multiple LPI translation caches
+- KVM:arm64:vgic update openEuler's config's to enable MULTI_LPI_TRANSLATE_CACHE
+- KVM: arm64: vgic-its: Do not execute invalidate MSI-LPI translation cache on movi command
+- KVM: arm64: vgic-its: Introduce multiple LPI translation caches
+- !5208 Revert “Fix the header file location error and adjust the function and structure version.”
+- Revert “Fix the header file location error and adjust the function and structure version.”
+- !5199 v2 mTHP anon support
+- uprobes: use pagesize-aligned virtual address when replacing pages
+- selftests/mm/cow: add tests for anonymous multi-size THP
+- selftests/mm/cow: generalize do_run_with_thp() helper
+- selftests/mm/khugepaged: enlighten for multi-size THP
+- selftests/mm: support multi-size THP interface in thp_settings
+- selftests/mm: factor out thp settings management
+- selftests/mm/kugepaged: restore thp settings at exit
+- mm: thp: support allocation of anonymous multi-size THP
+- mm: thp: introduce multi-size THP sysfs interface
+- mm: non-pmd-mappable, large folios for folio_add_new_anon_rmap()
+- mm: allow deferred splitting of arbitrary anon large folios
+- mm/readahead: do not allow order-1 folio
+- mm: more ptep_get() conversion
+- mm/thp: fix "mm: thp: kill __transhuge_page_enabled()"
+- memory: move exclusivity detection in do_wp_page() into wp_can_reuse_anon_folio()
+- mm/rmap: convert page_move_anon_rmap() to folio_move_anon_rmap()
+- mm/rmap: move SetPageAnonExclusive() out of page_move_anon_rmap()
+- mm/rmap: pass folio to hugepage_add_anon_rmap()
+- mm/rmap: simplify PageAnonExclusive sanity checks when adding anon rmap
+- mm/rmap: warn on new PTE-mapped folios in page_add_anon_rmap()
+- mm/rmap: move folio_test_anon() check out of __folio_set_anon()
+- mm/rmap: move SetPageAnonExclusive out of __page_set_anon_rmap()
+- mm/rmap: drop stale comment in page_add_anon_rmap and hugepage_add_anon_rmap()
+- !4908 cgroup/cpuset: add exclusive and exclusive.effective for v2
+- cgroup/cpuset: Fix retval in update_cpumask()
+- cgroup/cpuset: Fix a memory leak in update_exclusive_cpumask()
+- cgroup/cpuset: Cleanup signedness issue in cpu_exclusive_check()
+- cgroup/cpuset: Enable invalid to valid local partition transition
+- cgroup/cpuset: Check partition conflict with housekeeping setup
+- cgroup/cpuset: Introduce remote partition
+- cgroup/cpuset: Add cpuset.cpus.exclusive for v2
+- cgroup/cpuset: Add cpuset.cpus.exclusive.effective for v2
+- !5159 【OLK-6.6】iommu: reserve KABI for struct iommu_ops
+- [OLK-6.6] iommu:kabi reserver space for struct iommu_ops
+- !5149 net: hns3: add support some customized exception handling interfaces
+- net: hns3: add input parameters checking
+- net: hns3: add extend interface support for read and write phy register
+- net: hns3: add support set led
+- net: hns3: add support set mac state
+- net: hns3: add support detect port wire type
+- net: hns3: add support PF provides customized interfaces to detect port faults.
+- net: hns3: support set pfc pause trans time
+- net: hns3: add support disable nic clock
+- net: hns3: add support config and query serdes lane status
+- net: hns3: add supports configure optical module enable
+- net: hns3: add support query the presence of optical module
+- net: hns3: add support modified tx timeout
+- net: hns3: add support query port ext information
+- net: hns3: add support configuring function-level interrupt affinity
+- net: hns3: add support clear mac statistics
+- net: hns3: add support to get/set 1d torus param
+- net: hns3: add supports fast reporting of faulty nodes
+- net: hns3: add supports pfc storm detection and suppression
+- net: hns3: add support customized exception handling interfaces
+- !4761 [OLK-6.6] backport 6.7 kernel signal patch
+- riscv: signal: handle syscall restart before get_signal
+- !5151 intel-sig: configs: enable TPMI related configs for OLK6.6
+- config: update Intel TPMI based driver configs to openeuler_defconfig for x86
+- !5150 intel-sig: configs: enable PMT related configs for OLK6.6
+- config: x86: Intel: enabled PMT SDSI TPMI configs
+- !4427 【OLK-6.6】watchdog: Support watchdog_sdei coexist with existing watchdogs
+- watchdog: Support watchdog_sdei coexist with existing watchdogs
+- !4776 [OLK-6.6] kabi:reserve space for msi expansion
+- [OLK-6.6] kabi:reserve space for msi expansion
+- !5041 [OLK-6.6] support the AMD Zen5 Turin
+- x86/CPU/AMD: Add more models to X86_FEATURE_ZEN5
+- x86/CPU/AMD: Add X86_FEATURE_ZEN5
+- x86/CPU/AMD: Add X86_FEATURE_ZEN1
+- x86/CPU/AMD: Drop now unused CPU erratum checking function
+- x86/CPU/AMD: Get rid of amd_erratum_1485[]
+- x86/CPU/AMD: Get rid of amd_erratum_400[]
+- x86/CPU/AMD: Get rid of amd_erratum_383[]
+- x86/CPU/AMD: Get rid of amd_erratum_1054[]
+- x86/CPU/AMD: Move the DIV0 bug detection to the Zen1 init function
+- x86/CPU/AMD: Move Zenbleed check to the Zen2 init function
+- x86/CPU/AMD: Rename init_amd_zn() to init_amd_zen_common()
+- x86/CPU/AMD: Call the spectral chicken in the Zen2 init function
+- x86/CPU/AMD: Move erratum 1076 fix into the Zen1 init function
+- x86/CPU/AMD: Move the Zen3 BTC_NO detection to the Zen3 init function
+- x86/CPU/AMD: Carve out the erratum 1386 fix
+- x86/CPU/AMD: Add ZenX generations flags
+- !5036 [OLK-6.6] Do not serialize MSR accesses on AMD
+- x86/barrier: Do not serialize MSR accesses on AMD
+- !5134 modpost: Optimize symbol search from linear to binary search
+- modpost: Optimize symbol search from linear to binary search
+- !4826 add sw64 architecture support
+- drivers: vfio: add sw64 support
+- drivers: usb: add sw64 support
+- drivers: tty: add sw64 support
+- drivers: spi: add sw64 support
+- drivers: scsi: add sw64 support
+- drivers: rtc: add sw64 rtc support
+- drivers: qemu_fw_cfg: add sw64 support
+- drivers: platform: add sw64 support
+- drivers: pci: add sw64 support
+- drivers: misc: add sw64 support
+- drivers: mfd: add sw64 support
+- drivers: irqchip: add sw64 support
+- drivers: iommu: add sw64 support
+- drivers: i2c: add sw64 support
+- drivers: hwmon: add sw64 support
+- drivers: gpio: add sw64 support
+- drivers: efi: add sw64 support
+- !4927 ima: digest list new support modsig
+- ima: digest list new support modsig
+- !4971 net: hns3: backport some patch from kernel 6.7
+- net: hns3: add some link modes for hisilicon device
+- net: hns3: add vf fault detect support
+- net: hns3: add hns3 vf fault detect cap bit support
+- !5040 [OLK-6.6] Add support for Vendor Defined Error Types in Einj Module
+- ACPI: APEI: EINJ: Add support for vendor defined error types
+- platform/chrome: cros_ec_debugfs: Fix permissions for panicinfo
+- fs: debugfs: Add write functionality to debugfs blobs
+- ACPI: APEI: EINJ: Refactor available_error_type_show()
+- !5039 [OLK-6.6] Fix disabling memory if DVSEC CXL Range does not match a CFMWS window
+- cxl/pci: Fix disabling memory if DVSEC CXL Range does not match a CFMWS window
+- !5047 Backport etmem swapcache recalim feature to OLK 6.6
+- etmem: add swapcache reclaim to etmem
+- etmem: Expose symbol reclaim_folio_list
+- !4514 [OLK-6.6] kabi: IOMMU subsystem reservation
+- kabi: IOMMU reservations
+- kabi: bus_type, device_driver, dev_pm_ops reservation
+- !5056 erofs: fix handling kern_mount() failure
+- erofs: fix handling kern_mount() failure
+- !5059 dm: limit the number of targets and parameter size area
+- dm: limit the number of targets and parameter size area
+- !5021 LoongArch: fix some known issue and update defconfig
+- LoongArch: enable CONFIG_DEBUG_INFO_BTF by default
+- net: stmmac: fix potential double free of dma descriptor resources
+- drm/radeon: Workaround radeon driver bug for Loongson
+- irqchip/loongson-liointc: Set different isr for differnt core
+- LoongArch: kdump: Add high memory reservation
+- LoongArch: Fix kdump failure on v40 interface specification
+- LoongArch: kexec: Add compatibility with old interfaces
+- LoongArch: kdump: Add memory reservation for old kernel
+- LoongArch: defconfig: Enable a large number of configurations
+- irqchip/loongson-pch-pic: 7a1000 int_clear reg must use 64bit write.
+- LoongArch: Remove generic irq migration
+- LoongArch: Adapted SECTION_SIZE_BITS with page size
+- !4689 Remove WQ_FLAG_BOOKMARK flag
+- sched: remove wait bookmarks
+- filemap: remove use of wait bookmarks
+- !5024 v2 vmemmap optimize bugfix
+- mm: hugetlb_vmemmap: allow alloc vmemmap pages fallback to other nodes
+- mm: hugetlb_vmemmap: fix hugetlb page number decrease failed on movable nodes
+- !4653 [OLK-6.6] Add support for Mucse Network Adapter(N10/N400)
+- drivers: initial support for rnp drivers from Mucse Technology
+- !4935 RDMA/hns: Support userspace configuring congestion control algorithm with QP granularity
+- RDMA/hns: Support userspace configuring congestion control algorithm with QP granularity
+- RDMA/hns: Fix mis-modifying default congestion control algorithm
+- !4993 v3 kworker: Fix the problem of ipsan performance degradation
+- Add kernel compilation configuration options
+- iscsi: use dynamic single thread workqueue to improve performance
+- workqueue: add member for NUMA aware order workqueue and implement NUMA affinity for single thread workqueue
+- !4930 erofs: fix lz4 inplace decompression
+- erofs: fix lz4 inplace decompression
+- !4082 【OLK-6.6】KVM: arm64: vtimer irq bypass support
+- mbigen: probe mbigen driver with arch_initcall
+- mbigen: vtimer: disable vtimer mbigen probe when vtimer_irqbypass disabled
+- mbigen: Sets the regs related to vtimer irqbypass
+- KVM: arm64: vgic-v3: Clearing pending status of vtimer on guest reset
+- mbigen: vtimer: add support for MBIX1_CPPI_NEGEDGE_CLR_EN_SETR(CLRR)
+- KVM: arm64: arch_timer: Make vtimer_irqbypass a Distributor attr
+- KVM: arm64: vtimer: Expose HW-based vtimer interrupt in debugfs
+- KVM: arm64: GICv4.1: Allow non-trapping WFI when using direct vtimer interrupt
+- KVM: arm64: GICv4.1: Add support for MBIGEN save/restore
+- KVM: arm64: arch_timer: Rework vcpu init/reset logic
+- KVM: arm64: arch_timer: Probe vtimer irqbypass capability
+- KVM: arm64: GICv4.1: Enable vtimer vPPI irqbypass config
+- KVM: arm64: GICv4.1: Add direct injection capability to PPI registers
+- KVM: arm64: vgic: Add helper for vtimer vppi info register
+- KVM: arm64: GICv4.1: Inform the HiSilicon vtimer irqbypass capability
+- irqchip/gic-v4.1: Probe vtimer irqbypass capability at RD level
+- irqchip/gic-v4.1: Rework its_alloc_vcpu_sgis() to support vPPI allocation
+- irqchip/gic-v4.1: Rework get/set_irqchip_state callbacks of GICv4.1-sgi chip
+- irqchip/gic-v4.1: Extend VSGI command to support the new vPPI
+- irqchip/gic-v4.1: Detect ITS vtimer interrupt bypass capability
+- mbigen: vtimer mbigen driver support
+- mbigen: vtimer: isolate mbigen vtimer funcs with macro
+- !4875 [OLK-6.6] backport latest v6.8 iommu fixes
+- iommufd/selftest: Don't check map/unmap pairing with HUGE_PAGES
+- iommufd: Fix protection fault in iommufd_test_syz_conv_iova
+- iommufd/selftest: Fix mock_dev_num bug
+- iommufd: Fix iopt_access_list_id overwrite bug
+- iommu/sva: Fix SVA handle sharing in multi device case
+- !4867 ext4: regenerate buddy after block freeing failed if under fc replay
+- ext4: regenerate buddy after block freeing failed if under fc replay
+- !4851 cachefiles: fix memory leak in cachefiles_add_cache()
+- cachefiles: fix memory leak in cachefiles_add_cache()
+- !4913 RDMA/hns: Support SCC parameter configuration and reporting of the down/up event of the HNS RoCE network port
+- RDMA/hns: Add support for sending port down event fastly
+- RDMA/hns: Deliver net device event to ofed
+- RDMA/hns: Support congestion control algorithm parameter configuration
+- !4670 crypto HiSilicon round main line code
+- crypto: hisilicon/qm - change function type to void
+- crypto: hisilicon/qm - obtain stop queue status
+- crypto: hisilicon/qm - add stop function by hardware
+- crypto: hisilicon/sec - remove unused parameter
+- crypto: hisilicon/sec2 - fix some cleanup issues
+- crypto: hisilicon/sec2 - modify nested macro call
+- crypto: hisilicon/sec2 - updates the sec DFX function register
+- crypto: hisilicon - Fix smp_processor_id() warnings
+- crypto: hisilicon/qm - dump important registers values before resetting
+- crypto: hisilicon/qm - support get device state
+- crypto: hisilicon/sec2 - optimize the error return process
+- crypto: hisilicon/qm - delete a dbg function
+- crypto: hisilicon/sec2 - Remove cfb and ofb
+- crypto: hisilicon/zip - save capability registers in probe process
+- crypto: hisilicon/sec2 - save capability registers in probe process
+- crypto: hisilicon/hpre - save capability registers in probe process
+- crypto: hisilicon/qm - save capability registers in qm init process
+- crypto: hisilicon/qm - add a function to set qm algs
+- crypto: hisilicon/qm - add comments and remove redundant array element
+- crypto: hisilicon/qm - simplify the status of qm
+- crypto: hisilicon/sgl - small cleanups for sgl.c
+- crypto: hisilicon/zip - add zip comp high perf mode configuration
+- crypto: hisilicon/qm - remove incorrect type cast
+- crypto: hisilicon/qm - print device abnormal information
+- crypto: hisilicon/trng - Convert to platform remove callback returning void
+- crypto: hisilicon/sec - Convert to platform remove callback returning void
+- crypto: hisilicon/qm - fix EQ/AEQ interrupt issue
+- crypto: hisilicon/qm - alloc buffer to set and get xqc
+- crypto: hisilicon/qm - check function qp num before alg register
+- crypto: hisilicon/qm - fix the type value of aeq
+- crypto: hisilicon/sec - fix for sgl unmmap problem
+- crypto: hisilicon/zip - remove zlib and gzip
+- crypto: hisilicon/zip - support deflate algorithm
+- uacce: make uacce_class constant
+- !4725 [OLK-6.6] merge upstream net-v6.7 all wangxun patches
+- net: fill in MODULE_DESCRIPTION()s for wx_lib
+- wangxun: select CONFIG_PHYLINK where needed
+- net: wangxun: add ethtool_ops for msglevel
+- net: wangxun: add coalesce options support
+- net: wangxun: add ethtool_ops for ring parameters
+- net: wangxun: add flow control support
+- net: ngbe: convert phylib to phylink
+- net: txgbe: use phylink bits added in libwx
+- net: libwx: add phylink to libwx
+- net: wangxun: remove redundant kernel log
+- net: ngbe: add ethtool stats support
+- net: txgbe: add ethtool stats support
+- net: wangxun: move MDIO bus implementation to the library
+- net: libwx: fix memory leak on free page
+- net: libwx: support hardware statistics
+- net: wangxun: fix changing mac failed when running
+- !4841 Intel-sig: intel_idle: add Sierra Forest SoC support on 6.6
+- intel_idle: add Sierra Forest SoC support
+- !4834 ras: fix return type of log_arm_hw_error when not add CONFIG_RAS_ARM_EVENT_INFO config
+- ras: fix return type of log_arm_hw_error when not add CONFIG_RAS_ARM_EVENT_INFO config
+- !4845 PCI: Avoid potential out-of-bounds read in pci_dev_for_each_resource()
+- PCI: Avoid potential out-of-bounds read in pci_dev_for_each_resource()
+- !4773 Add loongarch kernel kvm support
+- loongarch/kernel: Fix loongarch compilation error
+- LoongArch: KVM: Add returns to SIMD stubs
+- LoongArch: KVM: Streamline kvm_check_cpucfg() and improve comments
+- LoongArch: KVM: Rename _kvm_get_cpucfg() to _kvm_get_cpucfg_mask()
+- LoongArch: KVM: Fix input validation of _kvm_get_cpucfg() & kvm_check_cpucfg()
+- irqchip/loongson-eiointc: Use correct struct type in eiointc_domain_alloc()
+- LoongArch: KVM: Add LASX (256bit SIMD) support
+- LoongArch: KVM: Add LSX (128bit SIMD) support
+- LoongArch: KVM: Fix timer emulation with oneshot mode
+- LoongArch: KVM: Remove kvm_acquire_timer() before entering guest
+- LoongArch: KVM: Allow to access HW timer CSR registers always
+- LoongArch: KVM: Remove SW timer switch when vcpu is halt polling
+- LoongArch: KVM: Optimization for memslot hugepage checking
+- LoongArch: Implement constant timer shutdown interface
+- LoongArch: KVM: Add maintainers for LoongArch KVM
+- LoongArch: KVM: Supplement kvm document about LoongArch-specific part
+- LoongArch: KVM: Enable kvm config and add the makefile
+- LoongArch: KVM: Implement vcpu world switch
+- LoongArch: KVM: Implement kvm exception vectors
+- LoongArch: KVM: Implement handle fpu exception
+- LoongArch: KVM: Implement handle mmio exception
+- LoongArch: KVM: Implement handle gspr exception
+- LoongArch: KVM: Implement handle idle exception
+- LoongArch: KVM: Implement handle iocsr exception
+- LoongArch: KVM: Implement handle csr exception
+- LoongArch: KVM: Implement kvm mmu operations
+- LoongArch: KVM: Implement virtual machine tlb operations
+- LoongArch: KVM: Implement vcpu timer operations
+- LoongArch: KVM: Implement misc vcpu related interfaces
+- LoongArch: KVM: Implement vcpu load and vcpu put operations
+- LoongArch: KVM: Implement vcpu interrupt operations
+- LoongArch: KVM: Implement fpu operations for vcpu
+- LoongArch: KVM: Implement basic vcpu ioctl interfaces
+- LoongArch: KVM: Implement basic vcpu interfaces
+- LoongArch: KVM: Add vcpu related header files
+- LoongArch: KVM: Implement VM related functions
+- LoongArch: KVM: Implement kvm hardware enable, disable interface
+- LoongArch: KVM: Implement kvm module related interface
+- LoongArch: KVM: Add kvm related header files
+- !3951 【OLK-6.6】KVM/arm64: support virt_dev irqbypass
+- KVM: arm64: update arm64 openeuler_defconfig for CONFIG_VIRT_PLAT_DEV
+- KVM: arm64: sdev: Support virq bypass by INT/VSYNC command
+- KVM: arm64: kire: irq routing entry cached the relevant cache data
+- KVM: arm64: Introduce shadow device
+- virt_plat_dev: Register the virt platform device driver
+- irqchip/gic-v3-its: Add virt platform devices MSI support
+- irqchip/gic-v3-its: Alloc/Free device id from pools for virtual devices
+- irqchip/gic-v3-its: Introduce the reserved device ID pools
+- !4425 【OLK-6.6】arm64/nmi: Support for FEAT_NMI
+- irqchip/gic-v3: Fix hard LOCKUP caused by NMI being masked
+- config: enable CONFIG_ARM64_NMI and CONFIG_HARDLOCKUP_DETECTOR_PERF for arm64
+- irqchip/gic-v3: Implement FEAT_GICv3_NMI support
+- arm64/nmi: Add Kconfig for NMI
+- arm64/nmi: Add handling of superpriority interrupts as NMIs
+- arm64/irq: Document handling of FEAT_NMI in irqflags.h
+- arm64/entry: Don't call preempt_schedule_irq() with NMIs masked
+- arm64/nmi: Manage masking for superpriority interrupts along with DAIF
+- KVM: arm64: Hide FEAT_NMI from guests
+- arm64/cpufeature: Detect PE support for FEAT_NMI
+- arm64/idreg: Add an override for FEAT_NMI
+- arm64/hyp-stub: Enable access to ALLINT
+- arm64/asm: Introduce assembly macros for managing ALLINT
+- arm64/sysreg: Add definitions for immediate versions of MSR ALLINT
+- arm64/booting: Document boot requirements for FEAT_NMI
+- !4679 f2fs: fix to avoid dirent corruption
+- f2fs: fix to avoid dirent corruption
+- !4730 coresight: trbe: Enable ACPI based devices
+- coresight: trbe: Enable ACPI based TRBE devices
+- coresight: trbe: Add a representative coresight_platform_data for TRBE
+- !4807 [OLK-6.6] Intel: backport KVM LAM from v6.8 to OLK-6.6
+- KVM: x86: Use KVM-governed feature framework to track "LAM enabled"
+- KVM: x86: Advertise and enable LAM (user and supervisor)
+- KVM: x86: Virtualize LAM for user pointer
+- KVM: x86: Virtualize LAM for supervisor pointer
+- KVM: x86: Untag addresses for LAM emulation where applicable
+- KVM: x86: Introduce get_untagged_addr() in kvm_x86_ops and call it in emulator
+- KVM: x86: Remove kvm_vcpu_is_illegal_gpa()
+- KVM: x86: Add & use kvm_vcpu_is_legal_cr3() to check CR3's legality
+- KVM: x86/mmu: Drop non-PA bits when getting GFN for guest's PGD
+- KVM: x86: Add X86EMUL_F_INVLPG and pass it in em_invlpg()
+- KVM: x86: Add an emulation flag for implicit system access
+- KVM: x86: Consolidate flags for __linearize()
+- !4700 efivarfs: force RO when remounting if SetVariable is not supported
+- efivarfs: force RO when remounting if SetVariable is not supported
+- !4785 Support PV-sched feature
+- KVM: arm64: Support the vCPU preemption check
+- KVM: arm64: Add interface to support vCPU preempted check
+- KVM: arm64: Support pvsched preempted via shared structure
+- KVM: arm64: Implement PV_SCHED_FEATURES call
+- KVM: arm64: Document PV-sched interface
+- !4629 add sw64 architecture support
+- drivers: cpufreq: add sw64 support
+- drivers: clocksource: add sw64 support
+- drivers: acpi: add sw64 support
+- selftests: fix sw64 support
+- perf: fix sw64 support
+- perf: add sw64 support
+- tools: fix basic sw64 support
+- tools: add basic sw64 support
+- sw64: fix ftrace support
+- sw64: fix audit support
+- sw64: fix kexec support
+- sw64: fix PCI support
+- sw64: fix KVM support
+- sw64: fix module support
+- sw64: fix ACPI support
+- sw64: fix rrk support
+- sw64: fix ELF support
+- !4727 RAS: Report ARM processor information to userspace
+- RAS: Report ARM processor information to userspace
+- !4769 [sync] PR-4729: serial: 8250: omap: Don't skip resource freeing if pm_runtime_resume_and_get() failed
+- serial: 8250: omap: Don't skip resource freeing if pm_runtime_resume_and_get() failed
+- !4781 x86/fpu: Stop relying on userspace for info to fault in xsave buffer
+- x86/fpu: Stop relying on userspace for info to fault in xsave buffer
+- !4787 v2 gfs2: Fix kernel NULL pointer dereference in gfs2_rgrp_dump
+- gfs2: Fix kernel NULL pointer dereference in gfs2_rgrp_dump
+- !4789 v2 fix CVE-2024-26590
+- erofs: fix inconsistent per-file compression format
+- erofs: simplify compression configuration parser
+- !4736 PCIe and miniIO OLK-5.10 branch partial code round OLK-6.6 branch
+- xhci:fix USB xhci controller issue
+- spi: hisi-sfc-v3xx: return IRQ_NONE if no interrupts were detected
+- Add the verification operation after the bus recovery operation obtains resources through the ACPI
+- i2c: hisi: Add gpio bus recovery support
+- gpio: hisi: Fix format specifier
+- perf hisi-ptt: Fix one memory leakage in hisi_ptt_process_auxtrace_event()
+- Fix the header file location error and adjust the function and structure version.
+- hwtracing: hisi_ptt: Don't try to attach a task
+- hwtracing: hisi_ptt: Optimize the trace data committing
+- hwtracing: hisi_ptt: Handle the interrupt in hardirq context
+- hwtracing: hisi_ptt: Disable interrupt after trace end
+- !4802 Export vcpu stat via debugfs
+- kvm: debugfs: add EXIT_REASON_PREEMPTION_TIMER to vcpu_stat
+- kvm: debugfs: add fastpath msr_wr exits to debugfs statistics
+- kvm: debugfs: Export x86 kvm exits to vcpu_stat
+- kvm: debugfs: aarch64 export cpu time related items to debugfs
+- kvm: debugfs: export remaining aarch64 kvm exit reasons to debugfs
+- kvm: debugfs: Export vcpu stat via debugfs
+- !4676 [OLK-6.6] kabi/iommu: Backport patches from upstream and maintainer tree
+- iommu/sva: Restore SVA handle sharing
+- iommu/arm-smmu-v3: Do not use GFP_KERNEL under as spinlock
+- Revert "iommu/arm-smmu: Convert to domain_alloc_paging()"
+- iommu/vt-d: Fix constant-out-of-range warning
+- iommu/vt-d: Set SSADE when attaching to a parent with dirty tracking
+- iommu/vt-d: Add missing dirty tracking set for parent domain
+- iommu/vt-d: Wrap the dirty tracking loop to be a helper
+- iommu/vt-d: Remove domain parameter for intel_pasid_setup_dirty_tracking()
+- iommu/vt-d: Add missing device iotlb flush for parent domain
+- iommu/vt-d: Update iotlb in nested domain attach
+- iommu/vt-d: Add missing iotlb flush for parent domain
+- iommu/vt-d: Add __iommu_flush_iotlb_psi()
+- iommu/vt-d: Track nested domains in parent
+- iommu: Make iommu_report_device_fault() return void
+- iommu: Make iopf_group_response() return void
+- iommu: Track iopf group instead of last fault
+- iommu: Improve iopf_queue_remove_device()
+- iommu: Use refcount for fault data access
+- iommu: Refine locking for per-device fault data management
+- iommu: Separate SVA and IOPF
+- iommu: Make iommu_queue_iopf() more generic
+- iommu: Prepare for separating SVA and IOPF
+- iommu: Merge iommu_fault_event and iopf_fault
+- iommu: Remove iommu_[un]register_device_fault_handler()
+- iommu: Merge iopf_device_param into iommu_fault_param
+- iommu: Cleanup iopf data structure definitions
+- iommu: Remove unrecoverable fault data
+- iommu/arm-smmu-v3: Remove unrecoverable faults reporting
+- iommu: Move iommu fault data to linux/iommu.h
+- iommu/iova: use named kmem_cache for iova magazines
+- iommu/iova: Reorganise some code
+- iommu/iova: Tidy up iova_cache_get() failure
+- selftests/iommu: fix the config fragment
+- iommufd: Reject non-zero data_type if no data_len is provided
+- iommufd/iova_bitmap: Consider page offset for the pages to be pinned
+- iommufd/selftest: Add mock IO hugepages tests
+- iommufd/selftest: Hugepage mock domain support
+- iommufd/selftest: Refactor mock_domain_read_and_clear_dirty()
+- iommufd/selftest: Refactor dirty bitmap tests
+- iommufd/iova_bitmap: Handle recording beyond the mapped pages
+- iommufd/selftest: Test u64 unaligned bitmaps
+- iommufd/iova_bitmap: Switch iova_bitmap::bitmap to an u8 array
+- iommufd/iova_bitmap: Bounds check mapped::pages access
+- powerpc/iommu: Fix the missing iommu_group_put() during platform domain attach
+- powerpc: iommu: Bring back table group release_ownership() call
+- iommu: Allow ops->default_domain to work when !CONFIG_IOMMU_DMA
+- iommufd/selftest: Check the bus type during probe
+- iommu/vt-d: Add iotlb flush for nested domain
+- iommufd: Add data structure for Intel VT-d stage-1 cache invalidation
+- iommufd/selftest: Add coverage for IOMMU_HWPT_INVALIDATE ioctl
+- iommufd/selftest: Add IOMMU_TEST_OP_MD_CHECK_IOTLB test op
+- iommufd/selftest: Add mock_domain_cache_invalidate_user support
+- iommu: Add iommu_copy_struct_from_user_array helper
+- iommufd: Add IOMMU_HWPT_INVALIDATE
+- iommu: Add cache_invalidate_user op
+- iommu: Don't reserve 0-length IOVA region
+- iommu/sva: Fix memory leak in iommu_sva_bind_device()
+- iommu/dma: Trace bounce buffer usage when mapping buffers
+- iommu/tegra: Use tegra_dev_iommu_get_stream_id() in the remaining places
+- acpi: Do not return struct iommu_ops from acpi_iommu_configure_id()
+- iommu: Mark dev_iommu_priv_set() with a lockdep
+- iommu: Mark dev_iommu_get() with lockdep
+- iommu/of: Use -ENODEV consistently in of_iommu_configure()
+- iommmu/of: Do not return struct iommu_ops from of_iommu_configure()
+- iommu: Remove struct iommu_ops *iommu from arch_setup_dma_ops()
+- iommu: Set owner token to SVA domain
+- mm: Deprecate pasid field
+- iommu: Support mm PASID 1:n with sva domains
+- mm: Add structure to keep sva information
+- iommu: Add mm_get_enqcmd_pasid() helper function
+- iommu/vt-d: Remove mm->pasid in intel_sva_bind_mm()
+- iommu: Change kconfig around IOMMU_SVA
+- iommu: Extend LPAE page table format to support custom allocators
+- iommu: Allow passing custom allocators to pgtable drivers
+- iommu: Clean up open-coded ownership checks
+- iommu: Retire bus ops
+- iommu/arm-smmu: Don't register fwnode for legacy binding
+- iommu: Decouple iommu_domain_alloc() from bus ops
+- iommu: Validate that devices match domains
+- iommu: Decouple iommu_present() from bus ops
+- iommu: Factor out some helpers
+- iommu: Map reserved memory as cacheable if device is coherent
+- iommu/vt-d: Move inline helpers to header files
+- iommu/vt-d: Remove unused vcmd interfaces
+- iommu/vt-d: Remove unused parameter of intel_pasid_setup_pass_through()
+- iommu/vt-d: Refactor device_to_iommu() to retrieve iommu directly
+- iommu/virtio: Add ops->flush_iotlb_all and enable deferred flush
+- iommu/virtio: Make use of ops->iotlb_sync_map
+- iommu/arm-smmu: Convert to domain_alloc_paging()
+- iommu/arm-smmu: Pass arm_smmu_domain to internal functions
+- iommu/arm-smmu: Implement IOMMU_DOMAIN_BLOCKED
+- iommu/arm-smmu: Convert to a global static identity domain
+- iommu/arm-smmu: Reorganize arm_smmu_domain_add_master()
+- iommu/arm-smmu-v3: Remove ARM_SMMU_DOMAIN_NESTED
+- iommu/arm-smmu-v3: Master cannot be NULL in arm_smmu_write_strtab_ent()
+- iommu/arm-smmu-v3: Add a type for the STE
+- iommu/apple-dart: Fix spelling mistake "grups" -> "groups"
+- iommu/apple-dart: Use readl instead of readl_relaxed for consistency
+- iommu/apple-dart: Add support for t8103 USB4 DART
+- iommu/apple-dart: Write to all DART_T8020_STREAM_SELECT
+- dt-bindings: iommu: dart: Add t8103-usb4-dart compatible
+- iommufd: Do not UAF during iommufd_put_object()
+- iommufd: Add iommufd_ctx to iommufd_put_object()
+- iommu/vt-d: Support enforce_cache_coherency only for empty domains
+- iommu: Flow ERR_PTR out from __iommu_domain_alloc()
+- iommu/dma: Use a large flush queue and timeout for shadow_on_flush
+- iommu/dma: Allow a single FQ in addition to per-CPU FQs
+- iommu/s390: Disable deferred flush for ISM devices
+- s390/pci: Use dma-iommu layer
+- s390/pci: prepare is_passed_through() for dma-iommu
+- iommu: Allow .iotlb_sync_map to fail and handle s390's -ENOMEM return
+- iommu/dart: Remove the force_bypass variable
+- iommu/dart: Call apple_dart_finalize_domain() as part of alloc_paging()
+- iommu/dart: Convert to domain_alloc_paging()
+- iommu/dart: Move the blocked domain support to a global static
+- iommu/dart: Use static global identity domains
+- iommufd: Convert to alloc_domain_paging()
+- iommu/vt-d: Use ops->blocked_domain
+- iommu/vt-d: Update the definition of the blocking domain
+- iommu: Move IOMMU_DOMAIN_BLOCKED global statics to ops->blocked_domain
+- iommu: change iommu_map_sgtable to return signed values
+- powerpc/iommu: Do not do platform domain attach atctions after probe
+- iommu: Fix return code in iommu_group_alloc_default_domain()
+- iommu: Do not use IOMMU_DOMAIN_DMA if CONFIG_IOMMU_DMA is not enabled
+- iommu: Remove duplicate include
+- iommu: Improve map/unmap sanity checks
+- iommu: Retire map/unmap ops
+- iommu/tegra-smmu: Update to {map,unmap}_pages
+- iommu/sun50i: Update to {map,unmap}_pages
+- iommu/rockchip: Update to {map,unmap}_pages
+- iommu/omap: Update to {map,unmap}_pages
+- iommu/exynos: Update to {map,unmap}_pages
+- iommu/omap: Convert to generic_single_device_group()
+- iommu/ipmmu-vmsa: Convert to generic_single_device_group()
+- iommu/rockchip: Convert to generic_single_device_group()
+- iommu/sprd: Convert to generic_single_device_group()
+- iommu/sun50i: Convert to generic_single_device_group()
+- iommu: Add generic_single_device_group()
+- iommu: Remove useless group refcounting
+- iommu: Convert remaining simple drivers to domain_alloc_paging()
+- iommu: Convert simple drivers with DOMAIN_DMA to domain_alloc_paging()
+- iommu: Add ops->domain_alloc_paging()
+- iommu: Add __iommu_group_domain_alloc()
+- iommu: Require a default_domain for all iommu drivers
+- iommu/sun50i: Add an IOMMU_IDENTITIY_DOMAIN
+- iommu/mtk_iommu: Add an IOMMU_IDENTITIY_DOMAIN
+- iommu/ipmmu: Add an IOMMU_IDENTITIY_DOMAIN
+- iommu/qcom_iommu: Add an IOMMU_IDENTITIY_DOMAIN
+- iommu: Remove ops->set_platform_dma_ops()
+- iommu/msm: Implement an IDENTITY domain
+- iommu/omap: Implement an IDENTITY domain
+- iommu/tegra-smmu: Support DMA domains in tegra
+- iommu/tegra-smmu: Implement an IDENTITY domain
+- iommu/exynos: Implement an IDENTITY domain
+- iommu: Allow an IDENTITY domain as the default_domain in ARM32
+- iommu: Reorganize iommu_get_default_domain_type() to respect def_domain_type()
+- iommu/mtk_iommu_v1: Implement an IDENTITY domain
+- iommu/tegra-gart: Remove tegra-gart
+- iommu/fsl_pamu: Implement a PLATFORM domain
+- iommu: Add IOMMU_DOMAIN_PLATFORM for S390
+- powerpc/iommu: Setup a default domain and remove set_platform_dma_ops
+- iommu: Add IOMMU_DOMAIN_PLATFORM
+- iommu: Add iommu_ops->identity_domain
+- iommu/vt-d: debugfs: Support dumping a specified page table
+- iommu/vt-d: debugfs: Create/remove debugfs file per {device, pasid}
+- iommu/vt-d: debugfs: Dump entry pointing to huge page
+- iommu/virtio: Add __counted_by for struct viommu_request and use struct_size()
+- iommu/arm-smmu-v3-sva: Remove bond refcount
+- iommu/arm-smmu-v3-sva: Remove unused iommu_sva handle
+- iommu/arm-smmu-v3: Rename cdcfg to cd_table
+- iommu/arm-smmu-v3: Update comment about STE liveness
+- iommu/arm-smmu-v3: Cleanup arm_smmu_domain_finalise
+- iommu/arm-smmu-v3: Move CD table to arm_smmu_master
+- iommu/arm-smmu-v3: Refactor write_ctx_desc
+- iommu/arm-smmu-v3: move stall_enabled to the cd table
+- iommu/arm-smmu-v3: Encapsulate ctx_desc_cfg init in alloc_cd_tables
+- iommu/arm-smmu-v3: Replace s1_cfg with cdtab_cfg
+- iommu/arm-smmu-v3: Move ctx_desc out of s1_cfg
+- iommu/tegra-smmu: Drop unnecessary error check for for debugfs_create_dir()
+- powerpc: Remove extern from function implementations
+- iommufd: Organize the mock domain alloc functions closer to Joerg's tree
+- iommu/vt-d: Disallow read-only mappings to nest parent domain
+- iommu/vt-d: Add nested domain allocation
+- iommu/vt-d: Set the nested domain to a device
+- iommu/vt-d: Make domain attach helpers to be extern
+- iommu/vt-d: Add helper to setup pasid nested translation
+- iommu/vt-d: Add helper for nested domain allocation
+- iommu/vt-d: Extend dmar_domain to support nested domain
+- iommufd: Add data structure for Intel VT-d stage-1 domain allocation
+- iommufd/selftest: Add coverage for IOMMU_HWPT_ALLOC with nested HWPTs
+- iommufd/selftest: Add nested domain allocation for mock domain
+- iommu: Add iommu_copy_struct_from_user helper
+- iommufd: Add a nested HW pagetable object
+- iommu: Pass in parent domain with user_data to domain_alloc_user op
+- iommufd: Share iommufd_hwpt_alloc with IOMMUFD_OBJ_HWPT_NESTED
+- iommufd: Derive iommufd_hwpt_paging from iommufd_hw_pagetable
+- iommufd/device: Wrap IOMMUFD_OBJ_HWPT_PAGING-only configurations
+- iommufd: Rename IOMMUFD_OBJ_HW_PAGETABLE to IOMMUFD_OBJ_HWPT_PAGING
+- iommu: Add IOMMU_DOMAIN_NESTED
+- iommufd: Only enforce cache coherency in iommufd_hw_pagetable_alloc
+- iommufd: Fix spelling errors in comments
+- !4767 reserve space for arch related structures
+- kabi: reserve space for struct mfd_cell
+- kabi: reserve space for struct irq_work
+- !4709 mtd: Fix gluebi NULL pointer dereference caused by ftl notifier
+- mtd: Fix gluebi NULL pointer dereference caused by ftl notifier
+- !4738 blk-mq: fix IO hang from sbitmap wakeup race
+- blk-mq: fix IO hang from sbitmap wakeup race
+- !4561 sched: migtate user interface from smart grid to sched bpf
+- sched: migtate user interface from smart grid to sched bpf
+- !4026 [OLK-6.6]Add support for Mont-TSSE
+- add support for Mont-TSSE Driver
+- !4564 v2 reserve space for arm64 related structures
+- kabi: reserve space for processor.h
+- kabi: reserve space for fb.h
+- kabi: reserve space for efi.h
+- !4675 v5 Backport vDPA migration support patches
+- vdpa: add CONFIG_VHOST_VDPA_MIGRATION
+- vdpa: add vmstate header file
+- vhost-vdpa: add reset state params to indicate reset level
+- vhost-vdpa: allow set feature VHOST_F_LOG_ALL when been negotiated.
+- vhost-vdpa: fix msi irq request err
+- vhost-vdpa: Allow transparent MSI IOV
+- vhost: add VHOST feature VHOST_BACKEND_F_BYTEMAPLOG
+- vhost-vdpa: add uAPI for device migration status
+- vdpa: add vdpa device migration status ops
+- vhost-vdpa: add uAPI for device buffer
+- vdpa: add device state operations
+- vhost-vdpa: add uAPI for logging
+- vdpa: add log operations
+- !4660 Intel: Backport to fix In Field Scan(IFS) SAF for GNR & SRF
+- platform/x86/intel/ifs: Call release_firmware() when handling errors.
+- !4652 RDMA/hns: Support SCC context query and DSCP configuration.
+- RDMA/hns: Support DSCP of userspace
+- RDMA/hns: Append SCC context to the raw dump of QP Resource
+- !4628 fs:/dcache.c: fix negative dentry flag warning in dentry_free
+- fs:/dcache.c: fix negative dentry flag warning in dentry_free
+- !4654 hisi_ptt: Move type check to the beginning of hisi_ptt_pmu_event_init()
+- hwtracing: hisi_ptt: Move type check to the beginning of hisi_ptt_pmu_event_init()
+- !3880 ima: Add IMA digest lists extension
+- ima: add default INITRAMFS_FILE_METADATA and EVM_DEFAULT_HASH CONFIG
+- ima: don't allow control characters in policy path
+- ima: Add max size for IMA digest database
+- config: add digest list options for arm64 and x86
+- evm: Propagate choice of HMAC algorithm in evm_crypto.c
+- ima: Execute parser to upload digest lists not recognizable by the kernel
+- evm: Extend evm= with x509. allow_metadata_writes and complete values
+- ima: Add parser keyword to the policy
+- ima: Allow direct upload of digest lists to securityfs
+- ima: Search key in the built-in keyrings
+- certs: Introduce search_trusted_key()
+- KEYS: Provide a function to load keys from a PGP keyring blob
+- KEYS: Introduce load_pgp_public_keyring()
+- KEYS: Provide PGP key description autogeneration
+- KEYS: PGP data parser
+- PGPLIB: Basic packet parser
+- PGPLIB: PGP definitions (RFC 4880)
+- rsa: add parser of raw format
+- mpi: introduce mpi_key_length()
+- ima: Add Documentation/security/IMA-digest-lists.txt
+- ima: Introduce appraise_exec_immutable policy
+- ima: Introduce appraise_exec_tcb policy
+- ima: Introduce exec_tcb policy
+- ima: Add meta_immutable appraisal type
+- evm: Add support for digest lists of metadata
+- ima: Add support for appraisal with digest lists
+- ima: Add support for measurement with digest lists
+- ima: Load all digest lists from a directory at boot time
+- ima: Introduce new hook DIGEST_LIST_CHECK
+- ima: Introduce new securityfs files
+- ima: Prevent usage of digest lists not measured or appraised
+- ima: Add parser of compact digest list
+- ima: Use ima_show_htable_value to show violations and hash table data
+- ima: Generalize policy file operations
+- ima: Generalize ima_write_policy() and raise uploaded data size limit
+- ima: Generalize ima_read_policy()
+- ima: Allow choice of file hash algorithm for measurement and audit
+- ima: Add enforce-evm and log-evm modes to strictly check EVM status
+- init: Add kernel option to force usage of tmpfs for rootfs
+- gen_init_cpio: add support for file metadata
+- initramfs: read metadata from special file METADATA!!!
+- initramfs: add file metadata
+- !4542 Support feature TLBI DVMBM
+- KVM: arm64: Implement the capability of DVMBM
+- KVM: arm64: Add kvm_arch::sched_cpus and sched_lock
+- KVM: arm64: Add kvm_vcpu_arch::sched_cpus and pre_sched_cpus
+- KVM: arm64: Probe and configure DVMBM capability on HiSi CPUs
+- KVM: arm64: Support a new HiSi CPU type
+- KVM: arm64: Only probe Hisi ncsnp feature on Hisi CPUs
+- KVM: arm64: Add support for probing Hisi ncsnp capability
+- KVM: arm64: Probe Hisi CPU TYPE from ACPI/DTB
+- !4661 [OLK-6.6] Fix gic support for Phytium S2500
+- Enable CONFIG_ARCH_PHYTIUM
+- Fix gic support for Phytium S2500
+- !4644 f2fs: explicitly null-terminate the xattr list
+- f2fs: explicitly null-terminate the xattr list
+- !4637 Using smmu IIDR registers
+- iommu/arm-smmu-v3: Enable iotlb_sync_map according to SMMU_IIDR
+- Revert "iommu/arm-smmu-v3: Add a SYNC command to avoid broken page table prefetch"
+- !4506 ubi: fastmap: Optimize ubi wl algorithm to improve flash service life
+- ubi: fastmap: Add control in 'UBI_IOCATT' ioctl to reserve PEBs for filling pools
+- ubi: fastmap: Add module parameter to control reserving filling pool PEBs
+- ubi: fastmap: Fix lapsed wear leveling for first 64 PEBs
+- ubi: fastmap: Get wl PEB even ec beyonds the 'max' if free PEBs are run out
+- ubi: fastmap: may_reserve_for_fm: Don't reserve PEB if fm_anchor exists
+- ubi: fastmap: Remove unneeded break condition while filling pools
+- ubi: fastmap: Wait until there are enough free PEBs before filling pools
+- ubi: fastmap: Use free pebs reserved for bad block handling
+- ubi: Replace erase_block() with sync_erase()
+- ubi: fastmap: Allocate memory with GFP_NOFS in ubi_update_fastmap
+- ubi: fastmap: erase_block: Get erase counter from wl_entry rather than flash
+- ubi: fastmap: Fix missed ec updating after erasing old fastmap data block
+- !4624 6.6: i2c: Optimized the value setting of maxwrite limit to fifo depth - 1
+- i2c: hisi: Add clearing tx aempty interrupt operation
+- i2c: hisi: Optimized the value setting of maxwrite limit to fifo depth - 1
+- !4631 Add kabi reserve
+- drm/ttm: Add kabi reserve in ttm_tt.h
+- drm/ttm: Add kabi reserve in ttm_resource.h
+- drm/ttm: Add kabi reserve in ttm_bo.h
+- drm: Add kabi reserve in drm_gpu_scheduler.h
+- drm: Add kabi reserve in drm_syncobj.h
+- drm: Add kabi reserve in drm_plane.h
+- drm: Add kabi reserve in drm_modeset_lock.h
+- drm: Add kabi reserve in drm_mode_config.h
+- sbitmap: Add kabi reserve
+- xarray: Reserve kabi for xa_state
+- delayacct: Reserve kabi for task_delay_info
+
+* Mon Feb 26 2024 huangzq6 <huangzhenqiang2@huawei.com> - 6.6.0-10.0.0.7
+- add signature for vmlinux
+
+* Wed Feb 21 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-10.0.0.6
+- !4598 [OLK-6.6] Add iommu support for Phytium S2500
+- Add iommu support for Phytium S2500
+- !4596 add sw64 architecture support
+- sw64: fix build support
+- sw64: add dynamic turning on/off cores support
+- sw64: add dynamic frequency scaling support
+- sw64: add kgdb support
+- sw64: add jump_label support
+- sw64: add uprobe support
+- sw64: add kprobe support
+- sw64: add kernel relocation support
+- sw64: add ftrace support
+- sw64: add hibernation support
+- sw64: add suspend support
+- sw64: add eBPF JIT support
+- sw64: add kdump support
+- sw64: add kexec support
+- sw64: add perf events support
+- sw64: add qspinlock support
+- sw64: add stacktrace support
+- !4567 Support feature TWED
+- KVM: arm64: Make use of TWED feature
+- arm64: cpufeature: TWED support detection
+- !4383 [OLK-6.6] kabi: add more x86/cpu reservations in cpu feature bits and bug bits
+- kabi: reserve x86 cpu bug fields
+- kabi: reserve x86 cpu capability fields
+- !3695 x86: Add x86 related kabi reservations
+- x86: Add x86 related kabi reservations
+- !4589 fs,hugetlb: fix NULL pointer dereference in hugetlbs_fill_super
+- fs,hugetlb: fix NULL pointer dereference in hugetlbs_fill_super
+- !4451 v5 kabi reserve patches
+- kabi: reserve space for arm64 cpufeature related structure
+- kabi: reserve space for power management related structure
+- energy_model: Add kabi_reserve
+- pm: pm.h: Add kabi_reserve
+- pm: pm_domain.h: Add kabi_reserve
+- drm: drm_gem.h: Add kabi_reserve
+- drm: drm_fourcc.h: Add kabi_reserve
+- drm: drm_file.h: Add kabi_reserve
+- drm: drm_fb_helper.h: Add kabi_reserve
+- drm: drm_drv.h: Add kabi_reserve
+- drm: drm_device.h: Add kabi_reserve
+- drm: drm_crtc.h: Add kabi_reserve
+- drm: drm_connector.h: Add kabi_reserve
+- drm: drm_client.h: Add kabi_reserve
+- drm: drm_atomic.h: Add kabi_reserve
+- irqdomain: Add kabi_reserve in irqdomain
+- irq_desc: Add kabi_reserve in irq_desc
+- irq: Add kabi_reserve in irq
+- interrupt: Add kabi_reserve in interrupt.h
+- msi: Add kabi_reserve in msi.h
+- kabi: reserve space for struct cpu_stop_work
+- KABI: reserve space for struct input_dev
+- !4557 Add ZONE_EXTMEM to avoid kabi broken
+- openeuler_defconfig: enable CONFIG_ZONE_EXTMEM for arm64
+- mm: add ZONE_EXTMEM for future extension to avoid kabi broken
+- !4569 add sw64 architecture support
+- sw64: add KVM support
+- sw64: add EFI support
+- sw64: add DMA support
+- sw64: add ACPI support
+- sw64: add device trees
+- sw64: add MSI support
+- sw64: add PCI support
+- sw64: add default configs
+- sw64: add NUMA support
+- sw64: add SMP support
+- sw64: add VDSO support
+- sw64: add some library functions
+- sw64: add some other routines
+- sw64: add some common routines
+- sw64: add module support
+- sw64: add basic IO support
+- sw64: add FPU support
+- !3498 fuse: reserve space for future expansion
+- kabi:fuse: reserve space for future expansion
+- !4435 v2 kabi: reserve space for struct ptp_clock
+- kabi: reserve space for struct ptp_clock
+- !4584 v5 kabi reserve
+- kabi: reserve space for struct clocksource
+- kabi: reserve space for struct timer_list
+- kabi: reserve space for struct ptp_clock_info
+- kabi: reserve space for posix clock related structure
+- kabi: reserve space for hrtimer related structures
+- kabi: reserve space for kobject related structures
+- !4049 openeuler_defconfig: Disable new HW_RANDOM support for arm64
+- openeuler_defconfig: Disable new HW_RANDOM support for arm64
+- !4582 cgroup/hugetlb: hugetlb accounting
+- mm: memcg: fix split queue list crash when large folio migration
+- hugetlb: memcg: account hugetlb-backed memory in memory controller
+- memcontrol: only transfer the memcg data for migration
+- memcontrol: add helpers for hugetlb memcg accounting
+- !4347 【OLK-6.6】AMD: CXL RCH Protocol Error Handling supporting
+- openeuler_defconfig: Enable CONFIG_PCIEAER_CXL=y
+- cxl/hdm: Fix && vs || bug
+- cxl/pci: Change CXL AER support check to use native AER
+- cxl/core/regs: Rework cxl_map_pmu_regs() to use map->dev for devm
+- cxl/core/regs: Rename phys_addr in cxl_map_component_regs()
+- PCI/AER: Unmask RCEC internal errors to enable RCH downstream port error handling
+- PCI/AER: Forward RCH downstream port-detected errors to the CXL.mem dev handler
+- cxl/pci: Disable root port interrupts in RCH mode
+- cxl/pci: Add RCH downstream port error logging
+- cxl/pci: Map RCH downstream AER registers for logging protocol errors
+- cxl/pci: Update CXL error logging to use RAS register address
+- PCI/AER: Refactor cper_print_aer() for use by CXL driver module
+- cxl/pci: Add RCH downstream port AER register discovery
+- cxl/port: Remove Component Register base address from struct cxl_port
+- cxl/pci: Remove Component Register base address from struct cxl_dev_state
+- cxl/hdm: Use stored Component Register mappings to map HDM decoder capability
+- cxl/pci: Store the endpoint's Component Register mappings in struct cxl_dev_state
+- cxl/port: Pre-initialize component register mappings
+- cxl/port: Rename @comp_map to @reg_map in struct cxl_register_map
+- !4390 [OLK-6.6] Add kdump support for Phytium S2500
+- Add kdump support for Phytium S2500
+- !4459 v2 Introduce page eject for arm64
+- config: update defconfig for PAGE_EJECT
+- mm: page_eject: Introuduce page ejection
+- mm/memory-failure: introduce soft_online_page
+- mm/hwpoison: Export symbol soft_offline_page
+- !3699 [OLK-6.6] Enable CONFIG_IOMMUFD and CONFIG_VFIO_DEVICE_CDEV in x86/arm64 defconfig
+- defconfig: enable CONFIG_IOMMUFD and CONFIG_VFIO_DEVICE_CDEV
+- !4571 scsi: iscsi: kabi: KABI reservation for iscsi_transport
+- scsi: iscsi: kabi: KABI reservation for iscsi_transport
+- !4546 RDMA/hns: Support MR management
+- RDMA/hns: Simplify 'struct hns_roce_hem' allocation
+- RDMA/hns: Support adaptive PBL hopnum
+- RDMA/hns: Support flexible umem page size
+- RDMA/hns: Alloc MTR memory before alloc_mtt()
+- RDMA/hns: Refactor mtr_init_buf_cfg()
+- RDMA/hns: Refactor mtr find
+- !4576 v6 Add support for ecmdq
+- iommu/arm-smmu-v3: Allow disabling ECMDQs at boot time
+- iommu/arm-smmu-v3: Add support for less than one ECMDQ per core
+- iommu/arm-smmu-v3: Add arm_smmu_ecmdq_issue_cmdlist() for non-shared ECMDQ
+- iommu/arm-smmu-v3: Ensure that a set of associated commands are inserted in the same ECMDQ
+- iommu/arm-smmu-v3: Add support for ECMDQ register mode
+- !3697 enable ARM64/X86 CONFIG_BPF_LSM config
+- lsm: enable CONFIG_BPF_LSM for use bpf in lsm program
+- !4537 mainline cgroup bufix
+- cgroup: use legacy_name for cgroup v1 disable info
+- blk-cgroup: bypass blkcg_deactivate_policy after destroying
+- cgroup: Check for ret during cgroup1_base_files cft addition
+- !4438 kabi: reserve space for workqueue subsystem related structure
+- kabi: reserve space for workqueue subsystem related structure
+- !4570 v2 scsi: reserve space for structures in scsi
+- scsi: reserve space for structures in scsi
+- !4566 v2 reserve kabi space for some structures
+- libnvdimm: reserve space for structures in libnvdimm
+- ata: libata: reserve space for structures in libata
+- elevator: reserve space for structures in elevator
+
+* Wed Feb 7 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-9.0.0.5
+- !4545 add sw64 architecture support
+- sw64: add signal handling support
+- sw64: add system call support
+- sw64: add hugetlb support
+- sw64: add memory management
+- sw64: add hardware match support
+- sw64: add process management
+- sw64: add exception handling support
+- sw64: add irq handling support
+- sw64: add timer support
+- sw64: add topology setup routine
+- sw64: add boot and setup routines
+- sw64: add some other headers
+- sw64: add ELF support
+- sw64: add common headers
+- sw64: add atomic/locking headers
+- sw64: add CPU definition headers
+- sw64: add build infrastructure
+- !4423 kabi: reserve space for pci subsystem and thread_info
+- kabi: reserve space for pci subsystem related structure
+- kabi: reserve space for thread_info structure
+- !3997 [OLK-6.6] openEuler-24.03 Phytium S2500 IPMI adaption
+- ipmi_si: Phytium S2500 workaround for MMIO-based IPMI
+- !3841 Add support for Hygon family 18h model 5h HD-Audio
+- ALSA: hda: Fix single byte writing issue for Hygon family 18h model 5h
+- ALSA: hda: Add support for Hygon family 18h model 5h HD-Audio
+- !3835 Add support for Hygon model 6h L3 PMU
+- perf/x86/uncore: Add L3 PMU support for Hygon family 18h model 6h
+- !3698 enable ARM64/X86_64 CONFIG_MPTCP/CONFIG_MPTCP_IPV6 config
+- mptcp: enable config CONFIG_MPTCP and CONFIG_MPTCP_IPV6
+- !3696 enable ARM64/X86 CONFIG_XDP_SOCKET、CONFIG_XDP_SOCKETS_DIAG config
+- xdp: enable config CONFIG_XDP_SOCKETS and CONFIG_XDP_SOCKETS_DIAG
+- !3183 [OLK-6.6] Add support Zhaoxin GPIO pinctrl
+- configs: add CONFIG_PINCTRL_ZHAOXIN and KX7000 to m
+- Add support Zhaoxin GPIO pinctrl
+- !4539 nvme: kabi: KABI reservation for nvme_ctrl
+- nvme: kabi: KABI reservation for nvme_ctrl
+- !4527 v3 block: kabi: KABI reservation for blk-cgroup
+- block: kabi: KABI reservation for blk-cgroup
+- !4554 v3 kabi: Reserve KABI slots for fs module
+- sysfs: kabi: Reserve KABI slots for bin_attribute struct
+- profs: kabi: Reserve KABI slots for proc_ops struct
+- dax: kabi: Reserve KABI slots for dax_* struct
+- fs: kabi: Reserve KABI slots for nameidata struct
+- xattr: kabi: Reserve KABI slots for xattr_handler struct
+- kernfs: kabi: Reserve KABI slots for kernfs_* struct
+- fanotify: kabi: Reserve KABI slots for fsnotify_* struct
+- fscrypt: kabi: Reserve KABI slots for fscrypt_operations struct
+- !3932 [OLK-6.6] 同步OLK-5.10 SMMU HTTU补丁
+- iommu/arm-smmu-v3: Add Arm SMMU HTTU config
+- vfio/iommu_type1: Add support for manual dirty log clear
+- vfio/iommu_type1: Optimize dirty bitmap population based on iommu HWDBM
+- vfio/iommu_type1: Add HWDBM status maintenance
+- iommu/arm-smmu-v3: Realize support_dirty_log iommu ops
+- iommu/arm-smmu-v3: Realize clear_dirty_log iommu ops
+- iommu/arm-smmu-v3: Realize sync_dirty_log iommu ops
+- iommu/arm-smmu-v3: Realize switch_dirty_log iommu ops
+- iommu/arm-smmu-v3: Add feature detection for BBML
+- iommu/arm-smmu-v3: Enable HTTU for stage1 with io-pgtable mapping
+- iommu/io-pgtable-arm: Add and realize clear_dirty_log ops
+- iommu/io-pgtable-arm: Add and realize sync_dirty_log ops
+- iommu/io-pgtable-arm: Add and realize merge_page ops
+- iommu/io-pgtable-arm: Add and realize split_block ops
+- iommu/io-pgtable-arm: Add __arm_lpae_set_pte
+- iommu/io-pgtable-arm: Add quirk ARM_HD and ARM_BBMLx
+- iommu: Introduce dirty log tracking framework
+- iommu/arm-smmu-v3: Add support for Hardware Translation Table Update
+- !4560 v5 block: reserve kabi space for general block layer structures
+- block: reserve kabi space for general block layer structures
+- !4168 Reserve syscall entries for kabi compatibility
+- kabi: Reserve syscall entries for kabi compatibility
+- arch: Reserve map_shadow_stack() syscall number for all architectures
+- !4532 v2 fscache: reserve kabi for fscache structures
+- fscache: reserve kabi for fscache structures
+- !4543 v2 fs/dcache: kabi: KABI reservation for dentry
+- fs/dcache: kabi: KABI reservation for dentry
+- !4533 quota: kabi: KABI reservation for quota
+- quota: kabi: KABI reservation for quota
+- !4528 v3 jbd2: kabi: KABI reservation for jbd2
+- jbd2: kabi: KABI reservation for jbd2
+- !4483 block: kabi: KABI reservation for iocontext
+- block: kabi: KABI reservation for iocontext
+- !4455 scsi: iscsi: kabi: KABI reservation for scsi_transport_iscsi.h
+- scsi: iscsi: kabi: KABI reservation for scsi_transport_iscsi.h
+- !4456 scsi: scsi_transport_fc: kabi: KABI reservation for scsi_transport_fc
+- scsi: scsi_transport_fc: kabi: KABI reservation for scsi_transport_fc
+- !4472 nvmet-fc: kabi: KABI reservation for nvme_fc_port_template
+- nvmet-fc: kabi: KABI reservation for nvme_fc_port_template
+- !4474 scsi: libsas: kabi: KABI reservation for libsas
+- scsi: libsas: kabi: KABI reservation for libsas
+- !4463 RDMA/hns: Backport bugfix
+- RDMA/hns: Fix memory leak in free_mr_init()
+- RDMA/hns: Remove unnecessary checks for NULL in mtr_alloc_bufs()
+- RDMA/hns: Add a max length of gid table
+- RDMA/hns: Response dmac to userspace
+- RDMA/hns: Rename the interrupts
+- RDMA/hns: Support SW stats with debugfs
+- RDMA/hns: Add debugfs to hns RoCE
+- RDMA/hns: Fix inappropriate err code for unsupported operations
+- !3838 Add support for Hygon model 4h EDAC
+- EDAC/amd64: Adjust UMC channel for Hygon family 18h model 6h
+- EDAC/amd64: Add support for Hygon family 18h model 6h
+- EDAC/amd64: Add support for Hygon family 18h model 5h
+- EDAC/mce_amd: Use struct cpuinfo_x86.logical_die_id for Hygon NodeId
+- EDAC/amd64: Adjust address translation for Hygon family 18h model 4h
+- EDAC/amd64: Add support for Hygon family 18h model 4h
+- EDAC/amd64: Get UMC channel from the 6th nibble for Hygon
+- !4408 v2 kabi: reserve space for struct acpi_device and acpi_scan_handler
+- kabi: reserve space for struct acpi_device and acpi_scan_handler
+- !4495 KABI reservation for driver
+- audit: kabi: Remove extra semicolons
+- ipmi: kabi: KABI reservation for ipmi
+- mmc: kabi: KABI reservation for mmc
+- mtd: kabi: KABI reservation for mtd
+- tty: kabi: KABI reservation for tty
+- !3831 Add support for loading Hygon microcode
+- x86/microcode/hygon: Add microcode loading support for Hygon processors
+- !4356 【OLK-6.6】AMD: support the UMC Performance Counters for Zen4
+- perf vendor events amd: Add Zen 4 memory controller events
+- perf/x86/amd/uncore: Pass through error code for initialization failures, instead of -ENODEV
+- perf/x86/amd/uncore: Fix uninitialized return value in amd_uncore_init()
+- perf/x86/amd/uncore: Add memory controller support
+- perf/x86/amd/uncore: Add group exclusivity
+- perf/x86/amd/uncore: Use rdmsr if rdpmc is unavailable
+- perf/x86/amd/uncore: Move discovery and registration
+- perf/x86/amd/uncore: Refactor uncore management
+- !4494 v2 writeback: kabi: KABI reservation for writeback
+- writeback: kabi: KABI reservation for writeback
+- !4491 sched/rt: Fix possible warn when push_rt_task
+- sched/rt: Fix possible warn when push_rt_task
+- !4396 [OLK-6.6] perf/x86/zhaoxin/uncore: add NULL pointer check after kzalloc
+- perf/x86/zhaoxin/uncore: add NULL pointer check after kzalloc
+- !4405 mm: improve performance of accounted kernel memory allocations
+- mm: kmem: properly initialize local objcg variable in current_obj_cgroup()
+- mm: kmem: reimplement get_obj_cgroup_from_current()
+- percpu: scoped objcg protection
+- mm: kmem: scoped objcg protection
+- mm: kmem: make memcg keep a reference to the original objcg
+- mm: kmem: add direct objcg pointer to task_struct
+- mm: kmem: optimize get_obj_cgroup_from_current()
+- !4500 fs: kabi: KABI reservation for vfs
+- fs: kabi: KABI reservation for vfs
+- !4505 iov_iter: kabi: KABI reservation for iov_iter
+- iov_iter: kabi: KABI reservation for iov_iter
+- !4486 v2 openeuler_defconfig: enable CONFIG_PAGE_CACHE_LIMIT
+- openeuler_defconfig: enable CONFIG_PAGE_CACHE_LIMIT
+- !4489 【OLK-6.6】AMD: fix brstack event for AMD Zen CPU
+- perf/x86/amd: Reject branch stack for IBS events
+- !4376 [OLK-6.6] Add Phytium Display Engine support to the OLK-6.6.
+- DRM: Phytium display DRM doc
+- DRM: Phytium display DRM driver
+- !4385 v2 sched: remove __GENKSYMS__ used
+- sched: remove __GENKSYMS__ used
+- !4449 memory tiering: calculate abstract distance based on ACPI HMAT
+- dax, kmem: calculate abstract distance with general interface
+- acpi, hmat: calculate abstract distance with HMAT
+- acpi, hmat: refactor hmat_register_target_initiators()
+- memory tiering: add abstract distance calculation algorithms management
+- !4362 ubifs: Queue up space reservation tasks if retrying many times
+- ubifs: Queue up space reservation tasks if retrying many times
+- !4450 change zswap's default allocator to zsmalloc
+- openeuler_defconfig: set ZSWAP_ZPOOL_DEFAULT to ZSMALLOC
+- zswap: change zswap's default allocator to zsmalloc
+- !4298 misc for controlling fd
+- cgroup/misc: support cgroup misc to control fd
+- filescgroup: add adapter for legacy and misc cgroup
+- filescgroup: rename filescontrol.c to legacy-filescontrol.c
+- filescgroup: Add CONFIG_CGROUP_FILES at files_cgroup in files_struct
+- filescgroup: remove files of dfl_cftypes.
+- !4173 block: remove precise_iostat
+- block: remove precise_iostat
+- !4481 cred: kabi: KABI reservation for cred
+- cred: kabi: KABI reservation for cred
+- !4418 KABI: Add reserve space for sched structures
+- KABI: Reserve space for fwnode.h
+- KABI: Reserve space for struct module
+- fork: Allocate a new task_struct_resvd object for fork task
+- KABI: Add reserve space for sched structures
+- !4355 v4 kabi reserve for memcg and cgroup_bpf
+- cgroup_bpf/kabi: reserve space for cgroup_bpf related structures
+- memcg/kabi: reserve space for memcg related structures
+- !4476 net/kabi: Reserve space for net structures
+- net/kabi: Reserve space for net structures
+- !4440 v2 kabi:dma:add kabi reserve for dma_map_ops structure
+- kabi:dma:add kabi reserve for dma_map_ops structure
+- !4479 mm/memcontrol: fix out-of-bound access in mem_cgroup_sysctls_init
+- mm/memcontrol: fix out-of-bound access in mem_cgroup_sysctls_init
+- !4429 Remove unnecessary KABI reservation
+- crypto: kabi: Removed unnecessary KABI reservation
+- !4211 blk-mq: avoid housekeeping CPUs scheduling a worker on a non-housekeeping CPU
+- blk-mq: avoid housekeeping CPUs scheduling a worker on a non-housekeeping CPU
+- !4407 sched/topology: Fix cpus hotplug deadlock in check_node_limit()
+- sched/topology: Fix cpus hotplug deadlock in check_node_limit()
+- !4351 kabi: net: reserve space for net subsystem related structure
+- kabi: net: reserve space for net subsystem related structure
+- !4453 arm64/ascend: Make enable_oom_killer feature depends on ASCEND_FEATURE
+- arm64/ascend: Make enable_oom_killer feature depends on ASCEND_FEATURE
+- !4386 fix static scanning issues
+- bond: fix static scanning issue with bond_broadcast_arp_or_nd_table_header
+- tcp: fix static scanning issue with sysctl_local_port_allocation
+- !4403 v2 kabi: net: reserve space for net related structure
+- kabi: net: reserve space for net related structure
+- !4406 v2 net/kabi: reserve space for net related structures
+- net/kabi: reserve space for net related structures
+- !4398 v2 vfs: reserve kabi space for vfs related structures
+- vfs: reserve kabi space for vfs related structures
+- !4372 kabi: reserve space for struct rate_sample
+- kabi: reserve space for struct rate_sample
+- !4322 cgroup_writeback: fix deadlock
+- cgroup_writeback: fix deadlock in cgroup1_writeback
+- !4414 Support srq record doorbell and support query srq context
+- RDMA/hns: Support SRQ record doorbell
+- RDMA/hns: Support SRQ restrack ops for hns driver
+- RDMA/core: Add support to dump SRQ resource in RAW format
+- RDMA/core: Add dedicated SRQ resource tracker function
+- !4165 tlb: reserve fields for struct mmu_gather
+- tlb: reserve fields for struct mmu_gather
+- !4178 OLK-6.6 cred backport for kabi reserve
+- cred: get rid of CONFIG_DEBUG_CREDENTIALS
+- groups: Convert group_info.usage to refcount_t
+- cred: switch to using atomic_long_t
+- cred: add get_cred_many and put_cred_many
+- !4343 v3 reserve KABI slots for file system or storage related structures
+- mtd: kabi: Reserve KABI slots for mtd_device_xxx_register() related structures
+- pipe: kabi: Reserve KABI slots for pipe_inode_info structure
+- exportfs: kabi: Reserve KABI slots for export_operations structure
+- !4200 Expose swapcache stat for memcg v1
+- memcg: remove unused do_memsw_account in memcg1_stat_format
+- memcg: expose swapcache stat for memcg v1
+- !4140 backport some patches for kunpeng hccs
+- soc: hisilicon: kunpeng_hccs: Support the platform with PCC type3 and interrupt ack
+- doc: kunpeng_hccs: Fix incorrect email domain name
+- soc: hisilicon: kunpeng_hccs: Remove an unused blank line
+- soc: hisilicon: kunpeng_hccs: Add failure log for no _CRS method
+- soc: hisilicon: kunpeng_hccs: Fix some incorrect format strings
+- soc/hisilicon: kunpeng_hccs: Convert to platform remove callback returning void
+- soc: kunpeng_hccs: Migrate to use generic PCC shmem related macros
+- hwmon: (xgene) Migrate to use generic PCC shmem related macros
+- i2c: xgene-slimpro: Migrate to use generic PCC shmem related macros
+- ACPI: PCC: Add PCC shared memory region command and status bitfields
+- !3641 Make the cpuinfo_cur_freq interface read correctly
+- cpufreq: CPPC: Keep the target core awake when reading its cpufreq rate
+- arm64: cpufeature: Export cpu_has_amu_feat()
+- !4410 config: Update openeuler_defconfig base on current
+- config: x86: Update openeuler_defconfig base on current source code
+- config: arm64: Update openeuler_defconfig base on current source code
+- !4400 v2 soc: hisilicon: hisi_hbmdev: Fix compile error
+- soc: hisilicon: hisi_hbmdev: Fix compile error
+- !4397 v2 cryptd: kabi: Fixed boot panic
+- cryptd: kabi: Fixed boot panic
+- !4393 [OLK-6.6] crypto: sm4: fix the build warning issue of sm4 driver
+- crypto: sm4: fix the build warning issue of sm4 driver
+- !4368 cgroup/misc: fix compiling waring
+- cgroup/misc: fix compiling waring
+- !4364 [OLK-6.6] crypto: sm3/sm4: fix zhaoxin sm3/sm4 driver file name mismatch issue
+- crypto: sm3/sm4: fix zhaoxin sm3/sm4 driver file name mismatch issue
+- !4204 arm64: Turn on CONFIG_IPI_AS_NMI in openeuler_defconfig
+- arm64: Turn on CONFIG_IPI_AS_NMI in openeuler_defconfig
+- !4314 tracing: Reserve kabi fields
+- tracing: Reserve kabi fields
+- !4301 v3 kabi: reserve space for cpu cgroup and cpuset cgroup related structures
+- kabi: reserve space for cpu cgroup and cpuset cgroup related structures
+- !4177 kabi: reserve space for bpf related structures
+- kabi: reserve space for bpf related structures
+- !4354 v7 KABI reservation for IMA and crypto
+- ima: kabi: KABI reservation for IMA
+- crypto: kabi: KABI reservation for crypto
+- !4346 v2 pciehp: fix a race between pciehp and removing operations by sysfs
+- pciehp: fix a race between pciehp and removing operations by sysfs
+- !4146 tcp: fix compilation issue when CONFIG_SYSCTL is disabled
+- tcp: fix compilation issue when CONFIG_SYSCTL is disabled
+- !4066 smb: client: fix OOB in receive_encrypted_standard()
+- smb: client: fix OOB in receive_encrypted_standard()
+- !3995 net: config: enable network config
+- net: config: enable network config
+- !3745 【OLK-6.6】Support SMT control on arm64
+- config: enable CONFIG_HOTPLUG_SMT for arm64
+- arm64: Kconfig: Enable HOTPLUG_SMT
+- arm64: topology: Support SMT control on ACPI based system
+- arch_topology: Support SMT control for OF based system
+- arch_topology: Support basic SMT control for the driver
+- !4000 audit: kabi: KABI reservation for audit
+- audit: kabi: KABI reservation for audit
+- !4249 ubifs: fix possible dereference after free
+- ubifs: fix possible dereference after free
+- !3178 [OLK-6.6] Driver for Zhaoxin SM3 and SM4 algorithm
+- configs: Add Zhaoxin SM3 and SM4 algorithm configs
+- Add support for Zhaoxin GMI SM4 Block Cipher algorithm
+- Add support for Zhaoxin GMI SM3 Secure Hash algorithm
+- !4219 Initial cleanups for vCPU hotplug
+- riscv: convert to use arch_cpu_is_hotpluggable()
+- riscv: Switch over to GENERIC_CPU_DEVICES
+- LoongArch: convert to use arch_cpu_is_hotpluggable()
+- LoongArch: Use the __weak version of arch_unregister_cpu()
+- LoongArch: Switch over to GENERIC_CPU_DEVICES
+- x86/topology: convert to use arch_cpu_is_hotpluggable()
+- x86/topology: use weak version of arch_unregister_cpu()
+- x86/topology: Switch over to GENERIC_CPU_DEVICES
+- arm64: convert to arch_cpu_is_hotpluggable()
+- arm64: setup: Switch over to GENERIC_CPU_DEVICES using arch_register_cpu()
+- drivers: base: Print a warning instead of panic() when register_cpu() fails
+- drivers: base: Move cpu_dev_init() after node_dev_init()
+- drivers: base: add arch_cpu_is_hotpluggable()
+- drivers: base: Implement weak arch_unregister_cpu()
+- drivers: base: Allow parts of GENERIC_CPU_DEVICES to be overridden
+- drivers: base: Use present CPUs in GENERIC_CPU_DEVICES
+- ACPI: Move ACPI_HOTPLUG_CPU to be disabled on arm64 and riscv
+- Loongarch: remove arch_*register_cpu() exports
+- x86/topology: remove arch_*register_cpu() exports
+- x86: intel_epb: Don't rely on link order
+- arch_topology: Make register_cpu_capacity_sysctl() tolerant to late CPUs
+- arm64, irqchip/gic-v3, ACPI: Move MADT GICC enabled check into a helper
+- ACPI: scan: Rename acpi_scan_device_not_present() to be about enumeration
+- ACPI: scan: Use the acpi_device_is_present() helper in more places
+- !4215 pci: Enable acs for QLogic HBA cards
+- pci: Enable acs for QLogic HBA cards
+- !4267 ksmbd: fix slab-out-of-bounds in smb_strndup_from_utf16()
+- ksmbd: fix slab-out-of-bounds in smb_strndup_from_utf16()
+- !4317 [OLK-6.6] cputemp: zhaoxin: fix HWMON_THERMAL namespace not import issue
+- cputemp: zhaoxin: fix HWMON_THERMAL namespace not import issue.
+- !3682 cgroup and ns kabi reserve
+- cgroup/misc: reserve kabi for future misc development
+- cgroup/psi: reserve kabi for future psi development
+- namespace: kabi: reserve for future namespace development
+- cgroup: kabi: reserve space for cgroup frame
+- !4291 fs:/dcache.c: fix negative dentry limit not complete problem
+- fs:/dcache.c: fix negative dentry limit not complete problem
+- !4292 powerpc: Add PVN support for HeXin C2000 processor
+- powerpc: Add PVN support for HeXin C2000 processor
+- !3129 [OLK-6.6] Driver for Zhaoxin AES and SHA algorithm
+- Add Zhaoxin aes/sha items in openeuler_config
+- Add support for Zhaoxin SHA algorithm
+- Add support for Zhaoxin AES algorithm
+- !3959 kabi: mm: add kabi reserve for mm structure
+- kabi: mm: add kabi reserve for mm structure
+- !4046 [OLK-6.6] Add gic support for Phytium S2500
+- Add gic support for Phytium S2500
+- !3126 [OLK-6.6] Driver for Zhaoxin HW Random Number Generator
+- Add CONFIG_HW_RANDOM_ZHAOXIN in openeuler_defconfig
+- Add support for Zhaoxin HW Random Number Generator
+- !3169 [OLK-6.6] x86/perf: Add uncore performance events support for Zhaoxin CPU
+- x86/perf: Add uncore performance events support for Zhaoxin CPU
+- !3187 [OLK-6.6] Add support for Zhaoxin I2C controller
+- configs: add CONFIG_I2C_ZHAOXIN to m
+- Add support for Zhaoxin I2C controller
+- !4164 arch/mm/fault: fix major fault accounting when retrying under per-VMA lock
+- arch/mm/fault: fix major fault accounting when retrying under per-VMA lock
+- !3903 kabi: Reserve space for perf subsystem related structures
+- kabi: Reserve space for perf subsystem related structures
+- !4128 drm/qxl: Fix missing free_irq
+- drm/qxl: Fix missing free_irq
+- !4050 kabi: net: reserve space for net
+- kabi: net: reserve space for net sunrpc subsystem related structure
+- kabi: net: reserve space for net rdma subsystem related structure
+- kabi: net: reserve space for net netfilter subsystem related structure
+- kabi: net: reserve space for net can subsystem related structure
+- kabi: net: reserve space for net bpf subsystem related structure
+- kabi: net: reserve space for net base subsystem related structure
+- !3774 [OLK-6.6] sched/fair: Scan cluster before scanning LLC in wake-up path
+- sched/fair: Use candidate prev/recent_used CPU if scanning failed for cluster wakeup
+- sched/fair: Scan cluster before scanning LLC in wake-up path
+- sched: Add cpus_share_resources API
+- !3125 [OLK-6.6] Driver for Zhaoxin Serial ATA IDE
+- configs: enable CONFIG_SATA_ZHAOXIN to y
+- Add support for Zhaoxin Serial ATA IDE.
+- !4044 Set CONFIG_NODES_SHIFT to 8
+- openeuler_defconfig: set CONFIG_NODES_SHIFT to 8 for both x86_64/ARM64
+- x86/Kconfig: allow NODES_SHIFT to be set on MAXSMP
+- !3840 Remove Hygon SMBus IMC detecting
+- i2c-piix4: Remove the IMC detecting for Hygon SMBus
+- !3839 Add support for Hygon model 4h k10temp
+- hwmon/k10temp: Add support for Hygon family 18h model 5h
+- hwmon/k10temp: Add support for Hygon family 18h model 4h
+- !3837 Add support for Hygon model 4h northbridge
+- x86/amd_nb: Add support for Hygon family 18h model 6h
+- x86/amd_nb: Add support for Hygon family 18h model 5h
+- x86/amd_nb: Add northbridge support for Hygon family 18h model 4h
+- x86/amd_nb: Add Hygon family 18h model 4h PCI IDs
+- !4199 Support large folio for mlock
+- mm: mlock: avoid folio_within_range() on KSM pages
+- mm: mlock: update mlock_pte_range to handle large folio
+- mm: handle large folio when large folio in VM_LOCKED VMA range
+- mm: add functions folio_in_range() and folio_within_vma()
+- !4147 arm64: Add CONFIG_IPI_AS_NMI to IPI as NMI feature
+- arm64: Add CONFIG_IPI_AS_NMI to IPI as NMI feature
+- !4159 Backport iommufd dirty tracking from v6.7
+- iommu/vt-d: Set variable intel_dirty_ops to static
+- iommufd/selftest: Fix _test_mock_dirty_bitmaps()
+- iommufd/selftest: Fix page-size check in iommufd_test_dirty()
+- iommu/vt-d: Enhance capability check for nested parent domain allocation
+- iommufd/selftest: Test IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR flag
+- iommufd/selftest: Test out_capabilities in IOMMU_GET_HW_INFO
+- iommufd/selftest: Test IOMMU_HWPT_GET_DIRTY_BITMAP
+- iommufd/selftest: Test IOMMU_HWPT_SET_DIRTY_TRACKING
+- iommufd/selftest: Test IOMMU_HWPT_ALLOC_DIRTY_TRACKING
+- iommufd/selftest: Expand mock_domain with dev_flags
+- iommu/vt-d: Access/Dirty bit support for SS domains
+- iommu/amd: Access/Dirty bit support in IOPTEs
+- iommu/amd: Add domain_alloc_user based domain allocation
+- iommufd: Add a flag to skip clearing of IOPTE dirty
+- iommufd: Add capabilities to IOMMU_GET_HW_INFO
+- iommufd: Add IOMMU_HWPT_GET_DIRTY_BITMAP
+- iommufd: Add IOMMU_HWPT_SET_DIRTY_TRACKING
+- iommufd: Add a flag to enforce dirty tracking on attach
+- iommufd: Correct IOMMU_HWPT_ALLOC_NEST_PARENT description
+- iommu: Add iommu_domain ops for dirty tracking
+- iommufd/iova_bitmap: Move symbols to IOMMUFD namespace
+- vfio: Move iova_bitmap into iommufd
+- vfio/iova_bitmap: Export more API symbols
+- iommufd/selftest: Rework TEST_LENGTH to test min_size explicitly
+- iommu/vt-d: Add domain_alloc_user op
+- iommufd/selftest: Add domain_alloc_user() support in iommu mock
+- iommufd/selftest: Iterate idev_ids in mock_domain's alloc_hwpt test
+- iommufd: Support allocating nested parent domain
+- iommufd: Flow user flags for domain allocation to domain_alloc_user()
+- iommufd: Use the domain_alloc_user() op for domain allocation
+- iommu: Add new iommu op to create domains owned by userspace
+- !4109 PCI: add a member in 'struct pci_bus' to record the original 'pci_ops'
+- PCI: add a member in 'struct pci_bus' to record the original 'pci_ops'
+- !4108 PCI/AER: increments pci bus reference count in aer-inject process
+- PCI/AER: increments pci bus reference count in aer-inject process
+- !4114 pci: do not save 'PCI_BRIDGE_CTL_BUS_RESET'
+- pci: do not save 'PCI_BRIDGE_CTL_BUS_RESET'
+- !4113 PCI: check BIR before mapping MSI-X Table
+- PCI: check BIR before mapping MSI-X Table
+- !4112 PCI: Fail MSI-X mapping if MSI-X Table offset is out of range of BAR space
+- PCI: Fail MSI-X mapping if MSI-X Table offset is out of range of BAR space
+- !4110 PCI: Add MCFG quirks for some Hisilicon Chip host controllers
+- PCI: Add MCFG quirks for some Hisilicon Chip host controllers
+- !4111 sysrq: avoid concurrently info printing by 'sysrq-trigger'
+- sysrq: avoid concurrently info printing by 'sysrq-trigger'
+- !4107 ntp: Avoid undefined behaviour in second_overflow()
+- ntp: Avoid undefined behaviour in second_overflow()
+- !4105 PCI/sysfs: Take reference on device to be removed
+- PCI/sysfs: Take reference on device to be removed
+- !3836 Add support for Hygon model 4h QoS
+- x86/resctrl: Add Hygon QoS support
+- !4154 Add per-node vmstat info and memcg info
+- mm/vmstat: move pgdemote_* out of CONFIG_NUMA_BALANCING
+- mm/vmstat: move pgdemote_* to per-node stats
+- mm: memcg: add THP swap out info for anonymous reclaim
+- !4170 mm/ksm: generalize ksm_process_profit
+- mm/ksm: generalize ksm_process_profit
+- !4120 arm_mpam: support mpam feature in OLK-6.6
+- arm_mpam: control memory bandwidth with hard limit flag
+- fs/resctrl: Remove the limit on the number of CLOSID
+- arm_mpam: resctrl: Update the rmid reallocation limit
+- arm_mpam: resctrl: Call resctrl_exit() in the event of errors
+- arm_mpam: resctrl: Tell resctrl about cpu/domain online/offline
+- perf/arm-cmn: Stop claiming all the resources
+- arm64: mpam: Select ARCH_HAS_CPU_RESCTRL
+- arm_mpam: resctrl: Add dummy definition for free running counters
+- arm_mpam: resctrl: Add empty definitions for fine-grained enables
+- arm_mpam: resctrl: Add empty definitions for pseudo lock
+- untested: arm_mpam: resctrl: Allow monitors to be configured
+- arm_mpam: resctrl: Add resctrl_arch_rmid_read() and resctrl_arch_reset_rmid()
+- arm_mpam: resctrl: Allow resctrl to allocate monitors
+- untested: arm_mpam: resctrl: Add support for mbm counters
+- untested: arm_mpam: resctrl: Add support for MB resource
+- arm_mpam: resctrl: Add rmid index helpers
+- arm64: mpam: Add helpers to change a tasks and cpu mpam partid/pmg values
+- arm_mpam: resctrl: Add CDP emulation
+- arm_mpam: resctrl: Implement helpers to update configuration
+- arm_mpam: resctrl: Add resctrl_arch_get_config()
+- arm_mpam: resctrl: Implement resctrl_arch_reset_resources()
+- arm_mpam: resctrl: Pick a value for num_rmid
+- arm_mpam: resctrl: Pick the caches we will use as resctrl resources
+- arm_mpam: resctrl: Add boilerplate cpuhp and domain allocation
+- arm_mpam: Add helper to reset saved mbwu state
+- arm_mpam: Use long MBWU counters if supported
+- arm_mpam: Probe for long/lwd mbwu counters
+- arm_mpam: Track bandwidth counter state for overflow and power management
+- arm_mpam: Add mpam_msmon_read() to read monitor value
+- arm_mpam: Add helpers to allocate monitors
+- arm_mpam: Probe and reset the rest of the features
+- arm_mpam: Allow configuration to be applied and restored during cpu online
+- arm_mpam: Use the arch static key to indicate when mpam is enabled
+- arm_mpam: Register and enable IRQs
+- arm_mpam: Extend reset logic to allow devices to be reset any time
+- arm_mpam: Add a helper to touch an MSC from any CPU
+- arm_mpam: Reset MSC controls from cpu hp callbacks
+- arm_mpam: Merge supported features during mpam_enable() into mpam_class
+- arm_mpam: Probe the hardware features resctrl supports
+- arm_mpam: Probe MSCs to find the supported partid/pmg values
+- arm_mpam: Add cpuhp callbacks to probe MSC hardware
+- arm_mpam: Add MPAM MSC register layout definitions
+- arm_mpam: Add the class and component structures for ris firmware described
+- arm_mpam: Add probe/remove for mpam msc driver and kbuild boiler plate
+- dt-bindings: arm: Add MPAM MSC binding
+- ACPI / MPAM: Parse the MPAM table
+- drivers: base: cacheinfo: Add helper to find the cache size from cpu+level
+- cacheinfo: Expose the code to generate a cache-id from a device_node
+- cacheinfo: Set cache 'id' based on DT data
+- cacheinfo: Allow for >32-bit cache 'id'
+- ACPI / PPTT: Add a helper to fill a cpumask from a cache_id
+- ACPI / PPTT: Add a helper to fill a cpumask from a processor container
+- ACPI / PPTT: Find PPTT cache level by ID
+- ACPI / PPTT: Provide a helper to walk processor containers
+- untested: KVM: arm64: Force guest EL1 to use user-space's partid configuration
+- arm64: mpam: Context switch the MPAM registers
+- KVM: arm64: Disable MPAM visibility by default, and handle traps
+- KVM: arm64: Fix missing traps of guest accesses to the MPAM registers
+- arm64: cpufeature: discover CPU support for MPAM
+- arm64: head.S: Initialise MPAM EL2 registers and disable traps
+- x86/resctrl: Move the filesystem portions of resctrl to live in '/fs/'
+- x86/resctrl: Move the filesystem bits to headers visible to fs/resctrl
+- fs/resctrl: Add boiler plate for external resctrl code
+- x86/resctrl: Drop __init/__exit on assorted symbols
+- x86/resctrl: Describe resctrl's bitmap size assumptions
+- x86/resctrl: Claim get_domain_from_cpu() for resctrl
+- x86/resctrl: Move get_config_index() to a header
+- x86/resctrl: Move thread_throttle_mode_init() to be managed by resctrl
+- x86/resctrl: Make resctrl_arch_pseudo_lock_fn() take a plr
+- x86/resctrl: Make prefetch_disable_bits belong to the arch code
+- x86/resctrl: Allow an architecture to disable pseudo lock
+- x86/resctrl: Allow resctrl_arch_mon_event_config_write() to return an error
+- x86/resctrl: Change mon_event_config_{read,write}() to be arch helpers
+- x86/resctrl: Add resctrl_arch_is_evt_configurable() to abstract BMEC
+- x86/resctrl: Export the is_mbm_*_enabled() helpers to asm/resctrl.h
+- x86/resctrl: Stop using the for_each_*_rdt_resource() walkers
+- x86/resctrl: Move max_{name,data}_width into resctrl code
+- x86/resctrl: Move monitor exit work to a restrl exit call
+- x86/resctrl: Move monitor init work to a resctrl init call
+- x86/resctrl: Add a resctrl helper to reset all the resources
+- x86/resctrl: Move resctrl types to a separate header
+- x86/resctrl: Wrap resctrl_arch_find_domain() around rdt_find_domain()
+- x86/resctrl: Export resctrl fs's init function
+- x86/resctrl: Remove rdtgroup from update_cpu_closid_rmid()
+- x86/resctrl: Add helper for setting CPU default properties
+- x86/resctrl: Move ctrlval string parsing links away from the arch code
+- x86/resctrl: Add a helper to avoid reaching into the arch code resource list
+- x86/resctrl: Separate arch and fs resctrl locks
+- x86/resctrl: Move domain helper migration into resctrl_offline_cpu()
+- x86/resctrl: Add CPU offline callback for resctrl work
+- x86/resctrl: Allow overflow/limbo handlers to be scheduled on any-but cpu
+- x86/resctrl: Add CPU online callback for resctrl work
+- x86/resctrl: Add helpers for system wide mon/alloc capable
+- x86/resctrl: Make rdt_enable_key the arch's decision to switch
+- x86/resctrl: Move alloc/mon static keys into helpers
+- x86/resctrl: Make resctrl_mounted checks explicit
+- x86/resctrl: Allow arch to allocate memory needed in resctrl_arch_rmid_read()
+- x86/resctrl: Allow resctrl_arch_rmid_read() to sleep
+- x86/resctrl: Queue mon_event_read() instead of sending an IPI
+- x86/resctrl: Add cpumask_any_housekeeping() for limbo/overflow
+- x86/resctrl: Move CLOSID/RMID matching and setting to use helpers
+- x86/resctrl: Allocate the cleanest CLOSID by searching closid_num_dirty_rmid
+- x86/resctrl: Use __set_bit()/__clear_bit() instead of open coding
+- x86/resctrl: Track the number of dirty RMID a CLOSID has
+- x86/resctrl: Allow RMID allocation to be scoped by CLOSID
+- x86/resctrl: Access per-rmid structures by index
+- x86/resctrl: Track the closid with the rmid
+- x86/resctrl: Move rmid allocation out of mkdir_rdt_prepare()
+- x86/resctrl: Create helper for RMID allocation and mondata dir creation
+- x86/resctrl: kfree() rmid_ptrs from resctrl_exit()
+- tick/nohz: Move tick_nohz_full_mask declaration outside the #ifdef
+- x86/resctrl: Display RMID of resource group
+- x86/resctrl: Add support for the files of MON groups only
+- x86/resctrl: Display CLOSID for resource group
+- x86/resctrl: Introduce "-o debug" mount option
+- x86/resctrl: Move default group file creation to mount
+- x86/resctrl: Unwind properly from rdt_enable_ctx()
+- x86/resctrl: Rename rftype flags for consistency
+- x86/resctrl: Simplify rftype flag definitions
+- x86/resctrl: Add multiple tasks to the resctrl group at once
+- x86/resctrl: Fix remaining kernel-doc warnings
+- !3834 Add support for Hygon model 4h IOAPIC
+- iommu/hygon: Add support for Hygon family 18h model 4h IOAPIC
+- !3830 Add support for Hygon model 5h CPU cache
+- x86/cpu: Get LLC ID for Hygon family 18h model 5h
+- !3311 Add support for Hygon model 4h CPU topology
+- x86/cpu/hygon: Fix __max_die_per_package for Hygon family 18h model 4h
+- !3124 [OLK-6.6] Add support for Zhaoxin HDAC and codec
+- ALSA: hda: Add support of Zhaoxin NB HDAC codec
+- ALSA: hda: Add support of Zhaoxin NB HDAC
+- ALSA: hda: Add support of Zhaoxin SB HDAC
+- !3098 [OLK-6.6] Add support for Zhaoxin Processors
+- x86/cpu: Add detect extended topology for Zhaoxin CPUs
+- x86/cpufeatures: Add Zhaoxin feature bits
+- !3742 arch/powerpc: add ppc little endian openuler defconfig
+- arch/powerpc: add ppc little endian openuler defconfig
+- !4099 Intel: Backport SRF LBR branch counter support to kernel v6.6
+- perf/x86/intel: Support branch counters logging
+- perf/x86/intel: Reorganize attrs and is_visible
+- perf: Add branch_sample_call_stack
+- perf/x86: Add PERF_X86_EVENT_NEEDS_BRANCH_STACK flag
+- perf: Add branch stack counters
+- !3177 [OLK-6.6] Add MWAIT Cx support for Zhaoxin CPUs
+- Add MWAIT Cx support for Zhaoxin CPUs
+- !3170 [OLK-6.6] rtc: Fix set RTC time delay 500ms on some Zhaoxin SOCs
+- rtc: Fix set RTC time delay 500ms on some Zhaoxin SOCs
+- !3131 [OLK-6.6] Driver for Zhaoxin CPU core temperature monitoring
+- Add CONFIG_SENSORS_ZHAOXIN_CPUTEMP in openeuler_defconfig
+- Add support for Zhaoxin core temperature monitoring
+- !3102 [OLK-6.6] x86/mce: Add Centaur MCA support
+- x86/mce: Add Centaur MCA support
+- !4116 Intel: Backport GNR/SRF PMU uncore support to kernel v6.6
+- perf/x86/intel/uncore: Support Sierra Forest and Grand Ridge
+- perf/x86/intel/uncore: Support IIO free-running counters on GNR
+- perf/x86/intel/uncore: Support Granite Rapids
+- perf/x86/uncore: Use u64 to replace unsigned for the uncore offsets array
+- perf/x86/intel/uncore: Generic uncore_get_uncores and MMIO format of SPR
+- !4115 Intel: Backport In Field Scan(IFS) SAF & Array BIST support for GNR & SRF
+- platform/x86/intel/ifs: ARRAY BIST for Sierra Forest
+- platform/x86/intel/ifs: Add new error code
+- platform/x86/intel/ifs: Add new CPU support
+- platform/x86/intel/ifs: Metadata validation for start_chunk
+- platform/x86/intel/ifs: Validate image size
+- platform/x86/intel/ifs: Gen2 Scan test support
+- platform/x86/intel/ifs: Gen2 scan image loading
+- platform/x86/intel/ifs: Refactor image loading code
+- platform/x86/intel/ifs: Store IFS generation number
+- !4103 [OLK-6.6] Intel: microcode restructuring backport
+- x86/setup: Make relocated_ramdisk a local variable of relocate_initrd()
+- x86/microcode/intel: Add a minimum required revision for late loading
+- x86/microcode: Prepare for minimal revision check
+- x86/microcode: Handle "offline" CPUs correctly
+- x86/apic: Provide apic_force_nmi_on_cpu()
+- x86/microcode: Protect against instrumentation
+- x86/microcode: Rendezvous and load in NMI
+- x86/microcode: Replace the all-in-one rendevous handler
+- x86/microcode: Provide new control functions
+- x86/microcode: Add per CPU control field
+- x86/microcode: Add per CPU result state
+- x86/microcode: Sanitize __wait_for_cpus()
+- x86/microcode: Clarify the late load logic
+- x86/microcode: Handle "nosmt" correctly
+- x86/microcode: Clean up mc_cpu_down_prep()
+- x86/microcode: Get rid of the schedule work indirection
+- x86/microcode: Mop up early loading leftovers
+- x86/microcode/amd: Use cached microcode for AP load
+- x86/microcode/amd: Cache builtin/initrd microcode early
+- x86/microcode/amd: Cache builtin microcode too
+- x86/microcode/amd: Use correct per CPU ucode_cpu_info
+- x86/microcode: Remove pointless apply() invocation
+- x86/microcode/intel: Rework intel_find_matching_signature()
+- x86/microcode/intel: Reuse intel_cpu_collect_info()
+- x86/microcode/intel: Rework intel_cpu_collect_info()
+- x86/microcode/intel: Unify microcode apply() functions
+- x86/microcode/intel: Switch to kvmalloc()
+- x86/microcode/intel: Save the microcode only after a successful late-load
+- x86/microcode/intel: Simplify early loading
+- x86/microcode/intel: Cleanup code further
+- x86/microcode/intel: Simplify and rename generic_load_microcode()
+- x86/microcode/intel: Simplify scan_microcode()
+- x86/microcode/intel: Rip out mixed stepping support for Intel CPUs
+- x86/microcode/32: Move early loading after paging enable
+- x86/boot/32: Temporarily map initrd for microcode loading
+- x86/microcode: Provide CONFIG_MICROCODE_INITRD32
+- x86/boot/32: Restructure mk_early_pgtbl_32()
+- x86/boot/32: De-uglify the 2/3 level paging difference in mk_early_pgtbl_32()
+- x86/boot: Use __pa_nodebug() in mk_early_pgtbl_32()
+- x86/boot/32: Disable stackprotector and tracing for mk_early_pgtbl_32()
+- x86/microcode/amd: Fix snprintf() format string warning in W=1 build
+- !4102 Intel: Backport Sierra Forest(SRF) perf cstate support to kernel OLK-6.6
+- perf/x86/intel/cstate: Add Grand Ridge support
+- perf/x86/intel/cstate: Add Sierra Forest support
+- x86/smp: Export symbol cpu_clustergroup_mask()
+- perf/x86/intel/cstate: Cleanup duplicate attr_groups
+- !4104 arm64: Add the arm64.nolse command line option
+- arm64: Add the arm64.nolse command line option
+- !4093 introduce smart_grid zone
+- smart_grid: introduce smart_grid cmdline
+- smart_grid: cpufreq: introduce smart_grid cpufreq control
+- smart_grid: introduce smart_grid_strategy_ctrl sysctl
+- smart_grid: introduce /proc/pid/smart_grid_level
+- sched: introduce smart grid qos zone
+- config: enable CONFIG_QOS_SCHED_SMART_GRID by default
+- sched: smart grid: init sched_grid_qos structure on QOS purpose
+- sched: Introduce smart grid scheduling strategy for cfs
+
+* Wed Jan 31 2024 Jialin Zhang <zhangjialin11@huawei.com> - 6.6.0-6.0.0.4
+- Module.kabi_aarch64 and Module.kabi_x86_64 v1
+
+* Tue Jan 23 2024 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-6.0.0.3
+- !4087 backport two page_owner patchsets:
+- mm/page_owner: record and dump free_pid and free_tgid
+- tools/mm: update the usage output to be more organized
+- tools/mm: fix the default case for page_owner_sort
+- tools/mm: filter out timestamps for correct collation
+- tools/mm: remove references to free_ts from page_owner_sort
+- mm/page_owner: remove free_ts from page_owner output
+- !4070 Backport etmem feature to OLK 6.6
+- etmem: enable etmem configurations
+- etmem: add original kernel swap enabled options
+- etmem: add etmem swap feature
+- mm: Export symbol reclaim_pages
+- etmem: add etmem scan feature
+- mm: Export symbol walk_page_range
+- mm: Export symbol __pud_trans_huge_lock
+- etmem: add ETMEM scan feature CONFIG to mm/Kconfig
+- etmem: add ETMEM feature CONFIG to mm/Kconfig
+- !3444 LoongArch: fix some pci problems
+- LoongArch: pci root bridige set acpi companion only when not acpi_disabled.
+- PCI: irq: Add early_param pci_irq_limit to limit pci irq numbers
+- PCI: fix X server auto probe fail when both ast and etnaviv drm present
+- PCI: LS7A2000: fix GPU card error
+- PCI: LS7A2000: fix pm transition of devices under pcie port
+- LoongArch: fix some PCIE card not scanning properly
+- PCI: fix kabi error caused by pm_suspend_target_state
+- PCI: PM: fix pcie mrrs restoring
+- PCI: Check if the pci controller can use both CFG0 and CFG1 mode to access configuration space
+- PCI: Check if entry->offset already exist for mem resource
+- LS7A2000: Add quirk for OHCI device rev 0x02
+- !4027 [OLK-6.6] Intel RDT non-contiguous CBM support
+- Documentation/x86: Document resctrl's new sparse_masks
+- x86/resctrl: Add sparse_masks file in info
+- x86/resctrl: Enable non-contiguous CBMs in Intel CAT
+- x86/resctrl: Rename arch_has_sparse_bitmaps
+- !4098 sched: programmable: Fix is_cpu_allowed build error
+- sched: programmable: Fix is_cpu_allowed build error
+- !4072 cgroup/misc: openeuler_defconfig open misc config by default
+- cgroup/misc: openeuler_defconfig open misc config by default
+- !4053 sched: basic infrastructure for scheduler bpf
+- openeuler_defconfig: enable CONFIG_BPF_SCHED
+- sched: programmable: Add hook in can_migrate_task()
+- sched: programmable: Add hook in select_task_rq_fair()
+- sched: introduce bpf_sched_enable()
+- sched: basic infrastructure for scheduler bpf
+- sched: programmable: Add user interface of task tag
+- sched: programmable: Add user interface of task group tag
+- sched: programmable: Add a tag for the task group
+- sched: programmable: Add a tag for the task
+- sched: programmable: Introduce bpf sched
+- !4068 mm/oom_kill: fix NULL pointer dereference in memcg_print_bad_task()
+- mm/oom_kill: fix NULL pointer dereference in memcg_print_bad_task()
+- !4036 ubi: fix slab-out-of-bounds in ubi_eba_get_ldesc+0xfb/0x130
+- ubi: fix slab-out-of-bounds in ubi_eba_get_ldesc+0xfb/0x130
+- !3971 optimize inlining
+- make OPTIMIZE_INLINING config editable
+- Revert "compiler: remove CONFIG_OPTIMIZE_INLINING entirely"
+- !3631 drm: fix free illegal pointer when create drm_property_blob failed
+- drm: fix free illegal pointer when create drm_property_blob failed
+- !3958 Revert "drm/prime: Unexport helpers for fd/handle conversion"
+- Revert "drm/prime: Unexport helpers for fd/handle conversion"
+- !3670 Add initial openeuler_defconfig for riscv64
+- config: add initial openeuler_defconfig for riscv64
+- !3895 Spark SQL scenario bpf readahead optimization synchronization to OLK-6.6
+- selftests/bpf: Update the demo file_read_pattern to run on libbpf 1.0+
+- VFS: Rolling Back the fmode macro definition and structure members
+- selftests/bpf: add demo for file read pattern detection
+- ext4: add trace for the read and release of regular file
+- xfs: add trace for read and release of regular file
+- fs: add helper fs_file_read_do_trace()
+- vfs: add bare tracepoints for vfs read and release
+- readahead: introduce FMODE_CTL_WILLNEED to read first 2MB of file
+- !3964 drivers: hooks: add bonding driver vendor hooks
+- drivers: hooks: add bonding driver vendor hooks
+- !3996 hfs: fix null-ptr-deref in hfs_find_init()
+- hfs: fix null-ptr-deref in hfs_find_init()
+- !3976 Introduce dynamic pool feature
+- mm/dynamic_pool: enable CONFIG_DYNAMIC_POOL on x86_64 and arm64 by default
+- mm/dynamic_pool: add Document for dynamic hugetlb feature
+- mm/dynamic_pool: compatible with memory hwpoison
+- mm/dynamic_pool: compatible with HugeTLB Vmemmap
+- mm/dynamic_pool: compatible with HugeTLB dissolve
+- mm/dynamic_pool: disable THP for task attached with dpool
+- mm/dynamic_pool: fill dpool with pagelist
+- mm/dynamic_pool: add tracepoints for dpool
+- mm/dynamic_pool: support HugeTLB page allocation from dpool
+- mm/dynamic_pool: check resv for HugeTLB allocation from dpool
+- mm/dynamic_pool: speed up allocation by percpu pages pool
+- mm/dynamic_pool: support page allocation from dpool
+- mm/dynamic_pool: prevent task attach to another dpool
+- mm/dynamic_pool: call mem_cgroup_force_empty before restore pool
+- mm/dynamic_pool: migrate used pages before promote to huge page
+- mm/dynamic_pool: support to flow pages between 2M and 4K pages pool
+- mm/dynamic_pool: support to flow pages between 1G and 2M pages pool
+- mm/dynamic_pool: add restore_pool ops to reclaim memory and restore hugepages
+- mm/dynamic_pool: add interface to configure the count of hugepages
+- mm/dynamic_pool: fill dpool with HugeTLB 1G pages
+- mm/dynamic_pool: create dpool by dhugetlb.nr_pages interface
+- mm/dynamic_pool: introduce PG_pool to mark pages allocated from dpool
+- mm/dynamic_pool: introduce PG_dpool to mark free pages in dpool
+- mm/dynamic_pool: introduce per-memcg memory pool
+- mm/memcg: introduce memcg_has_children to check memcg
+- mm/memcg: introduce mem_cgroup_scan_cgroups to scan all memcgs
+- !3833 xfs: fix block space problems
+- xfs: longest free extent no need consider postalloc
+- xfs: fix xfs shutdown since we reserve more blocks in agfl fixup
+- xfs: set minleft correctly for randomly sparse inode allocations
+- xfs: account extra freespace btree splits for multiple allocations
+- !3902 xfs: update the last_sync_lsn with ctx start lsn
+- xfs: update the last_sync_lsn with ctx start lsn
+- !3977 Terrace Service Acceleration
+- bpf, sockmap: Add sk_rmem_alloc check for sockmap
+- bpf: Add new bpf helper to get SO_ORIGINAL_DST/REPLY_SRC
+- bpf: Add bpf_get_sockops_uid_gid helper function
+- net: core: Add a GID field to struct sock.
+- !3974 Add support for mbigen to generate SPIs
+- dt-bindings/irqchip/mbigen: add example of MBIGEN generate SPIs
+- irqchip/mbigen: add support for a MBIGEN generating SPIs
+- irqchip/mbigen: rename register marcros
+- !3963 block: Add config to show info about opening a mounted device for write
+- add config about writing mounted devices in openeuler_defconfig
+- block: Show info about opening a lower device for write while upper-layers mounted
+- block: Add config option to show info about opening a mounted device for write
+- block: Add config option to detect writing to part0 while partitions mounted
+- block: Expand the meaning of bdev_allow_write_mounted
+- block: Record writing and mounting regardless of whether bdev_allow_write_mounted is set
+- !3921 mm: mem_reliable: Introduce memory reliable
+- config: enable MEMORY_RELIABLE by default
+- mm: mem_reliable: Show debug info about memory reliable if oom occurs
+- mm: mem_reliable: Introduce proc interface to disable memory reliable features
+- proc: mem_reliable: Count reliable memory usage of reliable tasks
+- mm: mem_reliable: Introduce fallback mechanism for memory reliable
+- mm: mem_reliable: Add limiting the usage of reliable memory
+- mm: mem_reliable: Show reliable meminfo
+- mm: mem_reliable: Count reliable shmem usage
+- mm: mem_reliable: Count reliable page cache usage
+- mm: mem_reliable: Add cmdline reliable_debug to enable separate feature
+- mm/hugetlb: Allocate non-mirrored memory by default
+- mm/memblock: Introduce ability to alloc memory from specify memory region
+- mm: mem_reliable: Add memory reliable support during hugepaged collapse
+- mm: mem_reliable: Alloc pagecache from reliable region
+- shmem: mem_reliable: Alloc shmem from reliable region
+- mm: mem_reliable: Alloc task memory from reliable region
+- mm: mem_reliable: Introduce memory reliable
+- efi: Disable mirror feature during crashkernel
+- proc: introduce proc_hide_ents to hide proc files
+- !3935 pid_ns: Make pid_max per namespace
+- pid_ns: Make pid_max per namespace
+- !3913 arm64: Add non nmi ipi backtrace support
+- arm64: Add non nmi ipi backtrace support
+- !3785 【OLK-6.6】PSI cgroupv1 and PSI fine grained
+- sched/psi: enable PSI_CGROUP_V1 and PSI_FINE_GRAINED in openeuler_defconfig
+- sched/psi: add cpu fine grained stall tracking in pressure.stat
+- sched/psi: add more memory fine grained stall tracking in pressure.stat
+- sched/psi: Introduce pressure.stat in psi
+- sched/psi: Introduce avgs and total calculation for cgroup reclaim
+- sched/psi: Introduce fine grained stall time collect for cgroup reclaim
+- sched/psi: introduce tracepoints for psi_memstall_{enter, leave}
+- sched/psi: update psi irqtime when the irq delta is nozero
+- sched/psi: Export cgroup psi from cgroupv2 to cgroupv1
+- sched/psi: Bail out early from irq time accounting
+- !3907 cgroup: Support iocost for cgroup v1
+- openeuler_defconfig: enable iocost in openeuler_defconfig for x86 and arm64
+- cgroup: Support iocost for cgroup v1
+- !3897 Some simple extensions of the kfence feature
+- arm64: kfence: scale sample_interval to support early init for kfence.
+- kfence: Add a module parameter to adjust kfence objects
+- !3888 fs/dcache.c: avoid panic while lockref of dentry overflow
+- fs/dcache.c: avoid panic while lockref of dentry overflow
+- !3894 Add swap control for memcg
+- config: enable memcg swap qos for x86_64 and arm64 by default
+- memcg/swap: add ability to disable memcg swap
+- mm: swap_slots: add per-type slot cache
+- mm/swapfile: introduce per-memcg swapfile control
+- memcg: add restrict to swap to cgroup1
+- memcg: introduce per-memcg swapin interface
+- memcg: introduce memcg swap qos feature
+- memcg: make sysctl registration more extensible
+- memcg: add page type to memory.reclaim interface
+- !3827 backport mainline md patch
+- dm-raid: delay flushing event_work() after reconfig_mutex is released
+- md/raid1: support read error check
+- md: factor out a helper exceed_read_errors() to check read_errors
+- md: Whenassemble the array, consult the superblock of the freshest device
+- md/raid1: remove unnecessary null checking
+- md: split MD_RECOVERY_NEEDED out of mddev_resume
+- md: fix stopping sync thread
+- md: fix missing flush of sync_work
+- md: synchronize flush io with array reconfiguration
+- md/md-multipath: remove rcu protection to access rdev from conf
+- md/raid5: remove rcu protection to access rdev from conf
+- md/raid1: remove rcu protection to access rdev from conf
+- md/raid10: remove rcu protection to access rdev from conf
+- md: remove flag RemoveSynchronized
+- Revert "md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d"
+- md: bypass block throttle for superblock update
+- md: cleanup pers->prepare_suspend()
+- md-cluster: check for timeout while a new disk adding
+- md: rename __mddev_suspend/resume() back to mddev_suspend/resume()
+- md: remove old apis to suspend the array
+- md: suspend array in md_start_sync() if array need reconfiguration
+- md/raid5: replace suspend with quiesce() callback
+- md/md-linear: cleanup linear_add()
+- md: cleanup mddev_create/destroy_serial_pool()
+- md: use new apis to suspend array before mddev_create/destroy_serial_pool
+- md: use new apis to suspend array for ioctls involed array reconfiguration
+- md: use new apis to suspend array for adding/removing rdev from state_store()
+- md: use new apis to suspend array for sysfs apis
+- md/raid5: use new apis to suspend array
+- md/raid5-cache: use new apis to suspend array
+- md/md-bitmap: use new apis to suspend array for location_store()
+- md/dm-raid: use new apis to suspend array
+- md: add new helpers to suspend/resume and lock/unlock array
+- md: add new helpers to suspend/resume array
+- md: replace is_md_suspended() with 'mddev->suspended' in md_check_recovery()
+- md/raid5-cache: use READ_ONCE/WRITE_ONCE for 'conf->log'
+- md: use READ_ONCE/WRITE_ONCE for 'suspend_lo' and 'suspend_hi'
+- md/raid1: don't split discard io for write behind
+- md: do not require mddev_lock() for all options in array_state_store()
+- md: simplify md_seq_ops
+- md: factor out a helper from mddev_put()
+- md: replace deprecated strncpy with memcpy
+- md: don't check 'mddev->pers' and 'pers->quiesce' from suspend_lo_store()
+- md: don't check 'mddev->pers' from suspend_hi_store()
+- md-bitmap: suspend array earlier in location_store()
+- md-bitmap: remove the checking of 'pers->quiesce' from location_store()
+- md: initialize 'writes_pending' while allocating mddev
+- md: initialize 'active_io' while allocating mddev
+- md: delay remove_and_add_spares() for read only array to md_start_sync()
+- md: factor out a helper rdev_addable() from remove_and_add_spares()
+- md: factor out a helper rdev_is_spare() from remove_and_add_spares()
+- md: factor out a helper rdev_removeable() from remove_and_add_spares()
+- md: delay choosing sync action to md_start_sync()
+- md: factor out a helper to choose sync action from md_check_recovery()
+- md: use separate work_struct for md_start_sync()
+- !3857 scsi: fix use-after-free problem in scsi_remove_target
+- scsi: fix use-after-free problem in scsi_remove_target
+- !3906 sched/core: Change depends of SCHED_CORE
+- sched/core: Change depends of SCHED_CORE
+- !3747 Introduce multiple qos level
+- config: Enable CONFIG_QOS_SCHED_MULTILEVEL
+- sched/fair: Introduce multiple qos level
+- !3899 fs/dirty_pages: dump the number of dirty pages for each inode
+- fs/dirty_pages: dump the number of dirty pages for each inode
+- !3815 JFFS2: Fix the race issues caused by the GC of jffs2
+- jffs2: reset pino_nlink to 0 when inode creation failed
+- jffs2: make the overwritten xattr invisible after remount
+- jffs2: handle INO_STATE_CLEARING in jffs2_do_read_inode()
+- jffs2: protect no-raw-node-ref check of inocache by erase_completion_lock
+- !3891 block: support to account io_ticks precisely
+- block: support to account io_ticks precisely
+- !3881 iommu: set CONFIG_SMMU_BYPASS_DEV=y
+- iommu: set CONFIG_SMMU_BYPASS_DEV=y
+- !3819 support ext3/ext4 netlink error report.
+- Add new config 'CONFIG_EXT4_ERROR_REPORT' to control ext3/4 error reporting
+- ext4: report error to userspace by netlink
+- !3720 blk-mq: make fair tag sharing configurable
+- scsi_lib: disable fair tag sharing by default if total tags is less than 128
+- scsi: core: make fair tag sharing configurable via sysfs
+- blk-mq: add apis to disable fair tag sharing
+- !3090 fs/dcache.c: avoid softlock since too many negative dentry
+- fs/dcache.c: avoid softlock since too many negative dentry
+- !3656 iommu: Enable smmu-v3 when 3408iMR/3416iMRraid card exist
+- iommu: Enable smmu-v3 when 3408iMR/3416iMRraid card exist
+- !3843 [OLK-6.6] export cgroup.stat from cgroupv2 to cgroupv1
+- cgroup: Export cgroup.stat from cgroupv2 to cgroupv1
+- !3828 openeuler_defconfig: enable erofs ondemand for x86 and arm64
+- openeuler_defconfig: enable erofs ondemand for x86 and arm64
+- !3851 ext4: fix slab-out-of-bounds in ext4_find_extent()
+- ext4: check magic even the extent block bh is verified
+- ext4: avoid recheck extent for EXT4_EX_FORCE_CACHE
+- !3850 aio: add timeout validity check for io_[p
+- aio: add timeout validity check for io_[p]getevents
+- !3849 pipe: Fix endless sleep problem due to the out-of-order
+- pipe: Fix endless sleep problem due to the out-of-order
+- !3787 scsi: sd: unregister device if device_add_disk() failed in sd_probe()
+- scsi: sd: unregister device if device_add_disk() failed in sd_probe()
+- !3450 Backport nbd bugfix patch
+- nbd: pass nbd_sock to nbd_read_reply() instead of index
+- nbd: fix null-ptr-dereference while accessing 'nbd->config'
+- nbd: factor out a helper to get nbd_config without holding 'config_lock'
+- nbd: fold nbd config initialization into nbd_alloc_config()
+- !3675 block mainline bugfix backport
+- block: Set memalloc_noio to false on device_add_disk() error path
+- block: add check of 'minors' and 'first_minor' in device_add_disk()
+- block: add check that partition length needs to be aligned with block size
+- !3786 ubi: block: fix memleak in ubiblock_create()
+- ubi: block: fix memleak in ubiblock_create()
+- !3448 ubi: block: Fix use-after-free in ubiblock_cleanup
+- ubi: block: Fix use-after-free in ubiblock_cleanup
+- !3760 Add huge page allocation limit
+- openeuler_defconfig: enable HUGETLB_ALLOC_LIMIT
+- hugetlb: Add huge page allocation limit
+- !3818 [sync] PR-1989: support Android vendor hooks
+- openeuler_defconfig: enable CONFIG_VENDOR_HOOKS for x86 and arm64
+- vendor_hooks: make android vendor hooks feature generic.
+- ANDROID: fixup restricted hooks after tracepont refactoring
+- ANDROID: simplify vendor hooks for non-GKI builds
+- ANDROID: vendor_hooks: fix __section macro
+- ANDROID: use static_call() for restricted hooks
+- ANDROID: fix redefinition error for restricted vendor hooks
+- ANDROID: add support for vendor hooks
+- !3502 ARM: LPAE: Use phys_addr_t instead of unsigned long in outercache hooks
+- ARM: LPAE: Use phys_addr_t instead of unsigned long in outercache hooks
+- !3755 livepatch/core: Fix miss disable ro for MOD_RO_AFTER_INIT memory
+- livepatch/core: Fix miss disable ro for MOD_RO_AFTER_INIT memory
+- !3813 kernel: add OPENEULER_VERSION_CODE to version.h
+- kernel: add OPENEULER_VERSION_CODE to version.h
+- !3744 Add NUMA-awareness to qspinlock
+- config: Enable CONFIG_NUMA_AWARE_SPINLOCKS on x86
+- locking/qspinlock: Disable CNA by default
+- locking/qspinlock: Introduce the shuffle reduction optimization into CNA
+- locking/qspinlock: Avoid moving certain threads between waiting queues in CNA
+- locking/qspinlock: Introduce starvation avoidance into CNA
+- locking/qspinlock: Introduce CNA into the slow path of qspinlock
+- locking/qspinlock: Refactor the qspinlock slow path
+- locking/qspinlock: Rename mcs lock/unlock macros and make them more generic
+- !3517 support CLOCKSOURCE_VALIDATE_LAST_CYCLE on
+- config: make CLOCKSOURCE_VALIDATE_LAST_CYCLE not set by default
+- timekeeping: Make CLOCKSOURCE_VALIDATE_LAST_CYCLE configurable
+- !3710 Backport 6.6.7 LTS Patches
+- drm/amdgpu: Restrict extended wait to PSP v13.0.6
+- drm/amdgpu: update retry times for psp BL wait
+- drm/amdgpu: Fix refclk reporting for SMU v13.0.6
+- riscv: Kconfig: Add select ARM_AMBA to SOC_STARFIVE
+- gcc-plugins: randstruct: Update code comment in relayout_struct()
+- ASoC: qcom: sc8280xp: Limit speaker digital volumes
+- netfilter: nft_set_pipapo: skip inactive elements during set walk
+- MIPS: Loongson64: Enable DMA noncoherent support
+- MIPS: Loongson64: Handle more memory types passed from firmware
+- MIPS: Loongson64: Reserve vgabios memory on boot
+- perf metrics: Avoid segv if default metricgroup isn't set
+- perf list: Fix JSON segfault by setting the used skip_duplicate_pmus callback
+- KVM: SVM: Update EFER software model on CR0 trap for SEV-ES
+- KVM: s390/mm: Properly reset no-dat
+- MIPS: kernel: Clear FPU states when setting up kernel threads
+- cifs: Fix flushing, invalidation and file size with FICLONE
+- cifs: Fix flushing, invalidation and file size with copy_file_range()
+- USB: gadget: core: adjust uevent timing on gadget unbind
+- powerpc/ftrace: Fix stack teardown in ftrace_no_trace
+- x86/CPU/AMD: Check vendor in the AMD microcode callback
+- devcoredump: Send uevent once devcd is ready
+- serial: 8250_omap: Add earlycon support for the AM654 UART controller
+- serial: 8250: 8250_omap: Do not start RX DMA on THRI interrupt
+- serial: 8250: 8250_omap: Clear UART_HAS_RHR_IT_DIS bit
+- serial: sc16is7xx: address RX timeout interrupt errata
+- ARM: PL011: Fix DMA support
+- usb: typec: class: fix typec_altmode_put_partner to put plugs
+- smb: client: fix potential NULL deref in parse_dfs_referrals()
+- Revert "xhci: Loosen RPM as default policy to cover for AMD xHC 1.1"
+- cifs: Fix non-availability of dedup breaking generic/304
+- parport: Add support for Brainboxes IX/UC/PX parallel cards
+- serial: ma35d1: Validate console index before assignment
+- serial: 8250_dw: Add ACPI ID for Granite Rapids-D UART
+- nvmem: Do not expect fixed layouts to grab a layout driver
+- usb: gadget: f_hid: fix report descriptor allocation
+- kprobes: consistent rcu api usage for kretprobe holder
+- ASoC: ops: add correct range check for limiting volume
+- gpiolib: sysfs: Fix error handling on failed export
+- x86/sev: Fix kernel crash due to late update to read-only ghcb_version
+- perf: Fix perf_event_validate_size()
+- drm/amdgpu: disable MCBP by default
+- arm64: dts: mt8183: kukui: Fix underscores in node names
+- arm64: dts: mediatek: add missing space before {
+- parisc: Fix asm operand number out of range build error in bug table
+- parisc: Reduce size of the bug_table on 64-bit kernel by half
+- LoongArch: BPF: Don't sign extend function return value
+- LoongArch: BPF: Don't sign extend memory load operand
+- perf vendor events arm64: AmpereOne: Add missing DefaultMetricgroupName fields
+- misc: mei: client.c: fix problem of return '-EOVERFLOW' in mei_cl_write
+- misc: mei: client.c: return negative error code in mei_cl_write
+- coresight: ultrasoc-smb: Fix uninitialized before use buf_hw_base
+- coresight: ultrasoc-smb: Config SMB buffer before register sink
+- coresight: ultrasoc-smb: Fix sleep while close preempt in enable_smb
+- hwtracing: hisi_ptt: Add dummy callback pmu::read()
+- coresight: Fix crash when Perf and sysfs modes are used concurrently
+- coresight: etm4x: Remove bogous __exit annotation for some functions
+- arm64: dts: mediatek: mt8186: Change gpu speedbin nvmem cell name
+- arm64: dts: mediatek: mt8186: fix clock names for power domains
+- arm64: dts: mediatek: mt8183-evb: Fix unit_address_vs_reg warning on ntc
+- arm64: dts: mediatek: mt8183: Move thermal-zones to the root node
+- arm64: dts: mediatek: mt8183: Fix unit address for scp reserved memory
+- arm64: dts: mediatek: mt8195: Fix PM suspend/resume with venc clocks
+- arm64: dts: mediatek: mt8173-evb: Fix regulator-fixed node names
+- arm64: dts: mediatek: cherry: Fix interrupt cells for MT6360 on I2C7
+- arm64: dts: mediatek: mt8183-kukui-jacuzzi: fix dsi unnecessary cells properties
+- arm64: dts: mediatek: mt7622: fix memory node warning check
+- arm64: dts: mt7986: fix emmc hs400 mode without uboot initialization
+- arm64: dts: mt7986: define 3W max power to both SFP on BPI-R3
+- arm64: dts: mt7986: change cooling trips
+- drm/i915: Skip some timing checks on BXT/GLK DSI transcoders
+- drm/i915/mst: Reject modes that require the bigjoiner
+- drm/i915/mst: Fix .mode_valid_ctx() return values
+- drm/atomic-helpers: Invoke end_fb_access while owning plane state
+- md/raid6: use valid sector values to determine if an I/O should wait on the reshape
+- powercap: DTPM: Fix missing cpufreq_cpu_put() calls
+- mm/memory_hotplug: fix error handling in add_memory_resource()
+- mm: fix oops when filemap_map_pmd() without prealloc_pte
+- mm/memory_hotplug: add missing mem_hotplug_lock
+- drivers/base/cpu: crash data showing should depends on KEXEC_CORE
+- hugetlb: fix null-ptr-deref in hugetlb_vma_lock_write
+- workqueue: Make sure that wq_unbound_cpumask is never empty
+- platform/surface: aggregator: fix recv_buf() return value
+- regmap: fix bogus error on regcache_sync success
+- r8169: fix rtl8125b PAUSE frames blasting when suspended
+- packet: Move reference count in packet_sock to atomic_long_t
+- nfp: flower: fix for take a mutex lock in soft irq context and rcu lock
+- leds: trigger: netdev: fix RTNL handling to prevent potential deadlock
+- tracing: Fix a possible race when disabling buffered events
+- tracing: Fix incomplete locking when disabling buffered events
+- tracing: Disable snapshot buffer when stopping instance tracers
+- tracing: Stop current tracer when resizing buffer
+- tracing: Always update snapshot buffer size
+- checkstack: fix printed address
+- cgroup_freezer: cgroup_freezing: Check if not frozen
+- lib/group_cpus.c: avoid acquiring cpu hotplug lock in group_cpus_evenly
+- nilfs2: prevent WARNING in nilfs_sufile_set_segment_usage()
+- nilfs2: fix missing error check for sb_set_blocksize call
+- highmem: fix a memory copy problem in memcpy_from_folio
+- ring-buffer: Force absolute timestamp on discard of event
+- ring-buffer: Test last update in 32bit version of __rb_time_read()
+- ALSA: hda/realtek: Add quirk for Lenovo Yoga Pro 7
+- ALSA: hda/realtek: Add Framework laptop 16 to quirks
+- ALSA: hda/realtek: add new Framework laptop to quirks
+- ALSA: hda/realtek: Enable headset on Lenovo M90 Gen5
+- ALSA: hda/realtek: fix speakers on XPS 9530 (2023)
+- ALSA: hda/realtek: Apply quirk for ASUS UM3504DA
+- ALSA: pcm: fix out-of-bounds in snd_pcm_state_names
+- ALSA: usb-audio: Add Pioneer DJM-450 mixer controls
+- io_uring: fix mutex_unlock with unreferenced ctx
+- nvme-pci: Add sleep quirk for Kingston drives
+- io_uring/af_unix: disable sending io_uring over sockets
+- ASoC: amd: yc: Fix non-functional mic on ASUS E1504FA
+- rethook: Use __rcu pointer for rethook::handler
+- scripts/gdb: fix lx-device-list-bus and lx-device-list-class
+- kernel/Kconfig.kexec: drop select of KEXEC for CRASH_DUMP
+- md: don't leave 'MD_RECOVERY_FROZEN' in error path of md_set_readonly()
+- riscv: errata: andes: Probe for IOCP only once in boot stage
+- riscv: fix misaligned access handling of C.SWSP and C.SDSP
+- arm64: dts: rockchip: Fix eMMC Data Strobe PD on rk3588
+- ARM: dts: imx28-xea: Pass the 'model' property
+- ARM: dts: imx7: Declare timers compatible with fsl,imx6dl-gpt
+- arm64: dts: imx8-apalis: set wifi regulator to always-on
+- ARM: imx: Check return value of devm_kasprintf in imx_mmdc_perf_init
+- arm64: dts: imx93: correct mediamix power
+- arm64: dts: freescale: imx8-ss-lsio: Fix #pwm-cells
+- arm64: dts: imx8-ss-lsio: Add PWM interrupts
+- scsi: be2iscsi: Fix a memleak in beiscsi_init_wrb_handle()
+- tracing: Fix a warning when allocating buffered events fails
+- io_uring/kbuf: check for buffer list readiness after NULL check
+- io_uring/kbuf: Fix an NULL vs IS_ERR() bug in io_alloc_pbuf_ring()
+- ARM: dts: imx6ul-pico: Describe the Ethernet PHY clock
+- arm64: dts: imx8mp: imx8mq: Add parkmode-disable-ss-quirk on DWC3
+- drm/bridge: tc358768: select CONFIG_VIDEOMODE_HELPERS
+- RDMA/irdma: Avoid free the non-cqp_request scratch
+- RDMA/irdma: Fix support for 64k pages
+- RDMA/irdma: Ensure iWarp QP queue memory is OS paged aligned
+- RDMA/core: Fix umem iterator when PAGE_SIZE is greater then HCA pgsz
+- ASoC: wm_adsp: fix memleak in wm_adsp_buffer_populate
+- firmware: arm_scmi: Fix possible frequency truncation when using level indexing mode
+- firmware: arm_scmi: Simplify error path in scmi_dvfs_device_opps_add()
+- firmware: arm_scmi: Fix frequency truncation by promoting multiplier type
+- firmware: arm_scmi: Extend perf protocol ops to get information of a domain
+- firmware: arm_scmi: Extend perf protocol ops to get number of domains
+- hwmon: (nzxt-kraken2) Fix error handling path in kraken2_probe()
+- ASoC: codecs: lpass-tx-macro: set active_decimator correct default value
+- hwmon: (acpi_power_meter) Fix 4.29 MW bug
+- ARM: dts: bcm2711-rpi-400: Fix delete-node of led_act
+- ARM: dts: rockchip: Fix sdmmc_pwren's pinmux setting for RK3128
+- ARM: dts: imx6q: skov: fix ethernet clock regression
+- arm64: dt: imx93: tqma9352-mba93xxla: Fix LPUART2 pad config
+- RDMA/irdma: Fix UAF in irdma_sc_ccq_get_cqe_info()
+- RDMA/bnxt_re: Correct module description string
+- RDMA/rtrs-clt: Remove the warnings for req in_use check
+- RDMA/rtrs-clt: Fix the max_send_wr setting
+- RDMA/rtrs-srv: Destroy path files after making sure no IOs in-flight
+- RDMA/rtrs-srv: Free srv_mr iu only when always_invalidate is true
+- RDMA/rtrs-srv: Check return values while processing info request
+- RDMA/rtrs-clt: Start hb after path_up
+- RDMA/rtrs-srv: Do not unconditionally enable irq
+- ASoC: fsl_sai: Fix no frame sync clock issue on i.MX8MP
+- arm64: dts: rockchip: Expand reg size of vdec node for RK3399
+- arm64: dts: rockchip: Expand reg size of vdec node for RK3328
+- RDMA/irdma: Add wait for suspend on SQD
+- RDMA/irdma: Do not modify to SQD on error
+- RDMA/hns: Fix unnecessary err return when using invalid congest control algorithm
+- RDMA/core: Fix uninit-value access in ib_get_eth_speed()
+- tee: optee: Fix supplicant based device enumeration
+- mm/damon/sysfs: eliminate potential uninitialized variable warning
+- drm/amdkfd: get doorbell's absolute offset based on the db_size
+- drm/amd/amdgpu/amdgpu_doorbell_mgr: Correct misdocumented param 'doorbell_index'
+- net/smc: fix missing byte order conversion in CLC handshake
+- net: dsa: microchip: provide a list of valid protocols for xmit handler
+- drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group
+- psample: Require 'CAP_NET_ADMIN' when joining "packets" group
+- bpf: sockmap, updating the sg structure should also update curr
+- net: tls, update curr on splice as well
+- net: dsa: mv88e6xxx: Restore USXGMII support for 6393X
+- tcp: do not accept ACK of bytes we never sent
+- netfilter: xt_owner: Fix for unsafe access of sk->sk_socket
+- netfilter: nf_tables: validate family when identifying table via handle
+- netfilter: nf_tables: bail out on mismatching dynset and set expressions
+- netfilter: nf_tables: fix 'exist' matching on bigendian arches
+- netfilter: bpf: fix bad registration on nf_defrag
+- dt-bindings: interrupt-controller: Allow #power-domain-cells
+- octeontx2-af: Update Tx link register range
+- octeontx2-af: Add missing mcs flr handler call
+- octeontx2-af: Fix mcs stats register address
+- octeontx2-af: Fix mcs sa cam entries size
+- octeontx2-af: Adjust Tx credits when MCS external bypass is disabled
+- net: hns: fix fake link up on xge port
+- net: hns: fix wrong head when modify the tx feature when sending packets
+- net: atlantic: Fix NULL dereference of skb pointer in
+- ipv4: ip_gre: Avoid skb_pull() failure in ipgre_xmit()
+- ionic: Fix dim work handling in split interrupt mode
+- ionic: fix snprintf format length warning
+- tcp: fix mid stream window clamp.
+- net: bnxt: fix a potential use-after-free in bnxt_init_tc
+- iavf: validate tx_coalesce_usecs even if rx_coalesce_usecs is zero
+- i40e: Fix unexpected MFS warning message
+- ice: Restore fix disabling RX VLAN filtering
+- octeontx2-af: fix a use-after-free in rvu_npa_register_reporters
+- xsk: Skip polling event check for unbound socket
+- net: stmmac: fix FPE events losing
+- octeontx2-pf: consider both Rx and Tx packet stats for adaptive interrupt coalescing
+- arcnet: restoring support for multiple Sohard Arcnet cards
+- platform/mellanox: Check devm_hwmon_device_register_with_groups() return value
+- platform/mellanox: Add null pointer checks for devm_kasprintf()
+- mlxbf-bootctl: correctly identify secure boot with development keys
+- r8152: Add RTL8152_INACCESSIBLE to r8153_aldps_en()
+- r8152: Add RTL8152_INACCESSIBLE to r8153_pre_firmware_1()
+- r8152: Add RTL8152_INACCESSIBLE to r8156b_wait_loading_flash()
+- r8152: Add RTL8152_INACCESSIBLE checks to more loops
+- r8152: Hold the rtnl_lock for all of reset
+- hv_netvsc: rndis_filter needs to select NLS
+- bpf: Fix a verifier bug due to incorrect branch offset comparison with cpu=v4
+- octeontx2-af: Check return value of nix_get_nixlf before using nixlf
+- octeontx2-pf: Add missing mutex lock in otx2_get_pauseparam
+- ipv6: fix potential NULL deref in fib6_add()
+- platform/x86: wmi: Skip blocks with zero instances
+- of: dynamic: Fix of_reconfig_get_state_change() return value documentation
+- platform/x86: asus-wmi: Move i8042 filter install to shared asus-wmi code
+- dt: dt-extract-compatibles: Don't follow symlinks when walking tree
+- dt: dt-extract-compatibles: Handle cfile arguments in generator function
+- x86/tdx: Allow 32-bit emulation by default
+- x86/entry: Do not allow external 0x80 interrupts
+- x86/entry: Convert INT 0x80 emulation to IDTENTRY
+- x86/coco: Disable 32-bit emulation by default on TDX and SEV
+- x86: Introduce ia32_enabled()
+- dm-crypt: start allocating with MAX_ORDER
+- drm/amdgpu: correct chunk_ptr to a pointer to chunk.
+- drm/amdgpu: finalizing mem_partitions at the end of GMC v9 sw_fini
+- drm/amdgpu: Do not program VF copy regs in mmhub v1.8 under SRIOV (v2)
+- kconfig: fix memory leak from range properties
+- modpost: fix section mismatch message for RELA
+- tg3: Increment tx_dropped in tg3_tso_bug()
+- tg3: Move the [rt]x_dropped counters to tg3_napi
+- zstd: Fix array-index-out-of-bounds UBSAN warning
+- nouveau: use an rwlock for the event lock.
+- netfilter: ipset: fix race condition between swap/destroy and kernel side add/del/test
+- i2c: ocores: Move system PM hooks to the NOIRQ phase
+- i2c: designware: Fix corrupted memory seen in the ISR
+- hrtimers: Push pending hrtimers away from outgoing CPU earlier
+- scsi: sd: Fix sshdr use in sd_suspend_common()
+- vdpa/mlx5: preserve CVQ vringh index
+- !3749 support nokaslr and memmap parameter for kaslr collision detection
+- kaslr: enable CONFIG_SKIP_KASLR_MEM_RANGE in openeuler defconfig
+- x86/boot: add x86 nokaslr memory regions
+- efi/libstub: add arm64 nokaslr memory regions
+- efi/libstub: arm64: Fix KASLR and memmap= collision
+- efi/libstub: arm64: support strchr function for EFI stub
+- efi/libstub: add arm64 kaslr memory region avoid support
+- !3737 arm64: Fix compilation error with ILP32
+- config: Disable CONFIG_COMPAT_BINFMT_ELF as default
+- arm64: Fix compilation error with ILP32 support
+- Revert "Kconfig: regularize selection of CONFIG_BINFMT_ELF"
+- !3743 Fix ppc32 build error
+- powerpc: Fix ppc32 build
+- !3713 Introduce CPU inspect feature
+- openeuler_defconfig: enable CPU inspect for arm64 by default
+- cpuinspect: add ATF inspector
+- cpuinspect: add CPU-inspect infrastructure
+- !3730 ARM: spectre-v2: turn off the mitigation via boot cmdline param
+- ARM: spectre-v2: turn off the mitigation via boot cmdline param
+- !3732 tcp_comp: implement tcp compression
+- tcp_comp: implement tcp compression
+- !3748 jffs2: move jffs2_init_inode_info() just after allocating inode
+- jffs2: move jffs2_init_inode_info() just after allocating inode
+- !3542 Support kernel livepatching
+- livepatch/powerpc: Add arch_klp_module_check_calltrace
+- livepatch/powerpc: Support breakpoint exception optimization
+- livepatch/ppc64: Sample testcase fix ppc64
+- livepatch/ppc64: Implement livepatch without ftrace for ppc64be
+- livepatch: Bypass dead thread when check calltrace
+- livepatch/arm: Add arch_klp_module_check_calltrace
+- livepatch/arm64: Add arch_klp_module_check_calltrace
+- livepatch/x86: Add arch_klp_module_check_calltrace
+- livepatch: Add klp_module_delete_safety_check
+- livepatch/arm: Support breakpoint exception optimization
+- livepatch/arm64: Support breakpoint exception optimization
+- livepatch: Add arch_klp_init
+- livepatch/x86: Support breakpoint exception optimization
+- livepatch: Use breakpoint exception to optimize enabling livepatch
+- livepatch/ppc32: Support livepatch without ftrace
+- livepatch/arm: Support livepatch without ftrace
+- livepatch/core: Add support for arm for klp relocation
+- arm/module: Use plt section indices for relocations
+- livepatch: Enable livepatch configs in openeuler_defconfig
+- livepatch/core: Revert module_enable_ro and module_disable_ro
+- livepatch/arm64: Support livepatch without ftrace
+- livepatch/core: Avoid conflict with static {call,key}
+- livepatch: Fix patching functions which have static_call
+- livepatch: Fix crash when access the global variable in hook
+- livepatch/core: Support jump_label
+- livepatch: samples: Adapt livepatch-sample for solution without ftrace
+- livepatch/core: Support load and unload hooks
+- livepatch/core: Restrict livepatch patched/unpatched when plant kprobe
+- livepatch/core: Disable support for replacing
+- livepatch/x86: Support livepatch without ftrace
+- Revert "x86/insn: Make insn_complete() static"
+- livepatch/core: Reuse common codes in the solution without ftrace
+- livepatch/core: Allow implementation without ftrace
+- !3678 timer_list: avoid other cpu soft lockup when printing timer list
+- timer_list: avoid other cpu soft lockup when printing timer list
+- !3733 drm/radeon: check the alloc_workqueue return value in radeon_crtc_init()
+- drm/radeon: check the alloc_workqueue return value in radeon_crtc_init()
+- !3734 Introduce qos smt expeller for co-location
+- sched/fair: Add cmdline nosmtexpell
+- sched/fair: Introduce QOS_SMT_EXPELL priority reversion mechanism
+- sched/fair: Start tracking qos_offline tasks count in cfs_rq
+- config: Enable CONFIG_QOS_SCHED_SMT_EXPELLER
+- sched: Add tracepoint for qos smt expeller
+- sched: Add statistics for qos smt expeller
+- sched: Implement the function of qos smt expeller
+- sched: Introduce qos smt expeller for co-location
+- !3629 x86/kdump: make crash kernel boot faster
+- x86/kdump: make crash kernel boot faster
+- !3722 add memmap interface to reserved memory
+- arm64: Request resources for reserved memory via memmap
+- arm64: Add support for memmap kernel parameters
+- !3724 lib/clear_user: ensure loop in __arch_clear_user cache-aligned v2
+- config: enable CONFIG_CLEAR_USER_WORKAROUND by default
+- lib/clear_user: ensure loop in __arch_clear_user cache-aligned v2
+- !3688 Support priority load balance for qos scheduler
+- sched: Introduce priority load balance for qos scheduler
+- !3712 sched: steal tasks to improve CPU utilization
+- config: enable CONFIG_SCHED_STEAL by default
+- sched/fair: introduce SCHED_STEAL
+- disable stealing by default
+- sched/fair: Provide idle search schedstats
+- sched/fair: disable stealing if too many NUMA nodes
+- sched/fair: Steal work from an overloaded CPU when CPU goes idle
+- sched/fair: Provide can_migrate_task_llc
+- sched/fair: Generalize the detach_task interface
+- sched/fair: Hoist idle_stamp up from idle_balance
+- sched/fair: Dynamically update cfs_overload_cpus
+- sched/topology: Provide cfs_overload_cpus bitmap
+- sched/topology: Provide hooks to allocate data shared per LLC
+- sched: Provide sparsemask, a reduced contention bitmap
+- !3701 mm: Add sysctl to clear free list pages
+- mm: Add sysctl to clear free list pages
+- !3598 arm64: add config switch and kernel parameter for cpu0 hotplug
+- config: disable config ARM64_BOOTPARAM_HOTPLUG_CPU0 by default
+- arm64: Add config switch and kernel parameter for CPU0 hotplug
+- !3649 x86/kdump: add log before booting crash kernel
+- x86/kdump: add log before booting crash kernel
+- !3700 Backport 6.6.6 LTS Patches
+- Revert "wifi: cfg80211: fix CQM for non-range use"
+- !3565 blk-throttle: enable hierarchical throttle in cgroup v1
+- blk-throttle: enable hierarchical throttle in cgroup v1
+- !3608 xfs: fix two corruption problems
+- xfs: shutdown xfs once inode double free
+- xfs: shutdown to ensure submits buffers on LSN boundaries
+- !3674 mm/hugetlb: Introduce alloc_hugetlb_folio_size()
+- mm/hugetlb: Introduce alloc_hugetlb_folio_size()
+- !3651 nbd: get config_lock before sock_shutdown
+- nbd: get config_lock before sock_shutdown
+- !3573 Support dynamic affinity scheduler
+- sched/fair: Modify idle cpu judgment in dynamic affinity
+- sched/fair: Remove invalid cpu selection logic in dynamic affinity
+- config: enable CONFIG_QOS_SCHED_DYNAMIC_AFFINITY by default
+- sched: Add cmdline for dynamic affinity
+- sched: Add statistics for scheduler dynamic affinity
+- sched: Adjust cpu allowed in load balance dynamicly
+- sched: Adjust wakeup cpu range according CPU util dynamicly
+- cpuset: Introduce new interface for scheduler dynamic affinity
+- sched: Introduce dynamic affinity for cfs scheduler
+- !3599 arm64: Add framework to turn IPI as NMI
+- arm64: kgdb: Roundup cpus using IPI as NMI
+- kgdb: Expose default CPUs roundup fallback mechanism
+- arm64: ipi_nmi: Add support for NMI backtrace
+- nmi: backtrace: Allow runtime arch specific override
+- arm64: smp: Assign and setup an IPI as NMI
+- irqchip/gic-v3: Enable support for SGIs to act as NMIs
+- arm64: Add framework to turn IPI as NMI
+- !3638 memcg: support OOM priority for memcg
+- memcg: enable CONFIG_MEMCG_OOM_PRIORITY by default
+- memcg: Add sysctl memcg_qos_enable
+- memcg: support priority for oom
+- !3602 xfs: fix attr inactive problems
+- xfs: atomic drop extent entries when inactiving attr
+- xfs: factor out __xfs_da3_node_read()
+- xfs: force shutdown xfs when xfs_attr_inactive fails
+- !3601 xfs: fix perag leak when growfs fails
+- xfs: fix perag leak when growfs fails
+- xfs: add lock protection when remove perag from radix tree
+- !3575 ubi: Enhance fault injection capability for the UBI driver
+- mtd: Add several functions to the fail_function list
+- ubi: Reserve sufficient buffer length for the input mask
+- ubi: Add six fault injection type for testing
+- ubi: Split io_failures into write_failure and erase_failure
+- ubi: Use the fault injection framework to enhance the fault injection capability
+- !3588 files cgroups
+- enable CONFIG_CGROUP_FILES in openeuler_defconfig for x86 and arm64
+- cgroup/files: support boot parameter to control if disable files cgroup
+- fs/filescontrol: add a switch to enable / disable accounting of open fds
+- cgroups: Resource controller for open files
+- !3605 openeuler_defconfig: enable CONFIG_UNICODE for x86 and arm64
+- openeuler_defconfig: enable CONFIG_UNICODE for x86 and arm64
+- !3600 iommu/arm-smmu-v3: Add a SYNC command to avoid broken page table prefetch
+- iommu/arm-smmu-v3: Add a SYNC command to avoid broken page table prefetch
+- !3397 xfs: fix some growfs problems
+- xfs: fix dir3 block read verify fail during log recover
+- xfs: keep growfs sb log item active until ail flush success
+- xfs: fix mounting failed caused by sequencing problem in the log records
+- xfs: fix the problem of mount failure caused by not refreshing mp->m_sb
+- !3582 Add support for memory limit
+- mm: support pagecache limit
+- mm: support periodical memory reclaim
+- !3323 LoongArch: add cpufreq and ls2k500 bmc support
+- LoongArch: fix ls2k500 bmc not work when installing iso
+- LoongArch: defconfig: enable CONFIG_FB_LS2K500=m.
+- ipmi: add ls2k500 bmc ipmi support.
+- fbdev: add ls2k500sfb driver for ls2k500 bmc.
+- cpufreq: Add cpufreq driver for LoongArch
+- !3363 xfs: fix some misc issue
+- xfs: xfs_trans_cancel() path must check for log shutdown
+- xfs: don't verify agf length when log recovery
+- xfs: fix a UAF in xfs_iflush_abort_clean
+- xfs: fix a UAF when inode item push
+- !3495 xfs: fix hung and warning
+- xfs: fix warning in xfs_vm_writepages()
+- xfs: fix hung when transaction commit fail in xfs_inactive_ifree
+- xfs: fix dead loop when do mount with IO fault injection
+- !3525 ARM: support kaslr feature in arm32 platform
+- arm32: kaslr: Fix clock_gettime and gettimeofday performance degradation when configure CONFIG_RANDOMIZE_BASE
+- arm32: kaslr: Fix the bug of symbols relocation
+- arm32: kaslr: print kaslr offset when kernel panic
+- arm32: kaslr: pop visibility when compile decompress boot code as we need relocate BSS by GOT.
+- arm32: kaslr: When boot with vxboot, we must adjust dtb address before kaslr_early_init, and store dtb address after init.
+- No idea why this broke ...
+- ARM: decompressor: add KASLR support
+- ARM: decompressor: explicitly map decompressor binary cacheable
+- ARM: kernel: implement randomization of the kernel load address
+- arm: vectors: use local symbol names for vector entry points
+- ARM: kernel: refer to swapper_pg_dir via its symbol
+- ARM: mm: export default vmalloc base address
+- ARM: kernel: use PC relative symbol references in suspend/resume code
+- ARM: kernel: use PC-relative symbol references in MMU switch code
+- ARM: kernel: make vmlinux buildable as a PIE executable
+- ARM: kernel: switch to relative exception tables
+- arm-soc: various: replace open coded VA->PA calculation of pen_release
+- arm-soc: mvebu: replace open coded VA->PA conversion
+- arm-soc: exynos: replace open coded VA->PA conversions
+- asm-generic: add .data.rel.ro sections to __ro_after_init
+- !3563 memcg: support ksm merge any mode per cgroup
+- memcg: support ksm merge any mode per cgroup
+- !3528 Print rootfs and tmpfs files charged by memcg
+- config: enable CONFIG_MEMCG_MEMFS_INFO by default
+- mm/memcg_memfs_info: show files that having pages charged in mem_cgroup
+- fs: move {lock, unlock}_mount_hash to fs/mount.h
+- !3489 ascend: export interfaces required by ascend drivers
+- ascend: export interfaces required by ascend drivers
+- !3381 cgroupv1 cgroup writeback enable
+- openeuler_defconfig: enable CONFIG_CGROUP_V1_WRITEBACK in openeuler_defconfig for x86 and arm64
+- cgroup: support cgroup writeback on cgroupv1
+- cgroup: factor out __cgroup_get_from_id() for cgroup v1
+- !3537 backport cgroup bugs from olk5.10
+- cgroup: disable kernel memory accounting for all memory cgroups by default
+- cgroup: Return ERSCH when add Z process into task
+- cgroup: wait for cgroup destruction to complete when umount
+- cgroup: check if cgroup root is alive in cgroupstats_show()
+- !3439 security: restrict init parameters by configuration
+- security: restrict init parameters by configuration
+- !3475 kaslr: ppc64: Introduce KASLR for PPC64
+- powerpc/fsl_booke/kaslr: Fix preserved memory size for int-vectors issue
+- powerpc/fsl_booke/kaslr: Provide correct r5 value for relocated kernel
+- powerpc/fsl_booke/kaslr: rename kaslr-booke32.rst to kaslr-booke.rst and add 64bit part
+- powerpc/fsl_booke/64: clear the original kernel if randomized
+- powerpc/fsl_booke/64: do not clear the BSS for the second pass
+- powerpc/fsl_booke/64: implement KASLR for fsl_booke64
+- powerpc/fsl_booke/64: introduce reloc_kernel_entry() helper
+- powerpc/fsl_booke/kaslr: refactor kaslr_legal_offset() and kaslr_early_init()
+- !3486 sync smmu patches for olk-6.6
+- iommu/arm-smmu-v3: disable stall for quiet_cd
+- iommu/iova: Manage the depot list size
+- iommu/iova: Make the rcache depot scale better
+- !3434 arm64/ascend: Add new enable_oom_killer interface for oom contrl
+- arm64/ascend: Add new enable_oom_killer interface for oom contrl
+- !3479 cache: Workaround HiSilicon Linxicore DC CVAU
+- cache: Workaround HiSilicon Linxicore DC CVAU
+- !3367 ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
+- ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
+- !3471 add redis sockmap sample code
+- tools: add sample sockmap code for redis
+- net: add local_skb parameter to identify local tcp connection
+- net: let sockops can use bpf_get_current_comm()
+- !3432 ACPI / APEI: Notify all ras err to driver
+- ACPI / APEI: Notify all ras err to driver
+
+* Tue Dec 26 2023 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-2.0.0.2
+- !3435 iommu/arm-smmu-v3: Add suspend and resume support
+- !3315 Backport 6.6.5 LTS Patches
+- !3314 Backport 6.6.4 LTS Patches
+- !3286 block: Add config option to not allow writing to mounted devices
+- !3430 Add support for hisi HBM devices
+- !3431 memcg reclaim and cgroup kill
+- iommu/arm-smmu-v3: Add suspend and resume support
+- config: enable CONFIG_MEMCG_V1_RECLAIM and CONFIG_CGROUP_V1_KILL
+- memcg: introduce per-memcg reclaim interface
+- memcg: export high_async_ratio to userland
+- memcg: enable memcg async reclaim
+- memcg: Export memory.events{local} from cgroupv2 to cgroupv1
+- memcg: Export memcg.{min/low/high} from cgroupv2 to cgroupv1
+- cgroup: Export cgroup.kill from cgroupv2 to cgroupv1
+- soc: hisilicon: hisi_hbmdev: Add hbm acls repair and query methods
+- soc: hbmcache: Add support for online and offline the hbm cache
+- soc: hisilicon: hisi_hbmdev: Provide extra memory topology information
+- ACPI: memhotplug: export the state of each hotplug device
+- soc: hisilicon: hisi_hbmdev: Add power domain control methods
+- ACPI: OSL: Export the symbol of acpi_hotplug_schedule
+- !3391 nbd_genl_status: null check for nla_nest_start
+- !3352 support userswap feature
+- !3383 Support Qos Scheduler
+- nbd_genl_status: null check for nla_nest_start
+- sched: Enable qos scheduler config
+- sched: Introduce handle priority reversion mechanism
+- sched: Support kill boost for offline task
+- sched: Throttle qos cfs_rq when current cpu is running online task
+- sched: Introduce qos scheduler for co-location
+- !3306 improve gettimeofday() performance in user space
+- !3331 kabi: add kabi helper macros and tools
+- mm/userswap: openeuler_defconfig: enable userswap
+- mm/userswap: provide cpu info in userfault msg
+- mm/userswap: introduce UFFDIO_COPY_MODE_DIRECT_MAP
+- mm/userswap: support userswap via userfaultfd
+- mm/userswap: introduce MREMAP_USWAP_SET_PTE
+- mm/userswap: add enable_userswap boot option
+- mm/userswap: add VM_USWAP and SWP_USERSWAP_ENTRY
+- !3326 config: Open CONFIG_AARCH32_EL0 and keep CONFIG_ARM64_ILP32 closed
+- kabi: add kABI reference checking tool
+- kabi: add a tool to generate the kabi reference relationship
+- kabi: add script tools to check kabi symbol
+- kabi: deduplication friendly structs
+- kabi: Generalize naming of kabi helper macros
+- openeuler_defconfig: Enable CONFIG_KABI_RESERVE for x86 and arm64
+- KABI: Add CONFIG_KABI_RESERVE to control KABI padding reserve
+- kabi: enables more stringent kabi checks
+- kabi: add KABI_SIZE_ALIGN_CHECKS for more stringent kabi checks
+- kabi: add kabi helper macros
+- !3298 ARM: Add unwinding annotations to __loop.*delay functions
+- config: Open CONFIG_AARCH32_EL0 and keep CONFIG_ARM64_ILP32 closed
+- !3300 Add sharepool support v3
+- vfio: Drop vfio_file_iommu_group() stub to fudge around a KVM wart
+- x86/xen: fix percpu vcpu_info allocation
+- vfio/pds: Fix possible sleep while in atomic context
+- vfio/pds: Fix mutex lock->magic != lock warning
+- drm/amd/display: Fix MPCC 1DLUT programming
+- drm/amd/display: Simplify brightness initialization
+- drm/amd/display: Reduce default backlight min from 5 nits to 1 nits
+- drm/amd/display: refactor ILR to make it work
+- iommu: Fix printk arg in of_iommu_get_resv_regions()
+- drm/amd/pm: fix a memleak in aldebaran_tables_init
+- cpufreq/amd-pstate: Only print supported EPP values for performance governor
+- cpufreq/amd-pstate: Fix scaling_min_freq and scaling_max_freq update
+- drm/panel: nt36523: fix return value check in nt36523_probe()
+- drm/panel: starry-2081101qfh032011-53g: Fine tune the panel power sequence
+- drm/i915/gsc: Mark internal GSC engine with reserved uabi class
+- iommu/vt-d: Make context clearing consistent with context mapping
+- iommu/vt-d: Disable PCI ATS in legacy passthrough mode
+- iommu/vt-d: Omit devTLB invalidation requests when TES=0
+- cpufreq: imx6q: Don't disable 792 Mhz OPP unnecessarily
+- drm/amd/display: Remove power sequencing check
+- drm/amd/display: Refactor edp power control
+- s390/cmma: fix handling of swapper_pg_dir and invalid_pg_dir
+- powerpc/pseries/iommu: enable_ddw incorrectly returns direct mapping for SR-IOV device
+- net: ravb: Keep reverse order of operations in ravb_remove()
+- net: ravb: Stop DMA in case of failures on ravb_open()
+- net: ravb: Start TX queues after HW initialization succeeded
+- net: ravb: Make write access to CXR35 first before accessing other EMAC registers
+- net: ravb: Use pm_runtime_resume_and_get()
+- net: ravb: Check return value of reset_control_deassert()
+- ice: Fix VF Reset paths when interface in a failed over aggregate
+- bpf, sockmap: af_unix stream sockets need to hold ref for pair sock
+- ethtool: don't propagate EOPNOTSUPP from dumps
+- ravb: Fix races between ravb_tx_timeout_work() and net related ops
+- r8169: prevent potential deadlock in rtl8169_close
+- efi/unaccepted: Fix off-by-one when checking for overlapping ranges
+- neighbour: Fix __randomize_layout crash in struct neighbour
+- octeontx2-pf: Restore TC ingress police rules when interface is up
+- octeontx2-pf: Fix adding mbox work queue entry when num_vfs > 64
+- net: stmmac: xgmac: Disable FPE MMC interrupts
+- octeontx2-af: Fix possible buffer overflow
+- selftests/net: mptcp: fix uninitialized variable warnings
+- selftests/net: unix: fix unused variable compiler warning
+- selftests/net: fix a char signedness issue
+- selftests/net: ipsec: fix constant out of range
+- uapi: propagate __struct_group() attributes to the container union
+- bpf: Add missed allocation hint for bpf_mem_cache_alloc_flags()
+- dpaa2-eth: recycle the RX buffer only after all processing done
+- dpaa2-eth: increase the needed headroom to account for alignment
+- net: dsa: mv88e6xxx: fix marvell 6350 probe crash
+- net: dsa: mv88e6xxx: fix marvell 6350 switch probing
+- wifi: mac80211: do not pass AP_VLAN vif pointer to drivers during flush
+- wifi: iwlwifi: mvm: fix an error code in iwl_mvm_mld_add_sta()
+- ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
+- net: rswitch: Fix missing dev_kfree_skb_any() in error path
+- net: rswitch: Fix return value in rswitch_start_xmit()
+- net: rswitch: Fix type of ret in rswitch_start_xmit()
+- netdevsim: Don't accept device bound programs
+- media: v4l2-subdev: Fix a 64bit bug
+- pinctrl: stm32: fix array read out of bound
+- pinctrl: stm32: Add check for devm_kcalloc
+- wifi: cfg80211: fix CQM for non-range use
+- io_uring/kbuf: recycle freed mapped buffer ring entries
+- io_uring/kbuf: defer release of mapped buffer rings
+- io_uring: enable io_mem_alloc/free to be used in other parts
+- btrfs: fix 64bit compat send ioctl arguments not initializing version member
+- btrfs: free the allocated memory if btrfs_alloc_page_array() fails
+- btrfs: make error messages more clear when getting a chunk map
+- btrfs: send: ensure send_fd is writable
+- btrfs: fix off-by-one when checking chunk map includes logical address
+- btrfs: ref-verify: fix memory leaks in btrfs_ref_tree_mod()
+- btrfs: add dmesg output for first mount and last unmount of a filesystem
+- parisc: Mark altinstructions read-only and 32-bit aligned
+- parisc: Ensure 32-bit alignment on parisc unwind section
+- parisc: Mark jump_table naturally aligned
+- parisc: Drop the HP-UX ENOSYM and EREMOTERELEASE error codes
+- parisc: Mark lock_aligned variables 16-byte aligned on SMP
+- parisc: Use natural CPU alignment for bug_table
+- parisc: Mark ex_table entries 32-bit aligned in uaccess.h
+- parisc: Mark ex_table entries 32-bit aligned in assembly.h
+- powerpc: Don't clobber f0/vs0 during fp|altivec register save
+- KVM: PPC: Book3S HV: Fix KVM_RUN clobbering FP/VEC user registers
+- iommu/vt-d: Add MTL to quirk list to skip TE disabling
+- ext2: Fix ki_pos update for DIO buffered-io fallback case
+- bcache: revert replacing IS_ERR_OR_NULL with IS_ERR
+- iommu: Avoid more races around device probe
+- io_uring: don't guard IORING_OFF_PBUF_RING with SETUP_NO_MMAP
+- dma-buf: fix check in dma_resv_add_fence
+- cpufreq/amd-pstate: Fix the return value of amd_pstate_fast_switch()
+- powercap: DTPM: Fix unneeded conversions to micro-Watts
+- nouveau: find the smallest page allocation to cover a buffer alloc.
+- io_uring: free io_buffer_list entries via RCU
+- iommu/vt-d: Fix incorrect cache invalidation for mm notification
+- io_uring: don't allow discontig pages for IORING_SETUP_NO_MMAP
+- ACPI: video: Use acpi_video_device for cooling-dev driver data
+- r8169: fix deadlock on RTL8125 in jumbo mtu mode
+- nvme: check for valid nvme_identify_ns() before using it
+- dm verity: don't perform FEC for failed readahead IO
+- dm verity: initialize fec io before freeing it
+- drm/amd/display: force toggle rate wa for first link training for a retimer
+- drm/amd/display: fix ABM disablement
+- drm/amd/display: Update min Z8 residency time to 2100 for DCN314
+- drm/amd/display: Use DRAM speed from validation for dummy p-state
+- drm/amd/display: Remove min_dst_y_next_start check for Z8
+- drm/amd/display: Include udelay when waiting for INBOX0 ACK
+- drm/amdgpu: Update EEPROM I2C address for smu v13_0_0
+- drm/amdgpu: fix memory overflow in the IB test
+- drm/amdgpu: Force order between a read and write to the same address
+- drm/amdgpu: correct the amdgpu runtime dereference usage count
+- drm/amd: Enable PCIe PME from D3
+- scsi: ufs: core: Clear cmd if abort succeeds in MCQ mode
+- scsi: sd: Fix system start for ATA devices
+- scsi: Change SCSI device boolean fields to single bit flags
+- dm-verity: align struct dm_verity_fec_io properly
+- net: libwx: fix memory leak on msix entry
+- ALSA: hda/realtek: Add supported ALC257 for ChromeOS
+- ALSA: hda/realtek: Headset Mic VREF to 100%
+- ALSA: hda: Disable power-save on KONTRON SinglePC
+- drm/i915: Also check for VGA converter in eDP probe
+- mmc: block: Be sure to wait while busy in CQE error recovery
+- mmc: block: Do not lose cache flush during CQE error recovery
+- mmc: block: Retry commands in CQE error recovery
+- mmc: cqhci: Fix task clearing in CQE error recovery
+- mmc: cqhci: Warn of halt or task clear failure
+- mmc: cqhci: Increase recovery halt timeout
+- mmc: sdhci-sprd: Fix vqmmc not shutting down after the card was pulled
+- mmc: sdhci-pci-gli: Disable LPM during initialization
+- firewire: core: fix possible memory leak in create_units()
+- pinctrl: avoid reload of p state in list iteration
+- ksmbd: fix possible deadlock in smb2_open
+- smb: client: report correct st_size for SMB and NFS symlinks
+- smb: client: fix missing mode bits for SMB symlinks
+- cifs: Fix FALLOC_FL_INSERT_RANGE by setting i_size after EOF moved
+- cifs: Fix FALLOC_FL_ZERO_RANGE by setting i_size if EOF moved
+- leds: class: Don't expose color sysfs entry
+- USB: dwc3: qcom: fix wakeup after probe deferral
+- USB: dwc3: qcom: fix software node leak on probe errors
+- usb: dwc3: set the dma max_seg_size
+- usb: dwc3: Fix default mode initialization
+- USB: dwc2: write HCINT with INTMASK applied
+- usb: typec: tcpm: Skip hard reset when in error recovery
+- usb: typec: tcpm: Fix sink caps op current check
+- USB: serial: option: don't claim interface 4 for ZTE MF290
+- USB: serial: option: fix FM101R-GL defines
+- USB: serial: option: add Fibocom L7xx modules
+- usb: cdnsp: Fix deadlock issue during using NCM gadget
+- usb: config: fix iteration issue in 'usb_get_bos_descriptor()'
+- USB: xhci-plat: fix legacy PHY double init
+- bcache: fixup lock c->root error
+- bcache: fixup init dirty data errors
+- bcache: prevent potential division by zero error
+- bcache: check return value from btree_node_alloc_replacement()
+- veth: Use tstats per-CPU traffic counters
+- dm-delay: fix a race between delay_presuspend and delay_bio
+- ALSA: hda/realtek: Add quirks for ASUS 2024 Zenbooks
+- ALSA: hda: ASUS UM5302LA: Added quirks for cs35L41/10431A83 on i2c bus
+- cifs: fix leak of iface for primary channel
+- cifs: account for primary channel in the interface list
+- cifs: distribute channels across interfaces based on speed
+- Revert "phy: realtek: usb: Add driver for the Realtek SoC USB 2.0 PHY"
+- Revert "phy: realtek: usb: Add driver for the Realtek SoC USB 3.0 PHY"
+- Revert "usb: phy: add usb phy notify port status API"
+- hv_netvsc: Mark VF as slave before exposing it to user-mode
+- hv_netvsc: Fix race of register_netdevice_notifier and VF register
+- hv_netvsc: fix race of netvsc and VF register_netdevice
+- platform/x86: ideapad-laptop: Set max_brightness before using it
+- platform/x86/amd/pmc: adjust getting DRAM size behavior
+- USB: serial: option: add Luat Air72*U series products
+- usb: misc: onboard-hub: add support for Microchip USB5744
+- dt-bindings: usb: microchip,usb5744: Add second supply
+- platform/x86: hp-bioscfg: Fix error handling in hp_add_other_attributes()
+- platform/x86: hp-bioscfg: move mutex_lock() down in hp_add_other_attributes()
+- platform/x86: hp-bioscfg: Simplify return check in hp_add_other_attributes()
+- s390/dasd: protect device queue against concurrent access
+- io_uring/fs: consider link->flags when getting path for LINKAT
+- bcache: fixup multi-threaded bch_sectors_dirty_init() wake-up race
+- md: fix bi_status reporting in md_end_clone_io
+- bcache: replace a mistaken IS_ERR() by IS_ERR_OR_NULL() in btree_gc_coalesce()
+- io_uring: fix off-by one bvec index
+- tls: fix NULL deref on tls_sw_splice_eof() with empty record
+- swiotlb-xen: provide the "max_mapping_size" method
+- ACPI: PM: Add acpi_device_fix_up_power_children() function
+- ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CVA
+- ACPI: processor_idle: use raw_safe_halt() in acpi_idle_play_dead()
+- ACPI: video: Use acpi_device_fix_up_power_children()
+- thunderbolt: Set lane bonding bit only for downstream port
+- drm/ast: Disconnect BMC if physical connector is connected
+- drm/msm/dpu: Add missing safe_lut_tbl in sc8280xp catalog
+- kselftest/arm64: Fix output formatting for za-fork
+- prctl: Disable prctl(PR_SET_MDWE) on parisc
+- mm: add a NO_INHERIT flag to the PR_SET_MDWE prctl
+- lockdep: Fix block chain corruption
+- USB: dwc3: qcom: fix ACPI platform device leak
+- USB: dwc3: qcom: fix resource leaks on probe deferral
+- nvmet: nul-terminate the NQNs passed in the connect command
+- nvme: blank out authentication fabrics options if not configured
+- afs: Fix file locking on R/O volumes to operate in local mode
+- afs: Return ENOENT if no cell DNS record can be found
+- net: ipa: fix one GSI register field width
+- net: axienet: Fix check for partial TX checksum
+- vsock/test: fix SEQPACKET message bounds test
+- i40e: Fix adding unsupported cloud filters
+- amd-xgbe: propagate the correct speed and duplex status
+- amd-xgbe: handle the corner-case during tx completion
+- amd-xgbe: handle corner-case during sfp hotplug
+- net: veth: fix ethtool stats reporting
+- octeontx2-pf: Fix ntuple rule creation to direct packet to VF with higher Rx queue than its PF
+- arm/xen: fix xen_vcpu_info allocation alignment
+- arm64: mm: Fix "rodata=on" when CONFIG_RODATA_FULL_DEFAULT_ENABLED=y
+- s390/ipl: add missing IPL_TYPE_ECKD_DUMP case to ipl_init()
+- net/smc: avoid data corruption caused by decline
+- net: usb: ax88179_178a: fix failed operations during ax88179_reset
+- drm/panel: boe-tv101wum-nl6: Fine tune Himax83102-j02 panel HFP and HBP
+- ipv4: Correct/silence an endian warning in __ip_do_redirect
+- HID: fix HID device resource race between HID core and debugging support
+- accel/ivpu/37xx: Fix hangs related to MMIO reset
+- accel/ivpu: Do not initialize parameters on power up
+- bpf: Fix dev's rx stats for bpf_redirect_peer traffic
+- net: Move {l,t,d}stats allocation to core and convert veth & vrf
+- net, vrf: Move dstats structure to core
+- PM: tools: Fix sleepgraph syntax error
+- drm/rockchip: vop: Fix color for RGB888/BGR888 format on VOP full
+- libfs: getdents() should return 0 after reaching EOD
+- block: update the stable_writes flag in bdev_add
+- filemap: add a per-mapping stable writes flag
+- drm/i915: do not clean GT table on error path
+- ata: pata_isapnp: Add missing error check for devm_ioport_map()
+- octeontx2-pf: Fix memory leak during interface down
+- wireguard: use DEV_STATS_INC()
+- net: wangxun: fix kernel panic due to null pointer
+- drm/panel: simple: Fix Innolux G101ICE-L01 timings
+- drm/panel: simple: Fix Innolux G101ICE-L01 bus flags
+- fs: Pass AT_GETATTR_NOSEC flag to getattr interface function
+- drm/panel: auo,b101uan08.3: Fine tune the panel power sequence
+- blk-cgroup: avoid to warn !rcu_read_lock_held() in blkg_lookup()
+- afs: Make error on cell lookup failure consistent with OpenAFS
+- afs: Fix afs_server_list to be cleaned up with RCU
+- rxrpc: Defer the response to a PING ACK until we've parsed it
+- rxrpc: Fix RTT determination to use any ACK as a source
+- s390/ism: ism driver implies smc protocol
+- drm/msm/dsi: use the correct VREG_CTRL_1 value for 4nm cphy
+- sched/fair: Fix the decision for load balance
+- sched/eevdf: Fix vruntime adjustment on reweight
+- hv/hv_kvp_daemon: Some small fixes for handling NM keyfiles
+- irqchip/gic-v3-its: Flush ITS tables correctly in non-coherent GIC designs
+- NFSD: Fix checksum mismatches in the duplicate reply cache
+- NFSD: Fix "start of NFS reply" pointer passed to nfsd_cache_update()
+- !3310 kasan: fix the compilation error for memcpy_mcs()
+- kasan: fix the compilation error for memcpy_mcs()
+- arm64: arch_timer: disable CONFIG_ARM_ARCH_TIMER_WORKAROUND_IN_USERSPACE
+- vdso: do cntvct workaround in the VDSO
+- arm64: arch_timer: Disable CNTVCT_EL0 trap if workaround is enabled
+- mm/sharepool: Protect the va reserved for sharepool
+- mm/sharepool: support fork() and exit() to handle the mm
+- mm/sharepool: Add proc interfaces to show sp info
+- mm/sharepool: Implement mg_sp_config_dvpp_range()
+- mm/sharepool: Implement mg_sp_id_of_current()
+- mm/sharepool: Implement mg_sp_group_id_by_pid()
+- mm/sharepool: Implement mg_sp_group_add_task()
+- mm/sharepool: Implement mg_sp_make_share_k2u()
+- mm/sharepool: Implement mg_sp_alloc()
+- mm/sharepool: Implement mg_sp_free()
+- mm/sharepool: Implement mg_sp_walk_page_range()
+- mm/sharepool: Implement mg_sp_unshare_kva
+- mm/sharepool: Implement mg_sp_make_share_u2k()
+- mm/sharepool: Reserve the va space for share_pool
+- mm/sharepool: Add sp_area management code
+- mm/sharepool: Add base framework for share_pool
+- mm: Extend mmap assocated functions to accept mm_struct
+- mm/vmalloc: Extend vmalloc usage about hugepage
+- mm/hugetlb: Introduce hugetlb_insert_hugepage_pte[_by_pa]
+- ARM: Add unwinding annotations to __loop.*delay functions
+- !3285 arm64: errata: add option to disable cache readunique prefetch on HIP08
+- !3280 arm64: add machine check safe support
+- !3036 Added SM3 as module signing algorithm
+- ext4: Block writes to journal device
+- xfs: Block writes to log device
+- fs: Block writes to mounted block devices
+- btrfs: Do not restrict writes to btrfs devices
+- block: Add config option to not allow writing to mounted devices
+- arm64: errata: enable HISILICON_ERRATUM_HIP08_RU_PREFETCH
+- arm64: errata: add option to disable cache readunique prefetch on HIP08
+- arm64: add machine check safe sysctl interface
+- arm64: introduce copy_mc_to_kernel() implementation
+- arm64: support copy_mc_[user]_highpage()
+- mm/hwpoison: return -EFAULT when copy fail in copy_mc_[user]_highpage()
+- arm64: add uaccess to machine check safe
+- arm64: add support for machine check error safe
+- uaccess: add generic fallback version of copy_mc_to_user()
+- !3275 arm64: kernel: disable CNP on LINXICORE9100
+- !3099 block: Make blkdev_get_by_*() return
+- arm64: kernel: disable CNP on LINXICORE9100
+- !3111 openeuler_defconfig: enable some mm new
+- !3211 Add SDEI Watchdog Support
+- !3041 Random boot-time optimization
+- !3026 Backport ARM64-ILP32 patches
+- !3156 xfs: fix intent item leak during reovery
+- !3137 LoongArch: add old BPI compatibility
+- !3218 ipvlan: Introduce l2e mode
+- !3209 exec: Remove redundant check in do_open_execat/uselib
+- ipvlan: Introduce local xmit queue for l2e mode
+- ipvlan: Introduce l2e mode
+- arm64: kexec: only clear EOI for SDEI in NMI context
+- stop_machine: mask sdei before running the callback
+- openeuler_defconfig: Enable SDEI Watchdog
+- kprobes/arm64: Blacklist sdei watchdog callback functions
+- init: only move down lockup_detector_init() when sdei_watchdog is enabled
+- sdei_watchdog: avoid possible false hardlockup
+- sdei_watchdog: set secure timer period base on 'watchdog_thresh'
+- sdei_watchdog: clear EOI of the secure timer before kdump
+- watchdog: add nmi_watchdog support for arm64 based on SDEI
+- lockup_detector: init lockup detector after all the init_calls
+- firmware: arm_sdei: make 'sdei_api_event_disable/enable' public
+- firmware: arm_sdei: add interrupt binding api
+- exec: Remove redundant check in do_open_execat/uselib
+- xfs: abort intent items when recovery intents fail
+- xfs: factor out xfs_defer_pending_abort
+- !3141 Backport 6.6.3 LTS Patches
+- drm/amd/display: Change the DMCUB mailbox memory location from FB to inbox
+- drm/amd/display: Clear dpcd_sink_ext_caps if not set
+- drm/amd/display: Enable fast plane updates on DCN3.2 and above
+- drm/amd/display: fix a NULL pointer dereference in amdgpu_dm_i2c_xfer()
+- drm/amd/display: Fix DSC not Enabled on Direct MST Sink
+- drm/amd/display: Guard against invalid RPTR/WPTR being set
+- drm/amdgpu: Fix possible null pointer dereference
+- drm/amdgpu: lower CS errors to debug severity
+- drm/amdgpu: fix error handling in amdgpu_bo_list_get()
+- drm/amdgpu: fix error handling in amdgpu_vm_init
+- drm/amdgpu: don't use ATRM for external devices
+- drm/amdgpu: add a retry for IP discovery init
+- drm/amdgpu: fix GRBM read timeout when do mes_self_test
+- drm/amdgpu: don't use pci_is_thunderbolt_attached()
+- drm/amdgpu/smu13: drop compute workload workaround
+- drm/amd/pm: Fix error of MACO flag setting code
+- drm/i915: Flush WC GGTT only on required platforms
+- drm/i915: Fix potential spectre vulnerability
+- drm/i915: Bump GLK CDCLK frequency when driving multiple pipes
+- drm/i915/mtl: Support HBR3 rate with C10 phy and eDP in MTL
+- drm/amd/display: Add Null check for DPP resource
+- x86/srso: Move retbleed IBPB check into existing 'has_microcode' code block
+- drm: bridge: it66121: ->get_edid callback must not return err pointers
+- drm/amd/pm: Handle non-terminated overdrive commands.
+- ext4: fix racy may inline data check in dio write
+- ext4: properly sync file size update after O_SYNC direct IO
+- ext4: add missed brelse in update_backups
+- ext4: remove gdb backup copy for meta bg in setup_new_flex_group_blocks
+- ext4: correct the start block of counting reserved clusters
+- ext4: correct return value of ext4_convert_meta_bg
+- ext4: mark buffer new if it is unwritten to avoid stale data exposure
+- ext4: correct offset of gdb backup in non meta_bg group to update_backups
+- ext4: apply umask if ACL support is disabled
+- ext4: make sure allocate pending entry not fail
+- ext4: no need to generate from free list in mballoc
+- ext4: fix race between writepages and remount
+- Revert "net: r8169: Disable multicast filter for RTL8168H and RTL8107E"
+- Revert "HID: logitech-dj: Add support for a new lightspeed receiver iteration"
+- media: qcom: camss: Fix csid-gen2 for test pattern generator
+- media: qcom: camss: Fix invalid clock enable bit disjunction
+- media: qcom: camss: Fix set CSI2_RX_CFG1_VC_MODE when VC is greater than 3
+- media: qcom: camss: Fix missing vfe_lite clocks check
+- media: qcom: camss: Fix VFE-480 vfe_disable_output()
+- media: qcom: camss: Fix VFE-17x vfe_disable_output()
+- media: qcom: camss: Fix vfe_get() error jump
+- media: qcom: camss: Fix pm_domain_on sequence in probe
+- mmc: sdhci-pci-gli: GL9750: Mask the replay timer timeout of AER
+- r8169: add handling DASH when DASH is disabled
+- r8169: fix network lost after resume on DASH systems
+- selftests: mptcp: fix fastclose with csum failure
+- mptcp: fix setsockopt(IP_TOS) subflow locking
+- mptcp: add validity check for sending RM_ADDR
+- mptcp: deal with large GSO size
+- mm: kmem: drop __GFP_NOFAIL when allocating objcg vectors
+- mm: fix for negative counter: nr_file_hugepages
+- mmc: sdhci-pci-gli: A workaround to allow GL9750 to enter ASPM L1.2
+- riscv: kprobes: allow writing to x0
+- riscv: correct pt_level name via pgtable_l5/4_enabled
+- riscv: mm: Update the comment of CONFIG_PAGE_OFFSET
+- riscv: put interrupt entries into .irqentry.text
+- riscv: Using TOOLCHAIN_HAS_ZIHINTPAUSE marco replace zihintpause
+- swiotlb: fix out-of-bounds TLB allocations with CONFIG_SWIOTLB_DYNAMIC
+- swiotlb: do not free decrypted pages if dynamic
+- tracing: fprobe-event: Fix to check tracepoint event and return
+- LoongArch: Mark __percpu functions as always inline
+- NFSD: Update nfsd_cache_append() to use xdr_stream
+- nfsd: fix file memleak on client_opens_release
+- dm-verity: don't use blocking calls from tasklets
+- dm-bufio: fix no-sleep mode
+- drm/mediatek/dp: fix memory leak on ->get_edid callback error path
+- drm/mediatek/dp: fix memory leak on ->get_edid callback audio detection
+- media: ccs: Correctly initialise try compose rectangle
+- media: venus: hfi: add checks to handle capabilities from firmware
+- media: venus: hfi: fix the check to handle session buffer requirement
+- media: venus: hfi_parser: Add check to keep the number of codecs within range
+- media: sharp: fix sharp encoding
+- media: lirc: drop trailing space from scancode transmit
+- f2fs: split initial and dynamic conditions for extent_cache
+- f2fs: avoid format-overflow warning
+- f2fs: set the default compress_level on ioctl
+- f2fs: do not return EFSCORRUPTED, but try to run online repair
+- i2c: i801: fix potential race in i801_block_transaction_byte_by_byte
+- gfs2: don't withdraw if init_threads() got interrupted
+- net: phylink: initialize carrier state at creation
+- net: dsa: lan9303: consequently nested-lock physical MDIO
+- net: ethtool: Fix documentation of ethtool_sprintf()
+- s390/ap: fix AP bus crash on early config change callback invocation
+- i2c: designware: Disable TX_EMPTY irq while waiting for block length byte
+- sbsa_gwdt: Calculate timeout with 64-bit math
+- lsm: fix default return value for inode_getsecctx
+- lsm: fix default return value for vm_enough_memory
+- Revert "i2c: pxa: move to generic GPIO recovery"
+- Revert ncsi: Propagate carrier gain/loss events to the NCSI controller
+- ALSA: hda/realtek: Add quirks for HP Laptops
+- ALSA: hda/realtek: Enable Mute LED on HP 255 G10
+- ALSA: hda/realtek - Enable internal speaker of ASUS K6500ZC
+- ALSA: hda/realtek - Add Dell ALC295 to pin fall back table
+- ALSA: hda/realtek: Enable Mute LED on HP 255 G8
+- ALSA: info: Fix potential deadlock at disconnection
+- btrfs: zoned: wait for data BG to be finished on direct IO allocation
+- xfs: recovery should not clear di_flushiter unconditionally
+- cifs: Fix encryption of cleared, but unset rq_iter data buffers
+- cifs: do not pass cifs_sb when trying to add channels
+- cifs: do not reset chan_max if multichannel is not supported at mount
+- cifs: force interface update before a fresh session setup
+- cifs: reconnect helper should set reconnect for the right channel
+- smb: client: fix mount when dns_resolver key is not available
+- smb: client: fix potential deadlock when releasing mids
+- smb: client: fix use-after-free in smb2_query_info_compound()
+- smb: client: fix use-after-free bug in cifs_debug_data_proc_show()
+- smb3: fix caching of ctime on setxattr
+- smb3: allow dumping session and tcon id to improve stats analysis and debugging
+- smb3: fix touch -h of symlink
+- smb3: fix creating FIFOs when mounting with "sfu" mount option
+- xhci: Enable RPM on controllers that support low-power states
+- parisc: fix mmap_base calculation when stack grows upwards
+- parisc/power: Fix power soft-off when running on qemu
+- parisc/pgtable: Do not drop upper 5 address bits of physical address
+- parisc: Prevent booting 64-bit kernels on PA1.x machines
+- selftests/resctrl: Extend signal handler coverage to unmount on receiving signal
+- selftests/resctrl: Make benchmark command const and build it with pointers
+- selftests/resctrl: Simplify span lifetime
+- selftests/resctrl: Remove bw_report and bm_type from main()
+- rcutorture: Fix stuttering races and other issues
+- torture: Make torture_hrtimeout_ns() take an hrtimer mode parameter
+- drm/amd/display: enable dsc_clk even if dsc_pg disabled
+- Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE
+- Bluetooth: btusb: Add RTW8852BE device 13d3:3570 to device tables
+- apparmor: Fix regression in mount mediation
+- apparmor: pass cred through to audit info.
+- apparmor: rename audit_data->label to audit_data->subj_label
+- apparmor: combine common_audit_data and apparmor_audit_data
+- apparmor: Fix kernel-doc warnings in apparmor/policy.c
+- apparmor: Fix kernel-doc warnings in apparmor/resource.c
+- apparmor: Fix kernel-doc warnings in apparmor/lib.c
+- apparmor: Fix kernel-doc warnings in apparmor/audit.c
+- cxl/port: Fix delete_endpoint() vs parent unregistration race
+- cxl/region: Fix x1 root-decoder granularity calculations
+- i3c: master: svc: fix random hot join failure since timeout error
+- i3c: master: svc: fix SDA keep low when polling IBIWON timeout happen
+- i3c: master: svc: fix check wrong status register in irq handler
+- i3c: master: svc: fix ibi may not return mandatory data byte
+- i3c: master: svc: fix wrong data return when IBI happen during start frame
+- i3c: master: svc: fix race condition in ibi work thread
+- i3c: master: cdns: Fix reading status register
+- cxl/region: Do not try to cleanup after cxl_region_setup_targets() fails
+- mtd: cfi_cmdset_0001: Byte swap OTP info
+- mm: make PR_MDWE_REFUSE_EXEC_GAIN an unsigned long
+- mm/memory_hotplug: use pfn math in place of direct struct page manipulation
+- mm/hugetlb: use nth_page() in place of direct struct page manipulation
+- mm/cma: use nth_page() in place of direct struct page manipulation
+- s390/cmma: fix detection of DAT pages
+- s390/mm: add missing arch_set_page_dat() call to gmap allocations
+- s390/mm: add missing arch_set_page_dat() call to vmem_crst_alloc()
+- dmaengine: stm32-mdma: correct desc prep when channel running
+- mcb: fix error handling for different scenarios when parsing
+- driver core: Release all resources during unbind before updating device links
+- tracing: Have the user copy of synthetic event address use correct context
+- selftests/clone3: Fix broken test under !CONFIG_TIME_NS
+- i2c: core: Run atomic i2c xfer when !preemptible
+- mips: use nth_page() in place of direct struct page manipulation
+- fs: use nth_page() in place of direct struct page manipulation
+- scripts/gdb/vmalloc: disable on no-MMU
+- kernel/reboot: emergency_restart: Set correct system_state
+- quota: explicitly forbid quota files from being encrypted
+- jbd2: fix potential data lost in recovering journal raced with synchronizing fs bdev
+- ASoC: codecs: wsa-macro: fix uninitialized stack variables with name prefix
+- hid: lenovo: Resend all settings on reset_resume for compact keyboards
+- selftests/resctrl: Reduce failures due to outliers in MBA/MBM tests
+- selftests/resctrl: Fix feature checks
+- selftests/resctrl: Refactor feature check to use resource and feature name
+- selftests/resctrl: Move _GNU_SOURCE define into Makefile
+- selftests/resctrl: Remove duplicate feature check from CMT test
+- selftests/resctrl: Fix uninitialized .sa_flags
+- ASoC: codecs: wsa883x: make use of new mute_unmute_on_trigger flag
+- ASoC: soc-dai: add flag to mute and unmute stream during trigger
+- netfilter: nf_tables: split async and sync catchall in two functions
+- netfilter: nf_tables: remove catchall element in GC sync path
+- ima: detect changes to the backing overlay file
+- ima: annotate iint mutex to avoid lockdep false positive warnings
+- mfd: qcom-spmi-pmic: Fix revid implementation
+- mfd: qcom-spmi-pmic: Fix reference leaks in revid helper
+- leds: trigger: netdev: Move size check in set_device_name
+- arm64: dts: qcom: ipq6018: Fix tcsr_mutex register size
+- arm64: dts: qcom: ipq9574: Fix hwlock index for SMEM
+- ACPI: FPDT: properly handle invalid FPDT subtables
+- firmware: qcom_scm: use 64-bit calling convention only when client is 64-bit
+- arm64: dts: qcom: ipq8074: Fix hwlock index for SMEM
+- arm64: dts: qcom: ipq5332: Fix hwlock index for SMEM
+- thermal: intel: powerclamp: fix mismatch in get function for max_idle
+- btrfs: don't arbitrarily slow down delalloc if we're committing
+- rcu: kmemleak: Ignore kmemleak false positives when RCU-freeing objects
+- PM: hibernate: Clean up sync_read handling in snapshot_write_next()
+- PM: hibernate: Use __get_safe_page() rather than touching the list
+- dt-bindings: timer: renesas,rz-mtu3: Fix overflow/underflow interrupt names
+- arm64: dts: qcom: ipq6018: Fix hwlock index for SMEM
+- rcu/tree: Defer setting of jiffies during stall reset
+- svcrdma: Drop connection after an RDMA Read error
+- wifi: wilc1000: use vmm_table as array in wilc struct
+- PCI: Lengthen reset delay for VideoPropulsion Torrent QN16e card
+- PCI: exynos: Don't discard .remove() callback
+- PCI: kirin: Don't discard .remove() callback
+- PCI/ASPM: Fix L1 substate handling in aspm_attr_store_common()
+- PCI: qcom-ep: Add dedicated callback for writing to DBI2 registers
+- mmc: Add quirk MMC_QUIRK_BROKEN_CACHE_FLUSH for Micron eMMC Q2J54A
+- mmc: sdhci_am654: fix start loop index for TAP value parsing
+- mmc: vub300: fix an error code
+- ksmbd: fix slab out of bounds write in smb_inherit_dacl()
+- ksmbd: handle malformed smb1 message
+- ksmbd: fix recursive locking in vfs helpers
+- clk: qcom: ipq6018: drop the CLK_SET_RATE_PARENT flag from PLL clocks
+- clk: qcom: ipq8074: drop the CLK_SET_RATE_PARENT flag from PLL clocks
+- integrity: powerpc: Do not select CA_MACHINE_KEYRING
+- clk: visconti: Fix undefined behavior bug in struct visconti_pll_provider
+- clk: socfpga: Fix undefined behavior bug in struct stratix10_clock_data
+- powercap: intel_rapl: Downgrade BIOS locked limits pr_warn() to pr_debug()
+- cpufreq: stats: Fix buffer overflow detection in trans_stats()
+- parisc/power: Add power soft-off when running on qemu
+- parisc/pdc: Add width field to struct pdc_model
+- parisc/agp: Use 64-bit LE values in SBA IOMMU PDIR table
+- pmdomain: imx: Make imx pgc power domain also set the fwnode
+- arm64: module: Fix PLT counting when CONFIG_RANDOMIZE_BASE=n
+- arm64: Restrict CPU_BIG_ENDIAN to GNU as or LLVM IAS 15.x or newer
+- pmdomain: amlogic: Fix mask for the second NNA mem PD domain
+- PCI: keystone: Don't discard .probe() callback
+- PCI: keystone: Don't discard .remove() callback
+- KEYS: trusted: Rollback init_trusted() consistently
+- KEYS: trusted: tee: Refactor register SHM usage
+- pmdomain: bcm: bcm2835-power: check if the ASB register is equal to enable
+- sched/core: Fix RQCF_ACT_SKIP leak
+- genirq/generic_chip: Make irq_remove_generic_chip() irqdomain aware
+- mmc: meson-gx: Remove setting of CMD_CFG_ERROR
+- wifi: ath12k: fix dfs-radar and temperature event locking
+- wifi: ath12k: fix htt mlo-offset event locking
+- wifi: ath11k: fix gtk offload status event locking
+- wifi: ath11k: fix htt pktlog locking
+- wifi: ath11k: fix dfs radar event locking
+- wifi: ath11k: fix temperature event locking
+- regmap: Ensure range selector registers are updated after cache sync
+- ACPI: resource: Do IRQ override on TongFang GMxXGxx
+- parisc: Add nop instructions after TLB inserts
+- mm/damon/sysfs: check error from damon_sysfs_update_target()
+- mm/damon/core.c: avoid unintentional filtering out of schemes
+- mm/damon/sysfs-schemes: handle tried regions sysfs directory allocation failure
+- mm/damon/sysfs-schemes: handle tried region directory allocation failure
+- mm/damon/core: avoid divide-by-zero during monitoring results update
+- mm/damon: implement a function for max nr_accesses safe calculation
+- mm/damon/ops-common: avoid divide-by-zero during region hotness calculation
+- mm/damon/lru_sort: avoid divide-by-zero in hot threshold calculation
+- dm crypt: account large pages in cc->n_allocated_pages
+- fbdev: stifb: Make the STI next font pointer a 32-bit signed offset
+- iommufd: Fix missing update of domains_itree after splitting iopt_area
+- watchdog: move softlockup_panic back to early_param
+- mm/damon/sysfs: update monitoring target regions for online input commit
+- mm/damon/sysfs: remove requested targets when online-commit inputs
+- PCI/sysfs: Protect driver's D3cold preference from user space
+- hvc/xen: fix event channel handling for secondary consoles
+- hvc/xen: fix error path in xen_hvc_init() to always register frontend driver
+- hvc/xen: fix console unplug
+- acpi/processor: sanitize _OSC/_PDC capabilities for Xen dom0
+- tty: serial: meson: fix hard LOCKUP on crtscts mode
+- tty/sysrq: replace smp_processor_id() with get_cpu()
+- proc: sysctl: prevent aliased sysctls from getting passed to init
+- audit: don't WARN_ON_ONCE(!current->mm) in audit_exe_compare()
+- audit: don't take task_lock() in audit_exe_compare() code path
+- sched: psi: fix unprivileged polling against cgroups
+- mmc: sdhci-pci-gli: GL9755: Mask the replay timer timeout of AER
+- KVM: x86: Fix lapic timer interrupt lost after loading a snapshot.
+- KVM: x86: Clear bit12 of ICR after APIC-write VM-exit
+- KVM: x86: Ignore MSR_AMD64_TW_CFG access
+- KVM: x86: hyper-v: Don't auto-enable stimer on write from user-space
+- x86/cpu/hygon: Fix the CPU topology evaluation for real
+- x86/apic/msi: Fix misconfigured non-maskable MSI quirk
+- x86/PCI: Avoid PME from D3hot/D3cold for AMD Rembrandt and Phoenix USB4
+- crypto: x86/sha - load modules based on CPU features
+- x86/shstk: Delay signal entry SSP write until after user accesses
+- scsi: ufs: core: Fix racing issue between ufshcd_mcq_abort() and ISR
+- scsi: qla2xxx: Fix system crash due to bad pointer access
+- scsi: ufs: qcom: Update PHY settings only when scaling to higher gears
+- scsi: megaraid_sas: Increase register read retry rount from 3 to 30 for selected registers
+- scsi: mpt3sas: Fix loop logic
+- bpf: Fix precision tracking for BPF_ALU | BPF_TO_BE | BPF_END
+- bpf: Fix check_stack_write_fixed_off() to correctly spill imm
+- spi: Fix null dereference on suspend
+- randstruct: Fix gcc-plugin performance mode to stay in group
+- powerpc/perf: Fix disabling BHRB and instruction sampling
+- perf intel-pt: Fix async branch flags
+- media: venus: hfi: add checks to perform sanity on queue pointers
+- drivers: perf: Check find_first_bit() return value
+- perf: arm_cspmu: Reject events meant for other PMUs
+- i915/perf: Fix NULL deref bugs with drm_dbg() calls
+- perf/core: Fix cpuctx refcounting
+- cifs: fix check of rc in function generate_smb3signingkey
+- cifs: spnego: add ';' in HOST_KEY_LEN
+- scsi: ufs: core: Expand MCQ queue slot to DeviceQueueDepth + 1
+- tools/power/turbostat: Enable the C-state Pre-wake printing
+- tools/power/turbostat: Fix a knl bug
+- macvlan: Don't propagate promisc change to lower dev in passthru
+- net: sched: do not offload flows with a helper in act_ct
+- net/mlx5e: Check return value of snprintf writing to fw_version buffer for representors
+- net/mlx5e: Check return value of snprintf writing to fw_version buffer
+- net/mlx5e: Reduce the size of icosq_str
+- net/mlx5: Increase size of irq name buffer
+- net/mlx5e: Update doorbell for port timestamping CQ before the software counter
+- net/mlx5e: Track xmit submission to PTP WQ after populating metadata map
+- net/mlx5e: Avoid referencing skb after free-ing in drop path of mlx5e_sq_xmit_wqe
+- net/mlx5e: Don't modify the peer sent-to-vport rules for IPSec offload
+- net/mlx5e: Fix pedit endianness
+- net/mlx5e: fix double free of encap_header in update funcs
+- net/mlx5e: fix double free of encap_header
+- net/mlx5: Decouple PHC .adjtime and .adjphase implementations
+- net/mlx5: Free used cpus mask when an IRQ is released
+- Revert "net/mlx5: DR, Supporting inline WQE when possible"
+- io_uring/fdinfo: remove need for sqpoll lock for thread/pid retrieval
+- gve: Fixes for napi_poll when budget is 0
+- pds_core: fix up some format-truncation complaints
+- pds_core: use correct index to mask irq
+- net: stmmac: avoid rx queue overrun
+- net: stmmac: fix rx budget limit check
+- netfilter: nf_tables: bogus ENOENT when destroying element which does not exist
+- netfilter: nf_tables: fix pointer math issue in nft_byteorder_eval()
+- netfilter: nf_conntrack_bridge: initialize err to 0
+- af_unix: fix use-after-free in unix_stream_read_actor()
+- net: ethernet: cortina: Fix MTU max setting
+- net: ethernet: cortina: Handle large frames
+- net: ethernet: cortina: Fix max RX frame define
+- bonding: stop the device in bond_setup_by_slave()
+- ptp: annotate data-race around q->head and q->tail
+- blk-mq: make sure active queue usage is held for bio_integrity_prep()
+- xen/events: fix delayed eoi list handling
+- ppp: limit MRU to 64K
+- net: mvneta: fix calls to page_pool_get_stats
+- tipc: Fix kernel-infoleak due to uninitialized TLV value
+- net: hns3: fix VF wrong speed and duplex issue
+- net: hns3: fix VF reset fail issue
+- net: hns3: fix variable may not initialized problem in hns3_init_mac_addr()
+- net: hns3: fix out-of-bounds access may occur when coalesce info is read via debugfs
+- net: hns3: fix incorrect capability bit display for copper port
+- net: hns3: add barrier in vf mailbox reply process
+- net: hns3: fix add VLAN fail issue
+- xen/events: avoid using info_for_irq() in xen_send_IPI_one()
+- net: ti: icssg-prueth: Fix error cleanup on failing pruss_request_mem_region
+- net: ti: icssg-prueth: Add missing icss_iep_put to error path
+- tty: Fix uninit-value access in ppp_sync_receive()
+- ipvlan: add ipvlan_route_v6_outbound() helper
+- net: set SOCK_RCU_FREE before inserting socket into hashtable
+- bpf: fix control-flow graph checking in privileged mode
+- bpf: fix precision backtracking instruction iteration
+- bpf: handle ldimm64 properly in check_cfg()
+- gcc-plugins: randstruct: Only warn about true flexible arrays
+- vhost-vdpa: fix use after free in vhost_vdpa_probe()
+- vdpa_sim_blk: allocate the buffer zeroed
+- riscv: split cache ops out of dma-noncoherent.c
+- drm/i915/tc: Fix -Wformat-truncation in intel_tc_port_init
+- gfs2: Silence "suspicious RCU usage in gfs2_permission" warning
+- riscv: provide riscv-specific is_trap_insn()
+- RISC-V: hwprobe: Fix vDSO SIGSEGV
+- SUNRPC: Fix RPC client cleaned up the freed pipefs dentries
+- NFSv4.1: fix SP4_MACH_CRED protection for pnfs IO
+- SUNRPC: Add an IS_ERR() check back to where it was
+- NFSv4.1: fix handling NFS4ERR_DELAY when testing for session trunking
+- drm/i915/mtl: avoid stringop-overflow warning
+- mtd: rawnand: meson: check return value of devm_kasprintf()
+- mtd: rawnand: intel: check return value of devm_kasprintf()
+- SUNRPC: ECONNRESET might require a rebind
+- dt-bindings: serial: fix regex pattern for matching serial node children
+- samples/bpf: syscall_tp_user: Fix array out-of-bound access
+- samples/bpf: syscall_tp_user: Rename num_progs into nr_tests
+- sched/core: Optimize in_task() and in_interrupt() a bit
+- wifi: iwlwifi: Use FW rate for non-data frames
+- mtd: rawnand: tegra: add missing check for platform_get_irq()
+- pwm: Fix double shift bug
+- drm/amdgpu: fix software pci_unplug on some chips
+- ALSA: hda/realtek: Add quirk for ASUS UX7602ZM
+- drm/qxl: prevent memory leak
+- ASoC: ti: omap-mcbsp: Fix runtime PM underflow warnings
+- i2c: dev: copy userspace array safely
+- riscv: VMAP_STACK overflow detection thread-safe
+- kgdb: Flush console before entering kgdb on panic
+- gfs2: Fix slab-use-after-free in gfs2_qd_dealloc
+- drm/amd/display: Avoid NULL dereference of timing generator
+- media: imon: fix access to invalid resource for the second interface
+- media: ccs: Fix driver quirk struct documentation
+- media: cobalt: Use FIELD_GET() to extract Link Width
+- gfs2: fix an oops in gfs2_permission
+- gfs2: ignore negated quota changes
+- media: ipu-bridge: increase sensor_name size
+- media: vivid: avoid integer overflow
+- media: gspca: cpia1: shift-out-of-bounds in set_flicker
+- i3c: master: mipi-i3c-hci: Fix a kernel panic for accessing DAT_data.
+- virtio-blk: fix implicit overflow on virtio_max_dma_size
+- i2c: sun6i-p2wi: Prevent potential division by zero
+- i2c: fix memleak in i2c_new_client_device()
+- i2c: i801: Add support for Intel Birch Stream SoC
+- i3c: mipi-i3c-hci: Fix out of bounds access in hci_dma_irq_handler
+- 9p: v9fs_listxattr: fix %s null argument warning
+- 9p/trans_fd: Annotate data-racy writes to file::f_flags
+- usb: gadget: f_ncm: Always set current gadget in ncm_bind()
+- usb: host: xhci: Avoid XHCI resume delay if SSUSB device is not present
+- f2fs: fix error handling of __get_node_page
+- f2fs: fix error path of __f2fs_build_free_nids
+- soundwire: dmi-quirks: update HP Omen match
+- usb: ucsi: glink: use the connector orientation GPIO to provide switch events
+- usb: dwc3: core: configure TX/RX threshold for DWC3_IP
+- phy: qualcomm: phy-qcom-eusb2-repeater: Zero out untouched tuning regs
+- phy: qualcomm: phy-qcom-eusb2-repeater: Use regmap_fields
+- dt-bindings: phy: qcom,snps-eusb2-repeater: Add magic tuning overrides
+- tty: vcc: Add check for kstrdup() in vcc_probe()
+- thunderbolt: Apply USB 3.x bandwidth quirk only in software connection manager
+- iio: adc: stm32-adc: harden against NULL pointer deref in stm32_adc_probe()
+- mfd: intel-lpss: Add Intel Lunar Lake-M PCI IDs
+- exfat: support handle zero-size directory
+- HID: Add quirk for Dell Pro Wireless Keyboard and Mouse KM5221W
+- crypto: hisilicon/qm - prevent soft lockup in receive loop
+- ASoC: Intel: soc-acpi-cht: Add Lenovo Yoga Tab 3 Pro YT3-X90 quirk
+- PCI: Use FIELD_GET() in Sapphire RX 5600 XT Pulse quirk
+- misc: pci_endpoint_test: Add Device ID for R-Car S4-8 PCIe controller
+- PCI: dwc: Add missing PCI_EXP_LNKCAP_MLW handling
+- PCI: dwc: Add dw_pcie_link_set_max_link_width()
+- PCI: Disable ATS for specific Intel IPU E2000 devices
+- PCI: Extract ATS disabling to a helper function
+- PCI: Use FIELD_GET() to extract Link Width
+- scsi: libfc: Fix potential NULL pointer dereference in fc_lport_ptp_setup()
+- PCI: Do error check on own line to split long "if" conditions
+- atm: iphase: Do PCI error checks on own line
+- PCI: mvebu: Use FIELD_PREP() with Link Width
+- PCI: tegra194: Use FIELD_GET()/FIELD_PREP() with Link Width fields
+- gpiolib: of: Add quirk for mt2701-cs42448 ASoC sound
+- ALSA: hda: Fix possible null-ptr-deref when assigning a stream
+- ARM: 9320/1: fix stack depot IRQ stack filter
+- HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround
+- jfs: fix array-index-out-of-bounds in diAlloc
+- jfs: fix array-index-out-of-bounds in dbFindLeaf
+- fs/jfs: Add validity check for db_maxag and db_agpref
+- fs/jfs: Add check for negative db_l2nbperpage
+- scsi: ibmvfc: Remove BUG_ON in the case of an empty event pool
+- scsi: hisi_sas: Set debugfs_dir pointer to NULL after removing debugfs
+- RDMA/hfi1: Use FIELD_GET() to extract Link Width
+- ASoC: SOF: ipc4: handle EXCEPTION_CAUGHT notification from firmware
+- crypto: pcrypt - Fix hungtask for PADATA_RESET
+- ASoC: cs35l56: Use PCI SSID as the firmware UID
+- ASoC: Intel: sof_sdw: Copy PCI SSID to struct snd_soc_card
+- ASoC: SOF: Pass PCI SSID to machine driver
+- ASoC: soc-card: Add storage for PCI SSID
+- ASoC: mediatek: mt8188-mt6359: support dynamic pinctrl
+- selftests/efivarfs: create-read: fix a resource leak
+- arm64: dts: ls208xa: use a pseudo-bus to constrain usb dma size
+- arm64: dts: rockchip: Add NanoPC T6 PCIe e-key support
+- soc: qcom: pmic: Fix resource leaks in a device_for_each_child_node() loop
+- drm/amd: check num of link levels when update pcie param
+- drm/amd/display: fix num_ways overflow error
+- drm/amd: Disable PP_PCIE_DPM_MASK when dynamic speed switching not supported
+- drm/amdgpu: Fix a null pointer access when the smc_rreg pointer is NULL
+- drm/amdkfd: Fix shift out-of-bounds issue
+- drm/panel: st7703: Pick different reset sequence
+- drm/amdgpu/vkms: fix a possible null pointer dereference
+- drm/radeon: fix a possible null pointer dereference
+- drm/panel/panel-tpo-tpg110: fix a possible null pointer dereference
+- drm/panel: fix a possible null pointer dereference
+- drm/amdgpu: Fix potential null pointer derefernce
+- drm/amd: Fix UBSAN array-index-out-of-bounds for Polaris and Tonga
+- drm/amd: Fix UBSAN array-index-out-of-bounds for SMU7
+- drm/msm/dp: skip validity check for DP CTS EDID checksum
+- drm: vmwgfx_surface.c: copy user-array safely
+- drm_lease.c: copy user-array safely
+- kernel: watch_queue: copy user-array safely
+- kernel: kexec: copy user-array safely
+- string.h: add array-wrappers for (v)memdup_user()
+- drm/amd/display: use full update for clip size increase of large plane source
+- drm/amd: Update `update_pcie_parameters` functions to use uint8_t arguments
+- drm/amdgpu: update retry times for psp vmbx wait
+- drm/amdkfd: Fix a race condition of vram buffer unref in svm code
+- drm/amdgpu: not to save bo in the case of RAS err_event_athub
+- md: don't rely on 'mddev->pers' to be set in mddev_suspend()
+- drm/edid: Fixup h/vsync_end instead of h/vtotal
+- drm/amd/display: add seamless pipe topology transition check
+- drm/amd/display: Don't lock phantom pipe on disabling
+- drm/amd/display: Blank phantom OTG before enabling
+- drm/komeda: drop all currently held locks if deadlock happens
+- drm/amdkfd: ratelimited SQ interrupt messages
+- drm/gma500: Fix call trace when psb_gem_mm_init() fails
+- platform/x86: thinkpad_acpi: Add battery quirk for Thinkpad X120e
+- of: address: Fix address translation when address-size is greater than 2
+- platform/chrome: kunit: initialize lock for fake ec_dev
+- gpiolib: acpi: Add a ignore interrupt quirk for Peaq C1010
+- tsnep: Fix tsnep_request_irq() format-overflow warning
+- ACPI: EC: Add quirk for HP 250 G7 Notebook PC
+- Bluetooth: Fix double free in hci_conn_cleanup
+- Bluetooth: btusb: Add date->evt_skb is NULL check
+- wifi: iwlwifi: mvm: fix size check for fw_link_id
+- bpf: Ensure proper register state printing for cond jumps
+- vsock: read from socket's error queue
+- net: sfp: add quirk for FS's 2.5G copper SFP
+- wifi: ath10k: Don't touch the CE interrupt registers after power up
+- wifi: ath12k: mhi: fix potential memory leak in ath12k_mhi_register()
+- net: annotate data-races around sk->sk_dst_pending_confirm
+- net: annotate data-races around sk->sk_tx_queue_mapping
+- wifi: mt76: fix clang-specific fortify warnings
+- wifi: mt76: mt7921e: Support MT7992 IP in Xiaomi Redmibook 15 Pro (2023)
+- net: sfp: add quirk for Fiberstone GPON-ONU-34-20BI
+- ACPI: APEI: Fix AER info corruption when error status data has multiple sections
+- wifi: ath12k: fix possible out-of-bound write in ath12k_wmi_ext_hal_reg_caps()
+- wifi: ath10k: fix clang-specific fortify warning
+- wifi: ath12k: fix possible out-of-bound read in ath12k_htt_pull_ppdu_stats()
+- wifi: ath9k: fix clang-specific fortify warnings
+- bpf: Detect IP == ksym.end as part of BPF program
+- atl1c: Work around the DMA RX overflow issue
+- wifi: mac80211: don't return unset power in ieee80211_get_tx_power()
+- wifi: mac80211_hwsim: fix clang-specific fortify warning
+- wifi: ath12k: Ignore fragments from uninitialized peer in dp
+- wifi: plfxlc: fix clang-specific fortify warning
+- x86/mm: Drop the 4 MB restriction on minimal NUMA node memory size
+- workqueue: Provide one lock class key per work_on_cpu() callsite
+- cpu/hotplug: Don't offline the last non-isolated CPU
+- smp,csd: Throw an error if a CSD lock is stuck for too long
+- srcu: Only accelerate on enqueue time
+- clocksource/drivers/timer-atmel-tcb: Fix initialization on SAM9 hardware
+- clocksource/drivers/timer-imx-gpt: Fix potential memory leak
+- selftests/lkdtm: Disable CONFIG_UBSAN_TRAP in test config
+- srcu: Fix srcu_struct node grpmask overflow on 64-bit systems
+- perf/core: Bail out early if the request AUX area is out of bound
+- x86/retpoline: Make sure there are no unconverted return thunks due to KCSAN
+- lib/generic-radix-tree.c: Don't overflow in peek()
+- btrfs: abort transaction on generation mismatch when marking eb as dirty
+- locking/ww_mutex/test: Fix potential workqueue corruption
+- LoongArch: use arch specific phys_to_dma
+- LoongArch: Fixed EIOINTC structure members
+- LoongArch: Fix virtual machine startup error
+- LoongArch: Old BPI compatibility
+- LoongArch: add kernel setvirtmap for runtime
+- arm64: openeuler_defconfig: update for new feature
+- x86: openeuler_defconfig: update from new feature
+- erofs: fix NULL dereference of dif->bdev_handle in fscache mode
+- block: Remove blkdev_get_by_*() functions
+- bcache: Fixup error handling in register_cache()
+- xfs: Convert to bdev_open_by_path()
+- reiserfs: Convert to bdev_open_by_dev/path()
+- ocfs2: Convert to use bdev_open_by_dev()
+- nfs/blocklayout: Convert to use bdev_open_by_dev/path()
+- jfs: Convert to bdev_open_by_dev()
+- f2fs: Convert to bdev_open_by_dev/path()
+- ext4: Convert to bdev_open_by_dev()
+- erofs: Convert to use bdev_open_by_path()
+- btrfs: Convert to bdev_open_by_path()
+- fs: Convert to bdev_open_by_dev()
+- mm/swap: Convert to use bdev_open_by_dev()
+- PM: hibernate: Drop unused snapshot_test argument
+- PM: hibernate: Convert to bdev_open_by_dev()
+- scsi: target: Convert to bdev_open_by_path()
+- s390/dasd: Convert to bdev_open_by_path()
+- nvmet: Convert to bdev_open_by_path()
+- mtd: block2mtd: Convert to bdev_open_by_dev/path()
+- md: Convert to bdev_open_by_dev()
+- dm: Convert to bdev_open_by_dev()
+- bcache: Convert to bdev_open_by_path()
+- zram: Convert to use bdev_open_by_dev()
+- xen/blkback: Convert to bdev_open_by_dev()
+- rnbd-srv: Convert to use bdev_open_by_path()
+- pktcdvd: Convert to bdev_open_by_dev()
+- drdb: Convert to use bdev_open_by_path()
+- block: Use bdev_open_by_dev() in disk_scan_partitions() and blkdev_bszset()
+- block: Use bdev_open_by_dev() in blkdev_open()
+- block: Provide bdev_open_* functions
+- alinux: random: speed up the initialization of module
+- keys: Allow automatic module signature with SM3
+- arm64: fix image size inflation with CONFIG_COMPAT_TASK_SIZE
+- arm64: set 32-bit compatible TASK_SIZE_MAX to fix U32 libc_write_01 error
+- arm64: replace is_compat_task() with is_ilp32_compat_task() in TASK_SIZE_MAX
+- arm64: fix address limit problem with TASK_SIZE_MAX
+- ilp32: fix compile problem when ARM64_ILP32 and UBSAN are both enabled
+- arm64: fix abi change caused by ILP32
+- arm64: fix AUDIT_ARCH_AARCH64ILP32 bug on audit subsystem
+- ilp32: skip ARM erratum 1418040 for ilp32 application
+- ilp32: avoid clearing upper 32 bits of syscall return value for ilp32
+- arm64: secomp: fix the secure computing mode 1 syscall check for ilp32
+- arm64:ilp32: add ARM64_ILP32 to Kconfig
+- arm64:ilp32: add vdso-ilp32 and use for signal return
+- arm64: ptrace: handle ptrace_request differently for aarch32 and ilp32
+- arm64: ilp32: introduce ilp32-specific sigframe and ucontext
+- arm64: signal32: move ilp32 and aarch32 common code to separated file
+- arm64: signal: share lp64 signal structures and routines to ilp32
+- arm64: ilp32: introduce syscall table for ILP32
+- arm64: ilp32: share aarch32 syscall handlers
+- arm64: ilp32: introduce binfmt_ilp32.c
+- arm64: change compat_elf_hwcap and compat_elf_hwcap2 prefix to a32
+- arm64: introduce binfmt_elf32.c
+- arm64: introduce AUDIT_ARCH_AARCH64ILP32 for ilp32
+- arm64: ilp32: add is_ilp32_compat_{task,thread} and TIF_32BIT_AARCH64
+- arm64: introduce is_a32_compat_{task,thread} for AArch32 compat
+- arm64: uapi: set __BITS_PER_LONG correctly for ILP32 and LP64
+- arm64: rename functions that reference compat term
+- arm64: rename COMPAT to AARCH32_EL0
+- arm64: ilp32: add documentation on the ILP32 ABI for ARM64
+- thread: move thread bits accessors to separated file
+- ptrace: Add compat PTRACE_{G,S}ETSIGMASK handlers
+- arm64: signal: Make parse_user_sigframe() independent of rt_sigframe layout
+
+* Tue Dec 5 2023 Zheng Zengkai <zhengzengkai@huawei.com> - 6.6.0-1.0.0.1
+- !3058 tcp/dccp: Add another way to allocate local ports in connect()
+- !3064 mm: PCP high auto-tuning
+- !2985 hugetlbfs: avoid overflow in hugetlbfs_fallocate
+- !3059 Handle more faults under the VMA lock
+- mm, pcp: reduce detecting time of consecutive high order page freeing
+- mm, pcp: decrease PCP high if free pages < high watermark
+- mm: tune PCP high automatically
+- mm: add framework for PCP high auto-tuning
+- mm, page_alloc: scale the number of pages that are batch allocated
+- mm: restrict the pcp batch scale factor to avoid too long latency
+- mm, pcp: reduce lock contention for draining high-order pages
+- cacheinfo: calculate size of per-CPU data cache slice
+- mm, pcp: avoid to drain PCP when process exit
+- mm: handle write faults to RO pages under the VMA lock
+- mm: handle read faults under the VMA lock
+- mm: handle COW faults under the VMA lock
+- mm: handle shared faults under the VMA lock
+- mm: call wp_page_copy() under the VMA lock
+- mm: make lock_folio_maybe_drop_mmap() VMA lock aware
+- tcp/dccp: Add another way to allocate local ports in connect()
+- !3044 mm: hugetlb: Skip initialization of gigantic tail struct pages if freed by HVO
+- !2980 io_uring: fix soft lockup in io_submit_sqes()
+- !3014 anolis: bond: broadcast ARP or ND messages to all slaves
+- !3018 folio conversions for numa balance
+- mm: hugetlb: skip initialization of gigantic tail struct pages if freed by HVO
+- memblock: introduce MEMBLOCK_RSRV_NOINIT flag
+- memblock: pass memblock_type to memblock_setclr_flag
+- mm: hugetlb_vmemmap: use nid of the head page to reallocate it
+- mm: remove page_cpupid_xchg_last()
+- mm: use folio_xchg_last_cpupid() in wp_page_reuse()
+- mm: convert wp_page_reuse() and finish_mkwrite_fault() to take a folio
+- mm: make finish_mkwrite_fault() static
+- mm: huge_memory: use folio_xchg_last_cpupid() in __split_huge_page_tail()
+- mm: migrate: use folio_xchg_last_cpupid() in folio_migrate_flags()
+- sched/fair: use folio_xchg_last_cpupid() in should_numa_migrate_memory()
+- mm: add folio_xchg_last_cpupid()
+- mm: remove xchg_page_access_time()
+- mm: huge_memory: use a folio in change_huge_pmd()
+- mm: mprotect: use a folio in change_pte_range()
+- sched/fair: use folio_xchg_access_time() in numa_hint_fault_latency()
+- mm: add folio_xchg_access_time()
+- mm: remove page_cpupid_last()
+- mm: huge_memory: use folio_last_cpupid() in __split_huge_page_tail()
+- mm: huge_memory: use folio_last_cpupid() in do_huge_pmd_numa_page()
+- mm: memory: use folio_last_cpupid() in do_numa_page()
+- mm: add folio_last_cpupid()
+- mm_types: add virtual and _last_cpupid into struct folio
+- sched/numa, mm: make numa migrate functions to take a folio
+- mm: mempolicy: make mpol_misplaced() to take a folio
+- mm: memory: make numa_migrate_prep() to take a folio
+- mm: memory: use a folio in do_numa_page()
+- mm: huge_memory: use a folio in do_huge_pmd_numa_page()
+- mm: memory: add vm_normal_folio_pmd()
+- mm: migrate: remove isolated variable in add_page_for_migration()
+- mm: migrate: remove PageHead() check for HugeTLB in add_page_for_migration()
+- mm: migrate: use a folio in add_page_for_migration()
+- mm: migrate: use __folio_test_movable()
+- mm: migrate: convert migrate_misplaced_page() to migrate_misplaced_folio()
+- mm: migrate: convert numamigrate_isolate_page() to numamigrate_isolate_folio()
+- mm: migrate: remove THP mapcount check in numamigrate_isolate_page()
+- mm: migrate: remove PageTransHuge check in numamigrate_isolate_page()
+- anolis: bond: broadcast ARP or ND messages to all slaves
+- hugetlbfs: avoid overflow in hugetlbfs_fallocate
+- io_uring: fix soft lockup in io_submit_sqes()
+- !2971 net: sched: sch_qfq: Use non-work-conserving warning handler
+- !2968 checkpatch: Update link tags to fix ci warning
+- net: sched: sch_qfq: Use non-work-conserving warning handler
+- checkpatch: Update check of link tags
+- !2945 Backport linux 6.6.2 LTS patches
+- btrfs: make found_logical_ret parameter mandatory for function queue_scrub_stripe()
+- btrfs: use u64 for buffer sizes in the tree search ioctls
+- Revert "mmc: core: Capture correct oemid-bits for eMMC cards"
+- Revert "PCI/ASPM: Disable only ASPM_STATE_L1 when driver, disables L1"
+- x86/amd_nb: Use Family 19h Models 60h-7Fh Function 4 IDs
+- io_uring/net: ensure socket is marked connected on connect retry
+- selftests: mptcp: fix wait_rm_addr/sf parameters
+- selftests: mptcp: run userspace pm tests slower
+- eventfs: Check for NULL ef in eventfs_set_attr()
+- tracing/kprobes: Fix the order of argument descriptions
+- fbdev: fsl-diu-fb: mark wr_reg_wa() static
+- ALSA: hda/realtek: Add support dual speaker for Dell
+- fbdev: imsttfb: fix a resource leak in probe
+- fbdev: imsttfb: fix double free in probe()
+- arm64/arm: arm_pmuv3: perf: Don't truncate 64-bit registers
+- spi: spi-zynq-qspi: add spi-mem to driver kconfig dependencies
+- ASoC: dapm: fix clock get name
+- ASoC: hdmi-codec: register hpd callback on component probe
+- ASoC: mediatek: mt8186_mt6366_rt1019_rt5682s: trivial: fix error messages
+- ASoC: rt712-sdca: fix speaker route missing issue
+- drm/syncobj: fix DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE
+- drm/vc4: tests: Fix UAF in the mock helpers
+- fs: dlm: Simplify buffer size computation in dlm_create_debug_file()
+- module/decompress: use kvmalloc() consistently
+- drivers: perf: Do not broadcast to other cpus when starting a counter
+- net: ti: icss-iep: fix setting counter value
+- RISC-V: Don't fail in riscv_of_parent_hartid() for disabled HARTs
+- net/sched: act_ct: Always fill offloading tuple iifidx
+- netfilter: nat: fix ipv6 nat redirect with mapped and scoped addresses
+- netfilter: xt_recent: fix (increase) ipv6 literal buffer length
+- i2c: iproc: handle invalid slave state
+- net: enetc: shorten enetc_setup_xdp_prog() error message to fit NETLINK_MAX_FMTMSG_LEN
+- virtio/vsock: Fix uninit-value in virtio_transport_recv_pkt()
+- r8169: respect userspace disabling IFF_MULTICAST
+- vsock/virtio: remove socket from connected/bound list on shutdown
+- blk-core: use pr_warn_ratelimited() in bio_check_ro()
+- nbd: fix uaf in nbd_open
+- tg3: power down device only on SYSTEM_POWER_OFF
+- ice: Fix VF-VF direction matching in drop rule in switchdev
+- ice: Fix VF-VF filter rules in switchdev mode
+- ice: lag: in RCU, use atomic allocation
+- ice: Fix SRIOV LAG disable on non-compliant aggregate
+- riscv: boot: Fix creation of loader.bin
+- nvme: fix error-handling for io_uring nvme-passthrough
+- net/smc: put sk reference if close work was canceled
+- net/smc: allow cdc msg send rather than drop it with NULL sndbuf_desc
+- net/smc: fix dangling sock under state SMC_APPFINCLOSEWAIT
+- octeontx2-pf: Free pending and dropped SQEs
+- selftests: pmtu.sh: fix result checking
+- net: stmmac: xgmac: Enable support for multiple Flexible PPS outputs
+- Fix termination state for idr_for_each_entry_ul()
+- net: r8169: Disable multicast filter for RTL8168H and RTL8107E
+- dccp/tcp: Call security_inet_conn_request() after setting IPv6 addresses.
+- dccp: Call security_inet_conn_request() after setting IPv4 addresses.
+- net: page_pool: add missing free_percpu when page_pool_init fail
+- octeontx2-pf: Fix holes in error code
+- octeontx2-pf: Fix error codes
+- inet: shrink struct flowi_common
+- bpf: Check map->usercnt after timer->timer is assigned
+- rxrpc: Fix two connection reaping bugs
+- tipc: Change nla_policy for bearer-related names to NLA_NUL_STRING
+- hsr: Prevent use after free in prp_create_tagged_frame()
+- llc: verify mac len before reading mac header
+- watchdog: ixp4xx: Make sure restart always works
+- watchdog: marvell_gti_wdt: Fix error code in probe()
+- Input: synaptics-rmi4 - fix use after free in rmi_unregister_function()
+- pwm: brcmstb: Utilize appropriate clock APIs in suspend/resume
+- pwm: sti: Reduce number of allocations and drop usage of chip_data
+- drm/amdgpu: don't put MQDs in VRAM on ARM | ARM64
+- drm/amdgpu/gfx10,11: use memcpy_to/fromio for MQDs
+- regmap: prevent noinc writes from clobbering cache
+- cpupower: fix reference to nonexistent document
+- media: cec: meson: always include meson sub-directory in Makefile
+- media: platform: mtk-mdp3: fix uninitialized variable in mdp_path_config()
+- media: mediatek: vcodec: using encoder device to alloc/free encoder memory
+- media: imx-jpeg: notify source chagne event when the first picture parsed
+- media: mediatek: vcodec: Handle invalid encoder vsi
+- media: verisilicon: Fixes clock list for rk3588 av1 decoder
+- media: dvb-usb-v2: af9035: fix missing unlock
+- media: cadence: csi2rx: Unregister v4l2 async notifier
+- media: i2c: imx219: Drop IMX219_REG_CSI_LANE_MODE from common regs array
+- media: i2c: imx219: Replace register addresses with macros
+- media: i2c: imx219: Convert to CCI register access helpers
+- media: cedrus: Fix clock/reset sequence
+- media: vidtv: mux: Add check and kfree for kstrdup
+- media: vidtv: psi: Add check for kstrdup
+- media: s3c-camif: Avoid inappropriate kfree()
+- media: mtk-jpegenc: Fix bug in JPEG encode quality selection
+- media: amphion: handle firmware debug message
+- media: bttv: fix use after free error due to btv->timeout timer
+- media: ov5640: Fix a memory leak when ov5640_probe fails
+- media: i2c: max9286: Fix some redundant of_node_put() calls
+- media: ov5640: fix vblank unchange issue when work at dvp mode
+- media: ov13b10: Fix some error checking in probe
+- media: verisilicon: Do not enable G2 postproc downscale if source is narrower than destination
+- media: hantro: Check whether reset op is defined before use
+- media: imx-jpeg: initiate a drain of the capture queue in dynamic resolution change
+- pcmcia: ds: fix possible name leak in error path in pcmcia_device_add()
+- pcmcia: ds: fix refcount leak in pcmcia_device_add()
+- pcmcia: cs: fix possible hung task and memory leak pccardd()
+- cxl/hdm: Remove broken error path
+- cxl/port: Fix @host confusion in cxl_dport_setup_regs()
+- cxl/core/regs: Rename @dev to @host in struct cxl_register_map
+- cxl/region: Fix cxl_region_rwsem lock held when returning to user space
+- cxl/region: Use cxl_calc_interleave_pos() for auto-discovery
+- cxl/region: Calculate a target position in a region interleave
+- cxl/region: Prepare the decoder match range helper for reuse
+- rtc: pcf85363: fix wrong mask/val parameters in regmap_update_bits call
+- virt: sevguest: Fix passing a stack buffer as a scatterlist target
+- cxl/mem: Fix shutdown order
+- cxl/memdev: Fix sanitize vs decoder setup locking
+- cxl/pci: Fix sanitize notifier setup
+- cxl/pci: Clarify devm host for memdev relative setup
+- cxl/pci: Remove inconsistent usage of dev_err_probe()
+- cxl/pci: Cleanup 'sanitize' to always poll
+- cxl/pci: Remove unnecessary device reference management in sanitize work
+- rtc: brcmstb-waketimer: support level alarm_irq
+- i3c: Fix potential refcount leak in i3c_master_register_new_i3c_devs
+- rtla: Fix uninitialized variable found
+- 9p/net: fix possible memory leak in p9_check_errors()
+- perf vendor events intel: Add broadwellde two metrics
+- perf vendor events intel: Fix broadwellde tma_info_system_dram_bw_use metric
+- perf hist: Add missing puts to hist__account_cycles
+- libperf rc_check: Make implicit enabling work for GCC
+- perf machine: Avoid out of bounds LBR memory read
+- powerpc/vmcore: Add MMU information to vmcoreinfo
+- usb: host: xhci-plat: fix possible kernel oops while resuming
+- xhci: Loosen RPM as default policy to cover for AMD xHC 1.1
+- perf vendor events: Update PMC used in PM_RUN_INST_CMPL event for power10 platform
+- powerpc/pseries: fix potential memory leak in init_cpu_associativity()
+- powerpc/imc-pmu: Use the correct spinlock initializer.
+- powerpc/vas: Limit open window failure messages in log bufffer
+- perf trace: Use the right bpf_probe_read(_str) variant for reading user data
+- powerpc: Hide empty pt_regs at base of the stack
+- powerpc/xive: Fix endian conversion size
+- powerpc/40x: Remove stale PTE_ATOMIC_UPDATES macro
+- perf tools: Do not ignore the default vmlinux.h
+- modpost: fix ishtp MODULE_DEVICE_TABLE built on big-endian host
+- modpost: fix tee MODULE_DEVICE_TABLE built on big-endian host
+- s390/ap: re-init AP queues on config on
+- perf mem-events: Avoid uninitialized read
+- perf parse-events: Fix for term values that are raw events
+- perf build: Add missing comment about NO_LIBTRACEEVENT=1
+- interconnect: fix error handling in qnoc_probe()
+- powerpc: Only define __parse_fpscr() when required
+- interconnect: qcom: osm-l3: Replace custom implementation of COUNT_ARGS()
+- interconnect: qcom: sm8350: Set ACV enable_mask
+- interconnect: qcom: sm8250: Set ACV enable_mask
+- interconnect: qcom: sm8150: Set ACV enable_mask
+- interconnect: qcom: sm6350: Set ACV enable_mask
+- interconnect: qcom: sdm845: Set ACV enable_mask
+- interconnect: qcom: sdm670: Set ACV enable_mask
+- interconnect: qcom: sc8280xp: Set ACV enable_mask
+- interconnect: qcom: sc8180x: Set ACV enable_mask
+- interconnect: qcom: sc7280: Set ACV enable_mask
+- interconnect: qcom: sc7180: Set ACV enable_mask
+- interconnect: qcom: qdu1000: Set ACV enable_mask
+- f2fs: fix to initialize map.m_pblk in f2fs_precache_extents()
+- dmaengine: pxa_dma: Remove an erroneous BUG_ON() in pxad_free_desc()
+- USB: usbip: fix stub_dev hub disconnect
+- tools: iio: iio_generic_buffer ensure alignment
+- debugfs: Fix __rcu type comparison warning
+- misc: st_core: Do not call kfree_skb() under spin_lock_irqsave()
+- tools/perf: Update call stack check in builtin-lock.c
+- dmaengine: ti: edma: handle irq_of_parse_and_map() errors
+- usb: chipidea: Simplify Tegra DMA alignment code
+- usb: chipidea: Fix DMA overwrite for Tegra
+- usb: dwc2: fix possible NULL pointer dereference caused by driver concurrency
+- dmaengine: idxd: Register dsa_bus_type before registering idxd sub-drivers
+- perf record: Fix BTF type checks in the off-cpu profiling
+- perf vendor events arm64: Fix for AmpereOne metrics
+- pinctrl: renesas: rzg2l: Make reverse order of enable() for disable()
+- livepatch: Fix missing newline character in klp_resolve_symbols()
+- perf parse-events: Fix tracepoint name memory leak
+- tty: tty_jobctrl: fix pid memleak in disassociate_ctty()
+- f2fs: fix to drop meta_inode's page cache in f2fs_put_super()
+- f2fs: compress: fix to avoid redundant compress extension
+- f2fs: compress: fix to avoid use-after-free on dic
+- f2fs: compress: fix deadloop in f2fs_write_cache_pages()
+- perf kwork: Set ordered_events to true in 'struct perf_tool'
+- perf kwork: Add the supported subcommands to the document
+- perf kwork: Fix incorrect and missing free atom in work_push_atom()
+- pinctrl: baytrail: fix debounce disable case
+- iio: frequency: adf4350: Use device managed functions and fix power down issue.
+- perf stat: Fix aggr mode initialization
+- apparmor: fix invalid reference on profile->disconnected
+- scripts/gdb: fix usage of MOD_TEXT not defined when CONFIG_MODULES=n
+- leds: trigger: ledtrig-cpu:: Fix 'output may be truncated' issue for 'cpu'
+- leds: pwm: Don't disable the PWM when the LED should be off
+- leds: turris-omnia: Do not use SMBUS calls
+- mfd: arizona-spi: Set pdata.hpdet_channel for ACPI enumerated devs
+- dt-bindings: mfd: mt6397: Split out compatible for MediaTek MT6366 PMIC
+- mfd: dln2: Fix double put in dln2_probe
+- mfd: core: Ensure disabled devices are skipped without aborting
+- mfd: core: Un-constify mfd_cell.of_reg
+- IB/mlx5: Fix init stage error handling to avoid double free of same QP and UAF
+- erofs: fix erofs_insert_workgroup() lockref usage
+- ASoC: ams-delta.c: use component after check
+- crypto: qat - fix deadlock in backlog processing
+- crypto: qat - fix ring to service map for QAT GEN4
+- crypto: qat - use masks for AE groups
+- crypto: qat - refactor fw config related functions
+- crypto: qat - enable dc chaining service
+- crypto: qat - consolidate services structure
+- certs: Break circular dependency when selftest is modular
+- padata: Fix refcnt handling in padata_free_shell()
+- PCI: endpoint: Fix double free in __pci_epc_create()
+- ASoC: Intel: Skylake: Fix mem leak when parsing UUIDs fails
+- HID: logitech-hidpp: Move get_wireless_feature_index() check to hidpp_connect_event()
+- HID: logitech-hidpp: Revert "Don't restart communication if not necessary"
+- HID: logitech-hidpp: Don't restart IO, instead defer hid_connect() only
+- sh: bios: Revive earlyprintk support
+- HID: uclogic: Fix a work->entry not empty bug in __queue_work()
+- HID: uclogic: Fix user-memory-access bug in uclogic_params_ugee_v2_init_event_hooks()
+- hid: cp2112: Fix IRQ shutdown stopping polling for all IRQs on chip
+- RDMA/hfi1: Workaround truncation compilation error
+- scsi: ufs: core: Leave space for '\0' in utf8 desc string
+- ASoC: fsl: Fix PM disable depth imbalance in fsl_easrc_probe
+- ASoC: intel: sof_sdw: Stop processing CODECs when enough are found
+- ASoC: SOF: core: Ensure sof_ops_free() is still called when probe never ran.
+- RDMA/hns: Fix init failure of RoCE VF and HIP08
+- RDMA/hns: Fix unnecessary port_num transition in HW stats allocation
+- RDMA/hns: The UD mode can only be configured with DCQCN
+- RDMA/hns: Add check for SL
+- RDMA/hns: Fix signed-unsigned mixed comparisons
+- RDMA/hns: Fix uninitialized ucmd in hns_roce_create_qp_common()
+- RDMA/hns: Fix printing level of asynchronous events
+- IB/mlx5: Fix rdma counter binding for RAW QP
+- dlm: fix no ack after final message
+- dlm: be sure we reset all nodes at forced shutdown
+- dlm: fix remove member after close call
+- dlm: fix creating multiple node structures
+- fs: dlm: Fix the size of a buffer in dlm_create_debug_file()
+- ASoC: fsl-asoc-card: Add comment for mclk in the codec_priv
+- ASoC: Intel: sof_sdw_rt_sdca_jack_common: add rt713 support
+- backlight: pwm_bl: Disable PWM on shutdown, suspend and remove
+- ASoC: fsl: mpc5200_dma.c: Fix warning of Function parameter or member not described
+- kselftest: vm: fix mdwe's mmap_FIXED test case
+- ext4: move 'ix' sanity check to corrent position
+- ext4: add missing initialization of call_notify_error in update_super_work()
+- ARM: 9323/1: mm: Fix ARCH_LOW_ADDRESS_LIMIT when CONFIG_ZONE_DMA
+- ARM: 9321/1: memset: cast the constant byte to unsigned char
+- crypto: hisilicon/qm - fix PF queue parameter issue
+- hid: cp2112: Fix duplicate workqueue initialization
+- PCI: vmd: Correct PCI Header Type Register's multi-function check
+- ASoC: SOF: ipc4-topology: Use size_add() in call to struct_size()
+- crypto: qat - increase size of buffers
+- crypto: caam/jr - fix Chacha20 + Poly1305 self test failure
+- crypto: caam/qi2 - fix Chacha20 + Poly1305 self test failure
+- nd_btt: Make BTT lanes preemptible
+- libnvdimm/of_pmem: Use devm_kstrdup instead of kstrdup and check its return value
+- ASoC: soc-pcm.c: Make sure DAI parameters cleared if the DAI becomes inactive
+- scsi: ibmvfc: Fix erroneous use of rtas_busy_delay with hcall return code
+- crypto: qat - fix unregistration of compression algorithms
+- crypto: qat - fix unregistration of crypto algorithms
+- crypto: qat - ignore subsequent state up commands
+- crypto: qat - fix state machines cleanup paths
+- RDMA/core: Use size_{add,sub,mul}() in calls to struct_size()
+- hwrng: geode - fix accessing registers
+- hwrng: bcm2835 - Fix hwrng throughput regression
+- crypto: hisilicon/hpre - Fix a erroneous check after snprintf()
+- crypto: ccp - Fix some unfused tests
+- crypto: ccp - Fix sample application signature passing
+- crypto: ccp - Fix DBC sample application error handling
+- crypto: ccp - Fix ioctl unit tests
+- crypto: ccp - Get a free page to use while fetching initial nonce
+- KEYS: Include linux/errno.h in linux/verification.h
+- ALSA: hda: cs35l41: Undo runtime PM changes at driver exit time
+- ALSA: hda: cs35l41: Fix unbalanced pm_runtime_get()
+- ASoC: cs35l41: Undo runtime PM changes at driver exit time
+- ASoC: cs35l41: Verify PM runtime resume errors in IRQ handler
+- ASoC: cs35l41: Fix broken shared boost activation
+- ASoC: cs35l41: Initialize completion object before requesting IRQ
+- ASoC: cs35l41: Handle mdsync_up reg write errors
+- ASoC: cs35l41: Handle mdsync_down reg write errors
+- module/decompress: use vmalloc() for gzip decompression workspace
+- iommufd: Add iopt_area_alloc()
+- ARM: dts: BCM5301X: Explicitly disable unused switch CPU ports
+- soc: qcom: pmic_glink: fix connector type to be DisplayPort
+- selftests/resctrl: Ensure the benchmark commands fits to its array
+- selftests/pidfd: Fix ksft print formats
+- arm64: tegra: Use correct interrupts for Tegra234 TKE
+- memory: tegra: Set BPMP msg flags to reset IPC channels
+- firmware: tegra: Add suspend hook and reset BPMP IPC early on resume
+- arm64: tegra: Fix P3767 QSPI speed
+- arm64: tegra: Fix P3767 card detect polarity
+- arm64: dts: imx8mn: Add sound-dai-cells to micfil node
+- arm64: dts: imx8mm: Add sound-dai-cells to micfil node
+- arm64: dts: imx8mp-debix-model-a: Remove USB hub reset-gpios
+- arm64: dts: imx8qm-ss-img: Fix jpegenc compatible entry
+- clk: scmi: Free scmi_clk allocated when the clocks with invalid info are skipped
+- ARM: dts: am3517-evm: Fix LED3/4 pinmux
+- firmware: arm_ffa: Allow the FF-A drivers to use 32bit mode of messaging
+- firmware: arm_ffa: Assign the missing IDR allocation ID to the FFA device
+- arm64: dts: ti: Fix HDMI Audio overlay in Makefile
+- arm64: dts: ti: k3-am62a7-sk: Drop i2c-1 to 100Khz
+- arm64: dts: ti: k3-am625-beagleplay: Fix typo in ramoops reg
+- arm64: dts: ti: verdin-am62: disable MIPI DSI bridge
+- arm64: dts: ti: k3-j721s2-evm-gesi: Specify base dtb for overlay file
+- firmware: ti_sci: Mark driver as non removable
+- ARM: dts: stm32: stm32f7-pinctrl: don't use multiple blank lines
+- kunit: test: Fix the possible memory leak in executor_test
+- kunit: Fix possible memory leak in kunit_filter_suites()
+- kunit: Fix the wrong kfree of copy for kunit_filter_suites()
+- kunit: Fix missed memory release in kunit_free_suite_set()
+- soc: qcom: llcc: Handle a second device without data corruption
+- ARM: dts: qcom: mdm9615: populate vsdcc fixed regulator
+- ARM: dts: qcom: apq8026-samsung-matisse-wifi: Fix inverted hall sensor
+- arm64: dts: qcom: apq8016-sbc: Add missing ADV7533 regulators
+- riscv: dts: allwinner: remove address-cells from intc node
+- arm64: dts: qcom: msm8939: Fix iommu local address range
+- arm64: dts: qcom: msm8976: Fix ipc bit shifts
+- ARM64: dts: marvell: cn9310: Use appropriate label for spi1 pins
+- arm64: dts: qcom: sdx75-idp: align RPMh regulator nodes with bindings
+- arm64: dts: qcom: sdm845-mtp: fix WiFi configuration
+- arm64: dts: qcom: sm8350: fix pinctrl for UART18
+- arm64: dts: qcom: sm8150: add ref clock to PCIe PHYs
+- arm64: dts: qcom: sc7280: drop incorrect EUD port on SoC side
+- arm64: dts: qcom: sdm670: Fix pdc mapping
+- arm64: dts: qcom: qrb2210-rb1: Fix regulators
+- arm64: dts: qcom: qrb2210-rb1: Swap UART index
+- arm64: dts: qcom: sc7280: Add missing LMH interrupts
+- arm64: dts: qcom: sm6125: Pad APPS IOMMU address to 8 characters
+- arm64: dts: qcom: msm8992-libra: drop duplicated reserved memory
+- arm64: dts: qcom: msm8916: Fix iommu local address range
+- arm64: dts: qcom: sc7280: link usb3_phy_wrapper_gcc_usb30_pipe_clk
+- arm64: dts: qcom: sdm845: cheza doesn't support LMh node
+- arm64: dts: qcom: sdm845: Fix PSCI power domain names
+- ARM: dts: renesas: blanche: Fix typo in GP_11_2 pin name
+- perf: hisi: Fix use-after-free when register pmu fails
+- drivers/perf: hisi_pcie: Check the type first in pmu::event_init()
+- perf/arm-cmn: Fix DTC domain detection
+- drm/amd/pm: Fix a memory leak on an error path
+- drivers/perf: hisi: use cpuhp_state_remove_instance_nocalls() for hisi_hns3_pmu uninit process
+- drm: mediatek: mtk_dsi: Fix NO_EOT_PACKET settings/handling
+- clocksource/drivers/arm_arch_timer: limit XGene-1 workaround
+- drm/msm/dsi: free TX buffer in unbind
+- drm/msm/dsi: use msm_gem_kernel_put to free TX buffer
+- xen-pciback: Consider INTx disabled when MSI/MSI-X is enabled
+- xen: irqfd: Use _IOW instead of the internal _IOC() macro
+- xen: Make struct privcmd_irqfd's layout architecture independent
+- xenbus: fix error exit in xenbus_init()
+- drm/rockchip: Fix type promotion bug in rockchip_gem_iommu_map()
+- arm64/arm: xen: enlighten: Fix KPTI checks
+- drm/bridge: lt9611uxc: fix the race in the error path
+- gpu: host1x: Correct allocated size for contexts
+- drm/rockchip: cdn-dp: Fix some error handling paths in cdn_dp_probe()
+- drm/msm/a6xx: Fix unknown speedbin case
+- drm/msm/adreno: Fix SM6375 GPU ID
+- accel/habanalabs/gaudi2: Fix incorrect string length computation in gaudi2_psoc_razwi_get_engines()
+- drm/mediatek: Fix iommu fault during crtc enabling
+- drm/mediatek: Fix iommu fault by swapping FBs after updating plane state
+- drm/mediatek: Add mmsys_dev_num to mt8188 vdosys0 driver data
+- io_uring/kbuf: Allow the full buffer id space for provided buffers
+- io_uring/kbuf: Fix check of BID wrapping in provided buffers
+- drm/amd/display: Bail from dm_check_crtc_cursor if no relevant change
+- drm/amd/display: Refactor dm_get_plane_scale helper
+- drm/amd/display: Check all enabled planes in dm_check_crtc_cursor
+- drm/amd/display: Fix null pointer dereference in error message
+- drm/amdkfd: Handle errors from svm validate and map
+- drm/amdkfd: Remove svm range validated_once flag
+- drm/amdkfd: fix some race conditions in vram buffer alloc/free of svm code
+- drm/amdgpu: Increase IH soft ring size for GFX v9.4.3 dGPU
+- drm: Call drm_atomic_helper_shutdown() at shutdown/remove time for misc drivers
+- drm/bridge: tc358768: Fix tc358768_ns_to_cnt()
+- drm/bridge: tc358768: Clean up clock period code
+- drm/bridge: tc358768: Rename dsibclk to hsbyteclk
+- drm/bridge: tc358768: Use dev for dbg prints, not priv->dev
+- drm/bridge: tc358768: Print logical values, not raw register values
+- drm/bridge: tc358768: Use struct videomode
+- drm/bridge: tc358768: Fix bit updates
+- drm/bridge: tc358768: Fix use of uninitialized variable
+- x86/tdx: Zero out the missing RSI in TDX_HYPERCALL macro
+- drm/mediatek: Fix coverity issue with unintentional integer overflow
+- drm/ssd130x: Fix screen clearing
+- drm/bridge: lt8912b: Add missing drm_bridge_attach call
+- drm/bridge: lt8912b: Manually disable HPD only if it was enabled
+- drm/bridge: lt8912b: Fix crash on bridge detach
+- drm/bridge: lt8912b: Fix bridge_detach
+- drm: bridge: it66121: Fix invalid connector dereference
+- drm/radeon: Remove the references of radeon_gem_ pread & pwrite ioctls
+- drm/radeon: possible buffer overflow
+- drm/rockchip: vop2: Add missing call to crtc reset helper
+- drm/rockchip: vop2: Don't crash for invalid duplicate_state
+- drm/rockchip: vop: Fix call to crtc reset helper
+- drm/rockchip: vop: Fix reset of state in duplicate state crtc funcs
+- drm/loongson: Fix error handling in lsdc_pixel_pll_setup()
+- drm: bridge: samsung-dsim: Fix waiting for empty cmd transfer FIFO on older Exynos
+- drm: bridge: for GENERIC_PHY_MIPI_DPHY also select GENERIC_PHY
+- drm: bridge: samsung-dsim: Initialize ULPS EXIT for i.MX8M DSIM
+- spi: omap2-mcspi: Fix hardcoded reference clock
+- spi: omap2-mcspi: switch to use modern name
+- platform/chrome: cros_ec_lpc: Separate host command and irq disable
+- hte: tegra: Fix missing error code in tegra_hte_test_probe()
+- hwmon: (sch5627) Disallow write access if virtual registers are locked
+- hwmon: (sch5627) Use bit macros when accessing the control register
+- hwmon: (pmbus/mp2975) Move PGOOD fix
+- Revert "hwmon: (sch56xx-common) Add automatic module loading on supported devices"
+- Revert "hwmon: (sch56xx-common) Add DMI override table"
+- hwmon: (coretemp) Fix potentially truncated sysfs attribute name
+- hwmon: (axi-fan-control) Fix possible NULL pointer dereference
+- regulator: qcom-rpmh: Fix smps4 regulator for pm8550ve
+- platform/x86: wmi: Fix opening of char device
+- platform/x86: wmi: Fix probe failure when failing to register WMI devices
+- clk: mediatek: fix double free in mtk_clk_register_pllfh()
+- clk: qcom: ipq5332: drop the CLK_SET_RATE_PARENT flag from GPLL clocks
+- clk: qcom: ipq9574: drop the CLK_SET_RATE_PARENT flag from GPLL clocks
+- clk: qcom: ipq5018: drop the CLK_SET_RATE_PARENT flag from GPLL clocks
+- clk: qcom: apss-ipq-pll: Fix 'l' value for ipq5332_pll_config
+- clk: qcom: apss-ipq-pll: Use stromer plus ops for stromer plus pll
+- clk: qcom: clk-alpha-pll: introduce stromer plus ops
+- clk: qcom: config IPQ_APSS_6018 should depend on QCOM_SMEM
+- clk: mediatek: clk-mt2701: Add check for mtk_alloc_clk_data
+- clk: mediatek: clk-mt7629: Add check for mtk_alloc_clk_data
+- clk: mediatek: clk-mt7629-eth: Add check for mtk_alloc_clk_data
+- clk: mediatek: clk-mt6797: Add check for mtk_alloc_clk_data
+- clk: mediatek: clk-mt6779: Add check for mtk_alloc_clk_data
+- clk: mediatek: clk-mt6765: Add check for mtk_alloc_clk_data
+- clk: npcm7xx: Fix incorrect kfree
+- clk: ti: fix double free in of_ti_divider_clk_setup()
+- clk: keystone: pll: fix a couple NULL vs IS_ERR() checks
+- clk: ralink: mtmips: quiet unused variable warning
+- spi: nxp-fspi: use the correct ioremap function
+- clk: linux/clk-provider.h: fix kernel-doc warnings and typos
+- clk: renesas: rzg2l: Fix computation formula
+- clk: renesas: rzg2l: Use FIELD_GET() for PLL register fields
+- clk: renesas: rzg2l: Trust value returned by hardware
+- clk: renesas: rzg2l: Lock around writes to mux register
+- clk: renesas: rzg2l: Wait for status bit of SD mux before continuing
+- clk: renesas: rcar-gen3: Extend SDnH divider table
+- clk: imx: imx8qxp: Fix elcdif_pll clock
+- clk: imx: imx8mq: correct error handling path
+- clk: imx: imx8: Fix an error handling path in imx8_acm_clk_probe()
+- clk: imx: imx8: Fix an error handling path if devm_clk_hw_register_mux_parent_data_table() fails
+- clk: imx: imx8: Fix an error handling path in clk_imx_acm_attach_pm_domains()
+- clk: imx: Select MXC_CLK for CLK_IMX8QXP
+- regulator: mt6358: Fail probe on unknown chip ID
+- gpio: sim: initialize a managed pointer when declaring it
+- clk: qcom: gcc-sm8150: Fix gcc_sdcc2_apps_clk_src
+- clk: qcom: mmcc-msm8998: Fix the SMMU GDSC
+- clk: qcom: mmcc-msm8998: Don't check halt bit on some branch clks
+- clk: qcom: clk-rcg2: Fix clock rate overflow for high parent frequencies
+- clk: qcom: gcc-msm8996: Remove RPM bus clocks
+- clk: qcom: ipq5332: Drop set rate parent from gpll0 dependent clocks
+- spi: tegra: Fix missing IRQ check in tegra_slink_probe()
+- regmap: debugfs: Fix a erroneous check after snprintf()
+- ipvlan: properly track tx_errors
+- net: add DEV_STATS_READ() helper
+- virtio_net: use u64_stats_t infra to avoid data-races
+- ipv6: avoid atomic fragment on GSO packets
+- mptcp: properly account fastopen data
+- ACPI: sysfs: Fix create_pnp_modalias() and create_of_modalias()
+- bpf: Fix unnecessary -EBUSY from htab_lock_bucket
+- Bluetooth: hci_sync: Fix Opcode prints in bt_dev_dbg/err
+- Bluetooth: Make handle of hci_conn be unique
+- Bluetooth: ISO: Pass BIG encryption info through QoS
+- wifi: iwlwifi: empty overflow queue during flush
+- wifi: iwlwifi: mvm: update IGTK in mvmvif upon D3 resume
+- wifi: iwlwifi: pcie: synchronize IRQs before NAPI
+- wifi: iwlwifi: mvm: fix netif csum flags
+- wifi: iwlwifi: increase number of RX buffers for EHT devices
+- wifi: iwlwifi: mvm: remove TDLS stations from FW
+- wifi: iwlwifi: mvm: fix iwl_mvm_mac_flush_sta()
+- wifi: iwlwifi: mvm: change iwl_mvm_flush_sta() API
+- wifi: iwlwifi: mvm: Don't always bind/link the P2P Device interface
+- wifi: iwlwifi: mvm: Fix key flags for IGTK on AP interface
+- wifi: iwlwifi: mvm: Correctly set link configuration
+- wifi: iwlwifi: yoyo: swap cdb and jacket bits values
+- wifi: mac80211: Fix setting vif links
+- wifi: mac80211: don't recreate driver link debugfs in reconfig
+- wifi: iwlwifi: mvm: use correct sta ID for IGTK/BIGTK
+- wifi: iwlwifi: mvm: fix removing pasn station for responder
+- wifi: iwlwifi: mvm: update station's MFP flag after association
+- tcp: fix cookie_init_timestamp() overflows
+- chtls: fix tp->rcv_tstamp initialization
+- thermal: core: Don't update trip points inside the hysteresis range
+- selftests/bpf: Make linked_list failure test more robust
+- net: skb_find_text: Ignore patterns extending past 'to'
+- bpf: Fix missed rcu read lock in bpf_task_under_cgroup()
+- thermal/drivers/mediatek: Fix probe for THERMAL_V2
+- r8169: fix rare issue with broken rx after link-down on RTL8125
+- thermal: core: prevent potential string overflow
+- wifi: rtw88: Remove duplicate NULL check before calling usb_kill/free_urb()
+- virtio-net: fix the vq coalescing setting for vq resize
+- virtio-net: fix per queue coalescing parameter setting
+- virtio-net: consistently save parameters for per-queue
+- virtio-net: fix mismatch of getting tx-frames
+- netfilter: nf_tables: Drop pointless memset when dumping rules
+- wifi: wfx: fix case where rates are out of order
+- PM / devfreq: rockchip-dfi: Make pmu regmap mandatory
+- can: dev: can_put_echo_skb(): don't crash kernel if can_priv::echo_skb is accessed out of bounds
+- can: dev: can_restart(): fix race condition between controller restart and netif_carrier_on()
+- can: dev: can_restart(): don't crash kernel if carrier is OK
+- wifi: ath11k: fix Tx power value during active CAC
+- r8152: break the loop when the budget is exhausted
+- selftests/bpf: Define SYS_NANOSLEEP_KPROBE_NAME for riscv
+- selftests/bpf: Define SYS_PREFIX for riscv
+- libbpf: Fix syscall access arguments on riscv
+- can: etas_es58x: add missing a blank line after declaration
+- can: etas_es58x: rework the version check logic to silence -Wformat-truncation
+- ACPI: video: Add acpi_backlight=vendor quirk for Toshiba Portégé R100
+- ACPI: property: Allow _DSD buffer data only for byte accessors
+- wifi: rtlwifi: fix EDCA limit set by BT coexistence
+- tcp_metrics: do not create an entry from tcp_init_metrics()
+- tcp_metrics: properly set tp->snd_ssthresh in tcp_init_metrics()
+- tcp_metrics: add missing barriers on delete
+- wifi: ath: dfs_pattern_detector: Fix a memory initialization issue
+- wifi: mt76: mt7921: fix the wrong rate selected in fw for the chanctx driver
+- wifi: mt76: mt7921: fix the wrong rate pickup for the chanctx driver
+- wifi: mt76: move struct ieee80211_chanctx_conf up to struct mt76_vif
+- wifi: mt76: mt7915: fix beamforming availability check
+- wifi: mt76: fix per-band IEEE80211_CONF_MONITOR flag comparison
+- wifi: mt76: get rid of false alamrs of tx emission issues
+- wifi: mt76: fix potential memory leak of beacon commands
+- wifi: mt76: update beacon size limitation
+- wifi: mt76: mt7996: fix TWT command format
+- wifi: mt76: mt7996: fix rx rate report for CBW320-2
+- wifi: mt76: mt7996: fix wmm queue mapping
+- wifi: mt76: mt7996: fix beamformee ss subfield in EHT PHY cap
+- wifi: mt76: mt7996: fix beamform mcu cmd configuration
+- wifi: mt76: mt7996: set correct wcid in txp
+- wifi: mt76: remove unused error path in mt76_connac_tx_complete_skb
+- wifi: mt76: mt7603: improve stuck beacon handling
+- wifi: mt76: mt7603: improve watchdog reset reliablity
+- wifi: mt76: mt7603: rework/fix rx pse hang check
+- cpufreq: tegra194: fix warning due to missing opp_put
+- PM: sleep: Fix symbol export for _SIMPLE_ variants of _PM_OPS()
+- wifi: mac80211: fix check for unusable RX result
+- wifi: ath11k: fix boot failure with one MSI vector
+- wifi: ath12k: fix DMA unmap warning on NULL DMA address
+- wifi: rtw88: debug: Fix the NULL vs IS_ERR() bug for debugfs_create_file()
+- net: ethernet: mtk_wed: fix EXT_INT_STATUS_RX_FBUF definitions for MT7986 SoC
+- ice: fix pin assignment for E810-T without SMA control
+- net: spider_net: Use size_add() in call to struct_size()
+- tipc: Use size_add() in calls to struct_size()
+- tls: Use size_add() in call to struct_size()
+- mlxsw: Use size_mul() in call to struct_size()
+- gve: Use size_add() in call to struct_size()
+- bpf: Fix kfunc callback register type handling
+- tcp: call tcp_try_undo_recovery when an RTOd TFO SYNACK is ACKed
+- selftests/bpf: Skip module_fentry_shadow test when bpf_testmod is not available
+- udplite: fix various data-races
+- udplite: remove UDPLITE_BIT
+- udp: annotate data-races around udp->encap_type
+- udp: lockless UDP_ENCAP_L2TPINUDP / UDP_GRO
+- udp: move udp->accept_udp_{l4|fraglist} to udp->udp_flags
+- udp: add missing WRITE_ONCE() around up->encap_rcv
+- udp: move udp->gro_enabled to udp->udp_flags
+- udp: move udp->no_check6_rx to udp->udp_flags
+- udp: move udp->no_check6_tx to udp->udp_flags
+- udp: introduce udp->udp_flags
+- wifi: cfg80211: fix kernel-doc for wiphy_delayed_work_flush()
+- bpf, x64: Fix tailcall infinite loop
+- selftests/bpf: Correct map_fd to data_fd in tailcalls
+- iavf: Fix promiscuous mode configuration flow messages
+- i40e: fix potential memory leaks in i40e_remove()
+- wifi: iwlwifi: don't use an uninitialized variable
+- wifi: iwlwifi: honor the enable_ini value
+- wifi: mac80211: fix # of MSDU in A-MSDU calculation
+- wifi: cfg80211: fix off-by-one in element defrag
+- wifi: mac80211: fix RCU usage warning in mesh fast-xmit
+- wifi: mac80211: move sched-scan stop work to wiphy work
+- wifi: mac80211: move offchannel works to wiphy work
+- wifi: mac80211: move scan work to wiphy work
+- wifi: mac80211: move radar detect work to wiphy work
+- wifi: cfg80211: add flush functions for wiphy work
+- wifi: ath12k: fix undefined behavior with __fls in dp
+- irqchip/sifive-plic: Fix syscore registration for multi-socket systems
+- genirq/matrix: Exclude managed interrupts in irq_matrix_allocated()
+- string: Adjust strtomem() logic to allow for smaller sources
+- PCI/MSI: Provide stubs for IMS functions
+- selftests/x86/lam: Zero out buffer for readlink()
+- perf: Optimize perf_cgroup_switch()
+- pstore/platform: Add check for kstrdup
+- x86/nmi: Fix out-of-order NMI nesting checks & false positive warning
+- drivers/clocksource/timer-ti-dm: Don't call clk_get_rate() in stop function
+- srcu: Fix callbacks acceleration mishandling
+- x86/apic: Fake primary thread mask for XEN/PV
+- cpu/SMT: Make SMT control more robust against enumeration failures
+- x86/boot: Fix incorrect startup_gdt_descr.size
+- x86/sev-es: Allow copy_from_kernel_nofault() in earlier boot
+- cgroup/cpuset: Fix load balance state in update_partition_sd_lb()
+- ACPI/NUMA: Apply SRAT proximity domain to entire CFMWS window
+- x86/numa: Introduce numa_fill_memblks()
+- futex: Don't include process MM in futex key on no-MMU
+- x86/srso: Fix unret validation dependencies
+- x86/srso: Fix vulnerability reporting for missing microcode
+- x86/srso: Print mitigation for retbleed IBPB case
+- x86/srso: Fix SBPB enablement for (possible) future fixed HW
+- writeback, cgroup: switch inodes with dirty timestamps to release dying cgwbs
+- vfs: fix readahead(2) on block devices
+- nfsd: Handle EOPENSTALE correctly in the filecache
+- sched: Fix stop_one_cpu_nowait() vs hotplug
+- objtool: Propagate early errors
+- sched/uclamp: Ignore (util == 0) optimization in feec() when p_util_max = 0
+- sched/uclamp: Set max_spare_cap_cpu even if max_spare_cap is 0
+- iov_iter, x86: Be consistent about the __user tag on copy_mc_to_user()
+- sched/fair: Fix cfs_rq_is_decayed() on !SMP
+- sched/topology: Fix sched_numa_find_nth_cpu() in non-NUMA case
+- sched/topology: Fix sched_numa_find_nth_cpu() in CPU-less case
+- numa: Generalize numa_map_to_online_node()
+- hwmon: (nct6775) Fix incorrect variable reuse in fan_div calculation
+- !2933 Backport linux 6.6.1 LTS patches
+- ASoC: SOF: sof-pci-dev: Fix community key quirk detection
+- ALSA: hda: intel-dsp-config: Fix JSL Chromebook quirk detection
+- serial: core: Fix runtime PM handling for pending tx
+- misc: pci_endpoint_test: Add deviceID for J721S2 PCIe EP device support
+- dt-bindings: serial: rs485: Add rs485-rts-active-high
+- tty: 8250: Add Brainboxes Oxford Semiconductor-based quirks
+- tty: 8250: Add support for Intashield IX cards
+- tty: 8250: Add support for additional Brainboxes PX cards
+- tty: 8250: Fix up PX-803/PX-857
+- tty: 8250: Fix port count of PX-257
+- tty: 8250: Add support for Intashield IS-100
+- tty: 8250: Add support for Brainboxes UP cards
+- tty: 8250: Add support for additional Brainboxes UC cards
+- tty: 8250: Remove UC-257 and UC-431
+- tty: n_gsm: fix race condition in status line change on dead connections
+- Bluetooth: hci_bcm4377: Mark bcm4378/bcm4387 as BROKEN_LE_CODED
+- usb: raw-gadget: properly handle interrupted requests
+- usb: typec: tcpm: Fix NULL pointer dereference in tcpm_pd_svdm()
+- usb: typec: tcpm: Add additional checks for contaminant
+- usb: storage: set 1.50 as the lower bcdDevice for older "Super Top" compatibility
+- PCI: Prevent xHCI driver from claiming AMD VanGogh USB3 DRD device
+- ALSA: usb-audio: add quirk flag to enable native DSD for McIntosh devices
+- eventfs: Use simple_recursive_removal() to clean up dentries
+- eventfs: Delete eventfs_inode when the last dentry is freed
+- eventfs: Save ownership and mode
+- eventfs: Remove "is_freed" union with rcu head
+- tracing: Have trace_event_file have ref counters
+- perf evlist: Avoid frequency mode for the dummy event
+- power: supply: core: Use blocking_notifier_call_chain to avoid RCU complaint
+- drm/amd/display: Don't use fsleep for PSR exit waits
+- !2927 dm ioctl: add DMINFO() to track dm device create/remove
+- dm ioctl: add DMINFO() to track dm device create/remove
+- !2900 Add initial openeuler_defconfig for arm64 and x86
+- config: add initial openeuler_defconfig for x86
+- config: add initial openeuler_defconfig for arm64
+- kconfig: Add script to check & update openeuler_defconfig
+- init from linux v6.6
diff --git a/mkgrub-menu-aarch64.sh b/mkgrub-menu-aarch64.sh
new file mode 100644
index 0000000..5a58218
--- /dev/null
+++ b/mkgrub-menu-aarch64.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+#This script is used for creating a new grub menu item when update kernel.
+#It uses the new version-number as the id and display.
+
+NEW_KERN_VERSION=$1
+GRUB_CFG=$2
+OP_TYPE=$3
+
+#########################################################
+# Description: SetupOS_Initrd_for_softraid
+# Input none
+# Return: 0: SUCCESS
+# 1: Internal Error.
+#########################################################
+function SoftRaid_Initrd()
+{
+ SI_INITRD=initramfs-${NEW_KERN_VERSION}.img
+ mkdir -p /initramfs/usr/lib/systemd/system
+ mkdir -p /initramfs/etc/systemd/system/default.target.wants
+ mdadm --detail --scan >> /initramfs/etc/mdadm.conf
+
+ cd /initramfs
+ cat <<EOF > /initramfs/usr/lib/systemd/assemble-md
+#!/bin/bash
+declare -i count=5
+if [ -f /etc/mdadm.conf ];then
+ while (( count > 0 )) ;
+ do
+ sleep 10s
+ let count--;
+ if [ -e "/dev/sda1" ];then
+ mdadm -A -s
+ break;
+ fi
+ echo " waiting harddisk get online .... countdown ${count} "
+ done
+fi
+EOF
+ if [ $? -ne 0 ];then
+ g_Log_Error "generate assemble-md failed"
+ return 1
+ fi
+ chmod -R 755 /initramfs/usr/lib/systemd/assemble-md
+ cat << EOF > /initramfs/usr/lib/systemd/system/assemble-md.service
+[Unit]
+Description=assemble the md
+DefaultDependencies=no
+After=local-fs-pre.target systemd-udev-trigger.service systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket
+Before=local-fs.target diskconf-reload.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=/usr/lib/systemd/assemble-md
+StandardOutput=journal+console
+
+[Install]
+WantedBy=default.target
+EOF
+ if [ $? -ne 0 ];then
+ g_Log_Error "generate assemble-md.service failed"
+ return 1
+ fi
+
+ cp /initramfs/usr/lib/systemd/system/assemble-md.service /initramfs/etc/systemd/system/default.target.wants/
+ dracut --force --include /initramfs / /boot/${SI_INITRD} ${NEW_KERN_VERSION}
+ rm -r /initramfs
+ cd -
+}
+
+if [ "x${NEW_KERN_VERSION}" == "x" ] || [ "x${GRUB_CFG}" == "x" ] || [ "x${OP_TYPE}" == "x" ] ; then
+ echo "There some mkgrub-menu parameter is null,please check "
+ exit 1;
+fi
+
+if [ "update" = "${OP_TYPE}" ]; then
+
+DEF_VER=`grep -nr "default=" $GRUB_CFG|awk -F = '{print $2}'` ;
+START_LN=`grep -nr " --id ${DEF_VER}" $GRUB_CFG|awk -F: '{print $1}'` ;
+/bin/sed -rn "p;${START_LN},/}/H;$ {g;s/^\n//;p}" $GRUB_CFG > tempfile ;
+/bin/sed -i "$[START_LN+5],/ --id ${DEF_VER}/{s/ --id ${DEF_VER}/ --id linux-${NEW_KERN_VERSION}/}" tempfile ;
+OLDLABLE=`sed -n "$[START_LN+5],/ --id ${DEF_VER}/p" tempfile |grep menuentry |tail -1 |awk '{print $2}' |sed "s/\"//g" `
+/bin/sed -i "$[START_LN+5],/ --id ${DEF_VER}/{s/${OLDLABLE}/EulerOS-${NEW_KERN_VERSION}/}" tempfile ;
+/bin/sed -i "/ --id linux-${NEW_KERN_VERSION}/,/}/{s/`uname -r`/${NEW_KERN_VERSION}/} " tempfile ;
+/bin/sed -i "s/default=${DEF_VER}/default=linux-${NEW_KERN_VERSION}/" tempfile ;
+mv tempfile $GRUB_CFG
+
+if [ `cat /proc/mdstat |wc -l ` -gt 2 ]; then
+ SoftRaid_Initrd > /dev/null 2>&1
+fi
+
+fi
+
+if [ "remove" = "${OP_TYPE}" ]; then
+ /bin/sed -i "/ --id linux-${NEW_KERN_VERSION}/,/}/d" $GRUB_CFG
+ DEF_VER=`grep -nr "menuentry" $GRUB_CFG |head -1 |awk '{print $4}' |sed "s/{//g" `
+ /bin/sed -i "s/default=linux-${NEW_KERN_VERSION}/default=${DEF_VER}/" $GRUB_CFG
+fi
diff --git a/sign-modules b/sign-modules
new file mode 100644
index 0000000..020905f
--- /dev/null
+++ b/sign-modules
@@ -0,0 +1,25 @@
+#! /bin/bash
+
+moddir=$1
+
+modules=`find $moddir -name *.ko`
+
+MODSECKEY="./signing_key.pem"
+MODPUBKEY="./signing_key.x509"
+
+for mod in $modules
+do
+ dir=`dirname $mod`
+ file=`basename $mod`
+
+ ./scripts/sign-file sha256 ${MODSECKEY} ${MODPUBKEY} ${dir}/${file}
+ rm -f ${dir}/${file}.{sig,dig}
+done
+
+RANDOMMOD=$(find $moddir -type f -name '*.ko' | sort -R | tail -n 1)
+if [ "~Module signature appended~" != "$(tail -c 28 $RANDOMMOD)" ]; then
+ echo "*** Modules are unsigned! ***"
+ exit 1
+fi
+
+exit 0
diff --git a/sources b/sources
new file mode 100644
index 0000000..e0a28d5
--- /dev/null
+++ b/sources
@@ -0,0 +1,2 @@
+d41d8cd98f00b204e9800998ecf8427e extra_certificates
+d849db48ec85ad2064eb3dab5dbccd7a kernel.tar.xz
diff --git a/x509.genkey b/x509.genkey
new file mode 100644
index 0000000..31cd75c
--- /dev/null
+++ b/x509.genkey
@@ -0,0 +1,16 @@
+[ req ]
+default_bits = 4096
+distinguished_name = req_distinguished_name
+prompt = no
+x509_extensions = myexts
+
+[ req_distinguished_name ]
+O = openEuler
+CN = openEuler kernel signing key
+emailAddress = kernel@openeuler.org
+
+[ myexts ]
+basicConstraints=critical,CA:FALSE
+keyUsage=digitalSignature
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid