mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-25 15:51:41 +01:00
Compare commits
230 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6b5188ca14 | ||
![]() |
d5d12a91d1 | ||
![]() |
0412460baf | ||
![]() |
391ec85875 | ||
![]() |
b848d8763a | ||
![]() |
ca7810aecd | ||
![]() |
a8ee82cd8c | ||
![]() |
9a2eeb4aae | ||
![]() |
fabbc00668 | ||
![]() |
91c8a7d5ce | ||
![]() |
8509e46ca6 | ||
![]() |
34da6638ad | ||
![]() |
7a3354ac15 | ||
![]() |
8b1617d13a | ||
![]() |
684090272a | ||
![]() |
0021b43737 | ||
![]() |
64e8b9f72e | ||
![]() |
506928a1be | ||
![]() |
cb568b9b29 | ||
![]() |
7b087781c2 | ||
![]() |
c2be21432c | ||
![]() |
8b00be6927 | ||
![]() |
ed8b8f5254 | ||
![]() |
e1a0cb062a | ||
![]() |
e9775120f5 | ||
![]() |
4640d041d3 | ||
![]() |
d3fcff77a1 | ||
![]() |
6cd4b9b223 | ||
![]() |
a36d455182 | ||
![]() |
cfbabb9ec6 | ||
![]() |
ad2ac29263 | ||
![]() |
1f6866e015 | ||
![]() |
5daa0ef087 | ||
![]() |
e9bc7f1757 | ||
![]() |
cc54184619 | ||
![]() |
f8eec91de8 | ||
![]() |
fc82e84329 | ||
![]() |
74e20293c4 | ||
![]() |
49b0e355e6 | ||
![]() |
ba32021683 | ||
![]() |
9a740f5c46 | ||
![]() |
1b0d71bb9f | ||
![]() |
8e63716c1c | ||
![]() |
14f5c4cb4d | ||
![]() |
7b29264f11 | ||
![]() |
8e9966c1a7 | ||
![]() |
21ba418f1a | ||
![]() |
85cf56c159 | ||
![]() |
22f38ee6c6 | ||
![]() |
56bed1a0fe | ||
![]() |
9d54f431e8 | ||
![]() |
51acd4956a | ||
![]() |
0fee0bf826 | ||
![]() |
d682a0afa1 | ||
![]() |
c8683c57f6 | ||
![]() |
ce7c490719 | ||
![]() |
6f3258e671 | ||
![]() |
127a3f2ab4 | ||
![]() |
8234fc1bdf | ||
![]() |
ef9f02e7fb | ||
![]() |
88f58a3694 | ||
![]() |
9899b59beb | ||
![]() |
bd7ef41398 | ||
![]() |
dcdaf30274 | ||
![]() |
60b78fee92 | ||
![]() |
11d14ae7f2 | ||
![]() |
98aa12738d | ||
![]() |
b6e520b2a8 | ||
![]() |
2f63f2465c | ||
![]() |
4f2acb53e2 | ||
![]() |
c316fa38c2 | ||
![]() |
e54cb3298b | ||
![]() |
3f3d401d2d | ||
![]() |
7105c189f6 | ||
![]() |
7f09fba86e | ||
![]() |
49372f2691 | ||
![]() |
8ce486a781 | ||
![]() |
46e744ab67 | ||
![]() |
37a0d83b6d | ||
![]() |
19664f6757 | ||
![]() |
d32b0a92db | ||
![]() |
5019fd124b | ||
![]() |
ee69f8eeb3 | ||
![]() |
d10c1f4acd | ||
![]() |
c9b388d578 | ||
![]() |
e238459fab | ||
![]() |
1664d0efce | ||
![]() |
a90cf6b186 | ||
![]() |
622cc5f014 | ||
![]() |
cbaa9b0333 | ||
![]() |
adf44b51ba | ||
![]() |
111afc1230 | ||
![]() |
a69eb6cc65 | ||
![]() |
5a0ca098f1 | ||
![]() |
1c4ce74f51 | ||
![]() |
1fbe7778c9 | ||
![]() |
9529e360df | ||
![]() |
a6a85579b6 | ||
![]() |
0723bab8fe | ||
![]() |
eccb9df5cf | ||
![]() |
bc317a378f | ||
![]() |
d514a8f0dc | ||
![]() |
68d7b85ec7 | ||
![]() |
5616aa4f4a | ||
![]() |
b126ce4a8f | ||
![]() |
0b1cf2f645 | ||
![]() |
76af9d40da | ||
![]() |
013dbb3a60 | ||
![]() |
3e76a607b5 | ||
![]() |
2adc94b466 | ||
![]() |
26bbff5f76 | ||
![]() |
de80e9337d | ||
![]() |
662e631cce | ||
![]() |
422f0e0486 | ||
![]() |
b9edf49b67 | ||
![]() |
f27203525a | ||
![]() |
7198e1d06f | ||
![]() |
7d28d3be50 | ||
![]() |
8e86b23db9 | ||
![]() |
11c0008862 | ||
![]() |
860a376817 | ||
![]() |
83db3af5f9 | ||
![]() |
1545afd342 | ||
![]() |
88b790f129 | ||
![]() |
4e21ccacd1 | ||
![]() |
0374ccf3f1 | ||
![]() |
caa5eeacac | ||
![]() |
994c8cfb29 | ||
![]() |
4489876e93 | ||
![]() |
3f66465fb6 | ||
![]() |
c6fdbcf83f | ||
![]() |
6f1fe98c2f | ||
![]() |
d76a196bfc | ||
![]() |
7738345396 | ||
![]() |
c6530012d4 | ||
![]() |
a07402ac9c | ||
![]() |
187127fb89 | ||
![]() |
551c70c040 | ||
![]() |
9dc5ec5c51 | ||
![]() |
5e5675874c | ||
![]() |
69be3dff9d | ||
![]() |
2b79b694a8 | ||
![]() |
415ecf28f7 | ||
![]() |
8c362e7d06 | ||
![]() |
2ea7799d56 | ||
![]() |
79e42eb2d6 | ||
![]() |
b20ed9febe | ||
![]() |
ce1d6188a2 | ||
![]() |
adc3388d76 | ||
![]() |
cb8271c8e4 | ||
![]() |
ff65bfec4e | ||
![]() |
295e5f3c69 | ||
![]() |
fab0379bb6 | ||
![]() |
f067bb84cf | ||
![]() |
1bc67db80c | ||
![]() |
575bb4e8ca | ||
![]() |
616da52e18 | ||
![]() |
90a9dd2b22 | ||
![]() |
851c14d455 | ||
![]() |
9a7a677d5f | ||
![]() |
a3a3c60b66 | ||
![]() |
4eacd8229b | ||
![]() |
998ed43fde | ||
![]() |
4ee0c57969 | ||
![]() |
3a69d12fc3 | ||
![]() |
bfeb305e0f | ||
![]() |
1e62705adc | ||
![]() |
73cf511914 | ||
![]() |
7fb474b9dd | ||
![]() |
f726f2dc01 | ||
![]() |
023f0ad2d9 | ||
![]() |
994ace30f7 | ||
![]() |
be4903ae00 | ||
![]() |
cad6c91045 | ||
![]() |
a6ab94fdbf | ||
![]() |
97a17c2e5c | ||
![]() |
dbc3d8f0ef | ||
![]() |
d4b563c881 | ||
![]() |
5b8b377178 | ||
![]() |
5a6be99cc5 | ||
![]() |
1a754bb365 | ||
![]() |
b0c9df514b | ||
![]() |
e576b3e620 | ||
![]() |
474a9d4555 | ||
![]() |
d62f6da062 | ||
![]() |
4035ae94be | ||
![]() |
9cd95e13bb | ||
![]() |
c1e47d0c3f | ||
![]() |
5c5cbb53a4 | ||
![]() |
3383d6a4d1 | ||
![]() |
d44568a0f2 | ||
![]() |
499601a4ff | ||
![]() |
794986f87f | ||
![]() |
47d676570d | ||
![]() |
31fecad46d | ||
![]() |
722f80d8e9 | ||
![]() |
7924a0b220 | ||
![]() |
1b42d3ace3 | ||
![]() |
555bdb1cf3 | ||
![]() |
d552fc8d36 | ||
![]() |
b6b7220a47 | ||
![]() |
2dfbd3c0e2 | ||
![]() |
4998a712b2 | ||
![]() |
f3f4604c19 | ||
![]() |
f2ccf2f783 | ||
![]() |
3a69cc1487 | ||
![]() |
8e2ef4f7af | ||
![]() |
34612193af | ||
![]() |
99792653de | ||
![]() |
7127aaaaf7 | ||
![]() |
811da5c541 | ||
![]() |
9f73669959 | ||
![]() |
55e79f823d | ||
![]() |
10509405b2 | ||
![]() |
5f56314618 | ||
![]() |
222132f48c | ||
![]() |
65b4c7c01e | ||
![]() |
8f96070067 | ||
![]() |
01250d0044 | ||
![]() |
ce4c0188d9 | ||
![]() |
6ad8917b7e | ||
![]() |
5d53b55aa7 | ||
![]() |
a26dc609df | ||
![]() |
3b7c204dca | ||
![]() |
632f59392b | ||
![]() |
5d025eb235 | ||
![]() |
fb688d9e9d | ||
![]() |
8257262dbf | ||
![]() |
6dde43584f | ||
![]() |
5b9960379f |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,3 +9,5 @@ install/
|
|||||||
|
|
||||||
# Development friendly files
|
# Development friendly files
|
||||||
tags
|
tags
|
||||||
|
cscope*
|
||||||
|
*.swp
|
||||||
|
25
Kconfig
Normal file
25
Kconfig
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
mainmenu "OpenSBI $(OPENSBI_PLATFORM) Configuration"
|
||||||
|
|
||||||
|
config OPENSBI_SRC_DIR
|
||||||
|
string
|
||||||
|
option env="OPENSBI_SRC_DIR"
|
||||||
|
|
||||||
|
config OPENSBI_PLATFORM
|
||||||
|
string
|
||||||
|
option env="OPENSBI_PLATFORM"
|
||||||
|
|
||||||
|
config OPENSBI_PLATFORM_SRC_DIR
|
||||||
|
string
|
||||||
|
option env="OPENSBI_PLATFORM_SRC_DIR"
|
||||||
|
|
||||||
|
menu "Platform Options"
|
||||||
|
source "$(OPENSBI_PLATFORM_SRC_DIR)/Kconfig"
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/sbi/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/firmware/Kconfig"
|
158
Makefile
158
Makefile
@@ -47,11 +47,14 @@ ifdef PLATFORM_DIR
|
|||||||
platform_parent_dir=$(platform_dir_path)
|
platform_parent_dir=$(platform_dir_path)
|
||||||
else
|
else
|
||||||
PLATFORM=$(shell basename $(platform_dir_path))
|
PLATFORM=$(shell basename $(platform_dir_path))
|
||||||
platform_parent_dir=$(subst $(PLATFORM),,$(platform_dir_path))
|
platform_parent_dir=$(shell realpath ${platform_dir_path}/..)
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
platform_parent_dir=$(src_dir)/platform
|
platform_parent_dir=$(src_dir)/platform
|
||||||
endif
|
endif
|
||||||
|
ifndef PLATFORM_DEFCONFIG
|
||||||
|
PLATFORM_DEFCONFIG=defconfig
|
||||||
|
endif
|
||||||
|
|
||||||
# Check if verbosity is ON for build process
|
# Check if verbosity is ON for build process
|
||||||
CMD_PREFIX_DEFAULT := @
|
CMD_PREFIX_DEFAULT := @
|
||||||
@@ -70,6 +73,20 @@ export libsbi_dir=$(CURDIR)/lib/sbi
|
|||||||
export libsbiutils_dir=$(CURDIR)/lib/utils
|
export libsbiutils_dir=$(CURDIR)/lib/utils
|
||||||
export firmware_dir=$(CURDIR)/firmware
|
export firmware_dir=$(CURDIR)/firmware
|
||||||
|
|
||||||
|
# Setup variables for kconfig
|
||||||
|
ifdef PLATFORM
|
||||||
|
export PYTHONDONTWRITEBYTECODE=1
|
||||||
|
export KCONFIG_DIR=$(platform_build_dir)/kconfig
|
||||||
|
export KCONFIG_AUTOLIST=$(KCONFIG_DIR)/auto.list
|
||||||
|
export KCONFIG_AUTOHEADER=$(KCONFIG_DIR)/autoconf.h
|
||||||
|
export KCONFIG_AUTOCMD=$(KCONFIG_DIR)/auto.conf.cmd
|
||||||
|
export KCONFIG_CONFIG=$(KCONFIG_DIR)/.config
|
||||||
|
# Additional exports for include paths in Kconfig files
|
||||||
|
export OPENSBI_SRC_DIR=$(src_dir)
|
||||||
|
export OPENSBI_PLATFORM=$(PLATFORM)
|
||||||
|
export OPENSBI_PLATFORM_SRC_DIR=$(platform_src_dir)
|
||||||
|
endif
|
||||||
|
|
||||||
# Find library version
|
# Find library version
|
||||||
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
|
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
|
||||||
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
|
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
|
||||||
@@ -153,6 +170,9 @@ OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fP
|
|||||||
# Check whether the compiler supports -m(no-)save-restore
|
# Check whether the compiler supports -m(no-)save-restore
|
||||||
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep "\-save\-restore" >/dev/null && echo n || echo y)
|
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep "\-save\-restore" >/dev/null && echo n || echo y)
|
||||||
|
|
||||||
|
# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions
|
||||||
|
CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep "zicsr\|zifencei" > /dev/null && echo n || echo y)
|
||||||
|
|
||||||
# Build Info:
|
# Build Info:
|
||||||
# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp
|
# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp
|
||||||
# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info
|
# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info
|
||||||
@@ -180,12 +200,38 @@ libsbi-object-mks=$(shell if [ -d $(libsbi_dir) ]; then find $(libsbi_dir) -inam
|
|||||||
libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
|
libsbiutils-object-mks=$(shell if [ -d $(libsbiutils_dir) ]; then find $(libsbiutils_dir) -iname "objects.mk" | sort -r; fi)
|
||||||
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
|
firmware-object-mks=$(shell if [ -d $(firmware_dir) ]; then find $(firmware_dir) -iname "objects.mk" | sort -r; fi)
|
||||||
|
|
||||||
# Include platform specifig config.mk
|
# The "make all" rule should always be first rule
|
||||||
|
.PHONY: all
|
||||||
|
all:
|
||||||
|
|
||||||
|
# Include platform specific .config
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
include $(platform_src_dir)/config.mk
|
.PHONY: menuconfig
|
||||||
|
menuconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
|
||||||
|
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/menuconfig.py $(src_dir)/Kconfig
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
|
||||||
|
|
||||||
|
.PHONY: savedefconfig
|
||||||
|
savedefconfig: $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
|
||||||
|
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/savedefconfig.py --kconfig $(src_dir)/Kconfig --out $(KCONFIG_DIR)/defconfig
|
||||||
|
|
||||||
|
$(KCONFIG_CONFIG): $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG) $(platform_src_dir)/Kconfig $(src_dir)/Kconfig
|
||||||
|
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/defconfig.py --kconfig $(src_dir)/Kconfig $(platform_src_dir)/configs/$(PLATFORM_DEFCONFIG)
|
||||||
|
$(CMD_PREFIX)$(src_dir)/scripts/Kconfiglib/genconfig.py --header-path $(KCONFIG_AUTOHEADER) --sync-deps $(KCONFIG_DIR) --file-list $(KCONFIG_AUTOLIST) $(src_dir)/Kconfig
|
||||||
|
|
||||||
|
$(KCONFIG_AUTOCMD): $(KCONFIG_CONFIG)
|
||||||
|
$(CMD_PREFIX)mkdir -p $(KCONFIG_DIR)
|
||||||
|
$(CMD_PREFIX)printf "%s: " $(KCONFIG_CONFIG) > $(KCONFIG_AUTOCMD)
|
||||||
|
$(CMD_PREFIX)cat $(KCONFIG_AUTOLIST) | tr '\n' ' ' >> $(KCONFIG_AUTOCMD)
|
||||||
|
|
||||||
|
include $(KCONFIG_CONFIG)
|
||||||
|
include $(KCONFIG_AUTOCMD)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Include all object.mk files
|
# Include all objects.mk files
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
include $(platform-object-mks)
|
include $(platform-object-mks)
|
||||||
endif
|
endif
|
||||||
@@ -195,8 +241,8 @@ include $(firmware-object-mks)
|
|||||||
|
|
||||||
# Setup list of objects
|
# Setup list of objects
|
||||||
libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
|
libsbi-objs-path-y=$(foreach obj,$(libsbi-objs-y),$(build_dir)/lib/sbi/$(obj))
|
||||||
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
|
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
|
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(platform_build_dir)/lib/utils/$(obj))
|
||||||
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
|
platform-objs-path-y=$(foreach obj,$(platform-objs-y),$(platform_build_dir)/$(obj))
|
||||||
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
|
firmware-bins-path-y=$(foreach bin,$(firmware-bins-y),$(platform_build_dir)/firmware/$(bin))
|
||||||
endif
|
endif
|
||||||
@@ -223,7 +269,11 @@ ifndef PLATFORM_RISCV_ABI
|
|||||||
endif
|
endif
|
||||||
ifndef PLATFORM_RISCV_ISA
|
ifndef PLATFORM_RISCV_ISA
|
||||||
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
|
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
|
||||||
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
|
ifeq ($(CC_SUPPORT_ZICSR_ZIFENCEI), y)
|
||||||
|
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc_zicsr_zifencei
|
||||||
|
else
|
||||||
|
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
|
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
|
||||||
endif
|
endif
|
||||||
@@ -273,6 +323,9 @@ ifeq ($(BUILD_INFO),y)
|
|||||||
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
|
GENFLAGS += -DOPENSBI_BUILD_TIME_STAMP="\"$(OPENSBI_BUILD_TIME_STAMP)\""
|
||||||
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
|
GENFLAGS += -DOPENSBI_BUILD_COMPILER_VERSION="\"$(OPENSBI_BUILD_COMPILER_VERSION)\""
|
||||||
endif
|
endif
|
||||||
|
ifdef PLATFORM
|
||||||
|
GENFLAGS += -include $(KCONFIG_AUTOHEADER)
|
||||||
|
endif
|
||||||
GENFLAGS += $(libsbiutils-genflags-y)
|
GENFLAGS += $(libsbiutils-genflags-y)
|
||||||
GENFLAGS += $(platform-genflags-y)
|
GENFLAGS += $(platform-genflags-y)
|
||||||
GENFLAGS += $(firmware-genflags-y)
|
GENFLAGS += $(firmware-genflags-y)
|
||||||
@@ -397,66 +450,73 @@ compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
|||||||
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
|
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
|
||||||
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
|
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
|
||||||
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
|
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
|
||||||
|
compile_carray = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
|
echo " CARRAY $(subst $(build_dir)/,,$(1))"; \
|
||||||
|
$(eval CARRAY_VAR_LIST := $(carray-$(subst .c,,$(shell basename $(1)))-y)) \
|
||||||
|
$(src_dir)/scripts/carray.sh -i $(2) -l "$(CARRAY_VAR_LIST)" > $(1)
|
||||||
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
|
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
|
||||||
echo "$(1:.dep=$(2)): $(3)" >> $(1)
|
echo "$(1:.dep=$(2)): $(3)" >> $(1)
|
||||||
|
|
||||||
targets-y = $(build_dir)/lib/libsbi.a
|
targets-y = $(build_dir)/lib/libsbi.a
|
||||||
targets-y += $(build_dir)/lib/libsbiutils.a
|
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
targets-y += $(platform_build_dir)/lib/libplatsbi.a
|
targets-y += $(platform_build_dir)/lib/libplatsbi.a
|
||||||
endif
|
endif
|
||||||
targets-y += $(firmware-bins-path-y)
|
targets-y += $(firmware-bins-path-y)
|
||||||
|
|
||||||
# Default rule "make" should always be first rule
|
# The default "make all" rule
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(targets-y)
|
all: $(targets-y)
|
||||||
|
|
||||||
# Preserve all intermediate files
|
# Preserve all intermediate files
|
||||||
.SECONDARY:
|
.SECONDARY:
|
||||||
|
|
||||||
|
# Rules for lib/sbi sources
|
||||||
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
|
$(build_dir)/lib/libsbi.a: $(libsbi-objs-path-y)
|
||||||
$(call compile_ar,$@,$^)
|
$(call compile_ar,$@,$^)
|
||||||
|
|
||||||
$(build_dir)/lib/libsbiutils.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y)
|
|
||||||
$(call compile_ar,$@,$^)
|
|
||||||
|
|
||||||
$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
|
$(platform_build_dir)/lib/libplatsbi.a: $(libsbi-objs-path-y) $(libsbiutils-objs-path-y) $(platform-objs-path-y)
|
||||||
$(call compile_ar,$@,$^)
|
$(call compile_ar,$@,$^)
|
||||||
|
|
||||||
$(build_dir)/%.dep: $(src_dir)/%.c
|
$(build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG)
|
||||||
|
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
|
||||||
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
|
$(build_dir)/%.c: $(src_dir)/%.carray
|
||||||
|
$(call compile_carray,$@,$<)
|
||||||
|
|
||||||
|
$(build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG)
|
||||||
$(call compile_cc_dep,$@,$<)
|
$(call compile_cc_dep,$@,$<)
|
||||||
|
|
||||||
$(build_dir)/%.o: $(src_dir)/%.c
|
$(build_dir)/%.o: $(src_dir)/%.c
|
||||||
$(call compile_cc,$@,$<)
|
$(call compile_cc,$@,$<)
|
||||||
|
|
||||||
|
$(build_dir)/%.o: $(build_dir)/%.c
|
||||||
|
$(call compile_cc,$@,$<)
|
||||||
|
|
||||||
ifeq ($(BUILD_INFO),y)
|
ifeq ($(BUILD_INFO),y)
|
||||||
$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
|
$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
|
||||||
$(call compile_cc,$@,$<)
|
$(call compile_cc,$@,$<)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(build_dir)/%.dep: $(src_dir)/%.S
|
$(build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG)
|
||||||
$(call compile_as_dep,$@,$<)
|
$(call compile_as_dep,$@,$<)
|
||||||
|
|
||||||
$(build_dir)/%.o: $(src_dir)/%.S
|
$(build_dir)/%.o: $(src_dir)/%.S
|
||||||
$(call compile_as,$@,$<)
|
$(call compile_as,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
|
# Rules for platform sources
|
||||||
$(call compile_objcopy,$@,$<)
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.carray $(KCONFIG_CONFIG)
|
||||||
|
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
|
||||||
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
|
$(platform_build_dir)/%.c: $(platform_src_dir)/%.carray
|
||||||
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
|
$(call compile_carray,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c $(KCONFIG_CONFIG)
|
||||||
$(call compile_cpp,$@,$<)
|
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
|
|
||||||
$(call compile_cc_dep,$@,$<)
|
$(call compile_cc_dep,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
|
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c $(KCONFIG_CONFIG)
|
||||||
$(call compile_cc,$@,$<)
|
|
||||||
|
|
||||||
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
|
|
||||||
$(call compile_cc,$@,$<)
|
$(call compile_cc,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
||||||
@@ -465,8 +525,8 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
|||||||
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
|
$(platform_build_dir)/%.o: $(platform_src_dir)/%.S
|
||||||
$(call compile_as,$@,$<)
|
$(call compile_as,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.dts $(KCONFIG_CONFIG)
|
||||||
$(call compile_gen_dep,$@,.dtb,$<)
|
$(call compile_gen_dep,$@,.dtb,$< $(KCONFIG_CONFIG))
|
||||||
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
|
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
|
||||||
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
@@ -476,13 +536,30 @@ $(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
|
|||||||
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
|
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
|
||||||
$(call compile_dts,$@,$<)
|
$(call compile_dts,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(src_dir)/%.c
|
# Rules for lib/utils and firmware sources
|
||||||
|
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
|
||||||
|
$(call compile_objcopy,$@,$<)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.elf: $(platform_build_dir)/%.o $(platform_build_dir)/%.elf.ld $(platform_build_dir)/lib/libplatsbi.a
|
||||||
|
$(call compile_elf,$@,$@.ld,$< $(platform_build_dir)/lib/libplatsbi.a)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.ld: $(src_dir)/%.ldS
|
||||||
|
$(call compile_cpp,$@,$<)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.dep: $(src_dir)/%.carray $(KCONFIG_CONFIG)
|
||||||
|
$(call compile_gen_dep,$@,.c,$< $(KCONFIG_CONFIG))
|
||||||
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.c: $(src_dir)/%.carray
|
||||||
|
$(call compile_carray,$@,$<)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.dep: $(src_dir)/%.c $(KCONFIG_CONFIG)
|
||||||
$(call compile_cc_dep,$@,$<)
|
$(call compile_cc_dep,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.o: $(src_dir)/%.c
|
$(platform_build_dir)/%.o: $(src_dir)/%.c
|
||||||
$(call compile_cc,$@,$<)
|
$(call compile_cc,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(src_dir)/%.S
|
$(platform_build_dir)/%.dep: $(src_dir)/%.S $(KCONFIG_CONFIG)
|
||||||
$(call compile_as_dep,$@,$<)
|
$(call compile_as_dep,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.o: $(src_dir)/%.S
|
$(platform_build_dir)/%.o: $(src_dir)/%.S
|
||||||
@@ -526,7 +603,6 @@ endif
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
install_targets-y = install_libsbi
|
install_targets-y = install_libsbi
|
||||||
install_targets-y += install_libsbiutils
|
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
install_targets-y += install_libplatsbi
|
install_targets-y += install_libplatsbi
|
||||||
install_targets-y += install_firmwares
|
install_targets-y += install_firmwares
|
||||||
@@ -541,17 +617,12 @@ install_libsbi: $(build_dir)/lib/libsbi.a
|
|||||||
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
|
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi)
|
||||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
|
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbi.a,$(build_dir)/lib/libsbi.a)
|
||||||
|
|
||||||
.PHONY: install_libsbiutils
|
|
||||||
install_libsbiutils: $(build_dir)/lib/libsbiutils.a
|
|
||||||
$(call inst_header_dir,$(install_root_dir)/$(install_include_path),$(include_dir)/sbi_utils)
|
|
||||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/libsbiutils.a,$(build_dir)/lib/libsbiutils.a)
|
|
||||||
|
|
||||||
.PHONY: install_libplatsbi
|
.PHONY: install_libplatsbi
|
||||||
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a
|
install_libplatsbi: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a
|
||||||
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
|
$(call inst_file,$(install_root_dir)/$(install_lib_path)/opensbi/$(platform_subdir)/lib/libplatsbi.a,$(platform_build_dir)/lib/libplatsbi.a)
|
||||||
|
|
||||||
.PHONY: install_firmwares
|
.PHONY: install_firmwares
|
||||||
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(build_dir)/lib/libsbiutils.a $(firmware-bins-path-y)
|
install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsbi.a $(firmware-bins-path-y)
|
||||||
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
|
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-elfs-path-y))
|
||||||
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
|
$(call inst_file_list,$(install_root_dir),$(build_dir),$(install_firmware_path)/$(platform_subdir)/firmware,$(firmware-bins-path-y))
|
||||||
|
|
||||||
@@ -559,6 +630,17 @@ install_firmwares: $(platform_build_dir)/lib/libplatsbi.a $(build_dir)/lib/libsb
|
|||||||
install_docs: $(build_dir)/docs/latex/refman.pdf
|
install_docs: $(build_dir)/docs/latex/refman.pdf
|
||||||
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
|
$(call inst_file,$(install_root_dir)/$(install_docs_path)/refman.pdf,$(build_dir)/docs/latex/refman.pdf)
|
||||||
|
|
||||||
|
.PHONY: cscope
|
||||||
|
cscope:
|
||||||
|
$(CMD_PREFIX)find \
|
||||||
|
"$(src_dir)/firmware" \
|
||||||
|
"$(src_dir)/include" \
|
||||||
|
"$(src_dir)/lib" \
|
||||||
|
"$(platform_src_dir)" \
|
||||||
|
-name "*.[chS]" -print > cscope.files
|
||||||
|
$(CMD_PREFIX)echo "$(KCONFIG_AUTOHEADER)" >> cscope.files
|
||||||
|
$(CMD_PREFIX)cscope -bkq -i cscope.files -f cscope.out
|
||||||
|
|
||||||
# Rule for "make clean"
|
# Rule for "make clean"
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@@ -588,6 +670,8 @@ ifeq ($(install_root_dir),$(install_root_dir_default)/usr)
|
|||||||
$(if $(V), @echo " RM $(install_root_dir_default)")
|
$(if $(V), @echo " RM $(install_root_dir_default)")
|
||||||
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
|
$(CMD_PREFIX)rm -rf $(install_root_dir_default)
|
||||||
endif
|
endif
|
||||||
|
$(if $(V), @echo " RM $(src_dir)/cscope*")
|
||||||
|
$(CMD_PREFIX)rm -f $(src_dir)/cscope*
|
||||||
|
|
||||||
.PHONY: FORCE
|
.PHONY: FORCE
|
||||||
FORCE:
|
FORCE:
|
||||||
|
25
README.md
25
README.md
@@ -92,8 +92,8 @@ N.B. Any S-mode boot loader (i.e. U-Boot) doesn't need to support HSM extension,
|
|||||||
as it doesn't need to boot all the harts. The operating system should be
|
as it doesn't need to boot all the harts. The operating system should be
|
||||||
capable enough to bring up all other non-booting harts using HSM extension.
|
capable enough to bring up all other non-booting harts using HSM extension.
|
||||||
|
|
||||||
Required Toolchain
|
Required Toolchain and Packages
|
||||||
------------------
|
-------------------------------
|
||||||
|
|
||||||
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
|
OpenSBI can be compiled natively or cross-compiled on a x86 host. For
|
||||||
cross-compilation, you can build your own toolchain, download a prebuilt one
|
cross-compilation, you can build your own toolchain, download a prebuilt one
|
||||||
@@ -115,6 +115,14 @@ triple is used (e.g. *-target riscv64-unknown-elf*).
|
|||||||
Please note that only a 64-bit version of the toolchain is available in
|
Please note that only a 64-bit version of the toolchain is available in
|
||||||
the Bootlin toolchain repository for now.
|
the Bootlin toolchain repository for now.
|
||||||
|
|
||||||
|
In addition to a toolchain, OpenSBI also requires the following packages on
|
||||||
|
the host:
|
||||||
|
|
||||||
|
1. device-tree-compiler: The device tree compiler for compiling device
|
||||||
|
tree sources (DTS files).
|
||||||
|
2. python3: The python 3.0 (or compatible) language support for various
|
||||||
|
scripts.
|
||||||
|
|
||||||
Building and Installing the OpenSBI Platform-Independent Library
|
Building and Installing the OpenSBI Platform-Independent Library
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
@@ -196,6 +204,19 @@ top-level make command line. These options, such as *PLATFORM_<xyz>* or
|
|||||||
*docs/platform/<platform_name>.md* files and
|
*docs/platform/<platform_name>.md* files and
|
||||||
*docs/firmware/<firmware_name>.md* files.
|
*docs/firmware/<firmware_name>.md* files.
|
||||||
|
|
||||||
|
All OpenSBI platforms support Kconfig style build-time configuration. Users
|
||||||
|
can change the build-time configuration of a platform using a graphical
|
||||||
|
interface as follows:
|
||||||
|
```
|
||||||
|
make PLATFORM=<platform_subdir> menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternately, an OpenSBI platform can have multiple default configurations
|
||||||
|
and users can select a custom default configuration as follows:
|
||||||
|
```
|
||||||
|
make PLATFORM=<platform_subdir> PLATFORM_DEFCONFIG=<platform_custom_defconfig>
|
||||||
|
```
|
||||||
|
|
||||||
Building 32-bit / 64-bit OpenSBI Images
|
Building 32-bit / 64-bit OpenSBI Images
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
By default, building OpenSBI generates 32-bit or 64-bit images based on the
|
By default, building OpenSBI generates 32-bit or 64-bit images based on the
|
||||||
|
@@ -29,7 +29,7 @@ and "top:".
|
|||||||
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
|
5. Maintainers should use "Rebase and Merge" when using GitHub to merge pull
|
||||||
requests to avoid creating unnecessary merge commits.
|
requests to avoid creating unnecessary merge commits.
|
||||||
6. Maintainers should avoid creating branches directly in the main
|
6. Maintainers should avoid creating branches directly in the main
|
||||||
riscv/opensbi repository. Instead prefer using a fork of the riscv/opensbi main
|
riscv/opensbi repository. Instead, prefer using a fork of the riscv/opensbi main
|
||||||
repository and branches within that fork to create pull requests.
|
repository and branches within that fork to create pull requests.
|
||||||
7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
|
7. A maintainer cannot merge his own pull requests in the riscv/opensbi main
|
||||||
repository.
|
repository.
|
||||||
|
@@ -2,7 +2,7 @@ OpenSBI Domain Support
|
|||||||
======================
|
======================
|
||||||
|
|
||||||
An OpenSBI domain is a system-level partition (subset) of underlying hardware
|
An OpenSBI domain is a system-level partition (subset) of underlying hardware
|
||||||
having it's own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
|
having its own memory regions (RAM and MMIO devices) and HARTs. The OpenSBI
|
||||||
will try to achieve secure isolation between domains using RISC-V platform
|
will try to achieve secure isolation between domains using RISC-V platform
|
||||||
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
|
features such as PMP, ePMP, IOPMP, SiFive Shield, etc.
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ Important entities which help implement OpenSBI domain support are:
|
|||||||
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
|
Each HART of a RISC-V platform must have an OpenSBI domain assigned to it.
|
||||||
The OpenSBI platform support is responsible for populating domains and
|
The OpenSBI platform support is responsible for populating domains and
|
||||||
providing HART id to domain mapping. The OpenSBI domain support will by
|
providing HART id to domain mapping. The OpenSBI domain support will by
|
||||||
default assign **the ROOT domain** to all HARTs of a RISC-V platform so
|
default assign **the ROOT domain** to all HARTs of a RISC-V platform, so
|
||||||
it is not mandatory for the OpenSBI platform support to populate domains.
|
it is not mandatory for the OpenSBI platform support to populate domains.
|
||||||
|
|
||||||
Domain Memory Region
|
Domain Memory Region
|
||||||
@@ -29,7 +29,7 @@ OpenSBI and has following details:
|
|||||||
* **base** - The base address of a memory region is **2 ^ order**
|
* **base** - The base address of a memory region is **2 ^ order**
|
||||||
aligned start address
|
aligned start address
|
||||||
* **flags** - The flags of a memory region represent memory type (i.e.
|
* **flags** - The flags of a memory region represent memory type (i.e.
|
||||||
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc)
|
RAM or MMIO) and allowed accesses (i.e. READ, WRITE, EXECUTE, etc.)
|
||||||
|
|
||||||
Domain Instance
|
Domain Instance
|
||||||
---------------
|
---------------
|
||||||
|
@@ -53,7 +53,7 @@ the booting stage to follow OpenSBI firmware.
|
|||||||
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
|
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
|
||||||
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
|
to OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In such
|
||||||
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
|
case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree in the
|
||||||
.text section of the final firmware.
|
.rodata section of the final firmware.
|
||||||
|
|
||||||
Firmware Configuration and Compilation
|
Firmware Configuration and Compilation
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
@@ -20,7 +20,7 @@ the booting stage binary to follow OpenSBI firmware.
|
|||||||
A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
|
A platform can enable *FW_DYNAMIC* firmware using any of the following methods.
|
||||||
|
|
||||||
1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
|
1. Specifying `FW_DYNAMIC=y` on the top level `make` command line.
|
||||||
2. Specifying `FW_DYNAMIC=y` in the target platform *config.mk* configuration
|
2. Specifying `FW_DYNAMIC=y` in the target platform *objects.mk* configuration
|
||||||
file.
|
file.
|
||||||
|
|
||||||
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
|
The compiled *FW_DYNAMIC* firmware ELF file is named *fw_dynamic.elf*. It's
|
||||||
@@ -31,6 +31,6 @@ directory.
|
|||||||
*FW_DYNAMIC* Firmware Configuration Options
|
*FW_DYNAMIC* Firmware Configuration Options
|
||||||
-------------------------------------------
|
-------------------------------------------
|
||||||
|
|
||||||
The *FW_DYNAMIC* firmware does not requires any platform specific configuration
|
The *FW_DYNAMIC* firmware does not require any platform specific configuration
|
||||||
parameters because all required information is passed by previous booting stage
|
parameters because all required information is passed by previous booting stage
|
||||||
at runtime via *struct fw_dynamic_info*.
|
at runtime via *struct fw_dynamic_info*.
|
||||||
|
@@ -15,7 +15,7 @@ and the booting stage binary to follow the OpenSBI firmware.
|
|||||||
A platform *FW_JUMP* firmware can be enabled by any of the following methods:
|
A platform *FW_JUMP* firmware can be enabled by any of the following methods:
|
||||||
|
|
||||||
1. Specifying `FW_JUMP=y` on the top level `make` command line.
|
1. Specifying `FW_JUMP=y` on the top level `make` command line.
|
||||||
2. Specifying `FW_JUMP=y` in the target platform *config.mk* configuration file.
|
2. Specifying `FW_JUMP=y` in the target platform *objects.mk* configuration file.
|
||||||
|
|
||||||
The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
|
The compiled *FW_JUMP* firmware ELF file is named *fw_jump.elf*. Its expanded
|
||||||
image file is *fw_jump.bin*. Both files are created in the platform-specific
|
image file is *fw_jump.bin*. Both files are created in the platform-specific
|
||||||
@@ -26,7 +26,7 @@ build directory under the *build/platform/<platform_subdir>/firmware* directory.
|
|||||||
|
|
||||||
To operate correctly, a *FW_JUMP* firmware requires some configuration
|
To operate correctly, a *FW_JUMP* firmware requires some configuration
|
||||||
parameters to be defined using either the top level `make` command line or the
|
parameters to be defined using either the top level `make` command line or the
|
||||||
target platform *config.mk* configuration file. The possible parameters are as
|
target platform *objects.mk* configuration file. The possible parameters are as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
|
* **FW_JUMP_ADDR** - Address of the entry point of the booting stage to be
|
||||||
@@ -41,6 +41,22 @@ follows:
|
|||||||
provided, then the OpenSBI firmware will pass the FDT address passed by the
|
provided, then the OpenSBI firmware will pass the FDT address passed by the
|
||||||
previous booting stage to the next booting stage.
|
previous booting stage to the next booting stage.
|
||||||
|
|
||||||
|
When using the default *FW_JUMP_FDT_ADDR* with *PLATFORM=generic*, you must
|
||||||
|
ensure *FW_JUMP_FDT_ADDR* is set high enough to avoid overwriting the kernel.
|
||||||
|
You can use the following method.
|
||||||
|
|
||||||
|
```
|
||||||
|
${CROSS_COMPILE}objdump -h $KERNEL_ELF | sort -k 5,5 | awk -n '/^ +[0-9]+ /\
|
||||||
|
{addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' \
|
||||||
|
| (( `tail -1` > 0x2200000 )) && echo fdt overlaps kernel,\
|
||||||
|
increase FW_JUMP_FDT_ADDR
|
||||||
|
|
||||||
|
${LLVM}objdump -h --show-lma $KERNEL_ELF | sort -k 5,5 | \
|
||||||
|
awk -n '/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}'\
|
||||||
|
| (( `tail -1` > 0x2200000 )) && echo fdt overlaps kernel,\
|
||||||
|
increase FW_JUMP_FDT_ADDR
|
||||||
|
```
|
||||||
|
|
||||||
*FW_JUMP* Example
|
*FW_JUMP* Example
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
@@ -12,7 +12,7 @@ firmware and the booting stage to follow OpenSBI firmware.
|
|||||||
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
|
A *FW_PAYLOAD* firmware is also useful for cases where the booting stage prior
|
||||||
to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
|
to the OpenSBI firmware does not pass a *flattened device tree (FDT file)*. In
|
||||||
such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
|
such a case, a *FW_PAYLOAD* firmware allows embedding a flattened device tree
|
||||||
in the .text section of the final firmware.
|
in the .rodata section of the final firmware.
|
||||||
|
|
||||||
Enabling *FW_PAYLOAD* compilation
|
Enabling *FW_PAYLOAD* compilation
|
||||||
---------------------------------
|
---------------------------------
|
||||||
@@ -20,7 +20,7 @@ Enabling *FW_PAYLOAD* compilation
|
|||||||
The *FW_PAYLOAD* firmware can be enabled by any of the following methods:
|
The *FW_PAYLOAD* firmware can be enabled by any of the following methods:
|
||||||
|
|
||||||
1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
|
1. Specifying `FW_PAYLOAD=y` on the top level `make` command line.
|
||||||
2. Specifying `FW_PAYLOAD=y` in the target platform *config.mk* configuration
|
2. Specifying `FW_PAYLOAD=y` in the target platform *objects.mk* configuration
|
||||||
file.
|
file.
|
||||||
|
|
||||||
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
|
The compiled *FW_PAYLOAD* firmware ELF file is named *fw_jump.elf*. Its
|
||||||
@@ -33,7 +33,7 @@ Configuration Options
|
|||||||
|
|
||||||
A *FW_PAYLOAD* firmware is built according to configuration parameters and
|
A *FW_PAYLOAD* firmware is built according to configuration parameters and
|
||||||
options. These configuration parameters can be defined using either the top
|
options. These configuration parameters can be defined using either the top
|
||||||
level `make` command line or the target platform *config.mk* configuration
|
level `make` command line or the target platform *objects.mk* configuration
|
||||||
file. The parameters currently defined are as follows:
|
file. The parameters currently defined are as follows:
|
||||||
|
|
||||||
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
|
* **FW_PAYLOAD_OFFSET** - Offset from *FW_TEXT_BASE* where the payload binary
|
||||||
|
@@ -8,11 +8,7 @@ OpenSBI provides two types of static libraries:
|
|||||||
hooks for the execution of this interface must be provided by the firmware or
|
hooks for the execution of this interface must be provided by the firmware or
|
||||||
bootloader linking with this library. This library is installed as
|
bootloader linking with this library. This library is installed as
|
||||||
*<install_directory>/lib/libsbi.a*
|
*<install_directory>/lib/libsbi.a*
|
||||||
2. *libsbiutils.a* - A static library that will contain all common code required
|
2. *libplatsbi.a* - An example platform-specific static library integrating
|
||||||
by any platform supported in OpenSBI. It will be built by default and included
|
|
||||||
in libplatsbi.a. This library is installed as
|
|
||||||
*<install_directory>/lib/libsbiutils.a*.
|
|
||||||
3. *libplatsbi.a* - An example platform-specific static library integrating
|
|
||||||
*libsbi.a* with platform-specific hooks. This library is available only for
|
*libsbi.a* with platform-specific hooks. This library is available only for
|
||||||
the platforms supported by OpenSBI. This library is installed as
|
the platforms supported by OpenSBI. This library is installed as
|
||||||
*<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
|
*<install_directory>/platform/<platform_subdir>/lib/libplatsbi.a*
|
||||||
@@ -77,7 +73,7 @@ firmware drivers based on the external firmware architecture.
|
|||||||
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
|
**OPENSBI_EXTERNAL_SBI_TYPES** identifier is introduced to *sbi_types.h* for selecting
|
||||||
external header file during the build preprocess in order to define OpensSBI data types
|
external header file during the build preprocess in order to define OpensSBI data types
|
||||||
based on external firmware data type binding.
|
based on external firmware data type binding.
|
||||||
For example, *bool* is declared as *int* in sbi_types.h. However in EDK2 build system,
|
For example, *bool* is declared as *int* in sbi_types.h. However, in EDK2 build system,
|
||||||
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
|
*bool* is declared as *BOOLEAN* which is defined as *unsigned char* data type.
|
||||||
|
|
||||||
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
|
External firmware can define **OPENSBI_EXTERNAL_SBI_TYPES** in CFLAGS and specify it to the
|
||||||
|
@@ -8,7 +8,7 @@ AHB/APB IPs suites a majority embedded systems, and the verified platform serves
|
|||||||
as a starting point to jump start SoC designs.
|
as a starting point to jump start SoC designs.
|
||||||
|
|
||||||
To build platform specific library and firmwares, provide the
|
To build platform specific library and firmwares, provide the
|
||||||
*PLATFORM=andes/ae350* parameter to the top level make command.
|
*PLATFORM=generic* parameter to the top level `make` command.
|
||||||
|
|
||||||
Platform Options
|
Platform Options
|
||||||
----------------
|
----------------
|
||||||
@@ -18,13 +18,190 @@ The Andes AE350 platform does not have any platform-specific options.
|
|||||||
Building Andes AE350 Platform
|
Building Andes AE350 Platform
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using
|
AE350's dts is included in https://github.com/andestech/linux/tree/RISCV-Linux-5.4-ast-v5_1_0-branch
|
||||||
the compile time option FW_FDT_PATH.
|
|
||||||
|
|
||||||
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
|
|
||||||
|
|
||||||
**Linux Kernel Payload**
|
**Linux Kernel Payload**
|
||||||
|
|
||||||
```
|
```
|
||||||
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
|
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_FDT_PATH=<ae350.dtb path>
|
||||||
|
```
|
||||||
|
|
||||||
|
DTS Example: (Quad-core AX45MP)
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
```
|
||||||
|
compatible = "andestech,ae350";
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
timebase-frequency = <60000000>;
|
||||||
|
|
||||||
|
CPU0: cpu@0 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <0>;
|
||||||
|
status = "okay";
|
||||||
|
compatible = "riscv";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
riscv,priv-major = <1>;
|
||||||
|
riscv,priv-minor = <10>;
|
||||||
|
mmu-type = "riscv,sv48";
|
||||||
|
clock-frequency = <60000000>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-sets = <256>;
|
||||||
|
i-cache-line-size = <64>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-sets = <128>;
|
||||||
|
d-cache-line-size = <64>;
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
next-level-cache = <&L2>;
|
||||||
|
CPU0_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
CPU1: cpu@1 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <1>;
|
||||||
|
status = "okay";
|
||||||
|
compatible = "riscv";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
riscv,priv-major = <1>;
|
||||||
|
riscv,priv-minor = <10>;
|
||||||
|
mmu-type = "riscv,sv48";
|
||||||
|
clock-frequency = <60000000>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-sets = <256>;
|
||||||
|
i-cache-line-size = <64>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-sets = <128>;
|
||||||
|
d-cache-line-size = <64>;
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
next-level-cache = <&L2>;
|
||||||
|
CPU1_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
CPU2: cpu@2 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <2>;
|
||||||
|
status = "okay";
|
||||||
|
compatible = "riscv";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
riscv,priv-major = <1>;
|
||||||
|
riscv,priv-minor = <10>;
|
||||||
|
mmu-type = "riscv,sv48";
|
||||||
|
clock-frequency = <60000000>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-sets = <256>;
|
||||||
|
i-cache-line-size = <64>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-sets = <128>;
|
||||||
|
d-cache-line-size = <64>;
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
next-level-cache = <&L2>;
|
||||||
|
CPU2_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
CPU3: cpu@3 {
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <3>;
|
||||||
|
status = "okay";
|
||||||
|
compatible = "riscv";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
riscv,priv-major = <1>;
|
||||||
|
riscv,priv-minor = <10>;
|
||||||
|
mmu-type = "riscv,sv48";
|
||||||
|
clock-frequency = <60000000>;
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-sets = <256>;
|
||||||
|
i-cache-line-size = <64>;
|
||||||
|
i-cache-block-size = <64>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-sets = <128>;
|
||||||
|
d-cache-line-size = <64>;
|
||||||
|
d-cache-block-size = <64>;
|
||||||
|
next-level-cache = <&L2>;
|
||||||
|
CPU3_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
soc {
|
||||||
|
#address-cells = <2>;
|
||||||
|
#size-cells = <2>;
|
||||||
|
compatible = "andestech,riscv-ae350-soc", "simple-bus";
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
plic0: interrupt-controller@e4000000 {
|
||||||
|
compatible = "riscv,plic0";
|
||||||
|
reg = <0x00000000 0xe4000000 0x00000000 0x02000000>;
|
||||||
|
interrupts-extended = < &CPU0_intc 11 &CPU0_intc 9
|
||||||
|
&CPU1_intc 11 &CPU1_intc 9
|
||||||
|
&CPU2_intc 11 &CPU2_intc 9
|
||||||
|
&CPU3_intc 11 &CPU3_intc 9 >;
|
||||||
|
interrupt-controller;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
riscv,ndev = <71>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plicsw: interrupt-controller@e6400000 {
|
||||||
|
compatible = "andestech,plicsw";
|
||||||
|
reg = <0x00000000 0xe6400000 0x00000000 0x00400000>;
|
||||||
|
interrupts-extended = < &CPU0_intc 3
|
||||||
|
&CPU1_intc 3
|
||||||
|
&CPU2_intc 3
|
||||||
|
&CPU3_intc 3 >;
|
||||||
|
interrupt-controller;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plmt0: plmt0@e6000000 {
|
||||||
|
compatible = "andestech,plmt0";
|
||||||
|
reg = <0x00000000 0xe6000000 0x00000000 0x00100000>;
|
||||||
|
interrupts-extended = < &CPU0_intc 7
|
||||||
|
&CPU1_intc 7
|
||||||
|
&CPU2_intc 7
|
||||||
|
&CPU3_intc 7 >;
|
||||||
|
};
|
||||||
|
|
||||||
|
wdt: watchdog@f0500000 {
|
||||||
|
compatible = "andestech,atcwdt200";
|
||||||
|
reg = <0x00000000 0xf0500000 0x00000000 0x00001000>;
|
||||||
|
interrupts = <3 4>;
|
||||||
|
interrupt-parent = <&plic0>;
|
||||||
|
clock-frequency = <15000000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
serial0: serial@f0300000 {
|
||||||
|
compatible = "andestech,uart16550", "ns16550a";
|
||||||
|
reg = <0x00000000 0xf0300000 0x00000000 0x00001000>;
|
||||||
|
interrupts = <9 4>;
|
||||||
|
interrupt-parent = <&plic0>;
|
||||||
|
clock-frequency = <19660800>;
|
||||||
|
current-speed = <38400>;
|
||||||
|
reg-shift = <2>;
|
||||||
|
reg-offset = <32>;
|
||||||
|
reg-io-width = <4>;
|
||||||
|
no-loopback-test = <1>;
|
||||||
|
};
|
||||||
|
|
||||||
|
smu: smu@f0100000 {
|
||||||
|
compatible = "andestech,atcsmu";
|
||||||
|
reg = <0x00000000 0xf0100000 0x00000000 0x00001000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
@@ -7,7 +7,7 @@ Linux.
|
|||||||
|
|
||||||
The FPGA SoC currently contains the following peripherals:
|
The FPGA SoC currently contains the following peripherals:
|
||||||
- DDR3 memory controller
|
- DDR3 memory controller
|
||||||
- SPI controller to conncet to an SDCard
|
- SPI controller to connect to an SDCard
|
||||||
- Ethernet controller
|
- Ethernet controller
|
||||||
- JTAG port (see debugging section below)
|
- JTAG port (see debugging section below)
|
||||||
- Bootrom containing zero stage bootloader and device tree.
|
- Bootrom containing zero stage bootloader and device tree.
|
||||||
|
@@ -45,13 +45,17 @@ The *Generic* platform does not have any platform-specific options.
|
|||||||
RISC-V Platforms Using Generic Platform
|
RISC-V Platforms Using Generic Platform
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
* **Andes AE350 Platform** (*[andes-ae350.md]*)
|
||||||
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
|
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
|
||||||
|
* **Renesas RZ/Five SoC** (*[renesas-rzfive.md]*)
|
||||||
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
|
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
|
||||||
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
|
* **SiFive HiFive Unleashed** (*[sifive_fu540.md]*)
|
||||||
* **Spike** (*[spike.md]*)
|
* **Spike** (*[spike.md]*)
|
||||||
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
|
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
|
||||||
|
|
||||||
|
[andes-ae350.md]: andse-ae350.md
|
||||||
[qemu_virt.md]: qemu_virt.md
|
[qemu_virt.md]: qemu_virt.md
|
||||||
|
[renesas-rzfive.md]: renesas-rzfive.md
|
||||||
[shakti_cclass.md]: shakti_cclass.md
|
[shakti_cclass.md]: shakti_cclass.md
|
||||||
[sifive_fu540.md]: sifive_fu540.md
|
[sifive_fu540.md]: sifive_fu540.md
|
||||||
[spike.md]: spike.md
|
[spike.md]: spike.md
|
||||||
|
@@ -39,11 +39,15 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
|||||||
processor based SOCs. More details on this platform can be found in the
|
processor based SOCs. More details on this platform can be found in the
|
||||||
file *[shakti_cclass.md]*.
|
file *[shakti_cclass.md]*.
|
||||||
|
|
||||||
|
* **Renesas RZ/Five SoC**: Platform support for Renesas RZ/Five (R9A07G043F) SoC
|
||||||
|
used on the Renesas RZ/Five SMARC EVK board. More details on this platform can
|
||||||
|
be found in the file *[renesas-rzfive.md]*.
|
||||||
|
|
||||||
The code for these supported platforms can be used as example to implement
|
The code for these supported platforms can be used as example to implement
|
||||||
support for other platforms. The *platform/template* directory also provides
|
support for other platforms. The *platform/template* directory also provides
|
||||||
template files for implementing support for a new platform. The *object.mk*,
|
template files for implementing support for a new platform. The *objects.mk*,
|
||||||
*config.mk* and *platform.c* template files provides enough comments to
|
*Kconfig*, *configs/defconfig* and *platform.c* template files provides enough
|
||||||
facilitate the implementation.
|
comments to facilitate the implementation.
|
||||||
|
|
||||||
[generic.md]: generic.md
|
[generic.md]: generic.md
|
||||||
[qemu_virt.md]: qemu_virt.md
|
[qemu_virt.md]: qemu_virt.md
|
||||||
@@ -54,3 +58,4 @@ facilitate the implementation.
|
|||||||
[spike.md]: spike.md
|
[spike.md]: spike.md
|
||||||
[fpga-openpiton.md]: fpga-openpiton.md
|
[fpga-openpiton.md]: fpga-openpiton.md
|
||||||
[shakti_cclass.md]: shakti_cclass.md
|
[shakti_cclass.md]: shakti_cclass.md
|
||||||
|
[renesas-rzfive.md]: renesas-rzfive.md
|
||||||
|
160
docs/platform/renesas-rzfive.md
Normal file
160
docs/platform/renesas-rzfive.md
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
Renesas RZ/Five SoC (R9A07G043F) Platform
|
||||||
|
=========================================
|
||||||
|
The RZ/Five microprocessor includes a single RISC-V CPU Core (Andes AX45MP)
|
||||||
|
1.0 GHz, 16-bit DDR3L/DDR4 interface. Supported interfaces include:
|
||||||
|
- Memory controller for DDR4-1600 / DDR3L-1333 with 16 bits
|
||||||
|
- System RAM (RAM of 128 Kbytes (ECC))
|
||||||
|
- SPI Multi I/O Bus Controller 1ch
|
||||||
|
- SD Card Host Interface/Multimedia Card Interface (SD/MMC) 2ch
|
||||||
|
- Serial Sound Interface (SSI) 4ch
|
||||||
|
- Sampling Rate Converter (SRC) 1ch
|
||||||
|
- USB2.0 host/function interface 2ch (ch0: Host-Function ch1: Host only)
|
||||||
|
- Gigabit Ethernet Interface (GbE) 2ch
|
||||||
|
- Controller Area Network Interface (CAN) 2ch (CAN-FD ISO 11898-1 (CD2014) compliant)
|
||||||
|
- Multi-function Timer Pulse Unit 3 (MTU3a) 9 ch (16 bits × 8 channels, 32 bits × 1 channel)
|
||||||
|
- Port Output Enable 3 (POE3)
|
||||||
|
- Watchdog Timer (WDT) 1ch
|
||||||
|
- General Timer (GTM) 3ch (32bits)
|
||||||
|
- I2C Bus Interface (I2C) 4ch
|
||||||
|
- Serial Communication Interface with FIFO (SCIFA) 5ch
|
||||||
|
- Serial Communication Interface (SCI) 2ch
|
||||||
|
- Renesas Serial Peripheral Interface (RSPI) 3ch
|
||||||
|
- A/D Converter (ADC) 2ch
|
||||||
|
making it ideal for applications such as entry-class social infrastructure
|
||||||
|
gateway control and industrial gateway control. More details can be found at
|
||||||
|
below link [0].
|
||||||
|
|
||||||
|
[0] https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rz-mpus/rzfive-general-purpose-microprocessors-risc-v-cpu-core-andes-ax45mp-single-10-ghz-2ch-gigabit-ethernet
|
||||||
|
|
||||||
|
To build platform specific library and firmwares, provide the
|
||||||
|
*PLATFORM=generic* parameter to the top level make command.
|
||||||
|
|
||||||
|
Platform Options
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The Renesas RZ/Five platform does not have any platform-specific options.
|
||||||
|
|
||||||
|
Building Renesas RZ/Five Platform
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
```
|
||||||
|
make PLATFORM=generic
|
||||||
|
```
|
||||||
|
|
||||||
|
DTS Example: (RZ/Five AX45MP)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
```
|
||||||
|
compatible = "renesas,r9a07g043f01", "renesas,r9a07g043";
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
timebase-frequency = <12000000>;
|
||||||
|
|
||||||
|
cpu0: cpu@0 {
|
||||||
|
compatible = "andestech,ax45mp", "riscv";
|
||||||
|
device_type = "cpu";
|
||||||
|
reg = <0x0>;
|
||||||
|
status = "okay";
|
||||||
|
riscv,isa = "rv64imafdc";
|
||||||
|
mmu-type = "riscv,sv39";
|
||||||
|
i-cache-size = <0x8000>;
|
||||||
|
i-cache-line-size = <0x40>;
|
||||||
|
d-cache-size = <0x8000>;
|
||||||
|
d-cache-line-size = <0x40>;
|
||||||
|
clocks = <&cpg CPG_CORE R9A07G043_CLK_I>;
|
||||||
|
|
||||||
|
cpu0_intc: interrupt-controller {
|
||||||
|
#interrupt-cells = <1>;
|
||||||
|
compatible = "riscv,cpu-intc";
|
||||||
|
interrupt-controller;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
soc {
|
||||||
|
compatible = "simple-bus";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
scif0: serial@1004b800 {
|
||||||
|
compatible = "renesas,scif-r9a07g043",
|
||||||
|
"renesas,scif-r9a07g044";
|
||||||
|
reg = <0 0x1004b800 0 0x400>;
|
||||||
|
interrupts = <412 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<414 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<415 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<413 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<416 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<416 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
interrupt-names = "eri", "rxi", "txi",
|
||||||
|
"bri", "dri", "tei";
|
||||||
|
clocks = <&cpg CPG_MOD R9A07G043_SCIF0_CLK_PCK>;
|
||||||
|
clock-names = "fck";
|
||||||
|
power-domains = <&cpg>;
|
||||||
|
resets = <&cpg R9A07G043_SCIF0_RST_SYSTEM_N>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
cpg: clock-controller@11010000 {
|
||||||
|
compatible = "renesas,r9a07g043-cpg";
|
||||||
|
reg = <0 0x11010000 0 0x10000>;
|
||||||
|
clocks = <&extal_clk>;
|
||||||
|
clock-names = "extal";
|
||||||
|
#clock-cells = <2>;
|
||||||
|
#reset-cells = <1>;
|
||||||
|
#power-domain-cells = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
sysc: system-controller@11020000 {
|
||||||
|
compatible = "renesas,r9a07g043-sysc";
|
||||||
|
reg = <0 0x11020000 0 0x10000>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
pinctrl: pinctrl@11030000 {
|
||||||
|
compatible = "renesas,r9a07g043-pinctrl";
|
||||||
|
reg = <0 0x11030000 0 0x10000>;
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
interrupt-controller;
|
||||||
|
gpio-ranges = <&pinctrl 0 0 152>;
|
||||||
|
clocks = <&cpg CPG_MOD R9A07G043_GPIO_HCLK>;
|
||||||
|
power-domains = <&cpg>;
|
||||||
|
resets = <&cpg R9A07G043_GPIO_RSTN>,
|
||||||
|
<&cpg R9A07G043_GPIO_PORT_RESETN>,
|
||||||
|
<&cpg R9A07G043_GPIO_SPARE_RESETN>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plmt0: plmt0@110c0000 {
|
||||||
|
compatible = "andestech,plmt0", "riscv,plmt0";
|
||||||
|
reg = <0x0 0x110c0000 0x0 0x10000>;
|
||||||
|
interrupts-extended = <&cpu0_intc 7>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plic: interrupt-controller@12c00000 {
|
||||||
|
compatible = "renesas,r9a07g043-plic", "andestech,nceplic100";
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
#address-cells = <0>;
|
||||||
|
riscv,ndev = <511>;
|
||||||
|
interrupt-controller;
|
||||||
|
reg = <0x0 0x12c00000 0x0 0x400000>;
|
||||||
|
clocks = <&cpg CPG_MOD R9A07G043_NCEPLIC_ACLK>;
|
||||||
|
power-domains = <&cpg>;
|
||||||
|
resets = <&cpg R9A07G043_NCEPLIC_ARESETN>;
|
||||||
|
interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>;
|
||||||
|
};
|
||||||
|
|
||||||
|
plicsw: interrupt-controller@13000000 {
|
||||||
|
compatible = "andestech,plicsw";
|
||||||
|
reg = <0x0 0x13000000 0x0 0x400000>;
|
||||||
|
interrupts-extended = <&cpu0_intc 3>;
|
||||||
|
interrupt-controller;
|
||||||
|
#address-cells = <2>;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
@@ -150,7 +150,7 @@ If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
|
|||||||
same instructions above, with the exception of not passing FW_FDT_PATH.
|
same instructions above, with the exception of not passing FW_FDT_PATH.
|
||||||
|
|
||||||
This is because QEMU generates a device tree blob on the fly based on the
|
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
|
command line parameters, and it's compatible with the one used in the upstream
|
||||||
Linux kernel.
|
Linux kernel.
|
||||||
|
|
||||||
When U-Boot v2021.07 (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
|
||||||
|
@@ -13,7 +13,7 @@ Platform Options
|
|||||||
----------------
|
----------------
|
||||||
|
|
||||||
The *T-HEAD C9xx* does not have any platform-specific compile options
|
The *T-HEAD C9xx* does not have any platform-specific compile options
|
||||||
because it use generic platform.
|
because it uses generic platform.
|
||||||
|
|
||||||
```
|
```
|
||||||
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
|
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic /usr/bin/make
|
||||||
@@ -52,12 +52,11 @@ DTS Example1: (Single core, eg: Allwinner D1 - c906)
|
|||||||
ranges;
|
ranges;
|
||||||
|
|
||||||
clint0: clint@14000000 {
|
clint0: clint@14000000 {
|
||||||
compatible = "riscv,clint0";
|
compatible = "allwinner,sun20i-d1-clint";
|
||||||
interrupts-extended = <
|
interrupts-extended = <
|
||||||
&cpu0_intc 3 &cpu0_intc 7
|
&cpu0_intc 3 &cpu0_intc 7
|
||||||
>;
|
>;
|
||||||
reg = <0x0 0x14000000 0x0 0x04000000>;
|
reg = <0x0 0x14000000 0x0 0x04000000>;
|
||||||
clint,has-no-64bit-mmio;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
intc: interrupt-controller@10000000 {
|
intc: interrupt-controller@10000000 {
|
||||||
@@ -163,7 +162,6 @@ DTS Example2: (Multi cores with soc reset-regs)
|
|||||||
&cpu4_intc 3 &cpu4_intc 7
|
&cpu4_intc 3 &cpu4_intc 7
|
||||||
>;
|
>;
|
||||||
reg = <0xff 0xdc000000 0x0 0x04000000>;
|
reg = <0xff 0xdc000000 0x0 0x04000000>;
|
||||||
clint,has-no-64bit-mmio;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
intc: interrupt-controller@ffd8000000 {
|
intc: interrupt-controller@ffd8000000 {
|
||||||
|
@@ -28,11 +28,12 @@ Adding support for a new platform
|
|||||||
Support for a new platform named *<xyz>* can be added as follows:
|
Support for a new platform named *<xyz>* can be added as follows:
|
||||||
|
|
||||||
1. Create a directory named *<xyz>* under the *platform/* directory.
|
1. Create a directory named *<xyz>* under the *platform/* directory.
|
||||||
2. Create a platform configuration file named *config.mk* under the
|
2. Create platform configuration files named *Kconfig* and *configs/defconfig*
|
||||||
*platform/<xyz>/* directory. This configuration file will provide
|
under the *platform/<xyz>/* directory. These configuration files will
|
||||||
|
provide the build time configuration for the sources to be compiled.
|
||||||
|
3. Create a *platform/<xyz>/objects.mk* file for listing the platform
|
||||||
|
object files to be compiled. This file also provides platform-specific
|
||||||
compiler flags, and select firmware options.
|
compiler flags, and select firmware options.
|
||||||
3. Create a *platform/<xyz>/objects.mk* file for listing the
|
|
||||||
platform-specific object files to be compiled.
|
|
||||||
4. Create a *platform/<xyz>/platform.c* file providing a
|
4. Create a *platform/<xyz>/platform.c* file providing a
|
||||||
*struct sbi_platform* instance.
|
*struct sbi_platform* instance.
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ To handle this, we have two types of RISC-V platform requirements:
|
|||||||
2. **Release specific platform requirements** which apply to a OpenSBI
|
2. **Release specific platform requirements** which apply to a OpenSBI
|
||||||
release and later releases
|
release and later releases
|
||||||
|
|
||||||
Currently, we don't have any **Release specific platform requirements**
|
Currently, we don't have any **Release specific platform requirements**,
|
||||||
but such platform requirements will be added in future.
|
but such platform requirements will be added in future.
|
||||||
|
|
||||||
Base Platform Requirements
|
Base Platform Requirements
|
||||||
|
@@ -1,14 +1,11 @@
|
|||||||
OpenSBI SBI PMU extension support
|
OpenSBI SBI PMU extension support
|
||||||
==================================
|
==================================
|
||||||
SBI PMU extension supports allow supervisor software to configure/start/stop
|
SBI PMU extension supports allow supervisor software to configure/start/stop
|
||||||
any performance counter at anytime. Thus, an user can leverage full
|
any performance counter at anytime. Thus, a user can leverage full
|
||||||
capability of performance analysis tools such as perf if SBI PMU extension is
|
capability of performance analysis tools such as perf if SBI PMU extension is
|
||||||
enabled. The OpenSBI implementation makes the following assumptions about the
|
enabled. The OpenSBI implementation makes the following assumptions about the
|
||||||
hardware platform.
|
hardware platform.
|
||||||
|
|
||||||
* MCOUNTINHIBIT CSR must be implemented in the hardware. Otherwise, SBI PMU
|
|
||||||
extension will not be enabled.
|
|
||||||
|
|
||||||
* The platform must provide information about PMU event to counter mapping
|
* The platform must provide information about PMU event to counter mapping
|
||||||
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
|
via device tree or platform specific hooks. Otherwise, SBI PMU extension will
|
||||||
not be enabled.
|
not be enabled.
|
||||||
@@ -25,7 +22,7 @@ SBI PMU Device Tree Bindings
|
|||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
Platforms may choose to describe PMU event selector and event to counter mapping
|
Platforms may choose to describe PMU event selector and event to counter mapping
|
||||||
values via device tree. The following sections describes the PMU DT node
|
values via device tree. The following sections describe the PMU DT node
|
||||||
bindings in details.
|
bindings in details.
|
||||||
|
|
||||||
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
|
* **compatible** (Mandatory) - The compatible string of SBI PMU device tree node.
|
||||||
@@ -42,46 +39,89 @@ This property shouldn't encode any raw hardware event.
|
|||||||
* **riscv,event-to-mhpmcounters**(Optional) - It represents a MANY-to-MANY
|
* **riscv,event-to-mhpmcounters**(Optional) - It represents a MANY-to-MANY
|
||||||
mapping between a range of events and all the MHPMCOUNTERx in a bitmap format
|
mapping between a range of events and all the MHPMCOUNTERx in a bitmap format
|
||||||
that can be used to monitor these range of events. The information is encoded in
|
that can be used to monitor these range of events. The information is encoded in
|
||||||
a table format where each row represent a certain range of events and
|
a table format where each row represents a certain range of events and
|
||||||
corresponding counters. The first column represents starting of the pmu event id
|
corresponding counters. The first column represents starting of the pmu event id
|
||||||
and 2nd column represents the end of the pmu event id. The third column
|
and 2nd column represents the end of the pmu event id. The third column
|
||||||
represent a bitmap of all the MHPMCOUNTERx. This property is mandatory if
|
represent a bitmap of all the MHPMCOUNTERx. This property is mandatory if
|
||||||
event-to-mhpmevent is present. Otherwise, it can be omitted. This property
|
riscv,event-to-mhpmevent is present. Otherwise, it can be omitted. This property
|
||||||
shouldn't encode any raw event.
|
shouldn't encode any raw event.
|
||||||
|
|
||||||
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
|
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
|
||||||
or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
|
or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
|
||||||
a bitmap format that can be used to monitor that raw event, which depends on
|
a bitmap format that can be used to monitor that raw event. The encoding of the
|
||||||
how the platform encodes the monitor events. Currently, only the following three
|
raw events are platform specific. The information is encoded in a table format
|
||||||
encoding methods are supported, encoding each event as a number, using a bitmap
|
where each row represents the specific raw event(s). The first column is a 64bit
|
||||||
to encode monitor events, and mixing the previous two methods. The information
|
match value where the invariant bits of range of events are set. The second
|
||||||
is encoded in a table format where each row represent the specific raw event(s).
|
column is a 64 bit mask that will have all the variant bits of the range of
|
||||||
The first column represents a 64-bit selector value which can indicate an
|
events cleared. All other bits should be set in the mask.
|
||||||
monitor event ID (encoded by a number) or an event set (encoded by a bitmap).
|
The third column is a 32bit value to represent bitmap of all MHPMCOUNTERx that
|
||||||
In case of the latter, the lower bits used to encode a set of events should be
|
can monitor these set of event(s).
|
||||||
set to zero. The second column is a 64-bit selector mask where any bits used
|
If a platform directly encodes each raw PMU event as a unique ID, the value of
|
||||||
for event encoding will be cleared. If a platform directly encodes each raw PMU
|
select_mask must be 0xffffffff_ffffffff.
|
||||||
event as a unique ID, the value of select_mask will be 0xffffffff_ffffffff.
|
|
||||||
The third column represent a bitmap of all the MHPMCOUNTERx that can be used for
|
|
||||||
monitoring the specified event(s).
|
|
||||||
|
|
||||||
*Note:* A platform may choose to provide the mapping between event & counters
|
*Note:* A platform may choose to provide the mapping between event & counters
|
||||||
via platform hooks rather than the device tree.
|
via platform hooks rather than the device tree.
|
||||||
|
|
||||||
### Example
|
### Example 1
|
||||||
|
|
||||||
```
|
```
|
||||||
pmu {
|
pmu {
|
||||||
compatible = "riscv,pmu";
|
compatible = "riscv,pmu";
|
||||||
interrupts = <0x100>;
|
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>;
|
||||||
interrupt-parent = <&plic>
|
|
||||||
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>,
|
|
||||||
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
|
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
|
||||||
<0x00002 0x00002 0x00000004>,
|
<0x00002 0x00002 0x00000004>,
|
||||||
<0x00003 0x0000A 0x00000ff8>,
|
<0x00003 0x0000A 0x00000ff8>,
|
||||||
<0x10000 0x10033 0x000ff000>,
|
<0x10000 0x10033 0x000ff000>;
|
||||||
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
|
/* For event ID 0x0002 */
|
||||||
<0xffffffff 0xfffffff0 0xffffffff 0xfffffff0 0x00000ff0>,
|
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
|
||||||
|
/* For event ID 0-4 */
|
||||||
|
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
|
||||||
|
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
|
||||||
|
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>;
|
||||||
};
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2
|
||||||
|
|
||||||
```
|
```
|
||||||
|
/*
|
||||||
|
* For HiFive Unmatched board. The encodings can be found here
|
||||||
|
* https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
|
||||||
|
* This example also binds standard SBI PMU hardware id's to U74 PMU event codes, U74 uses bitfield for
|
||||||
|
* events encoding, so several U74 events can be bound to single perf id.
|
||||||
|
* See SBI PMU hardware id's in include/sbi/sbi_ecall_interface.h
|
||||||
|
*/
|
||||||
|
pmu {
|
||||||
|
compatible = "riscv,pmu";
|
||||||
|
riscv,event-to-mhpmevent =
|
||||||
|
/* SBI_PMU_HW_CACHE_REFERENCES -> Instruction cache/ITIM busy | Data cache/DTIM busy */
|
||||||
|
<0x00003 0x00000000 0x1801>,
|
||||||
|
/* SBI_PMU_HW_CACHE_MISSES -> Instruction cache miss | Data cache miss or memory-mapped I/O access */
|
||||||
|
<0x00004 0x00000000 0x0302>,
|
||||||
|
/* SBI_PMU_HW_BRANCH_INSTRUCTIONS -> Conditional branch retired */
|
||||||
|
<0x00005 0x00000000 0x4000>,
|
||||||
|
/* SBI_PMU_HW_BRANCH_MISSES -> Branch direction misprediction | Branch/jump target misprediction */
|
||||||
|
<0x00006 0x00000000 0x6001>,
|
||||||
|
/* L1D_READ_MISS -> Data cache miss or memory-mapped I/O access */
|
||||||
|
<0x10001 0x00000000 0x0202>,
|
||||||
|
/* L1D_WRITE_ACCESS -> Data cache write-back */
|
||||||
|
<0x10002 0x00000000 0x0402>,
|
||||||
|
/* L1I_READ_ACCESS -> Instruction cache miss */
|
||||||
|
<0x10009 0x00000000 0x0102>,
|
||||||
|
/* LL_READ_MISS -> UTLB miss */
|
||||||
|
<0x10011 0x00000000 0x2002>,
|
||||||
|
/* DTLB_READ_MISS -> Data TLB miss */
|
||||||
|
<0x10019 0x00000000 0x1002>,
|
||||||
|
/* ITLB_READ_MISS-> Instruction TLB miss */
|
||||||
|
<0x10021 0x00000000 0x0802>;
|
||||||
|
riscv,event-to-mhpmcounters = <0x00003 0x00006 0x18>,
|
||||||
|
<0x10001 0x10002 0x18>,
|
||||||
|
<0x10009 0x10009 0x18>,
|
||||||
|
<0x10011 0x10011 0x18>,
|
||||||
|
<0x10019 0x10019 0x18>,
|
||||||
|
<0x10021 0x10021 0x18>;
|
||||||
|
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0x18>,
|
||||||
|
<0x0 0x1 0xffffffff 0xfff800ff 0x18>,
|
||||||
|
<0x0 0x2 0xffffffff 0xffffe0ff 0x18>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
1
firmware/Kconfig
Normal file
1
firmware/Kconfig
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
@@ -128,9 +128,9 @@ _relocate:
|
|||||||
REG_L t1, 0(t1)
|
REG_L t1, 0(t1)
|
||||||
lla t2, _load_start
|
lla t2, _load_start
|
||||||
REG_L t2, 0(t2)
|
REG_L t2, 0(t2)
|
||||||
|
beq t0, t2, _relocate_done
|
||||||
sub t3, t1, t0
|
sub t3, t1, t0
|
||||||
add t3, t3, t2
|
add t3, t3, t2
|
||||||
beq t0, t2, _relocate_done
|
|
||||||
lla t4, _relocate_done
|
lla t4, _relocate_done
|
||||||
sub t4, t4, t2
|
sub t4, t4, t2
|
||||||
add t4, t4, t0
|
add t4, t4, t0
|
||||||
@@ -259,7 +259,7 @@ _bss_zero:
|
|||||||
* s8 -> HART Stack Size
|
* s8 -> HART Stack Size
|
||||||
*/
|
*/
|
||||||
lla a4, platform
|
lla a4, platform
|
||||||
#if __riscv_xlen == 64
|
#if __riscv_xlen > 32
|
||||||
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
|
||||||
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
|
||||||
#else
|
#else
|
||||||
|
@@ -24,14 +24,12 @@
|
|||||||
PROVIDE(_text_end = .);
|
PROVIDE(_text_end = .);
|
||||||
}
|
}
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
|
||||||
|
|
||||||
/* End of the code sections */
|
/* End of the code sections */
|
||||||
|
|
||||||
/* Beginning of the read-only data sections */
|
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
|
/* Beginning of the read-only data sections */
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
{
|
{
|
||||||
PROVIDE(_rodata_start = .);
|
PROVIDE(_rodata_start = .);
|
||||||
@@ -42,10 +40,10 @@
|
|||||||
|
|
||||||
/* End of the read-only data sections */
|
/* End of the read-only data sections */
|
||||||
|
|
||||||
/* Beginning of the read-write data sections */
|
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
|
/* Beginning of the read-write data sections */
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
{
|
{
|
||||||
PROVIDE(_data_start = .);
|
PROVIDE(_data_start = .);
|
||||||
|
@@ -33,14 +33,12 @@ SECTIONS
|
|||||||
PROVIDE(_text_end = .);
|
PROVIDE(_text_end = .);
|
||||||
}
|
}
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
|
||||||
|
|
||||||
/* End of the code sections */
|
/* End of the code sections */
|
||||||
|
|
||||||
/* Beginning of the read-only data sections */
|
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
|
/* Beginning of the read-only data sections */
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
{
|
{
|
||||||
PROVIDE(_rodata_start = .);
|
PROVIDE(_rodata_start = .);
|
||||||
@@ -51,10 +49,10 @@ SECTIONS
|
|||||||
|
|
||||||
/* End of the read-only data sections */
|
/* End of the read-only data sections */
|
||||||
|
|
||||||
/* Beginning of the read-write data sections */
|
|
||||||
|
|
||||||
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
. = ALIGN(0x1000); /* Ensure next section is page aligned */
|
||||||
|
|
||||||
|
/* Beginning of the read-write data sections */
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
{
|
{
|
||||||
PROVIDE(_data_start = .);
|
PROVIDE(_data_start = .);
|
||||||
|
@@ -75,6 +75,41 @@ struct fw_dynamic_info {
|
|||||||
unsigned long boot_hart;
|
unsigned long boot_hart;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent modification of struct fw_dynamic_info from affecting
|
||||||
|
* FW_DYNAMIC_INFO_xxx_OFFSET
|
||||||
|
*/
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct fw_dynamic_info, magic)
|
||||||
|
== FW_DYNAMIC_INFO_MAGIC_OFFSET,
|
||||||
|
"struct fw_dynamic_info definition has changed, please redefine "
|
||||||
|
"FW_DYNAMIC_INFO_MAGIC_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct fw_dynamic_info, version)
|
||||||
|
== FW_DYNAMIC_INFO_VERSION_OFFSET,
|
||||||
|
"struct fw_dynamic_info definition has changed, please redefine "
|
||||||
|
"FW_DYNAMIC_INFO_VERSION_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct fw_dynamic_info, next_addr)
|
||||||
|
== FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET,
|
||||||
|
"struct fw_dynamic_info definition has changed, please redefine "
|
||||||
|
"FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct fw_dynamic_info, next_mode)
|
||||||
|
== FW_DYNAMIC_INFO_NEXT_MODE_OFFSET,
|
||||||
|
"struct fw_dynamic_info definition has changed, please redefine "
|
||||||
|
"FW_DYNAMIC_INFO_NEXT_MODE_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct fw_dynamic_info, options)
|
||||||
|
== FW_DYNAMIC_INFO_OPTIONS_OFFSET,
|
||||||
|
"struct fw_dynamic_info definition has changed, please redefine "
|
||||||
|
"FW_DYNAMIC_INFO_OPTIONS_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct fw_dynamic_info, boot_hart)
|
||||||
|
== FW_DYNAMIC_INFO_BOOT_HART_OFFSET,
|
||||||
|
"struct fw_dynamic_info definition has changed, please redefine "
|
||||||
|
"FW_DYNAMIC_INFO_BOOT_HART_OFFSET");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
|
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
|
||||||
#define MSTATUS_FS _UL(0x00006000)
|
#define MSTATUS_FS _UL(0x00006000)
|
||||||
#define MSTATUS_XS _UL(0x00018000)
|
#define MSTATUS_XS _UL(0x00018000)
|
||||||
#define MSTATUS_VS _UL(0x01800000)
|
#define MSTATUS_VS _UL(0x00000600)
|
||||||
#define MSTATUS_MPRV _UL(0x00020000)
|
#define MSTATUS_MPRV _UL(0x00020000)
|
||||||
#define MSTATUS_SUM _UL(0x00040000)
|
#define MSTATUS_SUM _UL(0x00040000)
|
||||||
#define MSTATUS_MXR _UL(0x00080000)
|
#define MSTATUS_MXR _UL(0x00080000)
|
||||||
@@ -38,10 +38,14 @@
|
|||||||
#define MSTATUS_SXL _ULL(0x0000000C00000000)
|
#define MSTATUS_SXL _ULL(0x0000000C00000000)
|
||||||
#define MSTATUS_SBE _ULL(0x0000001000000000)
|
#define MSTATUS_SBE _ULL(0x0000001000000000)
|
||||||
#define MSTATUS_MBE _ULL(0x0000002000000000)
|
#define MSTATUS_MBE _ULL(0x0000002000000000)
|
||||||
|
#define MSTATUS_GVA _ULL(0x0000004000000000)
|
||||||
|
#define MSTATUS_GVA_SHIFT 38
|
||||||
#define MSTATUS_MPV _ULL(0x0000008000000000)
|
#define MSTATUS_MPV _ULL(0x0000008000000000)
|
||||||
#else
|
#else
|
||||||
#define MSTATUSH_SBE _UL(0x00000010)
|
#define MSTATUSH_SBE _UL(0x00000010)
|
||||||
#define MSTATUSH_MBE _UL(0x00000020)
|
#define MSTATUSH_MBE _UL(0x00000020)
|
||||||
|
#define MSTATUSH_GVA _UL(0x00000040)
|
||||||
|
#define MSTATUSH_GVA_SHIFT 6
|
||||||
#define MSTATUSH_MPV _UL(0x00000080)
|
#define MSTATUSH_MPV _UL(0x00000080)
|
||||||
#endif
|
#endif
|
||||||
#define MSTATUS32_SD _UL(0x80000000)
|
#define MSTATUS32_SD _UL(0x80000000)
|
||||||
@@ -173,6 +177,10 @@
|
|||||||
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
|
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TOPI_IID_SHIFT 16
|
||||||
|
#define TOPI_IID_MASK 0xfff
|
||||||
|
#define TOPI_IPRIO_MASK 0xff
|
||||||
|
|
||||||
#if __riscv_xlen == 64
|
#if __riscv_xlen == 64
|
||||||
#define MHPMEVENT_OF (_UL(1) << 63)
|
#define MHPMEVENT_OF (_UL(1) << 63)
|
||||||
#define MHPMEVENT_MINH (_UL(1) << 62)
|
#define MHPMEVENT_MINH (_UL(1) << 62)
|
||||||
@@ -181,13 +189,14 @@
|
|||||||
#define MHPMEVENT_VSINH (_UL(1) << 59)
|
#define MHPMEVENT_VSINH (_UL(1) << 59)
|
||||||
#define MHPMEVENT_VUINH (_UL(1) << 58)
|
#define MHPMEVENT_VUINH (_UL(1) << 58)
|
||||||
#else
|
#else
|
||||||
#define MHPMEVENTH_OF (_UL(1) << 31)
|
#define MHPMEVENTH_OF (_ULL(1) << 31)
|
||||||
#define MHPMEVENTH_MINH (_ULL(1) << 30)
|
#define MHPMEVENTH_MINH (_ULL(1) << 30)
|
||||||
#define MHPMEVENTH_SINH (_ULL(1) << 29)
|
#define MHPMEVENTH_SINH (_ULL(1) << 29)
|
||||||
#define MHPMEVENTH_UINH (_ULL(1) << 28)
|
#define MHPMEVENTH_UINH (_ULL(1) << 28)
|
||||||
#define MHPMEVENTH_VSINH (_ULL(1) << 27)
|
#define MHPMEVENTH_VSINH (_ULL(1) << 27)
|
||||||
#define MHPMEVENTH_VUINH (_ULL(1) << 26)
|
#define MHPMEVENTH_VUINH (_ULL(1) << 26)
|
||||||
|
|
||||||
|
#define MHPMEVENT_OF (MHPMEVENTH_OF << 32)
|
||||||
#define MHPMEVENT_MINH (MHPMEVENTH_MINH << 32)
|
#define MHPMEVENT_MINH (MHPMEVENTH_MINH << 32)
|
||||||
#define MHPMEVENT_SINH (MHPMEVENTH_SINH << 32)
|
#define MHPMEVENT_SINH (MHPMEVENTH_SINH << 32)
|
||||||
#define MHPMEVENT_UINH (MHPMEVENTH_UINH << 32)
|
#define MHPMEVENT_UINH (MHPMEVENTH_UINH << 32)
|
||||||
@@ -198,6 +207,22 @@
|
|||||||
|
|
||||||
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
|
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
|
||||||
|
|
||||||
|
#if __riscv_xlen > 32
|
||||||
|
#define ENVCFG_STCE (_ULL(1) << 63)
|
||||||
|
#define ENVCFG_PBMTE (_ULL(1) << 62)
|
||||||
|
#else
|
||||||
|
#define ENVCFGH_STCE (_UL(1) << 31)
|
||||||
|
#define ENVCFGH_PBMTE (_UL(1) << 30)
|
||||||
|
#endif
|
||||||
|
#define ENVCFG_CBZE (_UL(1) << 7)
|
||||||
|
#define ENVCFG_CBCFE (_UL(1) << 6)
|
||||||
|
#define ENVCFG_CBIE_SHIFT 4
|
||||||
|
#define ENVCFG_CBIE (_UL(0x3) << ENVCFG_CBIE_SHIFT)
|
||||||
|
#define ENVCFG_CBIE_ILL _UL(0x0)
|
||||||
|
#define ENVCFG_CBIE_FLUSH _UL(0x1)
|
||||||
|
#define ENVCFG_CBIE_INV _UL(0x3)
|
||||||
|
#define ENVCFG_FIOM _UL(0x1)
|
||||||
|
|
||||||
/* ===== User-level CSRs ===== */
|
/* ===== User-level CSRs ===== */
|
||||||
|
|
||||||
/* User Trap Setup (N-extension) */
|
/* User Trap Setup (N-extension) */
|
||||||
@@ -287,12 +312,13 @@
|
|||||||
|
|
||||||
/* Supervisor Trap Setup */
|
/* Supervisor Trap Setup */
|
||||||
#define CSR_SSTATUS 0x100
|
#define CSR_SSTATUS 0x100
|
||||||
#define CSR_SEDELEG 0x102
|
|
||||||
#define CSR_SIDELEG 0x103
|
|
||||||
#define CSR_SIE 0x104
|
#define CSR_SIE 0x104
|
||||||
#define CSR_STVEC 0x105
|
#define CSR_STVEC 0x105
|
||||||
#define CSR_SCOUNTEREN 0x106
|
#define CSR_SCOUNTEREN 0x106
|
||||||
|
|
||||||
|
/* Supervisor Configuration */
|
||||||
|
#define CSR_SENVCFG 0x10a
|
||||||
|
|
||||||
/* Supervisor Trap Handling */
|
/* Supervisor Trap Handling */
|
||||||
#define CSR_SSCRATCH 0x140
|
#define CSR_SSCRATCH 0x140
|
||||||
#define CSR_SEPC 0x141
|
#define CSR_SEPC 0x141
|
||||||
@@ -300,9 +326,31 @@
|
|||||||
#define CSR_STVAL 0x143
|
#define CSR_STVAL 0x143
|
||||||
#define CSR_SIP 0x144
|
#define CSR_SIP 0x144
|
||||||
|
|
||||||
|
/* Sstc extension */
|
||||||
|
#define CSR_STIMECMP 0x14D
|
||||||
|
#define CSR_STIMECMPH 0x15D
|
||||||
|
|
||||||
/* Supervisor Protection and Translation */
|
/* Supervisor Protection and Translation */
|
||||||
#define CSR_SATP 0x180
|
#define CSR_SATP 0x180
|
||||||
|
|
||||||
|
/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
|
||||||
|
#define CSR_SISELECT 0x150
|
||||||
|
#define CSR_SIREG 0x151
|
||||||
|
|
||||||
|
/* Supervisor-Level Interrupts (AIA) */
|
||||||
|
#define CSR_STOPEI 0x15c
|
||||||
|
#define CSR_STOPI 0xdb0
|
||||||
|
|
||||||
|
/* Supervisor-Level High-Half CSRs (AIA) */
|
||||||
|
#define CSR_SIEH 0x114
|
||||||
|
#define CSR_SIPH 0x154
|
||||||
|
|
||||||
|
/* Supervisor stateen CSRs */
|
||||||
|
#define CSR_SSTATEEN0 0x10C
|
||||||
|
#define CSR_SSTATEEN1 0x10D
|
||||||
|
#define CSR_SSTATEEN2 0x10E
|
||||||
|
#define CSR_SSTATEEN3 0x10F
|
||||||
|
|
||||||
/* ===== Hypervisor-level CSRs ===== */
|
/* ===== Hypervisor-level CSRs ===== */
|
||||||
|
|
||||||
/* Hypervisor Trap Setup (H-extension) */
|
/* Hypervisor Trap Setup (H-extension) */
|
||||||
@@ -313,6 +361,10 @@
|
|||||||
#define CSR_HCOUNTEREN 0x606
|
#define CSR_HCOUNTEREN 0x606
|
||||||
#define CSR_HGEIE 0x607
|
#define CSR_HGEIE 0x607
|
||||||
|
|
||||||
|
/* Hypervisor Configuration */
|
||||||
|
#define CSR_HENVCFG 0x60a
|
||||||
|
#define CSR_HENVCFGH 0x61a
|
||||||
|
|
||||||
/* Hypervisor Trap Handling (H-extension) */
|
/* Hypervisor Trap Handling (H-extension) */
|
||||||
#define CSR_HTVAL 0x643
|
#define CSR_HTVAL 0x643
|
||||||
#define CSR_HIP 0x644
|
#define CSR_HIP 0x644
|
||||||
@@ -338,6 +390,39 @@
|
|||||||
#define CSR_VSIP 0x244
|
#define CSR_VSIP 0x244
|
||||||
#define CSR_VSATP 0x280
|
#define CSR_VSATP 0x280
|
||||||
|
|
||||||
|
/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
|
||||||
|
#define CSR_HVIEN 0x608
|
||||||
|
#define CSR_HVICTL 0x609
|
||||||
|
#define CSR_HVIPRIO1 0x646
|
||||||
|
#define CSR_HVIPRIO2 0x647
|
||||||
|
|
||||||
|
/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
|
||||||
|
#define CSR_VSISELECT 0x250
|
||||||
|
#define CSR_VSIREG 0x251
|
||||||
|
|
||||||
|
/* VS-Level Interrupts (H-extension with AIA) */
|
||||||
|
#define CSR_VSTOPEI 0x25c
|
||||||
|
#define CSR_VSTOPI 0xeb0
|
||||||
|
|
||||||
|
/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
|
||||||
|
#define CSR_HIDELEGH 0x613
|
||||||
|
#define CSR_HVIENH 0x618
|
||||||
|
#define CSR_HVIPH 0x655
|
||||||
|
#define CSR_HVIPRIO1H 0x656
|
||||||
|
#define CSR_HVIPRIO2H 0x657
|
||||||
|
#define CSR_VSIEH 0x214
|
||||||
|
#define CSR_VSIPH 0x254
|
||||||
|
|
||||||
|
/* Hypervisor stateen CSRs */
|
||||||
|
#define CSR_HSTATEEN0 0x60C
|
||||||
|
#define CSR_HSTATEEN0H 0x61C
|
||||||
|
#define CSR_HSTATEEN1 0x60D
|
||||||
|
#define CSR_HSTATEEN1H 0x61D
|
||||||
|
#define CSR_HSTATEEN2 0x60E
|
||||||
|
#define CSR_HSTATEEN2H 0x61E
|
||||||
|
#define CSR_HSTATEEN3 0x60F
|
||||||
|
#define CSR_HSTATEEN3H 0x61F
|
||||||
|
|
||||||
/* ===== Machine-level CSRs ===== */
|
/* ===== Machine-level CSRs ===== */
|
||||||
|
|
||||||
/* Machine Information Registers */
|
/* Machine Information Registers */
|
||||||
@@ -356,6 +441,10 @@
|
|||||||
#define CSR_MCOUNTEREN 0x306
|
#define CSR_MCOUNTEREN 0x306
|
||||||
#define CSR_MSTATUSH 0x310
|
#define CSR_MSTATUSH 0x310
|
||||||
|
|
||||||
|
/* Machine Configuration */
|
||||||
|
#define CSR_MENVCFG 0x30a
|
||||||
|
#define CSR_MENVCFGH 0x31a
|
||||||
|
|
||||||
/* Machine Trap Handling */
|
/* Machine Trap Handling */
|
||||||
#define CSR_MSCRATCH 0x340
|
#define CSR_MSCRATCH 0x340
|
||||||
#define CSR_MEPC 0x341
|
#define CSR_MEPC 0x341
|
||||||
@@ -589,6 +678,36 @@
|
|||||||
#define CSR_DSCRATCH0 0x7b2
|
#define CSR_DSCRATCH0 0x7b2
|
||||||
#define CSR_DSCRATCH1 0x7b3
|
#define CSR_DSCRATCH1 0x7b3
|
||||||
|
|
||||||
|
/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
|
||||||
|
#define CSR_MISELECT 0x350
|
||||||
|
#define CSR_MIREG 0x351
|
||||||
|
|
||||||
|
/* Machine-Level Interrupts (AIA) */
|
||||||
|
#define CSR_MTOPEI 0x35c
|
||||||
|
#define CSR_MTOPI 0xfb0
|
||||||
|
|
||||||
|
/* Virtual Interrupts for Supervisor Level (AIA) */
|
||||||
|
#define CSR_MVIEN 0x308
|
||||||
|
#define CSR_MVIP 0x309
|
||||||
|
|
||||||
|
/* Smstateen extension registers */
|
||||||
|
/* Machine stateen CSRs */
|
||||||
|
#define CSR_MSTATEEN0 0x30C
|
||||||
|
#define CSR_MSTATEEN0H 0x31C
|
||||||
|
#define CSR_MSTATEEN1 0x30D
|
||||||
|
#define CSR_MSTATEEN1H 0x31D
|
||||||
|
#define CSR_MSTATEEN2 0x30E
|
||||||
|
#define CSR_MSTATEEN2H 0x31E
|
||||||
|
#define CSR_MSTATEEN3 0x30F
|
||||||
|
#define CSR_MSTATEEN3H 0x31F
|
||||||
|
|
||||||
|
/* Machine-Level High-Half CSRs (AIA) */
|
||||||
|
#define CSR_MIDELEGH 0x313
|
||||||
|
#define CSR_MIEH 0x314
|
||||||
|
#define CSR_MVIENH 0x318
|
||||||
|
#define CSR_MVIPH 0x319
|
||||||
|
#define CSR_MIPH 0x354
|
||||||
|
|
||||||
/* ===== Trap/Exception Causes ===== */
|
/* ===== Trap/Exception Causes ===== */
|
||||||
|
|
||||||
#define CAUSE_MISALIGNED_FETCH 0x0
|
#define CAUSE_MISALIGNED_FETCH 0x0
|
||||||
@@ -611,6 +730,23 @@
|
|||||||
#define CAUSE_VIRTUAL_INST_FAULT 0x16
|
#define CAUSE_VIRTUAL_INST_FAULT 0x16
|
||||||
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
|
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
|
||||||
|
|
||||||
|
/* Common defines for all smstateen */
|
||||||
|
#define SMSTATEEN_MAX_COUNT 4
|
||||||
|
#define SMSTATEEN0_CS_SHIFT 0
|
||||||
|
#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT)
|
||||||
|
#define SMSTATEEN0_FCSR_SHIFT 1
|
||||||
|
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
|
||||||
|
#define SMSTATEEN0_IMSIC_SHIFT 58
|
||||||
|
#define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT)
|
||||||
|
#define SMSTATEEN0_AIA_SHIFT 59
|
||||||
|
#define SMSTATEEN0_AIA (_ULL(1) << SMSTATEEN0_AIA_SHIFT)
|
||||||
|
#define SMSTATEEN0_SVSLCT_SHIFT 60
|
||||||
|
#define SMSTATEEN0_SVSLCT (_ULL(1) << SMSTATEEN0_SVSLCT_SHIFT)
|
||||||
|
#define SMSTATEEN0_HSENVCFG_SHIFT 62
|
||||||
|
#define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT)
|
||||||
|
#define SMSTATEEN_STATEN_SHIFT 63
|
||||||
|
#define SMSTATEEN_STATEN (_ULL(1) << SMSTATEEN_STATEN_SHIFT)
|
||||||
|
|
||||||
/* ===== Instruction Encodings ===== */
|
/* ===== Instruction Encodings ===== */
|
||||||
|
|
||||||
#define INSN_MATCH_LB 0x3
|
#define INSN_MATCH_LB 0x3
|
||||||
@@ -686,6 +822,29 @@
|
|||||||
#define INSN_MASK_WFI 0xffffff00
|
#define INSN_MASK_WFI 0xffffff00
|
||||||
#define INSN_MATCH_WFI 0x10500000
|
#define INSN_MATCH_WFI 0x10500000
|
||||||
|
|
||||||
|
#define INSN_MASK_FENCE_TSO 0xffffffff
|
||||||
|
#define INSN_MATCH_FENCE_TSO 0x8330000f
|
||||||
|
|
||||||
|
#if __riscv_xlen == 64
|
||||||
|
|
||||||
|
/* 64-bit read for VS-stage address translation (RV64) */
|
||||||
|
#define INSN_PSEUDO_VS_LOAD 0x00003000
|
||||||
|
|
||||||
|
/* 64-bit write for VS-stage address translation (RV64) */
|
||||||
|
#define INSN_PSEUDO_VS_STORE 0x00003020
|
||||||
|
|
||||||
|
#elif __riscv_xlen == 32
|
||||||
|
|
||||||
|
/* 32-bit read for VS-stage address translation (RV32) */
|
||||||
|
#define INSN_PSEUDO_VS_LOAD 0x00002000
|
||||||
|
|
||||||
|
/* 32-bit write for VS-stage address translation (RV32) */
|
||||||
|
#define INSN_PSEUDO_VS_STORE 0x00002020
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unexpected __riscv_xlen"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define INSN_16BIT_MASK 0x3
|
#define INSN_16BIT_MASK 0x3
|
||||||
#define INSN_32BIT_MASK 0x1c
|
#define INSN_32BIT_MASK 0x1c
|
||||||
|
|
||||||
|
@@ -37,47 +37,12 @@
|
|||||||
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
|
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ffs - Find first bit set
|
* sbi_ffs - find first (less-significant) set bit in a long word.
|
||||||
* @x: the word to search
|
|
||||||
*
|
|
||||||
* This is defined the same way as
|
|
||||||
* the libc and compiler builtin ffs routines, therefore
|
|
||||||
* differs in spirit from the above ffz (man ffs).
|
|
||||||
*/
|
|
||||||
static inline int ffs(int x)
|
|
||||||
{
|
|
||||||
int r = 1;
|
|
||||||
|
|
||||||
if (!x)
|
|
||||||
return 0;
|
|
||||||
if (!(x & 0xffff)) {
|
|
||||||
x >>= 16;
|
|
||||||
r += 16;
|
|
||||||
}
|
|
||||||
if (!(x & 0xff)) {
|
|
||||||
x >>= 8;
|
|
||||||
r += 8;
|
|
||||||
}
|
|
||||||
if (!(x & 0xf)) {
|
|
||||||
x >>= 4;
|
|
||||||
r += 4;
|
|
||||||
}
|
|
||||||
if (!(x & 3)) {
|
|
||||||
x >>= 2;
|
|
||||||
r += 2;
|
|
||||||
}
|
|
||||||
if (!(x & 1))
|
|
||||||
r += 1;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __ffs - find first bit in word.
|
|
||||||
* @word: The word to search
|
* @word: The word to search
|
||||||
*
|
*
|
||||||
* Undefined if no bit exists, so code should check against 0 first.
|
* Undefined if no bit exists, so code should check against 0 first.
|
||||||
*/
|
*/
|
||||||
static inline int __ffs(unsigned long word)
|
static inline int sbi_ffs(unsigned long word)
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
|
||||||
@@ -109,55 +74,20 @@ static inline int __ffs(unsigned long word)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ffz - find first zero in word.
|
* sbi_ffz - find first zero in word.
|
||||||
* @word: The word to search
|
* @word: The word to search
|
||||||
*
|
*
|
||||||
* Undefined if no zero exists, so code should check against ~0UL first.
|
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||||
*/
|
*/
|
||||||
#define ffz(x) __ffs(~(x))
|
#define sbi_ffz(x) sbi_ffs(~(x))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fls - find last (most-significant) bit set
|
* sbi_fls - find last (most-significant) set bit in a long word
|
||||||
* @x: the word to search
|
|
||||||
*
|
|
||||||
* This is defined the same way as ffs.
|
|
||||||
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline int fls(int x)
|
|
||||||
{
|
|
||||||
int r = 32;
|
|
||||||
|
|
||||||
if (!x)
|
|
||||||
return 0;
|
|
||||||
if (!(x & 0xffff0000u)) {
|
|
||||||
x <<= 16;
|
|
||||||
r -= 16;
|
|
||||||
}
|
|
||||||
if (!(x & 0xff000000u)) {
|
|
||||||
x <<= 8;
|
|
||||||
r -= 8;
|
|
||||||
}
|
|
||||||
if (!(x & 0xf0000000u)) {
|
|
||||||
x <<= 4;
|
|
||||||
r -= 4;
|
|
||||||
}
|
|
||||||
if (!(x & 0xc0000000u)) {
|
|
||||||
x <<= 2;
|
|
||||||
r -= 2;
|
|
||||||
}
|
|
||||||
if (!(x & 0x80000000u))
|
|
||||||
r -= 1;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __fls - find last (most-significant) set bit in a long word
|
|
||||||
* @word: the word to search
|
* @word: the word to search
|
||||||
*
|
*
|
||||||
* Undefined if no set bit exists, so code should check against 0 first.
|
* Undefined if no set bit exists, so code should check against 0 first.
|
||||||
*/
|
*/
|
||||||
static inline unsigned long __fls(unsigned long word)
|
static inline unsigned long sbi_fls(unsigned long word)
|
||||||
{
|
{
|
||||||
int num = BITS_PER_LONG - 1;
|
int num = BITS_PER_LONG - 1;
|
||||||
|
|
||||||
|
@@ -174,10 +174,26 @@ int sbi_domain_register(struct sbi_domain *dom,
|
|||||||
* Add a memory region to the root domain
|
* Add a memory region to the root domain
|
||||||
* @param reg pointer to the memory region to be added
|
* @param reg pointer to the memory region to be added
|
||||||
*
|
*
|
||||||
* @return 0 on success and negative error code on failure
|
* @return 0 on success
|
||||||
|
* @return SBI_EALREADY if memory region conflicts with the existing one
|
||||||
|
* @return SBI_EINVAL otherwise
|
||||||
*/
|
*/
|
||||||
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
|
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a memory range with its flags to the root domain
|
||||||
|
* @param addr start physical address of memory range
|
||||||
|
* @param size physical size of memory range
|
||||||
|
* @param align alignment of memory region
|
||||||
|
* @param region_flags memory range flags
|
||||||
|
*
|
||||||
|
* @return 0 on success
|
||||||
|
* @return SBI_EALREADY if memory region conflicts with the existing one
|
||||||
|
* @return SBI_EINVAL otherwise
|
||||||
|
*/
|
||||||
|
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
|
||||||
|
unsigned long align, unsigned long region_flags);
|
||||||
|
|
||||||
/** Finalize domain tables and startup non-root domains */
|
/** Finalize domain tables and startup non-root domains */
|
||||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
|
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);
|
||||||
|
|
||||||
|
@@ -13,8 +13,8 @@
|
|||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
#include <sbi/sbi_list.h>
|
#include <sbi/sbi_list.h>
|
||||||
|
|
||||||
#define SBI_ECALL_VERSION_MAJOR 0
|
#define SBI_ECALL_VERSION_MAJOR 1
|
||||||
#define SBI_ECALL_VERSION_MINOR 3
|
#define SBI_ECALL_VERSION_MINOR 0
|
||||||
#define SBI_OPENSBI_IMPID 1
|
#define SBI_OPENSBI_IMPID 1
|
||||||
|
|
||||||
struct sbi_trap_regs;
|
struct sbi_trap_regs;
|
||||||
@@ -31,16 +31,6 @@ struct sbi_ecall_extension {
|
|||||||
struct sbi_trap_info *out_trap);
|
struct sbi_trap_info *out_trap);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct sbi_ecall_extension ecall_base;
|
|
||||||
extern struct sbi_ecall_extension ecall_legacy;
|
|
||||||
extern struct sbi_ecall_extension ecall_time;
|
|
||||||
extern struct sbi_ecall_extension ecall_rfence;
|
|
||||||
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_pmu;
|
|
||||||
|
|
||||||
u16 sbi_ecall_version_major(void);
|
u16 sbi_ecall_version_major(void);
|
||||||
|
|
||||||
u16 sbi_ecall_version_minor(void);
|
u16 sbi_ecall_version_minor(void);
|
||||||
|
@@ -208,6 +208,12 @@ enum sbi_pmu_ctr_type {
|
|||||||
|
|
||||||
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
|
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_OPS_RESULT 0x1
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_MASK 0x6
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET 1
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_ID_MASK 0xfff8
|
||||||
|
#define SBI_PMU_EVENT_HW_CACHE_ID_OFFSET 3
|
||||||
|
|
||||||
/* Flags defined for config matching function */
|
/* Flags defined for config matching function */
|
||||||
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
|
#define SBI_PMU_CFG_FLAG_SKIP_MATCH (1 << 0)
|
||||||
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
|
#define SBI_PMU_CFG_FLAG_CLEAR_VALUE (1 << 1)
|
||||||
|
@@ -12,21 +12,44 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
/** Possible feature flags of a hart */
|
/** Possible privileged specification versions of a hart */
|
||||||
enum sbi_hart_features {
|
enum sbi_hart_priv_versions {
|
||||||
/** Hart has S-mode counter enable */
|
/** Unknown privileged specification */
|
||||||
SBI_HART_HAS_SCOUNTEREN = (1 << 0),
|
SBI_HART_PRIV_VER_UNKNOWN = 0,
|
||||||
/** Hart has M-mode counter enable */
|
/** Privileged specification v1.10 */
|
||||||
SBI_HART_HAS_MCOUNTEREN = (1 << 1),
|
SBI_HART_PRIV_VER_1_10 = 1,
|
||||||
/** Hart has counter inhibit CSR */
|
/** Privileged specification v1.11 */
|
||||||
SBI_HART_HAS_MCOUNTINHIBIT = (1 << 2),
|
SBI_HART_PRIV_VER_1_11 = 2,
|
||||||
/** Hart has sscofpmf extension */
|
/** Privileged specification v1.12 */
|
||||||
SBI_HART_HAS_SSCOFPMF = (1 << 3),
|
SBI_HART_PRIV_VER_1_12 = 3,
|
||||||
/** HART has timer csr implementation in hardware */
|
};
|
||||||
SBI_HART_HAS_TIME = (1 << 4),
|
|
||||||
|
|
||||||
/** Last index of Hart features*/
|
/** Possible ISA extensions of a hart */
|
||||||
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
|
enum sbi_hart_extensions {
|
||||||
|
/** Hart has Sscofpmt extension */
|
||||||
|
SBI_HART_EXT_SSCOFPMF = 0,
|
||||||
|
/** HART has HW time CSR (extension name not available) */
|
||||||
|
SBI_HART_EXT_TIME,
|
||||||
|
/** HART has AIA M-mode CSRs */
|
||||||
|
SBI_HART_EXT_SMAIA,
|
||||||
|
/** HART has Smstateen CSR **/
|
||||||
|
SBI_HART_EXT_SMSTATEEN,
|
||||||
|
/** HART has Sstc extension */
|
||||||
|
SBI_HART_EXT_SSTC,
|
||||||
|
|
||||||
|
/** Maximum index of Hart extension */
|
||||||
|
SBI_HART_EXT_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sbi_hart_features {
|
||||||
|
bool detected;
|
||||||
|
int priv_version;
|
||||||
|
unsigned long extensions;
|
||||||
|
unsigned int pmp_count;
|
||||||
|
unsigned int pmp_addr_bits;
|
||||||
|
unsigned long pmp_gran;
|
||||||
|
unsigned int mhpm_count;
|
||||||
|
unsigned int mhpm_bits;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sbi_scratch;
|
struct sbi_scratch;
|
||||||
@@ -48,9 +71,16 @@ unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
|
|||||||
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
|
||||||
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
|
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
|
||||||
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
|
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
|
||||||
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
|
int sbi_hart_priv_version(struct sbi_scratch *scratch);
|
||||||
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
|
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
|
||||||
char *features_str, int nfstr);
|
char *version_str, int nvstr);
|
||||||
|
void sbi_hart_update_extension(struct sbi_scratch *scratch,
|
||||||
|
enum sbi_hart_extensions ext,
|
||||||
|
bool enable);
|
||||||
|
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
|
||||||
|
enum sbi_hart_extensions ext);
|
||||||
|
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
|
||||||
|
char *extension_str, int nestr);
|
||||||
|
|
||||||
void __attribute__((noreturn)) sbi_hart_hang(void);
|
void __attribute__((noreturn)) sbi_hart_hang(void);
|
||||||
|
|
||||||
|
@@ -34,9 +34,17 @@ struct sbi_hsm_device {
|
|||||||
* the hart resumes normal execution.
|
* the hart resumes normal execution.
|
||||||
*
|
*
|
||||||
* For successful non-retentive suspend, the hart will resume from
|
* For successful non-retentive suspend, the hart will resume from
|
||||||
* specified resume address
|
* the warm boot entry point.
|
||||||
*/
|
*/
|
||||||
int (*hart_suspend)(u32 suspend_type, ulong raddr);
|
int (*hart_suspend)(u32 suspend_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform platform-specific actions to resume from a suspended state.
|
||||||
|
*
|
||||||
|
* This includes restoring any platform state that was lost during
|
||||||
|
* non-retentive suspend.
|
||||||
|
*/
|
||||||
|
void (*hart_resume)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sbi_domain;
|
struct sbi_domain;
|
||||||
|
@@ -75,7 +75,7 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
|
|||||||
|
|
||||||
void sbi_ipi_process(void);
|
void sbi_ipi_process(void);
|
||||||
|
|
||||||
void sbi_ipi_raw_send(u32 target_hart);
|
int sbi_ipi_raw_send(u32 target_hart);
|
||||||
|
|
||||||
const struct sbi_ipi_device *sbi_ipi_get_device(void);
|
const struct sbi_ipi_device *sbi_ipi_get_device(void);
|
||||||
|
|
||||||
|
44
include/sbi/sbi_irqchip.h
Normal file
44
include/sbi/sbi_irqchip.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <apatel@ventanamicro.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SBI_IRQCHIP_H__
|
||||||
|
#define __SBI_IRQCHIP_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct sbi_scratch;
|
||||||
|
struct sbi_trap_regs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set external interrupt handling function
|
||||||
|
*
|
||||||
|
* This function is called by OpenSBI platform code to set a handler for
|
||||||
|
* external interrupts
|
||||||
|
*
|
||||||
|
* @param fn function pointer for handling external irqs
|
||||||
|
*/
|
||||||
|
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process external interrupts
|
||||||
|
*
|
||||||
|
* This function is called by sbi_trap_handler() to handle external
|
||||||
|
* interrupts.
|
||||||
|
*
|
||||||
|
* @param regs pointer for trap registers
|
||||||
|
*/
|
||||||
|
int sbi_irqchip_process(struct sbi_trap_regs *regs);
|
||||||
|
|
||||||
|
/** Initialize interrupt controllers */
|
||||||
|
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||||
|
|
||||||
|
/** Exit interrupt controllers */
|
||||||
|
void sbi_irqchip_exit(struct sbi_scratch *scratch);
|
||||||
|
|
||||||
|
#endif
|
@@ -48,6 +48,7 @@
|
|||||||
struct sbi_domain_memregion;
|
struct sbi_domain_memregion;
|
||||||
struct sbi_trap_info;
|
struct sbi_trap_info;
|
||||||
struct sbi_trap_regs;
|
struct sbi_trap_regs;
|
||||||
|
struct sbi_hart_features;
|
||||||
|
|
||||||
/** Possible feature flags of a platform */
|
/** Possible feature flags of a platform */
|
||||||
enum sbi_platform_features {
|
enum sbi_platform_features {
|
||||||
@@ -64,6 +65,9 @@ enum sbi_platform_features {
|
|||||||
|
|
||||||
/** Platform functions */
|
/** Platform functions */
|
||||||
struct sbi_platform_operations {
|
struct sbi_platform_operations {
|
||||||
|
/* Platform nascent initialization */
|
||||||
|
int (*nascent_init)(void);
|
||||||
|
|
||||||
/** Platform early initialization */
|
/** Platform early initialization */
|
||||||
int (*early_init)(bool cold_boot);
|
int (*early_init)(bool cold_boot);
|
||||||
/** Platform final initialization */
|
/** Platform final initialization */
|
||||||
@@ -86,6 +90,9 @@ struct sbi_platform_operations {
|
|||||||
*/
|
*/
|
||||||
int (*misa_get_xlen)(void);
|
int (*misa_get_xlen)(void);
|
||||||
|
|
||||||
|
/** Initialize (or populate) HART extensions for the platform */
|
||||||
|
int (*extensions_init)(struct sbi_hart_features *hfeatures);
|
||||||
|
|
||||||
/** Initialize (or populate) domains for the platform */
|
/** Initialize (or populate) domains for the platform */
|
||||||
int (*domains_init)(void);
|
int (*domains_init)(void);
|
||||||
|
|
||||||
@@ -172,6 +179,56 @@ struct sbi_platform {
|
|||||||
const u32 *hart_index2id;
|
const u32 *hart_index2id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent modification of struct sbi_platform from affecting
|
||||||
|
* SBI_PLATFORM_xxx_OFFSET
|
||||||
|
*/
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, opensbi_version)
|
||||||
|
== SBI_PLATFORM_OPENSBI_VERSION_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_OPENSBI_VERSION_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, platform_version)
|
||||||
|
== SBI_PLATFORM_VERSION_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_VERSION_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, name)
|
||||||
|
== SBI_PLATFORM_NAME_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_NAME_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, features)
|
||||||
|
== SBI_PLATFORM_FEATURES_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_FEATURES_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, hart_count)
|
||||||
|
== SBI_PLATFORM_HART_COUNT_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_HART_COUNT_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, hart_stack_size)
|
||||||
|
== SBI_PLATFORM_HART_STACK_SIZE_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_HART_STACK_SIZE_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, platform_ops_addr)
|
||||||
|
== SBI_PLATFORM_OPS_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_OPS_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, firmware_context)
|
||||||
|
== SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_platform, hart_index2id)
|
||||||
|
== SBI_PLATFORM_HART_INDEX2ID_OFFSET,
|
||||||
|
"struct sbi_platform definition has changed, please redefine "
|
||||||
|
"SBI_PLATFORM_HART_INDEX2ID_OFFSET");
|
||||||
|
|
||||||
/** Get pointer to sbi_platform for sbi_scratch pointer */
|
/** Get pointer to sbi_platform for sbi_scratch pointer */
|
||||||
#define sbi_platform_ptr(__s) \
|
#define sbi_platform_ptr(__s) \
|
||||||
((const struct sbi_platform *)((__s)->platform_addr))
|
((const struct sbi_platform *)((__s)->platform_addr))
|
||||||
@@ -299,6 +356,23 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nascent (very early) initialization for current HART
|
||||||
|
*
|
||||||
|
* NOTE: This function can be used to do very early initialization of
|
||||||
|
* platform specific per-HART CSRs and devices.
|
||||||
|
*
|
||||||
|
* @param plat pointer to struct sbi_platform
|
||||||
|
*
|
||||||
|
* @return 0 on success and negative error code on failure
|
||||||
|
*/
|
||||||
|
static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
|
||||||
|
{
|
||||||
|
if (plat && sbi_platform_ops(plat)->nascent_init)
|
||||||
|
return sbi_platform_ops(plat)->nascent_init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Early initialization for current HART
|
* Early initialization for current HART
|
||||||
*
|
*
|
||||||
@@ -383,6 +457,22 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize (or populate) HART extensions for the platform
|
||||||
|
*
|
||||||
|
* @param plat pointer to struct sbi_platform
|
||||||
|
*
|
||||||
|
* @return 0 on success and negative error code on failure
|
||||||
|
*/
|
||||||
|
static inline int sbi_platform_extensions_init(
|
||||||
|
const struct sbi_platform *plat,
|
||||||
|
struct sbi_hart_features *hfeatures)
|
||||||
|
{
|
||||||
|
if (plat && sbi_platform_ops(plat)->extensions_init)
|
||||||
|
return sbi_platform_ops(plat)->extensions_init(hfeatures);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize (or populate) domains for the platform
|
* Initialize (or populate) domains for the platform
|
||||||
*
|
*
|
||||||
|
@@ -11,16 +11,12 @@
|
|||||||
#define __SBI_PMU_H__
|
#define __SBI_PMU_H__
|
||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
#include <sbi/sbi_hartmask.h>
|
|
||||||
#include <sbi/sbi_scratch.h>
|
struct sbi_scratch;
|
||||||
#include <sbi/sbi_ecall_interface.h>
|
|
||||||
|
|
||||||
/* Event related macros */
|
/* Event related macros */
|
||||||
/* Maximum number of hardware events that can mapped by OpenSBI */
|
/* Maximum number of hardware events that can mapped by OpenSBI */
|
||||||
#define SBI_PMU_HW_EVENT_MAX 64
|
#define SBI_PMU_HW_EVENT_MAX 256
|
||||||
|
|
||||||
/* Maximum number of firmware events that can mapped by OpenSBI */
|
|
||||||
#define SBI_PMU_FW_EVENT_MAX 32
|
|
||||||
|
|
||||||
/* Counter related macros */
|
/* Counter related macros */
|
||||||
#define SBI_PMU_FW_CTR_MAX 16
|
#define SBI_PMU_FW_CTR_MAX 16
|
||||||
@@ -28,12 +24,77 @@
|
|||||||
#define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
|
#define SBI_PMU_CTR_MAX (SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX)
|
||||||
#define SBI_PMU_FIXED_CTR_MASK 0x07
|
#define SBI_PMU_FIXED_CTR_MASK 0x07
|
||||||
|
|
||||||
|
struct sbi_pmu_device {
|
||||||
|
/** Name of the PMU platform device */
|
||||||
|
char name[32];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate event code of custom firmware event
|
||||||
|
* Note: SBI_PMU_FW_MAX <= event_idx_code
|
||||||
|
*/
|
||||||
|
int (*fw_event_validate_code)(uint32_t event_idx_code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match custom firmware counter with custom firmware event
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
bool (*fw_counter_match_code)(uint32_t counter_index,
|
||||||
|
uint32_t event_idx_code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read value of custom firmware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
uint64_t (*fw_counter_read_value)(uint32_t counter_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start custom firmware counter
|
||||||
|
* Note: SBI_PMU_FW_MAX <= event_idx_code
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
int (*fw_counter_start)(uint32_t counter_index,
|
||||||
|
uint32_t event_idx_code,
|
||||||
|
uint64_t init_val, bool init_val_update);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop custom firmware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_FW_CTR_MAX
|
||||||
|
*/
|
||||||
|
int (*fw_counter_stop)(uint32_t counter_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom enable irq for hardware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
|
||||||
|
*/
|
||||||
|
void (*hw_counter_enable_irq)(uint32_t counter_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom disable irq for hardware counter
|
||||||
|
* Note: 0 <= counter_index < SBI_PMU_HW_CTR_MAX
|
||||||
|
*/
|
||||||
|
void (*hw_counter_disable_irq)(uint32_t counter_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom function returning the machine-specific irq-bit.
|
||||||
|
*/
|
||||||
|
int (*hw_counter_irq_bit)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get the PMU platform device */
|
||||||
|
const struct sbi_pmu_device *sbi_pmu_get_device(void);
|
||||||
|
|
||||||
|
/** Set the PMU platform device */
|
||||||
|
void sbi_pmu_set_device(const struct sbi_pmu_device *dev);
|
||||||
|
|
||||||
/** Initialize PMU */
|
/** Initialize PMU */
|
||||||
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
|
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot);
|
||||||
|
|
||||||
/** Reset PMU during hart exit */
|
/** Reset PMU during hart exit */
|
||||||
void sbi_pmu_exit(struct sbi_scratch *scratch);
|
void sbi_pmu_exit(struct sbi_scratch *scratch);
|
||||||
|
|
||||||
|
/** Return the pmu irq bit depending on extension existence */
|
||||||
|
int sbi_pmu_irq_bit(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the hardware event to counter mapping information. This should be called
|
* Add the hardware event to counter mapping information. This should be called
|
||||||
* from the platform code to update the mapping table.
|
* from the platform code to update the mapping table.
|
||||||
@@ -53,7 +114,7 @@ int sbi_pmu_add_hw_event_counter_map(u32 eidx_start, u32 eidx_end, u32 cmap);
|
|||||||
|
|
||||||
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
|
int sbi_pmu_add_raw_event_counter_map(uint64_t select, uint64_t select_mask, u32 cmap);
|
||||||
|
|
||||||
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval);
|
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval);
|
||||||
|
|
||||||
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
|
int sbi_pmu_ctr_stop(unsigned long cidx_base, unsigned long cidx_mask,
|
||||||
unsigned long flag);
|
unsigned long flag);
|
||||||
|
@@ -57,7 +57,7 @@ struct sbi_scratch {
|
|||||||
unsigned long next_arg1;
|
unsigned long next_arg1;
|
||||||
/** Address of next booting stage for this HART */
|
/** Address of next booting stage for this HART */
|
||||||
unsigned long next_addr;
|
unsigned long next_addr;
|
||||||
/** Priviledge mode of next booting stage for this HART */
|
/** Privilege mode of next booting stage for this HART */
|
||||||
unsigned long next_mode;
|
unsigned long next_mode;
|
||||||
/** Warm boot entry point address for this HART */
|
/** Warm boot entry point address for this HART */
|
||||||
unsigned long warmboot_addr;
|
unsigned long warmboot_addr;
|
||||||
@@ -73,6 +73,66 @@ struct sbi_scratch {
|
|||||||
unsigned long options;
|
unsigned long options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent modification of struct sbi_scratch from affecting
|
||||||
|
* SBI_SCRATCH_xxx_OFFSET
|
||||||
|
*/
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, fw_start)
|
||||||
|
== SBI_SCRATCH_FW_START_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_FW_START_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, fw_size)
|
||||||
|
== SBI_SCRATCH_FW_SIZE_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_FW_SIZE_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, next_arg1)
|
||||||
|
== SBI_SCRATCH_NEXT_ARG1_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_NEXT_ARG1_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, next_addr)
|
||||||
|
== SBI_SCRATCH_NEXT_ADDR_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_NEXT_ADDR_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, next_mode)
|
||||||
|
== SBI_SCRATCH_NEXT_MODE_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_NEXT_MODE_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, warmboot_addr)
|
||||||
|
== SBI_SCRATCH_WARMBOOT_ADDR_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_WARMBOOT_ADDR_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, platform_addr)
|
||||||
|
== SBI_SCRATCH_PLATFORM_ADDR_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_PLATFORM_ADDR_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, hartid_to_scratch)
|
||||||
|
== SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, trap_exit)
|
||||||
|
== SBI_SCRATCH_TRAP_EXIT_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_TRAP_EXIT_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, tmp0)
|
||||||
|
== SBI_SCRATCH_TMP0_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_TMP0_OFFSET");
|
||||||
|
_Static_assert(
|
||||||
|
offsetof(struct sbi_scratch, options)
|
||||||
|
== SBI_SCRATCH_OPTIONS_OFFSET,
|
||||||
|
"struct sbi_scratch definition has changed, please redefine "
|
||||||
|
"SBI_SCRATCH_OPTIONS_OFFSET");
|
||||||
|
|
||||||
/** Possible options for OpenSBI library */
|
/** Possible options for OpenSBI library */
|
||||||
enum sbi_scratch_options {
|
enum sbi_scratch_options {
|
||||||
/** Disable prints during boot */
|
/** Disable prints during boot */
|
||||||
@@ -104,11 +164,11 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size);
|
|||||||
void sbi_scratch_free_offset(unsigned long offset);
|
void sbi_scratch_free_offset(unsigned long offset);
|
||||||
|
|
||||||
/** Get pointer from offset in sbi_scratch */
|
/** Get pointer from offset in sbi_scratch */
|
||||||
#define sbi_scratch_offset_ptr(scratch, offset) ((void *)scratch + (offset))
|
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
|
||||||
|
|
||||||
/** Get pointer from offset in sbi_scratch for current HART */
|
/** Get pointer from offset in sbi_scratch for current HART */
|
||||||
#define sbi_scratch_thishart_offset_ptr(offset) \
|
#define sbi_scratch_thishart_offset_ptr(offset) \
|
||||||
((void *)sbi_scratch_thishart_ptr() + (offset))
|
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
|
||||||
|
|
||||||
/** HART id to scratch table */
|
/** HART id to scratch table */
|
||||||
extern struct sbi_scratch *hartid_to_scratch_table[];
|
extern struct sbi_scratch *hartid_to_scratch_table[];
|
||||||
|
@@ -48,6 +48,24 @@ static inline void sbi_timer_udelay(ulong usecs)
|
|||||||
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
|
sbi_timer_delay_loop(usecs, 1000000, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A blocking function that will wait until @p predicate returns true or
|
||||||
|
* @p timeout_ms milliseconds elapsed. @p arg will be passed as argument to
|
||||||
|
* @p predicate function.
|
||||||
|
*
|
||||||
|
* @param predicate Pointer to a function that returns true if certain
|
||||||
|
* condition is met. It shouldn't block the code execution.
|
||||||
|
* @param arg Argument to pass to @p predicate.
|
||||||
|
* @param timeout_ms Timeout value in milliseconds. The function will return
|
||||||
|
* false if @p timeout_ms time period elapsed but still @p predicate doesn't
|
||||||
|
* return true.
|
||||||
|
*
|
||||||
|
* @return true if @p predicate returns true within @p timeout_ms, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
|
||||||
|
uint64_t timeout_ms);
|
||||||
|
|
||||||
/** Get timer value for current HART */
|
/** Get timer value for current HART */
|
||||||
u64 sbi_timer_value(void);
|
u64 sbi_timer_value(void);
|
||||||
|
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
#ifndef __SBI_TRAP_H__
|
#ifndef __SBI_TRAP_H__
|
||||||
#define __SBI_TRAP_H__
|
#define __SBI_TRAP_H__
|
||||||
|
|
||||||
|
#include <sbi/riscv_encoding.h>
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
/** Index of zero member in sbi_trap_regs */
|
/** Index of zero member in sbi_trap_regs */
|
||||||
@@ -95,8 +97,10 @@
|
|||||||
#define SBI_TRAP_INFO_tval2 3
|
#define SBI_TRAP_INFO_tval2 3
|
||||||
/** Index of tinst member in sbi_trap_info */
|
/** Index of tinst member in sbi_trap_info */
|
||||||
#define SBI_TRAP_INFO_tinst 4
|
#define SBI_TRAP_INFO_tinst 4
|
||||||
|
/** Index of gva member in sbi_trap_info */
|
||||||
|
#define SBI_TRAP_INFO_gva 5
|
||||||
/** Last member index in sbi_trap_info */
|
/** Last member index in sbi_trap_info */
|
||||||
#define SBI_TRAP_INFO_last 5
|
#define SBI_TRAP_INFO_last 6
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
@@ -200,8 +204,26 @@ struct sbi_trap_info {
|
|||||||
unsigned long tval2;
|
unsigned long tval2;
|
||||||
/** tinst Trap instruction */
|
/** tinst Trap instruction */
|
||||||
unsigned long tinst;
|
unsigned long tinst;
|
||||||
|
/** gva Guest virtual address in tval flag */
|
||||||
|
unsigned long gva;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline unsigned long sbi_regs_gva(const struct sbi_trap_regs *regs)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the hypervisor extension is not implemented, mstatus[h].GVA is a
|
||||||
|
* WPRI field, which is guaranteed to read as zero. In addition, in this
|
||||||
|
* case we don't read mstatush and instead pretend it is zero, which
|
||||||
|
* handles privileged spec version < 1.12.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
return (regs->mstatusH & MSTATUSH_GVA) ? 1 : 0;
|
||||||
|
#else
|
||||||
|
return (regs->mstatus & MSTATUS_GVA) ? 1 : 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
||||||
struct sbi_trap_info *trap);
|
struct sbi_trap_info *trap);
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
#define __SBI_VERSION_H__
|
#define __SBI_VERSION_H__
|
||||||
|
|
||||||
#define OPENSBI_VERSION_MAJOR 1
|
#define OPENSBI_VERSION_MAJOR 1
|
||||||
#define OPENSBI_VERSION_MINOR 0
|
#define OPENSBI_VERSION_MINOR 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenSBI 32-bit version with:
|
* OpenSBI 32-bit version with:
|
||||||
|
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_DOMAIN
|
||||||
|
|
||||||
struct sbi_domain;
|
struct sbi_domain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,4 +72,11 @@ void fdt_domain_fixup(void *fdt);
|
|||||||
*/
|
*/
|
||||||
int fdt_domains_populate(void *fdt);
|
int fdt_domains_populate(void *fdt);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_domain_fixup(void *fdt) { }
|
||||||
|
static inline int fdt_domains_populate(void *fdt) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __FDT_DOMAIN_H__ */
|
#endif /* __FDT_DOMAIN_H__ */
|
||||||
|
@@ -21,6 +21,30 @@
|
|||||||
*/
|
*/
|
||||||
void fdt_cpu_fixup(void *fdt);
|
void fdt_cpu_fixup(void *fdt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix up the APLIC nodes in the device tree
|
||||||
|
*
|
||||||
|
* This routine disables APLIC nodes which are not accessible to the next
|
||||||
|
* booting stage based on currently assigned domain.
|
||||||
|
*
|
||||||
|
* It is recommended that platform codes call this helper in their final_init()
|
||||||
|
*
|
||||||
|
* @param fdt: device tree blob
|
||||||
|
*/
|
||||||
|
void fdt_aplic_fixup(void *fdt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix up the IMSIC nodes in the device tree
|
||||||
|
*
|
||||||
|
* This routine disables IMSIC nodes which are not accessible to the next
|
||||||
|
* booting stage based on currently assigned domain.
|
||||||
|
*
|
||||||
|
* It is recommended that platform codes call this helper in their final_init()
|
||||||
|
*
|
||||||
|
* @param fdt: device tree blob
|
||||||
|
*/
|
||||||
|
void fdt_imsic_fixup(void *fdt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix up the PLIC node in the device tree
|
* Fix up the PLIC node in the device tree
|
||||||
*
|
*
|
||||||
@@ -64,8 +88,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
|
|||||||
* General device tree fix-up
|
* General device tree fix-up
|
||||||
*
|
*
|
||||||
* This routine do all required device tree fix-ups for a typical platform.
|
* This routine do all required device tree fix-ups for a typical platform.
|
||||||
* It fixes up the PLIC node and the reserved memory node in the device tree
|
* It fixes up the PLIC node, IMSIC nodes, APLIC nodes, and the reserved
|
||||||
* by calling the corresponding helper routines to accomplish the task.
|
* memory node in the device tree by calling the corresponding helper
|
||||||
|
* routines to accomplish the task.
|
||||||
*
|
*
|
||||||
* It is recommended that platform codes call this helper in their final_init()
|
* It is recommended that platform codes call this helper in their final_init()
|
||||||
*
|
*
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
struct fdt_match {
|
struct fdt_match {
|
||||||
const char *compatible;
|
const char *compatible;
|
||||||
void *data;
|
const void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FDT_MAX_PHANDLE_ARGS 16
|
#define FDT_MAX_PHANDLE_ARGS 16
|
||||||
@@ -31,6 +31,7 @@ struct platform_uart_data {
|
|||||||
unsigned long baud;
|
unsigned long baud;
|
||||||
unsigned long reg_shift;
|
unsigned long reg_shift;
|
||||||
unsigned long reg_io_width;
|
unsigned long reg_io_width;
|
||||||
|
unsigned long reg_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
|
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
|
||||||
@@ -47,27 +48,45 @@ int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
|
|||||||
int fdt_get_node_addr_size(void *fdt, int node, int index,
|
int fdt_get_node_addr_size(void *fdt, int node, int index,
|
||||||
uint64_t *addr, uint64_t *size);
|
uint64_t *addr, uint64_t *size);
|
||||||
|
|
||||||
|
bool fdt_node_is_enabled(void *fdt, int nodeoff);
|
||||||
|
|
||||||
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
|
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
|
||||||
|
|
||||||
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid);
|
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid);
|
||||||
|
|
||||||
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
|
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
|
||||||
|
|
||||||
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
|
int fdt_parse_renesas_scif_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
|
int fdt_parse_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
||||||
const char *compatible);
|
const char *compatible);
|
||||||
|
|
||||||
|
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
|
struct aplic_data;
|
||||||
|
|
||||||
|
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic);
|
||||||
|
|
||||||
|
struct imsic_data;
|
||||||
|
|
||||||
|
bool fdt_check_imsic_mlevel(void *fdt);
|
||||||
|
|
||||||
|
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic);
|
||||||
|
|
||||||
struct plic_data;
|
struct plic_data;
|
||||||
|
|
||||||
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
|
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
|
||||||
@@ -79,6 +98,12 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
|
|||||||
unsigned long *out_addr2, unsigned long *out_size2,
|
unsigned long *out_addr2, unsigned long *out_size2,
|
||||||
u32 *out_first_hartid, u32 *out_hart_count);
|
u32 *out_first_hartid, u32 *out_hart_count);
|
||||||
|
|
||||||
|
int fdt_parse_plmt_node(void *fdt, int nodeoffset, unsigned long *plmt_base,
|
||||||
|
unsigned long *plmt_size, u32 *hart_count);
|
||||||
|
|
||||||
|
int fdt_parse_plicsw_node(void *fdt, int nodeoffset, unsigned long *plicsw_base,
|
||||||
|
unsigned long *size, u32 *hart_count);
|
||||||
|
|
||||||
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
|
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
|
||||||
const char *compatible);
|
const char *compatible);
|
||||||
|
|
||||||
|
@@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_PMU
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix up the PMU node in the device tree
|
* Fix up the PMU node in the device tree
|
||||||
*
|
*
|
||||||
@@ -43,4 +45,12 @@ int fdt_pmu_setup(void *fdt);
|
|||||||
*/
|
*/
|
||||||
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
|
uint64_t fdt_pmu_get_select_value(uint32_t event_idx);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_pmu_fixup(void *fdt) { }
|
||||||
|
static inline int fdt_pmu_setup(void *fdt) { return 0; }
|
||||||
|
static inline uint64_t fdt_pmu_get_select_value(uint32_t event_idx) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi_utils/gpio/gpio.h>
|
#include <sbi_utils/gpio/gpio.h>
|
||||||
|
|
||||||
|
struct fdt_phandle_args;
|
||||||
|
|
||||||
/** FDT based GPIO driver */
|
/** FDT based GPIO driver */
|
||||||
struct fdt_gpio {
|
struct fdt_gpio {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
|
46
include/sbi_utils/ipi/andes_plicsw.h
Normal file
46
include/sbi_utils/ipi/andes_plicsw.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Andes Technology Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Zong Li <zong@andestech.com>
|
||||||
|
* Nylon Chen <nylon7@andestech.com>
|
||||||
|
* Leo Yu-Chi Liang <ycliang@andestech.com>
|
||||||
|
* Yu Chien Peter Lin <peterlin@andestech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IPI_ANDES_PLICSW_H_
|
||||||
|
#define _IPI_ANDES_PLICSW_H_
|
||||||
|
|
||||||
|
#define PLICSW_PRIORITY_BASE 0x4
|
||||||
|
|
||||||
|
#define PLICSW_PENDING_BASE 0x1000
|
||||||
|
#define PLICSW_PENDING_STRIDE 0x8
|
||||||
|
|
||||||
|
#define PLICSW_ENABLE_BASE 0x2000
|
||||||
|
#define PLICSW_ENABLE_STRIDE 0x80
|
||||||
|
|
||||||
|
#define PLICSW_CONTEXT_BASE 0x200000
|
||||||
|
#define PLICSW_CONTEXT_STRIDE 0x1000
|
||||||
|
#define PLICSW_CONTEXT_CLAIM 0x4
|
||||||
|
|
||||||
|
#define PLICSW_HART_MASK 0x01010101
|
||||||
|
|
||||||
|
#define PLICSW_HART_MAX_NR 8
|
||||||
|
|
||||||
|
#define PLICSW_REGION_ALIGN 0x1000
|
||||||
|
|
||||||
|
struct plicsw_data {
|
||||||
|
unsigned long addr;
|
||||||
|
unsigned long size;
|
||||||
|
uint32_t hart_count;
|
||||||
|
/* hart id to source id table */
|
||||||
|
uint32_t source_id[PLICSW_HART_MAX_NR];
|
||||||
|
};
|
||||||
|
|
||||||
|
int plicsw_warm_ipi_init(void);
|
||||||
|
|
||||||
|
int plicsw_cold_ipi_init(struct plicsw_data *plicsw);
|
||||||
|
|
||||||
|
#endif /* _IPI_ANDES_PLICSW_H_ */
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_IPI
|
||||||
|
|
||||||
struct fdt_ipi {
|
struct fdt_ipi {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
@@ -23,4 +25,11 @@ void fdt_ipi_exit(void);
|
|||||||
|
|
||||||
int fdt_ipi_init(bool cold_boot);
|
int fdt_ipi_init(bool cold_boot);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_ipi_exit(void) { }
|
||||||
|
static inline int fdt_ipi_init(bool cold_boot) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
47
include/sbi_utils/irqchip/aplic.h
Normal file
47
include/sbi_utils/irqchip/aplic.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
||||||
|
* Copyright (c) 2022 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IRQCHIP_APLIC_H__
|
||||||
|
#define __IRQCHIP_APLIC_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#define APLIC_MAX_DELEGATE 16
|
||||||
|
|
||||||
|
struct aplic_msicfg_data {
|
||||||
|
unsigned long lhxs;
|
||||||
|
unsigned long lhxw;
|
||||||
|
unsigned long hhxs;
|
||||||
|
unsigned long hhxw;
|
||||||
|
unsigned long base_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aplic_delegate_data {
|
||||||
|
u32 first_irq;
|
||||||
|
u32 last_irq;
|
||||||
|
u32 child_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aplic_data {
|
||||||
|
unsigned long addr;
|
||||||
|
unsigned long size;
|
||||||
|
unsigned long num_idc;
|
||||||
|
unsigned long num_source;
|
||||||
|
bool targets_mmode;
|
||||||
|
bool has_msicfg_mmode;
|
||||||
|
struct aplic_msicfg_data msicfg_mmode;
|
||||||
|
bool has_msicfg_smode;
|
||||||
|
struct aplic_msicfg_data msicfg_smode;
|
||||||
|
struct aplic_delegate_data delegate[APLIC_MAX_DELEGATE];
|
||||||
|
};
|
||||||
|
|
||||||
|
int aplic_cold_irqchip_init(struct aplic_data *aplic);
|
||||||
|
|
||||||
|
#endif
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_IRQCHIP
|
||||||
|
|
||||||
struct fdt_irqchip {
|
struct fdt_irqchip {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
@@ -23,4 +25,12 @@ void fdt_irqchip_exit(void);
|
|||||||
|
|
||||||
int fdt_irqchip_init(bool cold_boot);
|
int fdt_irqchip_init(bool cold_boot);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_irqchip_exit(void) { }
|
||||||
|
|
||||||
|
static inline int fdt_irqchip_init(bool cold_boot) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
33
include/sbi_utils/irqchip/fdt_irqchip_plic.h
Normal file
33
include/sbi_utils/irqchip/fdt_irqchip_plic.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Samuel Holland <samuel@sholland.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IRQCHIP_FDT_IRQCHIP_PLIC_H__
|
||||||
|
#define __IRQCHIP_FDT_IRQCHIP_PLIC_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the PLIC priority state
|
||||||
|
* @param priority pointer to the memory region for the saved priority
|
||||||
|
* @param num size of the memory region including interrupt source 0
|
||||||
|
*/
|
||||||
|
void fdt_plic_priority_save(u8 *priority, u32 num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the PLIC priority state
|
||||||
|
* @param priority pointer to the memory region for the saved priority
|
||||||
|
* @param num size of the memory region including interrupt source 0
|
||||||
|
*/
|
||||||
|
void fdt_plic_priority_restore(const u8 *priority, u32 num);
|
||||||
|
|
||||||
|
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold, u32 num);
|
||||||
|
|
||||||
|
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold,
|
||||||
|
u32 num);
|
||||||
|
|
||||||
|
void thead_plic_restore(void);
|
||||||
|
|
||||||
|
#endif
|
60
include/sbi_utils/irqchip/imsic.h
Normal file
60
include/sbi_utils/irqchip/imsic.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
|
||||||
|
* Copyright (c) 2022 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IRQCHIP_IMSIC_H__
|
||||||
|
#define __IRQCHIP_IMSIC_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#define IMSIC_MMIO_PAGE_SHIFT 12
|
||||||
|
#define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT)
|
||||||
|
|
||||||
|
#define IMSIC_MAX_REGS 16
|
||||||
|
|
||||||
|
struct imsic_regs {
|
||||||
|
unsigned long addr;
|
||||||
|
unsigned long size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct imsic_data {
|
||||||
|
bool targets_mmode;
|
||||||
|
u32 guest_index_bits;
|
||||||
|
u32 hart_index_bits;
|
||||||
|
u32 group_index_bits;
|
||||||
|
u32 group_index_shift;
|
||||||
|
unsigned long num_ids;
|
||||||
|
struct imsic_regs regs[IMSIC_MAX_REGS];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_IRQCHIP_IMSIC
|
||||||
|
|
||||||
|
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file);
|
||||||
|
|
||||||
|
struct imsic_data *imsic_get_data(u32 hartid);
|
||||||
|
|
||||||
|
int imsic_get_target_file(u32 hartid);
|
||||||
|
|
||||||
|
void imsic_local_irqchip_init(void);
|
||||||
|
|
||||||
|
int imsic_warm_irqchip_init(void);
|
||||||
|
|
||||||
|
int imsic_data_check(struct imsic_data *imsic);
|
||||||
|
|
||||||
|
int imsic_cold_irqchip_init(struct imsic_data *imsic);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void imsic_local_irqchip_init(void) { }
|
||||||
|
|
||||||
|
static inline int imsic_data_check(struct imsic_data *imsic) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@@ -17,13 +17,24 @@ struct plic_data {
|
|||||||
unsigned long num_src;
|
unsigned long num_src;
|
||||||
};
|
};
|
||||||
|
|
||||||
int plic_warm_irqchip_init(struct plic_data *plic,
|
/* So far, priorities on all consumers of these functions fit in 8 bits. */
|
||||||
|
void plic_priority_save(const struct plic_data *plic, u8 *priority, u32 num);
|
||||||
|
|
||||||
|
void plic_priority_restore(const struct plic_data *plic, const u8 *priority,
|
||||||
|
u32 num);
|
||||||
|
|
||||||
|
void plic_context_save(const struct plic_data *plic, int context_id,
|
||||||
|
u32 *enable, u32 *threshold, u32 num);
|
||||||
|
|
||||||
|
void plic_context_restore(const struct plic_data *plic, int context_id,
|
||||||
|
const u32 *enable, u32 threshold, u32 num);
|
||||||
|
|
||||||
|
int plic_context_init(const struct plic_data *plic, int context_id,
|
||||||
|
bool enable, u32 threshold);
|
||||||
|
|
||||||
|
int plic_warm_irqchip_init(const struct plic_data *plic,
|
||||||
int m_cntx_id, int s_cntx_id);
|
int m_cntx_id, int s_cntx_id);
|
||||||
|
|
||||||
int plic_cold_irqchip_init(struct plic_data *plic);
|
int plic_cold_irqchip_init(const struct plic_data *plic);
|
||||||
|
|
||||||
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
|
|
||||||
|
|
||||||
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -17,6 +17,8 @@ struct fdt_reset {
|
|||||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_RESET
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
|
* fdt_reset_driver_init() - initialize reset driver based on the device-tree
|
||||||
*/
|
*/
|
||||||
@@ -29,4 +31,14 @@ int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv);
|
|||||||
*/
|
*/
|
||||||
void fdt_reset_init(void);
|
void fdt_reset_init(void);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline void fdt_reset_init(void) { }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
16
include/sbi_utils/serial/cadence-uart.h
Normal file
16
include/sbi_utils/serial/cadence-uart.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 StarFive Technology Co., Ltd.
|
||||||
|
*
|
||||||
|
* Author: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SERIAL_CADENCE_UART_H__
|
||||||
|
#define __SERIAL_CADENCE_UART_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
int cadence_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||||
|
|
||||||
|
#endif
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_SERIAL
|
||||||
|
|
||||||
struct fdt_serial {
|
struct fdt_serial {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
@@ -19,4 +21,10 @@ struct fdt_serial {
|
|||||||
|
|
||||||
int fdt_serial_init(void);
|
int fdt_serial_init(void);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int fdt_serial_init(void) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
11
include/sbi_utils/serial/renesas-scif.h
Normal file
11
include/sbi_utils/serial/renesas-scif.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Renesas Electronics Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SERIAL_RENESAS_SCIF_H__
|
||||||
|
#define __SERIAL_RENESAS_SCIF_H__
|
||||||
|
|
||||||
|
int renesas_scif_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||||
|
|
||||||
|
#endif /* __SERIAL_RENESAS_SCIF_H__ */
|
47
include/sbi_utils/serial/semihosting.h
Normal file
47
include/sbi_utils/serial/semihosting.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <apatel@ventanamicro.com>
|
||||||
|
* Kautuk Consul <kconsul@ventanamicro.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SERIAL_SEMIHOSTING_H__
|
||||||
|
#define __SERIAL_SEMIHOSTING_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum semihosting_open_mode - Numeric file modes for use with semihosting_open()
|
||||||
|
* MODE_READ: 'r'
|
||||||
|
* MODE_BINARY: 'b'
|
||||||
|
* MODE_PLUS: '+'
|
||||||
|
* MODE_WRITE: 'w'
|
||||||
|
* MODE_APPEND: 'a'
|
||||||
|
*
|
||||||
|
* These modes represent the mode string used by fopen(3) in a form which can
|
||||||
|
* be passed to semihosting_open(). These do NOT correspond directly to %O_RDONLY,
|
||||||
|
* %O_CREAT, etc; see fopen(3) for details. In particular, @MODE_PLUS
|
||||||
|
* effectively results in adding %O_RDWR, and @MODE_WRITE will add %O_TRUNC.
|
||||||
|
* For compatibility, @MODE_BINARY should be added when opening non-text files
|
||||||
|
* (such as images).
|
||||||
|
*/
|
||||||
|
enum semihosting_open_mode {
|
||||||
|
MODE_READ = 0x0,
|
||||||
|
MODE_BINARY = 0x1,
|
||||||
|
MODE_PLUS = 0x2,
|
||||||
|
MODE_WRITE = 0x4,
|
||||||
|
MODE_APPEND = 0x8,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_SEMIHOSTING
|
||||||
|
int semihosting_init(void);
|
||||||
|
int semihosting_enabled(void);
|
||||||
|
#else
|
||||||
|
static inline int semihosting_init(void) { return SBI_ENODEV; }
|
||||||
|
static inline int semihosting_enabled(void) { return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@@ -13,6 +13,6 @@
|
|||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
||||||
u32 reg_width);
|
u32 reg_width, u32 reg_offset);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
16
include/sbi_utils/serial/xlnx_uartlite.h
Normal file
16
include/sbi_utils/serial/xlnx_uartlite.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Alistair Francis <alistair.francis@wdc.com>
|
||||||
|
*/
|
||||||
|
#ifndef __SERIAL_XLNX_UARTLITE_H__
|
||||||
|
#define __SERIAL_XLNX_UARTLITE_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
int xlnx_uartlite_init(unsigned long base);
|
||||||
|
|
||||||
|
#endif
|
@@ -10,8 +10,12 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
int htif_serial_init(void);
|
int htif_serial_init(bool custom_addr,
|
||||||
|
unsigned long custom_fromhost_addr,
|
||||||
|
unsigned long custom_tohost_addr);
|
||||||
|
|
||||||
int htif_system_reset_init(void);
|
int htif_system_reset_init(bool custom_addr,
|
||||||
|
unsigned long custom_fromhost_addr,
|
||||||
|
unsigned long custom_tohost_addr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#define CLINT_MTIMER_OFFSET 0x4000
|
#define CLINT_MTIMER_OFFSET 0x4000
|
||||||
|
|
||||||
|
#define MTIMER_REGION_ALIGN 0x1000
|
||||||
|
|
||||||
struct aclint_mtimer_data {
|
struct aclint_mtimer_data {
|
||||||
/* Public details */
|
/* Public details */
|
||||||
unsigned long mtime_freq;
|
unsigned long mtime_freq;
|
||||||
|
29
include/sbi_utils/timer/andes_plmt.h
Normal file
29
include/sbi_utils/timer/andes_plmt.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Andes Technology Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Zong Li <zong@andestech.com>
|
||||||
|
* Nylon Chen <nylon7@andestech.com>
|
||||||
|
* Yu Chien Peter Lin <peterlin@andestech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TIMER_ANDES_PLMT_H__
|
||||||
|
#define __TIMER_ANDES_PLMT_H__
|
||||||
|
|
||||||
|
#define DEFAULT_AE350_PLMT_FREQ 60000000
|
||||||
|
#define PLMT_REGION_ALIGN 0x1000
|
||||||
|
|
||||||
|
struct plmt_data {
|
||||||
|
u32 hart_count;
|
||||||
|
unsigned long size;
|
||||||
|
unsigned long timer_freq;
|
||||||
|
volatile u64 *time_val;
|
||||||
|
volatile u64 *time_cmp;
|
||||||
|
};
|
||||||
|
|
||||||
|
int plmt_cold_timer_init(struct plmt_data *plmt);
|
||||||
|
int plmt_warm_timer_init(void);
|
||||||
|
|
||||||
|
#endif /* __TIMER_ANDES_PLMT_H__ */
|
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_FDT_TIMER
|
||||||
|
|
||||||
struct fdt_timer {
|
struct fdt_timer {
|
||||||
const struct fdt_match *match_table;
|
const struct fdt_match *match_table;
|
||||||
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
@@ -23,4 +25,11 @@ void fdt_timer_exit(void);
|
|||||||
|
|
||||||
int fdt_timer_init(bool cold_boot);
|
int fdt_timer_init(bool cold_boot);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline void fdt_timer_exit(void) { }
|
||||||
|
static inline int fdt_timer_init(bool cold_boot) { return 0; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
37
lib/sbi/Kconfig
Normal file
37
lib/sbi/Kconfig
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
menu "SBI Extension Support"
|
||||||
|
|
||||||
|
config SBI_ECALL_TIME
|
||||||
|
bool "Timer extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_RFENCE
|
||||||
|
bool "RFENCE extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_IPI
|
||||||
|
bool "IPI extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_HSM
|
||||||
|
bool "Hart State Management extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_SRST
|
||||||
|
bool "System Reset extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_PMU
|
||||||
|
bool "Performance Monitoring Unit extension"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_LEGACY
|
||||||
|
bool "SBI v0.1 legacy extensions"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SBI_ECALL_VENDOR
|
||||||
|
bool "Platform-defined vendor extensions"
|
||||||
|
default y
|
||||||
|
|
||||||
|
endmenu
|
@@ -12,17 +12,41 @@ libsbi-objs-y += riscv_atomic.o
|
|||||||
libsbi-objs-y += riscv_hardfp.o
|
libsbi-objs-y += riscv_hardfp.o
|
||||||
libsbi-objs-y += riscv_locks.o
|
libsbi-objs-y += riscv_locks.o
|
||||||
|
|
||||||
|
libsbi-objs-y += sbi_ecall.o
|
||||||
|
libsbi-objs-y += sbi_ecall_exts.o
|
||||||
|
|
||||||
|
# The order of below extensions is performance optimized
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_TIME) += ecall_time
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_TIME) += sbi_ecall_time.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_RFENCE) += ecall_rfence
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_RFENCE) += sbi_ecall_rfence.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_IPI) += ecall_ipi
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_IPI) += sbi_ecall_ipi.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-y += ecall_base
|
||||||
|
libsbi-objs-y += sbi_ecall_base.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_HSM) += ecall_hsm
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_HSM) += sbi_ecall_hsm.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_SRST) += ecall_srst
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_SRST) += sbi_ecall_srst.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_PMU) += ecall_pmu
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_PMU) += sbi_ecall_pmu.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_LEGACY) += ecall_legacy
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_LEGACY) += sbi_ecall_legacy.o
|
||||||
|
|
||||||
|
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_VENDOR) += ecall_vendor
|
||||||
|
libsbi-objs-$(CONFIG_SBI_ECALL_VENDOR) += sbi_ecall_vendor.o
|
||||||
|
|
||||||
libsbi-objs-y += sbi_bitmap.o
|
libsbi-objs-y += sbi_bitmap.o
|
||||||
libsbi-objs-y += sbi_bitops.o
|
libsbi-objs-y += sbi_bitops.o
|
||||||
libsbi-objs-y += sbi_console.o
|
libsbi-objs-y += sbi_console.o
|
||||||
libsbi-objs-y += sbi_domain.o
|
libsbi-objs-y += sbi_domain.o
|
||||||
libsbi-objs-y += sbi_ecall.o
|
|
||||||
libsbi-objs-y += sbi_ecall_base.o
|
|
||||||
libsbi-objs-y += sbi_ecall_hsm.o
|
|
||||||
libsbi-objs-y += sbi_ecall_legacy.o
|
|
||||||
libsbi-objs-y += sbi_ecall_pmu.o
|
|
||||||
libsbi-objs-y += sbi_ecall_replace.o
|
|
||||||
libsbi-objs-y += sbi_ecall_vendor.o
|
|
||||||
libsbi-objs-y += sbi_emulate_csr.o
|
libsbi-objs-y += sbi_emulate_csr.o
|
||||||
libsbi-objs-y += sbi_fifo.o
|
libsbi-objs-y += sbi_fifo.o
|
||||||
libsbi-objs-y += sbi_hart.o
|
libsbi-objs-y += sbi_hart.o
|
||||||
@@ -32,6 +56,7 @@ libsbi-objs-y += sbi_hsm.o
|
|||||||
libsbi-objs-y += sbi_illegal_insn.o
|
libsbi-objs-y += sbi_illegal_insn.o
|
||||||
libsbi-objs-y += sbi_init.o
|
libsbi-objs-y += sbi_init.o
|
||||||
libsbi-objs-y += sbi_ipi.o
|
libsbi-objs-y += sbi_ipi.o
|
||||||
|
libsbi-objs-y += sbi_irqchip.o
|
||||||
libsbi-objs-y += sbi_misaligned_ldst.o
|
libsbi-objs-y += sbi_misaligned_ldst.o
|
||||||
libsbi-objs-y += sbi_platform.o
|
libsbi-objs-y += sbi_platform.o
|
||||||
libsbi-objs-y += sbi_pmu.o
|
libsbi-objs-y += sbi_pmu.o
|
||||||
|
@@ -53,7 +53,7 @@ int misa_xlen(void)
|
|||||||
void misa_string(int xlen, char *out, unsigned int out_sz)
|
void misa_string(int xlen, char *out, unsigned int out_sz)
|
||||||
{
|
{
|
||||||
unsigned int i, pos = 0;
|
unsigned int i, pos = 0;
|
||||||
const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
|
const char valid_isa_order[] = "iemafdqclbjtpvnhkorwxyzg";
|
||||||
|
|
||||||
if (!out)
|
if (!out)
|
||||||
return;
|
return;
|
||||||
@@ -139,6 +139,10 @@ unsigned long csr_read_num(int csr_num)
|
|||||||
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
|
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
|
||||||
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
|
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
|
||||||
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
|
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
|
||||||
|
/**
|
||||||
|
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
|
||||||
|
* extension is present. The caller must ensure that.
|
||||||
|
*/
|
||||||
switchcase_csr_read(CSR_MHPMEVENT3H, ret)
|
switchcase_csr_read(CSR_MHPMEVENT3H, ret)
|
||||||
switchcase_csr_read_4(CSR_MHPMEVENT4H, ret)
|
switchcase_csr_read_4(CSR_MHPMEVENT4H, ret)
|
||||||
switchcase_csr_read_8(CSR_MHPMEVENT8H, ret)
|
switchcase_csr_read_8(CSR_MHPMEVENT8H, ret)
|
||||||
@@ -261,7 +265,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
|||||||
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
|
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
|
||||||
pmpcfg_shift = (n & 7) << 3;
|
pmpcfg_shift = (n & 7) << 3;
|
||||||
#else
|
#else
|
||||||
return SBI_ENOTSUPP;
|
# error "Unexpected __riscv_xlen"
|
||||||
#endif
|
#endif
|
||||||
pmpaddr_csr = CSR_PMPADDR0 + n;
|
pmpaddr_csr = CSR_PMPADDR0 + n;
|
||||||
|
|
||||||
@@ -312,7 +316,7 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
|||||||
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
|
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
|
||||||
pmpcfg_shift = (n & 7) << 3;
|
pmpcfg_shift = (n & 7) << 3;
|
||||||
#else
|
#else
|
||||||
return SBI_ENOTSUPP;
|
# error "Unexpected __riscv_xlen"
|
||||||
#endif
|
#endif
|
||||||
pmpaddr_csr = CSR_PMPADDR0 + n;
|
pmpaddr_csr = CSR_PMPADDR0 + n;
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ unsigned long find_first_bit(const unsigned long *addr,
|
|||||||
if (tmp == 0UL) /* Are any bits set? */
|
if (tmp == 0UL) /* Are any bits set? */
|
||||||
return result + size; /* Nope. */
|
return result + size; /* Nope. */
|
||||||
found:
|
found:
|
||||||
return result + __ffs(tmp);
|
return result + sbi_ffs(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +69,7 @@ unsigned long find_first_zero_bit(const unsigned long *addr,
|
|||||||
if (tmp == ~0UL) /* Are any bits zero? */
|
if (tmp == ~0UL) /* Are any bits zero? */
|
||||||
return result + size; /* Nope. */
|
return result + size; /* Nope. */
|
||||||
found:
|
found:
|
||||||
return result + ffz(tmp);
|
return result + sbi_ffz(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,7 +100,7 @@ unsigned long find_last_bit(const unsigned long *addr,
|
|||||||
tmp = addr[--words];
|
tmp = addr[--words];
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
found:
|
found:
|
||||||
return words * BITS_PER_LONG + __fls(tmp);
|
return words * BITS_PER_LONG + sbi_fls(tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ found_first:
|
|||||||
if (tmp == 0UL) /* Are any bits set? */
|
if (tmp == 0UL) /* Are any bits set? */
|
||||||
return result + size; /* Nope. */
|
return result + size; /* Nope. */
|
||||||
found_middle:
|
found_middle:
|
||||||
return result + __ffs(tmp);
|
return result + sbi_ffs(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -196,5 +196,5 @@ found_first:
|
|||||||
if (tmp == ~0UL) /* Are any bits zero? */
|
if (tmp == ~0UL) /* Are any bits zero? */
|
||||||
return result + size; /* Nope. */
|
return result + size; /* Nope. */
|
||||||
found_middle:
|
found_middle:
|
||||||
return result + ffz(tmp);
|
return result + sbi_ffz(tmp);
|
||||||
}
|
}
|
||||||
|
@@ -76,20 +76,22 @@ typedef __builtin_va_list va_list;
|
|||||||
|
|
||||||
static void printc(char **out, u32 *out_len, char ch)
|
static void printc(char **out, u32 *out_len, char ch)
|
||||||
{
|
{
|
||||||
if (out) {
|
if (!out) {
|
||||||
if (*out) {
|
|
||||||
if (out_len && (0 < *out_len)) {
|
|
||||||
**out = ch;
|
|
||||||
++(*out);
|
|
||||||
(*out_len)--;
|
|
||||||
} else {
|
|
||||||
**out = ch;
|
|
||||||
++(*out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sbi_putc(ch);
|
sbi_putc(ch);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The *printf entry point functions have enforced that (*out) can
|
||||||
|
* only be null when out_len is non-null and its value is zero.
|
||||||
|
*/
|
||||||
|
if (!out_len || *out_len > 1) {
|
||||||
|
*(*out)++ = ch;
|
||||||
|
**out = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_len && *out_len > 0)
|
||||||
|
--(*out_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prints(char **out, u32 *out_len, const char *string, int width,
|
static int prints(char **out, u32 *out_len, const char *string, int width,
|
||||||
@@ -181,7 +183,7 @@ static int printi(char **out, u32 *out_len, long long i, int b, int sg,
|
|||||||
|
|
||||||
static int print(char **out, u32 *out_len, const char *format, va_list args)
|
static int print(char **out, u32 *out_len, const char *format, va_list args)
|
||||||
{
|
{
|
||||||
int width, flags, acnt = 0;
|
int width, flags;
|
||||||
int pc = 0;
|
int pc = 0;
|
||||||
char scr[2];
|
char scr[2];
|
||||||
unsigned long long tmp;
|
unsigned long long tmp;
|
||||||
@@ -193,7 +195,7 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
|
|||||||
if (*format == '\0')
|
if (*format == '\0')
|
||||||
break;
|
break;
|
||||||
if (*format == '%')
|
if (*format == '%')
|
||||||
goto out;
|
goto literal;
|
||||||
/* Get flags */
|
/* Get flags */
|
||||||
if (*format == '-') {
|
if (*format == '-') {
|
||||||
++format;
|
++format;
|
||||||
@@ -214,7 +216,6 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
|
|||||||
}
|
}
|
||||||
if (*format == 's') {
|
if (*format == 's') {
|
||||||
char *s = va_arg(args, char *);
|
char *s = va_arg(args, char *);
|
||||||
acnt += sizeof(char *);
|
|
||||||
pc += prints(out, out_len, s ? s : "(null)",
|
pc += prints(out, out_len, s ? s : "(null)",
|
||||||
width, flags);
|
width, flags);
|
||||||
continue;
|
continue;
|
||||||
@@ -222,61 +223,40 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
|
|||||||
if ((*format == 'd') || (*format == 'i')) {
|
if ((*format == 'd') || (*format == 'i')) {
|
||||||
pc += printi(out, out_len, va_arg(args, int),
|
pc += printi(out, out_len, va_arg(args, int),
|
||||||
10, 1, width, flags, '0');
|
10, 1, width, flags, '0');
|
||||||
acnt += sizeof(int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'x') {
|
if (*format == 'x') {
|
||||||
pc += printi(out, out_len,
|
pc += printi(out, out_len,
|
||||||
va_arg(args, unsigned int), 16, 0,
|
va_arg(args, unsigned int), 16, 0,
|
||||||
width, flags, 'a');
|
width, flags, 'a');
|
||||||
acnt += sizeof(unsigned int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'X') {
|
if (*format == 'X') {
|
||||||
pc += printi(out, out_len,
|
pc += printi(out, out_len,
|
||||||
va_arg(args, unsigned int), 16, 0,
|
va_arg(args, unsigned int), 16, 0,
|
||||||
width, flags, 'A');
|
width, flags, 'A');
|
||||||
acnt += sizeof(unsigned int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'u') {
|
if (*format == 'u') {
|
||||||
pc += printi(out, out_len,
|
pc += printi(out, out_len,
|
||||||
va_arg(args, unsigned int), 10, 0,
|
va_arg(args, unsigned int), 10, 0,
|
||||||
width, flags, 'a');
|
width, flags, 'a');
|
||||||
acnt += sizeof(unsigned int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'p') {
|
if (*format == 'p') {
|
||||||
pc += printi(out, out_len,
|
pc += printi(out, out_len,
|
||||||
va_arg(args, unsigned long), 16, 0,
|
va_arg(args, unsigned long), 16, 0,
|
||||||
width, flags, 'a');
|
width, flags, 'a');
|
||||||
acnt += sizeof(unsigned long);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'P') {
|
if (*format == 'P') {
|
||||||
pc += printi(out, out_len,
|
pc += printi(out, out_len,
|
||||||
va_arg(args, unsigned long), 16, 0,
|
va_arg(args, unsigned long), 16, 0,
|
||||||
width, flags, 'A');
|
width, flags, 'A');
|
||||||
acnt += sizeof(unsigned long);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (*format == 'l' && *(format + 1) == 'l') {
|
if (*format == 'l' && *(format + 1) == 'l') {
|
||||||
while (acnt &
|
tmp = va_arg(args, unsigned long long);
|
||||||
(sizeof(unsigned long long) - 1)) {
|
|
||||||
va_arg(args, int);
|
|
||||||
acnt += sizeof(int);
|
|
||||||
}
|
|
||||||
if (sizeof(unsigned long long) ==
|
|
||||||
sizeof(unsigned long)) {
|
|
||||||
tmp = va_arg(args, unsigned long long);
|
|
||||||
acnt += sizeof(unsigned long long);
|
|
||||||
} else {
|
|
||||||
((unsigned long *)&tmp)[0] =
|
|
||||||
va_arg(args, unsigned long);
|
|
||||||
((unsigned long *)&tmp)[1] =
|
|
||||||
va_arg(args, unsigned long);
|
|
||||||
acnt += 2 * sizeof(unsigned long);
|
|
||||||
}
|
|
||||||
if (*(format + 2) == 'u') {
|
if (*(format + 2) == 'u') {
|
||||||
format += 2;
|
format += 2;
|
||||||
pc += printi(out, out_len, tmp, 10, 0,
|
pc += printi(out, out_len, tmp, 10, 0,
|
||||||
@@ -308,19 +288,16 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
|
|||||||
out, out_len,
|
out, out_len,
|
||||||
va_arg(args, unsigned long), 16,
|
va_arg(args, unsigned long), 16,
|
||||||
0, width, flags, 'a');
|
0, width, flags, 'a');
|
||||||
acnt += sizeof(unsigned long);
|
|
||||||
} else if (*(format + 1) == 'X') {
|
} else if (*(format + 1) == 'X') {
|
||||||
format += 1;
|
format += 1;
|
||||||
pc += printi(
|
pc += printi(
|
||||||
out, out_len,
|
out, out_len,
|
||||||
va_arg(args, unsigned long), 16,
|
va_arg(args, unsigned long), 16,
|
||||||
0, width, flags, 'A');
|
0, width, flags, 'A');
|
||||||
acnt += sizeof(unsigned long);
|
|
||||||
} else {
|
} else {
|
||||||
pc += printi(out, out_len,
|
pc += printi(out, out_len,
|
||||||
va_arg(args, long), 10, 1,
|
va_arg(args, long), 10, 1,
|
||||||
width, flags, '0');
|
width, flags, '0');
|
||||||
acnt += sizeof(long);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*format == 'c') {
|
if (*format == 'c') {
|
||||||
@@ -328,17 +305,14 @@ static int print(char **out, u32 *out_len, const char *format, va_list args)
|
|||||||
scr[0] = va_arg(args, int);
|
scr[0] = va_arg(args, int);
|
||||||
scr[1] = '\0';
|
scr[1] = '\0';
|
||||||
pc += prints(out, out_len, scr, width, flags);
|
pc += prints(out, out_len, scr, width, flags);
|
||||||
acnt += sizeof(int);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out:
|
literal:
|
||||||
printc(out, out_len, *format);
|
printc(out, out_len, *format);
|
||||||
++pc;
|
++pc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (out)
|
|
||||||
**out = '\0';
|
|
||||||
|
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
@@ -348,6 +322,9 @@ int sbi_sprintf(char *out, const char *format, ...)
|
|||||||
va_list args;
|
va_list args;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
if (unlikely(!out))
|
||||||
|
sbi_panic("sbi_sprintf called with NULL output string\n");
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
retval = print(&out, NULL, format, args);
|
retval = print(&out, NULL, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@@ -360,6 +337,10 @@ int sbi_snprintf(char *out, u32 out_sz, const char *format, ...)
|
|||||||
va_list args;
|
va_list args;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
if (unlikely(!out && out_sz != 0))
|
||||||
|
sbi_panic("sbi_snprintf called with NULL output string and "
|
||||||
|
"output size is not zero\n");
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
retval = print(&out, &out_sz, format, args);
|
retval = print(&out, &out_sz, format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
@@ -105,7 +105,7 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
|||||||
unsigned long addr, unsigned long mode,
|
unsigned long addr, unsigned long mode,
|
||||||
unsigned long access_flags)
|
unsigned long access_flags)
|
||||||
{
|
{
|
||||||
bool mmio = FALSE;
|
bool rmmio, mmio = FALSE;
|
||||||
struct sbi_domain_memregion *reg;
|
struct sbi_domain_memregion *reg;
|
||||||
unsigned long rstart, rend, rflags, rwx = 0;
|
unsigned long rstart, rend, rflags, rwx = 0;
|
||||||
|
|
||||||
@@ -130,8 +130,8 @@ bool sbi_domain_check_addr(const struct sbi_domain *dom,
|
|||||||
rend = (reg->order < __riscv_xlen) ?
|
rend = (reg->order < __riscv_xlen) ?
|
||||||
rstart + ((1UL << reg->order) - 1) : -1UL;
|
rstart + ((1UL << reg->order) - 1) : -1UL;
|
||||||
if (rstart <= addr && addr <= rend) {
|
if (rstart <= addr && addr <= rend) {
|
||||||
if ((mmio && !(rflags & SBI_DOMAIN_MEMREGION_MMIO)) ||
|
rmmio = (rflags & SBI_DOMAIN_MEMREGION_MMIO) ? TRUE : FALSE;
|
||||||
(!mmio && (rflags & SBI_DOMAIN_MEMREGION_MMIO)))
|
if (mmio != rmmio)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
return ((rflags & rwx) == rwx) ? TRUE : FALSE;
|
return ((rflags & rwx) == rwx) ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,10 @@ static bool is_region_valid(const struct sbi_domain_memregion *reg)
|
|||||||
if (reg->order < 3 || __riscv_xlen < reg->order)
|
if (reg->order < 3 || __riscv_xlen < reg->order)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (reg->base & (BIT(reg->order) - 1))
|
if (reg->order == __riscv_xlen && reg->base != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (reg->order < __riscv_xlen && (reg->base & (BIT(reg->order) - 1)))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -159,7 +162,7 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
|
|||||||
ulong regA_start = regA->base;
|
ulong regA_start = regA->base;
|
||||||
ulong regA_end = regA->base + (BIT(regA->order) - 1);
|
ulong regA_end = regA->base + (BIT(regA->order) - 1);
|
||||||
ulong regB_start = regB->base;
|
ulong regB_start = regB->base;
|
||||||
ulong regB_end = regB->base + (BIT(regA->order) - 1);
|
ulong regB_end = regB->base + (BIT(regB->order) - 1);
|
||||||
|
|
||||||
if ((regB_start <= regA_start) &&
|
if ((regB_start <= regA_start) &&
|
||||||
(regA_start < regB_end) &&
|
(regA_start < regB_end) &&
|
||||||
@@ -471,8 +474,12 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
|
|||||||
|
|
||||||
/* Check for conflicts */
|
/* Check for conflicts */
|
||||||
sbi_domain_for_each_memregion(&root, nreg) {
|
sbi_domain_for_each_memregion(&root, nreg) {
|
||||||
if (is_region_conflict(reg, nreg))
|
if (is_region_conflict(reg, nreg)) {
|
||||||
return SBI_EINVAL;
|
sbi_printf("%s: is_region_conflict check failed"
|
||||||
|
" 0x%lx conflicts existing 0x%lx\n", __func__,
|
||||||
|
reg->base, nreg->base);
|
||||||
|
return SBI_EALREADY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Append the memregion to root memregions */
|
/* Append the memregion to root memregions */
|
||||||
@@ -518,6 +525,33 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sbi_domain_root_add_memrange(unsigned long addr, unsigned long size,
|
||||||
|
unsigned long align, unsigned long region_flags)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
unsigned long pos, end, rsize;
|
||||||
|
struct sbi_domain_memregion reg;
|
||||||
|
|
||||||
|
pos = addr;
|
||||||
|
end = addr + size;
|
||||||
|
while (pos < end) {
|
||||||
|
rsize = pos & (align - 1);
|
||||||
|
if (rsize)
|
||||||
|
rsize = 1UL << sbi_ffs(pos);
|
||||||
|
else
|
||||||
|
rsize = ((end - pos) < align) ?
|
||||||
|
(end - pos) : align;
|
||||||
|
|
||||||
|
sbi_domain_memregion_init(pos, rsize, region_flags, ®);
|
||||||
|
rc = sbi_domain_root_add_memregion(®);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
pos += rsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
@@ -13,6 +13,9 @@
|
|||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
|
|
||||||
|
extern struct sbi_ecall_extension *sbi_ecall_exts[];
|
||||||
|
extern unsigned long sbi_ecall_exts_size;
|
||||||
|
|
||||||
u16 sbi_ecall_version_major(void)
|
u16 sbi_ecall_version_major(void)
|
||||||
{
|
{
|
||||||
return SBI_ECALL_VERSION_MAJOR;
|
return SBI_ECALL_VERSION_MAJOR;
|
||||||
@@ -144,35 +147,15 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
|||||||
int sbi_ecall_init(void)
|
int sbi_ecall_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
struct sbi_ecall_extension *ext;
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
/* The order of below registrations is performance optimized */
|
for (i = 0; i < sbi_ecall_exts_size; i++) {
|
||||||
ret = sbi_ecall_register_extension(&ecall_time);
|
ext = sbi_ecall_exts[i];
|
||||||
if (ret)
|
ret = sbi_ecall_register_extension(ext);
|
||||||
return ret;
|
if (ret)
|
||||||
ret = sbi_ecall_register_extension(&ecall_rfence);
|
return ret;
|
||||||
if (ret)
|
}
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_ipi);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_base);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_hsm);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_srst);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_pmu);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_legacy);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = sbi_ecall_register_extension(&ecall_vendor);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
3
lib/sbi/sbi_ecall_exts.carray
Normal file
3
lib/sbi/sbi_ecall_exts.carray
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
HEADER: sbi/sbi_ecall.h
|
||||||
|
TYPE: struct sbi_ecall_extension
|
||||||
|
NAME: sbi_ecall_exts
|
36
lib/sbi/sbi_ecall_ipi.c
Normal file
36
lib/sbi/sbi_ecall_ipi.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
* Atish Patra <atish.patra@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_ecall.h>
|
||||||
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
|
#include <sbi/sbi_trap.h>
|
||||||
|
#include <sbi/sbi_ipi.h>
|
||||||
|
|
||||||
|
static int sbi_ecall_ipi_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 = 0;
|
||||||
|
|
||||||
|
if (funcid == SBI_EXT_IPI_SEND_IPI)
|
||||||
|
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
|
||||||
|
else
|
||||||
|
ret = SBI_ENOTSUPP;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_ipi = {
|
||||||
|
.extid_start = SBI_EXT_IPI,
|
||||||
|
.extid_end = SBI_EXT_IPI,
|
||||||
|
.handle = sbi_ecall_ipi_handler,
|
||||||
|
};
|
@@ -51,7 +51,8 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_PMU_COUNTER_FW_READ:
|
case SBI_EXT_PMU_COUNTER_FW_READ:
|
||||||
ret = sbi_pmu_ctr_read(regs->a0, out_val);
|
ret = sbi_pmu_ctr_fw_read(regs->a0, &temp);
|
||||||
|
*out_val = temp;
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_PMU_COUNTER_START:
|
case SBI_EXT_PMU_COUNTER_START:
|
||||||
|
|
||||||
|
@@ -9,40 +9,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_ecall.h>
|
#include <sbi/sbi_ecall.h>
|
||||||
#include <sbi/sbi_ecall_interface.h>
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
#include <sbi/sbi_error.h>
|
|
||||||
#include <sbi/sbi_hart.h>
|
|
||||||
#include <sbi/sbi_ipi.h>
|
|
||||||
#include <sbi/sbi_system.h>
|
|
||||||
#include <sbi/sbi_timer.h>
|
|
||||||
#include <sbi/sbi_tlb.h>
|
|
||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
|
#include <sbi/sbi_tlb.h>
|
||||||
static int sbi_ecall_time_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 = 0;
|
|
||||||
|
|
||||||
if (funcid == SBI_EXT_TIME_SET_TIMER) {
|
|
||||||
#if __riscv_xlen == 32
|
|
||||||
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
|
|
||||||
#else
|
|
||||||
sbi_timer_event_start((u64)regs->a0);
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
ret = SBI_ENOTSUPP;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sbi_ecall_extension ecall_time = {
|
|
||||||
.extid_start = SBI_EXT_TIME,
|
|
||||||
.extid_end = SBI_EXT_TIME,
|
|
||||||
.handle = sbi_ecall_time_handler,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
||||||
const struct sbi_trap_regs *regs,
|
const struct sbi_trap_regs *regs,
|
||||||
@@ -113,84 +84,3 @@ struct sbi_ecall_extension ecall_rfence = {
|
|||||||
.extid_end = SBI_EXT_RFENCE,
|
.extid_end = SBI_EXT_RFENCE,
|
||||||
.handle = sbi_ecall_rfence_handler,
|
.handle = sbi_ecall_rfence_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sbi_ecall_ipi_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 = 0;
|
|
||||||
|
|
||||||
if (funcid == SBI_EXT_IPI_SEND_IPI)
|
|
||||||
ret = sbi_ipi_send_smode(regs->a0, regs->a1);
|
|
||||||
else
|
|
||||||
ret = SBI_ENOTSUPP;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sbi_ecall_extension ecall_ipi = {
|
|
||||||
.extid_start = SBI_EXT_IPI,
|
|
||||||
.extid_end = SBI_EXT_IPI,
|
|
||||||
.handle = sbi_ecall_ipi_handler,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
|
|
||||||
const struct sbi_trap_regs *regs,
|
|
||||||
unsigned long *out_val,
|
|
||||||
struct sbi_trap_info *out_trap)
|
|
||||||
{
|
|
||||||
if (funcid == SBI_EXT_SRST_RESET) {
|
|
||||||
if ((((u32)-1U) <= ((u64)regs->a0)) ||
|
|
||||||
(((u32)-1U) <= ((u64)regs->a1)))
|
|
||||||
return SBI_EINVAL;
|
|
||||||
|
|
||||||
switch (regs->a0) {
|
|
||||||
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
|
||||||
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
|
|
||||||
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SBI_EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (regs->a1) {
|
|
||||||
case SBI_SRST_RESET_REASON_NONE:
|
|
||||||
case SBI_SRST_RESET_REASON_SYSFAIL:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SBI_EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sbi_system_reset_supported(regs->a0, regs->a1))
|
|
||||||
sbi_system_reset(regs->a0, regs->a1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SBI_ENOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
|
|
||||||
{
|
|
||||||
u32 type, count = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* At least one standard reset types should be supported by
|
|
||||||
* the platform for SBI SRST extension to be usable.
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) {
|
|
||||||
if (sbi_system_reset_supported(type,
|
|
||||||
SBI_SRST_RESET_REASON_NONE))
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_val = (count) ? 1 : 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sbi_ecall_extension ecall_srst = {
|
|
||||||
.extid_start = SBI_EXT_SRST,
|
|
||||||
.extid_end = SBI_EXT_SRST,
|
|
||||||
.handle = sbi_ecall_srst_handler,
|
|
||||||
.probe = sbi_ecall_srst_probe,
|
|
||||||
};
|
|
75
lib/sbi/sbi_ecall_srst.c
Normal file
75
lib/sbi/sbi_ecall_srst.c
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
* Atish Patra <atish.patra@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_ecall.h>
|
||||||
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
|
#include <sbi/sbi_trap.h>
|
||||||
|
#include <sbi/sbi_system.h>
|
||||||
|
|
||||||
|
static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
|
||||||
|
const struct sbi_trap_regs *regs,
|
||||||
|
unsigned long *out_val,
|
||||||
|
struct sbi_trap_info *out_trap)
|
||||||
|
{
|
||||||
|
if (funcid == SBI_EXT_SRST_RESET) {
|
||||||
|
if ((((u32)-1U) <= ((u64)regs->a0)) ||
|
||||||
|
(((u32)-1U) <= ((u64)regs->a1)))
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
switch (regs->a0) {
|
||||||
|
case SBI_SRST_RESET_TYPE_SHUTDOWN:
|
||||||
|
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
|
||||||
|
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SBI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (regs->a1) {
|
||||||
|
case SBI_SRST_RESET_REASON_NONE:
|
||||||
|
case SBI_SRST_RESET_REASON_SYSFAIL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SBI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbi_system_reset_supported(regs->a0, regs->a1))
|
||||||
|
sbi_system_reset(regs->a0, regs->a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
|
||||||
|
{
|
||||||
|
u32 type, count = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At least one standard reset types should be supported by
|
||||||
|
* the platform for SBI SRST extension to be usable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) {
|
||||||
|
if (sbi_system_reset_supported(type,
|
||||||
|
SBI_SRST_RESET_REASON_NONE))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_val = (count) ? 1 : 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_srst = {
|
||||||
|
.extid_start = SBI_EXT_SRST,
|
||||||
|
.extid_end = SBI_EXT_SRST,
|
||||||
|
.handle = sbi_ecall_srst_handler,
|
||||||
|
.probe = sbi_ecall_srst_probe,
|
||||||
|
};
|
40
lib/sbi/sbi_ecall_time.c
Normal file
40
lib/sbi/sbi_ecall_time.c
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
* Atish Patra <atish.patra@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_ecall.h>
|
||||||
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
|
#include <sbi/sbi_trap.h>
|
||||||
|
#include <sbi/sbi_timer.h>
|
||||||
|
|
||||||
|
static int sbi_ecall_time_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 = 0;
|
||||||
|
|
||||||
|
if (funcid == SBI_EXT_TIME_SET_TIMER) {
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
sbi_timer_event_start((((u64)regs->a1 << 32) | (u64)regs->a0));
|
||||||
|
#else
|
||||||
|
sbi_timer_event_start((u64)regs->a0);
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
|
ret = SBI_ENOTSUPP;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sbi_ecall_extension ecall_time = {
|
||||||
|
.extid_start = SBI_EXT_TIME,
|
||||||
|
.extid_end = SBI_EXT_TIME,
|
||||||
|
.handle = sbi_ecall_time_handler,
|
||||||
|
};
|
@@ -24,7 +24,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
|
|||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
|
||||||
if (prev_mode <= PRV_S) {
|
if (prev_mode <= PRV_S) {
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN)) {
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10) {
|
||||||
cen &= csr_read(CSR_MCOUNTEREN);
|
cen &= csr_read(CSR_MCOUNTEREN);
|
||||||
if (virt)
|
if (virt)
|
||||||
cen &= csr_read(CSR_HCOUNTEREN);
|
cen &= csr_read(CSR_HCOUNTEREN);
|
||||||
@@ -33,7 +33,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prev_mode == PRV_U) {
|
if (prev_mode == PRV_U) {
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
|
||||||
cen &= csr_read(CSR_SCOUNTEREN);
|
cen &= csr_read(CSR_SCOUNTEREN);
|
||||||
else
|
else
|
||||||
cen = 0;
|
cen = 0;
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume that faulting instruction is is 4-byte long and blindly
|
* We assume that faulting instruction is 4-byte long and blindly
|
||||||
* increment SEPC by 4.
|
* increment SEPC by 4.
|
||||||
*
|
*
|
||||||
* The trap info will be saved as follows:
|
* The trap info will be saved as follows:
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
.align 3
|
.align 3
|
||||||
.global __sbi_expected_trap
|
.global __sbi_expected_trap
|
||||||
__sbi_expected_trap:
|
__sbi_expected_trap:
|
||||||
/* Without H-extension so, MTVAL2 and MTINST CSRs not available */
|
/* Without H-extension so, MTVAL2 and MTINST CSRs and GVA not available */
|
||||||
csrr a4, CSR_MEPC
|
csrr a4, CSR_MEPC
|
||||||
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
|
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
|
||||||
csrr a4, CSR_MCAUSE
|
csrr a4, CSR_MCAUSE
|
||||||
@@ -31,6 +31,7 @@ __sbi_expected_trap:
|
|||||||
REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
|
REG_S a4, SBI_TRAP_INFO_OFFSET(tval)(a3)
|
||||||
REG_S zero, SBI_TRAP_INFO_OFFSET(tval2)(a3)
|
REG_S zero, SBI_TRAP_INFO_OFFSET(tval2)(a3)
|
||||||
REG_S zero, SBI_TRAP_INFO_OFFSET(tinst)(a3)
|
REG_S zero, SBI_TRAP_INFO_OFFSET(tinst)(a3)
|
||||||
|
REG_S zero, SBI_TRAP_INFO_OFFSET(gva)(a3)
|
||||||
csrr a4, CSR_MEPC
|
csrr a4, CSR_MEPC
|
||||||
addi a4, a4, 4
|
addi a4, a4, 4
|
||||||
csrw CSR_MEPC, a4
|
csrw CSR_MEPC, a4
|
||||||
@@ -39,7 +40,7 @@ __sbi_expected_trap:
|
|||||||
.align 3
|
.align 3
|
||||||
.global __sbi_expected_trap_hext
|
.global __sbi_expected_trap_hext
|
||||||
__sbi_expected_trap_hext:
|
__sbi_expected_trap_hext:
|
||||||
/* With H-extension so, MTVAL2 and MTINST CSRs available */
|
/* With H-extension so, MTVAL2 and MTINST CSRs and GVA available */
|
||||||
csrr a4, CSR_MEPC
|
csrr a4, CSR_MEPC
|
||||||
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
|
REG_S a4, SBI_TRAP_INFO_OFFSET(epc)(a3)
|
||||||
csrr a4, CSR_MCAUSE
|
csrr a4, CSR_MCAUSE
|
||||||
@@ -50,6 +51,18 @@ __sbi_expected_trap_hext:
|
|||||||
REG_S a4, SBI_TRAP_INFO_OFFSET(tval2)(a3)
|
REG_S a4, SBI_TRAP_INFO_OFFSET(tval2)(a3)
|
||||||
csrr a4, CSR_MTINST
|
csrr a4, CSR_MTINST
|
||||||
REG_S a4, SBI_TRAP_INFO_OFFSET(tinst)(a3)
|
REG_S a4, SBI_TRAP_INFO_OFFSET(tinst)(a3)
|
||||||
|
|
||||||
|
/* Extract GVA bit from MSTATUS or MSTATUSH */
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
csrr a4, CSR_MSTATUSH
|
||||||
|
srli a4, a4, MSTATUSH_GVA_SHIFT
|
||||||
|
#else
|
||||||
|
csrr a4, CSR_MSTATUS
|
||||||
|
srli a4, a4, MSTATUS_GVA_SHIFT
|
||||||
|
#endif
|
||||||
|
andi a4, a4, 1
|
||||||
|
REG_S a4, SBI_TRAP_INFO_OFFSET(gva)(a3)
|
||||||
|
|
||||||
csrr a4, CSR_MEPC
|
csrr a4, CSR_MEPC
|
||||||
addi a4, a4, 4
|
addi a4, a4, 4
|
||||||
csrw CSR_MEPC, a4
|
csrw CSR_MEPC, a4
|
||||||
|
@@ -66,7 +66,7 @@ static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
|
|||||||
if (head >= fifo->num_entries)
|
if (head >= fifo->num_entries)
|
||||||
head = head - fifo->num_entries;
|
head = head - fifo->num_entries;
|
||||||
|
|
||||||
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
|
sbi_memcpy((char *)fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
|
||||||
|
|
||||||
fifo->avail++;
|
fifo->avail++;
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
|
|||||||
index = fifo->tail + i;
|
index = fifo->tail + i;
|
||||||
if (index >= fifo->num_entries)
|
if (index >= fifo->num_entries)
|
||||||
index -= fifo->num_entries;
|
index -= fifo->num_entries;
|
||||||
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
|
entry = (char *)fifo->queue + (u32)index * fifo->entry_size;
|
||||||
ret = fptr(in, entry);
|
ret = fptr(in, entry);
|
||||||
|
|
||||||
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
|
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
|
||||||
@@ -184,7 +184,7 @@ int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data)
|
|||||||
return SBI_ENOENT;
|
return SBI_ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
sbi_memcpy(data, fifo->queue + (u32)fifo->tail * fifo->entry_size,
|
sbi_memcpy(data, (char *)fifo->queue + (u32)fifo->tail * fifo->entry_size,
|
||||||
fifo->entry_size);
|
fifo->entry_size);
|
||||||
|
|
||||||
fifo->avail--;
|
fifo->avail--;
|
||||||
|
@@ -19,27 +19,25 @@
|
|||||||
#include <sbi/sbi_hart.h>
|
#include <sbi/sbi_hart.h>
|
||||||
#include <sbi/sbi_math.h>
|
#include <sbi/sbi_math.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
|
#include <sbi/sbi_pmu.h>
|
||||||
#include <sbi/sbi_string.h>
|
#include <sbi/sbi_string.h>
|
||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
|
#include <sbi/sbi_hfence.h>
|
||||||
|
|
||||||
extern void __sbi_expected_trap(void);
|
extern void __sbi_expected_trap(void);
|
||||||
extern void __sbi_expected_trap_hext(void);
|
extern void __sbi_expected_trap_hext(void);
|
||||||
|
|
||||||
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
|
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
|
||||||
|
|
||||||
struct hart_features {
|
|
||||||
unsigned long features;
|
|
||||||
unsigned int pmp_count;
|
|
||||||
unsigned int pmp_addr_bits;
|
|
||||||
unsigned long pmp_gran;
|
|
||||||
unsigned int mhpm_count;
|
|
||||||
unsigned int mhpm_bits;
|
|
||||||
};
|
|
||||||
static unsigned long hart_features_offset;
|
static unsigned long hart_features_offset;
|
||||||
|
|
||||||
static void mstatus_init(struct sbi_scratch *scratch)
|
static void mstatus_init(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
unsigned long mstatus_val = 0;
|
unsigned long menvcfg_val, mstatus_val = 0;
|
||||||
|
int cidx;
|
||||||
|
unsigned int num_mhpm = sbi_hart_mhpm_count(scratch);
|
||||||
|
uint64_t mhpmevent_init_val = 0;
|
||||||
|
uint64_t mstateen_val;
|
||||||
|
|
||||||
/* Enable FPU */
|
/* Enable FPU */
|
||||||
if (misa_extension('D') || misa_extension('F'))
|
if (misa_extension('D') || misa_extension('F'))
|
||||||
@@ -53,7 +51,7 @@ static void mstatus_init(struct sbi_scratch *scratch)
|
|||||||
|
|
||||||
/* Disable user mode usage of all perf counters except default ones (CY, TM, IR) */
|
/* Disable user mode usage of all perf counters except default ones (CY, TM, IR) */
|
||||||
if (misa_extension('S') &&
|
if (misa_extension('S') &&
|
||||||
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
|
sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
|
||||||
csr_write(CSR_SCOUNTEREN, 7);
|
csr_write(CSR_SCOUNTEREN, 7);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,13 +59,107 @@ static void mstatus_init(struct sbi_scratch *scratch)
|
|||||||
* Supervisor mode usage for all counters are enabled by default
|
* Supervisor mode usage for all counters are enabled by default
|
||||||
* But counters will not run until mcountinhibit is set.
|
* But counters will not run until mcountinhibit is set.
|
||||||
*/
|
*/
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
|
||||||
csr_write(CSR_MCOUNTEREN, -1);
|
csr_write(CSR_MCOUNTEREN, -1);
|
||||||
|
|
||||||
/* All programmable counters will start running at runtime after S-mode request */
|
/* All programmable counters will start running at runtime after S-mode request */
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
|
||||||
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
|
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mhpmeventn[h] CSR should be initialized with interrupt disabled
|
||||||
|
* and inhibited running in M-mode during init.
|
||||||
|
* To keep it simple, only contiguous mhpmcounters are supported as a
|
||||||
|
* platform with discontiguous mhpmcounters may not make much sense.
|
||||||
|
*/
|
||||||
|
mhpmevent_init_val |= (MHPMEVENT_OF | MHPMEVENT_MINH);
|
||||||
|
for (cidx = 0; cidx < num_mhpm; cidx++) {
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val & 0xFFFFFFFF);
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
|
csr_write_num(CSR_MHPMEVENT3H + cidx,
|
||||||
|
mhpmevent_init_val >> BITS_PER_LONG);
|
||||||
|
#else
|
||||||
|
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMSTATEEN)) {
|
||||||
|
mstateen_val = csr_read(CSR_MSTATEEN0);
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
mstateen_val |= ((uint64_t)csr_read(CSR_MSTATEEN0H)) << 32;
|
||||||
|
#endif
|
||||||
|
mstateen_val |= SMSTATEEN_STATEN;
|
||||||
|
mstateen_val |= SMSTATEEN0_HSENVCFG;
|
||||||
|
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMAIA))
|
||||||
|
mstateen_val |= (SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
|
||||||
|
SMSTATEEN0_IMSIC);
|
||||||
|
else
|
||||||
|
mstateen_val &= ~(SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
|
||||||
|
SMSTATEEN0_IMSIC);
|
||||||
|
csr_write(CSR_MSTATEEN0, mstateen_val);
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
csr_write(CSR_MSTATEEN0H, mstateen_val >> 32);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12) {
|
||||||
|
menvcfg_val = csr_read(CSR_MENVCFG);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set menvcfg.CBZE == 1
|
||||||
|
*
|
||||||
|
* If Zicboz extension is not available then writes to
|
||||||
|
* menvcfg.CBZE will be ignored because it is a WARL field.
|
||||||
|
*/
|
||||||
|
menvcfg_val |= ENVCFG_CBZE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set menvcfg.CBCFE == 1
|
||||||
|
*
|
||||||
|
* If Zicbom extension is not available then writes to
|
||||||
|
* menvcfg.CBCFE will be ignored because it is a WARL field.
|
||||||
|
*/
|
||||||
|
menvcfg_val |= ENVCFG_CBCFE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set menvcfg.CBIE == 3
|
||||||
|
*
|
||||||
|
* If Zicbom extension is not available then writes to
|
||||||
|
* menvcfg.CBIE will be ignored because it is a WARL field.
|
||||||
|
*/
|
||||||
|
menvcfg_val |= ENVCFG_CBIE_INV << ENVCFG_CBIE_SHIFT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set menvcfg.PBMTE == 1 for RV64 or RV128
|
||||||
|
*
|
||||||
|
* If Svpbmt extension is not available then menvcfg.PBMTE
|
||||||
|
* will be read-only zero.
|
||||||
|
*/
|
||||||
|
#if __riscv_xlen > 32
|
||||||
|
menvcfg_val |= ENVCFG_PBMTE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The spec doesn't explicitly describe the reset value of menvcfg.
|
||||||
|
* Enable access to stimecmp if sstc extension is present in the
|
||||||
|
* hardware.
|
||||||
|
*/
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSTC)) {
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
unsigned long menvcfgh_val;
|
||||||
|
menvcfgh_val = csr_read(CSR_MENVCFGH);
|
||||||
|
menvcfgh_val |= ENVCFGH_STCE;
|
||||||
|
csr_write(CSR_MENVCFGH, menvcfgh_val);
|
||||||
|
#else
|
||||||
|
menvcfg_val |= ENVCFG_STCE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
csr_write(CSR_MENVCFG, menvcfg_val);
|
||||||
|
}
|
||||||
|
|
||||||
/* Disable all interrupts */
|
/* Disable all interrupts */
|
||||||
csr_write(CSR_MIE, 0);
|
csr_write(CSR_MIE, 0);
|
||||||
|
|
||||||
@@ -108,8 +200,7 @@ static int delegate_traps(struct sbi_scratch *scratch)
|
|||||||
|
|
||||||
/* Send M-mode interrupts and most exceptions to S-mode */
|
/* Send M-mode interrupts and most exceptions to S-mode */
|
||||||
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
|
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
|
interrupts |= sbi_pmu_irq_bit();
|
||||||
interrupts |= MIP_LCOFIP;
|
|
||||||
|
|
||||||
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
|
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
|
||||||
(1U << CAUSE_USER_ECALL);
|
(1U << CAUSE_USER_ECALL);
|
||||||
@@ -154,7 +245,7 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch,
|
|||||||
|
|
||||||
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
|
unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
struct hart_features *hfeatures =
|
struct sbi_hart_features *hfeatures =
|
||||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
return hfeatures->mhpm_count;
|
return hfeatures->mhpm_count;
|
||||||
@@ -162,7 +253,7 @@ unsigned int sbi_hart_mhpm_count(struct sbi_scratch *scratch)
|
|||||||
|
|
||||||
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
|
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
struct hart_features *hfeatures =
|
struct sbi_hart_features *hfeatures =
|
||||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
return hfeatures->pmp_count;
|
return hfeatures->pmp_count;
|
||||||
@@ -170,7 +261,7 @@ unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
|
|||||||
|
|
||||||
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
|
unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
struct hart_features *hfeatures =
|
struct sbi_hart_features *hfeatures =
|
||||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
return hfeatures->pmp_gran;
|
return hfeatures->pmp_gran;
|
||||||
@@ -178,7 +269,7 @@ unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch)
|
|||||||
|
|
||||||
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
|
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
struct hart_features *hfeatures =
|
struct sbi_hart_features *hfeatures =
|
||||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
return hfeatures->pmp_addr_bits;
|
return hfeatures->pmp_addr_bits;
|
||||||
@@ -186,7 +277,7 @@ unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch)
|
|||||||
|
|
||||||
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
|
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
struct hart_features *hfeatures =
|
struct sbi_hart_features *hfeatures =
|
||||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
return hfeatures->mhpm_bits;
|
return hfeatures->mhpm_bits;
|
||||||
@@ -231,106 +322,180 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As per section 3.7.2 of privileged specification v1.12,
|
||||||
|
* virtual address translations can be speculatively performed
|
||||||
|
* (even before actual access). These, along with PMP traslations,
|
||||||
|
* can be cached. This can pose a problem with CPU hotplug
|
||||||
|
* and non-retentive suspend scenario because PMP states are
|
||||||
|
* not preserved.
|
||||||
|
* It is advisable to flush the caching structures under such
|
||||||
|
* conditions.
|
||||||
|
*/
|
||||||
|
if (misa_extension('S')) {
|
||||||
|
__asm__ __volatile__("sfence.vma");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If hypervisor mode is supported, flush caching
|
||||||
|
* structures in guest mode too.
|
||||||
|
*/
|
||||||
|
if (misa_extension('H'))
|
||||||
|
__sbi_hfence_gvma_all();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int sbi_hart_priv_version(struct sbi_scratch *scratch)
|
||||||
* Check whether a particular hart feature is available
|
|
||||||
*
|
|
||||||
* @param scratch pointer to the HART scratch space
|
|
||||||
* @param feature the feature to check
|
|
||||||
* @returns true (feature available) or false (feature not available)
|
|
||||||
*/
|
|
||||||
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature)
|
|
||||||
{
|
{
|
||||||
struct hart_features *hfeatures =
|
struct sbi_hart_features *hfeatures =
|
||||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
if (hfeatures->features & feature)
|
return hfeatures->priv_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
|
||||||
|
char *version_str, int nvstr)
|
||||||
|
{
|
||||||
|
char *temp;
|
||||||
|
struct sbi_hart_features *hfeatures =
|
||||||
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
|
switch (hfeatures->priv_version) {
|
||||||
|
case SBI_HART_PRIV_VER_1_10:
|
||||||
|
temp = "v1.10";
|
||||||
|
break;
|
||||||
|
case SBI_HART_PRIV_VER_1_11:
|
||||||
|
temp = "v1.11";
|
||||||
|
break;
|
||||||
|
case SBI_HART_PRIV_VER_1_12:
|
||||||
|
temp = "v1.12";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
temp = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sbi_snprintf(version_str, nvstr, "%s", temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __sbi_hart_update_extension(
|
||||||
|
struct sbi_hart_features *hfeatures,
|
||||||
|
enum sbi_hart_extensions ext,
|
||||||
|
bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
hfeatures->extensions |= BIT(ext);
|
||||||
|
else
|
||||||
|
hfeatures->extensions &= ~BIT(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable a particular hart extension
|
||||||
|
*
|
||||||
|
* @param scratch pointer to the HART scratch space
|
||||||
|
* @param ext the extension number to check
|
||||||
|
* @param enable new state of hart extension
|
||||||
|
*/
|
||||||
|
void sbi_hart_update_extension(struct sbi_scratch *scratch,
|
||||||
|
enum sbi_hart_extensions ext,
|
||||||
|
bool enable)
|
||||||
|
{
|
||||||
|
struct sbi_hart_features *hfeatures =
|
||||||
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
|
__sbi_hart_update_extension(hfeatures, ext, enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a particular hart extension is available
|
||||||
|
*
|
||||||
|
* @param scratch pointer to the HART scratch space
|
||||||
|
* @param ext the extension number to check
|
||||||
|
* @returns true (available) or false (not available)
|
||||||
|
*/
|
||||||
|
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
|
||||||
|
enum sbi_hart_extensions ext)
|
||||||
|
{
|
||||||
|
struct sbi_hart_features *hfeatures =
|
||||||
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
|
if (hfeatures->extensions & BIT(ext))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long hart_get_features(struct sbi_scratch *scratch)
|
static inline char *sbi_hart_extension_id2string(int ext)
|
||||||
{
|
{
|
||||||
struct hart_features *hfeatures =
|
char *estr = NULL;
|
||||||
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
|
||||||
|
|
||||||
return hfeatures->features;
|
switch (ext) {
|
||||||
}
|
case SBI_HART_EXT_SSCOFPMF:
|
||||||
|
estr = "sscofpmf";
|
||||||
static inline char *sbi_hart_feature_id2string(unsigned long feature)
|
|
||||||
{
|
|
||||||
char *fstr = NULL;
|
|
||||||
|
|
||||||
if (!feature)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
switch (feature) {
|
|
||||||
case SBI_HART_HAS_SCOUNTEREN:
|
|
||||||
fstr = "scounteren";
|
|
||||||
break;
|
break;
|
||||||
case SBI_HART_HAS_MCOUNTEREN:
|
case SBI_HART_EXT_TIME:
|
||||||
fstr = "mcounteren";
|
estr = "time";
|
||||||
break;
|
break;
|
||||||
case SBI_HART_HAS_MCOUNTINHIBIT:
|
case SBI_HART_EXT_SMAIA:
|
||||||
fstr = "mcountinhibit";
|
estr = "smaia";
|
||||||
break;
|
break;
|
||||||
case SBI_HART_HAS_SSCOFPMF:
|
case SBI_HART_EXT_SSTC:
|
||||||
fstr = "sscofpmf";
|
estr = "sstc";
|
||||||
break;
|
break;
|
||||||
case SBI_HART_HAS_TIME:
|
case SBI_HART_EXT_SMSTATEEN:
|
||||||
fstr = "time";
|
estr = "smstateen";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fstr;
|
return estr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the hart features in string format
|
* Get the hart extensions in string format
|
||||||
*
|
*
|
||||||
* @param scratch pointer to the HART scratch space
|
* @param scratch pointer to the HART scratch space
|
||||||
* @param features_str pointer to a char array where the features string will be
|
* @param extensions_str pointer to a char array where the extensions string
|
||||||
* updated
|
* will be updated
|
||||||
* @param nfstr length of the features_str. The feature string will be truncated
|
* @param nestr length of the features_str. The feature string will be
|
||||||
* if nfstr is not long enough.
|
* truncated if nestr is not long enough.
|
||||||
*/
|
*/
|
||||||
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
|
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
|
||||||
char *features_str, int nfstr)
|
char *extensions_str, int nestr)
|
||||||
{
|
{
|
||||||
unsigned long features, feat = 1UL;
|
struct sbi_hart_features *hfeatures =
|
||||||
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
int offset = 0, ext = 0;
|
||||||
char *temp;
|
char *temp;
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
if (!features_str || nfstr <= 0)
|
if (!extensions_str || nestr <= 0)
|
||||||
return;
|
return;
|
||||||
sbi_memset(features_str, 0, nfstr);
|
sbi_memset(extensions_str, 0, nestr);
|
||||||
|
|
||||||
features = hart_get_features(scratch);
|
if (!hfeatures->extensions)
|
||||||
if (!features)
|
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (features & feat) {
|
if (hfeatures->extensions & BIT(ext)) {
|
||||||
temp = sbi_hart_feature_id2string(feat);
|
temp = sbi_hart_extension_id2string(ext);
|
||||||
if (temp) {
|
if (temp) {
|
||||||
sbi_snprintf(features_str + offset, nfstr,
|
sbi_snprintf(extensions_str + offset,
|
||||||
|
nestr - offset,
|
||||||
"%s,", temp);
|
"%s,", temp);
|
||||||
offset = offset + sbi_strlen(temp) + 1;
|
offset = offset + sbi_strlen(temp) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
feat = feat << 1;
|
|
||||||
} while (feat <= SBI_HART_HAS_LAST_FEATURE);
|
ext++;
|
||||||
|
} while (ext < SBI_HART_EXT_MAX);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (offset)
|
if (offset)
|
||||||
features_str[offset - 1] = '\0';
|
extensions_str[offset - 1] = '\0';
|
||||||
else
|
else
|
||||||
sbi_strncpy(features_str, "none", nfstr);
|
sbi_strncpy(extensions_str, "none", nestr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long hart_pmp_get_allowed_addr(void)
|
static unsigned long hart_pmp_get_allowed_addr(void)
|
||||||
@@ -368,7 +533,7 @@ static int hart_pmu_get_allowed_bits(void)
|
|||||||
if (trap.cause)
|
if (trap.cause)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
num_bits = __fls(val) + 1;
|
num_bits = sbi_fls(val) + 1;
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
csr_write_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap, val);
|
csr_write_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap, val);
|
||||||
if (!trap.cause) {
|
if (!trap.cause) {
|
||||||
@@ -376,34 +541,39 @@ static int hart_pmu_get_allowed_bits(void)
|
|||||||
if (trap.cause)
|
if (trap.cause)
|
||||||
return num_bits;
|
return num_bits;
|
||||||
}
|
}
|
||||||
num_bits += __fls(val) + 1;
|
num_bits += sbi_fls(val) + 1;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return num_bits;
|
return num_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hart_detect_features(struct sbi_scratch *scratch)
|
static int hart_detect_features(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
struct sbi_trap_info trap = {0};
|
struct sbi_trap_info trap = {0};
|
||||||
struct hart_features *hfeatures;
|
struct sbi_hart_features *hfeatures =
|
||||||
unsigned long val;
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
unsigned long val, oldval;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* Reset hart features */
|
/* If hart features already detected then do nothing */
|
||||||
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
if (hfeatures->detected)
|
||||||
hfeatures->features = 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Clear hart features */
|
||||||
|
hfeatures->extensions = 0;
|
||||||
hfeatures->pmp_count = 0;
|
hfeatures->pmp_count = 0;
|
||||||
hfeatures->mhpm_count = 0;
|
hfeatures->mhpm_count = 0;
|
||||||
|
|
||||||
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
|
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
|
||||||
val = csr_read_allowed(__csr, (ulong)&trap); \
|
oldval = csr_read_allowed(__csr, (ulong)&trap); \
|
||||||
if (!trap.cause) { \
|
if (!trap.cause) { \
|
||||||
if (__rdonly) { \
|
if (__rdonly) { \
|
||||||
(hfeatures->__field)++; \
|
(hfeatures->__field)++; \
|
||||||
} else { \
|
} else { \
|
||||||
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
|
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
|
||||||
if (!trap.cause) { \
|
if (!trap.cause) { \
|
||||||
if (csr_swap(__csr, val) == __wrval) \
|
if (csr_swap(__csr, oldval) == __wrval) \
|
||||||
(hfeatures->__field)++; \
|
(hfeatures->__field)++; \
|
||||||
else \
|
else \
|
||||||
goto __skip; \
|
goto __skip; \
|
||||||
@@ -439,8 +609,8 @@ static void hart_detect_features(struct sbi_scratch *scratch)
|
|||||||
*/
|
*/
|
||||||
val = hart_pmp_get_allowed_addr();
|
val = hart_pmp_get_allowed_addr();
|
||||||
if (val) {
|
if (val) {
|
||||||
hfeatures->pmp_gran = 1 << (__ffs(val) + 2);
|
hfeatures->pmp_gran = 1 << (sbi_ffs(val) + 2);
|
||||||
hfeatures->pmp_addr_bits = __fls(val) + 1;
|
hfeatures->pmp_addr_bits = sbi_fls(val) + 1;
|
||||||
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
|
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
|
||||||
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
|
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
|
||||||
}
|
}
|
||||||
@@ -469,43 +639,70 @@ __mhpm_skip:
|
|||||||
#undef __check_csr_2
|
#undef __check_csr_2
|
||||||
#undef __check_csr
|
#undef __check_csr
|
||||||
|
|
||||||
/* Detect if hart supports SCOUNTEREN feature */
|
/* Detect if hart supports Priv v1.10 */
|
||||||
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
|
|
||||||
if (!trap.cause) {
|
|
||||||
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
|
|
||||||
if (!trap.cause)
|
|
||||||
hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detect if hart supports MCOUNTEREN feature */
|
|
||||||
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
|
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
|
||||||
if (!trap.cause) {
|
if (!trap.cause)
|
||||||
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
|
hfeatures->priv_version = SBI_HART_PRIV_VER_1_10;
|
||||||
if (!trap.cause)
|
|
||||||
hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detect if hart supports MCOUNTINHIBIT feature */
|
/* Detect if hart supports Priv v1.11 */
|
||||||
val = csr_read_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap);
|
val = csr_read_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap);
|
||||||
if (!trap.cause) {
|
if (!trap.cause &&
|
||||||
csr_write_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap, val);
|
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_10))
|
||||||
if (!trap.cause)
|
hfeatures->priv_version = SBI_HART_PRIV_VER_1_11;
|
||||||
hfeatures->features |= SBI_HART_HAS_MCOUNTINHIBIT;
|
|
||||||
}
|
/* Detect if hart supports Priv v1.12 */
|
||||||
|
csr_read_allowed(CSR_MENVCFG, (unsigned long)&trap);
|
||||||
|
if (!trap.cause &&
|
||||||
|
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_11))
|
||||||
|
hfeatures->priv_version = SBI_HART_PRIV_VER_1_12;
|
||||||
|
|
||||||
/* Counter overflow/filtering is not useful without mcounter/inhibit */
|
/* Counter overflow/filtering is not useful without mcounter/inhibit */
|
||||||
if (hfeatures->features & SBI_HART_HAS_MCOUNTINHIBIT &&
|
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
|
||||||
hfeatures->features & SBI_HART_HAS_MCOUNTEREN) {
|
|
||||||
/* Detect if hart supports sscofpmf */
|
/* Detect if hart supports sscofpmf */
|
||||||
csr_read_allowed(CSR_SCOUNTOVF, (unsigned long)&trap);
|
csr_read_allowed(CSR_SCOUNTOVF, (unsigned long)&trap);
|
||||||
if (!trap.cause)
|
if (!trap.cause)
|
||||||
hfeatures->features |= SBI_HART_HAS_SSCOFPMF;
|
__sbi_hart_update_extension(hfeatures,
|
||||||
|
SBI_HART_EXT_SSCOFPMF, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detect if hart supports time CSR */
|
/* Detect if hart supports time CSR */
|
||||||
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
|
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
|
||||||
if (!trap.cause)
|
if (!trap.cause)
|
||||||
hfeatures->features |= SBI_HART_HAS_TIME;
|
__sbi_hart_update_extension(hfeatures,
|
||||||
|
SBI_HART_EXT_TIME, true);
|
||||||
|
|
||||||
|
/* Detect if hart has AIA local interrupt CSRs */
|
||||||
|
csr_read_allowed(CSR_MTOPI, (unsigned long)&trap);
|
||||||
|
if (!trap.cause)
|
||||||
|
__sbi_hart_update_extension(hfeatures,
|
||||||
|
SBI_HART_EXT_SMAIA, true);
|
||||||
|
|
||||||
|
/* Detect if hart supports stimecmp CSR(Sstc extension) */
|
||||||
|
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
|
||||||
|
csr_read_allowed(CSR_STIMECMP, (unsigned long)&trap);
|
||||||
|
if (!trap.cause)
|
||||||
|
__sbi_hart_update_extension(hfeatures,
|
||||||
|
SBI_HART_EXT_SSTC, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detect if hart supports mstateen CSRs */
|
||||||
|
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
|
||||||
|
val = csr_read_allowed(CSR_MSTATEEN0, (unsigned long)&trap);
|
||||||
|
if (!trap.cause)
|
||||||
|
__sbi_hart_update_extension(hfeatures,
|
||||||
|
SBI_HART_EXT_SMSTATEEN, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let platform populate extensions */
|
||||||
|
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr(),
|
||||||
|
hfeatures);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Mark hart feature detection done */
|
||||||
|
hfeatures->detected = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_hart_reinit(struct sbi_scratch *scratch)
|
int sbi_hart_reinit(struct sbi_scratch *scratch)
|
||||||
@@ -527,17 +724,21 @@ int sbi_hart_reinit(struct sbi_scratch *scratch)
|
|||||||
|
|
||||||
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
|
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
if (misa_extension('H'))
|
if (misa_extension('H'))
|
||||||
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
|
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
|
||||||
|
|
||||||
hart_features_offset = sbi_scratch_alloc_offset(
|
hart_features_offset = sbi_scratch_alloc_offset(
|
||||||
sizeof(struct hart_features));
|
sizeof(struct sbi_hart_features));
|
||||||
if (!hart_features_offset)
|
if (!hart_features_offset)
|
||||||
return SBI_ENOMEM;
|
return SBI_ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
hart_detect_features(scratch);
|
rc = hart_detect_features(scratch);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
return sbi_hart_reinit(scratch);
|
return sbi_hart_reinit(scratch);
|
||||||
}
|
}
|
||||||
@@ -581,19 +782,12 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
|
|||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
if (misa_extension('H')) {
|
if (misa_extension('H')) {
|
||||||
valH = csr_read(CSR_MSTATUSH);
|
valH = csr_read(CSR_MSTATUSH);
|
||||||
if (next_virt)
|
valH = INSERT_FIELD(valH, MSTATUSH_MPV, next_virt);
|
||||||
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
|
|
||||||
else
|
|
||||||
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
|
|
||||||
csr_write(CSR_MSTATUSH, valH);
|
csr_write(CSR_MSTATUSH, valH);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (misa_extension('H')) {
|
if (misa_extension('H'))
|
||||||
if (next_virt)
|
val = INSERT_FIELD(val, MSTATUS_MPV, next_virt);
|
||||||
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
|
|
||||||
else
|
|
||||||
val = INSERT_FIELD(val, MSTATUS_MPV, 0);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
csr_write(CSR_MSTATUS, val);
|
csr_write(CSR_MSTATUS, val);
|
||||||
csr_write(CSR_MEPC, next_addr);
|
csr_write(CSR_MEPC, next_addr);
|
||||||
|
@@ -113,8 +113,8 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
/* Save MIE CSR */
|
/* Save MIE CSR */
|
||||||
saved_mie = csr_read(CSR_MIE);
|
saved_mie = csr_read(CSR_MIE);
|
||||||
|
|
||||||
/* Set MSIE bit to receive IPI */
|
/* Set MSIE and MEIE bits to receive IPI */
|
||||||
csr_set(CSR_MIE, MIP_MSIP);
|
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
|
||||||
|
|
||||||
/* Wait for hart_add call*/
|
/* Wait for hart_add call*/
|
||||||
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
|
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
|
||||||
@@ -171,13 +171,19 @@ static int hsm_device_hart_stop(void)
|
|||||||
return SBI_ENOTSUPP;
|
return SBI_ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hsm_device_hart_suspend(u32 suspend_type, ulong raddr)
|
static int hsm_device_hart_suspend(u32 suspend_type)
|
||||||
{
|
{
|
||||||
if (hsm_dev && hsm_dev->hart_suspend)
|
if (hsm_dev && hsm_dev->hart_suspend)
|
||||||
return hsm_dev->hart_suspend(suspend_type, raddr);
|
return hsm_dev->hart_suspend(suspend_type);
|
||||||
return SBI_ENOTSUPP;
|
return SBI_ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hsm_device_hart_resume(void)
|
||||||
|
{
|
||||||
|
if (hsm_dev && hsm_dev->hart_resume)
|
||||||
|
hsm_dev->hart_resume();
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
@@ -283,7 +289,9 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
|
|||||||
(hsm_device_has_hart_secondary_boot() && !init_count)) {
|
(hsm_device_has_hart_secondary_boot() && !init_count)) {
|
||||||
return hsm_device_hart_start(hartid, scratch->warmboot_addr);
|
return hsm_device_hart_start(hartid, scratch->warmboot_addr);
|
||||||
} else {
|
} else {
|
||||||
sbi_ipi_raw_send(hartid);
|
int rc = sbi_ipi_raw_send(hartid);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -313,7 +321,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __sbi_hsm_suspend_ret_default(struct sbi_scratch *scratch)
|
static int __sbi_hsm_suspend_default(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
/* Wait for interrupt */
|
/* Wait for interrupt */
|
||||||
wfi();
|
wfi();
|
||||||
@@ -353,23 +361,6 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
|
|||||||
csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
|
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;
|
|
||||||
|
|
||||||
/* 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)
|
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
int oldstate;
|
int oldstate;
|
||||||
@@ -384,6 +375,8 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
|
|||||||
__func__, oldstate);
|
__func__, oldstate);
|
||||||
sbi_hart_hang();
|
sbi_hart_hang();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hsm_device_hart_resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
|
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
|
||||||
@@ -465,17 +458,28 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
|
|||||||
__sbi_hsm_suspend_non_ret_save(scratch);
|
__sbi_hsm_suspend_non_ret_save(scratch);
|
||||||
|
|
||||||
/* Try platform specific suspend */
|
/* Try platform specific suspend */
|
||||||
ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr);
|
ret = hsm_device_hart_suspend(suspend_type);
|
||||||
if (ret == SBI_ENOTSUPP) {
|
if (ret == SBI_ENOTSUPP) {
|
||||||
/* Try generic implementation of default suspend types */
|
/* Try generic implementation of default suspend types */
|
||||||
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) {
|
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT ||
|
||||||
ret = __sbi_hsm_suspend_ret_default(scratch);
|
suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
|
||||||
} else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
|
ret = __sbi_hsm_suspend_default(scratch);
|
||||||
ret = __sbi_hsm_suspend_non_ret_default(scratch,
|
|
||||||
scratch->warmboot_addr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The platform may have coordinated a retentive suspend, or it may
|
||||||
|
* have exited early from a non-retentive suspend. Either way, the
|
||||||
|
* caller is not expecting a successful return, so jump to the warm
|
||||||
|
* boot entry point to simulate resume from a non-retentive suspend.
|
||||||
|
*/
|
||||||
|
if (ret == 0 && (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)) {
|
||||||
|
void (*jump_warmboot)(void) =
|
||||||
|
(void (*)(void))scratch->warmboot_addr;
|
||||||
|
|
||||||
|
jump_warmboot();
|
||||||
|
}
|
||||||
|
|
||||||
fail_restore_state:
|
fail_restore_state:
|
||||||
/*
|
/*
|
||||||
* We might have successfully resumed from retentive suspend
|
* We might have successfully resumed from retentive suspend
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
|
#include <sbi/riscv_barrier.h>
|
||||||
#include <sbi/riscv_encoding.h>
|
#include <sbi/riscv_encoding.h>
|
||||||
#include <sbi/sbi_bitops.h>
|
#include <sbi/sbi_bitops.h>
|
||||||
#include <sbi/sbi_emulate_csr.h>
|
#include <sbi/sbi_emulate_csr.h>
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
#include <sbi/sbi_pmu.h>
|
#include <sbi/sbi_pmu.h>
|
||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
#include <sbi/sbi_unpriv.h>
|
#include <sbi/sbi_unpriv.h>
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
|
||||||
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
|
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
|
||||||
|
|
||||||
@@ -28,17 +30,37 @@ static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
|
|||||||
trap.tval = insn;
|
trap.tval = insn;
|
||||||
trap.tval2 = 0;
|
trap.tval2 = 0;
|
||||||
trap.tinst = 0;
|
trap.tinst = 0;
|
||||||
|
trap.gva = 0;
|
||||||
|
|
||||||
return sbi_trap_redirect(regs, &trap);
|
return sbi_trap_redirect(regs, &trap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int misc_mem_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
|
||||||
|
{
|
||||||
|
/* Errata workaround: emulate `fence.tso` as `fence rw, rw`. */
|
||||||
|
if ((insn & INSN_MASK_FENCE_TSO) == INSN_MATCH_FENCE_TSO) {
|
||||||
|
smp_mb();
|
||||||
|
regs->mepc += 4;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return truly_illegal_insn(insn, regs);
|
||||||
|
}
|
||||||
|
|
||||||
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
|
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
|
||||||
{
|
{
|
||||||
int do_write, rs1_num = (insn >> 15) & 0x1f;
|
int do_write, rs1_num = (insn >> 15) & 0x1f;
|
||||||
ulong rs1_val = GET_RS1(insn, regs);
|
ulong rs1_val = GET_RS1(insn, regs);
|
||||||
int csr_num = (u32)insn >> 20;
|
int csr_num = (u32)insn >> 20;
|
||||||
|
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
|
||||||
ulong csr_val, new_csr_val;
|
ulong csr_val, new_csr_val;
|
||||||
|
|
||||||
|
if (prev_mode == PRV_M) {
|
||||||
|
sbi_printf("%s: Failed to access CSR %#x from M-mode",
|
||||||
|
__func__, csr_num);
|
||||||
|
return SBI_EFAIL;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: Ensure that we got CSR read/write instruction */
|
/* TODO: Ensure that we got CSR read/write instruction */
|
||||||
|
|
||||||
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
|
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
|
||||||
@@ -80,11 +102,11 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static illegal_insn_func illegal_insn_table[32] = {
|
static const illegal_insn_func illegal_insn_table[32] = {
|
||||||
truly_illegal_insn, /* 0 */
|
truly_illegal_insn, /* 0 */
|
||||||
truly_illegal_insn, /* 1 */
|
truly_illegal_insn, /* 1 */
|
||||||
truly_illegal_insn, /* 2 */
|
truly_illegal_insn, /* 2 */
|
||||||
truly_illegal_insn, /* 3 */
|
misc_mem_opcode_insn, /* 3 */
|
||||||
truly_illegal_insn, /* 4 */
|
truly_illegal_insn, /* 4 */
|
||||||
truly_illegal_insn, /* 5 */
|
truly_illegal_insn, /* 5 */
|
||||||
truly_illegal_insn, /* 6 */
|
truly_illegal_insn, /* 6 */
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include <sbi/sbi_hartmask.h>
|
#include <sbi/sbi_hartmask.h>
|
||||||
#include <sbi/sbi_hsm.h>
|
#include <sbi/sbi_hsm.h>
|
||||||
#include <sbi/sbi_ipi.h>
|
#include <sbi/sbi_ipi.h>
|
||||||
|
#include <sbi/sbi_irqchip.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_pmu.h>
|
#include <sbi/sbi_pmu.h>
|
||||||
#include <sbi/sbi_system.h>
|
#include <sbi/sbi_system.h>
|
||||||
@@ -62,6 +63,7 @@ static void sbi_boot_print_banner(struct sbi_scratch *scratch)
|
|||||||
static void sbi_boot_print_general(struct sbi_scratch *scratch)
|
static void sbi_boot_print_general(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
char str[128];
|
char str[128];
|
||||||
|
const struct sbi_pmu_device *pdev;
|
||||||
const struct sbi_hsm_device *hdev;
|
const struct sbi_hsm_device *hdev;
|
||||||
const struct sbi_ipi_device *idev;
|
const struct sbi_ipi_device *idev;
|
||||||
const struct sbi_timer_device *tdev;
|
const struct sbi_timer_device *tdev;
|
||||||
@@ -92,6 +94,9 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
|
|||||||
hdev = sbi_hsm_get_device();
|
hdev = sbi_hsm_get_device();
|
||||||
sbi_printf("Platform HSM Device : %s\n",
|
sbi_printf("Platform HSM Device : %s\n",
|
||||||
(hdev) ? hdev->name : "---");
|
(hdev) ? hdev->name : "---");
|
||||||
|
pdev = sbi_pmu_get_device();
|
||||||
|
sbi_printf("Platform PMU Device : %s\n",
|
||||||
|
(pdev) ? pdev->name : "---");
|
||||||
srdev = sbi_system_reset_get_device(SBI_SRST_RESET_TYPE_COLD_REBOOT, 0);
|
srdev = sbi_system_reset_get_device(SBI_SRST_RESET_TYPE_COLD_REBOOT, 0);
|
||||||
sbi_printf("Platform Reboot Device : %s\n",
|
sbi_printf("Platform Reboot Device : %s\n",
|
||||||
(srdev) ? srdev->name : "---");
|
(srdev) ? srdev->name : "---");
|
||||||
@@ -138,10 +143,12 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
/* Boot HART details */
|
/* Boot HART details */
|
||||||
sbi_printf("Boot HART ID : %u\n", hartid);
|
sbi_printf("Boot HART ID : %u\n", hartid);
|
||||||
sbi_printf("Boot HART Domain : %s\n", dom->name);
|
sbi_printf("Boot HART Domain : %s\n", dom->name);
|
||||||
|
sbi_hart_get_priv_version_str(scratch, str, sizeof(str));
|
||||||
|
sbi_printf("Boot HART Priv Version : %s\n", str);
|
||||||
misa_string(xlen, str, sizeof(str));
|
misa_string(xlen, str, sizeof(str));
|
||||||
sbi_printf("Boot HART ISA : %s\n", str);
|
sbi_printf("Boot HART Base ISA : %s\n", str);
|
||||||
sbi_hart_get_features_str(scratch, str, sizeof(str));
|
sbi_hart_get_extensions_str(scratch, str, sizeof(str));
|
||||||
sbi_printf("Boot HART Features : %s\n", str);
|
sbi_printf("Boot HART ISA Extensions : %s\n", str);
|
||||||
sbi_printf("Boot HART PMP Count : %d\n",
|
sbi_printf("Boot HART PMP Count : %d\n",
|
||||||
sbi_hart_pmp_count(scratch));
|
sbi_hart_pmp_count(scratch));
|
||||||
sbi_printf("Boot HART PMP Granularity : %lu\n",
|
sbi_printf("Boot HART PMP Granularity : %lu\n",
|
||||||
@@ -165,8 +172,8 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
/* Save MIE CSR */
|
/* Save MIE CSR */
|
||||||
saved_mie = csr_read(CSR_MIE);
|
saved_mie = csr_read(CSR_MIE);
|
||||||
|
|
||||||
/* Set MSIE bit to receive IPI */
|
/* Set MSIE and MEIE bits to receive IPI */
|
||||||
csr_set(CSR_MIE, MIP_MSIP);
|
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
|
||||||
|
|
||||||
/* Acquire coldboot lock */
|
/* Acquire coldboot lock */
|
||||||
spin_lock(&coldboot_lock);
|
spin_lock(&coldboot_lock);
|
||||||
@@ -182,7 +189,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
do {
|
do {
|
||||||
wfi();
|
wfi();
|
||||||
cmip = csr_read(CSR_MIP);
|
cmip = csr_read(CSR_MIP);
|
||||||
} while (!(cmip & MIP_MSIP));
|
} while (!(cmip & (MIP_MSIP | MIP_MEIP)));
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Acquire coldboot lock */
|
/* Acquire coldboot lock */
|
||||||
@@ -270,9 +277,9 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
|
|
||||||
sbi_boot_print_banner(scratch);
|
sbi_boot_print_banner(scratch);
|
||||||
|
|
||||||
rc = sbi_platform_irqchip_init(plat, TRUE);
|
rc = sbi_irqchip_init(scratch, TRUE);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
sbi_printf("%s: platform irqchip init failed (error %d)\n",
|
sbi_printf("%s: irqchip init failed (error %d)\n",
|
||||||
__func__, rc);
|
__func__, rc);
|
||||||
sbi_hart_hang();
|
sbi_hart_hang();
|
||||||
}
|
}
|
||||||
@@ -373,7 +380,7 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
if (rc)
|
if (rc)
|
||||||
sbi_hart_hang();
|
sbi_hart_hang();
|
||||||
|
|
||||||
rc = sbi_platform_irqchip_init(plat, FALSE);
|
rc = sbi_irqchip_init(scratch, FALSE);
|
||||||
if (rc)
|
if (rc)
|
||||||
sbi_hart_hang();
|
sbi_hart_hang();
|
||||||
|
|
||||||
@@ -494,6 +501,14 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
|
|||||||
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
|
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
|
||||||
coldboot = TRUE;
|
coldboot = TRUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do platform specific nascent (very early) initialization so
|
||||||
|
* that platform can initialize platform specific per-HART CSRs
|
||||||
|
* or per-HART devices.
|
||||||
|
*/
|
||||||
|
if (sbi_platform_nascent_init(plat))
|
||||||
|
sbi_hart_hang();
|
||||||
|
|
||||||
if (coldboot)
|
if (coldboot)
|
||||||
init_coldboot(scratch, hartid);
|
init_coldboot(scratch, hartid);
|
||||||
else
|
else
|
||||||
@@ -542,7 +557,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
|
|||||||
|
|
||||||
sbi_ipi_exit(scratch);
|
sbi_ipi_exit(scratch);
|
||||||
|
|
||||||
sbi_platform_irqchip_exit(plat);
|
sbi_irqchip_exit(scratch);
|
||||||
|
|
||||||
sbi_platform_final_exit(plat);
|
sbi_platform_final_exit(plat);
|
||||||
|
|
||||||
|
@@ -208,10 +208,13 @@ skip:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_ipi_raw_send(u32 target_hart)
|
int sbi_ipi_raw_send(u32 target_hart)
|
||||||
{
|
{
|
||||||
if (ipi_dev && ipi_dev->ipi_send)
|
if (!ipi_dev || !ipi_dev->ipi_send)
|
||||||
ipi_dev->ipi_send(target_hart);
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
ipi_dev->ipi_send(target_hart);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct sbi_ipi_device *sbi_ipi_get_device(void)
|
const struct sbi_ipi_device *sbi_ipi_get_device(void)
|
||||||
|
54
lib/sbi/sbi_irqchip.c
Normal file
54
lib/sbi/sbi_irqchip.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Ventana Micro Systems Inc.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <apatel@ventanamicro.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_irqchip.h>
|
||||||
|
#include <sbi/sbi_platform.h>
|
||||||
|
|
||||||
|
static int default_irqfn(struct sbi_trap_regs *regs)
|
||||||
|
{
|
||||||
|
return SBI_ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int (*ext_irqfn)(struct sbi_trap_regs *regs) = default_irqfn;
|
||||||
|
|
||||||
|
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs))
|
||||||
|
{
|
||||||
|
if (fn)
|
||||||
|
ext_irqfn = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sbi_irqchip_process(struct sbi_trap_regs *regs)
|
||||||
|
{
|
||||||
|
return ext_irqfn(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
|
||||||
|
rc = sbi_platform_irqchip_init(plat, cold_boot);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (ext_irqfn != default_irqfn)
|
||||||
|
csr_set(CSR_MIE, MIP_MEIP);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sbi_irqchip_exit(struct sbi_scratch *scratch)
|
||||||
|
{
|
||||||
|
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
|
||||||
|
if (ext_irqfn != default_irqfn)
|
||||||
|
csr_clear(CSR_MIE, MIP_MEIP);
|
||||||
|
|
||||||
|
sbi_platform_irqchip_exit(plat);
|
||||||
|
}
|
@@ -22,6 +22,18 @@ union reg_data {
|
|||||||
u64 data_u64;
|
u64 data_u64;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ulong sbi_misaligned_tinst_fixup(ulong orig_tinst, ulong new_tinst,
|
||||||
|
ulong addr_offset)
|
||||||
|
{
|
||||||
|
if (new_tinst == INSN_PSEUDO_VS_LOAD ||
|
||||||
|
new_tinst == INSN_PSEUDO_VS_STORE)
|
||||||
|
return new_tinst;
|
||||||
|
else if (orig_tinst == 0)
|
||||||
|
return 0UL;
|
||||||
|
else
|
||||||
|
return orig_tinst | (addr_offset << SH_RS1);
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
||||||
struct sbi_trap_regs *regs)
|
struct sbi_trap_regs *regs)
|
||||||
{
|
{
|
||||||
@@ -117,6 +129,7 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
|||||||
uptrap.tval = addr;
|
uptrap.tval = addr;
|
||||||
uptrap.tval2 = tval2;
|
uptrap.tval2 = tval2;
|
||||||
uptrap.tinst = tinst;
|
uptrap.tinst = tinst;
|
||||||
|
uptrap.gva = sbi_regs_gva(regs);
|
||||||
return sbi_trap_redirect(regs, &uptrap);
|
return sbi_trap_redirect(regs, &uptrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +139,8 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
|
|||||||
&uptrap);
|
&uptrap);
|
||||||
if (uptrap.cause) {
|
if (uptrap.cause) {
|
||||||
uptrap.epc = regs->mepc;
|
uptrap.epc = regs->mepc;
|
||||||
|
uptrap.tinst = sbi_misaligned_tinst_fixup(
|
||||||
|
tinst, uptrap.tinst, i);
|
||||||
return sbi_trap_redirect(regs, &uptrap);
|
return sbi_trap_redirect(regs, &uptrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,6 +245,7 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
|
|||||||
uptrap.tval = addr;
|
uptrap.tval = addr;
|
||||||
uptrap.tval2 = tval2;
|
uptrap.tval2 = tval2;
|
||||||
uptrap.tinst = tinst;
|
uptrap.tinst = tinst;
|
||||||
|
uptrap.gva = sbi_regs_gva(regs);
|
||||||
return sbi_trap_redirect(regs, &uptrap);
|
return sbi_trap_redirect(regs, &uptrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,6 +254,8 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
|
|||||||
&uptrap);
|
&uptrap);
|
||||||
if (uptrap.cause) {
|
if (uptrap.cause) {
|
||||||
uptrap.epc = regs->mepc;
|
uptrap.epc = regs->mepc;
|
||||||
|
uptrap.tinst = sbi_misaligned_tinst_fixup(
|
||||||
|
tinst, uptrap.tinst, i);
|
||||||
return sbi_trap_redirect(regs, &uptrap);
|
return sbi_trap_redirect(regs, &uptrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
#include <sbi/sbi_bitops.h>
|
#include <sbi/sbi_bitops.h>
|
||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
#include <sbi/sbi_hart.h>
|
#include <sbi/sbi_hart.h>
|
||||||
|
#include <sbi/sbi_hartmask.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_pmu.h>
|
#include <sbi/sbi_pmu.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
@@ -33,18 +35,6 @@ struct sbi_pmu_hw_event {
|
|||||||
uint64_t select_mask;
|
uint64_t select_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Representation of a firmware event */
|
|
||||||
struct sbi_pmu_fw_event {
|
|
||||||
/* Event associated with the particular counter */
|
|
||||||
uint32_t event_idx;
|
|
||||||
|
|
||||||
/* Current value of the counter */
|
|
||||||
unsigned long curr_count;
|
|
||||||
|
|
||||||
/* A flag indicating pmu event monitoring is started */
|
|
||||||
bool bStarted;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Information about PMU counters as per SBI specification */
|
/* Information about PMU counters as per SBI specification */
|
||||||
union sbi_pmu_ctr_info {
|
union sbi_pmu_ctr_info {
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
@@ -60,14 +50,23 @@ union sbi_pmu_ctr_info {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Platform specific PMU device */
|
||||||
|
static const struct sbi_pmu_device *pmu_dev = NULL;
|
||||||
|
|
||||||
/* Mapping between event range and possible counters */
|
/* Mapping between event range and possible counters */
|
||||||
static struct sbi_pmu_hw_event hw_event_map[SBI_PMU_HW_EVENT_MAX] = {0};
|
static struct sbi_pmu_hw_event hw_event_map[SBI_PMU_HW_EVENT_MAX] = {0};
|
||||||
|
|
||||||
/* counter to enabled event mapping */
|
/* counter to enabled event mapping */
|
||||||
static uint32_t active_events[SBI_HARTMASK_MAX_BITS][SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX];
|
static uint32_t active_events[SBI_HARTMASK_MAX_BITS][SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX];
|
||||||
|
|
||||||
/* Contains all the information about firmwares events */
|
/* Bitmap of firmware counters started on each HART */
|
||||||
static struct sbi_pmu_fw_event fw_event_map[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_EVENT_MAX] = {0};
|
#if SBI_PMU_FW_CTR_MAX >= BITS_PER_LONG
|
||||||
|
#error "Can't handle firmware counters beyond BITS_PER_LONG"
|
||||||
|
#endif
|
||||||
|
static unsigned long fw_counters_started[SBI_HARTMASK_MAX_BITS];
|
||||||
|
|
||||||
|
/* Values of firmwares counters on each HART */
|
||||||
|
static uint64_t fw_counters_value[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_CTR_MAX] = {0};
|
||||||
|
|
||||||
/* Maximum number of hardware events available */
|
/* Maximum number of hardware events available */
|
||||||
static uint32_t num_hw_events;
|
static uint32_t num_hw_events;
|
||||||
@@ -107,19 +106,66 @@ static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pmu_event_validate(unsigned long event_idx)
|
||||||
|
{
|
||||||
|
uint32_t event_idx_type = get_cidx_type(event_idx);
|
||||||
|
uint32_t event_idx_code = get_cidx_code(event_idx);
|
||||||
|
uint32_t event_idx_code_max = -1;
|
||||||
|
uint32_t cache_ops_result, cache_ops_id, cache_id;
|
||||||
|
|
||||||
|
switch(event_idx_type) {
|
||||||
|
case SBI_PMU_EVENT_TYPE_HW:
|
||||||
|
event_idx_code_max = SBI_PMU_HW_GENERAL_MAX;
|
||||||
|
break;
|
||||||
|
case SBI_PMU_EVENT_TYPE_FW:
|
||||||
|
if (SBI_PMU_FW_MAX <= event_idx_code &&
|
||||||
|
pmu_dev && pmu_dev->fw_event_validate_code)
|
||||||
|
return pmu_dev->fw_event_validate_code(event_idx_code);
|
||||||
|
else
|
||||||
|
event_idx_code_max = SBI_PMU_FW_MAX;
|
||||||
|
break;
|
||||||
|
case SBI_PMU_EVENT_TYPE_HW_CACHE:
|
||||||
|
cache_ops_result = event_idx_code &
|
||||||
|
SBI_PMU_EVENT_HW_CACHE_OPS_RESULT;
|
||||||
|
cache_ops_id = (event_idx_code &
|
||||||
|
SBI_PMU_EVENT_HW_CACHE_OPS_ID_MASK) >>
|
||||||
|
SBI_PMU_EVENT_HW_CACHE_OPS_ID_OFFSET;
|
||||||
|
cache_id = (event_idx_code &
|
||||||
|
SBI_PMU_EVENT_HW_CACHE_ID_MASK) >>
|
||||||
|
SBI_PMU_EVENT_HW_CACHE_ID_OFFSET;
|
||||||
|
if ((cache_ops_result < SBI_PMU_HW_CACHE_RESULT_MAX) &&
|
||||||
|
(cache_ops_id < SBI_PMU_HW_CACHE_OP_MAX) &&
|
||||||
|
(cache_id < SBI_PMU_HW_CACHE_MAX))
|
||||||
|
return event_idx_type;
|
||||||
|
else
|
||||||
|
return SBI_EINVAL;
|
||||||
|
break;
|
||||||
|
case SBI_PMU_EVENT_TYPE_HW_RAW:
|
||||||
|
event_idx_code_max = 1; // event_idx.code should be zero
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SBI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_idx_code < event_idx_code_max)
|
||||||
|
return event_idx_type;
|
||||||
|
|
||||||
|
return SBI_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
|
static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
|
||||||
{
|
{
|
||||||
uint32_t event_idx_val;
|
uint32_t event_idx_val;
|
||||||
uint32_t event_idx_type;
|
uint32_t event_idx_type;
|
||||||
u32 hartid = current_hartid();
|
u32 hartid = current_hartid();
|
||||||
|
|
||||||
event_idx_val = active_events[hartid][cidx];
|
if (cidx >= total_ctrs)
|
||||||
|
|
||||||
if (cidx >= total_ctrs || (event_idx_val == SBI_PMU_EVENT_IDX_INVALID))
|
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
event_idx_val = active_events[hartid][cidx];
|
||||||
event_idx_type = get_cidx_type(event_idx_val);
|
event_idx_type = get_cidx_type(event_idx_val);
|
||||||
if (event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
|
if (event_idx_val == SBI_PMU_EVENT_IDX_INVALID ||
|
||||||
|
event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
*event_idx_code = get_cidx_code(event_idx_val);
|
*event_idx_code = get_cidx_code(event_idx_val);
|
||||||
@@ -127,50 +173,22 @@ static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
|
|||||||
return event_idx_type;
|
return event_idx_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pmu_ctr_read_fw(uint32_t cidx, unsigned long *cval,
|
int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
|
||||||
uint32_t fw_evt_code)
|
|
||||||
{
|
|
||||||
u32 hartid = current_hartid();
|
|
||||||
struct sbi_pmu_fw_event fevent;
|
|
||||||
|
|
||||||
fevent = fw_event_map[hartid][fw_evt_code];
|
|
||||||
*cval = fevent.curr_count;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a hardware counter read for completeness for future purpose */
|
|
||||||
static int pmu_ctr_read_hw(uint32_t cidx, uint64_t *cval)
|
|
||||||
{
|
|
||||||
/* Check for invalid hw counter read requests */
|
|
||||||
if (unlikely(cidx == 1))
|
|
||||||
return SBI_EINVAL;
|
|
||||||
#if __riscv_xlen == 32
|
|
||||||
uint32_t temp, temph = 0;
|
|
||||||
|
|
||||||
temp = csr_read_num(CSR_MCYCLE + cidx);
|
|
||||||
temph = csr_read_num(CSR_MCYCLEH + cidx);
|
|
||||||
*cval = ((uint64_t)temph << 32) | temp;
|
|
||||||
#else
|
|
||||||
*cval = csr_read_num(CSR_MCYCLE + cidx);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sbi_pmu_ctr_read(uint32_t cidx, unsigned long *cval)
|
|
||||||
{
|
{
|
||||||
int event_idx_type;
|
int event_idx_type;
|
||||||
uint32_t event_code;
|
uint32_t event_code;
|
||||||
uint64_t cval64;
|
u32 hartid = current_hartid();
|
||||||
|
|
||||||
event_idx_type = pmu_ctr_validate(cidx, &event_code);
|
event_idx_type = pmu_ctr_validate(cidx, &event_code);
|
||||||
if (event_idx_type < 0)
|
if (event_idx_type != SBI_PMU_EVENT_TYPE_FW)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
|
|
||||||
pmu_ctr_read_fw(cidx, cval, event_code);
|
if (SBI_PMU_FW_MAX <= event_code &&
|
||||||
else
|
pmu_dev && pmu_dev->fw_counter_read_value)
|
||||||
pmu_ctr_read_hw(cidx, &cval64);
|
fw_counters_value[hartid][cidx - num_hw_ctrs] =
|
||||||
|
pmu_dev->fw_counter_read_value(cidx - num_hw_ctrs);
|
||||||
|
|
||||||
|
*cval = fw_counters_value[hartid][cidx - num_hw_ctrs];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -181,6 +199,9 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
bool is_overlap;
|
bool is_overlap;
|
||||||
struct sbi_pmu_hw_event *event = &hw_event_map[num_hw_events];
|
struct sbi_pmu_hw_event *event = &hw_event_map[num_hw_events];
|
||||||
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
int hw_ctr_avail = sbi_hart_mhpm_count(scratch);
|
||||||
|
uint32_t ctr_avail_mask = ((uint32_t)(~0) >> (32 - (hw_ctr_avail + 3)));
|
||||||
|
|
||||||
/* The first two counters are reserved by priv spec */
|
/* The first two counters are reserved by priv spec */
|
||||||
if (eidx_start > SBI_PMU_HW_INSTRUCTIONS && (cmap & SBI_PMU_FIXED_CTR_MASK))
|
if (eidx_start > SBI_PMU_HW_INSTRUCTIONS && (cmap & SBI_PMU_FIXED_CTR_MASK))
|
||||||
@@ -208,7 +229,8 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
|
|||||||
}
|
}
|
||||||
|
|
||||||
event->select_mask = select_mask;
|
event->select_mask = select_mask;
|
||||||
event->counters = cmap;
|
/* Map the only the counters that are available in the hardware */
|
||||||
|
event->counters = cmap & ctr_avail_mask;
|
||||||
event->select = select;
|
event->select = select;
|
||||||
num_hw_events++;
|
num_hw_events++;
|
||||||
|
|
||||||
@@ -252,7 +274,7 @@ static int pmu_ctr_enable_irq_hw(int ctr_idx)
|
|||||||
|
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
mhpmevent_csr = CSR_MHPMEVENT3H + ctr_idx - 3;
|
mhpmevent_csr = CSR_MHPMEVENT3H + ctr_idx - 3;
|
||||||
of_mask = ~MHPMEVENTH_OF;
|
of_mask = (uint32_t)~MHPMEVENTH_OF;
|
||||||
#else
|
#else
|
||||||
mhpmevent_csr = CSR_MHPMEVENT3 + ctr_idx - 3;
|
mhpmevent_csr = CSR_MHPMEVENT3 + ctr_idx - 3;
|
||||||
of_mask = ~MHPMEVENT_OF;
|
of_mask = ~MHPMEVENT_OF;
|
||||||
@@ -293,10 +315,10 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
|
|||||||
unsigned long mctr_inhbt;
|
unsigned long mctr_inhbt;
|
||||||
|
|
||||||
/* Make sure the counter index lies within the range and is not TM bit */
|
/* Make sure the counter index lies within the range and is not TM bit */
|
||||||
if (cidx > num_hw_ctrs || cidx == 1)
|
if (cidx >= num_hw_ctrs || cidx == 1)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
|
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
|
||||||
goto skip_inhibit_update;
|
goto skip_inhibit_update;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -309,8 +331,10 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
|
|||||||
|
|
||||||
__clear_bit(cidx, &mctr_inhbt);
|
__clear_bit(cidx, &mctr_inhbt);
|
||||||
|
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
pmu_ctr_enable_irq_hw(cidx);
|
pmu_ctr_enable_irq_hw(cidx);
|
||||||
|
if (pmu_dev && pmu_dev->hw_counter_enable_irq)
|
||||||
|
pmu_dev->hw_counter_enable_irq(cidx);
|
||||||
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
|
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
|
||||||
|
|
||||||
skip_inhibit_update:
|
skip_inhibit_update:
|
||||||
@@ -320,16 +344,36 @@ skip_inhibit_update:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pmu_ctr_start_fw(uint32_t cidx, uint32_t fw_evt_code,
|
int sbi_pmu_irq_bit(void)
|
||||||
|
{
|
||||||
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
|
return MIP_LCOFIP;
|
||||||
|
if (pmu_dev && pmu_dev->hw_counter_irq_bit)
|
||||||
|
return pmu_dev->hw_counter_irq_bit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code,
|
||||||
uint64_t ival, bool ival_update)
|
uint64_t ival, bool ival_update)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
u32 hartid = current_hartid();
|
u32 hartid = current_hartid();
|
||||||
struct sbi_pmu_fw_event *fevent;
|
|
||||||
|
|
||||||
fevent = &fw_event_map[hartid][fw_evt_code];
|
if (SBI_PMU_FW_MAX <= event_code &&
|
||||||
|
pmu_dev && pmu_dev->fw_counter_start) {
|
||||||
|
ret = pmu_dev->fw_counter_start(cidx - num_hw_ctrs,
|
||||||
|
event_code,
|
||||||
|
ival, ival_update);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (ival_update)
|
if (ival_update)
|
||||||
fevent->curr_count = ival;
|
fw_counters_value[hartid][cidx - num_hw_ctrs] = ival;
|
||||||
fevent->bStarted = TRUE;
|
fw_counters_started[hartid] |= BIT(cidx - num_hw_ctrs);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -339,25 +383,26 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
|
|||||||
{
|
{
|
||||||
int event_idx_type;
|
int event_idx_type;
|
||||||
uint32_t event_code;
|
uint32_t event_code;
|
||||||
unsigned long ctr_mask = cmask << cbase;
|
|
||||||
int ret = SBI_EINVAL;
|
int ret = SBI_EINVAL;
|
||||||
bool bUpdate = FALSE;
|
bool bUpdate = FALSE;
|
||||||
|
int i, cidx;
|
||||||
|
|
||||||
if (__fls(ctr_mask) >= total_ctrs)
|
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
|
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
|
||||||
bUpdate = TRUE;
|
bUpdate = TRUE;
|
||||||
|
|
||||||
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
|
for_each_set_bit(i, &cmask, total_ctrs) {
|
||||||
event_idx_type = pmu_ctr_validate(cbase, &event_code);
|
cidx = i + cbase;
|
||||||
|
event_idx_type = pmu_ctr_validate(cidx, &event_code);
|
||||||
if (event_idx_type < 0)
|
if (event_idx_type < 0)
|
||||||
/* Continue the start operation for other counters */
|
/* Continue the start operation for other counters */
|
||||||
continue;
|
continue;
|
||||||
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
|
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
|
||||||
ret = pmu_ctr_start_fw(cbase, event_code, ival, bUpdate);
|
ret = pmu_ctr_start_fw(cidx, event_code, ival, bUpdate);
|
||||||
else
|
else
|
||||||
ret = pmu_ctr_start_hw(cbase, ival, bUpdate);
|
ret = pmu_ctr_start_hw(cidx, ival, bUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -368,13 +413,13 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
|
|||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
unsigned long mctr_inhbt;
|
unsigned long mctr_inhbt;
|
||||||
|
|
||||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
|
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
|
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
|
||||||
|
|
||||||
/* Make sure the counter index lies within the range and is not TM bit */
|
/* Make sure the counter index lies within the range and is not TM bit */
|
||||||
if (cidx > num_hw_ctrs || cidx == 1)
|
if (cidx >= num_hw_ctrs || cidx == 1)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
if (!__test_bit(cidx, &mctr_inhbt)) {
|
if (!__test_bit(cidx, &mctr_inhbt)) {
|
||||||
@@ -385,11 +430,18 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
|
|||||||
return SBI_EALREADY_STOPPED;
|
return SBI_EALREADY_STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t fw_evt_code)
|
static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code)
|
||||||
{
|
{
|
||||||
u32 hartid = current_hartid();
|
int ret;
|
||||||
|
|
||||||
fw_event_map[hartid][fw_evt_code].bStarted = FALSE;
|
if (SBI_PMU_FW_MAX <= event_code &&
|
||||||
|
pmu_dev && pmu_dev->fw_counter_stop) {
|
||||||
|
ret = pmu_dev->fw_counter_stop(cidx - num_hw_ctrs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_counters_started[current_hartid()] &= ~BIT(cidx - num_hw_ctrs);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -400,7 +452,9 @@ static int pmu_reset_hw_mhpmevent(int ctr_idx)
|
|||||||
return SBI_EFAIL;
|
return SBI_EFAIL;
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
|
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
|
||||||
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, 0);
|
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
|
||||||
|
SBI_HART_EXT_SSCOFPMF))
|
||||||
|
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, 0);
|
||||||
#else
|
#else
|
||||||
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
|
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
|
||||||
#endif
|
#endif
|
||||||
@@ -415,25 +469,26 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
|
|||||||
int ret = SBI_EINVAL;
|
int ret = SBI_EINVAL;
|
||||||
int event_idx_type;
|
int event_idx_type;
|
||||||
uint32_t event_code;
|
uint32_t event_code;
|
||||||
unsigned long ctr_mask = cmask << cbase;
|
int i, cidx;
|
||||||
|
|
||||||
if (__fls(ctr_mask) >= total_ctrs)
|
if ((cbase + sbi_fls(cmask)) >= total_ctrs)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
|
for_each_set_bit(i, &cmask, total_ctrs) {
|
||||||
event_idx_type = pmu_ctr_validate(cbase, &event_code);
|
cidx = i + cbase;
|
||||||
|
event_idx_type = pmu_ctr_validate(cidx, &event_code);
|
||||||
if (event_idx_type < 0)
|
if (event_idx_type < 0)
|
||||||
/* Continue the stop operation for other counters */
|
/* Continue the stop operation for other counters */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
|
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
|
||||||
ret = pmu_ctr_stop_fw(cbase, event_code);
|
ret = pmu_ctr_stop_fw(cidx, event_code);
|
||||||
else
|
else
|
||||||
ret = pmu_ctr_stop_hw(cbase);
|
ret = pmu_ctr_stop_hw(cidx);
|
||||||
|
|
||||||
if (flag & SBI_PMU_STOP_FLAG_RESET) {
|
if (flag & SBI_PMU_STOP_FLAG_RESET) {
|
||||||
active_events[hartid][cbase] = SBI_PMU_EVENT_IDX_INVALID;
|
active_events[hartid][cidx] = SBI_PMU_EVENT_IDX_INVALID;
|
||||||
pmu_reset_hw_mhpmevent(cbase);
|
pmu_reset_hw_mhpmevent(cidx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,16 +521,25 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
|
|||||||
if (!mhpmevent_val || ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
|
if (!mhpmevent_val || ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
|
||||||
return SBI_EFAIL;
|
return SBI_EFAIL;
|
||||||
|
|
||||||
/* Always clear the OVF bit and inhibit countin of events in M-mode */
|
/**
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
|
* Always set the OVF bit(disable interrupts) and inhibit counting of
|
||||||
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) | MHPMEVENT_MINH;
|
* events in M-mode. The OVF bit should be enabled during the start call.
|
||||||
|
*/
|
||||||
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
|
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) |
|
||||||
|
MHPMEVENT_MINH | MHPMEVENT_OF;
|
||||||
|
|
||||||
|
if (pmu_dev && pmu_dev->hw_counter_disable_irq)
|
||||||
|
pmu_dev->hw_counter_disable_irq(ctr_idx);
|
||||||
|
|
||||||
/* Update the inhibit flags based on inhibit flags received from supervisor */
|
/* Update the inhibit flags based on inhibit flags received from supervisor */
|
||||||
pmu_update_inhibit_flags(flags, &mhpmevent_val);
|
pmu_update_inhibit_flags(flags, &mhpmevent_val);
|
||||||
|
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
|
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
|
||||||
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, mhpmevent_val >> BITS_PER_LONG);
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
|
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3,
|
||||||
|
mhpmevent_val >> BITS_PER_LONG);
|
||||||
#else
|
#else
|
||||||
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
|
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
|
||||||
#endif
|
#endif
|
||||||
@@ -504,7 +568,7 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
|
|||||||
u32 hartid = current_hartid();
|
u32 hartid = current_hartid();
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
|
|
||||||
if (cbase > num_hw_ctrs)
|
if (cbase >= num_hw_ctrs)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -513,10 +577,10 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
|
|||||||
*/
|
*/
|
||||||
fixed_ctr = pmu_ctr_find_fixed_fw(event_idx);
|
fixed_ctr = pmu_ctr_find_fixed_fw(event_idx);
|
||||||
if (fixed_ctr >= 0 &&
|
if (fixed_ctr >= 0 &&
|
||||||
!sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
|
!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
return fixed_ctr;
|
return fixed_ctr;
|
||||||
|
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
|
||||||
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
|
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
|
||||||
for (i = 0; i < num_hw_events; i++) {
|
for (i = 0; i < num_hw_events; i++) {
|
||||||
temp = &hw_event_map[i];
|
temp = &hw_event_map[i];
|
||||||
@@ -543,7 +607,7 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
|
|||||||
if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID)
|
if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID)
|
||||||
continue;
|
continue;
|
||||||
/* If mcountinhibit is supported, the bit must be enabled */
|
/* If mcountinhibit is supported, the bit must be enabled */
|
||||||
if ((sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT)) &&
|
if ((sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) &&
|
||||||
!__test_bit(cbase, &mctr_inhbt))
|
!__test_bit(cbase, &mctr_inhbt))
|
||||||
continue;
|
continue;
|
||||||
/* We found a valid counter that is not started yet */
|
/* We found a valid counter that is not started yet */
|
||||||
@@ -575,21 +639,26 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
|
|||||||
* Thus, select the first available fw counter after sanity
|
* Thus, select the first available fw counter after sanity
|
||||||
* check.
|
* check.
|
||||||
*/
|
*/
|
||||||
static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, u32 hartid)
|
static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask,
|
||||||
|
uint32_t event_code, u32 hartid)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i, cidx;
|
||||||
int fw_base;
|
|
||||||
unsigned long ctr_mask = cmask << cbase;
|
|
||||||
|
|
||||||
if (cbase <= num_hw_ctrs)
|
for_each_set_bit(i, &cmask, BITS_PER_LONG) {
|
||||||
fw_base = num_hw_ctrs + 1;
|
cidx = i + cbase;
|
||||||
else
|
if (cidx < num_hw_ctrs || total_ctrs <= cidx)
|
||||||
fw_base = cbase;
|
continue;
|
||||||
|
if (active_events[hartid][i] != SBI_PMU_EVENT_IDX_INVALID)
|
||||||
|
continue;
|
||||||
|
if (SBI_PMU_FW_MAX <= event_code &&
|
||||||
|
pmu_dev && pmu_dev->fw_counter_match_code) {
|
||||||
|
if (!pmu_dev->fw_counter_match_code(cidx - num_hw_ctrs,
|
||||||
|
event_code))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = fw_base; i < total_ctrs; i++)
|
return i;
|
||||||
if ((active_events[hartid][i] == SBI_PMU_EVENT_IDX_INVALID) &&
|
}
|
||||||
((1UL << i) & ctr_mask))
|
|
||||||
return i;
|
|
||||||
|
|
||||||
return SBI_ENOTSUPP;
|
return SBI_ENOTSUPP;
|
||||||
}
|
}
|
||||||
@@ -598,17 +667,19 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
|
|||||||
unsigned long flags, unsigned long event_idx,
|
unsigned long flags, unsigned long event_idx,
|
||||||
uint64_t event_data)
|
uint64_t event_data)
|
||||||
{
|
{
|
||||||
int ctr_idx = SBI_ENOTSUPP;
|
int ret, ctr_idx = SBI_ENOTSUPP;
|
||||||
u32 hartid = current_hartid();
|
u32 event_code, hartid = current_hartid();
|
||||||
int event_type = get_cidx_type(event_idx);
|
int event_type;
|
||||||
struct sbi_pmu_fw_event *fevent;
|
|
||||||
uint32_t fw_evt_code;
|
|
||||||
unsigned long tmp = cidx_mask << cidx_base;
|
|
||||||
|
|
||||||
/* Do a basic sanity check of counter base & mask */
|
/* Do a basic sanity check of counter base & mask */
|
||||||
if (__fls(tmp) >= total_ctrs || event_type >= SBI_PMU_EVENT_TYPE_MAX)
|
if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
event_type = pmu_event_validate(event_idx);
|
||||||
|
if (event_type < 0)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
event_code = get_cidx_code(event_idx);
|
||||||
|
|
||||||
if (flags & SBI_PMU_CFG_FLAG_SKIP_MATCH) {
|
if (flags & SBI_PMU_CFG_FLAG_SKIP_MATCH) {
|
||||||
/* The caller wants to skip the match because it already knows the
|
/* The caller wants to skip the match because it already knows the
|
||||||
* counter idx for the given event. Verify that the counter idx
|
* counter idx for the given event. Verify that the counter idx
|
||||||
@@ -622,7 +693,7 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
|
|||||||
|
|
||||||
if (event_type == SBI_PMU_EVENT_TYPE_FW) {
|
if (event_type == SBI_PMU_EVENT_TYPE_FW) {
|
||||||
/* Any firmware counter can be used track any firmware event */
|
/* Any firmware counter can be used track any firmware event */
|
||||||
ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, hartid);
|
ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, event_code, hartid);
|
||||||
} else {
|
} else {
|
||||||
ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx,
|
ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx,
|
||||||
event_data);
|
event_data);
|
||||||
@@ -639,30 +710,46 @@ skip_match:
|
|||||||
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
|
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
|
||||||
pmu_ctr_start_hw(ctr_idx, 0, false);
|
pmu_ctr_start_hw(ctr_idx, 0, false);
|
||||||
} else if (event_type == SBI_PMU_EVENT_TYPE_FW) {
|
} else if (event_type == SBI_PMU_EVENT_TYPE_FW) {
|
||||||
fw_evt_code = get_cidx_code(event_idx);
|
|
||||||
fevent = &fw_event_map[hartid][fw_evt_code];
|
|
||||||
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
|
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
|
||||||
fevent->curr_count = 0;
|
fw_counters_value[hartid][ctr_idx - num_hw_ctrs] = 0;
|
||||||
if (flags & SBI_PMU_CFG_FLAG_AUTO_START)
|
if (flags & SBI_PMU_CFG_FLAG_AUTO_START) {
|
||||||
fevent->bStarted = TRUE;
|
if (SBI_PMU_FW_MAX <= event_code &&
|
||||||
|
pmu_dev && pmu_dev->fw_counter_start) {
|
||||||
|
ret = pmu_dev->fw_counter_start(
|
||||||
|
ctr_idx - num_hw_ctrs, event_code,
|
||||||
|
fw_counters_value[hartid][ctr_idx - num_hw_ctrs],
|
||||||
|
true);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fw_counters_started[hartid] |= BIT(ctr_idx - num_hw_ctrs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctr_idx;
|
return ctr_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
|
int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
|
||||||
{
|
{
|
||||||
u32 hartid = current_hartid();
|
u32 cidx, hartid = current_hartid();
|
||||||
struct sbi_pmu_fw_event *fevent;
|
uint64_t *fcounter = NULL;
|
||||||
|
|
||||||
|
if (likely(!fw_counters_started[hartid]))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (unlikely(fw_id >= SBI_PMU_FW_MAX))
|
if (unlikely(fw_id >= SBI_PMU_FW_MAX))
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
fevent = &fw_event_map[hartid][fw_id];
|
for (cidx = num_hw_ctrs; cidx < total_ctrs; cidx++) {
|
||||||
|
if (get_cidx_code(active_events[hartid][cidx]) == fw_id &&
|
||||||
|
(fw_counters_started[hartid] & BIT(cidx - num_hw_ctrs))) {
|
||||||
|
fcounter = &fw_counters_value[hartid][cidx - num_hw_ctrs];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* PMU counters will be only enabled during performance debugging */
|
if (fcounter)
|
||||||
if (unlikely(fevent->bStarted))
|
(*fcounter)++;
|
||||||
fevent->curr_count++;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -682,7 +769,7 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
|
|||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
/* We have 31 HW counters with 31 being the last index(MHPMCOUNTER31) */
|
/* We have 31 HW counters with 31 being the last index(MHPMCOUNTER31) */
|
||||||
if (cidx <= num_hw_ctrs) {
|
if (cidx < num_hw_ctrs) {
|
||||||
cinfo.type = SBI_PMU_CTR_TYPE_HW;
|
cinfo.type = SBI_PMU_CTR_TYPE_HW;
|
||||||
cinfo.csr = CSR_CYCLE + cidx;
|
cinfo.csr = CSR_CYCLE + cidx;
|
||||||
/* mcycle & minstret are always 64 bit */
|
/* mcycle & minstret are always 64 bit */
|
||||||
@@ -693,8 +780,8 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
|
|||||||
} else {
|
} else {
|
||||||
/* it's a firmware counter */
|
/* it's a firmware counter */
|
||||||
cinfo.type = SBI_PMU_CTR_TYPE_FW;
|
cinfo.type = SBI_PMU_CTR_TYPE_FW;
|
||||||
/* Firmware counters are XLEN bits wide */
|
/* Firmware counters are always 64 bits wide */
|
||||||
cinfo.width = BITS_PER_LONG - 1;
|
cinfo.width = 63;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ctr_info = cinfo.value;
|
*ctr_info = cinfo.value;
|
||||||
@@ -710,18 +797,32 @@ static void pmu_reset_event_map(u32 hartid)
|
|||||||
for (j = 3; j < total_ctrs; j++)
|
for (j = 3; j < total_ctrs; j++)
|
||||||
active_events[hartid][j] = SBI_PMU_EVENT_IDX_INVALID;
|
active_events[hartid][j] = SBI_PMU_EVENT_IDX_INVALID;
|
||||||
for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++)
|
for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++)
|
||||||
sbi_memset(&fw_event_map[hartid][j], 0,
|
fw_counters_value[hartid][j] = 0;
|
||||||
sizeof(struct sbi_pmu_fw_event));
|
fw_counters_started[hartid] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct sbi_pmu_device *sbi_pmu_get_device(void)
|
||||||
|
{
|
||||||
|
return pmu_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sbi_pmu_set_device(const struct sbi_pmu_device *dev)
|
||||||
|
{
|
||||||
|
if (!dev || pmu_dev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pmu_dev = dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_pmu_exit(struct sbi_scratch *scratch)
|
void sbi_pmu_exit(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
u32 hartid = current_hartid();
|
u32 hartid = current_hartid();
|
||||||
|
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
|
||||||
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
|
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
|
||||||
|
|
||||||
csr_write(CSR_MCOUNTEREN, -1);
|
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
|
||||||
|
csr_write(CSR_MCOUNTEREN, -1);
|
||||||
pmu_reset_event_map(hartid);
|
pmu_reset_event_map(hartid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,7 +837,7 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
|
|||||||
sbi_platform_pmu_init(plat);
|
sbi_platform_pmu_init(plat);
|
||||||
|
|
||||||
/* mcycle & minstret is available always */
|
/* mcycle & minstret is available always */
|
||||||
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 2;
|
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 3;
|
||||||
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
|
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -59,7 +59,6 @@ size_t sbi_strnlen(const char *str, size_t count)
|
|||||||
while (*str != '\0' && ret < count) {
|
while (*str != '\0' && ret < count) {
|
||||||
ret++;
|
ret++;
|
||||||
str++;
|
str++;
|
||||||
count--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -149,8 +148,8 @@ void *sbi_memmove(void *dest, const void *src, size_t count)
|
|||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
temp1 = dest + count - 1;
|
temp1 = (char *)dest + count - 1;
|
||||||
temp2 = src + count - 1;
|
temp2 = (char *)src + count - 1;
|
||||||
|
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
*temp1-- = *temp2--;
|
*temp1-- = *temp2--;
|
||||||
|
@@ -44,11 +44,6 @@ static u64 get_ticks(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static u64 get_platform_ticks(void)
|
|
||||||
{
|
|
||||||
return timer_dev->timer_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nop_delay_fn(void *opaque)
|
static void nop_delay_fn(void *opaque)
|
||||||
{
|
{
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
@@ -81,6 +76,19 @@ void sbi_timer_delay_loop(ulong units, u64 unit_freq,
|
|||||||
delay_fn(opaque);
|
delay_fn(opaque);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sbi_timer_waitms_until(bool (*predicate)(void *), void *arg,
|
||||||
|
uint64_t timeout_ms)
|
||||||
|
{
|
||||||
|
uint64_t start_time = sbi_timer_value();
|
||||||
|
uint64_t ticks =
|
||||||
|
(sbi_timer_get_device()->timer_freq / 1000) *
|
||||||
|
timeout_ms;
|
||||||
|
while(!predicate(arg))
|
||||||
|
if (sbi_timer_value() - start_time >= ticks)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
u64 sbi_timer_value(void)
|
u64 sbi_timer_value(void)
|
||||||
{
|
{
|
||||||
if (get_time_val)
|
if (get_time_val)
|
||||||
@@ -124,16 +132,35 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
|
|||||||
void sbi_timer_event_start(u64 next_event)
|
void sbi_timer_event_start(u64 next_event)
|
||||||
{
|
{
|
||||||
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
|
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
|
||||||
if (timer_dev && timer_dev->timer_event_start)
|
|
||||||
|
/**
|
||||||
|
* Update the stimecmp directly if available. This allows
|
||||||
|
* the older software to leverage sstc extension on newer hardware.
|
||||||
|
*/
|
||||||
|
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC)) {
|
||||||
|
#if __riscv_xlen == 32
|
||||||
|
csr_write(CSR_STIMECMP, next_event & 0xFFFFFFFF);
|
||||||
|
csr_write(CSR_STIMECMPH, next_event >> 32);
|
||||||
|
#else
|
||||||
|
csr_write(CSR_STIMECMP, next_event);
|
||||||
|
#endif
|
||||||
|
} else if (timer_dev && timer_dev->timer_event_start) {
|
||||||
timer_dev->timer_event_start(next_event);
|
timer_dev->timer_event_start(next_event);
|
||||||
csr_clear(CSR_MIP, MIP_STIP);
|
csr_clear(CSR_MIP, MIP_STIP);
|
||||||
|
}
|
||||||
csr_set(CSR_MIE, MIP_MTIP);
|
csr_set(CSR_MIE, MIP_MTIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_timer_process(void)
|
void sbi_timer_process(void)
|
||||||
{
|
{
|
||||||
csr_clear(CSR_MIE, MIP_MTIP);
|
csr_clear(CSR_MIE, MIP_MTIP);
|
||||||
csr_set(CSR_MIP, MIP_STIP);
|
/*
|
||||||
|
* If sstc extension is available, supervisor can receive the timer
|
||||||
|
* directly without M-mode come in between. This function should
|
||||||
|
* only invoked if M-mode programs the timer for its own purpose.
|
||||||
|
*/
|
||||||
|
if (!sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC))
|
||||||
|
csr_set(CSR_MIP, MIP_STIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct sbi_timer_device *sbi_timer_get_device(void)
|
const struct sbi_timer_device *sbi_timer_get_device(void)
|
||||||
@@ -148,7 +175,7 @@ void sbi_timer_set_device(const struct sbi_timer_device *dev)
|
|||||||
|
|
||||||
timer_dev = dev;
|
timer_dev = dev;
|
||||||
if (!get_time_val && timer_dev->timer_value)
|
if (!get_time_val && timer_dev->timer_value)
|
||||||
get_time_val = get_platform_ticks;
|
get_time_val = timer_dev->timer_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||||
@@ -161,7 +188,7 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
|||||||
if (!time_delta_off)
|
if (!time_delta_off)
|
||||||
return SBI_ENOMEM;
|
return SBI_ENOMEM;
|
||||||
|
|
||||||
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
|
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_TIME))
|
||||||
get_time_val = get_ticks;
|
get_time_val = get_ticks;
|
||||||
} else {
|
} else {
|
||||||
if (!time_delta_off)
|
if (!time_delta_off)
|
||||||
|
@@ -9,12 +9,14 @@
|
|||||||
|
|
||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
#include <sbi/riscv_encoding.h>
|
#include <sbi/riscv_encoding.h>
|
||||||
|
#include <sbi/sbi_bitops.h>
|
||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
#include <sbi/sbi_ecall.h>
|
#include <sbi/sbi_ecall.h>
|
||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_hart.h>
|
#include <sbi/sbi_hart.h>
|
||||||
#include <sbi/sbi_illegal_insn.h>
|
#include <sbi/sbi_illegal_insn.h>
|
||||||
#include <sbi/sbi_ipi.h>
|
#include <sbi/sbi_ipi.h>
|
||||||
|
#include <sbi/sbi_irqchip.h>
|
||||||
#include <sbi/sbi_misaligned_ldst.h>
|
#include <sbi/sbi_misaligned_ldst.h>
|
||||||
#include <sbi/sbi_pmu.h>
|
#include <sbi/sbi_pmu.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
@@ -98,17 +100,14 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
|||||||
if (prev_mode != PRV_S && prev_mode != PRV_U)
|
if (prev_mode != PRV_S && prev_mode != PRV_U)
|
||||||
return SBI_ENOTSUPP;
|
return SBI_ENOTSUPP;
|
||||||
|
|
||||||
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
|
/* If exceptions came from VS/VU-mode, redirect to VS-mode if
|
||||||
|
* delegated in hedeleg
|
||||||
|
*/
|
||||||
if (misa_extension('H') && prev_virt) {
|
if (misa_extension('H') && prev_virt) {
|
||||||
switch (trap->cause) {
|
if ((trap->cause < __riscv_xlen) &&
|
||||||
case CAUSE_FETCH_PAGE_FAULT:
|
(csr_read(CSR_HEDELEG) & BIT(trap->cause))) {
|
||||||
case CAUSE_LOAD_PAGE_FAULT:
|
|
||||||
case CAUSE_STORE_PAGE_FAULT:
|
|
||||||
next_virt = TRUE;
|
next_virt = TRUE;
|
||||||
break;
|
}
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update MSTATUS MPV bits */
|
/* Update MSTATUS MPV bits */
|
||||||
@@ -120,14 +119,18 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
|||||||
regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
|
regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
|
/* Update hypervisor CSRs if going to HS-mode */
|
||||||
if (misa_extension('H') && prev_virt && !next_virt) {
|
if (misa_extension('H') && !next_virt) {
|
||||||
/* Update HSTATUS SPVP and SPV bits */
|
|
||||||
hstatus = csr_read(CSR_HSTATUS);
|
hstatus = csr_read(CSR_HSTATUS);
|
||||||
hstatus &= ~HSTATUS_SPVP;
|
if (prev_virt) {
|
||||||
hstatus |= (prev_mode == PRV_S) ? HSTATUS_SPVP : 0;
|
/* hstatus.SPVP is only updated if coming from VS/VU-mode */
|
||||||
|
hstatus &= ~HSTATUS_SPVP;
|
||||||
|
hstatus |= (prev_mode == PRV_S) ? HSTATUS_SPVP : 0;
|
||||||
|
}
|
||||||
hstatus &= ~HSTATUS_SPV;
|
hstatus &= ~HSTATUS_SPV;
|
||||||
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
|
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
|
||||||
|
hstatus &= ~HSTATUS_GVA;
|
||||||
|
hstatus |= (trap->gva) ? HSTATUS_GVA : 0;
|
||||||
csr_write(CSR_HSTATUS, hstatus);
|
csr_write(CSR_HSTATUS, hstatus);
|
||||||
csr_write(CSR_HTVAL, trap->tval2);
|
csr_write(CSR_HTVAL, trap->tval2);
|
||||||
csr_write(CSR_HTINST, trap->tinst);
|
csr_write(CSR_HTINST, trap->tinst);
|
||||||
@@ -195,6 +198,52 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
|
||||||
|
{
|
||||||
|
mcause &= ~(1UL << (__riscv_xlen - 1));
|
||||||
|
switch (mcause) {
|
||||||
|
case IRQ_M_TIMER:
|
||||||
|
sbi_timer_process();
|
||||||
|
break;
|
||||||
|
case IRQ_M_SOFT:
|
||||||
|
sbi_ipi_process();
|
||||||
|
break;
|
||||||
|
case IRQ_M_EXT:
|
||||||
|
return sbi_irqchip_process(regs);
|
||||||
|
default:
|
||||||
|
return SBI_ENOENT;
|
||||||
|
};
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
unsigned long mtopi;
|
||||||
|
|
||||||
|
while ((mtopi = csr_read(CSR_MTOPI))) {
|
||||||
|
mtopi = mtopi >> TOPI_IID_SHIFT;
|
||||||
|
switch (mtopi) {
|
||||||
|
case IRQ_M_TIMER:
|
||||||
|
sbi_timer_process();
|
||||||
|
break;
|
||||||
|
case IRQ_M_SOFT:
|
||||||
|
sbi_ipi_process();
|
||||||
|
break;
|
||||||
|
case IRQ_M_EXT:
|
||||||
|
rc = sbi_irqchip_process(regs);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SBI_ENOENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle trap/interrupt
|
* Handle trap/interrupt
|
||||||
*
|
*
|
||||||
@@ -225,18 +274,15 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mcause & (1UL << (__riscv_xlen - 1))) {
|
if (mcause & (1UL << (__riscv_xlen - 1))) {
|
||||||
mcause &= ~(1UL << (__riscv_xlen - 1));
|
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
|
||||||
switch (mcause) {
|
SBI_HART_EXT_SMAIA))
|
||||||
case IRQ_M_TIMER:
|
rc = sbi_trap_aia_irq(regs, mcause);
|
||||||
sbi_timer_process();
|
else
|
||||||
break;
|
rc = sbi_trap_nonaia_irq(regs, mcause);
|
||||||
case IRQ_M_SOFT:
|
if (rc) {
|
||||||
sbi_ipi_process();
|
msg = "unhandled local interrupt";
|
||||||
break;
|
|
||||||
default:
|
|
||||||
msg = "unhandled external interrupt";
|
|
||||||
goto trap_error;
|
goto trap_error;
|
||||||
};
|
}
|
||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,6 +316,8 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
|
|||||||
trap.tval = mtval;
|
trap.tval = mtval;
|
||||||
trap.tval2 = mtval2;
|
trap.tval2 = mtval2;
|
||||||
trap.tinst = mtinst;
|
trap.tinst = mtinst;
|
||||||
|
trap.gva = sbi_regs_gva(regs);
|
||||||
|
|
||||||
rc = sbi_trap_redirect(regs, &trap);
|
rc = sbi_trap_redirect(regs, &trap);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@@ -83,7 +83,7 @@ DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
|
|||||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
|
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
|
||||||
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
|
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
|
||||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
|
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
|
||||||
#else
|
#elif __riscv_xlen == 32
|
||||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
|
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
|
||||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
|
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
|
||||||
|
|
||||||
@@ -112,6 +112,8 @@ void sbi_store_u64(u64 *addr, u64 val,
|
|||||||
if (trap->cause)
|
if (trap->cause)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
# error "Unexpected __riscv_xlen"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
|
ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
|
||||||
@@ -147,15 +149,17 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
|
|||||||
switch (trap->cause) {
|
switch (trap->cause) {
|
||||||
case CAUSE_LOAD_ACCESS:
|
case CAUSE_LOAD_ACCESS:
|
||||||
trap->cause = CAUSE_FETCH_ACCESS;
|
trap->cause = CAUSE_FETCH_ACCESS;
|
||||||
trap->tval = mepc;
|
trap->tinst = 0UL;
|
||||||
break;
|
break;
|
||||||
case CAUSE_LOAD_PAGE_FAULT:
|
case CAUSE_LOAD_PAGE_FAULT:
|
||||||
trap->cause = CAUSE_FETCH_PAGE_FAULT;
|
trap->cause = CAUSE_FETCH_PAGE_FAULT;
|
||||||
trap->tval = mepc;
|
trap->tinst = 0UL;
|
||||||
break;
|
break;
|
||||||
case CAUSE_LOAD_GUEST_PAGE_FAULT:
|
case CAUSE_LOAD_GUEST_PAGE_FAULT:
|
||||||
trap->cause = CAUSE_FETCH_GUEST_PAGE_FAULT;
|
trap->cause = CAUSE_FETCH_GUEST_PAGE_FAULT;
|
||||||
trap->tval = mepc;
|
if (trap->tinst != INSN_PSEUDO_VS_LOAD &&
|
||||||
|
trap->tinst != INSN_PSEUDO_VS_STORE)
|
||||||
|
trap->tinst = 0UL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
25
lib/utils/Kconfig
Normal file
25
lib/utils/Kconfig
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
menu "Utils and Drivers Support"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/gpio/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/i2c/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/ipi/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/irqchip/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/libfdt/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/reset/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/serial/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/sys/Kconfig"
|
||||||
|
|
||||||
|
source "$(OPENSBI_SRC_DIR)/lib/utils/timer/Kconfig"
|
||||||
|
|
||||||
|
endmenu
|
18
lib/utils/fdt/Kconfig
Normal file
18
lib/utils/fdt/Kconfig
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
menuconfig FDT
|
||||||
|
bool "Flattened Device Tree (FDT) support"
|
||||||
|
select LIBFDT
|
||||||
|
default n
|
||||||
|
|
||||||
|
if FDT
|
||||||
|
|
||||||
|
config FDT_DOMAIN
|
||||||
|
bool "FDT domain support"
|
||||||
|
default n
|
||||||
|
|
||||||
|
config FDT_PMU
|
||||||
|
bool "FDT performance monitoring unit (PMU) support"
|
||||||
|
default n
|
||||||
|
|
||||||
|
endif
|
@@ -165,6 +165,9 @@ void fdt_domain_fixup(void *fdt)
|
|||||||
if (err)
|
if (err)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(fdt, doffset))
|
||||||
|
continue;
|
||||||
|
|
||||||
fdt_nop_property(fdt, doffset, "opensbi-domain");
|
fdt_nop_property(fdt, doffset, "opensbi-domain");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +246,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
|
|||||||
|
|
||||||
/* Read "base" DT property */
|
/* Read "base" DT property */
|
||||||
val = fdt_getprop(fdt, region_offset, "base", &len);
|
val = fdt_getprop(fdt, region_offset, "base", &len);
|
||||||
if (!val && len >= 8)
|
if (!val || len != 8)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
val64 = fdt32_to_cpu(val[0]);
|
val64 = fdt32_to_cpu(val[0]);
|
||||||
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
|
val64 = (val64 << 32) | fdt32_to_cpu(val[1]);
|
||||||
@@ -251,7 +254,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
|
|||||||
|
|
||||||
/* Read "order" DT property */
|
/* Read "order" DT property */
|
||||||
val = fdt_getprop(fdt, region_offset, "order", &len);
|
val = fdt_getprop(fdt, region_offset, "order", &len);
|
||||||
if (!val && len >= 4)
|
if (!val || len != 4)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
val32 = fdt32_to_cpu(*val);
|
val32 = fdt32_to_cpu(*val);
|
||||||
if (val32 < 3 || __riscv_xlen < val32)
|
if (val32 < 3 || __riscv_xlen < val32)
|
||||||
@@ -308,6 +311,9 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(fdt, cpu_offset))
|
||||||
|
continue;
|
||||||
|
|
||||||
sbi_hartmask_set_hart(val32, mask);
|
sbi_hartmask_set_hart(val32, mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,7 +353,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
|
|||||||
if (val && len >= 4) {
|
if (val && len >= 4) {
|
||||||
cpu_offset = fdt_node_offset_by_phandle(fdt,
|
cpu_offset = fdt_node_offset_by_phandle(fdt,
|
||||||
fdt32_to_cpu(*val));
|
fdt32_to_cpu(*val));
|
||||||
if (cpu_offset >= 0)
|
if (cpu_offset >= 0 && fdt_node_is_enabled(fdt, cpu_offset))
|
||||||
fdt_parse_hart_id(fdt, cpu_offset, &val32);
|
fdt_parse_hart_id(fdt, cpu_offset, &val32);
|
||||||
} else {
|
} else {
|
||||||
if (domain_offset == *cold_domain_offset)
|
if (domain_offset == *cold_domain_offset)
|
||||||
@@ -414,6 +420,9 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
|
|||||||
if (SBI_HARTMASK_MAX_BITS <= val32)
|
if (SBI_HARTMASK_MAX_BITS <= val32)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(fdt, cpu_offset))
|
||||||
|
continue;
|
||||||
|
|
||||||
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
|
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
|
||||||
if (!val || len < 4)
|
if (!val || len < 4)
|
||||||
return SBI_EINVAL;
|
return SBI_EINVAL;
|
||||||
@@ -460,6 +469,9 @@ int fdt_domains_populate(void *fdt)
|
|||||||
if (hartid != cold_hartid)
|
if (hartid != cold_hartid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(fdt, cpu_offset))
|
||||||
|
continue;
|
||||||
|
|
||||||
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
|
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
|
||||||
if (val && len >= 4)
|
if (val && len >= 4)
|
||||||
cold_domain_offset = fdt_node_offset_by_phandle(fdt,
|
cold_domain_offset = fdt_node_offset_by_phandle(fdt,
|
||||||
|
@@ -38,6 +38,9 @@ void fdt_cpu_fixup(void *fdt)
|
|||||||
if (err)
|
if (err)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(fdt, cpu_offset))
|
||||||
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable a HART DT node if one of the following is true:
|
* Disable a HART DT node if one of the following is true:
|
||||||
* 1. The HART is not assigned to the current domain
|
* 1. The HART is not assigned to the current domain
|
||||||
@@ -52,6 +55,44 @@ void fdt_cpu_fixup(void *fdt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint64_t reg_addr, reg_size;
|
||||||
|
struct sbi_domain *dom = sbi_domain_thishart_ptr();
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, ®_size);
|
||||||
|
if (rc < 0 || !reg_addr || !reg_size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
|
||||||
|
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
|
||||||
|
rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
|
||||||
|
if (rc < 0)
|
||||||
|
return;
|
||||||
|
fdt_setprop_string(fdt, nodeoff, "status", "disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fdt_fixup_node(void *fdt, const char *compatible)
|
||||||
|
{
|
||||||
|
int noff = 0;
|
||||||
|
|
||||||
|
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
|
||||||
|
compatible)) >= 0)
|
||||||
|
fdt_domain_based_fixup_one(fdt, noff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fdt_aplic_fixup(void *fdt)
|
||||||
|
{
|
||||||
|
fdt_fixup_node(fdt, "riscv,aplic");
|
||||||
|
}
|
||||||
|
|
||||||
|
void fdt_imsic_fixup(void *fdt)
|
||||||
|
{
|
||||||
|
fdt_fixup_node(fdt, "riscv,imsics");
|
||||||
|
}
|
||||||
|
|
||||||
void fdt_plic_fixup(void *fdt)
|
void fdt_plic_fixup(void *fdt)
|
||||||
{
|
{
|
||||||
u32 *cells;
|
u32 *cells;
|
||||||
@@ -261,10 +302,12 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
|
|||||||
|
|
||||||
void fdt_fixups(void *fdt)
|
void fdt_fixups(void *fdt)
|
||||||
{
|
{
|
||||||
|
fdt_aplic_fixup(fdt);
|
||||||
|
|
||||||
|
fdt_imsic_fixup(fdt);
|
||||||
|
|
||||||
fdt_plic_fixup(fdt);
|
fdt_plic_fixup(fdt);
|
||||||
|
|
||||||
fdt_reserved_memory_fixup(fdt);
|
fdt_reserved_memory_fixup(fdt);
|
||||||
fdt_pmu_fixup(fdt);
|
fdt_pmu_fixup(fdt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -13,19 +13,21 @@
|
|||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
#include <sbi_utils/fdt/fdt_helper.h>
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/irqchip/aplic.h>
|
||||||
|
#include <sbi_utils/irqchip/imsic.h>
|
||||||
#include <sbi_utils/irqchip/plic.h>
|
#include <sbi_utils/irqchip/plic.h>
|
||||||
|
|
||||||
#define DEFAULT_UART_FREQ 0
|
#define DEFAULT_UART_FREQ 0
|
||||||
#define DEFAULT_UART_BAUD 115200
|
#define DEFAULT_UART_BAUD 115200
|
||||||
#define DEFAULT_UART_REG_SHIFT 0
|
#define DEFAULT_UART_REG_SHIFT 0
|
||||||
#define DEFAULT_UART_REG_IO_WIDTH 1
|
#define DEFAULT_UART_REG_IO_WIDTH 1
|
||||||
|
#define DEFAULT_UART_REG_OFFSET 0
|
||||||
|
|
||||||
|
#define DEFAULT_RENESAS_SCIF_FREQ 100000000
|
||||||
|
#define DEFAULT_RENESAS_SCIF_BAUD 115200
|
||||||
|
|
||||||
#define DEFAULT_SIFIVE_UART_FREQ 0
|
#define DEFAULT_SIFIVE_UART_FREQ 0
|
||||||
#define DEFAULT_SIFIVE_UART_BAUD 115200
|
#define DEFAULT_SIFIVE_UART_BAUD 115200
|
||||||
#define DEFAULT_SIFIVE_UART_REG_SHIFT 0
|
|
||||||
#define DEFAULT_SIFIVE_UART_REG_IO_WIDTH 4
|
|
||||||
|
|
||||||
#define DEFAULT_GAISLER_UART_REG_IO_WIDTH 4
|
|
||||||
|
|
||||||
#define DEFAULT_SHAKTI_UART_FREQ 50000000
|
#define DEFAULT_SHAKTI_UART_FREQ 50000000
|
||||||
#define DEFAULT_SHAKTI_UART_BAUD 115200
|
#define DEFAULT_SHAKTI_UART_BAUD 115200
|
||||||
@@ -125,7 +127,7 @@ static int fdt_translate_address(void *fdt, uint64_t reg, int parent,
|
|||||||
int i, rlen;
|
int i, rlen;
|
||||||
int cell_addr, cell_size;
|
int cell_addr, cell_size;
|
||||||
const fdt32_t *ranges;
|
const fdt32_t *ranges;
|
||||||
uint64_t offset = 0, caddr = 0, paddr = 0, rsize = 0;
|
uint64_t offset, caddr = 0, paddr = 0, rsize = 0;
|
||||||
|
|
||||||
cell_addr = fdt_address_cells(fdt, parent);
|
cell_addr = fdt_address_cells(fdt, parent);
|
||||||
if (cell_addr < 1)
|
if (cell_addr < 1)
|
||||||
@@ -213,6 +215,24 @@ int fdt_get_node_addr_size(void *fdt, int node, int index,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool fdt_node_is_enabled(void *fdt, int nodeoff)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
const void *prop;
|
||||||
|
|
||||||
|
prop = fdt_getprop(fdt, nodeoff, "status", &len);
|
||||||
|
if (!prop)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!strncmp(prop, "okay", strlen("okay")))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!strncmp(prop, "ok", strlen("ok")))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
|
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@@ -241,7 +261,7 @@ int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
|
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid)
|
||||||
{
|
{
|
||||||
u32 hartid;
|
u32 hartid;
|
||||||
int err, cpu_offset, cpus_offset;
|
int err, cpu_offset, cpus_offset;
|
||||||
@@ -262,6 +282,9 @@ int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
|
|||||||
if (err)
|
if (err)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(fdt, cpu_offset))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (hartid > *max_hartid)
|
if (hartid > *max_hartid)
|
||||||
*max_hartid = hartid;
|
*max_hartid = hartid;
|
||||||
}
|
}
|
||||||
@@ -290,8 +313,10 @@ int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
|
static int fdt_parse_uart_node_common(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart)
|
struct platform_uart_data *uart,
|
||||||
|
unsigned long default_freq,
|
||||||
|
unsigned long default_baud)
|
||||||
{
|
{
|
||||||
int len, rc;
|
int len, rc;
|
||||||
const fdt32_t *val;
|
const fdt32_t *val;
|
||||||
@@ -314,126 +339,60 @@ int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
|
|||||||
if (len > 0 && val)
|
if (len > 0 && val)
|
||||||
uart->freq = fdt32_to_cpu(*val);
|
uart->freq = fdt32_to_cpu(*val);
|
||||||
else
|
else
|
||||||
uart->freq = DEFAULT_UART_FREQ;
|
uart->freq = default_freq;
|
||||||
|
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
|
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
|
||||||
if (len > 0 && val)
|
if (len > 0 && val)
|
||||||
uart->baud = fdt32_to_cpu(*val);
|
uart->baud = fdt32_to_cpu(*val);
|
||||||
else
|
else
|
||||||
uart->baud = DEFAULT_UART_BAUD;
|
uart->baud = default_baud;
|
||||||
|
|
||||||
/* For Gaisler APBUART, the reg-shift and reg-io-width are fixed .*/
|
|
||||||
uart->reg_shift = DEFAULT_UART_REG_SHIFT;
|
|
||||||
uart->reg_io_width = DEFAULT_GAISLER_UART_REG_IO_WIDTH;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fdt_parse_gaisler_uart_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart)
|
||||||
|
{
|
||||||
|
return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
|
||||||
|
DEFAULT_UART_FREQ,
|
||||||
|
DEFAULT_UART_BAUD);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_renesas_scif_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart)
|
||||||
|
{
|
||||||
|
return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
|
||||||
|
DEFAULT_RENESAS_SCIF_FREQ,
|
||||||
|
DEFAULT_RENESAS_SCIF_BAUD);
|
||||||
|
}
|
||||||
|
|
||||||
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart)
|
struct platform_uart_data *uart)
|
||||||
{
|
{
|
||||||
int len, rc;
|
return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
|
||||||
const fdt32_t *val;
|
DEFAULT_SHAKTI_UART_FREQ,
|
||||||
uint64_t reg_addr, reg_size;
|
DEFAULT_SHAKTI_UART_BAUD);
|
||||||
|
|
||||||
if (nodeoffset < 0 || !uart || !fdt)
|
|
||||||
return SBI_ENODEV;
|
|
||||||
|
|
||||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
|
|
||||||
®_addr, ®_size);
|
|
||||||
if (rc < 0 || !reg_addr || !reg_size)
|
|
||||||
return SBI_ENODEV;
|
|
||||||
uart->addr = reg_addr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UART address is mandaotry. clock-frequency and current-speed
|
|
||||||
* may not be present. Don't return error.
|
|
||||||
*/
|
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
|
|
||||||
if (len > 0 && val)
|
|
||||||
uart->freq = fdt32_to_cpu(*val);
|
|
||||||
else
|
|
||||||
uart->freq = DEFAULT_SHAKTI_UART_FREQ;
|
|
||||||
|
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
|
|
||||||
if (len > 0 && val)
|
|
||||||
uart->baud = fdt32_to_cpu(*val);
|
|
||||||
else
|
|
||||||
uart->baud = DEFAULT_SHAKTI_UART_BAUD;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart)
|
struct platform_uart_data *uart)
|
||||||
{
|
{
|
||||||
int len, rc;
|
return fdt_parse_uart_node_common(fdt, nodeoffset, uart,
|
||||||
const fdt32_t *val;
|
DEFAULT_SIFIVE_UART_FREQ,
|
||||||
uint64_t reg_addr, reg_size;
|
DEFAULT_SIFIVE_UART_BAUD);
|
||||||
|
|
||||||
if (nodeoffset < 0 || !uart || !fdt)
|
|
||||||
return SBI_ENODEV;
|
|
||||||
|
|
||||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
|
|
||||||
®_addr, ®_size);
|
|
||||||
if (rc < 0 || !reg_addr || !reg_size)
|
|
||||||
return SBI_ENODEV;
|
|
||||||
uart->addr = reg_addr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UART address is mandaotry. clock-frequency and current-speed
|
|
||||||
* may not be present. Don't return error.
|
|
||||||
*/
|
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
|
|
||||||
if (len > 0 && val)
|
|
||||||
uart->freq = fdt32_to_cpu(*val);
|
|
||||||
else
|
|
||||||
uart->freq = DEFAULT_SIFIVE_UART_FREQ;
|
|
||||||
|
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
|
|
||||||
if (len > 0 && val)
|
|
||||||
uart->baud = fdt32_to_cpu(*val);
|
|
||||||
else
|
|
||||||
uart->baud = DEFAULT_SIFIVE_UART_BAUD;
|
|
||||||
|
|
||||||
/* For SiFive UART, the reg-shift and reg-io-width are fixed .*/
|
|
||||||
uart->reg_shift = DEFAULT_SIFIVE_UART_REG_SHIFT;
|
|
||||||
uart->reg_io_width = DEFAULT_SIFIVE_UART_REG_IO_WIDTH;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
|
int fdt_parse_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart)
|
struct platform_uart_data *uart)
|
||||||
{
|
{
|
||||||
int len, rc;
|
int len, rc;
|
||||||
const fdt32_t *val;
|
const fdt32_t *val;
|
||||||
uint64_t reg_addr, reg_size;
|
|
||||||
|
|
||||||
if (nodeoffset < 0 || !uart || !fdt)
|
rc = fdt_parse_uart_node_common(fdt, nodeoffset, uart,
|
||||||
return SBI_ENODEV;
|
DEFAULT_UART_FREQ,
|
||||||
|
DEFAULT_UART_BAUD);
|
||||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
|
if (rc)
|
||||||
®_addr, ®_size);
|
return rc;
|
||||||
if (rc < 0 || !reg_addr || !reg_size)
|
|
||||||
return SBI_ENODEV;
|
|
||||||
uart->addr = reg_addr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UART address is mandaotry. clock-frequency and current-speed
|
|
||||||
* may not be present. Don't return error.
|
|
||||||
*/
|
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
|
|
||||||
if (len > 0 && val)
|
|
||||||
uart->freq = fdt32_to_cpu(*val);
|
|
||||||
else
|
|
||||||
uart->freq = DEFAULT_UART_FREQ;
|
|
||||||
|
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
|
|
||||||
if (len > 0 && val)
|
|
||||||
uart->baud = fdt32_to_cpu(*val);
|
|
||||||
else
|
|
||||||
uart->baud = DEFAULT_UART_BAUD;
|
|
||||||
|
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-shift", &len);
|
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-shift", &len);
|
||||||
if (len > 0 && val)
|
if (len > 0 && val)
|
||||||
@@ -447,6 +406,12 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
|
|||||||
else
|
else
|
||||||
uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
|
uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
|
||||||
|
|
||||||
|
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-offset", &len);
|
||||||
|
if (len > 0 && val)
|
||||||
|
uart->reg_offset = fdt32_to_cpu(*val);
|
||||||
|
else
|
||||||
|
uart->reg_offset = DEFAULT_UART_REG_OFFSET;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,7 +427,273 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
|||||||
if (nodeoffset < 0)
|
if (nodeoffset < 0)
|
||||||
return nodeoffset;
|
return nodeoffset;
|
||||||
|
|
||||||
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
|
return fdt_parse_uart_node(fdt, nodeoffset, uart);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart)
|
||||||
|
{
|
||||||
|
return fdt_parse_uart_node_common(fdt, nodeoffset, uart, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic)
|
||||||
|
{
|
||||||
|
bool child_found;
|
||||||
|
const fdt32_t *val;
|
||||||
|
const fdt32_t *del;
|
||||||
|
struct imsic_data imsic;
|
||||||
|
int i, j, d, dcnt, len, noff, rc;
|
||||||
|
uint64_t reg_addr, reg_size;
|
||||||
|
struct aplic_delegate_data *deleg;
|
||||||
|
|
||||||
|
if (nodeoff < 0 || !aplic || !fdt)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
memset(aplic, 0, sizeof(*aplic));
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, ®_addr, ®_size);
|
||||||
|
if (rc < 0 || !reg_addr || !reg_size)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
aplic->addr = reg_addr;
|
||||||
|
aplic->size = reg_size;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "riscv,num-sources", &len);
|
||||||
|
if (len > 0)
|
||||||
|
aplic->num_source = fdt32_to_cpu(*val);
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
|
||||||
|
if (val && len > sizeof(fdt32_t)) {
|
||||||
|
len = len / sizeof(fdt32_t);
|
||||||
|
for (i = 0; i < len; i += 2) {
|
||||||
|
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
|
||||||
|
aplic->targets_mmode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aplic->num_idc = len / 2;
|
||||||
|
goto aplic_msi_parent_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
|
||||||
|
if (val && len >= sizeof(fdt32_t)) {
|
||||||
|
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
|
||||||
|
if (noff < 0)
|
||||||
|
return noff;
|
||||||
|
|
||||||
|
rc = fdt_parse_imsic_node(fdt, noff, &imsic);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = imsic_data_check(&imsic);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
aplic->targets_mmode = imsic.targets_mmode;
|
||||||
|
|
||||||
|
if (imsic.targets_mmode) {
|
||||||
|
aplic->has_msicfg_mmode = true;
|
||||||
|
aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
|
||||||
|
aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
|
||||||
|
aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
|
||||||
|
aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
|
||||||
|
if (aplic->msicfg_mmode.hhxs <
|
||||||
|
(2 * IMSIC_MMIO_PAGE_SHIFT))
|
||||||
|
return SBI_EINVAL;
|
||||||
|
aplic->msicfg_mmode.hhxs -= 24;
|
||||||
|
aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
|
||||||
|
} else {
|
||||||
|
goto aplic_msi_parent_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
|
||||||
|
if (!val || len < sizeof(fdt32_t))
|
||||||
|
goto aplic_msi_parent_done;
|
||||||
|
|
||||||
|
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
|
||||||
|
if (noff < 0)
|
||||||
|
return noff;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, noff, "msi-parent", &len);
|
||||||
|
if (!val || len < sizeof(fdt32_t))
|
||||||
|
goto aplic_msi_parent_done;
|
||||||
|
|
||||||
|
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
|
||||||
|
if (noff < 0)
|
||||||
|
return noff;
|
||||||
|
|
||||||
|
rc = fdt_parse_imsic_node(fdt, noff, &imsic);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = imsic_data_check(&imsic);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (!imsic.targets_mmode) {
|
||||||
|
aplic->has_msicfg_smode = true;
|
||||||
|
aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
|
||||||
|
aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
|
||||||
|
aplic->msicfg_smode.hhxw = imsic.group_index_bits;
|
||||||
|
aplic->msicfg_smode.hhxs = imsic.group_index_shift;
|
||||||
|
if (aplic->msicfg_smode.hhxs <
|
||||||
|
(2 * IMSIC_MMIO_PAGE_SHIFT))
|
||||||
|
return SBI_EINVAL;
|
||||||
|
aplic->msicfg_smode.hhxs -= 24;
|
||||||
|
aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aplic_msi_parent_done:
|
||||||
|
|
||||||
|
for (d = 0; d < APLIC_MAX_DELEGATE; d++) {
|
||||||
|
deleg = &aplic->delegate[d];
|
||||||
|
deleg->first_irq = 0;
|
||||||
|
deleg->last_irq = 0;
|
||||||
|
deleg->child_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
del = fdt_getprop(fdt, nodeoff, "riscv,delegate", &len);
|
||||||
|
if (!del || len < (3 * sizeof(fdt32_t)))
|
||||||
|
goto skip_delegate_parse;
|
||||||
|
d = 0;
|
||||||
|
dcnt = len / sizeof(fdt32_t);
|
||||||
|
for (i = 0; i < dcnt; i += 3) {
|
||||||
|
if (d >= APLIC_MAX_DELEGATE)
|
||||||
|
break;
|
||||||
|
deleg = &aplic->delegate[d];
|
||||||
|
|
||||||
|
deleg->first_irq = fdt32_to_cpu(del[i + 1]);
|
||||||
|
deleg->last_irq = fdt32_to_cpu(del[i + 2]);
|
||||||
|
deleg->child_index = 0;
|
||||||
|
|
||||||
|
child_found = false;
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
|
||||||
|
if (!val || len < sizeof(fdt32_t)) {
|
||||||
|
deleg->first_irq = 0;
|
||||||
|
deleg->last_irq = 0;
|
||||||
|
deleg->child_index = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
len = len / sizeof(fdt32_t);
|
||||||
|
for (j = 0; j < len; j++) {
|
||||||
|
if (del[i] != val[j])
|
||||||
|
continue;
|
||||||
|
deleg->child_index = j;
|
||||||
|
child_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child_found) {
|
||||||
|
d++;
|
||||||
|
} else {
|
||||||
|
deleg->first_irq = 0;
|
||||||
|
deleg->last_irq = 0;
|
||||||
|
deleg->child_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
skip_delegate_parse:
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fdt_check_imsic_mlevel(void *fdt)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
int i, len, noff = 0;
|
||||||
|
|
||||||
|
if (!fdt)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
|
||||||
|
"riscv,imsics")) >= 0) {
|
||||||
|
val = fdt_getprop(fdt, noff, "interrupts-extended", &len);
|
||||||
|
if (val && len > sizeof(fdt32_t)) {
|
||||||
|
len = len / sizeof(fdt32_t);
|
||||||
|
for (i = 0; i < len; i += 2) {
|
||||||
|
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
struct imsic_regs *regs;
|
||||||
|
uint64_t reg_addr, reg_size;
|
||||||
|
int i, rc, len, nr_parent_irqs;
|
||||||
|
|
||||||
|
if (nodeoff < 0 || !imsic || !fdt)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
imsic->targets_mmode = false;
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
|
||||||
|
if (val && len > sizeof(fdt32_t)) {
|
||||||
|
len = len / sizeof(fdt32_t);
|
||||||
|
nr_parent_irqs = len / 2;
|
||||||
|
for (i = 0; i < len; i += 2) {
|
||||||
|
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
|
||||||
|
imsic->targets_mmode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "riscv,guest-index-bits", &len);
|
||||||
|
if (val && len > 0)
|
||||||
|
imsic->guest_index_bits = fdt32_to_cpu(*val);
|
||||||
|
else
|
||||||
|
imsic->guest_index_bits = 0;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "riscv,hart-index-bits", &len);
|
||||||
|
if (val && len > 0) {
|
||||||
|
imsic->hart_index_bits = fdt32_to_cpu(*val);
|
||||||
|
} else {
|
||||||
|
imsic->hart_index_bits = sbi_fls(nr_parent_irqs);
|
||||||
|
if ((1UL << imsic->hart_index_bits) < nr_parent_irqs)
|
||||||
|
imsic->hart_index_bits++;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "riscv,group-index-bits", &len);
|
||||||
|
if (val && len > 0)
|
||||||
|
imsic->group_index_bits = fdt32_to_cpu(*val);
|
||||||
|
else
|
||||||
|
imsic->group_index_bits = 0;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "riscv,group-index-shift", &len);
|
||||||
|
if (val && len > 0)
|
||||||
|
imsic->group_index_shift = fdt32_to_cpu(*val);
|
||||||
|
else
|
||||||
|
imsic->group_index_shift = 2 * IMSIC_MMIO_PAGE_SHIFT;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "riscv,num-ids", &len);
|
||||||
|
if (val && len > 0)
|
||||||
|
imsic->num_ids = fdt32_to_cpu(*val);
|
||||||
|
else
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < IMSIC_MAX_REGS; i++) {
|
||||||
|
regs = &imsic->regs[i];
|
||||||
|
regs->addr = 0;
|
||||||
|
regs->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (IMSIC_MAX_REGS - 1); i++) {
|
||||||
|
regs = &imsic->regs[i];
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoff, i,
|
||||||
|
®_addr, ®_size);
|
||||||
|
if (rc < 0 || !reg_addr || !reg_size)
|
||||||
|
break;
|
||||||
|
regs->addr = reg_addr;
|
||||||
|
regs->size = reg_size;
|
||||||
|
};
|
||||||
|
if (!imsic->regs[0].size)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
|
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
|
||||||
@@ -552,7 +783,7 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
|
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
|
||||||
if (cpu_intc_offset < 0)
|
if (cpu_offset < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
@@ -580,6 +811,118 @@ int fdt_parse_aclint_node(void *fdt, int nodeoffset, bool for_timer,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fdt_parse_plmt_node(void *fdt, int nodeoffset, unsigned long *plmt_base,
|
||||||
|
unsigned long *plmt_size, u32 *hart_count)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
int rc, i, count;
|
||||||
|
uint64_t reg_addr, reg_size;
|
||||||
|
u32 phandle, hwirq, hartid, hcount;
|
||||||
|
|
||||||
|
if (nodeoffset < 0 || !fdt || !plmt_base ||
|
||||||
|
!hart_count || !plmt_size)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
|
||||||
|
®_addr, ®_size);
|
||||||
|
if (rc < 0)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
*plmt_base = reg_addr;
|
||||||
|
*plmt_size = reg_size;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
|
||||||
|
if (!val || count < sizeof(fdt32_t))
|
||||||
|
return 0;
|
||||||
|
count = count / sizeof(fdt32_t);
|
||||||
|
|
||||||
|
hcount = 0;
|
||||||
|
for (i = 0; i < (count / 2); i++) {
|
||||||
|
int cpu_offset, cpu_intc_offset;
|
||||||
|
|
||||||
|
phandle = fdt32_to_cpu(val[2 * i]);
|
||||||
|
hwirq = fdt32_to_cpu(val[2 * i + 1]);
|
||||||
|
|
||||||
|
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
|
||||||
|
if (cpu_intc_offset < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
|
||||||
|
if (cpu_offset < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SBI_HARTMASK_MAX_BITS <= hartid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (hwirq == IRQ_M_TIMER)
|
||||||
|
hcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*hart_count = hcount;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_plicsw_node(void *fdt, int nodeoffset, unsigned long *plicsw_base,
|
||||||
|
unsigned long *size, u32 *hart_count)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
int rc, i, count;
|
||||||
|
uint64_t reg_addr, reg_size;
|
||||||
|
u32 phandle, hwirq, hartid, hcount;
|
||||||
|
|
||||||
|
if (nodeoffset < 0 || !fdt || !plicsw_base ||
|
||||||
|
!hart_count || !size)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
|
||||||
|
®_addr, ®_size);
|
||||||
|
if (rc < 0)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
*plicsw_base = reg_addr;
|
||||||
|
*size = reg_size;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
|
||||||
|
if (!val || count < sizeof(fdt32_t))
|
||||||
|
return 0;
|
||||||
|
count = count / sizeof(fdt32_t);
|
||||||
|
|
||||||
|
hcount = 0;
|
||||||
|
for (i = 0; i < (count / 2); i++) {
|
||||||
|
int cpu_offset, cpu_intc_offset;
|
||||||
|
|
||||||
|
phandle = fdt32_to_cpu(val[2 * i]);
|
||||||
|
hwirq = fdt32_to_cpu(val[2 * i + 1]);
|
||||||
|
|
||||||
|
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
|
||||||
|
if (cpu_intc_offset < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
|
||||||
|
if (cpu_offset < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SBI_HARTMASK_MAX_BITS <= hartid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (hwirq == IRQ_M_SOFT)
|
||||||
|
hcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*hart_count = hcount;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
|
int fdt_parse_compat_addr(void *fdt, uint64_t *addr,
|
||||||
const char *compatible)
|
const char *compatible)
|
||||||
{
|
{
|
||||||
|
@@ -53,7 +53,7 @@ int fdt_pmu_fixup(void *fdt)
|
|||||||
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmcounters");
|
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmcounters");
|
||||||
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmevent");
|
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmevent");
|
||||||
fdt_delprop(fdt, pmu_offset, "riscv,raw-event-to-mhpmcounters");
|
fdt_delprop(fdt, pmu_offset, "riscv,raw-event-to-mhpmcounters");
|
||||||
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
|
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
|
||||||
fdt_delprop(fdt, pmu_offset, "interrupts-extended");
|
fdt_delprop(fdt, pmu_offset, "interrupts-extended");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -75,42 +75,52 @@ int fdt_pmu_setup(void *fdt)
|
|||||||
if (pmu_offset < 0)
|
if (pmu_offset < 0)
|
||||||
return SBI_EFAIL;
|
return SBI_EFAIL;
|
||||||
|
|
||||||
event_ctr_map = fdt_getprop(fdt, pmu_offset, "riscv,event-to-mhpmcounters", &len);
|
event_ctr_map = fdt_getprop(fdt, pmu_offset,
|
||||||
if (!event_ctr_map || len < 8)
|
"riscv,event-to-mhpmcounters", &len);
|
||||||
return SBI_EFAIL;
|
if (event_ctr_map && len >= 8) {
|
||||||
len = len / (sizeof(u32) * 3);
|
len = len / (sizeof(u32) * 3);
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
event_idx_start = fdt32_to_cpu(event_ctr_map[3 * i]);
|
event_idx_start = fdt32_to_cpu(event_ctr_map[3 * i]);
|
||||||
event_idx_end = fdt32_to_cpu(event_ctr_map[3 * i + 1]);
|
event_idx_end = fdt32_to_cpu(event_ctr_map[3 * i + 1]);
|
||||||
ctr_map = fdt32_to_cpu(event_ctr_map[3 * i + 2]);
|
ctr_map = fdt32_to_cpu(event_ctr_map[3 * i + 2]);
|
||||||
sbi_pmu_add_hw_event_counter_map(event_idx_start, event_idx_end, ctr_map);
|
result = sbi_pmu_add_hw_event_counter_map(
|
||||||
|
event_idx_start, event_idx_end, ctr_map);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event_val = fdt_getprop(fdt, pmu_offset, "riscv,event-to-mhpmevent", &len);
|
event_val = fdt_getprop(fdt, pmu_offset,
|
||||||
if (!event_val || len < 8)
|
"riscv,event-to-mhpmevent", &len);
|
||||||
return SBI_EFAIL;
|
if (event_val && len >= 8) {
|
||||||
len = len / (sizeof(u32) * 3);
|
len = len / (sizeof(u32) * 3);
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
event = &fdt_pmu_evt_select[hw_event_count];
|
event = &fdt_pmu_evt_select[hw_event_count];
|
||||||
event->eidx = fdt32_to_cpu(event_val[3 * i]);
|
event->eidx = fdt32_to_cpu(event_val[3 * i]);
|
||||||
event->select = fdt32_to_cpu(event_val[3 * i + 1]);
|
event->select = fdt32_to_cpu(event_val[3 * i + 1]);
|
||||||
event->select = (event->select << 32) | fdt32_to_cpu(event_val[3 * i + 2]);
|
event->select = (event->select << 32) |
|
||||||
hw_event_count++;
|
fdt32_to_cpu(event_val[3 * i + 2]);
|
||||||
}
|
|
||||||
|
|
||||||
event_val = fdt_getprop(fdt, pmu_offset, "riscv,raw-event-to-mhpmcounters", &len);
|
|
||||||
if (!event_val || len < 20)
|
|
||||||
return SBI_EFAIL;
|
|
||||||
len = len / (sizeof(u32) * 5);
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
raw_selector = fdt32_to_cpu(event_val[5 * i]);
|
|
||||||
raw_selector = (raw_selector << 32) | fdt32_to_cpu(event_val[5 * i + 1]);
|
|
||||||
select_mask = fdt32_to_cpu(event_val[5 * i + 2]);
|
|
||||||
select_mask = (select_mask << 32) | fdt32_to_cpu(event_val[5 * i + 3]);
|
|
||||||
ctr_map = fdt32_to_cpu(event_val[5 * i + 4]);
|
|
||||||
result = sbi_pmu_add_raw_event_counter_map(raw_selector, select_mask, ctr_map);
|
|
||||||
if (!result)
|
|
||||||
hw_event_count++;
|
hw_event_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event_val = fdt_getprop(fdt, pmu_offset,
|
||||||
|
"riscv,raw-event-to-mhpmcounters", &len);
|
||||||
|
if (event_val && len >= 20) {
|
||||||
|
len = len / (sizeof(u32) * 5);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
raw_selector = fdt32_to_cpu(event_val[5 * i]);
|
||||||
|
raw_selector = (raw_selector << 32) |
|
||||||
|
fdt32_to_cpu(event_val[5 * i + 1]);
|
||||||
|
select_mask = fdt32_to_cpu(event_val[5 * i + 2]);
|
||||||
|
select_mask = (select_mask << 32) |
|
||||||
|
fdt32_to_cpu(event_val[5 * i + 3]);
|
||||||
|
ctr_map = fdt32_to_cpu(event_val[5 * i + 4]);
|
||||||
|
result = sbi_pmu_add_raw_event_counter_map(
|
||||||
|
raw_selector, select_mask, ctr_map);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
# Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
|
# Copyright (C) 2020 Bin Meng <bmeng.cn@gmail.com>
|
||||||
#
|
#
|
||||||
|
|
||||||
libsbiutils-objs-y += fdt/fdt_domain.o
|
libsbiutils-objs-$(CONFIG_FDT_DOMAIN) += fdt/fdt_domain.o
|
||||||
libsbiutils-objs-y += fdt/fdt_pmu.o
|
libsbiutils-objs-$(CONFIG_FDT_PMU) += fdt/fdt_pmu.o
|
||||||
libsbiutils-objs-y += fdt/fdt_helper.o
|
libsbiutils-objs-$(CONFIG_FDT) += fdt/fdt_helper.o
|
||||||
libsbiutils-objs-y += fdt/fdt_fixup.o
|
libsbiutils-objs-$(CONFIG_FDT) += fdt/fdt_fixup.o
|
||||||
|
23
lib/utils/gpio/Kconfig
Normal file
23
lib/utils/gpio/Kconfig
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
menu "GPIO Support"
|
||||||
|
|
||||||
|
config FDT_GPIO
|
||||||
|
bool "FDT based GPIO drivers"
|
||||||
|
depends on FDT
|
||||||
|
select GPIO
|
||||||
|
default n
|
||||||
|
|
||||||
|
if FDT_GPIO
|
||||||
|
|
||||||
|
config FDT_GPIO_SIFIVE
|
||||||
|
bool "SiFive GPIO FDT driver"
|
||||||
|
default n
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
config GPIO
|
||||||
|
bool "GPIO support"
|
||||||
|
default n
|
||||||
|
|
||||||
|
endmenu
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user