Compare commits
62 Commits
v0.9
...
sg200x-dev
| Author | SHA1 | Date | |
|---|---|---|---|
| f879119605 | |||
| aedef73d12 | |||
| 92ee61dae4 | |||
|
|
6766e9cc96 | ||
|
|
3b045ae374 | ||
|
|
fffb4754ee | ||
|
|
ab9b8f8d10 | ||
|
|
3fd99912a6 | ||
|
|
216793f112 | ||
|
|
ba54b0038e | ||
|
|
ba85a8ec52 | ||
|
|
885df4577a | ||
|
|
f67338cc74 | ||
|
|
632e27bb91 | ||
|
|
e9a27ab8ea | ||
|
|
a84a1ddbba | ||
|
|
043d088e39 | ||
|
|
dc39c7b630 | ||
|
|
559a8f1d3b | ||
|
|
068ca086af | ||
|
|
a3689db92a | ||
|
|
6d1642f856 | ||
|
|
1db843622a | ||
|
|
bf3ef53bb7 | ||
|
|
0d56293817 | ||
|
|
49e422c5ad | ||
|
|
c5d0645052 | ||
|
|
f41196a9d2 | ||
|
|
e7e4bcd5b9 | ||
|
|
fc37c9712d | ||
|
|
8b56980347 | ||
|
|
4dc0001b09 | ||
|
|
7495bce6f9 | ||
|
|
b1df1acd20 | ||
|
|
27a16b1545 | ||
|
|
70ffc3e2e6 | ||
|
|
4d8e2f135d | ||
|
|
d0e406fa44 | ||
|
|
d4a94ea471 | ||
|
|
e71a7c10a9 | ||
|
|
3d8a952737 | ||
|
|
4ef2f5d3e6 | ||
|
|
4edc822407 | ||
|
|
ca3f35821b | ||
|
|
9190ad12f7 | ||
|
|
bfc85c70e7 | ||
|
|
ddad02d625 | ||
|
|
0f20e8adcf | ||
|
|
22d8ee9758 | ||
|
|
ff5bd949d5 | ||
|
|
50d4fde1c5 | ||
|
|
b9cf617a9f | ||
|
|
74756891cc | ||
|
|
807d71c4ff | ||
|
|
4b05df6700 | ||
|
|
6290a22e34 | ||
|
|
ca864a978d | ||
|
|
638c948ab9 | ||
|
|
7c867fd19f | ||
|
|
8df1f9a0d3 | ||
|
|
5487cf095d | ||
|
|
ec5274b04c |
@@ -1,16 +0,0 @@
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignEscapedNewlines: Left
|
||||
AlignTrailingComments: true
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
BreakBeforeBraces: Custom
|
||||
BreakStringLiterals: false
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: false
|
||||
IndentWidth: 8
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SpacesInContainerLiterals: false
|
||||
TabWidth: 8
|
||||
UseTab: Always
|
||||
33
Makefile
33
Makefile
@@ -143,6 +143,20 @@ deps-y+=$(libsbi-objs-path-y:.o=.dep)
|
||||
deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
|
||||
deps-y+=$(firmware-objs-path-y:.o=.dep)
|
||||
|
||||
ifeq (,$(wildcard ${PM_SRAM_BIN_PATH}))
|
||||
ifeq (${CHIP_ARCH},CV180X)
|
||||
PM_SRAM_BIN_PATH=${OPENSBI_PATH}/pm_default_cv180x.bin
|
||||
endif
|
||||
ifeq (${CHIP_ARCH},CV181X)
|
||||
PM_SRAM_BIN_PATH=${OPENSBI_PATH}/pm_default_cv181x.bin
|
||||
endif
|
||||
else
|
||||
ifeq ($(filter clean %clean clean%,$(MAKECMDGOALS)),)
|
||||
$(shell touch -c platform\generic\cvitek_riscv.c > /dev/null)
|
||||
endif
|
||||
endif
|
||||
$(info PM_SRAM_BIN_PATH is '${PM_SRAM_BIN_PATH}')
|
||||
|
||||
# Setup platform ABI, ISA and Code Model
|
||||
ifndef PLATFORM_RISCV_ABI
|
||||
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
|
||||
@@ -203,6 +217,14 @@ GENFLAGS += $(libsbiutils-genflags-y)
|
||||
GENFLAGS += $(platform-genflags-y)
|
||||
GENFLAGS += $(firmware-genflags-y)
|
||||
|
||||
define add_define
|
||||
GENFLAGS += -D$(1)$(if $(value $(1)),=$(value $(1)),)
|
||||
endef
|
||||
|
||||
ifeq (${CONFIG_OPENSBI_FASTBOOT},y)
|
||||
$(eval $(call add_define,CONFIG_OPENSBI_FASTBOOT))
|
||||
endif
|
||||
|
||||
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
|
||||
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||
CFLAGS += -mno-save-restore -mstrict-align
|
||||
@@ -210,14 +232,21 @@ CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
|
||||
CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
|
||||
CFLAGS += $(GENFLAGS)
|
||||
CFLAGS += $(platform-cflags-y)
|
||||
CFLAGS += $(firmware-cflags-y)
|
||||
CFLAGS += -fno-pie -no-pie
|
||||
CFLAGS += $(firmware-cflags-y)
|
||||
CFLAGS += -DPM_SRAM_BIN_PATH=$(PM_SRAM_BIN_PATH)
|
||||
ifeq ($(CHIP_ARCH),CV180X)
|
||||
CFLAGS += -DCONFIG_CV180X
|
||||
endif
|
||||
ifeq (${CHIP_ARCH},CV181X)
|
||||
CFLAGS += -DCONFIG_CV181X
|
||||
endif
|
||||
|
||||
CPPFLAGS += $(GENFLAGS)
|
||||
CPPFLAGS += $(platform-cppflags-y)
|
||||
CPPFLAGS += $(firmware-cppflags-y)
|
||||
|
||||
ASFLAGS = -g -Wall -nostdlib -D__ASSEMBLY__
|
||||
ASFLAGS = -g -Wall -nostdlib
|
||||
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||
ASFLAGS += -mno-save-restore -mstrict-align
|
||||
ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
|
||||
|
||||
@@ -52,6 +52,7 @@ has following details:
|
||||
* **next_mode** - Privilege mode of the next booting stage for this
|
||||
domain. This can be either S-mode or U-mode.
|
||||
* **system_reset_allowed** - Is domain allowed to reset the system?
|
||||
* **system_suspend_allowed** - Is domain allowed to suspend the system?
|
||||
|
||||
The memory regions represented by **regions** in **struct sbi_domain** have
|
||||
following additional constraints to align with RISC-V PMP requirements:
|
||||
@@ -91,6 +92,7 @@ following manner:
|
||||
* **next_mode** - Next booting stage mode in coldboot HART scratch space
|
||||
is the next mode for the ROOT domain
|
||||
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
|
||||
* **system_suspend_allowed** - The ROOT domain is allowed to suspend the system
|
||||
|
||||
Domain Effects
|
||||
--------------
|
||||
@@ -187,6 +189,8 @@ The DT properties of a domain instance DT node are as follows:
|
||||
stage mode of coldboot HART** is used as default value.
|
||||
* **system-reset-allowed** (Optional) - A boolean flag representing
|
||||
whether the domain instance is allowed to do system reset.
|
||||
* **system-suspend-allowed** (Optional) - A boolean flag representing
|
||||
whether the domain instance is allowed to do system suspend.
|
||||
|
||||
### Assigning HART To Domain Instance
|
||||
|
||||
@@ -252,6 +256,7 @@ be done:
|
||||
next-addr = <0x0 0x80100000>;
|
||||
next-mode = <0x0>;
|
||||
system-reset-allowed;
|
||||
system-suspend-allowed;
|
||||
};
|
||||
|
||||
udomain: untrusted-domain {
|
||||
|
||||
@@ -48,7 +48,9 @@ RISC-V Platforms Using Generic Platform
|
||||
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
|
||||
* **Spike** (*[spike.md]*)
|
||||
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
|
||||
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
|
||||
|
||||
[qemu_virt.md]: qemu_virt.md
|
||||
[spike.md]: spike.md
|
||||
[shakti_cclass.md]: shakti_cclass.md
|
||||
[thead-c9xx.md]: thead-c9xx.md
|
||||
|
||||
@@ -28,15 +28,12 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
||||
* **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]*.
|
||||
|
||||
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor. More
|
||||
details on this platform can be found in the file *[thead-c910.md]*.
|
||||
|
||||
* **Spike**: Platform support for the Spike emulator. More
|
||||
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]*.
|
||||
*[fpga-openpiton.md]*.
|
||||
|
||||
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
|
||||
processor based SOCs. More details on this platform can be found in the
|
||||
@@ -55,5 +52,5 @@ facilitate the implementation.
|
||||
[andes-ae350.md]: andes-ae350.md
|
||||
[thead-c910.md]: thead-c910.md
|
||||
[spike.md]: spike.md
|
||||
[fpga_openpiton.md]: fpga_openpiton.md
|
||||
[fpga-openpiton.md]: fpga-openpiton.md
|
||||
[shakti_cclass.md]: shakti_cclass.md
|
||||
|
||||
@@ -42,7 +42,7 @@ make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/bo
|
||||
|
||||
The command-line example here assumes that U-Boot was compiled using the
|
||||
sifive_fu540_defconfig configuration and with U-Boot v2020.01, and up to
|
||||
v2020.07-rc3.
|
||||
v2021.04. sifive_unleashed_defconfig shall be used with v2021.07 or above.
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
|
||||
@@ -153,11 +153,12 @@ This is because QEMU generates a device tree blob on the fly based on the
|
||||
command line parameters and it's compatible with the one used in the upstream
|
||||
Linux kernel.
|
||||
|
||||
When U-Boot v2020.01 (or higher) is used as the payload, as the SiFive FU540
|
||||
When U-Boot v2021.07 (or higher) is used as the payload, as the SiFive FU540
|
||||
DTB for the real hardware is embedded in U-Boot binary itself, due to the same
|
||||
reason above, we need to switch the U-Boot sifive_fu540_defconfig configuration
|
||||
from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that U-Boot uses the
|
||||
DTB generated by QEMU, and u-boot.bin should be used as the payload image, like:
|
||||
reason above, we need to switch the U-Boot sifive_unleashed_defconfig
|
||||
configuration from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that
|
||||
U-Boot uses the DTB generated by QEMU, and u-boot.bin should be used as the
|
||||
payload image, like:
|
||||
|
||||
```
|
||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
T-HEAD C910 Processor
|
||||
=====================
|
||||
C910 is a 12-stage, 3 issues, 8 executions, out-of-order 64-bit RISC-V CPU which
|
||||
supports 16 cores, runs with 2.5GHz, and is capable of running Linux.
|
||||
|
||||
To build platform specific library and firmwares, provide the
|
||||
*PLATFORM=thead/c910* parameter to the top level make command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *T-HEAD C910* platform does not have any platform-specific options.
|
||||
|
||||
Building T-HEAD C910 Platform
|
||||
-----------------------------
|
||||
|
||||
```
|
||||
make PLATFORM=thead/c910
|
||||
```
|
||||
|
||||
Booting T-HEAD C910 Platform
|
||||
----------------------------
|
||||
|
||||
**No Payload**
|
||||
|
||||
As there's no payload, you may download vmlinux or u-boot to FW_JUMP_ADDR which
|
||||
specified in config.mk or compile commands with GDB. And the execution flow will
|
||||
turn to vmlinux or u-boot when opensbi ends.
|
||||
|
||||
**Linux Kernel Payload**
|
||||
|
||||
You can also choose to use Linux kernel as payload by enabling FW_PAYLOAD=y
|
||||
along with specifying FW_PAYLOAD_OFFSET. The kernel image will be embedded in
|
||||
the OPENSBI firmware binary, T-head will directly boot into Linux after OpenSBI.
|
||||
204
docs/platform/thead-c9xx.md
Normal file
204
docs/platform/thead-c9xx.md
Normal file
@@ -0,0 +1,204 @@
|
||||
T-HEAD C9xx Series Processors
|
||||
=============================
|
||||
|
||||
The **C9xx** series processors are high-performance RISC-V architecture
|
||||
multi-core processors with AI vector acceleration engine.
|
||||
|
||||
For more details, refer [T-HEAD.CN](https://www.t-head.cn/)
|
||||
|
||||
To build the platform-specific library and firmware images, provide the
|
||||
*PLATFORM=generic* parameter to the top level `make` command.
|
||||
|
||||
Platform Options
|
||||
----------------
|
||||
|
||||
The *T-HEAD C9xx* does not have any platform-specific compile options
|
||||
because it use generic platform.
|
||||
|
||||
```
|
||||
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic FW_PIC=y /usr/bin/make
|
||||
```
|
||||
|
||||
The *T-HEAD C9xx* DTB provided to OpenSBI generic firmwares will usually have
|
||||
"riscv,clint0", "riscv,plic0", "thead,reset-sample" compatible strings.
|
||||
|
||||
DTS Example1: (Single core, eg: Allwinner D1 - c906)
|
||||
----------------------------------------------------
|
||||
|
||||
```
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <3000000>;
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
status = "okay";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdcv";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu0_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
compatible = "simple-bus";
|
||||
ranges;
|
||||
|
||||
reset: reset-sample {
|
||||
compatible = "thead,reset-sample";
|
||||
plic-delegate = <0x0 0x101ffffc>;
|
||||
};
|
||||
|
||||
clint0: clint@14000000 {
|
||||
compatible = "riscv,clint0";
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 3 &cpu0_intc 7
|
||||
>;
|
||||
reg = <0x0 0x14000000 0x0 0x04000000>;
|
||||
clint,has-no-64bit-mmio;
|
||||
};
|
||||
|
||||
intc: interrupt-controller@10000000 {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,plic0";
|
||||
interrupt-controller;
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 0xffffffff &cpu0_intc 9
|
||||
>;
|
||||
reg = <0x0 0x10000000 0x0 0x04000000>;
|
||||
reg-names = "control";
|
||||
riscv,max-priority = <7>;
|
||||
riscv,ndev = <200>;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
DTS Example2: (Multi cores with soc reset-regs)
|
||||
-----------------------------------------------
|
||||
|
||||
```
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
timebase-frequency = <3000000>;
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
status = "okay";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu0_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu@1 {
|
||||
device_type = "cpu";
|
||||
reg = <1>;
|
||||
status = "fail";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu1_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu@2 {
|
||||
device_type = "cpu";
|
||||
reg = <2>;
|
||||
status = "fail";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu2_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
cpu@3 {
|
||||
device_type = "cpu";
|
||||
reg = <3>;
|
||||
status = "fail";
|
||||
compatible = "riscv";
|
||||
riscv,isa = "rv64imafdc";
|
||||
mmu-type = "riscv,sv39";
|
||||
cpu3_intc: interrupt-controller {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,cpu-intc";
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
compatible = "simple-bus";
|
||||
ranges;
|
||||
|
||||
reset: reset-sample {
|
||||
compatible = "thead,reset-sample";
|
||||
plic-delegate = <0xff 0xd81ffffc>;
|
||||
entry-reg = <0xff 0xff019050>;
|
||||
entry-cnt = <4>;
|
||||
control-reg = <0xff 0xff015004>;
|
||||
control-val = <0x1c>;
|
||||
csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
|
||||
};
|
||||
|
||||
clint0: clint@ffdc000000 {
|
||||
compatible = "riscv,clint0";
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 3 &cpu0_intc 7
|
||||
&cpu1_intc 3 &cpu1_intc 7
|
||||
&cpu2_intc 3 &cpu2_intc 7
|
||||
&cpu3_intc 3 &cpu3_intc 7
|
||||
&cpu4_intc 3 &cpu4_intc 7
|
||||
>;
|
||||
reg = <0xff 0xdc000000 0x0 0x04000000>;
|
||||
clint,has-no-64bit-mmio;
|
||||
};
|
||||
|
||||
intc: interrupt-controller@ffd8000000 {
|
||||
#interrupt-cells = <1>;
|
||||
compatible = "riscv,plic0";
|
||||
interrupt-controller;
|
||||
interrupts-extended = <
|
||||
&cpu0_intc 0xffffffff &cpu0_intc 9
|
||||
&cpu1_intc 0xffffffff &cpu1_intc 9
|
||||
&cpu2_intc 0xffffffff &cpu2_intc 9
|
||||
&cpu3_intc 0xffffffff &cpu3_intc 9
|
||||
>;
|
||||
reg = <0xff 0xd8000000 0x0 0x04000000>;
|
||||
reg-names = "control";
|
||||
riscv,max-priority = <7>;
|
||||
riscv,ndev = <80>;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
DTS Example2: (Multi cores with old reset csrs)
|
||||
-----------------------------------------------
|
||||
```
|
||||
reset: reset-sample {
|
||||
compatible = "thead,reset-sample";
|
||||
plic-delegate = <0xff 0xd81ffffc>;
|
||||
using-csr-reset;
|
||||
csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
|
||||
0x3b0 0x3b1 0x3b2 0x3b3
|
||||
0x3b4 0x3b5 0x3b6 0x3b7
|
||||
0x3a0>;
|
||||
};
|
||||
```
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/riscv_elf.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
@@ -57,39 +58,91 @@ _start:
|
||||
bne a0, a6, _wait_relocate_copy_done
|
||||
_try_lottery:
|
||||
/* Jump to relocation wait loop if we don't get relocation lottery */
|
||||
la a6, _relocate_lottery
|
||||
lla a6, _relocate_lottery
|
||||
li a7, 1
|
||||
amoadd.w a6, a7, (a6)
|
||||
bnez a6, _wait_relocate_copy_done
|
||||
|
||||
/* Save load address */
|
||||
la t0, _load_start
|
||||
la t1, _start
|
||||
lla t0, _load_start
|
||||
lla t1, _start
|
||||
REG_S t1, 0(t0)
|
||||
|
||||
#ifdef FW_PIC
|
||||
/* relocate the global table content */
|
||||
lla t0, _link_start
|
||||
REG_L t0, 0(t0)
|
||||
/* t1 shall has the address of _start */
|
||||
sub t2, t1, t0
|
||||
lla t3, _runtime_offset
|
||||
REG_S t2, (t3)
|
||||
lla t0, __rel_dyn_start
|
||||
lla t1, __rel_dyn_end
|
||||
beq t0, t1, _relocate_done
|
||||
j 5f
|
||||
2:
|
||||
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
|
||||
li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
|
||||
bne t5, t3, 3f
|
||||
REG_L t3, -(REGBYTES*3)(t0)
|
||||
REG_L t5, -(REGBYTES)(t0) /* t5 <-- addend */
|
||||
add t5, t5, t2
|
||||
add t3, t3, t2
|
||||
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
|
||||
j 5f
|
||||
|
||||
3:
|
||||
lla t4, __dyn_sym_start
|
||||
|
||||
4:
|
||||
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
|
||||
srli t6, t5, SYM_INDEX /* t6 <--- sym table index */
|
||||
andi t5, t5, 0xFF /* t5 <--- relocation type */
|
||||
li t3, RELOC_TYPE
|
||||
bne t5, t3, 5f
|
||||
|
||||
/* address R_RISCV_64 or R_RISCV_32 cases*/
|
||||
REG_L t3, -(REGBYTES*3)(t0)
|
||||
li t5, SYM_SIZE
|
||||
mul t6, t6, t5
|
||||
add s5, t4, t6
|
||||
REG_L t6, -(REGBYTES)(t0) /* t0 <-- addend */
|
||||
REG_L t5, REGBYTES(s5)
|
||||
add t5, t5, t6
|
||||
add t5, t5, t2 /* t5 <-- location to fix up in RAM */
|
||||
add t3, t3, t2 /* t3 <-- location to fix up in RAM */
|
||||
REG_S t5, 0(t3) /* store runtime address to the variable */
|
||||
|
||||
5:
|
||||
addi t0, t0, (REGBYTES*3)
|
||||
ble t0, t1, 2b
|
||||
j _relocate_done
|
||||
_wait_relocate_copy_done:
|
||||
j _wait_for_boot_hart
|
||||
#else
|
||||
/* Relocate if load address != link address */
|
||||
_relocate:
|
||||
la t0, _link_start
|
||||
lla t0, _link_start
|
||||
REG_L t0, 0(t0)
|
||||
la t1, _link_end
|
||||
lla t1, _link_end
|
||||
REG_L t1, 0(t1)
|
||||
la t2, _load_start
|
||||
lla t2, _load_start
|
||||
REG_L t2, 0(t2)
|
||||
sub t3, t1, t0
|
||||
add t3, t3, t2
|
||||
beq t0, t2, _relocate_done
|
||||
la t4, _relocate_done
|
||||
lla t4, _relocate_done
|
||||
sub t4, t4, t2
|
||||
add t4, t4, t0
|
||||
blt t2, t0, _relocate_copy_to_upper
|
||||
_relocate_copy_to_lower:
|
||||
ble t1, t2, _relocate_copy_to_lower_loop
|
||||
la t3, _relocate_lottery
|
||||
lla t3, _relocate_lottery
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
la t3, _boot_status
|
||||
lla t3, _boot_status
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
la t3, _relocate
|
||||
la t5, _relocate_done
|
||||
lla t3, _relocate
|
||||
lla t5, _relocate_done
|
||||
BRANGE t2, t1, t3, _start_hang
|
||||
BRANGE t2, t1, t5, _start_hang
|
||||
BRANGE t3, t5, t2, _start_hang
|
||||
@@ -102,12 +155,12 @@ _relocate_copy_to_lower_loop:
|
||||
jr t4
|
||||
_relocate_copy_to_upper:
|
||||
ble t3, t0, _relocate_copy_to_upper_loop
|
||||
la t2, _relocate_lottery
|
||||
lla t2, _relocate_lottery
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
la t2, _boot_status
|
||||
lla t2, _boot_status
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
la t2, _relocate
|
||||
la t5, _relocate_done
|
||||
lla t2, _relocate
|
||||
lla t5, _relocate_done
|
||||
BRANGE t0, t3, t2, _start_hang
|
||||
BRANGE t0, t3, t5, _start_hang
|
||||
BRANGE t2, t5, t0, _start_hang
|
||||
@@ -119,12 +172,12 @@ _relocate_copy_to_upper_loop:
|
||||
blt t0, t1, _relocate_copy_to_upper_loop
|
||||
jr t4
|
||||
_wait_relocate_copy_done:
|
||||
la t0, _start
|
||||
la t1, _link_start
|
||||
lla t0, _start
|
||||
lla t1, _link_start
|
||||
REG_L t1, 0(t1)
|
||||
beq t0, t1, _wait_for_boot_hart
|
||||
la t2, _boot_status
|
||||
la t3, _wait_for_boot_hart
|
||||
lla t2, _boot_status
|
||||
lla t3, _wait_for_boot_hart
|
||||
sub t3, t3, t0
|
||||
add t3, t3, t1
|
||||
1:
|
||||
@@ -137,19 +190,22 @@ _wait_relocate_copy_done:
|
||||
nop
|
||||
bgt t4, t5, 1b
|
||||
jr t3
|
||||
#endif
|
||||
_relocate_done:
|
||||
|
||||
/*
|
||||
* Mark relocate copy done
|
||||
* Use _boot_status copy relative to the load address
|
||||
*/
|
||||
la t0, _boot_status
|
||||
la t1, _link_start
|
||||
lla t0, _boot_status
|
||||
#ifndef FW_PIC
|
||||
lla t1, _link_start
|
||||
REG_L t1, 0(t1)
|
||||
la t2, _load_start
|
||||
lla t2, _load_start
|
||||
REG_L t2, 0(t2)
|
||||
sub t0, t0, t1
|
||||
add t0, t0, t2
|
||||
#endif
|
||||
li t1, BOOT_STATUS_RELOCATE_DONE
|
||||
REG_S t1, 0(t0)
|
||||
fence rw, rw
|
||||
@@ -161,19 +217,19 @@ _relocate_done:
|
||||
call _reset_regs
|
||||
|
||||
/* Zero-out BSS */
|
||||
la s4, _bss_start
|
||||
la s5, _bss_end
|
||||
lla s4, _bss_start
|
||||
lla s5, _bss_end
|
||||
_bss_zero:
|
||||
REG_S zero, (s4)
|
||||
add s4, s4, __SIZEOF_POINTER__
|
||||
blt s4, s5, _bss_zero
|
||||
|
||||
/* Setup temporary trap handler */
|
||||
la s4, _start_hang
|
||||
lla s4, _start_hang
|
||||
csrw CSR_MTVEC, s4
|
||||
|
||||
/* Setup temporary stack */
|
||||
la s4, _fw_end
|
||||
lla s4, _fw_end
|
||||
li s5, (SBI_SCRATCH_SIZE * 2)
|
||||
add sp, s4, s5
|
||||
|
||||
@@ -184,7 +240,7 @@ _bss_zero:
|
||||
|
||||
#ifdef FW_FDT_PATH
|
||||
/* Override previous arg1 */
|
||||
la a1, fw_fdt_bin
|
||||
lla a1, fw_fdt_bin
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -202,7 +258,7 @@ _bss_zero:
|
||||
* s7 -> HART Count
|
||||
* s8 -> HART Stack Size
|
||||
*/
|
||||
la a4, platform
|
||||
lla a4, platform
|
||||
#if __riscv_xlen == 64
|
||||
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
||||
@@ -212,7 +268,7 @@ _bss_zero:
|
||||
#endif
|
||||
|
||||
/* Setup scratch space for all the HARTs*/
|
||||
la tp, _fw_end
|
||||
lla tp, _fw_end
|
||||
mul a5, s7, s8
|
||||
add tp, tp, a5
|
||||
/* Keep a copy of tp */
|
||||
@@ -230,8 +286,8 @@ _scratch_init:
|
||||
|
||||
/* Initialize scratch space */
|
||||
/* Store fw_start and fw_size in scratch space */
|
||||
la a4, _fw_start
|
||||
la a5, _fw_end
|
||||
lla a4, _fw_start
|
||||
lla a5, _fw_end
|
||||
mul t0, s7, s8
|
||||
add a5, a5, t0
|
||||
sub a5, a5, a4
|
||||
@@ -253,16 +309,16 @@ _scratch_init:
|
||||
REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
|
||||
MOV_3R a0, s0, a1, s1, a2, s2
|
||||
/* Store warm_boot address in scratch space */
|
||||
la a4, _start_warm
|
||||
lla a4, _start_warm
|
||||
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
|
||||
/* Store platform address in scratch space */
|
||||
la a4, platform
|
||||
lla a4, platform
|
||||
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
|
||||
/* Store hartid-to-scratch function address in scratch space */
|
||||
la a4, _hartid_to_scratch
|
||||
lla a4, _hartid_to_scratch
|
||||
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
|
||||
/* Store trap-exit function address in scratch space */
|
||||
la a4, _trap_exit
|
||||
lla a4, _trap_exit
|
||||
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(tp)
|
||||
/* Clear tmp0 in scratch space */
|
||||
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
|
||||
@@ -343,7 +399,7 @@ _fdt_reloc_done:
|
||||
|
||||
/* mark boot hart done */
|
||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||
la t1, _boot_status
|
||||
lla t1, _boot_status
|
||||
REG_S t0, 0(t1)
|
||||
fence rw, rw
|
||||
j _start_warm
|
||||
@@ -351,7 +407,7 @@ _fdt_reloc_done:
|
||||
/* waiting for boot hart to be done (_boot_status == 2) */
|
||||
_wait_for_boot_hart:
|
||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||
la t1, _boot_status
|
||||
lla t1, _boot_status
|
||||
REG_L t1, 0(t1)
|
||||
/* Reduce the bus traffic so that boot hart may proceed faster */
|
||||
nop
|
||||
@@ -369,7 +425,7 @@ _start_warm:
|
||||
csrw CSR_MIP, zero
|
||||
|
||||
/* Find HART count and HART stack size */
|
||||
la a4, platform
|
||||
lla a4, platform
|
||||
#if __riscv_xlen == 64
|
||||
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
||||
@@ -400,7 +456,7 @@ _start_warm:
|
||||
3: bge s6, s7, _start_hang
|
||||
|
||||
/* Find the scratch space based on HART index */
|
||||
la tp, _fw_end
|
||||
lla tp, _fw_end
|
||||
mul a5, s7, s8
|
||||
add tp, tp, a5
|
||||
mul a5, s8, s6
|
||||
@@ -415,13 +471,13 @@ _start_warm:
|
||||
add sp, tp, zero
|
||||
|
||||
/* Setup trap handler */
|
||||
la a4, _trap_handler
|
||||
lla a4, _trap_handler
|
||||
#if __riscv_xlen == 32
|
||||
csrr a5, CSR_MISA
|
||||
srli a5, a5, ('H' - 'A')
|
||||
andi a5, a5, 0x1
|
||||
beq a5, zero, _skip_trap_handler_rv32_hyp
|
||||
la a4, _trap_handler_rv32_hyp
|
||||
lla a4, _trap_handler_rv32_hyp
|
||||
_skip_trap_handler_rv32_hyp:
|
||||
#endif
|
||||
csrw CSR_MTVEC, a4
|
||||
@@ -432,7 +488,7 @@ _skip_trap_handler_rv32_hyp:
|
||||
srli a5, a5, ('H' - 'A')
|
||||
andi a5, a5, 0x1
|
||||
beq a5, zero, _skip_trap_exit_rv32_hyp
|
||||
la a4, _trap_exit_rv32_hyp
|
||||
lla a4, _trap_exit_rv32_hyp
|
||||
csrr a5, CSR_MSCRATCH
|
||||
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(a5)
|
||||
_skip_trap_exit_rv32_hyp:
|
||||
@@ -446,6 +502,10 @@ _skip_trap_exit_rv32_hyp:
|
||||
j _start_hang
|
||||
|
||||
.align 3
|
||||
#ifdef FW_PIC
|
||||
_runtime_offset:
|
||||
RISCV_PTR 0
|
||||
#endif
|
||||
_relocate_lottery:
|
||||
RISCV_PTR 0
|
||||
_boot_status:
|
||||
@@ -453,7 +513,7 @@ _boot_status:
|
||||
_load_start:
|
||||
RISCV_PTR _fw_start
|
||||
_link_start:
|
||||
RISCV_PTR _fw_start
|
||||
RISCV_PTR FW_TEXT_START
|
||||
_link_end:
|
||||
RISCV_PTR _fw_reloc_end
|
||||
|
||||
@@ -468,7 +528,7 @@ _hartid_to_scratch:
|
||||
* t1 -> HART Stack End
|
||||
* t2 -> Temporary
|
||||
*/
|
||||
la t2, platform
|
||||
lla t2, platform
|
||||
#if __riscv_xlen == 64
|
||||
lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
|
||||
lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
|
||||
@@ -478,7 +538,7 @@ _hartid_to_scratch:
|
||||
#endif
|
||||
sub t2, t2, a1
|
||||
mul t2, t2, t0
|
||||
la t1, _fw_end
|
||||
lla t1, _fw_end
|
||||
add t1, t1, t2
|
||||
li t2, SBI_SCRATCH_SIZE
|
||||
sub a0, t1, t2
|
||||
@@ -595,62 +655,63 @@ fw_platform_init:
|
||||
call sbi_trap_handler
|
||||
.endm
|
||||
|
||||
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
/* Restore all general regisers except SP and T0 */
|
||||
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
|
||||
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
|
||||
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
|
||||
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
|
||||
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
|
||||
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
|
||||
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
|
||||
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
|
||||
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
|
||||
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
|
||||
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
|
||||
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
|
||||
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
|
||||
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
|
||||
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
|
||||
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
|
||||
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
|
||||
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
|
||||
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
|
||||
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
|
||||
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
|
||||
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
|
||||
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
|
||||
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
|
||||
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
|
||||
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
|
||||
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
|
||||
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
|
||||
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
|
||||
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
||||
/* Restore all general regisers except A0 and T0 */
|
||||
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(a0)
|
||||
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(a0)
|
||||
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(a0)
|
||||
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(a0)
|
||||
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(a0)
|
||||
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(a0)
|
||||
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(a0)
|
||||
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(a0)
|
||||
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(a0)
|
||||
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(a0)
|
||||
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(a0)
|
||||
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(a0)
|
||||
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(a0)
|
||||
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(a0)
|
||||
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(a0)
|
||||
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(a0)
|
||||
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(a0)
|
||||
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(a0)
|
||||
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(a0)
|
||||
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(a0)
|
||||
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(a0)
|
||||
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(a0)
|
||||
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(a0)
|
||||
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(a0)
|
||||
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(a0)
|
||||
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(a0)
|
||||
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(a0)
|
||||
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(a0)
|
||||
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(a0)
|
||||
.endm
|
||||
|
||||
.macro TRAP_RESTORE_MEPC_MSTATUS have_mstatush
|
||||
/* Restore MEPC and MSTATUS CSRs */
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(a0)
|
||||
csrw CSR_MEPC, t0
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(a0)
|
||||
csrw CSR_MSTATUS, t0
|
||||
.if \have_mstatush
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(a0)
|
||||
csrw CSR_MSTATUSH, t0
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro TRAP_RESTORE_SP_T0
|
||||
.macro TRAP_RESTORE_A0_T0
|
||||
/* Restore T0 */
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
|
||||
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(a0)
|
||||
|
||||
/* Restore SP */
|
||||
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
|
||||
/* Restore A0 */
|
||||
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(a0)
|
||||
.endm
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler
|
||||
.globl _trap_exit
|
||||
_trap_handler:
|
||||
TRAP_SAVE_AND_SETUP_SP_T0
|
||||
|
||||
@@ -660,25 +721,12 @@ _trap_handler:
|
||||
|
||||
TRAP_CALL_C_ROUTINE
|
||||
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 0
|
||||
|
||||
TRAP_RESTORE_SP_T0
|
||||
|
||||
mret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_exit
|
||||
_trap_exit:
|
||||
add sp, a0, zero
|
||||
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 0
|
||||
|
||||
TRAP_RESTORE_SP_T0
|
||||
TRAP_RESTORE_A0_T0
|
||||
|
||||
mret
|
||||
|
||||
@@ -686,6 +734,7 @@ _trap_exit:
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_handler_rv32_hyp
|
||||
.globl _trap_exit_rv32_hyp
|
||||
_trap_handler_rv32_hyp:
|
||||
TRAP_SAVE_AND_SETUP_SP_T0
|
||||
|
||||
@@ -695,25 +744,12 @@ _trap_handler_rv32_hyp:
|
||||
|
||||
TRAP_CALL_C_ROUTINE
|
||||
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 1
|
||||
|
||||
TRAP_RESTORE_SP_T0
|
||||
|
||||
mret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
.align 3
|
||||
.globl _trap_exit_rv32_hyp
|
||||
_trap_exit_rv32_hyp:
|
||||
add sp, a0, zero
|
||||
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
|
||||
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
|
||||
|
||||
TRAP_RESTORE_MEPC_MSTATUS 1
|
||||
|
||||
TRAP_RESTORE_SP_T0
|
||||
TRAP_RESTORE_A0_T0
|
||||
|
||||
mret
|
||||
#endif
|
||||
|
||||
@@ -61,6 +61,19 @@
|
||||
PROVIDE(_data_end = .);
|
||||
}
|
||||
|
||||
.dynsym : {
|
||||
PROVIDE(__dyn_sym_start = .);
|
||||
*(.dynsym)
|
||||
PROVIDE(__dyn_sym_end = .);
|
||||
}
|
||||
|
||||
.rela.dyn : {
|
||||
PROVIDE(__rel_dyn_start = .);
|
||||
*(.rela*)
|
||||
. = ALIGN(8);
|
||||
PROVIDE(__rel_dyn_end = .);
|
||||
}
|
||||
|
||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||
|
||||
.bss :
|
||||
|
||||
@@ -54,7 +54,7 @@ fw_boot_hart:
|
||||
*/
|
||||
fw_save_info:
|
||||
/* Save next arg1 in 'a1' */
|
||||
la a4, _dynamic_next_arg1
|
||||
lla a4, _dynamic_next_arg1
|
||||
REG_S a1, (a4)
|
||||
|
||||
/* Sanity checks */
|
||||
@@ -66,13 +66,13 @@ fw_save_info:
|
||||
bgt a3, a4, _bad_dynamic_info
|
||||
|
||||
/* Save version == 0x1 fields */
|
||||
la a4, _dynamic_next_addr
|
||||
lla a4, _dynamic_next_addr
|
||||
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
la a4, _dynamic_next_mode
|
||||
lla a4, _dynamic_next_mode
|
||||
REG_L a3, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
la a4, _dynamic_options
|
||||
lla a4, _dynamic_options
|
||||
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
|
||||
@@ -80,7 +80,7 @@ fw_save_info:
|
||||
li a4, 0x2
|
||||
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
|
||||
blt a3, a4, 2f
|
||||
la a4, _dynamic_boot_hart
|
||||
lla a4, _dynamic_boot_hart
|
||||
REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
|
||||
REG_S a3, (a4)
|
||||
2:
|
||||
@@ -96,7 +96,7 @@ fw_save_info:
|
||||
* The next arg1 should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_arg1:
|
||||
la a0, _dynamic_next_arg1
|
||||
lla a0, _dynamic_next_arg1
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
@@ -108,7 +108,7 @@ fw_next_arg1:
|
||||
* The next address should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_addr:
|
||||
la a0, _dynamic_next_addr
|
||||
lla a0, _dynamic_next_addr
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
@@ -120,7 +120,7 @@ fw_next_addr:
|
||||
* The next address should be returned in 'a0'
|
||||
*/
|
||||
fw_next_mode:
|
||||
la a0, _dynamic_next_mode
|
||||
lla a0, _dynamic_next_mode
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
@@ -133,7 +133,7 @@ fw_next_mode:
|
||||
* The next address should be returned in 'a0'.
|
||||
*/
|
||||
fw_options:
|
||||
la a0, _dynamic_options
|
||||
lla a0, _dynamic_options
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ fw_next_arg1:
|
||||
* The next address should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_addr:
|
||||
la a0, _jump_addr
|
||||
lla a0, _jump_addr
|
||||
REG_L a0, (a0)
|
||||
ret
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ fw_next_arg1:
|
||||
* The next address should be returned in 'a0'.
|
||||
*/
|
||||
fw_next_addr:
|
||||
la a0, payload_bin
|
||||
lla a0, payload_bin
|
||||
ret
|
||||
|
||||
.section .entry, "ax", %progbits
|
||||
|
||||
@@ -13,6 +13,17 @@ firmware-cflags-y +=
|
||||
firmware-asflags-y +=
|
||||
firmware-ldflags-y +=
|
||||
|
||||
ifndef FW_PIC
|
||||
FW_PIC := y
|
||||
endif
|
||||
|
||||
ifeq ($(FW_PIC),y)
|
||||
firmware-genflags-y += -DFW_PIC
|
||||
firmware-asflags-y += -fpic
|
||||
firmware-cflags-y += -fPIE -pie
|
||||
firmware-ldflags-y += -Wl,--no-dynamic-linker
|
||||
endif
|
||||
|
||||
ifdef FW_TEXT_START
|
||||
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
|
||||
endif
|
||||
|
||||
@@ -28,20 +28,20 @@
|
||||
.globl _start
|
||||
_start:
|
||||
/* Pick one hart to run the main boot sequence */
|
||||
la a3, _hart_lottery
|
||||
lla a3, _hart_lottery
|
||||
li a2, 1
|
||||
amoadd.w a3, a2, (a3)
|
||||
bnez a3, _start_hang
|
||||
|
||||
/* Save a0 and a1 */
|
||||
la a3, _boot_a0
|
||||
lla a3, _boot_a0
|
||||
REG_S a0, 0(a3)
|
||||
la a3, _boot_a1
|
||||
lla a3, _boot_a1
|
||||
REG_S a1, 0(a3)
|
||||
|
||||
/* Zero-out BSS */
|
||||
la a4, _bss_start
|
||||
la a5, _bss_end
|
||||
lla a4, _bss_start
|
||||
lla a5, _bss_end
|
||||
_bss_zero:
|
||||
REG_S zero, (a4)
|
||||
add a4, a4, __SIZEOF_POINTER__
|
||||
@@ -53,18 +53,18 @@ _start_warm:
|
||||
csrw CSR_SIP, zero
|
||||
|
||||
/* Setup exception vectors */
|
||||
la a3, _start_hang
|
||||
lla a3, _start_hang
|
||||
csrw CSR_STVEC, a3
|
||||
|
||||
/* Setup stack */
|
||||
la a3, _payload_end
|
||||
lla a3, _payload_end
|
||||
li a4, 0x2000
|
||||
add sp, a3, a4
|
||||
|
||||
/* Jump to C main */
|
||||
la a3, _boot_a0
|
||||
lla a3, _boot_a0
|
||||
REG_L a0, 0(a3)
|
||||
la a3, _boot_a1
|
||||
lla a3, _boot_a1
|
||||
REG_L a1, 0(a3)
|
||||
call test_main
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef __ASSEMBLER__
|
||||
#define __ASM_STR(x) x
|
||||
#else
|
||||
#define __ASM_STR(x) #x
|
||||
@@ -38,7 +38,7 @@
|
||||
#define LGREG __REG_SEL(3, 2)
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef __ASSEMBLER__
|
||||
#define RISCV_PTR .dword
|
||||
#define RISCV_SZPTR 8
|
||||
#define RISCV_LGPTR 3
|
||||
@@ -48,7 +48,7 @@
|
||||
#define RISCV_LGPTR "3"
|
||||
#endif
|
||||
#elif __SIZEOF_POINTER__ == 4
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef __ASSEMBLER__
|
||||
#define RISCV_PTR .word
|
||||
#define RISCV_SZPTR 4
|
||||
#define RISCV_LGPTR 2
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#define csr_swap(csr, val) \
|
||||
({ \
|
||||
@@ -157,6 +157,11 @@ void csr_write_num(int csr_num, unsigned long val);
|
||||
__asm__ __volatile__("wfi" ::: "memory"); \
|
||||
} while (0)
|
||||
|
||||
#define ebreak() \
|
||||
do { \
|
||||
__asm__ __volatile__("ebreak" ::: "memory"); \
|
||||
} while (0)
|
||||
|
||||
/* Get current HART id */
|
||||
#define current_hartid() ((unsigned int)csr_read(CSR_MHARTID))
|
||||
|
||||
@@ -182,6 +187,6 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
||||
unsigned long *log2len);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#endif /* !__ASSEMBLER__ */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#define RISCV_FENCE(p, s) \
|
||||
__asm__ __volatile__ ("fence " #p "," #s : : : "memory")
|
||||
|
||||
#define RISCV_FENCE_I \
|
||||
__asm__ __volatile__ ("fence.i" : : : "memory")
|
||||
|
||||
/* Read & Write Memory barrier */
|
||||
#define mb() RISCV_FENCE(iorw,iorw)
|
||||
|
||||
|
||||
14
include/sbi/riscv_elf.h
Normal file
14
include/sbi/riscv_elf.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef __RISCV_ELF_H__
|
||||
#define __RISCV_ELF_H__
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
|
||||
#define R_RISCV_32 1
|
||||
#define R_RISCV_64 2
|
||||
#define R_RISCV_RELATIVE 3
|
||||
|
||||
#define RELOC_TYPE __REG_SEL(R_RISCV_64, R_RISCV_32)
|
||||
#define SYM_INDEX __REG_SEL(0x20, 0x8)
|
||||
#define SYM_SIZE __REG_SEL(0x18,0x10)
|
||||
|
||||
#endif
|
||||
@@ -2,26 +2,37 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
|
||||
*/
|
||||
|
||||
#ifndef __RISCV_LOCKS_H__
|
||||
#define __RISCV_LOCKS_H__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
#define TICKET_SHIFT 16
|
||||
|
||||
typedef struct {
|
||||
volatile long lock;
|
||||
} spinlock_t;
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
u16 next;
|
||||
u16 owner;
|
||||
#else
|
||||
u16 owner;
|
||||
u16 next;
|
||||
#endif
|
||||
} __aligned(4) spinlock_t;
|
||||
|
||||
#define __RISCV_SPIN_UNLOCKED 0
|
||||
#define __SPIN_LOCK_UNLOCKED \
|
||||
(spinlock_t) { 0, 0 }
|
||||
|
||||
#define SPIN_LOCK_INIT(_lptr) (_lptr)->lock = __RISCV_SPIN_UNLOCKED
|
||||
#define SPIN_LOCK_INIT(x) \
|
||||
x = __SPIN_LOCK_UNLOCKED
|
||||
|
||||
#define SPIN_LOCK_INITIALIZER \
|
||||
{ \
|
||||
.lock = __RISCV_SPIN_UNLOCKED, \
|
||||
}
|
||||
#define SPIN_LOCK_INITIALIZER \
|
||||
__SPIN_LOCK_UNLOCKED
|
||||
|
||||
#define DEFINE_SPIN_LOCK(x) \
|
||||
spinlock_t SPIN_LOCK_INIT(x)
|
||||
|
||||
int spin_lock_check(spinlock_t *lock);
|
||||
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
struct sbi_console_device {
|
||||
/** Name of the console device */
|
||||
char name[32];
|
||||
|
||||
/** Write a character to the console output */
|
||||
void (*console_putc)(char ch);
|
||||
|
||||
/** Read a character from the console input */
|
||||
int (*console_getc)(void);
|
||||
};
|
||||
|
||||
#define __printf(a, b) __attribute__((format(printf, a, b)))
|
||||
|
||||
bool sbi_isprintable(char ch);
|
||||
@@ -32,6 +43,10 @@ int __printf(1, 2) sbi_printf(const char *format, ...);
|
||||
|
||||
int __printf(1, 2) sbi_dprintf(const char *format, ...);
|
||||
|
||||
const struct sbi_console_device *sbi_console_get_device(void);
|
||||
|
||||
void sbi_console_set_device(const struct sbi_console_device *dev);
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_console_init(struct sbi_scratch *scratch);
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#ifdef __ASSEMBLER__
|
||||
#define _AC(X,Y) X
|
||||
#define _AT(T,X) X
|
||||
#else
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
|
||||
#define csr_read_allowed(csr_num, trap) \
|
||||
({ \
|
||||
@@ -19,6 +20,7 @@
|
||||
register ulong ttmp asm("a4"); \
|
||||
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||
register ulong ret = 0; \
|
||||
((struct sbi_trap_info *)(trap))->cause = 0; \
|
||||
asm volatile( \
|
||||
"add %[ttmp], %[tinfo], zero\n" \
|
||||
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||
@@ -36,6 +38,7 @@
|
||||
register ulong tinfo asm("a3") = (ulong)trap; \
|
||||
register ulong ttmp asm("a4"); \
|
||||
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||
((struct sbi_trap_info *)(trap))->cause = 0; \
|
||||
asm volatile( \
|
||||
"add %[ttmp], %[tinfo], zero\n" \
|
||||
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||
|
||||
@@ -78,8 +78,13 @@ struct sbi_domain {
|
||||
unsigned long next_mode;
|
||||
/** Is domain allowed to reset the system */
|
||||
bool system_reset_allowed;
|
||||
/** Is domain allowed to suspend the system */
|
||||
bool system_suspend_allowed;
|
||||
};
|
||||
|
||||
/** The root domain instance */
|
||||
extern struct sbi_domain root;
|
||||
|
||||
/** HART id to domain table */
|
||||
extern struct sbi_domain *hartid_to_domain_table[];
|
||||
|
||||
@@ -124,8 +129,19 @@ bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
|
||||
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
||||
ulong hbase);
|
||||
|
||||
/** Initialize a domain memory region as firmware region */
|
||||
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg);
|
||||
/**
|
||||
* Initialize a domain memory region based on it's physical
|
||||
* address and size.
|
||||
*
|
||||
* @param addr start physical address of memory region
|
||||
* @param size physical size of memory region
|
||||
* @param flags memory region flags
|
||||
* @param reg pointer to memory region being initialized
|
||||
*/
|
||||
void sbi_domain_memregion_init(unsigned long addr,
|
||||
unsigned long size,
|
||||
unsigned long flags,
|
||||
struct sbi_domain_memregion *reg);
|
||||
|
||||
/**
|
||||
* Check whether we can access specified address for given mode and
|
||||
@@ -156,6 +172,14 @@ void sbi_domain_dump_all(const char *suffix);
|
||||
int sbi_domain_register(struct sbi_domain *dom,
|
||||
const struct sbi_hartmask *assign_mask);
|
||||
|
||||
/**
|
||||
* Add a memory region to the root domain
|
||||
* @param reg pointer to the memory region to be added
|
||||
*
|
||||
* @return 0 on success and negative error code on failure
|
||||
*/
|
||||
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
|
||||
|
||||
/** Finalize domain tables and startup non-root domains */
|
||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <sbi/sbi_list.h>
|
||||
|
||||
#define SBI_ECALL_VERSION_MAJOR 0
|
||||
#define SBI_ECALL_VERSION_MINOR 2
|
||||
#define SBI_ECALL_VERSION_MINOR 3
|
||||
#define SBI_OPENSBI_IMPID 1
|
||||
|
||||
struct sbi_trap_regs;
|
||||
@@ -39,6 +39,7 @@ extern struct sbi_ecall_extension ecall_ipi;
|
||||
extern struct sbi_ecall_extension ecall_vendor;
|
||||
extern struct sbi_ecall_extension ecall_hsm;
|
||||
extern struct sbi_ecall_extension ecall_srst;
|
||||
extern struct sbi_ecall_extension ecall_susp;
|
||||
|
||||
u16 sbi_ecall_version_major(void);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define SBI_EXT_RFENCE 0x52464E43
|
||||
#define SBI_EXT_HSM 0x48534D
|
||||
#define SBI_EXT_SRST 0x53525354
|
||||
#define SBI_EXT_SUSP 0x53555350
|
||||
|
||||
/* SBI function IDs for BASE extension*/
|
||||
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
|
||||
@@ -37,6 +38,9 @@
|
||||
#define SBI_EXT_BASE_GET_MVENDORID 0x4
|
||||
#define SBI_EXT_BASE_GET_MARCHID 0x5
|
||||
#define SBI_EXT_BASE_GET_MIMPID 0x6
|
||||
#define SBI_EXT_BASE_RESET_C906L 0x7
|
||||
#define SBI_EXT_BASE_RST_C906L 0x8
|
||||
#define SBI_EXT_BASE_UNRST_C906L 0x9
|
||||
|
||||
/* SBI function IDs for TIME extension*/
|
||||
#define SBI_EXT_TIME_SET_TIMER 0x0
|
||||
@@ -48,20 +52,37 @@
|
||||
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
|
||||
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
|
||||
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x3
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x4
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x5
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x6
|
||||
|
||||
/* SBI function IDs for HSM extension */
|
||||
#define SBI_EXT_HSM_HART_START 0x0
|
||||
#define SBI_EXT_HSM_HART_STOP 0x1
|
||||
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
|
||||
#define SBI_EXT_HSM_HART_SUSPEND 0x3
|
||||
|
||||
#define SBI_HSM_HART_STATUS_STARTED 0x0
|
||||
#define SBI_HSM_HART_STATUS_STOPPED 0x1
|
||||
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
|
||||
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
|
||||
#define SBI_HSM_STATE_STARTED 0x0
|
||||
#define SBI_HSM_STATE_STOPPED 0x1
|
||||
#define SBI_HSM_STATE_START_PENDING 0x2
|
||||
#define SBI_HSM_STATE_STOP_PENDING 0x3
|
||||
#define SBI_HSM_STATE_SUSPENDED 0x4
|
||||
#define SBI_HSM_STATE_SUSPEND_PENDING 0x5
|
||||
#define SBI_HSM_STATE_RESUME_PENDING 0x6
|
||||
|
||||
#define SBI_HSM_SUSP_BASE_MASK 0x7fffffff
|
||||
#define SBI_HSM_SUSP_NON_RET_BIT 0x80000000
|
||||
#define SBI_HSM_SUSP_PLAT_BASE 0x10000000
|
||||
|
||||
#define SBI_HSM_SUSPEND_RET_DEFAULT 0x00000000
|
||||
#define SBI_HSM_SUSPEND_RET_PLATFORM SBI_HSM_SUSP_PLAT_BASE
|
||||
#define SBI_HSM_SUSPEND_RET_LAST SBI_HSM_SUSP_BASE_MASK
|
||||
#define SBI_HSM_SUSPEND_NON_RET_DEFAULT SBI_HSM_SUSP_NON_RET_BIT
|
||||
#define SBI_HSM_SUSPEND_NON_RET_PLATFORM (SBI_HSM_SUSP_NON_RET_BIT | \
|
||||
SBI_HSM_SUSP_PLAT_BASE)
|
||||
#define SBI_HSM_SUSPEND_NON_RET_LAST (SBI_HSM_SUSP_NON_RET_BIT | \
|
||||
SBI_HSM_SUSP_BASE_MASK)
|
||||
|
||||
/* SBI function IDs for SRST extension */
|
||||
#define SBI_EXT_SRST_RESET 0x0
|
||||
@@ -91,6 +112,13 @@
|
||||
#define SBI_ERR_INVALID_ADDRESS -5
|
||||
#define SBI_ERR_ALREADY_AVAILABLE -6
|
||||
|
||||
/* SBI function IDs for SUSP extension */
|
||||
#define SBI_EXT_SUSP_SUSPEND 0x0
|
||||
|
||||
#define SBI_SUSP_SLEEP_TYPE_SUSPEND 0x0
|
||||
#define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND
|
||||
#define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000
|
||||
|
||||
#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
@@ -27,6 +27,7 @@ enum sbi_hart_features {
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
int sbi_hart_reinit(struct sbi_scratch *scratch);
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
extern void (*sbi_hart_expected_trap)(void);
|
||||
|
||||
@@ -12,16 +12,40 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/** Hart state values **/
|
||||
#define SBI_HART_STOPPED 0
|
||||
#define SBI_HART_STOPPING 1
|
||||
#define SBI_HART_STARTING 2
|
||||
#define SBI_HART_STARTED 3
|
||||
#define SBI_HART_UNKNOWN 4
|
||||
/** Hart state managment device */
|
||||
struct sbi_hsm_device {
|
||||
/** Name of the hart state managment device */
|
||||
char name[32];
|
||||
|
||||
/** Start (or power-up) the given hart */
|
||||
int (*hart_start)(u32 hartid, ulong saddr);
|
||||
|
||||
/**
|
||||
* Stop (or power-down) the current hart from running. This call
|
||||
* doesn't expect to return if success.
|
||||
*/
|
||||
int (*hart_stop)(void);
|
||||
|
||||
/**
|
||||
* Put the current hart in platform specific suspend (or low-power)
|
||||
* state.
|
||||
*
|
||||
* For successful retentive suspend, the call will return 0 when
|
||||
* the hart resumes normal execution.
|
||||
*
|
||||
* For successful non-retentive suspend, the hart will resume from
|
||||
* specified resume address
|
||||
*/
|
||||
int (*hart_suspend)(u32 suspend_type, ulong raddr);
|
||||
};
|
||||
|
||||
struct sbi_domain;
|
||||
struct sbi_scratch;
|
||||
|
||||
const struct sbi_hsm_device *sbi_hsm_get_device(void);
|
||||
|
||||
void sbi_hsm_set_device(const struct sbi_hsm_device *dev);
|
||||
|
||||
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
|
||||
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
|
||||
|
||||
@@ -29,10 +53,17 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||
const struct sbi_domain *dom,
|
||||
u32 hartid, ulong saddr, ulong smode, ulong priv);
|
||||
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
|
||||
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch);
|
||||
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch);
|
||||
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
|
||||
ulong raddr, ulong rmode, ulong priv);
|
||||
int sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
|
||||
long newstate);
|
||||
int __sbi_hsm_hart_get_state(u32 hartid);
|
||||
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
|
||||
int sbi_hsm_hart_state_to_status(int state);
|
||||
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
|
||||
ulong hbase, ulong *out_hmask);
|
||||
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
|
||||
ulong hbase, ulong *out_hmask);
|
||||
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch);
|
||||
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,18 @@
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/** IPI hardware device */
|
||||
struct sbi_ipi_device {
|
||||
/** Name of the IPI device */
|
||||
char name[32];
|
||||
|
||||
/** Send IPI to a target HART */
|
||||
void (*ipi_send)(u32 target_hart);
|
||||
|
||||
/** Clear IPI for a target HART */
|
||||
void (*ipi_clear)(u32 target_hart);
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
/** IPI event operations or callbacks */
|
||||
@@ -63,6 +75,12 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
|
||||
|
||||
void sbi_ipi_process(void);
|
||||
|
||||
void sbi_ipi_raw_send(u32 target_hart);
|
||||
|
||||
const struct sbi_ipi_device *sbi_ipi_get_device(void);
|
||||
|
||||
void sbi_ipi_set_device(const struct sbi_ipi_device *dev);
|
||||
|
||||
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
void sbi_ipi_exit(struct sbi_scratch *scratch);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
@@ -51,22 +51,16 @@ struct sbi_trap_regs;
|
||||
|
||||
/** Possible feature flags of a platform */
|
||||
enum sbi_platform_features {
|
||||
/** Platform has timer value */
|
||||
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
|
||||
/** Platform has HART hotplug support */
|
||||
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
|
||||
/** Platform has fault delegation support */
|
||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
|
||||
/** Platform has custom secondary hart booting support */
|
||||
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
|
||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 1),
|
||||
|
||||
/** Last index of Platform features*/
|
||||
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
|
||||
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_MFAULTS_DELEGATION,
|
||||
};
|
||||
|
||||
/** Default feature set for a platform */
|
||||
#define SBI_PLATFORM_DEFAULT_FEATURES \
|
||||
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
(SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
|
||||
/** Platform functions */
|
||||
struct sbi_platform_operations {
|
||||
@@ -92,15 +86,9 @@ struct sbi_platform_operations {
|
||||
*/
|
||||
int (*misa_get_xlen)(void);
|
||||
|
||||
/** Get platform specific root domain memory regions */
|
||||
struct sbi_domain_memregion *(*domains_root_regions)(void);
|
||||
/** Initialize (or populate) domains for the platform */
|
||||
int (*domains_init)(void);
|
||||
|
||||
/** Write a character to the platform console output */
|
||||
void (*console_putc)(char ch);
|
||||
/** Read a character from the platform console input */
|
||||
int (*console_getc)(void);
|
||||
/** Initialize the platform console */
|
||||
int (*console_init)(void);
|
||||
|
||||
@@ -109,10 +97,6 @@ struct sbi_platform_operations {
|
||||
/** Exit the platform interrupt controller for current HART */
|
||||
void (*irqchip_exit)(void);
|
||||
|
||||
/** Send IPI to a target HART */
|
||||
void (*ipi_send)(u32 target_hart);
|
||||
/** Clear IPI for a target HART */
|
||||
void (*ipi_clear)(u32 target_hart);
|
||||
/** Initialize IPI for current HART */
|
||||
int (*ipi_init)(bool cold_boot);
|
||||
/** Exit IPI for current HART */
|
||||
@@ -121,30 +105,11 @@ struct sbi_platform_operations {
|
||||
/** Get tlb flush limit value **/
|
||||
u64 (*get_tlbr_flush_limit)(void);
|
||||
|
||||
/** Get platform timer value */
|
||||
u64 (*timer_value)(void);
|
||||
/** Start platform timer event for current HART */
|
||||
void (*timer_event_start)(u64 next_event);
|
||||
/** Stop platform timer event for current HART */
|
||||
void (*timer_event_stop)(void);
|
||||
/** Initialize platform timer for current HART */
|
||||
int (*timer_init)(bool cold_boot);
|
||||
/** Exit platform timer for current HART */
|
||||
void (*timer_exit)(void);
|
||||
|
||||
/** Bringup the given hart */
|
||||
int (*hart_start)(u32 hartid, ulong saddr);
|
||||
/**
|
||||
* Stop the current hart from running. This call doesn't expect to
|
||||
* return if success.
|
||||
*/
|
||||
int (*hart_stop)(void);
|
||||
|
||||
/* Check whether reset type and reason supported by the platform */
|
||||
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
|
||||
/** Reset the platform */
|
||||
void (*system_reset)(u32 reset_type, u32 reset_reason);
|
||||
|
||||
/** platform specific SBI extension implementation probe function */
|
||||
int (*vendor_ext_check)(long extid);
|
||||
/** platform specific SBI extension implementation provider */
|
||||
@@ -211,18 +176,9 @@ struct sbi_platform {
|
||||
#define sbi_platform_ops(__p) \
|
||||
((const struct sbi_platform_operations *)(__p)->platform_ops_addr)
|
||||
|
||||
/** Check whether the platform supports timer value */
|
||||
#define sbi_platform_has_timer_value(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
|
||||
/** Check whether the platform supports HART hotplug */
|
||||
#define sbi_platform_has_hart_hotplug(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
|
||||
/** Check whether the platform supports fault delegation */
|
||||
#define sbi_platform_has_mfaults_delegation(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||
/** Check whether the platform supports custom secondary hart booting support */
|
||||
#define sbi_platform_has_hart_secondary_boot(__p) \
|
||||
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
|
||||
|
||||
/**
|
||||
* Get HART index for the given HART
|
||||
@@ -337,39 +293,6 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bringup a given hart from previous stage. Platform should implement this
|
||||
* operation if they support a custom mechanism to start a hart. Otherwise,
|
||||
* a generic WFI based approach will be used to start/stop a hart in OpenSBI.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param hartid HART id
|
||||
* @param saddr M-mode start physical address for the HART
|
||||
*
|
||||
* @return 0 if sucessful and negative error code on failure
|
||||
*/
|
||||
static inline int sbi_platform_hart_start(const struct sbi_platform *plat,
|
||||
u32 hartid, ulong saddr)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->hart_start)
|
||||
return sbi_platform_ops(plat)->hart_start(hartid, saddr);
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the current hart in OpenSBI.
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return Negative error code on failure. It doesn't return on success.
|
||||
*/
|
||||
static inline int sbi_platform_hart_stop(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->hart_stop)
|
||||
return sbi_platform_ops(plat)->hart_stop();
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Early initialization for current HART
|
||||
*
|
||||
@@ -454,22 +377,6 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform specific root domain memory regions
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return an array of memory regions terminated by a region with order zero
|
||||
* or NULL for no memory regions
|
||||
*/
|
||||
static inline struct sbi_domain_memregion *
|
||||
sbi_platform_domains_root_regions(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->domains_root_regions)
|
||||
return sbi_platform_ops(plat)->domains_root_regions();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize (or populate) domains for the platform
|
||||
*
|
||||
@@ -484,33 +391,6 @@ static inline int sbi_platform_domains_init(const struct sbi_platform *plat)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a character to the platform console output
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param ch character to write
|
||||
*/
|
||||
static inline void sbi_platform_console_putc(const struct sbi_platform *plat,
|
||||
char ch)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->console_putc)
|
||||
sbi_platform_ops(plat)->console_putc(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a character from the platform console input
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return character read from console input
|
||||
*/
|
||||
static inline int sbi_platform_console_getc(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->console_getc)
|
||||
return sbi_platform_ops(plat)->console_getc();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the platform console
|
||||
*
|
||||
@@ -552,32 +432,6 @@ static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
|
||||
sbi_platform_ops(plat)->irqchip_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send IPI to a target HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param target_hart HART ID of IPI target
|
||||
*/
|
||||
static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
|
||||
u32 target_hart)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->ipi_send)
|
||||
sbi_platform_ops(plat)->ipi_send(target_hart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear IPI for a target HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param target_hart HART ID of IPI target
|
||||
*/
|
||||
static inline void sbi_platform_ipi_clear(const struct sbi_platform *plat,
|
||||
u32 target_hart)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->ipi_clear)
|
||||
sbi_platform_ops(plat)->ipi_clear(target_hart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the platform IPI support for current HART
|
||||
*
|
||||
@@ -605,45 +459,6 @@ static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
|
||||
sbi_platform_ops(plat)->ipi_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get platform timer value
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*
|
||||
* @return 64-bit timer value
|
||||
*/
|
||||
static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->timer_value)
|
||||
return sbi_platform_ops(plat)->timer_value();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start platform timer event for current HART
|
||||
*
|
||||
* @param plat pointer to struct struct sbi_platform
|
||||
* @param next_event timer value when timer event will happen
|
||||
*/
|
||||
static inline void
|
||||
sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->timer_event_start)
|
||||
sbi_platform_ops(plat)->timer_event_start(next_event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop platform timer event for current HART
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
*/
|
||||
static inline void
|
||||
sbi_platform_timer_event_stop(const struct sbi_platform *plat)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->timer_event_stop)
|
||||
sbi_platform_ops(plat)->timer_event_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the platform timer for current HART
|
||||
*
|
||||
@@ -671,41 +486,6 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
|
||||
sbi_platform_ops(plat)->timer_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether reset type and reason supported by the platform
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param reset_type type of reset
|
||||
* @param reset_reason reason for reset
|
||||
*
|
||||
* @return 0 if reset type and reason not supported and 1 if supported
|
||||
*/
|
||||
static inline int sbi_platform_system_reset_check(
|
||||
const struct sbi_platform *plat,
|
||||
u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->system_reset_check)
|
||||
return sbi_platform_ops(plat)->system_reset_check(reset_type,
|
||||
reset_reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the platform
|
||||
*
|
||||
* This function will not return for supported reset type and reset reason
|
||||
*
|
||||
* @param plat pointer to struct sbi_platform
|
||||
* @param reset_type type of reset
|
||||
* @param reset_reason reason for reset
|
||||
*/
|
||||
static inline void sbi_platform_system_reset(const struct sbi_platform *plat,
|
||||
u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (plat && sbi_platform_ops(plat)->system_reset)
|
||||
sbi_platform_ops(plat)->system_reset(reset_type, reset_reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a vendor extension is implemented or not.
|
||||
*
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
|
||||
@@ -12,8 +12,50 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/** System reset hardware device */
|
||||
struct sbi_system_reset_device {
|
||||
/** Name of the system reset device */
|
||||
char name[32];
|
||||
|
||||
/* Check whether reset type and reason supported by the device */
|
||||
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
|
||||
|
||||
/** Reset the system */
|
||||
void (*system_reset)(u32 reset_type, u32 reset_reason);
|
||||
};
|
||||
|
||||
const struct sbi_system_reset_device *sbi_system_reset_get_device(void);
|
||||
|
||||
void sbi_system_reset_set_device(const struct sbi_system_reset_device *dev);
|
||||
|
||||
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);
|
||||
|
||||
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
|
||||
|
||||
/** System suspend device */
|
||||
struct sbi_system_suspend_device {
|
||||
/** Name of the system suspend device */
|
||||
char name[32];
|
||||
|
||||
/* Check whether sleep type is supported by the device */
|
||||
int (*system_suspend_check)(u32 sleep_type);
|
||||
|
||||
/**
|
||||
* Suspend the system
|
||||
*
|
||||
* @sleep_type: The sleep type identifier passed to the SBI call.
|
||||
* @mmode_resume_addr:
|
||||
* This is the same as sbi_scratch.warmboot_addr. Some platforms
|
||||
* may not be able to return from system_suspend(), so they will
|
||||
* jump directly to this address instead. Platforms which can
|
||||
* return from system_suspend() may ignore this parameter.
|
||||
*/
|
||||
int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr);
|
||||
};
|
||||
|
||||
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void);
|
||||
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev);
|
||||
bool sbi_system_suspend_supported(u32 sleep_type);
|
||||
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,21 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
/** Timer hardware device */
|
||||
struct sbi_timer_device {
|
||||
/** Name of the timer operations */
|
||||
char name[32];
|
||||
|
||||
/** Get free-running timer value */
|
||||
u64 (*timer_value)(void);
|
||||
|
||||
/** Start timer event for current HART */
|
||||
void (*timer_event_start)(u64 next_event);
|
||||
|
||||
/** Stop timer event for current HART */
|
||||
void (*timer_event_stop)(void);
|
||||
};
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
/** Get timer value for current HART */
|
||||
@@ -35,6 +50,12 @@ void sbi_timer_event_start(u64 next_event);
|
||||
/** Process timer event for current HART */
|
||||
void sbi_timer_process(void);
|
||||
|
||||
/** Get current timer device */
|
||||
const struct sbi_timer_device *sbi_timer_get_device(void);
|
||||
|
||||
/** Register timer device */
|
||||
void sbi_timer_set_device(const struct sbi_timer_device *dev);
|
||||
|
||||
/* Initialize timer */
|
||||
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
/** Size (in bytes) of sbi_trap_info */
|
||||
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
@@ -205,7 +205,7 @@ struct sbi_trap_info {
|
||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
struct sbi_trap_info *trap);
|
||||
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs);
|
||||
struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs);
|
||||
|
||||
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs);
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ typedef unsigned long physical_size_t;
|
||||
|
||||
#define __packed __attribute__((packed))
|
||||
#define __noreturn __attribute__((noreturn))
|
||||
#define __aligned(x) __attribute__((aligned(x)))
|
||||
|
||||
#define likely(x) __builtin_expect((x), 1)
|
||||
#define unlikely(x) __builtin_expect((x), 0)
|
||||
|
||||
@@ -30,9 +30,8 @@ void fdt_cpu_fixup(void *fdt);
|
||||
* It is recommended that platform codes call this helper in their final_init()
|
||||
*
|
||||
* @param fdt: device tree blob
|
||||
* @param compat: PLIC node compatible string
|
||||
*/
|
||||
void fdt_plic_fixup(void *fdt, const char *compat);
|
||||
void fdt_plic_fixup(void *fdt);
|
||||
|
||||
/**
|
||||
* Fix up the reserved memory node in the device tree
|
||||
|
||||
@@ -17,14 +17,8 @@ struct fdt_ipi {
|
||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
int (*warm_init)(void);
|
||||
void (*exit)(void);
|
||||
void (*send)(u32 target_hart);
|
||||
void (*clear)(u32 target_hart);
|
||||
};
|
||||
|
||||
void fdt_ipi_send(u32 target_hart);
|
||||
|
||||
void fdt_ipi_clear(u32 target_hart);
|
||||
|
||||
void fdt_ipi_exit(void);
|
||||
|
||||
int fdt_ipi_init(bool cold_boot);
|
||||
|
||||
@@ -15,14 +15,8 @@
|
||||
struct fdt_reset {
|
||||
const struct fdt_match *match_table;
|
||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
|
||||
void (*system_reset)(u32 reset_type, u32 reset_reason);
|
||||
};
|
||||
|
||||
int fdt_system_reset_check(u32 reset_type, u32 reset_reason);
|
||||
|
||||
void fdt_system_reset(u32 reset_type, u32 reset_reason);
|
||||
|
||||
int fdt_reset_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,14 +15,8 @@
|
||||
struct fdt_serial {
|
||||
const struct fdt_match *match_table;
|
||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
void (*putc)(char ch);
|
||||
int (*getc)(void);
|
||||
};
|
||||
|
||||
void fdt_serial_putc(char ch);
|
||||
|
||||
int fdt_serial_getc(void);
|
||||
|
||||
int fdt_serial_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void shakti_uart_putc(char ch);
|
||||
|
||||
int shakti_uart_getc(void);
|
||||
|
||||
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void sifive_uart_putc(char ch);
|
||||
|
||||
int sifive_uart_getc(void);
|
||||
|
||||
int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void uart8250_putc(char ch);
|
||||
|
||||
int uart8250_getc(void);
|
||||
|
||||
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
||||
u32 reg_width);
|
||||
|
||||
|
||||
@@ -29,20 +29,10 @@ struct clint_data {
|
||||
void (*time_wr)(u64 value, volatile u64 *addr);
|
||||
};
|
||||
|
||||
void clint_ipi_send(u32 target_hart);
|
||||
|
||||
void clint_ipi_clear(u32 target_hart);
|
||||
|
||||
int clint_warm_ipi_init(void);
|
||||
|
||||
int clint_cold_ipi_init(struct clint_data *clint);
|
||||
|
||||
u64 clint_timer_value(void);
|
||||
|
||||
void clint_timer_event_stop(void);
|
||||
|
||||
void clint_timer_event_start(u64 next_event);
|
||||
|
||||
int clint_warm_timer_init(void);
|
||||
|
||||
int clint_cold_timer_init(struct clint_data *clint,
|
||||
|
||||
@@ -10,12 +10,8 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
void htif_putc(char ch);
|
||||
int htif_serial_init(void);
|
||||
|
||||
int htif_getc(void);
|
||||
|
||||
int htif_system_reset_check(u32 type, u32 reason);
|
||||
|
||||
void htif_system_reset(u32 type, u32 reason);
|
||||
int htif_system_reset_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
|
||||
#include <sbi/sbi_types.h>
|
||||
|
||||
int sifive_test_system_reset_check(u32 type, u32 reason);
|
||||
|
||||
void sifive_test_system_reset(u32 type, u32 reason);
|
||||
|
||||
int sifive_test_init(unsigned long base);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,17 +17,8 @@ struct fdt_timer {
|
||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||
int (*warm_init)(void);
|
||||
void (*exit)(void);
|
||||
u64 (*value)(void);
|
||||
void (*event_stop)(void);
|
||||
void (*event_start)(u64 next_event);
|
||||
};
|
||||
|
||||
u64 fdt_timer_value(void);
|
||||
|
||||
void fdt_timer_event_stop(void);
|
||||
|
||||
void fdt_timer_event_start(u64 next_event);
|
||||
|
||||
void fdt_timer_exit(void);
|
||||
|
||||
int fdt_timer_init(bool cold_boot);
|
||||
|
||||
@@ -22,6 +22,7 @@ libsbi-objs-y += sbi_ecall_hsm.o
|
||||
libsbi-objs-y += sbi_ecall_legacy.o
|
||||
libsbi-objs-y += sbi_ecall_replace.o
|
||||
libsbi-objs-y += sbi_ecall_vendor.o
|
||||
libsbi-objs-y += sbi_ecall_susp.o
|
||||
libsbi-objs-y += sbi_emulate_csr.o
|
||||
libsbi-objs-y += sbi_fifo.o
|
||||
libsbi-objs-y += sbi_hart.o
|
||||
|
||||
@@ -28,25 +28,23 @@ void atomic_write(atomic_t *atom, long value)
|
||||
long atomic_add_return(atomic_t *atom, long value)
|
||||
{
|
||||
long ret;
|
||||
|
||||
#if __SIZEOF_LONG__ == 4
|
||||
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
|
||||
: "+A"(atom->counter), "=r"(ret)
|
||||
: "r"(value)
|
||||
: "memory");
|
||||
|
||||
#elif __SIZEOF_LONG__ == 8
|
||||
__asm__ __volatile__(" amoadd.d.aqrl %1, %2, %0"
|
||||
: "+A"(atom->counter), "=r"(ret)
|
||||
: "r"(value)
|
||||
: "memory");
|
||||
#endif
|
||||
return ret + value;
|
||||
}
|
||||
|
||||
long atomic_sub_return(atomic_t *atom, long value)
|
||||
{
|
||||
long ret;
|
||||
|
||||
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
|
||||
: "+A"(atom->counter), "=r"(ret)
|
||||
: "r"(-value)
|
||||
: "memory");
|
||||
|
||||
return ret - value;
|
||||
return atomic_add_return(atom, -value);
|
||||
}
|
||||
|
||||
#define __axchg(ptr, new, size) \
|
||||
|
||||
@@ -2,44 +2,76 @@
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_barrier.h>
|
||||
#include <sbi/riscv_locks.h>
|
||||
|
||||
int spin_lock_check(spinlock_t *lock)
|
||||
static inline int spin_lock_unlocked(spinlock_t lock)
|
||||
{
|
||||
return (lock->lock == __RISCV_SPIN_UNLOCKED) ? 0 : 1;
|
||||
return lock.owner == lock.next;
|
||||
}
|
||||
|
||||
bool spin_lock_check(spinlock_t *lock)
|
||||
{
|
||||
RISCV_FENCE(r, rw);
|
||||
return !spin_lock_unlocked(*lock);
|
||||
}
|
||||
|
||||
int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
int tmp = 1, busy;
|
||||
unsigned long inc = 1u << TICKET_SHIFT;
|
||||
unsigned long mask = 0xffffu << TICKET_SHIFT;
|
||||
u32 l0, tmp1, tmp2;
|
||||
|
||||
__asm__ __volatile__(
|
||||
" amoswap.w %0, %2, %1\n" RISCV_ACQUIRE_BARRIER
|
||||
: "=r"(busy), "+A"(lock->lock)
|
||||
: "r"(tmp)
|
||||
/* Get the current lock counters. */
|
||||
"1: lr.w.aq %0, %3\n"
|
||||
" slli %2, %0, %6\n"
|
||||
" and %2, %2, %5\n"
|
||||
" and %1, %0, %5\n"
|
||||
/* Is the lock free right now? */
|
||||
" bne %1, %2, 2f\n"
|
||||
" add %0, %0, %4\n"
|
||||
/* Acquire the lock. */
|
||||
" sc.w.rl %0, %0, %3\n"
|
||||
" bnez %0, 1b\n"
|
||||
"2:"
|
||||
: "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
|
||||
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
|
||||
: "memory");
|
||||
|
||||
return !busy;
|
||||
return !l0;
|
||||
}
|
||||
|
||||
void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (1) {
|
||||
if (spin_lock_check(lock))
|
||||
continue;
|
||||
unsigned long inc = 1u << TICKET_SHIFT;
|
||||
unsigned long mask = 0xffffu;
|
||||
u32 l0, tmp1, tmp2;
|
||||
|
||||
if (spin_trylock(lock))
|
||||
break;
|
||||
}
|
||||
__asm__ __volatile__(
|
||||
/* Atomically increment the next ticket. */
|
||||
" amoadd.w.aqrl %0, %4, %3\n"
|
||||
|
||||
/* Did we get the lock? */
|
||||
" srli %1, %0, %6\n"
|
||||
" and %1, %1, %5\n"
|
||||
"1: and %2, %0, %5\n"
|
||||
" beq %1, %2, 2f\n"
|
||||
|
||||
/* If not, then spin on the lock. */
|
||||
" lw %0, %3\n"
|
||||
RISCV_ACQUIRE_BARRIER
|
||||
" j 1b\n"
|
||||
"2:"
|
||||
: "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
|
||||
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
__smp_store_release(&lock->lock, __RISCV_SPIN_UNLOCKED);
|
||||
__smp_store_release(&lock->owner, lock->owner + 1);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
|
||||
static const struct sbi_platform *console_plat = NULL;
|
||||
static const struct sbi_console_device *console_dev = NULL;
|
||||
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
|
||||
|
||||
bool sbi_isprintable(char c)
|
||||
@@ -26,14 +26,18 @@ bool sbi_isprintable(char c)
|
||||
|
||||
int sbi_getc(void)
|
||||
{
|
||||
return sbi_platform_console_getc(console_plat);
|
||||
if (console_dev && console_dev->console_getc)
|
||||
return console_dev->console_getc();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void sbi_putc(char ch)
|
||||
{
|
||||
if (ch == '\n')
|
||||
sbi_platform_console_putc(console_plat, '\r');
|
||||
sbi_platform_console_putc(console_plat, ch);
|
||||
if (console_dev && console_dev->console_putc) {
|
||||
if (ch == '\n')
|
||||
console_dev->console_putc('\r');
|
||||
console_dev->console_putc(ch);
|
||||
}
|
||||
}
|
||||
|
||||
void sbi_puts(const char *str)
|
||||
@@ -390,9 +394,20 @@ int sbi_dprintf(const char *format, ...)
|
||||
return retval;
|
||||
}
|
||||
|
||||
const struct sbi_console_device *sbi_console_get_device(void)
|
||||
{
|
||||
return console_dev;
|
||||
}
|
||||
|
||||
void sbi_console_set_device(const struct sbi_console_device *dev)
|
||||
{
|
||||
if (!dev || console_dev)
|
||||
return;
|
||||
|
||||
console_dev = dev;
|
||||
}
|
||||
|
||||
int sbi_console_init(struct sbi_scratch *scratch)
|
||||
{
|
||||
console_plat = sbi_platform_ptr(scratch);
|
||||
|
||||
return sbi_platform_console_init(console_plat);
|
||||
return sbi_platform_console_init(sbi_platform_ptr(scratch));
|
||||
}
|
||||
|
||||
@@ -19,21 +19,22 @@
|
||||
|
||||
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
|
||||
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX] = { 0 };
|
||||
|
||||
static u32 domain_count = 0;
|
||||
static bool domain_finalized = false;
|
||||
|
||||
static struct sbi_hartmask root_hmask = { 0 };
|
||||
|
||||
#define ROOT_FW_REGION 0
|
||||
#define ROOT_ALL_REGION 1
|
||||
#define ROOT_END_REGION 2
|
||||
static struct sbi_domain_memregion root_memregs[ROOT_END_REGION + 1] = { 0 };
|
||||
#define ROOT_REGION_MAX 16
|
||||
static u32 root_memregs_count = 0;
|
||||
static struct sbi_domain_memregion root_fw_region;
|
||||
static struct sbi_domain_memregion root_memregs[ROOT_REGION_MAX + 1] = { 0 };
|
||||
|
||||
static struct sbi_domain root = {
|
||||
struct sbi_domain root = {
|
||||
.name = "root",
|
||||
.possible_harts = &root_hmask,
|
||||
.regions = root_memregs,
|
||||
.system_reset_allowed = TRUE,
|
||||
.system_suspend_allowed = TRUE,
|
||||
};
|
||||
|
||||
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
|
||||
@@ -64,12 +65,41 @@ ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg)
|
||||
static void domain_memregion_initfw(struct sbi_domain_memregion *reg)
|
||||
{
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
sbi_memcpy(reg, &root_memregs[ROOT_FW_REGION], sizeof(*reg));
|
||||
sbi_memcpy(reg, &root_fw_region, sizeof(*reg));
|
||||
}
|
||||
|
||||
void sbi_domain_memregion_init(unsigned long addr,
|
||||
unsigned long size,
|
||||
unsigned long flags,
|
||||
struct sbi_domain_memregion *reg)
|
||||
{
|
||||
unsigned long base = 0, order;
|
||||
|
||||
for (order = log2roundup(size) ; order <= __riscv_xlen; order++) {
|
||||
if (order < __riscv_xlen) {
|
||||
base = addr & ~((1UL << order) - 1UL);
|
||||
if ((base <= addr) &&
|
||||
(addr < (base + (1UL << order))) &&
|
||||
(base <= (addr + size - 1UL)) &&
|
||||
((addr + size - 1UL) < (base + (1UL << order))))
|
||||
break;
|
||||
} else {
|
||||
base = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (reg) {
|
||||
reg->base = base;
|
||||
reg->order = order;
|
||||
reg->flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
||||
@@ -207,9 +237,9 @@ static int sanitize_domain(const struct sbi_platform *plat,
|
||||
count = 0;
|
||||
have_fw_reg = FALSE;
|
||||
sbi_domain_for_each_memregion(dom, reg) {
|
||||
if (reg->order == root_memregs[ROOT_FW_REGION].order &&
|
||||
reg->base == root_memregs[ROOT_FW_REGION].base &&
|
||||
reg->flags == root_memregs[ROOT_FW_REGION].flags)
|
||||
if (reg->order == root_fw_region.order &&
|
||||
reg->base == root_fw_region.base &&
|
||||
reg->flags == root_fw_region.flags)
|
||||
have_fw_reg = TRUE;
|
||||
count++;
|
||||
}
|
||||
@@ -354,6 +384,8 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
|
||||
|
||||
sbi_printf("Domain%d SysReset %s: %s\n",
|
||||
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
|
||||
sbi_printf("Domain%d SysSuspend %s: %s\n",
|
||||
dom->index, suffix, (dom->system_suspend_allowed) ? "yes" : "no");
|
||||
}
|
||||
|
||||
void sbi_domain_dump_all(const char *suffix)
|
||||
@@ -376,7 +408,8 @@ int sbi_domain_register(struct sbi_domain *dom,
|
||||
u32 cold_hartid = current_hartid();
|
||||
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
|
||||
|
||||
if (!dom || !assign_mask)
|
||||
/* Sanity checks */
|
||||
if (!dom || !assign_mask || domain_finalized)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Check if domain already discovered */
|
||||
@@ -438,6 +471,67 @@ int sbi_domain_register(struct sbi_domain *dom,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
|
||||
{
|
||||
int rc;
|
||||
bool reg_merged;
|
||||
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
|
||||
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
|
||||
|
||||
/* Sanity checks */
|
||||
if (!reg || domain_finalized ||
|
||||
(root.regions != root_memregs) ||
|
||||
(ROOT_REGION_MAX <= root_memregs_count))
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Check for conflicts */
|
||||
sbi_domain_for_each_memregion(&root, nreg) {
|
||||
if (is_region_conflict(reg, nreg))
|
||||
return SBI_EINVAL;
|
||||
}
|
||||
|
||||
/* Append the memregion to root memregions */
|
||||
nreg = &root_memregs[root_memregs_count];
|
||||
sbi_memcpy(nreg, reg, sizeof(*reg));
|
||||
root_memregs_count++;
|
||||
root_memregs[root_memregs_count].order = 0;
|
||||
|
||||
/* Sort and optimize root regions */
|
||||
do {
|
||||
/* Sanitize the root domain so that memregions are sorted */
|
||||
rc = sanitize_domain(plat, &root);
|
||||
if (rc) {
|
||||
sbi_printf("%s: sanity checks failed for"
|
||||
" %s (error %d)\n", __func__,
|
||||
root.name, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Merge consecutive memregions with same order and flags */
|
||||
reg_merged = false;
|
||||
sbi_domain_for_each_memregion(&root, nreg) {
|
||||
nreg1 = nreg + 1;
|
||||
if (!nreg1->order)
|
||||
continue;
|
||||
|
||||
if ((nreg->base + BIT(nreg->order)) == nreg1->base &&
|
||||
nreg->order == nreg1->order &&
|
||||
nreg->flags == nreg1->flags) {
|
||||
nreg->order++;
|
||||
while (nreg1->order) {
|
||||
nreg2 = nreg1 + 1;
|
||||
sbi_memcpy(nreg1, nreg2, sizeof(*nreg1));
|
||||
nreg1++;
|
||||
}
|
||||
reg_merged = true;
|
||||
root_memregs_count--;
|
||||
}
|
||||
}
|
||||
} while (reg_merged);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||
{
|
||||
int rc;
|
||||
@@ -490,35 +584,34 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the finalized flag so that the root domain
|
||||
* regions can't be changed.
|
||||
*/
|
||||
domain_finalized = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||
{
|
||||
u32 i;
|
||||
struct sbi_domain_memregion *memregs;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Root domain firmware memory region */
|
||||
root_memregs[ROOT_FW_REGION].order = log2roundup(scratch->fw_size);
|
||||
root_memregs[ROOT_FW_REGION].base = scratch->fw_start &
|
||||
~((1UL << root_memregs[0].order) - 1UL);
|
||||
root_memregs[ROOT_FW_REGION].flags = 0;
|
||||
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, 0,
|
||||
&root_fw_region);
|
||||
domain_memregion_initfw(&root_memregs[root_memregs_count++]);
|
||||
|
||||
/* Root domain allow everything memory region */
|
||||
root_memregs[ROOT_ALL_REGION].order = __riscv_xlen;
|
||||
root_memregs[ROOT_ALL_REGION].base = 0;
|
||||
root_memregs[ROOT_ALL_REGION].flags = (SBI_DOMAIN_MEMREGION_READABLE |
|
||||
SBI_DOMAIN_MEMREGION_WRITEABLE |
|
||||
SBI_DOMAIN_MEMREGION_EXECUTABLE);
|
||||
sbi_domain_memregion_init(0, ~0UL,
|
||||
(SBI_DOMAIN_MEMREGION_READABLE |
|
||||
SBI_DOMAIN_MEMREGION_WRITEABLE |
|
||||
SBI_DOMAIN_MEMREGION_EXECUTABLE),
|
||||
&root_memregs[root_memregs_count++]);
|
||||
|
||||
/* Root domain memory region end */
|
||||
root_memregs[ROOT_END_REGION].order = 0;
|
||||
|
||||
/* Use platform specific root memory regions when available */
|
||||
memregs = sbi_platform_domains_root_regions(plat);
|
||||
if (memregs)
|
||||
root.regions = memregs;
|
||||
root_memregs[root_memregs_count].order = 0;
|
||||
|
||||
/* Root domain boot HART id is same as coldboot HART id */
|
||||
root.boot_hartid = cold_hartid;
|
||||
|
||||
@@ -168,6 +168,9 @@ int sbi_ecall_init(void)
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_vendor);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = sbi_ecall_register_extension(&ecall_susp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_version.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_io.h>
|
||||
|
||||
static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
|
||||
{
|
||||
@@ -32,6 +33,41 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SEC_SYS_BASE (0x020B0000)
|
||||
static int sbi_ecall_base_rst_c906l(void)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = readl((void *)0x3003024);
|
||||
writel((value & (~(1 << 6))), (void *)0x3003024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_base_unrst_c906l(const unsigned long address)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = readl((void *)SEC_SYS_BASE + 0x04);
|
||||
writel((value | (1 << 13)), (void *)SEC_SYS_BASE + 0x04);
|
||||
writel(address, (void *)SEC_SYS_BASE + 0x20);
|
||||
writel((address >> 32), (void *)SEC_SYS_BASE + 0x24);
|
||||
|
||||
value = readl((void *)0x3003024);
|
||||
writel((value | (1 << 6)), (void *)0x3003024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_base_reset_c906l(const unsigned long address)
|
||||
{
|
||||
sbi_ecall_base_rst_c906l();
|
||||
|
||||
sbi_ecall_base_unrst_c906l(address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
@@ -65,6 +101,16 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
|
||||
case SBI_EXT_BASE_PROBE_EXT:
|
||||
ret = sbi_ecall_base_probe(regs->a0, out_val);
|
||||
break;
|
||||
case SBI_EXT_BASE_RESET_C906L:
|
||||
ret = sbi_ecall_base_reset_c906l(regs->a0);
|
||||
*out_val = regs->a0;
|
||||
break;
|
||||
case SBI_EXT_BASE_RST_C906L:
|
||||
ret = sbi_ecall_base_rst_c906l();
|
||||
break;
|
||||
case SBI_EXT_BASE_UNRST_C906L:
|
||||
ret = sbi_ecall_base_unrst_c906l(regs->a0);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
@@ -22,14 +22,13 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
ulong smode;
|
||||
int ret = 0, hstate;
|
||||
int ret = 0;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >>
|
||||
MSTATUS_MPP_SHIFT;
|
||||
|
||||
switch (funcid) {
|
||||
case SBI_EXT_HSM_HART_START:
|
||||
smode = csr_read(CSR_MSTATUS);
|
||||
smode = (smode & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
ret = sbi_hsm_hart_start(scratch, sbi_domain_thishart_ptr(),
|
||||
regs->a0, regs->a1, smode, regs->a2);
|
||||
break;
|
||||
@@ -37,9 +36,12 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
|
||||
ret = sbi_hsm_hart_stop(scratch, TRUE);
|
||||
break;
|
||||
case SBI_EXT_HSM_HART_GET_STATUS:
|
||||
hstate = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
|
||||
regs->a0);
|
||||
ret = sbi_hsm_hart_state_to_status(hstate);
|
||||
ret = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
|
||||
regs->a0);
|
||||
break;
|
||||
case SBI_EXT_HSM_HART_SUSPEND:
|
||||
ret = sbi_hsm_hart_suspend(scratch, regs->a0, regs->a1,
|
||||
smode, regs->a2);
|
||||
break;
|
||||
default:
|
||||
ret = SBI_ENOTSUPP;
|
||||
|
||||
@@ -34,8 +34,8 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
|
||||
if (uptrap->cause)
|
||||
return SBI_ETRAP;
|
||||
} else {
|
||||
sbi_hsm_hart_started_mask(sbi_domain_thishart_ptr(),
|
||||
0, &mask);
|
||||
sbi_hsm_hart_interruptible_mask(sbi_domain_thishart_ptr(),
|
||||
0, &mask);
|
||||
}
|
||||
*hmask = mask;
|
||||
|
||||
|
||||
60
lib/sbi/sbi_ecall_susp.c
Normal file
60
lib/sbi/sbi_ecall_susp.c
Normal file
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
#include <sbi/sbi_ecall.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
|
||||
static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
|
||||
const struct sbi_trap_regs *regs,
|
||||
unsigned long *out_val,
|
||||
struct sbi_trap_info *out_trap)
|
||||
{
|
||||
int ret = SBI_ENOTSUPP;
|
||||
|
||||
if (funcid == SBI_EXT_SUSP_SUSPEND)
|
||||
ret = sbi_system_suspend(regs->a0, regs->a1, regs->a2);
|
||||
|
||||
if (ret >= 0) {
|
||||
*out_val = ret;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool susp_available(void)
|
||||
{
|
||||
u32 type;
|
||||
|
||||
/*
|
||||
* At least one suspend type should be supported by the
|
||||
* platform for the SBI SUSP extension to be usable.
|
||||
*/
|
||||
for (type = 0; type <= SBI_SUSP_SLEEP_TYPE_LAST; type++) {
|
||||
if (sbi_system_suspend_supported(type))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_susp;
|
||||
|
||||
static int sbi_ecall_susp_register_extensions(unsigned long extid, unsigned long *out_val)
|
||||
{
|
||||
if (!susp_available()) {
|
||||
*out_val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_val = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sbi_ecall_extension ecall_susp = {
|
||||
.extid_start = SBI_EXT_SUSP,
|
||||
.extid_end = SBI_EXT_SUSP,
|
||||
.probe = sbi_ecall_susp_register_extensions,
|
||||
.handle = sbi_ecall_susp_handler,
|
||||
};
|
||||
@@ -21,14 +21,23 @@
|
||||
static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
|
||||
{
|
||||
ulong cen = -1UL;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
if (prev_mode <= PRV_S) {
|
||||
cen &= csr_read(CSR_MCOUNTEREN);
|
||||
if (virt)
|
||||
cen &= csr_read(CSR_HCOUNTEREN);
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN)) {
|
||||
cen &= csr_read(CSR_MCOUNTEREN);
|
||||
if (virt)
|
||||
cen &= csr_read(CSR_HCOUNTEREN);
|
||||
} else {
|
||||
cen = 0;
|
||||
}
|
||||
}
|
||||
if (prev_mode == PRV_U) {
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
|
||||
cen &= csr_read(CSR_SCOUNTEREN);
|
||||
else
|
||||
cen = 0;
|
||||
}
|
||||
if (prev_mode == PRV_U)
|
||||
cen &= csr_read(CSR_SCOUNTEREN);
|
||||
|
||||
return ((cen >> hpm_num) & 1) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
|
||||
fifo->queue = queue_mem;
|
||||
fifo->num_entries = entries;
|
||||
fifo->entry_size = entry_size;
|
||||
SPIN_LOCK_INIT(&fifo->qlock);
|
||||
SPIN_LOCK_INIT(fifo->qlock);
|
||||
fifo->avail = fifo->tail = 0;
|
||||
sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
|
||||
}
|
||||
|
||||
@@ -406,7 +406,6 @@ __mhpm_skip:
|
||||
#undef __check_csr
|
||||
|
||||
/* Detect if hart supports SCOUNTEREN feature */
|
||||
trap.cause = 0;
|
||||
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
|
||||
if (!trap.cause) {
|
||||
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
|
||||
@@ -415,7 +414,6 @@ __mhpm_skip:
|
||||
}
|
||||
|
||||
/* Detect if hart supports MCOUNTEREN feature */
|
||||
trap.cause = 0;
|
||||
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
|
||||
if (!trap.cause) {
|
||||
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
|
||||
@@ -424,16 +422,30 @@ __mhpm_skip:
|
||||
}
|
||||
|
||||
/* Detect if hart supports time CSR */
|
||||
trap.cause = 0;
|
||||
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
|
||||
if (!trap.cause)
|
||||
hfeatures->features |= SBI_HART_HAS_TIME;
|
||||
}
|
||||
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
int sbi_hart_reinit(struct sbi_scratch *scratch)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mstatus_init(scratch);
|
||||
|
||||
rc = fp_init(scratch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = delegate_traps(scratch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
{
|
||||
if (cold_boot) {
|
||||
if (misa_extension('H'))
|
||||
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
|
||||
@@ -447,17 +459,7 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
|
||||
hart_detect_features(scratch);
|
||||
|
||||
mstatus_init(scratch);
|
||||
|
||||
rc = fp_init(scratch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = delegate_traps(scratch);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
return sbi_hart_reinit(scratch);
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) sbi_hart_hang(void)
|
||||
|
||||
@@ -21,50 +21,47 @@
|
||||
#include <sbi/sbi_hsm.h>
|
||||
#include <sbi/sbi_init.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
|
||||
static const struct sbi_hsm_device *hsm_dev = NULL;
|
||||
static unsigned long hart_data_offset;
|
||||
|
||||
/** Per hart specific data to manage state transition **/
|
||||
struct sbi_hsm_data {
|
||||
atomic_t state;
|
||||
unsigned long suspend_type;
|
||||
unsigned long saved_mie;
|
||||
unsigned long saved_mip;
|
||||
};
|
||||
#define __sbi_hsm_hart_change_state(hdata, oldstate, newstate) \
|
||||
({ \
|
||||
long state = atomic_cmpxchg(&(hdata)->state, oldstate, newstate); \
|
||||
if (state != (oldstate)) \
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%lu]\n", \
|
||||
__func__, state); \
|
||||
state == (oldstate); \
|
||||
})
|
||||
|
||||
int sbi_hsm_hart_state_to_status(int state)
|
||||
int sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
|
||||
long newstate)
|
||||
{
|
||||
int ret;
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
switch (state) {
|
||||
case SBI_HART_STOPPED:
|
||||
ret = SBI_HSM_HART_STATUS_STOPPED;
|
||||
break;
|
||||
case SBI_HART_STOPPING:
|
||||
ret = SBI_HSM_HART_STATUS_STOP_PENDING;
|
||||
break;
|
||||
case SBI_HART_STARTING:
|
||||
ret = SBI_HSM_HART_STATUS_START_PENDING;
|
||||
break;
|
||||
case SBI_HART_STARTED:
|
||||
ret = SBI_HSM_HART_STATUS_STARTED;
|
||||
break;
|
||||
default:
|
||||
ret = SBI_EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return __sbi_hsm_hart_change_state(hdata, oldstate, newstate);
|
||||
}
|
||||
|
||||
static inline int __sbi_hsm_hart_get_state(u32 hartid)
|
||||
int __sbi_hsm_hart_get_state(u32 hartid)
|
||||
{
|
||||
struct sbi_hsm_data *hdata;
|
||||
struct sbi_scratch *scratch;
|
||||
|
||||
scratch = sbi_hartid_to_scratch(hartid);
|
||||
if (!scratch)
|
||||
return SBI_HART_UNKNOWN;
|
||||
return SBI_EINVAL;
|
||||
|
||||
hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
|
||||
return atomic_read(&hdata->state);
|
||||
@@ -73,19 +70,11 @@ static inline int __sbi_hsm_hart_get_state(u32 hartid)
|
||||
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid)
|
||||
{
|
||||
if (!sbi_domain_is_assigned_hart(dom, hartid))
|
||||
return SBI_HART_UNKNOWN;
|
||||
return SBI_EINVAL;
|
||||
|
||||
return __sbi_hsm_hart_get_state(hartid);
|
||||
}
|
||||
|
||||
static bool sbi_hsm_hart_started(const struct sbi_domain *dom, u32 hartid)
|
||||
{
|
||||
if (sbi_hsm_hart_get_state(dom, hartid) == SBI_HART_STARTED)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ulong HART mask for given HART base ID
|
||||
* @param dom the domain to be used for output HART mask
|
||||
@@ -94,9 +83,10 @@ static bool sbi_hsm_hart_started(const struct sbi_domain *dom, u32 hartid)
|
||||
* @return 0 on success and SBI_Exxx (< 0) on failure
|
||||
* Note: the output HART mask will be set to zero on failure as well.
|
||||
*/
|
||||
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
|
||||
ulong hbase, ulong *out_hmask)
|
||||
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
|
||||
ulong hbase, ulong *out_hmask)
|
||||
{
|
||||
int hstate;
|
||||
ulong i, hmask, dmask;
|
||||
ulong hend = sbi_scratch_last_hartid() + 1;
|
||||
|
||||
@@ -109,9 +99,12 @@ int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
|
||||
dmask = sbi_domain_get_assigned_hartmask(dom, hbase);
|
||||
for (i = hbase; i < hend; i++) {
|
||||
hmask = 1UL << (i - hbase);
|
||||
if ((dmask & hmask) &&
|
||||
(__sbi_hsm_hart_get_state(i) == SBI_HART_STARTED))
|
||||
*out_hmask |= hmask;
|
||||
if (dmask & hmask) {
|
||||
hstate = __sbi_hsm_hart_get_state(i);
|
||||
if (hstate == SBI_HSM_STATE_STARTED ||
|
||||
hstate == SBI_HSM_STATE_SUSPENDED)
|
||||
*out_hmask |= hmask;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -123,16 +116,15 @@ void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid)
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTING,
|
||||
SBI_HART_STARTED);
|
||||
if (oldstate != SBI_HART_STARTING)
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_START_PENDING,
|
||||
SBI_HSM_STATE_STARTED);
|
||||
if (oldstate != SBI_HSM_STATE_START_PENDING)
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
unsigned long saved_mie;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
/* Save MIE CSR */
|
||||
@@ -142,15 +134,65 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
|
||||
csr_set(CSR_MIE, MIP_MSIP);
|
||||
|
||||
/* Wait for hart_add call*/
|
||||
while (atomic_read(&hdata->state) != SBI_HART_STARTING) {
|
||||
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
|
||||
wfi();
|
||||
};
|
||||
|
||||
/* Restore MIE CSR */
|
||||
csr_write(CSR_MIE, saved_mie);
|
||||
|
||||
/* Clear current HART IPI */
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
/*
|
||||
* No need to clear IPI here because the sbi_ipi_init() will
|
||||
* clear it for current HART via sbi_platform_ipi_init().
|
||||
*/
|
||||
}
|
||||
|
||||
const struct sbi_hsm_device *sbi_hsm_get_device(void)
|
||||
{
|
||||
return hsm_dev;
|
||||
}
|
||||
|
||||
void sbi_hsm_set_device(const struct sbi_hsm_device *dev)
|
||||
{
|
||||
if (!dev || hsm_dev)
|
||||
return;
|
||||
|
||||
hsm_dev = dev;
|
||||
}
|
||||
|
||||
static bool hsm_device_has_hart_hotplug(void)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_start && hsm_dev->hart_stop)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hsm_device_has_hart_secondary_boot(void)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_start && !hsm_dev->hart_stop)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int hsm_device_hart_start(u32 hartid, ulong saddr)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_start)
|
||||
return hsm_dev->hart_start(hartid, saddr);
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
static int hsm_device_hart_stop(void)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_stop)
|
||||
return hsm_dev->hart_stop();
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
static int hsm_device_hart_suspend(u32 suspend_type, ulong raddr)
|
||||
{
|
||||
if (hsm_dev && hsm_dev->hart_suspend)
|
||||
return hsm_dev->hart_suspend(suspend_type, raddr);
|
||||
return SBI_ENOTSUPP;
|
||||
}
|
||||
|
||||
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
@@ -174,7 +216,9 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
hdata = sbi_scratch_offset_ptr(rscratch,
|
||||
hart_data_offset);
|
||||
ATOMIC_INIT(&hdata->state,
|
||||
(i == hartid) ? SBI_HART_STARTING : SBI_HART_STOPPED);
|
||||
(i == hartid) ?
|
||||
SBI_HSM_STATE_START_PENDING :
|
||||
SBI_HSM_STATE_STOPPED);
|
||||
}
|
||||
} else {
|
||||
sbi_hsm_hart_wait(scratch, hartid);
|
||||
@@ -186,18 +230,17 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
u32 hstate;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
|
||||
|
||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPING,
|
||||
SBI_HART_STOPPED);
|
||||
if (hstate != SBI_HART_STOPPING)
|
||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOP_PENDING,
|
||||
SBI_HSM_STATE_STOPPED);
|
||||
if (hstate != SBI_HSM_STATE_STOP_PENDING)
|
||||
goto fail_exit;
|
||||
|
||||
if (sbi_platform_has_hart_hotplug(plat)) {
|
||||
sbi_platform_hart_stop(plat);
|
||||
if (hsm_device_has_hart_hotplug()) {
|
||||
hsm_device_hart_stop();
|
||||
/* It should never reach here */
|
||||
goto fail_exit;
|
||||
}
|
||||
@@ -223,7 +266,6 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||
unsigned int hstate;
|
||||
struct sbi_scratch *rscratch;
|
||||
struct sbi_hsm_data *hdata;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* For now, we only allow start mode to be S-mode or U-mode. */
|
||||
if (smode != PRV_S && smode != PRV_U)
|
||||
@@ -232,22 +274,22 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||
return SBI_EINVAL;
|
||||
if (dom && !sbi_domain_check_addr(dom, saddr, smode,
|
||||
SBI_DOMAIN_EXECUTE))
|
||||
return SBI_EINVAL;
|
||||
return SBI_EINVALID_ADDR;
|
||||
|
||||
rscratch = sbi_hartid_to_scratch(hartid);
|
||||
if (!rscratch)
|
||||
return SBI_EINVAL;
|
||||
hdata = sbi_scratch_offset_ptr(rscratch, hart_data_offset);
|
||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
|
||||
SBI_HART_STARTING);
|
||||
if (hstate == SBI_HART_STARTED)
|
||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED,
|
||||
SBI_HSM_STATE_START_PENDING);
|
||||
if (hstate == SBI_HSM_STATE_STARTED)
|
||||
return SBI_EALREADY;
|
||||
|
||||
/**
|
||||
* if a hart is already transition to start or stop, another start call
|
||||
* is considered as invalid request.
|
||||
*/
|
||||
if (hstate != SBI_HART_STOPPED)
|
||||
if (hstate != SBI_HSM_STATE_STOPPED)
|
||||
return SBI_EINVAL;
|
||||
|
||||
init_count = sbi_init_count(hartid);
|
||||
@@ -255,12 +297,11 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||
rscratch->next_addr = saddr;
|
||||
rscratch->next_mode = smode;
|
||||
|
||||
if (sbi_platform_has_hart_hotplug(plat) ||
|
||||
(sbi_platform_has_hart_secondary_boot(plat) && !init_count)) {
|
||||
return sbi_platform_hart_start(plat, hartid,
|
||||
scratch->warmboot_addr);
|
||||
if (hsm_device_has_hart_hotplug() ||
|
||||
(hsm_device_has_hart_secondary_boot() && !init_count)) {
|
||||
return hsm_device_hart_start(hartid, scratch->warmboot_addr);
|
||||
} else {
|
||||
sbi_platform_ipi_send(plat, hartid);
|
||||
sbi_ipi_raw_send(hartid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -269,19 +310,19 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
||||
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
|
||||
{
|
||||
int oldstate;
|
||||
u32 hartid = current_hartid();
|
||||
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
if (!sbi_hsm_hart_started(sbi_domain_thishart_ptr(), hartid))
|
||||
return SBI_EINVAL;
|
||||
if (!dom)
|
||||
return SBI_EFAIL;
|
||||
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,
|
||||
SBI_HART_STOPPING);
|
||||
if (oldstate != SBI_HART_STARTED) {
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STARTED,
|
||||
SBI_HSM_STATE_STOP_PENDING);
|
||||
if (oldstate != SBI_HSM_STATE_STARTED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
return SBI_EDENIED;
|
||||
return SBI_EFAIL;
|
||||
}
|
||||
|
||||
if (exitnow)
|
||||
@@ -289,3 +330,181 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __sbi_hsm_suspend_ret_default(struct sbi_scratch *scratch)
|
||||
{
|
||||
/* Wait for interrupt */
|
||||
wfi();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
/*
|
||||
* We will be resuming in warm-boot path so the MIE and MIP CSRs
|
||||
* will be back to initial state. It is possible that HART has
|
||||
* configured timer event before going to suspend state so we
|
||||
* should save MIE and MIP CSRs and restore it after resuming.
|
||||
*
|
||||
* Further, the M-mode bits in MIP CSR are read-only and set by
|
||||
* external devices (such as interrupt controller) whereas all
|
||||
* VS-mode bits in MIP are read-only alias of bits in HVIP CSR.
|
||||
*
|
||||
* This means we should only save/restore S-mode bits of MIP CSR
|
||||
* such as MIP.SSIP and MIP.STIP.
|
||||
*/
|
||||
|
||||
hdata->saved_mie = csr_read(CSR_MIE);
|
||||
hdata->saved_mip = csr_read(CSR_MIP) & (MIP_SSIP | MIP_STIP);
|
||||
}
|
||||
|
||||
static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
|
||||
{
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
csr_write(CSR_MIE, hdata->saved_mie);
|
||||
csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
|
||||
}
|
||||
|
||||
static int __sbi_hsm_suspend_non_ret_default(struct sbi_scratch *scratch,
|
||||
ulong raddr)
|
||||
{
|
||||
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
|
||||
|
||||
/*
|
||||
* Save some of the M-mode CSRs which should be restored after
|
||||
* resuming from suspend state
|
||||
*/
|
||||
__sbi_hsm_suspend_non_ret_save(scratch);
|
||||
|
||||
/* Wait for interrupt */
|
||||
wfi();
|
||||
|
||||
/*
|
||||
* Directly jump to warm reboot to simulate resume from a
|
||||
* non-retentive suspend.
|
||||
*/
|
||||
jump_warmboot();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
|
||||
{
|
||||
int oldstate;
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
/* If current HART was SUSPENDED then set RESUME_PENDING state */
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_SUSPENDED,
|
||||
SBI_HSM_STATE_RESUME_PENDING);
|
||||
if (oldstate != SBI_HSM_STATE_SUSPENDED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
}
|
||||
|
||||
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
|
||||
{
|
||||
u32 oldstate;
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
/* If current HART was RESUME_PENDING then set STARTED state */
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_RESUME_PENDING,
|
||||
SBI_HSM_STATE_STARTED);
|
||||
if (oldstate != SBI_HSM_STATE_RESUME_PENDING) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore some of the M-mode CSRs which we are re-configured by
|
||||
* the warm-boot sequence.
|
||||
*/
|
||||
__sbi_hsm_suspend_non_ret_restore(scratch);
|
||||
}
|
||||
|
||||
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
|
||||
ulong raddr, ulong rmode, ulong priv)
|
||||
{
|
||||
int oldstate, ret;
|
||||
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
|
||||
hart_data_offset);
|
||||
|
||||
/* For now, we only allow suspend from S-mode or U-mode. */
|
||||
|
||||
/* Sanity check on domain assigned to current HART */
|
||||
if (!dom)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Sanity check on suspend type */
|
||||
if (SBI_HSM_SUSPEND_RET_DEFAULT < suspend_type &&
|
||||
suspend_type < SBI_HSM_SUSPEND_RET_PLATFORM)
|
||||
return SBI_EINVAL;
|
||||
if (SBI_HSM_SUSPEND_NON_RET_DEFAULT < suspend_type &&
|
||||
suspend_type < SBI_HSM_SUSPEND_NON_RET_PLATFORM)
|
||||
return SBI_EINVAL;
|
||||
|
||||
/* Additional sanity check for non-retentive suspend */
|
||||
if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT) {
|
||||
if (rmode != PRV_S && rmode != PRV_U)
|
||||
return SBI_EINVAL;
|
||||
if (dom && !sbi_domain_check_addr(dom, raddr, rmode,
|
||||
SBI_DOMAIN_EXECUTE))
|
||||
return SBI_EINVALID_ADDR;
|
||||
}
|
||||
|
||||
/* Save the resume address and resume mode */
|
||||
scratch->next_arg1 = priv;
|
||||
scratch->next_addr = raddr;
|
||||
scratch->next_mode = rmode;
|
||||
|
||||
/* Directly move from STARTED to SUSPENDED state */
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STARTED,
|
||||
SBI_HSM_STATE_SUSPENDED);
|
||||
if (oldstate != SBI_HSM_STATE_STARTED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
ret = SBI_EDENIED;
|
||||
goto fail_restore_state;
|
||||
}
|
||||
|
||||
/* Save the suspend type */
|
||||
hdata->suspend_type = suspend_type;
|
||||
|
||||
/* Try platform specific suspend */
|
||||
ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr);
|
||||
if (ret == SBI_ENOTSUPP) {
|
||||
/* Try generic implementation of default suspend types */
|
||||
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) {
|
||||
ret = __sbi_hsm_suspend_ret_default(scratch);
|
||||
} else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
|
||||
ret = __sbi_hsm_suspend_non_ret_default(scratch,
|
||||
scratch->warmboot_addr);
|
||||
}
|
||||
}
|
||||
|
||||
fail_restore_state:
|
||||
/*
|
||||
* We might have successfully resumed from retentive suspend
|
||||
* or suspend failed. In both cases, we restore state of hart.
|
||||
*/
|
||||
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_SUSPENDED,
|
||||
SBI_HSM_STATE_STARTED);
|
||||
if (oldstate != SBI_HSM_STATE_SUSPENDED) {
|
||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||
__func__, oldstate);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,12 @@ static void sbi_boot_print_banner(struct sbi_scratch *scratch)
|
||||
static void sbi_boot_print_general(struct sbi_scratch *scratch)
|
||||
{
|
||||
char str[128];
|
||||
const struct sbi_hsm_device *hdev;
|
||||
const struct sbi_ipi_device *idev;
|
||||
const struct sbi_timer_device *tdev;
|
||||
const struct sbi_console_device *cdev;
|
||||
const struct sbi_system_reset_device *srdev;
|
||||
const struct sbi_system_suspend_device *susp_dev;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
|
||||
@@ -65,6 +71,24 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
|
||||
sbi_printf("Platform Features : %s\n", str);
|
||||
sbi_printf("Platform HART Count : %u\n",
|
||||
sbi_platform_hart_count(plat));
|
||||
idev = sbi_ipi_get_device();
|
||||
sbi_printf("Platform IPI Device : %s\n",
|
||||
(idev) ? idev->name : "---");
|
||||
tdev = sbi_timer_get_device();
|
||||
sbi_printf("Platform Timer Device : %s\n",
|
||||
(tdev) ? tdev->name : "---");
|
||||
cdev = sbi_console_get_device();
|
||||
sbi_printf("Platform Console Device : %s\n",
|
||||
(cdev) ? cdev->name : "---");
|
||||
hdev = sbi_hsm_get_device();
|
||||
sbi_printf("Platform HSM Device : %s\n",
|
||||
(hdev) ? hdev->name : "---");
|
||||
srdev = sbi_system_reset_get_device();
|
||||
sbi_printf("Platform SysReset Device : %s\n",
|
||||
(srdev) ? srdev->name : "---");
|
||||
susp_dev = sbi_system_suspend_get_device();
|
||||
sbi_printf("Platform Suspend Device : %s\n",
|
||||
(susp_dev) ? susp_dev->name : "---");
|
||||
|
||||
/* Firmware details */
|
||||
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
|
||||
@@ -130,7 +154,6 @@ static unsigned long coldboot_done;
|
||||
static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
unsigned long saved_mie, cmip;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Save MIE CSR */
|
||||
saved_mie = csr_read(CSR_MIE);
|
||||
@@ -167,14 +190,18 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
/* Restore MIE CSR */
|
||||
csr_write(CSR_MIE, saved_mie);
|
||||
|
||||
/* Clear current HART IPI */
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
/*
|
||||
* The wait for coldboot is common for both warm startup and
|
||||
* warm resume path so clearing IPI here would result in losing
|
||||
* an IPI in warm resume path.
|
||||
*
|
||||
* Also, the sbi_platform_ipi_init() called from sbi_ipi_init()
|
||||
* will automatically clear IPI for current HART.
|
||||
*/
|
||||
}
|
||||
|
||||
static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
/* Mark coldboot done */
|
||||
__smp_store_release(&coldboot_done, 1);
|
||||
|
||||
@@ -185,7 +212,7 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
|
||||
for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
|
||||
if ((i != hartid) &&
|
||||
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
|
||||
sbi_platform_ipi_send(plat, i);
|
||||
sbi_ipi_raw_send(i);
|
||||
}
|
||||
|
||||
/* Release coldboot lock */
|
||||
@@ -198,7 +225,9 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int rc;
|
||||
unsigned long *init_count;
|
||||
#ifndef CONFIG_OPENSBI_FASTBOOT
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
#endif
|
||||
|
||||
/* Note: This has to be first thing in coldboot init sequence */
|
||||
rc = sbi_scratch_init(scratch);
|
||||
@@ -219,20 +248,25 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
#ifndef CONFIG_OPENSBI_FASTBOOT
|
||||
rc = sbi_platform_early_init(plat, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
#endif
|
||||
|
||||
rc = sbi_hart_init(scratch, TRUE);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
#ifndef CONFIG_OPENSBI_FASTBOOT
|
||||
rc = sbi_console_init(scratch);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
#endif
|
||||
|
||||
sbi_boot_print_banner(scratch);
|
||||
|
||||
#ifndef CONFIG_OPENSBI_FASTBOOT
|
||||
rc = sbi_platform_irqchip_init(plat, TRUE);
|
||||
if (rc) {
|
||||
sbi_printf("%s: platform irqchip init failed (error %d)\n",
|
||||
@@ -245,6 +279,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = sbi_tlb_init(scratch, TRUE);
|
||||
if (rc) {
|
||||
@@ -292,12 +327,14 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
* Note: Platform final initialization should be last so that
|
||||
* it sees correct domain assignment and PMP configuration.
|
||||
*/
|
||||
#ifndef CONFIG_OPENSBI_FASTBOOT
|
||||
rc = sbi_platform_final_init(plat, TRUE);
|
||||
if (rc) {
|
||||
sbi_printf("%s: platform final init failed (error %d)\n",
|
||||
__func__, rc);
|
||||
sbi_hart_hang();
|
||||
}
|
||||
#endif
|
||||
|
||||
sbi_boot_print_hart(scratch, hartid);
|
||||
|
||||
@@ -311,14 +348,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
scratch->next_mode, FALSE);
|
||||
}
|
||||
|
||||
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int rc;
|
||||
unsigned long *init_count;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
|
||||
wait_for_coldboot(scratch, hartid);
|
||||
|
||||
if (!init_count_offset)
|
||||
sbi_hart_hang();
|
||||
|
||||
@@ -362,6 +397,40 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
(*init_count)++;
|
||||
|
||||
sbi_hsm_prepare_next_jump(scratch, hartid);
|
||||
}
|
||||
|
||||
static void init_warm_resume(struct sbi_scratch *scratch)
|
||||
{
|
||||
int rc;
|
||||
|
||||
sbi_hsm_hart_resume_start(scratch);
|
||||
|
||||
rc = sbi_hart_reinit(scratch);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
rc = sbi_hart_pmp_configure(scratch);
|
||||
if (rc)
|
||||
sbi_hart_hang();
|
||||
|
||||
sbi_hsm_hart_resume_finish(scratch);
|
||||
}
|
||||
|
||||
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
|
||||
{
|
||||
int hstate;
|
||||
|
||||
wait_for_coldboot(scratch, hartid);
|
||||
|
||||
hstate = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(), hartid);
|
||||
if (hstate < 0)
|
||||
sbi_hart_hang();
|
||||
|
||||
if (hstate == SBI_HSM_STATE_SUSPENDED)
|
||||
init_warm_resume(scratch);
|
||||
else
|
||||
init_warm_startup(scratch, hartid);
|
||||
|
||||
sbi_hart_switch_mode(hartid, scratch->next_arg1,
|
||||
scratch->next_addr,
|
||||
scratch->next_mode, FALSE);
|
||||
|
||||
@@ -25,7 +25,7 @@ struct sbi_ipi_data {
|
||||
};
|
||||
|
||||
static unsigned long ipi_data_off;
|
||||
|
||||
static const struct sbi_ipi_device *ipi_dev = NULL;
|
||||
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_hartid,
|
||||
@@ -33,7 +33,6 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
|
||||
{
|
||||
int ret;
|
||||
struct sbi_scratch *remote_scratch = NULL;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_ipi_data *ipi_data;
|
||||
const struct sbi_ipi_event_ops *ipi_ops;
|
||||
|
||||
@@ -61,7 +60,9 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
|
||||
*/
|
||||
atomic_raw_set_bit(event, &ipi_data->ipi_type);
|
||||
smp_wmb();
|
||||
sbi_platform_ipi_send(plat, remote_hartid);
|
||||
|
||||
if (ipi_dev && ipi_dev->ipi_send)
|
||||
ipi_dev->ipi_send(remote_hartid);
|
||||
|
||||
if (ipi_ops->sync)
|
||||
ipi_ops->sync(scratch);
|
||||
@@ -82,7 +83,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
if (hbase != -1UL) {
|
||||
rc = sbi_hsm_hart_started_mask(dom, hbase, &m);
|
||||
rc = sbi_hsm_hart_interruptible_mask(dom, hbase, &m);
|
||||
if (rc)
|
||||
return rc;
|
||||
m &= hmask;
|
||||
@@ -94,7 +95,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
|
||||
}
|
||||
} else {
|
||||
hbase = 0;
|
||||
while (!sbi_hsm_hart_started_mask(dom, hbase, &m)) {
|
||||
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) {
|
||||
/* Send IPIs */
|
||||
for (i = hbase; m; i++, m >>= 1) {
|
||||
if (m & 1UL)
|
||||
@@ -178,12 +179,12 @@ void sbi_ipi_process(void)
|
||||
unsigned int ipi_event;
|
||||
const struct sbi_ipi_event_ops *ipi_ops;
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
struct sbi_ipi_data *ipi_data =
|
||||
sbi_scratch_offset_ptr(scratch, ipi_data_off);
|
||||
|
||||
u32 hartid = current_hartid();
|
||||
sbi_platform_ipi_clear(plat, hartid);
|
||||
|
||||
if (ipi_dev && ipi_dev->ipi_clear)
|
||||
ipi_dev->ipi_clear(hartid);
|
||||
|
||||
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
|
||||
ipi_event = 0;
|
||||
@@ -201,6 +202,25 @@ skip:
|
||||
};
|
||||
}
|
||||
|
||||
void sbi_ipi_raw_send(u32 target_hart)
|
||||
{
|
||||
if (ipi_dev && ipi_dev->ipi_send)
|
||||
ipi_dev->ipi_send(target_hart);
|
||||
}
|
||||
|
||||
const struct sbi_ipi_device *sbi_ipi_get_device(void)
|
||||
{
|
||||
return ipi_dev;
|
||||
}
|
||||
|
||||
void sbi_ipi_set_device(const struct sbi_ipi_device *dev)
|
||||
{
|
||||
if (!dev || ipi_dev)
|
||||
return;
|
||||
|
||||
ipi_dev = dev;
|
||||
}
|
||||
|
||||
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
{
|
||||
int ret;
|
||||
@@ -230,7 +250,10 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
|
||||
ipi_data->ipi_type = 0x00;
|
||||
|
||||
/* Platform init */
|
||||
/*
|
||||
* Initialize platform IPI support. This will also clear any
|
||||
* pending IPIs for current/calling HART.
|
||||
*/
|
||||
ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -19,18 +19,9 @@ static inline char *sbi_platform_feature_id2string(unsigned long feature)
|
||||
return NULL;
|
||||
|
||||
switch (feature) {
|
||||
case SBI_PLATFORM_HAS_TIMER_VALUE:
|
||||
fstr = "timer";
|
||||
break;
|
||||
case SBI_PLATFORM_HAS_HART_HOTPLUG:
|
||||
fstr = "hotplug";
|
||||
break;
|
||||
case SBI_PLATFORM_HAS_MFAULTS_DELEGATION:
|
||||
fstr = "mfdeleg";
|
||||
break;
|
||||
case SBI_PLATFORM_HAS_HART_SECONDARY_BOOT:
|
||||
fstr = "sec_boot";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -18,15 +18,31 @@
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_init.h>
|
||||
|
||||
static const struct sbi_system_reset_device *reset_dev = NULL;
|
||||
|
||||
const struct sbi_system_reset_device *sbi_system_reset_get_device(void)
|
||||
{
|
||||
return reset_dev;
|
||||
}
|
||||
|
||||
void sbi_system_reset_set_device(const struct sbi_system_reset_device *dev)
|
||||
{
|
||||
if (!dev || reset_dev)
|
||||
return;
|
||||
|
||||
reset_dev = dev;
|
||||
}
|
||||
|
||||
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (sbi_platform_system_reset_check(sbi_platform_thishart_ptr(),
|
||||
reset_type, reset_reason))
|
||||
if (reset_dev && reset_dev->system_reset_check &&
|
||||
reset_dev->system_reset_check(reset_type, reset_reason))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#include <sbi/riscv_io.h>
|
||||
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
ulong hbase = 0, hmask;
|
||||
@@ -35,7 +51,7 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
|
||||
/* Send HALT IPI to every hart other than the current hart */
|
||||
while (!sbi_hsm_hart_started_mask(dom, hbase, &hmask)) {
|
||||
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &hmask)) {
|
||||
if (hbase <= cur_hartid)
|
||||
hmask &= ~(1UL << (cur_hartid - hbase));
|
||||
if (hmask)
|
||||
@@ -47,10 +63,97 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
|
||||
sbi_hsm_hart_stop(scratch, FALSE);
|
||||
|
||||
/* Platform specific reset if domain allowed system reset */
|
||||
if (dom->system_reset_allowed)
|
||||
sbi_platform_system_reset(sbi_platform_ptr(scratch),
|
||||
reset_type, reset_reason);
|
||||
if (dom->system_reset_allowed &&
|
||||
reset_dev && reset_dev->system_reset)
|
||||
reset_dev->system_reset(reset_type, reset_reason);
|
||||
|
||||
writew(0x5555, (void *)0x100000); // qemu poweroff
|
||||
|
||||
/* If platform specific reset did not work then do sbi_exit() */
|
||||
sbi_exit(scratch);
|
||||
}
|
||||
|
||||
static const struct sbi_system_suspend_device *suspend_dev;
|
||||
|
||||
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void)
|
||||
{
|
||||
return suspend_dev;
|
||||
}
|
||||
|
||||
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev)
|
||||
{
|
||||
if (!dev || suspend_dev)
|
||||
return;
|
||||
|
||||
suspend_dev = dev;
|
||||
}
|
||||
|
||||
bool sbi_system_suspend_supported(u32 sleep_type)
|
||||
{
|
||||
return suspend_dev && suspend_dev->system_suspend_check &&
|
||||
suspend_dev->system_suspend_check(sleep_type) == 0;
|
||||
}
|
||||
|
||||
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
|
||||
{
|
||||
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
|
||||
//unsigned int hartid = current_hartid();
|
||||
unsigned long prev_mode;
|
||||
//unsigned long i, j;
|
||||
int ret;
|
||||
|
||||
if (!dom || !dom->system_suspend_allowed)
|
||||
return SBI_EFAIL;
|
||||
|
||||
if (!suspend_dev || !suspend_dev->system_suspend ||
|
||||
!suspend_dev->system_suspend_check)
|
||||
return SBI_EFAIL;
|
||||
|
||||
ret = suspend_dev->system_suspend_check(sleep_type);
|
||||
if (ret != SBI_OK)
|
||||
return ret;
|
||||
|
||||
prev_mode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||
if (prev_mode != PRV_S && prev_mode != PRV_U)
|
||||
return SBI_EFAIL;
|
||||
|
||||
//FIX ME: hartindex to hart
|
||||
//sbi_hartmask_for_each_hartindex(j, &dom->assigned_harts) {
|
||||
// //i = sbi_hartindex_to_hartid(j);
|
||||
// if (i == hartid)
|
||||
// continue;
|
||||
// if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED)
|
||||
// return SBI_ERR_DENIED;
|
||||
//}
|
||||
|
||||
if (!sbi_domain_check_addr(dom, resume_addr, prev_mode,
|
||||
SBI_DOMAIN_EXECUTE))
|
||||
return SBI_EINVALID_ADDR;
|
||||
|
||||
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_STARTED,
|
||||
SBI_HSM_STATE_SUSPENDED))
|
||||
return SBI_EFAIL;
|
||||
|
||||
/* Prepare for resume */
|
||||
scratch->next_mode = prev_mode;
|
||||
scratch->next_addr = resume_addr;
|
||||
scratch->next_arg1 = opaque;
|
||||
|
||||
__sbi_hsm_suspend_non_ret_save(scratch);
|
||||
|
||||
/* Suspend */
|
||||
ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr);
|
||||
if (ret != SBI_OK) {
|
||||
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED,
|
||||
SBI_HSM_STATE_STARTED))
|
||||
sbi_hart_hang();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Resume */
|
||||
jump_warmboot();
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
#include <sbi/sbi_timer.h>
|
||||
|
||||
static unsigned long time_delta_off;
|
||||
static u64 (*get_time_val)(const struct sbi_platform *plat);
|
||||
static u64 (*get_time_val)(void);
|
||||
static const struct sbi_timer_device *timer_dev = NULL;
|
||||
|
||||
#if __riscv_xlen == 32
|
||||
static u64 get_ticks(const struct sbi_platform *plat)
|
||||
static u64 get_ticks(void)
|
||||
{
|
||||
u32 lo, hi, tmp;
|
||||
__asm__ __volatile__("1:\n"
|
||||
@@ -31,7 +32,7 @@ static u64 get_ticks(const struct sbi_platform *plat)
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
#else
|
||||
static u64 get_ticks(const struct sbi_platform *plat)
|
||||
static u64 get_ticks(void)
|
||||
{
|
||||
unsigned long n;
|
||||
|
||||
@@ -40,9 +41,16 @@ static u64 get_ticks(const struct sbi_platform *plat)
|
||||
}
|
||||
#endif
|
||||
|
||||
static u64 get_platform_ticks(void)
|
||||
{
|
||||
return timer_dev->timer_value();
|
||||
}
|
||||
|
||||
u64 sbi_timer_value(void)
|
||||
{
|
||||
return get_time_val(sbi_platform_thishart_ptr());
|
||||
if (get_time_val)
|
||||
return get_time_val();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 sbi_timer_virt_value(void)
|
||||
@@ -80,7 +88,8 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
|
||||
|
||||
void sbi_timer_event_start(u64 next_event)
|
||||
{
|
||||
sbi_platform_timer_event_start(sbi_platform_thishart_ptr(), next_event);
|
||||
if (timer_dev && timer_dev->timer_event_start)
|
||||
timer_dev->timer_event_start(next_event);
|
||||
csr_clear(CSR_MIP, MIP_STIP);
|
||||
csr_set(CSR_MIE, MIP_MTIP);
|
||||
}
|
||||
@@ -91,17 +100,34 @@ void sbi_timer_process(void)
|
||||
csr_set(CSR_MIP, MIP_STIP);
|
||||
}
|
||||
|
||||
const struct sbi_timer_device *sbi_timer_get_device(void)
|
||||
{
|
||||
return timer_dev;
|
||||
}
|
||||
|
||||
void sbi_timer_set_device(const struct sbi_timer_device *dev)
|
||||
{
|
||||
if (!dev || timer_dev)
|
||||
return;
|
||||
|
||||
timer_dev = dev;
|
||||
if (!get_time_val && timer_dev->timer_value)
|
||||
get_time_val = get_platform_ticks;
|
||||
}
|
||||
|
||||
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
{
|
||||
u64 *time_delta;
|
||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||
int ret;
|
||||
|
||||
if (cold_boot) {
|
||||
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
|
||||
"TIME_DELTA");
|
||||
if (!time_delta_off)
|
||||
return SBI_ENOMEM;
|
||||
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
|
||||
get_time_val = get_ticks;
|
||||
} else {
|
||||
if (!time_delta_off)
|
||||
return SBI_ENOMEM;
|
||||
@@ -110,24 +136,13 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
|
||||
*time_delta = 0;
|
||||
|
||||
ret = sbi_platform_timer_init(plat, cold_boot);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
|
||||
get_time_val = get_ticks;
|
||||
else if (sbi_platform_has_timer_value(plat))
|
||||
get_time_val = sbi_platform_timer_value;
|
||||
else
|
||||
/* There is no method to provide timer value */
|
||||
return SBI_ENODEV;
|
||||
|
||||
return 0;
|
||||
return sbi_platform_timer_init(plat, cold_boot);
|
||||
}
|
||||
|
||||
void sbi_timer_exit(struct sbi_scratch *scratch)
|
||||
{
|
||||
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
|
||||
if (timer_dev && timer_dev->timer_event_stop)
|
||||
timer_dev->timer_event_stop();
|
||||
|
||||
csr_clear(CSR_MIP, MIP_STIP);
|
||||
csr_clear(CSR_MIE, MIP_MTIP);
|
||||
|
||||
@@ -210,7 +210,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||
*
|
||||
* @param regs pointer to register state
|
||||
*/
|
||||
void sbi_trap_handler(struct sbi_trap_regs *regs)
|
||||
struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
|
||||
{
|
||||
int rc = SBI_ENOTSUPP;
|
||||
const char *msg = "trap handler failed";
|
||||
@@ -236,7 +236,7 @@ void sbi_trap_handler(struct sbi_trap_regs *regs)
|
||||
msg = "unhandled external interrupt";
|
||||
goto trap_error;
|
||||
};
|
||||
return;
|
||||
return regs;
|
||||
}
|
||||
|
||||
switch (mcause) {
|
||||
@@ -271,6 +271,7 @@ void sbi_trap_handler(struct sbi_trap_regs *regs)
|
||||
trap_error:
|
||||
if (rc)
|
||||
sbi_trap_error(msg, rc, mcause, mtval, mtval2, mtinst, regs);
|
||||
return regs;
|
||||
}
|
||||
|
||||
typedef void (*trap_exit_t)(const struct sbi_trap_regs *regs);
|
||||
|
||||
@@ -222,7 +222,7 @@ static u32 fdt_domains_count;
|
||||
static struct sbi_domain fdt_domains[FDT_DOMAIN_MAX_COUNT];
|
||||
static struct sbi_hartmask fdt_masks[FDT_DOMAIN_MAX_COUNT];
|
||||
static struct sbi_domain_memregion
|
||||
fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 2];
|
||||
fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 1];
|
||||
|
||||
static int __fdt_parse_region(void *fdt, int domain_offset,
|
||||
int region_offset, u32 region_access,
|
||||
@@ -276,7 +276,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
|
||||
struct sbi_hartmask *mask;
|
||||
struct sbi_hartmask assign_mask;
|
||||
int *cold_domain_offset = opaque;
|
||||
struct sbi_domain_memregion *regions;
|
||||
struct sbi_domain_memregion *reg, *regions;
|
||||
int i, err, len, cpus_offset, cpu_offset, doffset;
|
||||
|
||||
/* Sanity check on maximum domains we can handle */
|
||||
@@ -314,13 +314,31 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
|
||||
/* Setup memregions from DT */
|
||||
val32 = 0;
|
||||
sbi_memset(regions, 0,
|
||||
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 2));
|
||||
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 1));
|
||||
dom->regions = regions;
|
||||
err = fdt_iterate_each_memregion(fdt, domain_offset, &val32,
|
||||
__fdt_parse_region);
|
||||
if (err)
|
||||
return err;
|
||||
sbi_domain_memregion_initfw(®ions[val32]);
|
||||
|
||||
/*
|
||||
* Copy over root domain memregions which don't allow
|
||||
* read, write and execute from lower privilege modes.
|
||||
*
|
||||
* These root domain memregions without read, write,
|
||||
* and execute permissions include:
|
||||
* 1) firmware region protecting the firmware memory
|
||||
* 2) mmio regions protecting M-mode only mmio devices
|
||||
*/
|
||||
sbi_domain_for_each_memregion(&root, reg) {
|
||||
if ((reg->flags & SBI_DOMAIN_MEMREGION_READABLE) ||
|
||||
(reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE) ||
|
||||
(reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE))
|
||||
continue;
|
||||
if (FDT_DOMAIN_REGION_MAX_COUNT <= val32)
|
||||
return SBI_EINVAL;
|
||||
sbi_memcpy(®ions[val32++], reg, sizeof(*reg));
|
||||
}
|
||||
|
||||
/* Read "boot-hart" DT property */
|
||||
val32 = -1U;
|
||||
@@ -380,6 +398,13 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
|
||||
else
|
||||
dom->system_reset_allowed = FALSE;
|
||||
|
||||
/* Read "system-suspend-allowed" DT property */
|
||||
if (fdt_get_property(fdt, domain_offset,
|
||||
"system-suspend-allowed", NULL))
|
||||
dom->system_suspend_allowed = TRUE;
|
||||
else
|
||||
dom->system_suspend_allowed = FALSE;
|
||||
|
||||
/* Find /cpus DT node */
|
||||
cpus_offset = fdt_path_offset(fdt, "/cpus");
|
||||
if (cpus_offset < 0)
|
||||
|
||||
@@ -51,15 +51,18 @@ void fdt_cpu_fixup(void *fdt)
|
||||
}
|
||||
}
|
||||
|
||||
void fdt_plic_fixup(void *fdt, const char *compat)
|
||||
void fdt_plic_fixup(void *fdt)
|
||||
{
|
||||
u32 *cells;
|
||||
int i, cells_count;
|
||||
int plic_off;
|
||||
|
||||
plic_off = fdt_node_offset_by_compatible(fdt, 0, compat);
|
||||
if (plic_off < 0)
|
||||
return;
|
||||
plic_off = fdt_node_offset_by_compatible(fdt, 0, "sifive,plic-1.0.0");
|
||||
if (plic_off < 0) {
|
||||
plic_off = fdt_node_offset_by_compatible(fdt, 0, "riscv,plic0");
|
||||
if (plic_off < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
cells = (u32 *)fdt_getprop(fdt, plic_off,
|
||||
"interrupts-extended", &cells_count);
|
||||
@@ -257,7 +260,7 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
|
||||
|
||||
void fdt_fixups(void *fdt)
|
||||
{
|
||||
fdt_plic_fixup(fdt, "riscv,plic0");
|
||||
fdt_plic_fixup(fdt);
|
||||
|
||||
fdt_reserved_memory_fixup(fdt);
|
||||
}
|
||||
|
||||
@@ -442,8 +442,9 @@ int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
|
||||
if (clint->hart_count < count)
|
||||
clint->hart_count = count;
|
||||
|
||||
/* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
|
||||
clint->has_64bit_mmio = TRUE;
|
||||
if (fdt_getprop(fdt, nodeoffset, "clint,has-no-64bit-mmio", &count))
|
||||
clint->has_64bit_mmio = FALSE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -17,35 +17,15 @@ static struct fdt_ipi *ipi_drivers[] = {
|
||||
&fdt_ipi_clint
|
||||
};
|
||||
|
||||
static void dummy_send(u32 target_hart)
|
||||
{
|
||||
}
|
||||
|
||||
static void dummy_clear(u32 target_hart)
|
||||
{
|
||||
}
|
||||
|
||||
static struct fdt_ipi dummy = {
|
||||
.match_table = NULL,
|
||||
.cold_init = NULL,
|
||||
.warm_init = NULL,
|
||||
.exit = NULL,
|
||||
.send = dummy_send,
|
||||
.clear = dummy_clear
|
||||
};
|
||||
|
||||
static struct fdt_ipi *current_driver = &dummy;
|
||||
|
||||
void fdt_ipi_send(u32 target_hart)
|
||||
{
|
||||
current_driver->send(target_hart);
|
||||
}
|
||||
|
||||
void fdt_ipi_clear(u32 target_hart)
|
||||
{
|
||||
current_driver->clear(target_hart);
|
||||
}
|
||||
|
||||
void fdt_ipi_exit(void)
|
||||
{
|
||||
if (current_driver->exit)
|
||||
|
||||
@@ -36,6 +36,7 @@ static int ipi_clint_cold_init(void *fdt, int nodeoff,
|
||||
|
||||
static const struct fdt_match ipi_clint_match[] = {
|
||||
{ .compatible = "riscv,clint0" },
|
||||
{ .compatible = "sifive,clint0" },
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -44,6 +45,4 @@ struct fdt_ipi fdt_ipi_clint = {
|
||||
.cold_init = ipi_clint_cold_init,
|
||||
.warm_init = clint_warm_ipi_init,
|
||||
.exit = NULL,
|
||||
.send = clint_ipi_send,
|
||||
.clear = clint_ipi_clear,
|
||||
};
|
||||
|
||||
@@ -94,7 +94,7 @@ int plic_cold_irqchip_init(struct plic_data *plic)
|
||||
|
||||
/* Configure default priorities of all IRQs */
|
||||
for (i = 1; i <= plic->num_src; i++)
|
||||
plic_set_priority(plic, i, 0);
|
||||
plic_set_priority(plic, i, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
struct fdt_header {
|
||||
fdt32_t magic; /* magic word FDT_MAGIC */
|
||||
|
||||
@@ -13,28 +13,16 @@
|
||||
|
||||
extern struct fdt_reset fdt_reset_sifive;
|
||||
extern struct fdt_reset fdt_reset_htif;
|
||||
extern struct fdt_reset fdt_reset_thead;
|
||||
|
||||
static struct fdt_reset *reset_drivers[] = {
|
||||
&fdt_reset_sifive,
|
||||
&fdt_reset_htif,
|
||||
&fdt_reset_thead,
|
||||
};
|
||||
|
||||
static struct fdt_reset *current_driver = NULL;
|
||||
|
||||
int fdt_system_reset_check(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (current_driver && current_driver->system_reset_check)
|
||||
return current_driver->system_reset_check(reset_type,
|
||||
reset_reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fdt_system_reset(u32 reset_type, u32 reset_reason)
|
||||
{
|
||||
if (current_driver && current_driver->system_reset)
|
||||
current_driver->system_reset(reset_type, reset_reason);
|
||||
}
|
||||
|
||||
int fdt_reset_init(void)
|
||||
{
|
||||
int pos, noff, rc;
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
#include <sbi_utils/sys/htif.h>
|
||||
|
||||
static int htif_reset_init(void *fdt, int nodeoff,
|
||||
const struct fdt_match *match)
|
||||
{
|
||||
return htif_system_reset_init();
|
||||
}
|
||||
|
||||
static const struct fdt_match htif_reset_match[] = {
|
||||
{ .compatible = "ucb,htif0" },
|
||||
{ },
|
||||
@@ -18,6 +24,5 @@ static const struct fdt_match htif_reset_match[] = {
|
||||
|
||||
struct fdt_reset fdt_reset_htif = {
|
||||
.match_table = htif_reset_match,
|
||||
.system_reset_check = htif_system_reset_check,
|
||||
.system_reset = htif_system_reset
|
||||
.init = htif_reset_init
|
||||
};
|
||||
|
||||
@@ -33,6 +33,4 @@ static const struct fdt_match sifive_test_reset_match[] = {
|
||||
struct fdt_reset fdt_reset_sifive = {
|
||||
.match_table = sifive_test_reset_match,
|
||||
.init = sifive_test_reset_init,
|
||||
.system_reset_check = sifive_test_system_reset_check,
|
||||
.system_reset = sifive_test_system_reset
|
||||
};
|
||||
|
||||
140
lib/utils/reset/fdt_reset_thead.c
Normal file
140
lib/utils/reset/fdt_reset_thead.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <libfdt.h>
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_bitops.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
#include <sbi_utils/reset/fdt_reset.h>
|
||||
|
||||
#include "fdt_reset_thead.h"
|
||||
|
||||
struct custom_csr custom_csr[MAX_CUSTOM_CSR];
|
||||
|
||||
#define CSR_OPCODE 0x39073
|
||||
static void clone_csrs(int cnt)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
/* Write csr BIT[31 - 20] to stub */
|
||||
__reset_thead_csr_stub[3*i + 1] =
|
||||
CSR_OPCODE | (custom_csr[i].index << 20);
|
||||
|
||||
/* Mask csr BIT[31 - 20] */
|
||||
*(u32 *)&__fdt_reset_thead_csrr &= BIT(20) - 1;
|
||||
smp_mb();
|
||||
|
||||
/* Write csr BIT[31 - 20] to __fdt_reset_thead_csrr */
|
||||
*(u32 *)&__fdt_reset_thead_csrr |= custom_csr[i].index << 20;
|
||||
smp_mb();
|
||||
|
||||
RISCV_FENCE_I;
|
||||
|
||||
custom_csr[i].value = __fdt_reset_thead_csrr();
|
||||
}
|
||||
}
|
||||
|
||||
static int thead_system_reset_check(u32 type, u32 reason)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void thead_system_reset(u32 type, u32 reason)
|
||||
{
|
||||
ebreak();
|
||||
}
|
||||
|
||||
static struct sbi_system_reset_device thead_reset = {
|
||||
.name = "thead_reset",
|
||||
.system_reset_check = thead_system_reset_check,
|
||||
.system_reset = thead_system_reset
|
||||
};
|
||||
|
||||
extern void __thead_pre_start_warm(void);
|
||||
static int thead_reset_init(void *fdt, int nodeoff,
|
||||
const struct fdt_match *match)
|
||||
{
|
||||
void *p;
|
||||
const fdt64_t *val;
|
||||
const fdt32_t *val_w;
|
||||
int len, i, cnt;
|
||||
u32 t, tmp = 0;
|
||||
|
||||
/* Prepare clone csrs */
|
||||
val_w = fdt_getprop(fdt, nodeoff, "csr-copy", &len);
|
||||
if (len > 0 && val_w) {
|
||||
cnt = len / sizeof(fdt32_t);
|
||||
|
||||
if (cnt > MAX_CUSTOM_CSR)
|
||||
sbi_hart_hang();
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
custom_csr[i].index = fdt32_to_cpu(val_w[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt)
|
||||
clone_csrs(cnt);
|
||||
|
||||
/* Delegate plic enable regs for S-mode */
|
||||
val = fdt_getprop(fdt, nodeoff, "plic-delegate", &len);
|
||||
if (len > 0 && val) {
|
||||
p = (void *)(ulong)fdt64_to_cpu(*val);
|
||||
writel(BIT(0), p);
|
||||
}
|
||||
|
||||
/* Old reset method for secondary harts */
|
||||
if (fdt_getprop(fdt, nodeoff, "using-csr-reset", &len)) {
|
||||
csr_write(0x7c7, (ulong)&__thead_pre_start_warm);
|
||||
csr_write(0x7c6, -1);
|
||||
}
|
||||
|
||||
/* Custom reset method for secondary harts */
|
||||
val = fdt_getprop(fdt, nodeoff, "entry-reg", &len);
|
||||
if (len > 0 && val) {
|
||||
p = (void *)(ulong)fdt64_to_cpu(*val);
|
||||
|
||||
val_w = fdt_getprop(fdt, nodeoff, "entry-cnt", &len);
|
||||
if (len > 0 && val_w) {
|
||||
tmp = fdt32_to_cpu(*val_w);
|
||||
|
||||
for (i = 0; i < tmp; i++) {
|
||||
t = (ulong)&__thead_pre_start_warm;
|
||||
writel(t, p + (8 * i));
|
||||
t = (u64)(ulong)&__thead_pre_start_warm >> 32;
|
||||
writel(t, p + (8 * i) + 4);
|
||||
}
|
||||
}
|
||||
|
||||
val = fdt_getprop(fdt, nodeoff, "control-reg", &len);
|
||||
if (len > 0 && val) {
|
||||
p = (void *)(ulong)fdt64_to_cpu(*val);
|
||||
|
||||
val_w = fdt_getprop(fdt, nodeoff, "control-val", &len);
|
||||
if (len > 0 && val_w) {
|
||||
tmp = fdt32_to_cpu(*val_w);
|
||||
tmp |= readl(p);
|
||||
writel(tmp, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sbi_system_reset_set_device(&thead_reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fdt_match thead_reset_match[] = {
|
||||
{ .compatible = "thead,reset-sample" },
|
||||
{ },
|
||||
};
|
||||
|
||||
struct fdt_reset fdt_reset_thead = {
|
||||
.match_table = thead_reset_match,
|
||||
.init = thead_reset_init
|
||||
};
|
||||
23
lib/utils/reset/fdt_reset_thead.h
Normal file
23
lib/utils/reset/fdt_reset_thead.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#ifndef __FDT_RESET_THEAD_H__
|
||||
#define __FDT_RESET_THEAD_H__
|
||||
|
||||
#define MAX_CUSTOM_CSR 32
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
struct custom_csr {
|
||||
unsigned long index;
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
u64 __fdt_reset_thead_csrr(void);
|
||||
|
||||
extern struct custom_csr custom_csr[MAX_CUSTOM_CSR];
|
||||
extern u32 __reset_thead_csr_stub[];
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#endif /* __FDT_RESET_THEAD_H__ */
|
||||
47
lib/utils/reset/fdt_reset_thead_asm.S
Normal file
47
lib/utils/reset/fdt_reset_thead_asm.S
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include "fdt_reset_thead.h"
|
||||
|
||||
/*
|
||||
* csrrs rd, csr, rs1
|
||||
* |31 20|19 15|14 12|11 7|6 0|
|
||||
* csr rs1 010 rd 1110011
|
||||
*/
|
||||
#define CSR_STUB addi x0, x0, 0
|
||||
|
||||
.option norvc
|
||||
.align 3
|
||||
.global __fdt_reset_thead_csrr
|
||||
__fdt_reset_thead_csrr:
|
||||
csrrs a0, 0, x0
|
||||
ret
|
||||
|
||||
.align 3
|
||||
.global __thead_pre_start_warm
|
||||
__thead_pre_start_warm:
|
||||
/*
|
||||
* Clear L1 cache & BTB & BHT ...
|
||||
*/
|
||||
li t1, 0x70013
|
||||
csrw 0x7c2, t1
|
||||
fence rw,rw
|
||||
|
||||
lla t1, custom_csr
|
||||
|
||||
.global __reset_thead_csr_stub
|
||||
__reset_thead_csr_stub:
|
||||
.rept MAX_CUSTOM_CSR
|
||||
REG_L t2, 8(t1)
|
||||
CSR_STUB
|
||||
addi t1, t1, 16
|
||||
.endr
|
||||
/*
|
||||
* Clear L1 cache & BTB & BHT ...
|
||||
*/
|
||||
li t1, 0x70013
|
||||
csrw 0x7c2, t1
|
||||
fence rw,rw
|
||||
j _start_warm
|
||||
@@ -10,3 +10,5 @@
|
||||
libsbiutils-objs-y += reset/fdt_reset.o
|
||||
libsbiutils-objs-y += reset/fdt_reset_htif.o
|
||||
libsbiutils-objs-y += reset/fdt_reset_sifive.o
|
||||
libsbiutils-objs-y += reset/fdt_reset_thead.o
|
||||
libsbiutils-objs-y += reset/fdt_reset_thead_asm.o
|
||||
|
||||
@@ -24,34 +24,13 @@ static struct fdt_serial *serial_drivers[] = {
|
||||
&fdt_serial_shakti,
|
||||
};
|
||||
|
||||
static void dummy_putc(char ch)
|
||||
{
|
||||
}
|
||||
|
||||
static int dummy_getc(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct fdt_serial dummy = {
|
||||
.match_table = NULL,
|
||||
.init = NULL,
|
||||
.putc = dummy_putc,
|
||||
.getc = dummy_getc,
|
||||
};
|
||||
|
||||
static struct fdt_serial *current_driver = &dummy;
|
||||
|
||||
void fdt_serial_putc(char ch)
|
||||
{
|
||||
current_driver->putc(ch);
|
||||
}
|
||||
|
||||
int fdt_serial_getc(void)
|
||||
{
|
||||
return current_driver->getc();
|
||||
}
|
||||
|
||||
int fdt_serial_init(void)
|
||||
{
|
||||
const void *prop;
|
||||
|
||||
@@ -16,9 +16,13 @@ static const struct fdt_match serial_htif_match[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static int serial_htif_init(void *fdt, int nodeoff,
|
||||
const struct fdt_match *match)
|
||||
{
|
||||
return htif_serial_init();
|
||||
}
|
||||
|
||||
struct fdt_serial fdt_serial_htif = {
|
||||
.match_table = serial_htif_match,
|
||||
.init = NULL,
|
||||
.getc = htif_getc,
|
||||
.putc = htif_putc
|
||||
.init = serial_htif_init
|
||||
};
|
||||
|
||||
@@ -29,7 +29,5 @@ static const struct fdt_match serial_shakti_match[] = {
|
||||
|
||||
struct fdt_serial fdt_serial_shakti = {
|
||||
.match_table = serial_shakti_match,
|
||||
.init = serial_shakti_init,
|
||||
.getc = shakti_uart_getc,
|
||||
.putc = shakti_uart_putc
|
||||
.init = serial_shakti_init
|
||||
};
|
||||
|
||||
@@ -32,7 +32,5 @@ static const struct fdt_match serial_sifive_match[] = {
|
||||
|
||||
struct fdt_serial fdt_serial_sifive = {
|
||||
.match_table = serial_sifive_match,
|
||||
.init = serial_sifive_init,
|
||||
.getc = sifive_uart_getc,
|
||||
.putc = sifive_uart_putc
|
||||
.init = serial_sifive_init
|
||||
};
|
||||
|
||||
3
lib/utils/serial/fdt_serial_uart8250.c
Normal file → Executable file
3
lib/utils/serial/fdt_serial_uart8250.c
Normal file → Executable file
@@ -26,6 +26,7 @@ static int serial_uart8250_init(void *fdt, int nodeoff,
|
||||
}
|
||||
|
||||
static const struct fdt_match serial_uart8250_match[] = {
|
||||
{ .compatible = "snps,dw-apb-uart" },
|
||||
{ .compatible = "ns16550" },
|
||||
{ .compatible = "ns16550a" },
|
||||
{ },
|
||||
@@ -34,6 +35,4 @@ static const struct fdt_match serial_uart8250_match[] = {
|
||||
struct fdt_serial fdt_serial_uart8250 = {
|
||||
.match_table = serial_uart8250_match,
|
||||
.init = serial_uart8250_init,
|
||||
.getc = uart8250_getc,
|
||||
.putc = uart8250_putc
|
||||
};
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
|
||||
static volatile void *uart_base;
|
||||
|
||||
void shakti_uart_putc(char ch)
|
||||
static void shakti_uart_putc(char ch)
|
||||
{
|
||||
while((readw(uart_base + REG_STATUS) & UART_TX_FULL))
|
||||
;
|
||||
writeb(ch, uart_base + REG_TX);
|
||||
}
|
||||
|
||||
int shakti_uart_getc(void)
|
||||
static int shakti_uart_getc(void)
|
||||
{
|
||||
u16 status = readw(uart_base + REG_STATUS);
|
||||
if (status & UART_RX_FULL)
|
||||
@@ -38,11 +38,19 @@ int shakti_uart_getc(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct sbi_console_device shakti_console = {
|
||||
.name = "shakti_uart",
|
||||
.console_putc = shakti_uart_putc,
|
||||
.console_getc = shakti_uart_getc
|
||||
};
|
||||
|
||||
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
|
||||
{
|
||||
uart_base = (volatile void *)base;
|
||||
u16 baud = (u16)(in_freq/(16 * baudrate));
|
||||
writew(baud, uart_base + REG_BAUD);
|
||||
|
||||
sbi_console_set_device(&shakti_console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ static void set_reg(u32 num, u32 val)
|
||||
writel(val, uart_base + (num * 0x4));
|
||||
}
|
||||
|
||||
void sifive_uart_putc(char ch)
|
||||
static void sifive_uart_putc(char ch)
|
||||
{
|
||||
while (get_reg(UART_REG_TXFIFO) & UART_TXFIFO_FULL)
|
||||
;
|
||||
@@ -74,7 +74,7 @@ void sifive_uart_putc(char ch)
|
||||
set_reg(UART_REG_TXFIFO, ch);
|
||||
}
|
||||
|
||||
int sifive_uart_getc(void)
|
||||
static int sifive_uart_getc(void)
|
||||
{
|
||||
u32 ret = get_reg(UART_REG_RXFIFO);
|
||||
if (!(ret & UART_RXFIFO_EMPTY))
|
||||
@@ -82,6 +82,12 @@ int sifive_uart_getc(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct sbi_console_device sifive_console = {
|
||||
.name = "sifive_uart",
|
||||
.console_putc = sifive_uart_putc,
|
||||
.console_getc = sifive_uart_getc
|
||||
};
|
||||
|
||||
int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
|
||||
{
|
||||
uart_base = (volatile void *)base;
|
||||
@@ -98,5 +104,7 @@ int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
|
||||
/* Enable Rx */
|
||||
set_reg(UART_REG_RXCTRL, UART_RXCTRL_RXEN);
|
||||
|
||||
sbi_console_set_device(&sifive_console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi_utils/serial/uart8250.h>
|
||||
|
||||
/* clang-format off */
|
||||
@@ -68,7 +69,7 @@ static void set_reg(u32 num, u32 val)
|
||||
writel(val, uart8250_base + offset);
|
||||
}
|
||||
|
||||
void uart8250_putc(char ch)
|
||||
static void uart8250_putc(char ch)
|
||||
{
|
||||
while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0)
|
||||
;
|
||||
@@ -76,13 +77,19 @@ void uart8250_putc(char ch)
|
||||
set_reg(UART_THR_OFFSET, ch);
|
||||
}
|
||||
|
||||
int uart8250_getc(void)
|
||||
static int uart8250_getc(void)
|
||||
{
|
||||
if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
|
||||
return get_reg(UART_RBR_OFFSET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct sbi_console_device uart8250_console = {
|
||||
.name = "uart8250",
|
||||
.console_putc = uart8250_putc,
|
||||
.console_getc = uart8250_getc
|
||||
};
|
||||
|
||||
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
||||
u32 reg_width)
|
||||
{
|
||||
@@ -94,7 +101,7 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
||||
uart8250_in_freq = in_freq;
|
||||
uart8250_baudrate = baudrate;
|
||||
|
||||
bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
|
||||
bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) / (16 * uart8250_baudrate);
|
||||
|
||||
/* Disable all interrupts */
|
||||
set_reg(UART_IER_OFFSET, 0x00);
|
||||
@@ -121,5 +128,7 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
||||
/* Set scratchpad */
|
||||
set_reg(UART_SCR_OFFSET, 0x00);
|
||||
|
||||
sbi_console_set_device(&uart8250_console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,17 +10,25 @@
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_atomic.h>
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_domain.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hartmask.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
#include <sbi_utils/sys/clint.h>
|
||||
|
||||
#define CLINT_IPI_OFF 0
|
||||
#define CLINT_IPI_SIZE 0x4000
|
||||
|
||||
#define CLINT_TIME_CMP_OFF 0x4000
|
||||
#define CLINT_TIME_CMP_SIZE 0x4000
|
||||
|
||||
#define CLINT_TIME_VAL_OFF 0xbff8
|
||||
#define CLINT_TIME_VAL_SIZE 0x4000
|
||||
|
||||
static struct clint_data *clint_ipi_hartid2data[SBI_HARTMASK_MAX_BITS];
|
||||
|
||||
void clint_ipi_send(u32 target_hart)
|
||||
static void clint_ipi_send(u32 target_hart)
|
||||
{
|
||||
struct clint_data *clint;
|
||||
|
||||
@@ -34,7 +42,7 @@ void clint_ipi_send(u32 target_hart)
|
||||
writel(1, &clint->ipi[target_hart - clint->first_hartid]);
|
||||
}
|
||||
|
||||
void clint_ipi_clear(u32 target_hart)
|
||||
static void clint_ipi_clear(u32 target_hart)
|
||||
{
|
||||
struct clint_data *clint;
|
||||
|
||||
@@ -48,6 +56,12 @@ void clint_ipi_clear(u32 target_hart)
|
||||
writel(0, &clint->ipi[target_hart - clint->first_hartid]);
|
||||
}
|
||||
|
||||
static struct sbi_ipi_device clint_ipi = {
|
||||
.name = "clint",
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_clear = clint_ipi_clear
|
||||
};
|
||||
|
||||
int clint_warm_ipi_init(void)
|
||||
{
|
||||
/* Clear CLINT IPI for current HART */
|
||||
@@ -59,6 +73,8 @@ int clint_warm_ipi_init(void)
|
||||
int clint_cold_ipi_init(struct clint_data *clint)
|
||||
{
|
||||
u32 i;
|
||||
int rc;
|
||||
struct sbi_domain_memregion reg;
|
||||
|
||||
if (!clint)
|
||||
return SBI_EINVAL;
|
||||
@@ -70,6 +86,16 @@ int clint_cold_ipi_init(struct clint_data *clint)
|
||||
for (i = 0; i < clint->hart_count; i++)
|
||||
clint_ipi_hartid2data[clint->first_hartid + i] = clint;
|
||||
|
||||
/* Add CLINT ipi region to the root domain */
|
||||
sbi_domain_memregion_init(clint->addr + CLINT_IPI_OFF,
|
||||
CLINT_IPI_SIZE,
|
||||
SBI_DOMAIN_MEMREGION_MMIO, ®);
|
||||
rc = sbi_domain_root_add_memregion(®);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
sbi_ipi_set_device(&clint_ipi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -107,7 +133,7 @@ static void clint_time_wr32(u64 value, volatile u64 *addr)
|
||||
writel_relaxed(value >> 32, (void *)(addr) + 0x04);
|
||||
}
|
||||
|
||||
u64 clint_timer_value(void)
|
||||
static u64 clint_timer_value(void)
|
||||
{
|
||||
struct clint_data *clint = clint_timer_hartid2data[current_hartid()];
|
||||
|
||||
@@ -115,7 +141,7 @@ u64 clint_timer_value(void)
|
||||
return clint->time_rd(clint->time_val) + clint->time_delta;
|
||||
}
|
||||
|
||||
void clint_timer_event_stop(void)
|
||||
static void clint_timer_event_stop(void)
|
||||
{
|
||||
u32 target_hart = current_hartid();
|
||||
struct clint_data *clint = clint_timer_hartid2data[target_hart];
|
||||
@@ -125,7 +151,7 @@ void clint_timer_event_stop(void)
|
||||
&clint->time_cmp[target_hart - clint->first_hartid]);
|
||||
}
|
||||
|
||||
void clint_timer_event_start(u64 next_event)
|
||||
static void clint_timer_event_start(u64 next_event)
|
||||
{
|
||||
u32 target_hart = current_hartid();
|
||||
struct clint_data *clint = clint_timer_hartid2data[target_hart];
|
||||
@@ -135,6 +161,13 @@ void clint_timer_event_start(u64 next_event)
|
||||
&clint->time_cmp[target_hart - clint->first_hartid]);
|
||||
}
|
||||
|
||||
static struct sbi_timer_device clint_timer = {
|
||||
.name = "clint",
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_event_stop = clint_timer_event_stop
|
||||
};
|
||||
|
||||
int clint_warm_timer_init(void)
|
||||
{
|
||||
u64 v1, v2, mv;
|
||||
@@ -174,6 +207,8 @@ int clint_cold_timer_init(struct clint_data *clint,
|
||||
struct clint_data *reference)
|
||||
{
|
||||
u32 i;
|
||||
int rc;
|
||||
struct sbi_domain_memregion reg;
|
||||
|
||||
if (!clint)
|
||||
return SBI_EINVAL;
|
||||
@@ -199,5 +234,23 @@ int clint_cold_timer_init(struct clint_data *clint,
|
||||
for (i = 0; i < clint->hart_count; i++)
|
||||
clint_timer_hartid2data[clint->first_hartid + i] = clint;
|
||||
|
||||
/* Add CLINT mtime region to the root domain */
|
||||
sbi_domain_memregion_init(clint->addr + CLINT_TIME_VAL_OFF,
|
||||
CLINT_TIME_VAL_SIZE,
|
||||
SBI_DOMAIN_MEMREGION_MMIO, ®);
|
||||
rc = sbi_domain_root_add_memregion(®);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Add CLINT timecmp region to the root domain */
|
||||
sbi_domain_memregion_init(clint->addr + CLINT_TIME_CMP_OFF,
|
||||
CLINT_TIME_CMP_SIZE,
|
||||
SBI_DOMAIN_MEMREGION_MMIO, ®);
|
||||
rc = sbi_domain_root_add_memregion(®);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
sbi_timer_set_device(&clint_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_locks.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi_utils/sys/htif.h>
|
||||
|
||||
#define HTIF_DATA_BITS 48
|
||||
@@ -98,7 +100,7 @@ static void do_tohost_fromhost(uint64_t dev, uint64_t cmd, uint64_t data)
|
||||
spin_unlock(&htif_lock);
|
||||
}
|
||||
|
||||
void htif_putc(char ch)
|
||||
static void htif_putc(char ch)
|
||||
{
|
||||
/* HTIF devices are not supported on RV32, so do a proxy write call */
|
||||
volatile uint64_t magic_mem[8];
|
||||
@@ -109,7 +111,7 @@ void htif_putc(char ch)
|
||||
do_tohost_fromhost(HTIF_DEV_SYSTEM, 0, (uint64_t)(uintptr_t)magic_mem);
|
||||
}
|
||||
#else
|
||||
void htif_putc(char ch)
|
||||
static void htif_putc(char ch)
|
||||
{
|
||||
spin_lock(&htif_lock);
|
||||
__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
|
||||
@@ -117,7 +119,7 @@ void htif_putc(char ch)
|
||||
}
|
||||
#endif
|
||||
|
||||
int htif_getc(void)
|
||||
static int htif_getc(void)
|
||||
{
|
||||
int ch;
|
||||
|
||||
@@ -140,15 +142,41 @@ int htif_getc(void)
|
||||
return ch - 1;
|
||||
}
|
||||
|
||||
int htif_system_reset_check(u32 type, u32 reason)
|
||||
static struct sbi_console_device htif_console = {
|
||||
.name = "htif",
|
||||
.console_putc = htif_putc,
|
||||
.console_getc = htif_getc
|
||||
};
|
||||
|
||||
int htif_serial_init(void)
|
||||
{
|
||||
sbi_console_set_device(&htif_console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int htif_system_reset_check(u32 type, u32 reason)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void htif_system_reset(u32 type, u32 reason)
|
||||
static void htif_system_reset(u32 type, u32 reason)
|
||||
{
|
||||
while (1) {
|
||||
fromhost = 0;
|
||||
tohost = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static struct sbi_system_reset_device htif_reset = {
|
||||
.name = "htif",
|
||||
.system_reset_check = htif_system_reset_check,
|
||||
.system_reset = htif_system_reset
|
||||
};
|
||||
|
||||
int htif_system_reset_init(void)
|
||||
{
|
||||
sbi_system_reset_set_device(&htif_reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi_utils/sys/sifive_test.h>
|
||||
|
||||
#define FINISHER_FAIL 0x3333
|
||||
@@ -17,7 +18,7 @@
|
||||
|
||||
static void *sifive_test_base;
|
||||
|
||||
int sifive_test_system_reset_check(u32 type, u32 reason)
|
||||
static int sifive_test_system_reset_check(u32 type, u32 reason)
|
||||
{
|
||||
switch (type) {
|
||||
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
||||
@@ -29,7 +30,7 @@ int sifive_test_system_reset_check(u32 type, u32 reason)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sifive_test_system_reset(u32 type, u32 reason)
|
||||
static void sifive_test_system_reset(u32 type, u32 reason)
|
||||
{
|
||||
/*
|
||||
* Tell the "finisher" that the simulation
|
||||
@@ -49,9 +50,16 @@ void sifive_test_system_reset(u32 type, u32 reason)
|
||||
}
|
||||
}
|
||||
|
||||
static struct sbi_system_reset_device sifive_test_reset = {
|
||||
.name = "sifive_test",
|
||||
.system_reset_check = sifive_test_system_reset_check,
|
||||
.system_reset = sifive_test_system_reset
|
||||
};
|
||||
|
||||
int sifive_test_init(unsigned long base)
|
||||
{
|
||||
sifive_test_base = (void *)base;
|
||||
sbi_system_reset_set_device(&sifive_test_reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -17,46 +17,15 @@ static struct fdt_timer *timer_drivers[] = {
|
||||
&fdt_timer_clint
|
||||
};
|
||||
|
||||
static u64 dummy_value(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dummy_event_stop(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void dummy_event_start(u64 next_event)
|
||||
{
|
||||
}
|
||||
|
||||
static struct fdt_timer dummy = {
|
||||
.match_table = NULL,
|
||||
.cold_init = NULL,
|
||||
.warm_init = NULL,
|
||||
.exit = NULL,
|
||||
.value = dummy_value,
|
||||
.event_stop = dummy_event_stop,
|
||||
.event_start = dummy_event_start
|
||||
};
|
||||
|
||||
static struct fdt_timer *current_driver = &dummy;
|
||||
|
||||
u64 fdt_timer_value(void)
|
||||
{
|
||||
return current_driver->value();
|
||||
}
|
||||
|
||||
void fdt_timer_event_stop(void)
|
||||
{
|
||||
current_driver->event_stop();
|
||||
}
|
||||
|
||||
void fdt_timer_event_start(u64 next_event)
|
||||
{
|
||||
current_driver->event_start(next_event);
|
||||
}
|
||||
|
||||
void fdt_timer_exit(void)
|
||||
{
|
||||
if (current_driver->exit)
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#define CLINT_TIMER_MAX_NR 16
|
||||
|
||||
static unsigned long clint_timer_count = 0;
|
||||
static struct clint_data clint_timer[CLINT_TIMER_MAX_NR];
|
||||
static struct clint_data clint_timer[CLINT_TIMER_MAX_NR] = {
|
||||
{.addr = 0x74000000, .first_hartid = 0, .hart_count = 1, .has_64bit_mmio = 0, },
|
||||
};
|
||||
|
||||
static int timer_clint_cold_init(void *fdt, int nodeoff,
|
||||
const struct fdt_match *match)
|
||||
@@ -29,15 +31,18 @@ static int timer_clint_cold_init(void *fdt, int nodeoff,
|
||||
if (1 < clint_timer_count)
|
||||
ctmaster = &clint_timer[0];
|
||||
|
||||
rc = fdt_parse_clint_node(fdt, nodeoff, TRUE, ct);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (clint_timer_count != 1) {
|
||||
rc = fdt_parse_clint_node(fdt, nodeoff, TRUE, ct);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return clint_cold_timer_init(ct, ctmaster);
|
||||
}
|
||||
|
||||
static const struct fdt_match timer_clint_match[] = {
|
||||
{ .compatible = "riscv,clint0" },
|
||||
{ .compatible = "sifive,clint0" },
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -46,7 +51,4 @@ struct fdt_timer fdt_timer_clint = {
|
||||
.cold_init = timer_clint_cold_init,
|
||||
.warm_init = clint_warm_timer_init,
|
||||
.exit = NULL,
|
||||
.value = clint_timer_value,
|
||||
.event_stop = clint_timer_event_stop,
|
||||
.event_start = clint_timer_event_start,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <sbi/riscv_encoding.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_const.h>
|
||||
#include <sbi/sbi_ipi.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_trap.h>
|
||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||
@@ -85,6 +86,12 @@ static int ae350_irqchip_init(bool cold_boot)
|
||||
return plic_warm_irqchip_init(&plic, 2 * hartid, 2 * hartid + 1);
|
||||
}
|
||||
|
||||
static struct sbi_ipi_device plicsw_ipi = {
|
||||
.name = "ae350_plicsw",
|
||||
.ipi_send = plicsw_ipi_send,
|
||||
.ipi_clear = plicsw_ipi_clear
|
||||
};
|
||||
|
||||
/* Initialize IPI for current HART. */
|
||||
static int ae350_ipi_init(bool cold_boot)
|
||||
{
|
||||
@@ -95,6 +102,8 @@ static int ae350_ipi_init(bool cold_boot)
|
||||
AE350_HART_COUNT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sbi_ipi_set_device(&plicsw_ipi);
|
||||
}
|
||||
|
||||
return plicsw_warm_ipi_init();
|
||||
@@ -164,19 +173,12 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.final_init = ae350_final_init,
|
||||
|
||||
.console_init = ae350_console_init,
|
||||
.console_putc = uart8250_putc,
|
||||
.console_getc = uart8250_getc,
|
||||
|
||||
.irqchip_init = ae350_irqchip_init,
|
||||
|
||||
.ipi_init = ae350_ipi_init,
|
||||
.ipi_send = plicsw_ipi_send,
|
||||
.ipi_clear = plicsw_ipi_clear,
|
||||
|
||||
.timer_init = ae350_timer_init,
|
||||
.timer_value = plmt_timer_value,
|
||||
.timer_event_start = plmt_timer_event_start,
|
||||
.timer_event_stop = plmt_timer_event_stop,
|
||||
|
||||
.vendor_ext_provider = ae350_vendor_ext_provider
|
||||
};
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_timer.h>
|
||||
|
||||
static u32 plmt_time_hart_count;
|
||||
static volatile void *plmt_time_base;
|
||||
static volatile u64 *plmt_time_val;
|
||||
static volatile u64 *plmt_time_cmp;
|
||||
|
||||
u64 plmt_timer_value(void)
|
||||
static u64 plmt_timer_value(void)
|
||||
{
|
||||
#if __riscv_xlen == 64
|
||||
return readq_relaxed(plmt_time_val);
|
||||
@@ -32,7 +33,7 @@ u64 plmt_timer_value(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void plmt_timer_event_stop(void)
|
||||
static void plmt_timer_event_stop(void)
|
||||
{
|
||||
u32 target_hart = current_hartid();
|
||||
|
||||
@@ -48,7 +49,7 @@ void plmt_timer_event_stop(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void plmt_timer_event_start(u64 next_event)
|
||||
static void plmt_timer_event_start(u64 next_event)
|
||||
{
|
||||
u32 target_hart = current_hartid();
|
||||
|
||||
@@ -68,6 +69,13 @@ void plmt_timer_event_start(u64 next_event)
|
||||
|
||||
}
|
||||
|
||||
static struct sbi_timer_device plmt_timer = {
|
||||
.name = "ae350_plmt",
|
||||
.timer_value = plmt_timer_value,
|
||||
.timer_event_start = plmt_timer_event_start,
|
||||
.timer_event_stop = plmt_timer_event_stop
|
||||
};
|
||||
|
||||
int plmt_warm_timer_init(void)
|
||||
{
|
||||
u32 target_hart = current_hartid();
|
||||
@@ -93,5 +101,7 @@ int plmt_cold_timer_init(unsigned long base, u32 hart_count)
|
||||
plmt_time_val = (u64 *)(plmt_time_base);
|
||||
plmt_time_cmp = (u64 *)(plmt_time_base + 0x8);
|
||||
|
||||
sbi_timer_set_device(&plmt_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
#ifndef _AE350_PLMT_H_
|
||||
#define _AE350_PLMT_H_
|
||||
|
||||
u64 plmt_timer_value(void);
|
||||
|
||||
void plmt_timer_event_stop(void);
|
||||
|
||||
void plmt_timer_event_start(u64 next_event);
|
||||
|
||||
int plmt_warm_timer_init(void);
|
||||
|
||||
int plmt_cold_timer_init(unsigned long base, u32 hart_count);
|
||||
|
||||
@@ -154,16 +154,9 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.early_init = ariane_early_init,
|
||||
.final_init = ariane_final_init,
|
||||
.console_init = ariane_console_init,
|
||||
.console_putc = uart8250_putc,
|
||||
.console_getc = uart8250_getc,
|
||||
.irqchip_init = ariane_irqchip_init,
|
||||
.ipi_init = ariane_ipi_init,
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_clear = clint_ipi_clear,
|
||||
.timer_init = ariane_timer_init,
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
|
||||
@@ -180,16 +180,9 @@ const struct sbi_platform_operations platform_ops = {
|
||||
.early_init = openpiton_early_init,
|
||||
.final_init = openpiton_final_init,
|
||||
.console_init = openpiton_console_init,
|
||||
.console_putc = uart8250_putc,
|
||||
.console_getc = uart8250_getc,
|
||||
.irqchip_init = openpiton_irqchip_init,
|
||||
.ipi_init = openpiton_ipi_init,
|
||||
.ipi_send = clint_ipi_send,
|
||||
.ipi_clear = clint_ipi_clear,
|
||||
.timer_init = openpiton_timer_init,
|
||||
.timer_value = clint_timer_value,
|
||||
.timer_event_start = clint_timer_event_start,
|
||||
.timer_event_stop = clint_timer_event_stop,
|
||||
};
|
||||
|
||||
const struct sbi_platform platform = {
|
||||
|
||||
@@ -28,7 +28,8 @@ else
|
||||
# This needs to be 2MB aligned for 64-bit system
|
||||
FW_JUMP_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x200000)))
|
||||
endif
|
||||
FW_JUMP_FDT_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x2200000)))
|
||||
#set FDT_ADDR 0xB0000000
|
||||
FW_JUMP_FDT_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x30000000)))
|
||||
FW_PAYLOAD=y
|
||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||
# This needs to be 4MB aligned for 32-bit system
|
||||
|
||||
111
platform/generic/cvitek_riscv.c
Normal file
111
platform/generic/cvitek_riscv.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <platform_override.h>
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_ecall_interface.h>
|
||||
#include <sbi/sbi_string.h>
|
||||
#include <sbi/sbi_types.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/riscv_io.h>
|
||||
|
||||
__asm__(".section .rodata\n"
|
||||
".global suspend_sram_entry\n"
|
||||
".global suspend_sram_end\n"
|
||||
".type suspend_sram_entry, @object\n"
|
||||
".type suspend_sram_end, @object\n"
|
||||
".align 4\n"
|
||||
"suspend_sram_entry:\n"
|
||||
".incbin \"" STRINGIFY(PM_SRAM_BIN_PATH) "\"\n"
|
||||
".align 4\n"
|
||||
"suspend_sram_end:\n"
|
||||
".text\n");
|
||||
|
||||
#define RTC_SRAM_FLAG_ADDR 0x05026ff8
|
||||
#ifdef CONFIG_CV180X
|
||||
#define SUSPEND_SRAM_ENTRY 0x3C000000
|
||||
#endif
|
||||
#ifdef CONFIG_CV181X
|
||||
#define SUSPEND_SRAM_ENTRY 0xC030000
|
||||
#endif
|
||||
|
||||
#define SUSPEND_SRAM_ENTRY 0xC030000
|
||||
|
||||
#define memcpy sbi_memcpy
|
||||
|
||||
static void rtc_latch_pinmux_settings(void)
|
||||
{
|
||||
writel(0x2, (void *)0x50250ac);
|
||||
writel(0x0, (void *)0x5027084);
|
||||
//TODO
|
||||
}
|
||||
|
||||
static void rtc_power_saving_settings_for_suspend(void)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
static int cvitek_sbi_system_suspend_check(u32 sleep_type)
|
||||
{
|
||||
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? 0 : SBI_EINVAL;
|
||||
}
|
||||
|
||||
static int cvitek_sbi_system_suspend(u32 sleep_type,
|
||||
unsigned long mmode_resume_addr)
|
||||
{
|
||||
void (*suspend)(void) = (void *)SUSPEND_SRAM_ENTRY;
|
||||
|
||||
if (sleep_type != SBI_SUSP_SLEEP_TYPE_SUSPEND)
|
||||
return SBI_EINVAL;
|
||||
|
||||
rtc_latch_pinmux_settings();
|
||||
rtc_power_saving_settings_for_suspend();
|
||||
|
||||
/* store warmboot entry for resume*/
|
||||
writel(mmode_resume_addr, (void *)RTC_SRAM_FLAG_ADDR);
|
||||
writel(readl((void *)0x03002000) | 0x10, (void *)0x03002000); //enable TPU clock
|
||||
memcpy((void *)SUSPEND_SRAM_ENTRY, suspend_sram_entry, suspend_sram_end - suspend_sram_entry);
|
||||
|
||||
asm volatile("fence.i" ::: "memory");
|
||||
|
||||
asm volatile("fence rw,rw\n\t");
|
||||
|
||||
suspend();
|
||||
|
||||
wfi();
|
||||
|
||||
return SBI_OK;
|
||||
}
|
||||
|
||||
static struct sbi_system_suspend_device cvitek_sbi_suspend_device = {
|
||||
.name = "cvi-suspend",
|
||||
.system_suspend_check = cvitek_sbi_system_suspend_check,
|
||||
.system_suspend = cvitek_sbi_system_suspend,
|
||||
};
|
||||
|
||||
static int cvitek_riscv_early_init(bool cold_boot, const struct fdt_match *match)
|
||||
{
|
||||
sbi_system_suspend_set_device(&cvitek_sbi_suspend_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fdt_match cvitek_riscv_match[] = {
|
||||
{ .compatible = "cvitek,cv180x" },
|
||||
{ .compatible = "cvitek,cv181x" },
|
||||
{ .compatible = "cvitek,sg200x" }
|
||||
};
|
||||
|
||||
const struct platform_override cvitek_riscv = {
|
||||
.match_table = cvitek_riscv_match,
|
||||
.early_init = cvitek_riscv_early_init,
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user