62 Commits

Author SHA1 Message Date
f879119605 Обновить platform/generic/cvitek_riscv.c 2026-02-11 02:19:45 +07:00
aedef73d12 Обновить platform/generic/cvitek_riscv.c 2026-02-11 01:41:03 +07:00
92ee61dae4 Обновить platform/generic/cvitek_riscv.c 2026-02-11 01:34:56 +07:00
sophgo-forum-service
6766e9cc96 opensbi: weekly rls 2025.01.24
daa470, [fix](opensbi): add rls_info.txt
b21a54, [test](opensbi): opensbi tailoring (time optimizing)
6ff231, [fix](str): fix riscv suspend section which do not use varivales and functions beyond syspend section.
2025-01-24 14:50:56 +08:00
sophgo-forum-service
3b045ae374 opensbi: weekly rls 2025.01.10
daa470, [fix](opensbi): add rls_info.txt
b21a54, [test](opensbi): opensbi tailoring (time optimizing)
6ff231, [fix](str): fix riscv suspend section which do not use varivales and functions beyond syspend section.

Change-Id: I8c6e7698b475b2d14c02308121f621dafe9b9e36
2025-01-13 16:32:03 +08:00
sophgo-forum-service
fffb4754ee opensbi: weekly rls 2024.10.14
-0f5edb, [fix](str):fix chip id miss and fix suspend bug on rtc
-a068cd, [fix](str): refine rtc suspend/resume process

Change-Id: Ice28701d616192d7d6a6f13621d739dd07424571
2024-10-14 19:27:45 +08:00
sophgo-forum-service
ab9b8f8d10 opensbi: weekly rls 2024.07.20
-0aa741, support cv181x/cv180x suspend to ram.

Change-Id: I64dcb0ff942aa7238a88ef3bd1da2c67f5d089b4
2024-07-20 21:40:47 +08:00
sophgo-forum-service
3fd99912a6 opensbi: weekly rls 2024.06.6
-2da720, Add rst/unrst/reset c906l ecall.

Change-Id: Id1b2de0c5cb4607d46fd4397a78e77109790cc49
2024-06-06 15:17:01 +08:00
sophgo-forum-service
216793f112 (opensbi): Init branch sg200x-dev
Change-Id: If4dd4f7d55a714cff21c4ead4376a4137ee03330
2024-02-14 16:36:52 +08:00
sophgo-forum-service
ba54b0038e note: sync patch from T-Head.
https://github.com/T-head-Semi/opensbi commit: 89182b257c8798e15e4c685c1af0c2862d528d2a
2024-02-14 16:31:42 +08:00
Guo Ren
ba85a8ec52 platform/generic/platform.c: Support qemu poweroff
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
2024-01-10 17:35:55 +08:00
Guo Ren
885df4577a utils: irqchip: Fixup priority init overwrite zero
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
2024-01-10 17:35:47 +08:00
Guo Ren
f67338cc74 thead PMU supported
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
2024-01-10 17:35:39 +08:00
Bin Meng
632e27bb91 docs/platform: sifive_fu540: Update U-Boot defconfig name
With latest U-Boot upstream (v2021.07 in development), the defconfig
name has been changed to sifive_unleashed_defconfig. Update the doc.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-29 15:11:24 +05:30
Anup Patel
e9a27ab8ea lib: sbi: Show devices provided by platform in boot prints
We extend the boot-time prints to show various devices provided
(or registered) by the platform support. This will help users
verify hardware devices available for OpenSBI firmwares.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:33:37 +05:30
Anup Patel
a84a1ddbba lib: sbi: Simplify HSM platform operations
Instead of having hsm_start(), hsm_stop() and hsm_suspend()
callbacks in platform operations, it will be much simpler for
HSM driver to directly register these operations as a device
to the sbi_hsm implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:31:07 +05:30
Anup Patel
043d088e39 lib: sbi: Simplify system reset platform operations
Instead of having system_reset_check() and system_reset() callbacks
in platform operations, it will be much simpler for reset driver to
directly register these operations as a device to the sbi_system
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:25:00 +05:30
Anup Patel
dc39c7b630 lib: sbi: Simplify ipi platform operations
Instead of having ipi_send() and ipi_clear() callbacks in
platform operations, it will be much simpler for ipi driver
to directly register these operations as a device to sbi_ipi
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:03:31 +05:30
Anup Patel
559a8f1d3b lib: sbi: Simplify timer platform operations
Instead of having timer_value(), timer_event_start(), and
timer_event_stop() callbacks in platform operations, it will
be much simpler for timer driver to directly register these
operations as device to the sbi_timer implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-28 17:00:49 +05:30
Anup Patel
068ca086af lib: sbi: Simplify console platform operations
Instead of having console_putc() and console_getc() callbacks in
platform operations, it will be much simpler for console driver to
directly register these operations as device to the sbi_console
implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-28 16:58:23 +05:30
Anup Patel
a3689db92a lib: sbi: Remove domains_root_regions() platform callback
We now have sbi_domain_root_add_memregion() which allows platform
support to add root domain regions at boot-time so let's remove
the domains_root_regions() platform callback which was added
for this purpose.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-28 16:56:58 +05:30
Guo Ren
6d1642f856 docs: generic: Add T-HEAD C9xx series processors
Add description and dts examples for T-HEAD C9xx platforms.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-28 16:12:02 +05:30
Guo Ren
1db843622a platform: Remove platform/thead
We could use platform/generic instead, and won't use
platform/thead/c910 again.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-28 15:43:04 +05:30
Guo Ren
bf3ef53bb7 firmware: Enable FW_PIC by default
Let's have FW_PIC enabled by default so that OpenSBI firmware
can by default run from any physical address.

Tested with qemu_rv32 & rv64, T-HEAD all hardwares.

Suggested-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Tested-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-28 15:38:22 +05:30
Anup Patel
0d56293817 lib: sbi: Fix sbi_domain_root_add_memregion() for merging memregions
We should decrement root_memregs_count by one after merging two
memregions otherwise new memregion added after a merge will be
appended after last sentinel memregion of zero order.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-24 13:05:09 +05:30
Guo Ren
49e422c5ad lib: utils: reset: Add T-HEAD sample platform reset driver
This driver is for T-HEAD test chip, fpga. It could work with
all T-HEAD riscv processors: C9xx series.

example1: (Using io-regs for reset)
reset: reset-sample {
	compatible = "thead,reset-sample";
	plic-delegate = <0xff 0xd81ffffc>;
	entry-reg = <0xff 0xff019050>;
	entry-cnt = <4>;
	control-reg = <0xff 0xff015004>;
	control-val = <0x1c>;
	csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
};

example2: (Using csr-regs for reset)
reset: reset-sample {
	compatible = "thead,reset-sample";
	plic-delegate = <0xff 0xd81ffffc>;
	using-csr-reset;
	csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
		    0x3b0 0x3b1 0x3b2 0x3b3
		    0x3b4 0x3b5 0x3b6 0x3b7
		    0x3a0>;
};

example3: (Only delegate plic enable to S-mode)
reset: reset-sample {
	compatible = "thead,reset-sample";
	plic-delegate = <0xff 0xd81ffffc>;
};

After this patch, all T-HEAD c9xx would use platform/generic with fw_dynamic
as default:

CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic FW_PIC=y /usr/bin/make

The platform/thead will be deprecated.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-22 15:13:53 +05:30
Guo Ren
c5d0645052 lib: utils: Implement "64bit-mmio" property parsing
Figure out CLINT has_64bit_mmio from DT node and using antonym for
compatibility.

Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-22 15:00:58 +05:30
Anup Patel
f41196a9d2 lib: sbi: Make sbi_domain_memregion_initfw() a local function
The sbi_domain_memregion_initfw() is no longer used outside
sbi_domain.c so let's make it a local function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:51 +05:30
Anup Patel
e7e4bcd5b9 lib: utils: Copy over restricted root domain memregions to FDT domains
We should copy over all restricted memregions from the root domain
to the domains populated from FDT. These restricted root memregions
are typically firmware memregion and M-mode only mmio memregions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:48 +05:30
Anup Patel
fc37c9712d lib: sbi: Make the root domain instance global variable
We make the the root domain instance global variable so that
platform support and drivers can iterate over the root domain
regions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:45 +05:30
Anup Patel
8b56980347 lib: utils/sys: Add CLINT memregion in the root domain
The CLINT memory should not be accessed by the supervisor-mode
software so let's protect it by adding CLINT memregion to the
root domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:42 +05:30
Anup Patel
4dc0001b09 lib: sbi: Add sbi_domain_root_add_memregion() API
We should allow platform support to add more root memory regions
before domains are finalized. This will help platform support to
protect critical M-mode only resources.

This patch adds sbi_domain_root_add_memregion() API for above
described purpose.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:37 +05:30
Anup Patel
7495bce6f9 lib: sbi: Add sbi_domain_memregion_init() API
This patch adds sbi_domain_memregion_init() helper API which can
be used by platform support to initialize a domain memory region
before adding it to the root domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:35 +05:30
Anup Patel
b1df1acd20 lib: sbi: Domains can be registered only before finalizing domains
The domains are boot-time system-level partitions so we should
allow platform support to register domains only before hart
domain assignments are finalized.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2021-04-13 10:56:32 +05:30
hasheddan
27a16b1545 docs: fix link to OpenPiton documentation
Updates link in platforms documentation to point to the correct
OpenPiton document.

Signed-off-by: hasheddan <georgedanielmangum@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-12 13:36:08 +05:30
Xiang W
70ffc3e2e6 lib: sbi: fix atomic_add_return
The unsigned length may be 4 bytes or 8 bytes, amoadd.w only applies
to 4 bytes hence this patch.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-09 18:51:02 +05:30
Christoph Muellner
4d8e2f135d lib: sbi: Replace test-and-set locks by ticket locks
Replace the test-and-set spinlock implementation with ticket locks
in order to get fairness (in form of FIFO order).

The implementation uses a 32-bit wide struct, which consists of
two 16-bit counters (owner and next). This is inspired by similar
spinlock implementations on other architectures.
This allows that the code works for both, RV32 and RV64.

Signed-off-by: Christoph Muellner <cmuellner@linux.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-09 18:48:50 +05:30
Christoph Muellner
d0e406fa44 include: sbi: Allow direct initialization via SPIN_LOCK_INIT()
The current implementation of SPIN_LOCK_INIT() provides the spinlock
to be initialized as reference. This does not allow a direct
initialization of the spinlock object at the creation site.

Let's pass the spinlock directly instead (like Linux does as well)
and adjust all users of the macro (in fact there is only one user).

Signed-off-by: Christoph Muellner <cmuellner@linux.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-09 18:39:50 +05:30
Christoph Muellner
d4a94ea471 include: types: Add __aligned(x) to define the minimum alignement
The __aligned(x) macro is a common wrapper around compiler's
aligned attribute, which allow to define the minimum alignement
of a data type. Let's add this macro.

Signed-off-by: Christoph Muellner <cmuellner@linux.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-09 18:37:06 +05:30
Anup Patel
e71a7c10a9 firmware: Remove redundant add instruction from trap restore path
The "add sp, a0, zero" instruction in the trap restore path is redundant
and can be avoided if TRAP_RESTORE_xyz() assembly macros use a0 as the
base register instead of sp.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2021-04-05 15:39:28 +05:30
Xiang W
3d8a952737 lib: fix csr detect support
csr_read_allowed/csr_read_allowed requires trap.case to detect the results,
but if no exception occurs, the value of trap.case will remain unchanged,
which makes the detection results unreliable. Add code to initialize
trap.case to 0.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-05 13:43:08 +05:30
Xiang W
4ef2f5d3e6 firware: optimize the exception exit code
There are two copies of the same abnormal exit code, this patch deletes one

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-01 10:48:35 +05:30
Bin Meng
4edc822407 lib/utils: Support fixing up the official DT bindings of PLIC
Current fdt_plic_fixup() only does necessary fix-up against the legacy
"riscv,plic0" node. The upstream Linux kernel defines its official DT
bindings which uses "sifive,plic-1.0.0" as the compatible string and
we should check that first, and if not present fall back to legacy.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-01 10:31:11 +05:30
Bin Meng
ca3f35821b lib/utils: Drop the 'compat' parameter of fdt_plic_fixup()
At present fdt_plic_fixup() accepts a 'compat' parameter for PLIC
compatible string. In preparation to support the new DT bindings,
drop this and use "riscv,plic0" directly in fdt_plic_fixup().

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-01 10:27:28 +05:30
Bin Meng
9190ad12f7 lib/utils: Support the official clint DT bindings
Linux kernel commit a2770b57d083 ("dt-bindings: timer: Add CLINT bindings")
adds the official DT bindings for CLINT, which uses "sifive,clint0"
as the compatible string. "riscv,clint0" is now legacy and has to
be kept for backward compatibility of legacy systems.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-04-01 10:26:41 +05:30
Marouene Boubakri
bfc85c70e7 include: headers: Replace __ASSEMBLY__ with __ASSEMBLER__
GCC has already a predefined macro __ASSEMBLER__ therefore, it can be
used without the need to define a new flag with -D__ASSEMBLY__.
This is useful when adding the library to projects having a build
system such one can build without the need to make changes.
THe build system does not use the Makefile in the sources tree.

Signed-off-by: Marouene Boubakri <marouene.boubakri@nxp.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
2021-03-22 16:02:48 +05:30
Heinrich Schuchardt
ddad02d625 lib: sbi: illegal CSR 0x306 access in hpm_allowed()
The trap handler sbi_emulate_csr_read() invokes hpm_allowed() which reads
CSR 0x306 (mcounteren). The K210 does not support CSR 0x306. While trying
to handle a trap occurring in S-mode code this creates an additional trap
in M-mode. This results in failure to redirect to S-mode and the system
hanging in sbi_hart_hang().

In hart_detect_features() we have already determined if CSR 0x306 is
available and stored that information in the scratch area. We can use this
information to decide if CSR 0x306 shall be accessed in hpm_allowed() and
thus avoid the M-mode trap.

Likewise if CSR scounteren is not available we have to avoid reading CSR
0x106.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-03-22 09:18:56 +05:30
Vincent Chen
0f20e8adcf firmware: Support position independent execution
Enable OpenSBI to support position independent execution. Because the
position independent code will cause an additional GOT reference when
accessing the global variables, it will reduce performance a bit. Therefore,
the position independent execution is disabled by default. Users can
through specifying "FW_PIC=y" on the make command to enable this feature.

In theory, after enabling position-independent execution, the OpenSBI
can run at arbitrary address with appropriate alignment. Therefore, the
original relocation mechanism will be skipped. In other words, OpenSBI will
directly run at the load address without any code movement.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-03-19 15:00:50 +05:30
Vincent Chen
22d8ee9758 firmware: Use lla to access all global symbols
When OpenSBI is compiled as fPIE mode, the assembler will translate "la"
to GOT reference pattern. It will cause to cost an additional load
instruction when obtaining the symbol address. However, if the symbol
locates within the positive or negative 2GB region, we can use "lla"
instead of "la" to avoid unneeded GOT references. This patch assumes that
the OpenSBI image excluding the payload does not exceed 2GB. Based on
this assumption, all "la" instructions are replaced by "lla" to avoid
performance degradation when compiling as fPIE mode.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-03-19 14:57:45 +05:30
Heinrich Schuchardt
ff5bd949d5 include: sbi: SBI function IDs for RFENCE extension
The SBI function IDs for RFENCE extension must match the SBI specification.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-12 09:32:53 +05:30
Anup Patel
50d4fde1c5 lib: Remove redundant sbi_platform_ipi_clear() calls
The sbi_platform_ipi_clear() called from wait_for_coldboot() and
sbi_hsm_hart_wait() is redundant because IPI will be automatically
cleared by sbi_platform_ipi_init() called from sbi_ipi_init().

Further, wait_for_coldboot() is common for warm startup and warm
resume path so the sbi_platform_ipi_clear() called in warm resume
path cause resuming HART to miss an IPI injected other HART to
wakeup the HART.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 13:54:50 +05:30
Anup Patel
b9cf617a9f include: sbi: Upgrade SBI implementation version to v0.3
The OpenSBI SBI implementation is now compliant with latest draft
SBI v0.3 specification so let's upgrade SBI implementation version.

This will also help HSM suspend function detection in S-mode because
HSM suspend function is only present when HSM extension is present
and SBI implementation version is 0.3 (or higher).

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 13:54:44 +05:30
Anup Patel
74756891cc lib: sbi: Implement SBI HSM suspend function
This patch implements the SBI HSM suspend function. Using this
new SBI call, the S-mode software can put calling HART in platform
specific suspend (i.e. low-power) state. For a successful retentive
suspend, the SBI call will return without errors upon resuming
whereas for a successful non-retentive suspend, the SBI call will
resume from a user provided resume address.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 13:51:15 +05:30
Anup Patel
807d71c4ff include: sbi: Add hart_suspend() platform callback
We add hart_suspend() callback in platform operations which will
be used by HSM implementation to enter retentive or non-retentive
suspend state.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:19:24 +05:30
Anup Patel
4b05df6700 lib: sbi: Add sbi_hart_reinit() function
We add sbi_hart_reinit() function which will re-initialize HART CSRs
assuming HART features are already detected. This new function will
be useful in re-initializing HART after it resumes from HSM SUSPENDED
state.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:19:18 +05:30
Anup Patel
6290a22e34 include: sbi: Add HSM suspend related defines
This patch adds SBI HSM suspend related defines to ecall interface
header.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:19:13 +05:30
Anup Patel
ca864a978d lib: sbi: Fix error codes returned by HSM start() and stop() functions
The sbi_hsm_hart_start() and sbi_hsm_hart_stop() functions should
only return error codes as defined by the SBI specification.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:19:01 +05:30
Anup Patel
638c948ab9 lib: sbi: Remove redundant sbi_hsm_hart_started() function
The sbi_hsm_hart_started() function is only used by sbi_hsm_hart_stop()
for checking state of calling HART and current domain assignment.

The atomic_cmpxchg() called by sbi_hsm_hart_stop() will check state of
calling hart anyway and domain assignment can be checked by other domain
function such as sbi_domain_is_assigned_hart().

This means sbi_hsm_hart_started() is redundant and can be removed.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:18:23 +05:30
Anup Patel
7c867fd19f lib: sbi: Rename sbi_hsm_hart_started_mask() function
A hart can take interrupt in the new HSM states introduced by the
SBI HSM suspend function (such as SUSPENDED state) so we rename
sbi_hsm_hart_started_mask() to something more generic such as
sbi_hsm_hart_interruptible_mask().

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:17:45 +05:30
Anup Patel
8df1f9a0d3 lib: sbi: Use SBI_HSM_STATE_xyz defines instead of SBI_STATE_xyz defines
We replace the use of SBI_STATE_xyz defines with SBI_HSM_STATE_xyz
defines because the HSM state defines are complete enough to implement
HSM state machine in OpenSBI. As a result of this, we can now remove
sbi_hsm_hart_state_to_status() function because it is now redundant
and sbi_hsm_hart_get_state() can directly return HSM state or error.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:17:41 +05:30
Anup Patel
5487cf095d include: sbi: Simplify HSM state define names
We simplify HSM state define names so that these defines can directly
replace SBI_HART_xyz defines used by SBI HSM implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2021-03-03 10:17:35 +05:30
Heinrich Schuchardt
ec5274b04c platform: implement K210 system reset
Implement rebooting the K210 via the system reset extension.

All reset types are treated in the same way.
A request for shutdown results in a reboot.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2021-03-03 08:39:10 +05:30
115 changed files with 2383 additions and 1283 deletions

View File

@@ -1,16 +0,0 @@
AlignConsecutiveAssignments: true
AlignEscapedNewlines: Left
AlignTrailingComments: true
AllowShortFunctionsOnASingleLine: None
BraceWrapping:
AfterFunction: true
BreakBeforeBraces: Custom
BreakStringLiterals: false
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
IndentWidth: 8
ReflowComments: false
SortIncludes: false
SpacesInContainerLiterals: false
TabWidth: 8
UseTab: Always

View File

@@ -143,6 +143,20 @@ deps-y+=$(libsbi-objs-path-y:.o=.dep)
deps-y+=$(libsbiutils-objs-path-y:.o=.dep)
deps-y+=$(firmware-objs-path-y:.o=.dep)
ifeq (,$(wildcard ${PM_SRAM_BIN_PATH}))
ifeq (${CHIP_ARCH},CV180X)
PM_SRAM_BIN_PATH=${OPENSBI_PATH}/pm_default_cv180x.bin
endif
ifeq (${CHIP_ARCH},CV181X)
PM_SRAM_BIN_PATH=${OPENSBI_PATH}/pm_default_cv181x.bin
endif
else
ifeq ($(filter clean %clean clean%,$(MAKECMDGOALS)),)
$(shell touch -c platform\generic\cvitek_riscv.c > /dev/null)
endif
endif
$(info PM_SRAM_BIN_PATH is '${PM_SRAM_BIN_PATH}')
# Setup platform ABI, ISA and Code Model
ifndef PLATFORM_RISCV_ABI
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
@@ -203,6 +217,14 @@ GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)
define add_define
GENFLAGS += -D$(1)$(if $(value $(1)),=$(value $(1)),)
endef
ifeq (${CONFIG_OPENSBI_FASTBOOT},y)
$(eval $(call add_define,CONFIG_OPENSBI_FASTBOOT))
endif
CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib -fno-strict-aliasing -O2
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
CFLAGS += -mno-save-restore -mstrict-align
@@ -210,14 +232,21 @@ CFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
CFLAGS += -mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y)
CFLAGS += $(firmware-cflags-y)
CFLAGS += -fno-pie -no-pie
CFLAGS += $(firmware-cflags-y)
CFLAGS += -DPM_SRAM_BIN_PATH=$(PM_SRAM_BIN_PATH)
ifeq ($(CHIP_ARCH),CV180X)
CFLAGS += -DCONFIG_CV180X
endif
ifeq (${CHIP_ARCH},CV181X)
CFLAGS += -DCONFIG_CV181X
endif
CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y)
CPPFLAGS += $(firmware-cppflags-y)
ASFLAGS = -g -Wall -nostdlib -D__ASSEMBLY__
ASFLAGS = -g -Wall -nostdlib
ASFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
ASFLAGS += -mno-save-restore -mstrict-align
ASFLAGS += -mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)

View File

@@ -52,6 +52,7 @@ has following details:
* **next_mode** - Privilege mode of the next booting stage for this
domain. This can be either S-mode or U-mode.
* **system_reset_allowed** - Is domain allowed to reset the system?
* **system_suspend_allowed** - Is domain allowed to suspend the system?
The memory regions represented by **regions** in **struct sbi_domain** have
following additional constraints to align with RISC-V PMP requirements:
@@ -91,6 +92,7 @@ following manner:
* **next_mode** - Next booting stage mode in coldboot HART scratch space
is the next mode for the ROOT domain
* **system_reset_allowed** - The ROOT domain is allowed to reset the system
* **system_suspend_allowed** - The ROOT domain is allowed to suspend the system
Domain Effects
--------------
@@ -187,6 +189,8 @@ The DT properties of a domain instance DT node are as follows:
stage mode of coldboot HART** is used as default value.
* **system-reset-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system reset.
* **system-suspend-allowed** (Optional) - A boolean flag representing
whether the domain instance is allowed to do system suspend.
### Assigning HART To Domain Instance
@@ -252,6 +256,7 @@ be done:
next-addr = <0x0 0x80100000>;
next-mode = <0x0>;
system-reset-allowed;
system-suspend-allowed;
};
udomain: untrusted-domain {

View File

@@ -48,7 +48,9 @@ RISC-V Platforms Using Generic Platform
* **QEMU RISC-V Virt Machine** (*[qemu_virt.md]*)
* **Spike** (*[spike.md]*)
* **Shakti C-class SoC Platform** (*[shakti_cclass.md]*)
* **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*)
[qemu_virt.md]: qemu_virt.md
[spike.md]: spike.md
[shakti_cclass.md]: shakti_cclass.md
[thead-c9xx.md]: thead-c9xx.md

View File

@@ -28,15 +28,12 @@ OpenSBI currently supports the following virtual and hardware platforms:
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350). More
details on this platform can be found in the file *[andes-ae350.md]*.
* **T-HEAD C910**: Platform support for the T-HEAD C910 Processor. More
details on this platform can be found in the file *[thead-c910.md]*.
* **Spike**: Platform support for the Spike emulator. More
details on this platform can be found in the file *[spike.md]*.
* **OpenPiton FPGA SoC**: Platform support OpenPiton research platform based
on ariane core. More details on this platform can be found in the file
*[fpga_openpiton.md]*.
*[fpga-openpiton.md]*.
* **Shakti C-class SoC Platform**: Platform support for Shakti C-class
processor based SOCs. More details on this platform can be found in the
@@ -55,5 +52,5 @@ facilitate the implementation.
[andes-ae350.md]: andes-ae350.md
[thead-c910.md]: thead-c910.md
[spike.md]: spike.md
[fpga_openpiton.md]: fpga_openpiton.md
[fpga-openpiton.md]: fpga-openpiton.md
[shakti_cclass.md]: shakti_cclass.md

View File

@@ -42,7 +42,7 @@ make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/bo
The command-line example here assumes that U-Boot was compiled using the
sifive_fu540_defconfig configuration and with U-Boot v2020.01, and up to
v2020.07-rc3.
v2021.04. sifive_unleashed_defconfig shall be used with v2021.07 or above.
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot-dtb.bin
@@ -153,11 +153,12 @@ This is because QEMU generates a device tree blob on the fly based on the
command line parameters and it's compatible with the one used in the upstream
Linux kernel.
When U-Boot v2020.01 (or higher) is used as the payload, as the SiFive FU540
When U-Boot v2021.07 (or higher) is used as the payload, as the SiFive FU540
DTB for the real hardware is embedded in U-Boot binary itself, due to the same
reason above, we need to switch the U-Boot sifive_fu540_defconfig configuration
from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that U-Boot uses the
DTB generated by QEMU, and u-boot.bin should be used as the payload image, like:
reason above, we need to switch the U-Boot sifive_unleashed_defconfig
configuration from **CONFIG_OF_SEPARATE** to **CONFIG_OF_PRIOR_STAGE** so that
U-Boot uses the DTB generated by QEMU, and u-boot.bin should be used as the
payload image, like:
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin

View File

@@ -1,34 +0,0 @@
T-HEAD C910 Processor
=====================
C910 is a 12-stage, 3 issues, 8 executions, out-of-order 64-bit RISC-V CPU which
supports 16 cores, runs with 2.5GHz, and is capable of running Linux.
To build platform specific library and firmwares, provide the
*PLATFORM=thead/c910* parameter to the top level make command.
Platform Options
----------------
The *T-HEAD C910* platform does not have any platform-specific options.
Building T-HEAD C910 Platform
-----------------------------
```
make PLATFORM=thead/c910
```
Booting T-HEAD C910 Platform
----------------------------
**No Payload**
As there's no payload, you may download vmlinux or u-boot to FW_JUMP_ADDR which
specified in config.mk or compile commands with GDB. And the execution flow will
turn to vmlinux or u-boot when opensbi ends.
**Linux Kernel Payload**
You can also choose to use Linux kernel as payload by enabling FW_PAYLOAD=y
along with specifying FW_PAYLOAD_OFFSET. The kernel image will be embedded in
the OPENSBI firmware binary, T-head will directly boot into Linux after OpenSBI.

204
docs/platform/thead-c9xx.md Normal file
View File

@@ -0,0 +1,204 @@
T-HEAD C9xx Series Processors
=============================
The **C9xx** series processors are high-performance RISC-V architecture
multi-core processors with AI vector acceleration engine.
For more details, refer [T-HEAD.CN](https://www.t-head.cn/)
To build the platform-specific library and firmware images, provide the
*PLATFORM=generic* parameter to the top level `make` command.
Platform Options
----------------
The *T-HEAD C9xx* does not have any platform-specific compile options
because it use generic platform.
```
CROSS_COMPILE=riscv64-linux-gnu- PLATFORM=generic FW_PIC=y /usr/bin/make
```
The *T-HEAD C9xx* DTB provided to OpenSBI generic firmwares will usually have
"riscv,clint0", "riscv,plic0", "thead,reset-sample" compatible strings.
DTS Example1: (Single core, eg: Allwinner D1 - c906)
----------------------------------------------------
```
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <3000000>;
cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdcv";
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges;
reset: reset-sample {
compatible = "thead,reset-sample";
plic-delegate = <0x0 0x101ffffc>;
};
clint0: clint@14000000 {
compatible = "riscv,clint0";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
>;
reg = <0x0 0x14000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@10000000 {
#interrupt-cells = <1>;
compatible = "riscv,plic0";
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
>;
reg = <0x0 0x10000000 0x0 0x04000000>;
reg-names = "control";
riscv,max-priority = <7>;
riscv,ndev = <200>;
};
}
```
DTS Example2: (Multi cores with soc reset-regs)
-----------------------------------------------
```
cpus {
#address-cells = <1>;
#size-cells = <0>;
timebase-frequency = <3000000>;
cpu@0 {
device_type = "cpu";
reg = <0>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu0_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@1 {
device_type = "cpu";
reg = <1>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu1_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@2 {
device_type = "cpu";
reg = <2>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu2_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
cpu@3 {
device_type = "cpu";
reg = <3>;
status = "fail";
compatible = "riscv";
riscv,isa = "rv64imafdc";
mmu-type = "riscv,sv39";
cpu3_intc: interrupt-controller {
#interrupt-cells = <1>;
compatible = "riscv,cpu-intc";
interrupt-controller;
};
};
};
soc {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges;
reset: reset-sample {
compatible = "thead,reset-sample";
plic-delegate = <0xff 0xd81ffffc>;
entry-reg = <0xff 0xff019050>;
entry-cnt = <4>;
control-reg = <0xff 0xff015004>;
control-val = <0x1c>;
csr-copy = <0x7f3 0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc>;
};
clint0: clint@ffdc000000 {
compatible = "riscv,clint0";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
&cpu1_intc 3 &cpu1_intc 7
&cpu2_intc 3 &cpu2_intc 7
&cpu3_intc 3 &cpu3_intc 7
&cpu4_intc 3 &cpu4_intc 7
>;
reg = <0xff 0xdc000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@ffd8000000 {
#interrupt-cells = <1>;
compatible = "riscv,plic0";
interrupt-controller;
interrupts-extended = <
&cpu0_intc 0xffffffff &cpu0_intc 9
&cpu1_intc 0xffffffff &cpu1_intc 9
&cpu2_intc 0xffffffff &cpu2_intc 9
&cpu3_intc 0xffffffff &cpu3_intc 9
>;
reg = <0xff 0xd8000000 0x0 0x04000000>;
reg-names = "control";
riscv,max-priority = <7>;
riscv,ndev = <80>;
};
}
```
DTS Example2: (Multi cores with old reset csrs)
-----------------------------------------------
```
reset: reset-sample {
compatible = "thead,reset-sample";
plic-delegate = <0xff 0xd81ffffc>;
using-csr-reset;
csr-copy = <0x7c0 0x7c1 0x7c2 0x7c3 0x7c5 0x7cc
0x3b0 0x3b1 0x3b2 0x3b3
0x3b4 0x3b5 0x3b6 0x3b7
0x3a0>;
};
```

View File

@@ -9,6 +9,7 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/riscv_elf.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
@@ -57,39 +58,91 @@ _start:
bne a0, a6, _wait_relocate_copy_done
_try_lottery:
/* Jump to relocation wait loop if we don't get relocation lottery */
la a6, _relocate_lottery
lla a6, _relocate_lottery
li a7, 1
amoadd.w a6, a7, (a6)
bnez a6, _wait_relocate_copy_done
/* Save load address */
la t0, _load_start
la t1, _start
lla t0, _load_start
lla t1, _start
REG_S t1, 0(t0)
#ifdef FW_PIC
/* relocate the global table content */
lla t0, _link_start
REG_L t0, 0(t0)
/* t1 shall has the address of _start */
sub t2, t1, t0
lla t3, _runtime_offset
REG_S t2, (t3)
lla t0, __rel_dyn_start
lla t1, __rel_dyn_end
beq t0, t1, _relocate_done
j 5f
2:
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
bne t5, t3, 3f
REG_L t3, -(REGBYTES*3)(t0)
REG_L t5, -(REGBYTES)(t0) /* t5 <-- addend */
add t5, t5, t2
add t3, t3, t2
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
j 5f
3:
lla t4, __dyn_sym_start
4:
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
srli t6, t5, SYM_INDEX /* t6 <--- sym table index */
andi t5, t5, 0xFF /* t5 <--- relocation type */
li t3, RELOC_TYPE
bne t5, t3, 5f
/* address R_RISCV_64 or R_RISCV_32 cases*/
REG_L t3, -(REGBYTES*3)(t0)
li t5, SYM_SIZE
mul t6, t6, t5
add s5, t4, t6
REG_L t6, -(REGBYTES)(t0) /* t0 <-- addend */
REG_L t5, REGBYTES(s5)
add t5, t5, t6
add t5, t5, t2 /* t5 <-- location to fix up in RAM */
add t3, t3, t2 /* t3 <-- location to fix up in RAM */
REG_S t5, 0(t3) /* store runtime address to the variable */
5:
addi t0, t0, (REGBYTES*3)
ble t0, t1, 2b
j _relocate_done
_wait_relocate_copy_done:
j _wait_for_boot_hart
#else
/* Relocate if load address != link address */
_relocate:
la t0, _link_start
lla t0, _link_start
REG_L t0, 0(t0)
la t1, _link_end
lla t1, _link_end
REG_L t1, 0(t1)
la t2, _load_start
lla t2, _load_start
REG_L t2, 0(t2)
sub t3, t1, t0
add t3, t3, t2
beq t0, t2, _relocate_done
la t4, _relocate_done
lla t4, _relocate_done
sub t4, t4, t2
add t4, t4, t0
blt t2, t0, _relocate_copy_to_upper
_relocate_copy_to_lower:
ble t1, t2, _relocate_copy_to_lower_loop
la t3, _relocate_lottery
lla t3, _relocate_lottery
BRANGE t2, t1, t3, _start_hang
la t3, _boot_status
lla t3, _boot_status
BRANGE t2, t1, t3, _start_hang
la t3, _relocate
la t5, _relocate_done
lla t3, _relocate
lla t5, _relocate_done
BRANGE t2, t1, t3, _start_hang
BRANGE t2, t1, t5, _start_hang
BRANGE t3, t5, t2, _start_hang
@@ -102,12 +155,12 @@ _relocate_copy_to_lower_loop:
jr t4
_relocate_copy_to_upper:
ble t3, t0, _relocate_copy_to_upper_loop
la t2, _relocate_lottery
lla t2, _relocate_lottery
BRANGE t0, t3, t2, _start_hang
la t2, _boot_status
lla t2, _boot_status
BRANGE t0, t3, t2, _start_hang
la t2, _relocate
la t5, _relocate_done
lla t2, _relocate
lla t5, _relocate_done
BRANGE t0, t3, t2, _start_hang
BRANGE t0, t3, t5, _start_hang
BRANGE t2, t5, t0, _start_hang
@@ -119,12 +172,12 @@ _relocate_copy_to_upper_loop:
blt t0, t1, _relocate_copy_to_upper_loop
jr t4
_wait_relocate_copy_done:
la t0, _start
la t1, _link_start
lla t0, _start
lla t1, _link_start
REG_L t1, 0(t1)
beq t0, t1, _wait_for_boot_hart
la t2, _boot_status
la t3, _wait_for_boot_hart
lla t2, _boot_status
lla t3, _wait_for_boot_hart
sub t3, t3, t0
add t3, t3, t1
1:
@@ -137,19 +190,22 @@ _wait_relocate_copy_done:
nop
bgt t4, t5, 1b
jr t3
#endif
_relocate_done:
/*
* Mark relocate copy done
* Use _boot_status copy relative to the load address
*/
la t0, _boot_status
la t1, _link_start
lla t0, _boot_status
#ifndef FW_PIC
lla t1, _link_start
REG_L t1, 0(t1)
la t2, _load_start
lla t2, _load_start
REG_L t2, 0(t2)
sub t0, t0, t1
add t0, t0, t2
#endif
li t1, BOOT_STATUS_RELOCATE_DONE
REG_S t1, 0(t0)
fence rw, rw
@@ -161,19 +217,19 @@ _relocate_done:
call _reset_regs
/* Zero-out BSS */
la s4, _bss_start
la s5, _bss_end
lla s4, _bss_start
lla s5, _bss_end
_bss_zero:
REG_S zero, (s4)
add s4, s4, __SIZEOF_POINTER__
blt s4, s5, _bss_zero
/* Setup temporary trap handler */
la s4, _start_hang
lla s4, _start_hang
csrw CSR_MTVEC, s4
/* Setup temporary stack */
la s4, _fw_end
lla s4, _fw_end
li s5, (SBI_SCRATCH_SIZE * 2)
add sp, s4, s5
@@ -184,7 +240,7 @@ _bss_zero:
#ifdef FW_FDT_PATH
/* Override previous arg1 */
la a1, fw_fdt_bin
lla a1, fw_fdt_bin
#endif
/*
@@ -202,7 +258,7 @@ _bss_zero:
* s7 -> HART Count
* s8 -> HART Stack Size
*/
la a4, platform
lla a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
@@ -212,7 +268,7 @@ _bss_zero:
#endif
/* Setup scratch space for all the HARTs*/
la tp, _fw_end
lla tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
/* Keep a copy of tp */
@@ -230,8 +286,8 @@ _scratch_init:
/* Initialize scratch space */
/* Store fw_start and fw_size in scratch space */
la a4, _fw_start
la a5, _fw_end
lla a4, _fw_start
lla a5, _fw_end
mul t0, s7, s8
add a5, a5, t0
sub a5, a5, a4
@@ -253,16 +309,16 @@ _scratch_init:
REG_S a0, SBI_SCRATCH_NEXT_MODE_OFFSET(tp)
MOV_3R a0, s0, a1, s1, a2, s2
/* Store warm_boot address in scratch space */
la a4, _start_warm
lla a4, _start_warm
REG_S a4, SBI_SCRATCH_WARMBOOT_ADDR_OFFSET(tp)
/* Store platform address in scratch space */
la a4, platform
lla a4, platform
REG_S a4, SBI_SCRATCH_PLATFORM_ADDR_OFFSET(tp)
/* Store hartid-to-scratch function address in scratch space */
la a4, _hartid_to_scratch
lla a4, _hartid_to_scratch
REG_S a4, SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET(tp)
/* Store trap-exit function address in scratch space */
la a4, _trap_exit
lla a4, _trap_exit
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(tp)
/* Clear tmp0 in scratch space */
REG_S zero, SBI_SCRATCH_TMP0_OFFSET(tp)
@@ -343,7 +399,7 @@ _fdt_reloc_done:
/* mark boot hart done */
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
lla t1, _boot_status
REG_S t0, 0(t1)
fence rw, rw
j _start_warm
@@ -351,7 +407,7 @@ _fdt_reloc_done:
/* waiting for boot hart to be done (_boot_status == 2) */
_wait_for_boot_hart:
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
lla t1, _boot_status
REG_L t1, 0(t1)
/* Reduce the bus traffic so that boot hart may proceed faster */
nop
@@ -369,7 +425,7 @@ _start_warm:
csrw CSR_MIP, zero
/* Find HART count and HART stack size */
la a4, platform
lla a4, platform
#if __riscv_xlen == 64
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
@@ -400,7 +456,7 @@ _start_warm:
3: bge s6, s7, _start_hang
/* Find the scratch space based on HART index */
la tp, _fw_end
lla tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
mul a5, s8, s6
@@ -415,13 +471,13 @@ _start_warm:
add sp, tp, zero
/* Setup trap handler */
la a4, _trap_handler
lla a4, _trap_handler
#if __riscv_xlen == 32
csrr a5, CSR_MISA
srli a5, a5, ('H' - 'A')
andi a5, a5, 0x1
beq a5, zero, _skip_trap_handler_rv32_hyp
la a4, _trap_handler_rv32_hyp
lla a4, _trap_handler_rv32_hyp
_skip_trap_handler_rv32_hyp:
#endif
csrw CSR_MTVEC, a4
@@ -432,7 +488,7 @@ _skip_trap_handler_rv32_hyp:
srli a5, a5, ('H' - 'A')
andi a5, a5, 0x1
beq a5, zero, _skip_trap_exit_rv32_hyp
la a4, _trap_exit_rv32_hyp
lla a4, _trap_exit_rv32_hyp
csrr a5, CSR_MSCRATCH
REG_S a4, SBI_SCRATCH_TRAP_EXIT_OFFSET(a5)
_skip_trap_exit_rv32_hyp:
@@ -446,6 +502,10 @@ _skip_trap_exit_rv32_hyp:
j _start_hang
.align 3
#ifdef FW_PIC
_runtime_offset:
RISCV_PTR 0
#endif
_relocate_lottery:
RISCV_PTR 0
_boot_status:
@@ -453,7 +513,7 @@ _boot_status:
_load_start:
RISCV_PTR _fw_start
_link_start:
RISCV_PTR _fw_start
RISCV_PTR FW_TEXT_START
_link_end:
RISCV_PTR _fw_reloc_end
@@ -468,7 +528,7 @@ _hartid_to_scratch:
* t1 -> HART Stack End
* t2 -> Temporary
*/
la t2, platform
lla t2, platform
#if __riscv_xlen == 64
lwu t0, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(t2)
lwu t2, SBI_PLATFORM_HART_COUNT_OFFSET(t2)
@@ -478,7 +538,7 @@ _hartid_to_scratch:
#endif
sub t2, t2, a1
mul t2, t2, t0
la t1, _fw_end
lla t1, _fw_end
add t1, t1, t2
li t2, SBI_SCRATCH_SIZE
sub a0, t1, t2
@@ -595,62 +655,63 @@ fw_platform_init:
call sbi_trap_handler
.endm
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
/* Restore all general regisers except SP and T0 */
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(sp)
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(sp)
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(sp)
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(sp)
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(sp)
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(sp)
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(sp)
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(sp)
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(sp)
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(sp)
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(sp)
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(sp)
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(sp)
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(sp)
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(sp)
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(sp)
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(sp)
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(sp)
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(sp)
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(sp)
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(sp)
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(sp)
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(sp)
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(sp)
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(sp)
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(sp)
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(sp)
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(sp)
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(sp)
.macro TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
/* Restore all general regisers except A0 and T0 */
REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(a0)
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(a0)
REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(a0)
REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(a0)
REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(a0)
REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(a0)
REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(a0)
REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(a0)
REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(a0)
REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(a0)
REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(a0)
REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(a0)
REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(a0)
REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(a0)
REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(a0)
REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(a0)
REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(a0)
REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(a0)
REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(a0)
REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(a0)
REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(a0)
REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(a0)
REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(a0)
REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(a0)
REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(a0)
REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(a0)
REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(a0)
REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(a0)
REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(a0)
.endm
.macro TRAP_RESTORE_MEPC_MSTATUS have_mstatush
/* Restore MEPC and MSTATUS CSRs */
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(a0)
csrw CSR_MEPC, t0
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(a0)
csrw CSR_MSTATUS, t0
.if \have_mstatush
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(a0)
csrw CSR_MSTATUSH, t0
.endif
.endm
.macro TRAP_RESTORE_SP_T0
.macro TRAP_RESTORE_A0_T0
/* Restore T0 */
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(a0)
/* Restore SP */
REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(sp)
/* Restore A0 */
REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(a0)
.endm
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler
.globl _trap_exit
_trap_handler:
TRAP_SAVE_AND_SETUP_SP_T0
@@ -660,25 +721,12 @@ _trap_handler:
TRAP_CALL_C_ROUTINE
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_MEPC_MSTATUS 0
TRAP_RESTORE_SP_T0
mret
.section .entry, "ax", %progbits
.align 3
.globl _trap_exit
_trap_exit:
add sp, a0, zero
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
TRAP_RESTORE_MEPC_MSTATUS 0
TRAP_RESTORE_SP_T0
TRAP_RESTORE_A0_T0
mret
@@ -686,6 +734,7 @@ _trap_exit:
.section .entry, "ax", %progbits
.align 3
.globl _trap_handler_rv32_hyp
.globl _trap_exit_rv32_hyp
_trap_handler_rv32_hyp:
TRAP_SAVE_AND_SETUP_SP_T0
@@ -695,25 +744,12 @@ _trap_handler_rv32_hyp:
TRAP_CALL_C_ROUTINE
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_MEPC_MSTATUS 1
TRAP_RESTORE_SP_T0
mret
.section .entry, "ax", %progbits
.align 3
.globl _trap_exit_rv32_hyp
_trap_exit_rv32_hyp:
add sp, a0, zero
TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0
TRAP_RESTORE_GENERAL_REGS_EXCEPT_A0_T0
TRAP_RESTORE_MEPC_MSTATUS 1
TRAP_RESTORE_SP_T0
TRAP_RESTORE_A0_T0
mret
#endif

View File

@@ -61,6 +61,19 @@
PROVIDE(_data_end = .);
}
.dynsym : {
PROVIDE(__dyn_sym_start = .);
*(.dynsym)
PROVIDE(__dyn_sym_end = .);
}
.rela.dyn : {
PROVIDE(__rel_dyn_start = .);
*(.rela*)
. = ALIGN(8);
PROVIDE(__rel_dyn_end = .);
}
. = ALIGN(0x1000); /* Ensure next section is page aligned */
.bss :

View File

@@ -54,7 +54,7 @@ fw_boot_hart:
*/
fw_save_info:
/* Save next arg1 in 'a1' */
la a4, _dynamic_next_arg1
lla a4, _dynamic_next_arg1
REG_S a1, (a4)
/* Sanity checks */
@@ -66,13 +66,13 @@ fw_save_info:
bgt a3, a4, _bad_dynamic_info
/* Save version == 0x1 fields */
la a4, _dynamic_next_addr
lla a4, _dynamic_next_addr
REG_L a3, FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET(a2)
REG_S a3, (a4)
la a4, _dynamic_next_mode
lla a4, _dynamic_next_mode
REG_L a3, FW_DYNAMIC_INFO_NEXT_MODE_OFFSET(a2)
REG_S a3, (a4)
la a4, _dynamic_options
lla a4, _dynamic_options
REG_L a3, FW_DYNAMIC_INFO_OPTIONS_OFFSET(a2)
REG_S a3, (a4)
@@ -80,7 +80,7 @@ fw_save_info:
li a4, 0x2
REG_L a3, FW_DYNAMIC_INFO_VERSION_OFFSET(a2)
blt a3, a4, 2f
la a4, _dynamic_boot_hart
lla a4, _dynamic_boot_hart
REG_L a3, FW_DYNAMIC_INFO_BOOT_HART_OFFSET(a2)
REG_S a3, (a4)
2:
@@ -96,7 +96,7 @@ fw_save_info:
* The next arg1 should be returned in 'a0'.
*/
fw_next_arg1:
la a0, _dynamic_next_arg1
lla a0, _dynamic_next_arg1
REG_L a0, (a0)
ret
@@ -108,7 +108,7 @@ fw_next_arg1:
* The next address should be returned in 'a0'.
*/
fw_next_addr:
la a0, _dynamic_next_addr
lla a0, _dynamic_next_addr
REG_L a0, (a0)
ret
@@ -120,7 +120,7 @@ fw_next_addr:
* The next address should be returned in 'a0'
*/
fw_next_mode:
la a0, _dynamic_next_mode
lla a0, _dynamic_next_mode
REG_L a0, (a0)
ret
@@ -133,7 +133,7 @@ fw_next_mode:
* The next address should be returned in 'a0'.
*/
fw_options:
la a0, _dynamic_options
lla a0, _dynamic_options
REG_L a0, (a0)
ret

View File

@@ -59,7 +59,7 @@ fw_next_arg1:
* The next address should be returned in 'a0'.
*/
fw_next_addr:
la a0, _jump_addr
lla a0, _jump_addr
REG_L a0, (a0)
ret

View File

@@ -59,7 +59,7 @@ fw_next_arg1:
* The next address should be returned in 'a0'.
*/
fw_next_addr:
la a0, payload_bin
lla a0, payload_bin
ret
.section .entry, "ax", %progbits

View File

@@ -13,6 +13,17 @@ firmware-cflags-y +=
firmware-asflags-y +=
firmware-ldflags-y +=
ifndef FW_PIC
FW_PIC := y
endif
ifeq ($(FW_PIC),y)
firmware-genflags-y += -DFW_PIC
firmware-asflags-y += -fpic
firmware-cflags-y += -fPIE -pie
firmware-ldflags-y += -Wl,--no-dynamic-linker
endif
ifdef FW_TEXT_START
firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
endif

View File

@@ -28,20 +28,20 @@
.globl _start
_start:
/* Pick one hart to run the main boot sequence */
la a3, _hart_lottery
lla a3, _hart_lottery
li a2, 1
amoadd.w a3, a2, (a3)
bnez a3, _start_hang
/* Save a0 and a1 */
la a3, _boot_a0
lla a3, _boot_a0
REG_S a0, 0(a3)
la a3, _boot_a1
lla a3, _boot_a1
REG_S a1, 0(a3)
/* Zero-out BSS */
la a4, _bss_start
la a5, _bss_end
lla a4, _bss_start
lla a5, _bss_end
_bss_zero:
REG_S zero, (a4)
add a4, a4, __SIZEOF_POINTER__
@@ -53,18 +53,18 @@ _start_warm:
csrw CSR_SIP, zero
/* Setup exception vectors */
la a3, _start_hang
lla a3, _start_hang
csrw CSR_STVEC, a3
/* Setup stack */
la a3, _payload_end
lla a3, _payload_end
li a4, 0x2000
add sp, a3, a4
/* Jump to C main */
la a3, _boot_a0
lla a3, _boot_a0
REG_L a0, 0(a3)
la a3, _boot_a1
lla a3, _boot_a1
REG_L a1, 0(a3)
call test_main

View File

@@ -40,7 +40,7 @@
/* clang-format on */
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_types.h>

View File

@@ -14,7 +14,7 @@
/* clang-format off */
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define __ASM_STR(x) x
#else
#define __ASM_STR(x) #x
@@ -38,7 +38,7 @@
#define LGREG __REG_SEL(3, 2)
#if __SIZEOF_POINTER__ == 8
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define RISCV_PTR .dword
#define RISCV_SZPTR 8
#define RISCV_LGPTR 3
@@ -48,7 +48,7 @@
#define RISCV_LGPTR "3"
#endif
#elif __SIZEOF_POINTER__ == 4
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define RISCV_PTR .word
#define RISCV_SZPTR 4
#define RISCV_LGPTR 2
@@ -79,7 +79,7 @@
/* clang-format on */
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#define csr_swap(csr, val) \
({ \
@@ -157,6 +157,11 @@ void csr_write_num(int csr_num, unsigned long val);
__asm__ __volatile__("wfi" ::: "memory"); \
} while (0)
#define ebreak() \
do { \
__asm__ __volatile__("ebreak" ::: "memory"); \
} while (0)
/* Get current HART id */
#define current_hartid() ((unsigned int)csr_read(CSR_MHARTID))
@@ -182,6 +187,6 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
unsigned long *log2len);
#endif /* !__ASSEMBLY__ */
#endif /* !__ASSEMBLER__ */
#endif

View File

@@ -18,6 +18,9 @@
#define RISCV_FENCE(p, s) \
__asm__ __volatile__ ("fence " #p "," #s : : : "memory")
#define RISCV_FENCE_I \
__asm__ __volatile__ ("fence.i" : : : "memory")
/* Read & Write Memory barrier */
#define mb() RISCV_FENCE(iorw,iorw)

14
include/sbi/riscv_elf.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef __RISCV_ELF_H__
#define __RISCV_ELF_H__
#include <sbi/riscv_asm.h>
#define R_RISCV_32 1
#define R_RISCV_64 2
#define R_RISCV_RELATIVE 3
#define RELOC_TYPE __REG_SEL(R_RISCV_64, R_RISCV_32)
#define SYM_INDEX __REG_SEL(0x20, 0x8)
#define SYM_SIZE __REG_SEL(0x18,0x10)
#endif

View File

@@ -2,26 +2,37 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
*/
#ifndef __RISCV_LOCKS_H__
#define __RISCV_LOCKS_H__
#include <sbi/sbi_types.h>
#define TICKET_SHIFT 16
typedef struct {
volatile long lock;
} spinlock_t;
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
u16 next;
u16 owner;
#else
u16 owner;
u16 next;
#endif
} __aligned(4) spinlock_t;
#define __RISCV_SPIN_UNLOCKED 0
#define __SPIN_LOCK_UNLOCKED \
(spinlock_t) { 0, 0 }
#define SPIN_LOCK_INIT(_lptr) (_lptr)->lock = __RISCV_SPIN_UNLOCKED
#define SPIN_LOCK_INIT(x) \
x = __SPIN_LOCK_UNLOCKED
#define SPIN_LOCK_INITIALIZER \
{ \
.lock = __RISCV_SPIN_UNLOCKED, \
}
#define SPIN_LOCK_INITIALIZER \
__SPIN_LOCK_UNLOCKED
#define DEFINE_SPIN_LOCK(x) \
spinlock_t SPIN_LOCK_INIT(x)
int spin_lock_check(spinlock_t *lock);

View File

@@ -12,6 +12,17 @@
#include <sbi/sbi_types.h>
struct sbi_console_device {
/** Name of the console device */
char name[32];
/** Write a character to the console output */
void (*console_putc)(char ch);
/** Read a character from the console input */
int (*console_getc)(void);
};
#define __printf(a, b) __attribute__((format(printf, a, b)))
bool sbi_isprintable(char ch);
@@ -32,6 +43,10 @@ int __printf(1, 2) sbi_printf(const char *format, ...);
int __printf(1, 2) sbi_dprintf(const char *format, ...);
const struct sbi_console_device *sbi_console_get_device(void);
void sbi_console_set_device(const struct sbi_console_device *dev);
struct sbi_scratch;
int sbi_console_init(struct sbi_scratch *scratch);

View File

@@ -22,7 +22,7 @@
/* clang-format off */
#ifdef __ASSEMBLY__
#ifdef __ASSEMBLER__
#define _AC(X,Y) X
#define _AT(T,X) X
#else

View File

@@ -12,6 +12,7 @@
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_trap.h>
#define csr_read_allowed(csr_num, trap) \
({ \
@@ -19,6 +20,7 @@
register ulong ttmp asm("a4"); \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
register ulong ret = 0; \
((struct sbi_trap_info *)(trap))->cause = 0; \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
@@ -36,6 +38,7 @@
register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4"); \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
((struct sbi_trap_info *)(trap))->cause = 0; \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \

View File

@@ -78,8 +78,13 @@ struct sbi_domain {
unsigned long next_mode;
/** Is domain allowed to reset the system */
bool system_reset_allowed;
/** Is domain allowed to suspend the system */
bool system_suspend_allowed;
};
/** The root domain instance */
extern struct sbi_domain root;
/** HART id to domain table */
extern struct sbi_domain *hartid_to_domain_table[];
@@ -124,8 +129,19 @@ bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid);
ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
ulong hbase);
/** Initialize a domain memory region as firmware region */
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg);
/**
* Initialize a domain memory region based on it's physical
* address and size.
*
* @param addr start physical address of memory region
* @param size physical size of memory region
* @param flags memory region flags
* @param reg pointer to memory region being initialized
*/
void sbi_domain_memregion_init(unsigned long addr,
unsigned long size,
unsigned long flags,
struct sbi_domain_memregion *reg);
/**
* Check whether we can access specified address for given mode and
@@ -156,6 +172,14 @@ void sbi_domain_dump_all(const char *suffix);
int sbi_domain_register(struct sbi_domain *dom,
const struct sbi_hartmask *assign_mask);
/**
* Add a memory region to the root domain
* @param reg pointer to the memory region to be added
*
* @return 0 on success and negative error code on failure
*/
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);
/** Finalize domain tables and startup non-root domains */
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid);

View File

@@ -14,7 +14,7 @@
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 2
#define SBI_ECALL_VERSION_MINOR 3
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;
@@ -39,6 +39,7 @@ extern struct sbi_ecall_extension ecall_ipi;
extern struct sbi_ecall_extension ecall_vendor;
extern struct sbi_ecall_extension ecall_hsm;
extern struct sbi_ecall_extension ecall_srst;
extern struct sbi_ecall_extension ecall_susp;
u16 sbi_ecall_version_major(void);

View File

@@ -28,6 +28,7 @@
#define SBI_EXT_RFENCE 0x52464E43
#define SBI_EXT_HSM 0x48534D
#define SBI_EXT_SRST 0x53525354
#define SBI_EXT_SUSP 0x53555350
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -37,6 +38,9 @@
#define SBI_EXT_BASE_GET_MVENDORID 0x4
#define SBI_EXT_BASE_GET_MARCHID 0x5
#define SBI_EXT_BASE_GET_MIMPID 0x6
#define SBI_EXT_BASE_RESET_C906L 0x7
#define SBI_EXT_BASE_RST_C906L 0x8
#define SBI_EXT_BASE_UNRST_C906L 0x9
/* SBI function IDs for TIME extension*/
#define SBI_EXT_TIME_SET_TIMER 0x0
@@ -48,20 +52,37 @@
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x3
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x4
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x5
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x6
/* SBI function IDs for HSM extension */
#define SBI_EXT_HSM_HART_START 0x0
#define SBI_EXT_HSM_HART_STOP 0x1
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
#define SBI_EXT_HSM_HART_SUSPEND 0x3
#define SBI_HSM_HART_STATUS_STARTED 0x0
#define SBI_HSM_HART_STATUS_STOPPED 0x1
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
#define SBI_HSM_STATE_STARTED 0x0
#define SBI_HSM_STATE_STOPPED 0x1
#define SBI_HSM_STATE_START_PENDING 0x2
#define SBI_HSM_STATE_STOP_PENDING 0x3
#define SBI_HSM_STATE_SUSPENDED 0x4
#define SBI_HSM_STATE_SUSPEND_PENDING 0x5
#define SBI_HSM_STATE_RESUME_PENDING 0x6
#define SBI_HSM_SUSP_BASE_MASK 0x7fffffff
#define SBI_HSM_SUSP_NON_RET_BIT 0x80000000
#define SBI_HSM_SUSP_PLAT_BASE 0x10000000
#define SBI_HSM_SUSPEND_RET_DEFAULT 0x00000000
#define SBI_HSM_SUSPEND_RET_PLATFORM SBI_HSM_SUSP_PLAT_BASE
#define SBI_HSM_SUSPEND_RET_LAST SBI_HSM_SUSP_BASE_MASK
#define SBI_HSM_SUSPEND_NON_RET_DEFAULT SBI_HSM_SUSP_NON_RET_BIT
#define SBI_HSM_SUSPEND_NON_RET_PLATFORM (SBI_HSM_SUSP_NON_RET_BIT | \
SBI_HSM_SUSP_PLAT_BASE)
#define SBI_HSM_SUSPEND_NON_RET_LAST (SBI_HSM_SUSP_NON_RET_BIT | \
SBI_HSM_SUSP_BASE_MASK)
/* SBI function IDs for SRST extension */
#define SBI_EXT_SRST_RESET 0x0
@@ -91,6 +112,13 @@
#define SBI_ERR_INVALID_ADDRESS -5
#define SBI_ERR_ALREADY_AVAILABLE -6
/* SBI function IDs for SUSP extension */
#define SBI_EXT_SUSP_SUSPEND 0x0
#define SBI_SUSP_SLEEP_TYPE_SUSPEND 0x0
#define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND
#define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000
#define SBI_LAST_ERR SBI_ERR_ALREADY_AVAILABLE
/* clang-format on */

View File

@@ -27,6 +27,7 @@ enum sbi_hart_features {
struct sbi_scratch;
int sbi_hart_reinit(struct sbi_scratch *scratch);
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot);
extern void (*sbi_hart_expected_trap)(void);

View File

@@ -12,16 +12,40 @@
#include <sbi/sbi_types.h>
/** Hart state values **/
#define SBI_HART_STOPPED 0
#define SBI_HART_STOPPING 1
#define SBI_HART_STARTING 2
#define SBI_HART_STARTED 3
#define SBI_HART_UNKNOWN 4
/** Hart state managment device */
struct sbi_hsm_device {
/** Name of the hart state managment device */
char name[32];
/** Start (or power-up) the given hart */
int (*hart_start)(u32 hartid, ulong saddr);
/**
* Stop (or power-down) the current hart from running. This call
* doesn't expect to return if success.
*/
int (*hart_stop)(void);
/**
* Put the current hart in platform specific suspend (or low-power)
* state.
*
* For successful retentive suspend, the call will return 0 when
* the hart resumes normal execution.
*
* For successful non-retentive suspend, the hart will resume from
* specified resume address
*/
int (*hart_suspend)(u32 suspend_type, ulong raddr);
};
struct sbi_domain;
struct sbi_scratch;
const struct sbi_hsm_device *sbi_hsm_get_device(void);
void sbi_hsm_set_device(const struct sbi_hsm_device *dev);
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot);
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch);
@@ -29,10 +53,17 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
const struct sbi_domain *dom,
u32 hartid, ulong saddr, ulong smode, ulong priv);
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow);
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch);
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch);
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
ulong raddr, ulong rmode, ulong priv);
int sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
long newstate);
int __sbi_hsm_hart_get_state(u32 hartid);
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid);
int sbi_hsm_hart_state_to_status(int state);
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
ulong hbase, ulong *out_hmask);
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
ulong hbase, ulong *out_hmask);
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch);
void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid);
#endif

View File

@@ -18,6 +18,18 @@
/* clang-format on */
/** IPI hardware device */
struct sbi_ipi_device {
/** Name of the IPI device */
char name[32];
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
};
struct sbi_scratch;
/** IPI event operations or callbacks */
@@ -63,6 +75,12 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
void sbi_ipi_process(void);
void sbi_ipi_raw_send(u32 target_hart);
const struct sbi_ipi_device *sbi_ipi_get_device(void);
void sbi_ipi_set_device(const struct sbi_ipi_device *dev);
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_ipi_exit(struct sbi_scratch *scratch);

View File

@@ -38,7 +38,7 @@
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
@@ -51,22 +51,16 @@ struct sbi_trap_regs;
/** Possible feature flags of a platform */
enum sbi_platform_features {
/** Platform has timer value */
SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */
SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
/** Platform has fault delegation support */
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
/** Platform has custom secondary hart booting support */
SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 1),
/** Last index of Platform features*/
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_MFAULTS_DELEGATION,
};
/** Default feature set for a platform */
#define SBI_PLATFORM_DEFAULT_FEATURES \
(SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
(SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Platform functions */
struct sbi_platform_operations {
@@ -92,15 +86,9 @@ struct sbi_platform_operations {
*/
int (*misa_get_xlen)(void);
/** Get platform specific root domain memory regions */
struct sbi_domain_memregion *(*domains_root_regions)(void);
/** Initialize (or populate) domains for the platform */
int (*domains_init)(void);
/** Write a character to the platform console output */
void (*console_putc)(char ch);
/** Read a character from the platform console input */
int (*console_getc)(void);
/** Initialize the platform console */
int (*console_init)(void);
@@ -109,10 +97,6 @@ struct sbi_platform_operations {
/** Exit the platform interrupt controller for current HART */
void (*irqchip_exit)(void);
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
/** Initialize IPI for current HART */
int (*ipi_init)(bool cold_boot);
/** Exit IPI for current HART */
@@ -121,30 +105,11 @@ struct sbi_platform_operations {
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
/** Get platform timer value */
u64 (*timer_value)(void);
/** Start platform timer event for current HART */
void (*timer_event_start)(u64 next_event);
/** Stop platform timer event for current HART */
void (*timer_event_stop)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Exit platform timer for current HART */
void (*timer_exit)(void);
/** Bringup the given hart */
int (*hart_start)(u32 hartid, ulong saddr);
/**
* Stop the current hart from running. This call doesn't expect to
* return if success.
*/
int (*hart_stop)(void);
/* Check whether reset type and reason supported by the platform */
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
/** Reset the platform */
void (*system_reset)(u32 reset_type, u32 reset_reason);
/** platform specific SBI extension implementation probe function */
int (*vendor_ext_check)(long extid);
/** platform specific SBI extension implementation provider */
@@ -211,18 +176,9 @@ struct sbi_platform {
#define sbi_platform_ops(__p) \
((const struct sbi_platform_operations *)(__p)->platform_ops_addr)
/** Check whether the platform supports timer value */
#define sbi_platform_has_timer_value(__p) \
((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
/** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
/** Check whether the platform supports fault delegation */
#define sbi_platform_has_mfaults_delegation(__p) \
((__p)->features & SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Check whether the platform supports custom secondary hart booting support */
#define sbi_platform_has_hart_secondary_boot(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_SECONDARY_BOOT)
/**
* Get HART index for the given HART
@@ -337,39 +293,6 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
return FALSE;
}
/**
* Bringup a given hart from previous stage. Platform should implement this
* operation if they support a custom mechanism to start a hart. Otherwise,
* a generic WFI based approach will be used to start/stop a hart in OpenSBI.
*
* @param plat pointer to struct sbi_platform
* @param hartid HART id
* @param saddr M-mode start physical address for the HART
*
* @return 0 if sucessful and negative error code on failure
*/
static inline int sbi_platform_hart_start(const struct sbi_platform *plat,
u32 hartid, ulong saddr)
{
if (plat && sbi_platform_ops(plat)->hart_start)
return sbi_platform_ops(plat)->hart_start(hartid, saddr);
return SBI_ENOTSUPP;
}
/**
* Stop the current hart in OpenSBI.
*
* @param plat pointer to struct sbi_platform
*
* @return Negative error code on failure. It doesn't return on success.
*/
static inline int sbi_platform_hart_stop(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->hart_stop)
return sbi_platform_ops(plat)->hart_stop();
return SBI_ENOTSUPP;
}
/**
* Early initialization for current HART
*
@@ -454,22 +377,6 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
return -1;
}
/**
* Get platform specific root domain memory regions
*
* @param plat pointer to struct sbi_platform
*
* @return an array of memory regions terminated by a region with order zero
* or NULL for no memory regions
*/
static inline struct sbi_domain_memregion *
sbi_platform_domains_root_regions(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->domains_root_regions)
return sbi_platform_ops(plat)->domains_root_regions();
return NULL;
}
/**
* Initialize (or populate) domains for the platform
*
@@ -484,33 +391,6 @@ static inline int sbi_platform_domains_init(const struct sbi_platform *plat)
return 0;
}
/**
* Write a character to the platform console output
*
* @param plat pointer to struct sbi_platform
* @param ch character to write
*/
static inline void sbi_platform_console_putc(const struct sbi_platform *plat,
char ch)
{
if (plat && sbi_platform_ops(plat)->console_putc)
sbi_platform_ops(plat)->console_putc(ch);
}
/**
* Read a character from the platform console input
*
* @param plat pointer to struct sbi_platform
*
* @return character read from console input
*/
static inline int sbi_platform_console_getc(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->console_getc)
return sbi_platform_ops(plat)->console_getc();
return -1;
}
/**
* Initialize the platform console
*
@@ -552,32 +432,6 @@ static inline void sbi_platform_irqchip_exit(const struct sbi_platform *plat)
sbi_platform_ops(plat)->irqchip_exit();
}
/**
* Send IPI to a target HART
*
* @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
u32 target_hart)
{
if (plat && sbi_platform_ops(plat)->ipi_send)
sbi_platform_ops(plat)->ipi_send(target_hart);
}
/**
* Clear IPI for a target HART
*
* @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_clear(const struct sbi_platform *plat,
u32 target_hart)
{
if (plat && sbi_platform_ops(plat)->ipi_clear)
sbi_platform_ops(plat)->ipi_clear(target_hart);
}
/**
* Initialize the platform IPI support for current HART
*
@@ -605,45 +459,6 @@ static inline void sbi_platform_ipi_exit(const struct sbi_platform *plat)
sbi_platform_ops(plat)->ipi_exit();
}
/**
* Get platform timer value
*
* @param plat pointer to struct sbi_platform
*
* @return 64-bit timer value
*/
static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->timer_value)
return sbi_platform_ops(plat)->timer_value();
return 0;
}
/**
* Start platform timer event for current HART
*
* @param plat pointer to struct struct sbi_platform
* @param next_event timer value when timer event will happen
*/
static inline void
sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
{
if (plat && sbi_platform_ops(plat)->timer_event_start)
sbi_platform_ops(plat)->timer_event_start(next_event);
}
/**
* Stop platform timer event for current HART
*
* @param plat pointer to struct sbi_platform
*/
static inline void
sbi_platform_timer_event_stop(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->timer_event_stop)
sbi_platform_ops(plat)->timer_event_stop();
}
/**
* Initialize the platform timer for current HART
*
@@ -671,41 +486,6 @@ static inline void sbi_platform_timer_exit(const struct sbi_platform *plat)
sbi_platform_ops(plat)->timer_exit();
}
/**
* Check whether reset type and reason supported by the platform
*
* @param plat pointer to struct sbi_platform
* @param reset_type type of reset
* @param reset_reason reason for reset
*
* @return 0 if reset type and reason not supported and 1 if supported
*/
static inline int sbi_platform_system_reset_check(
const struct sbi_platform *plat,
u32 reset_type, u32 reset_reason)
{
if (plat && sbi_platform_ops(plat)->system_reset_check)
return sbi_platform_ops(plat)->system_reset_check(reset_type,
reset_reason);
return 0;
}
/**
* Reset the platform
*
* This function will not return for supported reset type and reset reason
*
* @param plat pointer to struct sbi_platform
* @param reset_type type of reset
* @param reset_reason reason for reset
*/
static inline void sbi_platform_system_reset(const struct sbi_platform *plat,
u32 reset_type, u32 reset_reason)
{
if (plat && sbi_platform_ops(plat)->system_reset)
sbi_platform_ops(plat)->system_reset(reset_type, reset_reason);
}
/**
* Check if a vendor extension is implemented or not.
*

View File

@@ -43,7 +43,7 @@
/* clang-format on */
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_types.h>

View File

@@ -12,8 +12,50 @@
#include <sbi/sbi_types.h>
/** System reset hardware device */
struct sbi_system_reset_device {
/** Name of the system reset device */
char name[32];
/* Check whether reset type and reason supported by the device */
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
/** Reset the system */
void (*system_reset)(u32 reset_type, u32 reset_reason);
};
const struct sbi_system_reset_device *sbi_system_reset_get_device(void);
void sbi_system_reset_set_device(const struct sbi_system_reset_device *dev);
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason);
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason);
/** System suspend device */
struct sbi_system_suspend_device {
/** Name of the system suspend device */
char name[32];
/* Check whether sleep type is supported by the device */
int (*system_suspend_check)(u32 sleep_type);
/**
* Suspend the system
*
* @sleep_type: The sleep type identifier passed to the SBI call.
* @mmode_resume_addr:
* This is the same as sbi_scratch.warmboot_addr. Some platforms
* may not be able to return from system_suspend(), so they will
* jump directly to this address instead. Platforms which can
* return from system_suspend() may ignore this parameter.
*/
int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr);
};
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void);
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev);
bool sbi_system_suspend_supported(u32 sleep_type);
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque);
#endif

View File

@@ -12,6 +12,21 @@
#include <sbi/sbi_types.h>
/** Timer hardware device */
struct sbi_timer_device {
/** Name of the timer operations */
char name[32];
/** Get free-running timer value */
u64 (*timer_value)(void);
/** Start timer event for current HART */
void (*timer_event_start)(u64 next_event);
/** Stop timer event for current HART */
void (*timer_event_stop)(void);
};
struct sbi_scratch;
/** Get timer value for current HART */
@@ -35,6 +50,12 @@ void sbi_timer_event_start(u64 next_event);
/** Process timer event for current HART */
void sbi_timer_process(void);
/** Get current timer device */
const struct sbi_timer_device *sbi_timer_get_device(void);
/** Register timer device */
void sbi_timer_set_device(const struct sbi_timer_device *dev);
/* Initialize timer */
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);

View File

@@ -110,7 +110,7 @@
/** Size (in bytes) of sbi_trap_info */
#define SBI_TRAP_INFO_SIZE SBI_TRAP_INFO_OFFSET(last)
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
#include <sbi/sbi_types.h>
@@ -205,7 +205,7 @@ struct sbi_trap_info {
int sbi_trap_redirect(struct sbi_trap_regs *regs,
struct sbi_trap_info *trap);
void sbi_trap_handler(struct sbi_trap_regs *regs);
struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs);
void __noreturn sbi_trap_exit(const struct sbi_trap_regs *regs);

View File

@@ -63,6 +63,7 @@ typedef unsigned long physical_size_t;
#define __packed __attribute__((packed))
#define __noreturn __attribute__((noreturn))
#define __aligned(x) __attribute__((aligned(x)))
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)

View File

@@ -30,9 +30,8 @@ void fdt_cpu_fixup(void *fdt);
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
* @param compat: PLIC node compatible string
*/
void fdt_plic_fixup(void *fdt, const char *compat);
void fdt_plic_fixup(void *fdt);
/**
* Fix up the reserved memory node in the device tree

View File

@@ -17,14 +17,8 @@ struct fdt_ipi {
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*warm_init)(void);
void (*exit)(void);
void (*send)(u32 target_hart);
void (*clear)(u32 target_hart);
};
void fdt_ipi_send(u32 target_hart);
void fdt_ipi_clear(u32 target_hart);
void fdt_ipi_exit(void);
int fdt_ipi_init(bool cold_boot);

View File

@@ -15,14 +15,8 @@
struct fdt_reset {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*system_reset_check)(u32 reset_type, u32 reset_reason);
void (*system_reset)(u32 reset_type, u32 reset_reason);
};
int fdt_system_reset_check(u32 reset_type, u32 reset_reason);
void fdt_system_reset(u32 reset_type, u32 reset_reason);
int fdt_reset_init(void);
#endif

View File

@@ -15,14 +15,8 @@
struct fdt_serial {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
void (*putc)(char ch);
int (*getc)(void);
};
void fdt_serial_putc(char ch);
int fdt_serial_getc(void);
int fdt_serial_init(void);
#endif

View File

@@ -9,10 +9,6 @@
#include <sbi/sbi_types.h>
void shakti_uart_putc(char ch);
int shakti_uart_getc(void);
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -12,10 +12,6 @@
#include <sbi/sbi_types.h>
void sifive_uart_putc(char ch);
int sifive_uart_getc(void);
int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
#endif

View File

@@ -12,10 +12,6 @@
#include <sbi/sbi_types.h>
void uart8250_putc(char ch);
int uart8250_getc(void);
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width);

View File

@@ -29,20 +29,10 @@ struct clint_data {
void (*time_wr)(u64 value, volatile u64 *addr);
};
void clint_ipi_send(u32 target_hart);
void clint_ipi_clear(u32 target_hart);
int clint_warm_ipi_init(void);
int clint_cold_ipi_init(struct clint_data *clint);
u64 clint_timer_value(void);
void clint_timer_event_stop(void);
void clint_timer_event_start(u64 next_event);
int clint_warm_timer_init(void);
int clint_cold_timer_init(struct clint_data *clint,

View File

@@ -10,12 +10,8 @@
#include <sbi/sbi_types.h>
void htif_putc(char ch);
int htif_serial_init(void);
int htif_getc(void);
int htif_system_reset_check(u32 type, u32 reason);
void htif_system_reset(u32 type, u32 reason);
int htif_system_reset_init(void);
#endif

View File

@@ -12,10 +12,6 @@
#include <sbi/sbi_types.h>
int sifive_test_system_reset_check(u32 type, u32 reason);
void sifive_test_system_reset(u32 type, u32 reason);
int sifive_test_init(unsigned long base);
#endif

View File

@@ -17,17 +17,8 @@ struct fdt_timer {
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*warm_init)(void);
void (*exit)(void);
u64 (*value)(void);
void (*event_stop)(void);
void (*event_start)(u64 next_event);
};
u64 fdt_timer_value(void);
void fdt_timer_event_stop(void);
void fdt_timer_event_start(u64 next_event);
void fdt_timer_exit(void);
int fdt_timer_init(bool cold_boot);

View File

@@ -22,6 +22,7 @@ libsbi-objs-y += sbi_ecall_hsm.o
libsbi-objs-y += sbi_ecall_legacy.o
libsbi-objs-y += sbi_ecall_replace.o
libsbi-objs-y += sbi_ecall_vendor.o
libsbi-objs-y += sbi_ecall_susp.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o

View File

@@ -28,25 +28,23 @@ void atomic_write(atomic_t *atom, long value)
long atomic_add_return(atomic_t *atom, long value)
{
long ret;
#if __SIZEOF_LONG__ == 4
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(value)
: "memory");
#elif __SIZEOF_LONG__ == 8
__asm__ __volatile__(" amoadd.d.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(value)
: "memory");
#endif
return ret + value;
}
long atomic_sub_return(atomic_t *atom, long value)
{
long ret;
__asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0"
: "+A"(atom->counter), "=r"(ret)
: "r"(-value)
: "memory");
return ret - value;
return atomic_add_return(atom, -value);
}
#define __axchg(ptr, new, size) \

View File

@@ -2,44 +2,76 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Copyright (c) 2021 Christoph Müllner <cmuellner@linux.com>
*/
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_locks.h>
int spin_lock_check(spinlock_t *lock)
static inline int spin_lock_unlocked(spinlock_t lock)
{
return (lock->lock == __RISCV_SPIN_UNLOCKED) ? 0 : 1;
return lock.owner == lock.next;
}
bool spin_lock_check(spinlock_t *lock)
{
RISCV_FENCE(r, rw);
return !spin_lock_unlocked(*lock);
}
int spin_trylock(spinlock_t *lock)
{
int tmp = 1, busy;
unsigned long inc = 1u << TICKET_SHIFT;
unsigned long mask = 0xffffu << TICKET_SHIFT;
u32 l0, tmp1, tmp2;
__asm__ __volatile__(
" amoswap.w %0, %2, %1\n" RISCV_ACQUIRE_BARRIER
: "=r"(busy), "+A"(lock->lock)
: "r"(tmp)
/* Get the current lock counters. */
"1: lr.w.aq %0, %3\n"
" slli %2, %0, %6\n"
" and %2, %2, %5\n"
" and %1, %0, %5\n"
/* Is the lock free right now? */
" bne %1, %2, 2f\n"
" add %0, %0, %4\n"
/* Acquire the lock. */
" sc.w.rl %0, %0, %3\n"
" bnez %0, 1b\n"
"2:"
: "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
: "memory");
return !busy;
return !l0;
}
void spin_lock(spinlock_t *lock)
{
while (1) {
if (spin_lock_check(lock))
continue;
unsigned long inc = 1u << TICKET_SHIFT;
unsigned long mask = 0xffffu;
u32 l0, tmp1, tmp2;
if (spin_trylock(lock))
break;
}
__asm__ __volatile__(
/* Atomically increment the next ticket. */
" amoadd.w.aqrl %0, %4, %3\n"
/* Did we get the lock? */
" srli %1, %0, %6\n"
" and %1, %1, %5\n"
"1: and %2, %0, %5\n"
" beq %1, %2, 2f\n"
/* If not, then spin on the lock. */
" lw %0, %3\n"
RISCV_ACQUIRE_BARRIER
" j 1b\n"
"2:"
: "=&r"(l0), "=&r"(tmp1), "=&r"(tmp2), "+A"(*lock)
: "r"(inc), "r"(mask), "I"(TICKET_SHIFT)
: "memory");
}
void spin_unlock(spinlock_t *lock)
{
__smp_store_release(&lock->lock, __RISCV_SPIN_UNLOCKED);
__smp_store_release(&lock->owner, lock->owner + 1);
}

View File

@@ -12,7 +12,7 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
static const struct sbi_platform *console_plat = NULL;
static const struct sbi_console_device *console_dev = NULL;
static spinlock_t console_out_lock = SPIN_LOCK_INITIALIZER;
bool sbi_isprintable(char c)
@@ -26,14 +26,18 @@ bool sbi_isprintable(char c)
int sbi_getc(void)
{
return sbi_platform_console_getc(console_plat);
if (console_dev && console_dev->console_getc)
return console_dev->console_getc();
return -1;
}
void sbi_putc(char ch)
{
if (ch == '\n')
sbi_platform_console_putc(console_plat, '\r');
sbi_platform_console_putc(console_plat, ch);
if (console_dev && console_dev->console_putc) {
if (ch == '\n')
console_dev->console_putc('\r');
console_dev->console_putc(ch);
}
}
void sbi_puts(const char *str)
@@ -390,9 +394,20 @@ int sbi_dprintf(const char *format, ...)
return retval;
}
const struct sbi_console_device *sbi_console_get_device(void)
{
return console_dev;
}
void sbi_console_set_device(const struct sbi_console_device *dev)
{
if (!dev || console_dev)
return;
console_dev = dev;
}
int sbi_console_init(struct sbi_scratch *scratch)
{
console_plat = sbi_platform_ptr(scratch);
return sbi_platform_console_init(console_plat);
return sbi_platform_console_init(sbi_platform_ptr(scratch));
}

View File

@@ -19,21 +19,22 @@
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX] = { 0 };
static u32 domain_count = 0;
static bool domain_finalized = false;
static struct sbi_hartmask root_hmask = { 0 };
#define ROOT_FW_REGION 0
#define ROOT_ALL_REGION 1
#define ROOT_END_REGION 2
static struct sbi_domain_memregion root_memregs[ROOT_END_REGION + 1] = { 0 };
#define ROOT_REGION_MAX 16
static u32 root_memregs_count = 0;
static struct sbi_domain_memregion root_fw_region;
static struct sbi_domain_memregion root_memregs[ROOT_REGION_MAX + 1] = { 0 };
static struct sbi_domain root = {
struct sbi_domain root = {
.name = "root",
.possible_harts = &root_hmask,
.regions = root_memregs,
.system_reset_allowed = TRUE,
.system_suspend_allowed = TRUE,
};
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
@@ -64,12 +65,41 @@ ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
return ret;
}
void sbi_domain_memregion_initfw(struct sbi_domain_memregion *reg)
static void domain_memregion_initfw(struct sbi_domain_memregion *reg)
{
if (!reg)
return;
sbi_memcpy(reg, &root_memregs[ROOT_FW_REGION], sizeof(*reg));
sbi_memcpy(reg, &root_fw_region, sizeof(*reg));
}
void sbi_domain_memregion_init(unsigned long addr,
unsigned long size,
unsigned long flags,
struct sbi_domain_memregion *reg)
{
unsigned long base = 0, order;
for (order = log2roundup(size) ; order <= __riscv_xlen; order++) {
if (order < __riscv_xlen) {
base = addr & ~((1UL << order) - 1UL);
if ((base <= addr) &&
(addr < (base + (1UL << order))) &&
(base <= (addr + size - 1UL)) &&
((addr + size - 1UL) < (base + (1UL << order))))
break;
} else {
base = 0;
break;
}
}
if (reg) {
reg->base = base;
reg->order = order;
reg->flags = flags;
}
}
bool sbi_domain_check_addr(const struct sbi_domain *dom,
@@ -207,9 +237,9 @@ static int sanitize_domain(const struct sbi_platform *plat,
count = 0;
have_fw_reg = FALSE;
sbi_domain_for_each_memregion(dom, reg) {
if (reg->order == root_memregs[ROOT_FW_REGION].order &&
reg->base == root_memregs[ROOT_FW_REGION].base &&
reg->flags == root_memregs[ROOT_FW_REGION].flags)
if (reg->order == root_fw_region.order &&
reg->base == root_fw_region.base &&
reg->flags == root_fw_region.flags)
have_fw_reg = TRUE;
count++;
}
@@ -354,6 +384,8 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
sbi_printf("Domain%d SysReset %s: %s\n",
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
sbi_printf("Domain%d SysSuspend %s: %s\n",
dom->index, suffix, (dom->system_suspend_allowed) ? "yes" : "no");
}
void sbi_domain_dump_all(const char *suffix)
@@ -376,7 +408,8 @@ int sbi_domain_register(struct sbi_domain *dom,
u32 cold_hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
if (!dom || !assign_mask)
/* Sanity checks */
if (!dom || !assign_mask || domain_finalized)
return SBI_EINVAL;
/* Check if domain already discovered */
@@ -438,6 +471,67 @@ int sbi_domain_register(struct sbi_domain *dom,
return 0;
}
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
{
int rc;
bool reg_merged;
struct sbi_domain_memregion *nreg, *nreg1, *nreg2;
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
/* Sanity checks */
if (!reg || domain_finalized ||
(root.regions != root_memregs) ||
(ROOT_REGION_MAX <= root_memregs_count))
return SBI_EINVAL;
/* Check for conflicts */
sbi_domain_for_each_memregion(&root, nreg) {
if (is_region_conflict(reg, nreg))
return SBI_EINVAL;
}
/* Append the memregion to root memregions */
nreg = &root_memregs[root_memregs_count];
sbi_memcpy(nreg, reg, sizeof(*reg));
root_memregs_count++;
root_memregs[root_memregs_count].order = 0;
/* Sort and optimize root regions */
do {
/* Sanitize the root domain so that memregions are sorted */
rc = sanitize_domain(plat, &root);
if (rc) {
sbi_printf("%s: sanity checks failed for"
" %s (error %d)\n", __func__,
root.name, rc);
return rc;
}
/* Merge consecutive memregions with same order and flags */
reg_merged = false;
sbi_domain_for_each_memregion(&root, nreg) {
nreg1 = nreg + 1;
if (!nreg1->order)
continue;
if ((nreg->base + BIT(nreg->order)) == nreg1->base &&
nreg->order == nreg1->order &&
nreg->flags == nreg1->flags) {
nreg->order++;
while (nreg1->order) {
nreg2 = nreg1 + 1;
sbi_memcpy(nreg1, nreg2, sizeof(*nreg1));
nreg1++;
}
reg_merged = true;
root_memregs_count--;
}
}
} while (reg_merged);
return 0;
}
int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
{
int rc;
@@ -490,35 +584,34 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
}
}
/*
* Set the finalized flag so that the root domain
* regions can't be changed.
*/
domain_finalized = true;
return 0;
}
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
{
u32 i;
struct sbi_domain_memregion *memregs;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Root domain firmware memory region */
root_memregs[ROOT_FW_REGION].order = log2roundup(scratch->fw_size);
root_memregs[ROOT_FW_REGION].base = scratch->fw_start &
~((1UL << root_memregs[0].order) - 1UL);
root_memregs[ROOT_FW_REGION].flags = 0;
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_size, 0,
&root_fw_region);
domain_memregion_initfw(&root_memregs[root_memregs_count++]);
/* Root domain allow everything memory region */
root_memregs[ROOT_ALL_REGION].order = __riscv_xlen;
root_memregs[ROOT_ALL_REGION].base = 0;
root_memregs[ROOT_ALL_REGION].flags = (SBI_DOMAIN_MEMREGION_READABLE |
SBI_DOMAIN_MEMREGION_WRITEABLE |
SBI_DOMAIN_MEMREGION_EXECUTABLE);
sbi_domain_memregion_init(0, ~0UL,
(SBI_DOMAIN_MEMREGION_READABLE |
SBI_DOMAIN_MEMREGION_WRITEABLE |
SBI_DOMAIN_MEMREGION_EXECUTABLE),
&root_memregs[root_memregs_count++]);
/* Root domain memory region end */
root_memregs[ROOT_END_REGION].order = 0;
/* Use platform specific root memory regions when available */
memregs = sbi_platform_domains_root_regions(plat);
if (memregs)
root.regions = memregs;
root_memregs[root_memregs_count].order = 0;
/* Root domain boot HART id is same as coldboot HART id */
root.boot_hartid = cold_hartid;

View File

@@ -168,6 +168,9 @@ int sbi_ecall_init(void)
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_vendor);
if (ret)
return ret;
ret = sbi_ecall_register_extension(&ecall_susp);
if (ret)
return ret;

View File

@@ -14,6 +14,7 @@
#include <sbi/sbi_trap.h>
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
{
@@ -32,6 +33,41 @@ static int sbi_ecall_base_probe(unsigned long extid, unsigned long *out_val)
return 0;
}
#define SEC_SYS_BASE (0x020B0000)
static int sbi_ecall_base_rst_c906l(void)
{
unsigned int value;
value = readl((void *)0x3003024);
writel((value & (~(1 << 6))), (void *)0x3003024);
return 0;
}
static int sbi_ecall_base_unrst_c906l(const unsigned long address)
{
unsigned int value;
value = readl((void *)SEC_SYS_BASE + 0x04);
writel((value | (1 << 13)), (void *)SEC_SYS_BASE + 0x04);
writel(address, (void *)SEC_SYS_BASE + 0x20);
writel((address >> 32), (void *)SEC_SYS_BASE + 0x24);
value = readl((void *)0x3003024);
writel((value | (1 << 6)), (void *)0x3003024);
return 0;
}
static int sbi_ecall_base_reset_c906l(const unsigned long address)
{
sbi_ecall_base_rst_c906l();
sbi_ecall_base_unrst_c906l(address);
return 0;
}
static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
@@ -65,6 +101,16 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_ecall_base_probe(regs->a0, out_val);
break;
case SBI_EXT_BASE_RESET_C906L:
ret = sbi_ecall_base_reset_c906l(regs->a0);
*out_val = regs->a0;
break;
case SBI_EXT_BASE_RST_C906L:
ret = sbi_ecall_base_rst_c906l();
break;
case SBI_EXT_BASE_UNRST_C906L:
ret = sbi_ecall_base_unrst_c906l(regs->a0);
break;
default:
ret = SBI_ENOTSUPP;
}

View File

@@ -22,14 +22,13 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
ulong smode;
int ret = 0, hstate;
int ret = 0;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
ulong smode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >>
MSTATUS_MPP_SHIFT;
switch (funcid) {
case SBI_EXT_HSM_HART_START:
smode = csr_read(CSR_MSTATUS);
smode = (smode & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
ret = sbi_hsm_hart_start(scratch, sbi_domain_thishart_ptr(),
regs->a0, regs->a1, smode, regs->a2);
break;
@@ -37,9 +36,12 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
ret = sbi_hsm_hart_stop(scratch, TRUE);
break;
case SBI_EXT_HSM_HART_GET_STATUS:
hstate = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
regs->a0);
ret = sbi_hsm_hart_state_to_status(hstate);
ret = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(),
regs->a0);
break;
case SBI_EXT_HSM_HART_SUSPEND:
ret = sbi_hsm_hart_suspend(scratch, regs->a0, regs->a1,
smode, regs->a2);
break;
default:
ret = SBI_ENOTSUPP;

View File

@@ -34,8 +34,8 @@ static int sbi_load_hart_mask_unpriv(ulong *pmask, ulong *hmask,
if (uptrap->cause)
return SBI_ETRAP;
} else {
sbi_hsm_hart_started_mask(sbi_domain_thishart_ptr(),
0, &mask);
sbi_hsm_hart_interruptible_mask(sbi_domain_thishart_ptr(),
0, &mask);
}
*hmask = mask;

60
lib/sbi/sbi_ecall_susp.c Normal file
View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: BSD-2-Clause
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_system.h>
static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = SBI_ENOTSUPP;
if (funcid == SBI_EXT_SUSP_SUSPEND)
ret = sbi_system_suspend(regs->a0, regs->a1, regs->a2);
if (ret >= 0) {
*out_val = ret;
ret = 0;
}
return ret;
}
static bool susp_available(void)
{
u32 type;
/*
* At least one suspend type should be supported by the
* platform for the SBI SUSP extension to be usable.
*/
for (type = 0; type <= SBI_SUSP_SLEEP_TYPE_LAST; type++) {
if (sbi_system_suspend_supported(type))
return true;
}
return false;
}
struct sbi_ecall_extension ecall_susp;
static int sbi_ecall_susp_register_extensions(unsigned long extid, unsigned long *out_val)
{
if (!susp_available()) {
*out_val = 0;
return 0;
}
*out_val = 1;
return 0;
}
struct sbi_ecall_extension ecall_susp = {
.extid_start = SBI_EXT_SUSP,
.extid_end = SBI_EXT_SUSP,
.probe = sbi_ecall_susp_register_extensions,
.handle = sbi_ecall_susp_handler,
};

View File

@@ -21,14 +21,23 @@
static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
{
ulong cen = -1UL;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (prev_mode <= PRV_S) {
cen &= csr_read(CSR_MCOUNTEREN);
if (virt)
cen &= csr_read(CSR_HCOUNTEREN);
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN)) {
cen &= csr_read(CSR_MCOUNTEREN);
if (virt)
cen &= csr_read(CSR_HCOUNTEREN);
} else {
cen = 0;
}
}
if (prev_mode == PRV_U) {
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
cen &= csr_read(CSR_SCOUNTEREN);
else
cen = 0;
}
if (prev_mode == PRV_U)
cen &= csr_read(CSR_SCOUNTEREN);
return ((cen >> hpm_num) & 1) ? TRUE : FALSE;
}

View File

@@ -18,7 +18,7 @@ void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
fifo->queue = queue_mem;
fifo->num_entries = entries;
fifo->entry_size = entry_size;
SPIN_LOCK_INIT(&fifo->qlock);
SPIN_LOCK_INIT(fifo->qlock);
fifo->avail = fifo->tail = 0;
sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
}

View File

@@ -406,7 +406,6 @@ __mhpm_skip:
#undef __check_csr
/* Detect if hart supports SCOUNTEREN feature */
trap.cause = 0;
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
@@ -415,7 +414,6 @@ __mhpm_skip:
}
/* Detect if hart supports MCOUNTEREN feature */
trap.cause = 0;
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
@@ -424,16 +422,30 @@ __mhpm_skip:
}
/* Detect if hart supports time CSR */
trap.cause = 0;
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_TIME;
}
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
int sbi_hart_reinit(struct sbi_scratch *scratch)
{
int rc;
mstatus_init(scratch);
rc = fp_init(scratch);
if (rc)
return rc;
rc = delegate_traps(scratch);
if (rc)
return rc;
return 0;
}
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
{
if (cold_boot) {
if (misa_extension('H'))
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
@@ -447,17 +459,7 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
hart_detect_features(scratch);
mstatus_init(scratch);
rc = fp_init(scratch);
if (rc)
return rc;
rc = delegate_traps(scratch);
if (rc)
return rc;
return 0;
return sbi_hart_reinit(scratch);
}
void __attribute__((noreturn)) sbi_hart_hang(void)

View File

@@ -21,50 +21,47 @@
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_console.h>
static const struct sbi_hsm_device *hsm_dev = NULL;
static unsigned long hart_data_offset;
/** Per hart specific data to manage state transition **/
struct sbi_hsm_data {
atomic_t state;
unsigned long suspend_type;
unsigned long saved_mie;
unsigned long saved_mip;
};
#define __sbi_hsm_hart_change_state(hdata, oldstate, newstate) \
({ \
long state = atomic_cmpxchg(&(hdata)->state, oldstate, newstate); \
if (state != (oldstate)) \
sbi_printf("%s: ERR: The hart is in invalid state [%lu]\n", \
__func__, state); \
state == (oldstate); \
})
int sbi_hsm_hart_state_to_status(int state)
int sbi_hsm_hart_change_state(struct sbi_scratch *scratch, long oldstate,
long newstate)
{
int ret;
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
switch (state) {
case SBI_HART_STOPPED:
ret = SBI_HSM_HART_STATUS_STOPPED;
break;
case SBI_HART_STOPPING:
ret = SBI_HSM_HART_STATUS_STOP_PENDING;
break;
case SBI_HART_STARTING:
ret = SBI_HSM_HART_STATUS_START_PENDING;
break;
case SBI_HART_STARTED:
ret = SBI_HSM_HART_STATUS_STARTED;
break;
default:
ret = SBI_EINVAL;
}
return ret;
return __sbi_hsm_hart_change_state(hdata, oldstate, newstate);
}
static inline int __sbi_hsm_hart_get_state(u32 hartid)
int __sbi_hsm_hart_get_state(u32 hartid)
{
struct sbi_hsm_data *hdata;
struct sbi_scratch *scratch;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return SBI_HART_UNKNOWN;
return SBI_EINVAL;
hdata = sbi_scratch_offset_ptr(scratch, hart_data_offset);
return atomic_read(&hdata->state);
@@ -73,19 +70,11 @@ static inline int __sbi_hsm_hart_get_state(u32 hartid)
int sbi_hsm_hart_get_state(const struct sbi_domain *dom, u32 hartid)
{
if (!sbi_domain_is_assigned_hart(dom, hartid))
return SBI_HART_UNKNOWN;
return SBI_EINVAL;
return __sbi_hsm_hart_get_state(hartid);
}
static bool sbi_hsm_hart_started(const struct sbi_domain *dom, u32 hartid)
{
if (sbi_hsm_hart_get_state(dom, hartid) == SBI_HART_STARTED)
return TRUE;
else
return FALSE;
}
/**
* Get ulong HART mask for given HART base ID
* @param dom the domain to be used for output HART mask
@@ -94,9 +83,10 @@ static bool sbi_hsm_hart_started(const struct sbi_domain *dom, u32 hartid)
* @return 0 on success and SBI_Exxx (< 0) on failure
* Note: the output HART mask will be set to zero on failure as well.
*/
int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
ulong hbase, ulong *out_hmask)
int sbi_hsm_hart_interruptible_mask(const struct sbi_domain *dom,
ulong hbase, ulong *out_hmask)
{
int hstate;
ulong i, hmask, dmask;
ulong hend = sbi_scratch_last_hartid() + 1;
@@ -109,9 +99,12 @@ int sbi_hsm_hart_started_mask(const struct sbi_domain *dom,
dmask = sbi_domain_get_assigned_hartmask(dom, hbase);
for (i = hbase; i < hend; i++) {
hmask = 1UL << (i - hbase);
if ((dmask & hmask) &&
(__sbi_hsm_hart_get_state(i) == SBI_HART_STARTED))
*out_hmask |= hmask;
if (dmask & hmask) {
hstate = __sbi_hsm_hart_get_state(i);
if (hstate == SBI_HSM_STATE_STARTED ||
hstate == SBI_HSM_STATE_SUSPENDED)
*out_hmask |= hmask;
}
}
return 0;
@@ -123,16 +116,15 @@ void sbi_hsm_prepare_next_jump(struct sbi_scratch *scratch, u32 hartid)
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTING,
SBI_HART_STARTED);
if (oldstate != SBI_HART_STARTING)
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_START_PENDING,
SBI_HSM_STATE_STARTED);
if (oldstate != SBI_HSM_STATE_START_PENDING)
sbi_hart_hang();
}
static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/* Save MIE CSR */
@@ -142,15 +134,65 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
csr_set(CSR_MIE, MIP_MSIP);
/* Wait for hart_add call*/
while (atomic_read(&hdata->state) != SBI_HART_STARTING) {
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
wfi();
};
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
/*
* No need to clear IPI here because the sbi_ipi_init() will
* clear it for current HART via sbi_platform_ipi_init().
*/
}
const struct sbi_hsm_device *sbi_hsm_get_device(void)
{
return hsm_dev;
}
void sbi_hsm_set_device(const struct sbi_hsm_device *dev)
{
if (!dev || hsm_dev)
return;
hsm_dev = dev;
}
static bool hsm_device_has_hart_hotplug(void)
{
if (hsm_dev && hsm_dev->hart_start && hsm_dev->hart_stop)
return true;
return false;
}
static bool hsm_device_has_hart_secondary_boot(void)
{
if (hsm_dev && hsm_dev->hart_start && !hsm_dev->hart_stop)
return true;
return false;
}
static int hsm_device_hart_start(u32 hartid, ulong saddr)
{
if (hsm_dev && hsm_dev->hart_start)
return hsm_dev->hart_start(hartid, saddr);
return SBI_ENOTSUPP;
}
static int hsm_device_hart_stop(void)
{
if (hsm_dev && hsm_dev->hart_stop)
return hsm_dev->hart_stop();
return SBI_ENOTSUPP;
}
static int hsm_device_hart_suspend(u32 suspend_type, ulong raddr)
{
if (hsm_dev && hsm_dev->hart_suspend)
return hsm_dev->hart_suspend(suspend_type, raddr);
return SBI_ENOTSUPP;
}
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
@@ -174,7 +216,9 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
hdata = sbi_scratch_offset_ptr(rscratch,
hart_data_offset);
ATOMIC_INIT(&hdata->state,
(i == hartid) ? SBI_HART_STARTING : SBI_HART_STOPPED);
(i == hartid) ?
SBI_HSM_STATE_START_PENDING :
SBI_HSM_STATE_STOPPED);
}
} else {
sbi_hsm_hart_wait(scratch, hartid);
@@ -186,18 +230,17 @@ int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
void __noreturn sbi_hsm_exit(struct sbi_scratch *scratch)
{
u32 hstate;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPING,
SBI_HART_STOPPED);
if (hstate != SBI_HART_STOPPING)
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOP_PENDING,
SBI_HSM_STATE_STOPPED);
if (hstate != SBI_HSM_STATE_STOP_PENDING)
goto fail_exit;
if (sbi_platform_has_hart_hotplug(plat)) {
sbi_platform_hart_stop(plat);
if (hsm_device_has_hart_hotplug()) {
hsm_device_hart_stop();
/* It should never reach here */
goto fail_exit;
}
@@ -223,7 +266,6 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
unsigned int hstate;
struct sbi_scratch *rscratch;
struct sbi_hsm_data *hdata;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* For now, we only allow start mode to be S-mode or U-mode. */
if (smode != PRV_S && smode != PRV_U)
@@ -232,22 +274,22 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
return SBI_EINVAL;
if (dom && !sbi_domain_check_addr(dom, saddr, smode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVAL;
return SBI_EINVALID_ADDR;
rscratch = sbi_hartid_to_scratch(hartid);
if (!rscratch)
return SBI_EINVAL;
hdata = sbi_scratch_offset_ptr(rscratch, hart_data_offset);
hstate = atomic_cmpxchg(&hdata->state, SBI_HART_STOPPED,
SBI_HART_STARTING);
if (hstate == SBI_HART_STARTED)
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED,
SBI_HSM_STATE_START_PENDING);
if (hstate == SBI_HSM_STATE_STARTED)
return SBI_EALREADY;
/**
* if a hart is already transition to start or stop, another start call
* is considered as invalid request.
*/
if (hstate != SBI_HART_STOPPED)
if (hstate != SBI_HSM_STATE_STOPPED)
return SBI_EINVAL;
init_count = sbi_init_count(hartid);
@@ -255,12 +297,11 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
rscratch->next_addr = saddr;
rscratch->next_mode = smode;
if (sbi_platform_has_hart_hotplug(plat) ||
(sbi_platform_has_hart_secondary_boot(plat) && !init_count)) {
return sbi_platform_hart_start(plat, hartid,
scratch->warmboot_addr);
if (hsm_device_has_hart_hotplug() ||
(hsm_device_has_hart_secondary_boot() && !init_count)) {
return hsm_device_hart_start(hartid, scratch->warmboot_addr);
} else {
sbi_platform_ipi_send(plat, hartid);
sbi_ipi_raw_send(hartid);
}
return 0;
@@ -269,19 +310,19 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
{
int oldstate;
u32 hartid = current_hartid();
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
if (!sbi_hsm_hart_started(sbi_domain_thishart_ptr(), hartid))
return SBI_EINVAL;
if (!dom)
return SBI_EFAIL;
oldstate = atomic_cmpxchg(&hdata->state, SBI_HART_STARTED,
SBI_HART_STOPPING);
if (oldstate != SBI_HART_STARTED) {
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STARTED,
SBI_HSM_STATE_STOP_PENDING);
if (oldstate != SBI_HSM_STATE_STARTED) {
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
__func__, oldstate);
return SBI_EDENIED;
return SBI_EFAIL;
}
if (exitnow)
@@ -289,3 +330,181 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
return 0;
}
static int __sbi_hsm_suspend_ret_default(struct sbi_scratch *scratch)
{
/* Wait for interrupt */
wfi();
return 0;
}
void __sbi_hsm_suspend_non_ret_save(struct sbi_scratch *scratch)
{
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/*
* We will be resuming in warm-boot path so the MIE and MIP CSRs
* will be back to initial state. It is possible that HART has
* configured timer event before going to suspend state so we
* should save MIE and MIP CSRs and restore it after resuming.
*
* Further, the M-mode bits in MIP CSR are read-only and set by
* external devices (such as interrupt controller) whereas all
* VS-mode bits in MIP are read-only alias of bits in HVIP CSR.
*
* This means we should only save/restore S-mode bits of MIP CSR
* such as MIP.SSIP and MIP.STIP.
*/
hdata->saved_mie = csr_read(CSR_MIE);
hdata->saved_mip = csr_read(CSR_MIP) & (MIP_SSIP | MIP_STIP);
}
static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
{
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
csr_write(CSR_MIE, hdata->saved_mie);
csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
}
static int __sbi_hsm_suspend_non_ret_default(struct sbi_scratch *scratch,
ulong raddr)
{
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
/*
* Save some of the M-mode CSRs which should be restored after
* resuming from suspend state
*/
__sbi_hsm_suspend_non_ret_save(scratch);
/* Wait for interrupt */
wfi();
/*
* Directly jump to warm reboot to simulate resume from a
* non-retentive suspend.
*/
jump_warmboot();
return 0;
}
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
{
int oldstate;
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/* If current HART was SUSPENDED then set RESUME_PENDING state */
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_SUSPENDED,
SBI_HSM_STATE_RESUME_PENDING);
if (oldstate != SBI_HSM_STATE_SUSPENDED) {
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
__func__, oldstate);
sbi_hart_hang();
}
}
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
{
u32 oldstate;
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/* If current HART was RESUME_PENDING then set STARTED state */
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_RESUME_PENDING,
SBI_HSM_STATE_STARTED);
if (oldstate != SBI_HSM_STATE_RESUME_PENDING) {
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
__func__, oldstate);
sbi_hart_hang();
}
/*
* Restore some of the M-mode CSRs which we are re-configured by
* the warm-boot sequence.
*/
__sbi_hsm_suspend_non_ret_restore(scratch);
}
int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
ulong raddr, ulong rmode, ulong priv)
{
int oldstate, ret;
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_hsm_data *hdata = sbi_scratch_offset_ptr(scratch,
hart_data_offset);
/* For now, we only allow suspend from S-mode or U-mode. */
/* Sanity check on domain assigned to current HART */
if (!dom)
return SBI_EINVAL;
/* Sanity check on suspend type */
if (SBI_HSM_SUSPEND_RET_DEFAULT < suspend_type &&
suspend_type < SBI_HSM_SUSPEND_RET_PLATFORM)
return SBI_EINVAL;
if (SBI_HSM_SUSPEND_NON_RET_DEFAULT < suspend_type &&
suspend_type < SBI_HSM_SUSPEND_NON_RET_PLATFORM)
return SBI_EINVAL;
/* Additional sanity check for non-retentive suspend */
if (suspend_type & SBI_HSM_SUSP_NON_RET_BIT) {
if (rmode != PRV_S && rmode != PRV_U)
return SBI_EINVAL;
if (dom && !sbi_domain_check_addr(dom, raddr, rmode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVALID_ADDR;
}
/* Save the resume address and resume mode */
scratch->next_arg1 = priv;
scratch->next_addr = raddr;
scratch->next_mode = rmode;
/* Directly move from STARTED to SUSPENDED state */
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STARTED,
SBI_HSM_STATE_SUSPENDED);
if (oldstate != SBI_HSM_STATE_STARTED) {
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
__func__, oldstate);
ret = SBI_EDENIED;
goto fail_restore_state;
}
/* Save the suspend type */
hdata->suspend_type = suspend_type;
/* Try platform specific suspend */
ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr);
if (ret == SBI_ENOTSUPP) {
/* Try generic implementation of default suspend types */
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) {
ret = __sbi_hsm_suspend_ret_default(scratch);
} else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
ret = __sbi_hsm_suspend_non_ret_default(scratch,
scratch->warmboot_addr);
}
}
fail_restore_state:
/*
* We might have successfully resumed from retentive suspend
* or suspend failed. In both cases, we restore state of hart.
*/
oldstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_SUSPENDED,
SBI_HSM_STATE_STARTED);
if (oldstate != SBI_HSM_STATE_SUSPENDED) {
sbi_printf("%s: ERR: The hart is in invalid state [%u]\n",
__func__, oldstate);
sbi_hart_hang();
}
return ret;
}

View File

@@ -53,6 +53,12 @@ static void sbi_boot_print_banner(struct sbi_scratch *scratch)
static void sbi_boot_print_general(struct sbi_scratch *scratch)
{
char str[128];
const struct sbi_hsm_device *hdev;
const struct sbi_ipi_device *idev;
const struct sbi_timer_device *tdev;
const struct sbi_console_device *cdev;
const struct sbi_system_reset_device *srdev;
const struct sbi_system_suspend_device *susp_dev;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
@@ -65,6 +71,24 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
sbi_printf("Platform Features : %s\n", str);
sbi_printf("Platform HART Count : %u\n",
sbi_platform_hart_count(plat));
idev = sbi_ipi_get_device();
sbi_printf("Platform IPI Device : %s\n",
(idev) ? idev->name : "---");
tdev = sbi_timer_get_device();
sbi_printf("Platform Timer Device : %s\n",
(tdev) ? tdev->name : "---");
cdev = sbi_console_get_device();
sbi_printf("Platform Console Device : %s\n",
(cdev) ? cdev->name : "---");
hdev = sbi_hsm_get_device();
sbi_printf("Platform HSM Device : %s\n",
(hdev) ? hdev->name : "---");
srdev = sbi_system_reset_get_device();
sbi_printf("Platform SysReset Device : %s\n",
(srdev) ? srdev->name : "---");
susp_dev = sbi_system_suspend_get_device();
sbi_printf("Platform Suspend Device : %s\n",
(susp_dev) ? susp_dev->name : "---");
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
@@ -130,7 +154,6 @@ static unsigned long coldboot_done;
static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long saved_mie, cmip;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
@@ -167,14 +190,18 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
/*
* The wait for coldboot is common for both warm startup and
* warm resume path so clearing IPI here would result in losing
* an IPI in warm resume path.
*
* Also, the sbi_platform_ipi_init() called from sbi_ipi_init()
* will automatically clear IPI for current HART.
*/
}
static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Mark coldboot done */
__smp_store_release(&coldboot_done, 1);
@@ -185,7 +212,7 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
if ((i != hartid) &&
sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
sbi_platform_ipi_send(plat, i);
sbi_ipi_raw_send(i);
}
/* Release coldboot lock */
@@ -198,7 +225,9 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *init_count;
#ifndef CONFIG_OPENSBI_FASTBOOT
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
#endif
/* Note: This has to be first thing in coldboot init sequence */
rc = sbi_scratch_init(scratch);
@@ -219,20 +248,25 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
#ifndef CONFIG_OPENSBI_FASTBOOT
rc = sbi_platform_early_init(plat, TRUE);
if (rc)
sbi_hart_hang();
#endif
rc = sbi_hart_init(scratch, TRUE);
if (rc)
sbi_hart_hang();
#ifndef CONFIG_OPENSBI_FASTBOOT
rc = sbi_console_init(scratch);
if (rc)
sbi_hart_hang();
#endif
sbi_boot_print_banner(scratch);
#ifndef CONFIG_OPENSBI_FASTBOOT
rc = sbi_platform_irqchip_init(plat, TRUE);
if (rc) {
sbi_printf("%s: platform irqchip init failed (error %d)\n",
@@ -245,6 +279,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_printf("%s: ipi init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
#endif
rc = sbi_tlb_init(scratch, TRUE);
if (rc) {
@@ -292,12 +327,14 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
* Note: Platform final initialization should be last so that
* it sees correct domain assignment and PMP configuration.
*/
#ifndef CONFIG_OPENSBI_FASTBOOT
rc = sbi_platform_final_init(plat, TRUE);
if (rc) {
sbi_printf("%s: platform final init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
#endif
sbi_boot_print_hart(scratch, hartid);
@@ -311,14 +348,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
scratch->next_mode, FALSE);
}
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
wait_for_coldboot(scratch, hartid);
if (!init_count_offset)
sbi_hart_hang();
@@ -362,6 +397,40 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
(*init_count)++;
sbi_hsm_prepare_next_jump(scratch, hartid);
}
static void init_warm_resume(struct sbi_scratch *scratch)
{
int rc;
sbi_hsm_hart_resume_start(scratch);
rc = sbi_hart_reinit(scratch);
if (rc)
sbi_hart_hang();
rc = sbi_hart_pmp_configure(scratch);
if (rc)
sbi_hart_hang();
sbi_hsm_hart_resume_finish(scratch);
}
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
{
int hstate;
wait_for_coldboot(scratch, hartid);
hstate = sbi_hsm_hart_get_state(sbi_domain_thishart_ptr(), hartid);
if (hstate < 0)
sbi_hart_hang();
if (hstate == SBI_HSM_STATE_SUSPENDED)
init_warm_resume(scratch);
else
init_warm_startup(scratch, hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr,
scratch->next_mode, FALSE);

View File

@@ -25,7 +25,7 @@ struct sbi_ipi_data {
};
static unsigned long ipi_data_off;
static const struct sbi_ipi_device *ipi_dev = NULL;
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
@@ -33,7 +33,6 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
{
int ret;
struct sbi_scratch *remote_scratch = NULL;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data;
const struct sbi_ipi_event_ops *ipi_ops;
@@ -61,7 +60,9 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
*/
atomic_raw_set_bit(event, &ipi_data->ipi_type);
smp_wmb();
sbi_platform_ipi_send(plat, remote_hartid);
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(remote_hartid);
if (ipi_ops->sync)
ipi_ops->sync(scratch);
@@ -82,7 +83,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (hbase != -1UL) {
rc = sbi_hsm_hart_started_mask(dom, hbase, &m);
rc = sbi_hsm_hart_interruptible_mask(dom, hbase, &m);
if (rc)
return rc;
m &= hmask;
@@ -94,7 +95,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
}
} else {
hbase = 0;
while (!sbi_hsm_hart_started_mask(dom, hbase, &m)) {
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) {
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
@@ -178,12 +179,12 @@ void sbi_ipi_process(void)
unsigned int ipi_event;
const struct sbi_ipi_event_ops *ipi_ops;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data =
sbi_scratch_offset_ptr(scratch, ipi_data_off);
u32 hartid = current_hartid();
sbi_platform_ipi_clear(plat, hartid);
if (ipi_dev && ipi_dev->ipi_clear)
ipi_dev->ipi_clear(hartid);
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
ipi_event = 0;
@@ -201,6 +202,25 @@ skip:
};
}
void sbi_ipi_raw_send(u32 target_hart)
{
if (ipi_dev && ipi_dev->ipi_send)
ipi_dev->ipi_send(target_hart);
}
const struct sbi_ipi_device *sbi_ipi_get_device(void)
{
return ipi_dev;
}
void sbi_ipi_set_device(const struct sbi_ipi_device *dev)
{
if (!dev || ipi_dev)
return;
ipi_dev = dev;
}
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
{
int ret;
@@ -230,7 +250,10 @@ int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)
ipi_data = sbi_scratch_offset_ptr(scratch, ipi_data_off);
ipi_data->ipi_type = 0x00;
/* Platform init */
/*
* Initialize platform IPI support. This will also clear any
* pending IPIs for current/calling HART.
*/
ret = sbi_platform_ipi_init(sbi_platform_ptr(scratch), cold_boot);
if (ret)
return ret;

View File

@@ -19,18 +19,9 @@ static inline char *sbi_platform_feature_id2string(unsigned long feature)
return NULL;
switch (feature) {
case SBI_PLATFORM_HAS_TIMER_VALUE:
fstr = "timer";
break;
case SBI_PLATFORM_HAS_HART_HOTPLUG:
fstr = "hotplug";
break;
case SBI_PLATFORM_HAS_MFAULTS_DELEGATION:
fstr = "mfdeleg";
break;
case SBI_PLATFORM_HAS_HART_SECONDARY_BOOT:
fstr = "sec_boot";
break;
default:
break;
}

View File

@@ -18,15 +18,31 @@
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_init.h>
static const struct sbi_system_reset_device *reset_dev = NULL;
const struct sbi_system_reset_device *sbi_system_reset_get_device(void)
{
return reset_dev;
}
void sbi_system_reset_set_device(const struct sbi_system_reset_device *dev)
{
if (!dev || reset_dev)
return;
reset_dev = dev;
}
bool sbi_system_reset_supported(u32 reset_type, u32 reset_reason)
{
if (sbi_platform_system_reset_check(sbi_platform_thishart_ptr(),
reset_type, reset_reason))
if (reset_dev && reset_dev->system_reset_check &&
reset_dev->system_reset_check(reset_type, reset_reason))
return TRUE;
return FALSE;
}
#include <sbi/riscv_io.h>
void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
{
ulong hbase = 0, hmask;
@@ -35,7 +51,7 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* Send HALT IPI to every hart other than the current hart */
while (!sbi_hsm_hart_started_mask(dom, hbase, &hmask)) {
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &hmask)) {
if (hbase <= cur_hartid)
hmask &= ~(1UL << (cur_hartid - hbase));
if (hmask)
@@ -47,10 +63,97 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
sbi_hsm_hart_stop(scratch, FALSE);
/* Platform specific reset if domain allowed system reset */
if (dom->system_reset_allowed)
sbi_platform_system_reset(sbi_platform_ptr(scratch),
reset_type, reset_reason);
if (dom->system_reset_allowed &&
reset_dev && reset_dev->system_reset)
reset_dev->system_reset(reset_type, reset_reason);
writew(0x5555, (void *)0x100000); // qemu poweroff
/* If platform specific reset did not work then do sbi_exit() */
sbi_exit(scratch);
}
static const struct sbi_system_suspend_device *suspend_dev;
const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void)
{
return suspend_dev;
}
void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev)
{
if (!dev || suspend_dev)
return;
suspend_dev = dev;
}
bool sbi_system_suspend_supported(u32 sleep_type)
{
return suspend_dev && suspend_dev->system_suspend_check &&
suspend_dev->system_suspend_check(sleep_type) == 0;
}
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
{
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
//unsigned int hartid = current_hartid();
unsigned long prev_mode;
//unsigned long i, j;
int ret;
if (!dom || !dom->system_suspend_allowed)
return SBI_EFAIL;
if (!suspend_dev || !suspend_dev->system_suspend ||
!suspend_dev->system_suspend_check)
return SBI_EFAIL;
ret = suspend_dev->system_suspend_check(sleep_type);
if (ret != SBI_OK)
return ret;
prev_mode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_EFAIL;
//FIX ME: hartindex to hart
//sbi_hartmask_for_each_hartindex(j, &dom->assigned_harts) {
// //i = sbi_hartindex_to_hartid(j);
// if (i == hartid)
// continue;
// if (__sbi_hsm_hart_get_state(i) != SBI_HSM_STATE_STOPPED)
// return SBI_ERR_DENIED;
//}
if (!sbi_domain_check_addr(dom, resume_addr, prev_mode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVALID_ADDR;
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_STARTED,
SBI_HSM_STATE_SUSPENDED))
return SBI_EFAIL;
/* Prepare for resume */
scratch->next_mode = prev_mode;
scratch->next_addr = resume_addr;
scratch->next_arg1 = opaque;
__sbi_hsm_suspend_non_ret_save(scratch);
/* Suspend */
ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr);
if (ret != SBI_OK) {
if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED,
SBI_HSM_STATE_STARTED))
sbi_hart_hang();
return ret;
}
/* Resume */
jump_warmboot();
__builtin_unreachable();
}

View File

@@ -16,10 +16,11 @@
#include <sbi/sbi_timer.h>
static unsigned long time_delta_off;
static u64 (*get_time_val)(const struct sbi_platform *plat);
static u64 (*get_time_val)(void);
static const struct sbi_timer_device *timer_dev = NULL;
#if __riscv_xlen == 32
static u64 get_ticks(const struct sbi_platform *plat)
static u64 get_ticks(void)
{
u32 lo, hi, tmp;
__asm__ __volatile__("1:\n"
@@ -31,7 +32,7 @@ static u64 get_ticks(const struct sbi_platform *plat)
return ((u64)hi << 32) | lo;
}
#else
static u64 get_ticks(const struct sbi_platform *plat)
static u64 get_ticks(void)
{
unsigned long n;
@@ -40,9 +41,16 @@ static u64 get_ticks(const struct sbi_platform *plat)
}
#endif
static u64 get_platform_ticks(void)
{
return timer_dev->timer_value();
}
u64 sbi_timer_value(void)
{
return get_time_val(sbi_platform_thishart_ptr());
if (get_time_val)
return get_time_val();
return 0;
}
u64 sbi_timer_virt_value(void)
@@ -80,7 +88,8 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
void sbi_timer_event_start(u64 next_event)
{
sbi_platform_timer_event_start(sbi_platform_thishart_ptr(), next_event);
if (timer_dev && timer_dev->timer_event_start)
timer_dev->timer_event_start(next_event);
csr_clear(CSR_MIP, MIP_STIP);
csr_set(CSR_MIE, MIP_MTIP);
}
@@ -91,17 +100,34 @@ void sbi_timer_process(void)
csr_set(CSR_MIP, MIP_STIP);
}
const struct sbi_timer_device *sbi_timer_get_device(void)
{
return timer_dev;
}
void sbi_timer_set_device(const struct sbi_timer_device *dev)
{
if (!dev || timer_dev)
return;
timer_dev = dev;
if (!get_time_val && timer_dev->timer_value)
get_time_val = get_platform_ticks;
}
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{
u64 *time_delta;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int ret;
if (cold_boot) {
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
"TIME_DELTA");
if (!time_delta_off)
return SBI_ENOMEM;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
get_time_val = get_ticks;
} else {
if (!time_delta_off)
return SBI_ENOMEM;
@@ -110,24 +136,13 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = 0;
ret = sbi_platform_timer_init(plat, cold_boot);
if (ret)
return ret;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
get_time_val = get_ticks;
else if (sbi_platform_has_timer_value(plat))
get_time_val = sbi_platform_timer_value;
else
/* There is no method to provide timer value */
return SBI_ENODEV;
return 0;
return sbi_platform_timer_init(plat, cold_boot);
}
void sbi_timer_exit(struct sbi_scratch *scratch)
{
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
if (timer_dev && timer_dev->timer_event_stop)
timer_dev->timer_event_stop();
csr_clear(CSR_MIP, MIP_STIP);
csr_clear(CSR_MIE, MIP_MTIP);

View File

@@ -210,7 +210,7 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
*
* @param regs pointer to register state
*/
void sbi_trap_handler(struct sbi_trap_regs *regs)
struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
{
int rc = SBI_ENOTSUPP;
const char *msg = "trap handler failed";
@@ -236,7 +236,7 @@ void sbi_trap_handler(struct sbi_trap_regs *regs)
msg = "unhandled external interrupt";
goto trap_error;
};
return;
return regs;
}
switch (mcause) {
@@ -271,6 +271,7 @@ void sbi_trap_handler(struct sbi_trap_regs *regs)
trap_error:
if (rc)
sbi_trap_error(msg, rc, mcause, mtval, mtval2, mtinst, regs);
return regs;
}
typedef void (*trap_exit_t)(const struct sbi_trap_regs *regs);

View File

@@ -222,7 +222,7 @@ static u32 fdt_domains_count;
static struct sbi_domain fdt_domains[FDT_DOMAIN_MAX_COUNT];
static struct sbi_hartmask fdt_masks[FDT_DOMAIN_MAX_COUNT];
static struct sbi_domain_memregion
fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 2];
fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 1];
static int __fdt_parse_region(void *fdt, int domain_offset,
int region_offset, u32 region_access,
@@ -276,7 +276,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
struct sbi_hartmask *mask;
struct sbi_hartmask assign_mask;
int *cold_domain_offset = opaque;
struct sbi_domain_memregion *regions;
struct sbi_domain_memregion *reg, *regions;
int i, err, len, cpus_offset, cpu_offset, doffset;
/* Sanity check on maximum domains we can handle */
@@ -314,13 +314,31 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
/* Setup memregions from DT */
val32 = 0;
sbi_memset(regions, 0,
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 2));
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 1));
dom->regions = regions;
err = fdt_iterate_each_memregion(fdt, domain_offset, &val32,
__fdt_parse_region);
if (err)
return err;
sbi_domain_memregion_initfw(&regions[val32]);
/*
* Copy over root domain memregions which don't allow
* read, write and execute from lower privilege modes.
*
* These root domain memregions without read, write,
* and execute permissions include:
* 1) firmware region protecting the firmware memory
* 2) mmio regions protecting M-mode only mmio devices
*/
sbi_domain_for_each_memregion(&root, reg) {
if ((reg->flags & SBI_DOMAIN_MEMREGION_READABLE) ||
(reg->flags & SBI_DOMAIN_MEMREGION_WRITEABLE) ||
(reg->flags & SBI_DOMAIN_MEMREGION_EXECUTABLE))
continue;
if (FDT_DOMAIN_REGION_MAX_COUNT <= val32)
return SBI_EINVAL;
sbi_memcpy(&regions[val32++], reg, sizeof(*reg));
}
/* Read "boot-hart" DT property */
val32 = -1U;
@@ -380,6 +398,13 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
else
dom->system_reset_allowed = FALSE;
/* Read "system-suspend-allowed" DT property */
if (fdt_get_property(fdt, domain_offset,
"system-suspend-allowed", NULL))
dom->system_suspend_allowed = TRUE;
else
dom->system_suspend_allowed = FALSE;
/* Find /cpus DT node */
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0)

View File

@@ -51,15 +51,18 @@ void fdt_cpu_fixup(void *fdt)
}
}
void fdt_plic_fixup(void *fdt, const char *compat)
void fdt_plic_fixup(void *fdt)
{
u32 *cells;
int i, cells_count;
int plic_off;
plic_off = fdt_node_offset_by_compatible(fdt, 0, compat);
if (plic_off < 0)
return;
plic_off = fdt_node_offset_by_compatible(fdt, 0, "sifive,plic-1.0.0");
if (plic_off < 0) {
plic_off = fdt_node_offset_by_compatible(fdt, 0, "riscv,plic0");
if (plic_off < 0)
return;
}
cells = (u32 *)fdt_getprop(fdt, plic_off,
"interrupts-extended", &cells_count);
@@ -257,7 +260,7 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
void fdt_fixups(void *fdt)
{
fdt_plic_fixup(fdt, "riscv,plic0");
fdt_plic_fixup(fdt);
fdt_reserved_memory_fixup(fdt);
}

View File

@@ -442,8 +442,9 @@ int fdt_parse_clint_node(void *fdt, int nodeoffset, bool for_timer,
if (clint->hart_count < count)
clint->hart_count = count;
/* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
clint->has_64bit_mmio = TRUE;
if (fdt_getprop(fdt, nodeoffset, "clint,has-no-64bit-mmio", &count))
clint->has_64bit_mmio = FALSE;
return 0;
}

View File

@@ -17,35 +17,15 @@ static struct fdt_ipi *ipi_drivers[] = {
&fdt_ipi_clint
};
static void dummy_send(u32 target_hart)
{
}
static void dummy_clear(u32 target_hart)
{
}
static struct fdt_ipi dummy = {
.match_table = NULL,
.cold_init = NULL,
.warm_init = NULL,
.exit = NULL,
.send = dummy_send,
.clear = dummy_clear
};
static struct fdt_ipi *current_driver = &dummy;
void fdt_ipi_send(u32 target_hart)
{
current_driver->send(target_hart);
}
void fdt_ipi_clear(u32 target_hart)
{
current_driver->clear(target_hart);
}
void fdt_ipi_exit(void)
{
if (current_driver->exit)

View File

@@ -36,6 +36,7 @@ static int ipi_clint_cold_init(void *fdt, int nodeoff,
static const struct fdt_match ipi_clint_match[] = {
{ .compatible = "riscv,clint0" },
{ .compatible = "sifive,clint0" },
{ },
};
@@ -44,6 +45,4 @@ struct fdt_ipi fdt_ipi_clint = {
.cold_init = ipi_clint_cold_init,
.warm_init = clint_warm_ipi_init,
.exit = NULL,
.send = clint_ipi_send,
.clear = clint_ipi_clear,
};

View File

@@ -94,7 +94,7 @@ int plic_cold_irqchip_init(struct plic_data *plic)
/* Configure default priorities of all IRQs */
for (i = 1; i <= plic->num_src; i++)
plic_set_priority(plic, i, 0);
plic_set_priority(plic, i, 1);
return 0;
}

View File

@@ -7,7 +7,7 @@
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*/
#ifndef __ASSEMBLY__
#ifndef __ASSEMBLER__
struct fdt_header {
fdt32_t magic; /* magic word FDT_MAGIC */

View File

@@ -13,28 +13,16 @@
extern struct fdt_reset fdt_reset_sifive;
extern struct fdt_reset fdt_reset_htif;
extern struct fdt_reset fdt_reset_thead;
static struct fdt_reset *reset_drivers[] = {
&fdt_reset_sifive,
&fdt_reset_htif,
&fdt_reset_thead,
};
static struct fdt_reset *current_driver = NULL;
int fdt_system_reset_check(u32 reset_type, u32 reset_reason)
{
if (current_driver && current_driver->system_reset_check)
return current_driver->system_reset_check(reset_type,
reset_reason);
return 0;
}
void fdt_system_reset(u32 reset_type, u32 reset_reason)
{
if (current_driver && current_driver->system_reset)
current_driver->system_reset(reset_type, reset_reason);
}
int fdt_reset_init(void)
{
int pos, noff, rc;

View File

@@ -11,6 +11,12 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/sys/htif.h>
static int htif_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
return htif_system_reset_init();
}
static const struct fdt_match htif_reset_match[] = {
{ .compatible = "ucb,htif0" },
{ },
@@ -18,6 +24,5 @@ static const struct fdt_match htif_reset_match[] = {
struct fdt_reset fdt_reset_htif = {
.match_table = htif_reset_match,
.system_reset_check = htif_system_reset_check,
.system_reset = htif_system_reset
.init = htif_reset_init
};

View File

@@ -33,6 +33,4 @@ static const struct fdt_match sifive_test_reset_match[] = {
struct fdt_reset fdt_reset_sifive = {
.match_table = sifive_test_reset_match,
.init = sifive_test_reset_init,
.system_reset_check = sifive_test_system_reset_check,
.system_reset = sifive_test_system_reset
};

View File

@@ -0,0 +1,140 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <libfdt.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_system.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/reset/fdt_reset.h>
#include "fdt_reset_thead.h"
struct custom_csr custom_csr[MAX_CUSTOM_CSR];
#define CSR_OPCODE 0x39073
static void clone_csrs(int cnt)
{
unsigned long i;
for (i = 0; i < cnt; i++) {
/* Write csr BIT[31 - 20] to stub */
__reset_thead_csr_stub[3*i + 1] =
CSR_OPCODE | (custom_csr[i].index << 20);
/* Mask csr BIT[31 - 20] */
*(u32 *)&__fdt_reset_thead_csrr &= BIT(20) - 1;
smp_mb();
/* Write csr BIT[31 - 20] to __fdt_reset_thead_csrr */
*(u32 *)&__fdt_reset_thead_csrr |= custom_csr[i].index << 20;
smp_mb();
RISCV_FENCE_I;
custom_csr[i].value = __fdt_reset_thead_csrr();
}
}
static int thead_system_reset_check(u32 type, u32 reason)
{
return 1;
}
static void thead_system_reset(u32 type, u32 reason)
{
ebreak();
}
static struct sbi_system_reset_device thead_reset = {
.name = "thead_reset",
.system_reset_check = thead_system_reset_check,
.system_reset = thead_system_reset
};
extern void __thead_pre_start_warm(void);
static int thead_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
void *p;
const fdt64_t *val;
const fdt32_t *val_w;
int len, i, cnt;
u32 t, tmp = 0;
/* Prepare clone csrs */
val_w = fdt_getprop(fdt, nodeoff, "csr-copy", &len);
if (len > 0 && val_w) {
cnt = len / sizeof(fdt32_t);
if (cnt > MAX_CUSTOM_CSR)
sbi_hart_hang();
for (i = 0; i < cnt; i++) {
custom_csr[i].index = fdt32_to_cpu(val_w[i]);
}
}
if (cnt)
clone_csrs(cnt);
/* Delegate plic enable regs for S-mode */
val = fdt_getprop(fdt, nodeoff, "plic-delegate", &len);
if (len > 0 && val) {
p = (void *)(ulong)fdt64_to_cpu(*val);
writel(BIT(0), p);
}
/* Old reset method for secondary harts */
if (fdt_getprop(fdt, nodeoff, "using-csr-reset", &len)) {
csr_write(0x7c7, (ulong)&__thead_pre_start_warm);
csr_write(0x7c6, -1);
}
/* Custom reset method for secondary harts */
val = fdt_getprop(fdt, nodeoff, "entry-reg", &len);
if (len > 0 && val) {
p = (void *)(ulong)fdt64_to_cpu(*val);
val_w = fdt_getprop(fdt, nodeoff, "entry-cnt", &len);
if (len > 0 && val_w) {
tmp = fdt32_to_cpu(*val_w);
for (i = 0; i < tmp; i++) {
t = (ulong)&__thead_pre_start_warm;
writel(t, p + (8 * i));
t = (u64)(ulong)&__thead_pre_start_warm >> 32;
writel(t, p + (8 * i) + 4);
}
}
val = fdt_getprop(fdt, nodeoff, "control-reg", &len);
if (len > 0 && val) {
p = (void *)(ulong)fdt64_to_cpu(*val);
val_w = fdt_getprop(fdt, nodeoff, "control-val", &len);
if (len > 0 && val_w) {
tmp = fdt32_to_cpu(*val_w);
tmp |= readl(p);
writel(tmp, p);
}
}
}
sbi_system_reset_set_device(&thead_reset);
return 0;
}
static const struct fdt_match thead_reset_match[] = {
{ .compatible = "thead,reset-sample" },
{ },
};
struct fdt_reset fdt_reset_thead = {
.match_table = thead_reset_match,
.init = thead_reset_init
};

View File

@@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*/
#ifndef __FDT_RESET_THEAD_H__
#define __FDT_RESET_THEAD_H__
#define MAX_CUSTOM_CSR 32
#ifndef __ASSEMBLER__
struct custom_csr {
unsigned long index;
unsigned long value;
};
u64 __fdt_reset_thead_csrr(void);
extern struct custom_csr custom_csr[MAX_CUSTOM_CSR];
extern u32 __reset_thead_csr_stub[];
#endif /* __ASSEMBLER__ */
#endif /* __FDT_RESET_THEAD_H__ */

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <sbi/riscv_asm.h>
#include "fdt_reset_thead.h"
/*
* csrrs rd, csr, rs1
* |31 20|19 15|14 12|11 7|6 0|
* csr rs1 010 rd 1110011
*/
#define CSR_STUB addi x0, x0, 0
.option norvc
.align 3
.global __fdt_reset_thead_csrr
__fdt_reset_thead_csrr:
csrrs a0, 0, x0
ret
.align 3
.global __thead_pre_start_warm
__thead_pre_start_warm:
/*
* Clear L1 cache & BTB & BHT ...
*/
li t1, 0x70013
csrw 0x7c2, t1
fence rw,rw
lla t1, custom_csr
.global __reset_thead_csr_stub
__reset_thead_csr_stub:
.rept MAX_CUSTOM_CSR
REG_L t2, 8(t1)
CSR_STUB
addi t1, t1, 16
.endr
/*
* Clear L1 cache & BTB & BHT ...
*/
li t1, 0x70013
csrw 0x7c2, t1
fence rw,rw
j _start_warm

View File

@@ -10,3 +10,5 @@
libsbiutils-objs-y += reset/fdt_reset.o
libsbiutils-objs-y += reset/fdt_reset_htif.o
libsbiutils-objs-y += reset/fdt_reset_sifive.o
libsbiutils-objs-y += reset/fdt_reset_thead.o
libsbiutils-objs-y += reset/fdt_reset_thead_asm.o

View File

@@ -24,34 +24,13 @@ static struct fdt_serial *serial_drivers[] = {
&fdt_serial_shakti,
};
static void dummy_putc(char ch)
{
}
static int dummy_getc(void)
{
return -1;
}
static struct fdt_serial dummy = {
.match_table = NULL,
.init = NULL,
.putc = dummy_putc,
.getc = dummy_getc,
};
static struct fdt_serial *current_driver = &dummy;
void fdt_serial_putc(char ch)
{
current_driver->putc(ch);
}
int fdt_serial_getc(void)
{
return current_driver->getc();
}
int fdt_serial_init(void)
{
const void *prop;

View File

@@ -16,9 +16,13 @@ static const struct fdt_match serial_htif_match[] = {
{ },
};
static int serial_htif_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
return htif_serial_init();
}
struct fdt_serial fdt_serial_htif = {
.match_table = serial_htif_match,
.init = NULL,
.getc = htif_getc,
.putc = htif_putc
.init = serial_htif_init
};

View File

@@ -29,7 +29,5 @@ static const struct fdt_match serial_shakti_match[] = {
struct fdt_serial fdt_serial_shakti = {
.match_table = serial_shakti_match,
.init = serial_shakti_init,
.getc = shakti_uart_getc,
.putc = shakti_uart_putc
.init = serial_shakti_init
};

View File

@@ -32,7 +32,5 @@ static const struct fdt_match serial_sifive_match[] = {
struct fdt_serial fdt_serial_sifive = {
.match_table = serial_sifive_match,
.init = serial_sifive_init,
.getc = sifive_uart_getc,
.putc = sifive_uart_putc
.init = serial_sifive_init
};

3
lib/utils/serial/fdt_serial_uart8250.c Normal file → Executable file
View File

@@ -26,6 +26,7 @@ static int serial_uart8250_init(void *fdt, int nodeoff,
}
static const struct fdt_match serial_uart8250_match[] = {
{ .compatible = "snps,dw-apb-uart" },
{ .compatible = "ns16550" },
{ .compatible = "ns16550a" },
{ },
@@ -34,6 +35,4 @@ static const struct fdt_match serial_uart8250_match[] = {
struct fdt_serial fdt_serial_uart8250 = {
.match_table = serial_uart8250_match,
.init = serial_uart8250_init,
.getc = uart8250_getc,
.putc = uart8250_putc
};

View File

@@ -23,14 +23,14 @@
static volatile void *uart_base;
void shakti_uart_putc(char ch)
static void shakti_uart_putc(char ch)
{
while((readw(uart_base + REG_STATUS) & UART_TX_FULL))
;
writeb(ch, uart_base + REG_TX);
}
int shakti_uart_getc(void)
static int shakti_uart_getc(void)
{
u16 status = readw(uart_base + REG_STATUS);
if (status & UART_RX_FULL)
@@ -38,11 +38,19 @@ int shakti_uart_getc(void)
return -1;
}
static struct sbi_console_device shakti_console = {
.name = "shakti_uart",
.console_putc = shakti_uart_putc,
.console_getc = shakti_uart_getc
};
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
{
uart_base = (volatile void *)base;
u16 baud = (u16)(in_freq/(16 * baudrate));
writew(baud, uart_base + REG_BAUD);
sbi_console_set_device(&shakti_console);
return 0;
}

View File

@@ -66,7 +66,7 @@ static void set_reg(u32 num, u32 val)
writel(val, uart_base + (num * 0x4));
}
void sifive_uart_putc(char ch)
static void sifive_uart_putc(char ch)
{
while (get_reg(UART_REG_TXFIFO) & UART_TXFIFO_FULL)
;
@@ -74,7 +74,7 @@ void sifive_uart_putc(char ch)
set_reg(UART_REG_TXFIFO, ch);
}
int sifive_uart_getc(void)
static int sifive_uart_getc(void)
{
u32 ret = get_reg(UART_REG_RXFIFO);
if (!(ret & UART_RXFIFO_EMPTY))
@@ -82,6 +82,12 @@ int sifive_uart_getc(void)
return -1;
}
static struct sbi_console_device sifive_console = {
.name = "sifive_uart",
.console_putc = sifive_uart_putc,
.console_getc = sifive_uart_getc
};
int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
{
uart_base = (volatile void *)base;
@@ -98,5 +104,7 @@ int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
/* Enable Rx */
set_reg(UART_REG_RXCTRL, UART_RXCTRL_RXEN);
sbi_console_set_device(&sifive_console);
return 0;
}

View File

@@ -8,6 +8,7 @@
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/serial/uart8250.h>
/* clang-format off */
@@ -68,7 +69,7 @@ static void set_reg(u32 num, u32 val)
writel(val, uart8250_base + offset);
}
void uart8250_putc(char ch)
static void uart8250_putc(char ch)
{
while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0)
;
@@ -76,13 +77,19 @@ void uart8250_putc(char ch)
set_reg(UART_THR_OFFSET, ch);
}
int uart8250_getc(void)
static int uart8250_getc(void)
{
if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
return get_reg(UART_RBR_OFFSET);
return -1;
}
static struct sbi_console_device uart8250_console = {
.name = "uart8250",
.console_putc = uart8250_putc,
.console_getc = uart8250_getc
};
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width)
{
@@ -94,7 +101,7 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
uart8250_in_freq = in_freq;
uart8250_baudrate = baudrate;
bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) / (16 * uart8250_baudrate);
/* Disable all interrupts */
set_reg(UART_IER_OFFSET, 0x00);
@@ -121,5 +128,7 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
/* Set scratchpad */
set_reg(UART_SCR_OFFSET, 0x00);
sbi_console_set_device(&uart8250_console);
return 0;
}

View File

@@ -10,17 +10,25 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_timer.h>
#include <sbi_utils/sys/clint.h>
#define CLINT_IPI_OFF 0
#define CLINT_IPI_SIZE 0x4000
#define CLINT_TIME_CMP_OFF 0x4000
#define CLINT_TIME_CMP_SIZE 0x4000
#define CLINT_TIME_VAL_OFF 0xbff8
#define CLINT_TIME_VAL_SIZE 0x4000
static struct clint_data *clint_ipi_hartid2data[SBI_HARTMASK_MAX_BITS];
void clint_ipi_send(u32 target_hart)
static void clint_ipi_send(u32 target_hart)
{
struct clint_data *clint;
@@ -34,7 +42,7 @@ void clint_ipi_send(u32 target_hart)
writel(1, &clint->ipi[target_hart - clint->first_hartid]);
}
void clint_ipi_clear(u32 target_hart)
static void clint_ipi_clear(u32 target_hart)
{
struct clint_data *clint;
@@ -48,6 +56,12 @@ void clint_ipi_clear(u32 target_hart)
writel(0, &clint->ipi[target_hart - clint->first_hartid]);
}
static struct sbi_ipi_device clint_ipi = {
.name = "clint",
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear
};
int clint_warm_ipi_init(void)
{
/* Clear CLINT IPI for current HART */
@@ -59,6 +73,8 @@ int clint_warm_ipi_init(void)
int clint_cold_ipi_init(struct clint_data *clint)
{
u32 i;
int rc;
struct sbi_domain_memregion reg;
if (!clint)
return SBI_EINVAL;
@@ -70,6 +86,16 @@ int clint_cold_ipi_init(struct clint_data *clint)
for (i = 0; i < clint->hart_count; i++)
clint_ipi_hartid2data[clint->first_hartid + i] = clint;
/* Add CLINT ipi region to the root domain */
sbi_domain_memregion_init(clint->addr + CLINT_IPI_OFF,
CLINT_IPI_SIZE,
SBI_DOMAIN_MEMREGION_MMIO, &reg);
rc = sbi_domain_root_add_memregion(&reg);
if (rc)
return rc;
sbi_ipi_set_device(&clint_ipi);
return 0;
}
@@ -107,7 +133,7 @@ static void clint_time_wr32(u64 value, volatile u64 *addr)
writel_relaxed(value >> 32, (void *)(addr) + 0x04);
}
u64 clint_timer_value(void)
static u64 clint_timer_value(void)
{
struct clint_data *clint = clint_timer_hartid2data[current_hartid()];
@@ -115,7 +141,7 @@ u64 clint_timer_value(void)
return clint->time_rd(clint->time_val) + clint->time_delta;
}
void clint_timer_event_stop(void)
static void clint_timer_event_stop(void)
{
u32 target_hart = current_hartid();
struct clint_data *clint = clint_timer_hartid2data[target_hart];
@@ -125,7 +151,7 @@ void clint_timer_event_stop(void)
&clint->time_cmp[target_hart - clint->first_hartid]);
}
void clint_timer_event_start(u64 next_event)
static void clint_timer_event_start(u64 next_event)
{
u32 target_hart = current_hartid();
struct clint_data *clint = clint_timer_hartid2data[target_hart];
@@ -135,6 +161,13 @@ void clint_timer_event_start(u64 next_event)
&clint->time_cmp[target_hart - clint->first_hartid]);
}
static struct sbi_timer_device clint_timer = {
.name = "clint",
.timer_value = clint_timer_value,
.timer_event_start = clint_timer_event_start,
.timer_event_stop = clint_timer_event_stop
};
int clint_warm_timer_init(void)
{
u64 v1, v2, mv;
@@ -174,6 +207,8 @@ int clint_cold_timer_init(struct clint_data *clint,
struct clint_data *reference)
{
u32 i;
int rc;
struct sbi_domain_memregion reg;
if (!clint)
return SBI_EINVAL;
@@ -199,5 +234,23 @@ int clint_cold_timer_init(struct clint_data *clint,
for (i = 0; i < clint->hart_count; i++)
clint_timer_hartid2data[clint->first_hartid + i] = clint;
/* Add CLINT mtime region to the root domain */
sbi_domain_memregion_init(clint->addr + CLINT_TIME_VAL_OFF,
CLINT_TIME_VAL_SIZE,
SBI_DOMAIN_MEMREGION_MMIO, &reg);
rc = sbi_domain_root_add_memregion(&reg);
if (rc)
return rc;
/* Add CLINT timecmp region to the root domain */
sbi_domain_memregion_init(clint->addr + CLINT_TIME_CMP_OFF,
CLINT_TIME_CMP_SIZE,
SBI_DOMAIN_MEMREGION_MMIO, &reg);
rc = sbi_domain_root_add_memregion(&reg);
if (rc)
return rc;
sbi_timer_set_device(&clint_timer);
return 0;
}

View File

@@ -6,6 +6,8 @@
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_system.h>
#include <sbi_utils/sys/htif.h>
#define HTIF_DATA_BITS 48
@@ -98,7 +100,7 @@ static void do_tohost_fromhost(uint64_t dev, uint64_t cmd, uint64_t data)
spin_unlock(&htif_lock);
}
void htif_putc(char ch)
static void htif_putc(char ch)
{
/* HTIF devices are not supported on RV32, so do a proxy write call */
volatile uint64_t magic_mem[8];
@@ -109,7 +111,7 @@ void htif_putc(char ch)
do_tohost_fromhost(HTIF_DEV_SYSTEM, 0, (uint64_t)(uintptr_t)magic_mem);
}
#else
void htif_putc(char ch)
static void htif_putc(char ch)
{
spin_lock(&htif_lock);
__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
@@ -117,7 +119,7 @@ void htif_putc(char ch)
}
#endif
int htif_getc(void)
static int htif_getc(void)
{
int ch;
@@ -140,15 +142,41 @@ int htif_getc(void)
return ch - 1;
}
int htif_system_reset_check(u32 type, u32 reason)
static struct sbi_console_device htif_console = {
.name = "htif",
.console_putc = htif_putc,
.console_getc = htif_getc
};
int htif_serial_init(void)
{
sbi_console_set_device(&htif_console);
return 0;
}
static int htif_system_reset_check(u32 type, u32 reason)
{
return 1;
}
void htif_system_reset(u32 type, u32 reason)
static void htif_system_reset(u32 type, u32 reason)
{
while (1) {
fromhost = 0;
tohost = 1;
}
}
static struct sbi_system_reset_device htif_reset = {
.name = "htif",
.system_reset_check = htif_system_reset_check,
.system_reset = htif_system_reset
};
int htif_system_reset_init(void)
{
sbi_system_reset_set_device(&htif_reset);
return 0;
}

View File

@@ -9,6 +9,7 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_system.h>
#include <sbi_utils/sys/sifive_test.h>
#define FINISHER_FAIL 0x3333
@@ -17,7 +18,7 @@
static void *sifive_test_base;
int sifive_test_system_reset_check(u32 type, u32 reason)
static int sifive_test_system_reset_check(u32 type, u32 reason)
{
switch (type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
@@ -29,7 +30,7 @@ int sifive_test_system_reset_check(u32 type, u32 reason)
return 0;
}
void sifive_test_system_reset(u32 type, u32 reason)
static void sifive_test_system_reset(u32 type, u32 reason)
{
/*
* Tell the "finisher" that the simulation
@@ -49,9 +50,16 @@ void sifive_test_system_reset(u32 type, u32 reason)
}
}
static struct sbi_system_reset_device sifive_test_reset = {
.name = "sifive_test",
.system_reset_check = sifive_test_system_reset_check,
.system_reset = sifive_test_system_reset
};
int sifive_test_init(unsigned long base)
{
sifive_test_base = (void *)base;
sbi_system_reset_set_device(&sifive_test_reset);
return 0;
}

View File

@@ -17,46 +17,15 @@ static struct fdt_timer *timer_drivers[] = {
&fdt_timer_clint
};
static u64 dummy_value(void)
{
return 0;
}
static void dummy_event_stop(void)
{
}
static void dummy_event_start(u64 next_event)
{
}
static struct fdt_timer dummy = {
.match_table = NULL,
.cold_init = NULL,
.warm_init = NULL,
.exit = NULL,
.value = dummy_value,
.event_stop = dummy_event_stop,
.event_start = dummy_event_start
};
static struct fdt_timer *current_driver = &dummy;
u64 fdt_timer_value(void)
{
return current_driver->value();
}
void fdt_timer_event_stop(void)
{
current_driver->event_stop();
}
void fdt_timer_event_start(u64 next_event)
{
current_driver->event_start(next_event);
}
void fdt_timer_exit(void)
{
if (current_driver->exit)

View File

@@ -15,7 +15,9 @@
#define CLINT_TIMER_MAX_NR 16
static unsigned long clint_timer_count = 0;
static struct clint_data clint_timer[CLINT_TIMER_MAX_NR];
static struct clint_data clint_timer[CLINT_TIMER_MAX_NR] = {
{.addr = 0x74000000, .first_hartid = 0, .hart_count = 1, .has_64bit_mmio = 0, },
};
static int timer_clint_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
@@ -29,15 +31,18 @@ static int timer_clint_cold_init(void *fdt, int nodeoff,
if (1 < clint_timer_count)
ctmaster = &clint_timer[0];
rc = fdt_parse_clint_node(fdt, nodeoff, TRUE, ct);
if (rc)
return rc;
if (clint_timer_count != 1) {
rc = fdt_parse_clint_node(fdt, nodeoff, TRUE, ct);
if (rc)
return rc;
}
return clint_cold_timer_init(ct, ctmaster);
}
static const struct fdt_match timer_clint_match[] = {
{ .compatible = "riscv,clint0" },
{ .compatible = "sifive,clint0" },
{ },
};
@@ -46,7 +51,4 @@ struct fdt_timer fdt_timer_clint = {
.cold_init = timer_clint_cold_init,
.warm_init = clint_warm_timer_init,
.exit = NULL,
.value = clint_timer_value,
.event_stop = clint_timer_event_stop,
.event_start = clint_timer_event_start,
};

View File

@@ -12,6 +12,7 @@
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_trap.h>
#include <sbi_utils/fdt/fdt_fixup.h>
@@ -85,6 +86,12 @@ static int ae350_irqchip_init(bool cold_boot)
return plic_warm_irqchip_init(&plic, 2 * hartid, 2 * hartid + 1);
}
static struct sbi_ipi_device plicsw_ipi = {
.name = "ae350_plicsw",
.ipi_send = plicsw_ipi_send,
.ipi_clear = plicsw_ipi_clear
};
/* Initialize IPI for current HART. */
static int ae350_ipi_init(bool cold_boot)
{
@@ -95,6 +102,8 @@ static int ae350_ipi_init(bool cold_boot)
AE350_HART_COUNT);
if (ret)
return ret;
sbi_ipi_set_device(&plicsw_ipi);
}
return plicsw_warm_ipi_init();
@@ -164,19 +173,12 @@ const struct sbi_platform_operations platform_ops = {
.final_init = ae350_final_init,
.console_init = ae350_console_init,
.console_putc = uart8250_putc,
.console_getc = uart8250_getc,
.irqchip_init = ae350_irqchip_init,
.ipi_init = ae350_ipi_init,
.ipi_send = plicsw_ipi_send,
.ipi_clear = plicsw_ipi_clear,
.timer_init = ae350_timer_init,
.timer_value = plmt_timer_value,
.timer_event_start = plmt_timer_event_start,
.timer_event_stop = plmt_timer_event_stop,
.vendor_ext_provider = ae350_vendor_ext_provider
};

View File

@@ -10,13 +10,14 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_timer.h>
static u32 plmt_time_hart_count;
static volatile void *plmt_time_base;
static volatile u64 *plmt_time_val;
static volatile u64 *plmt_time_cmp;
u64 plmt_timer_value(void)
static u64 plmt_timer_value(void)
{
#if __riscv_xlen == 64
return readq_relaxed(plmt_time_val);
@@ -32,7 +33,7 @@ u64 plmt_timer_value(void)
#endif
}
void plmt_timer_event_stop(void)
static void plmt_timer_event_stop(void)
{
u32 target_hart = current_hartid();
@@ -48,7 +49,7 @@ void plmt_timer_event_stop(void)
#endif
}
void plmt_timer_event_start(u64 next_event)
static void plmt_timer_event_start(u64 next_event)
{
u32 target_hart = current_hartid();
@@ -68,6 +69,13 @@ void plmt_timer_event_start(u64 next_event)
}
static struct sbi_timer_device plmt_timer = {
.name = "ae350_plmt",
.timer_value = plmt_timer_value,
.timer_event_start = plmt_timer_event_start,
.timer_event_stop = plmt_timer_event_stop
};
int plmt_warm_timer_init(void)
{
u32 target_hart = current_hartid();
@@ -93,5 +101,7 @@ int plmt_cold_timer_init(unsigned long base, u32 hart_count)
plmt_time_val = (u64 *)(plmt_time_base);
plmt_time_cmp = (u64 *)(plmt_time_base + 0x8);
sbi_timer_set_device(&plmt_timer);
return 0;
}

View File

@@ -10,12 +10,6 @@
#ifndef _AE350_PLMT_H_
#define _AE350_PLMT_H_
u64 plmt_timer_value(void);
void plmt_timer_event_stop(void);
void plmt_timer_event_start(u64 next_event);
int plmt_warm_timer_init(void);
int plmt_cold_timer_init(unsigned long base, u32 hart_count);

View File

@@ -154,16 +154,9 @@ const struct sbi_platform_operations platform_ops = {
.early_init = ariane_early_init,
.final_init = ariane_final_init,
.console_init = ariane_console_init,
.console_putc = uart8250_putc,
.console_getc = uart8250_getc,
.irqchip_init = ariane_irqchip_init,
.ipi_init = ariane_ipi_init,
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.timer_init = ariane_timer_init,
.timer_value = clint_timer_value,
.timer_event_start = clint_timer_event_start,
.timer_event_stop = clint_timer_event_stop,
};
const struct sbi_platform platform = {

View File

@@ -180,16 +180,9 @@ const struct sbi_platform_operations platform_ops = {
.early_init = openpiton_early_init,
.final_init = openpiton_final_init,
.console_init = openpiton_console_init,
.console_putc = uart8250_putc,
.console_getc = uart8250_getc,
.irqchip_init = openpiton_irqchip_init,
.ipi_init = openpiton_ipi_init,
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.timer_init = openpiton_timer_init,
.timer_value = clint_timer_value,
.timer_event_start = clint_timer_event_start,
.timer_event_stop = clint_timer_event_stop,
};
const struct sbi_platform platform = {

View File

@@ -28,7 +28,8 @@ else
# This needs to be 2MB aligned for 64-bit system
FW_JUMP_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x200000)))
endif
FW_JUMP_FDT_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x2200000)))
#set FDT_ADDR 0xB0000000
FW_JUMP_FDT_ADDR=$(shell printf "0x%X" $$(($(FW_TEXT_START) + 0x30000000)))
FW_PAYLOAD=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
# This needs to be 4MB aligned for 32-bit system

View File

@@ -0,0 +1,111 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <platform_override.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_fixup.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_types.h>
#include <sbi/sbi_error.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
__asm__(".section .rodata\n"
".global suspend_sram_entry\n"
".global suspend_sram_end\n"
".type suspend_sram_entry, @object\n"
".type suspend_sram_end, @object\n"
".align 4\n"
"suspend_sram_entry:\n"
".incbin \"" STRINGIFY(PM_SRAM_BIN_PATH) "\"\n"
".align 4\n"
"suspend_sram_end:\n"
".text\n");
#define RTC_SRAM_FLAG_ADDR 0x05026ff8
#ifdef CONFIG_CV180X
#define SUSPEND_SRAM_ENTRY 0x3C000000
#endif
#ifdef CONFIG_CV181X
#define SUSPEND_SRAM_ENTRY 0xC030000
#endif
#define SUSPEND_SRAM_ENTRY 0xC030000
#define memcpy sbi_memcpy
static void rtc_latch_pinmux_settings(void)
{
writel(0x2, (void *)0x50250ac);
writel(0x0, (void *)0x5027084);
//TODO
}
static void rtc_power_saving_settings_for_suspend(void)
{
//TODO
}
static int cvitek_sbi_system_suspend_check(u32 sleep_type)
{
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? 0 : SBI_EINVAL;
}
static int cvitek_sbi_system_suspend(u32 sleep_type,
unsigned long mmode_resume_addr)
{
void (*suspend)(void) = (void *)SUSPEND_SRAM_ENTRY;
if (sleep_type != SBI_SUSP_SLEEP_TYPE_SUSPEND)
return SBI_EINVAL;
rtc_latch_pinmux_settings();
rtc_power_saving_settings_for_suspend();
/* store warmboot entry for resume*/
writel(mmode_resume_addr, (void *)RTC_SRAM_FLAG_ADDR);
writel(readl((void *)0x03002000) | 0x10, (void *)0x03002000); //enable TPU clock
memcpy((void *)SUSPEND_SRAM_ENTRY, suspend_sram_entry, suspend_sram_end - suspend_sram_entry);
asm volatile("fence.i" ::: "memory");
asm volatile("fence rw,rw\n\t");
suspend();
wfi();
return SBI_OK;
}
static struct sbi_system_suspend_device cvitek_sbi_suspend_device = {
.name = "cvi-suspend",
.system_suspend_check = cvitek_sbi_system_suspend_check,
.system_suspend = cvitek_sbi_system_suspend,
};
static int cvitek_riscv_early_init(bool cold_boot, const struct fdt_match *match)
{
sbi_system_suspend_set_device(&cvitek_sbi_suspend_device);
return 0;
}
static const struct fdt_match cvitek_riscv_match[] = {
{ .compatible = "cvitek,cv180x" },
{ .compatible = "cvitek,cv181x" },
{ .compatible = "cvitek,sg200x" }
};
const struct platform_override cvitek_riscv = {
.match_table = cvitek_riscv_match,
.early_init = cvitek_riscv_early_init,
};

Some files were not shown because too many files have changed in this diff Show More