forked from Mirrors/opensbi
Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afc24152bb | ||
|
|
dffa24b7f5 | ||
|
|
6a20872c91 | ||
|
|
d65c1e95a7 | ||
|
|
51fe6a8bc9 | ||
|
|
1f9677582a | ||
|
|
126c9d34d2 | ||
|
|
b8b26fe121 | ||
|
|
f71bb323f4 | ||
|
|
ec51e91eaa | ||
|
|
35aece218a | ||
|
|
de376252f4 | ||
|
|
4997eb28da | ||
|
|
825d0e918a | ||
|
|
d28e2fa9cc | ||
|
|
c9f856e23f | ||
|
|
da05980de6 | ||
|
|
c75f468ad5 | ||
|
|
fade4399d2 | ||
|
|
976a6a8612 | ||
|
|
2e9dc3b430 | ||
|
|
5de1d3240f | ||
|
|
38a6106b10 | ||
|
|
e8dfa55f3d | ||
|
|
834d0d9f26 | ||
|
|
a28e51016e | ||
|
|
fa911ebe72 | ||
|
|
0250db4dad | ||
|
|
b210376fe2 | ||
|
|
631efeeb49 | ||
|
|
b34caeef81 | ||
|
|
34657b377f | ||
|
|
90c3b94094 | ||
|
|
667eed2266 | ||
|
|
32c1d38dcf | ||
|
|
37b72cb575 | ||
|
|
ab23d8a392 | ||
|
|
8f8c393155 | ||
|
|
1514a32730 | ||
|
|
94f0f84656 | ||
|
|
c2d2b9140a | ||
|
|
64904e5d5c | ||
|
|
8752c809b3 | ||
|
|
ce4dc7649e | ||
|
|
8ea972838c | ||
|
|
d6b684ec86 | ||
|
|
1207c7568f | ||
|
|
ac16c6b604 | ||
|
|
63aacbd782 | ||
|
|
1db95da299 | ||
|
|
55296fd27c | ||
|
|
3990c8ee07 | ||
|
|
ca380bcb10 | ||
|
|
fb70fe8b98 | ||
|
|
1f84ec2ac2 | ||
|
|
e3eb59a396 | ||
|
|
38c31ffb8f | ||
|
|
f7d060c26a | ||
|
|
5de8c1d499 | ||
|
|
040f3100a9 | ||
|
|
8408845cc9 | ||
|
|
944db4eced | ||
|
|
d9afef57b7 | ||
|
|
f04ae48263 | ||
|
|
55135abcd5 | ||
|
|
cb70dffa0a | ||
|
|
85f22b38c8 | ||
|
|
ee92afa638 | ||
|
|
17b8d1900d | ||
|
|
153cdeea53 | ||
|
|
8dcd1448e7 | ||
|
|
64a38525e6 | ||
|
|
1ffbd063c4 | ||
|
|
6a1f53bc2d | ||
|
|
4b687e3669 | ||
|
|
6068efc7f5 | ||
|
|
bbe9a23060 | ||
|
|
525ac970b3 | ||
|
|
3204d74486 |
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
# See here for more information about the format and editor support:
|
# See here for more information about the format and editor support:
|
||||||
# https://editorconfig.org/
|
# https://editorconfig.org/
|
||||||
|
|
||||||
|
|||||||
12
Makefile
12
Makefile
@@ -151,6 +151,12 @@ endif
|
|||||||
|
|
||||||
# Guess the compiler's XLEN
|
# Guess the compiler's XLEN
|
||||||
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) $(CLANG_TARGET) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
|
OPENSBI_CC_XLEN := $(shell TMP=`$(CC) $(CLANG_TARGET) -dumpmachine | sed 's/riscv\([0-9][0-9]\).*/\1/'`; echo $${TMP})
|
||||||
|
# If guessing XLEN fails, default to 64
|
||||||
|
ifneq ($(OPENSBI_CC_XLEN),32)
|
||||||
|
ifneq ($(OPENSBI_CC_XLEN),64)
|
||||||
|
OPENSBI_CC_XLEN = 64
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# Guess the compiler's ABI and ISA
|
# Guess the compiler's ABI and ISA
|
||||||
ifneq ($(CC_IS_CLANG),y)
|
ifneq ($(CC_IS_CLANG),y)
|
||||||
@@ -374,6 +380,7 @@ GENFLAGS += $(firmware-genflags-y)
|
|||||||
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -ffunction-sections -fdata-sections
|
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-stack-protector -fno-strict-aliasing -ffunction-sections -fdata-sections
|
||||||
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||||
CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
|
CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
|
||||||
|
CFLAGS += -std=gnu11
|
||||||
CFLAGS += $(REPRODUCIBLE_FLAGS)
|
CFLAGS += $(REPRODUCIBLE_FLAGS)
|
||||||
# Optionally supported flags
|
# Optionally supported flags
|
||||||
ifeq ($(CC_SUPPORT_VECTOR),y)
|
ifeq ($(CC_SUPPORT_VECTOR),y)
|
||||||
@@ -444,11 +451,14 @@ DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assemble
|
|||||||
|
|
||||||
ifneq ($(DEBUG),)
|
ifneq ($(DEBUG),)
|
||||||
CFLAGS += -O0
|
CFLAGS += -O0
|
||||||
ELFFLAGS += -Wl,--print-gc-sections
|
|
||||||
else
|
else
|
||||||
CFLAGS += -O2
|
CFLAGS += -O2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(V), 1)
|
||||||
|
ELFFLAGS += -Wl,--print-gc-sections
|
||||||
|
endif
|
||||||
|
|
||||||
# Setup functions for compilation
|
# Setup functions for compilation
|
||||||
define dynamic_flags
|
define dynamic_flags
|
||||||
-I$(shell dirname $(2)) -D__OBJNAME__=$(subst -,_,$(shell basename $(1) .o))
|
-I$(shell dirname $(2)) -D__OBJNAME__=$(subst -,_,$(shell basename $(1) .o))
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ The FPGA SoC currently contains the following peripherals:
|
|||||||
- Bootrom containing zero stage bootloader and device tree.
|
- Bootrom containing zero stage bootloader and device tree.
|
||||||
|
|
||||||
To build platform specific library and firmwares, provide the
|
To build platform specific library and firmwares, provide the
|
||||||
*PLATFORM=fpga/ariane* parameter to the top level `make` command.
|
*PLATFORM=generic* parameter to the top level `make` command.
|
||||||
|
|
||||||
Platform Options
|
Platform Options
|
||||||
----------------
|
----------------
|
||||||
@@ -26,7 +26,7 @@ Building Ariane FPGA Platform
|
|||||||
**Linux Kernel Payload**
|
**Linux Kernel Payload**
|
||||||
|
|
||||||
```
|
```
|
||||||
make PLATFORM=fpga/ariane FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||||
```
|
```
|
||||||
|
|
||||||
Booting Ariane FPGA Platform
|
Booting Ariane FPGA Platform
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ processor from ETH Zurich. To this end, Ariane has been equipped with a
|
|||||||
different L1 cache subsystem that follows a write-through protocol and that has
|
different L1 cache subsystem that follows a write-through protocol and that has
|
||||||
support for cache invalidations and atomics.
|
support for cache invalidations and atomics.
|
||||||
|
|
||||||
To build platform specific library and firmwares, provide the
|
To build platform specific library and firmwares, provide the *PLATFORM=generic*
|
||||||
*PLATFORM=fpga/openpiton* parameter to the top level `make` command.
|
parameter to the top level `make` command.
|
||||||
|
|
||||||
Platform Options
|
Platform Options
|
||||||
----------------
|
----------------
|
||||||
@@ -21,7 +21,7 @@ Building Ariane FPGA Platform
|
|||||||
**Linux Kernel Payload**
|
**Linux Kernel Payload**
|
||||||
|
|
||||||
```
|
```
|
||||||
make PLATFORM=fpga/openpiton FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||||
```
|
```
|
||||||
|
|
||||||
Booting Ariane FPGA Platform
|
Booting Ariane FPGA Platform
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ RISC-V Platforms Using Generic Platform
|
|||||||
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
|
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
|
||||||
* **Spike** (*[spike.md]*)
|
* **Spike** (*[spike.md]*)
|
||||||
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
|
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
|
||||||
|
* **OpenPiton FPGA SoC** (*[fpga-openpiton.md]*)
|
||||||
|
* **Ariane FPGA SoC** (*[fpga-ariane.md]*)
|
||||||
|
|
||||||
[andes-ae350.md]: andes-ae350.md
|
[andes-ae350.md]: andes-ae350.md
|
||||||
[qemu_virt.md]: qemu_virt.md
|
[qemu_virt.md]: qemu_virt.md
|
||||||
@@ -55,3 +57,5 @@ RISC-V Platforms Using Generic Platform
|
|||||||
[sifive_fu540.md]: sifive_fu540.md
|
[sifive_fu540.md]: sifive_fu540.md
|
||||||
[spike.md]: spike.md
|
[spike.md]: spike.md
|
||||||
[thead-c9xx.md]: thead-c9xx.md
|
[thead-c9xx.md]: thead-c9xx.md
|
||||||
|
[fpga-openpiton.md]: fpga-openpiton.md
|
||||||
|
[fpga-ariane.md]: fpga-ariane.md
|
||||||
|
|||||||
@@ -21,20 +21,12 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
|||||||
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
|
* **Kendryte K210 SoC**: Platform support for the Kendryte K210 SoC used on
|
||||||
boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
|
boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
|
||||||
|
|
||||||
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
|
|
||||||
Genesys 2 board. More details on this platform can be found in the file
|
|
||||||
*[fpga-ariane.md]*.
|
|
||||||
|
|
||||||
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
|
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
|
||||||
details on this platform can be found in the file *[andes-ae350.md]*.
|
details on this platform can be found in the file *[andes-ae350.md]*.
|
||||||
|
|
||||||
* **Spike**: Platform support for the Spike emulator. More
|
* **Spike**: Platform support for the Spike emulator. More
|
||||||
details on this platform can be found in the file *[spike.md]*.
|
details on this platform can be found in the file *[spike.md]*.
|
||||||
|
|
||||||
* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based
|
|
||||||
on ariane core. More details on this platform can be found in the file
|
|
||||||
*[fpga-openpiton.md]*.
|
|
||||||
|
|
||||||
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
|
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
|
||||||
processor based SOCs. More details on this platform can be found in the
|
processor based SOCs. More details on this platform can be found in the
|
||||||
file *[shakti_cclass.md]*.
|
file *[shakti_cclass.md]*.
|
||||||
@@ -52,10 +44,8 @@ comments to facilitate the implementation.
|
|||||||
[generic.md]: generic.md
|
[generic.md]: generic.md
|
||||||
[qemu_virt.md]: qemu_virt.md
|
[qemu_virt.md]: qemu_virt.md
|
||||||
[sifive_fu540.md]: sifive_fu540.md
|
[sifive_fu540.md]: sifive_fu540.md
|
||||||
[fpga-ariane.md]: fpga-ariane.md
|
|
||||||
[andes-ae350.md]: andes-ae350.md
|
[andes-ae350.md]: andes-ae350.md
|
||||||
[thead-c910.md]: thead-c910.md
|
[thead-c910.md]: thead-c910.md
|
||||||
[spike.md]: spike.md
|
[spike.md]: spike.md
|
||||||
[fpga-openpiton.md]: fpga-openpiton.md
|
|
||||||
[shakti_cclass.md]: shakti_cclass.md
|
[shakti_cclass.md]: shakti_cclass.md
|
||||||
[renesas-rzfive.md]: renesas-rzfive.md
|
[renesas-rzfive.md]: renesas-rzfive.md
|
||||||
|
|||||||
@@ -122,6 +122,50 @@ enum {
|
|||||||
RV_DBTR_DECLARE_BIT_MASK(MC, TYPE, 4),
|
RV_DBTR_DECLARE_BIT_MASK(MC, TYPE, 4),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ICOUNT - Match Control Type Register */
|
||||||
|
enum {
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, ACTION, 0),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, U, 6),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, S, 7),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, PENDING, 8),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, M, 9),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, COUNT, 10),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, HIT, 24),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, VU, 25),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, VS, 26),
|
||||||
|
#if __riscv_xlen == 64
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, DMODE, 59),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, TYPE, 60),
|
||||||
|
#elif __riscv_xlen == 32
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, DMODE, 27),
|
||||||
|
RV_DBTR_DECLARE_BIT(ICOUNT, TYPE, 28),
|
||||||
|
#else
|
||||||
|
#error "Unknown __riscv_xlen"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, ACTION, 6),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, U, 1),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, S, 1),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, PENDING, 1),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, M, 1),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, COUNT, 14),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, HIT, 1),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, VU, 1),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, VS, 1),
|
||||||
|
#if __riscv_xlen == 64
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, DMODE, 1),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, TYPE, 4),
|
||||||
|
#elif __riscv_xlen == 32
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, DMODE, 1),
|
||||||
|
RV_DBTR_DECLARE_BIT_MASK(ICOUNT, TYPE, 4),
|
||||||
|
#else
|
||||||
|
#error "Unknown __riscv_xlen"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/* MC6 - Match Control 6 Type Register */
|
/* MC6 - Match Control 6 Type Register */
|
||||||
enum {
|
enum {
|
||||||
RV_DBTR_DECLARE_BIT(MC6, LOAD, 0),
|
RV_DBTR_DECLARE_BIT(MC6, LOAD, 0),
|
||||||
|
|||||||
@@ -378,6 +378,9 @@
|
|||||||
#define CSR_SSTATEEN2 0x10E
|
#define CSR_SSTATEEN2 0x10E
|
||||||
#define CSR_SSTATEEN3 0x10F
|
#define CSR_SSTATEEN3 0x10F
|
||||||
|
|
||||||
|
/* Supervisor Resource Management Configuration CSRs */
|
||||||
|
#define CSR_SRMCFG 0x181
|
||||||
|
|
||||||
/* Machine-Level Control transfer records CSRs */
|
/* Machine-Level Control transfer records CSRs */
|
||||||
#define CSR_MCTRCTL 0x34e
|
#define CSR_MCTRCTL 0x34e
|
||||||
|
|
||||||
@@ -783,6 +786,40 @@
|
|||||||
#define CSR_VTYPE 0xc21
|
#define CSR_VTYPE 0xc21
|
||||||
#define CSR_VLENB 0xc22
|
#define CSR_VLENB 0xc22
|
||||||
|
|
||||||
|
/* Custom CSR ranges */
|
||||||
|
#define CSR_CUSTOM0_U_RW_BASE 0x800
|
||||||
|
#define CSR_CUSTOM0_U_RW_COUNT 0x100
|
||||||
|
|
||||||
|
#define CSR_CUSTOM1_U_RO_BASE 0xCC0
|
||||||
|
#define CSR_CUSTOM1_U_RO_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM2_S_RW_BASE 0x5C0
|
||||||
|
#define CSR_CUSTOM2_S_RW_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM3_S_RW_BASE 0x9C0
|
||||||
|
#define CSR_CUSTOM3_S_RW_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM4_S_RO_BASE 0xDC0
|
||||||
|
#define CSR_CUSTOM4_S_RO_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM5_HS_RW_BASE 0x6C0
|
||||||
|
#define CSR_CUSTOM5_HS_RW_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM6_HS_RW_BASE 0xAC0
|
||||||
|
#define CSR_CUSTOM6_HS_RW_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM7_HS_RO_BASE 0xEC0
|
||||||
|
#define CSR_CUSTOM7_HS_RO_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM8_M_RW_BASE 0x7C0
|
||||||
|
#define CSR_CUSTOM8_M_RW_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM9_M_RW_BASE 0xBC0
|
||||||
|
#define CSR_CUSTOM9_M_RW_COUNT 0x040
|
||||||
|
|
||||||
|
#define CSR_CUSTOM10_M_RO_BASE 0xFC0
|
||||||
|
#define CSR_CUSTOM10_M_RO_COUNT 0x040
|
||||||
|
|
||||||
/* ===== Trap/Exception Causes ===== */
|
/* ===== Trap/Exception Causes ===== */
|
||||||
|
|
||||||
#define CAUSE_MISALIGNED_FETCH 0x0
|
#define CAUSE_MISALIGNED_FETCH 0x0
|
||||||
@@ -815,6 +852,8 @@
|
|||||||
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
|
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
|
||||||
#define SMSTATEEN0_CTR_SHIFT 54
|
#define SMSTATEEN0_CTR_SHIFT 54
|
||||||
#define SMSTATEEN0_CTR (_ULL(1) << SMSTATEEN0_CTR_SHIFT)
|
#define SMSTATEEN0_CTR (_ULL(1) << SMSTATEEN0_CTR_SHIFT)
|
||||||
|
#define SMSTATEEN0_SRMCFG_SHIFT 55
|
||||||
|
#define SMSTATEEN0_SRMCFG (_ULL(1) << SMSTATEEN0_SRMCFG_SHIFT)
|
||||||
#define SMSTATEEN0_CONTEXT_SHIFT 57
|
#define SMSTATEEN0_CONTEXT_SHIFT 57
|
||||||
#define SMSTATEEN0_CONTEXT (_ULL(1) << SMSTATEEN0_CONTEXT_SHIFT)
|
#define SMSTATEEN0_CONTEXT (_ULL(1) << SMSTATEEN0_CONTEXT_SHIFT)
|
||||||
#define SMSTATEEN0_IMSIC_SHIFT 58
|
#define SMSTATEEN0_IMSIC_SHIFT 58
|
||||||
@@ -910,7 +949,7 @@
|
|||||||
#define INSN_MASK_WFI 0xffffff00
|
#define INSN_MASK_WFI 0xffffff00
|
||||||
#define INSN_MATCH_WFI 0x10500000
|
#define INSN_MATCH_WFI 0x10500000
|
||||||
|
|
||||||
#define INSN_MASK_FENCE_TSO 0xffffffff
|
#define INSN_MASK_FENCE_TSO 0xfff0707f
|
||||||
#define INSN_MATCH_FENCE_TSO 0x8330000f
|
#define INSN_MATCH_FENCE_TSO 0x8330000f
|
||||||
|
|
||||||
#define INSN_MASK_VECTOR_UNIT_STRIDE 0xfdf0707f
|
#define INSN_MASK_VECTOR_UNIT_STRIDE 0xfdf0707f
|
||||||
|
|||||||
@@ -121,6 +121,9 @@ struct sbi_domain_memregion {
|
|||||||
((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \
|
((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK) && \
|
||||||
!(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK))
|
!(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK))
|
||||||
|
|
||||||
|
#define SBI_DOMAIN_MEMREGION_IS_FIRMWARE(__flags) \
|
||||||
|
((__flags & SBI_DOMAIN_MEMREGION_FW) ? true : false) \
|
||||||
|
|
||||||
/** Bit to control if permissions are enforced on all modes */
|
/** Bit to control if permissions are enforced on all modes */
|
||||||
#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6)
|
#define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS (1UL << 6)
|
||||||
|
|
||||||
@@ -157,6 +160,7 @@ struct sbi_domain_memregion {
|
|||||||
SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
|
SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
|
||||||
|
|
||||||
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
|
#define SBI_DOMAIN_MEMREGION_MMIO (1UL << 31)
|
||||||
|
#define SBI_DOMAIN_MEMREGION_FW (1UL << 30)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -249,6 +253,13 @@ void sbi_domain_memregion_init(unsigned long addr,
|
|||||||
unsigned long flags,
|
unsigned long flags,
|
||||||
struct sbi_domain_memregion *reg);
|
struct sbi_domain_memregion *reg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Smepmp pmpcfg LRWX encoding for the flags in @reg.
|
||||||
|
*
|
||||||
|
* @param reg pointer to memory region; its flags field encodes permissions.
|
||||||
|
*/
|
||||||
|
unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether we can access specified address for given mode and
|
* Check whether we can access specified address for given mode and
|
||||||
* memory region flags under a domain
|
* memory region flags under a domain
|
||||||
|
|||||||
@@ -291,6 +291,15 @@ struct sbi_pmu_event_info {
|
|||||||
#define SBI_PMU_CFG_FLAG_SET_UINH (1 << 5)
|
#define SBI_PMU_CFG_FLAG_SET_UINH (1 << 5)
|
||||||
#define SBI_PMU_CFG_FLAG_SET_SINH (1 << 6)
|
#define SBI_PMU_CFG_FLAG_SET_SINH (1 << 6)
|
||||||
#define SBI_PMU_CFG_FLAG_SET_MINH (1 << 7)
|
#define SBI_PMU_CFG_FLAG_SET_MINH (1 << 7)
|
||||||
|
/* Event configuration mask */
|
||||||
|
#define SBI_PMU_CFG_EVENT_MASK \
|
||||||
|
( \
|
||||||
|
SBI_PMU_CFG_FLAG_SET_VUINH | \
|
||||||
|
SBI_PMU_CFG_FLAG_SET_VSINH | \
|
||||||
|
SBI_PMU_CFG_FLAG_SET_UINH | \
|
||||||
|
SBI_PMU_CFG_FLAG_SET_SINH | \
|
||||||
|
SBI_PMU_CFG_FLAG_SET_MINH \
|
||||||
|
)
|
||||||
|
|
||||||
/* Flags defined for counter start function */
|
/* Flags defined for counter start function */
|
||||||
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
|
#define SBI_PMU_START_FLAG_SET_INIT_VALUE (1 << 0)
|
||||||
|
|||||||
@@ -79,8 +79,14 @@ enum sbi_hart_extensions {
|
|||||||
SBI_HART_EXT_SMCTR,
|
SBI_HART_EXT_SMCTR,
|
||||||
/** HART has CTR S-mode CSRs */
|
/** HART has CTR S-mode CSRs */
|
||||||
SBI_HART_EXT_SSCTR,
|
SBI_HART_EXT_SSCTR,
|
||||||
|
/** Hart has Ssqosid extension */
|
||||||
|
SBI_HART_EXT_SSQOSID,
|
||||||
/** HART has Ssstateen extension **/
|
/** HART has Ssstateen extension **/
|
||||||
SBI_HART_EXT_SSSTATEEN,
|
SBI_HART_EXT_SSSTATEEN,
|
||||||
|
/** Hart has Xsfcflushdlone extension */
|
||||||
|
SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1,
|
||||||
|
/** Hart has Xsfcease extension */
|
||||||
|
SBI_HART_EXT_XSIFIVE_CEASE,
|
||||||
|
|
||||||
/** Maximum index of Hart extension */
|
/** Maximum index of Hart extension */
|
||||||
SBI_HART_EXT_MAX,
|
SBI_HART_EXT_MAX,
|
||||||
@@ -142,6 +148,7 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
|
|||||||
unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_pmp_log2gran(struct sbi_scratch *scratch);
|
||||||
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
|
||||||
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
|
||||||
|
bool sbi_hart_smepmp_is_fw_region(unsigned int pmp_idx);
|
||||||
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
|
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
|
||||||
int sbi_hart_map_saddr(unsigned long base, unsigned long size);
|
int sbi_hart_map_saddr(unsigned long base, unsigned long size);
|
||||||
int sbi_hart_unmap_saddr(void);
|
int sbi_hart_unmap_saddr(void);
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ struct sbi_ipi_device {
|
|||||||
/** Name of the IPI device */
|
/** Name of the IPI device */
|
||||||
char name[32];
|
char name[32];
|
||||||
|
|
||||||
|
/** Ratings of the IPI device (higher is better) */
|
||||||
|
unsigned long rating;
|
||||||
|
|
||||||
/** Send IPI to a target HART index */
|
/** Send IPI to a target HART index */
|
||||||
void (*ipi_send)(u32 hart_index);
|
void (*ipi_send)(u32 hart_index);
|
||||||
|
|
||||||
@@ -85,13 +88,13 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
|
|||||||
|
|
||||||
void sbi_ipi_process(void);
|
void sbi_ipi_process(void);
|
||||||
|
|
||||||
int sbi_ipi_raw_send(u32 hartindex);
|
int sbi_ipi_raw_send(u32 hartindex, bool all_devices);
|
||||||
|
|
||||||
void sbi_ipi_raw_clear(void);
|
void sbi_ipi_raw_clear(bool all_devices);
|
||||||
|
|
||||||
const struct sbi_ipi_device *sbi_ipi_get_device(void);
|
const struct sbi_ipi_device *sbi_ipi_get_device(void);
|
||||||
|
|
||||||
void sbi_ipi_set_device(const struct sbi_ipi_device *dev);
|
void sbi_ipi_add_device(const struct sbi_ipi_device *dev);
|
||||||
|
|
||||||
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
|
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||||
|
|
||||||
|
|||||||
@@ -173,4 +173,15 @@ static inline void sbi_list_del_init(struct sbi_dlist *entry)
|
|||||||
&pos->member != (head); \
|
&pos->member != (head); \
|
||||||
pos = n, n = sbi_list_entry(pos->member.next, typeof(*pos), member))
|
pos = n, n = sbi_list_entry(pos->member.next, typeof(*pos), member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over list of given type in reverse order
|
||||||
|
* @param pos the type * to use as a loop cursor.
|
||||||
|
* @param head the head for your list.
|
||||||
|
* @param member the name of the list_struct within the struct.
|
||||||
|
*/
|
||||||
|
#define sbi_list_for_each_entry_reverse(pos, head, member) \
|
||||||
|
for (pos = sbi_list_entry((head)->prev, typeof(*pos), member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = sbi_list_entry(pos->member.prev, typeof(*pos), member))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -116,9 +116,6 @@ struct sbi_platform_operations {
|
|||||||
/** Initialize the platform interrupt controller during cold boot */
|
/** Initialize the platform interrupt controller during cold boot */
|
||||||
int (*irqchip_init)(void);
|
int (*irqchip_init)(void);
|
||||||
|
|
||||||
/** Initialize IPI during cold boot */
|
|
||||||
int (*ipi_init)(void);
|
|
||||||
|
|
||||||
/** Get tlb flush limit value **/
|
/** Get tlb flush limit value **/
|
||||||
u64 (*get_tlbr_flush_limit)(void);
|
u64 (*get_tlbr_flush_limit)(void);
|
||||||
|
|
||||||
@@ -528,20 +525,6 @@ static inline int sbi_platform_irqchip_init(const struct sbi_platform *plat)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the platform IPI support during cold boot
|
|
||||||
*
|
|
||||||
* @param plat pointer to struct sbi_platform
|
|
||||||
*
|
|
||||||
* @return 0 on success and negative error code on failure
|
|
||||||
*/
|
|
||||||
static inline int sbi_platform_ipi_init(const struct sbi_platform *plat)
|
|
||||||
{
|
|
||||||
if (plat && sbi_platform_ops(plat)->ipi_init)
|
|
||||||
return sbi_platform_ops(plat)->ipi_init();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the platform timer during cold boot
|
* Initialize the platform timer during cold boot
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -69,11 +69,18 @@ struct sbi_system_suspend_device {
|
|||||||
* return from system_suspend() may ignore this parameter.
|
* return from system_suspend() may ignore this parameter.
|
||||||
*/
|
*/
|
||||||
int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr);
|
int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resume the system from system suspend
|
||||||
|
*/
|
||||||
|
void (*system_resume)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void);
|
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void);
|
||||||
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev);
|
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev);
|
||||||
void sbi_system_suspend_test_enable(void);
|
void sbi_system_suspend_test_enable(void);
|
||||||
|
void sbi_system_resume(void);
|
||||||
|
bool sbi_system_is_suspended(void);
|
||||||
bool sbi_system_suspend_supported(u32 sleep_type);
|
bool sbi_system_suspend_supported(u32 sleep_type);
|
||||||
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque);
|
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
typedef char s8;
|
typedef signed char s8;
|
||||||
typedef unsigned char u8;
|
typedef unsigned char u8;
|
||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
|
|
||||||
|
|||||||
69
include/sbi_utils/cache/cache.h
vendored
Normal file
69
include/sbi_utils/cache/cache.h
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CACHE_H__
|
||||||
|
#define __CACHE_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_list.h>
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#define CACHE_NAME_LEN 32
|
||||||
|
|
||||||
|
struct cache_device;
|
||||||
|
|
||||||
|
struct cache_ops {
|
||||||
|
/** Warm init **/
|
||||||
|
int (*warm_init)(struct cache_device *dev);
|
||||||
|
/** Flush entire cache **/
|
||||||
|
int (*cache_flush_all)(struct cache_device *dev);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cache_device {
|
||||||
|
/** Name of the device **/
|
||||||
|
char name[CACHE_NAME_LEN];
|
||||||
|
/** List node for search **/
|
||||||
|
struct sbi_dlist node;
|
||||||
|
/** Point to the next level cache **/
|
||||||
|
struct cache_device *next;
|
||||||
|
/** Cache Management Operations **/
|
||||||
|
struct cache_ops *ops;
|
||||||
|
/** CPU private cache **/
|
||||||
|
bool cpu_private;
|
||||||
|
/** The unique id of this cache device **/
|
||||||
|
u32 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a registered cache device
|
||||||
|
*
|
||||||
|
* @param id unique ID of the cache device
|
||||||
|
*
|
||||||
|
* @return the cache device or NULL
|
||||||
|
*/
|
||||||
|
struct cache_device *cache_find(u32 id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a cache device
|
||||||
|
*
|
||||||
|
* cache_device->id must be initialized already and must not change during the life
|
||||||
|
* of the cache_device object.
|
||||||
|
*
|
||||||
|
* @param dev the cache device to register
|
||||||
|
*
|
||||||
|
* @return 0 on success, or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int cache_add(struct cache_device *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush the entire cache
|
||||||
|
*
|
||||||
|
* @param dev the cache to flush
|
||||||
|
*
|
||||||
|
* @return 0 on success, or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int cache_flush_all(struct cache_device *dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
34
include/sbi_utils/cache/fdt_cache.h
vendored
Normal file
34
include/sbi_utils/cache/fdt_cache.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_CACHE_H__
|
||||||
|
#define __FDT_CACHE_H__
|
||||||
|
|
||||||
|
#include <sbi_utils/cache/cache.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a cache device using information from the DT
|
||||||
|
*
|
||||||
|
* @param fdt devicetree blob
|
||||||
|
* @param noff offset of a node in the devicetree blob
|
||||||
|
* @param dev cache device to register for this devicetree node
|
||||||
|
*
|
||||||
|
* @return 0 on success, or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdt_cache_add(const void *fdt, int noff, struct cache_device *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cache device referencd by the "next-level-cache" property of a DT node
|
||||||
|
*
|
||||||
|
* @param fdt devicetree blob
|
||||||
|
* @param noff offset of a node in the devicetree blob
|
||||||
|
* @param out_dev location to return the cache device
|
||||||
|
*
|
||||||
|
* @return 0 on success, or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdt_next_cache_get(const void *fdt, int noff, struct cache_device **out_dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
40
include/sbi_utils/cache/fdt_cmo_helper.h
vendored
Normal file
40
include/sbi_utils/cache/fdt_cmo_helper.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_CMO_HELPER_H__
|
||||||
|
#define __FDT_CMO_HELPER_H__
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_CACHE
|
||||||
|
/**
|
||||||
|
* Flush the private first level cache of the current hart
|
||||||
|
*
|
||||||
|
* @return 0 on success, or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdt_cmo_private_flc_flush_all(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush the last level cache of the current hart
|
||||||
|
*
|
||||||
|
* @return 0 on success, or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdt_cmo_llc_flush_all(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the cache devices for each hart
|
||||||
|
*
|
||||||
|
* @param fdt devicetree blob
|
||||||
|
* @param cold_boot cold init or warm init
|
||||||
|
*
|
||||||
|
* @return 0 on success, or a negative error code on failure
|
||||||
|
*/
|
||||||
|
int fdt_cmo_init(bool cold_boot);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int fdt_cmo_init(bool cold_boot) { return 0; }
|
||||||
|
|
||||||
|
#endif /* CONFIG_FDT_CACHE */
|
||||||
|
#endif /* __FDT_CMO_HELPER_H__ */
|
||||||
20
include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
Normal file
20
include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_HSM_SIFIVE_INST_H__
|
||||||
|
#define __FDT_HSM_SIFIVE_INST_H__
|
||||||
|
|
||||||
|
static inline void sifive_cease(void)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(".insn 0x30500073" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sifive_cflush(void)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(".insn 0xfc000073" ::: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
14
include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
Normal file
14
include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_HSM_SIFIVE_TMC0_H__
|
||||||
|
#define __FDT_HSM_SIFIVE_TMC0_H__
|
||||||
|
|
||||||
|
int sifive_tmc0_set_wakemask_enareq(u32 hartid);
|
||||||
|
void sifive_tmc0_set_wakemask_disreq(u32 hartid);
|
||||||
|
bool sifive_tmc0_is_pg(u32 hartid);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Anup Patel <anup.patel@wdc.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FDT_IPI_H__
|
|
||||||
#define __FDT_IPI_H__
|
|
||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
|
||||||
#include <sbi_utils/fdt/fdt_driver.h>
|
|
||||||
|
|
||||||
#ifdef CONFIG_FDT_IPI
|
|
||||||
|
|
||||||
int fdt_ipi_init(void);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline int fdt_ipi_init(void) { return 0; }
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -33,6 +33,7 @@ struct aplic_delegate_data {
|
|||||||
struct aplic_data {
|
struct aplic_data {
|
||||||
/* Private members */
|
/* Private members */
|
||||||
struct sbi_irqchip_device irqchip;
|
struct sbi_irqchip_device irqchip;
|
||||||
|
struct sbi_dlist node;
|
||||||
/* Public members */
|
/* Public members */
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
@@ -48,4 +49,6 @@ struct aplic_data {
|
|||||||
|
|
||||||
int aplic_cold_irqchip_init(struct aplic_data *aplic);
|
int aplic_cold_irqchip_init(struct aplic_data *aplic);
|
||||||
|
|
||||||
|
void aplic_reinit_all(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -216,7 +216,10 @@ enum rpmi_servicegroup_id {
|
|||||||
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x0004,
|
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x0004,
|
||||||
RPMI_SRVGRP_HSM = 0x0005,
|
RPMI_SRVGRP_HSM = 0x0005,
|
||||||
RPMI_SRVGRP_CPPC = 0x0006,
|
RPMI_SRVGRP_CPPC = 0x0006,
|
||||||
|
RPMI_SRVGRP_VOLTAGE = 0x00007,
|
||||||
RPMI_SRVGRP_CLOCK = 0x0008,
|
RPMI_SRVGRP_CLOCK = 0x0008,
|
||||||
|
RPMI_SRVGRP_DEVICE_POWER = 0x0009,
|
||||||
|
RPMI_SRVGRP_PERFORMANCE = 0x0000A,
|
||||||
RPMI_SRVGRP_ID_MAX_COUNT,
|
RPMI_SRVGRP_ID_MAX_COUNT,
|
||||||
|
|
||||||
/* Reserved range for service groups */
|
/* Reserved range for service groups */
|
||||||
@@ -611,6 +614,86 @@ struct rpmi_cppc_hart_list_resp {
|
|||||||
u32 hartid[(RPMI_MSG_DATA_SIZE(RPMI_SLOT_SIZE_MIN) - (sizeof(u32) * 3)) / sizeof(u32)];
|
u32 hartid[(RPMI_MSG_DATA_SIZE(RPMI_SLOT_SIZE_MIN) - (sizeof(u32) * 3)) / sizeof(u32)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** RPMI Voltage ServiceGroup Service IDs */
|
||||||
|
enum rpmi_voltage_service_id {
|
||||||
|
RPMI_VOLTAGE_SRV_ENABLE_NOTIFICATION = 0x01,
|
||||||
|
RPMI_VOLTAGE_SRV_GET_NUM_DOMAINS = 0x02,
|
||||||
|
RPMI_VOLTAGE_SRV_GET_ATTRIBUTES = 0x03,
|
||||||
|
RPMI_VOLTAGE_SRV_GET_SUPPORTED_LEVELS = 0x04,
|
||||||
|
RPMI_VOLTAGE_SRV_SET_CONFIG = 0x05,
|
||||||
|
RPMI_VOLTAGE_SRV_GET_CONFIG = 0x06,
|
||||||
|
RPMI_VOLTAGE_SRV_SET_LEVEL = 0x07,
|
||||||
|
RPMI_VOLTAGE_SRV_GET_LEVEL = 0x08,
|
||||||
|
RPMI_VOLTAGE_SRV_MAX_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_num_domains_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 num_domains;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_attributes_req {
|
||||||
|
u32 domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_attributes_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 flags;
|
||||||
|
u32 num_levels;
|
||||||
|
u32 transition_latency;
|
||||||
|
u8 name[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_supported_rate_req {
|
||||||
|
u32 domain_id;
|
||||||
|
u32 index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_supported_rate_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 flags;
|
||||||
|
u32 remaining;
|
||||||
|
u32 returned;
|
||||||
|
u32 level[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_set_config_req {
|
||||||
|
u32 domain_id;
|
||||||
|
#define RPMI_CLOCK_CONFIG_ENABLE (1U << 0)
|
||||||
|
u32 config;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_set_config_resp {
|
||||||
|
s32 status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_config_req {
|
||||||
|
u32 domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_config_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 config;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_set_level_req {
|
||||||
|
u32 domain_id;
|
||||||
|
s32 level;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_set_level_resp {
|
||||||
|
s32 status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_level_req {
|
||||||
|
u32 domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_voltage_get_level_resp {
|
||||||
|
s32 status;
|
||||||
|
s32 level;
|
||||||
|
};
|
||||||
|
|
||||||
/** RPMI Clock ServiceGroup Service IDs */
|
/** RPMI Clock ServiceGroup Service IDs */
|
||||||
enum rpmi_clock_service_id {
|
enum rpmi_clock_service_id {
|
||||||
RPMI_CLOCK_SRV_ENABLE_NOTIFICATION = 0x01,
|
RPMI_CLOCK_SRV_ENABLE_NOTIFICATION = 0x01,
|
||||||
@@ -703,4 +786,165 @@ struct rpmi_clock_get_rate_resp {
|
|||||||
u32 clock_rate_high;
|
u32 clock_rate_high;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** RPMI Device Power ServiceGroup Service IDs */
|
||||||
|
enum rpmi_dpwr_service_id {
|
||||||
|
RPMI_DPWR_SRV_ENABLE_NOTIFICATION = 0x01,
|
||||||
|
RPMI_DPWR_SRV_GET_NUM_DOMAINS = 0x02,
|
||||||
|
RPMI_DPWR_SRV_GET_ATTRIBUTES = 0x03,
|
||||||
|
RPMI_DPWR_SRV_SET_STATE = 0x04,
|
||||||
|
RPMI_DPWR_SRV_GET_STATE = 0x05,
|
||||||
|
RPMI_DPWR_SRV_MAX_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_dpwr_get_num_domain_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 num_domain;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_dpwr_get_attrs_req {
|
||||||
|
u32 domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_dpwr_get_attrs_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 flags;
|
||||||
|
u32 transition_latency;
|
||||||
|
u8 name[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_dpwr_set_state_req {
|
||||||
|
u32 domain_id;
|
||||||
|
u32 state;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_dpwr_set_state_resp {
|
||||||
|
s32 status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_dpwr_get_state_req {
|
||||||
|
u32 domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_dpwr_get_state_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 state;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** RPMI Performance ServiceGroup Service IDs */
|
||||||
|
enum rpmi_performance_service_id {
|
||||||
|
RPMI_PERF_SRV_ENABLE_NOTIFICATION = 0x01,
|
||||||
|
RPMI_PERF_SRV_GET_NUM_DOMAINS = 0x02,
|
||||||
|
RPMI_PERF_SRV_GET_ATTRIBUTES = 0x03,
|
||||||
|
RPMI_PERF_SRV_GET_SUPPORTED_LEVELS = 0x04,
|
||||||
|
RPMI_PERF_SRV_GET_LEVEL = 0x05,
|
||||||
|
RPMI_PERF_SRV_SET_LEVEL = 0x06,
|
||||||
|
RPMI_PERF_SRV_GET_LIMIT = 0x07,
|
||||||
|
RPMI_PERF_SRV_SET_LIMIT = 0x08,
|
||||||
|
RPMI_PERF_SRV_GET_FAST_CHANNEL_REGION = 0x09,
|
||||||
|
RPMI_PERF_SRV_GET_FAST_CHANNEL_ATTRIBUTES = 0x0A,
|
||||||
|
RPMI_PERF_SRV_MAX_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_num_domain_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 num_domains;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_attrs_req {
|
||||||
|
u32 domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_attrs_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 flags;
|
||||||
|
u32 num_level;
|
||||||
|
u32 latency;
|
||||||
|
u8 name[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_supported_level_req {
|
||||||
|
u32 domain_id;
|
||||||
|
u32 perf_level_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_domain_level {
|
||||||
|
u32 level_index;
|
||||||
|
u32 opp_level;
|
||||||
|
u32 power_cost_uw;
|
||||||
|
u32 transition_latency_us;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_supported_level_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 reserve;
|
||||||
|
u32 remaining;
|
||||||
|
u32 returned;
|
||||||
|
struct rpmi_perf_domain_level level[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_level_req {
|
||||||
|
u32 domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_level_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 level_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_set_level_req {
|
||||||
|
u32 domain_id;
|
||||||
|
u32 level_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_set_level_resp {
|
||||||
|
s32 status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_limit_req {
|
||||||
|
u32 domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_limit_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 level_index_max;
|
||||||
|
u32 level_index_min;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_set_limit_req {
|
||||||
|
u32 domain_id;
|
||||||
|
u32 level_index_max;
|
||||||
|
u32 level_index_min;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_set_limit_resp {
|
||||||
|
s32 status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_fast_chn_region_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 region_phy_addr_low;
|
||||||
|
u32 region_phy_addr_high;
|
||||||
|
u32 region_size_low;
|
||||||
|
u32 region_size_high;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_fast_chn_attr_req {
|
||||||
|
u32 domain_id;
|
||||||
|
u32 service_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rpmi_perf_get_fast_chn_attr_resp {
|
||||||
|
s32 status;
|
||||||
|
u32 flags;
|
||||||
|
u32 region_offset_low;
|
||||||
|
u32 region_offset_high;
|
||||||
|
u32 region_size;
|
||||||
|
u32 db_addr_low;
|
||||||
|
u32 db_addr_high;
|
||||||
|
u32 db_id_low;
|
||||||
|
u32 db_id_high;
|
||||||
|
u32 db_perserved_low;
|
||||||
|
u32 db_perserved_high;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* !__RPMI_MSGPROT_H__ */
|
#endif /* !__RPMI_MSGPROT_H__ */
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ struct aclint_mtimer_data {
|
|||||||
void (*time_wr)(bool timecmp, u64 value, volatile u64 *addr);
|
void (*time_wr)(bool timecmp, u64 value, volatile u64 *addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct aclint_mtimer_data *aclint_get_mtimer_data(void);
|
||||||
|
|
||||||
|
void aclint_mtimer_update(struct aclint_mtimer_data *mt,
|
||||||
|
struct aclint_mtimer_data *ref);
|
||||||
|
|
||||||
void aclint_mtimer_sync(struct aclint_mtimer_data *mt);
|
void aclint_mtimer_sync(struct aclint_mtimer_data *mt);
|
||||||
|
|
||||||
void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
|
void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
|
||||||
|
|||||||
@@ -93,77 +93,91 @@ void misa_string(int xlen, char *out, unsigned int out_sz)
|
|||||||
|
|
||||||
unsigned long csr_read_num(int csr_num)
|
unsigned long csr_read_num(int csr_num)
|
||||||
{
|
{
|
||||||
#define switchcase_csr_read(__csr_num, __val) \
|
#define switchcase_csr_read(__csr_num) \
|
||||||
case __csr_num: \
|
case __csr_num: \
|
||||||
__val = csr_read(__csr_num); \
|
return csr_read(__csr_num);
|
||||||
break;
|
#define switchcase_csr_read_2(__csr_num) \
|
||||||
#define switchcase_csr_read_2(__csr_num, __val) \
|
switchcase_csr_read(__csr_num + 0) \
|
||||||
switchcase_csr_read(__csr_num + 0, __val) \
|
switchcase_csr_read(__csr_num + 1)
|
||||||
switchcase_csr_read(__csr_num + 1, __val)
|
#define switchcase_csr_read_4(__csr_num) \
|
||||||
#define switchcase_csr_read_4(__csr_num, __val) \
|
switchcase_csr_read_2(__csr_num + 0) \
|
||||||
switchcase_csr_read_2(__csr_num + 0, __val) \
|
switchcase_csr_read_2(__csr_num + 2)
|
||||||
switchcase_csr_read_2(__csr_num + 2, __val)
|
#define switchcase_csr_read_8(__csr_num) \
|
||||||
#define switchcase_csr_read_8(__csr_num, __val) \
|
switchcase_csr_read_4(__csr_num + 0) \
|
||||||
switchcase_csr_read_4(__csr_num + 0, __val) \
|
switchcase_csr_read_4(__csr_num + 4)
|
||||||
switchcase_csr_read_4(__csr_num + 4, __val)
|
#define switchcase_csr_read_16(__csr_num) \
|
||||||
#define switchcase_csr_read_16(__csr_num, __val) \
|
switchcase_csr_read_8(__csr_num + 0) \
|
||||||
switchcase_csr_read_8(__csr_num + 0, __val) \
|
switchcase_csr_read_8(__csr_num + 8)
|
||||||
switchcase_csr_read_8(__csr_num + 8, __val)
|
#define switchcase_csr_read_32(__csr_num) \
|
||||||
#define switchcase_csr_read_32(__csr_num, __val) \
|
switchcase_csr_read_16(__csr_num + 0) \
|
||||||
switchcase_csr_read_16(__csr_num + 0, __val) \
|
switchcase_csr_read_16(__csr_num + 16)
|
||||||
switchcase_csr_read_16(__csr_num + 16, __val)
|
#define switchcase_csr_read_64(__csr_num) \
|
||||||
#define switchcase_csr_read_64(__csr_num, __val) \
|
switchcase_csr_read_32(__csr_num + 0) \
|
||||||
switchcase_csr_read_32(__csr_num + 0, __val) \
|
switchcase_csr_read_32(__csr_num + 32)
|
||||||
switchcase_csr_read_32(__csr_num + 32, __val)
|
#define switchcase_csr_read_128(__csr_num) \
|
||||||
|
switchcase_csr_read_64(__csr_num + 0) \
|
||||||
unsigned long ret = 0;
|
switchcase_csr_read_64(__csr_num + 64)
|
||||||
|
#define switchcase_csr_read_256(__csr_num) \
|
||||||
|
switchcase_csr_read_128(__csr_num + 0) \
|
||||||
|
switchcase_csr_read_128(__csr_num + 128)
|
||||||
|
|
||||||
switch (csr_num) {
|
switch (csr_num) {
|
||||||
switchcase_csr_read_16(CSR_PMPCFG0, ret)
|
switchcase_csr_read_16(CSR_PMPCFG0)
|
||||||
switchcase_csr_read_64(CSR_PMPADDR0, ret)
|
switchcase_csr_read_64(CSR_PMPADDR0)
|
||||||
switchcase_csr_read(CSR_MCYCLE, ret)
|
switchcase_csr_read(CSR_MCYCLE)
|
||||||
switchcase_csr_read(CSR_MINSTRET, ret)
|
switchcase_csr_read(CSR_MINSTRET)
|
||||||
switchcase_csr_read(CSR_MHPMCOUNTER3, ret)
|
switchcase_csr_read(CSR_MHPMCOUNTER3)
|
||||||
switchcase_csr_read_4(CSR_MHPMCOUNTER4, ret)
|
switchcase_csr_read_4(CSR_MHPMCOUNTER4)
|
||||||
switchcase_csr_read_8(CSR_MHPMCOUNTER8, ret)
|
switchcase_csr_read_8(CSR_MHPMCOUNTER8)
|
||||||
switchcase_csr_read_16(CSR_MHPMCOUNTER16, ret)
|
switchcase_csr_read_16(CSR_MHPMCOUNTER16)
|
||||||
switchcase_csr_read(CSR_MCOUNTINHIBIT, ret)
|
switchcase_csr_read(CSR_MCOUNTINHIBIT)
|
||||||
switchcase_csr_read(CSR_MCYCLECFG, ret)
|
switchcase_csr_read(CSR_MCYCLECFG)
|
||||||
switchcase_csr_read(CSR_MINSTRETCFG, ret)
|
switchcase_csr_read(CSR_MINSTRETCFG)
|
||||||
switchcase_csr_read(CSR_MHPMEVENT3, ret)
|
switchcase_csr_read(CSR_MHPMEVENT3)
|
||||||
switchcase_csr_read_4(CSR_MHPMEVENT4, ret)
|
switchcase_csr_read_4(CSR_MHPMEVENT4)
|
||||||
switchcase_csr_read_8(CSR_MHPMEVENT8, ret)
|
switchcase_csr_read_8(CSR_MHPMEVENT8)
|
||||||
switchcase_csr_read_16(CSR_MHPMEVENT16, ret)
|
switchcase_csr_read_16(CSR_MHPMEVENT16)
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
switchcase_csr_read(CSR_MCYCLEH, ret)
|
switchcase_csr_read(CSR_MCYCLEH)
|
||||||
switchcase_csr_read(CSR_MINSTRETH, ret)
|
switchcase_csr_read(CSR_MINSTRETH)
|
||||||
switchcase_csr_read(CSR_MHPMCOUNTER3H, ret)
|
switchcase_csr_read(CSR_MHPMCOUNTER3H)
|
||||||
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
|
switchcase_csr_read_4(CSR_MHPMCOUNTER4H)
|
||||||
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
|
switchcase_csr_read_8(CSR_MHPMCOUNTER8H)
|
||||||
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
|
switchcase_csr_read_16(CSR_MHPMCOUNTER16H)
|
||||||
/**
|
/**
|
||||||
* The CSR range M[CYCLE, INSTRET]CFGH are available only if smcntrpmf
|
* The CSR range M[CYCLE, INSTRET]CFGH are available only if smcntrpmf
|
||||||
* extension is present. The caller must ensure that.
|
* extension is present. The caller must ensure that.
|
||||||
*/
|
*/
|
||||||
switchcase_csr_read(CSR_MCYCLECFGH, ret)
|
switchcase_csr_read(CSR_MCYCLECFGH)
|
||||||
switchcase_csr_read(CSR_MINSTRETCFGH, ret)
|
switchcase_csr_read(CSR_MINSTRETCFGH)
|
||||||
/**
|
/**
|
||||||
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
|
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
|
||||||
* extension is present. The caller must ensure that.
|
* extension is present. The caller must ensure that.
|
||||||
*/
|
*/
|
||||||
switchcase_csr_read(CSR_MHPMEVENT3H, ret)
|
switchcase_csr_read(CSR_MHPMEVENT3H)
|
||||||
switchcase_csr_read_4(CSR_MHPMEVENT4H, ret)
|
switchcase_csr_read_4(CSR_MHPMEVENT4H)
|
||||||
switchcase_csr_read_8(CSR_MHPMEVENT8H, ret)
|
switchcase_csr_read_8(CSR_MHPMEVENT8H)
|
||||||
switchcase_csr_read_16(CSR_MHPMEVENT16H, ret)
|
switchcase_csr_read_16(CSR_MHPMEVENT16H)
|
||||||
#endif
|
#endif
|
||||||
|
switchcase_csr_read_256(CSR_CUSTOM0_U_RW_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM1_U_RO_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM2_S_RW_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM3_S_RW_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM4_S_RO_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM5_HS_RW_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM6_HS_RW_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM7_HS_RO_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM8_M_RW_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM9_M_RW_BASE)
|
||||||
|
switchcase_csr_read_64(CSR_CUSTOM10_M_RO_BASE)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
#undef switchcase_csr_read_256
|
||||||
|
#undef switchcase_csr_read_128
|
||||||
#undef switchcase_csr_read_64
|
#undef switchcase_csr_read_64
|
||||||
#undef switchcase_csr_read_32
|
#undef switchcase_csr_read_32
|
||||||
#undef switchcase_csr_read_16
|
#undef switchcase_csr_read_16
|
||||||
@@ -197,6 +211,12 @@ void csr_write_num(int csr_num, unsigned long val)
|
|||||||
#define switchcase_csr_write_64(__csr_num, __val) \
|
#define switchcase_csr_write_64(__csr_num, __val) \
|
||||||
switchcase_csr_write_32(__csr_num + 0, __val) \
|
switchcase_csr_write_32(__csr_num + 0, __val) \
|
||||||
switchcase_csr_write_32(__csr_num + 32, __val)
|
switchcase_csr_write_32(__csr_num + 32, __val)
|
||||||
|
#define switchcase_csr_write_128(__csr_num, __val) \
|
||||||
|
switchcase_csr_write_64(__csr_num + 0, __val) \
|
||||||
|
switchcase_csr_write_64(__csr_num + 64, __val)
|
||||||
|
#define switchcase_csr_write_256(__csr_num, __val) \
|
||||||
|
switchcase_csr_write_128(__csr_num + 0, __val) \
|
||||||
|
switchcase_csr_write_128(__csr_num + 128, __val)
|
||||||
|
|
||||||
switch (csr_num) {
|
switch (csr_num) {
|
||||||
switchcase_csr_write_16(CSR_PMPCFG0, val)
|
switchcase_csr_write_16(CSR_PMPCFG0, val)
|
||||||
@@ -228,12 +248,21 @@ void csr_write_num(int csr_num, unsigned long val)
|
|||||||
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
|
switchcase_csr_write_4(CSR_MHPMEVENT4, val)
|
||||||
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
|
switchcase_csr_write_8(CSR_MHPMEVENT8, val)
|
||||||
switchcase_csr_write_16(CSR_MHPMEVENT16, val)
|
switchcase_csr_write_16(CSR_MHPMEVENT16, val)
|
||||||
|
switchcase_csr_write_256(CSR_CUSTOM0_U_RW_BASE, val)
|
||||||
|
switchcase_csr_write_64(CSR_CUSTOM2_S_RW_BASE, val)
|
||||||
|
switchcase_csr_write_64(CSR_CUSTOM3_S_RW_BASE, val)
|
||||||
|
switchcase_csr_write_64(CSR_CUSTOM5_HS_RW_BASE, val)
|
||||||
|
switchcase_csr_write_64(CSR_CUSTOM6_HS_RW_BASE, val)
|
||||||
|
switchcase_csr_write_64(CSR_CUSTOM8_M_RW_BASE, val)
|
||||||
|
switchcase_csr_write_64(CSR_CUSTOM9_M_RW_BASE, val)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef switchcase_csr_write_256
|
||||||
|
#undef switchcase_csr_write_128
|
||||||
#undef switchcase_csr_write_64
|
#undef switchcase_csr_write_64
|
||||||
#undef switchcase_csr_write_32
|
#undef switchcase_csr_write_32
|
||||||
#undef switchcase_csr_write_16
|
#undef switchcase_csr_write_16
|
||||||
|
|||||||
@@ -336,6 +336,19 @@ static void dbtr_trigger_setup(struct sbi_dbtr_trigger *trig,
|
|||||||
if (__test_bit(RV_DBTR_BIT(MC6, VS), &tdata1))
|
if (__test_bit(RV_DBTR_BIT(MC6, VS), &tdata1))
|
||||||
__set_bit(RV_DBTR_BIT(TS, VS), &trig->state);
|
__set_bit(RV_DBTR_BIT(TS, VS), &trig->state);
|
||||||
break;
|
break;
|
||||||
|
case RISCV_DBTR_TRIG_ICOUNT:
|
||||||
|
if (__test_bit(RV_DBTR_BIT(ICOUNT, U), &tdata1))
|
||||||
|
__set_bit(RV_DBTR_BIT(TS, U), &trig->state);
|
||||||
|
|
||||||
|
if (__test_bit(RV_DBTR_BIT(ICOUNT, S), &tdata1))
|
||||||
|
__set_bit(RV_DBTR_BIT(TS, S), &trig->state);
|
||||||
|
|
||||||
|
if (__test_bit(RV_DBTR_BIT(ICOUNT, VU), &tdata1))
|
||||||
|
__set_bit(RV_DBTR_BIT(TS, VU), &trig->state);
|
||||||
|
|
||||||
|
if (__test_bit(RV_DBTR_BIT(ICOUNT, VS), &tdata1))
|
||||||
|
__set_bit(RV_DBTR_BIT(TS, VS), &trig->state);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sbi_dprintf("%s: Unknown type (tdata1: 0x%lx Type: %ld)\n",
|
sbi_dprintf("%s: Unknown type (tdata1: 0x%lx Type: %ld)\n",
|
||||||
__func__, tdata1, TDATA1_GET_TYPE(tdata1));
|
__func__, tdata1, TDATA1_GET_TYPE(tdata1));
|
||||||
@@ -379,6 +392,16 @@ static void dbtr_trigger_enable(struct sbi_dbtr_trigger *trig)
|
|||||||
update_bit(state & RV_DBTR_BIT_MASK(TS, S),
|
update_bit(state & RV_DBTR_BIT_MASK(TS, S),
|
||||||
RV_DBTR_BIT(MC6, S), &trig->tdata1);
|
RV_DBTR_BIT(MC6, S), &trig->tdata1);
|
||||||
break;
|
break;
|
||||||
|
case RISCV_DBTR_TRIG_ICOUNT:
|
||||||
|
update_bit(state & RV_DBTR_BIT_MASK(TS, VU),
|
||||||
|
RV_DBTR_BIT(ICOUNT, VU), &trig->tdata1);
|
||||||
|
update_bit(state & RV_DBTR_BIT_MASK(TS, VS),
|
||||||
|
RV_DBTR_BIT(ICOUNT, VS), &trig->tdata1);
|
||||||
|
update_bit(state & RV_DBTR_BIT_MASK(TS, U),
|
||||||
|
RV_DBTR_BIT(ICOUNT, U), &trig->tdata1);
|
||||||
|
update_bit(state & RV_DBTR_BIT_MASK(TS, S),
|
||||||
|
RV_DBTR_BIT(ICOUNT, S), &trig->tdata1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -418,6 +441,12 @@ static void dbtr_trigger_disable(struct sbi_dbtr_trigger *trig)
|
|||||||
__clear_bit(RV_DBTR_BIT(MC6, U), &trig->tdata1);
|
__clear_bit(RV_DBTR_BIT(MC6, U), &trig->tdata1);
|
||||||
__clear_bit(RV_DBTR_BIT(MC6, S), &trig->tdata1);
|
__clear_bit(RV_DBTR_BIT(MC6, S), &trig->tdata1);
|
||||||
break;
|
break;
|
||||||
|
case RISCV_DBTR_TRIG_ICOUNT:
|
||||||
|
__clear_bit(RV_DBTR_BIT(ICOUNT, VU), &trig->tdata1);
|
||||||
|
__clear_bit(RV_DBTR_BIT(ICOUNT, VS), &trig->tdata1);
|
||||||
|
__clear_bit(RV_DBTR_BIT(ICOUNT, U), &trig->tdata1);
|
||||||
|
__clear_bit(RV_DBTR_BIT(ICOUNT, S), &trig->tdata1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -441,6 +470,7 @@ static int dbtr_trigger_supported(unsigned long type)
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case RISCV_DBTR_TRIG_MCONTROL:
|
case RISCV_DBTR_TRIG_MCONTROL:
|
||||||
case RISCV_DBTR_TRIG_MCONTROL6:
|
case RISCV_DBTR_TRIG_MCONTROL6:
|
||||||
|
case RISCV_DBTR_TRIG_ICOUNT:
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -462,6 +492,11 @@ static int dbtr_trigger_valid(unsigned long type, unsigned long tdata)
|
|||||||
!(tdata & RV_DBTR_BIT_MASK(MC6, M)))
|
!(tdata & RV_DBTR_BIT_MASK(MC6, M)))
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
|
case RISCV_DBTR_TRIG_ICOUNT:
|
||||||
|
if (!(tdata & RV_DBTR_BIT_MASK(ICOUNT, DMODE)) &&
|
||||||
|
!(tdata & RV_DBTR_BIT_MASK(ICOUNT, M)))
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -528,6 +563,10 @@ int sbi_dbtr_read_trig(unsigned long smode,
|
|||||||
for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
|
for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
|
||||||
xmit = &entry->data;
|
xmit = &entry->data;
|
||||||
trig = INDEX_TO_TRIGGER((_idx + trig_idx_base));
|
trig = INDEX_TO_TRIGGER((_idx + trig_idx_base));
|
||||||
|
csr_write(CSR_TSELECT, trig->index);
|
||||||
|
trig->tdata1 = csr_read(CSR_TDATA1);
|
||||||
|
trig->tdata2 = csr_read(CSR_TDATA2);
|
||||||
|
trig->tdata3 = csr_read(CSR_TDATA3);
|
||||||
xmit->tstate = cpu_to_lle(trig->state);
|
xmit->tstate = cpu_to_lle(trig->state);
|
||||||
xmit->tdata1 = cpu_to_lle(trig->tdata1);
|
xmit->tdata1 = cpu_to_lle(trig->tdata1);
|
||||||
xmit->tdata2 = cpu_to_lle(trig->tdata2);
|
xmit->tdata2 = cpu_to_lle(trig->tdata2);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ static u32 domain_count = 0;
|
|||||||
static bool domain_finalized = false;
|
static bool domain_finalized = false;
|
||||||
|
|
||||||
#define ROOT_REGION_MAX 32
|
#define ROOT_REGION_MAX 32
|
||||||
static u32 root_memregs_count = 0;
|
|
||||||
|
|
||||||
struct sbi_domain root = {
|
struct sbi_domain root = {
|
||||||
.name = "root",
|
.name = "root",
|
||||||
@@ -122,6 +121,80 @@ void sbi_domain_memregion_init(unsigned long addr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg)
|
||||||
|
{
|
||||||
|
unsigned int pmp_flags = 0;
|
||||||
|
unsigned long rstart, rend;
|
||||||
|
|
||||||
|
if ((reg->flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == 0) {
|
||||||
|
/*
|
||||||
|
* Region is inaccessible in all privilege modes.
|
||||||
|
*
|
||||||
|
* SmePMP allows two encodings for an inaccessible region:
|
||||||
|
* - pmpcfg.LRWX = 0000 (Inaccessible region)
|
||||||
|
* - pmpcfg.LRWX = 1000 (Locked inaccessible region)
|
||||||
|
* We use the first encoding here.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
} else if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) {
|
||||||
|
/* Read only for both M and SU modes */
|
||||||
|
if (SBI_DOMAIN_MEMREGION_IS_SUR_MR(reg->flags))
|
||||||
|
pmp_flags = (PMP_L | PMP_R | PMP_W | PMP_X);
|
||||||
|
|
||||||
|
/* Execute for SU but Read/Execute for M mode */
|
||||||
|
else if (SBI_DOMAIN_MEMREGION_IS_SUX_MRX(reg->flags))
|
||||||
|
/* locked region */
|
||||||
|
pmp_flags = (PMP_L | PMP_W | PMP_X);
|
||||||
|
|
||||||
|
/* Execute only for both M and SU modes */
|
||||||
|
else if (SBI_DOMAIN_MEMREGION_IS_SUX_MX(reg->flags))
|
||||||
|
pmp_flags = (PMP_L | PMP_W);
|
||||||
|
|
||||||
|
/* Read/Write for both M and SU modes */
|
||||||
|
else if (SBI_DOMAIN_MEMREGION_IS_SURW_MRW(reg->flags))
|
||||||
|
pmp_flags = (PMP_W | PMP_X);
|
||||||
|
|
||||||
|
/* Read only for SU mode but Read/Write for M mode */
|
||||||
|
else if (SBI_DOMAIN_MEMREGION_IS_SUR_MRW(reg->flags))
|
||||||
|
pmp_flags = (PMP_W);
|
||||||
|
} else if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
|
||||||
|
/*
|
||||||
|
* When smepmp is supported and used, M region cannot have RWX
|
||||||
|
* permissions on any region.
|
||||||
|
*/
|
||||||
|
if ((reg->flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)
|
||||||
|
== SBI_DOMAIN_MEMREGION_M_RWX) {
|
||||||
|
sbi_printf("%s: M-mode only regions cannot have"
|
||||||
|
"RWX permissions\n", __func__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* M-mode only access regions are always locked */
|
||||||
|
pmp_flags |= PMP_L;
|
||||||
|
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
|
||||||
|
pmp_flags |= PMP_R;
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
|
||||||
|
pmp_flags |= PMP_W;
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
|
||||||
|
pmp_flags |= PMP_X;
|
||||||
|
} else if (SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(reg->flags)) {
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
|
||||||
|
pmp_flags |= PMP_R;
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
|
||||||
|
pmp_flags |= PMP_W;
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
|
||||||
|
pmp_flags |= PMP_X;
|
||||||
|
} else {
|
||||||
|
rstart = reg->base;
|
||||||
|
rend = (reg->order < __riscv_xlen) ? rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||||
|
sbi_printf("%s: Unsupported Smepmp permissions on region 0x%"PRILX"-0x%"PRILX"\n",
|
||||||
|
__func__, rstart, rend);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pmp_flags;
|
||||||
|
}
|
||||||
|
|
||||||
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
||||||
unsigned long addr, unsigned long mode,
|
unsigned long addr, unsigned long mode,
|
||||||
unsigned long access_flags)
|
unsigned long access_flags)
|
||||||
@@ -162,7 +235,11 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
|||||||
rstart + ((1UL << reg->order) - 1) : -1UL;
|
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||||
if (rstart <= addr && addr <= rend) {
|
if (rstart <= addr && addr <= rend) {
|
||||||
rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? true : false;
|
rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? true : false;
|
||||||
if (mmio != rmmio)
|
/*
|
||||||
|
* MMIO devices may appear in regions without the flag set (such as the
|
||||||
|
* default region), but MMIO device regions should not be used as memory.
|
||||||
|
*/
|
||||||
|
if (!mmio && rmmio)
|
||||||
return false;
|
return false;
|
||||||
return ((rrwx & rwx) == rwx) ? true : false;
|
return ((rrwx & rwx) == rwx) ? true : false;
|
||||||
}
|
}
|
||||||
@@ -218,6 +295,19 @@ static bool is_region_compatible(const struct sbi_domain_memregion *regA,
|
|||||||
static bool is_region_before(const struct sbi_domain_memregion *regA,
|
static bool is_region_before(const struct sbi_domain_memregion *regA,
|
||||||
const struct sbi_domain_memregion *regB)
|
const struct sbi_domain_memregion *regB)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Enforce firmware region ordering for memory access
|
||||||
|
* under SmePMP.
|
||||||
|
* Place firmware regions first to ensure consistent
|
||||||
|
* PMP entries during domain context switches.
|
||||||
|
*/
|
||||||
|
if (SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regA->flags) &&
|
||||||
|
!SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regB->flags))
|
||||||
|
return true;
|
||||||
|
if (!SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regA->flags) &&
|
||||||
|
SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regB->flags))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (regA->order < regB->order)
|
if (regA->order < regB->order)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -281,6 +371,17 @@ static void clear_region(struct sbi_domain_memregion* reg)
|
|||||||
sbi_memset(reg, 0x0, sizeof(*reg));
|
sbi_memset(reg, 0x0, sizeof(*reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sbi_domain_used_memregions(const struct sbi_domain *dom)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
struct sbi_domain_memregion *reg;
|
||||||
|
|
||||||
|
sbi_domain_for_each_memregion(dom, reg)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static int sanitize_domain(struct sbi_domain *dom)
|
static int sanitize_domain(struct sbi_domain *dom)
|
||||||
{
|
{
|
||||||
u32 i, j, count;
|
u32 i, j, count;
|
||||||
@@ -319,9 +420,7 @@ static int sanitize_domain(struct sbi_domain *dom)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Count memory regions */
|
/* Count memory regions */
|
||||||
count = 0;
|
count = sbi_domain_used_memregions(dom);
|
||||||
sbi_domain_for_each_memregion(dom, reg)
|
|
||||||
count++;
|
|
||||||
|
|
||||||
/* Check presence of firmware regions */
|
/* Check presence of firmware regions */
|
||||||
if (!dom->fw_region_inited) {
|
if (!dom->fw_region_inited) {
|
||||||
@@ -344,7 +443,7 @@ static int sanitize_domain(struct sbi_domain *dom)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Remove covered regions */
|
/* Remove covered regions */
|
||||||
while(i < (count - 1)) {
|
for (i = 0; i < (count - 1);) {
|
||||||
is_covered = false;
|
is_covered = false;
|
||||||
reg = &dom->regions[i];
|
reg = &dom->regions[i];
|
||||||
|
|
||||||
@@ -464,6 +563,8 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
|||||||
sbi_printf("M: ");
|
sbi_printf("M: ");
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
|
if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
|
||||||
sbi_printf("%cI", (k++) ? ',' : '(');
|
sbi_printf("%cI", (k++) ? ',' : '(');
|
||||||
|
if (reg->flags & SBI_DOMAIN_MEMREGION_FW)
|
||||||
|
sbi_printf("%cF", (k++) ? ',' : '(');
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
|
if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
|
||||||
sbi_printf("%cR", (k++) ? ',' : '(');
|
sbi_printf("%cR", (k++) ? ',' : '(');
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
|
if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
|
||||||
@@ -603,6 +704,7 @@ static int root_add_memregion(const struct sbi_domain_memregion *reg)
|
|||||||
int rc;
|
int rc;
|
||||||
bool reg_merged;
|
bool reg_merged;
|
||||||
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
|
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
|
||||||
|
int root_memregs_count = sbi_domain_used_memregions(&root);
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if (!reg || domain_finalized || !root.regions ||
|
if (!reg || domain_finalized || !root.regions ||
|
||||||
@@ -773,6 +875,7 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
|
|||||||
int rc;
|
int rc;
|
||||||
struct sbi_hartmask *root_hmask;
|
struct sbi_hartmask *root_hmask;
|
||||||
struct sbi_domain_memregion *root_memregs;
|
struct sbi_domain_memregion *root_memregs;
|
||||||
|
int root_memregs_count = 0;
|
||||||
|
|
||||||
SBI_INIT_LIST_HEAD(&domain_list);
|
SBI_INIT_LIST_HEAD(&domain_list);
|
||||||
|
|
||||||
@@ -817,13 +920,15 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
|
|||||||
/* Root domain firmware memory region */
|
/* Root domain firmware memory region */
|
||||||
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
|
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
|
||||||
(SBI_DOMAIN_MEMREGION_M_READABLE |
|
(SBI_DOMAIN_MEMREGION_M_READABLE |
|
||||||
SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
|
SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
|
||||||
|
SBI_DOMAIN_MEMREGION_FW),
|
||||||
&root_memregs[root_memregs_count++]);
|
&root_memregs[root_memregs_count++]);
|
||||||
|
|
||||||
sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
|
sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
|
||||||
(scratch->fw_size - scratch->fw_rw_offset),
|
(scratch->fw_size - scratch->fw_rw_offset),
|
||||||
(SBI_DOMAIN_MEMREGION_M_READABLE |
|
(SBI_DOMAIN_MEMREGION_M_READABLE |
|
||||||
SBI_DOMAIN_MEMREGION_M_WRITABLE),
|
SBI_DOMAIN_MEMREGION_M_WRITABLE |
|
||||||
|
SBI_DOMAIN_MEMREGION_FW),
|
||||||
&root_memregs[root_memregs_count++]);
|
&root_memregs[root_memregs_count++]);
|
||||||
|
|
||||||
root.fw_region_inited = true;
|
root.fw_region_inited = true;
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ struct hart_context {
|
|||||||
unsigned long scounteren;
|
unsigned long scounteren;
|
||||||
/** Supervisor environment configuration register */
|
/** Supervisor environment configuration register */
|
||||||
unsigned long senvcfg;
|
unsigned long senvcfg;
|
||||||
|
/** Supervisor resource management configuration register */
|
||||||
|
unsigned long srmcfg;
|
||||||
|
|
||||||
/** Reference to the owning domain */
|
/** Reference to the owning domain */
|
||||||
struct sbi_domain *dom;
|
struct sbi_domain *dom;
|
||||||
@@ -92,17 +94,23 @@ static void hart_context_set(struct sbi_domain *dom, u32 hartindex,
|
|||||||
*
|
*
|
||||||
* @param ctx pointer to the current HART context
|
* @param ctx pointer to the current HART context
|
||||||
* @param dom_ctx pointer to the target domain context
|
* @param dom_ctx pointer to the target domain context
|
||||||
|
*
|
||||||
|
* @return 0 on success and negative error code on failure
|
||||||
*/
|
*/
|
||||||
static void switch_to_next_domain_context(struct hart_context *ctx,
|
static int switch_to_next_domain_context(struct hart_context *ctx,
|
||||||
struct hart_context *dom_ctx)
|
struct hart_context *dom_ctx)
|
||||||
{
|
{
|
||||||
u32 hartindex = current_hartindex();
|
u32 hartindex = current_hartindex();
|
||||||
struct sbi_trap_context *trap_ctx;
|
struct sbi_trap_context *trap_ctx;
|
||||||
struct sbi_domain *current_dom = ctx->dom;
|
struct sbi_domain *current_dom, *target_dom;
|
||||||
struct sbi_domain *target_dom = dom_ctx->dom;
|
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
|
unsigned int pmp_count = sbi_hart_pmp_count(scratch);
|
||||||
|
|
||||||
|
if (!ctx || !dom_ctx || ctx == dom_ctx)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
current_dom = ctx->dom;
|
||||||
|
target_dom = dom_ctx->dom;
|
||||||
/* Assign current hart to target domain */
|
/* Assign current hart to target domain */
|
||||||
spin_lock(¤t_dom->assigned_harts_lock);
|
spin_lock(¤t_dom->assigned_harts_lock);
|
||||||
sbi_hartmask_clear_hartindex(hartindex, ¤t_dom->assigned_harts);
|
sbi_hartmask_clear_hartindex(hartindex, ¤t_dom->assigned_harts);
|
||||||
@@ -116,6 +124,10 @@ static void switch_to_next_domain_context(struct hart_context *ctx,
|
|||||||
|
|
||||||
/* Reconfigure PMP settings for the new domain */
|
/* Reconfigure PMP settings for the new domain */
|
||||||
for (int i = 0; i < pmp_count; i++) {
|
for (int i = 0; i < pmp_count; i++) {
|
||||||
|
/* Don't revoke firmware access permissions */
|
||||||
|
if (sbi_hart_smepmp_is_fw_region(i))
|
||||||
|
continue;
|
||||||
|
|
||||||
sbi_platform_pmp_disable(sbi_platform_thishart_ptr(), i);
|
sbi_platform_pmp_disable(sbi_platform_thishart_ptr(), i);
|
||||||
pmp_disable(i);
|
pmp_disable(i);
|
||||||
}
|
}
|
||||||
@@ -135,6 +147,8 @@ static void switch_to_next_domain_context(struct hart_context *ctx,
|
|||||||
ctx->scounteren = csr_swap(CSR_SCOUNTEREN, dom_ctx->scounteren);
|
ctx->scounteren = csr_swap(CSR_SCOUNTEREN, dom_ctx->scounteren);
|
||||||
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
|
||||||
ctx->senvcfg = csr_swap(CSR_SENVCFG, dom_ctx->senvcfg);
|
ctx->senvcfg = csr_swap(CSR_SENVCFG, dom_ctx->senvcfg);
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSQOSID))
|
||||||
|
ctx->srmcfg = csr_swap(CSR_SRMCFG, dom_ctx->srmcfg);
|
||||||
|
|
||||||
/* Save current trap state and restore target domain's trap state */
|
/* Save current trap state and restore target domain's trap state */
|
||||||
trap_ctx = sbi_trap_get_context(scratch);
|
trap_ctx = sbi_trap_get_context(scratch);
|
||||||
@@ -156,13 +170,57 @@ static void switch_to_next_domain_context(struct hart_context *ctx,
|
|||||||
else
|
else
|
||||||
sbi_hsm_hart_stop(scratch, true);
|
sbi_hsm_hart_stop(scratch, true);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hart_context_init(u32 hartindex)
|
||||||
|
{
|
||||||
|
struct hart_context *ctx;
|
||||||
|
struct sbi_domain *dom;
|
||||||
|
|
||||||
|
sbi_domain_for_each(dom) {
|
||||||
|
if (!sbi_hartmask_test_hartindex(hartindex,
|
||||||
|
dom->possible_harts))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ctx = sbi_zalloc(sizeof(struct hart_context));
|
||||||
|
if (!ctx)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
/* Bind context and domain */
|
||||||
|
ctx->dom = dom;
|
||||||
|
hart_context_set(dom, hartindex, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_domain_context_enter(struct sbi_domain *dom)
|
int sbi_domain_context_enter(struct sbi_domain *dom)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
struct hart_context *dom_ctx;
|
||||||
struct hart_context *ctx = hart_context_thishart_get();
|
struct hart_context *ctx = hart_context_thishart_get();
|
||||||
struct hart_context *dom_ctx = hart_context_get(dom, current_hartindex());
|
|
||||||
|
|
||||||
|
/* Target domain must not be same as the current domain */
|
||||||
|
if (!dom || dom == sbi_domain_thishart_ptr())
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it's first time to call `enter` on the current hart, no
|
||||||
|
* context allocated before. Allocate context for each valid
|
||||||
|
* domain on the current hart.
|
||||||
|
*/
|
||||||
|
if (!ctx) {
|
||||||
|
rc = hart_context_init(current_hartindex());
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
ctx = hart_context_thishart_get();
|
||||||
|
if (!ctx)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dom_ctx = hart_context_get(dom, current_hartindex());
|
||||||
/* Validate the domain context existence */
|
/* Validate the domain context existence */
|
||||||
if (!dom_ctx)
|
if (!dom_ctx)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
@@ -170,13 +228,12 @@ int sbi_domain_context_enter(struct sbi_domain *dom)
|
|||||||
/* Update target context's previous context to indicate the caller */
|
/* Update target context's previous context to indicate the caller */
|
||||||
dom_ctx->prev_ctx = ctx;
|
dom_ctx->prev_ctx = ctx;
|
||||||
|
|
||||||
switch_to_next_domain_context(ctx, dom_ctx);
|
return switch_to_next_domain_context(ctx, dom_ctx);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_domain_context_exit(void)
|
int sbi_domain_context_exit(void)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
u32 hartindex = current_hartindex();
|
u32 hartindex = current_hartindex();
|
||||||
struct sbi_domain *dom;
|
struct sbi_domain *dom;
|
||||||
struct hart_context *ctx = hart_context_thishart_get();
|
struct hart_context *ctx = hart_context_thishart_get();
|
||||||
@@ -188,21 +245,13 @@ int sbi_domain_context_exit(void)
|
|||||||
* its context on the current hart if valid.
|
* its context on the current hart if valid.
|
||||||
*/
|
*/
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
sbi_domain_for_each(dom) {
|
rc = hart_context_init(current_hartindex());
|
||||||
if (!sbi_hartmask_test_hartindex(hartindex,
|
if (rc)
|
||||||
dom->possible_harts))
|
return rc;
|
||||||
continue;
|
|
||||||
|
|
||||||
dom_ctx = sbi_zalloc(sizeof(struct hart_context));
|
|
||||||
if (!dom_ctx)
|
|
||||||
return SBI_ENOMEM;
|
|
||||||
|
|
||||||
/* Bind context and domain */
|
|
||||||
dom_ctx->dom = dom;
|
|
||||||
hart_context_set(dom, hartindex, dom_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = hart_context_thishart_get();
|
ctx = hart_context_thishart_get();
|
||||||
|
if (!ctx)
|
||||||
|
return SBI_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dom_ctx = ctx->prev_ctx;
|
dom_ctx = ctx->prev_ctx;
|
||||||
@@ -226,9 +275,7 @@ int sbi_domain_context_exit(void)
|
|||||||
if (!dom_ctx)
|
if (!dom_ctx)
|
||||||
dom_ctx = hart_context_get(&root, hartindex);
|
dom_ctx = hart_context_get(&root, hartindex);
|
||||||
|
|
||||||
switch_to_next_domain_context(ctx, dom_ctx);
|
return switch_to_next_domain_context(ctx, dom_ctx);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_domain_context_init(void)
|
int sbi_domain_context_init(void)
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ extern void __sbi_expected_trap_hext(void);
|
|||||||
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
|
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
|
||||||
|
|
||||||
static unsigned long hart_features_offset;
|
static unsigned long hart_features_offset;
|
||||||
|
static DECLARE_BITMAP(fw_smepmp_ids, PMP_COUNT);
|
||||||
|
static bool fw_smepmp_ids_inited;
|
||||||
|
|
||||||
static void mstatus_init(struct sbi_scratch *scratch)
|
static void mstatus_init(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
@@ -110,6 +112,11 @@ static void mstatus_init(struct sbi_scratch *scratch)
|
|||||||
else
|
else
|
||||||
mstateen_val &= ~SMSTATEEN0_CTR;
|
mstateen_val &= ~SMSTATEEN0_CTR;
|
||||||
|
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSQOSID))
|
||||||
|
mstateen_val |= SMSTATEEN0_SRMCFG;
|
||||||
|
else
|
||||||
|
mstateen_val &= ~SMSTATEEN0_SRMCFG;
|
||||||
|
|
||||||
csr_write64(CSR_MSTATEEN0, mstateen_val);
|
csr_write64(CSR_MSTATEEN0, mstateen_val);
|
||||||
csr_write64(CSR_MSTATEEN1, SMSTATEEN_STATEN);
|
csr_write64(CSR_MSTATEEN1, SMSTATEEN_STATEN);
|
||||||
csr_write64(CSR_MSTATEEN2, SMSTATEEN_STATEN);
|
csr_write64(CSR_MSTATEEN2, SMSTATEEN_STATEN);
|
||||||
@@ -301,67 +308,12 @@ unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
|
|||||||
return hfeatures->mhpm_bits;
|
return hfeatures->mhpm_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
bool sbi_hart_smepmp_is_fw_region(unsigned int pmp_idx)
|
||||||
* Returns Smepmp flags for a given domain and region based on permissions.
|
|
||||||
*/
|
|
||||||
static unsigned int sbi_hart_get_smepmp_flags(struct sbi_scratch *scratch,
|
|
||||||
struct sbi_domain *dom,
|
|
||||||
struct sbi_domain_memregion *reg)
|
|
||||||
{
|
{
|
||||||
unsigned int pmp_flags = 0;
|
if (!fw_smepmp_ids_inited)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) {
|
return bitmap_test(fw_smepmp_ids, pmp_idx) ? true : false;
|
||||||
/* Read only for both M and SU modes */
|
|
||||||
if (SBI_DOMAIN_MEMREGION_IS_SUR_MR(reg->flags))
|
|
||||||
pmp_flags = (PMP_L | PMP_R | PMP_W | PMP_X);
|
|
||||||
|
|
||||||
/* Execute for SU but Read/Execute for M mode */
|
|
||||||
else if (SBI_DOMAIN_MEMREGION_IS_SUX_MRX(reg->flags))
|
|
||||||
/* locked region */
|
|
||||||
pmp_flags = (PMP_L | PMP_W | PMP_X);
|
|
||||||
|
|
||||||
/* Execute only for both M and SU modes */
|
|
||||||
else if (SBI_DOMAIN_MEMREGION_IS_SUX_MX(reg->flags))
|
|
||||||
pmp_flags = (PMP_L | PMP_W);
|
|
||||||
|
|
||||||
/* Read/Write for both M and SU modes */
|
|
||||||
else if (SBI_DOMAIN_MEMREGION_IS_SURW_MRW(reg->flags))
|
|
||||||
pmp_flags = (PMP_W | PMP_X);
|
|
||||||
|
|
||||||
/* Read only for SU mode but Read/Write for M mode */
|
|
||||||
else if (SBI_DOMAIN_MEMREGION_IS_SUR_MRW(reg->flags))
|
|
||||||
pmp_flags = (PMP_W);
|
|
||||||
} else if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
|
|
||||||
/*
|
|
||||||
* When smepmp is supported and used, M region cannot have RWX
|
|
||||||
* permissions on any region.
|
|
||||||
*/
|
|
||||||
if ((reg->flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)
|
|
||||||
== SBI_DOMAIN_MEMREGION_M_RWX) {
|
|
||||||
sbi_printf("%s: M-mode only regions cannot have"
|
|
||||||
"RWX permissions\n", __func__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* M-mode only access regions are always locked */
|
|
||||||
pmp_flags |= PMP_L;
|
|
||||||
|
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
|
|
||||||
pmp_flags |= PMP_R;
|
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
|
|
||||||
pmp_flags |= PMP_W;
|
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
|
|
||||||
pmp_flags |= PMP_X;
|
|
||||||
} else if (SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(reg->flags)) {
|
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
|
|
||||||
pmp_flags |= PMP_R;
|
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
|
|
||||||
pmp_flags |= PMP_W;
|
|
||||||
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
|
|
||||||
pmp_flags |= PMP_X;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pmp_flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sbi_hart_smepmp_set(struct sbi_scratch *scratch,
|
static void sbi_hart_smepmp_set(struct sbi_scratch *scratch,
|
||||||
@@ -387,6 +339,15 @@ static void sbi_hart_smepmp_set(struct sbi_scratch *scratch,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_valid_pmp_idx(unsigned int pmp_count, unsigned int pmp_idx)
|
||||||
|
{
|
||||||
|
if (pmp_count > pmp_idx)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
sbi_printf("error: insufficient PMP entries\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
|
static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
|
||||||
unsigned int pmp_count,
|
unsigned int pmp_count,
|
||||||
unsigned int pmp_log2gran,
|
unsigned int pmp_log2gran,
|
||||||
@@ -411,8 +372,8 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
|
|||||||
/* Skip reserved entry */
|
/* Skip reserved entry */
|
||||||
if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
|
if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
|
||||||
pmp_idx++;
|
pmp_idx++;
|
||||||
if (pmp_count <= pmp_idx)
|
if (!is_valid_pmp_idx(pmp_count, pmp_idx))
|
||||||
break;
|
return SBI_EFAIL;
|
||||||
|
|
||||||
/* Skip shared and SU-only regions */
|
/* Skip shared and SU-only regions */
|
||||||
if (!SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
|
if (!SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
|
||||||
@@ -420,14 +381,31 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg);
|
/*
|
||||||
if (!pmp_flags)
|
* Track firmware PMP entries to preserve them during
|
||||||
return 0;
|
* domain switches. Under SmePMP, M-mode requires
|
||||||
|
* explicit PMP entries to access firmware code/data.
|
||||||
|
* These entries must remain enabled across domain
|
||||||
|
* context switches to prevent M-mode access faults.
|
||||||
|
*/
|
||||||
|
if (SBI_DOMAIN_MEMREGION_IS_FIRMWARE(reg->flags)) {
|
||||||
|
if (fw_smepmp_ids_inited) {
|
||||||
|
/* Check inconsistent firmware region */
|
||||||
|
if (!sbi_hart_smepmp_is_fw_region(pmp_idx))
|
||||||
|
return SBI_EINVAL;
|
||||||
|
} else {
|
||||||
|
bitmap_set(fw_smepmp_ids, pmp_idx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pmp_flags = sbi_domain_get_smepmp_flags(reg);
|
||||||
|
|
||||||
sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
|
sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
|
||||||
pmp_log2gran, pmp_addr_max);
|
pmp_log2gran, pmp_addr_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fw_smepmp_ids_inited = true;
|
||||||
|
|
||||||
/* Set the MML to enforce new encoding */
|
/* Set the MML to enforce new encoding */
|
||||||
csr_set(CSR_MSECCFG, MSECCFG_MML);
|
csr_set(CSR_MSECCFG, MSECCFG_MML);
|
||||||
|
|
||||||
@@ -437,8 +415,8 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
|
|||||||
/* Skip reserved entry */
|
/* Skip reserved entry */
|
||||||
if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
|
if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
|
||||||
pmp_idx++;
|
pmp_idx++;
|
||||||
if (pmp_count <= pmp_idx)
|
if (!is_valid_pmp_idx(pmp_count, pmp_idx))
|
||||||
break;
|
return SBI_EFAIL;
|
||||||
|
|
||||||
/* Skip M-only regions */
|
/* Skip M-only regions */
|
||||||
if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
|
if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
|
||||||
@@ -446,9 +424,7 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg);
|
pmp_flags = sbi_domain_get_smepmp_flags(reg);
|
||||||
if (!pmp_flags)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
|
sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
|
||||||
pmp_log2gran, pmp_addr_max);
|
pmp_log2gran, pmp_addr_max);
|
||||||
@@ -474,8 +450,8 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
|
|||||||
unsigned long pmp_addr;
|
unsigned long pmp_addr;
|
||||||
|
|
||||||
sbi_domain_for_each_memregion(dom, reg) {
|
sbi_domain_for_each_memregion(dom, reg) {
|
||||||
if (pmp_count <= pmp_idx)
|
if (!is_valid_pmp_idx(pmp_count, pmp_idx))
|
||||||
break;
|
return SBI_EFAIL;
|
||||||
|
|
||||||
pmp_flags = 0;
|
pmp_flags = 0;
|
||||||
|
|
||||||
@@ -714,7 +690,10 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
|
|||||||
__SBI_HART_EXT_DATA(ssdbltrp, SBI_HART_EXT_SSDBLTRP),
|
__SBI_HART_EXT_DATA(ssdbltrp, SBI_HART_EXT_SSDBLTRP),
|
||||||
__SBI_HART_EXT_DATA(smctr, SBI_HART_EXT_SMCTR),
|
__SBI_HART_EXT_DATA(smctr, SBI_HART_EXT_SMCTR),
|
||||||
__SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
|
__SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
|
||||||
|
__SBI_HART_EXT_DATA(ssqosid, SBI_HART_EXT_SSQOSID),
|
||||||
__SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
|
__SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
|
||||||
|
__SBI_HART_EXT_DATA(xsfcflushdlone, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1),
|
||||||
|
__SBI_HART_EXT_DATA(xsfcease, SBI_HART_EXT_XSIFIVE_CEASE),
|
||||||
};
|
};
|
||||||
|
|
||||||
_Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
|
_Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
|
||||||
@@ -1037,10 +1016,6 @@ int sbi_hart_reinit(struct sbi_scratch *scratch)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc = delegate_traps(scratch);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1068,6 +1043,10 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
rc = delegate_traps(scratch);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
return sbi_hart_reinit(scratch);
|
return sbi_hart_reinit(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
/* Minimum size and alignment of heap allocations */
|
/* Minimum size and alignment of heap allocations */
|
||||||
#define HEAP_ALLOC_ALIGN 64
|
#define HEAP_ALLOC_ALIGN 64
|
||||||
#define HEAP_HOUSEKEEPING_FACTOR 16
|
|
||||||
|
/* Number of heap nodes to allocate at once */
|
||||||
|
#define HEAP_NODE_BATCH_SIZE 8
|
||||||
|
|
||||||
struct heap_node {
|
struct heap_node {
|
||||||
struct sbi_dlist head;
|
struct sbi_dlist head;
|
||||||
@@ -28,20 +30,50 @@ struct sbi_heap_control {
|
|||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
unsigned long base;
|
unsigned long base;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
unsigned long hkbase;
|
unsigned long resv;
|
||||||
unsigned long hksize;
|
|
||||||
struct sbi_dlist free_node_list;
|
struct sbi_dlist free_node_list;
|
||||||
struct sbi_dlist free_space_list;
|
struct sbi_dlist free_space_list;
|
||||||
struct sbi_dlist used_space_list;
|
struct sbi_dlist used_space_list;
|
||||||
|
struct heap_node init_free_space_node;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sbi_heap_control global_hpctrl;
|
struct sbi_heap_control global_hpctrl;
|
||||||
|
|
||||||
|
static bool alloc_nodes(struct sbi_heap_control *hpctrl)
|
||||||
|
{
|
||||||
|
size_t size = HEAP_NODE_BATCH_SIZE * sizeof(struct heap_node);
|
||||||
|
struct heap_node *n, *new = NULL;
|
||||||
|
|
||||||
|
/* alloc_with_align() requires at most two free nodes */
|
||||||
|
if (hpctrl->free_node_list.next != hpctrl->free_node_list.prev)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
sbi_list_for_each_entry_reverse(n, &hpctrl->free_space_list, head) {
|
||||||
|
if (n->size >= size) {
|
||||||
|
n->size -= size;
|
||||||
|
if (!n->size) {
|
||||||
|
sbi_list_del(&n->head);
|
||||||
|
sbi_list_add_tail(&n->head, &hpctrl->free_node_list);
|
||||||
|
}
|
||||||
|
new = (void *)(n->addr + n->size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!new)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < HEAP_NODE_BATCH_SIZE; i++)
|
||||||
|
sbi_list_add_tail(&new[i].head, &hpctrl->free_node_list);
|
||||||
|
hpctrl->resv += size;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void *alloc_with_align(struct sbi_heap_control *hpctrl,
|
static void *alloc_with_align(struct sbi_heap_control *hpctrl,
|
||||||
size_t align, size_t size)
|
size_t align, size_t size)
|
||||||
{
|
{
|
||||||
void *ret = NULL;
|
void *ret = NULL;
|
||||||
struct heap_node *n, *np, *rem;
|
struct heap_node *n, *np;
|
||||||
unsigned long lowest_aligned;
|
unsigned long lowest_aligned;
|
||||||
size_t pad;
|
size_t pad;
|
||||||
|
|
||||||
@@ -53,6 +85,10 @@ static void *alloc_with_align(struct sbi_heap_control *hpctrl,
|
|||||||
|
|
||||||
spin_lock(&hpctrl->lock);
|
spin_lock(&hpctrl->lock);
|
||||||
|
|
||||||
|
/* Ensure at least two free nodes are available for use below */
|
||||||
|
if (!alloc_nodes(hpctrl))
|
||||||
|
goto out;
|
||||||
|
|
||||||
np = NULL;
|
np = NULL;
|
||||||
sbi_list_for_each_entry(n, &hpctrl->free_space_list, head) {
|
sbi_list_for_each_entry(n, &hpctrl->free_space_list, head) {
|
||||||
lowest_aligned = ROUNDUP(n->addr, align);
|
lowest_aligned = ROUNDUP(n->addr, align);
|
||||||
@@ -67,54 +103,33 @@ static void *alloc_with_align(struct sbi_heap_control *hpctrl,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (pad) {
|
if (pad) {
|
||||||
if (sbi_list_empty(&hpctrl->free_node_list)) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = sbi_list_first_entry(&hpctrl->free_node_list,
|
n = sbi_list_first_entry(&hpctrl->free_node_list,
|
||||||
struct heap_node, head);
|
struct heap_node, head);
|
||||||
sbi_list_del(&n->head);
|
sbi_list_del(&n->head);
|
||||||
|
|
||||||
if ((size + pad < np->size) &&
|
|
||||||
!sbi_list_empty(&hpctrl->free_node_list)) {
|
|
||||||
rem = sbi_list_first_entry(&hpctrl->free_node_list,
|
|
||||||
struct heap_node, head);
|
|
||||||
sbi_list_del(&rem->head);
|
|
||||||
rem->addr = np->addr + (size + pad);
|
|
||||||
rem->size = np->size - (size + pad);
|
|
||||||
sbi_list_add_tail(&rem->head,
|
|
||||||
&hpctrl->free_space_list);
|
|
||||||
} else if (size + pad != np->size) {
|
|
||||||
/* Can't allocate, return n */
|
|
||||||
sbi_list_add(&n->head, &hpctrl->free_node_list);
|
|
||||||
ret = NULL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
n->addr = lowest_aligned;
|
|
||||||
n->size = size;
|
|
||||||
sbi_list_add_tail(&n->head, &hpctrl->used_space_list);
|
|
||||||
|
|
||||||
np->size = pad;
|
|
||||||
ret = (void *)n->addr;
|
|
||||||
} else {
|
|
||||||
if ((size < np->size) &&
|
|
||||||
!sbi_list_empty(&hpctrl->free_node_list)) {
|
|
||||||
n = sbi_list_first_entry(&hpctrl->free_node_list,
|
|
||||||
struct heap_node, head);
|
|
||||||
sbi_list_del(&n->head);
|
|
||||||
n->addr = np->addr;
|
n->addr = np->addr;
|
||||||
n->size = size;
|
n->size = pad;
|
||||||
np->addr += size;
|
sbi_list_add_tail(&n->head, &np->head);
|
||||||
np->size -= size;
|
|
||||||
sbi_list_add_tail(&n->head, &hpctrl->used_space_list);
|
np->addr += pad;
|
||||||
ret = (void *)n->addr;
|
np->size -= pad;
|
||||||
} else if (size == np->size) {
|
}
|
||||||
|
|
||||||
|
if (size < np->size) {
|
||||||
|
n = sbi_list_first_entry(&hpctrl->free_node_list,
|
||||||
|
struct heap_node, head);
|
||||||
|
sbi_list_del(&n->head);
|
||||||
|
|
||||||
|
n->addr = np->addr + size;
|
||||||
|
n->size = np->size - size;
|
||||||
|
sbi_list_add(&n->head, &np->head);
|
||||||
|
|
||||||
|
np->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
sbi_list_del(&np->head);
|
sbi_list_del(&np->head);
|
||||||
sbi_list_add_tail(&np->head, &hpctrl->used_space_list);
|
sbi_list_add_tail(&np->head, &hpctrl->used_space_list);
|
||||||
ret = (void *)np->addr;
|
ret = (void *)np->addr;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock(&hpctrl->lock);
|
spin_unlock(&hpctrl->lock);
|
||||||
@@ -216,44 +231,32 @@ unsigned long sbi_heap_free_space_from(struct sbi_heap_control *hpctrl)
|
|||||||
|
|
||||||
unsigned long sbi_heap_used_space_from(struct sbi_heap_control *hpctrl)
|
unsigned long sbi_heap_used_space_from(struct sbi_heap_control *hpctrl)
|
||||||
{
|
{
|
||||||
return hpctrl->size - hpctrl->hksize - sbi_heap_free_space();
|
return hpctrl->size - hpctrl->resv - sbi_heap_free_space();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long sbi_heap_reserved_space_from(struct sbi_heap_control *hpctrl)
|
unsigned long sbi_heap_reserved_space_from(struct sbi_heap_control *hpctrl)
|
||||||
{
|
{
|
||||||
return hpctrl->hksize;
|
return hpctrl->resv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_heap_init_new(struct sbi_heap_control *hpctrl, unsigned long base,
|
int sbi_heap_init_new(struct sbi_heap_control *hpctrl, unsigned long base,
|
||||||
unsigned long size)
|
unsigned long size)
|
||||||
{
|
{
|
||||||
unsigned long i;
|
|
||||||
struct heap_node *n;
|
struct heap_node *n;
|
||||||
|
|
||||||
/* Initialize heap control */
|
/* Initialize heap control */
|
||||||
SPIN_LOCK_INIT(hpctrl->lock);
|
SPIN_LOCK_INIT(hpctrl->lock);
|
||||||
hpctrl->base = base;
|
hpctrl->base = base;
|
||||||
hpctrl->size = size;
|
hpctrl->size = size;
|
||||||
hpctrl->hkbase = hpctrl->base;
|
hpctrl->resv = 0;
|
||||||
hpctrl->hksize = hpctrl->size / HEAP_HOUSEKEEPING_FACTOR;
|
|
||||||
hpctrl->hksize &= ~((unsigned long)HEAP_BASE_ALIGN - 1);
|
|
||||||
SBI_INIT_LIST_HEAD(&hpctrl->free_node_list);
|
SBI_INIT_LIST_HEAD(&hpctrl->free_node_list);
|
||||||
SBI_INIT_LIST_HEAD(&hpctrl->free_space_list);
|
SBI_INIT_LIST_HEAD(&hpctrl->free_space_list);
|
||||||
SBI_INIT_LIST_HEAD(&hpctrl->used_space_list);
|
SBI_INIT_LIST_HEAD(&hpctrl->used_space_list);
|
||||||
|
|
||||||
/* Prepare free node list */
|
|
||||||
for (i = 0; i < (hpctrl->hksize / sizeof(*n)); i++) {
|
|
||||||
n = (struct heap_node *)(hpctrl->hkbase + (sizeof(*n) * i));
|
|
||||||
n->addr = n->size = 0;
|
|
||||||
sbi_list_add_tail(&n->head, &hpctrl->free_node_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare free space list */
|
/* Prepare free space list */
|
||||||
n = sbi_list_first_entry(&hpctrl->free_node_list,
|
n = &hpctrl->init_free_space_node;
|
||||||
struct heap_node, head);
|
n->addr = base;
|
||||||
sbi_list_del(&n->head);
|
n->size = size;
|
||||||
n->addr = hpctrl->hkbase + hpctrl->hksize;
|
|
||||||
n->size = hpctrl->size - hpctrl->hksize;
|
|
||||||
sbi_list_add_tail(&n->head, &hpctrl->free_space_list);
|
sbi_list_add_tail(&n->head, &hpctrl->free_space_list);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -47,10 +47,8 @@ struct sbi_hsm_data {
|
|||||||
unsigned long saved_mie;
|
unsigned long saved_mie;
|
||||||
unsigned long saved_mip;
|
unsigned long saved_mip;
|
||||||
unsigned long saved_medeleg;
|
unsigned long saved_medeleg;
|
||||||
unsigned long saved_menvcfg;
|
unsigned long saved_mideleg;
|
||||||
#if __riscv_xlen == 32
|
u64 saved_menvcfg;
|
||||||
unsigned long saved_menvcfgh;
|
|
||||||
#endif
|
|
||||||
atomic_t start_ticket;
|
atomic_t start_ticket;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -366,7 +364,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
|||||||
(hsm_device_has_hart_secondary_boot() && !init_count)) {
|
(hsm_device_has_hart_secondary_boot() && !init_count)) {
|
||||||
rc = hsm_device_hart_start(hartid, scratch->warmboot_addr);
|
rc = hsm_device_hart_start(hartid, scratch->warmboot_addr);
|
||||||
} else {
|
} else {
|
||||||
rc = sbi_ipi_raw_send(hartindex);
|
rc = sbi_ipi_raw_send(hartindex, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@@ -429,12 +427,9 @@ void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
|
|||||||
hdata->saved_mie = csr_read(CSR_MIE);
|
hdata->saved_mie = csr_read(CSR_MIE);
|
||||||
hdata->saved_mip = csr_read(CSR_MIP) & (MIP_SSIP | MIP_STIP);
|
hdata->saved_mip = csr_read(CSR_MIP) & (MIP_SSIP | MIP_STIP);
|
||||||
hdata->saved_medeleg = csr_read(CSR_MEDELEG);
|
hdata->saved_medeleg = csr_read(CSR_MEDELEG);
|
||||||
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12) {
|
hdata->saved_mideleg = csr_read(CSR_MIDELEG);
|
||||||
#if __riscv_xlen == 32
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
|
||||||
hdata->saved_menvcfgh = csr_read(CSR_MENVCFGH);
|
hdata->saved_menvcfg = csr_read64(CSR_MENVCFG);
|
||||||
#endif
|
|
||||||
hdata->saved_menvcfg = csr_read(CSR_MENVCFG);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
|
static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
|
||||||
@@ -442,12 +437,9 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
|
|||||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||||
hart_data_offset);
|
hart_data_offset);
|
||||||
|
|
||||||
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12) {
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12)
|
||||||
csr_write(CSR_MENVCFG, hdata->saved_menvcfg);
|
csr_write64(CSR_MENVCFG, hdata->saved_menvcfg);
|
||||||
#if __riscv_xlen == 32
|
csr_write(CSR_MIDELEG, hdata->saved_mideleg);
|
||||||
csr_write(CSR_MENVCFGH, hdata->saved_menvcfgh);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
csr_write(CSR_MEDELEG, hdata->saved_medeleg);
|
csr_write(CSR_MEDELEG, hdata->saved_medeleg);
|
||||||
csr_write(CSR_MIE, hdata->saved_mie);
|
csr_write(CSR_MIE, hdata->saved_mie);
|
||||||
csr_set(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
|
csr_set(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
|
||||||
@@ -463,6 +455,9 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
|
|||||||
SBI_HSM_STATE_RESUME_PENDING))
|
SBI_HSM_STATE_RESUME_PENDING))
|
||||||
sbi_hart_hang();
|
sbi_hart_hang();
|
||||||
|
|
||||||
|
if (sbi_system_is_suspended())
|
||||||
|
sbi_system_resume();
|
||||||
|
else
|
||||||
hsm_device_hart_resume();
|
hsm_device_hart_resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -507,7 +507,7 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
if (hstate == SBI_HSM_STATE_SUSPENDED) {
|
if (hstate == SBI_HSM_STATE_SUSPENDED) {
|
||||||
init_warm_resume(scratch, hartid);
|
init_warm_resume(scratch, hartid);
|
||||||
} else {
|
} else {
|
||||||
sbi_ipi_raw_clear();
|
sbi_ipi_raw_clear(true);
|
||||||
init_warm_startup(scratch, hartid);
|
init_warm_startup(scratch, hartid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,11 @@
|
|||||||
#include <sbi/sbi_domain.h>
|
#include <sbi/sbi_domain.h>
|
||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_hart.h>
|
#include <sbi/sbi_hart.h>
|
||||||
|
#include <sbi/sbi_heap.h>
|
||||||
#include <sbi/sbi_hsm.h>
|
#include <sbi/sbi_hsm.h>
|
||||||
#include <sbi/sbi_init.h>
|
#include <sbi/sbi_init.h>
|
||||||
#include <sbi/sbi_ipi.h>
|
#include <sbi/sbi_ipi.h>
|
||||||
|
#include <sbi/sbi_list.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_pmu.h>
|
#include <sbi/sbi_pmu.h>
|
||||||
#include <sbi/sbi_string.h>
|
#include <sbi/sbi_string.h>
|
||||||
@@ -32,8 +34,14 @@ _Static_assert(
|
|||||||
"type of sbi_ipi_data.ipi_type has changed, please redefine SBI_IPI_EVENT_MAX"
|
"type of sbi_ipi_data.ipi_type has changed, please redefine SBI_IPI_EVENT_MAX"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
struct sbi_ipi_device_node {
|
||||||
|
struct sbi_dlist head;
|
||||||
|
const struct sbi_ipi_device *dev;
|
||||||
|
};
|
||||||
|
|
||||||
static unsigned long ipi_data_off;
|
static unsigned long ipi_data_off;
|
||||||
static const struct sbi_ipi_device *ipi_dev = NULL;
|
static const struct sbi_ipi_device *ipi_dev = NULL;
|
||||||
|
static SBI_LIST_HEAD(ipi_dev_node_list);
|
||||||
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
|
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
|
||||||
|
|
||||||
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
|
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
|
||||||
@@ -80,7 +88,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
|
|||||||
*/
|
*/
|
||||||
if (!__atomic_fetch_or(&ipi_data->ipi_type,
|
if (!__atomic_fetch_or(&ipi_data->ipi_type,
|
||||||
BIT(event), __ATOMIC_RELAXED))
|
BIT(event), __ATOMIC_RELAXED))
|
||||||
ret = sbi_ipi_raw_send(remote_hartindex);
|
ret = sbi_ipi_raw_send(remote_hartindex, false);
|
||||||
|
|
||||||
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
|
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
|
||||||
|
|
||||||
@@ -248,7 +256,7 @@ void sbi_ipi_process(void)
|
|||||||
sbi_scratch_offset_ptr(scratch, ipi_data_off);
|
sbi_scratch_offset_ptr(scratch, ipi_data_off);
|
||||||
|
|
||||||
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_RECVD);
|
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_RECVD);
|
||||||
sbi_ipi_raw_clear();
|
sbi_ipi_raw_clear(false);
|
||||||
|
|
||||||
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
|
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
|
||||||
ipi_event = 0;
|
ipi_event = 0;
|
||||||
@@ -263,8 +271,10 @@ void sbi_ipi_process(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_ipi_raw_send(u32 hartindex)
|
int sbi_ipi_raw_send(u32 hartindex, bool all_devices)
|
||||||
{
|
{
|
||||||
|
struct sbi_ipi_device_node *entry;
|
||||||
|
|
||||||
if (!ipi_dev || !ipi_dev->ipi_send)
|
if (!ipi_dev || !ipi_dev->ipi_send)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
@@ -279,14 +289,31 @@ int sbi_ipi_raw_send(u32 hartindex)
|
|||||||
*/
|
*/
|
||||||
wmb();
|
wmb();
|
||||||
|
|
||||||
|
if (all_devices) {
|
||||||
|
sbi_list_for_each_entry(entry, &ipi_dev_node_list, head) {
|
||||||
|
if (entry->dev->ipi_send)
|
||||||
|
entry->dev->ipi_send(hartindex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
ipi_dev->ipi_send(hartindex);
|
ipi_dev->ipi_send(hartindex);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_ipi_raw_clear(void)
|
void sbi_ipi_raw_clear(bool all_devices)
|
||||||
{
|
{
|
||||||
|
struct sbi_ipi_device_node *entry;
|
||||||
|
|
||||||
|
if (all_devices) {
|
||||||
|
sbi_list_for_each_entry(entry, &ipi_dev_node_list, head) {
|
||||||
|
if (entry->dev->ipi_clear)
|
||||||
|
entry->dev->ipi_clear();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (ipi_dev && ipi_dev->ipi_clear)
|
if (ipi_dev && ipi_dev->ipi_clear)
|
||||||
ipi_dev->ipi_clear();
|
ipi_dev->ipi_clear();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that memory or MMIO writes after this
|
* Ensure that memory or MMIO writes after this
|
||||||
@@ -305,11 +332,21 @@ const struct sbi_ipi_device *sbi_ipi_get_device(void)
|
|||||||
return ipi_dev;
|
return ipi_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_ipi_set_device(const struct sbi_ipi_device *dev)
|
void sbi_ipi_add_device(const struct sbi_ipi_device *dev)
|
||||||
{
|
{
|
||||||
if (!dev || ipi_dev)
|
struct sbi_ipi_device_node *entry;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
entry = sbi_zalloc(sizeof(*entry));
|
||||||
|
if (!entry)
|
||||||
|
return;
|
||||||
|
SBI_INIT_LIST_HEAD(&entry->head);
|
||||||
|
entry->dev = dev;
|
||||||
|
sbi_list_add_tail(&entry->head, &ipi_dev_node_list);
|
||||||
|
|
||||||
|
if (!ipi_dev || ipi_dev->rating < dev->rating)
|
||||||
ipi_dev = dev;
|
ipi_dev = dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,11 +367,6 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
ipi_halt_event = ret;
|
ipi_halt_event = ret;
|
||||||
|
|
||||||
/* Initialize platform IPI support */
|
|
||||||
ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
} else {
|
} else {
|
||||||
if (!ipi_data_off)
|
if (!ipi_data_off)
|
||||||
return SBI_ENOMEM;
|
return SBI_ENOMEM;
|
||||||
@@ -347,7 +379,7 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
|
|||||||
ipi_data->ipi_type = 0x00;
|
ipi_data->ipi_type = 0x00;
|
||||||
|
|
||||||
/* Clear any pending IPIs for the current hart */
|
/* Clear any pending IPIs for the current hart */
|
||||||
sbi_ipi_raw_clear();
|
sbi_ipi_raw_clear(true);
|
||||||
|
|
||||||
/* Enable software interrupts */
|
/* Enable software interrupts */
|
||||||
csr_set(CSR_MIE, MIP_MSIP);
|
csr_set(CSR_MIE, MIP_MSIP);
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ union sbi_pmu_ctr_info {
|
|||||||
#error "Can't handle firmware counters beyond BITS_PER_LONG"
|
#error "Can't handle firmware counters beyond BITS_PER_LONG"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** HW event configuration parameters */
|
||||||
|
struct sbi_pmu_hw_event_config {
|
||||||
|
/* event_data value from sbi_pmu_ctr_cfg_match() */
|
||||||
|
uint64_t event_data;
|
||||||
|
/* HW events flags from sbi_pmu_ctr_cfg_match() */
|
||||||
|
uint64_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
/** Per-HART state of the PMU counters */
|
/** Per-HART state of the PMU counters */
|
||||||
struct sbi_pmu_hart_state {
|
struct sbi_pmu_hart_state {
|
||||||
/* HART to which this state belongs */
|
/* HART to which this state belongs */
|
||||||
@@ -72,6 +80,12 @@ struct sbi_pmu_hart_state {
|
|||||||
* and hence can optimally share the same memory.
|
* and hence can optimally share the same memory.
|
||||||
*/
|
*/
|
||||||
uint64_t fw_counters_data[SBI_PMU_FW_CTR_MAX];
|
uint64_t fw_counters_data[SBI_PMU_FW_CTR_MAX];
|
||||||
|
/* HW events configuration parameters from
|
||||||
|
* sbi_pmu_ctr_cfg_match() command which are
|
||||||
|
* used for restoring RAW hardware events after
|
||||||
|
* cpu suspending.
|
||||||
|
*/
|
||||||
|
struct sbi_pmu_hw_event_config hw_counters_cfg[SBI_PMU_HW_CTR_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Offset of pointer to PMU HART state in scratch space */
|
/** Offset of pointer to PMU HART state in scratch space */
|
||||||
@@ -463,6 +477,61 @@ static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pmu_update_inhibit_flags(unsigned long flags, uint64_t *mhpmevent_val)
|
||||||
|
{
|
||||||
|
if (flags & SBI_PMU_CFG_FLAG_SET_VUINH)
|
||||||
|
*mhpmevent_val |= MHPMEVENT_VUINH;
|
||||||
|
if (flags & SBI_PMU_CFG_FLAG_SET_VSINH)
|
||||||
|
*mhpmevent_val |= MHPMEVENT_VSINH;
|
||||||
|
if (flags & SBI_PMU_CFG_FLAG_SET_UINH)
|
||||||
|
*mhpmevent_val |= MHPMEVENT_UINH;
|
||||||
|
if (flags & SBI_PMU_CFG_FLAG_SET_SINH)
|
||||||
|
*mhpmevent_val |= MHPMEVENT_SINH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
|
||||||
|
unsigned long flags, unsigned long eindex,
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
uint64_t mhpmevent_val;
|
||||||
|
|
||||||
|
/* Get the final mhpmevent value to be written from platform */
|
||||||
|
mhpmevent_val = sbi_platform_pmu_xlate_to_mhpmevent(plat, eindex, data);
|
||||||
|
|
||||||
|
if (!mhpmevent_val || ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
|
||||||
|
return SBI_EFAIL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Always set the OVF bit(disable interrupts) and inhibit counting of
|
||||||
|
* events in M-mode. The OVF bit should be enabled during the start call.
|
||||||
|
*/
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
|
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) |
|
||||||
|
MHPMEVENT_MINH | MHPMEVENT_OF;
|
||||||
|
|
||||||
|
if (pmu_dev && pmu_dev->hw_counter_disable_irq)
|
||||||
|
pmu_dev->hw_counter_disable_irq(ctr_idx);
|
||||||
|
|
||||||
|
/* Update the inhibit flags based on inhibit flags received from supervisor */
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
|
pmu_update_inhibit_flags(flags, &mhpmevent_val);
|
||||||
|
if (pmu_dev && pmu_dev->hw_counter_filter_mode)
|
||||||
|
pmu_dev->hw_counter_filter_mode(flags, ctr_idx);
|
||||||
|
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
|
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3,
|
||||||
|
mhpmevent_val >> BITS_PER_LONG);
|
||||||
|
#else
|
||||||
|
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
|
int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
|
||||||
unsigned long flags, uint64_t ival)
|
unsigned long flags, uint64_t ival)
|
||||||
{
|
{
|
||||||
@@ -499,10 +568,21 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
|
|||||||
: 0x0;
|
: 0x0;
|
||||||
ret = pmu_ctr_start_fw(phs, cidx, event_code, edata,
|
ret = pmu_ctr_start_fw(phs, cidx, event_code, edata,
|
||||||
ival, bUpdate);
|
ival, bUpdate);
|
||||||
|
} else {
|
||||||
|
if (cidx >= 3) {
|
||||||
|
struct sbi_pmu_hw_event_config *ev_cfg =
|
||||||
|
&phs->hw_counters_cfg[cidx];
|
||||||
|
|
||||||
|
ret = pmu_update_hw_mhpmevent(&hw_event_map[cidx], cidx,
|
||||||
|
ev_cfg->flags,
|
||||||
|
phs->active_events[cidx],
|
||||||
|
ev_cfg->event_data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
ret = pmu_ctr_start_hw(cidx, ival, bUpdate);
|
ret = pmu_ctr_start_hw(cidx, ival, bUpdate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -614,61 +694,6 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pmu_update_inhibit_flags(unsigned long flags, uint64_t *mhpmevent_val)
|
|
||||||
{
|
|
||||||
if (flags & SBI_PMU_CFG_FLAG_SET_VUINH)
|
|
||||||
*mhpmevent_val |= MHPMEVENT_VUINH;
|
|
||||||
if (flags & SBI_PMU_CFG_FLAG_SET_VSINH)
|
|
||||||
*mhpmevent_val |= MHPMEVENT_VSINH;
|
|
||||||
if (flags & SBI_PMU_CFG_FLAG_SET_UINH)
|
|
||||||
*mhpmevent_val |= MHPMEVENT_UINH;
|
|
||||||
if (flags & SBI_PMU_CFG_FLAG_SET_SINH)
|
|
||||||
*mhpmevent_val |= MHPMEVENT_SINH;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
|
|
||||||
unsigned long flags, unsigned long eindex,
|
|
||||||
uint64_t data)
|
|
||||||
{
|
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
|
||||||
uint64_t mhpmevent_val;
|
|
||||||
|
|
||||||
/* Get the final mhpmevent value to be written from platform */
|
|
||||||
mhpmevent_val = sbi_platform_pmu_xlate_to_mhpmevent(plat, eindex, data);
|
|
||||||
|
|
||||||
if (!mhpmevent_val || ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
|
|
||||||
return SBI_EFAIL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Always set the OVF bit(disable interrupts) and inhibit counting of
|
|
||||||
* events in M-mode. The OVF bit should be enabled during the start call.
|
|
||||||
*/
|
|
||||||
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
|
||||||
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) |
|
|
||||||
MHPMEVENT_MINH | MHPMEVENT_OF;
|
|
||||||
|
|
||||||
if (pmu_dev && pmu_dev->hw_counter_disable_irq)
|
|
||||||
pmu_dev->hw_counter_disable_irq(ctr_idx);
|
|
||||||
|
|
||||||
/* Update the inhibit flags based on inhibit flags received from supervisor */
|
|
||||||
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
|
||||||
pmu_update_inhibit_flags(flags, &mhpmevent_val);
|
|
||||||
if (pmu_dev && pmu_dev->hw_counter_filter_mode)
|
|
||||||
pmu_dev->hw_counter_filter_mode(flags, ctr_idx);
|
|
||||||
|
|
||||||
#if __riscv_xlen == 32
|
|
||||||
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
|
|
||||||
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
|
||||||
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3,
|
|
||||||
mhpmevent_val >> BITS_PER_LONG);
|
|
||||||
#else
|
|
||||||
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pmu_fixed_ctr_update_inhibit_bits(int fixed_ctr, unsigned long flags)
|
static int pmu_fixed_ctr_update_inhibit_bits(int fixed_ctr, unsigned long flags)
|
||||||
{
|
{
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
@@ -780,6 +805,7 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
|
|||||||
continue;
|
continue;
|
||||||
/* We found a valid counter that is not started yet */
|
/* We found a valid counter that is not started yet */
|
||||||
ctr_idx = cbase;
|
ctr_idx = cbase;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,7 +843,7 @@ static int pmu_ctr_find_fw(struct sbi_pmu_hart_state *phs,
|
|||||||
cidx = i + cbase;
|
cidx = i + cbase;
|
||||||
if (cidx < num_hw_ctrs || total_ctrs <= cidx)
|
if (cidx < num_hw_ctrs || total_ctrs <= cidx)
|
||||||
continue;
|
continue;
|
||||||
if (phs->active_events[i] != SBI_PMU_EVENT_IDX_INVALID)
|
if (phs->active_events[cidx] != SBI_PMU_EVENT_IDX_INVALID)
|
||||||
continue;
|
continue;
|
||||||
if (SBI_PMU_FW_PLATFORM == event_code &&
|
if (SBI_PMU_FW_PLATFORM == event_code &&
|
||||||
pmu_dev && pmu_dev->fw_counter_match_encoding) {
|
pmu_dev && pmu_dev->fw_counter_match_encoding) {
|
||||||
@@ -827,7 +853,7 @@ static int pmu_ctr_find_fw(struct sbi_pmu_hart_state *phs,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return cidx;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SBI_ENOTSUPP;
|
return SBI_ENOTSUPP;
|
||||||
@@ -873,12 +899,20 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
|
|||||||
/* Any firmware counter can be used track any firmware event */
|
/* Any firmware counter can be used track any firmware event */
|
||||||
ctr_idx = pmu_ctr_find_fw(phs, cidx_base, cidx_mask,
|
ctr_idx = pmu_ctr_find_fw(phs, cidx_base, cidx_mask,
|
||||||
event_code, event_data);
|
event_code, event_data);
|
||||||
if (event_code == SBI_PMU_FW_PLATFORM)
|
if ((event_code == SBI_PMU_FW_PLATFORM) && (ctr_idx >= num_hw_ctrs))
|
||||||
phs->fw_counters_data[ctr_idx - num_hw_ctrs] =
|
phs->fw_counters_data[ctr_idx - num_hw_ctrs] =
|
||||||
event_data;
|
event_data;
|
||||||
} else {
|
} else {
|
||||||
ctr_idx = pmu_ctr_find_hw(phs, cidx_base, cidx_mask, flags,
|
ctr_idx = pmu_ctr_find_hw(phs, cidx_base, cidx_mask, flags,
|
||||||
event_idx, event_data);
|
event_idx, event_data);
|
||||||
|
if (ctr_idx >= 0) {
|
||||||
|
struct sbi_pmu_hw_event_config *ev_cfg =
|
||||||
|
&phs->hw_counters_cfg[ctr_idx];
|
||||||
|
|
||||||
|
ev_cfg->event_data = event_data;
|
||||||
|
/* Remove flags that are used in match call only */
|
||||||
|
ev_cfg->flags = flags & SBI_PMU_CFG_EVENT_MASK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctr_idx < 0)
|
if (ctr_idx < 0)
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct sbi_system_suspend_device *suspend_dev = NULL;
|
static const struct sbi_system_suspend_device *suspend_dev = NULL;
|
||||||
|
static bool system_suspended;
|
||||||
|
|
||||||
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void)
|
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void)
|
||||||
{
|
{
|
||||||
@@ -137,6 +138,19 @@ bool sbi_system_suspend_supported(u32 sleep_type)
|
|||||||
suspend_dev->system_suspend_check(sleep_type) == 0;
|
suspend_dev->system_suspend_check(sleep_type) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sbi_system_is_suspended(void)
|
||||||
|
{
|
||||||
|
return system_suspended;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sbi_system_resume(void)
|
||||||
|
{
|
||||||
|
if (suspend_dev && suspend_dev->system_resume)
|
||||||
|
suspend_dev->system_resume();
|
||||||
|
|
||||||
|
system_suspended = false;
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
|
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
|
||||||
{
|
{
|
||||||
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||||
@@ -189,11 +203,14 @@ int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
|
|||||||
__sbi_hsm_suspend_non_ret_save(scratch);
|
__sbi_hsm_suspend_non_ret_save(scratch);
|
||||||
|
|
||||||
/* Suspend */
|
/* Suspend */
|
||||||
|
system_suspended = true;
|
||||||
ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr);
|
ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr);
|
||||||
if (ret != SBI_OK) {
|
if (ret != SBI_OK) {
|
||||||
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED,
|
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED,
|
||||||
SBI_HSM_STATE_STARTED))
|
SBI_HSM_STATE_STARTED))
|
||||||
sbi_hart_hang();
|
sbi_hart_hang();
|
||||||
|
|
||||||
|
system_suspended = false;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
menu "Utils and Drivers Support"
|
menu "Utils and Drivers Support"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/cache/Kconfig"
|
||||||
|
|
||||||
source "$(OPENSBI_SRC_DIR)/lib/utils/cppc/Kconfig"
|
source "$(OPENSBI_SRC_DIR)/lib/utils/cppc/Kconfig"
|
||||||
|
|
||||||
source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
|
source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
|
||||||
|
|||||||
31
lib/utils/cache/Kconfig
vendored
Normal file
31
lib/utils/cache/Kconfig
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
menu "Cache Support"
|
||||||
|
|
||||||
|
config FDT_CACHE
|
||||||
|
bool "FDT based cache drivers"
|
||||||
|
depends on FDT
|
||||||
|
select CACHE
|
||||||
|
default n
|
||||||
|
|
||||||
|
if FDT_CACHE
|
||||||
|
|
||||||
|
config FDT_CACHE_SIFIVE_CCACHE
|
||||||
|
bool "SiFive CCACHE FDT cache driver"
|
||||||
|
default n
|
||||||
|
|
||||||
|
config FDT_CACHE_SIFIVE_EC
|
||||||
|
bool "SiFive EC FDT cache driver"
|
||||||
|
default n
|
||||||
|
|
||||||
|
config FDT_CACHE_SIFIVE_PL2
|
||||||
|
bool "SiFive PL2 FDT cache driver"
|
||||||
|
default n
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
config CACHE
|
||||||
|
bool "Cache support"
|
||||||
|
default n
|
||||||
|
|
||||||
|
endmenu
|
||||||
46
lib/utils/cache/cache.c
vendored
Normal file
46
lib/utils/cache/cache.c
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi_utils/cache/cache.h>
|
||||||
|
|
||||||
|
static SBI_LIST_HEAD(cache_list);
|
||||||
|
|
||||||
|
struct cache_device *cache_find(u32 id)
|
||||||
|
{
|
||||||
|
struct cache_device *dev;
|
||||||
|
|
||||||
|
sbi_list_for_each_entry(dev, &cache_list, node) {
|
||||||
|
if (dev->id == id)
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cache_add(struct cache_device *dev)
|
||||||
|
{
|
||||||
|
if (!dev)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
if (cache_find(dev->id))
|
||||||
|
return SBI_EALREADY;
|
||||||
|
|
||||||
|
sbi_list_add(&dev->node, &cache_list);
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cache_flush_all(struct cache_device *dev)
|
||||||
|
{
|
||||||
|
if (!dev)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
if (!dev->ops || !dev->ops->cache_flush_all)
|
||||||
|
return SBI_ENOTSUPP;
|
||||||
|
|
||||||
|
return dev->ops->cache_flush_all(dev);
|
||||||
|
}
|
||||||
89
lib/utils/cache/fdt_cache.c
vendored
Normal file
89
lib/utils/cache/fdt_cache.c
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_heap.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cache.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
|
|
||||||
|
/* List of FDT cache drivers generated at compile time */
|
||||||
|
extern const struct fdt_driver *const fdt_cache_drivers[];
|
||||||
|
|
||||||
|
int fdt_cache_add(const void *fdt, int noff, struct cache_device *dev)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
dev->id = noff;
|
||||||
|
sbi_strncpy(dev->name, fdt_get_name(fdt, noff, NULL), sizeof(dev->name) - 1);
|
||||||
|
sbi_dprintf("%s: %s\n", __func__, dev->name);
|
||||||
|
|
||||||
|
rc = fdt_next_cache_get(fdt, noff, &dev->next);
|
||||||
|
if (rc == SBI_ENOENT)
|
||||||
|
dev->next = NULL;
|
||||||
|
else if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return cache_add(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_cache_add_generic(const void *fdt, int noff)
|
||||||
|
{
|
||||||
|
struct cache_device *dev;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
dev = sbi_zalloc(sizeof(*dev));
|
||||||
|
if (!dev)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
rc = fdt_cache_add(fdt, noff, dev);
|
||||||
|
if (rc) {
|
||||||
|
sbi_free(dev);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_cache_find(const void *fdt, int noff, struct cache_device **out_dev)
|
||||||
|
{
|
||||||
|
struct cache_device *dev = cache_find(noff);
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
rc = fdt_driver_init_by_offset(fdt, noff, fdt_cache_drivers);
|
||||||
|
if (rc == SBI_ENODEV)
|
||||||
|
rc = fdt_cache_add_generic(fdt, noff);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
dev = cache_find(noff);
|
||||||
|
if (!dev)
|
||||||
|
return SBI_EFAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_dev)
|
||||||
|
*out_dev = dev;
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_next_cache_get(const void *fdt, int noff, struct cache_device **out_dev)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, noff, "next-level-cache", &len);
|
||||||
|
if (!val || len < sizeof(*val))
|
||||||
|
return SBI_ENOENT;
|
||||||
|
|
||||||
|
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(val[0]));
|
||||||
|
if (noff < 0)
|
||||||
|
return noff;
|
||||||
|
|
||||||
|
return fdt_cache_find(fdt, noff, out_dev);
|
||||||
|
}
|
||||||
3
lib/utils/cache/fdt_cache_drivers.carray
vendored
Normal file
3
lib/utils/cache/fdt_cache_drivers.carray
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
HEADER: sbi_utils/cache/fdt_cache.h
|
||||||
|
TYPE: const struct fdt_driver
|
||||||
|
NAME: fdt_cache_drivers
|
||||||
114
lib/utils/cache/fdt_cmo_helper.c
vendored
Normal file
114
lib/utils/cache/fdt_cmo_helper.c
vendored
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cache.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cmo_helper.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
|
||||||
|
static unsigned long flc_offset;
|
||||||
|
|
||||||
|
#define get_hart_flc(_s) \
|
||||||
|
sbi_scratch_read_type(_s, struct cache_device *, flc_offset)
|
||||||
|
#define set_hart_flc(_s, _p) \
|
||||||
|
sbi_scratch_write_type(_s, struct cache_device *, flc_offset, _p)
|
||||||
|
|
||||||
|
int fdt_cmo_private_flc_flush_all(void)
|
||||||
|
{
|
||||||
|
struct cache_device *flc = get_hart_flc(sbi_scratch_thishart_ptr());
|
||||||
|
|
||||||
|
if (!flc || !flc->cpu_private)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
return cache_flush_all(flc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_cmo_llc_flush_all(void)
|
||||||
|
{
|
||||||
|
struct cache_device *llc = get_hart_flc(sbi_scratch_thishart_ptr());
|
||||||
|
|
||||||
|
if (!llc)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
while (llc->next)
|
||||||
|
llc = llc->next;
|
||||||
|
|
||||||
|
return cache_flush_all(llc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_cmo_cold_init(const void *fdt)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch;
|
||||||
|
struct cache_device *dev;
|
||||||
|
int cpu_offset, cpus_offset, rc;
|
||||||
|
u32 hartid;
|
||||||
|
|
||||||
|
cpus_offset = fdt_path_offset(fdt, "/cpus");
|
||||||
|
if (cpus_offset < 0)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
|
||||||
|
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
|
if (rc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
scratch = sbi_hartid_to_scratch(hartid);
|
||||||
|
if (!scratch)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rc = fdt_next_cache_get(fdt, cpu_offset, &dev);
|
||||||
|
if (rc && rc != SBI_ENOENT)
|
||||||
|
return rc;
|
||||||
|
if (rc == SBI_ENOENT)
|
||||||
|
dev = NULL;
|
||||||
|
|
||||||
|
set_hart_flc(scratch, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_cmo_warm_init(void)
|
||||||
|
{
|
||||||
|
struct cache_device *cur = get_hart_flc(sbi_scratch_thishart_ptr());
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
while (cur) {
|
||||||
|
if (cur->ops && cur->ops->warm_init) {
|
||||||
|
rc = cur->ops->warm_init(cur);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_cmo_init(bool cold_boot)
|
||||||
|
{
|
||||||
|
const void *fdt = fdt_get_address();
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (cold_boot) {
|
||||||
|
flc_offset = sbi_scratch_alloc_type_offset(struct cache_device *);
|
||||||
|
if (!flc_offset)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
rc = fdt_cmo_cold_init(fdt);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fdt_cmo_warm_init();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
175
lib/utils/cache/fdt_sifive_ccache.c
vendored
Normal file
175
lib/utils/cache/fdt_sifive_ccache.c
vendored
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/riscv_barrier.h>
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_heap.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cache.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
|
|
||||||
|
#define CCACHE_CFG_CSR 0
|
||||||
|
#define CCACHE_CMD_CSR 0x280
|
||||||
|
#define CCACHE_STATUS_CSR 0x288
|
||||||
|
|
||||||
|
#define CFG_CSR_BANK_MASK 0xff
|
||||||
|
#define CFG_CSR_WAY_MASK 0xff00
|
||||||
|
#define CFG_CSR_WAY_OFFSET 8
|
||||||
|
#define CFG_CSR_SET_MASK 0xff0000
|
||||||
|
#define CFG_CSR_SET_OFFSET 16
|
||||||
|
|
||||||
|
#define CMD_CSR_CMD_OFFSET 56
|
||||||
|
#define CMD_CSR_BANK_OFFSET 6
|
||||||
|
|
||||||
|
#define CMD_OPCODE_SETWAY 0x1ULL
|
||||||
|
#define CMD_OPCODE_OFFSET 0x2ULL
|
||||||
|
|
||||||
|
#define CFLUSH_SETWAY_CLEANINV ((CMD_OPCODE_SETWAY << CMD_OPCODE_OFFSET) | 0x3)
|
||||||
|
|
||||||
|
#define CCACHE_CMD_QLEN 0xff
|
||||||
|
|
||||||
|
#define ccache_mb_b() RISCV_FENCE(rw, o)
|
||||||
|
#define ccache_mb_a() RISCV_FENCE(o, rw)
|
||||||
|
|
||||||
|
#define CCACHE_ALL_OP_REQ_BATCH_NUM 0x10
|
||||||
|
#define CCACHE_ALL_OP_REQ_BATCH_MASK (CCACHE_CMD_QLEN + 1 - CCACHE_ALL_OP_REQ_BATCH_NUM)
|
||||||
|
|
||||||
|
struct sifive_ccache {
|
||||||
|
struct cache_device dev;
|
||||||
|
void *addr;
|
||||||
|
u64 total_lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_ccache(_dev) container_of(_dev, struct sifive_ccache, dev)
|
||||||
|
|
||||||
|
static inline unsigned int sifive_ccache_read_status(void *status_addr)
|
||||||
|
{
|
||||||
|
return readl_relaxed(status_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sifive_ccache_write_cmd(u64 cmd, void *cmd_csr_addr)
|
||||||
|
{
|
||||||
|
#if __riscv_xlen != 32
|
||||||
|
writeq_relaxed(cmd, cmd_csr_addr);
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
* The cache maintenance request is only generated when the "command"
|
||||||
|
* field (part of the high word) is written.
|
||||||
|
*/
|
||||||
|
writel_relaxed(cmd, cmd_csr_addr);
|
||||||
|
writel(cmd >> 32, cmd_csr_addr + 4);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_ccache_flush_all(struct cache_device *dev)
|
||||||
|
{
|
||||||
|
struct sifive_ccache *ccache = to_ccache(dev);
|
||||||
|
void *status_addr = (char *)ccache->addr + CCACHE_STATUS_CSR;
|
||||||
|
void *cmd_csr_addr = (char *)ccache->addr + CCACHE_CMD_CSR;
|
||||||
|
u64 total_cnt = ccache->total_lines;
|
||||||
|
u64 cmd = CFLUSH_SETWAY_CLEANINV << CMD_CSR_CMD_OFFSET;
|
||||||
|
int loop_cnt = CCACHE_CMD_QLEN & CCACHE_ALL_OP_REQ_BATCH_MASK;
|
||||||
|
|
||||||
|
ccache_mb_b();
|
||||||
|
send_cmd:
|
||||||
|
total_cnt -= loop_cnt;
|
||||||
|
while (loop_cnt > 0) {
|
||||||
|
sifive_ccache_write_cmd(cmd + (0 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (1 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (2 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (3 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (4 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (5 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (6 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (7 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (8 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (9 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (10 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (11 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (12 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (13 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (14 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
sifive_ccache_write_cmd(cmd + (15 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
|
||||||
|
cmd += CCACHE_ALL_OP_REQ_BATCH_NUM << CMD_CSR_BANK_OFFSET;
|
||||||
|
loop_cnt -= CCACHE_ALL_OP_REQ_BATCH_NUM;
|
||||||
|
}
|
||||||
|
if (!total_cnt)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Ensure the ccache is able receive more than 16 requests */
|
||||||
|
do {
|
||||||
|
loop_cnt = (CCACHE_CMD_QLEN - sifive_ccache_read_status(status_addr));
|
||||||
|
} while (loop_cnt < CCACHE_ALL_OP_REQ_BATCH_NUM);
|
||||||
|
loop_cnt &= CCACHE_ALL_OP_REQ_BATCH_MASK;
|
||||||
|
|
||||||
|
if (total_cnt < loop_cnt) {
|
||||||
|
loop_cnt = (total_cnt + CCACHE_ALL_OP_REQ_BATCH_NUM) & CCACHE_ALL_OP_REQ_BATCH_MASK;
|
||||||
|
cmd -= ((loop_cnt - total_cnt) << CMD_CSR_BANK_OFFSET);
|
||||||
|
total_cnt = loop_cnt;
|
||||||
|
}
|
||||||
|
goto send_cmd;
|
||||||
|
done:
|
||||||
|
do {} while (sifive_ccache_read_status(status_addr));
|
||||||
|
ccache_mb_a();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cache_ops sifive_ccache_ops = {
|
||||||
|
.cache_flush_all = sifive_ccache_flush_all,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sifive_ccache_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
struct sifive_ccache *ccache;
|
||||||
|
struct cache_device *dev;
|
||||||
|
u64 reg_addr = 0;
|
||||||
|
u32 config_csr, banks, sets, ways;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* find the ccache base control address */
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, NULL);
|
||||||
|
if (rc < 0 && reg_addr)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
ccache = sbi_zalloc(sizeof(*ccache));
|
||||||
|
if (!ccache)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
dev = &ccache->dev;
|
||||||
|
dev->ops = &sifive_ccache_ops;
|
||||||
|
rc = fdt_cache_add(fdt, nodeoff, dev);
|
||||||
|
if (rc) {
|
||||||
|
sbi_free(ccache);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccache->addr = (void *)(uintptr_t)reg_addr;
|
||||||
|
|
||||||
|
/* get the info of ccache from config CSR */
|
||||||
|
config_csr = readl(ccache->addr + CCACHE_CFG_CSR);
|
||||||
|
banks = config_csr & CFG_CSR_BANK_MASK;
|
||||||
|
|
||||||
|
sets = (config_csr & CFG_CSR_SET_MASK) >> CFG_CSR_SET_OFFSET;
|
||||||
|
sets = (1 << sets);
|
||||||
|
|
||||||
|
ways = (config_csr & CFG_CSR_WAY_MASK) >> CFG_CSR_WAY_OFFSET;
|
||||||
|
|
||||||
|
ccache->total_lines = sets * ways * banks;
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match sifive_ccache_match[] = {
|
||||||
|
{ .compatible = "sifive,ccache2" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver fdt_sifive_ccache = {
|
||||||
|
.match_table = sifive_ccache_match,
|
||||||
|
.init = sifive_ccache_cold_init,
|
||||||
|
};
|
||||||
195
lib/utils/cache/fdt_sifive_ec.c
vendored
Normal file
195
lib/utils/cache/fdt_sifive_ec.c
vendored
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_heap.h>
|
||||||
|
#include <sbi/sbi_platform.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cache.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
|
|
||||||
|
#define SIFIVE_EC_FEATURE_DISABLE_OFF 0x100UL
|
||||||
|
#define SIFIVE_EC_FLUSH_CMD_OFF 0x800UL
|
||||||
|
#define SIFIVE_EC_FLUSH_STATUS_OFF 0x808UL
|
||||||
|
#define SIFIVE_EC_FLUSH_ADDR_OFF 0x810UL
|
||||||
|
#define SIFIVE_EC_MODE_CTRL 0xa00UL
|
||||||
|
|
||||||
|
#define SIFIVE_EC_FLUSH_COMPLETION_MASK BIT(0)
|
||||||
|
|
||||||
|
#define SIFIVE_EC_CLEANINV_ALL_CMD 0x3
|
||||||
|
|
||||||
|
#define SIFIVE_EC_FEATURE_DISABLE_VAL 0
|
||||||
|
|
||||||
|
struct sifive_ec_quirks {
|
||||||
|
bool two_mode;
|
||||||
|
char *reg_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sifive_ec_slice {
|
||||||
|
void *addr;
|
||||||
|
bool last_slice;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sifive_ec {
|
||||||
|
struct cache_device dev;
|
||||||
|
struct sifive_ec_slice *slices;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_ec(_dev) container_of(_dev, struct sifive_ec, dev)
|
||||||
|
|
||||||
|
static int sifive_ec_flush_all(struct cache_device *dev)
|
||||||
|
{
|
||||||
|
struct sifive_ec *ec_dev = to_ec(dev);
|
||||||
|
struct sifive_ec_slice *slices = ec_dev->slices;
|
||||||
|
u32 cmd = SIFIVE_EC_CLEANINV_ALL_CMD, i = 0;
|
||||||
|
void *addr;
|
||||||
|
|
||||||
|
do {
|
||||||
|
addr = slices[i].addr;
|
||||||
|
|
||||||
|
writel((int)-1, addr + SIFIVE_EC_FLUSH_ADDR_OFF);
|
||||||
|
writel((int)-1, addr + SIFIVE_EC_FLUSH_ADDR_OFF + sizeof(u32));
|
||||||
|
writel(cmd, addr + SIFIVE_EC_FLUSH_CMD_OFF);
|
||||||
|
} while (!slices[i++].last_slice);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
addr = slices[i].addr;
|
||||||
|
do {} while (!(readl(addr + SIFIVE_EC_FLUSH_STATUS_OFF) &
|
||||||
|
SIFIVE_EC_FLUSH_COMPLETION_MASK));
|
||||||
|
} while (!slices[i++].last_slice);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sifive_ec_warm_init(struct cache_device *dev)
|
||||||
|
{
|
||||||
|
struct sifive_ec *ec_dev = to_ec(dev);
|
||||||
|
struct sifive_ec_slice *slices = ec_dev->slices;
|
||||||
|
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (dom->boot_hartid == current_hartid()) {
|
||||||
|
do {
|
||||||
|
writel(SIFIVE_EC_FEATURE_DISABLE_VAL,
|
||||||
|
slices[i].addr + SIFIVE_EC_FEATURE_DISABLE_OFF);
|
||||||
|
} while (!slices[i++].last_slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cache_ops sifive_ec_ops = {
|
||||||
|
.warm_init = sifive_ec_warm_init,
|
||||||
|
.cache_flush_all = sifive_ec_flush_all,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sifive_ec_slices_cold_init(const void *fdt, int nodeoff,
|
||||||
|
struct sifive_ec_slice *slices,
|
||||||
|
const struct sifive_ec_quirks *quirks)
|
||||||
|
{
|
||||||
|
int rc, subnode, slice_idx = -1;
|
||||||
|
u64 reg_addr, size, start_addr = -1, end_addr = 0;
|
||||||
|
|
||||||
|
fdt_for_each_subnode(subnode, fdt, nodeoff) {
|
||||||
|
rc = fdt_get_node_addr_size_by_name(fdt, subnode, quirks->reg_name, ®_addr,
|
||||||
|
&size);
|
||||||
|
if (rc < 0)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
if (reg_addr < start_addr)
|
||||||
|
start_addr = reg_addr;
|
||||||
|
|
||||||
|
if (reg_addr + size > end_addr)
|
||||||
|
end_addr = reg_addr + size;
|
||||||
|
|
||||||
|
slices[++slice_idx].addr = (void *)(uintptr_t)reg_addr;
|
||||||
|
}
|
||||||
|
slices[slice_idx].last_slice = true;
|
||||||
|
|
||||||
|
/* Only enable the pmp to protect the EC m-mode region when it support two mode */
|
||||||
|
if (quirks->two_mode) {
|
||||||
|
rc = sbi_domain_root_add_memrange((unsigned long)start_addr,
|
||||||
|
(unsigned long)(end_addr - start_addr),
|
||||||
|
BIT(12),
|
||||||
|
(SBI_DOMAIN_MEMREGION_MMIO |
|
||||||
|
SBI_DOMAIN_MEMREGION_M_READABLE |
|
||||||
|
SBI_DOMAIN_MEMREGION_M_WRITABLE));
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_ec_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
const struct sifive_ec_quirks *quirks = match->data;
|
||||||
|
struct sifive_ec_slice *slices;
|
||||||
|
struct sifive_ec *ec_dev;
|
||||||
|
struct cache_device *dev;
|
||||||
|
int subnode, rc = SBI_ENOMEM;
|
||||||
|
u32 slice_count = 0;
|
||||||
|
|
||||||
|
/* Count the number of slices */
|
||||||
|
fdt_for_each_subnode(subnode, fdt, nodeoff)
|
||||||
|
slice_count++;
|
||||||
|
|
||||||
|
/* Need at least one slice */
|
||||||
|
if (!slice_count)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
ec_dev = sbi_zalloc(sizeof(*ec_dev));
|
||||||
|
if (!ec_dev)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
slices = sbi_zalloc(slice_count * sizeof(*slices));
|
||||||
|
if (!slices)
|
||||||
|
goto free_ec;
|
||||||
|
|
||||||
|
rc = sifive_ec_slices_cold_init(fdt, nodeoff, slices, quirks);
|
||||||
|
if (rc)
|
||||||
|
goto free_slice;
|
||||||
|
|
||||||
|
dev = &ec_dev->dev;
|
||||||
|
dev->ops = &sifive_ec_ops;
|
||||||
|
rc = fdt_cache_add(fdt, nodeoff, dev);
|
||||||
|
if (rc)
|
||||||
|
goto free_slice;
|
||||||
|
|
||||||
|
ec_dev->slices = slices;
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
|
||||||
|
free_slice:
|
||||||
|
sbi_free(slices);
|
||||||
|
free_ec:
|
||||||
|
sbi_free(ec_dev);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sifive_ec_quirks sifive_extensiblecache0_quirks = {
|
||||||
|
.two_mode = false,
|
||||||
|
.reg_name = "control",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sifive_ec_quirks sifive_extensiblecache4_quirks = {
|
||||||
|
.two_mode = true,
|
||||||
|
.reg_name = "m_mode",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fdt_match sifive_ec_match[] = {
|
||||||
|
{ .compatible = "sifive,extensiblecache4", .data = &sifive_extensiblecache4_quirks },
|
||||||
|
{ .compatible = "sifive,extensiblecache3", .data = &sifive_extensiblecache0_quirks },
|
||||||
|
{ .compatible = "sifive,extensiblecache2", .data = &sifive_extensiblecache0_quirks },
|
||||||
|
{ .compatible = "sifive,extensiblecache0", .data = &sifive_extensiblecache0_quirks },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_driver fdt_sifive_ec = {
|
||||||
|
.match_table = sifive_ec_match,
|
||||||
|
.init = sifive_ec_cold_init,
|
||||||
|
};
|
||||||
139
lib/utils/cache/fdt_sifive_pl2.c
vendored
Normal file
139
lib/utils/cache/fdt_sifive_pl2.c
vendored
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_heap.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cache.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
|
|
||||||
|
#define FLUSH64_CMD_TARGET_ALL (0x2 << 3)
|
||||||
|
#define FLUSH64_CMD_TYPE_FLUSH 0x3ULL
|
||||||
|
|
||||||
|
#define SIFIVE_PL2CACHE_CMD_QLEN 0xff
|
||||||
|
|
||||||
|
#define SIFIVE_PL2CACHE_FLUSH64_OFF 0x200ULL
|
||||||
|
#define SIFIVE_PL2CACHE_STATUS_OFF 0x208ULL
|
||||||
|
#define SIFIVE_PL2CACHE_CONFIG1_OFF 0x1000ULL
|
||||||
|
#define SIFIVE_PL2CACHE_CONFIG0_OFF 0x1008ULL
|
||||||
|
|
||||||
|
#define FLUSH64_CMD_POS 56
|
||||||
|
#define REGIONCLOCKDISABLE_MASK BIT(3)
|
||||||
|
|
||||||
|
#define CONFIG0_ACCEPT_DIRTY_DATA_ENABLE BIT(24)
|
||||||
|
|
||||||
|
struct sifive_pl2_quirks {
|
||||||
|
bool no_dirty_fill;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sifive_pl2 {
|
||||||
|
struct cache_device dev;
|
||||||
|
void *addr;
|
||||||
|
bool no_dirty_fill;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_pl2(_dev) container_of(_dev, struct sifive_pl2, dev)
|
||||||
|
|
||||||
|
static int sifive_pl2_flush_all(struct cache_device *dev)
|
||||||
|
{
|
||||||
|
struct sifive_pl2 *pl2_dev = to_pl2(dev);
|
||||||
|
char *addr = pl2_dev->addr;
|
||||||
|
u64 cmd = (FLUSH64_CMD_TARGET_ALL | FLUSH64_CMD_TYPE_FLUSH) << FLUSH64_CMD_POS;
|
||||||
|
u32 config0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While flushing pl2 cache, a speculative load might causes a dirty line pull
|
||||||
|
* into PL2. It will cause the SiFive SMC0 refuse to enter the power gating.
|
||||||
|
* Disable the ACCEPT_DIRTY_DATA_ENABLE to avoid the issue.
|
||||||
|
*/
|
||||||
|
if (pl2_dev->no_dirty_fill) {
|
||||||
|
config0 = readl((void *)addr + SIFIVE_PL2CACHE_CONFIG0_OFF);
|
||||||
|
config0 &= ~CONFIG0_ACCEPT_DIRTY_DATA_ENABLE;
|
||||||
|
writel(config0, (void *)addr + SIFIVE_PL2CACHE_CONFIG0_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __riscv_xlen != 32
|
||||||
|
writeq(cmd, addr + SIFIVE_PL2CACHE_FLUSH64_OFF);
|
||||||
|
#else
|
||||||
|
writel((u32)cmd, addr + SIFIVE_PL2CACHE_FLUSH64_OFF);
|
||||||
|
writel((u32)(cmd >> 32), addr + SIFIVE_PL2CACHE_FLUSH64_OFF + sizeof(u32));
|
||||||
|
#endif
|
||||||
|
do {} while (readl(addr + SIFIVE_PL2CACHE_STATUS_OFF) & SIFIVE_PL2CACHE_CMD_QLEN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_pl2_warm_init(struct cache_device *dev)
|
||||||
|
{
|
||||||
|
struct sifive_pl2 *pl2_dev = to_pl2(dev);
|
||||||
|
char *addr = pl2_dev->addr;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
/* Enabling the clock gating */
|
||||||
|
val = readl(addr + SIFIVE_PL2CACHE_CONFIG1_OFF);
|
||||||
|
val &= (~REGIONCLOCKDISABLE_MASK);
|
||||||
|
writel(val, addr + SIFIVE_PL2CACHE_CONFIG1_OFF);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cache_ops sifive_pl2_ops = {
|
||||||
|
.warm_init = sifive_pl2_warm_init,
|
||||||
|
.cache_flush_all = sifive_pl2_flush_all,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sifive_pl2_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
const struct sifive_pl2_quirks *quirk = match->data;
|
||||||
|
struct sifive_pl2 *pl2_dev;
|
||||||
|
struct cache_device *dev;
|
||||||
|
u64 reg_addr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* find the pl2 control base address */
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, NULL);
|
||||||
|
if (rc < 0 && reg_addr)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
pl2_dev = sbi_zalloc(sizeof(*pl2_dev));
|
||||||
|
if (!pl2_dev)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
dev = &pl2_dev->dev;
|
||||||
|
dev->ops = &sifive_pl2_ops;
|
||||||
|
dev->cpu_private = true;
|
||||||
|
|
||||||
|
rc = fdt_cache_add(fdt, nodeoff, dev);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
pl2_dev->addr = (void *)(uintptr_t)reg_addr;
|
||||||
|
if (quirk)
|
||||||
|
pl2_dev->no_dirty_fill = quirk->no_dirty_fill;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sifive_pl2_quirks pl2cache2_quirks = {
|
||||||
|
.no_dirty_fill = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sifive_pl2_quirks pl2cache0_quirks = {
|
||||||
|
.no_dirty_fill = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fdt_match sifive_pl2_match[] = {
|
||||||
|
{ .compatible = "sifive,pl2cache2", .data = &pl2cache2_quirks },
|
||||||
|
{ .compatible = "sifive,pl2cache1", .data = &pl2cache0_quirks },
|
||||||
|
{ .compatible = "sifive,pl2cache0", .data = &pl2cache0_quirks },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_driver fdt_sifive_pl2 = {
|
||||||
|
.match_table = sifive_pl2_match,
|
||||||
|
.init = sifive_pl2_cold_init,
|
||||||
|
};
|
||||||
20
lib/utils/cache/objects.mk
vendored
Normal file
20
lib/utils/cache/objects.mk
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 SiFive
|
||||||
|
#
|
||||||
|
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache.o
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache_drivers.carray.o
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cmo_helper.o
|
||||||
|
|
||||||
|
carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += fdt_sifive_ccache
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += cache/fdt_sifive_ccache.o
|
||||||
|
|
||||||
|
carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_PL2) += fdt_sifive_pl2
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_PL2) += cache/fdt_sifive_pl2.o
|
||||||
|
|
||||||
|
carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_EC) += fdt_sifive_ec
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_EC) += cache/fdt_sifive_ec.o
|
||||||
|
|
||||||
|
libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
|
||||||
@@ -185,7 +185,7 @@ static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
|
if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
|
||||||
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
|
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE | SBI_DOMAIN_MMIO)) {
|
||||||
rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
|
rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ config FDT_HSM_RPMI
|
|||||||
depends on FDT_MAILBOX && RPMI_MAILBOX
|
depends on FDT_MAILBOX && RPMI_MAILBOX
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config FDT_HSM_SIFIVE_TMC0
|
||||||
|
bool "FDT SiFive TMC v0 driver"
|
||||||
|
depends on FDT_CACHE
|
||||||
|
default n
|
||||||
|
|
||||||
|
config FDT_HSM_SPACEMIT
|
||||||
|
bool "FDT SPACEMIT HSM driver"
|
||||||
|
default n
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
367
lib/utils/hsm/fdt_hsm_sifive_tmc0.c
Normal file
367
lib/utils/hsm/fdt_hsm_sifive_tmc0.c
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/riscv_asm.h>
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_bitops.h>
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_hart.h>
|
||||||
|
#include <sbi/sbi_heap.h>
|
||||||
|
#include <sbi/sbi_hsm.h>
|
||||||
|
#include <sbi/sbi_ipi.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cmo_helper.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
|
||||||
|
#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
|
||||||
|
|
||||||
|
struct sifive_tmc0 {
|
||||||
|
unsigned long reg;
|
||||||
|
struct sbi_dlist node;
|
||||||
|
u32 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SBI_LIST_HEAD(tmc0_list);
|
||||||
|
static unsigned long tmc0_offset;
|
||||||
|
|
||||||
|
#define tmc0_ptr_get(__scratch) \
|
||||||
|
sbi_scratch_read_type((__scratch), struct sifive_tmc0 *, tmc0_offset)
|
||||||
|
|
||||||
|
#define tmc0_ptr_set(__scratch, __tmc0) \
|
||||||
|
sbi_scratch_write_type((__scratch), struct sifive_tmc0 *, tmc0_offset, (__tmc0))
|
||||||
|
|
||||||
|
/* TMC.PGPREP */
|
||||||
|
#define SIFIVE_TMC_PGPREP_OFF 0x0
|
||||||
|
#define SIFIVE_TMC_PGPREP_ENA_REQ BIT(31)
|
||||||
|
#define SIFIVE_TMC_PGPREP_ENA_ACK BIT(30)
|
||||||
|
#define SIFIVE_TMC_PGPREP_DIS_REQ BIT(29)
|
||||||
|
#define SIFIVE_TMC_PGPREP_DIS_ACK BIT(28)
|
||||||
|
#define SIFIVE_TMC_PGPREP_CLFPNOTQ BIT(18)
|
||||||
|
#define SIFIVE_TMC_PGPREP_PMCENAERR BIT(17)
|
||||||
|
#define SIFIVE_TMC_PGPREP_PMCDENY BIT(16)
|
||||||
|
#define SIFIVE_TMC_PGPREP_BUSERR BIT(15)
|
||||||
|
#define SIFIVE_TMC_PGPREP_WAKE_DETECT BIT(12)
|
||||||
|
#define SIFIVE_TMC_PGPREP_INTERNAL_ABORT BIT(2)
|
||||||
|
#define SIFIVE_TMC_PGPREP_ENARSP (SIFIVE_TMC_PGPREP_CLFPNOTQ | \
|
||||||
|
SIFIVE_TMC_PGPREP_PMCENAERR | \
|
||||||
|
SIFIVE_TMC_PGPREP_PMCDENY | \
|
||||||
|
SIFIVE_TMC_PGPREP_BUSERR | \
|
||||||
|
SIFIVE_TMC_PGPREP_WAKE_DETECT)
|
||||||
|
|
||||||
|
/* TMC.PG */
|
||||||
|
#define SIFIVE_TMC_PG_OFF 0x4
|
||||||
|
#define SIFIVE_TMC_PG_ENA_REQ BIT(31)
|
||||||
|
#define SIFIVE_TMC_PG_ENA_ACK BIT(30)
|
||||||
|
#define SIFIVE_TMC_PG_DIS_REQ BIT(29)
|
||||||
|
#define SIFIVE_TMC_PG_DIS_ACK BIT(28)
|
||||||
|
#define SIFIVE_TMC_PG_PMC_ENA_ERR BIT(17)
|
||||||
|
#define SIFIVE_TMC_PG_PMC_DENY BIT(16)
|
||||||
|
#define SIFIVE_TMC_PG_BUS_ERR BIT(15)
|
||||||
|
#define SIFIVE_TMC_PG_MASTNOTQ BIT(14)
|
||||||
|
#define SIFIVE_TMC_PG_WARM_RESET BIT(1)
|
||||||
|
#define SIFIVE_TMC_PG_ENARSP (SIFIVE_TMC_PG_PMC_ENA_ERR | \
|
||||||
|
SIFIVE_TMC_PG_PMC_DENY | \
|
||||||
|
SIFIVE_TMC_PG_BUS_ERR | \
|
||||||
|
SIFIVE_TMC_PG_MASTNOTQ)
|
||||||
|
|
||||||
|
/* TMC.RESUMEPC */
|
||||||
|
#define SIFIVE_TMC_RESUMEPC_LO 0x10
|
||||||
|
#define SIFIVE_TMC_RESUMEPC_HI 0x14
|
||||||
|
|
||||||
|
/* TMC.WAKEMASK */
|
||||||
|
#define SIFIVE_TMC_WAKE_MASK_OFF 0x20
|
||||||
|
#define SIFIVE_TMC_WAKE_MASK_WREQ BIT(31)
|
||||||
|
#define SIFIVE_TMC_WAKE_MASK_ACK BIT(30)
|
||||||
|
|
||||||
|
int sifive_tmc0_set_wakemask_enareq(u32 hartid)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
|
||||||
|
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
|
||||||
|
unsigned long addr;
|
||||||
|
u32 v;
|
||||||
|
|
||||||
|
if (!tmc0)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
|
||||||
|
v = readl((void *)addr);
|
||||||
|
writel(v | SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
|
||||||
|
|
||||||
|
while (!(readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK));
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sifive_tmc0_set_wakemask_disreq(u32 hartid)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
|
||||||
|
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
|
||||||
|
unsigned long addr;
|
||||||
|
u32 v;
|
||||||
|
|
||||||
|
if (!tmc0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
|
||||||
|
v = readl((void *)addr);
|
||||||
|
writel(v & ~SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
|
||||||
|
|
||||||
|
while (readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sifive_tmc0_is_pg(u32 hartid)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
|
||||||
|
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
|
||||||
|
unsigned long addr;
|
||||||
|
u32 v;
|
||||||
|
|
||||||
|
if (!tmc0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
addr = tmc0->reg + SIFIVE_TMC_PG_OFF;
|
||||||
|
v = readl((void *)addr);
|
||||||
|
if (!(v & SIFIVE_TMC_PG_ENA_ACK) ||
|
||||||
|
(v & SIFIVE_TMC_PG_ENARSP) ||
|
||||||
|
(v & SIFIVE_TMC_PG_DIS_REQ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sifive_tmc0_set_resumepc(physical_addr_t addr)
|
||||||
|
{
|
||||||
|
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
|
||||||
|
|
||||||
|
writel((u32)addr, (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_LO));
|
||||||
|
#if __riscv_xlen > 32
|
||||||
|
writel((u32)(addr >> 32), (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_HI));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 sifive_tmc0_set_pgprep_enareq(void)
|
||||||
|
{
|
||||||
|
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
|
||||||
|
unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
|
||||||
|
u32 v = readl((void *)reg);
|
||||||
|
|
||||||
|
writel(v | SIFIVE_TMC_PGPREP_ENA_REQ, (void *)reg);
|
||||||
|
while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_ENA_ACK));
|
||||||
|
|
||||||
|
v = readl((void *)reg);
|
||||||
|
return v & SIFIVE_TMC_PGPREP_INTERNAL_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sifive_tmc0_set_pgprep_disreq(void)
|
||||||
|
{
|
||||||
|
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
|
||||||
|
unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
|
||||||
|
u32 v = readl((void *)reg);
|
||||||
|
|
||||||
|
writel(v | SIFIVE_TMC_PGPREP_DIS_REQ, (void *)reg);
|
||||||
|
while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_DIS_ACK));
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 sifive_tmc0_get_pgprep_enarsp(void)
|
||||||
|
{
|
||||||
|
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
|
||||||
|
unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
|
||||||
|
u32 v = readl((void *)reg);
|
||||||
|
|
||||||
|
return v & SIFIVE_TMC_PGPREP_ENARSP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sifive_tmc0_set_pg_enareq(void)
|
||||||
|
{
|
||||||
|
struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
|
||||||
|
unsigned long reg = tmc0->reg + SIFIVE_TMC_PG_OFF;
|
||||||
|
u32 v = readl((void *)reg);
|
||||||
|
|
||||||
|
writel(v | SIFIVE_TMC_PG_ENA_REQ, (void *)reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_tmc0_prep(void)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
u32 rc;
|
||||||
|
|
||||||
|
if (!tmc0_ptr_get(scratch))
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
rc = sifive_tmc0_set_pgprep_enareq();
|
||||||
|
if (rc) {
|
||||||
|
sbi_printf("TMC0 error: Internal Abort (Wake detect)\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sifive_tmc0_get_pgprep_enarsp();
|
||||||
|
if (rc) {
|
||||||
|
sifive_tmc0_set_pgprep_disreq();
|
||||||
|
sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
sifive_tmc0_set_resumepc(scratch->warmboot_addr);
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return SBI_EFAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_tmc0_enter(void)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
u32 rc;
|
||||||
|
|
||||||
|
/* Flush cache and check if there is wake detect or bus error */
|
||||||
|
if (fdt_cmo_private_flc_flush_all() &&
|
||||||
|
sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
|
||||||
|
sifive_cflush();
|
||||||
|
|
||||||
|
rc = sifive_tmc0_get_pgprep_enarsp();
|
||||||
|
if (rc) {
|
||||||
|
sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
|
||||||
|
sifive_tmc0_set_pg_enareq();
|
||||||
|
while (1)
|
||||||
|
sifive_cease();
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SBI_ENOTSUPP;
|
||||||
|
fail:
|
||||||
|
sifive_tmc0_set_pgprep_disreq();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_tmc0_tile_pg(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = sifive_tmc0_prep();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return sifive_tmc0_enter();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_tmc0_start(u32 hartid, ulong saddr)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* In system suspend, the IMSIC will be reset in SiFive platform so
|
||||||
|
* we use the CLINT IPI as the wake event.
|
||||||
|
*/
|
||||||
|
sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid), true);
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_tmc0_stop(void)
|
||||||
|
{
|
||||||
|
unsigned long mie = csr_read(CSR_MIE);
|
||||||
|
int rc;
|
||||||
|
/* Set IPI as wake up source */
|
||||||
|
csr_set(CSR_MIE, MIP_MEIP | MIP_MSIP);
|
||||||
|
|
||||||
|
rc = sifive_tmc0_tile_pg();
|
||||||
|
if (rc) {
|
||||||
|
csr_write(CSR_MIE, mie);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sbi_hsm_device tmc0_hsm_dev = {
|
||||||
|
.name = "SiFive TMC0",
|
||||||
|
.hart_start = sifive_tmc0_start,
|
||||||
|
.hart_stop = sifive_tmc0_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sifive_tmc0_bind_cpu(struct sifive_tmc0 *tmc0)
|
||||||
|
{
|
||||||
|
const void *fdt = fdt_get_address();
|
||||||
|
struct sbi_scratch *scratch;
|
||||||
|
int cpus_off, cpu_off, rc;
|
||||||
|
const fdt32_t *val;
|
||||||
|
u32 hartid;
|
||||||
|
|
||||||
|
cpus_off = fdt_path_offset(fdt, "/cpus");
|
||||||
|
if (cpus_off < 0)
|
||||||
|
return SBI_ENOENT;
|
||||||
|
|
||||||
|
fdt_for_each_subnode(cpu_off, fdt, cpus_off) {
|
||||||
|
rc = fdt_parse_hart_id(fdt, cpu_off, &hartid);
|
||||||
|
if (rc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
scratch = sbi_hartid_to_scratch(hartid);
|
||||||
|
if (!scratch)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
|
||||||
|
if (!val)
|
||||||
|
return SBI_ENOENT;
|
||||||
|
|
||||||
|
if (tmc0->id == fdt32_to_cpu(val[0])) {
|
||||||
|
tmc0_ptr_set(scratch, tmc0);
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
struct sifive_tmc0 *tmc0;
|
||||||
|
u64 addr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!tmc0_offset) {
|
||||||
|
tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
|
||||||
|
if (!tmc0_offset)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
sbi_hsm_set_device(&tmc0_hsm_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmc0 = sbi_zalloc(sizeof(*tmc0));
|
||||||
|
if (!tmc0)
|
||||||
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
|
||||||
|
if (rc)
|
||||||
|
goto free_tmc0;
|
||||||
|
|
||||||
|
tmc0->reg = (unsigned long)addr;
|
||||||
|
tmc0->id = fdt_get_phandle(fdt_get_address(), nodeoff);
|
||||||
|
|
||||||
|
rc = sifive_tmc0_bind_cpu(tmc0);
|
||||||
|
if (rc)
|
||||||
|
goto free_tmc0;
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
|
||||||
|
free_tmc0:
|
||||||
|
sbi_free(tmc0);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match sifive_tmc0_match[] = {
|
||||||
|
{ .compatible = "sifive,tmc0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver fdt_hsm_sifive_tmc0 = {
|
||||||
|
.match_table = sifive_tmc0_match,
|
||||||
|
.init = sifive_tmc0_probe,
|
||||||
|
};
|
||||||
140
lib/utils/hsm/fdt_hsm_spacemit.c
Normal file
140
lib/utils/hsm/fdt_hsm_spacemit.c
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SpacemiT
|
||||||
|
* Authors:
|
||||||
|
* Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
|
||||||
|
* Troy Mitchell <troy.mitchell@linux.spacemit.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <platform_override.h>
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_hsm.h>
|
||||||
|
#include <spacemit/k1.h>
|
||||||
|
|
||||||
|
static const u64 cpu_wakeup_reg[] = {
|
||||||
|
PMU_AP_CORE0_WAKEUP,
|
||||||
|
PMU_AP_CORE1_WAKEUP,
|
||||||
|
PMU_AP_CORE2_WAKEUP,
|
||||||
|
PMU_AP_CORE3_WAKEUP,
|
||||||
|
PMU_AP_CORE4_WAKEUP,
|
||||||
|
PMU_AP_CORE5_WAKEUP,
|
||||||
|
PMU_AP_CORE6_WAKEUP,
|
||||||
|
PMU_AP_CORE7_WAKEUP,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u64 cpu_idle_reg[] = {
|
||||||
|
PMU_AP_CORE0_IDLE_CFG,
|
||||||
|
PMU_AP_CORE1_IDLE_CFG,
|
||||||
|
PMU_AP_CORE2_IDLE_CFG,
|
||||||
|
PMU_AP_CORE3_IDLE_CFG,
|
||||||
|
PMU_AP_CORE4_IDLE_CFG,
|
||||||
|
PMU_AP_CORE5_IDLE_CFG,
|
||||||
|
PMU_AP_CORE6_IDLE_CFG,
|
||||||
|
PMU_AP_CORE7_IDLE_CFG,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void spacemit_set_cpu_power(u32 hartid, bool enable)
|
||||||
|
{
|
||||||
|
unsigned int value;
|
||||||
|
unsigned int *cpu_idle_base = (unsigned int *)(unsigned long)cpu_idle_reg[hartid];
|
||||||
|
|
||||||
|
value = readl(cpu_idle_base);
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
value &= ~PMU_AP_IDLE_PWRDOWN_MASK;
|
||||||
|
else
|
||||||
|
value |= PMU_AP_IDLE_PWRDOWN_MASK;
|
||||||
|
|
||||||
|
writel(value, cpu_idle_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spacemit_wakeup_cpu(u32 mpidr)
|
||||||
|
{
|
||||||
|
unsigned int *cpu_reset_base;
|
||||||
|
unsigned int cur_hartid = current_hartid();
|
||||||
|
|
||||||
|
cpu_reset_base = (unsigned int *)(unsigned long)cpu_wakeup_reg[cur_hartid];
|
||||||
|
|
||||||
|
writel(1 << mpidr, cpu_reset_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spacemit_assert_cpu(void)
|
||||||
|
{
|
||||||
|
spacemit_set_cpu_power(current_hartid(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spacemit_deassert_cpu(unsigned int hartid)
|
||||||
|
{
|
||||||
|
spacemit_set_cpu_power(hartid, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start (or power-up) the given hart */
|
||||||
|
static int spacemit_hart_start(unsigned int hartid, unsigned long saddr)
|
||||||
|
{
|
||||||
|
spacemit_deassert_cpu(hartid);
|
||||||
|
spacemit_wakeup_cpu(hartid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop (or power-down) the current hart from running. This call
|
||||||
|
* doesn't expect to return if success.
|
||||||
|
*/
|
||||||
|
static int spacemit_hart_stop(void)
|
||||||
|
{
|
||||||
|
csr_write(CSR_STIMECMP, GENMASK_ULL(63, 0));
|
||||||
|
csr_clear(CSR_MIE, MIP_SSIP | MIP_MSIP | MIP_STIP | MIP_MTIP | MIP_SEIP | MIP_MEIP);
|
||||||
|
|
||||||
|
/* disable data preftch */
|
||||||
|
csr_clear(CSR_MSETUP, MSETUP_PFE);
|
||||||
|
asm volatile ("fence iorw, iorw");
|
||||||
|
|
||||||
|
/* flush local dcache */
|
||||||
|
csr_write(CSR_MRAOP, MRAOP_ICACHE_INVALID);
|
||||||
|
asm volatile ("fence iorw, iorw");
|
||||||
|
|
||||||
|
/* disable dcache */
|
||||||
|
csr_clear(CSR_MSETUP, MSETUP_DE);
|
||||||
|
asm volatile ("fence iorw, iorw");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Core4-7 do not have dedicated bits in ML2SETUP;
|
||||||
|
* instead, they reuse the same bits as core0-3.
|
||||||
|
*
|
||||||
|
* Thereforspacemit_deassert_cpue, use modulo with PLATFORM_MAX_CPUS_PER_CLUSTER
|
||||||
|
* to select the proper bit.
|
||||||
|
*/
|
||||||
|
csr_clear(CSR_ML2SETUP, 1 << (current_hartid() % PLATFORM_MAX_CPUS_PER_CLUSTER));
|
||||||
|
asm volatile ("fence iorw, iorw");
|
||||||
|
|
||||||
|
spacemit_assert_cpu();
|
||||||
|
|
||||||
|
wfi();
|
||||||
|
|
||||||
|
return SBI_ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sbi_hsm_device spacemit_hsm_ops = {
|
||||||
|
.name = "spacemit-hsm",
|
||||||
|
.hart_start = spacemit_hart_start,
|
||||||
|
.hart_stop = spacemit_hart_stop,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int spacemit_hsm_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
sbi_hsm_set_device(&spacemit_hsm_ops);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match spacemit_hsm_match[] = {
|
||||||
|
{ .compatible = "spacemit,k1" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver fdt_hsm_spacemit = {
|
||||||
|
.match_table = spacemit_hsm_match,
|
||||||
|
.init = spacemit_hsm_probe,
|
||||||
|
};
|
||||||
@@ -9,3 +9,9 @@
|
|||||||
|
|
||||||
carray-fdt_early_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
|
carray-fdt_early_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
|
||||||
libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
|
libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
|
||||||
|
|
||||||
|
carray-fdt_early_drivers-$(CONFIG_FDT_HSM_SPACEMIT) += fdt_hsm_spacemit
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_HSM_SPACEMIT) += hsm/fdt_hsm_spacemit.o
|
||||||
|
|
||||||
|
carray-fdt_early_drivers-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += fdt_hsm_sifive_tmc0
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += hsm/fdt_hsm_sifive_tmc0.o
|
||||||
@@ -62,6 +62,7 @@ static void mswi_ipi_clear(void)
|
|||||||
|
|
||||||
static struct sbi_ipi_device aclint_mswi = {
|
static struct sbi_ipi_device aclint_mswi = {
|
||||||
.name = "aclint-mswi",
|
.name = "aclint-mswi",
|
||||||
|
.rating = 100,
|
||||||
.ipi_send = mswi_ipi_send,
|
.ipi_send = mswi_ipi_send,
|
||||||
.ipi_clear = mswi_ipi_clear
|
.ipi_clear = mswi_ipi_clear
|
||||||
};
|
};
|
||||||
@@ -106,7 +107,7 @@ int aclint_mswi_cold_init(struct aclint_mswi_data *mswi)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
sbi_ipi_set_device(&aclint_mswi);
|
sbi_ipi_add_device(&aclint_mswi);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ static void plicsw_ipi_clear(void)
|
|||||||
|
|
||||||
static struct sbi_ipi_device plicsw_ipi = {
|
static struct sbi_ipi_device plicsw_ipi = {
|
||||||
.name = "andes_plicsw",
|
.name = "andes_plicsw",
|
||||||
|
.rating = 200,
|
||||||
.ipi_send = plicsw_ipi_send,
|
.ipi_send = plicsw_ipi_send,
|
||||||
.ipi_clear = plicsw_ipi_clear
|
.ipi_clear = plicsw_ipi_clear
|
||||||
};
|
};
|
||||||
@@ -99,7 +100,7 @@ int plicsw_cold_ipi_init(struct plicsw_data *plicsw)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
sbi_ipi_set_device(&plicsw_ipi);
|
sbi_ipi_add_device(&plicsw_ipi);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Anup Patel <anup.patel@wdc.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sbi_utils/ipi/fdt_ipi.h>
|
|
||||||
|
|
||||||
/* List of FDT ipi drivers generated at compile time */
|
|
||||||
extern const struct fdt_driver *const fdt_ipi_drivers[];
|
|
||||||
|
|
||||||
int fdt_ipi_init(void)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* On some single-hart system there is no need for IPIs,
|
|
||||||
* so do not return a failure if no device is found.
|
|
||||||
*/
|
|
||||||
return fdt_driver_init_all(fdt_get_address(), fdt_ipi_drivers);
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
HEADER: sbi_utils/ipi/fdt_ipi.h
|
|
||||||
TYPE: const struct fdt_driver
|
|
||||||
NAME: fdt_ipi_drivers
|
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_heap.h>
|
#include <sbi/sbi_heap.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
#include <sbi_utils/fdt/fdt_helper.h>
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
#include <sbi_utils/ipi/fdt_ipi.h>
|
|
||||||
#include <sbi_utils/ipi/aclint_mswi.h>
|
#include <sbi_utils/ipi/aclint_mswi.h>
|
||||||
|
|
||||||
static int ipi_mswi_cold_init(const void *fdt, int nodeoff,
|
static int ipi_mswi_cold_init(const void *fdt, int nodeoff,
|
||||||
@@ -57,6 +57,7 @@ static const struct fdt_match ipi_mswi_match[] = {
|
|||||||
{ .compatible = "sifive,clint0", .data = &clint_offset },
|
{ .compatible = "sifive,clint0", .data = &clint_offset },
|
||||||
{ .compatible = "thead,c900-clint", .data = &clint_offset },
|
{ .compatible = "thead,c900-clint", .data = &clint_offset },
|
||||||
{ .compatible = "thead,c900-aclint-mswi" },
|
{ .compatible = "thead,c900-aclint-mswi" },
|
||||||
|
{ .compatible = "mips,p8700-aclint-mswi" },
|
||||||
{ .compatible = "riscv,aclint-mswi" },
|
{ .compatible = "riscv,aclint-mswi" },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sbi/riscv_io.h>
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
#include <sbi_utils/fdt/fdt_helper.h>
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
#include <sbi_utils/ipi/fdt_ipi.h>
|
|
||||||
#include <sbi_utils/ipi/andes_plicsw.h>
|
#include <sbi_utils/ipi/andes_plicsw.h>
|
||||||
|
|
||||||
extern struct plicsw_data plicsw;
|
extern struct plicsw_data plicsw;
|
||||||
|
|||||||
@@ -10,11 +10,8 @@
|
|||||||
libsbiutils-objs-$(CONFIG_IPI_MSWI) += ipi/aclint_mswi.o
|
libsbiutils-objs-$(CONFIG_IPI_MSWI) += ipi/aclint_mswi.o
|
||||||
libsbiutils-objs-$(CONFIG_IPI_PLICSW) += ipi/andes_plicsw.o
|
libsbiutils-objs-$(CONFIG_IPI_PLICSW) += ipi/andes_plicsw.o
|
||||||
|
|
||||||
libsbiutils-objs-$(CONFIG_FDT_IPI) += ipi/fdt_ipi.o
|
carray-fdt_early_drivers-$(CONFIG_FDT_IPI_MSWI) += fdt_ipi_mswi
|
||||||
libsbiutils-objs-$(CONFIG_FDT_IPI) += ipi/fdt_ipi_drivers.carray.o
|
|
||||||
|
|
||||||
carray-fdt_ipi_drivers-$(CONFIG_FDT_IPI_MSWI) += fdt_ipi_mswi
|
|
||||||
libsbiutils-objs-$(CONFIG_FDT_IPI_MSWI) += ipi/fdt_ipi_mswi.o
|
libsbiutils-objs-$(CONFIG_FDT_IPI_MSWI) += ipi/fdt_ipi_mswi.o
|
||||||
|
|
||||||
carray-fdt_ipi_drivers-$(CONFIG_FDT_IPI_PLICSW) += fdt_ipi_plicsw
|
carray-fdt_early_drivers-$(CONFIG_FDT_IPI_PLICSW) += fdt_ipi_plicsw
|
||||||
libsbiutils-objs-$(CONFIG_FDT_IPI_PLICSW) += ipi/fdt_ipi_plicsw.o
|
libsbiutils-objs-$(CONFIG_FDT_IPI_PLICSW) += ipi/fdt_ipi_plicsw.o
|
||||||
|
|||||||
@@ -115,16 +115,96 @@
|
|||||||
#define APLIC_DISABLE_ITHRESHOLD 1
|
#define APLIC_DISABLE_ITHRESHOLD 1
|
||||||
#define APLIC_ENABLE_ITHRESHOLD 0
|
#define APLIC_ENABLE_ITHRESHOLD 0
|
||||||
|
|
||||||
|
static SBI_LIST_HEAD(aplic_list);
|
||||||
|
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
|
||||||
|
void *msicfgaddr, void *msicfgaddrH);
|
||||||
|
|
||||||
|
static void aplic_init(struct aplic_data *aplic)
|
||||||
|
{
|
||||||
|
struct aplic_delegate_data *deleg;
|
||||||
|
u32 i, j, tmp;
|
||||||
|
int locked;
|
||||||
|
|
||||||
|
/* Set domain configuration to 0 */
|
||||||
|
writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
|
||||||
|
|
||||||
|
/* Disable all interrupts */
|
||||||
|
for (i = 0; i <= aplic->num_source; i += 32)
|
||||||
|
writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
|
||||||
|
(i / 32) * sizeof(u32)));
|
||||||
|
|
||||||
|
/* Set interrupt type and priority for all interrupts */
|
||||||
|
for (i = 1; i <= aplic->num_source; i++) {
|
||||||
|
/* Set IRQ source configuration to 0 */
|
||||||
|
writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
|
||||||
|
(i - 1) * sizeof(u32)));
|
||||||
|
/* Set IRQ target hart index and priority to 1 */
|
||||||
|
writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
|
||||||
|
APLIC_TARGET_BASE +
|
||||||
|
(i - 1) * sizeof(u32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure IRQ delegation */
|
||||||
|
for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
|
||||||
|
deleg = &aplic->delegate[i];
|
||||||
|
if (!deleg->first_irq || !deleg->last_irq)
|
||||||
|
continue;
|
||||||
|
if (aplic->num_source < deleg->first_irq ||
|
||||||
|
aplic->num_source < deleg->last_irq)
|
||||||
|
continue;
|
||||||
|
if (deleg->child_index > APLIC_SOURCECFG_CHILDIDX_MASK)
|
||||||
|
continue;
|
||||||
|
if (deleg->first_irq > deleg->last_irq) {
|
||||||
|
tmp = deleg->first_irq;
|
||||||
|
deleg->first_irq = deleg->last_irq;
|
||||||
|
deleg->last_irq = tmp;
|
||||||
|
}
|
||||||
|
for (j = deleg->first_irq; j <= deleg->last_irq; j++)
|
||||||
|
writel(APLIC_SOURCECFG_D | deleg->child_index,
|
||||||
|
(void *)(aplic->addr + APLIC_SOURCECFG_BASE +
|
||||||
|
(j - 1) * sizeof(u32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default initialization of IDC structures */
|
||||||
|
for (i = 0; i < aplic->num_idc; i++) {
|
||||||
|
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
|
||||||
|
i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
|
||||||
|
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
|
||||||
|
i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
|
||||||
|
writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
|
||||||
|
APLIC_IDC_BASE +
|
||||||
|
(i * APLIC_IDC_SIZE) +
|
||||||
|
APLIC_IDC_ITHRESHOLD));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MSI configuration */
|
||||||
|
locked = readl((void *)(aplic->addr + APLIC_MMSICFGADDRH)) & APLIC_xMSICFGADDRH_L;
|
||||||
|
if (aplic->targets_mmode && aplic->has_msicfg_mmode && !locked) {
|
||||||
|
aplic_writel_msicfg(&aplic->msicfg_mmode,
|
||||||
|
(void *)(aplic->addr + APLIC_MMSICFGADDR),
|
||||||
|
(void *)(aplic->addr + APLIC_MMSICFGADDRH));
|
||||||
|
}
|
||||||
|
if (aplic->targets_mmode && aplic->has_msicfg_smode && !locked) {
|
||||||
|
aplic_writel_msicfg(&aplic->msicfg_smode,
|
||||||
|
(void *)(aplic->addr + APLIC_SMSICFGADDR),
|
||||||
|
(void *)(aplic->addr + APLIC_SMSICFGADDRH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aplic_reinit_all(void)
|
||||||
|
{
|
||||||
|
struct aplic_data *aplic;
|
||||||
|
|
||||||
|
sbi_list_for_each_entry(aplic, &aplic_list, node)
|
||||||
|
aplic_init(aplic);
|
||||||
|
}
|
||||||
|
|
||||||
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
|
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
|
||||||
void *msicfgaddr, void *msicfgaddrH)
|
void *msicfgaddr, void *msicfgaddrH)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
unsigned long base_ppn;
|
unsigned long base_ppn;
|
||||||
|
|
||||||
/* Check if MSI config is already locked */
|
|
||||||
if (readl(msicfgaddrH) & APLIC_xMSICFGADDRH_L)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Compute the MSI base PPN */
|
/* Compute the MSI base PPN */
|
||||||
base_ppn = msicfg->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT;
|
base_ppn = msicfg->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT;
|
||||||
base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(msicfg->lhxs);
|
base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(msicfg->lhxs);
|
||||||
@@ -168,9 +248,8 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
|
|||||||
int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
u32 i, j, tmp;
|
|
||||||
struct aplic_delegate_data *deleg;
|
struct aplic_delegate_data *deleg;
|
||||||
u32 first_deleg_irq, last_deleg_irq;
|
u32 first_deleg_irq, last_deleg_irq, i;
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if (!aplic ||
|
if (!aplic ||
|
||||||
@@ -188,81 +267,24 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set domain configuration to 0 */
|
/* Init the APLIC registers */
|
||||||
writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
|
aplic_init(aplic);
|
||||||
|
|
||||||
/* Disable all interrupts */
|
|
||||||
for (i = 0; i <= aplic->num_source; i += 32)
|
|
||||||
writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
|
|
||||||
(i / 32) * sizeof(u32)));
|
|
||||||
|
|
||||||
/* Set interrupt type and priority for all interrupts */
|
|
||||||
for (i = 1; i <= aplic->num_source; i++) {
|
|
||||||
/* Set IRQ source configuration to 0 */
|
|
||||||
writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
|
|
||||||
(i - 1) * sizeof(u32)));
|
|
||||||
/* Set IRQ target hart index and priority to 1 */
|
|
||||||
writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
|
|
||||||
APLIC_TARGET_BASE +
|
|
||||||
(i - 1) * sizeof(u32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure IRQ delegation */
|
|
||||||
first_deleg_irq = -1U;
|
|
||||||
last_deleg_irq = 0;
|
|
||||||
for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
|
|
||||||
deleg = &aplic->delegate[i];
|
|
||||||
if (!deleg->first_irq || !deleg->last_irq)
|
|
||||||
continue;
|
|
||||||
if (aplic->num_source < deleg->first_irq ||
|
|
||||||
aplic->num_source < deleg->last_irq)
|
|
||||||
continue;
|
|
||||||
if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index)
|
|
||||||
continue;
|
|
||||||
if (deleg->first_irq > deleg->last_irq) {
|
|
||||||
tmp = deleg->first_irq;
|
|
||||||
deleg->first_irq = deleg->last_irq;
|
|
||||||
deleg->last_irq = tmp;
|
|
||||||
}
|
|
||||||
if (deleg->first_irq < first_deleg_irq)
|
|
||||||
first_deleg_irq = deleg->first_irq;
|
|
||||||
if (last_deleg_irq < deleg->last_irq)
|
|
||||||
last_deleg_irq = deleg->last_irq;
|
|
||||||
for (j = deleg->first_irq; j <= deleg->last_irq; j++)
|
|
||||||
writel(APLIC_SOURCECFG_D | deleg->child_index,
|
|
||||||
(void *)(aplic->addr + APLIC_SOURCECFG_BASE +
|
|
||||||
(j - 1) * sizeof(u32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default initialization of IDC structures */
|
|
||||||
for (i = 0; i < aplic->num_idc; i++) {
|
|
||||||
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
|
|
||||||
i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
|
|
||||||
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
|
|
||||||
i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
|
|
||||||
writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
|
|
||||||
APLIC_IDC_BASE +
|
|
||||||
(i * APLIC_IDC_SIZE) +
|
|
||||||
APLIC_IDC_ITHRESHOLD));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MSI configuration */
|
|
||||||
if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
|
|
||||||
aplic_writel_msicfg(&aplic->msicfg_mmode,
|
|
||||||
(void *)(aplic->addr + APLIC_MMSICFGADDR),
|
|
||||||
(void *)(aplic->addr + APLIC_MMSICFGADDRH));
|
|
||||||
}
|
|
||||||
if (aplic->targets_mmode && aplic->has_msicfg_smode) {
|
|
||||||
aplic_writel_msicfg(&aplic->msicfg_smode,
|
|
||||||
(void *)(aplic->addr + APLIC_SMSICFGADDR),
|
|
||||||
(void *)(aplic->addr + APLIC_SMSICFGADDRH));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add APLIC region to the root domain if:
|
* Add APLIC region to the root domain if:
|
||||||
* 1) It targets M-mode of any HART directly or via MSIs
|
* 1) It targets M-mode of any HART directly or via MSIs
|
||||||
* 2) All interrupts are delegated to some child APLIC
|
* 2) All interrupts are delegated to some child APLIC
|
||||||
*/
|
*/
|
||||||
|
first_deleg_irq = -1U;
|
||||||
|
last_deleg_irq = 0;
|
||||||
|
for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
|
||||||
|
deleg = &aplic->delegate[i];
|
||||||
|
if (deleg->first_irq < first_deleg_irq)
|
||||||
|
first_deleg_irq = deleg->first_irq;
|
||||||
|
if (last_deleg_irq < deleg->last_irq)
|
||||||
|
last_deleg_irq = deleg->last_irq;
|
||||||
|
}
|
||||||
|
|
||||||
if (aplic->targets_mmode ||
|
if (aplic->targets_mmode ||
|
||||||
((first_deleg_irq < last_deleg_irq) &&
|
((first_deleg_irq < last_deleg_irq) &&
|
||||||
(last_deleg_irq == aplic->num_source) &&
|
(last_deleg_irq == aplic->num_source) &&
|
||||||
@@ -278,5 +300,8 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
|
|||||||
/* Register irqchip device */
|
/* Register irqchip device */
|
||||||
sbi_irqchip_add_device(&aplic->irqchip);
|
sbi_irqchip_add_device(&aplic->irqchip);
|
||||||
|
|
||||||
|
/* Attach to the aplic list */
|
||||||
|
sbi_list_add_tail(&aplic->node, &aplic_list);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ static void imsic_ipi_send(u32 hart_index)
|
|||||||
|
|
||||||
static struct sbi_ipi_device imsic_ipi_device = {
|
static struct sbi_ipi_device imsic_ipi_device = {
|
||||||
.name = "aia-imsic",
|
.name = "aia-imsic",
|
||||||
|
.rating = 300,
|
||||||
.ipi_send = imsic_ipi_send
|
.ipi_send = imsic_ipi_send
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -393,7 +394,7 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
|
|||||||
sbi_irqchip_add_device(&imsic_device);
|
sbi_irqchip_add_device(&imsic_device);
|
||||||
|
|
||||||
/* Register IPI device */
|
/* Register IPI device */
|
||||||
sbi_ipi_set_device(&imsic_ipi_device);
|
sbi_ipi_add_device(&imsic_ipi_device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ void plic_suspend(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
sbi_for_each_hartindex(h) {
|
sbi_for_each_hartindex(h) {
|
||||||
u32 context_id = plic->context_map[h][PLIC_S_CONTEXT];
|
s16 context_id = plic->context_map[h][PLIC_S_CONTEXT];
|
||||||
|
|
||||||
if (context_id < 0)
|
if (context_id < 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -167,7 +167,7 @@ void plic_resume(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
sbi_for_each_hartindex(h) {
|
sbi_for_each_hartindex(h) {
|
||||||
u32 context_id = plic->context_map[h][PLIC_S_CONTEXT];
|
s16 context_id = plic->context_map[h][PLIC_S_CONTEXT];
|
||||||
|
|
||||||
if (context_id < 0)
|
if (context_id < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -22,6 +22,18 @@ config FDT_MPXY_RPMI_SYSMSI
|
|||||||
bool "MPXY driver for RPMI system MSI service group"
|
bool "MPXY driver for RPMI system MSI service group"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config FDT_MPXY_RPMI_VOLTAGE
|
||||||
|
bool "MPXY driver for RPMI voltage service group"
|
||||||
|
default n
|
||||||
|
|
||||||
|
config FDT_MPXY_RPMI_DEVICE_POWER
|
||||||
|
bool "MPXY driver for RPMI device power service group"
|
||||||
|
default n
|
||||||
|
|
||||||
|
config FDT_MPXY_RPMI_PERFORMANCE
|
||||||
|
bool "MPXY driver for RPMI performance service group"
|
||||||
|
default n
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
56
lib/utils/mpxy/fdt_mpxy_rpmi_device_power.c
Normal file
56
lib/utils/mpxy/fdt_mpxy_rpmi_device_power.c
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include <sbi_utils/mpxy/fdt_mpxy_rpmi_mbox.h>
|
||||||
|
|
||||||
|
static struct mpxy_rpmi_service_data dpwr_services[] = {
|
||||||
|
{
|
||||||
|
.id = RPMI_DPWR_SRV_ENABLE_NOTIFICATION,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_enable_notification_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_enable_notification_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_enable_notification_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_enable_notification_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_DPWR_SRV_GET_NUM_DOMAINS,
|
||||||
|
.min_tx_len = 0,
|
||||||
|
.max_tx_len = 0,
|
||||||
|
.min_rx_len = sizeof(struct rpmi_dpwr_get_num_domain_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_dpwr_get_num_domain_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_DPWR_SRV_GET_ATTRIBUTES,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_dpwr_get_attrs_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_dpwr_get_attrs_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_dpwr_get_attrs_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_dpwr_get_attrs_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_DPWR_SRV_SET_STATE,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_dpwr_set_state_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_dpwr_set_state_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_dpwr_set_state_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_dpwr_set_state_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_DPWR_SRV_GET_STATE,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_dpwr_get_state_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_dpwr_get_state_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_dpwr_get_state_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_dpwr_get_state_resp),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mpxy_rpmi_mbox_data dpwr_data = {
|
||||||
|
.servicegrp_id = RPMI_SRVGRP_DEVICE_POWER,
|
||||||
|
.num_services = RPMI_DPWR_SRV_MAX_COUNT,
|
||||||
|
.service_data = dpwr_services,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fdt_match dpwr_match[] = {
|
||||||
|
{ .compatible = "riscv,rpmi-mpxy-device-power", .data = &dpwr_data },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver fdt_mpxy_rpmi_device_power = {
|
||||||
|
.experimental = true,
|
||||||
|
.match_table = dpwr_match,
|
||||||
|
.init = mpxy_rpmi_mbox_init,
|
||||||
|
};
|
||||||
91
lib/utils/mpxy/fdt_mpxy_rpmi_performance.c
Normal file
91
lib/utils/mpxy/fdt_mpxy_rpmi_performance.c
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include <sbi_utils/mpxy/fdt_mpxy_rpmi_mbox.h>
|
||||||
|
|
||||||
|
static struct mpxy_rpmi_service_data performance_services[] = {
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_ENABLE_NOTIFICATION,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_enable_notification_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_enable_notification_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_enable_notification_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_enable_notification_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_GET_NUM_DOMAINS,
|
||||||
|
.min_tx_len = 0,
|
||||||
|
.max_tx_len = 0,
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_get_num_domain_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_perf_get_num_domain_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_GET_ATTRIBUTES,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_perf_get_attrs_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_perf_get_attrs_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_get_attrs_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_perf_get_attrs_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_GET_SUPPORTED_LEVELS,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_perf_get_supported_level_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_perf_get_supported_level_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_get_supported_level_resp),
|
||||||
|
.max_rx_len = -1U,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_GET_LEVEL,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_perf_get_level_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_perf_get_level_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_get_level_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_perf_get_level_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_SET_LEVEL,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_perf_set_level_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_perf_set_level_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_set_level_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_perf_set_level_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_GET_LIMIT,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_perf_get_limit_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_perf_get_limit_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_get_limit_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_perf_get_limit_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_SET_LIMIT,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_perf_set_limit_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_perf_set_limit_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_set_limit_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_perf_set_limit_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_GET_FAST_CHANNEL_REGION,
|
||||||
|
.min_tx_len = 0,
|
||||||
|
.max_tx_len = 0,
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_get_fast_chn_region_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_perf_get_fast_chn_region_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_PERF_SRV_GET_FAST_CHANNEL_ATTRIBUTES,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_perf_get_fast_chn_attr_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_perf_get_fast_chn_attr_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_perf_get_fast_chn_attr_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_perf_get_fast_chn_attr_resp),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mpxy_rpmi_mbox_data performance_data = {
|
||||||
|
.servicegrp_id = RPMI_SRVGRP_PERFORMANCE ,
|
||||||
|
.num_services = RPMI_PERF_SRV_MAX_COUNT,
|
||||||
|
.service_data = performance_services,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fdt_match performance_match[] = {
|
||||||
|
{ .compatible = "riscv,rpmi-mpxy-performance", .data = &performance_data },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver fdt_mpxy_rpmi_performance = {
|
||||||
|
.experimental = true,
|
||||||
|
.match_table = performance_match,
|
||||||
|
.init = mpxy_rpmi_mbox_init,
|
||||||
|
};
|
||||||
@@ -57,7 +57,8 @@ static int mpxy_rpmi_sysmis_xfer(void *context, struct mbox_chan *chan,
|
|||||||
sys_msi_address |= ((u64)le32_to_cpu(((u32 *)xfer->tx)[2])) << 32;
|
sys_msi_address |= ((u64)le32_to_cpu(((u32 *)xfer->tx)[2])) << 32;
|
||||||
if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
|
if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
|
||||||
sys_msi_address, 0x4, PRV_S,
|
sys_msi_address, 0x4, PRV_S,
|
||||||
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
|
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE |
|
||||||
|
SBI_DOMAIN_MMIO)) {
|
||||||
((u32 *)xfer->rx)[0] = cpu_to_le32(RPMI_ERR_INVALID_ADDR);
|
((u32 *)xfer->rx)[0] = cpu_to_le32(RPMI_ERR_INVALID_ADDR);
|
||||||
args->rx_data_len = sizeof(u32);
|
args->rx_data_len = sizeof(u32);
|
||||||
break;
|
break;
|
||||||
|
|||||||
77
lib/utils/mpxy/fdt_mpxy_rpmi_voltage.c
Normal file
77
lib/utils/mpxy/fdt_mpxy_rpmi_voltage.c
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#include <sbi_utils/mpxy/fdt_mpxy_rpmi_mbox.h>
|
||||||
|
|
||||||
|
static struct mpxy_rpmi_service_data voltage_services[] = {
|
||||||
|
{
|
||||||
|
.id = RPMI_VOLTAGE_SRV_ENABLE_NOTIFICATION,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_enable_notification_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_enable_notification_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_enable_notification_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_enable_notification_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_VOLTAGE_SRV_GET_NUM_DOMAINS,
|
||||||
|
.min_tx_len = 0,
|
||||||
|
.max_tx_len = 0,
|
||||||
|
.min_rx_len = sizeof(struct rpmi_voltage_get_num_domains_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_voltage_get_num_domains_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_VOLTAGE_SRV_GET_ATTRIBUTES,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_voltage_get_attributes_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_voltage_get_attributes_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_voltage_get_attributes_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_voltage_get_attributes_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_VOLTAGE_SRV_GET_SUPPORTED_LEVELS,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_voltage_get_supported_rate_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_voltage_get_supported_rate_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_voltage_get_supported_rate_resp),
|
||||||
|
.max_rx_len = -1U,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_VOLTAGE_SRV_SET_CONFIG,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_voltage_set_config_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_voltage_set_config_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_voltage_set_config_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_voltage_set_config_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_VOLTAGE_SRV_GET_CONFIG,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_voltage_get_config_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_voltage_get_config_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_voltage_get_config_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_voltage_get_config_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_VOLTAGE_SRV_SET_LEVEL,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_voltage_set_level_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_voltage_set_level_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_voltage_set_level_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_voltage_set_level_resp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = RPMI_VOLTAGE_SRV_GET_LEVEL,
|
||||||
|
.min_tx_len = sizeof(struct rpmi_voltage_get_level_req),
|
||||||
|
.max_tx_len = sizeof(struct rpmi_voltage_get_level_req),
|
||||||
|
.min_rx_len = sizeof(struct rpmi_voltage_get_level_resp),
|
||||||
|
.max_rx_len = sizeof(struct rpmi_voltage_get_level_resp),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mpxy_rpmi_mbox_data voltage_data = {
|
||||||
|
.servicegrp_id = RPMI_SRVGRP_VOLTAGE,
|
||||||
|
.num_services = RPMI_VOLTAGE_SRV_MAX_COUNT,
|
||||||
|
.service_data = voltage_services,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fdt_match voltage_match[] = {
|
||||||
|
{ .compatible = "riscv,rpmi-mpxy-voltage", .data = &voltage_data },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver fdt_mpxy_rpmi_voltage = {
|
||||||
|
.experimental = true,
|
||||||
|
.match_table = voltage_match,
|
||||||
|
.init = mpxy_rpmi_mbox_init,
|
||||||
|
};
|
||||||
@@ -15,5 +15,14 @@ libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_MBOX) += mpxy/fdt_mpxy_rpmi_mbox.o
|
|||||||
carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_CLOCK) += fdt_mpxy_rpmi_clock
|
carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_CLOCK) += fdt_mpxy_rpmi_clock
|
||||||
libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_CLOCK) += mpxy/fdt_mpxy_rpmi_clock.o
|
libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_CLOCK) += mpxy/fdt_mpxy_rpmi_clock.o
|
||||||
|
|
||||||
|
carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_PERFORMANCE) += fdt_mpxy_rpmi_performance
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_PERFORMANCE) += mpxy/fdt_mpxy_rpmi_performance.o
|
||||||
|
|
||||||
carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_SYSMSI) += fdt_mpxy_rpmi_sysmsi
|
carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_SYSMSI) += fdt_mpxy_rpmi_sysmsi
|
||||||
libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_SYSMSI) += mpxy/fdt_mpxy_rpmi_sysmsi.o
|
libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_SYSMSI) += mpxy/fdt_mpxy_rpmi_sysmsi.o
|
||||||
|
|
||||||
|
carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_VOLTAGE) += fdt_mpxy_rpmi_voltage
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_VOLTAGE) += mpxy/fdt_mpxy_rpmi_voltage.o
|
||||||
|
|
||||||
|
carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_DEVICE_POWER) += fdt_mpxy_rpmi_device_power
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_DEVICE_POWER) += mpxy/fdt_mpxy_rpmi_device_power.o
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
* Rahul Pathak <rpathak@ventanamicro.com>
|
* Rahul Pathak <rpathak@ventanamicro.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_hart.h>
|
||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_system.h>
|
#include <sbi/sbi_system.h>
|
||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
@@ -56,6 +57,8 @@ static void rpmi_do_system_reset(u32 reset_type)
|
|||||||
if (ret)
|
if (ret)
|
||||||
sbi_printf("system reset failed [type: %d]: ret: %d\n",
|
sbi_printf("system reset failed [type: %d]: ret: %d\n",
|
||||||
reset_type, ret);
|
reset_type, ret);
|
||||||
|
|
||||||
|
sbi_hart_hang();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <sbi/riscv_io.h>
|
#include <sbi/riscv_io.h>
|
||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_domain.h>
|
||||||
#include <sbi_utils/serial/sifive-uart.h>
|
#include <sbi_utils/serial/sifive-uart.h>
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
@@ -111,5 +112,7 @@ int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
|
|||||||
|
|
||||||
sbi_console_set_device(&sifive_console);
|
sbi_console_set_device(&sifive_console);
|
||||||
|
|
||||||
return 0;
|
return sbi_domain_root_add_memrange(base, PAGE_SIZE, PAGE_SIZE,
|
||||||
|
(SBI_DOMAIN_MEMREGION_MMIO |
|
||||||
|
SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
#define UART_RBR_OFFSET 0 /* In: Recieve Buffer Register */
|
#define UART_RBR_OFFSET 0 /* In: Receive Buffer Register */
|
||||||
#define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */
|
#define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */
|
||||||
#define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */
|
#define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */
|
||||||
#define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */
|
#define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ config FDT_SUSPEND_RPMI
|
|||||||
depends on FDT_MAILBOX && RPMI_MAILBOX
|
depends on FDT_MAILBOX && RPMI_MAILBOX
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config FDT_SUSPEND_SIFIVE_SMC0
|
||||||
|
bool "FDT SIFIVE SMC0 suspend driver"
|
||||||
|
depends on FDT_HSM_SIFIVE_TMC0 && IRQCHIP_APLIC
|
||||||
|
default n
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
318
lib/utils/suspend/fdt_suspend_sifive_smc0.c
Normal file
318
lib/utils/suspend/fdt_suspend_sifive_smc0.c
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SiFive
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/riscv_asm.h>
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_domain.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_hart.h>
|
||||||
|
#include <sbi/sbi_hsm.h>
|
||||||
|
#include <sbi/sbi_system.h>
|
||||||
|
#include <sbi/sbi_timer.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cmo_helper.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
|
||||||
|
#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
|
||||||
|
#include <sbi_utils/irqchip/aplic.h>
|
||||||
|
#include <sbi_utils/timer/aclint_mtimer.h>
|
||||||
|
|
||||||
|
#define SIFIVE_SMC_PGPREP_OFF 0x0
|
||||||
|
#define SIFIVE_SMC_PG_OFF 0x4
|
||||||
|
#define SIFIVE_SMC_CCTIMER_OFF 0xc
|
||||||
|
#define SIFIVE_SMC_RESUMEPC_LO_OFF 0x10
|
||||||
|
#define SIFIVE_SMC_RESUMEPC_HI_OFF 0x14
|
||||||
|
#define SIFIVE_SMC_SYNC_PMC_OFF 0x24
|
||||||
|
#define SIFIVE_SMC_CYCLECOUNT_LO_OFF 0x28
|
||||||
|
#define SIFIVE_SMC_CYCLECOUNT_HI_OFF 0x2c
|
||||||
|
#define SIFIVE_SMC_WFI_UNCORE_CG_OFF 0x50
|
||||||
|
|
||||||
|
#define SIFIVE_SMC_PGPREP_ENA_REQ BIT(31)
|
||||||
|
#define SIFIVE_SMC_PGPREP_ENA_ACK BIT(30)
|
||||||
|
#define SIFIVE_SMC_PGPREP_DIS_REQ BIT(29)
|
||||||
|
#define SIFIVE_SMC_PGPREP_DIS_ACK BIT(29)
|
||||||
|
#define SIFIVE_SMC_PGPREP_FRONTNOTQ BIT(19)
|
||||||
|
#define SIFIVE_SMC_PGPREP_CLFPNOTQ BIT(18)
|
||||||
|
#define SIFIVE_SMC_PGPREP_PMCENAERR BIT(17)
|
||||||
|
#define SIFIVE_SMC_PGPREP_WAKE_DETECT BIT(16)
|
||||||
|
#define SIFIVE_SMC_PGPREP_BUSERR BIT(15)
|
||||||
|
#define SIFIVE_SMC_PGPREP_EARLY_ABORT BIT(3)
|
||||||
|
#define SIFIVE_SMC_PGPREP_INTERNAL_ABORT BIT(2)
|
||||||
|
#define SIFIVE_SMC_PGPREP_ENARSP (SIFIVE_SMC_PGPREP_FRONTNOTQ | \
|
||||||
|
SIFIVE_SMC_PGPREP_CLFPNOTQ | \
|
||||||
|
SIFIVE_SMC_PGPREP_PMCENAERR | \
|
||||||
|
SIFIVE_SMC_PGPREP_WAKE_DETECT | \
|
||||||
|
SIFIVE_SMC_PGPREP_BUSERR)
|
||||||
|
|
||||||
|
#define SIFIVE_SMC_PGPREP_ABORT (SIFIVE_SMC_PGPREP_EARLY_ABORT | \
|
||||||
|
SIFIVE_SMC_PGPREP_INTERNAL_ABORT)
|
||||||
|
|
||||||
|
#define SIFIVE_SMC_PG_ENA_REQ BIT(31)
|
||||||
|
#define SIFIVE_SMC_PG_WARM_RESET BIT(1)
|
||||||
|
|
||||||
|
#define SIFIVE_SMC_SYNCPMC_SYNC_REQ BIT(31)
|
||||||
|
#define SIFIVE_SMC_SYNCPMC_SYNC_WREQ BIT(30)
|
||||||
|
#define SIFIVE_SMC_SYNCPMC_SYNC_ACK BIT(29)
|
||||||
|
|
||||||
|
static struct aclint_mtimer_data smc_sync_timer;
|
||||||
|
static unsigned long smc0_base;
|
||||||
|
|
||||||
|
static void sifive_smc0_set_pmcsync(char regid, bool write_mode)
|
||||||
|
{
|
||||||
|
unsigned long addr = smc0_base + SIFIVE_SMC_SYNC_PMC_OFF;
|
||||||
|
u32 v = regid | SIFIVE_SMC_SYNCPMC_SYNC_REQ;
|
||||||
|
|
||||||
|
if (write_mode)
|
||||||
|
v |= SIFIVE_SMC_SYNCPMC_SYNC_WREQ;
|
||||||
|
|
||||||
|
writel(v, (void *)addr);
|
||||||
|
while (!(readl((void *)addr) & SIFIVE_SMC_SYNCPMC_SYNC_ACK));
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 sifive_smc0_time_read(volatile u64 *addr)
|
||||||
|
{
|
||||||
|
u32 lo, hi;
|
||||||
|
|
||||||
|
do {
|
||||||
|
sifive_smc0_set_pmcsync(SIFIVE_SMC_CYCLECOUNT_LO_OFF, false);
|
||||||
|
sifive_smc0_set_pmcsync(SIFIVE_SMC_CYCLECOUNT_HI_OFF, false);
|
||||||
|
hi = readl_relaxed((u32 *)addr + 1);
|
||||||
|
lo = readl_relaxed((u32 *)addr);
|
||||||
|
} while (hi != readl_relaxed((u32 *)addr + 1));
|
||||||
|
|
||||||
|
return ((u64)hi << 32) | (u64)lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sifive_smc0_set_resumepc(physical_addr_t raddr)
|
||||||
|
{
|
||||||
|
/* Set resumepc_lo */
|
||||||
|
writel((u32)raddr, (void *)(smc0_base + SIFIVE_SMC_RESUMEPC_LO_OFF));
|
||||||
|
/* copy resumepc_lo from SMC to PMC */
|
||||||
|
sifive_smc0_set_pmcsync(SIFIVE_SMC_RESUMEPC_LO_OFF, true);
|
||||||
|
#if __riscv_xlen > 32
|
||||||
|
/* Set resumepc_hi */
|
||||||
|
writel((u32)(raddr >> 32), (void *)(smc0_base + SIFIVE_SMC_RESUMEPC_HI_OFF));
|
||||||
|
/* copy resumepc_hi from SMC to PMC */
|
||||||
|
sifive_smc0_set_pmcsync(SIFIVE_SMC_RESUMEPC_HI_OFF, true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 sifive_smc0_get_pgprep_enarsp(void)
|
||||||
|
{
|
||||||
|
u32 v = readl((void *)(smc0_base + SIFIVE_SMC_PGPREP_OFF));
|
||||||
|
|
||||||
|
return v & SIFIVE_SMC_PGPREP_ENARSP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sifive_smc0_set_pgprep_disreq(void)
|
||||||
|
{
|
||||||
|
unsigned long addr = smc0_base + SIFIVE_SMC_PGPREP_OFF;
|
||||||
|
u32 v = readl((void *)addr);
|
||||||
|
|
||||||
|
writel(v | SIFIVE_SMC_PGPREP_DIS_REQ, (void *)addr);
|
||||||
|
while (!(readl((void *)addr) & SIFIVE_SMC_PGPREP_DIS_ACK));
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 sifive_smc0_set_pgprep_enareq(void)
|
||||||
|
{
|
||||||
|
unsigned long addr = smc0_base + SIFIVE_SMC_PGPREP_OFF;
|
||||||
|
u32 v = readl((void *)addr);
|
||||||
|
|
||||||
|
writel(v | SIFIVE_SMC_PGPREP_ENA_REQ, (void *)addr);
|
||||||
|
while (!(readl((void *)addr) & SIFIVE_SMC_PGPREP_ENA_ACK));
|
||||||
|
|
||||||
|
v = readl((void *)addr);
|
||||||
|
|
||||||
|
return v & SIFIVE_SMC_PGPREP_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sifive_smc0_set_pg_enareq(void)
|
||||||
|
{
|
||||||
|
unsigned long addr = smc0_base + SIFIVE_SMC_PG_OFF;
|
||||||
|
u32 v = readl((void *)addr);
|
||||||
|
|
||||||
|
writel(v | SIFIVE_SMC_PG_ENA_REQ, (void *)addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sifive_smc0_set_cg(bool enable)
|
||||||
|
{
|
||||||
|
unsigned long addr = smc0_base + SIFIVE_SMC_WFI_UNCORE_CG_OFF;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
writel(0, (void *)addr);
|
||||||
|
else
|
||||||
|
writel(1, (void *)addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_smc0_prep(void)
|
||||||
|
{
|
||||||
|
const struct sbi_domain *dom = &root;
|
||||||
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
unsigned long i;
|
||||||
|
int rc;
|
||||||
|
u32 target;
|
||||||
|
|
||||||
|
if (!smc0_base)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
/* Prevent all secondary tiles from waking up from PG state */
|
||||||
|
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
|
||||||
|
target = sbi_hartindex_to_hartid(i);
|
||||||
|
if (target != current_hartid()) {
|
||||||
|
rc = sifive_tmc0_set_wakemask_enareq(target);
|
||||||
|
if (rc) {
|
||||||
|
sbi_printf("Fail to enable wakemask for hart %d\n",
|
||||||
|
target);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if all secondary tiles enter PG state */
|
||||||
|
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
|
||||||
|
target = sbi_hartindex_to_hartid(i);
|
||||||
|
if (target != current_hartid() &&
|
||||||
|
!sifive_tmc0_is_pg(target)) {
|
||||||
|
sbi_printf("Hart %d not in the PG state\n", target);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sifive_smc0_set_pgprep_enareq();
|
||||||
|
if (rc) {
|
||||||
|
sbi_printf("SMC0 error: abort code: 0x%x\n", rc);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = sifive_smc0_get_pgprep_enarsp();
|
||||||
|
if (rc) {
|
||||||
|
sifive_smc0_set_pgprep_disreq();
|
||||||
|
sbi_printf("SMC0 error: error response code: 0x%x\n", rc);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
sifive_smc0_set_resumepc(scratch->warmboot_addr);
|
||||||
|
return SBI_OK;
|
||||||
|
fail:
|
||||||
|
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
|
||||||
|
target = sbi_hartindex_to_hartid(i);
|
||||||
|
if (target != current_hartid())
|
||||||
|
sifive_tmc0_set_wakemask_disreq(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_EFAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_smc0_enter(void)
|
||||||
|
{
|
||||||
|
const struct sbi_domain *dom = &root;
|
||||||
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
unsigned long i;
|
||||||
|
u32 target, rc;
|
||||||
|
|
||||||
|
/* Flush cache and check if there is wake detect or bus error */
|
||||||
|
if (fdt_cmo_llc_flush_all() &&
|
||||||
|
sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
|
||||||
|
sifive_cflush();
|
||||||
|
|
||||||
|
rc = sifive_smc0_get_pgprep_enarsp();
|
||||||
|
if (rc) {
|
||||||
|
sbi_printf("SMC0 error: error response code: 0x%x\n", rc);
|
||||||
|
rc = SBI_EFAIL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
|
||||||
|
sifive_smc0_set_pg_enareq();
|
||||||
|
while (1)
|
||||||
|
sifive_cease();
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SBI_ENOTSUPP;
|
||||||
|
fail:
|
||||||
|
sifive_smc0_set_pgprep_disreq();
|
||||||
|
sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
|
||||||
|
target = sbi_hartindex_to_hartid(i);
|
||||||
|
if (target != current_hartid())
|
||||||
|
sifive_tmc0_set_wakemask_disreq(target);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_smc0_pg(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = sifive_smc0_prep();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return sifive_smc0_enter();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sifive_smc0_mtime_update(void)
|
||||||
|
{
|
||||||
|
struct aclint_mtimer_data *mt = aclint_get_mtimer_data();
|
||||||
|
|
||||||
|
aclint_mtimer_update(mt, &smc_sync_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_smc0_system_suspend_check(u32 sleep_type)
|
||||||
|
{
|
||||||
|
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? SBI_OK : SBI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_smc0_system_suspend(u32 sleep_type, unsigned long addr)
|
||||||
|
{
|
||||||
|
/* Disable the timer interrupt */
|
||||||
|
sbi_timer_exit(sbi_scratch_thishart_ptr());
|
||||||
|
|
||||||
|
return sifive_smc0_pg();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sifive_smc0_system_resume(void)
|
||||||
|
{
|
||||||
|
aplic_reinit_all();
|
||||||
|
sifive_smc0_mtime_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sbi_system_suspend_device smc0_sys_susp = {
|
||||||
|
.name = "Sifive SMC0",
|
||||||
|
.system_suspend_check = sifive_smc0_system_suspend_check,
|
||||||
|
.system_suspend = sifive_smc0_system_suspend,
|
||||||
|
.system_resume = sifive_smc0_system_resume,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sifive_smc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
u64 addr;
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
smc0_base = (unsigned long)addr;
|
||||||
|
smc_sync_timer.time_rd = sifive_smc0_time_read;
|
||||||
|
smc_sync_timer.mtime_addr = smc0_base + SIFIVE_SMC_CYCLECOUNT_LO_OFF;
|
||||||
|
|
||||||
|
sbi_system_suspend_set_device(&smc0_sys_susp);
|
||||||
|
sifive_smc0_set_cg(true);
|
||||||
|
|
||||||
|
return SBI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match sifive_smc0_match[] = {
|
||||||
|
{ .compatible = "sifive,smc0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver fdt_suspend_sifive_smc0 = {
|
||||||
|
.match_table = sifive_smc0_match,
|
||||||
|
.init = sifive_smc0_probe,
|
||||||
|
};
|
||||||
@@ -9,3 +9,6 @@
|
|||||||
|
|
||||||
carray-fdt_early_drivers-$(CONFIG_FDT_SUSPEND_RPMI) += fdt_suspend_rpmi
|
carray-fdt_early_drivers-$(CONFIG_FDT_SUSPEND_RPMI) += fdt_suspend_rpmi
|
||||||
libsbiutils-objs-$(CONFIG_FDT_SUSPEND_RPMI) += suspend/fdt_suspend_rpmi.o
|
libsbiutils-objs-$(CONFIG_FDT_SUSPEND_RPMI) += suspend/fdt_suspend_rpmi.o
|
||||||
|
|
||||||
|
carray-fdt_early_drivers-$(CONFIG_FDT_SUSPEND_SIFIVE_SMC0) += fdt_suspend_sifive_smc0
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_SUSPEND_SIFIVE_SMC0) += suspend/fdt_suspend_sifive_smc0.o
|
||||||
|
|||||||
@@ -109,10 +109,34 @@ static struct sbi_timer_device mtimer = {
|
|||||||
.timer_event_stop = mtimer_event_stop
|
.timer_event_stop = mtimer_event_stop
|
||||||
};
|
};
|
||||||
|
|
||||||
void aclint_mtimer_sync(struct aclint_mtimer_data *mt)
|
struct aclint_mtimer_data *aclint_get_mtimer_data(void)
|
||||||
|
{
|
||||||
|
return mtimer_get_hart_data_ptr(sbi_scratch_thishart_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
void aclint_mtimer_update(struct aclint_mtimer_data *mt,
|
||||||
|
struct aclint_mtimer_data *ref)
|
||||||
{
|
{
|
||||||
u64 v1, v2, mv, delta;
|
u64 v1, v2, mv, delta;
|
||||||
u64 *mt_time_val, *ref_time_val;
|
u64 *mt_time_val, *ref_time_val;
|
||||||
|
|
||||||
|
if (!mt || !ref || !mt->time_rd || !mt->time_wr || !ref->time_rd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mt_time_val = (void *)mt->mtime_addr;
|
||||||
|
ref_time_val = (void *)ref->mtime_addr;
|
||||||
|
if (!atomic_raw_xchg_ulong(&mt->time_delta_computed, 1)) {
|
||||||
|
v1 = mt->time_rd(mt_time_val);
|
||||||
|
mv = ref->time_rd(ref_time_val);
|
||||||
|
v2 = mt->time_rd(mt_time_val);
|
||||||
|
delta = mv - ((v1 / 2) + (v2 / 2));
|
||||||
|
mt->time_wr(false, mt->time_rd(mt_time_val) + delta,
|
||||||
|
mt_time_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aclint_mtimer_sync(struct aclint_mtimer_data *mt)
|
||||||
|
{
|
||||||
struct aclint_mtimer_data *reference;
|
struct aclint_mtimer_data *reference;
|
||||||
|
|
||||||
/* Sync-up non-shared MTIME if reference is available */
|
/* Sync-up non-shared MTIME if reference is available */
|
||||||
@@ -120,17 +144,7 @@ void aclint_mtimer_sync(struct aclint_mtimer_data *mt)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
reference = mt->time_delta_reference;
|
reference = mt->time_delta_reference;
|
||||||
mt_time_val = (void *)mt->mtime_addr;
|
aclint_mtimer_update(mt, reference);
|
||||||
ref_time_val = (void *)reference->mtime_addr;
|
|
||||||
if (!atomic_raw_xchg_ulong(&mt->time_delta_computed, 1)) {
|
|
||||||
v1 = mt->time_rd(mt_time_val);
|
|
||||||
mv = reference->time_rd(ref_time_val);
|
|
||||||
v2 = mt->time_rd(mt_time_val);
|
|
||||||
delta = mv - ((v1 / 2) + (v2 / 2));
|
|
||||||
mt->time_wr(false, mt->time_rd(mt_time_val) + delta,
|
|
||||||
mt_time_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
|
void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ static int timer_mtimer_cold_init(const void *fdt, int nodeoff,
|
|||||||
struct aclint_mtimer_data *mt;
|
struct aclint_mtimer_data *mt;
|
||||||
const struct timer_mtimer_quirks *quirks = match->data;
|
const struct timer_mtimer_quirks *quirks = match->data;
|
||||||
bool is_clint = quirks && quirks->is_clint;
|
bool is_clint = quirks && quirks->is_clint;
|
||||||
|
bool is_ref = false;
|
||||||
|
|
||||||
mtn = sbi_zalloc(sizeof(*mtn));
|
mtn = sbi_zalloc(sizeof(*mtn));
|
||||||
if (!mtn)
|
if (!mtn)
|
||||||
@@ -110,13 +111,16 @@ static int timer_mtimer_cold_init(const void *fdt, int nodeoff,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Select first MTIMER device with no associated HARTs as our
|
* If we have a DT property to indicate which MTIMER is the reference,
|
||||||
* reference MTIMER device. This is only a temporary strategy
|
* select the first MTIMER device that has it. Otherwise, select the
|
||||||
* of selecting reference MTIMER device. In future, we might
|
* first MTIMER device with no associated HARTs as our reference.
|
||||||
* define an optional DT property or some other mechanism to
|
|
||||||
* help us select the reference MTIMER device.
|
|
||||||
*/
|
*/
|
||||||
if (!mt->hart_count && !mt_reference) {
|
if (fdt_getprop(fdt, nodeoff, "riscv,reference-mtimer", NULL))
|
||||||
|
is_ref = true;
|
||||||
|
else if (!mt->hart_count)
|
||||||
|
is_ref = true;
|
||||||
|
|
||||||
|
if (is_ref && !mt_reference) {
|
||||||
mt_reference = mt;
|
mt_reference = mt;
|
||||||
/*
|
/*
|
||||||
* Set reference for already propbed MTIMER devices
|
* Set reference for already propbed MTIMER devices
|
||||||
@@ -153,8 +157,10 @@ static const struct timer_mtimer_quirks thead_aclint_quirks = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct fdt_match timer_mtimer_match[] = {
|
static const struct fdt_match timer_mtimer_match[] = {
|
||||||
|
{ .compatible = "mips,p8700-aclint-mtimer" },
|
||||||
{ .compatible = "riscv,clint0", .data = &sifive_clint_quirks },
|
{ .compatible = "riscv,clint0", .data = &sifive_clint_quirks },
|
||||||
{ .compatible = "sifive,clint0", .data = &sifive_clint_quirks },
|
{ .compatible = "sifive,clint0", .data = &sifive_clint_quirks },
|
||||||
|
{ .compatible = "sifive,clint2", .data = &sifive_clint_quirks },
|
||||||
{ .compatible = "thead,c900-clint", .data = &thead_clint_quirks },
|
{ .compatible = "thead,c900-clint", .data = &thead_clint_quirks },
|
||||||
{ .compatible = "thead,c900-aclint-mtimer",
|
{ .compatible = "thead,c900-aclint-mtimer",
|
||||||
.data = &thead_aclint_quirks },
|
.data = &thead_aclint_quirks },
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
|
|
||||||
config PLATFORM_ARIANE_FPGA
|
|
||||||
bool
|
|
||||||
select FDT
|
|
||||||
select IPI_MSWI
|
|
||||||
select IRQCHIP_PLIC
|
|
||||||
select SERIAL_UART8250
|
|
||||||
select TIMER_MTIMER
|
|
||||||
default y
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Copyright (C) 2019 FORTH-ICS/CARV
|
|
||||||
# Panagiotis Peristerakis <perister@ics.forth.gr>
|
|
||||||
#
|
|
||||||
|
|
||||||
# Compiler flags
|
|
||||||
platform-cppflags-y =
|
|
||||||
platform-cflags-y =
|
|
||||||
platform-asflags-y =
|
|
||||||
platform-ldflags-y =
|
|
||||||
|
|
||||||
# Object to build
|
|
||||||
platform-objs-y += platform.o
|
|
||||||
|
|
||||||
PLATFORM_RISCV_XLEN = 64
|
|
||||||
|
|
||||||
# Blobs to build
|
|
||||||
FW_JUMP=n
|
|
||||||
|
|
||||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
|
||||||
# This needs to be 4MB aligned for 32-bit support
|
|
||||||
FW_JUMP_ADDR=0x80400000
|
|
||||||
else
|
|
||||||
# This needs to be 2MB aligned for 64-bit support
|
|
||||||
FW_JUMP_ADDR=0x80200000
|
|
||||||
endif
|
|
||||||
FW_JUMP_FDT_ADDR=0x82200000
|
|
||||||
|
|
||||||
# Firmware with payload configuration.
|
|
||||||
FW_PAYLOAD=y
|
|
||||||
|
|
||||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
|
||||||
# This needs to be 4MB aligned for 32-bit support
|
|
||||||
FW_PAYLOAD_OFFSET=0x400000
|
|
||||||
else
|
|
||||||
# This needs to be 2MB aligned for 64-bit support
|
|
||||||
FW_PAYLOAD_OFFSET=0x200000
|
|
||||||
endif
|
|
||||||
FW_PAYLOAD_FDT_ADDR=0x82200000
|
|
||||||
FW_PAYLOAD_ALIGN=0x1000
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
|
|
||||||
config PLATFORM_OPENPITON_FPGA
|
|
||||||
bool
|
|
||||||
select FDT
|
|
||||||
select IPI_MSWI
|
|
||||||
select IRQCHIP_PLIC
|
|
||||||
select SERIAL_UART8250
|
|
||||||
select TIMER_MTIMER
|
|
||||||
default y
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
#
|
|
||||||
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Compiler flags
|
|
||||||
platform-cppflags-y =
|
|
||||||
platform-cflags-y =
|
|
||||||
platform-asflags-y =
|
|
||||||
platform-ldflags-y =
|
|
||||||
|
|
||||||
# Objects to build
|
|
||||||
platform-objs-y += platform.o
|
|
||||||
|
|
||||||
PLATFORM_RISCV_XLEN = 64
|
|
||||||
|
|
||||||
# Blobs to build
|
|
||||||
FW_JUMP=n
|
|
||||||
|
|
||||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
|
||||||
# This needs to be 4MB aligned for 32-bit support
|
|
||||||
FW_JUMP_ADDR=0x80400000
|
|
||||||
else
|
|
||||||
# This needs to be 2MB aligned for 64-bit support
|
|
||||||
FW_JUMP_ADDR=0x80200000
|
|
||||||
endif
|
|
||||||
FW_JUMP_FDT_ADDR=0x82200000
|
|
||||||
|
|
||||||
# Firmware with payload configuration.
|
|
||||||
FW_PAYLOAD=y
|
|
||||||
|
|
||||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
|
||||||
# This needs to be 4MB aligned for 32-bit support
|
|
||||||
FW_PAYLOAD_OFFSET=0x400000
|
|
||||||
else
|
|
||||||
# This needs to be 2MB aligned for 64-bit support
|
|
||||||
FW_PAYLOAD_OFFSET=0x200000
|
|
||||||
endif
|
|
||||||
FW_PAYLOAD_FDT_ADDR=0x82200000
|
|
||||||
FW_PAYLOAD_ALIGN=0x1000
|
|
||||||
@@ -36,6 +36,21 @@ config PLATFORM_ANDES_AE350
|
|||||||
select ANDES_PMA
|
select ANDES_PMA
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config PLATFORM_ANDES_QILAI
|
||||||
|
bool "Andes QiLai support"
|
||||||
|
select ANDES_PMU
|
||||||
|
select ANDES_PMA
|
||||||
|
select ANDES_SBI
|
||||||
|
default n
|
||||||
|
|
||||||
|
config PLATFORM_OPENHWGROUP_OPENPITON
|
||||||
|
bool "OpenHWGroup Openpiton support"
|
||||||
|
default n
|
||||||
|
|
||||||
|
config PLATFORM_OPENHWGROUP_ARIANE
|
||||||
|
bool "OpenHWGroup Ariane support"
|
||||||
|
default n
|
||||||
|
|
||||||
config PLATFORM_RENESAS_RZFIVE
|
config PLATFORM_RENESAS_RZFIVE
|
||||||
bool "Renesas RZ/Five support"
|
bool "Renesas RZ/Five support"
|
||||||
select ANDES_PMA
|
select ANDES_PMA
|
||||||
@@ -72,6 +87,11 @@ config PLATFORM_MIPS_P8700
|
|||||||
bool "MIPS P8700 support"
|
bool "MIPS P8700 support"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config PLATFORM_SPACEMIT_K1
|
||||||
|
bool "Spacemit K1 support"
|
||||||
|
select FDT_HSM_SPACEMIT
|
||||||
|
default n
|
||||||
|
|
||||||
source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
|
source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
|
||||||
source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig"
|
source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig"
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ static int ae350_hart_start(u32 hartid, ulong saddr)
|
|||||||
* 2) the target hart is non-sleepable 25-series hart0
|
* 2) the target hart is non-sleepable 25-series hart0
|
||||||
*/
|
*/
|
||||||
if (!sbi_init_count(hartindex) || (is_andes(25) && hartid == 0))
|
if (!sbi_init_count(hartindex) || (is_andes(25) && hartid == 0))
|
||||||
return sbi_ipi_raw_send(hartindex);
|
return sbi_ipi_raw_send(hartindex, false);
|
||||||
|
|
||||||
/* Write wakeup command to the sleep hart */
|
/* Write wakeup command to the sleep hart */
|
||||||
smu_set_command(&smu, WAKEUP_CMD, hartid);
|
smu_set_command(&smu, WAKEUP_CMD, hartid);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 Renesas Electronics Corp.
|
* Copyright (C) 2023 Renesas Electronics Corp.
|
||||||
* Copyright (c) 2024 Andes Technology Corporation
|
* Copyright (c) 2024 Andes Technology Corporation
|
||||||
@@ -17,78 +17,6 @@
|
|||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi_utils/fdt/fdt_helper.h>
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
|
||||||
static unsigned long andes_pma_read_num(unsigned int csr_num)
|
|
||||||
{
|
|
||||||
#define switchcase_csr_read(__csr_num, __val) \
|
|
||||||
case __csr_num: \
|
|
||||||
__val = csr_read(__csr_num); \
|
|
||||||
break;
|
|
||||||
#define switchcase_csr_read_2(__csr_num, __val) \
|
|
||||||
switchcase_csr_read(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_read(__csr_num + 1, __val)
|
|
||||||
#define switchcase_csr_read_4(__csr_num, __val) \
|
|
||||||
switchcase_csr_read_2(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_read_2(__csr_num + 2, __val)
|
|
||||||
#define switchcase_csr_read_8(__csr_num, __val) \
|
|
||||||
switchcase_csr_read_4(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_read_4(__csr_num + 4, __val)
|
|
||||||
#define switchcase_csr_read_16(__csr_num, __val) \
|
|
||||||
switchcase_csr_read_8(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_read_8(__csr_num + 8, __val)
|
|
||||||
|
|
||||||
unsigned long ret = 0;
|
|
||||||
|
|
||||||
switch (csr_num) {
|
|
||||||
switchcase_csr_read_4(CSR_PMACFG0, ret)
|
|
||||||
switchcase_csr_read_16(CSR_PMAADDR0, ret)
|
|
||||||
default:
|
|
||||||
sbi_panic("%s: Unknown Andes PMA CSR %#x", __func__, csr_num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
#undef switchcase_csr_read_16
|
|
||||||
#undef switchcase_csr_read_8
|
|
||||||
#undef switchcase_csr_read_4
|
|
||||||
#undef switchcase_csr_read_2
|
|
||||||
#undef switchcase_csr_read
|
|
||||||
}
|
|
||||||
|
|
||||||
static void andes_pma_write_num(unsigned int csr_num, unsigned long val)
|
|
||||||
{
|
|
||||||
#define switchcase_csr_write(__csr_num, __val) \
|
|
||||||
case __csr_num: \
|
|
||||||
csr_write(__csr_num, __val); \
|
|
||||||
break;
|
|
||||||
#define switchcase_csr_write_2(__csr_num, __val) \
|
|
||||||
switchcase_csr_write(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_write(__csr_num + 1, __val)
|
|
||||||
#define switchcase_csr_write_4(__csr_num, __val) \
|
|
||||||
switchcase_csr_write_2(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_write_2(__csr_num + 2, __val)
|
|
||||||
#define switchcase_csr_write_8(__csr_num, __val) \
|
|
||||||
switchcase_csr_write_4(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_write_4(__csr_num + 4, __val)
|
|
||||||
#define switchcase_csr_write_16(__csr_num, __val) \
|
|
||||||
switchcase_csr_write_8(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_write_8(__csr_num + 8, __val)
|
|
||||||
|
|
||||||
switch (csr_num) {
|
|
||||||
switchcase_csr_write_4(CSR_PMACFG0, val)
|
|
||||||
switchcase_csr_write_16(CSR_PMAADDR0, val)
|
|
||||||
default:
|
|
||||||
sbi_panic("%s: Unknown Andes PMA CSR %#x", __func__, csr_num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef switchcase_csr_write_16
|
|
||||||
#undef switchcase_csr_write_8
|
|
||||||
#undef switchcase_csr_write_4
|
|
||||||
#undef switchcase_csr_write_2
|
|
||||||
#undef switchcase_csr_write
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool not_napot(unsigned long addr, unsigned long size)
|
static inline bool not_napot(unsigned long addr, unsigned long size)
|
||||||
{
|
{
|
||||||
return ((size & (size - 1)) || (addr & (size - 1)));
|
return ((size & (size - 1)) || (addr & (size - 1)));
|
||||||
@@ -108,11 +36,11 @@ static char get_pmaxcfg(int entry_id)
|
|||||||
|
|
||||||
#if __riscv_xlen == 64
|
#if __riscv_xlen == 64
|
||||||
pmacfg_addr = CSR_PMACFG0 + ((entry_id / 8) ? 2 : 0);
|
pmacfg_addr = CSR_PMACFG0 + ((entry_id / 8) ? 2 : 0);
|
||||||
pmacfg_val = andes_pma_read_num(pmacfg_addr);
|
pmacfg_val = csr_read_num(pmacfg_addr);
|
||||||
pmaxcfg = (char *)&pmacfg_val + (entry_id % 8);
|
pmaxcfg = (char *)&pmacfg_val + (entry_id % 8);
|
||||||
#elif __riscv_xlen == 32
|
#elif __riscv_xlen == 32
|
||||||
pmacfg_addr = CSR_PMACFG0 + (entry_id / 4);
|
pmacfg_addr = CSR_PMACFG0 + (entry_id / 4);
|
||||||
pmacfg_val = andes_pma_read_num(pmacfg_addr);
|
pmacfg_val = csr_read_num(pmacfg_addr);
|
||||||
pmaxcfg = (char *)&pmacfg_val + (entry_id % 4);
|
pmaxcfg = (char *)&pmacfg_val + (entry_id % 4);
|
||||||
#else
|
#else
|
||||||
#error "Unexpected __riscv_xlen"
|
#error "Unexpected __riscv_xlen"
|
||||||
@@ -128,17 +56,17 @@ static void set_pmaxcfg(int entry_id, char flags)
|
|||||||
|
|
||||||
#if __riscv_xlen == 64
|
#if __riscv_xlen == 64
|
||||||
pmacfg_addr = CSR_PMACFG0 + ((entry_id / 8) ? 2 : 0);
|
pmacfg_addr = CSR_PMACFG0 + ((entry_id / 8) ? 2 : 0);
|
||||||
pmacfg_val = andes_pma_read_num(pmacfg_addr);
|
pmacfg_val = csr_read_num(pmacfg_addr);
|
||||||
pmaxcfg = (char *)&pmacfg_val + (entry_id % 8);
|
pmaxcfg = (char *)&pmacfg_val + (entry_id % 8);
|
||||||
#elif __riscv_xlen == 32
|
#elif __riscv_xlen == 32
|
||||||
pmacfg_addr = CSR_PMACFG0 + (entry_id / 4);
|
pmacfg_addr = CSR_PMACFG0 + (entry_id / 4);
|
||||||
pmacfg_val = andes_pma_read_num(pmacfg_addr);
|
pmacfg_val = csr_read_num(pmacfg_addr);
|
||||||
pmaxcfg = (char *)&pmacfg_val + (entry_id % 4);
|
pmaxcfg = (char *)&pmacfg_val + (entry_id % 4);
|
||||||
#else
|
#else
|
||||||
#error "Unexpected __riscv_xlen"
|
#error "Unexpected __riscv_xlen"
|
||||||
#endif
|
#endif
|
||||||
*pmaxcfg = flags;
|
*pmaxcfg = flags;
|
||||||
andes_pma_write_num(pmacfg_addr, pmacfg_val);
|
csr_write_num(pmacfg_addr, pmacfg_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decode_pmaaddrx(int entry_id, unsigned long *start,
|
static void decode_pmaaddrx(int entry_id, unsigned long *start,
|
||||||
@@ -152,7 +80,7 @@ static void decode_pmaaddrx(int entry_id, unsigned long *start,
|
|||||||
* size = 2 ^ (k + 3)
|
* size = 2 ^ (k + 3)
|
||||||
* start = 4 * ($pmaaddr - (size / 8) + 1)
|
* start = 4 * ($pmaaddr - (size / 8) + 1)
|
||||||
*/
|
*/
|
||||||
pmaaddr = andes_pma_read_num(CSR_PMAADDR0 + entry_id);
|
pmaaddr = csr_read_num(CSR_PMAADDR0 + entry_id);
|
||||||
k = sbi_ffz(pmaaddr);
|
k = sbi_ffz(pmaaddr);
|
||||||
*size = 1 << (k + 3);
|
*size = 1 << (k + 3);
|
||||||
*start = (pmaaddr - (1 << k) + 1) << 2;
|
*start = (pmaaddr - (1 << k) + 1) << 2;
|
||||||
@@ -199,9 +127,9 @@ static unsigned long andes_pma_setup(const struct andes_pma_region *pma_region,
|
|||||||
|
|
||||||
pmaaddr = (addr >> 2) + (size >> 3) - 1;
|
pmaaddr = (addr >> 2) + (size >> 3) - 1;
|
||||||
|
|
||||||
andes_pma_write_num(CSR_PMAADDR0 + entry_id, pmaaddr);
|
csr_write_num(CSR_PMAADDR0 + entry_id, pmaaddr);
|
||||||
|
|
||||||
return andes_pma_read_num(CSR_PMAADDR0 + entry_id) == pmaaddr ?
|
return csr_read_num(CSR_PMAADDR0 + entry_id) == pmaaddr ?
|
||||||
pmaaddr : SBI_EINVAL;
|
pmaaddr : SBI_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +357,7 @@ int andes_sbi_free_pma(unsigned long pa)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
set_pmaxcfg(i, ANDES_PMACFG_ETYP_OFF);
|
set_pmaxcfg(i, ANDES_PMACFG_ETYP_OFF);
|
||||||
andes_pma_write_num(CSR_PMAADDR0 + i, 0);
|
csr_write_num(CSR_PMAADDR0 + i, 0);
|
||||||
|
|
||||||
return SBI_SUCCESS;
|
return SBI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350
|
carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350
|
||||||
platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o
|
platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o
|
||||||
|
|
||||||
|
carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_QILAI) += andes_qilai
|
||||||
|
platform-objs-$(CONFIG_PLATFORM_ANDES_QILAI) += andes/qilai.o
|
||||||
|
|
||||||
platform-objs-$(CONFIG_ANDES_PMA) += andes/andes_pma.o
|
platform-objs-$(CONFIG_ANDES_PMA) += andes/andes_pma.o
|
||||||
platform-objs-$(CONFIG_ANDES_SBI) += andes/andes_sbi.o
|
platform-objs-$(CONFIG_ANDES_SBI) += andes/andes_sbi.o
|
||||||
platform-objs-$(CONFIG_ANDES_PMU) += andes/andes_pmu.o
|
platform-objs-$(CONFIG_ANDES_PMU) += andes/andes_pmu.o
|
||||||
|
|||||||
66
platform/generic/andes/qilai.c
Normal file
66
platform/generic/andes/qilai.c
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 Andes Technology Corporation
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <andes/andes_pma.h>
|
||||||
|
#include <andes/andes_pmu.h>
|
||||||
|
#include <andes/andes_sbi.h>
|
||||||
|
#include <andes/qilai.h>
|
||||||
|
#include <platform_override.h>
|
||||||
|
#include <sbi/sbi_domain.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
|
||||||
|
static int andes_qilai_final_init(bool cold_boot)
|
||||||
|
{
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the memory attribute for 3 PCIE endpoint regions,
|
||||||
|
* and they are all non-idempotent and non-bufferable.
|
||||||
|
*/
|
||||||
|
rc = andes_sbi_set_pma((unsigned long)PCIE0_BASE, (unsigned long)PCIE0_SIZE,
|
||||||
|
ANDES_PMACFG_ETYP_NAPOT |
|
||||||
|
ANDES_PMACFG_MTYP_DEV_NOBUF);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = andes_sbi_set_pma((unsigned long)PCIE1_BASE, (unsigned long)PCIE1_SIZE,
|
||||||
|
ANDES_PMACFG_ETYP_NAPOT |
|
||||||
|
ANDES_PMACFG_MTYP_DEV_NOBUF);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = andes_sbi_set_pma((unsigned long)PCIE2_BASE, (unsigned long)PCIE2_SIZE,
|
||||||
|
ANDES_PMACFG_ETYP_NAPOT |
|
||||||
|
ANDES_PMACFG_MTYP_DEV_NOBUF);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return generic_final_init(cold_boot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int andes_qilai_platform_init(const void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
generic_platform_ops.final_init = andes_qilai_final_init;
|
||||||
|
generic_platform_ops.extensions_init = andes_pmu_extensions_init;
|
||||||
|
generic_platform_ops.pmu_init = andes_pmu_init;
|
||||||
|
generic_platform_ops.vendor_ext_provider =
|
||||||
|
andes_sbi_vendor_ext_provider;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match andes_qilai_match[] = {
|
||||||
|
{ .compatible = "andestech,qilai" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver andes_qilai = {
|
||||||
|
.match_table = andes_qilai_match,
|
||||||
|
.init = andes_qilai_platform_init,
|
||||||
|
};
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
CONFIG_PLATFORM_ALLWINNER_D1=y
|
CONFIG_PLATFORM_ALLWINNER_D1=y
|
||||||
CONFIG_PLATFORM_ANDES_AE350=y
|
CONFIG_PLATFORM_ANDES_AE350=y
|
||||||
|
CONFIG_PLATFORM_ANDES_QILAI=y
|
||||||
|
CONFIG_PLATFORM_OPENHWGROUP_ARIANE=y
|
||||||
|
CONFIG_PLATFORM_OPENHWGROUP_OPENPITON=y
|
||||||
CONFIG_PLATFORM_RENESAS_RZFIVE=y
|
CONFIG_PLATFORM_RENESAS_RZFIVE=y
|
||||||
CONFIG_PLATFORM_SIFIVE_FU540=y
|
CONFIG_PLATFORM_SIFIVE_FU540=y
|
||||||
CONFIG_PLATFORM_SIFIVE_FU740=y
|
CONFIG_PLATFORM_SIFIVE_FU740=y
|
||||||
@@ -7,6 +10,11 @@ CONFIG_PLATFORM_SOPHGO_SG2042=y
|
|||||||
CONFIG_PLATFORM_STARFIVE_JH7110=y
|
CONFIG_PLATFORM_STARFIVE_JH7110=y
|
||||||
CONFIG_PLATFORM_THEAD=y
|
CONFIG_PLATFORM_THEAD=y
|
||||||
CONFIG_PLATFORM_MIPS_P8700=y
|
CONFIG_PLATFORM_MIPS_P8700=y
|
||||||
|
CONFIG_PLATFORM_SPACEMIT_K1=y
|
||||||
|
CONFIG_FDT_CACHE=y
|
||||||
|
CONFIG_FDT_CACHE_SIFIVE_CCACHE=y
|
||||||
|
CONFIG_FDT_CACHE_SIFIVE_EC=y
|
||||||
|
CONFIG_FDT_CACHE_SIFIVE_PL2=y
|
||||||
CONFIG_FDT_CPPC=y
|
CONFIG_FDT_CPPC=y
|
||||||
CONFIG_FDT_CPPC_RPMI=y
|
CONFIG_FDT_CPPC_RPMI=y
|
||||||
CONFIG_FDT_GPIO=y
|
CONFIG_FDT_GPIO=y
|
||||||
@@ -15,6 +23,7 @@ CONFIG_FDT_GPIO_SIFIVE=y
|
|||||||
CONFIG_FDT_GPIO_STARFIVE=y
|
CONFIG_FDT_GPIO_STARFIVE=y
|
||||||
CONFIG_FDT_HSM=y
|
CONFIG_FDT_HSM=y
|
||||||
CONFIG_FDT_HSM_RPMI=y
|
CONFIG_FDT_HSM_RPMI=y
|
||||||
|
CONFIG_FDT_HSM_SIFIVE_TMC0=y
|
||||||
CONFIG_FDT_I2C=y
|
CONFIG_FDT_I2C=y
|
||||||
CONFIG_FDT_I2C_SIFIVE=y
|
CONFIG_FDT_I2C_SIFIVE=y
|
||||||
CONFIG_FDT_I2C_DW=y
|
CONFIG_FDT_I2C_DW=y
|
||||||
@@ -35,8 +44,8 @@ CONFIG_FDT_RESET_ATCWDT200=y
|
|||||||
CONFIG_FDT_RESET_GPIO=y
|
CONFIG_FDT_RESET_GPIO=y
|
||||||
CONFIG_FDT_RESET_HTIF=y
|
CONFIG_FDT_RESET_HTIF=y
|
||||||
CONFIG_FDT_RESET_RPMI=y
|
CONFIG_FDT_RESET_RPMI=y
|
||||||
CONFIG_FDT_RESET_SUNXI_WDT=y
|
|
||||||
CONFIG_FDT_RESET_SG2042_HWMON_MCU=y
|
CONFIG_FDT_RESET_SG2042_HWMON_MCU=y
|
||||||
|
CONFIG_FDT_RESET_SUNXI_WDT=y
|
||||||
CONFIG_FDT_RESET_SYSCON=y
|
CONFIG_FDT_RESET_SYSCON=y
|
||||||
CONFIG_FDT_SERIAL=y
|
CONFIG_FDT_SERIAL=y
|
||||||
CONFIG_FDT_SERIAL_CADENCE=y
|
CONFIG_FDT_SERIAL_CADENCE=y
|
||||||
@@ -51,10 +60,14 @@ CONFIG_FDT_SERIAL_XILINX_UARTLITE=y
|
|||||||
CONFIG_SERIAL_SEMIHOSTING=y
|
CONFIG_SERIAL_SEMIHOSTING=y
|
||||||
CONFIG_FDT_SUSPEND=y
|
CONFIG_FDT_SUSPEND=y
|
||||||
CONFIG_FDT_SUSPEND_RPMI=y
|
CONFIG_FDT_SUSPEND_RPMI=y
|
||||||
|
CONFIG_FDT_SUSPEND_SIFIVE_SMC0=y
|
||||||
CONFIG_FDT_TIMER=y
|
CONFIG_FDT_TIMER=y
|
||||||
CONFIG_FDT_TIMER_MTIMER=y
|
CONFIG_FDT_TIMER_MTIMER=y
|
||||||
CONFIG_FDT_TIMER_PLMT=y
|
CONFIG_FDT_TIMER_PLMT=y
|
||||||
CONFIG_FDT_MPXY=y
|
CONFIG_FDT_MPXY=y
|
||||||
CONFIG_FDT_MPXY_RPMI_MBOX=y
|
CONFIG_FDT_MPXY_RPMI_MBOX=y
|
||||||
CONFIG_FDT_MPXY_RPMI_CLOCK=y
|
CONFIG_FDT_MPXY_RPMI_CLOCK=y
|
||||||
|
CONFIG_FDT_MPXY_RPMI_VOLTAGE=y
|
||||||
|
CONFIG_FDT_MPXY_RPMI_DEVICE_POWER=y
|
||||||
|
CONFIG_FDT_MPXY_RPMI_PERFORMANCE=y
|
||||||
CONFIG_FDT_MPXY_RPMI_SYSMSI=y
|
CONFIG_FDT_MPXY_RPMI_SYSMSI=y
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Andes Technology Corporation
|
* Copyright (C) 2024 Andes Technology Corporation
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2023 Renesas Electronics Corp.
|
* Copyright (C) 2023 Renesas Electronics Corp.
|
||||||
*/
|
*/
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#define ANDES_PMACFG_ETYP_NAPOT (3 << ANDES_PMACFG_ETYP_OFFSET)
|
#define ANDES_PMACFG_ETYP_NAPOT (3 << ANDES_PMACFG_ETYP_OFFSET)
|
||||||
|
|
||||||
#define ANDES_PMACFG_MTYP_OFFSET 2
|
#define ANDES_PMACFG_MTYP_OFFSET 2
|
||||||
|
#define ANDES_PMACFG_MTYP_DEV_NOBUF (0 << ANDES_PMACFG_MTYP_OFFSET)
|
||||||
/* Memory, Non-cacheable, Bufferable */
|
/* Memory, Non-cacheable, Bufferable */
|
||||||
#define ANDES_PMACFG_MTYP_MEM_NON_CACHE_BUF (3 << ANDES_PMACFG_MTYP_OFFSET)
|
#define ANDES_PMACFG_MTYP_MEM_NON_CACHE_BUF (3 << ANDES_PMACFG_MTYP_OFFSET)
|
||||||
|
|
||||||
|
|||||||
18
platform/generic/include/andes/qilai.h
Normal file
18
platform/generic/include/andes/qilai.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 Andes Technology Corporation
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __QILAI_H__
|
||||||
|
#define __QILAI_H__
|
||||||
|
|
||||||
|
#define PCIE0_BASE 0x1000000000ULL
|
||||||
|
#define PCIE0_SIZE 0x800000000ULL
|
||||||
|
#define PCIE1_BASE 0x1800000000ULL
|
||||||
|
#define PCIE1_SIZE 0x800000000ULL
|
||||||
|
#define PCIE2_BASE 0x2000000000ULL
|
||||||
|
#define PCIE2_SIZE 0x2000000000ULL
|
||||||
|
|
||||||
|
#endif
|
||||||
98
platform/generic/include/spacemit/k1.h
Normal file
98
platform/generic/include/spacemit/k1.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#ifndef __RISCV_SPACEMIT_K1_H__
|
||||||
|
#define __RISCV_SPACEMIT_K1_H__
|
||||||
|
|
||||||
|
#define CSR_MSETUP 0x7c0
|
||||||
|
#define CSR_MHCR 0x7c1
|
||||||
|
#define CSR_MRAOP 0x7c2
|
||||||
|
#define CSR_MHINT 0x7c5
|
||||||
|
#define CSR_ML2SETUP 0x7f0
|
||||||
|
|
||||||
|
/* decache enable */
|
||||||
|
#define MSETUP_DE BIT(0)
|
||||||
|
/* icache enable */
|
||||||
|
#define MSETUP_IE BIT(1)
|
||||||
|
/* branch prediction enable */
|
||||||
|
#define MSETUP_BPE BIT(4)
|
||||||
|
/* prefetch functionality enable */
|
||||||
|
#define MSETUP_PFE BIT(5)
|
||||||
|
/* misaligned memory access enable */
|
||||||
|
#define MSETUP_MME BIT(6)
|
||||||
|
/* ECC enable */
|
||||||
|
#define MSETUP_ECCE BIT(16)
|
||||||
|
|
||||||
|
/* icache invalidation */
|
||||||
|
#define MRAOP_ICACHE_INVALID GENMASK(1, 0)
|
||||||
|
|
||||||
|
#define PMU_AP_BASE 0xd4282800
|
||||||
|
|
||||||
|
#define PMU_AP_CORE0_WAKEUP_OFFSET (PMU_AP_BASE + 0x12c)
|
||||||
|
#define PMU_AP_CORE4_WAKEUP_OFFSET (PMU_AP_BASE + 0x324)
|
||||||
|
#define PMU_AP_CLUSTER0_WAKEUP_OFFSET(index) (PMU_AP_CORE0_WAKEUP_OFFSET + index * 4)
|
||||||
|
#define PMU_AP_CLUSTER1_WAKEUP_OFFSET(index) (PMU_AP_CORE4_WAKEUP_OFFSET + index * 4)
|
||||||
|
|
||||||
|
#define PMU_AP_CORE0_IDLE_CFG_OFFSET (PMU_AP_BASE + 0x124)
|
||||||
|
#define PMU_AP_CORE4_IDLE_CFG_OFFSET (PMU_AP_BASE + 0x304)
|
||||||
|
#define PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(index) (PMU_AP_CORE0_IDLE_CFG_OFFSET + index * 4)
|
||||||
|
#define PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(index) (PMU_AP_CORE4_IDLE_CFG_OFFSET + index * 4)
|
||||||
|
|
||||||
|
#define PMU_AP_CORE0_WAKEUP PMU_AP_CLUSTER0_WAKEUP_OFFSET(0)
|
||||||
|
#define PMU_AP_CORE1_WAKEUP PMU_AP_CLUSTER0_WAKEUP_OFFSET(1)
|
||||||
|
#define PMU_AP_CORE2_WAKEUP PMU_AP_CLUSTER0_WAKEUP_OFFSET(2)
|
||||||
|
#define PMU_AP_CORE3_WAKEUP PMU_AP_CLUSTER0_WAKEUP_OFFSET(3)
|
||||||
|
#define PMU_AP_CORE4_WAKEUP PMU_AP_CLUSTER1_WAKEUP_OFFSET(0)
|
||||||
|
#define PMU_AP_CORE5_WAKEUP PMU_AP_CLUSTER1_WAKEUP_OFFSET(1)
|
||||||
|
#define PMU_AP_CORE6_WAKEUP PMU_AP_CLUSTER1_WAKEUP_OFFSET(2)
|
||||||
|
#define PMU_AP_CORE7_WAKEUP PMU_AP_CLUSTER1_WAKEUP_OFFSET(3)
|
||||||
|
|
||||||
|
#define PMU_AP_CORE0_IDLE_CFG PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(0)
|
||||||
|
#define PMU_AP_CORE1_IDLE_CFG PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(1)
|
||||||
|
#define PMU_AP_CORE2_IDLE_CFG PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(2)
|
||||||
|
#define PMU_AP_CORE3_IDLE_CFG PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(3)
|
||||||
|
#define PMU_AP_CORE4_IDLE_CFG PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(0)
|
||||||
|
#define PMU_AP_CORE5_IDLE_CFG PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(1)
|
||||||
|
#define PMU_AP_CORE6_IDLE_CFG PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(2)
|
||||||
|
#define PMU_AP_CORE7_IDLE_CFG PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(3)
|
||||||
|
|
||||||
|
/* power down */
|
||||||
|
#define PMU_AP_IDLE_PWRDWN BIT(0)
|
||||||
|
/* sram power down */
|
||||||
|
#define PMU_AP_IDLE_SRAM_PWRDWN BIT(1)
|
||||||
|
/* enable wake up the memory controller */
|
||||||
|
#define PMU_AP_IDLE_WAKE_MCE BIT(3)
|
||||||
|
/* disable memory controller software req */
|
||||||
|
#define PMU_AP_IDLE_MC_SW_REQ BIT(4)
|
||||||
|
|
||||||
|
#define PMU_AP_IDLE_PWRDOWN_MASK (PMU_AP_IDLE_PWRDWN | PMU_AP_IDLE_SRAM_PWRDWN | \
|
||||||
|
PMU_AP_IDLE_WAKE_MCE | PMU_AP_IDLE_MC_SW_REQ)
|
||||||
|
/* cci */
|
||||||
|
#define C0_RVBADDR_LO_ADDR 0xd4282db0
|
||||||
|
#define C0_RVBADDR_HI_ADDR 0xd4282db4
|
||||||
|
#define C1_RVBADDR_LO_ADDR 0xd4282eb0
|
||||||
|
#define C1_RVBADDR_HI_ADDR 0xd4282c04
|
||||||
|
|
||||||
|
#define CCI_550_PLATFORM_CCI_ADDR 0xd8500000
|
||||||
|
|
||||||
|
/* relative to cci base */
|
||||||
|
#define CCI_550_STATUS 0x000c
|
||||||
|
/* status register bits */
|
||||||
|
#define CCI_550_STATUS_CHANGE_PENDING BIT(0)
|
||||||
|
|
||||||
|
/* slave interface registers */
|
||||||
|
#define CCI_550_SLAVE_IFACE0_OFFSET 0x1000
|
||||||
|
#define CCI_550_SLAVE_IFACE_OFFSET(idx) (CCI_550_SLAVE_IFACE0_OFFSET + ((0x1000) * (idx)))
|
||||||
|
|
||||||
|
/* relative to slave interface base */
|
||||||
|
#define CCI_550_SNOOP_CTRL 0x0000
|
||||||
|
/* snoop control register bits */
|
||||||
|
#define CCI_550_SNOOP_CTRL_ENABLE_SNOOPS BIT(0)
|
||||||
|
#define CCI_550_SNOOP_CTRL_ENABLE_DVMS BIT(1)
|
||||||
|
|
||||||
|
/* clusters and CPU mapping */
|
||||||
|
#define PLATFORM_MAX_CPUS 8
|
||||||
|
#define PLATFORM_MAX_CPUS_PER_CLUSTER 4
|
||||||
|
#define CPU_TO_CLUSTER(cpu) ((cpu) / PLATFORM_MAX_CPUS_PER_CLUSTER)
|
||||||
|
|
||||||
|
#define PLAT_CCI_CLUSTER0_IFACE_IX 0
|
||||||
|
#define PLAT_CCI_CLUSTER1_IFACE_IX 1
|
||||||
|
|
||||||
|
#endif
|
||||||
12
platform/generic/mips/mips_warm_boot.S
Normal file
12
platform/generic/mips/mips_warm_boot.S
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 MIPS
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
.text
|
||||||
|
.align 12
|
||||||
|
.globl mips_warm_boot
|
||||||
|
mips_warm_boot:
|
||||||
|
j _start_warm
|
||||||
|
.align 2
|
||||||
@@ -4,5 +4,5 @@
|
|||||||
|
|
||||||
ifeq ($(PLATFORM_RISCV_XLEN), 64)
|
ifeq ($(PLATFORM_RISCV_XLEN), 64)
|
||||||
carray-platform_override_modules-$(CONFIG_PLATFORM_MIPS_P8700) += mips_p8700
|
carray-platform_override_modules-$(CONFIG_PLATFORM_MIPS_P8700) += mips_p8700
|
||||||
platform-objs-$(CONFIG_PLATFORM_MIPS_P8700) += mips/p8700.o
|
platform-objs-$(CONFIG_PLATFORM_MIPS_P8700) += mips/p8700.o mips/mips_warm_boot.o
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -16,77 +16,7 @@
|
|||||||
#include <mips/p8700.h>
|
#include <mips/p8700.h>
|
||||||
#include <mips/mips-cm.h>
|
#include <mips/mips-cm.h>
|
||||||
|
|
||||||
static unsigned long mips_csr_read_num(int csr_num)
|
extern void mips_warm_boot(void);
|
||||||
{
|
|
||||||
#define switchcase_csr_read(__csr_num, __val) \
|
|
||||||
case __csr_num: \
|
|
||||||
__val = csr_read(__csr_num); \
|
|
||||||
break;
|
|
||||||
#define switchcase_csr_read_2(__csr_num, __val) \
|
|
||||||
switchcase_csr_read(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_read(__csr_num + 1, __val)
|
|
||||||
#define switchcase_csr_read_4(__csr_num, __val) \
|
|
||||||
switchcase_csr_read_2(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_read_2(__csr_num + 2, __val)
|
|
||||||
#define switchcase_csr_read_8(__csr_num, __val) \
|
|
||||||
switchcase_csr_read_4(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_read_4(__csr_num + 4, __val)
|
|
||||||
#define switchcase_csr_read_16(__csr_num, __val) \
|
|
||||||
switchcase_csr_read_8(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_read_8(__csr_num + 8, __val)
|
|
||||||
|
|
||||||
unsigned long ret = 0;
|
|
||||||
|
|
||||||
switch(csr_num) {
|
|
||||||
switchcase_csr_read_16(CSR_MIPSPMACFG0, ret)
|
|
||||||
|
|
||||||
default:
|
|
||||||
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
#undef switchcase_csr_read_16
|
|
||||||
#undef switchcase_csr_read_8
|
|
||||||
#undef switchcase_csr_read_4
|
|
||||||
#undef switchcase_csr_read_2
|
|
||||||
#undef switchcase_csr_read
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mips_csr_write_num(int csr_num, unsigned long val)
|
|
||||||
{
|
|
||||||
#define switchcase_csr_write(__csr_num, __val) \
|
|
||||||
case __csr_num: \
|
|
||||||
csr_write(__csr_num, __val); \
|
|
||||||
break;
|
|
||||||
#define switchcase_csr_write_2(__csr_num, __val) \
|
|
||||||
switchcase_csr_write(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_write(__csr_num + 1, __val)
|
|
||||||
#define switchcase_csr_write_4(__csr_num, __val) \
|
|
||||||
switchcase_csr_write_2(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_write_2(__csr_num + 2, __val)
|
|
||||||
#define switchcase_csr_write_8(__csr_num, __val) \
|
|
||||||
switchcase_csr_write_4(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_write_4(__csr_num + 4, __val)
|
|
||||||
#define switchcase_csr_write_16(__csr_num, __val) \
|
|
||||||
switchcase_csr_write_8(__csr_num + 0, __val) \
|
|
||||||
switchcase_csr_write_8(__csr_num + 8, __val)
|
|
||||||
|
|
||||||
switch(csr_num) {
|
|
||||||
switchcase_csr_write_16(CSR_MIPSPMACFG0, val)
|
|
||||||
|
|
||||||
default:
|
|
||||||
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef switchcase_csr_write_16
|
|
||||||
#undef switchcase_csr_write_8
|
|
||||||
#undef switchcase_csr_write_4
|
|
||||||
#undef switchcase_csr_write_2
|
|
||||||
#undef switchcase_csr_write
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mips_p8700_pmp_set(unsigned int n, unsigned long flags,
|
static void mips_p8700_pmp_set(unsigned int n, unsigned long flags,
|
||||||
unsigned long prot, unsigned long addr,
|
unsigned long prot, unsigned long addr,
|
||||||
@@ -101,11 +31,11 @@ static void mips_p8700_pmp_set(unsigned int n, unsigned long flags,
|
|||||||
cfgmask = ~(0xffUL << pmacfg_shift);
|
cfgmask = ~(0xffUL << pmacfg_shift);
|
||||||
|
|
||||||
/* Read pmacfg to change cacheability */
|
/* Read pmacfg to change cacheability */
|
||||||
pmacfg = (mips_csr_read_num(pmacfg_csr) & cfgmask);
|
pmacfg = (csr_read_num(pmacfg_csr) & cfgmask);
|
||||||
cca = (flags & SBI_DOMAIN_MEMREGION_MMIO) ? CCA_CACHE_DISABLE :
|
cca = (flags & SBI_DOMAIN_MEMREGION_MMIO) ? CCA_CACHE_DISABLE :
|
||||||
CCA_CACHE_ENABLE | PMA_SPECULATION;
|
CCA_CACHE_ENABLE | PMA_SPECULATION;
|
||||||
pmacfg |= ((cca << pmacfg_shift) & ~cfgmask);
|
pmacfg |= ((cca << pmacfg_shift) & ~cfgmask);
|
||||||
mips_csr_write_num(pmacfg_csr, pmacfg);
|
csr_write_num(pmacfg_csr, pmacfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CLUSTERS_IN_PLATFORM > 1
|
#if CLUSTERS_IN_PLATFORM > 1
|
||||||
@@ -150,6 +80,9 @@ static int mips_hart_start(u32 hartid, ulong saddr)
|
|||||||
if (hartid == 0)
|
if (hartid == 0)
|
||||||
return SBI_ENOTSUPP;
|
return SBI_ENOTSUPP;
|
||||||
|
|
||||||
|
/* Change reset base to mips_warm_boot */
|
||||||
|
write_gcr_co_reset_base(hartid, (unsigned long)mips_warm_boot, local_p);
|
||||||
|
|
||||||
if (cpu_hart(hartid) == 0) {
|
if (cpu_hart(hartid) == 0) {
|
||||||
/* Ensure its coherency is disabled */
|
/* Ensure its coherency is disabled */
|
||||||
write_gcr_co_coherence(hartid, 0, local_p);
|
write_gcr_co_coherence(hartid, 0, local_p);
|
||||||
|
|||||||
@@ -4,26 +4,13 @@
|
|||||||
* Panagiotis Peristerakis <perister@ics.forth.gr>
|
* Panagiotis Peristerakis <perister@ics.forth.gr>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sbi/riscv_asm.h>
|
#include <platform_override.h>
|
||||||
#include <sbi/riscv_encoding.h>
|
|
||||||
#include <sbi/riscv_io.h>
|
|
||||||
#include <sbi/sbi_const.h>
|
|
||||||
#include <sbi/sbi_hart.h>
|
|
||||||
#include <sbi/sbi_platform.h>
|
|
||||||
#include <sbi_utils/fdt/fdt_helper.h>
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||||
#include <sbi_utils/ipi/aclint_mswi.h>
|
#include <sbi_utils/ipi/aclint_mswi.h>
|
||||||
#include <sbi_utils/irqchip/plic.h>
|
#include <sbi_utils/irqchip/plic.h>
|
||||||
#include <sbi_utils/serial/uart8250.h>
|
|
||||||
#include <sbi_utils/timer/aclint_mtimer.h>
|
#include <sbi_utils/timer/aclint_mtimer.h>
|
||||||
|
|
||||||
#define ARIANE_UART_ADDR 0x10000000
|
|
||||||
#define ARIANE_UART_FREQ 50000000
|
|
||||||
#define ARIANE_UART_BAUDRATE 115200
|
|
||||||
#define ARIANE_UART_REG_SHIFT 2
|
|
||||||
#define ARIANE_UART_REG_WIDTH 4
|
|
||||||
#define ARIANE_UART_REG_OFFSET 0
|
|
||||||
#define ARIANE_UART_CAPS 0
|
|
||||||
#define ARIANE_PLIC_ADDR 0xc000000
|
#define ARIANE_PLIC_ADDR 0xc000000
|
||||||
#define ARIANE_PLIC_SIZE (0x200000 + \
|
#define ARIANE_PLIC_SIZE (0x200000 + \
|
||||||
(ARIANE_HART_COUNT * 0x1000))
|
(ARIANE_HART_COUNT * 0x1000))
|
||||||
@@ -71,16 +58,39 @@ static struct aclint_mtimer_data mtimer = {
|
|||||||
*/
|
*/
|
||||||
static int ariane_early_init(bool cold_boot)
|
static int ariane_early_init(bool cold_boot)
|
||||||
{
|
{
|
||||||
|
const void *fdt;
|
||||||
|
struct plic_data plic_data = plic;
|
||||||
|
unsigned long aclint_freq;
|
||||||
|
uint64_t clint_addr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (!cold_boot)
|
if (!cold_boot)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return uart8250_init(ARIANE_UART_ADDR,
|
rc = generic_early_init(cold_boot);
|
||||||
ARIANE_UART_FREQ,
|
if (rc)
|
||||||
ARIANE_UART_BAUDRATE,
|
return rc;
|
||||||
ARIANE_UART_REG_SHIFT,
|
|
||||||
ARIANE_UART_REG_WIDTH,
|
fdt = fdt_get_address();
|
||||||
ARIANE_UART_REG_OFFSET,
|
|
||||||
ARIANE_UART_CAPS);
|
rc = fdt_parse_timebase_frequency(fdt, &aclint_freq);
|
||||||
|
if (!rc)
|
||||||
|
mtimer.mtime_freq = aclint_freq;
|
||||||
|
|
||||||
|
rc = fdt_parse_compat_addr(fdt, &clint_addr, "riscv,clint0");
|
||||||
|
if (!rc) {
|
||||||
|
mswi.addr = clint_addr;
|
||||||
|
mtimer.mtime_addr = clint_addr + CLINT_MTIMER_OFFSET +
|
||||||
|
ACLINT_DEFAULT_MTIME_OFFSET;
|
||||||
|
mtimer.mtimecmp_addr = clint_addr + CLINT_MTIMER_OFFSET +
|
||||||
|
ACLINT_DEFAULT_MTIMECMP_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fdt_parse_plic(fdt, &plic_data, "riscv,plic0");
|
||||||
|
if (!rc)
|
||||||
|
plic = plic_data;
|
||||||
|
|
||||||
|
return aclint_mswi_cold_init(&mswi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -107,14 +117,6 @@ static int ariane_irqchip_init(void)
|
|||||||
return plic_cold_irqchip_init(&plic);
|
return plic_cold_irqchip_init(&plic);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize IPI during cold boot.
|
|
||||||
*/
|
|
||||||
static int ariane_ipi_init(void)
|
|
||||||
{
|
|
||||||
return aclint_mswi_cold_init(&mswi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize ariane timer during cold boot.
|
* Initialize ariane timer during cold boot.
|
||||||
*/
|
*/
|
||||||
@@ -123,24 +125,22 @@ static int ariane_timer_init(void)
|
|||||||
return aclint_mtimer_cold_init(&mtimer, NULL);
|
return aclint_mtimer_cold_init(&mtimer, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int openhwgroup_ariane_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match)
|
||||||
* Platform descriptor.
|
{
|
||||||
*/
|
generic_platform_ops.early_init = ariane_early_init;
|
||||||
const struct sbi_platform_operations platform_ops = {
|
generic_platform_ops.timer_init = ariane_timer_init;
|
||||||
.early_init = ariane_early_init,
|
generic_platform_ops.irqchip_init = ariane_irqchip_init;
|
||||||
.final_init = ariane_final_init,
|
generic_platform_ops.final_init = ariane_final_init;
|
||||||
.irqchip_init = ariane_irqchip_init,
|
|
||||||
.ipi_init = ariane_ipi_init,
|
return 0;
|
||||||
.timer_init = ariane_timer_init,
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match openhwgroup_ariane_match[] = {
|
||||||
|
{ .compatible = "eth,ariane-bare-dev" },
|
||||||
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct sbi_platform platform = {
|
const struct fdt_driver openhwgroup_ariane = {
|
||||||
.opensbi_version = OPENSBI_VERSION,
|
.match_table = openhwgroup_ariane_match,
|
||||||
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
.init = openhwgroup_ariane_platform_init,
|
||||||
.name = "ARIANE RISC-V",
|
|
||||||
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
|
||||||
.hart_count = ARIANE_HART_COUNT,
|
|
||||||
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
|
|
||||||
.heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(ARIANE_HART_COUNT),
|
|
||||||
.platform_ops_addr = (unsigned long)&platform_ops
|
|
||||||
};
|
};
|
||||||
11
platform/generic/openhwgroup/objects.mk
Normal file
11
platform/generic/openhwgroup/objects.mk
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
#
|
||||||
|
|
||||||
|
carray-platform_override_modules-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup_openpiton
|
||||||
|
platform-objs-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup/openpiton.o
|
||||||
|
|
||||||
|
carray-platform_override_modules-$(CONFIG_PLATFORM_OPENHWGROUP_ARIANE) += openhwgroup_ariane
|
||||||
|
platform-objs-$(CONFIG_PLATFORM_OPENHWGROUP_ARIANE) += openhwgroup/ariane.o
|
||||||
@@ -3,45 +3,27 @@
|
|||||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sbi/riscv_asm.h>
|
#include <platform_override.h>
|
||||||
#include <sbi/riscv_encoding.h>
|
|
||||||
#include <sbi/riscv_io.h>
|
|
||||||
#include <sbi/sbi_const.h>
|
|
||||||
#include <sbi/sbi_hart.h>
|
|
||||||
#include <sbi/sbi_platform.h>
|
|
||||||
#include <sbi_utils/fdt/fdt_helper.h>
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||||
#include <sbi_utils/ipi/aclint_mswi.h>
|
#include <sbi_utils/ipi/aclint_mswi.h>
|
||||||
#include <sbi_utils/irqchip/plic.h>
|
#include <sbi_utils/irqchip/plic.h>
|
||||||
#include <sbi_utils/serial/uart8250.h>
|
|
||||||
#include <sbi_utils/timer/aclint_mtimer.h>
|
#include <sbi_utils/timer/aclint_mtimer.h>
|
||||||
|
|
||||||
#define OPENPITON_DEFAULT_UART_ADDR 0xfff0c2c000
|
#define OPENPITON_DEFAULT_PLIC_ADDR 0xfff1100000ULL
|
||||||
#define OPENPITON_DEFAULT_UART_FREQ 60000000
|
|
||||||
#define OPENPITON_DEFAULT_UART_BAUDRATE 115200
|
|
||||||
#define OPENPITON_DEFAULT_UART_REG_SHIFT 0
|
|
||||||
#define OPENPITON_DEFAULT_UART_REG_WIDTH 1
|
|
||||||
#define OPENPITON_DEFAULT_UART_REG_OFFSET 0
|
|
||||||
#define OPENPITON_DEFAULT_UART_CAPS 0
|
|
||||||
#define OPENPITON_DEFAULT_PLIC_ADDR 0xfff1100000
|
|
||||||
#define OPENPITON_DEFAULT_PLIC_SIZE (0x200000 + \
|
#define OPENPITON_DEFAULT_PLIC_SIZE (0x200000 + \
|
||||||
(OPENPITON_DEFAULT_HART_COUNT * 0x1000))
|
(OPENPITON_DEFAULT_HART_COUNT * 0x1000))
|
||||||
#define OPENPITON_DEFAULT_PLIC_NUM_SOURCES 2
|
#define OPENPITON_DEFAULT_PLIC_NUM_SOURCES 2
|
||||||
#define OPENPITON_DEFAULT_HART_COUNT 3
|
#define OPENPITON_DEFAULT_HART_COUNT 3
|
||||||
#define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000
|
#define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000ULL
|
||||||
#define OPENPITON_DEFAULT_ACLINT_MTIMER_FREQ 1000000
|
#define OPENPITON_DEFAULT_ACLINT_MTIMER_FREQ 1000000
|
||||||
#define OPENPITON_DEFAULT_ACLINT_MSWI_ADDR \
|
#define OPENPITON_DEFAULT_ACLINT_MSWI_ADDR \
|
||||||
(OPENPITON_DEFAULT_CLINT_ADDR + CLINT_MSWI_OFFSET)
|
(OPENPITON_DEFAULT_CLINT_ADDR + CLINT_MSWI_OFFSET)
|
||||||
#define OPENPITON_DEFAULT_ACLINT_MTIMER_ADDR \
|
#define OPENPITON_DEFAULT_ACLINT_MTIMER_ADDR \
|
||||||
(OPENPITON_DEFAULT_CLINT_ADDR + CLINT_MTIMER_OFFSET)
|
(OPENPITON_DEFAULT_CLINT_ADDR + CLINT_MTIMER_OFFSET)
|
||||||
|
|
||||||
static struct platform_uart_data uart = {
|
|
||||||
OPENPITON_DEFAULT_UART_ADDR,
|
|
||||||
OPENPITON_DEFAULT_UART_FREQ,
|
|
||||||
OPENPITON_DEFAULT_UART_BAUDRATE,
|
|
||||||
};
|
|
||||||
static struct plic_data plic = {
|
static struct plic_data plic = {
|
||||||
.addr = OPENPITON_DEFAULT_PLIC_ADDR,
|
.addr = (unsigned long)OPENPITON_DEFAULT_PLIC_ADDR,
|
||||||
.size = OPENPITON_DEFAULT_PLIC_SIZE,
|
.size = OPENPITON_DEFAULT_PLIC_SIZE,
|
||||||
.num_src = OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
|
.num_src = OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
|
||||||
.flags = PLIC_FLAG_ARIANE_BUG,
|
.flags = PLIC_FLAG_ARIANE_BUG,
|
||||||
@@ -53,7 +35,7 @@ static struct plic_data plic = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct aclint_mswi_data mswi = {
|
static struct aclint_mswi_data mswi = {
|
||||||
.addr = OPENPITON_DEFAULT_ACLINT_MSWI_ADDR,
|
.addr = (unsigned long)OPENPITON_DEFAULT_ACLINT_MSWI_ADDR,
|
||||||
.size = ACLINT_MSWI_SIZE,
|
.size = ACLINT_MSWI_SIZE,
|
||||||
.first_hartid = 0,
|
.first_hartid = 0,
|
||||||
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
|
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
|
||||||
@@ -61,10 +43,10 @@ static struct aclint_mswi_data mswi = {
|
|||||||
|
|
||||||
static struct aclint_mtimer_data mtimer = {
|
static struct aclint_mtimer_data mtimer = {
|
||||||
.mtime_freq = OPENPITON_DEFAULT_ACLINT_MTIMER_FREQ,
|
.mtime_freq = OPENPITON_DEFAULT_ACLINT_MTIMER_FREQ,
|
||||||
.mtime_addr = OPENPITON_DEFAULT_ACLINT_MTIMER_ADDR +
|
.mtime_addr = (unsigned long)OPENPITON_DEFAULT_ACLINT_MTIMER_ADDR +
|
||||||
ACLINT_DEFAULT_MTIME_OFFSET,
|
ACLINT_DEFAULT_MTIME_OFFSET,
|
||||||
.mtime_size = ACLINT_DEFAULT_MTIME_SIZE,
|
.mtime_size = ACLINT_DEFAULT_MTIME_SIZE,
|
||||||
.mtimecmp_addr = OPENPITON_DEFAULT_ACLINT_MTIMER_ADDR +
|
.mtimecmp_addr = (unsigned long)OPENPITON_DEFAULT_ACLINT_MTIMER_ADDR +
|
||||||
ACLINT_DEFAULT_MTIMECMP_OFFSET,
|
ACLINT_DEFAULT_MTIMECMP_OFFSET,
|
||||||
.mtimecmp_size = ACLINT_DEFAULT_MTIMECMP_SIZE,
|
.mtimecmp_size = ACLINT_DEFAULT_MTIMECMP_SIZE,
|
||||||
.first_hartid = 0,
|
.first_hartid = 0,
|
||||||
@@ -78,7 +60,6 @@ static struct aclint_mtimer_data mtimer = {
|
|||||||
static int openpiton_early_init(bool cold_boot)
|
static int openpiton_early_init(bool cold_boot)
|
||||||
{
|
{
|
||||||
const void *fdt;
|
const void *fdt;
|
||||||
struct platform_uart_data uart_data = { 0 };
|
|
||||||
struct plic_data plic_data = plic;
|
struct plic_data plic_data = plic;
|
||||||
unsigned long aclint_freq;
|
unsigned long aclint_freq;
|
||||||
uint64_t clint_addr;
|
uint64_t clint_addr;
|
||||||
@@ -88,9 +69,9 @@ static int openpiton_early_init(bool cold_boot)
|
|||||||
return 0;
|
return 0;
|
||||||
fdt = fdt_get_address();
|
fdt = fdt_get_address();
|
||||||
|
|
||||||
rc = fdt_parse_uart8250(fdt, &uart_data, "ns16550");
|
rc = generic_early_init(cold_boot);
|
||||||
if (!rc)
|
if (rc)
|
||||||
uart = uart_data;
|
return rc;
|
||||||
|
|
||||||
rc = fdt_parse_plic(fdt, &plic_data, "riscv,plic0");
|
rc = fdt_parse_plic(fdt, &plic_data, "riscv,plic0");
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@@ -109,11 +90,10 @@ static int openpiton_early_init(bool cold_boot)
|
|||||||
ACLINT_DEFAULT_MTIMECMP_OFFSET;
|
ACLINT_DEFAULT_MTIMECMP_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
return uart8250_init(uart.addr, uart.freq, uart.baud,
|
if (rc)
|
||||||
OPENPITON_DEFAULT_UART_REG_SHIFT,
|
return rc;
|
||||||
OPENPITON_DEFAULT_UART_REG_WIDTH,
|
|
||||||
OPENPITON_DEFAULT_UART_REG_OFFSET,
|
return aclint_mswi_cold_init(&mswi);
|
||||||
OPENPITON_DEFAULT_UART_CAPS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -140,14 +120,6 @@ static int openpiton_irqchip_init(void)
|
|||||||
return plic_cold_irqchip_init(&plic);
|
return plic_cold_irqchip_init(&plic);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize IPI during cold boot.
|
|
||||||
*/
|
|
||||||
static int openpiton_ipi_init(void)
|
|
||||||
{
|
|
||||||
return aclint_mswi_cold_init(&mswi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize openpiton timer during cold boot.
|
* Initialize openpiton timer during cold boot.
|
||||||
*/
|
*/
|
||||||
@@ -156,25 +128,22 @@ static int openpiton_timer_init(void)
|
|||||||
return aclint_mtimer_cold_init(&mtimer, NULL);
|
return aclint_mtimer_cold_init(&mtimer, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int openhwgroup_openpiton_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match)
|
||||||
* Platform descriptor.
|
{
|
||||||
*/
|
generic_platform_ops.early_init = openpiton_early_init;
|
||||||
const struct sbi_platform_operations platform_ops = {
|
generic_platform_ops.timer_init = openpiton_timer_init;
|
||||||
.early_init = openpiton_early_init,
|
generic_platform_ops.irqchip_init = openpiton_irqchip_init;
|
||||||
.final_init = openpiton_final_init,
|
generic_platform_ops.final_init = openpiton_final_init;
|
||||||
.irqchip_init = openpiton_irqchip_init,
|
|
||||||
.ipi_init = openpiton_ipi_init,
|
return 0;
|
||||||
.timer_init = openpiton_timer_init,
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match openhwgroup_openpiton_match[] = {
|
||||||
|
{ .compatible = "openpiton,cva6platform" },
|
||||||
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct sbi_platform platform = {
|
const struct fdt_driver openhwgroup_openpiton = {
|
||||||
.opensbi_version = OPENSBI_VERSION,
|
.match_table = openhwgroup_openpiton_match,
|
||||||
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
.init = openhwgroup_openpiton_platform_init,
|
||||||
.name = "OPENPITON RISC-V",
|
|
||||||
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
|
||||||
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
|
|
||||||
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
|
|
||||||
.heap_size =
|
|
||||||
SBI_PLATFORM_DEFAULT_HEAP_SIZE(OPENPITON_DEFAULT_HART_COUNT),
|
|
||||||
.platform_ops_addr = (unsigned long)&platform_ops
|
|
||||||
};
|
};
|
||||||
@@ -17,12 +17,12 @@
|
|||||||
#include <sbi/sbi_string.h>
|
#include <sbi/sbi_string.h>
|
||||||
#include <sbi/sbi_system.h>
|
#include <sbi/sbi_system.h>
|
||||||
#include <sbi/sbi_tlb.h>
|
#include <sbi/sbi_tlb.h>
|
||||||
|
#include <sbi_utils/cache/fdt_cmo_helper.h>
|
||||||
#include <sbi_utils/fdt/fdt_domain.h>
|
#include <sbi_utils/fdt/fdt_domain.h>
|
||||||
#include <sbi_utils/fdt/fdt_driver.h>
|
#include <sbi_utils/fdt/fdt_driver.h>
|
||||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||||
#include <sbi_utils/fdt/fdt_helper.h>
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
#include <sbi_utils/fdt/fdt_pmu.h>
|
#include <sbi_utils/fdt/fdt_pmu.h>
|
||||||
#include <sbi_utils/ipi/fdt_ipi.h>
|
|
||||||
#include <sbi_utils/irqchip/fdt_irqchip.h>
|
#include <sbi_utils/irqchip/fdt_irqchip.h>
|
||||||
#include <sbi_utils/irqchip/imsic.h>
|
#include <sbi_utils/irqchip/imsic.h>
|
||||||
#include <sbi_utils/mpxy/fdt_mpxy.h>
|
#include <sbi_utils/mpxy/fdt_mpxy.h>
|
||||||
@@ -231,7 +231,7 @@ int generic_early_init(bool cold_boot)
|
|||||||
fdt_driver_init_all(fdt, fdt_early_drivers);
|
fdt_driver_init_all(fdt, fdt_early_drivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return fdt_cmo_init(cold_boot);
|
||||||
}
|
}
|
||||||
|
|
||||||
int generic_final_init(bool cold_boot)
|
int generic_final_init(bool cold_boot)
|
||||||
@@ -245,6 +245,8 @@ int generic_final_init(bool cold_boot)
|
|||||||
fdt_fixups(fdt);
|
fdt_fixups(fdt);
|
||||||
fdt_domain_fixup(fdt);
|
fdt_domain_fixup(fdt);
|
||||||
|
|
||||||
|
fdt_pack(fdt);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +337,6 @@ struct sbi_platform_operations generic_platform_ops = {
|
|||||||
.extensions_init = generic_extensions_init,
|
.extensions_init = generic_extensions_init,
|
||||||
.domains_init = generic_domains_init,
|
.domains_init = generic_domains_init,
|
||||||
.irqchip_init = fdt_irqchip_init,
|
.irqchip_init = fdt_irqchip_init,
|
||||||
.ipi_init = fdt_ipi_init,
|
|
||||||
.pmu_init = generic_pmu_init,
|
.pmu_init = generic_pmu_init,
|
||||||
.pmu_xlate_to_mhpmevent = generic_pmu_xlate_to_mhpmevent,
|
.pmu_xlate_to_mhpmevent = generic_pmu_xlate_to_mhpmevent,
|
||||||
.get_tlbr_flush_limit = generic_tlbr_flush_limit,
|
.get_tlbr_flush_limit = generic_tlbr_flush_limit,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022 Renesas Electronics Corp.
|
* Copyright (C) 2022 Renesas Electronics Corp.
|
||||||
*
|
*
|
||||||
|
|||||||
113
platform/generic/spacemit/k1.c
Normal file
113
platform/generic/spacemit/k1.c
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 SpacemiT
|
||||||
|
* Authors:
|
||||||
|
* Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
|
||||||
|
* Troy Mitchell <troy.mitchell@linux.spacemit.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <platform_override.h>
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_hsm.h>
|
||||||
|
#include <spacemit/k1.h>
|
||||||
|
|
||||||
|
/* only use 0-1 cluster in SpacemiT K1 */
|
||||||
|
static const int cci_map[] = {
|
||||||
|
PLAT_CCI_CLUSTER0_IFACE_IX,
|
||||||
|
PLAT_CCI_CLUSTER1_IFACE_IX,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cci_enable_snoop_dvm_reqs(unsigned int master_id)
|
||||||
|
{
|
||||||
|
int slave_if_id = cci_map[master_id];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable Snoops and DVM messages, no need for Read/Modify/Write as
|
||||||
|
* rest of bits are write ignore
|
||||||
|
*/
|
||||||
|
writel(CCI_550_SNOOP_CTRL_ENABLE_DVMS | CCI_550_SNOOP_CTRL_ENABLE_SNOOPS,
|
||||||
|
(void *)(u64)CCI_550_PLATFORM_CCI_ADDR +
|
||||||
|
CCI_550_SLAVE_IFACE_OFFSET(slave_if_id) + CCI_550_SNOOP_CTRL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for the completion of the write to the Snoop Control Register
|
||||||
|
* before testing the change_pending bit
|
||||||
|
*/
|
||||||
|
mb();
|
||||||
|
|
||||||
|
/* Wait for the dust to settle down */
|
||||||
|
while ((readl((void *)(u64)CCI_550_PLATFORM_CCI_ADDR + CCI_550_STATUS) &
|
||||||
|
CCI_550_STATUS_CHANGE_PENDING))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spacemit_k1_pre_init(void)
|
||||||
|
{
|
||||||
|
unsigned int clusterid, cluster_enabled = 0;
|
||||||
|
struct sbi_scratch *scratch;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
scratch = sbi_scratch_thishart_ptr();
|
||||||
|
|
||||||
|
writel(scratch->warmboot_addr, (unsigned int *)C0_RVBADDR_LO_ADDR);
|
||||||
|
writel((u64)scratch->warmboot_addr >> 32, (unsigned int *)C0_RVBADDR_HI_ADDR);
|
||||||
|
|
||||||
|
writel(scratch->warmboot_addr, (unsigned int *)C1_RVBADDR_LO_ADDR);
|
||||||
|
writel((u64)scratch->warmboot_addr >> 32, (unsigned int *)C1_RVBADDR_HI_ADDR);
|
||||||
|
|
||||||
|
for (i = 0; i < PLATFORM_MAX_CPUS; i++) {
|
||||||
|
clusterid = CPU_TO_CLUSTER(i);
|
||||||
|
|
||||||
|
if (!(cluster_enabled & (1 << clusterid))) {
|
||||||
|
cluster_enabled |= 1 << clusterid;
|
||||||
|
cci_enable_snoop_dvm_reqs(clusterid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Platform early initialization.
|
||||||
|
*/
|
||||||
|
static int spacemit_k1_early_init(bool cold_boot)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = generic_early_init(cold_boot);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
csr_set(CSR_MSETUP, MSETUP_DE | MSETUP_IE | MSETUP_BPE |
|
||||||
|
MSETUP_PFE | MSETUP_MME | MSETUP_ECCE);
|
||||||
|
|
||||||
|
if (cold_boot)
|
||||||
|
spacemit_k1_pre_init();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool spacemit_cold_boot_allowed(u32 hartid)
|
||||||
|
{
|
||||||
|
csr_set(CSR_ML2SETUP, 1 << (hartid % PLATFORM_MAX_CPUS_PER_CLUSTER));
|
||||||
|
|
||||||
|
return !hartid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spacemit_k1_platform_init(const void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
generic_platform_ops.early_init = spacemit_k1_early_init;
|
||||||
|
generic_platform_ops.cold_boot_allowed = spacemit_cold_boot_allowed;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match spacemit_k1_match[] = {
|
||||||
|
{ .compatible = "spacemit,k1" },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct fdt_driver spacemit_k1 = {
|
||||||
|
.match_table = spacemit_k1_match,
|
||||||
|
.init = spacemit_k1_platform_init,
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user