mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 15:31:22 +01:00
Compare commits
89 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a98258d0b5 | ||
![]() |
2314101989 | ||
![]() |
9bd5f8f17d | ||
![]() |
db56ef367c | ||
![]() |
637b348224 | ||
![]() |
d5725c24c6 | ||
![]() |
518e85cccb | ||
![]() |
6966ad0abe | ||
![]() |
e2c3f01af4 | ||
![]() |
32f87e5a86 | ||
![]() |
980290651f | ||
![]() |
106b888e20 | ||
![]() |
79bfd67f9a | ||
![]() |
1b8c0128f1 | ||
![]() |
51f0e4a053 | ||
![]() |
72019ee202 | ||
![]() |
4e3876d5be | ||
![]() |
c6c65ee861 | ||
![]() |
86ec5341e4 | ||
![]() |
4ce6b7a82a | ||
![]() |
64f140830d | ||
![]() |
30b60401e1 | ||
![]() |
a63f05f3de | ||
![]() |
6956e83a94 | ||
![]() |
569dd64b72 | ||
![]() |
a9a9751185 | ||
![]() |
d30bb68448 | ||
![]() |
2c685c214f | ||
![]() |
446a9c6d1e | ||
![]() |
73d6ef3b29 | ||
![]() |
89ba63493c | ||
![]() |
a38bea9341 | ||
![]() |
2966510eed | ||
![]() |
63b0f5f71a | ||
![]() |
3a8fc81357 | ||
![]() |
3aa1036f91 | ||
![]() |
49841832b8 | ||
![]() |
28b4052849 | ||
![]() |
38a4b54cdc | ||
![]() |
36833abfbb | ||
![]() |
22c4334f5c | ||
![]() |
1f235ec47f | ||
![]() |
ec0d2a7d7d | ||
![]() |
4938024420 | ||
![]() |
b2df751acf | ||
![]() |
6a053f6e6c | ||
![]() |
79d0fadb06 | ||
![]() |
13ca20d8df | ||
![]() |
aef9a60d52 | ||
![]() |
63a513edec | ||
![]() |
7be75f519f | ||
![]() |
c2286b6f04 | ||
![]() |
dfd9dd67dc | ||
![]() |
b4efa70d12 | ||
![]() |
433bac7242 | ||
![]() |
dc38929dfb | ||
![]() |
5338679ff0 | ||
![]() |
7993ca2c8e | ||
![]() |
d626037258 | ||
![]() |
65c06b026d | ||
![]() |
13717a8e53 | ||
![]() |
4f18c6e550 | ||
![]() |
2ba7087b09 | ||
![]() |
1f21b99ff0 | ||
![]() |
f1aa9e54e0 | ||
![]() |
4d063538f0 | ||
![]() |
7cc6fa4d8a | ||
![]() |
76a89403c8 | ||
![]() |
75322a634b | ||
![]() |
76f0f81407 | ||
![]() |
8ff2b94ea1 | ||
![]() |
1ac794cb61 | ||
![]() |
f0eb503db4 | ||
![]() |
44dd7be3b2 | ||
![]() |
19e966b862 | ||
![]() |
66185b3ec9 | ||
![]() |
dd33b9e0a1 | ||
![]() |
a39cd6fe4c | ||
![]() |
e3ad7c13a0 | ||
![]() |
243b0d0c0c | ||
![]() |
0a0093b0bc | ||
![]() |
01a8c8eebb | ||
![]() |
e6c1345f89 | ||
![]() |
5bdf022d07 | ||
![]() |
3a326af9be | ||
![]() |
4781545512 | ||
![]() |
6585fabbcc | ||
![]() |
a9eac67ad0 | ||
![]() |
1bb00ab3ae |
29
Makefile
29
Makefile
@@ -130,7 +130,6 @@ 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))
|
libsbiutils-objs-path-y=$(foreach obj,$(libsbiutils-objs-y),$(build_dir)/lib/utils/$(obj))
|
||||||
ifdef PLATFORM
|
ifdef PLATFORM
|
||||||
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))
|
||||||
platform-dtb-path-y=$(foreach obj,$(platform-dtb-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
|
||||||
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
|
firmware-elfs-path-y=$(firmware-bins-path-y:.bin=.elf)
|
||||||
@@ -227,7 +226,7 @@ MERGEFLAGS += -r
|
|||||||
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
|
MERGEFLAGS += -b elf$(PLATFORM_RISCV_XLEN)-littleriscv
|
||||||
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
|
MERGEFLAGS += -m elf$(PLATFORM_RISCV_XLEN)lriscv
|
||||||
|
|
||||||
DTCFLAGS = -O dtb
|
DTSCPPFLAGS = $(CPPFLAGS) -nostdinc -nostdlib -fno-builtin -D__DTS__ -x assembler-with-cpp
|
||||||
|
|
||||||
# Setup functions for compilation
|
# Setup functions for compilation
|
||||||
define dynamic_flags
|
define dynamic_flags
|
||||||
@@ -289,13 +288,18 @@ compile_objcopy = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
|||||||
$(OBJCOPY) -S -O binary $(2) $(1)
|
$(OBJCOPY) -S -O binary $(2) $(1)
|
||||||
compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
compile_dts = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
echo " DTC $(subst $(build_dir)/,,$(1))"; \
|
echo " DTC $(subst $(build_dir)/,,$(1))"; \
|
||||||
$(DTC) $(DTCFLAGS) -o $(1) $(2)
|
$(CPP) $(DTSCPPFLAGS) $(2) | $(DTC) -O dtb -i `dirname $(2)` -o $(1)
|
||||||
|
compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
|
echo " D2C $(subst $(build_dir)/,,$(1))"; \
|
||||||
|
$(src_dir)/scripts/d2c.sh -i $(4) -a $(3) -p $(2) > $(1)
|
||||||
|
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
|
||||||
|
echo " GEN-DEP $(subst $(build_dir)/,,$(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
|
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
|
||||||
targets-y += $(platform-dtb-path-y)
|
|
||||||
endif
|
endif
|
||||||
targets-y += $(firmware-bins-path-y)
|
targets-y += $(firmware-bins-path-y)
|
||||||
|
|
||||||
@@ -342,12 +346,26 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
|
|||||||
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
|
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
|
||||||
$(call compile_cc,$@,$<)
|
$(call compile_cc,$@,$<)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
|
||||||
|
$(call compile_cc,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
|
||||||
$(call compile_as_dep,$@,$<)
|
$(call compile_as_dep,$@,$<)
|
||||||
|
|
||||||
$(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
|
||||||
|
$(call compile_gen_dep,$@,.dtb,$<)
|
||||||
|
$(call compile_gen_dep,$@,.c,$(@:.dep=.dtb))
|
||||||
|
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.c: $(platform_build_dir)/%.dtb
|
||||||
|
$(call compile_d2c,$@,$(platform-varprefix-$(subst .dtb,.o,$(subst /,-,$(subst $(platform_build_dir)/,,$<)))),16,$<)
|
||||||
|
|
||||||
|
$(platform_build_dir)/%.dtb: $(platform_src_dir)/%.dts
|
||||||
|
$(call compile_dts,$@,$<)
|
||||||
|
|
||||||
$(platform_build_dir)/%.dep: $(src_dir)/%.c
|
$(platform_build_dir)/%.dep: $(src_dir)/%.c
|
||||||
$(call compile_cc_dep,$@,$<)
|
$(call compile_cc_dep,$@,$<)
|
||||||
|
|
||||||
@@ -360,9 +378,6 @@ $(platform_build_dir)/%.dep: $(src_dir)/%.S
|
|||||||
$(platform_build_dir)/%.o: $(src_dir)/%.S
|
$(platform_build_dir)/%.o: $(src_dir)/%.S
|
||||||
$(call compile_as,$@,$<)
|
$(call compile_as,$@,$<)
|
||||||
|
|
||||||
$(build_dir)/%.dtb: $(src_dir)/%.dts
|
|
||||||
$(call compile_dts,$@,$<)
|
|
||||||
|
|
||||||
# Rule for "make docs"
|
# Rule for "make docs"
|
||||||
$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex
|
$(build_dir)/docs/latex/refman.pdf: $(build_dir)/docs/latex/refman.tex
|
||||||
$(CMD_PREFIX)mkdir -p $(build_dir)/docs
|
$(CMD_PREFIX)mkdir -p $(build_dir)/docs
|
||||||
|
71
README.md
71
README.md
@@ -1,9 +1,41 @@
|
|||||||
Copyright (c) 2019 Western Digital Corporation or its affiliates
|
|
||||||
and other contributors.
|
|
||||||
|
|
||||||
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
|
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
|
||||||
========================================================
|
========================================================
|
||||||
|
|
||||||
|
Copyright and License
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The OpenSBI project is copyright (c) 2019 Western Digital Corporation
|
||||||
|
or its affiliates and other contributors.
|
||||||
|
|
||||||
|
It is distributed under the terms of the BSD 2-clause license
|
||||||
|
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
|
||||||
|
A copy of this license with OpenSBI copyright can be found in the file
|
||||||
|
[COPYING.BSD].
|
||||||
|
|
||||||
|
All source files in OpenSBI contain the 2-Clause BSD license SPDX short
|
||||||
|
identifier in place of the full license text.
|
||||||
|
|
||||||
|
```
|
||||||
|
SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
```
|
||||||
|
|
||||||
|
This enables machine processing of license information based on the SPDX
|
||||||
|
License Identifiers that are available on the [SPDX] web site.
|
||||||
|
|
||||||
|
OpenSBI source code also contains code reused from other projects as listed
|
||||||
|
below. The original license text of these projects is included in the source
|
||||||
|
files where the reused code is present.
|
||||||
|
|
||||||
|
* The libfdt source code is disjunctively dual licensed
|
||||||
|
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
|
||||||
|
under the terms of the BSD 2-Clause license. Any contributions to this
|
||||||
|
code must be made under the terms of both licenses.
|
||||||
|
|
||||||
|
See also the [third party notices] file for more information.
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
|
The **RISC-V Supervisor Binary Interface (SBI)** is the recommended interface
|
||||||
between:
|
between:
|
||||||
|
|
||||||
@@ -115,7 +147,7 @@ line, the platform-specific static library *libplatsbi.a* and firmware examples
|
|||||||
are built for the platform *<platform_subdir>* present in the directory
|
are built for the platform *<platform_subdir>* present in the directory
|
||||||
*platform* in the OpenSBI top directory. For example, to compile the platform
|
*platform* in the OpenSBI top directory. For example, to compile the platform
|
||||||
library and the firmware examples for the QEMU RISC-V *virt* machine,
|
library and the firmware examples for the QEMU RISC-V *virt* machine,
|
||||||
*<platform_subdir>* should be *qemu/virt*.
|
*<platform_subdir>* should be *generic*.
|
||||||
|
|
||||||
To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
|
To build *libsbi.a*, *libplatsbi.a* and the firmware for one of the supported
|
||||||
platforms, run:
|
platforms, run:
|
||||||
@@ -171,35 +203,6 @@ export PLATFORM_RISCV_XLEN=32
|
|||||||
|
|
||||||
will generate 32-bit OpenSBI images. And vice vesa.
|
will generate 32-bit OpenSBI images. And vice vesa.
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
|
|
||||||
OpenSBI is distributed under the terms of the BSD 2-clause license
|
|
||||||
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).
|
|
||||||
A copy of this license with OpenSBI copyright can be found in the file
|
|
||||||
[COPYING.BSD].
|
|
||||||
|
|
||||||
All source files in OpenSBI contain the 2-Clause BSD license SPDX short
|
|
||||||
identifier in place of the full license text.
|
|
||||||
|
|
||||||
```
|
|
||||||
SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
```
|
|
||||||
|
|
||||||
This enables machine processing of license information based on the SPDX
|
|
||||||
License Identifiers that are available on the [SPDX] web site.
|
|
||||||
|
|
||||||
OpenSBI source code also contains code reused from other projects as listed
|
|
||||||
below. The original license text of these projects is included in the source
|
|
||||||
files where the reused code is present.
|
|
||||||
|
|
||||||
* The libfdt source code is disjunctively dual licensed
|
|
||||||
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
|
|
||||||
under the terms of the BSD 2-Clause license. Any contributions to this
|
|
||||||
code must be made under the terms of both licenses.
|
|
||||||
|
|
||||||
See also the [third party notices] file for more information.
|
|
||||||
|
|
||||||
Contributing to OpenSBI
|
Contributing to OpenSBI
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
@@ -218,6 +221,7 @@ Detailed documentation of various aspects of OpenSBI can be found under the
|
|||||||
|
|
||||||
* [Contribution Guideline]: Guideline for contributing code to OpenSBI project
|
* [Contribution Guideline]: Guideline for contributing code to OpenSBI project
|
||||||
* [Library Usage]: API documentation of OpenSBI static library *libsbi.a*
|
* [Library Usage]: API documentation of OpenSBI static library *libsbi.a*
|
||||||
|
* [Platform Requirements]: Requirements for using OpenSBI on a platform
|
||||||
* [Platform Support Guide]: Guideline for implementing support for new platforms
|
* [Platform Support Guide]: Guideline for implementing support for new platforms
|
||||||
* [Platform Documentation]: Documentation of the platforms currently supported.
|
* [Platform Documentation]: Documentation of the platforms currently supported.
|
||||||
* [Firmware Documentation]: Documentation for the different types of firmware
|
* [Firmware Documentation]: Documentation for the different types of firmware
|
||||||
@@ -270,6 +274,7 @@ make I=<install_directory> install_docs
|
|||||||
[Contribution Guideline]: docs/contributing.md
|
[Contribution Guideline]: docs/contributing.md
|
||||||
[Contributors List]: CONTRIBUTORS.md
|
[Contributors List]: CONTRIBUTORS.md
|
||||||
[Library Usage]: docs/library_usage.md
|
[Library Usage]: docs/library_usage.md
|
||||||
|
[Platform Requirements]: docs/platform_requirements.md
|
||||||
[Platform Support Guide]: docs/platform_guide.md
|
[Platform Support Guide]: docs/platform_guide.md
|
||||||
[Platform Documentation]: docs/platform/platform.md
|
[Platform Documentation]: docs/platform/platform.md
|
||||||
[Firmware Documentation]: docs/firmware/fw.md
|
[Firmware Documentation]: docs/firmware/fw.md
|
||||||
|
@@ -793,6 +793,7 @@ WARN_LOGFILE =
|
|||||||
INPUT = @@SRC_DIR@@/README.md \
|
INPUT = @@SRC_DIR@@/README.md \
|
||||||
@@SRC_DIR@@/docs/contributing.md \
|
@@SRC_DIR@@/docs/contributing.md \
|
||||||
@@SRC_DIR@@/docs/platform_guide.md \
|
@@SRC_DIR@@/docs/platform_guide.md \
|
||||||
|
@@SRC_DIR@@/docs/platform_requirements.md \
|
||||||
@@SRC_DIR@@/docs/library_usage.md \
|
@@SRC_DIR@@/docs/library_usage.md \
|
||||||
@@SRC_DIR@@/docs/firmware \
|
@@SRC_DIR@@/docs/firmware \
|
||||||
@@SRC_DIR@@/docs/platform \
|
@@SRC_DIR@@/docs/platform \
|
||||||
@@ -948,7 +949,7 @@ FILTER_SOURCE_PATTERNS =
|
|||||||
# (index.html). This can be useful if you have a project on for instance GitHub
|
# (index.html). This can be useful if you have a project on for instance GitHub
|
||||||
# and want to reuse the introduction page also for the doxygen output.
|
# and want to reuse the introduction page also for the doxygen output.
|
||||||
|
|
||||||
USE_MDFILE_AS_MAINPAGE =
|
USE_MDFILE_AS_MAINPAGE = README.md
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to source browsing
|
# Configuration options related to source browsing
|
||||||
@@ -1444,7 +1445,7 @@ DISABLE_INDEX = NO
|
|||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
GENERATE_TREEVIEW = NO
|
GENERATE_TREEVIEW = YES
|
||||||
|
|
||||||
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
|
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
|
||||||
# doxygen will group on one line in the generated HTML documentation.
|
# doxygen will group on one line in the generated HTML documentation.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
OpenSBI Firmware with Dynamic Information *FW_DYNAMIC*
|
OpenSBI Firmware with Dynamic Information (FW_DYNAMIC)
|
||||||
======================================================
|
======================================================
|
||||||
|
|
||||||
OpenSBI **firmware with dynamic info (FW_DYNAMIC)** is a firmware which gets
|
OpenSBI **firmware with dynamic info (FW_DYNAMIC)** is a firmware which gets
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
OpenSBI Firmware with Jump Address *FW_JUMP*
|
OpenSBI Firmware with Jump Address (FW_JUMP)
|
||||||
============================================
|
============================================
|
||||||
|
|
||||||
OpenSBI **firmware with Jump Address (FW_JUMP)** is a firmware which only
|
OpenSBI **firmware with Jump Address (FW_JUMP)** is a firmware which only
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
OpenSBI Firmware with Payload *FW_PAYLOAD*
|
OpenSBI Firmware with Payload (FW_PAYLOAD)
|
||||||
==========================================
|
==========================================
|
||||||
|
|
||||||
OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
|
OpenSBI **firmware with Payload (FW_PAYLOAD)** is a firmware which directly
|
||||||
@@ -57,17 +57,8 @@ file. The parameters currently defined are as follows:
|
|||||||
|
|
||||||
* **FW_PAYLOAD_FDT_PATH** - Path to an external flattened device tree binary
|
* **FW_PAYLOAD_FDT_PATH** - Path to an external flattened device tree binary
|
||||||
file to be embedded in the *.text* section of the final firmware. If this
|
file to be embedded in the *.text* section of the final firmware. If this
|
||||||
option is not provided and no internal device tree file is specified by the
|
option is not provided then the firmware will expect the FDT to be passed
|
||||||
platform (c.f. *FW_PAYLOAD_FDT*), then the firmware will expect the FDT to
|
as an argument by the prior booting stage.
|
||||||
be passed as an argument by the prior booting stage.
|
|
||||||
|
|
||||||
* **FW_PAYLOAD_FDT** - Path to an internal flattened device tree binary file
|
|
||||||
defined by the platform code. The file name must match the DTB file name
|
|
||||||
specified in the platform *objects.mk* file with the *platform-dtb-y* entry.
|
|
||||||
This option results in *FW_PAYLOAD_FDT_PATH* to be automatically set.
|
|
||||||
Specifying *FW_PAYLOAD_FDT_PATH* on the `make` command line disables
|
|
||||||
*FW_PAYLOAD_FDT* and the command line specified device tree binary file is
|
|
||||||
used for building the final firmware.
|
|
||||||
|
|
||||||
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting
|
* **FW_PAYLOAD_FDT_ADDR** - Address where the FDT passed by the prior booting
|
||||||
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
|
stage or specified by the *FW_PAYLOAD_FDT_PATH* parameter and embedded in
|
||||||
@@ -83,7 +74,4 @@ The *[qemu/virt]* platforms illustrate how to configure and use a *FW_PAYLOAD*
|
|||||||
firmware. Detailed information regarding these platforms can be found in the
|
firmware. Detailed information regarding these platforms can be found in the
|
||||||
platform documentation files.
|
platform documentation files.
|
||||||
|
|
||||||
The *kendryte/k210* platform also enables a build of a *FW_PAYLOAD* using an
|
|
||||||
internally defined device tree file (*FW_PAYLOAD_FDT*).
|
|
||||||
|
|
||||||
[qemu/virt]: ../platform/qemu_virt.md
|
[qemu/virt]: ../platform/qemu_virt.md
|
||||||
|
54
docs/platform/generic.md
Normal file
54
docs/platform/generic.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
Generic Platform
|
||||||
|
================
|
||||||
|
|
||||||
|
The **Generic** platform is a flattened device tree (FDT) based platform
|
||||||
|
where all platform specific functionality is provided based on FDT passed
|
||||||
|
by previous booting stage. The **Generic** platform allows us to use same
|
||||||
|
OpenSBI firmware binaries on various emulators, simulators, FPGAs, and
|
||||||
|
boards.
|
||||||
|
|
||||||
|
By default, the generic FDT platform makes following assumptions:
|
||||||
|
|
||||||
|
1. platform FW_TEXT_START is 0x80000000
|
||||||
|
2. platform features are default
|
||||||
|
3. platform stack size is default
|
||||||
|
4. platform has no quirks or work-arounds
|
||||||
|
|
||||||
|
The above assumptions (except 1) can be overridden by adding special platform
|
||||||
|
callbacks which will be called based on FDT root node compatible string.
|
||||||
|
|
||||||
|
Users of the generic FDT platform will have to ensure that:
|
||||||
|
|
||||||
|
1. Various FDT based drivers under lib/utils directory are upto date
|
||||||
|
based on their platform requirements
|
||||||
|
2. The FDT passed by previous booting stage has DT compatible strings and
|
||||||
|
DT properties in sync with the FDT based drivers under lib/utils directory
|
||||||
|
3. The FDT must have "stdout-path" DT property in the "/chosen" DT node when
|
||||||
|
a platform has multiple serial ports or consoles
|
||||||
|
4. On multi-HART platform, the FDT must have a DT node for IPI device and
|
||||||
|
lib/utils/ipi directory must have corresponding FDT based IPI driver
|
||||||
|
5. The FDT must have a DT node for timer device and lib/utils/timer directory
|
||||||
|
must have corresponding FDT based timer driver
|
||||||
|
|
||||||
|
To build the platform-specific library and firmware images, provide the
|
||||||
|
*PLATFORM=generic* parameter to the top level `make` command.
|
||||||
|
|
||||||
|
For custom FW_TEXT_START, we can build the platform-specific library and
|
||||||
|
firmware images by passing *PLATFORM=generic FW_TEXT_START=<custom_text_start>*
|
||||||
|
parameter to the top level `make` command.
|
||||||
|
|
||||||
|
Platform Options
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The *Generic* platform does not have any platform-specific options.
|
||||||
|
|
||||||
|
RISC-V Platforms Using Generic Platform
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
|
||||||
|
* **Spike** (*[spike.md]*)
|
||||||
|
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
|
||||||
|
|
||||||
|
[qemu_virt.md]: qemu_virt.md
|
||||||
|
[spike.md]: spike.md
|
||||||
|
[shakti_cclass.md]: shakti_cclass.md
|
22
docs/platform/nuclei_ux600.md
Normal file
22
docs/platform/nuclei_ux600.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
Nuclei UX600 Platform
|
||||||
|
=====================
|
||||||
|
|
||||||
|
The **Nuclei UX600** is a 64-bit RISC-V Core which is capable of running Linux.
|
||||||
|
|
||||||
|
> Nuclei UX600: single core, pipeline as single-issue and 6~9 variable stages, in-order dispatch and out-of-order write-back, running up to >1.2GHz
|
||||||
|
|
||||||
|
To build the platform-specific library and firmware images, provide the
|
||||||
|
*PLATFORM=nuclei/ux600* parameter to the top level `make` command.
|
||||||
|
|
||||||
|
Platform Options
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The *Nuclei UX600* platform does not have any platform-specific options.
|
||||||
|
|
||||||
|
Building Nuclei UX600 Platform
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
```
|
||||||
|
make PLATFORM=nuclei/ux600 clean all
|
||||||
|
```
|
@@ -3,6 +3,11 @@ OpenSBI Supported Platforms
|
|||||||
|
|
||||||
OpenSBI currently supports the following virtual and hardware platforms:
|
OpenSBI currently supports the following virtual and hardware platforms:
|
||||||
|
|
||||||
|
* **Generic**: Flattened device tree (FDT) based platform where platform
|
||||||
|
specific functionality is provided based on the FDT passed by previous
|
||||||
|
booting stage. More details on this platform can be found in the file
|
||||||
|
*[generic.md]*.
|
||||||
|
|
||||||
* **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
|
* **QEMU RISC-V Virt Machine**: Platform support for the QEMU *virt* virtual
|
||||||
RISC-V machine. This virtual machine is intended for RISC-V software
|
RISC-V machine. This virtual machine is intended for RISC-V software
|
||||||
development and tests. More details on this platform can be found in the
|
development and tests. More details on this platform can be found in the
|
||||||
@@ -17,16 +22,25 @@ OpenSBI currently supports the following virtual and hardware platforms:
|
|||||||
boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
|
boards such as the Kendryte KD233 or the Sipeed MAIX Dock.
|
||||||
|
|
||||||
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
|
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
|
||||||
Genesys 2 board.
|
Genesys 2 board. More details on this platform can be found in the file
|
||||||
|
*[fpga-ariane.md]*.
|
||||||
|
|
||||||
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350).
|
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
|
||||||
|
details on this platform can be found in the file *[andes-ae350.md]*.
|
||||||
|
|
||||||
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor.
|
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor. More
|
||||||
|
details on this platform can be found in the file *[thead-c910.md]*.
|
||||||
|
|
||||||
* **Spike**: Platform support for the Spike emulator.
|
* **Spike**: Platform support for the Spike emulator. More
|
||||||
|
details on this platform can be found in the file *[spike.md]*.
|
||||||
|
|
||||||
* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based on
|
* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based
|
||||||
ariane core.
|
on ariane core. More details on this platform can be found in the file
|
||||||
|
*[fpga_openpiton.md]*.
|
||||||
|
|
||||||
|
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
|
||||||
|
processor based SOCs. More details on this platform can be found in the
|
||||||
|
file *[shakti_cclass.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
|
||||||
@@ -34,10 +48,12 @@ template files for implementing support for a new platform. The *object.mk*,
|
|||||||
*config.mk* and *platform.c* template files provides enough comments to
|
*config.mk* and *platform.c* template files provides enough comments to
|
||||||
facilitate the implementation.
|
facilitate the implementation.
|
||||||
|
|
||||||
|
[generic.md]: generic.md
|
||||||
[qemu_virt.md]: qemu_virt.md
|
[qemu_virt.md]: qemu_virt.md
|
||||||
[sifive_fu540.md]: sifive_fu540.md
|
[sifive_fu540.md]: sifive_fu540.md
|
||||||
[fpga-ariane.md]: fpga-ariane.md
|
[fpga-ariane.md]: fpga-ariane.md
|
||||||
[andes_ae350.md]: andes-ae350.md
|
[andes-ae350.md]: andes-ae350.md
|
||||||
[thead-c910.md]: thead-c910.md
|
[thead-c910.md]: thead-c910.md
|
||||||
[spike.md]: spike.md
|
[spike.md]: spike.md
|
||||||
[fpga_openpiton.md]: fpga_openpiton.md
|
[fpga_openpiton.md]: fpga_openpiton.md
|
||||||
|
[shakti_cclass.md]: shakti_cclass.md
|
||||||
|
@@ -7,7 +7,7 @@ software development and testing. It is also referred to as
|
|||||||
storage, and other types of IO.
|
storage, and other types of IO.
|
||||||
|
|
||||||
To build the platform-specific library and firmware images, provide the
|
To build the platform-specific library and firmware images, provide the
|
||||||
*PLATFORM=qemu/virt* parameter to the top level `make` command.
|
*PLATFORM=generic* parameter to the top level `make` command.
|
||||||
|
|
||||||
Platform Options
|
Platform Options
|
||||||
----------------
|
----------------
|
||||||
@@ -22,13 +22,13 @@ Execution on QEMU RISC-V 64-bit
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=qemu/virt
|
make PLATFORM=generic
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
|
-kernel build/platform/generic/firmware/fw_payload.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
**U-Boot Payload**
|
**U-Boot Payload**
|
||||||
@@ -38,19 +38,19 @@ the `qemu-riscv64_smode_defconfig` configuration.
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
make PLATFORM=generic FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
|
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||||
```
|
```
|
||||||
or
|
or
|
||||||
```
|
```
|
||||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
|
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||||
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80200000
|
-kernel <uboot_build_directory>/u-boot.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
**Linux Kernel Payload**
|
**Linux Kernel Payload**
|
||||||
@@ -60,13 +60,13 @@ Note: We assume that the Linux kernel is compiled using
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \
|
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||||
-device virtio-blk-device,drive=hd0 \
|
-device virtio-blk-device,drive=hd0 \
|
||||||
-append "root=/dev/vda rw console=ttyS0"
|
-append "root=/dev/vda rw console=ttyS0"
|
||||||
@@ -74,8 +74,8 @@ qemu-system-riscv64 -M virt -m 256M -nographic \
|
|||||||
or
|
or
|
||||||
```
|
```
|
||||||
qemu-system-riscv64 -M virt -m 256M -nographic \
|
qemu-system-riscv64 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
|
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||||
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80200000 \
|
-kernel <linux_build_directory>/arch/riscv/boot/Image \
|
||||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||||
-device virtio-blk-device,drive=hd0 \
|
-device virtio-blk-device,drive=hd0 \
|
||||||
-append "root=/dev/vda rw console=ttyS0"
|
-append "root=/dev/vda rw console=ttyS0"
|
||||||
@@ -89,13 +89,13 @@ Execution on QEMU RISC-V 32-bit
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=qemu/virt
|
make PLATFORM=generic PLATFORM_RISCV_XLEN=32
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
|
-kernel build/platform/generic/firmware/fw_payload.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
**U-Boot Payload**
|
**U-Boot Payload**
|
||||||
@@ -105,37 +105,35 @@ the `qemu-riscv32_smode_defconfig` configuration.
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<uboot_build_directory>/u-boot.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf
|
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||||
```
|
```
|
||||||
or
|
or
|
||||||
```
|
```
|
||||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
|
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||||
-device loader,file=<uboot_build_directory>/u-boot.bin,addr=0x80400000
|
-kernel <uboot_build_directory>/u-boot.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
**Linux Kernel Payload**
|
**Linux Kernel Payload**
|
||||||
|
|
||||||
Note: We assume that the Linux kernel is compiled using
|
Note: We assume that the Linux kernel is compiled using
|
||||||
*arch/riscv/configs/rv32_defconfig* (kernel 5.1 and newer)
|
*arch/riscv/configs/rv32_defconfig*.
|
||||||
respectively using *arch/riscv/configs/defconfig* plus setting
|
|
||||||
CONFIG_ARCH_RV32I=y (kernel 5.0 and older).
|
|
||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=qemu/virt FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
make PLATFORM=generic PLATFORM_RISCV_XLEN=32 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_payload.elf \
|
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||||
-device virtio-blk-device,drive=hd0 \
|
-device virtio-blk-device,drive=hd0 \
|
||||||
-append "root=/dev/vda rw console=ttyS0"
|
-append "root=/dev/vda rw console=ttyS0"
|
||||||
@@ -143,8 +141,8 @@ qemu-system-riscv32 -M virt -m 256M -nographic \
|
|||||||
or
|
or
|
||||||
```
|
```
|
||||||
qemu-system-riscv32 -M virt -m 256M -nographic \
|
qemu-system-riscv32 -M virt -m 256M -nographic \
|
||||||
-kernel build/platform/qemu/virt/firmware/fw_jump.elf \
|
-bios build/platform/generic/firmware/fw_jump.bin \
|
||||||
-device loader,file=<linux_build_directory>/arch/riscv/boot/Image,addr=0x80400000 \
|
-kernel <linux_build_directory>/arch/riscv/boot/Image \
|
||||||
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
-drive file=<path_to_linux_rootfs>,format=raw,id=hd0 \
|
||||||
-device virtio-blk-device,drive=hd0 \
|
-device virtio-blk-device,drive=hd0 \
|
||||||
-append "root=/dev/vda rw console=ttyS0"
|
-append "root=/dev/vda rw console=ttyS0"
|
||||||
|
33
docs/platform/shakti_cclass.md
Normal file
33
docs/platform/shakti_cclass.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
Shakti C-class SoC Platform
|
||||||
|
===========================
|
||||||
|
C-Class is a member of the SHAKTI family of processors from
|
||||||
|
Indian Institute of Technology - Madras (IIT-M).
|
||||||
|
|
||||||
|
It is an extremely configurable and commercial-grade 5-stage
|
||||||
|
in-order core supporting the standard RV64GCSUN ISA extensions.
|
||||||
|
|
||||||
|
For more details, refer:
|
||||||
|
* https://gitlab.com/shaktiproject/cores/c-class/blob/master/README.md
|
||||||
|
* https://c-class.readthedocs.io/en/latest
|
||||||
|
* https://shakti.org.in
|
||||||
|
|
||||||
|
Platform Options
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The *Shakti C-class SoC* platform does not have any platform-specific
|
||||||
|
options.
|
||||||
|
|
||||||
|
Building Shakti C-class Platform
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
**Linux Kernel Payload**
|
||||||
|
|
||||||
|
```
|
||||||
|
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test Payload**
|
||||||
|
|
||||||
|
```
|
||||||
|
make PLATFORM=generic FW_PAYLOAD_FDT_PATH=<shakti.dtb path>
|
||||||
|
```
|
@@ -49,29 +49,6 @@ The detailed U-Boot booting guide is avaialble at [U-Boot].
|
|||||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
|
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
**U-Boot & Linux Kernel as a single payload**
|
|
||||||
|
|
||||||
A single monolithic image containing both U-Boot & Linux can also be used if
|
|
||||||
network boot setup is not available.
|
|
||||||
|
|
||||||
1. Create a temporary image with u-boot-dtb.bin as the first payload. The
|
|
||||||
command-line example here assumes that U-Boot was compiled using
|
|
||||||
sifive_fu540_defconfig configuration.
|
|
||||||
```
|
|
||||||
dd if=~/workspace/u-boot-riscv/u-boot-dtb.bin of=/tmp/temp.bin bs=1M
|
|
||||||
```
|
|
||||||
2. Append the Linux Kernel image.
|
|
||||||
```
|
|
||||||
dd if=<linux_build_directory>/arch/riscv/boot/Image of=/tmp/temp.bin bs=1M seek=4
|
|
||||||
```
|
|
||||||
3. Compile OpenSBI with temp.bin (generated in step 2) as payload.
|
|
||||||
```
|
|
||||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
|
|
||||||
or
|
|
||||||
(For U-Boot which follows Linux v5.2 (or higher) DT bindings)
|
|
||||||
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=/tmp/temp.bin
|
|
||||||
```
|
|
||||||
|
|
||||||
Flashing the OpenSBI firmware binary to storage media:
|
Flashing the OpenSBI firmware binary to storage media:
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
The first stage boot loader ([FSBL]) expects the storage media to have a GPT
|
The first stage boot loader ([FSBL]) expects the storage media to have a GPT
|
||||||
|
@@ -9,7 +9,7 @@ on **Spike** simulator and QEMU Spike machine.
|
|||||||
For more details, refer [Spike on GitHub](https://github.com/riscv/riscv-isa-sim)
|
For more details, refer [Spike on GitHub](https://github.com/riscv/riscv-isa-sim)
|
||||||
|
|
||||||
To build the platform-specific library and firmware images, provide the
|
To build the platform-specific library and firmware images, provide the
|
||||||
*PLATFORM=spike* parameter to the top level `make` command.
|
*PLATFORM=generic* parameter to the top level `make` command.
|
||||||
|
|
||||||
Platform Options
|
Platform Options
|
||||||
----------------
|
----------------
|
||||||
@@ -23,12 +23,12 @@ Execution on Spike Simulator
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=spike
|
make PLATFORM=generic
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
spike build/platform/spike/firmware/fw_payload.elf
|
spike build/platform/generic/firmware/fw_payload.elf
|
||||||
```
|
```
|
||||||
|
|
||||||
**Linux Kernel Payload**
|
**Linux Kernel Payload**
|
||||||
@@ -38,12 +38,12 @@ Note: We assume that the Linux kernel is compiled using
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=spike FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
spike --initrd <path_to_cpio_ramdisk> build/platform/spike/firmware/fw_payload.elf
|
spike --initrd <path_to_cpio_ramdisk> build/platform/generic/firmware/fw_payload.elf
|
||||||
```
|
```
|
||||||
|
|
||||||
Execution on QEMU RISC-V 64-bit
|
Execution on QEMU RISC-V 64-bit
|
||||||
@@ -53,13 +53,13 @@ Execution on QEMU RISC-V 64-bit
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=spike
|
make PLATFORM=generic
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||||
-kernel build/platform/spike/firmware/fw_payload.elf
|
-kernel build/platform/generic/firmware/fw_payload.elf
|
||||||
```
|
```
|
||||||
|
|
||||||
**Linux Kernel Payload**
|
**Linux Kernel Payload**
|
||||||
@@ -69,20 +69,20 @@ Note: We assume that the Linux kernel is compiled using
|
|||||||
|
|
||||||
Build:
|
Build:
|
||||||
```
|
```
|
||||||
make PLATFORM=spike FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
make PLATFORM=generic FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image
|
||||||
```
|
```
|
||||||
|
|
||||||
Run:
|
Run:
|
||||||
```
|
```
|
||||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||||
-kernel build/platform/spike/firmware/fw_payload.elf \
|
-kernel build/platform/generic/firmware/fw_payload.elf \
|
||||||
-initrd <path_to_cpio_ramdisk> \
|
-initrd <path_to_cpio_ramdisk> \
|
||||||
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
||||||
```
|
```
|
||||||
or
|
or
|
||||||
```
|
```
|
||||||
qemu-system-riscv64 -M spike -m 256M -nographic \
|
qemu-system-riscv64 -M spike -m 256M -nographic \
|
||||||
-bios build/platform/spike/firmware/fw_jump.elf \
|
-bios build/platform/generic/firmware/fw_jump.elf \
|
||||||
-kernel <linux_build_directory>/arch/riscv/boot/Image \
|
-kernel <linux_build_directory>/arch/riscv/boot/Image \
|
||||||
-initrd <path_to_cpio_ramdisk> \
|
-initrd <path_to_cpio_ramdisk> \
|
||||||
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
-append "root=/dev/ram rw console=hvc0 earlycon=sbi"
|
||||||
|
44
docs/platform_requirements.md
Normal file
44
docs/platform_requirements.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
OpenSBI Platform Requirements
|
||||||
|
=============================
|
||||||
|
|
||||||
|
The RISC-V platform requirements for OpenSBI can change over time
|
||||||
|
with advances in RISC-V specifications and ecosystem.
|
||||||
|
|
||||||
|
To handle this, we have two types of RISC-V platform requirements:
|
||||||
|
|
||||||
|
1. **Base platform requirements** which apply to all OpenSBI releases
|
||||||
|
2. **Release specific platform requirements** which apply to a OpenSBI
|
||||||
|
release and later releases
|
||||||
|
|
||||||
|
Currently, we don't have any **Release specific platform requirements**
|
||||||
|
but such platform requirements will be added in future.
|
||||||
|
|
||||||
|
Base Platform Requirements
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
The base RISC-V platform requirements for OpenSBI are as follows:
|
||||||
|
|
||||||
|
1. At least rv32ima or rv64ima required on all HARTs
|
||||||
|
2. At least one HART should have S-mode support because:
|
||||||
|
|
||||||
|
* SBI calls are meant for RISC-V S-mode (Supervisor mode)
|
||||||
|
* OpenSBI implements SBI calls for S-mode software
|
||||||
|
|
||||||
|
3. The MTVEC CSR on all HARTs must support direct mode
|
||||||
|
4. The PMP CSRs are optional. If PMP CSRs are not implemented then
|
||||||
|
OpenSBI cannot protect M-mode firmware and secured memory regions
|
||||||
|
5. The TIME CSR is optional. If TIME CSR is not implemented in
|
||||||
|
hardware then a 64-bit MMIO counter is required to track time
|
||||||
|
and emulate TIME CSR
|
||||||
|
6. Hardware support for injecting M-mode software interrupts on
|
||||||
|
a multi-HART platform
|
||||||
|
|
||||||
|
The RISC-V extensions not covered by rv32ima or rv64ima are optional
|
||||||
|
for OpenSBI. Although, OpenSBI will detect and handle some of these
|
||||||
|
optional RISC-V extensions at runtime.
|
||||||
|
|
||||||
|
The optional RISC-V extensions handled by OpenSBI at runtime are:
|
||||||
|
|
||||||
|
* D-extension: Double precision floating point
|
||||||
|
* F-extension: Single precision floating point
|
||||||
|
* H-extension: Hypervisor
|
@@ -160,11 +160,48 @@ _relocate_done:
|
|||||||
li ra, 0
|
li ra, 0
|
||||||
call _reset_regs
|
call _reset_regs
|
||||||
|
|
||||||
|
/* Zero-out BSS */
|
||||||
|
la s4, _bss_start
|
||||||
|
la s5, _bss_end
|
||||||
|
_bss_zero:
|
||||||
|
REG_S zero, (s4)
|
||||||
|
add s4, s4, __SIZEOF_POINTER__
|
||||||
|
blt s4, s5, _bss_zero
|
||||||
|
|
||||||
|
/* Setup temporary trap handler */
|
||||||
|
la s4, _start_hang
|
||||||
|
csrw CSR_MTVEC, s4
|
||||||
|
|
||||||
|
/* Setup temporary stack */
|
||||||
|
la s4, _fw_end
|
||||||
|
li s5, (SBI_SCRATCH_SIZE * 2)
|
||||||
|
add sp, s4, s5
|
||||||
|
|
||||||
/* Allow main firmware to save info */
|
/* Allow main firmware to save info */
|
||||||
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
|
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
|
||||||
call fw_save_info
|
call fw_save_info
|
||||||
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
|
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
|
||||||
|
|
||||||
|
/* Override previous arg1 */
|
||||||
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
|
call fw_prev_arg1
|
||||||
|
add t1, a0, zero
|
||||||
|
MOV_3R a0, s0, a1, s1, a2, s2
|
||||||
|
beqz t1, _prev_arg1_override_done
|
||||||
|
add a1, t1, zero
|
||||||
|
_prev_arg1_override_done:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize platform
|
||||||
|
* Note: The a0 to a4 registers passed to the
|
||||||
|
* firmware are parameters to this function.
|
||||||
|
*/
|
||||||
|
MOV_5R s0, a0, s1, a1, s2, a2, s3, a3, s4, a4
|
||||||
|
call fw_platform_init
|
||||||
|
add t0, a0, zero
|
||||||
|
MOV_5R a0, s0, a1, s1, a2, s2, a3, s3, a4, s4
|
||||||
|
add a1, t0, zero
|
||||||
|
|
||||||
/* Preload HART details
|
/* Preload HART details
|
||||||
* s7 -> HART Count
|
* s7 -> HART Count
|
||||||
* s8 -> HART Stack Size
|
* s8 -> HART Stack Size
|
||||||
@@ -233,35 +270,16 @@ _scratch_init:
|
|||||||
/* Store firmware options in scratch space */
|
/* Store firmware options in scratch space */
|
||||||
MOV_3R s0, a0, s1, a1, s2, a2
|
MOV_3R s0, a0, s1, a1, s2, a2
|
||||||
#ifdef FW_OPTIONS
|
#ifdef FW_OPTIONS
|
||||||
li a4, FW_OPTIONS
|
li a0, FW_OPTIONS
|
||||||
#else
|
#else
|
||||||
add a4, zero, zero
|
|
||||||
#endif
|
|
||||||
call fw_options
|
call fw_options
|
||||||
or a4, a4, a0
|
#endif
|
||||||
REG_S a4, SBI_SCRATCH_OPTIONS_OFFSET(tp)
|
REG_S a0, SBI_SCRATCH_OPTIONS_OFFSET(tp)
|
||||||
MOV_3R a0, s0, a1, s1, a2, s2
|
MOV_3R a0, s0, a1, s1, a2, s2
|
||||||
/* Move to next scratch space */
|
/* Move to next scratch space */
|
||||||
add t1, t1, t2
|
add t1, t1, t2
|
||||||
blt t1, s7, _scratch_init
|
blt t1, s7, _scratch_init
|
||||||
|
|
||||||
/* Zero-out BSS */
|
|
||||||
la a4, _bss_start
|
|
||||||
la a5, _bss_end
|
|
||||||
_bss_zero:
|
|
||||||
REG_S zero, (a4)
|
|
||||||
add a4, a4, __SIZEOF_POINTER__
|
|
||||||
blt a4, a5, _bss_zero
|
|
||||||
|
|
||||||
/* Override pervious arg1 */
|
|
||||||
MOV_3R s0, a0, s1, a1, s2, a2
|
|
||||||
call fw_prev_arg1
|
|
||||||
add t1, a0, zero
|
|
||||||
MOV_3R a0, s0, a1, s1, a2, s2
|
|
||||||
beqz t1, _prev_arg1_override_done
|
|
||||||
add a1, t1, zero
|
|
||||||
_prev_arg1_override_done:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Relocate Flatened Device Tree (FDT)
|
* Relocate Flatened Device Tree (FDT)
|
||||||
* source FDT address = previous arg1
|
* source FDT address = previous arg1
|
||||||
@@ -331,7 +349,7 @@ _fdt_reloc_done:
|
|||||||
fence rw, rw
|
fence rw, rw
|
||||||
j _start_warm
|
j _start_warm
|
||||||
|
|
||||||
/* waitting for boot hart done (_boot_status == 2) */
|
/* waiting for boot hart to be done (_boot_status == 2) */
|
||||||
_wait_for_boot_hart:
|
_wait_for_boot_hart:
|
||||||
li t0, BOOT_STATUS_BOOT_HART_DONE
|
li t0, BOOT_STATUS_BOOT_HART_DONE
|
||||||
la t1, _boot_status
|
la t1, _boot_status
|
||||||
@@ -400,9 +418,6 @@ _start_warm:
|
|||||||
/* Setup trap handler */
|
/* Setup trap handler */
|
||||||
la a4, _trap_handler
|
la a4, _trap_handler
|
||||||
csrw CSR_MTVEC, a4
|
csrw CSR_MTVEC, a4
|
||||||
/* Make sure that mtvec is updated */
|
|
||||||
1: csrr a5, CSR_MTVEC
|
|
||||||
bne a4, a5, 1b
|
|
||||||
|
|
||||||
/* Initialize SBI runtime */
|
/* Initialize SBI runtime */
|
||||||
csrr a0, CSR_MSCRATCH
|
csrr a0, CSR_MSCRATCH
|
||||||
@@ -457,6 +472,14 @@ _start_hang:
|
|||||||
wfi
|
wfi
|
||||||
j _start_hang
|
j _start_hang
|
||||||
|
|
||||||
|
.section .entry, "ax", %progbits
|
||||||
|
.align 3
|
||||||
|
.globl fw_platform_init
|
||||||
|
.weak fw_platform_init
|
||||||
|
fw_platform_init:
|
||||||
|
add a0, a1, zero
|
||||||
|
ret
|
||||||
|
|
||||||
.section .entry, "ax", %progbits
|
.section .entry, "ax", %progbits
|
||||||
.align 3
|
.align 3
|
||||||
.globl _trap_handler
|
.globl _trap_handler
|
||||||
|
@@ -41,11 +41,6 @@ ifdef FW_PAYLOAD_ALIGN
|
|||||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
|
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_ALIGN=$(FW_PAYLOAD_ALIGN)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef FW_PAYLOAD_FDT_PATH
|
|
||||||
ifdef FW_PAYLOAD_FDT
|
|
||||||
FW_PAYLOAD_FDT_PATH=$(platform_build_dir)/$(FW_PAYLOAD_FDT)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
ifdef FW_PAYLOAD_FDT_PATH
|
ifdef FW_PAYLOAD_FDT_PATH
|
||||||
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=\"$(FW_PAYLOAD_FDT_PATH)\"
|
firmware-genflags-$(FW_PAYLOAD) += -DFW_PAYLOAD_FDT_PATH=\"$(FW_PAYLOAD_FDT_PATH)\"
|
||||||
endif
|
endif
|
||||||
|
@@ -173,19 +173,8 @@ int misa_extension_imp(char ext);
|
|||||||
/* Get MXL field of misa, return -1 on error */
|
/* Get MXL field of misa, return -1 on error */
|
||||||
int misa_xlen(void);
|
int misa_xlen(void);
|
||||||
|
|
||||||
static inline void misa_string(char *out, unsigned int out_sz)
|
/* Get RISC-V ISA string representation */
|
||||||
{
|
void misa_string(int xlen, char *out, unsigned int out_sz);
|
||||||
unsigned long i;
|
|
||||||
|
|
||||||
for (i = 0; i < 26; i++) {
|
|
||||||
if (misa_extension_imp('A' + i)) {
|
|
||||||
*out = 'A' + i;
|
|
||||||
out++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*out = '\0';
|
|
||||||
out++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
||||||
unsigned long log2len);
|
unsigned long log2len);
|
||||||
|
@@ -61,12 +61,20 @@
|
|||||||
#define SSTATUS64_UXL MSTATUS_UXL
|
#define SSTATUS64_UXL MSTATUS_UXL
|
||||||
#define SSTATUS64_SD MSTATUS64_SD
|
#define SSTATUS64_SD MSTATUS64_SD
|
||||||
|
|
||||||
|
#if __riscv_xlen == 64
|
||||||
|
#define HSTATUS_VSXL _UL(0x300000000)
|
||||||
|
#define HSTATUS_VSXL_SHIFT 32
|
||||||
|
#endif
|
||||||
#define HSTATUS_VTSR _UL(0x00400000)
|
#define HSTATUS_VTSR _UL(0x00400000)
|
||||||
|
#define HSTATUS_VTW _UL(0x00200000)
|
||||||
#define HSTATUS_VTVM _UL(0x00100000)
|
#define HSTATUS_VTVM _UL(0x00100000)
|
||||||
#define HSTATUS_SP2V _UL(0x00000200)
|
#define HSTATUS_VGEIN _UL(0x0003f000)
|
||||||
#define HSTATUS_SP2P _UL(0x00000100)
|
#define HSTATUS_VGEIN_SHIFT 12
|
||||||
|
#define HSTATUS_HU _UL(0x00000200)
|
||||||
|
#define HSTATUS_SPVP _UL(0x00000100)
|
||||||
#define HSTATUS_SPV _UL(0x00000080)
|
#define HSTATUS_SPV _UL(0x00000080)
|
||||||
#define HSTATUS_SPRV _UL(0x00000001)
|
#define HSTATUS_GVA _UL(0x00000040)
|
||||||
|
#define HSTATUS_VSBE _UL(0x00000020)
|
||||||
|
|
||||||
#define IRQ_S_SOFT 1
|
#define IRQ_S_SOFT 1
|
||||||
#define IRQ_VS_SOFT 2
|
#define IRQ_VS_SOFT 2
|
||||||
@@ -111,6 +119,21 @@
|
|||||||
#define SATP_MODE_SV57 _UL(10)
|
#define SATP_MODE_SV57 _UL(10)
|
||||||
#define SATP_MODE_SV64 _UL(11)
|
#define SATP_MODE_SV64 _UL(11)
|
||||||
|
|
||||||
|
#define HGATP_MODE_OFF _UL(0)
|
||||||
|
#define HGATP_MODE_SV32X4 _UL(1)
|
||||||
|
#define HGATP_MODE_SV39X4 _UL(8)
|
||||||
|
#define HGATP_MODE_SV48X4 _UL(9)
|
||||||
|
|
||||||
|
#define HGATP32_MODE_SHIFT 31
|
||||||
|
#define HGATP32_VMID_SHIFT 22
|
||||||
|
#define HGATP32_VMID_MASK _UL(0x1FC00000)
|
||||||
|
#define HGATP32_PPN _UL(0x003FFFFF)
|
||||||
|
|
||||||
|
#define HGATP64_MODE_SHIFT 60
|
||||||
|
#define HGATP64_VMID_SHIFT 44
|
||||||
|
#define HGATP64_VMID_MASK _ULL(0x03FFF00000000000)
|
||||||
|
#define HGATP64_PPN _ULL(0x00000FFFFFFFFFFF)
|
||||||
|
|
||||||
#define PMP_R _UL(0x01)
|
#define PMP_R _UL(0x01)
|
||||||
#define PMP_W _UL(0x02)
|
#define PMP_W _UL(0x02)
|
||||||
#define PMP_X _UL(0x04)
|
#define PMP_X _UL(0x04)
|
||||||
@@ -123,35 +146,25 @@
|
|||||||
#define PMP_SHIFT 2
|
#define PMP_SHIFT 2
|
||||||
#define PMP_COUNT 16
|
#define PMP_COUNT 16
|
||||||
|
|
||||||
/* page table entry (PTE) fields */
|
|
||||||
#define PTE_V _UL(0x001) /* Valid */
|
|
||||||
#define PTE_R _UL(0x002) /* Read */
|
|
||||||
#define PTE_W _UL(0x004) /* Write */
|
|
||||||
#define PTE_X _UL(0x008) /* Execute */
|
|
||||||
#define PTE_U _UL(0x010) /* User */
|
|
||||||
#define PTE_G _UL(0x020) /* Global */
|
|
||||||
#define PTE_A _UL(0x040) /* Accessed */
|
|
||||||
#define PTE_D _UL(0x080) /* Dirty */
|
|
||||||
#define PTE_SOFT _UL(0x300) /* Reserved for Software */
|
|
||||||
|
|
||||||
#define PTE_PPN_SHIFT 10
|
|
||||||
|
|
||||||
#define PTE_TABLE(PTE) \
|
|
||||||
(((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
|
|
||||||
|
|
||||||
#if __riscv_xlen == 64
|
#if __riscv_xlen == 64
|
||||||
#define MSTATUS_SD MSTATUS64_SD
|
#define MSTATUS_SD MSTATUS64_SD
|
||||||
#define SSTATUS_SD SSTATUS64_SD
|
#define SSTATUS_SD SSTATUS64_SD
|
||||||
#define RISCV_PGLEVEL_BITS 9
|
|
||||||
#define SATP_MODE SATP64_MODE
|
#define SATP_MODE SATP64_MODE
|
||||||
|
|
||||||
|
#define HGATP_PPN HGATP64_PPN
|
||||||
|
#define HGATP_VMID_SHIFT HGATP64_VMID_SHIFT
|
||||||
|
#define HGATP_VMID_MASK HGATP64_VMID_MASK
|
||||||
|
#define HGATP_MODE_SHIFT HGATP64_MODE_SHIFT
|
||||||
#else
|
#else
|
||||||
#define MSTATUS_SD MSTATUS32_SD
|
#define MSTATUS_SD MSTATUS32_SD
|
||||||
#define SSTATUS_SD SSTATUS32_SD
|
#define SSTATUS_SD SSTATUS32_SD
|
||||||
#define RISCV_PGLEVEL_BITS 10
|
|
||||||
#define SATP_MODE SATP32_MODE
|
#define SATP_MODE SATP32_MODE
|
||||||
|
|
||||||
|
#define HGATP_PPN HGATP32_PPN
|
||||||
|
#define HGATP_VMID_SHIFT HGATP32_VMID_SHIFT
|
||||||
|
#define HGATP_VMID_MASK HGATP32_VMID_MASK
|
||||||
|
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
|
||||||
#endif
|
#endif
|
||||||
#define RISCV_PGSHIFT 12
|
|
||||||
#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
|
|
||||||
|
|
||||||
#define CSR_USTATUS 0x0
|
#define CSR_USTATUS 0x0
|
||||||
#define CSR_FFLAGS 0x1
|
#define CSR_FFLAGS 0x1
|
||||||
@@ -419,6 +432,7 @@
|
|||||||
#define CAUSE_STORE_PAGE_FAULT 0xf
|
#define CAUSE_STORE_PAGE_FAULT 0xf
|
||||||
#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14
|
#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14
|
||||||
#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15
|
#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15
|
||||||
|
#define CAUSE_VIRTUAL_INST_FAULT 0x16
|
||||||
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
|
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
|
||||||
|
|
||||||
#define INSN_MATCH_LB 0x3
|
#define INSN_MATCH_LB 0x3
|
||||||
|
50
include/sbi/sbi_csr_detect.h
Normal file
50
include/sbi/sbi_csr_detect.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Atish Patra <atish.patra@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SBI_CSR_DETECT__H
|
||||||
|
#define __SBI_CSR_DETECT__H
|
||||||
|
|
||||||
|
#include <sbi/riscv_encoding.h>
|
||||||
|
#include <sbi/sbi_hart.h>
|
||||||
|
|
||||||
|
#define csr_read_allowed(csr_num, trap) \
|
||||||
|
({ \
|
||||||
|
register ulong tinfo asm("a3") = (ulong)trap; \
|
||||||
|
register ulong ttmp asm("a4"); \
|
||||||
|
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||||
|
register ulong ret = 0; \
|
||||||
|
asm volatile( \
|
||||||
|
"add %[ttmp], %[tinfo], zero\n" \
|
||||||
|
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||||
|
"csrr %[ret], %[csr]\n" \
|
||||||
|
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
|
||||||
|
: [mtvec] "+&r"(mtvec), [tinfo] "+&r"(tinfo), \
|
||||||
|
[ttmp] "+&r"(ttmp), [ret] "=&r" (ret) \
|
||||||
|
: [csr] "i" (csr_num) \
|
||||||
|
: "memory"); \
|
||||||
|
ret; \
|
||||||
|
}) \
|
||||||
|
|
||||||
|
#define csr_write_allowed(csr_num, trap, value) \
|
||||||
|
({ \
|
||||||
|
register ulong tinfo asm("a3") = (ulong)trap; \
|
||||||
|
register ulong ttmp asm("a4"); \
|
||||||
|
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||||
|
asm volatile( \
|
||||||
|
"add %[ttmp], %[tinfo], zero\n" \
|
||||||
|
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||||
|
"csrw %[csr], %[val]\n" \
|
||||||
|
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
|
||||||
|
: [mtvec] "+&r"(mtvec), \
|
||||||
|
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp) \
|
||||||
|
: [csr] "i" (csr_num), [val] "r" (value) \
|
||||||
|
: "memory"); \
|
||||||
|
}) \
|
||||||
|
|
||||||
|
#endif
|
@@ -13,7 +13,7 @@
|
|||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
/* SBI Extension IDs */
|
/* SBI Extension IDs */
|
||||||
#define SBI_EXT_0_1_SET_TIMER 0x0
|
#define SBI_EXT_0_1_SET_TIMER 0x0
|
||||||
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
|
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
|
||||||
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
|
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
|
||||||
#define SBI_EXT_0_1_CLEAR_IPI 0x3
|
#define SBI_EXT_0_1_CLEAR_IPI 0x3
|
||||||
@@ -67,6 +67,20 @@
|
|||||||
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
|
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
|
||||||
#define SBI_EXT_VENDOR_START 0x09000000
|
#define SBI_EXT_VENDOR_START 0x09000000
|
||||||
#define SBI_EXT_VENDOR_END 0x09FFFFFF
|
#define SBI_EXT_VENDOR_END 0x09FFFFFF
|
||||||
|
#define SBI_EXT_FIRMWARE_START 0x0A000000
|
||||||
|
#define SBI_EXT_FIRMWARE_END 0x0AFFFFFF
|
||||||
|
|
||||||
|
/* SBI return error codes */
|
||||||
|
#define SBI_SUCCESS 0
|
||||||
|
#define SBI_ERR_FAILED -1
|
||||||
|
#define SBI_ERR_NOT_SUPPORTED -2
|
||||||
|
#define SBI_ERR_INVALID_PARAM -3
|
||||||
|
#define SBI_ERR_DENIED -4
|
||||||
|
#define SBI_ERR_INVALID_ADDRESS -5
|
||||||
|
#define SBI_ERR_ALREADY_AVAILABLE -6
|
||||||
|
|
||||||
|
#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -10,25 +10,28 @@
|
|||||||
#ifndef __SBI_ERROR_H__
|
#ifndef __SBI_ERROR_H__
|
||||||
#define __SBI_ERROR_H__
|
#define __SBI_ERROR_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_ecall_interface.h>
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
||||||
#define SBI_OK 0
|
#define SBI_OK 0
|
||||||
#define SBI_EFAIL -1
|
#define SBI_EFAIL SBI_ERR_FAILED
|
||||||
#define SBI_ENOTSUPP -2
|
#define SBI_ENOTSUPP SBI_ERR_NOT_SUPPORTED
|
||||||
#define SBI_EINVAL -3
|
#define SBI_EINVAL SBI_ERR_INVALID_PARAM
|
||||||
#define SBI_DENIED -4
|
#define SBI_EDENIED SBI_ERR_DENIED
|
||||||
#define SBI_INVALID_ADDR -5
|
#define SBI_EINVALID_ADDR SBI_ERR_INVALID_ADDRESS
|
||||||
#define SBI_ENODEV -6
|
#define SBI_EALREADY SBI_ERR_ALREADY_AVAILABLE
|
||||||
#define SBI_ENOSYS -7
|
|
||||||
#define SBI_ETIMEDOUT -8
|
#define SBI_ENODEV -1000
|
||||||
#define SBI_EIO -9
|
#define SBI_ENOSYS -1001
|
||||||
#define SBI_EILL -10
|
#define SBI_ETIMEDOUT -1002
|
||||||
#define SBI_ENOSPC -11
|
#define SBI_EIO -1003
|
||||||
#define SBI_ENOMEM -12
|
#define SBI_EILL -1004
|
||||||
#define SBI_ETRAP -13
|
#define SBI_ENOSPC -1005
|
||||||
#define SBI_EUNKNOWN -14
|
#define SBI_ENOMEM -1006
|
||||||
#define SBI_ENOENT -15
|
#define SBI_ETRAP -1007
|
||||||
#define SBI_EALREADY_STARTED -16
|
#define SBI_EUNKNOWN -1008
|
||||||
|
#define SBI_ENOENT -1009
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
|
@@ -12,20 +12,42 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
/** Possible feature flags of a hart */
|
||||||
|
enum sbi_hart_features {
|
||||||
|
/** Hart has PMP support */
|
||||||
|
SBI_HART_HAS_PMP = (1 << 0),
|
||||||
|
/** Hart has S-mode counter enable */
|
||||||
|
SBI_HART_HAS_SCOUNTEREN = (1 << 1),
|
||||||
|
/** Hart has M-mode counter enable */
|
||||||
|
SBI_HART_HAS_MCOUNTEREN = (1 << 2),
|
||||||
|
/** HART has timer csr implementation in hardware */
|
||||||
|
SBI_HART_HAS_TIME = (1 << 3),
|
||||||
|
|
||||||
|
/** Last index of Hart features*/
|
||||||
|
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
|
||||||
|
};
|
||||||
|
|
||||||
struct sbi_scratch;
|
struct sbi_scratch;
|
||||||
|
|
||||||
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
|
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
|
||||||
|
|
||||||
extern void (*sbi_hart_unpriv_trap)(void);
|
extern void (*sbi_hart_expected_trap)(void);
|
||||||
static inline ulong sbi_hart_unpriv_trap_addr(void)
|
static inline ulong sbi_hart_expected_trap_addr(void)
|
||||||
{
|
{
|
||||||
return (ulong)sbi_hart_unpriv_trap;
|
return (ulong)sbi_hart_expected_trap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
|
void sbi_hart_delegation_dump(struct sbi_scratch *scratch);
|
||||||
|
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch);
|
||||||
|
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
|
||||||
|
unsigned long *prot_out, unsigned long *addr_out,
|
||||||
|
unsigned long *size);
|
||||||
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
|
void sbi_hart_pmp_dump(struct sbi_scratch *scratch);
|
||||||
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
|
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long daddr,
|
||||||
unsigned long attr);
|
unsigned long attr);
|
||||||
|
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
|
||||||
|
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
|
||||||
|
char *features_str, int nfstr);
|
||||||
|
|
||||||
void __attribute__((noreturn)) sbi_hart_hang(void);
|
void __attribute__((noreturn)) sbi_hart_hang(void);
|
||||||
|
|
||||||
|
@@ -10,8 +10,9 @@
|
|||||||
|
|
||||||
#ifndef __SBI_FENCE_H__
|
#ifndef __SBI_FENCE_H__
|
||||||
#define __SBI_FENCE_H__
|
#define __SBI_FENCE_H__
|
||||||
|
|
||||||
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
|
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
|
||||||
void __sbi_hfence_gvma_vmid_gpa(unsigned long vmid, unsigned long gpa);
|
void __sbi_hfence_gvma_vmid_gpa(unsigned long gpa, unsigned long vmid);
|
||||||
|
|
||||||
/** Invalidate Stage2 TLBs for given VMID */
|
/** Invalidate Stage2 TLBs for given VMID */
|
||||||
void __sbi_hfence_gvma_vmid(unsigned long vmid);
|
void __sbi_hfence_gvma_vmid(unsigned long vmid);
|
||||||
@@ -23,7 +24,7 @@ void __sbi_hfence_gvma_gpa(unsigned long gpa);
|
|||||||
void __sbi_hfence_gvma_all(void);
|
void __sbi_hfence_gvma_all(void);
|
||||||
|
|
||||||
/** Invalidate unified TLB entries for given asid and guest virtual address */
|
/** Invalidate unified TLB entries for given asid and guest virtual address */
|
||||||
void __sbi_hfence_vvma_asid_va(unsigned long asid, unsigned long va);
|
void __sbi_hfence_vvma_asid_va(unsigned long va, unsigned long asid);
|
||||||
|
|
||||||
/** Invalidate unified TLB entries for given ASID for a guest*/
|
/** Invalidate unified TLB entries for given ASID for a guest*/
|
||||||
void __sbi_hfence_vvma_asid(unsigned long asid);
|
void __sbi_hfence_vvma_asid(unsigned long asid);
|
||||||
@@ -33,4 +34,5 @@ void __sbi_hfence_vvma_va(unsigned long va);
|
|||||||
|
|
||||||
/** Invalidate all possible Stage2 TLBs */
|
/** Invalidate all possible Stage2 TLBs */
|
||||||
void __sbi_hfence_vvma_all(void);
|
void __sbi_hfence_vvma_all(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
15
include/sbi/sbi_math.h
Normal file
15
include/sbi/sbi_math.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Atish Patra <atish.patra@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SBI_MATH_H__
|
||||||
|
#define __SBI_MATH_H__
|
||||||
|
|
||||||
|
unsigned long log2roundup(unsigned long x);
|
||||||
|
|
||||||
|
#endif
|
@@ -52,23 +52,18 @@ enum sbi_platform_features {
|
|||||||
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
|
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
|
||||||
/** Platform has HART hotplug support */
|
/** Platform has HART hotplug support */
|
||||||
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
|
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
|
||||||
/** Platform has PMP support */
|
|
||||||
SBI_PLATFORM_HAS_PMP = (1 << 2),
|
|
||||||
/** Platform has S-mode counter enable */
|
|
||||||
SBI_PLATFORM_HAS_SCOUNTEREN = (1 << 3),
|
|
||||||
/** Platform has M-mode counter enable */
|
|
||||||
SBI_PLATFORM_HAS_MCOUNTEREN = (1 << 4),
|
|
||||||
/** Platform has fault delegation support */
|
/** Platform has fault delegation support */
|
||||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 5),
|
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
|
||||||
/** Platform has custom secondary hart booting support */
|
/** Platform has custom secondary hart booting support */
|
||||||
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 6),
|
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
|
||||||
|
|
||||||
|
/** Last index of Platform features*/
|
||||||
|
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Default feature set for a platform */
|
/** Default feature set for a platform */
|
||||||
#define SBI_PLATFORM_DEFAULT_FEATURES \
|
#define SBI_PLATFORM_DEFAULT_FEATURES \
|
||||||
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_PMP | \
|
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||||
SBI_PLATFORM_HAS_SCOUNTEREN | SBI_PLATFORM_HAS_MCOUNTEREN | \
|
|
||||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
|
||||||
|
|
||||||
/** Platform functions */
|
/** Platform functions */
|
||||||
struct sbi_platform_operations {
|
struct sbi_platform_operations {
|
||||||
@@ -146,10 +141,11 @@ struct sbi_platform_operations {
|
|||||||
*/
|
*/
|
||||||
int (*hart_stop)(void);
|
int (*hart_stop)(void);
|
||||||
|
|
||||||
/** Reboot the platform */
|
/** Reset the platform */
|
||||||
int (*system_reboot)(u32 type);
|
#define SBI_PLATFORM_RESET_SHUTDOWN 0
|
||||||
/** Shutdown or poweroff the platform */
|
#define SBI_PLATFORM_RESET_COLD 1
|
||||||
int (*system_shutdown)(u32 type);
|
#define SBI_PLATFORM_RESET_WARM 2
|
||||||
|
int (*system_reset)(u32 reset_type);
|
||||||
|
|
||||||
/** platform specific SBI extension implementation probe function */
|
/** platform specific SBI extension implementation probe function */
|
||||||
int (*vendor_ext_check)(long extid);
|
int (*vendor_ext_check)(long extid);
|
||||||
@@ -223,14 +219,6 @@ struct sbi_platform {
|
|||||||
/** Check whether the platform supports HART hotplug */
|
/** Check whether the platform supports HART hotplug */
|
||||||
#define sbi_platform_has_hart_hotplug(__p) \
|
#define sbi_platform_has_hart_hotplug(__p) \
|
||||||
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
|
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
|
||||||
/** Check whether the platform has PMP support */
|
|
||||||
#define sbi_platform_has_pmp(__p) ((__p)->features & SBI_PLATFORM_HAS_PMP)
|
|
||||||
/** Check whether the platform supports scounteren CSR */
|
|
||||||
#define sbi_platform_has_scounteren(__p) \
|
|
||||||
((__p)->features & SBI_PLATFORM_HAS_SCOUNTEREN)
|
|
||||||
/** Check whether the platform supports mcounteren CSR */
|
|
||||||
#define sbi_platform_has_mcounteren(__p) \
|
|
||||||
((__p)->features & SBI_PLATFORM_HAS_MCOUNTEREN)
|
|
||||||
/** Check whether the platform supports fault delegation */
|
/** Check whether the platform supports fault delegation */
|
||||||
#define sbi_platform_has_mfaults_delegation(__p) \
|
#define sbi_platform_has_mfaults_delegation(__p) \
|
||||||
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
||||||
@@ -238,6 +226,28 @@ struct sbi_platform {
|
|||||||
#define sbi_platform_has_hart_secondary_boot(__p) \
|
#define sbi_platform_has_hart_secondary_boot(__p) \
|
||||||
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
|
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get HART index for the given HART
|
||||||
|
*
|
||||||
|
* @param plat pointer to struct sbi_platform
|
||||||
|
* @param hartid HART ID
|
||||||
|
*
|
||||||
|
* @return 0 <= value < hart_count for valid HART otherwise -1U
|
||||||
|
*/
|
||||||
|
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the platform features in string format
|
||||||
|
*
|
||||||
|
* @param plat pointer to struct sbi_platform
|
||||||
|
* @param features_str pointer to a char array where the features string will be
|
||||||
|
* updated
|
||||||
|
* @param nfstr length of the features_str. The feature string will be truncated
|
||||||
|
* if nfstr is not long enough.
|
||||||
|
*/
|
||||||
|
void sbi_platform_get_features_str(const struct sbi_platform *plat,
|
||||||
|
char *features_str, int nfstr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get name of the platform
|
* Get name of the platform
|
||||||
*
|
*
|
||||||
@@ -252,6 +262,21 @@ static inline const char *sbi_platform_name(const struct sbi_platform *plat)
|
|||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the platform features
|
||||||
|
*
|
||||||
|
* @param plat pointer to struct sbi_platform
|
||||||
|
*
|
||||||
|
* @return the features value currently set for the given platform
|
||||||
|
*/
|
||||||
|
static inline unsigned long sbi_platform_get_features(
|
||||||
|
const struct sbi_platform *plat)
|
||||||
|
{
|
||||||
|
if (plat)
|
||||||
|
return plat->features;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get platform specific tlb range flush maximum value. Any request with size
|
* Get platform specific tlb range flush maximum value. Any request with size
|
||||||
* higher than this is upgraded to a full flush.
|
* higher than this is upgraded to a full flush.
|
||||||
@@ -296,32 +321,6 @@ static inline u32 sbi_platform_hart_stack_size(const struct sbi_platform *plat)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get HART index for the given HART
|
|
||||||
*
|
|
||||||
* @param plat pointer to struct sbi_platform
|
|
||||||
* @param hartid HART ID
|
|
||||||
*
|
|
||||||
* @return 0 <= value < hart_count for valid HART otherwise -1U
|
|
||||||
*/
|
|
||||||
static inline u32 sbi_platform_hart_index(const struct sbi_platform *plat,
|
|
||||||
u32 hartid)
|
|
||||||
{
|
|
||||||
u32 i;
|
|
||||||
|
|
||||||
if (!plat)
|
|
||||||
return -1U;
|
|
||||||
if (plat->hart_index2id) {
|
|
||||||
for (i = 0; i < plat->hart_count; i++) {
|
|
||||||
if (plat->hart_index2id[i] == hartid)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1U;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hartid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether given HART is invalid
|
* Check whether given HART is invalid
|
||||||
*
|
*
|
||||||
@@ -492,8 +491,9 @@ static inline int sbi_platform_pmp_region_info(const struct sbi_platform *plat,
|
|||||||
ulong *log2size)
|
ulong *log2size)
|
||||||
{
|
{
|
||||||
if (plat && sbi_platform_ops(plat)->pmp_region_info)
|
if (plat && sbi_platform_ops(plat)->pmp_region_info)
|
||||||
return sbi_platform_ops(plat)->pmp_region_info(hartid, index, prot, addr,
|
return sbi_platform_ops(plat)->pmp_region_info(hartid, index,
|
||||||
log2size);
|
prot, addr,
|
||||||
|
log2size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,34 +685,18 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reboot the platform
|
* Reset the platform
|
||||||
*
|
*
|
||||||
* @param plat pointer to struct sbi_platform
|
* @param plat pointer to struct sbi_platform
|
||||||
* @param type type of reboot
|
* @param reset_type type of reset
|
||||||
*
|
*
|
||||||
* @return 0 on success and negative error code on failure
|
* @return 0 on success and negative error code on failure
|
||||||
*/
|
*/
|
||||||
static inline int sbi_platform_system_reboot(const struct sbi_platform *plat,
|
static inline int sbi_platform_system_reset(const struct sbi_platform *plat,
|
||||||
u32 type)
|
u32 reset_type)
|
||||||
{
|
{
|
||||||
if (plat && sbi_platform_ops(plat)->system_reboot)
|
if (plat && sbi_platform_ops(plat)->system_reset)
|
||||||
return sbi_platform_ops(plat)->system_reboot(type);
|
return sbi_platform_ops(plat)->system_reset(reset_type);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shutdown or poweroff the platform
|
|
||||||
*
|
|
||||||
* @param plat pointer to struct sbi_platform
|
|
||||||
* @param type type of shutdown or poweroff
|
|
||||||
*
|
|
||||||
* @return 0 on success and negative error code on failure
|
|
||||||
*/
|
|
||||||
static inline int sbi_platform_system_shutdown(const struct sbi_platform *plat,
|
|
||||||
u32 type)
|
|
||||||
{
|
|
||||||
if (plat && sbi_platform_ops(plat)->system_shutdown)
|
|
||||||
return sbi_platform_ops(plat)->system_shutdown(type);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
void __noreturn sbi_system_reboot(u32 type);
|
void __noreturn sbi_system_reset(u32 platform_reset_type);
|
||||||
|
|
||||||
void __noreturn sbi_system_shutdown(u32 type);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -38,17 +38,19 @@ struct sbi_tlb_info {
|
|||||||
unsigned long start;
|
unsigned long start;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
unsigned long asid;
|
unsigned long asid;
|
||||||
|
unsigned long vmid;
|
||||||
unsigned long type;
|
unsigned long type;
|
||||||
struct sbi_hartmask smask;
|
struct sbi_hartmask smask;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SBI_TLB_INFO_INIT(__ptr, __start, __size, __asid, __type, __src_hart) \
|
#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
|
||||||
do { \
|
do { \
|
||||||
(__ptr)->start = (__start); \
|
(__p)->start = (__start); \
|
||||||
(__ptr)->size = (__size); \
|
(__p)->size = (__size); \
|
||||||
(__ptr)->asid = (__asid); \
|
(__p)->asid = (__asid); \
|
||||||
(__ptr)->type = (__type); \
|
(__p)->vmid = (__vmid); \
|
||||||
SBI_HARTMASK_INIT_EXCEPT(&(__ptr)->smask, (__src_hart)); \
|
(__p)->type = (__type); \
|
||||||
|
SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
|
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
|
||||||
|
@@ -78,6 +78,8 @@ typedef unsigned long physical_size_t;
|
|||||||
const typeof(((type *)0)->member) * __mptr = (ptr); \
|
const typeof(((type *)0)->member) * __mptr = (ptr); \
|
||||||
(type *)((char *)__mptr - offsetof(type, member)); })
|
(type *)((char *)__mptr - offsetof(type, member)); })
|
||||||
|
|
||||||
|
#define array_size(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
|
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
#define __SBI_VERSION_H__
|
#define __SBI_VERSION_H__
|
||||||
|
|
||||||
#define OPENSBI_VERSION_MAJOR 0
|
#define OPENSBI_VERSION_MAJOR 0
|
||||||
#define OPENSBI_VERSION_MINOR 7
|
#define OPENSBI_VERSION_MINOR 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenSBI 32-bit version with:
|
* OpenSBI 32-bit version with:
|
||||||
|
@@ -47,6 +47,20 @@ void fdt_plic_fixup(void *fdt, const char *compat);
|
|||||||
*/
|
*/
|
||||||
int fdt_reserved_memory_fixup(void *fdt);
|
int fdt_reserved_memory_fixup(void *fdt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix up the reserved memory subnodes in the device tree
|
||||||
|
*
|
||||||
|
* This routine adds the no-map property to the reserved memory subnodes so
|
||||||
|
* that the OS does not map those PMP protected memory regions.
|
||||||
|
*
|
||||||
|
* Platform codes must call this helper in their final_init() after fdt_fixups()
|
||||||
|
* if the OS should not map the PMP protected reserved regions.
|
||||||
|
*
|
||||||
|
* @param fdt: device tree blob
|
||||||
|
* @return zero on success and -ve on failure
|
||||||
|
*/
|
||||||
|
int fdt_reserved_memory_nomap_fixup(void *fdt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General device tree fix-up
|
* General device tree fix-up
|
||||||
*
|
*
|
||||||
|
@@ -10,24 +10,59 @@
|
|||||||
#ifndef __FDT_HELPER_H__
|
#ifndef __FDT_HELPER_H__
|
||||||
#define __FDT_HELPER_H__
|
#define __FDT_HELPER_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct fdt_match {
|
||||||
|
const char *compatible;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
struct platform_uart_data {
|
struct platform_uart_data {
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
unsigned long freq;
|
unsigned long freq;
|
||||||
unsigned long baud;
|
unsigned long baud;
|
||||||
|
unsigned long reg_shift;
|
||||||
|
unsigned long reg_io_width;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_plic_data {
|
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
|
||||||
unsigned long addr;
|
const struct fdt_match *match_table);
|
||||||
unsigned long num_src;
|
|
||||||
};
|
int fdt_find_match(void *fdt, int startoff,
|
||||||
|
const struct fdt_match *match_table,
|
||||||
|
const struct fdt_match **out_match);
|
||||||
|
|
||||||
|
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
|
||||||
|
unsigned long *size);
|
||||||
|
|
||||||
|
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_shakti_uart_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
|
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
|
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
|
||||||
|
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_plic(void *fdt, struct platform_plic_data *plic,
|
struct plic_data;
|
||||||
const char *compatible);
|
|
||||||
|
|
||||||
int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
|
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
|
||||||
const char *compatible);
|
|
||||||
|
int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat);
|
||||||
|
|
||||||
|
struct clint_data;
|
||||||
|
|
||||||
|
int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
|
||||||
|
struct clint_data *clint);
|
||||||
|
|
||||||
|
int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
|
||||||
|
const char *compatible);
|
||||||
|
|
||||||
#endif /* __FDT_HELPER_H__ */
|
#endif /* __FDT_HELPER_H__ */
|
||||||
|
32
include/sbi_utils/ipi/fdt_ipi.h
Normal file
32
include/sbi_utils/ipi/fdt_ipi.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_IPI_H__
|
||||||
|
#define __FDT_IPI_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct fdt_ipi {
|
||||||
|
const struct fdt_match *match_table;
|
||||||
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
|
int (*warm_init)(void);
|
||||||
|
void (*exit)(void);
|
||||||
|
void (*send)(u32 target_hart);
|
||||||
|
void (*clear)(u32 target_hart);
|
||||||
|
};
|
||||||
|
|
||||||
|
void fdt_ipi_send(u32 target_hart);
|
||||||
|
|
||||||
|
void fdt_ipi_clear(u32 target_hart);
|
||||||
|
|
||||||
|
void fdt_ipi_exit(void);
|
||||||
|
|
||||||
|
int fdt_ipi_init(bool cold_boot);
|
||||||
|
|
||||||
|
#endif
|
26
include/sbi_utils/irqchip/fdt_irqchip.h
Normal file
26
include/sbi_utils/irqchip/fdt_irqchip.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_IRQCHIP_H__
|
||||||
|
#define __FDT_IRQCHIP_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct fdt_irqchip {
|
||||||
|
const struct fdt_match *match_table;
|
||||||
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
|
int (*warm_init)(void);
|
||||||
|
void (*exit)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
void fdt_irqchip_exit(void);
|
||||||
|
|
||||||
|
int fdt_irqchip_init(bool cold_boot);
|
||||||
|
|
||||||
|
#endif
|
@@ -12,12 +12,18 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id);
|
struct plic_data {
|
||||||
|
unsigned long addr;
|
||||||
|
unsigned long num_src;
|
||||||
|
};
|
||||||
|
|
||||||
int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count);
|
int plic_warm_irqchip_init(struct plic_data *plic,
|
||||||
|
int m_cntx_id, int s_cntx_id);
|
||||||
|
|
||||||
void plic_set_thresh(u32 cntxid, u32 val);
|
int plic_cold_irqchip_init(struct plic_data *plic);
|
||||||
|
|
||||||
void plic_set_ie(u32 cntxid, u32 word_index, u32 val);
|
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
|
||||||
|
25
include/sbi_utils/reset/fdt_reset.h
Normal file
25
include/sbi_utils/reset/fdt_reset.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_RESET_H__
|
||||||
|
#define __FDT_RESET_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct fdt_reset {
|
||||||
|
const struct fdt_match *match_table;
|
||||||
|
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
|
int (*system_reset)(u32 reset_type);
|
||||||
|
};
|
||||||
|
|
||||||
|
int fdt_system_reset(u32 reset_type);
|
||||||
|
|
||||||
|
int fdt_reset_init(void);
|
||||||
|
|
||||||
|
#endif
|
28
include/sbi_utils/serial/fdt_serial.h
Normal file
28
include/sbi_utils/serial/fdt_serial.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_SERIAL_H__
|
||||||
|
#define __FDT_SERIAL_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct fdt_serial {
|
||||||
|
const struct fdt_match *match_table;
|
||||||
|
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
|
void (*putc)(char ch);
|
||||||
|
int (*getc)(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
void fdt_serial_putc(char ch);
|
||||||
|
|
||||||
|
int fdt_serial_getc(void);
|
||||||
|
|
||||||
|
int fdt_serial_init(void);
|
||||||
|
|
||||||
|
#endif
|
18
include/sbi_utils/serial/shakti-uart.h
Normal file
18
include/sbi_utils/serial/shakti-uart.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SERIAL_SHAKTI_UART_H__
|
||||||
|
#define __SERIAL_SHAKTI_UART_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
void shakti_uart_putc(char ch);
|
||||||
|
|
||||||
|
int shakti_uart_getc(void);
|
||||||
|
|
||||||
|
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||||
|
|
||||||
|
#endif
|
@@ -12,15 +12,30 @@
|
|||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
void clint_ipi_send(u32 target_hart);
|
struct clint_data {
|
||||||
|
/* Public details */
|
||||||
|
unsigned long addr;
|
||||||
|
u32 first_hartid;
|
||||||
|
u32 hart_count;
|
||||||
|
bool has_64bit_mmio;
|
||||||
|
/* Private details (initialized and used by CLINT library)*/
|
||||||
|
u32 *ipi;
|
||||||
|
struct clint_data *time_delta_reference;
|
||||||
|
unsigned long time_delta_computed;
|
||||||
|
u64 time_delta;
|
||||||
|
u64 *time_val;
|
||||||
|
u64 *time_cmp;
|
||||||
|
u64 (*time_rd)(volatile u64 *addr);
|
||||||
|
void (*time_wr)(u64 value, volatile u64 *addr);
|
||||||
|
};
|
||||||
|
|
||||||
void clint_ipi_sync(u32 target_hart);
|
void clint_ipi_send(u32 target_hart);
|
||||||
|
|
||||||
void clint_ipi_clear(u32 target_hart);
|
void clint_ipi_clear(u32 target_hart);
|
||||||
|
|
||||||
int clint_warm_ipi_init(void);
|
int clint_warm_ipi_init(void);
|
||||||
|
|
||||||
int clint_cold_ipi_init(unsigned long base, u32 hart_count);
|
int clint_cold_ipi_init(struct clint_data *clint);
|
||||||
|
|
||||||
u64 clint_timer_value(void);
|
u64 clint_timer_value(void);
|
||||||
|
|
||||||
@@ -30,7 +45,7 @@ void clint_timer_event_start(u64 next_event);
|
|||||||
|
|
||||||
int clint_warm_timer_init(void);
|
int clint_warm_timer_init(void);
|
||||||
|
|
||||||
int clint_cold_timer_init(unsigned long base, u32 hart_count,
|
int clint_cold_timer_init(struct clint_data *clint,
|
||||||
bool has_64bit_mmio);
|
struct clint_data *reference);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -14,6 +14,6 @@ void htif_putc(char ch);
|
|||||||
|
|
||||||
int htif_getc(void);
|
int htif_getc(void);
|
||||||
|
|
||||||
int htif_system_down(u32 type);
|
int htif_system_reset(u32 type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
19
include/sbi_utils/sys/sifive_test.h
Normal file
19
include/sbi_utils/sys/sifive_test.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SYS_SIFIVE_TEST_H__
|
||||||
|
#define __SYS_SIFIVE_TEST_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
int sifive_test_system_reset(u32 type);
|
||||||
|
|
||||||
|
int sifive_test_init(unsigned long base);
|
||||||
|
|
||||||
|
#endif
|
35
include/sbi_utils/timer/fdt_timer.h
Normal file
35
include/sbi_utils/timer/fdt_timer.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDT_TIMER_H__
|
||||||
|
#define __FDT_TIMER_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct fdt_timer {
|
||||||
|
const struct fdt_match *match_table;
|
||||||
|
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
|
||||||
|
int (*warm_init)(void);
|
||||||
|
void (*exit)(void);
|
||||||
|
u64 (*value)(void);
|
||||||
|
void (*event_stop)(void);
|
||||||
|
void (*event_start)(u64 next_event);
|
||||||
|
};
|
||||||
|
|
||||||
|
u64 fdt_timer_value(void);
|
||||||
|
|
||||||
|
void fdt_timer_event_stop(void);
|
||||||
|
|
||||||
|
void fdt_timer_event_start(u64 next_event);
|
||||||
|
|
||||||
|
void fdt_timer_exit(void);
|
||||||
|
|
||||||
|
int fdt_timer_init(bool cold_boot);
|
||||||
|
|
||||||
|
#endif
|
@@ -24,12 +24,14 @@ 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
|
||||||
|
libsbi-objs-y += sbi_math.o
|
||||||
libsbi-objs-y += sbi_hfence.o
|
libsbi-objs-y += sbi_hfence.o
|
||||||
libsbi-objs-y += sbi_hsm.o
|
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_misaligned_ldst.o
|
libsbi-objs-y += sbi_misaligned_ldst.o
|
||||||
|
libsbi-objs-y += sbi_platform.o
|
||||||
libsbi-objs-y += sbi_scratch.o
|
libsbi-objs-y += sbi_scratch.o
|
||||||
libsbi-objs-y += sbi_string.o
|
libsbi-objs-y += sbi_string.o
|
||||||
libsbi-objs-y += sbi_system.o
|
libsbi-objs-y += sbi_system.o
|
||||||
@@ -37,4 +39,4 @@ libsbi-objs-y += sbi_timer.o
|
|||||||
libsbi-objs-y += sbi_tlb.o
|
libsbi-objs-y += sbi_tlb.o
|
||||||
libsbi-objs-y += sbi_trap.o
|
libsbi-objs-y += sbi_trap.o
|
||||||
libsbi-objs-y += sbi_unpriv.o
|
libsbi-objs-y += sbi_unpriv.o
|
||||||
libsbi-objs-y += sbi_unpriv_trap.o
|
libsbi-objs-y += sbi_expected_trap.o
|
||||||
|
@@ -17,8 +17,13 @@ int misa_extension_imp(char ext)
|
|||||||
{
|
{
|
||||||
unsigned long misa = csr_read(CSR_MISA);
|
unsigned long misa = csr_read(CSR_MISA);
|
||||||
|
|
||||||
if (misa)
|
if (misa) {
|
||||||
return misa & (1 << (ext - 'A'));
|
if ('A' <= ext && ext <= 'Z')
|
||||||
|
return misa & (1 << (ext - 'A'));
|
||||||
|
if ('a' <= ext && ext <= 'z')
|
||||||
|
return misa & (1 << (ext - 'a'));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return sbi_platform_misa_extension(sbi_platform_thishart_ptr(), ext);
|
return sbi_platform_misa_extension(sbi_platform_thishart_ptr(), ext);
|
||||||
}
|
}
|
||||||
@@ -44,6 +49,45 @@ int misa_xlen(void)
|
|||||||
return r ? r : -1;
|
return r ? r : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void misa_string(int xlen, char *out, unsigned int out_sz)
|
||||||
|
{
|
||||||
|
unsigned int i, pos = 0;
|
||||||
|
const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
|
||||||
|
|
||||||
|
if (!out)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (5 <= (out_sz - pos)) {
|
||||||
|
out[pos++] = 'r';
|
||||||
|
out[pos++] = 'v';
|
||||||
|
switch (xlen) {
|
||||||
|
case 1:
|
||||||
|
out[pos++] = '3';
|
||||||
|
out[pos++] = '2';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
out[pos++] = '6';
|
||||||
|
out[pos++] = '4';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
out[pos++] = '1';
|
||||||
|
out[pos++] = '2';
|
||||||
|
out[pos++] = '8';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < array_size(valid_isa_order) && (pos < out_sz); i++) {
|
||||||
|
if (misa_extension_imp(valid_isa_order[i]))
|
||||||
|
out[pos++] = valid_isa_order[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < out_sz)
|
||||||
|
out[pos++] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long csr_read_num(int csr_num)
|
unsigned long csr_read_num(int csr_num)
|
||||||
{
|
{
|
||||||
unsigned long ret = 0;
|
unsigned long ret = 0;
|
||||||
@@ -224,7 +268,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
|
|||||||
|
|
||||||
/* encode PMP config */
|
/* encode PMP config */
|
||||||
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
|
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
|
||||||
cfgmask = ~(0xff << pmpcfg_shift);
|
cfgmask = ~(0xffUL << pmpcfg_shift);
|
||||||
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
|
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
|
||||||
pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
|
pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
|
||||||
|
|
||||||
@@ -276,7 +320,7 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
|
|||||||
return SBI_ENOTSUPP;
|
return SBI_ENOTSUPP;
|
||||||
|
|
||||||
/* decode PMP config */
|
/* decode PMP config */
|
||||||
cfgmask = (0xff << pmpcfg_shift);
|
cfgmask = (0xffUL << pmpcfg_shift);
|
||||||
pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
|
pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
|
||||||
prot = pmpcfg >> pmpcfg_shift;
|
prot = pmpcfg >> pmpcfg_shift;
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
* Anup Patel <anup.patel@wdc.com>
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_console.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_error.h>
|
||||||
@@ -124,6 +125,13 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
|
|||||||
trap.epc = regs->mepc;
|
trap.epc = regs->mepc;
|
||||||
sbi_trap_redirect(regs, &trap);
|
sbi_trap_redirect(regs, &trap);
|
||||||
} else {
|
} else {
|
||||||
|
if (ret < SBI_LAST_ERR) {
|
||||||
|
sbi_printf("%s: Invalid error %d for ext=0x%lx "
|
||||||
|
"func=0x%lx\n", __func__, ret,
|
||||||
|
extension_id, func_id);
|
||||||
|
ret = SBI_ERR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function should return non-zero value only in case of
|
* This function should return non-zero value only in case of
|
||||||
* fatal error. However, there is no good way to distinguish
|
* fatal error. However, there is no good way to distinguish
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_hsm.h>
|
#include <sbi/sbi_hsm.h>
|
||||||
#include <sbi/sbi_ipi.h>
|
#include <sbi/sbi_ipi.h>
|
||||||
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_system.h>
|
#include <sbi/sbi_system.h>
|
||||||
#include <sbi/sbi_timer.h>
|
#include <sbi/sbi_timer.h>
|
||||||
#include <sbi/sbi_tlb.h>
|
#include <sbi/sbi_tlb.h>
|
||||||
@@ -75,7 +76,7 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
|||||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||||
&hmask, out_trap);
|
&hmask, out_trap);
|
||||||
if (ret != SBI_ETRAP) {
|
if (ret != SBI_ETRAP) {
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0,
|
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
||||||
SBI_ITLB_FLUSH, source_hart);
|
SBI_ITLB_FLUSH, source_hart);
|
||||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||||
}
|
}
|
||||||
@@ -84,7 +85,7 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
|||||||
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
ret = sbi_load_hart_mask_unpriv((ulong *)args[0],
|
||||||
&hmask, out_trap);
|
&hmask, out_trap);
|
||||||
if (ret != SBI_ETRAP) {
|
if (ret != SBI_ETRAP) {
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0,
|
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], 0, 0,
|
||||||
SBI_TLB_FLUSH_VMA, source_hart);
|
SBI_TLB_FLUSH_VMA, source_hart);
|
||||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||||
}
|
}
|
||||||
@@ -94,12 +95,13 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
|
|||||||
&hmask, out_trap);
|
&hmask, out_trap);
|
||||||
if (ret != SBI_ETRAP) {
|
if (ret != SBI_ETRAP) {
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3],
|
SBI_TLB_INFO_INIT(&tlb_info, args[1], args[2], args[3],
|
||||||
SBI_TLB_FLUSH_VMA_ASID, source_hart);
|
0, SBI_TLB_FLUSH_VMA_ASID,
|
||||||
|
source_hart);
|
||||||
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
ret = sbi_tlb_request(hmask, 0, &tlb_info);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_0_1_SHUTDOWN:
|
case SBI_EXT_0_1_SHUTDOWN:
|
||||||
sbi_system_shutdown(0);
|
sbi_system_reset(SBI_PLATFORM_RESET_SHUTDOWN);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SBI_ENOTSUPP;
|
ret = SBI_ENOTSUPP;
|
||||||
|
@@ -46,6 +46,7 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
|||||||
struct sbi_trap_info *out_trap)
|
struct sbi_trap_info *out_trap)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
unsigned long vmid;
|
||||||
struct sbi_tlb_info tlb_info;
|
struct sbi_tlb_info tlb_info;
|
||||||
u32 source_hart = current_hartid();
|
u32 source_hart = current_hartid();
|
||||||
|
|
||||||
@@ -56,37 +57,41 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
|
|||||||
|
|
||||||
switch (funcid) {
|
switch (funcid) {
|
||||||
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
|
case SBI_EXT_RFENCE_REMOTE_FENCE_I:
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0,
|
SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
|
||||||
SBI_ITLB_FLUSH, source_hart);
|
SBI_ITLB_FLUSH, source_hart);
|
||||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
|
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0,
|
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
|
||||||
SBI_TLB_FLUSH_GVMA, source_hart);
|
SBI_TLB_FLUSH_GVMA, source_hart);
|
||||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
|
case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4],
|
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, args[4],
|
||||||
SBI_TLB_FLUSH_GVMA_VMID, source_hart);
|
SBI_TLB_FLUSH_GVMA_VMID, source_hart);
|
||||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
|
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0,
|
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
|
||||||
|
vmid = vmid >> HGATP_VMID_SHIFT;
|
||||||
|
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, vmid,
|
||||||
SBI_TLB_FLUSH_VVMA, source_hart);
|
SBI_TLB_FLUSH_VVMA, source_hart);
|
||||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
|
case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4],
|
vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
|
||||||
|
vmid = vmid >> HGATP_VMID_SHIFT;
|
||||||
|
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], vmid,
|
||||||
SBI_TLB_FLUSH_VVMA_ASID, source_hart);
|
SBI_TLB_FLUSH_VVMA_ASID, source_hart);
|
||||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
|
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0,
|
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], 0, 0,
|
||||||
SBI_TLB_FLUSH_VMA, source_hart);
|
SBI_TLB_FLUSH_VMA, source_hart);
|
||||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||||
break;
|
break;
|
||||||
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
|
case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
|
||||||
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4],
|
SBI_TLB_INFO_INIT(&tlb_info, args[2], args[3], args[4], 0,
|
||||||
SBI_TLB_FLUSH_VMA_ASID, source_hart);
|
SBI_TLB_FLUSH_VMA_ASID, source_hart);
|
||||||
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
ret = sbi_tlb_request(args[0], args[1], &tlb_info);
|
||||||
break;
|
break;
|
||||||
|
@@ -11,8 +11,8 @@
|
|||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume that faulting unpriv load/store instruction is
|
* We assume that faulting instruction is is 4-byte long and blindly
|
||||||
* 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:
|
||||||
* A3 <- pointer struct sbi_trap_info
|
* A3 <- pointer struct sbi_trap_info
|
||||||
@@ -20,8 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_unpriv_trap
|
.global __sbi_expected_trap
|
||||||
__sbi_unpriv_trap:
|
__sbi_expected_trap:
|
||||||
/* Without H-extension so, MTVAL2 and MTINST CSRs not available */
|
/* Without H-extension so, MTVAL2 and MTINST CSRs 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)
|
||||||
@@ -37,8 +37,8 @@ __sbi_unpriv_trap:
|
|||||||
mret
|
mret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_unpriv_trap_hext
|
.global __sbi_expected_trap_hext
|
||||||
__sbi_unpriv_trap_hext:
|
__sbi_expected_trap_hext:
|
||||||
/* With H-extension so, MTVAL2 and MTINST CSRs available */
|
/* With H-extension so, MTVAL2 and MTINST CSRs 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)
|
@@ -13,18 +13,26 @@
|
|||||||
#include <sbi/riscv_fp.h>
|
#include <sbi/riscv_fp.h>
|
||||||
#include <sbi/sbi_bitops.h>
|
#include <sbi/sbi_bitops.h>
|
||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_csr_detect.h>
|
||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_hart.h>
|
#include <sbi/sbi_hart.h>
|
||||||
|
#include <sbi/sbi_math.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
|
#include <sbi/sbi_string.h>
|
||||||
|
|
||||||
extern void __sbi_unpriv_trap(void);
|
extern void __sbi_expected_trap(void);
|
||||||
extern void __sbi_unpriv_trap_hext(void);
|
extern void __sbi_expected_trap_hext(void);
|
||||||
|
|
||||||
void (*sbi_hart_unpriv_trap)(void) = &__sbi_unpriv_trap;
|
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
|
||||||
|
|
||||||
|
struct hart_features {
|
||||||
|
unsigned long features;
|
||||||
|
unsigned int pmp_count;
|
||||||
|
};
|
||||||
|
static unsigned long hart_features_offset;
|
||||||
|
|
||||||
static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
|
static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
|
||||||
{
|
{
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
|
||||||
unsigned long mstatus_val = 0;
|
unsigned long mstatus_val = 0;
|
||||||
|
|
||||||
/* Enable FPU */
|
/* Enable FPU */
|
||||||
@@ -38,9 +46,10 @@ static void mstatus_init(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
csr_write(CSR_MSTATUS, mstatus_val);
|
csr_write(CSR_MSTATUS, mstatus_val);
|
||||||
|
|
||||||
/* Enable user/supervisor use of perf counters */
|
/* Enable user/supervisor use of perf counters */
|
||||||
if (misa_extension('S') && sbi_platform_has_scounteren(plat))
|
if (misa_extension('S') &&
|
||||||
|
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
|
||||||
csr_write(CSR_SCOUNTEREN, -1);
|
csr_write(CSR_SCOUNTEREN, -1);
|
||||||
if (sbi_platform_has_mcounteren(plat))
|
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
|
||||||
csr_write(CSR_MCOUNTEREN, -1);
|
csr_write(CSR_MCOUNTEREN, -1);
|
||||||
|
|
||||||
/* Disable all interrupts */
|
/* Disable all interrupts */
|
||||||
@@ -101,6 +110,7 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
|
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
|
||||||
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
|
exceptions |= (1U << CAUSE_FETCH_GUEST_PAGE_FAULT);
|
||||||
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
|
exceptions |= (1U << CAUSE_LOAD_GUEST_PAGE_FAULT);
|
||||||
|
exceptions |= (1U << CAUSE_VIRTUAL_INST_FAULT);
|
||||||
exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
|
exceptions |= (1U << CAUSE_STORE_GUEST_PAGE_FAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +122,10 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
|
|
||||||
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
|
void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
|
if (!misa_extension('S'))
|
||||||
|
/* No delegation possible as mideleg does not exist*/
|
||||||
|
return;
|
||||||
|
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
|
sbi_printf("MIDELEG : 0x%08lx\n", csr_read(CSR_MIDELEG));
|
||||||
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
|
sbi_printf("MEDELEG : 0x%08lx\n", csr_read(CSR_MEDELEG));
|
||||||
@@ -121,29 +135,34 @@ void sbi_hart_delegation_dump(struct sbi_scratch *scratch)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long log2roundup(unsigned long x)
|
unsigned int sbi_hart_pmp_count(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
unsigned long ret = 0;
|
struct hart_features *hfeatures =
|
||||||
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
while (ret < __riscv_xlen) {
|
return hfeatures->pmp_count;
|
||||||
if (x <= (1UL << ret))
|
}
|
||||||
break;
|
|
||||||
ret++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
int sbi_hart_pmp_get(struct sbi_scratch *scratch, unsigned int n,
|
||||||
|
unsigned long *prot_out, unsigned long *addr_out,
|
||||||
|
unsigned long *size)
|
||||||
|
{
|
||||||
|
if (sbi_hart_pmp_count(scratch) <= n)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
return pmp_get(n, prot_out, addr_out, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
|
void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
|
||||||
{
|
{
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
|
||||||
unsigned long prot, addr, size;
|
unsigned long prot, addr, size;
|
||||||
unsigned int i;
|
unsigned int i, pmp_count;
|
||||||
|
|
||||||
if (!sbi_platform_has_pmp(plat))
|
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < PMP_COUNT; i++) {
|
pmp_count = sbi_hart_pmp_count(scratch);
|
||||||
|
for (i = 0; i < pmp_count; i++) {
|
||||||
pmp_get(i, &prot, &addr, &size);
|
pmp_get(i, &prot, &addr, &size);
|
||||||
if (!(prot & PMP_A))
|
if (!(prot & PMP_A))
|
||||||
continue;
|
continue;
|
||||||
@@ -168,19 +187,20 @@ void sbi_hart_pmp_dump(struct sbi_scratch *scratch)
|
|||||||
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
|
int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
|
||||||
unsigned long attr)
|
unsigned long attr)
|
||||||
{
|
{
|
||||||
unsigned long prot, size, i, tempaddr;
|
unsigned long prot, size, tempaddr;
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
unsigned int i, pmp_count;
|
||||||
|
|
||||||
if (!sbi_platform_has_pmp(plat))
|
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||||
return SBI_OK;
|
return SBI_OK;
|
||||||
|
|
||||||
for (i = 0; i < PMP_COUNT; i++) {
|
pmp_count = sbi_hart_pmp_count(scratch);
|
||||||
|
for (i = 0; i < pmp_count; i++) {
|
||||||
pmp_get(i, &prot, &tempaddr, &size);
|
pmp_get(i, &prot, &tempaddr, &size);
|
||||||
if (!(prot & PMP_A))
|
if (!(prot & PMP_A))
|
||||||
continue;
|
continue;
|
||||||
if (tempaddr <= addr && addr <= tempaddr + size)
|
if (tempaddr <= addr && addr <= tempaddr + size)
|
||||||
if (!(prot & attr))
|
if (!(prot & attr))
|
||||||
return SBI_INVALID_ADDR;
|
return SBI_EINVALID_ADDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SBI_OK;
|
return SBI_OK;
|
||||||
@@ -188,42 +208,219 @@ int sbi_hart_pmp_check_addr(struct sbi_scratch *scratch, unsigned long addr,
|
|||||||
|
|
||||||
static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
|
static int pmp_init(struct sbi_scratch *scratch, u32 hartid)
|
||||||
{
|
{
|
||||||
u32 i, count;
|
u32 i, pmp_idx = 0, pmp_count, count;
|
||||||
unsigned long fw_start, fw_size_log2;
|
unsigned long fw_start, fw_size_log2;
|
||||||
ulong prot, addr, log2size;
|
ulong prot, addr, log2size;
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
|
||||||
if (!sbi_platform_has_pmp(plat))
|
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Firmware PMP region to protect OpenSBI firmware */
|
||||||
fw_size_log2 = log2roundup(scratch->fw_size);
|
fw_size_log2 = log2roundup(scratch->fw_size);
|
||||||
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
|
fw_start = scratch->fw_start & ~((1UL << fw_size_log2) - 1UL);
|
||||||
|
pmp_set(pmp_idx++, 0, fw_start, fw_size_log2);
|
||||||
pmp_set(0, 0, fw_start, fw_size_log2);
|
|
||||||
|
|
||||||
|
/* Platform specific PMP regions */
|
||||||
count = sbi_platform_pmp_region_count(plat, hartid);
|
count = sbi_platform_pmp_region_count(plat, hartid);
|
||||||
if ((PMP_COUNT - 1) < count)
|
pmp_count = sbi_hart_pmp_count(scratch);
|
||||||
count = (PMP_COUNT - 1);
|
for (i = 0; i < count && pmp_idx < (pmp_count - 1); i++) {
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
|
if (sbi_platform_pmp_region_info(plat, hartid, i, &prot, &addr,
|
||||||
&log2size))
|
&log2size))
|
||||||
continue;
|
continue;
|
||||||
pmp_set(i + 1, prot, addr, log2size);
|
pmp_set(pmp_idx++, prot, addr, log2size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default PMP region for allowing S-mode and U-mode access to
|
||||||
|
* memory not covered by:
|
||||||
|
* 1) Firmware PMP region
|
||||||
|
* 2) Platform specific PMP regions
|
||||||
|
*/
|
||||||
|
pmp_set(pmp_idx++, PMP_R | PMP_W | PMP_X, 0, __riscv_xlen);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 =
|
||||||
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
|
if (hfeatures->features & feature)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long hart_get_features(struct sbi_scratch *scratch)
|
||||||
|
{
|
||||||
|
struct hart_features *hfeatures =
|
||||||
|
sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
|
||||||
|
return hfeatures->features;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char *sbi_hart_feature_id2string(unsigned long feature)
|
||||||
|
{
|
||||||
|
char *fstr = NULL;
|
||||||
|
|
||||||
|
if (!feature)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
switch (feature) {
|
||||||
|
case SBI_HART_HAS_PMP:
|
||||||
|
fstr = "pmp";
|
||||||
|
break;
|
||||||
|
case SBI_HART_HAS_SCOUNTEREN:
|
||||||
|
fstr = "scounteren";
|
||||||
|
break;
|
||||||
|
case SBI_HART_HAS_MCOUNTEREN:
|
||||||
|
fstr = "mcounteren";
|
||||||
|
break;
|
||||||
|
case SBI_HART_HAS_TIME:
|
||||||
|
fstr = "time";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the hart features in string format
|
||||||
|
*
|
||||||
|
* @param scratch pointer to the HART scratch space
|
||||||
|
* @param features_str pointer to a char array where the features string will be
|
||||||
|
* updated
|
||||||
|
* @param nfstr length of the features_str. The feature string will be truncated
|
||||||
|
* if nfstr is not long enough.
|
||||||
|
*/
|
||||||
|
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
|
||||||
|
char *features_str, int nfstr)
|
||||||
|
{
|
||||||
|
unsigned long features, feat = 1UL;
|
||||||
|
char *temp;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
if (!features_str || nfstr <= 0)
|
||||||
|
return;
|
||||||
|
sbi_memset(features_str, 0, nfstr);
|
||||||
|
|
||||||
|
features = hart_get_features(scratch);
|
||||||
|
if (!features)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (features & feat) {
|
||||||
|
temp = sbi_hart_feature_id2string(feat);
|
||||||
|
if (temp) {
|
||||||
|
sbi_snprintf(features_str + offset, nfstr,
|
||||||
|
"%s,", temp);
|
||||||
|
offset = offset + sbi_strlen(temp) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
feat = feat << 1;
|
||||||
|
} while (feat <= SBI_HART_HAS_LAST_FEATURE);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (offset)
|
||||||
|
features_str[offset - 1] = '\0';
|
||||||
|
else
|
||||||
|
sbi_strncpy(features_str, "none", nfstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hart_detect_features(struct sbi_scratch *scratch)
|
||||||
|
{
|
||||||
|
struct sbi_trap_info trap = {0};
|
||||||
|
struct hart_features *hfeatures;
|
||||||
|
unsigned long val;
|
||||||
|
|
||||||
|
/* Reset hart features */
|
||||||
|
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
|
||||||
|
hfeatures->features = 0;
|
||||||
|
hfeatures->pmp_count = 0;
|
||||||
|
|
||||||
|
/* Detect if hart supports PMP feature */
|
||||||
|
#define __detect_pmp(__pmp_csr) \
|
||||||
|
val = csr_read_allowed(__pmp_csr, (ulong)&trap); \
|
||||||
|
if (!trap.cause) { \
|
||||||
|
csr_write_allowed(__pmp_csr, (ulong)&trap, val);\
|
||||||
|
if (!trap.cause) \
|
||||||
|
hfeatures->pmp_count++; \
|
||||||
|
}
|
||||||
|
__detect_pmp(CSR_PMPADDR0);
|
||||||
|
__detect_pmp(CSR_PMPADDR1);
|
||||||
|
__detect_pmp(CSR_PMPADDR2);
|
||||||
|
__detect_pmp(CSR_PMPADDR3);
|
||||||
|
__detect_pmp(CSR_PMPADDR4);
|
||||||
|
__detect_pmp(CSR_PMPADDR5);
|
||||||
|
__detect_pmp(CSR_PMPADDR6);
|
||||||
|
__detect_pmp(CSR_PMPADDR7);
|
||||||
|
__detect_pmp(CSR_PMPADDR8);
|
||||||
|
__detect_pmp(CSR_PMPADDR9);
|
||||||
|
__detect_pmp(CSR_PMPADDR10);
|
||||||
|
__detect_pmp(CSR_PMPADDR11);
|
||||||
|
__detect_pmp(CSR_PMPADDR12);
|
||||||
|
__detect_pmp(CSR_PMPADDR13);
|
||||||
|
__detect_pmp(CSR_PMPADDR14);
|
||||||
|
__detect_pmp(CSR_PMPADDR15);
|
||||||
|
#undef __detect_pmp
|
||||||
|
|
||||||
|
/* Set hart PMP feature if we have at least one PMP region */
|
||||||
|
if (hfeatures->pmp_count)
|
||||||
|
hfeatures->features |= SBI_HART_HAS_PMP;
|
||||||
|
|
||||||
|
/* Detect if hart supports SCOUNTEREN feature */
|
||||||
|
trap.cause = 0;
|
||||||
|
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
|
||||||
|
if (!trap.cause) {
|
||||||
|
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
|
||||||
|
if (!trap.cause)
|
||||||
|
hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detect if hart supports MCOUNTEREN feature */
|
||||||
|
trap.cause = 0;
|
||||||
|
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
|
||||||
|
if (!trap.cause) {
|
||||||
|
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
|
||||||
|
if (!trap.cause)
|
||||||
|
hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detect if hart supports time CSR */
|
||||||
|
trap.cause = 0;
|
||||||
|
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
|
||||||
|
if (!trap.cause)
|
||||||
|
hfeatures->features |= SBI_HART_HAS_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
int sbi_hart_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
if (misa_extension('H'))
|
if (misa_extension('H'))
|
||||||
sbi_hart_unpriv_trap = &__sbi_unpriv_trap_hext;
|
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
|
||||||
|
|
||||||
|
hart_features_offset = sbi_scratch_alloc_offset(
|
||||||
|
sizeof(struct hart_features),
|
||||||
|
"HART_FEATURES");
|
||||||
|
if (!hart_features_offset)
|
||||||
|
return SBI_ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hart_detect_features(scratch);
|
||||||
|
|
||||||
mstatus_init(scratch, hartid);
|
mstatus_init(scratch, hartid);
|
||||||
|
|
||||||
rc = fp_init(hartid);
|
rc = fp_init(hartid);
|
||||||
|
@@ -9,67 +9,127 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Instruction encoding of hfence.gvma is:
|
* HFENCE.GVMA rs1, rs2
|
||||||
|
* HFENCE.GVMA zero, rs2
|
||||||
|
* HFENCE.GVMA rs1
|
||||||
|
* HFENCE.GVMA
|
||||||
|
*
|
||||||
|
* rs1!=zero and rs2!=zero ==> HFENCE.GVMA rs1, rs2
|
||||||
|
* rs1==zero and rs2!=zero ==> HFENCE.GVMA zero, rs2
|
||||||
|
* rs1!=zero and rs2==zero ==> HFENCE.GVMA rs1
|
||||||
|
* rs1==zero and rs2==zero ==> HFENCE.GVMA
|
||||||
|
*
|
||||||
|
* Instruction encoding of HFENCE.GVMA is:
|
||||||
* 0110001 rs2(5) rs1(5) 000 00000 1110011
|
* 0110001 rs2(5) rs1(5) 000 00000 1110011
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_hfence_gvma_vmid_gpa
|
.global __sbi_hfence_gvma_vmid_gpa
|
||||||
__sbi_hfence_gvma_vmid_gpa:
|
__sbi_hfence_gvma_vmid_gpa:
|
||||||
/* hfence.gvma a1, a0 */
|
/*
|
||||||
.word 0x62a60073
|
* rs1 = a0 (GPA)
|
||||||
|
* rs2 = a1 (VMID)
|
||||||
|
* HFENCE.GVMA a0, a1
|
||||||
|
* 0110001 01011 01010 000 00000 1110011
|
||||||
|
*/
|
||||||
|
.word 0x62b50073
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_hfence_gvma_vmid
|
.global __sbi_hfence_gvma_vmid
|
||||||
__sbi_hfence_gvma_vmid:
|
__sbi_hfence_gvma_vmid:
|
||||||
/* hfence.gvma zero, a0 */
|
/*
|
||||||
|
* rs1 = zero
|
||||||
|
* rs2 = a0 (VMID)
|
||||||
|
* HFENCE.GVMA zero, a0
|
||||||
|
* 0110001 01010 00000 000 00000 1110011
|
||||||
|
*/
|
||||||
.word 0x62a00073
|
.word 0x62a00073
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_hfence_gvma_gpa
|
.global __sbi_hfence_gvma_gpa
|
||||||
__sbi_hfence_gvma_gpa:
|
__sbi_hfence_gvma_gpa:
|
||||||
/* hfence.gvma a0 */
|
/*
|
||||||
|
* rs1 = a0 (GPA)
|
||||||
|
* rs2 = zero
|
||||||
|
* HFENCE.GVMA a0
|
||||||
|
* 0110001 00000 01010 000 00000 1110011
|
||||||
|
*/
|
||||||
.word 0x62050073
|
.word 0x62050073
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_hfence_gvma_all
|
.global __sbi_hfence_gvma_all
|
||||||
__sbi_hfence_gvma_all:
|
__sbi_hfence_gvma_all:
|
||||||
/* hfence.gvma */
|
/*
|
||||||
|
* rs1 = zero
|
||||||
|
* rs2 = zero
|
||||||
|
* HFENCE.GVMA
|
||||||
|
* 0110001 00000 00000 000 00000 1110011
|
||||||
|
*/
|
||||||
.word 0x62000073
|
.word 0x62000073
|
||||||
ret
|
ret
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Instruction encoding of hfence.bvma is:
|
* HFENCE.VVMA rs1, rs2
|
||||||
|
* HFENCE.VVMA zero, rs2
|
||||||
|
* HFENCE.VVMA rs1
|
||||||
|
* HFENCE.VVMA
|
||||||
|
*
|
||||||
|
* rs1!=zero and rs2!=zero ==> HFENCE.VVMA rs1, rs2
|
||||||
|
* rs1==zero and rs2!=zero ==> HFENCE.VVMA zero, rs2
|
||||||
|
* rs1!=zero and rs2==zero ==> HFENCE.VVMA rs1
|
||||||
|
* rs1==zero and rs2==zero ==> HFENCE.vVMA
|
||||||
|
*
|
||||||
|
* Instruction encoding of HFENCE.VVMA is:
|
||||||
* 0010001 rs2(5) rs1(5) 000 00000 1110011
|
* 0010001 rs2(5) rs1(5) 000 00000 1110011
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_hfence_vvma_asid_va
|
.global __sbi_hfence_vvma_asid_va
|
||||||
__sbi_hfence_vvma_asid_va:
|
__sbi_hfence_vvma_asid_va:
|
||||||
/* hfence.bvma a1, a0 */
|
/*
|
||||||
.word 0x22a60073
|
* rs1 = a0 (VA)
|
||||||
|
* rs2 = a1 (ASID)
|
||||||
|
* HFENCE.VVMA a0, a1
|
||||||
|
* 0010001 01011 01010 000 00000 1110011
|
||||||
|
*/
|
||||||
|
.word 0x22b50073
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_hfence_vvma_asid
|
.global __sbi_hfence_vvma_asid
|
||||||
__sbi_hfence_vvma_asid:
|
__sbi_hfence_vvma_asid:
|
||||||
/* hfence.bvma zero, a0 */
|
/*
|
||||||
|
* rs1 = zero
|
||||||
|
* rs2 = a0 (ASID)
|
||||||
|
* HFENCE.VVMA zero, a0
|
||||||
|
* 0010001 01010 00000 000 00000 1110011
|
||||||
|
*/
|
||||||
.word 0x22a00073
|
.word 0x22a00073
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_hfence_vvma_va
|
.global __sbi_hfence_vvma_va
|
||||||
__sbi_hfence_vvma_va:
|
__sbi_hfence_vvma_va:
|
||||||
/* hfence.bvma a0 */
|
/*
|
||||||
|
* rs1 = a0 (VA)
|
||||||
|
* rs2 = zero
|
||||||
|
* HFENCE.VVMA zero, a0
|
||||||
|
* 0010001 00000 01010 000 00000 1110011
|
||||||
|
*/
|
||||||
.word 0x22050073
|
.word 0x22050073
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.align 3
|
.align 3
|
||||||
.global __sbi_hfence_vvma_all
|
.global __sbi_hfence_vvma_all
|
||||||
__sbi_hfence_vvma_all:
|
__sbi_hfence_vvma_all:
|
||||||
/* hfence.bvma */
|
/*
|
||||||
|
* rs1 = zero
|
||||||
|
* rs2 = zero
|
||||||
|
* HFENCE.VVMA
|
||||||
|
* 0010001 00000 00000 000 00000 1110011
|
||||||
|
*/
|
||||||
.word 0x22000073
|
.word 0x22000073
|
||||||
ret
|
ret
|
||||||
|
@@ -219,7 +219,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch, u32 hartid,
|
|||||||
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
|
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
|
||||||
SBI_HART_STARTING);
|
SBI_HART_STARTING);
|
||||||
if (hstate == SBI_HART_STARTED)
|
if (hstate == SBI_HART_STARTED)
|
||||||
return SBI_EALREADY_STARTED;
|
return SBI_EALREADY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if a hart is already transition to start or stop, another start call
|
* if a hart is already transition to start or stop, another start call
|
||||||
@@ -263,7 +263,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
|
|||||||
if (oldstate != SBI_HART_STARTED) {
|
if (oldstate != SBI_HART_STARTED) {
|
||||||
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
|
||||||
__func__, oldstate);
|
__func__, oldstate);
|
||||||
return SBI_DENIED;
|
return SBI_EDENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exitnow)
|
if (exitnow)
|
||||||
|
@@ -38,17 +38,7 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
|
|||||||
int csr_num = (u32)insn >> 20;
|
int csr_num = (u32)insn >> 20;
|
||||||
ulong csr_val, new_csr_val;
|
ulong csr_val, new_csr_val;
|
||||||
|
|
||||||
/*
|
/* TODO: Ensure that we got CSR read/write instruction */
|
||||||
* WFI always traps as illegal instruction when executed from
|
|
||||||
* VS/VU mode so we just forward it to HS-mode.
|
|
||||||
*/
|
|
||||||
#if __riscv_xlen == 32
|
|
||||||
if ((regs->mstatusH & MSTATUSH_MPV) &&
|
|
||||||
#else
|
|
||||||
if ((regs->mstatus & MSTATUS_MPV) &&
|
|
||||||
#endif
|
|
||||||
(insn & INSN_MASK_WFI) == INSN_MATCH_WFI)
|
|
||||||
return truly_illegal_insn(insn, regs);
|
|
||||||
|
|
||||||
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
|
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
|
||||||
return truly_illegal_insn(insn, regs);
|
return truly_illegal_insn(insn, regs);
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include <sbi/sbi_ipi.h>
|
#include <sbi/sbi_ipi.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_system.h>
|
#include <sbi/sbi_system.h>
|
||||||
|
#include <sbi/sbi_string.h>
|
||||||
#include <sbi/sbi_timer.h>
|
#include <sbi/sbi_timer.h>
|
||||||
#include <sbi/sbi_tlb.h>
|
#include <sbi/sbi_tlb.h>
|
||||||
#include <sbi/sbi_version.h>
|
#include <sbi/sbi_version.h>
|
||||||
@@ -35,7 +36,7 @@
|
|||||||
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
||||||
{
|
{
|
||||||
int xlen;
|
int xlen;
|
||||||
char str[64];
|
char str[128];
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
|
||||||
#ifdef OPENSBI_VERSION_GIT
|
#ifdef OPENSBI_VERSION_GIT
|
||||||
@@ -53,19 +54,29 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
|
|||||||
sbi_printf("Error %d getting MISA XLEN\n", xlen);
|
sbi_printf("Error %d getting MISA XLEN\n", xlen);
|
||||||
sbi_hart_hang();
|
sbi_hart_hang();
|
||||||
}
|
}
|
||||||
xlen = 16 * (1 << xlen);
|
|
||||||
misa_string(str, sizeof(str));
|
|
||||||
|
|
||||||
/* Platform details */
|
/* Platform details */
|
||||||
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
|
sbi_printf("Platform Name : %s\n", sbi_platform_name(plat));
|
||||||
sbi_printf("Platform HART Features : RV%d%s\n", xlen, str);
|
sbi_platform_get_features_str(plat, str, sizeof(str));
|
||||||
sbi_printf("Current Hart : %u\n", hartid);
|
sbi_printf("Platform Features : %s\n", str);
|
||||||
|
sbi_printf("Platform HART Count : %u\n",
|
||||||
|
sbi_platform_hart_count(plat));
|
||||||
|
|
||||||
|
/* Boot HART details */
|
||||||
|
sbi_printf("Boot HART ID : %u\n", hartid);
|
||||||
|
misa_string(xlen, str, sizeof(str));
|
||||||
|
sbi_printf("Boot HART ISA : %s\n", str);
|
||||||
|
sbi_hart_get_features_str(scratch, str, sizeof(str));
|
||||||
|
sbi_printf("BOOT HART Features : %s\n", str);
|
||||||
|
sbi_printf("BOOT HART PMP Count : %d\n", sbi_hart_pmp_count(scratch));
|
||||||
|
|
||||||
/* Firmware details */
|
/* Firmware details */
|
||||||
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
|
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
|
||||||
sbi_printf("Firmware Size : %d KB\n",
|
sbi_printf("Firmware Size : %d KB\n",
|
||||||
(u32)(scratch->fw_size / 1024));
|
(u32)(scratch->fw_size / 1024));
|
||||||
|
|
||||||
/* Generic details */
|
/* Generic details */
|
||||||
sbi_printf("Runtime SBI Version : %d.%d\n",
|
sbi_printf("Runtime SBI Version : %d.%d\n",
|
||||||
sbi_ecall_version_major(), sbi_ecall_version_minor());
|
sbi_ecall_version_major(), sbi_ecall_version_minor());
|
||||||
sbi_printf("\n");
|
sbi_printf("\n");
|
||||||
|
|
||||||
|
23
lib/sbi/sbi_math.c
Normal file
23
lib/sbi/sbi_math.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Common helper functions used across OpenSBI project.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Atish Patra <atish.patra@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned long log2roundup(unsigned long x)
|
||||||
|
{
|
||||||
|
unsigned long ret = 0;
|
||||||
|
|
||||||
|
while (ret < __riscv_xlen) {
|
||||||
|
if (x <= (1UL << ret))
|
||||||
|
break;
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
90
lib/sbi/sbi_platform.c
Normal file
90
lib/sbi/sbi_platform.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Atish Patra <atish.patra@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_platform.h>
|
||||||
|
#include <sbi/sbi_string.h>
|
||||||
|
|
||||||
|
static inline char *sbi_platform_feature_id2string(unsigned long feature)
|
||||||
|
{
|
||||||
|
char *fstr = NULL;
|
||||||
|
|
||||||
|
if (!feature)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
switch (feature) {
|
||||||
|
case SBI_PLATFORM_HAS_TIMER_VALUE:
|
||||||
|
fstr = "timer";
|
||||||
|
break;
|
||||||
|
case SBI_PLATFORM_HAS_HART_HOTPLUG:
|
||||||
|
fstr = "hotplug";
|
||||||
|
break;
|
||||||
|
case SBI_PLATFORM_HAS_MFAULTS_DELEGATION:
|
||||||
|
fstr = "mfdeleg";
|
||||||
|
break;
|
||||||
|
case SBI_PLATFORM_HAS_HART_SECONDARY_BOOT:
|
||||||
|
fstr = "sec_boot";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sbi_platform_get_features_str(const struct sbi_platform *plat,
|
||||||
|
char *features_str, int nfstr)
|
||||||
|
{
|
||||||
|
unsigned long features, feat = 1UL;
|
||||||
|
char *temp;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
if (!plat || !features_str || !nfstr)
|
||||||
|
return;
|
||||||
|
sbi_memset(features_str, 0, nfstr);
|
||||||
|
|
||||||
|
features = sbi_platform_get_features(plat);
|
||||||
|
if (!features)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (features & feat) {
|
||||||
|
temp = sbi_platform_feature_id2string(feat);
|
||||||
|
if (temp) {
|
||||||
|
sbi_snprintf(features_str + offset, nfstr,
|
||||||
|
"%s,", temp);
|
||||||
|
offset = offset + sbi_strlen(temp) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
feat = feat << 1;
|
||||||
|
} while (feat <= SBI_PLATFORM_HAS_LAST_FEATURE);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (offset)
|
||||||
|
features_str[offset - 1] = '\0';
|
||||||
|
else
|
||||||
|
sbi_strncpy(features_str, "none", nfstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 sbi_platform_hart_index(const struct sbi_platform *plat, u32 hartid)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
if (!plat)
|
||||||
|
return -1U;
|
||||||
|
if (plat->hart_index2id) {
|
||||||
|
for (i = 0; i < plat->hart_count; i++) {
|
||||||
|
if (plat->hart_index2id[i] == hartid)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hartid;
|
||||||
|
}
|
@@ -17,7 +17,7 @@
|
|||||||
#include <sbi/sbi_ipi.h>
|
#include <sbi/sbi_ipi.h>
|
||||||
#include <sbi/sbi_init.h>
|
#include <sbi/sbi_init.h>
|
||||||
|
|
||||||
void __noreturn sbi_system_reboot(u32 type)
|
void __noreturn sbi_system_reset(u32 platform_reset_type)
|
||||||
{
|
{
|
||||||
ulong hbase = 0, hmask;
|
ulong hbase = 0, hmask;
|
||||||
u32 cur_hartid = current_hartid();
|
u32 cur_hartid = current_hartid();
|
||||||
@@ -35,34 +35,10 @@ void __noreturn sbi_system_reboot(u32 type)
|
|||||||
/* Stop current HART */
|
/* Stop current HART */
|
||||||
sbi_hsm_hart_stop(scratch, FALSE);
|
sbi_hsm_hart_stop(scratch, FALSE);
|
||||||
|
|
||||||
/* Platform specific reooot */
|
/* Platform specific reset */
|
||||||
sbi_platform_system_reboot(sbi_platform_ptr(scratch), type);
|
sbi_platform_system_reset(sbi_platform_ptr(scratch),
|
||||||
|
platform_reset_type);
|
||||||
|
|
||||||
/* If platform specific reboot did not work then do sbi_exit() */
|
/* If platform specific reset did not work then do sbi_exit() */
|
||||||
sbi_exit(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __noreturn sbi_system_shutdown(u32 type)
|
|
||||||
{
|
|
||||||
ulong hbase = 0, hmask;
|
|
||||||
u32 cur_hartid = current_hartid();
|
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
|
||||||
|
|
||||||
/* Send HALT IPI to every hart other than the current hart */
|
|
||||||
while (!sbi_hsm_hart_started_mask(hbase, &hmask)) {
|
|
||||||
if (hbase <= cur_hartid)
|
|
||||||
hmask &= ~(1UL << (cur_hartid - hbase));
|
|
||||||
if (hmask)
|
|
||||||
sbi_ipi_send_halt(hmask, hbase);
|
|
||||||
hbase += BITS_PER_LONG;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop current HART */
|
|
||||||
sbi_hsm_hart_stop(scratch, FALSE);
|
|
||||||
|
|
||||||
/* Platform specific shutdown */
|
|
||||||
sbi_platform_system_shutdown(sbi_platform_ptr(scratch), type);
|
|
||||||
|
|
||||||
/* If platform specific shutdown did not work then do sbi_exit() */
|
|
||||||
sbi_exit(scratch);
|
sbi_exit(scratch);
|
||||||
}
|
}
|
||||||
|
@@ -10,14 +10,16 @@
|
|||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
#include <sbi/riscv_encoding.h>
|
#include <sbi/riscv_encoding.h>
|
||||||
#include <sbi/sbi_error.h>
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_hart.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
#include <sbi/sbi_timer.h>
|
#include <sbi/sbi_timer.h>
|
||||||
|
|
||||||
static unsigned long time_delta_off;
|
static unsigned long time_delta_off;
|
||||||
|
static u64 (*get_time_val)(const struct sbi_platform *plat);
|
||||||
|
|
||||||
#if __riscv_xlen == 32
|
#if __riscv_xlen == 32
|
||||||
u64 get_ticks(void)
|
static u64 get_ticks(const struct sbi_platform *plat)
|
||||||
{
|
{
|
||||||
u32 lo, hi, tmp;
|
u32 lo, hi, tmp;
|
||||||
__asm__ __volatile__("1:\n"
|
__asm__ __volatile__("1:\n"
|
||||||
@@ -29,7 +31,7 @@ u64 get_ticks(void)
|
|||||||
return ((u64)hi << 32) | lo;
|
return ((u64)hi << 32) | lo;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
u64 get_ticks(void)
|
static u64 get_ticks(const struct sbi_platform *plat)
|
||||||
{
|
{
|
||||||
unsigned long n;
|
unsigned long n;
|
||||||
|
|
||||||
@@ -40,12 +42,7 @@ u64 get_ticks(void)
|
|||||||
|
|
||||||
u64 sbi_timer_value(void)
|
u64 sbi_timer_value(void)
|
||||||
{
|
{
|
||||||
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
|
return get_time_val(sbi_platform_thishart_ptr());
|
||||||
|
|
||||||
if (sbi_platform_has_timer_value(plat))
|
|
||||||
return sbi_platform_timer_value(plat);
|
|
||||||
else
|
|
||||||
return get_ticks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 sbi_timer_virt_value(void)
|
u64 sbi_timer_virt_value(void)
|
||||||
@@ -97,6 +94,8 @@ void sbi_timer_process(void)
|
|||||||
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
||||||
{
|
{
|
||||||
u64 *time_delta;
|
u64 *time_delta;
|
||||||
|
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
|
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
|
||||||
@@ -111,7 +110,19 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
|
|||||||
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
|
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
|
||||||
*time_delta = 0;
|
*time_delta = 0;
|
||||||
|
|
||||||
return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot);
|
ret = sbi_platform_timer_init(plat, cold_boot);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
|
||||||
|
get_time_val = get_ticks;
|
||||||
|
else if (sbi_platform_has_timer_value(plat))
|
||||||
|
get_time_val = sbi_platform_timer_value;
|
||||||
|
else
|
||||||
|
/* There is no method to provide timer value */
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sbi_timer_exit(struct sbi_scratch *scratch)
|
void sbi_timer_exit(struct sbi_scratch *scratch)
|
||||||
|
@@ -36,16 +36,23 @@ static void sbi_tlb_hfence_vvma(struct sbi_tlb_info *tinfo)
|
|||||||
{
|
{
|
||||||
unsigned long start = tinfo->start;
|
unsigned long start = tinfo->start;
|
||||||
unsigned long size = tinfo->size;
|
unsigned long size = tinfo->size;
|
||||||
unsigned long i;
|
unsigned long vmid = tinfo->vmid;
|
||||||
|
unsigned long i, hgatp;
|
||||||
|
|
||||||
|
hgatp = csr_swap(CSR_HGATP,
|
||||||
|
(vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
|
||||||
|
|
||||||
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
|
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
|
||||||
__sbi_hfence_vvma_all();
|
__sbi_hfence_vvma_all();
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||||
__sbi_hfence_vvma_va(start+i);
|
__sbi_hfence_vvma_va(start+i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
csr_write(CSR_HGATP, hgatp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
|
static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
|
||||||
@@ -88,28 +95,35 @@ static void sbi_tlb_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
|
|||||||
unsigned long start = tinfo->start;
|
unsigned long start = tinfo->start;
|
||||||
unsigned long size = tinfo->size;
|
unsigned long size = tinfo->size;
|
||||||
unsigned long asid = tinfo->asid;
|
unsigned long asid = tinfo->asid;
|
||||||
unsigned long i;
|
unsigned long vmid = tinfo->vmid;
|
||||||
|
unsigned long i, hgatp;
|
||||||
|
|
||||||
|
hgatp = csr_swap(CSR_HGATP,
|
||||||
|
(vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
|
||||||
|
|
||||||
if (start == 0 && size == 0) {
|
if (start == 0 && size == 0) {
|
||||||
__sbi_hfence_vvma_all();
|
__sbi_hfence_vvma_all();
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == SBI_TLB_FLUSH_ALL) {
|
if (size == SBI_TLB_FLUSH_ALL) {
|
||||||
__sbi_hfence_vvma_asid(asid);
|
__sbi_hfence_vvma_asid(asid);
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||||
__sbi_hfence_vvma_asid_va(asid, start + i);
|
__sbi_hfence_vvma_asid_va(start + i, asid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
csr_write(CSR_HGATP, hgatp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
|
static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
|
||||||
{
|
{
|
||||||
unsigned long start = tinfo->start;
|
unsigned long start = tinfo->start;
|
||||||
unsigned long size = tinfo->size;
|
unsigned long size = tinfo->size;
|
||||||
unsigned long vmid = tinfo->asid;
|
unsigned long vmid = tinfo->vmid;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
if (start == 0 && size == 0) {
|
if (start == 0 && size == 0) {
|
||||||
@@ -123,7 +137,7 @@ static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < size; i += PAGE_SIZE) {
|
for (i = 0; i < size; i += PAGE_SIZE) {
|
||||||
__sbi_hfence_gvma_vmid_gpa(vmid, start+i);
|
__sbi_hfence_gvma_vmid_gpa(start + i, vmid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -120,12 +120,10 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
|
|||||||
|
|
||||||
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
|
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
|
||||||
if (misa_extension('H') && prev_virt && !next_virt) {
|
if (misa_extension('H') && prev_virt && !next_virt) {
|
||||||
/* Update HSTATUS SP2P, SP2V, and SPV bits */
|
/* Update HSTATUS SPVP and SPV bits */
|
||||||
hstatus = csr_read(CSR_HSTATUS);
|
hstatus = csr_read(CSR_HSTATUS);
|
||||||
hstatus &= ~HSTATUS_SP2P;
|
hstatus &= ~HSTATUS_SPVP;
|
||||||
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SP2P : 0;
|
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SPVP : 0;
|
||||||
hstatus &= ~HSTATUS_SP2V;
|
|
||||||
hstatus |= (hstatus & HSTATUS_SPV) ? HSTATUS_SP2V : 0;
|
|
||||||
hstatus &= ~HSTATUS_SPV;
|
hstatus &= ~HSTATUS_SPV;
|
||||||
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
|
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
|
||||||
csr_write(CSR_HSTATUS, hstatus);
|
csr_write(CSR_HSTATUS, hstatus);
|
||||||
|
@@ -14,19 +14,21 @@
|
|||||||
#include <sbi/sbi_trap.h>
|
#include <sbi/sbi_trap.h>
|
||||||
#include <sbi/sbi_unpriv.h>
|
#include <sbi/sbi_unpriv.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a3 must a pointer to the sbi_trap_info and a4 is used as a temporary
|
||||||
|
* register in the trap handler. Make sure that compiler doesn't use a3 & a4.
|
||||||
|
*/
|
||||||
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
|
#define DEFINE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
|
||||||
type sbi_load_##type(const type *addr, \
|
type sbi_load_##type(const type *addr, \
|
||||||
struct sbi_trap_info *trap) \
|
struct sbi_trap_info *trap) \
|
||||||
{ \
|
{ \
|
||||||
register ulong tinfo asm("a3"); \
|
register ulong tinfo asm("a3"); \
|
||||||
register ulong ttmp asm("a4"); \
|
register ulong mstatus = 0; \
|
||||||
register ulong mstatus asm("a5"); \
|
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||||
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr(); \
|
|
||||||
type ret = 0; \
|
type ret = 0; \
|
||||||
trap->cause = 0; \
|
trap->cause = 0; \
|
||||||
asm volatile( \
|
asm volatile( \
|
||||||
"add %[tinfo], %[taddr], zero\n" \
|
"add %[tinfo], %[taddr], zero\n" \
|
||||||
"add %[ttmp], %[taddr], zero\n" \
|
|
||||||
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||||
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
|
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
|
||||||
".option push\n" \
|
".option push\n" \
|
||||||
@@ -36,11 +38,10 @@
|
|||||||
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
|
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
|
||||||
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
|
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
|
||||||
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
|
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
|
||||||
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp), \
|
[tinfo] "+&r"(tinfo), [ret] "=&r"(ret) \
|
||||||
[ret] "=&r"(ret) \
|
|
||||||
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
|
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
|
||||||
[taddr] "r"((ulong)trap) \
|
[taddr] "r"((ulong)trap) \
|
||||||
: "memory"); \
|
: "a4", "memory"); \
|
||||||
return ret; \
|
return ret; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,14 +49,12 @@
|
|||||||
void sbi_store_##type(type *addr, type val, \
|
void sbi_store_##type(type *addr, type val, \
|
||||||
struct sbi_trap_info *trap) \
|
struct sbi_trap_info *trap) \
|
||||||
{ \
|
{ \
|
||||||
register ulong tinfo asm("a3"); \
|
register ulong tinfo asm("a3") = (ulong)trap; \
|
||||||
register ulong ttmp asm("a4"); \
|
register ulong mstatus = 0; \
|
||||||
register ulong mstatus asm("a5"); \
|
register ulong mtvec = sbi_hart_expected_trap_addr(); \
|
||||||
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr(); \
|
|
||||||
trap->cause = 0; \
|
trap->cause = 0; \
|
||||||
asm volatile( \
|
asm volatile( \
|
||||||
"add %[tinfo], %[taddr], zero\n" \
|
"add %[tinfo], %[taddr], zero\n" \
|
||||||
"add %[ttmp], %[taddr], zero\n" \
|
|
||||||
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
|
||||||
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
|
"csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n" \
|
||||||
".option push\n" \
|
".option push\n" \
|
||||||
@@ -65,10 +64,10 @@
|
|||||||
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
|
"csrw " STR(CSR_MSTATUS) ", %[mstatus]\n" \
|
||||||
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
|
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
|
||||||
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
|
: [mstatus] "+&r"(mstatus), [mtvec] "+&r"(mtvec), \
|
||||||
[tinfo] "+&r"(tinfo), [ttmp] "+&r"(ttmp) \
|
[tinfo] "+&r"(tinfo) \
|
||||||
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
|
: [addr] "m"(*addr), [mprv] "r"(MSTATUS_MPRV), \
|
||||||
[taddr] "r"((ulong)trap), [val] "r"(val) \
|
[val] "r"(val), [taddr] "r"((ulong)trap) \
|
||||||
: "memory"); \
|
: "a4", "memory"); \
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
|
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u8, lbu)
|
||||||
@@ -119,8 +118,8 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
|
|||||||
{
|
{
|
||||||
register ulong tinfo asm("a3");
|
register ulong tinfo asm("a3");
|
||||||
register ulong ttmp asm("a4");
|
register ulong ttmp asm("a4");
|
||||||
register ulong mstatus asm("a5");
|
register ulong mstatus = 0;
|
||||||
register ulong mtvec asm("a6") = sbi_hart_unpriv_trap_addr();
|
register ulong mtvec = sbi_hart_expected_trap_addr();
|
||||||
ulong insn = 0;
|
ulong insn = 0;
|
||||||
|
|
||||||
trap->cause = 0;
|
trap->cause = 0;
|
||||||
|
@@ -8,19 +8,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
#include <sbi/riscv_asm.h>
|
|
||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_math.h>
|
||||||
|
#include <sbi/sbi_hart.h>
|
||||||
#include <sbi/sbi_platform.h>
|
#include <sbi/sbi_platform.h>
|
||||||
#include <sbi/sbi_scratch.h>
|
#include <sbi/sbi_scratch.h>
|
||||||
#include <sbi/sbi_string.h>
|
#include <sbi/sbi_string.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
|
||||||
void fdt_cpu_fixup(void *fdt)
|
void fdt_cpu_fixup(void *fdt)
|
||||||
{
|
{
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
||||||
int err, len, cpu_offset, cpus_offset;
|
int err, cpu_offset, cpus_offset;
|
||||||
const fdt32_t *val;
|
|
||||||
const void *prop;
|
|
||||||
u32 hartid;
|
u32 hartid;
|
||||||
|
|
||||||
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
|
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
|
||||||
@@ -32,19 +33,9 @@ void fdt_cpu_fixup(void *fdt)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
|
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
|
||||||
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
|
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
if (!prop || !len)
|
if (err)
|
||||||
continue;
|
continue;
|
||||||
if (sbi_strcmp(prop, "cpu"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
val = fdt_getprop(fdt, cpu_offset, "reg", &len);
|
|
||||||
if (!val || len < sizeof(fdt32_t))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (len > sizeof(fdt32_t))
|
|
||||||
val++;
|
|
||||||
hartid = fdt32_to_cpu(*val);
|
|
||||||
|
|
||||||
if (sbi_platform_hart_invalid(plat, hartid))
|
if (sbi_platform_hart_invalid(plat, hartid))
|
||||||
fdt_setprop_string(fdt, cpu_offset, "status",
|
fdt_setprop_string(fdt, cpu_offset, "status",
|
||||||
@@ -77,6 +68,65 @@ void fdt_plic_fixup(void *fdt, const char *compat)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
|
||||||
|
unsigned long size, int index,
|
||||||
|
int parent, bool no_map)
|
||||||
|
{
|
||||||
|
int na = fdt_address_cells(fdt, 0);
|
||||||
|
int ns = fdt_size_cells(fdt, 0);
|
||||||
|
fdt32_t addr_high, addr_low;
|
||||||
|
fdt32_t size_high, size_low;
|
||||||
|
int subnode, err;
|
||||||
|
fdt32_t reg[4];
|
||||||
|
fdt32_t *val;
|
||||||
|
char name[32];
|
||||||
|
|
||||||
|
addr_high = (u64)addr >> 32;
|
||||||
|
addr_low = addr;
|
||||||
|
size_high = (u64)size >> 32;
|
||||||
|
size_low = size;
|
||||||
|
|
||||||
|
if (na > 1 && addr_high)
|
||||||
|
sbi_snprintf(name, sizeof(name),
|
||||||
|
"mmode_pmp%d@%x,%x", index,
|
||||||
|
addr_high, addr_low);
|
||||||
|
else
|
||||||
|
sbi_snprintf(name, sizeof(name),
|
||||||
|
"mmode_pmp%d@%x", index,
|
||||||
|
addr_low);
|
||||||
|
|
||||||
|
subnode = fdt_add_subnode(fdt, parent, name);
|
||||||
|
if (subnode < 0)
|
||||||
|
return subnode;
|
||||||
|
|
||||||
|
if (no_map) {
|
||||||
|
/*
|
||||||
|
* Tell operating system not to create a virtual
|
||||||
|
* mapping of the region as part of its standard
|
||||||
|
* mapping of system memory.
|
||||||
|
*/
|
||||||
|
err = fdt_setprop_empty(fdt, subnode, "no-map");
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* encode the <reg> property value */
|
||||||
|
val = reg;
|
||||||
|
if (na > 1)
|
||||||
|
*val++ = cpu_to_fdt32(addr_high);
|
||||||
|
*val++ = cpu_to_fdt32(addr_low);
|
||||||
|
if (ns > 1)
|
||||||
|
*val++ = cpu_to_fdt32(size_high);
|
||||||
|
*val++ = cpu_to_fdt32(size_low);
|
||||||
|
|
||||||
|
err = fdt_setprop(fdt, subnode, "reg", reg,
|
||||||
|
(na + ns) * sizeof(fdt32_t));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use PMP to protect OpenSBI firmware to safe-guard it from buggy S-mode
|
* We use PMP to protect OpenSBI firmware to safe-guard it from buggy S-mode
|
||||||
* software, see pmp_init() in lib/sbi/sbi_hart.c. The protected memory region
|
* software, see pmp_init() in lib/sbi/sbi_hart.c. The protected memory region
|
||||||
@@ -95,21 +145,11 @@ void fdt_plic_fixup(void *fdt, const char *compat)
|
|||||||
int fdt_reserved_memory_fixup(void *fdt)
|
int fdt_reserved_memory_fixup(void *fdt)
|
||||||
{
|
{
|
||||||
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
|
||||||
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
|
|
||||||
unsigned long prot, addr, size;
|
unsigned long prot, addr, size;
|
||||||
|
int parent, i, j;
|
||||||
|
int err;
|
||||||
int na = fdt_address_cells(fdt, 0);
|
int na = fdt_address_cells(fdt, 0);
|
||||||
int ns = fdt_size_cells(fdt, 0);
|
int ns = fdt_size_cells(fdt, 0);
|
||||||
fdt32_t addr_high, addr_low;
|
|
||||||
fdt32_t size_high, size_low;
|
|
||||||
fdt32_t reg[4];
|
|
||||||
fdt32_t *val;
|
|
||||||
char name[32];
|
|
||||||
int parent, subnode;
|
|
||||||
int i, j;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!sbi_platform_has_pmp(plat))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* expand the device tree to accommodate new node */
|
/* expand the device tree to accommodate new node */
|
||||||
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 256);
|
err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 256);
|
||||||
@@ -153,54 +193,53 @@ int fdt_reserved_memory_fixup(void *fdt)
|
|||||||
* With above assumption, we create child nodes directly.
|
* With above assumption, we create child nodes directly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 0, j = 0; i < PMP_COUNT; i++) {
|
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_PMP)) {
|
||||||
pmp_get(i, &prot, &addr, &size);
|
/*
|
||||||
|
* Update the DT with firmware start & size even if PMP is not
|
||||||
|
* supported. This makes sure that supervisor OS is always
|
||||||
|
* aware of OpenSBI resident memory area.
|
||||||
|
*/
|
||||||
|
addr = scratch->fw_start & ~(scratch->fw_size - 1UL);
|
||||||
|
size = (1UL << log2roundup(scratch->fw_size));
|
||||||
|
return fdt_resv_memory_update_node(fdt, addr, size,
|
||||||
|
0, parent, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < sbi_hart_pmp_count(scratch); i++) {
|
||||||
|
err = sbi_hart_pmp_get(scratch, i, &prot, &addr, &size);
|
||||||
|
if (err)
|
||||||
|
continue;
|
||||||
if (!(prot & PMP_A))
|
if (!(prot & PMP_A))
|
||||||
continue;
|
continue;
|
||||||
if (!(prot & (PMP_R | PMP_W | PMP_X))) {
|
if (prot & (PMP_R | PMP_W | PMP_X))
|
||||||
addr_high = (u64)addr >> 32;
|
continue;
|
||||||
addr_low = addr;
|
|
||||||
size_high = (u64)size >> 32;
|
|
||||||
size_low = size;
|
|
||||||
|
|
||||||
if (na > 1 && addr_high)
|
fdt_resv_memory_update_node(fdt, addr, size, j, parent, false);
|
||||||
sbi_snprintf(name, sizeof(name),
|
j++;
|
||||||
"mmode_pmp%d@%x,%x", j,
|
}
|
||||||
addr_high, addr_low);
|
|
||||||
else
|
|
||||||
sbi_snprintf(name, sizeof(name),
|
|
||||||
"mmode_pmp%d@%x", j,
|
|
||||||
addr_low);
|
|
||||||
|
|
||||||
subnode = fdt_add_subnode(fdt, parent, name);
|
return 0;
|
||||||
if (subnode < 0)
|
}
|
||||||
return subnode;
|
|
||||||
|
|
||||||
/*
|
int fdt_reserved_memory_nomap_fixup(void *fdt)
|
||||||
* Tell operating system not to create a virtual
|
{
|
||||||
* mapping of the region as part of its standard
|
int parent, subnode;
|
||||||
* mapping of system memory.
|
int err;
|
||||||
*/
|
|
||||||
err = fdt_setprop_empty(fdt, subnode, "no-map");
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
/* encode the <reg> property value */
|
/* Locate the reserved memory node */
|
||||||
val = reg;
|
parent = fdt_path_offset(fdt, "/reserved-memory");
|
||||||
if (na > 1)
|
if (parent < 0)
|
||||||
*val++ = cpu_to_fdt32(addr_high);
|
return parent;
|
||||||
*val++ = cpu_to_fdt32(addr_low);
|
|
||||||
if (ns > 1)
|
|
||||||
*val++ = cpu_to_fdt32(size_high);
|
|
||||||
*val++ = cpu_to_fdt32(size_low);
|
|
||||||
|
|
||||||
err = fdt_setprop(fdt, subnode, "reg", reg,
|
fdt_for_each_subnode(subnode, fdt, parent) {
|
||||||
(na + ns) * sizeof(fdt32_t));
|
/*
|
||||||
if (err < 0)
|
* Tell operating system not to create a virtual
|
||||||
return err;
|
* mapping of the region as part of its standard
|
||||||
|
* mapping of system memory.
|
||||||
j++;
|
*/
|
||||||
}
|
err = fdt_setprop_empty(fdt, subnode, "no-map");
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -9,12 +9,70 @@
|
|||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_hartmask.h>
|
||||||
#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/plic.h>
|
||||||
|
#include <sbi_utils/sys/clint.h>
|
||||||
|
|
||||||
static int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
|
#define DEFAULT_UART_FREQ 0
|
||||||
unsigned long *size)
|
#define DEFAULT_UART_BAUD 115200
|
||||||
|
#define DEFAULT_UART_REG_SHIFT 0
|
||||||
|
#define DEFAULT_UART_REG_IO_WIDTH 1
|
||||||
|
|
||||||
|
#define DEFAULT_SIFIVE_UART_FREQ 0
|
||||||
|
#define DEFAULT_SIFIVE_UART_BAUD 115200
|
||||||
|
#define DEFAULT_SIFIVE_UART_REG_SHIFT 0
|
||||||
|
#define DEFAULT_SIFIVE_UART_REG_IO_WIDTH 4
|
||||||
|
|
||||||
|
#define DEFAULT_SHAKTI_UART_FREQ 50000000
|
||||||
|
#define DEFAULT_SHAKTI_UART_BAUD 115200
|
||||||
|
|
||||||
|
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match_table)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!fdt || nodeoff < 0 || !match_table)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (match_table->compatible) {
|
||||||
|
ret = fdt_node_check_compatible(fdt, nodeoff,
|
||||||
|
match_table->compatible);
|
||||||
|
if (!ret)
|
||||||
|
return match_table;
|
||||||
|
match_table++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_find_match(void *fdt, int startoff,
|
||||||
|
const struct fdt_match *match_table,
|
||||||
|
const struct fdt_match **out_match)
|
||||||
|
{
|
||||||
|
int nodeoff;
|
||||||
|
|
||||||
|
if (!fdt || !match_table)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
while (match_table->compatible) {
|
||||||
|
nodeoff = fdt_node_offset_by_compatible(fdt, startoff,
|
||||||
|
match_table->compatible);
|
||||||
|
if (nodeoff >= 0) {
|
||||||
|
if (out_match)
|
||||||
|
*out_match = match_table;
|
||||||
|
return nodeoff;
|
||||||
|
}
|
||||||
|
match_table++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SBI_ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
|
||||||
|
unsigned long *size)
|
||||||
{
|
{
|
||||||
int parent, len, i;
|
int parent, len, i;
|
||||||
int cell_addr, cell_size;
|
int cell_addr, cell_size;
|
||||||
@@ -53,21 +111,71 @@ static int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
|
||||||
const char *compatible)
|
|
||||||
{
|
{
|
||||||
int nodeoffset, len, rc;
|
int len;
|
||||||
fdt32_t *val;
|
const void *prop;
|
||||||
|
const fdt32_t *val;
|
||||||
|
|
||||||
|
if (!fdt || cpu_offset < 0)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
|
||||||
|
if (!prop || !len)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
if (sbi_strcmp(prop, "cpu"))
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, cpu_offset, "reg", &len);
|
||||||
|
if (!val || len < sizeof(fdt32_t))
|
||||||
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
if (len > sizeof(fdt32_t))
|
||||||
|
val++;
|
||||||
|
|
||||||
|
if (hartid)
|
||||||
|
*hartid = fdt32_to_cpu(*val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
|
||||||
|
{
|
||||||
|
u32 hartid;
|
||||||
|
int err, cpu_offset, cpus_offset;
|
||||||
|
|
||||||
|
if (!fdt)
|
||||||
|
return SBI_EINVAL;
|
||||||
|
if (!max_hartid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*max_hartid = 0;
|
||||||
|
|
||||||
|
cpus_offset = fdt_path_offset(fdt, "/cpus");
|
||||||
|
if (cpus_offset < 0)
|
||||||
|
return cpus_offset;
|
||||||
|
|
||||||
|
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
|
||||||
|
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
|
if (err)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (hartid > *max_hartid)
|
||||||
|
*max_hartid = hartid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
||||||
|
struct platform_uart_data *uart)
|
||||||
|
{
|
||||||
|
int len, rc;
|
||||||
|
const fdt32_t *val;
|
||||||
unsigned long reg_addr, reg_size;
|
unsigned long reg_addr, reg_size;
|
||||||
|
|
||||||
/**
|
if (nodeoffset < 0 || !uart || !fdt)
|
||||||
* TODO: We don't know how to handle multiple nodes with the same
|
return SBI_ENODEV;
|
||||||
* compatible sring. Just return the first node for now.
|
|
||||||
*/
|
|
||||||
|
|
||||||
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
|
|
||||||
if (nodeoffset < 0)
|
|
||||||
return nodeoffset;
|
|
||||||
|
|
||||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_addr, ®_size);
|
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_addr, ®_size);
|
||||||
if (rc < 0 || !reg_addr || !reg_size)
|
if (rc < 0 || !reg_addr || !reg_size)
|
||||||
@@ -75,31 +183,132 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
|||||||
uart->addr = reg_addr;
|
uart->addr = reg_addr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UART address is mandaotry. clock-frequency and current-speed may not
|
* UART address is mandaotry. clock-frequency and current-speed
|
||||||
* be present. Don't return error.
|
* may not be present. Don't return error.
|
||||||
*/
|
*/
|
||||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
|
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
|
||||||
if (len > 0 && val)
|
if (len > 0 && val)
|
||||||
uart->freq = fdt32_to_cpu(*val);
|
uart->freq = fdt32_to_cpu(*val);
|
||||||
|
else
|
||||||
|
uart->freq = DEFAULT_SHAKTI_UART_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
|
||||||
|
uart->baud = DEFAULT_SHAKTI_UART_BAUD;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_plic(void *fdt, struct platform_plic_data *plic,
|
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
||||||
const char *compatible)
|
struct platform_uart_data *uart)
|
||||||
{
|
{
|
||||||
int nodeoffset, len, rc;
|
int len, rc;
|
||||||
const fdt32_t *val;
|
const fdt32_t *val;
|
||||||
unsigned long reg_addr, reg_size;
|
unsigned long reg_addr, reg_size;
|
||||||
|
|
||||||
|
if (nodeoffset < 0 || !uart || !fdt)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_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,
|
||||||
|
struct platform_uart_data *uart)
|
||||||
|
{
|
||||||
|
int len, rc;
|
||||||
|
const fdt32_t *val;
|
||||||
|
unsigned long reg_addr, reg_size;
|
||||||
|
|
||||||
|
if (nodeoffset < 0 || !uart || !fdt)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_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_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);
|
||||||
|
if (len > 0 && val)
|
||||||
|
uart->reg_shift = fdt32_to_cpu(*val);
|
||||||
|
else
|
||||||
|
uart->reg_shift = DEFAULT_UART_REG_SHIFT;
|
||||||
|
|
||||||
|
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-io-width", &len);
|
||||||
|
if (len > 0 && val)
|
||||||
|
uart->reg_io_width = fdt32_to_cpu(*val);
|
||||||
|
else
|
||||||
|
uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
||||||
|
const char *compatible)
|
||||||
|
{
|
||||||
|
int nodeoffset;
|
||||||
|
|
||||||
|
if (!compatible || !uart || !fdt)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
|
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
|
||||||
if (nodeoffset < 0)
|
if (nodeoffset < 0)
|
||||||
return nodeoffset;
|
return nodeoffset;
|
||||||
|
|
||||||
|
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
|
||||||
|
{
|
||||||
|
int len, rc;
|
||||||
|
const fdt32_t *val;
|
||||||
|
unsigned long reg_addr, reg_size;
|
||||||
|
|
||||||
|
if (nodeoffset < 0 || !plic || !fdt)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_addr, ®_size);
|
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_addr, ®_size);
|
||||||
if (rc < 0 || !reg_addr || !reg_size)
|
if (rc < 0 || !reg_addr || !reg_size)
|
||||||
return SBI_ENODEV;
|
return SBI_ENODEV;
|
||||||
@@ -112,8 +321,89 @@ int fdt_parse_plic(void *fdt, struct platform_plic_data *plic,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
|
int fdt_parse_plic(void *fdt, struct plic_data *plic, const char *compat)
|
||||||
const char *compatible)
|
{
|
||||||
|
int nodeoffset;
|
||||||
|
|
||||||
|
if (!compat || !plic || !fdt)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compat);
|
||||||
|
if (nodeoffset < 0)
|
||||||
|
return nodeoffset;
|
||||||
|
|
||||||
|
return fdt_parse_plic_node(fdt, nodeoffset, plic);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
|
||||||
|
struct clint_data *clint)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
unsigned long reg_addr, reg_size;
|
||||||
|
int i, rc, count, cpu_offset, cpu_intc_offset;
|
||||||
|
u32 phandle, hwirq, hartid, first_hartid, last_hartid;
|
||||||
|
u32 match_hwirq = (for_timer) ? IRQ_M_TIMER : IRQ_M_SOFT;
|
||||||
|
|
||||||
|
if (nodeoffset < 0 || !clint || !fdt)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_addr, ®_size);
|
||||||
|
if (rc < 0 || !reg_addr || !reg_size)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
clint->addr = reg_addr;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count);
|
||||||
|
if (!val || count < sizeof(fdt32_t))
|
||||||
|
return SBI_EINVAL;
|
||||||
|
count = count / sizeof(fdt32_t);
|
||||||
|
|
||||||
|
first_hartid = -1U;
|
||||||
|
last_hartid = 0;
|
||||||
|
clint->hart_count = 0;
|
||||||
|
for (i = 0; i < count; i += 2) {
|
||||||
|
phandle = fdt32_to_cpu(val[i]);
|
||||||
|
hwirq = fdt32_to_cpu(val[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_intc_offset < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
|
if (rc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SBI_HARTMASK_MAX_BITS <= hartid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (match_hwirq == hwirq) {
|
||||||
|
if (hartid < first_hartid)
|
||||||
|
first_hartid = hartid;
|
||||||
|
if (hartid > last_hartid)
|
||||||
|
last_hartid = hartid;
|
||||||
|
clint->hart_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((last_hartid < first_hartid) || first_hartid == -1U)
|
||||||
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
clint->first_hartid = first_hartid;
|
||||||
|
count = last_hartid - first_hartid + 1;
|
||||||
|
if (clint->hart_count < count)
|
||||||
|
clint->hart_count = count;
|
||||||
|
|
||||||
|
/* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
|
||||||
|
clint->has_64bit_mmio = TRUE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_parse_compat_addr(void *fdt, unsigned long *addr,
|
||||||
|
const char *compatible)
|
||||||
{
|
{
|
||||||
int nodeoffset, rc;
|
int nodeoffset, rc;
|
||||||
|
|
||||||
@@ -121,8 +411,8 @@ int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
|
|||||||
if (nodeoffset < 0)
|
if (nodeoffset < 0)
|
||||||
return nodeoffset;
|
return nodeoffset;
|
||||||
|
|
||||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, clint_addr, NULL);
|
rc = fdt_get_node_addr_size(fdt, nodeoffset, addr, NULL);
|
||||||
if (rc < 0 || !clint_addr)
|
if (rc < 0 || !addr)
|
||||||
return SBI_ENODEV;
|
return SBI_ENODEV;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
101
lib/utils/ipi/fdt_ipi.c
Normal file
101
lib/utils/ipi/fdt_ipi.c
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/ipi/fdt_ipi.h>
|
||||||
|
|
||||||
|
extern struct fdt_ipi fdt_ipi_clint;
|
||||||
|
|
||||||
|
static struct fdt_ipi *ipi_drivers[] = {
|
||||||
|
&fdt_ipi_clint
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dummy_send(u32 target_hart)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dummy_clear(u32 target_hart)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fdt_ipi dummy = {
|
||||||
|
.match_table = NULL,
|
||||||
|
.cold_init = NULL,
|
||||||
|
.warm_init = NULL,
|
||||||
|
.exit = NULL,
|
||||||
|
.send = dummy_send,
|
||||||
|
.clear = dummy_clear
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fdt_ipi *current_driver = &dummy;
|
||||||
|
|
||||||
|
void fdt_ipi_send(u32 target_hart)
|
||||||
|
{
|
||||||
|
current_driver->send(target_hart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fdt_ipi_clear(u32 target_hart)
|
||||||
|
{
|
||||||
|
current_driver->clear(target_hart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fdt_ipi_exit(void)
|
||||||
|
{
|
||||||
|
if (current_driver->exit)
|
||||||
|
current_driver->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_ipi_warm_init(void)
|
||||||
|
{
|
||||||
|
if (current_driver->warm_init)
|
||||||
|
return current_driver->warm_init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_ipi_cold_init(void)
|
||||||
|
{
|
||||||
|
int pos, noff, rc;
|
||||||
|
struct fdt_ipi *drv;
|
||||||
|
const struct fdt_match *match;
|
||||||
|
void *fdt = sbi_scratch_thishart_arg1_ptr();
|
||||||
|
|
||||||
|
for (pos = 0; pos < array_size(ipi_drivers); pos++) {
|
||||||
|
drv = ipi_drivers[pos];
|
||||||
|
|
||||||
|
noff = -1;
|
||||||
|
while ((noff = fdt_find_match(fdt, noff,
|
||||||
|
drv->match_table, &match)) >= 0) {
|
||||||
|
if (drv->cold_init) {
|
||||||
|
rc = drv->cold_init(fdt, noff, match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
current_driver = drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_driver != &dummy)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_ipi_init(bool cold_boot)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (cold_boot) {
|
||||||
|
rc = fdt_ipi_cold_init();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fdt_ipi_warm_init();
|
||||||
|
}
|
49
lib/utils/ipi/fdt_ipi_clint.c
Normal file
49
lib/utils/ipi/fdt_ipi_clint.c
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/ipi/fdt_ipi.h>
|
||||||
|
#include <sbi_utils/sys/clint.h>
|
||||||
|
|
||||||
|
#define CLINT_IPI_MAX_NR 16
|
||||||
|
|
||||||
|
static unsigned long clint_ipi_count = 0;
|
||||||
|
static struct clint_data clint_ipi[CLINT_IPI_MAX_NR];
|
||||||
|
|
||||||
|
static int ipi_clint_cold_init(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct clint_data *ci;
|
||||||
|
|
||||||
|
if (CLINT_IPI_MAX_NR <= clint_ipi_count)
|
||||||
|
return SBI_ENOSPC;
|
||||||
|
ci = &clint_ipi[clint_ipi_count++];
|
||||||
|
|
||||||
|
rc = fdt_parse_clint_node(fdt, nodeoff, FALSE, ci);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return clint_cold_ipi_init(ci);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match ipi_clint_match[] = {
|
||||||
|
{ .compatible = "riscv,clint0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_ipi fdt_ipi_clint = {
|
||||||
|
.match_table = ipi_clint_match,
|
||||||
|
.cold_init = ipi_clint_cold_init,
|
||||||
|
.warm_init = clint_warm_ipi_init,
|
||||||
|
.exit = NULL,
|
||||||
|
.send = clint_ipi_send,
|
||||||
|
.clear = clint_ipi_clear,
|
||||||
|
};
|
11
lib/utils/ipi/objects.mk
Normal file
11
lib/utils/ipi/objects.mk
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# Anup Patel <anup.patel@wdc.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
libsbiutils-objs-y += ipi/fdt_ipi.o
|
||||||
|
libsbiutils-objs-y += ipi/fdt_ipi_clint.o
|
74
lib/utils/irqchip/fdt_irqchip.c
Normal file
74
lib/utils/irqchip/fdt_irqchip.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/irqchip/fdt_irqchip.h>
|
||||||
|
|
||||||
|
extern struct fdt_irqchip fdt_irqchip_plic;
|
||||||
|
|
||||||
|
static struct fdt_irqchip *irqchip_drivers[] = {
|
||||||
|
&fdt_irqchip_plic
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fdt_irqchip *current_driver = NULL;
|
||||||
|
|
||||||
|
void fdt_irqchip_exit(void)
|
||||||
|
{
|
||||||
|
if (current_driver && current_driver->exit)
|
||||||
|
current_driver->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_irqchip_warm_init(void)
|
||||||
|
{
|
||||||
|
if (current_driver && current_driver->warm_init)
|
||||||
|
return current_driver->warm_init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_irqchip_cold_init(void)
|
||||||
|
{
|
||||||
|
int pos, noff, rc;
|
||||||
|
struct fdt_irqchip *drv;
|
||||||
|
const struct fdt_match *match;
|
||||||
|
void *fdt = sbi_scratch_thishart_arg1_ptr();
|
||||||
|
|
||||||
|
for (pos = 0; pos < array_size(irqchip_drivers); pos++) {
|
||||||
|
drv = irqchip_drivers[pos];
|
||||||
|
|
||||||
|
noff = -1;
|
||||||
|
while ((noff = fdt_find_match(fdt, noff,
|
||||||
|
drv->match_table, &match)) >= 0) {
|
||||||
|
if (drv->cold_init) {
|
||||||
|
rc = drv->cold_init(fdt, noff, match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
current_driver = drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_driver)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_irqchip_init(bool cold_boot)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (cold_boot) {
|
||||||
|
rc = fdt_irqchip_cold_init();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fdt_irqchip_warm_init();
|
||||||
|
}
|
120
lib/utils/irqchip/fdt_irqchip_plic.c
Normal file
120
lib/utils/irqchip/fdt_irqchip_plic.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/riscv_asm.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_hartmask.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/irqchip/fdt_irqchip.h>
|
||||||
|
#include <sbi_utils/irqchip/plic.h>
|
||||||
|
|
||||||
|
#define PLIC_MAX_NR 16
|
||||||
|
|
||||||
|
static unsigned long plic_count = 0;
|
||||||
|
static struct plic_data plic[PLIC_MAX_NR];
|
||||||
|
|
||||||
|
static struct plic_data *plic_hartid2data[SBI_HARTMASK_MAX_BITS];
|
||||||
|
static int plic_hartid2context[SBI_HARTMASK_MAX_BITS][2];
|
||||||
|
|
||||||
|
static int irqchip_plic_warm_init(void)
|
||||||
|
{
|
||||||
|
u32 hartid = current_hartid();
|
||||||
|
|
||||||
|
return plic_warm_irqchip_init(plic_hartid2data[hartid],
|
||||||
|
plic_hartid2context[hartid][0],
|
||||||
|
plic_hartid2context[hartid][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff,
|
||||||
|
struct plic_data *pd)
|
||||||
|
{
|
||||||
|
const fdt32_t *val;
|
||||||
|
u32 phandle, hwirq, hartid;
|
||||||
|
int i, err, count, cpu_offset, cpu_intc_offset;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
|
||||||
|
if (!val || count < sizeof(fdt32_t))
|
||||||
|
return SBI_EINVAL;
|
||||||
|
count = count / sizeof(fdt32_t);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i += 2) {
|
||||||
|
phandle = fdt32_to_cpu(val[i]);
|
||||||
|
hwirq = fdt32_to_cpu(val[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_intc_offset < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
|
if (err)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SBI_HARTMASK_MAX_BITS <= hartid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
plic_hartid2data[hartid] = pd;
|
||||||
|
switch (hwirq) {
|
||||||
|
case IRQ_M_EXT:
|
||||||
|
plic_hartid2context[hartid][0] = i / 2;
|
||||||
|
break;
|
||||||
|
case IRQ_S_EXT:
|
||||||
|
plic_hartid2context[hartid][1] = i / 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int irqchip_plic_cold_init(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int i, rc;
|
||||||
|
struct plic_data *pd;
|
||||||
|
|
||||||
|
if (PLIC_MAX_NR <= plic_count)
|
||||||
|
return SBI_ENOSPC;
|
||||||
|
pd = &plic[plic_count++];
|
||||||
|
|
||||||
|
rc = fdt_parse_plic_node(fdt, nodeoff, pd);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = plic_cold_irqchip_init(pd);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (plic_count == 1) {
|
||||||
|
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
|
||||||
|
plic_hartid2data[i] = NULL;
|
||||||
|
plic_hartid2context[i][0] = -1;
|
||||||
|
plic_hartid2context[i][1] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return irqchip_plic_update_hartid_table(fdt, nodeoff, pd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match irqchip_plic_match[] = {
|
||||||
|
{ .compatible = "riscv,plic0" },
|
||||||
|
{ .compatible = "sifive,plic-1.0.0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_irqchip fdt_irqchip_plic = {
|
||||||
|
.match_table = irqchip_plic_match,
|
||||||
|
.cold_init = irqchip_plic_cold_init,
|
||||||
|
.warm_init = irqchip_plic_warm_init,
|
||||||
|
.exit = NULL,
|
||||||
|
};
|
@@ -7,4 +7,6 @@
|
|||||||
# Anup Patel <anup.patel@wdc.com>
|
# Anup Patel <anup.patel@wdc.com>
|
||||||
#
|
#
|
||||||
|
|
||||||
|
libsbiutils-objs-y += irqchip/fdt_irqchip.o
|
||||||
|
libsbiutils-objs-y += irqchip/fdt_irqchip_plic.o
|
||||||
libsbiutils-objs-y += irqchip/plic.o
|
libsbiutils-objs-y += irqchip/plic.o
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#include <sbi/riscv_io.h>
|
#include <sbi/riscv_io.h>
|
||||||
#include <sbi/riscv_encoding.h>
|
#include <sbi/riscv_encoding.h>
|
||||||
#include <sbi/sbi_console.h>
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
#include <sbi/sbi_string.h>
|
#include <sbi/sbi_string.h>
|
||||||
#include <sbi_utils/irqchip/plic.h>
|
#include <sbi_utils/irqchip/plic.h>
|
||||||
|
|
||||||
@@ -20,72 +21,80 @@
|
|||||||
#define PLIC_CONTEXT_BASE 0x200000
|
#define PLIC_CONTEXT_BASE 0x200000
|
||||||
#define PLIC_CONTEXT_STRIDE 0x1000
|
#define PLIC_CONTEXT_STRIDE 0x1000
|
||||||
|
|
||||||
static u32 plic_hart_count;
|
static void plic_set_priority(struct plic_data *plic, u32 source, u32 val)
|
||||||
static u32 plic_num_sources;
|
|
||||||
static volatile void *plic_base;
|
|
||||||
|
|
||||||
static void plic_set_priority(u32 source, u32 val)
|
|
||||||
{
|
{
|
||||||
volatile void *plic_priority =
|
volatile void *plic_priority = (void *)plic->addr +
|
||||||
plic_base + PLIC_PRIORITY_BASE + 4 * source;
|
PLIC_PRIORITY_BASE + 4 * source;
|
||||||
writel(val, plic_priority);
|
writel(val, plic_priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
void plic_set_thresh(u32 cntxid, u32 val)
|
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val)
|
||||||
{
|
{
|
||||||
volatile void *plic_thresh =
|
volatile void *plic_thresh;
|
||||||
plic_base + PLIC_CONTEXT_BASE + PLIC_CONTEXT_STRIDE * cntxid;
|
|
||||||
|
if (!plic)
|
||||||
|
return;
|
||||||
|
|
||||||
|
plic_thresh = (void *)plic->addr +
|
||||||
|
PLIC_CONTEXT_BASE + PLIC_CONTEXT_STRIDE * cntxid;
|
||||||
writel(val, plic_thresh);
|
writel(val, plic_thresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void plic_set_ie(u32 cntxid, u32 word_index, u32 val)
|
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val)
|
||||||
{
|
{
|
||||||
volatile void *plic_ie =
|
volatile void *plic_ie;
|
||||||
plic_base + PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid;
|
|
||||||
|
if (!plic)
|
||||||
|
return;
|
||||||
|
|
||||||
|
plic_ie = (void *)plic->addr +
|
||||||
|
PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid;
|
||||||
writel(val, plic_ie + word_index * 4);
|
writel(val, plic_ie + word_index * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
int plic_warm_irqchip_init(u32 target_hart, int m_cntx_id, int s_cntx_id)
|
int plic_warm_irqchip_init(struct plic_data *plic,
|
||||||
|
int m_cntx_id, int s_cntx_id)
|
||||||
{
|
{
|
||||||
size_t i, ie_words = plic_num_sources / 32 + 1;
|
size_t i, ie_words;
|
||||||
|
|
||||||
if (plic_hart_count <= target_hart)
|
if (!plic)
|
||||||
return -1;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
ie_words = plic->num_src / 32 + 1;
|
||||||
|
|
||||||
/* By default, disable all IRQs for M-mode of target HART */
|
/* By default, disable all IRQs for M-mode of target HART */
|
||||||
if (m_cntx_id > -1) {
|
if (m_cntx_id > -1) {
|
||||||
for (i = 0; i < ie_words; i++)
|
for (i = 0; i < ie_words; i++)
|
||||||
plic_set_ie(m_cntx_id, i, 0);
|
plic_set_ie(plic, m_cntx_id, i, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* By default, disable all IRQs for S-mode of target HART */
|
/* By default, disable all IRQs for S-mode of target HART */
|
||||||
if (s_cntx_id > -1) {
|
if (s_cntx_id > -1) {
|
||||||
for (i = 0; i < ie_words; i++)
|
for (i = 0; i < ie_words; i++)
|
||||||
plic_set_ie(s_cntx_id, i, 0);
|
plic_set_ie(plic, s_cntx_id, i, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* By default, disable M-mode threshold */
|
/* By default, disable M-mode threshold */
|
||||||
if (m_cntx_id > -1)
|
if (m_cntx_id > -1)
|
||||||
plic_set_thresh(m_cntx_id, 0x7);
|
plic_set_thresh(plic, m_cntx_id, 0x7);
|
||||||
|
|
||||||
/* By default, disable S-mode threshold */
|
/* By default, disable S-mode threshold */
|
||||||
if (s_cntx_id > -1)
|
if (s_cntx_id > -1)
|
||||||
plic_set_thresh(s_cntx_id, 0x7);
|
plic_set_thresh(plic, s_cntx_id, 0x7);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int plic_cold_irqchip_init(unsigned long base, u32 num_sources, u32 hart_count)
|
int plic_cold_irqchip_init(struct plic_data *plic)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
plic_hart_count = hart_count;
|
if (!plic)
|
||||||
plic_num_sources = num_sources;
|
return SBI_EINVAL;
|
||||||
plic_base = (void *)base;
|
|
||||||
|
|
||||||
/* Configure default priorities of all IRQs */
|
/* Configure default priorities of all IRQs */
|
||||||
for (i = 1; i <= plic_num_sources; i++)
|
for (i = 1; i <= plic->num_src; i++)
|
||||||
plic_set_priority(i, 0);
|
plic_set_priority(plic, i, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
55
lib/utils/reset/fdt_reset.c
Normal file
55
lib/utils/reset/fdt_reset.c
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/reset/fdt_reset.h>
|
||||||
|
|
||||||
|
extern struct fdt_reset fdt_reset_sifive;
|
||||||
|
extern struct fdt_reset fdt_reset_htif;
|
||||||
|
|
||||||
|
static struct fdt_reset *reset_drivers[] = {
|
||||||
|
&fdt_reset_sifive,
|
||||||
|
&fdt_reset_htif,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fdt_reset *current_driver = NULL;
|
||||||
|
|
||||||
|
int fdt_system_reset(u32 reset_type)
|
||||||
|
{
|
||||||
|
if (current_driver && current_driver->system_reset)
|
||||||
|
return current_driver->system_reset(reset_type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_reset_init(void)
|
||||||
|
{
|
||||||
|
int pos, noff, rc;
|
||||||
|
struct fdt_reset *drv;
|
||||||
|
const struct fdt_match *match;
|
||||||
|
void *fdt = sbi_scratch_thishart_arg1_ptr();
|
||||||
|
|
||||||
|
for (pos = 0; pos < array_size(reset_drivers); pos++) {
|
||||||
|
drv = reset_drivers[pos];
|
||||||
|
|
||||||
|
noff = fdt_find_match(fdt, -1, drv->match_table, &match);
|
||||||
|
if (noff < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (drv->init) {
|
||||||
|
rc = drv->init(fdt, noff, match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
current_driver = drv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
22
lib/utils/reset/fdt_reset_htif.c
Normal file
22
lib/utils/reset/fdt_reset_htif.c
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi_utils/reset/fdt_reset.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/sys/htif.h>
|
||||||
|
|
||||||
|
static const struct fdt_match htif_reset_match[] = {
|
||||||
|
{ .compatible = "ucb,htif0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_reset fdt_reset_htif = {
|
||||||
|
.match_table = htif_reset_match,
|
||||||
|
.system_reset = htif_system_reset
|
||||||
|
};
|
37
lib/utils/reset/fdt_reset_sifive.c
Normal file
37
lib/utils/reset/fdt_reset_sifive.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/reset/fdt_reset.h>
|
||||||
|
#include <sbi_utils/sys/sifive_test.h>
|
||||||
|
|
||||||
|
static int sifive_test_reset_init(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
unsigned long addr;
|
||||||
|
|
||||||
|
rc = fdt_get_node_addr_size(fdt, nodeoff, &addr, NULL);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return sifive_test_init(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match sifive_test_reset_match[] = {
|
||||||
|
{ .compatible = "sifive,test1" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_reset fdt_reset_sifive = {
|
||||||
|
.match_table = sifive_test_reset_match,
|
||||||
|
.init = sifive_test_reset_init,
|
||||||
|
.system_reset = sifive_test_system_reset
|
||||||
|
};
|
12
lib/utils/reset/objects.mk
Normal file
12
lib/utils/reset/objects.mk
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# Anup Patel <anup.patel@wdc.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
libsbiutils-objs-y += reset/fdt_reset.o
|
||||||
|
libsbiutils-objs-y += reset/fdt_reset_htif.o
|
||||||
|
libsbiutils-objs-y += reset/fdt_reset_sifive.o
|
111
lib/utils/serial/fdt_serial.c
Normal file
111
lib/utils/serial/fdt_serial.c
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/serial/fdt_serial.h>
|
||||||
|
|
||||||
|
extern struct fdt_serial fdt_serial_uart8250;
|
||||||
|
extern struct fdt_serial fdt_serial_sifive;
|
||||||
|
extern struct fdt_serial fdt_serial_htif;
|
||||||
|
extern struct fdt_serial fdt_serial_shakti;
|
||||||
|
|
||||||
|
static struct fdt_serial *serial_drivers[] = {
|
||||||
|
&fdt_serial_uart8250,
|
||||||
|
&fdt_serial_sifive,
|
||||||
|
&fdt_serial_htif,
|
||||||
|
&fdt_serial_shakti,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dummy_putc(char ch)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dummy_getc(void)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fdt_serial dummy = {
|
||||||
|
.match_table = NULL,
|
||||||
|
.init = NULL,
|
||||||
|
.putc = dummy_putc,
|
||||||
|
.getc = dummy_getc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fdt_serial *current_driver = &dummy;
|
||||||
|
|
||||||
|
void fdt_serial_putc(char ch)
|
||||||
|
{
|
||||||
|
current_driver->putc(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_serial_getc(void)
|
||||||
|
{
|
||||||
|
return current_driver->getc();
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_serial_init(void)
|
||||||
|
{
|
||||||
|
const void *prop;
|
||||||
|
struct fdt_serial *drv;
|
||||||
|
const struct fdt_match *match;
|
||||||
|
int pos, noff = -1, len, coff, rc;
|
||||||
|
void *fdt = sbi_scratch_thishart_arg1_ptr();
|
||||||
|
|
||||||
|
/* Find offset of node pointed by stdout-path */
|
||||||
|
coff = fdt_path_offset(fdt, "/chosen");
|
||||||
|
if (-1 < coff) {
|
||||||
|
prop = fdt_getprop(fdt, coff, "stdout-path", &len);
|
||||||
|
if (prop && len)
|
||||||
|
noff = fdt_path_offset(fdt, prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First check DT node pointed by stdout-path */
|
||||||
|
for (pos = 0; pos < array_size(serial_drivers) && -1 < noff; pos++) {
|
||||||
|
drv = serial_drivers[pos];
|
||||||
|
|
||||||
|
match = fdt_match_node(fdt, noff, drv->match_table);
|
||||||
|
if (!match)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (drv->init) {
|
||||||
|
rc = drv->init(fdt, noff, match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
current_driver = drv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we found desired driver */
|
||||||
|
if (current_driver != &dummy)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Lastly check all DT nodes */
|
||||||
|
for (pos = 0; pos < array_size(serial_drivers); pos++) {
|
||||||
|
drv = serial_drivers[pos];
|
||||||
|
|
||||||
|
noff = fdt_find_match(fdt, -1, drv->match_table, &match);
|
||||||
|
if (noff < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (drv->init) {
|
||||||
|
rc = drv->init(fdt, noff, match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
current_driver = drv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return 0;
|
||||||
|
}
|
24
lib/utils/serial/fdt_serial_htif.c
Normal file
24
lib/utils/serial/fdt_serial_htif.c
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/serial/fdt_serial.h>
|
||||||
|
#include <sbi_utils/sys/htif.h>
|
||||||
|
|
||||||
|
static const struct fdt_match serial_htif_match[] = {
|
||||||
|
{ .compatible = "ucb,htif0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_serial fdt_serial_htif = {
|
||||||
|
.match_table = serial_htif_match,
|
||||||
|
.init = NULL,
|
||||||
|
.getc = htif_getc,
|
||||||
|
.putc = htif_putc
|
||||||
|
};
|
35
lib/utils/serial/fdt_serial_shakti.c
Normal file
35
lib/utils/serial/fdt_serial_shakti.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/serial/fdt_serial.h>
|
||||||
|
#include <sbi_utils/serial/shakti-uart.h>
|
||||||
|
|
||||||
|
static int serial_shakti_init(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct platform_uart_data uart;
|
||||||
|
|
||||||
|
rc = fdt_parse_shakti_uart_node(fdt, nodeoff, &uart);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return shakti_uart_init(uart.addr, uart.freq, uart.baud);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match serial_shakti_match[] = {
|
||||||
|
{ .compatible = "shakti,uart0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_serial fdt_serial_shakti = {
|
||||||
|
.match_table = serial_shakti_match,
|
||||||
|
.init = serial_shakti_init,
|
||||||
|
.getc = shakti_uart_getc,
|
||||||
|
.putc = shakti_uart_putc
|
||||||
|
};
|
38
lib/utils/serial/fdt_serial_sifive.c
Normal file
38
lib/utils/serial/fdt_serial_sifive.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/serial/fdt_serial.h>
|
||||||
|
#include <sbi_utils/serial/sifive-uart.h>
|
||||||
|
|
||||||
|
static int serial_sifive_init(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct platform_uart_data uart;
|
||||||
|
|
||||||
|
rc = fdt_parse_sifive_uart_node(fdt, nodeoff, &uart);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return sifive_uart_init(uart.addr, uart.freq, uart.baud);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match serial_sifive_match[] = {
|
||||||
|
{ .compatible = "sifive,fu540-c000-uart" },
|
||||||
|
{ .compatible = "sifive,uart0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_serial fdt_serial_sifive = {
|
||||||
|
.match_table = serial_sifive_match,
|
||||||
|
.init = serial_sifive_init,
|
||||||
|
.getc = sifive_uart_getc,
|
||||||
|
.putc = sifive_uart_putc
|
||||||
|
};
|
39
lib/utils/serial/fdt_serial_uart8250.c
Normal file
39
lib/utils/serial/fdt_serial_uart8250.c
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/serial/fdt_serial.h>
|
||||||
|
#include <sbi_utils/serial/uart8250.h>
|
||||||
|
|
||||||
|
static int serial_uart8250_init(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct platform_uart_data uart;
|
||||||
|
|
||||||
|
rc = fdt_parse_uart8250_node(fdt, nodeoff, &uart);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return uart8250_init(uart.addr, uart.freq, uart.baud,
|
||||||
|
uart.reg_shift, uart.reg_io_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match serial_uart8250_match[] = {
|
||||||
|
{ .compatible = "ns16550" },
|
||||||
|
{ .compatible = "ns16550a" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_serial fdt_serial_uart8250 = {
|
||||||
|
.match_table = serial_uart8250_match,
|
||||||
|
.init = serial_uart8250_init,
|
||||||
|
.getc = uart8250_getc,
|
||||||
|
.putc = uart8250_putc
|
||||||
|
};
|
@@ -7,5 +7,11 @@
|
|||||||
# Anup Patel <anup.patel@wdc.com>
|
# Anup Patel <anup.patel@wdc.com>
|
||||||
#
|
#
|
||||||
|
|
||||||
|
libsbiutils-objs-y += serial/fdt_serial.o
|
||||||
|
libsbiutils-objs-y += serial/fdt_serial_htif.o
|
||||||
|
libsbiutils-objs-y += serial/fdt_serial_shakti.o
|
||||||
|
libsbiutils-objs-y += serial/fdt_serial_sifive.o
|
||||||
|
libsbiutils-objs-y += serial/fdt_serial_uart8250.o
|
||||||
|
libsbiutils-objs-y += serial/shakti-uart.o
|
||||||
libsbiutils-objs-y += serial/sifive-uart.o
|
libsbiutils-objs-y += serial/sifive-uart.o
|
||||||
libsbiutils-objs-y += serial/uart8250.o
|
libsbiutils-objs-y += serial/uart8250.o
|
||||||
|
44
lib/utils/serial/shakti-uart.c
Normal file
44
lib/utils/serial/shakti-uart.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Vijai Kumar K <vijai@behindbytes.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi_utils/serial/shakti-uart.h>
|
||||||
|
|
||||||
|
#define REG_BAUD 0x00
|
||||||
|
#define REG_TX 0x04
|
||||||
|
#define REG_RX 0x08
|
||||||
|
#define REG_STATUS 0x0C
|
||||||
|
#define REG_DELAY 0x10
|
||||||
|
#define REG_CONTROL 0x14
|
||||||
|
#define REG_INT_EN 0x18
|
||||||
|
#define REG_IQ_CYCLES 0x1C
|
||||||
|
#define REG_RX_THRES 0x20
|
||||||
|
|
||||||
|
static volatile void *uart_base;
|
||||||
|
|
||||||
|
void shakti_uart_putc(char ch)
|
||||||
|
{
|
||||||
|
while((readw(uart_base + REG_STATUS) & 0x2) == 0);
|
||||||
|
writeb(ch, uart_base + REG_TX);
|
||||||
|
}
|
||||||
|
|
||||||
|
int shakti_uart_getc(void)
|
||||||
|
{
|
||||||
|
u16 status = readw(uart_base + REG_STATUS);
|
||||||
|
if (status & 0x8)
|
||||||
|
return readb(uart_base + REG_RX);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
|
||||||
|
{
|
||||||
|
uart_base = (volatile void *)base;
|
||||||
|
u16 baud = (u16)(in_freq/(16 * baudrate));
|
||||||
|
writew(baud, uart_base + REG_BAUD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@@ -89,7 +89,8 @@ int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
|
|||||||
uart_baudrate = baudrate;
|
uart_baudrate = baudrate;
|
||||||
|
|
||||||
/* Configure baudrate */
|
/* Configure baudrate */
|
||||||
set_reg(UART_REG_DIV, uart_min_clk_divisor(in_freq, baudrate));
|
if (in_freq)
|
||||||
|
set_reg(UART_REG_DIV, uart_min_clk_divisor(in_freq, baudrate));
|
||||||
/* Disable interrupts */
|
/* Disable interrupts */
|
||||||
set_reg(UART_REG_IE, 0);
|
set_reg(UART_REG_IE, 0);
|
||||||
/* Enable TX */
|
/* Enable TX */
|
||||||
|
@@ -100,10 +100,14 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
|||||||
set_reg(UART_IER_OFFSET, 0x00);
|
set_reg(UART_IER_OFFSET, 0x00);
|
||||||
/* Enable DLAB */
|
/* Enable DLAB */
|
||||||
set_reg(UART_LCR_OFFSET, 0x80);
|
set_reg(UART_LCR_OFFSET, 0x80);
|
||||||
/* Set divisor low byte */
|
|
||||||
set_reg(UART_DLL_OFFSET, bdiv & 0xff);
|
if (bdiv) {
|
||||||
/* Set divisor high byte */
|
/* Set divisor low byte */
|
||||||
set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
|
set_reg(UART_DLL_OFFSET, bdiv & 0xff);
|
||||||
|
/* Set divisor high byte */
|
||||||
|
set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
/* 8 bits, no parity, one stop bit */
|
/* 8 bits, no parity, one stop bit */
|
||||||
set_reg(UART_LCR_OFFSET, 0x03);
|
set_reg(UART_LCR_OFFSET, 0x03);
|
||||||
/* Enable FIFO */
|
/* Enable FIFO */
|
||||||
|
@@ -10,57 +10,70 @@
|
|||||||
#include <sbi/riscv_asm.h>
|
#include <sbi/riscv_asm.h>
|
||||||
#include <sbi/riscv_atomic.h>
|
#include <sbi/riscv_atomic.h>
|
||||||
#include <sbi/riscv_io.h>
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi/sbi_hartmask.h>
|
||||||
#include <sbi_utils/sys/clint.h>
|
#include <sbi_utils/sys/clint.h>
|
||||||
|
|
||||||
static u32 clint_ipi_hart_count;
|
#define CLINT_IPI_OFF 0
|
||||||
static volatile void *clint_ipi_base;
|
#define CLINT_TIME_CMP_OFF 0x4000
|
||||||
static volatile u32 *clint_ipi;
|
#define CLINT_TIME_VAL_OFF 0xbff8
|
||||||
|
|
||||||
|
static struct clint_data *clint_ipi_hartid2data[SBI_HARTMASK_MAX_BITS];
|
||||||
|
|
||||||
void clint_ipi_send(u32 target_hart)
|
void clint_ipi_send(u32 target_hart)
|
||||||
{
|
{
|
||||||
if (clint_ipi_hart_count <= target_hart)
|
struct clint_data *clint;
|
||||||
|
|
||||||
|
if (SBI_HARTMASK_MAX_BITS <= target_hart)
|
||||||
|
return;
|
||||||
|
clint = clint_ipi_hartid2data[target_hart];
|
||||||
|
if (!clint)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Set CLINT IPI */
|
/* Set CLINT IPI */
|
||||||
writel(1, &clint_ipi[target_hart]);
|
writel(1, &clint->ipi[target_hart - clint->first_hartid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clint_ipi_clear(u32 target_hart)
|
void clint_ipi_clear(u32 target_hart)
|
||||||
{
|
{
|
||||||
if (clint_ipi_hart_count <= target_hart)
|
struct clint_data *clint;
|
||||||
|
|
||||||
|
if (SBI_HARTMASK_MAX_BITS <= target_hart)
|
||||||
|
return;
|
||||||
|
clint = clint_ipi_hartid2data[target_hart];
|
||||||
|
if (!clint)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Clear CLINT IPI */
|
/* Clear CLINT IPI */
|
||||||
writel(0, &clint_ipi[target_hart]);
|
writel(0, &clint->ipi[target_hart - clint->first_hartid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int clint_warm_ipi_init(void)
|
int clint_warm_ipi_init(void)
|
||||||
{
|
{
|
||||||
u32 hartid = current_hartid();
|
/* Clear CLINT IPI for current HART */
|
||||||
|
clint_ipi_clear(current_hartid());
|
||||||
if (!clint_ipi_base)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* Clear CLINT IPI */
|
|
||||||
clint_ipi_clear(hartid);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clint_cold_ipi_init(unsigned long base, u32 hart_count)
|
int clint_cold_ipi_init(struct clint_data *clint)
|
||||||
{
|
{
|
||||||
/* Figure-out CLINT IPI register address */
|
u32 i;
|
||||||
clint_ipi_hart_count = hart_count;
|
|
||||||
clint_ipi_base = (void *)base;
|
if (!clint)
|
||||||
clint_ipi = (u32 *)clint_ipi_base;
|
return SBI_EINVAL;
|
||||||
|
|
||||||
|
/* Initialize private data */
|
||||||
|
clint->ipi = (void *)clint->addr;
|
||||||
|
|
||||||
|
/* Update IPI hartid table */
|
||||||
|
for (i = 0; i < clint->hart_count; i++)
|
||||||
|
clint_ipi_hartid2data[clint->first_hartid + i] = clint;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 clint_time_hart_count;
|
static struct clint_data *clint_timer_hartid2data[SBI_HARTMASK_MAX_BITS];
|
||||||
static volatile void *clint_time_base;
|
|
||||||
static volatile u64 *clint_time_val;
|
|
||||||
static volatile u64 *clint_time_cmp;
|
|
||||||
|
|
||||||
#if __riscv_xlen != 32
|
#if __riscv_xlen != 32
|
||||||
static u64 clint_time_rd64(volatile u64 *addr)
|
static u64 clint_time_rd64(volatile u64 *addr)
|
||||||
@@ -94,66 +107,97 @@ static void clint_time_wr32(u64 value, volatile u64 *addr)
|
|||||||
writel_relaxed(value >> 32, (void *)(addr) + 0x04);
|
writel_relaxed(value >> 32, (void *)(addr) + 0x04);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 (*clint_time_rd)(volatile u64 *addr) = clint_time_rd32;
|
|
||||||
static void (*clint_time_wr)(u64 value, volatile u64 *addr) = clint_time_wr32;
|
|
||||||
|
|
||||||
u64 clint_timer_value(void)
|
u64 clint_timer_value(void)
|
||||||
{
|
{
|
||||||
|
struct clint_data *clint = clint_timer_hartid2data[current_hartid()];
|
||||||
|
|
||||||
/* Read CLINT Time Value */
|
/* Read CLINT Time Value */
|
||||||
return clint_time_rd(clint_time_val);
|
return clint->time_rd(clint->time_val) + clint->time_delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clint_timer_event_stop(void)
|
void clint_timer_event_stop(void)
|
||||||
{
|
{
|
||||||
u32 target_hart = current_hartid();
|
u32 target_hart = current_hartid();
|
||||||
|
struct clint_data *clint = clint_timer_hartid2data[target_hart];
|
||||||
if (clint_time_hart_count <= target_hart)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Clear CLINT Time Compare */
|
/* Clear CLINT Time Compare */
|
||||||
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
|
clint->time_wr(-1ULL,
|
||||||
|
&clint->time_cmp[target_hart - clint->first_hartid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clint_timer_event_start(u64 next_event)
|
void clint_timer_event_start(u64 next_event)
|
||||||
{
|
{
|
||||||
u32 target_hart = current_hartid();
|
u32 target_hart = current_hartid();
|
||||||
|
struct clint_data *clint = clint_timer_hartid2data[target_hart];
|
||||||
if (clint_time_hart_count <= target_hart)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Program CLINT Time Compare */
|
/* Program CLINT Time Compare */
|
||||||
clint_time_wr(next_event, &clint_time_cmp[target_hart]);
|
clint->time_wr(next_event - clint->time_delta,
|
||||||
|
&clint->time_cmp[target_hart - clint->first_hartid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int clint_warm_timer_init(void)
|
int clint_warm_timer_init(void)
|
||||||
{
|
{
|
||||||
|
u64 v1, v2, mv;
|
||||||
u32 target_hart = current_hartid();
|
u32 target_hart = current_hartid();
|
||||||
|
struct clint_data *reference;
|
||||||
|
struct clint_data *clint = clint_timer_hartid2data[target_hart];
|
||||||
|
|
||||||
if (clint_time_hart_count <= target_hart || !clint_time_base)
|
if (!clint)
|
||||||
return -1;
|
return SBI_ENODEV;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute delta if reference available
|
||||||
|
*
|
||||||
|
* We deliberately compute time_delta in warm init so that time_delta
|
||||||
|
* is computed on a HART which is going to use given CLINT. We use
|
||||||
|
* atomic flag timer_delta_computed to ensure that only one HART does
|
||||||
|
* time_delta computation.
|
||||||
|
*/
|
||||||
|
if (clint->time_delta_reference) {
|
||||||
|
reference = clint->time_delta_reference;
|
||||||
|
if (!atomic_raw_xchg_ulong(&clint->time_delta_computed, 1)) {
|
||||||
|
v1 = clint->time_rd(clint->time_val);
|
||||||
|
mv = reference->time_rd(reference->time_val);
|
||||||
|
v2 = clint->time_rd(clint->time_val);
|
||||||
|
clint->time_delta = mv - ((v1 / 2) + (v2 / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear CLINT Time Compare */
|
/* Clear CLINT Time Compare */
|
||||||
clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
|
clint->time_wr(-1ULL,
|
||||||
|
&clint->time_cmp[target_hart - clint->first_hartid]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clint_cold_timer_init(unsigned long base, u32 hart_count,
|
int clint_cold_timer_init(struct clint_data *clint,
|
||||||
bool has_64bit_mmio)
|
struct clint_data *reference)
|
||||||
{
|
{
|
||||||
/* Figure-out CLINT Time register address */
|
u32 i;
|
||||||
clint_time_hart_count = hart_count;
|
|
||||||
clint_time_base = (void *)base;
|
if (!clint)
|
||||||
clint_time_val = (u64 *)(clint_time_base + 0xbff8);
|
return SBI_EINVAL;
|
||||||
clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
|
|
||||||
|
/* Initialize private data */
|
||||||
|
clint->time_delta_reference = reference;
|
||||||
|
clint->time_delta_computed = 0;
|
||||||
|
clint->time_delta = 0;
|
||||||
|
clint->time_val = (u64 *)((void *)clint->addr + CLINT_TIME_VAL_OFF);
|
||||||
|
clint->time_cmp = (u64 *)((void *)clint->addr + CLINT_TIME_CMP_OFF);
|
||||||
|
clint->time_rd = clint_time_rd32;
|
||||||
|
clint->time_wr = clint_time_wr32;
|
||||||
|
|
||||||
/* Override read/write accessors for 64bit MMIO */
|
/* Override read/write accessors for 64bit MMIO */
|
||||||
#if __riscv_xlen != 32
|
#if __riscv_xlen != 32
|
||||||
if (has_64bit_mmio) {
|
if (clint->has_64bit_mmio) {
|
||||||
clint_time_rd = clint_time_rd64;
|
clint->time_rd = clint_time_rd64;
|
||||||
clint_time_wr = clint_time_wr64;
|
clint->time_wr = clint_time_wr64;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Update timer hartid table */
|
||||||
|
for (i = 0; i < clint->hart_count; i++)
|
||||||
|
clint_timer_hartid2data[clint->first_hartid + i] = clint;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -140,7 +140,7 @@ int htif_getc(void)
|
|||||||
return ch - 1;
|
return ch - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int htif_system_down(u32 type)
|
int htif_system_reset(u32 type)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
fromhost = 0;
|
fromhost = 0;
|
||||||
|
@@ -9,3 +9,4 @@
|
|||||||
|
|
||||||
libsbiutils-objs-y += sys/clint.o
|
libsbiutils-objs-y += sys/clint.o
|
||||||
libsbiutils-objs-y += sys/htif.o
|
libsbiutils-objs-y += sys/htif.o
|
||||||
|
libsbiutils-objs-y += sys/sifive_test.o
|
||||||
|
44
lib/utils/sys/sifive_test.c
Normal file
44
lib/utils/sys/sifive_test.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_platform.h>
|
||||||
|
#include <sbi_utils/sys/sifive_test.h>
|
||||||
|
|
||||||
|
#define FINISHER_FAIL 0x3333
|
||||||
|
#define FINISHER_PASS 0x5555
|
||||||
|
#define FINISHER_RESET 0x7777
|
||||||
|
|
||||||
|
static void *sifive_test_base;
|
||||||
|
|
||||||
|
int sifive_test_system_reset(u32 type)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Tell the "finisher" that the simulation
|
||||||
|
* was successful so that QEMU exits
|
||||||
|
*/
|
||||||
|
switch (type) {
|
||||||
|
case SBI_PLATFORM_RESET_SHUTDOWN:
|
||||||
|
writew(FINISHER_PASS, sifive_test_base);
|
||||||
|
break;
|
||||||
|
case SBI_PLATFORM_RESET_COLD:
|
||||||
|
case SBI_PLATFORM_RESET_WARM:
|
||||||
|
writew(FINISHER_RESET, sifive_test_base);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sifive_test_init(unsigned long base)
|
||||||
|
{
|
||||||
|
sifive_test_base = (void *)base;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
112
lib/utils/timer/fdt_timer.c
Normal file
112
lib/utils/timer/fdt_timer.c
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_scratch.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/timer/fdt_timer.h>
|
||||||
|
|
||||||
|
extern struct fdt_timer fdt_timer_clint;
|
||||||
|
|
||||||
|
static struct fdt_timer *timer_drivers[] = {
|
||||||
|
&fdt_timer_clint
|
||||||
|
};
|
||||||
|
|
||||||
|
static u64 dummy_value(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dummy_event_stop(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dummy_event_start(u64 next_event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fdt_timer dummy = {
|
||||||
|
.match_table = NULL,
|
||||||
|
.cold_init = NULL,
|
||||||
|
.warm_init = NULL,
|
||||||
|
.exit = NULL,
|
||||||
|
.value = dummy_value,
|
||||||
|
.event_stop = dummy_event_stop,
|
||||||
|
.event_start = dummy_event_start
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fdt_timer *current_driver = &dummy;
|
||||||
|
|
||||||
|
u64 fdt_timer_value(void)
|
||||||
|
{
|
||||||
|
return current_driver->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fdt_timer_event_stop(void)
|
||||||
|
{
|
||||||
|
current_driver->event_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fdt_timer_event_start(u64 next_event)
|
||||||
|
{
|
||||||
|
current_driver->event_start(next_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fdt_timer_exit(void)
|
||||||
|
{
|
||||||
|
if (current_driver->exit)
|
||||||
|
current_driver->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_timer_warm_init(void)
|
||||||
|
{
|
||||||
|
if (current_driver->warm_init)
|
||||||
|
return current_driver->warm_init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_timer_cold_init(void)
|
||||||
|
{
|
||||||
|
int pos, noff, rc;
|
||||||
|
struct fdt_timer *drv;
|
||||||
|
const struct fdt_match *match;
|
||||||
|
void *fdt = sbi_scratch_thishart_arg1_ptr();
|
||||||
|
|
||||||
|
for (pos = 0; pos < array_size(timer_drivers); pos++) {
|
||||||
|
drv = timer_drivers[pos];
|
||||||
|
|
||||||
|
noff = -1;
|
||||||
|
while ((noff = fdt_find_match(fdt, noff,
|
||||||
|
drv->match_table, &match)) >= 0) {
|
||||||
|
if (drv->cold_init) {
|
||||||
|
rc = drv->cold_init(fdt, noff, match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
current_driver = drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_driver != &dummy)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fdt_timer_init(bool cold_boot)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (cold_boot) {
|
||||||
|
rc = fdt_timer_cold_init();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fdt_timer_warm_init();
|
||||||
|
}
|
52
lib/utils/timer/fdt_timer_clint.c
Normal file
52
lib/utils/timer/fdt_timer_clint.c
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/sbi_error.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/timer/fdt_timer.h>
|
||||||
|
#include <sbi_utils/sys/clint.h>
|
||||||
|
|
||||||
|
#define CLINT_TIMER_MAX_NR 16
|
||||||
|
|
||||||
|
static unsigned long clint_timer_count = 0;
|
||||||
|
static struct clint_data clint_timer[CLINT_TIMER_MAX_NR];
|
||||||
|
|
||||||
|
static int timer_clint_cold_init(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct clint_data *ct, *ctmaster = NULL;
|
||||||
|
|
||||||
|
if (CLINT_TIMER_MAX_NR <= clint_timer_count)
|
||||||
|
return SBI_ENOSPC;
|
||||||
|
ct = &clint_timer[clint_timer_count++];
|
||||||
|
if (1 < clint_timer_count)
|
||||||
|
ctmaster = &clint_timer[0];
|
||||||
|
|
||||||
|
rc = fdt_parse_clint_node(fdt, nodeoff, TRUE, ct);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return clint_cold_timer_init(ct, ctmaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match timer_clint_match[] = {
|
||||||
|
{ .compatible = "riscv,clint0" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_timer fdt_timer_clint = {
|
||||||
|
.match_table = timer_clint_match,
|
||||||
|
.cold_init = timer_clint_cold_init,
|
||||||
|
.warm_init = clint_warm_timer_init,
|
||||||
|
.exit = NULL,
|
||||||
|
.value = clint_timer_value,
|
||||||
|
.event_stop = clint_timer_event_stop,
|
||||||
|
.event_start = clint_timer_event_start,
|
||||||
|
};
|
11
lib/utils/timer/objects.mk
Normal file
11
lib/utils/timer/objects.mk
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# Anup Patel <anup.patel@wdc.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
libsbiutils-objs-y += timer/fdt_timer.o
|
||||||
|
libsbiutils-objs-y += timer/fdt_timer_clint.o
|
89
platform/andes/ae350/cache.c
Normal file
89
platform/andes/ae350/cache.c
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Andes Technology Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Nylon Chen <nylon7@andestech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/riscv_asm.h>
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
uintptr_t mcall_set_mcache_ctl(unsigned long input)
|
||||||
|
{
|
||||||
|
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_MASK);
|
||||||
|
csr_write(CSR_MCACHECTL, input);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t mcall_set_mmisc_ctl(unsigned long input)
|
||||||
|
{
|
||||||
|
csr_clear(CSR_MMISCCTL, V5_MMISC_CTL_MASK);
|
||||||
|
csr_write(CSR_MMISCCTL, input);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t mcall_icache_op(unsigned int enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_IC_EN);
|
||||||
|
} else {
|
||||||
|
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_IC_EN);
|
||||||
|
asm volatile("fence.i\n\t");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t mcall_dcache_op(unsigned int enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_DC_EN);
|
||||||
|
} else {
|
||||||
|
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_DC_EN);
|
||||||
|
csr_write(CSR_MCCTLCOMMAND, V5_UCCTL_L1D_WBINVAL_ALL);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t mcall_l1_cache_i_prefetch_op(unsigned long enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_L1I_PREFETCH_EN);
|
||||||
|
} else {
|
||||||
|
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_L1I_PREFETCH_EN);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t mcall_l1_cache_d_prefetch_op(unsigned long enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_L1D_PREFETCH_EN);
|
||||||
|
} else {
|
||||||
|
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_L1D_PREFETCH_EN);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t mcall_non_blocking_load_store(unsigned long enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
csr_set(CSR_MCACHECTL, V5_MMISC_CTL_NON_BLOCKING_EN);
|
||||||
|
} else {
|
||||||
|
csr_clear(CSR_MCACHECTL, V5_MMISC_CTL_NON_BLOCKING_EN);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t mcall_write_around(unsigned long enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
csr_set(CSR_MCACHECTL, V5_MCACHE_CTL_DC_WAROUND_1_EN);
|
||||||
|
} else {
|
||||||
|
csr_clear(CSR_MCACHECTL, V5_MCACHE_CTL_DC_WAROUND_1_EN);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
17
platform/andes/ae350/cache.h
Normal file
17
platform/andes/ae350/cache.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Andes Technology Corporation
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Nylon Chen <nylon7@andestech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
uintptr_t mcall_set_mcache_ctl(unsigned long input);
|
||||||
|
uintptr_t mcall_set_mmisc_ctl(unsigned long input);
|
||||||
|
uintptr_t mcall_icache_op(unsigned int enable);
|
||||||
|
uintptr_t mcall_dcache_op(unsigned int enable);
|
||||||
|
uintptr_t mcall_l1_cache_i_prefetch_op(unsigned long enable);
|
||||||
|
uintptr_t mcall_l1_cache_d_prefetch_op(unsigned long enable);
|
||||||
|
uintptr_t mcall_non_blocking_load_store(unsigned long enable);
|
||||||
|
uintptr_t mcall_write_around(unsigned long enable);
|
@@ -8,4 +8,4 @@
|
|||||||
# Nylon Chen <nylon7@andestech.com>
|
# Nylon Chen <nylon7@andestech.com>
|
||||||
#
|
#
|
||||||
|
|
||||||
platform-objs-y += platform.o plicsw.o plmt.o
|
platform-objs-y += cache.o platform.o plicsw.o plmt.o
|
||||||
|
@@ -19,6 +19,12 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "plicsw.h"
|
#include "plicsw.h"
|
||||||
#include "plmt.h"
|
#include "plmt.h"
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
|
static struct plic_data plic = {
|
||||||
|
.addr = AE350_PLIC_ADDR,
|
||||||
|
.num_src = AE350_PLIC_NUM_SOURCES,
|
||||||
|
};
|
||||||
|
|
||||||
/* Platform final initialization. */
|
/* Platform final initialization. */
|
||||||
static int ae350_final_init(bool cold_boot)
|
static int ae350_final_init(bool cold_boot)
|
||||||
@@ -53,35 +59,6 @@ static int ae350_final_init(bool cold_boot)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get number of PMP regions for given HART. */
|
|
||||||
static u32 ae350_pmp_region_count(u32 hartid)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get PMP regions details (namely: protection, base address, and size) for
|
|
||||||
* a given HART.
|
|
||||||
*/
|
|
||||||
static int ae350_pmp_region_info(u32 hartid, u32 index, ulong *prot,
|
|
||||||
ulong *addr, ulong *log2size)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
*prot = PMP_R | PMP_W | PMP_X;
|
|
||||||
*addr = 0;
|
|
||||||
*log2size = __riscv_xlen;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -1;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the platform console. */
|
/* Initialize the platform console. */
|
||||||
static int ae350_console_init(void)
|
static int ae350_console_init(void)
|
||||||
{
|
{
|
||||||
@@ -99,14 +76,12 @@ static int ae350_irqchip_init(bool cold_boot)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
ret = plic_cold_irqchip_init(AE350_PLIC_ADDR,
|
ret = plic_cold_irqchip_init(&plic);
|
||||||
AE350_PLIC_NUM_SOURCES,
|
|
||||||
AE350_HART_COUNT);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return plic_warm_irqchip_init(hartid, 2 * hartid, 2 * hartid + 1);
|
return plic_warm_irqchip_init(&plic, 2 * hartid, 2 * hartid + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize IPI for current HART. */
|
/* Initialize IPI for current HART. */
|
||||||
@@ -139,29 +114,62 @@ static int ae350_timer_init(bool cold_boot)
|
|||||||
return plmt_warm_timer_init();
|
return plmt_warm_timer_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reboot the platform. */
|
/* Reset the platform. */
|
||||||
static int ae350_system_reboot(u32 type)
|
static int ae350_system_reset(u32 type)
|
||||||
{
|
{
|
||||||
/* For now nothing to do. */
|
/* For now nothing to do. */
|
||||||
sbi_printf("System reboot\n");
|
sbi_printf("System reset\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shutdown or poweroff the platform. */
|
/* Vendor-Specific SBI handler */
|
||||||
static int ae350_system_shutdown(u32 type)
|
static int ae350_vendor_ext_provider(long extid, long funcid,
|
||||||
|
unsigned long *args, unsigned long *out_value,
|
||||||
|
struct sbi_trap_info *out_trap)
|
||||||
{
|
{
|
||||||
/* For now nothing to do. */
|
int ret = 0;
|
||||||
sbi_printf("System shutdown\n");
|
switch (funcid) {
|
||||||
return 0;
|
case SBI_EXT_ANDES_GET_MCACHE_CTL_STATUS:
|
||||||
|
*out_value = csr_read(CSR_MCACHECTL);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_GET_MMISC_CTL_STATUS:
|
||||||
|
*out_value = csr_read(CSR_MMISCCTL);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_SET_MCACHE_CTL:
|
||||||
|
ret = mcall_set_mcache_ctl(args[0]);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_SET_MMISC_CTL:
|
||||||
|
ret = mcall_set_mmisc_ctl(args[0]);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_ICACHE_OP:
|
||||||
|
ret = mcall_icache_op(args[0]);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_DCACHE_OP:
|
||||||
|
ret = mcall_dcache_op(args[0]);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_L1CACHE_I_PREFETCH:
|
||||||
|
ret = mcall_l1_cache_i_prefetch_op(args[0]);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_L1CACHE_D_PREFETCH:
|
||||||
|
ret = mcall_l1_cache_d_prefetch_op(args[0]);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_NON_BLOCKING_LOAD_STORE:
|
||||||
|
ret = mcall_non_blocking_load_store(args[0]);
|
||||||
|
break;
|
||||||
|
case SBI_EXT_ANDES_WRITE_AROUND:
|
||||||
|
ret = mcall_write_around(args[0]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sbi_printf("Unsupported vendor sbi call : %ld\n", funcid);
|
||||||
|
asm volatile("ebreak");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Platform descriptor. */
|
/* Platform descriptor. */
|
||||||
const struct sbi_platform_operations platform_ops = {
|
const struct sbi_platform_operations platform_ops = {
|
||||||
.final_init = ae350_final_init,
|
.final_init = ae350_final_init,
|
||||||
|
|
||||||
.pmp_region_count = ae350_pmp_region_count,
|
|
||||||
.pmp_region_info = ae350_pmp_region_info,
|
|
||||||
|
|
||||||
.console_init = ae350_console_init,
|
.console_init = ae350_console_init,
|
||||||
.console_putc = uart8250_putc,
|
.console_putc = uart8250_putc,
|
||||||
.console_getc = uart8250_getc,
|
.console_getc = uart8250_getc,
|
||||||
@@ -177,8 +185,9 @@ const struct sbi_platform_operations platform_ops = {
|
|||||||
.timer_event_start = plmt_timer_event_start,
|
.timer_event_start = plmt_timer_event_start,
|
||||||
.timer_event_stop = plmt_timer_event_stop,
|
.timer_event_stop = plmt_timer_event_stop,
|
||||||
|
|
||||||
.system_reboot = ae350_system_reboot,
|
.system_reset = ae350_system_reset,
|
||||||
.system_shutdown = ae350_system_shutdown
|
|
||||||
|
.vendor_ext_provider = ae350_vendor_ext_provider
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct sbi_platform platform = {
|
const struct sbi_platform platform = {
|
||||||
|
@@ -29,9 +29,58 @@
|
|||||||
#define AE350_UART_REG_SHIFT 2
|
#define AE350_UART_REG_SHIFT 2
|
||||||
#define AE350_UART_REG_WIDTH 0
|
#define AE350_UART_REG_WIDTH 0
|
||||||
|
|
||||||
/* nds mcache_ctl register*/
|
/*Memory and Miscellaneous Registers*/
|
||||||
#define CSR_MCACHECTL 0x7ca
|
#define CSR_MILMB 0x7c0
|
||||||
|
#define CSR_MDLMB 0x7c1
|
||||||
|
#define CSR_MECC_CDOE 0x7c2
|
||||||
|
#define CSR_MNVEC 0x7c3
|
||||||
|
#define CSR_MPFTCTL 0x7c5
|
||||||
|
#define CSR_MCACHECTL 0x7ca
|
||||||
|
#define CSR_MCCTLBEGINADDR 0x7cb
|
||||||
|
#define CSR_MCCTLCOMMAND 0x7cc
|
||||||
|
#define CSR_MCCTLDATA 0x7cc
|
||||||
|
#define CSR_SCCTLDATA 0x9cd
|
||||||
|
#define CSR_UCCTLBEGINADDR 0x80c
|
||||||
|
#define CSR_MMISCCTL 0x7d0
|
||||||
|
|
||||||
|
enum sbi_ext_andes_fid {
|
||||||
|
SBI_EXT_ANDES_GET_MCACHE_CTL_STATUS = 0,
|
||||||
|
SBI_EXT_ANDES_GET_MMISC_CTL_STATUS,
|
||||||
|
SBI_EXT_ANDES_SET_MCACHE_CTL,
|
||||||
|
SBI_EXT_ANDES_SET_MMISC_CTL,
|
||||||
|
SBI_EXT_ANDES_ICACHE_OP,
|
||||||
|
SBI_EXT_ANDES_DCACHE_OP,
|
||||||
|
SBI_EXT_ANDES_L1CACHE_I_PREFETCH,
|
||||||
|
SBI_EXT_ANDES_L1CACHE_D_PREFETCH,
|
||||||
|
SBI_EXT_ANDES_NON_BLOCKING_LOAD_STORE,
|
||||||
|
SBI_EXT_ANDES_WRITE_AROUND,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* nds v5 mmisc_ctl register*/
|
||||||
|
#define V5_MMISC_CTL_VEC_PLIC_OFFSET 1
|
||||||
|
#define V5_MMISC_CTL_RVCOMPM_OFFSET 2
|
||||||
|
#define V5_MMISC_CTL_BRPE_OFFSET 3
|
||||||
|
#define V5_MMISC_CTL_MSA_OR_UNA_OFFSET 6
|
||||||
|
#define V5_MMISC_CTL_NON_BLOCKING_OFFSET 8
|
||||||
|
#define V5_MCACHE_CTL_L1I_PREFETCH_OFFSET 9
|
||||||
|
#define V5_MCACHE_CTL_L1D_PREFETCH_OFFSET 10
|
||||||
|
#define V5_MCACHE_CTL_DC_WAROUND_OFFSET_1 13
|
||||||
|
#define V5_MCACHE_CTL_DC_WAROUND_OFFSET_2 14
|
||||||
|
|
||||||
|
#define V5_MMISC_CTL_VEC_PLIC_EN (1UL << V5_MMISC_CTL_VEC_PLIC_OFFSET)
|
||||||
|
#define V5_MMISC_CTL_RVCOMPM_EN (1UL << V5_MMISC_CTL_RVCOMPM_OFFSET)
|
||||||
|
#define V5_MMISC_CTL_BRPE_EN (1UL << V5_MMISC_CTL_BRPE_OFFSET)
|
||||||
|
#define V5_MMISC_CTL_MSA_OR_UNA_EN (1UL << V5_MMISC_CTL_MSA_OR_UNA_OFFSET)
|
||||||
|
#define V5_MMISC_CTL_NON_BLOCKING_EN (1UL << V5_MMISC_CTL_NON_BLOCKING_OFFSET)
|
||||||
|
#define V5_MCACHE_CTL_L1I_PREFETCH_EN (1UL << V5_MCACHE_CTL_L1I_PREFETCH_OFFSET)
|
||||||
|
#define V5_MCACHE_CTL_L1D_PREFETCH_EN (1UL << V5_MCACHE_CTL_L1D_PREFETCH_OFFSET)
|
||||||
|
#define V5_MCACHE_CTL_DC_WAROUND_1_EN (1UL << V5_MCACHE_CTL_DC_WAROUND_OFFSET_1)
|
||||||
|
#define V5_MCACHE_CTL_DC_WAROUND_2_EN (1UL << V5_MCACHE_CTL_DC_WAROUND_OFFSET_2)
|
||||||
|
|
||||||
|
#define V5_MMISC_CTL_MASK (V5_MMISC_CTL_VEC_PLIC_EN | V5_MMISC_CTL_RVCOMPM_EN \
|
||||||
|
| V5_MMISC_CTL_BRPE_EN | V5_MMISC_CTL_MSA_OR_UNA_EN | V5_MMISC_CTL_NON_BLOCKING_EN)
|
||||||
|
|
||||||
|
/* nds mcache_ctl register*/
|
||||||
#define V5_MCACHE_CTL_IC_EN_OFFSET 0
|
#define V5_MCACHE_CTL_IC_EN_OFFSET 0
|
||||||
#define V5_MCACHE_CTL_DC_EN_OFFSET 1
|
#define V5_MCACHE_CTL_DC_EN_OFFSET 1
|
||||||
#define V5_MCACHE_CTL_IC_ECCEN_OFFSET 2
|
#define V5_MCACHE_CTL_IC_ECCEN_OFFSET 2
|
||||||
@@ -40,12 +89,22 @@
|
|||||||
#define V5_MCACHE_CTL_DC_RWECC_OFFSET 7
|
#define V5_MCACHE_CTL_DC_RWECC_OFFSET 7
|
||||||
#define V5_MCACHE_CTL_CCTL_SUEN_OFFSET 8
|
#define V5_MCACHE_CTL_CCTL_SUEN_OFFSET 8
|
||||||
|
|
||||||
|
/*nds cctl command*/
|
||||||
|
#define V5_UCCTL_L1D_WBINVAL_ALL 6
|
||||||
|
#define V5_UCCTL_L1D_WB_ALL 7
|
||||||
|
|
||||||
#define V5_MCACHE_CTL_IC_EN (1UL << V5_MCACHE_CTL_IC_EN_OFFSET)
|
#define V5_MCACHE_CTL_IC_EN (1UL << V5_MCACHE_CTL_IC_EN_OFFSET)
|
||||||
#define V5_MCACHE_CTL_DC_EN (1UL << V5_MCACHE_CTL_DC_EN_OFFSET)
|
#define V5_MCACHE_CTL_DC_EN (1UL << V5_MCACHE_CTL_DC_EN_OFFSET)
|
||||||
#define V5_MCACHE_CTL_IC_RWECC (1UL << V5_MCACHE_CTL_IC_RWECC_OFFSET)
|
#define V5_MCACHE_CTL_IC_RWECC (1UL << V5_MCACHE_CTL_IC_RWECC_OFFSET)
|
||||||
#define V5_MCACHE_CTL_DC_RWECC (1UL << V5_MCACHE_CTL_DC_RWECC_OFFSET)
|
#define V5_MCACHE_CTL_DC_RWECC (1UL << V5_MCACHE_CTL_DC_RWECC_OFFSET)
|
||||||
#define V5_MCACHE_CTL_CCTL_SUEN (1UL << V5_MCACHE_CTL_CCTL_SUEN_OFFSET)
|
#define V5_MCACHE_CTL_CCTL_SUEN (1UL << V5_MCACHE_CTL_CCTL_SUEN_OFFSET)
|
||||||
|
|
||||||
|
#define V5_MCACHE_CTL_MASK (V5_MCACHE_CTL_IC_EN | V5_MCACHE_CTL_DC_EN \
|
||||||
|
| V5_MCACHE_CTL_IC_RWECC | V5_MCACHE_CTL_DC_RWECC \
|
||||||
|
| V5_MCACHE_CTL_CCTL_SUEN | V5_MCACHE_CTL_L1I_PREFETCH_EN \
|
||||||
|
| V5_MCACHE_CTL_L1D_PREFETCH_EN | V5_MCACHE_CTL_DC_WAROUND_1_EN \
|
||||||
|
| V5_MCACHE_CTL_DC_WAROUND_2_EN)
|
||||||
|
|
||||||
#define V5_L2C_CTL_OFFSET 0x8
|
#define V5_L2C_CTL_OFFSET 0x8
|
||||||
#define V5_L2C_CTL_ENABLE_OFFSET 0
|
#define V5_L2C_CTL_ENABLE_OFFSET 0
|
||||||
#define V5_L2C_CTL_IPFDPT_OFFSET 3
|
#define V5_L2C_CTL_IPFDPT_OFFSET 3
|
||||||
|
@@ -24,13 +24,19 @@
|
|||||||
#define ARIANE_PLIC_ADDR 0xc000000
|
#define ARIANE_PLIC_ADDR 0xc000000
|
||||||
#define ARIANE_PLIC_NUM_SOURCES 3
|
#define ARIANE_PLIC_NUM_SOURCES 3
|
||||||
#define ARIANE_HART_COUNT 1
|
#define ARIANE_HART_COUNT 1
|
||||||
#define ARIANE_CLINT_ADDR 0x2000000
|
#define ARIANE_CLINT_ADDR 0x2000000
|
||||||
|
|
||||||
#define SBI_ARIANE_FEATURES \
|
static struct plic_data plic = {
|
||||||
(SBI_PLATFORM_HAS_TIMER_VALUE | \
|
.addr = ARIANE_PLIC_ADDR,
|
||||||
SBI_PLATFORM_HAS_SCOUNTEREN | \
|
.num_src = ARIANE_PLIC_NUM_SOURCES,
|
||||||
SBI_PLATFORM_HAS_MCOUNTEREN | \
|
};
|
||||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
|
||||||
|
static struct clint_data clint = {
|
||||||
|
.addr = ARIANE_CLINT_ADDR,
|
||||||
|
.first_hartid = 0,
|
||||||
|
.hart_count = ARIANE_HART_COUNT,
|
||||||
|
.has_64bit_mmio = TRUE,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ariane platform early initialization.
|
* Ariane platform early initialization.
|
||||||
@@ -69,29 +75,26 @@ static int ariane_console_init(void)
|
|||||||
ARIANE_UART_REG_WIDTH);
|
ARIANE_UART_REG_WIDTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int plic_ariane_warm_irqchip_init(u32 target_hart,
|
static int plic_ariane_warm_irqchip_init(int m_cntx_id, int s_cntx_id)
|
||||||
int m_cntx_id, int s_cntx_id)
|
|
||||||
{
|
{
|
||||||
size_t i, ie_words = ARIANE_PLIC_NUM_SOURCES / 32 + 1;
|
size_t i, ie_words = ARIANE_PLIC_NUM_SOURCES / 32 + 1;
|
||||||
|
|
||||||
if (ARIANE_HART_COUNT <= target_hart)
|
|
||||||
return -1;
|
|
||||||
/* By default, enable all IRQs for M-mode of target HART */
|
/* By default, enable all IRQs for M-mode of target HART */
|
||||||
if (m_cntx_id > -1) {
|
if (m_cntx_id > -1) {
|
||||||
for (i = 0; i < ie_words; i++)
|
for (i = 0; i < ie_words; i++)
|
||||||
plic_set_ie(m_cntx_id, i, 1);
|
plic_set_ie(&plic, m_cntx_id, i, 1);
|
||||||
}
|
}
|
||||||
/* Enable all IRQs for S-mode of target HART */
|
/* Enable all IRQs for S-mode of target HART */
|
||||||
if (s_cntx_id > -1) {
|
if (s_cntx_id > -1) {
|
||||||
for (i = 0; i < ie_words; i++)
|
for (i = 0; i < ie_words; i++)
|
||||||
plic_set_ie(s_cntx_id, i, 1);
|
plic_set_ie(&plic, s_cntx_id, i, 1);
|
||||||
}
|
}
|
||||||
/* By default, enable M-mode threshold */
|
/* By default, enable M-mode threshold */
|
||||||
if (m_cntx_id > -1)
|
if (m_cntx_id > -1)
|
||||||
plic_set_thresh(m_cntx_id, 1);
|
plic_set_thresh(&plic, m_cntx_id, 1);
|
||||||
/* By default, disable S-mode threshold */
|
/* By default, disable S-mode threshold */
|
||||||
if (s_cntx_id > -1)
|
if (s_cntx_id > -1)
|
||||||
plic_set_thresh(s_cntx_id, 0);
|
plic_set_thresh(&plic, s_cntx_id, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -105,14 +108,11 @@ static int ariane_irqchip_init(bool cold_boot)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
ret = plic_cold_irqchip_init(ARIANE_PLIC_ADDR,
|
ret = plic_cold_irqchip_init(&plic);
|
||||||
ARIANE_PLIC_NUM_SOURCES,
|
|
||||||
ARIANE_HART_COUNT);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return plic_ariane_warm_irqchip_init(hartid,
|
return plic_ariane_warm_irqchip_init(2 * hartid, 2 * hartid + 1);
|
||||||
2 * hartid, 2 * hartid + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -123,8 +123,7 @@ static int ariane_ipi_init(bool cold_boot)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
ret = clint_cold_ipi_init(ARIANE_CLINT_ADDR,
|
ret = clint_cold_ipi_init(&clint);
|
||||||
ARIANE_HART_COUNT);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -140,8 +139,7 @@ static int ariane_timer_init(bool cold_boot)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
ret = clint_cold_timer_init(ARIANE_CLINT_ADDR,
|
ret = clint_cold_timer_init(&clint, NULL);
|
||||||
ARIANE_HART_COUNT, TRUE);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -150,22 +148,12 @@ static int ariane_timer_init(bool cold_boot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reboot the ariane.
|
* Reset the ariane.
|
||||||
*/
|
*/
|
||||||
static int ariane_system_reboot(u32 type)
|
static int ariane_system_reset(u32 type)
|
||||||
{
|
{
|
||||||
/* For now nothing to do. */
|
/* For now nothing to do. */
|
||||||
sbi_printf("System reboot\n");
|
sbi_printf("System reset\n");
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Shutdown or poweroff the ariane.
|
|
||||||
*/
|
|
||||||
static int ariane_system_shutdown(u32 type)
|
|
||||||
{
|
|
||||||
/* For now nothing to do. */
|
|
||||||
sbi_printf("System shutdown\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,15 +174,14 @@ const struct sbi_platform_operations platform_ops = {
|
|||||||
.timer_value = clint_timer_value,
|
.timer_value = clint_timer_value,
|
||||||
.timer_event_start = clint_timer_event_start,
|
.timer_event_start = clint_timer_event_start,
|
||||||
.timer_event_stop = clint_timer_event_stop,
|
.timer_event_stop = clint_timer_event_stop,
|
||||||
.system_reboot = ariane_system_reboot,
|
.system_reset = ariane_system_reset
|
||||||
.system_shutdown = ariane_system_shutdown
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct sbi_platform platform = {
|
const struct sbi_platform platform = {
|
||||||
.opensbi_version = OPENSBI_VERSION,
|
.opensbi_version = OPENSBI_VERSION,
|
||||||
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
||||||
.name = "ARIANE RISC-V",
|
.name = "ARIANE RISC-V",
|
||||||
.features = SBI_ARIANE_FEATURES,
|
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
||||||
.hart_count = ARIANE_HART_COUNT,
|
.hart_count = ARIANE_HART_COUNT,
|
||||||
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
|
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
|
||||||
.platform_ops_addr = (unsigned long)&platform_ops
|
.platform_ops_addr = (unsigned long)&platform_ops
|
||||||
|
@@ -26,22 +26,22 @@
|
|||||||
#define OPENPITON_DEFAULT_HART_COUNT 3
|
#define OPENPITON_DEFAULT_HART_COUNT 3
|
||||||
#define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000
|
#define OPENPITON_DEFAULT_CLINT_ADDR 0xfff1020000
|
||||||
|
|
||||||
#define SBI_OPENPITON_FEATURES \
|
|
||||||
(SBI_PLATFORM_HAS_TIMER_VALUE | \
|
|
||||||
SBI_PLATFORM_HAS_SCOUNTEREN | \
|
|
||||||
SBI_PLATFORM_HAS_MCOUNTEREN | \
|
|
||||||
SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
|
|
||||||
|
|
||||||
static struct platform_uart_data uart = {
|
static struct platform_uart_data uart = {
|
||||||
OPENPITON_DEFAULT_UART_ADDR,
|
OPENPITON_DEFAULT_UART_ADDR,
|
||||||
OPENPITON_DEFAULT_UART_FREQ,
|
OPENPITON_DEFAULT_UART_FREQ,
|
||||||
OPENPITON_DEFAULT_UART_BAUDRATE,
|
OPENPITON_DEFAULT_UART_BAUDRATE,
|
||||||
};
|
};
|
||||||
static struct platform_plic_data plic = {
|
static struct plic_data plic = {
|
||||||
OPENPITON_DEFAULT_PLIC_ADDR,
|
.addr = OPENPITON_DEFAULT_PLIC_ADDR,
|
||||||
OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
|
.num_src = OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
|
||||||
};
|
};
|
||||||
static unsigned long clint_addr = OPENPITON_DEFAULT_CLINT_ADDR;
|
|
||||||
|
static struct clint_data clint = {
|
||||||
|
.addr = OPENPITON_DEFAULT_CLINT_ADDR,
|
||||||
|
.first_hartid = 0,
|
||||||
|
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
|
||||||
|
.has_64bit_mmio = TRUE,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OpenPiton platform early initialization.
|
* OpenPiton platform early initialization.
|
||||||
@@ -50,8 +50,8 @@ static int openpiton_early_init(bool cold_boot)
|
|||||||
{
|
{
|
||||||
void *fdt;
|
void *fdt;
|
||||||
struct platform_uart_data uart_data;
|
struct platform_uart_data uart_data;
|
||||||
struct platform_plic_data plic_data;
|
struct plic_data plic_data;
|
||||||
unsigned long clint_data;
|
unsigned long clint_addr;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!cold_boot)
|
if (!cold_boot)
|
||||||
@@ -66,9 +66,9 @@ static int openpiton_early_init(bool cold_boot)
|
|||||||
if (!rc)
|
if (!rc)
|
||||||
plic = plic_data;
|
plic = plic_data;
|
||||||
|
|
||||||
rc = fdt_parse_clint(fdt, &clint_data, "riscv,clint0");
|
rc = fdt_parse_compat_addr(fdt, &clint_addr, "riscv,clint0");
|
||||||
if (!rc)
|
if (!rc)
|
||||||
clint_addr = clint_data;
|
clint.addr = clint_addr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -101,29 +101,26 @@ static int openpiton_console_init(void)
|
|||||||
OPENPITON_DEFAULT_UART_REG_WIDTH);
|
OPENPITON_DEFAULT_UART_REG_WIDTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int plic_openpiton_warm_irqchip_init(u32 target_hart,
|
static int plic_openpiton_warm_irqchip_init(int m_cntx_id, int s_cntx_id)
|
||||||
int m_cntx_id, int s_cntx_id)
|
|
||||||
{
|
{
|
||||||
size_t i, ie_words = plic.num_src / 32 + 1;
|
size_t i, ie_words = plic.num_src / 32 + 1;
|
||||||
|
|
||||||
if (target_hart >= OPENPITON_DEFAULT_HART_COUNT)
|
|
||||||
return -1;
|
|
||||||
/* By default, enable all IRQs for M-mode of target HART */
|
/* By default, enable all IRQs for M-mode of target HART */
|
||||||
if (m_cntx_id > -1) {
|
if (m_cntx_id > -1) {
|
||||||
for (i = 0; i < ie_words; i++)
|
for (i = 0; i < ie_words; i++)
|
||||||
plic_set_ie(m_cntx_id, i, 1);
|
plic_set_ie(&plic, m_cntx_id, i, 1);
|
||||||
}
|
}
|
||||||
/* Enable all IRQs for S-mode of target HART */
|
/* Enable all IRQs for S-mode of target HART */
|
||||||
if (s_cntx_id > -1) {
|
if (s_cntx_id > -1) {
|
||||||
for (i = 0; i < ie_words; i++)
|
for (i = 0; i < ie_words; i++)
|
||||||
plic_set_ie(s_cntx_id, i, 1);
|
plic_set_ie(&plic, s_cntx_id, i, 1);
|
||||||
}
|
}
|
||||||
/* By default, enable M-mode threshold */
|
/* By default, enable M-mode threshold */
|
||||||
if (m_cntx_id > -1)
|
if (m_cntx_id > -1)
|
||||||
plic_set_thresh(m_cntx_id, 1);
|
plic_set_thresh(&plic, m_cntx_id, 1);
|
||||||
/* By default, disable S-mode threshold */
|
/* By default, disable S-mode threshold */
|
||||||
if (s_cntx_id > -1)
|
if (s_cntx_id > -1)
|
||||||
plic_set_thresh(s_cntx_id, 0);
|
plic_set_thresh(&plic, s_cntx_id, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -137,14 +134,11 @@ static int openpiton_irqchip_init(bool cold_boot)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
ret = plic_cold_irqchip_init(plic.addr,
|
ret = plic_cold_irqchip_init(&plic);
|
||||||
plic.num_src,
|
|
||||||
OPENPITON_DEFAULT_HART_COUNT);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return plic_openpiton_warm_irqchip_init(hartid,
|
return plic_openpiton_warm_irqchip_init(2 * hartid, 2 * hartid + 1);
|
||||||
2 * hartid, 2 * hartid + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -155,8 +149,7 @@ static int openpiton_ipi_init(bool cold_boot)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
ret = clint_cold_ipi_init(clint_addr,
|
ret = clint_cold_ipi_init(&clint);
|
||||||
OPENPITON_DEFAULT_HART_COUNT);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -172,8 +165,7 @@ static int openpiton_timer_init(bool cold_boot)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (cold_boot) {
|
if (cold_boot) {
|
||||||
ret = clint_cold_timer_init(clint_addr,
|
ret = clint_cold_timer_init(&clint, NULL);
|
||||||
OPENPITON_DEFAULT_HART_COUNT, TRUE);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -182,22 +174,12 @@ static int openpiton_timer_init(bool cold_boot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reboot the openpiton.
|
* Reset the openpiton.
|
||||||
*/
|
*/
|
||||||
static int openpiton_system_reboot(u32 type)
|
static int openpiton_system_reset(u32 type)
|
||||||
{
|
{
|
||||||
/* For now nothing to do. */
|
/* For now nothing to do. */
|
||||||
sbi_printf("System reboot\n");
|
sbi_printf("System reset\n");
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Shutdown or poweroff the openpiton.
|
|
||||||
*/
|
|
||||||
static int openpiton_system_shutdown(u32 type)
|
|
||||||
{
|
|
||||||
/* For now nothing to do. */
|
|
||||||
sbi_printf("System shutdown\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,15 +200,14 @@ const struct sbi_platform_operations platform_ops = {
|
|||||||
.timer_value = clint_timer_value,
|
.timer_value = clint_timer_value,
|
||||||
.timer_event_start = clint_timer_event_start,
|
.timer_event_start = clint_timer_event_start,
|
||||||
.timer_event_stop = clint_timer_event_stop,
|
.timer_event_stop = clint_timer_event_stop,
|
||||||
.system_reboot = openpiton_system_reboot,
|
.system_reset = openpiton_system_reset
|
||||||
.system_shutdown = openpiton_system_shutdown
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct sbi_platform platform = {
|
const struct sbi_platform platform = {
|
||||||
.opensbi_version = OPENSBI_VERSION,
|
.opensbi_version = OPENSBI_VERSION,
|
||||||
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
||||||
.name = "OPENPITON RISC-V",
|
.name = "OPENPITON RISC-V",
|
||||||
.features = SBI_OPENPITON_FEATURES,
|
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
||||||
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
|
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
|
||||||
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
|
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
|
||||||
.platform_ops_addr = (unsigned long)&platform_ops
|
.platform_ops_addr = (unsigned long)&platform_ops
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
#
|
#
|
||||||
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
#
|
#
|
||||||
# Authors:
|
# Authors:
|
||||||
# Anup Patel <anup.patel@wdc.com>
|
# Anup Patel <anup.patel@wdc.com>
|
||||||
@@ -15,7 +15,7 @@ platform-ldflags-y =
|
|||||||
|
|
||||||
# Command for platform specific "make run"
|
# Command for platform specific "make run"
|
||||||
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \
|
platform-runcmd = qemu-system-riscv$(PLATFORM_RISCV_XLEN) -M virt -m 256M \
|
||||||
-nographic -kernel $(build_dir)/platform/qemu/virt/firmware/fw_payload.elf
|
-nographic -kernel $(build_dir)/platform/generic/firmware/fw_payload.elf
|
||||||
|
|
||||||
# Blobs to build
|
# Blobs to build
|
||||||
FW_TEXT_START=0x80000000
|
FW_TEXT_START=0x80000000
|
||||||
@@ -23,12 +23,12 @@ FW_DYNAMIC=y
|
|||||||
FW_JUMP=y
|
FW_JUMP=y
|
||||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||||
# This needs to be 4MB aligned for 32-bit system
|
# This needs to be 4MB aligned for 32-bit system
|
||||||
FW_JUMP_ADDR=0x80400000
|
FW_JUMP_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x400000)))
|
||||||
else
|
else
|
||||||
# This needs to be 2MB aligned for 64-bit system
|
# This needs to be 2MB aligned for 64-bit system
|
||||||
FW_JUMP_ADDR=0x80200000
|
FW_JUMP_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x200000)))
|
||||||
endif
|
endif
|
||||||
FW_JUMP_FDT_ADDR=0x82200000
|
FW_JUMP_FDT_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x2200000)))
|
||||||
FW_PAYLOAD=y
|
FW_PAYLOAD=y
|
||||||
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
ifeq ($(PLATFORM_RISCV_XLEN), 32)
|
||||||
# This needs to be 4MB aligned for 32-bit system
|
# This needs to be 4MB aligned for 32-bit system
|
||||||
@@ -37,4 +37,4 @@ else
|
|||||||
# This needs to be 2MB aligned for 64-bit system
|
# This needs to be 2MB aligned for 64-bit system
|
||||||
FW_PAYLOAD_OFFSET=0x200000
|
FW_PAYLOAD_OFFSET=0x200000
|
||||||
endif
|
endif
|
||||||
FW_PAYLOAD_FDT_ADDR=0x82200000
|
FW_PAYLOAD_FDT_ADDR=$(FW_JUMP_FDT_ADDR)
|
27
platform/generic/include/platform_override.h
Normal file
27
platform/generic/include/platform_override.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLATFORM_OVERRIDE_H__
|
||||||
|
#define __PLATFORM_OVERRIDE_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
struct platform_override {
|
||||||
|
const struct fdt_match *match_table;
|
||||||
|
u64 (*features)(const struct fdt_match *match);
|
||||||
|
u64 (*tlbr_flush_limit)(const struct fdt_match *match);
|
||||||
|
int (*early_init)(bool cold_boot, const struct fdt_match *match);
|
||||||
|
int (*final_init)(bool cold_boot, const struct fdt_match *match);
|
||||||
|
void (*early_exit)(const struct fdt_match *match);
|
||||||
|
void (*final_exit)(const struct fdt_match *match);
|
||||||
|
int (*system_reset)(u32 reset_type, const struct fdt_match *match);
|
||||||
|
int (*fdt_fixup)(void *fdt, const struct fdt_match *match);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -3,5 +3,9 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
# Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
#
|
#
|
||||||
|
# Authors:
|
||||||
|
# Anup Patel <anup.patel@wdc.com>
|
||||||
|
#
|
||||||
|
|
||||||
platform-objs-y += platform.o
|
platform-objs-y += platform.o
|
||||||
|
platform-objs-y += sifive_fu540.o
|
224
platform/generic/platform.c
Normal file
224
platform/generic/platform.c
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libfdt.h>
|
||||||
|
#include <platform_override.h>
|
||||||
|
#include <sbi/riscv_asm.h>
|
||||||
|
#include <sbi/sbi_hartmask.h>
|
||||||
|
#include <sbi/sbi_platform.h>
|
||||||
|
#include <sbi/sbi_string.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/irqchip/fdt_irqchip.h>
|
||||||
|
#include <sbi_utils/serial/fdt_serial.h>
|
||||||
|
#include <sbi_utils/timer/fdt_timer.h>
|
||||||
|
#include <sbi_utils/ipi/fdt_ipi.h>
|
||||||
|
#include <sbi_utils/reset/fdt_reset.h>
|
||||||
|
|
||||||
|
extern const struct platform_override sifive_fu540;
|
||||||
|
|
||||||
|
static const struct platform_override *special_platforms[] = {
|
||||||
|
&sifive_fu540,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct platform_override *generic_plat = NULL;
|
||||||
|
static const struct fdt_match *generic_plat_match = NULL;
|
||||||
|
|
||||||
|
static void fw_platform_lookup_special(void *fdt, int root_offset)
|
||||||
|
{
|
||||||
|
int pos, noff;
|
||||||
|
const struct platform_override *plat;
|
||||||
|
const struct fdt_match *match;
|
||||||
|
|
||||||
|
for (pos = 0; pos < array_size(special_platforms); pos++) {
|
||||||
|
plat = special_platforms[pos];
|
||||||
|
if (!plat->match_table)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
noff = fdt_find_match(fdt, -1, plat->match_table, &match);
|
||||||
|
if (noff < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
generic_plat = plat;
|
||||||
|
generic_plat_match = match;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern struct sbi_platform platform;
|
||||||
|
static u32 generic_hart_index2id[SBI_HARTMASK_MAX_BITS] = { 0 };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The fw_platform_init() function is called very early on the boot HART
|
||||||
|
* OpenSBI reference firmwares so that platform specific code get chance
|
||||||
|
* to update "platform" instance before it is used.
|
||||||
|
*
|
||||||
|
* The arguments passed to fw_platform_init() function are boot time state
|
||||||
|
* of A0 to A4 register. The "arg0" will be boot HART id and "arg1" will
|
||||||
|
* be address of FDT passed by previous booting stage.
|
||||||
|
*
|
||||||
|
* The return value of fw_platform_init() function is the FDT location. If
|
||||||
|
* FDT is unchanged (or FDT is modified in-place) then fw_platform_init()
|
||||||
|
* can always return the original FDT location (i.e. 'arg1') unmodified.
|
||||||
|
*/
|
||||||
|
unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
|
||||||
|
unsigned long arg2, unsigned long arg3,
|
||||||
|
unsigned long arg4)
|
||||||
|
{
|
||||||
|
const char *model, *mmu_type;
|
||||||
|
void *fdt = (void *)arg1;
|
||||||
|
u32 hartid, hart_count = 0;
|
||||||
|
int rc, root_offset, cpus_offset, cpu_offset, len;
|
||||||
|
|
||||||
|
root_offset = fdt_path_offset(fdt, "/");
|
||||||
|
if (root_offset < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
fw_platform_lookup_special(fdt, root_offset);
|
||||||
|
|
||||||
|
model = fdt_getprop(fdt, root_offset, "model", &len);
|
||||||
|
if (model)
|
||||||
|
sbi_strncpy(platform.name, model, sizeof(platform.name));
|
||||||
|
|
||||||
|
if (generic_plat && generic_plat->features)
|
||||||
|
platform.features = generic_plat->features(generic_plat_match);
|
||||||
|
|
||||||
|
cpus_offset = fdt_path_offset(fdt, "/cpus");
|
||||||
|
if (cpus_offset < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
|
||||||
|
rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
|
||||||
|
if (rc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SBI_HARTMASK_MAX_BITS <= hartid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mmu_type = fdt_getprop(fdt, cpu_offset, "mmu-type", &len);
|
||||||
|
if (!mmu_type || !len)
|
||||||
|
hartid = -1U;
|
||||||
|
|
||||||
|
generic_hart_index2id[hart_count++] = hartid;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform.hart_count = hart_count;
|
||||||
|
|
||||||
|
/* Return original FDT pointer */
|
||||||
|
return arg1;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
while (1)
|
||||||
|
wfi();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int generic_early_init(bool cold_boot)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (generic_plat && generic_plat->early_init) {
|
||||||
|
rc = generic_plat->early_init(cold_boot, generic_plat_match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cold_boot)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return fdt_reset_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int generic_final_init(bool cold_boot)
|
||||||
|
{
|
||||||
|
void *fdt;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (generic_plat && generic_plat->final_init) {
|
||||||
|
rc = generic_plat->final_init(cold_boot, generic_plat_match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cold_boot)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fdt = sbi_scratch_thishart_arg1_ptr();
|
||||||
|
|
||||||
|
fdt_cpu_fixup(fdt);
|
||||||
|
fdt_fixups(fdt);
|
||||||
|
|
||||||
|
if (generic_plat && generic_plat->fdt_fixup) {
|
||||||
|
rc = generic_plat->fdt_fixup(fdt, generic_plat_match);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generic_early_exit(void)
|
||||||
|
{
|
||||||
|
if (generic_plat && generic_plat->early_exit)
|
||||||
|
generic_plat->early_exit(generic_plat_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generic_final_exit(void)
|
||||||
|
{
|
||||||
|
if (generic_plat && generic_plat->final_exit)
|
||||||
|
generic_plat->final_exit(generic_plat_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 generic_tlbr_flush_limit(void)
|
||||||
|
{
|
||||||
|
if (generic_plat && generic_plat->tlbr_flush_limit)
|
||||||
|
return generic_plat->tlbr_flush_limit(generic_plat_match);
|
||||||
|
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int generic_system_reset(u32 reset_type)
|
||||||
|
{
|
||||||
|
if (generic_plat && generic_plat->system_reset)
|
||||||
|
return generic_plat->system_reset(reset_type,
|
||||||
|
generic_plat_match);
|
||||||
|
return fdt_system_reset(reset_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct sbi_platform_operations platform_ops = {
|
||||||
|
.early_init = generic_early_init,
|
||||||
|
.final_init = generic_final_init,
|
||||||
|
.early_exit = generic_early_exit,
|
||||||
|
.final_exit = generic_final_exit,
|
||||||
|
.console_putc = fdt_serial_putc,
|
||||||
|
.console_getc = fdt_serial_getc,
|
||||||
|
.console_init = fdt_serial_init,
|
||||||
|
.irqchip_init = fdt_irqchip_init,
|
||||||
|
.irqchip_exit = fdt_irqchip_exit,
|
||||||
|
.ipi_send = fdt_ipi_send,
|
||||||
|
.ipi_clear = fdt_ipi_clear,
|
||||||
|
.ipi_init = fdt_ipi_init,
|
||||||
|
.ipi_exit = fdt_ipi_exit,
|
||||||
|
.get_tlbr_flush_limit = generic_tlbr_flush_limit,
|
||||||
|
.timer_value = fdt_timer_value,
|
||||||
|
.timer_event_stop = fdt_timer_event_stop,
|
||||||
|
.timer_event_start = fdt_timer_event_start,
|
||||||
|
.timer_init = fdt_timer_init,
|
||||||
|
.timer_exit = fdt_timer_exit,
|
||||||
|
.system_reset = generic_system_reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sbi_platform platform = {
|
||||||
|
.opensbi_version = OPENSBI_VERSION,
|
||||||
|
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
|
||||||
|
.name = "Generic",
|
||||||
|
.features = SBI_PLATFORM_DEFAULT_FEATURES,
|
||||||
|
.hart_count = SBI_HARTMASK_MAX_BITS,
|
||||||
|
.hart_index2id = generic_hart_index2id,
|
||||||
|
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
|
||||||
|
.platform_ops_addr = (unsigned long)&platform_ops
|
||||||
|
};
|
47
platform/generic/sifive_fu540.c
Normal file
47
platform/generic/sifive_fu540.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Anup Patel <anup.patel@wdc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <platform_override.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/fdt/fdt_fixup.h>
|
||||||
|
|
||||||
|
static u64 sifive_fu540_tlbr_flush_limit(const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The sfence.vma by virtual address does not work on
|
||||||
|
* SiFive FU540 so we return remote TLB flush limit as zero.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sifive_fu540_fdt_fixup(void *fdt, const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* SiFive Freedom U540 has an erratum that prevents S-mode software
|
||||||
|
* to access a PMP protected region using 1GB page table mapping, so
|
||||||
|
* always add the no-map attribute on this platform.
|
||||||
|
*/
|
||||||
|
fdt_reserved_memory_nomap_fixup(fdt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match sifive_fu540_match[] = {
|
||||||
|
{ .compatible = "sifive,fu540" },
|
||||||
|
{ .compatible = "sifive,fu540g" },
|
||||||
|
{ .compatible = "sifive,fu540-c000" },
|
||||||
|
{ .compatible = "sifive,hifive-unleashed-a00" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct platform_override sifive_fu540 = {
|
||||||
|
.match_table = sifive_fu540_match,
|
||||||
|
.tlbr_flush_limit = sifive_fu540_tlbr_flush_limit,
|
||||||
|
.fdt_fixup = sifive_fu540_fdt_fixup,
|
||||||
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user