51 Commits
v0.4 ... v0.5

Author SHA1 Message Date
Anup Patel
be92da280d include: Bump-up version to 0.5
This patch updates OpenSBI version to 0.5 as part of
release preparation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-10-09 11:33:53 +05:30
Atish Patra
30f09fbfd1 lib: Provide a platform hook to implement vendor specific SBI extensions.
SBI v0.2 specification allows vendor extensions and it should be
implemented in a independent of the core sbi library.

Introduce a single platform callback that will let platforms handle
all vendor extensions in platform specific code if they want.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:58:51 +05:30
Atish Patra
0790be0f2c lib: Implement SBI v0.2
SBI v0.2 introduces a base specification which is mandatory to
implement for any SBI implementations that is not legacy.

Add support for the base extension.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:56:55 +05:30
Atish Patra
848ed4f644 lib: Remove redundant variable assignment
An ecall handler should only return error if valid SBI function
fails. Otherwise, it should succeed with appropriate error in a0.

Get rid of unnecessary setting of the temporary return variable to
zero for the cases where errors are not expected.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:55:25 +05:30
Atish Patra
26aec6afed lib: Rename existing SBI implementation as 0.1.
Current SBI implementation is now considered as version 0.1 and will be
removed/replaced with newer extension/functions in future.

Rename the existing implementations accordingly to be in sync with the
specification.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Zong Li <zong.li@sifive.com>
2019-10-03 08:53:52 +05:30
Atish Patra
3d335bc54b lib: Align error codes as per SBI specification.
Follow the SBI specification for error codes.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:52:54 +05:30
Atish Patra
8925e3865c Test: Move test payload related code out of interface header
Test payload uses an SBI call and uses the macros defined in interface
header which is not the correct place to have these definitions.
The interface header file should be used to keep SBI specification
related macros.

Keep all the test payload related code in test itself.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-10-03 08:51:39 +05:30
Anup Patel
e561c63036 lib: Fix coldboot race condition observed on emulators/simulators
If we are running on RISC-V emulator/simulator with large number of
HARTs where each HART is a regular thread under UNIX host then it is
possible that some of the secondary HARTs don't get chance to run and
sbi_hart_wake_coldboot_harts() is called before secondary HARTs call
sbi_hart_wait_for_coldboot(). In this situation, some of the secondary
HARTs will never come-out of coldboot wait loop.

To tackle this, we introduce a global flag coldboot_done which will
be protected by coldboot lock and it will be set by primary HART from
sbi_hart_wake_coldboot_harts() before waking-up secondary HARTs. We
also re-arrange acquire/release of coldboot lock to reduce further
chances of race-condition.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Nylon Chen<nylon7@andestech.com>
2019-10-02 17:03:58 +05:30
Anup Patel
2c7bab76a2 Makefile: Minor fix in OPENSBI_VERSION_GIT
Currently, if someone has forked OpenSBI repo quite sometime back
and this fork is not having updated tags from upstream riscv/opensbi
repo then "git describe" command can fail. To tackle this, we redirect
error output of "git describe" to /dev/null.

Signed-off-by: Anup Patel <anup.pate@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-10-02 17:03:54 +05:30
Anup Patel
1e9f88889f lib: Emulate HTIMEDELTA CSR for platforms not having TIME CSR
For platforms not having TIME CSR, we trap-n-emulate TIME CSR
read/write in OpenSBI. Same rationale applies to HTIMEDELTA CSR
as well so we trap-n-emulate HTIMEDELTA CSR for platforms not
having TIME CSR.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-09-30 15:36:14 +05:30
Anup Patel
7d4420bd69 include: Extend get_insn() to read instruction from VS/VU mode
Current implementation of get_insn() is not suitable for reading
instruction from VS/VU mode because we have to set SSTATUS_MXR bit
in VSSTATUS CSR for reading instruction from VS/VU mode.

This patch extends get_insn() to read instruction from VS/VU mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-09-30 15:35:43 +05:30
Anup Patel
a14e7ee82c lib: Redirect WFI trapped from VS/VU mode to HS-mode
The WFI will trap as illegal instruction trap when executed
in VS/VU mode so we just forward/redirect it to HS-mode so
that hypervisor can deal with it appropriately.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-09-30 15:32:00 +05:30
Anup Patel
bbeb8e619d lib: Extend sbi_trap_redirect() for hypervisor extension
When hypervisor extension is available, we can get traps from VS/VU
modes. We should be able to force redirect some of these traps to
HS-mode. In other words, we should be able forward traps from VS/VU
mode to HS-mode using sbi_trap_redirect() hence this patch.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2019-09-30 15:29:37 +05:30
Anup Patel
1a5614e971 lib: Extend sbi_hart_switch_mode() to support hypervisor extension
This patch extends sbi_hart_switch_mode() to support entering
VS/VU modes when hypervisor extension is available.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-09-30 15:18:06 +05:30
Anup Patel
0089897d41 lib: Delegate supervisor ecall to HS-mode when H extension available
When hypervisor extension is available, we only handle hypervisor
ecalls coming from HS-mode and we let hypervisor handle ecalls coming
from VS-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-09-30 15:14:00 +05:30
Zong Li
1ed9eb255d Write MSIP by using memory-mapped control register
The machine-level MSIP bits are written by accesses to memory-mapped
control registers. Only use CSR instruction for SSIP and USIP.

There is no effect that using CSR instruction to write MSIP when testing
on unleashed board and QEMU.

Signed-off-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-28 18:23:13 +05:30
Atish Patra
0a482e2edb lib: Fix tlb flush range limit value
Use platform defined flush range limit value only if it is non-zero.
Otherwise, use the default value.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-09-28 18:21:34 +05:30
Damien Le Moal
190e3f4bd9 kendryte/k210: remove unused file
Commit 9dfe720579 ("kendryte/k210: remove sysctl code") missed
removing the file sysctl.c. Fix this here.

Fixes: 9dfe720579 ("kendryte/k210: remove sysctl code")
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-09-28 18:15:18 +05:30
Bin Meng
8853758268 docs: platform: Update descriptions for qemu/sifive_u support
With QEMU v4.2 release that has improved the emulation fidelity
of 'sifive_u' machine, OpenSBI v0.4 / U-Boot v2019.10-rc1 / Linux
kernel v5.3-rc2 images built for the SiFive HiFive Unleashed board
can be used out of the box without any special hack.

Update our documents to mention 'qemu/sifive_u' platform should
only be used with QEMU v4.1 or before, and it will be dropped
sometime in the future release.

Going forward, 'sifive/fu540' platform can be used on both real
hardware and QEMU v4.2+ 'sifive_u' machine.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-25 10:34:54 +05:30
Atish Patra
98ee15ca3a lib: provide a platform specific tlb range flush threshold
Currently, the tlb range flush threshold is fixed and set to 4k for
all platforms. However, it should be platform specific as it completely
depends upon how platform actually implements sfence instruction.

Define a platform feature that allows every individual platform to set
different values. If a platform doesn't define it, just use a page size as
the threshold.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-10 17:44:10 +05:30
Atish Patra
f2e82c3d79 lib: Change tlb range flush threshold to 4k page instead of 1G
In RISC-V, tlb flush happens at a page granularity. That's why OpenSBI
also have a tlb range flush limit which decides the which tlb flush
requests should be upgraded to full flush to avoid long delays.
Currently, this is set to 1G which would result in a many sfence.vma
execution in a tight loop for a large range.

Change the threshold to 4k to speed things up.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-10 17:44:07 +05:30
Damien Le Moal
144acef684 README: Update license information
With the Kendryte K210 platform code cleanup, none of the code copied
from Kendryte standalone SDK remains and this platform code is now
entirely licensed under OpenSBI BSD-2-clause license. Update the
README.md and ThirdPartyNotices.md files to reflect this.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-05 18:52:32 +05:30
Damien Le Moal
9dfe720579 kendryte/k210: remove sysctl code
Directly implement frequency discovery, making the sysctl code
unnecessary. While at it, Move all macro definitions from platform.c
into platform.h and cleanup that file, removing the need for the
Apache 2.0 license and Canaan Inc copyright.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-05 18:50:37 +05:30
Damien Le Moal
fca8c3be01 kendryte/k210: Use sifive UART driver
The Kendryte K210 UARTHS is compatible with SiFive UART. So use the
sifive uart driver and remove the k210 uarths platform code.

Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-09-05 18:47:56 +05:30
Atish Patra
6ed2bc154f docs: Update the fu540 platform guide as per U-Boot documents.
U-Boot readme for fu540 platform suggest that fdt_addr_r should be used
as DT address after DT is copied via tftpboot.

Update the OpenSBI docs to reflect that. Remove other stale informations
as well.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:16:44 +05:30
Atish Patra
7b7690ed9c lib: Upgrade to full flush if size is at least threshold
Currently, we upgrade to a full tlb flush only If a tlb flush request
size is greater than the threshold. This is done as sfence in RISC-V
can only flush 4KB at a time. Doing a large number of flushes page by
page impacts the performance. It is better to do a full tlbflush if the
request size is at least equal to the threshold size.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:15:21 +05:30
Atish Patra
6bd1512024 lib: Support atomic swap instructions
If compiler supports riscv atomic instructions, we should
use them instead of legacy gcc built-in macros
__sync_lock_test_and_set in atomic exchange functions.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:13:47 +05:30
Atish Patra
2e5cc9051b lib: Fix timer for 32 bit
To read 64bit time in 32 bit we have to read lower & upper half
separately and 'or' them together. However, upper half time may
have changed by the time we read lower half. Thus, the resultant
64 bit time may not be accurate.

Consider lower half time value only if upper half time value has
not changed.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:13:12 +05:30
Nylon Chen
ffa6c5f457 scripts: Add AE350 to platform list in the binary archive script
This patch adds Andes AE350 to RV64 platform list in the binary
archive script.

Signed-off-by: Nylon Chen <nylon7@andestech.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-31 13:10:06 +05:30
Nylon Chen
3cbb419def platform: Add Andes AE350 initial support
This commit provides basic support for the AE350 platform.

Signed-off-by: Zong Li <zongbox@gmail.com>
Signed-off-by: Nylon Chen <nylon7@andestech.com>
2019-08-23 16:25:56 +05:30
Palmer Dabbelt
a2a7763ac7 Include git describe in OpenSBI
OpenSBI includes a version, but that is only updated when tagged.  For
users that are using the git releases we instead end up with an
ambiguous version number, which makes it hard to figure out what
everyone is using.  This patch checks for a git directory and prints out
the result of `git describe`, which is a mix of pretty and unambiguous.

Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
2019-08-19 10:58:21 +05:30
Atish Patra
75229705a0 platform: Remove the ipi_sync method from all platforms.
OpenSBI manages outstanding TLB flush requests by queueing
them in a fifo synchronously. An ipi sync which uses an
atomic operation on MMIO address is no longer required.

Remove the ipi sync method from platform header and all usage.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-16 08:42:58 +05:30
Atish Patra
897a97a6af lib: Fix race conditions in tlb fifo access.
Linux kernel expects tlb flush SBI call to be completely synchronous i.e.
the SBI call should only return once corresponding *fence* instruction is
executed.

OpenSBI manages the outstanding TLB flush requests by keeping them in a
per hart based fifo. However, there are few corner cases that may lead to
race conditions while updating the fifo.

Currently, the caller hart waits for IPI acknowledgement via clint
address which is not a very good method as synchronization on MMIO may not
be supported in every platform. Moreover, the waiter doesn't have any way of
identifying if the IPI is received for specific tlb flush request or any
other IPI. This may lead to unpredictable behavior in supervisor/user space.

Fix this by waiting on individual fifo entries rather than MMIO address.
Currently, a relaxed loop is being used because wfi again involves MMIO write
which would be slower compared to relaxed loop. To avoid deadlock, fifo
is processed every time a hart loops for fifo enqueue or fifo sync to consume
the tlb flush requests sent by other harts.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-08-16 08:42:55 +05:30
Atish Patra
f6e13e0dd3 lib: Provide an atomic exchange function unsigned long
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
2019-08-16 08:42:52 +05:30
Anup Patel
a88e424f6c lib: Handle traps when doing unpriv load/store in get_insn()
We can get a page/access trap when doing unpriv load/store in
get_insn() function because on a SMP system Linux swapper running
on HART A can unmap pages from page table used by HART B.

To tackle this we extend get_insn() implementation so that if
we get trap in get_insn() then we redirect it to S-mode as fetch
page/access fault.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
2019-08-13 09:48:40 +05:30
Lukas Auer
2e0f3ac758 firmware: do not use relocated _boot_status before it is valid
When OpenSBI is started from an address not equal to the link address,
it is first relocated to the link address. Hart 0 performs the
relocation and notifies the other harts of its completion with the
_boot_status variable. It uses the copy of the variable relative to the
link address. This copy contains valid data only after relocation has
finished. The waiting harts will therefore read invalid data until
relocation has finished. This can cause them to continue execution too
early.

Fix this by using the _boot_status variable relative to the load address
while OpenSBI has not finished relocation.

Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-13 09:07:16 +05:30
Jacob Garber
6c24193293 lib: Correct null pointer check
In order to prevent a possible null pointer dereference, return early if
either one of 'in' or 'data' is null.

Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-08-12 09:27:47 +05:30
Jacob Garber
5e4021a2f5 lib: Prevent unintended sign extensions
In the last argument to sbi_memset() we essentially have the following
multiplication:

    size_t = u16 * u16

Due to C's integer semantics, both u16's are implicitly converted to int
before the multiplication, which cannot hold all possible values of a
u16 * u16. If the multiplication overflows, the intermediate result will
be a negative number. On 64-bit platforms, this will be sign-extended to
a huge integer in the conversion to a u64 (aka size_t). Being the size
argument to sbi_memset(), this could potentially cause a large
out-of-bounds write. The solution is to manually cast one of the u16 to
a size_t, which will make it large enough to avoid the implicit
conversion and any overflow.

Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-08-12 09:26:38 +05:30
Jacob Garber
6ddf71e6e9 lib: Use correct type for return value
The error check 'plic_off < 0' does nothing, since plic_off is stored as
a u32. Fix this by changing it to an int, which matches the return type of
fdt_node_offset_by_compatible().

Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-08-12 09:23:28 +05:30
Jacob Garber
3f738f5897 lib: Use bitwise & instead of boolean &&
!(mipval && MIP_MSIP) simplifies to !mipval, which checks if the entire
variable is zero, not just a single bit. Fix this to use bitwise &
instead.

Signed-off-by: Jacob Garber <jgarber1@ualberta.ca>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
2019-08-12 09:22:20 +05:30
Anup Patel
88c87f0af4 lib: Use sbi_dprintf() for invalid CSRs
We should sbi_dprintf() instead of sbi_printf() for invalid CSRs
because we are forwarding invalid CSR access back to S-mode.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-08-09 12:38:36 +05:30
Anup Patel
dbff3e9f12 lib: Introduce sbi_dprintf() API
This patch introduces new sbi_dprintf() API for runtime debug
prints. The sbi_dprintf() will print to console for a given
HART only when SBI_SCRATCH_DEBUG_PRINTS option in enabled in
sbi_scratch for this HART.

We can now add debug prints using sbi_dprintf() at important
places in OpenSBI sources. These debug prints will only show
up when previous booting stage or compile time parameter sets
the SBI_SCRATCH_DEBUG_PRINTS option in scratch space.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-08-09 12:38:33 +05:30
Bin Meng
b1318e578b firmware: Use macro instead of magic number for boot status
The boot status is currently hard-coded. Define some macros for it.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-09 12:30:08 +05:30
Bin Meng
446b6f30a4 platform: sifive: fu540: Expand FDT size before any patching
We should expand the FDT size before any patching, otherwise it's
possible the "status" fix up might fail due to insufficient space.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
2019-08-09 12:30:06 +05:30
Nylon Chen
c1b9dd3ab5 firmware: Fix the loop condition of _wait_relocate_copy_done section
If core-0 have finished _fdt_reloc_done but any of other cores has not
yet left the loop in _wait_relocate_copy_done, they could never leave
the loop because _boot_status is not equal to 1.
2019-08-07 18:04:53 +05:30
Anup Patel
0f18b3fe0a lib: Allow compiling without FP support
Currently, we mandate 'F' and 'D' extension in riscv_fp.h so that
misaligned load/store emulation has access to FP registers.

The above is too restrictive and we should certainly allow compilation
for soft-FP toolchains and explicit PLATFORM_RISCV_ISA not having 'F'
and 'D' extensions.

This patch extends riscv_fp.h and misaligned load/store emulation to
allow compiling OpenSBI without FP support.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2019-07-26 15:49:49 +05:30
Bin Meng
85546a5477 treewide: Use conventional names for 32-bit and 64-bit
There are several places in the source tree that have:

  32bit, 32 bit, 64bit, 64 bit

Fix by using the conventional names with a hyphen.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-25 09:14:58 +05:30
Bin Meng
c90009aa20 README: Document 32-bit / 64-bit images build
At present the exact details of building 32-bit or 64-bit OpenSBI
images are missing in the docs. This adds the missing part.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-25 09:11:49 +05:30
Georg Kotheimer
bf2ee7bcdc utils: Use cpu_to_fdt32() when writing to fdt
Although it does not make a functional difference, both cpu_to_fdt32()
and fdt32_to_cpu() pass on to CPU_TO_FDT32, we should use cpu_to_fdt32()
to be semantically correct.

Signed-off-by: Georg Kotheimer <georg.kotheimer@kernkonzept.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-25 08:59:50 +05:30
Anup Patel
e3f743339a platform: sifive/fu540: Move FDT further up
This patch changes FW_xyz_FDT_ADDR to RAM_START+128MB (i.e. 0x88000000)
so that next stage bootloader (i.e. U-Boot) has enough space to unpack
bigger kernel images.

Reported-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
Tested-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
2019-07-24 09:24:28 +05:30
Bin Meng
e7456399e4 platform: sifive: fu540: Use standard value string for cpu node status
Per device tree spec, the standard value string for the "status"
property of a cpu node is either "okay" or "disabled". "masked"
was once used but it is unfortunately a spec violation.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Anup Patel <anup.patel@wdc.com>
2019-07-22 11:14:05 +05:30
64 changed files with 2007 additions and 1985 deletions

View File

@@ -65,6 +65,7 @@ export firmware_dir=$(CURDIR)/firmware
# Find library version
OPENSBI_VERSION_MAJOR=`grep "define OPENSBI_VERSION_MAJOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MAJOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_MINOR=`grep "define OPENSBI_VERSION_MINOR" $(include_dir)/sbi/sbi_version.h | sed 's/.*MINOR.*\([0-9][0-9]*\)/\1/'`
OPENSBI_VERSION_GIT=$(shell if [ -d $(src_dir)/.git ]; then git describe 2> /dev/null; fi)
# Setup compilation commands
ifdef CROSS_COMPILE
@@ -151,6 +152,9 @@ endif
# Setup compilation commands flags
GENFLAGS = -I$(platform_src_dir)/include
GENFLAGS += -I$(include_dir)
ifneq ($(OPENSBI_VERSION_GIT),)
GENFLAGS += -DOPENSBI_VERSION_GIT="\"$(OPENSBI_VERSION_GIT)\""
endif
GENFLAGS += $(libsbiutils-genflags-y)
GENFLAGS += $(platform-genflags-y)
GENFLAGS += $(firmware-genflags-y)

View File

@@ -47,7 +47,7 @@ cross-compilation, you can build your own toolchain or just download
a prebuilt one from the
[Bootlin toolchain repository] (https://toolchains.bootlin.com/).
Please note that only a 64bit version of the toolchain is available in
Please note that only a 64-bit version of the toolchain is available in
the Bootlin toolchain repository for now.
Building and Installing the OpenSBI Platform-Independent Library
@@ -131,6 +131,25 @@ top-level make command line. These options, such as *PLATFORM_<xyz>* or
*docs/platform/<platform_name>.md* files and
*docs/firmware/<firmware_name>.md* files.
Building 32-bit / 64-bit OpenSBI Images
---------------------------------------
By default, building OpenSBI generates 32-bit or 64-bit images based on the
supplied RISC-V cross-compile toolchain. For example if *CROSS_COMPILE* is set
to *riscv64-unknown-elf-*, 64-bit OpenSBI images will be generated. If building
32-bit OpenSBI images, *CROSS_COMPILE* should be set to a toolchain that is
pre-configured to generate 32-bit RISC-V codes, like *riscv32-unknown-elf-*.
However it's possible to explicitly specify the image bits we want to build with
a given RISC-V toolchain. This can be done by setting the environment variable
*PLATFORM_RISCV_XLEN* to the desired width, for example:
```
export CROSS_COMPILE=riscv64-unknown-elf-
export PLATFORM_RISCV_XLEN=32
```
will generate 32-bit OpenSBI images. And vice vesa.
License
-------
@@ -153,14 +172,10 @@ OpenSBI source code also contains code reused from other projects as listed
below. The original license text of these projects is included in the source
files where the reused code is present.
1. The libfdt source code is disjunctively dual licensed
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
under the terms of the BSD 2-Clause license. Any contributions to this
code must be made under the terms of both licenses.
2. Some source file for the Kendryte/k210 platform code are based on code from
the [Kendryte standalone SDK] available on github. These files retain the
original copyright and license of the Kendryte standalone SDK project and
are licensed under the terms of the Apache License, Version 2.0.
* The libfdt source code is disjunctively dual licensed
(GPL-2.0+ OR BSD-2-Clause). Some of this project code is used in OpenSBI
under the terms of the BSD 2-Clause license. Any contributions to this
code must be made under the terms of both licenses.
See also the [third party notices] file for more information.

View File

@@ -17,191 +17,3 @@ BSD-2-Clause). Some of this project code is used in OpenSBI under the terms of
the BSD 2-Clause license. The full text of this license can be found in the
file [COPYING.BSD](COPYING.BSD).
Kendryte Standalone SDK
-----------------------
Copyright 2018 Canaan Inc.
The Kendryte K210 platform code reuses some code from Kendryte standalone SDK
licensed under the terms of the Apache License, Version 2.0. The full text of
this license is available at http://www.apache.org/licenses/LICENSE-2.0 and
included below.
```
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
```

View File

@@ -0,0 +1,28 @@
Andes AE350 SoC Platform
========================
The AE350 AXI/AHB-based platform N25(F)/NX25(F)/D25F/A25/AX25 CPU with
level-one memories,interrupt controller, debug module, AXI and AHB Bus
Matrix Controller, AXI-to-AHB Bridge and a collection of fundamentalAHB/APB
bus IP components pre-integrated together as a system design.The high-quality
and configurable AHB/APB IPs suites a majority embedded systems,
and the verified platform serves as a starting point to jump start SoC designs.
To build platform specific library and firmwares, provide the *PLATFORM=andes/ae350* parameter to the top level make command.
Platform Options
----------------
The Andes AE350 platform does not have any platform-specific options.
Building Andes AE350 Platform
-----------------------------
To use Linux v5.2 should be used to build Andes AE350 OpenSBI binaries by using the compile time option FW_PAYLOAD_FDT_PATH.
AE350's dts is included in https://github.com/andestech/linux/tree/ast-v3_2_0-release-public
**Linux Kernel Payload**
```
make PLATFORM=andes/ae350 FW_PAYLOAD_PATH=<linux_build_directory>/arch/riscv/boot/Image FW_PAYLOAD_FDT_PATH=<ae350.dtb path>
```

View File

@@ -24,6 +24,8 @@ OpenSBI currently supports the following virtual and hardware platforms:
* **Ariane FPGA SoC**: Platform support for the Ariane FPGA SoC used on
Genesys 2 board.
* **Andes AE350 SoC**: Platform support for the Andes's SoC (AE350).
The code for these supported platforms can be used as example to implement
support for other platforms. The *platform/template* directory also provides
template files for implementing support for a new platform. The *object.mk*,
@@ -34,3 +36,4 @@ facilitate the implementation.
[qemu_sifive_u.md]: qemu_sifive_u.md
[sifive_fu540.md]: sifive_fu540.md
[ariane-fpga.md]: ariane-fpga.md
[andes_ae350.md]: andes-ae350.md

View File

@@ -7,14 +7,22 @@ platform.
To build this platform specific library and firmwares, provide the
*PLATFORM=qemu/sifive_u* parameter to the top level `make` command line.
Note with QEMU v4.2 release, the QEMU *sifive_u* machine has been updated to
closely match the SiFive HiFive Unleashed hardware and can therefore run the
same firmware as what gets loaded onto the board, and OpenSBI's *qemu/sifive_u*
platform should only be used with QEMU v4.1 release or before.
The special *qemu/sifive_u* platform support will be dropped in the future
OpenSBI release.
Platform Options
----------------
The *QEMU SiFive Unleashed Machine* platform does not have any platform specific
options.
Executing on QEMU RISC-V 64bit
------------------------------
Executing on QEMU RISC-V 64-bit
-------------------------------
**No Payload Case**

View File

@@ -15,8 +15,8 @@ Platform Options
The *QEMU RISC-V Virt Machine* platform does not have any platform-specific
options.
Execution on QEMU RISC-V 64bit
------------------------------
Execution on QEMU RISC-V 64-bit
-------------------------------
**No Payload Case**
@@ -82,8 +82,8 @@ qemu-system-riscv64 -M virt -m 256M -nographic \
```
Execution on QEMU RISC-V 32bit
------------------------------
Execution on QEMU RISC-V 32-bit
-------------------------------
**No Payload Case**

View File

@@ -4,6 +4,9 @@ The FU540-C000 is the worlds first 4+1 64-bit RISC-V SoC from SiFive.
The HiFive Unleashed development platform is based on FU540-C000 and capable
of running Linux.
With QEMU v4.2 or above release, the 'sifive_u' machine can be used to test
OpenSBI image built for the real hardware as well.
To build platform specific library and firmwares, provide the
*PLATFORM=sifive/fu540* parameter to the top level `make` command.
@@ -47,11 +50,10 @@ 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 v2019.04 (or higher)
having SMP support.
having SMP support. From, Linux v5.2 (or higher) device tree is hosted in
Linux kernel and compiled as a part of Linux kernel build process.
To use U-Boot which follows Linux v5.2 (or higher) DT bindings, we will
need custom U-Boot with required driver changes which can be found in
riscv_unleashed_mmc_spi_v2 branch of https://github.com/avpatel/u-boot.git
The detailed U-Boot booting guide is avaialble at [U-Boot](https://gitlab.denx.de/u-boot/u-boot/blob/master/doc/board/sifive/fu540.rst)
```
make PLATFORM=sifive/fu540 FW_PAYLOAD_PATH=<u-boot_build_dir>/u-boot.bin
@@ -174,8 +176,11 @@ already part of the kernel or loaded from an external storage by kernel.
```
tftpboot ${ramdisk_addr_r} <ramdisk path in tftpboot directory>
```
7. Set the boot command-line arguments.
7. Load the pre-compiled device tree via tftpboot.
```
tftpboot ${fdt_addr_r} <linux source>/arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dtb
```
8. Set the boot command-line arguments.
```
setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
```
@@ -184,12 +189,12 @@ setenv bootargs "root=<root partition> rw console=ttySIF0 earlycon=sbi"
** root=/dev/mmcblk0pX ** - If a rootfs is already on some other partition
of sdcard)
8. Now boot into Linux.
9. Now boot into Linux.
```
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdtcontroladdr}
bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
or
(If ramdisk is not loaded from network)
bootm ${kernel_addr_r} - ${fdtcontroladdr}
bootm ${kernel_addr_r} - ${fdt_addr_r}
```
**U-Boot & Linux Kernel as a single payload**
@@ -197,5 +202,14 @@ bootm ${kernel_addr_r} - ${fdtcontroladdr}
At U-Boot prompt execute the following boot command to boot Linux.
```
bootm ${kernel_addr_r} - ${fdtcontroladdr}
bootm ${kernel_addr_r} - ${fdt_addr_r}
```
QEMU Specific Instructions
--------------------------
If you want to test OpenSBI with QEMU 'sifive_u' machine, please follow the
same instructions above, with the exception of not passing FW_PAYLOAD_FDT_PATH.
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.

View File

@@ -13,6 +13,9 @@
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_trap.h>
#define BOOT_STATUS_RELOCATE_DONE 1
#define BOOT_STATUS_BOOT_HART_DONE 2
.macro MOV_3R __d0, __s0, __d1, __s1, __d2, __s2
add \__d0, \__s0, zero
add \__d1, \__s1, zero
@@ -108,26 +111,33 @@ _wait_relocate_copy_done:
REG_L t1, 0(t1)
beq t0, t1, _wait_for_boot_hart
la t2, _boot_status
sub t2, t2, t0
add t2, t2, t1
la t3, _wait_for_boot_hart
sub t3, t3, t0
add t3, t3, t1
1:
/* waitting for relocate copy done (_boot_status == 1) */
li t4, 1
li t4, BOOT_STATUS_RELOCATE_DONE
REG_L t5, 0(t2)
/* Reduce the bus traffic so that boot hart may proceed faster */
nop
nop
nop
bne t4, t5, 1b
bgt t4, t5, 1b
jr t3
_relocate_done:
/* mark relocate copy done */
/*
* Mark relocate copy done
* Use _boot_status copy relative to the load address
*/
la t0, _boot_status
li t1, 1
la t1, _link_start
REG_L t1, 0(t1)
la t2, _load_start
REG_L t2, 0(t2)
sub t0, t0, t1
add t0, t0, t2
li t1, BOOT_STATUS_RELOCATE_DONE
REG_S t1, 0(t0)
fence rw, rw
@@ -302,7 +312,7 @@ _fdt_reloc_again:
_fdt_reloc_done:
/* mark boot hart done */
li t0, 2
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
REG_S t0, 0(t1)
fence rw, rw
@@ -310,7 +320,7 @@ _fdt_reloc_done:
/* waitting for boot hart done (_boot_status == 2) */
_wait_for_boot_hart:
li t0, 2
li t0, BOOT_STATUS_BOOT_HART_DONE
la t1, _boot_status
REG_L t1, 0(t1)
/* Reduce the bus traffic so that boot hart may proceed faster */
@@ -476,6 +486,16 @@ _trap_handler_all_mode:
REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp)
csrr t0, CSR_MSTATUS
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
#if __riscv_xlen == 32
csrr t0, CSR_MISA
srli t0, t0, ('H' - 'A')
andi t0, t0, 0x1
beq t0, zero, _skip_mstatush_save
csrr t0, CSR_MSTATUSH
REG_S t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
_skip_mstatush_save:
#endif
/* Save all general regisers except SP and T0 */
REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp)
@@ -550,6 +570,15 @@ _trap_handler_all_mode:
csrw CSR_MEPC, t0
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp)
csrw CSR_MSTATUS, t0
#if __riscv_xlen == 32
csrr t0, CSR_MISA
srli t0, t0, ('H' - 'A')
andi t0, t0, 0x1
beq t0, zero, _skip_mstatush_restore
REG_L t0, SBI_TRAP_REGS_OFFSET(mstatusH)(sp)
csrw CSR_MSTATUSH, t0
_skip_mstatush_restore:
#endif
/* Restore T0 */
REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(sp)

View File

@@ -9,6 +9,31 @@
#include <sbi/sbi_ecall_interface.h>
#define SBI_ECALL(__num, __a0, __a1, __a2) \
({ \
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
asm volatile("ecall" \
: "+r"(a0) \
: "r"(a1), "r"(a2), "r"(a7) \
: "memory"); \
a0; \
})
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_EXT_0_1_CONSOLE_PUTCHAR, (c))
static inline void sbi_ecall_console_puts(const char *str)
{
while (str && *str)
sbi_ecall_console_putc(*str++);
}
#define wfi() \
do { \
__asm__ __volatile__("wfi" ::: "memory"); \

View File

@@ -35,6 +35,9 @@ long arch_atomic_xchg(atomic_t *atom, long newval);
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
unsigned int newval);
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval);
/**
* Set a bit in an atomic variable and return the new value.
* @nr : Bit to set.

View File

@@ -38,15 +38,30 @@
#define MSTATUS_TW 0x00200000
#define MSTATUS_TSR 0x00400000
#define MSTATUS32_SD 0x80000000
#if __riscv_xlen == 64
#define MSTATUS_UXL 0x0000000300000000
#define MSTATUS_SXL 0x0000000C00000000
#define MSTATUS_MTL 0x0000004000000000
#define MSTATUS_MTL_SHIFT 38
#define MSTATUS_MPV 0x0000008000000000
#define MSTATUS_MPV_HIFT 39
#else
#define MSTATUSH_UXL 0x00000003
#define MSTATUSH_SXL 0x0000000C
#define MSTATUSH_MTL 0x00000040
#define MSTATUSH_MTL_SHIFT 6
#define MSTATUSH_MPV 0x00000080
#define MSTATUSH_MPV_HIFT 7
#endif
#define MSTATUS64_SD 0x8000000000000000
#define SSTATUS_UIE 0x00000001
#define SSTATUS_SIE 0x00000002
#define SSTATUS_UPIE 0x00000010
#define SSTATUS_SPIE 0x00000020
#define SSTATUS_SPP 0x00000100
#define SSTATUS_SPIE_SHIFT 5
#define SSTATUS_SPIE (1UL << MSTATUS_SPIE_SHIFT)
#define SSTATUS_SPP_SHIFT 8
#define SSTATUS_SPP (1UL << MSTATUS_SPP_SHIFT)
#define SSTATUS_FS 0x00006000
#define SSTATUS_XS 0x00018000
#define SSTATUS_SUM 0x00040000
@@ -55,6 +70,14 @@
#define SSTATUS_UXL 0x0000000300000000
#define SSTATUS64_SD 0x8000000000000000
#define HSTATUS_VTSR 0x00400000
#define HSTATUS_VTVM 0x00100000
#define HSTATUS_SP2V 0x00000200
#define HSTATUS_SP2P 0x00000100
#define HSTATUS_SPV 0x00000080
#define HSTATUS_STL 0x00000040
#define HSTATUS_SPRV 0x00000001
#define DCSR_XDEBUGVER (3U<<30)
#define DCSR_NDRESET (1<<29)
#define DCSR_FULLRESET (1<<28)
@@ -249,6 +272,25 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
#define CSR_SATP 0x180
#define CSR_HSTATUS 0x600
#define CSR_HEDELEG 0x602
#define CSR_HIDELEG 0x603
#define CSR_HTIMEDELTA 0x605
#define CSR_HTIMEDELTAH 0x615
#define CSR_HCOUNTERNEN 0x606
#define CSR_HGATP 0x680
#define CSR_VSSTATUS 0x200
#define CSR_VSIE 0x204
#define CSR_VSTVEC 0x205
#define CSR_VSSCRATCH 0x240
#define CSR_VSEPC 0x241
#define CSR_VSCAUSE 0x242
#define CSR_VSTVAL 0x243
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
#define CSR_MSTATUS 0x300
#define CSR_MISA 0x301
#define CSR_MEDELEG 0x302
@@ -256,6 +298,7 @@
#define CSR_MIE 0x304
#define CSR_MTVEC 0x305
#define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
#define CSR_MCAUSE 0x342
@@ -288,6 +331,7 @@
#define CSR_DCSR 0x7b0
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
#define CSR_MCYCLE 0xb00
#define CSR_MINSTRET 0xb02
#define CSR_MHPMCOUNTER3 0xb03
@@ -502,6 +546,9 @@
#define INSN_MATCH_C_FSWSP 0xe002
#define INSN_MASK_C_FSWSP 0xe003
#define INSN_MASK_WFI 0xffffff00
#define INSN_MATCH_WFI 0x10500000
#define INSN_LEN(insn) ((((insn) & 0x3) < 0x3) ? 2 : 4)
#if __riscv_xlen == 64

View File

@@ -73,10 +73,6 @@
#define SET_FS_DIRTY() ((void)0)
#else
#error "Floating point emulation not supported.\n"
#endif
#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
#define GET_F32_RS3(insn, regs) (GET_F32_REG(insn, 27, regs))
@@ -94,3 +90,5 @@
#define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs))
#endif
#endif

View File

@@ -43,6 +43,7 @@ DECLARE_UNPRIVILEGED_LOAD_FUNCTION(u64)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(u64)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(ulong)
ulong get_insn(ulong mepc, ulong *mstatus);
ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
struct unpriv_trap *trap);
#endif

View File

@@ -31,6 +31,10 @@ int __printf(3, 4) sbi_snprintf(char *out, u32 out_sz, const char *format, ...);
int __printf(1, 2) sbi_printf(const char *format, ...);
struct sbi_scratch;
int __printf(2, 3) sbi_dprintf(struct sbi_scratch *scratch,
const char *format, ...);
int sbi_console_init(struct sbi_scratch *scratch);
#endif

View File

@@ -12,41 +12,34 @@
/* clang-format off */
#define SBI_ECALL_SET_TIMER 0
#define SBI_ECALL_CONSOLE_PUTCHAR 1
#define SBI_ECALL_CONSOLE_GETCHAR 2
#define SBI_ECALL_CLEAR_IPI 3
#define SBI_ECALL_SEND_IPI 4
#define SBI_ECALL_REMOTE_FENCE_I 5
#define SBI_ECALL_REMOTE_SFENCE_VMA 6
#define SBI_ECALL_REMOTE_SFENCE_VMA_ASID 7
#define SBI_ECALL_SHUTDOWN 8
enum sbi_ext_id {
SBI_EXT_0_1_SET_TIMER = 0x0,
SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1,
SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2,
SBI_EXT_0_1_CLEAR_IPI = 0x3,
SBI_EXT_0_1_SEND_IPI = 0x4,
SBI_EXT_0_1_REMOTE_FENCE_I = 0x5,
SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6,
SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7,
SBI_EXT_0_1_SHUTDOWN = 0x8,
SBI_EXT_BASE = 0x10,
};
enum sbi_ext_base_fid {
SBI_EXT_BASE_GET_SPEC_VERSION = 0,
SBI_EXT_BASE_GET_IMP_ID,
SBI_EXT_BASE_GET_IMP_VERSION,
SBI_EXT_BASE_PROBE_EXT,
SBI_EXT_BASE_GET_MVENDORID,
SBI_EXT_BASE_GET_MARCHID,
SBI_EXT_BASE_GET_MIMPID,
};
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
#define SBI_EXT_VENDOR_START 0x09000000
#define SBI_EXT_VENDOR_END 0x09FFFFFF
/* clang-format on */
#define SBI_ECALL(__num, __a0, __a1, __a2) \
({ \
register unsigned long a0 asm("a0") = (unsigned long)(__a0); \
register unsigned long a1 asm("a1") = (unsigned long)(__a1); \
register unsigned long a2 asm("a2") = (unsigned long)(__a2); \
register unsigned long a7 asm("a7") = (unsigned long)(__num); \
asm volatile("ecall" \
: "+r"(a0) \
: "r"(a1), "r"(a2), "r"(a7) \
: "memory"); \
a0; \
})
#define SBI_ECALL_0(__num) SBI_ECALL(__num, 0, 0, 0)
#define SBI_ECALL_1(__num, __a0) SBI_ECALL(__num, __a0, 0, 0)
#define SBI_ECALL_2(__num, __a0, __a1) SBI_ECALL(__num, __a0, __a1, 0)
#define sbi_ecall_console_putc(c) SBI_ECALL_1(SBI_ECALL_CONSOLE_PUTCHAR, (c));
static inline void sbi_ecall_console_puts(const char *str)
{
while (str && *str)
sbi_ecall_console_putc(*str++);
}
#endif

View File

@@ -12,12 +12,13 @@
#include <sbi/sbi_types.h>
struct sbi_trap_regs;
struct sbi_scratch;
int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch, ulong *csr_val);
int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch, ulong csr_val);
#endif

View File

@@ -13,11 +13,11 @@
/* clang-format off */
#define SBI_OK 0
#define SBI_EUNKNOWN -1
#define SBI_EFAIL -2
#define SBI_EFAIL -1
#define SBI_ENOTSUPP -2
#define SBI_EINVAL -3
#define SBI_ENOENT -4
#define SBI_ENOTSUPP -5
#define SBI_DENIED -4
#define SBI_INVALID_ADDR -5
#define SBI_ENODEV -6
#define SBI_ENOSYS -7
#define SBI_ETIMEDOUT -8
@@ -26,6 +26,8 @@
#define SBI_ENOSPC -11
#define SBI_ENOMEM -12
#define SBI_ETRAP -13
#define SBI_EUNKNOWN -14
#define SBI_ENOENT -15
/* clang-format on */

View File

@@ -26,7 +26,6 @@ struct sbi_fifo {
enum sbi_fifo_inplace_update_types {
SBI_FIFO_SKIP,
SBI_FIFO_UPDATED,
SBI_FIFO_RESET,
SBI_FIFO_UNCHANGED,
};

View File

@@ -26,7 +26,8 @@ void __attribute__((noreturn)) sbi_hart_hang(void);
void __attribute__((noreturn))
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_mode);
unsigned long next_addr, unsigned long next_mode,
bool next_virt);
void sbi_hart_mark_available(u32 hartid);

View File

@@ -30,15 +30,21 @@
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
/** Offset of disabled_hart_mask in struct sbi_platform */
#define SBI_PLATFORM_DISABLED_HART_OFFSET (0x58)
/** Offset of tlb_range_flush_limit in struct sbi_platform */
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_OFFSET (0x60)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x60)
#define SBI_PLATFORM_OPS_OFFSET (0x68)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x68 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
#ifndef __ASSEMBLY__
#include <sbi/sbi_version.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_error.h>
/** Possible feature flags of a platform */
enum sbi_platform_features {
@@ -90,8 +96,6 @@ struct sbi_platform_operations {
/** Send IPI to a target HART */
void (*ipi_send)(u32 target_hart);
/** Wait for target HART to acknowledge IPI */
void (*ipi_sync)(u32 target_hart);
/** Clear IPI for a target HART */
void (*ipi_clear)(u32 target_hart);
/** Initialize IPI for current HART */
@@ -110,6 +114,14 @@ struct sbi_platform_operations {
int (*system_reboot)(u32 type);
/** Shutdown or poweroff the platform */
int (*system_shutdown)(u32 type);
/** platform specific SBI extension implementation probe function */
int (*vendor_ext_check)(long extid);
/** platform specific SBI extension implementation provider */
int (*vendor_ext_provider)(long extid, long funcid,
unsigned long *args, unsigned long *out_value,
unsigned long *out_trap_cause,
unsigned long *out_trap_val);
} __packed;
/** Representation of a platform */
@@ -136,6 +148,8 @@ struct sbi_platform {
u32 hart_stack_size;
/** Mask representing the set of disabled HARTs */
u64 disabled_hart_mask;
/* Maximum value of tlb flush range request*/
u64 tlb_range_flush_limit;
/** Pointer to sbi platform operations */
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
@@ -200,6 +214,22 @@ static inline bool sbi_platform_hart_disabled(const struct sbi_platform *plat,
return FALSE;
}
/**
* Get platform specific tlb range flush maximum value. Any request with size
* higher than this is upgraded to a full flush.
*
* @param plat pointer to struct sbi_platform
*
* @return tlb range flush limit value. Returns a default (page size) if not
* defined by platform.
*/
static inline u64 sbi_platform_tlbr_flush_limit(const struct sbi_platform *plat)
{
if (plat && plat->tlb_range_flush_limit)
return plat->tlb_range_flush_limit;
return SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT;
}
/**
* Get total number of HARTs supported by the platform
*
@@ -370,19 +400,6 @@ static inline void sbi_platform_ipi_send(const struct sbi_platform *plat,
sbi_platform_ops(plat)->ipi_send(target_hart);
}
/**
* Wait for target HART to acknowledge IPI
*
* @param plat pointer to struct sbi_platform
* @param target_hart HART ID of IPI target
*/
static inline void sbi_platform_ipi_sync(const struct sbi_platform *plat,
u32 target_hart)
{
if (plat && sbi_platform_ops(plat)->ipi_sync)
sbi_platform_ops(plat)->ipi_sync(target_hart);
}
/**
* Clear IPI for a target HART
*
@@ -417,7 +434,7 @@ static inline int sbi_platform_ipi_init(const struct sbi_platform *plat,
*
* @param plat pointer to struct sbi_platform
*
* @return 64bit timer value
* @return 64-bit timer value
*/
static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
{
@@ -499,6 +516,54 @@ static inline int sbi_platform_system_shutdown(const struct sbi_platform *plat,
return 0;
}
/**
* Check if a vendor extension is implemented or not.
*
* @param plat pointer to struct sbi_platform
* @param extid vendor SBI extension id
*
* @return 0 if extid is not implemented and 1 if implemented
*/
static inline int sbi_platform_vendor_ext_check(const struct sbi_platform *plat,
long extid)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_check)
return sbi_platform_ops(plat)->vendor_ext_check(extid);
return 0;
}
/**
* Invoke platform specific vendor SBI extension implementation.
*
* @param plat pointer to struct sbi_platform
* @param extid vendor SBI extension id
* @param funcid SBI function id within the extension id
* @param args pointer to arguments passed by the caller
* @param out_value output value that can be filled the callee
* @param out_tcause trap cause that can be filled the callee
* @param out_tvalue possible trap value that can be filled the callee
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_vendor_ext_provider(const struct sbi_platform *plat,
long extid, long funcid,
unsigned long *args,
unsigned long *out_value,
unsigned long *out_tcause,
unsigned long *out_tval)
{
if (plat && sbi_platform_ops(plat)->vendor_ext_provider) {
return sbi_platform_ops(plat)->vendor_ext_provider(extid,
funcid, args,
out_value,
out_tcause,
out_tval);
}
return SBI_ENOTSUPP;
}
#endif
#endif

View File

@@ -74,6 +74,8 @@ struct sbi_scratch {
enum sbi_scratch_options {
/** Disable prints during boot */
SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
/** Enable runtime debug prints */
SBI_SCRATCH_DEBUG_PRINTS = (1 << 1),
};
/** Get pointer to sbi_scratch for current HART */

View File

@@ -16,6 +16,14 @@ struct sbi_scratch;
u64 sbi_timer_value(struct sbi_scratch *scratch);
u64 sbi_timer_virt_value(struct sbi_scratch *scratch);
u64 sbi_timer_get_delta(struct sbi_scratch *scratch);
void sbi_timer_set_delta(struct sbi_scratch *scratch, ulong delta);
void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper);
void sbi_timer_event_stop(struct sbi_scratch *scratch);
void sbi_timer_event_start(struct sbi_scratch *scratch, u64 next_event);

View File

@@ -16,16 +16,16 @@
/* clang-format off */
#define SBI_TLB_FLUSH_ALL ((unsigned long)-1)
#define SBI_TLB_FLUSH_MAX_SIZE (1UL << 30)
/* clang-format on */
#define SBI_TLB_FIFO_NUM_ENTRIES 4
#define SBI_TLB_FIFO_NUM_ENTRIES 8
enum sbi_tlb_info_types {
SBI_TLB_FLUSH_VMA,
SBI_TLB_FLUSH_VMA_ASID,
SBI_TLB_FLUSH_VMA_VMID
SBI_TLB_FLUSH_VMA_VMID,
SBI_ITLB_FLUSH
};
struct sbi_scratch;
@@ -35,14 +35,17 @@ struct sbi_tlb_info {
unsigned long size;
unsigned long asid;
unsigned long type;
unsigned long shart_mask;
};
#define SBI_TLB_INFO_SIZE sizeof(struct sbi_tlb_info)
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 event, void *data);
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 hartid, void *data);
void sbi_tlb_fifo_process(struct sbi_scratch *scratch, u32 event);
void sbi_tlb_fifo_process(struct sbi_scratch *scratch);
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot);
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch);
#endif

View File

@@ -80,8 +80,10 @@
#define SBI_TRAP_REGS_mepc 32
/** Index of mstatus member in sbi_trap_regs */
#define SBI_TRAP_REGS_mstatus 33
/** Index of mstatusH member in sbi_trap_regs */
#define SBI_TRAP_REGS_mstatusH 34
/** Last member index in sbi_trap_regs */
#define SBI_TRAP_REGS_last 34
#define SBI_TRAP_REGS_last 35
/* clang-format on */
@@ -164,6 +166,8 @@ struct sbi_trap_regs {
unsigned long mepc;
/** mstatus register state */
unsigned long mstatus;
/** mstatusH register state (only for 32-bit) */
unsigned long mstatusH;
} __packed;
struct sbi_scratch;

View File

@@ -11,7 +11,7 @@
#define __SBI_VERSION_H__
#define OPENSBI_VERSION_MAJOR 0
#define OPENSBI_VERSION_MINOR 4
#define OPENSBI_VERSION_MINOR 5
/**
* OpenSBI 32-bit version with:

View File

@@ -50,6 +50,39 @@ long atomic_sub_return(atomic_t *atom, long value)
return ret - value;
}
#define __axchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
__typeof__(new) __new = (new); \
__typeof__(*(ptr)) __ret; \
switch (size) { \
case 4: \
__asm__ __volatile__ ( \
" amoswap.w.aqrl %0, %2, %1\n" \
: "=r" (__ret), "+A" (*__ptr) \
: "r" (__new) \
: "memory"); \
break; \
case 8: \
__asm__ __volatile__ ( \
" amoswap.d.aqrl %0, %2, %1\n" \
: "=r" (__ret), "+A" (*__ptr) \
: "r" (__new) \
: "memory"); \
break; \
default: \
break; \
} \
__ret; \
})
#define axchg(ptr, x) \
({ \
__typeof__(*(ptr)) _x_ = (x); \
(__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \
})
#define __xchg(ptr, new, size) \
({ \
__typeof__(ptr) __ptr = (ptr); \
@@ -148,12 +181,7 @@ long arch_atomic_xchg(atomic_t *atom, long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
/*
* The name of GCC built-in macro __sync_lock_test_and_set()
* is misleading. A more appropriate name for GCC built-in
* macro would be __sync_val_exchange().
*/
return __sync_lock_test_and_set(&atom->counter, newval);
return axchg(&atom->counter, newval);
#else
return xchg(&atom->counter, newval);
#endif
@@ -164,12 +192,18 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
/*
* The name of GCC built-in macro __sync_lock_test_and_set()
* is misleading. A more appropriate name for GCC built-in
* macro would be __sync_val_exchange().
*/
return __sync_lock_test_and_set(ptr, newval);
return axchg(ptr, newval);
#else
return xchg(ptr, newval);
#endif
}
unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr,
unsigned long newval)
{
/* Atomically set new value and return old value. */
#ifdef __riscv_atomic
return axchg(ptr, newval);
#else
return xchg(ptr, newval);
#endif

View File

@@ -97,11 +97,22 @@ void store_u64(u64 *addr, u64 val,
}
#endif
ulong get_insn(ulong mepc, ulong *mstatus)
ulong get_insn(ulong mepc, bool virt, struct sbi_scratch *scratch,
struct unpriv_trap *trap)
{
register ulong __mepc asm("a2") = mepc;
register ulong __mstatus asm("a3");
ulong val;
ulong __mstatus = 0, __vsstatus = 0, val = 0;
#ifdef __riscv_compressed
ulong rvc_mask = 3, tmp;
#endif
trap->ilen = 4;
trap->cause = 0;
trap->tval = 0;
sbi_hart_set_trap_info(scratch, trap);
if (virt)
__vsstatus = csr_read_set(CSR_VSSTATUS, SSTATUS_MXR);
#ifndef __riscv_compressed
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
#if __riscv_xlen == 64
@@ -109,37 +120,39 @@ ulong get_insn(ulong mepc, ulong *mstatus)
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
"csrw " STR(CSR_MSTATUS) ", %[mstatus]"
"csrw " STR(CSR_MSTATUS) ", %[mstatus]"
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val)
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc));
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc));
#else
ulong rvc_mask = 3, tmp;
asm("csrrs %[mstatus], " STR(CSR_MSTATUS) ", %[mprv]\n"
"and %[tmp], %[addr], 2\n"
"bnez %[tmp], 1f\n"
#if __riscv_xlen == 64
STR(LWU) " %[insn], (%[addr])\n"
#else
STR(LW) " %[insn], (%[addr])\n"
#endif
"and %[tmp], %[insn], %[rvc_mask]\n"
"beq %[tmp], %[rvc_mask], 2f\n"
"sll %[insn], %[insn], %[xlen_minus_16]\n"
"srl %[insn], %[insn], %[xlen_minus_16]\n"
"j 2f\n"
"1:\n"
"lhu %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
"lhu %[tmp], 2(%[addr])\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw " STR(CSR_MSTATUS) ", %[mstatus]"
"lhu %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
"lhu %[tmp], 2(%[addr])\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw " STR(CSR_MSTATUS) ", %[mstatus]"
: [mstatus] "+&r"(__mstatus), [insn] "=&r"(val), [tmp] "=&r"(tmp)
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(__mepc),
[rvc_mask] "r"(rvc_mask), [xlen_minus_16] "i"(__riscv_xlen - 16));
: [mprv] "r"(MSTATUS_MPRV | MSTATUS_MXR), [addr] "r"(mepc),
[rvc_mask] "r"(rvc_mask));
#endif
if (mstatus)
*mstatus = __mstatus;
if (virt)
csr_write(CSR_VSSTATUS, __vsstatus);
sbi_hart_set_trap_info(scratch, NULL);
switch (trap->cause) {
case CAUSE_LOAD_ACCESS:
trap->cause = CAUSE_FETCH_ACCESS;
trap->tval = mepc;
break;
case CAUSE_LOAD_PAGE_FAULT:
trap->cause = CAUSE_FETCH_PAGE_FAULT;
trap->tval = mepc;
break;
default:
break;
};
return val;
}

View File

@@ -375,6 +375,19 @@ int sbi_printf(const char *format, ...)
return retval;
}
int sbi_dprintf(struct sbi_scratch *scratch, const char *format, ...)
{
va_list args;
int retval = 0;
va_start(args, format);
if (scratch->options & SBI_SCRATCH_DEBUG_PRINTS)
retval = print(NULL, NULL, format, args);
va_end(args);
return retval;
}
int sbi_console_init(struct sbi_scratch *scratch)
{
console_plat = sbi_platform_ptr(scratch);

View File

@@ -12,13 +12,18 @@
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_version.h>
#include <sbi/riscv_asm.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 1
#define SBI_ECALL_VERSION_MINOR 2
#define SBI_OPENSBI_IMPID 1
u16 sbi_ecall_version_major(void)
{
@@ -30,78 +35,208 @@ u16 sbi_ecall_version_minor(void)
return SBI_ECALL_VERSION_MINOR;
}
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
int sbi_check_extension(struct sbi_scratch *scratch, unsigned long extid,
unsigned long *out_val)
{
int ret = SBI_ENOTSUPP;
struct unpriv_trap uptrap;
struct sbi_tlb_info tlb_info;
/**
* Each extension apart from base & 0.1, will be implemented as
* platform specific feature. Thus, extension probing can be achieved
* by checking the feature bits of the platform. We can create a map
* between extension ID & feature and use a generic function to check
* or just use a switch case for every new extension support added
* TODO: Implement it.
*/
switch (regs->a7) {
case SBI_ECALL_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)regs->a1 << 32) | (u64)regs->a0));
#else
sbi_timer_event_start(scratch, (u64)regs->a0);
#endif
ret = 0;
break;
case SBI_ECALL_CONSOLE_PUTCHAR:
sbi_putc(regs->a0);
ret = 0;
break;
case SBI_ECALL_CONSOLE_GETCHAR:
regs->a0 = sbi_getc();
ret = 0;
break;
case SBI_ECALL_CLEAR_IPI:
sbi_ipi_clear_smode(scratch);
ret = 0;
break;
case SBI_ECALL_SEND_IPI:
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
SBI_IPI_EVENT_SOFT, NULL);
break;
case SBI_ECALL_REMOTE_FENCE_I:
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
SBI_IPI_EVENT_FENCE_I, NULL);
break;
case SBI_ECALL_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)regs->a1;
tlb_info.size = (unsigned long)regs->a2;
tlb_info.type = SBI_TLB_FLUSH_VMA;
if ((extid >= SBI_EXT_0_1_SET_TIMER &&
extid <= SBI_EXT_0_1_SHUTDOWN) || (extid == SBI_EXT_BASE)) {
*out_val = 1;
} else if (extid >= SBI_EXT_VENDOR_START &&
extid <= SBI_EXT_VENDOR_END) {
*out_val = sbi_platform_vendor_ext_check(
sbi_platform_ptr(scratch),
extid);
} else
*out_val = 0;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
SBI_IPI_EVENT_SFENCE_VMA, &tlb_info);
break;
case SBI_ECALL_REMOTE_SFENCE_VMA_ASID:
tlb_info.start = (unsigned long)regs->a1;
tlb_info.size = (unsigned long)regs->a2;
tlb_info.asid = (unsigned long)regs->a3;
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
return 0;
}
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)regs->a0,
SBI_IPI_EVENT_SFENCE_VMA_ASID,
&tlb_info);
int sbi_ecall_vendor_ext_handler(struct sbi_scratch *scratch,
unsigned long extid, unsigned long funcid,
unsigned long *args, unsigned long *out_val,
unsigned long *out_tcause,
unsigned long *out_tval)
{
return sbi_platform_vendor_ext_provider(sbi_platform_ptr(scratch),
extid, funcid, args, out_val,
out_tcause, out_tval);
}
int sbi_ecall_base_handler(struct sbi_scratch *scratch, unsigned long extid,
unsigned long funcid, unsigned long *args,
unsigned long *out_val, unsigned long *out_tcause,
unsigned long *out_tval)
{
int ret = 0;
switch (funcid) {
case SBI_EXT_BASE_GET_SPEC_VERSION:
*out_val = (SBI_ECALL_VERSION_MAJOR <<
SBI_SPEC_VERSION_MAJOR_OFFSET) &
(SBI_SPEC_VERSION_MAJOR_MASK <<
SBI_SPEC_VERSION_MAJOR_OFFSET);
*out_val = *out_val | SBI_ECALL_VERSION_MINOR;
break;
case SBI_ECALL_SHUTDOWN:
sbi_system_shutdown(scratch, 0);
ret = 0;
case SBI_EXT_BASE_GET_IMP_ID:
*out_val = SBI_OPENSBI_IMPID;
break;
case SBI_EXT_BASE_GET_IMP_VERSION:
*out_val = OPENSBI_VERSION;
break;
case SBI_EXT_BASE_GET_MVENDORID:
*out_val = csr_read(CSR_MVENDORID);
break;
case SBI_EXT_BASE_GET_MARCHID:
*out_val = csr_read(CSR_MARCHID);
break;
case SBI_EXT_BASE_GET_MIMPID:
*out_val = csr_read(CSR_MIMPID);
break;
case SBI_EXT_BASE_PROBE_EXT:
ret = sbi_check_extension(scratch, args[0], out_val);
default:
regs->a0 = SBI_ENOTSUPP;
ret = 0;
break;
};
if (!ret) {
regs->mepc += 4;
} else if (ret == SBI_ETRAP) {
ret = 0;
sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
ret = SBI_ENOTSUPP;
}
return ret;
}
int sbi_ecall_0_1_handler(struct sbi_scratch *scratch, unsigned long extid,
unsigned long *args, unsigned long *tval,
unsigned long *tcause)
{
int ret = 0;
struct sbi_tlb_info tlb_info;
u32 source_hart = sbi_current_hartid();
struct unpriv_trap uptrap = {0};
switch (extid) {
case SBI_EXT_0_1_SET_TIMER:
#if __riscv_xlen == 32
sbi_timer_event_start(scratch,
(((u64)args[1] << 32) | (u64)args[0]));
#else
sbi_timer_event_start(scratch, (u64)args[0]);
#endif
break;
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
sbi_putc(args[0]);
break;
case SBI_EXT_0_1_CONSOLE_GETCHAR:
ret = sbi_getc();
break;
case SBI_EXT_0_1_CLEAR_IPI:
sbi_ipi_clear_smode(scratch);
break;
case SBI_EXT_0_1_SEND_IPI:
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SOFT, NULL);
break;
case SBI_EXT_0_1_REMOTE_FENCE_I:
tlb_info.start = 0;
tlb_info.size = 0;
tlb_info.type = SBI_ITLB_FLUSH;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_FENCE_I, &tlb_info);
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.type = SBI_TLB_FLUSH_VMA;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SFENCE_VMA, &tlb_info);
break;
case SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID:
tlb_info.start = (unsigned long)args[1];
tlb_info.size = (unsigned long)args[2];
tlb_info.asid = (unsigned long)args[3];
tlb_info.type = SBI_TLB_FLUSH_VMA_ASID;
tlb_info.shart_mask = 1UL << source_hart;
ret = sbi_ipi_send_many(scratch, &uptrap, (ulong *)args[0],
SBI_IPI_EVENT_SFENCE_VMA_ASID,
&tlb_info);
break;
case SBI_EXT_0_1_SHUTDOWN:
sbi_system_shutdown(scratch, 0);
break;
default:
ret = SBI_ENOTSUPP;
};
if (ret == SBI_ETRAP) {
*tcause = uptrap.cause;
*tval = uptrap.tval;
}
return ret;
}
int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
int ret = 0;
unsigned long extension_id = regs->a7;
unsigned long func_id = regs->a6;
unsigned long out_val;
unsigned long out_tval;
unsigned long out_tcause;
bool is_0_1_spec = 0;
unsigned long args[6];
args[0] = regs->a0;
args[1] = regs->a1;
args[2] = regs->a2;
args[3] = regs->a3;
args[4] = regs->a4;
args[5] = regs->a5;
if (extension_id >= SBI_EXT_0_1_SET_TIMER &&
extension_id <= SBI_EXT_0_1_SHUTDOWN) {
ret = sbi_ecall_0_1_handler(scratch, extension_id, args,
&out_tval, &out_tcause);
is_0_1_spec = 1;
} else if (extension_id == SBI_EXT_BASE)
ret = sbi_ecall_base_handler(scratch, extension_id, func_id,
args, &out_val,
&out_tval, &out_tcause);
else if (extension_id >= SBI_EXT_VENDOR_START &&
extension_id <= SBI_EXT_VENDOR_END) {
ret = sbi_ecall_vendor_ext_handler(scratch, extension_id,
func_id, args, &out_val,
&out_tval, &out_tcause);
} else {
ret = SBI_ENOTSUPP;
}
if (ret == SBI_ETRAP) {
sbi_trap_redirect(regs, scratch, regs->mepc,
out_tcause, out_tval);
} else {
/* This function should return non-zero value only in case of
* fatal error. However, there is no good way to distinguish
* between a fatal and non-fatal errors yet. That's why we treat
* every return value except ETRAP as non-fatal and just return
* accordingly for now. Once fatal errors are defined, that
* case should be handled differently.
*/
regs->mepc += 4;
regs->a0 = ret;
if (!is_0_1_spec)
regs->a1 = out_val;
}
return 0;
}

View File

@@ -14,16 +14,30 @@
#include <sbi/sbi_emulate_csr.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_trap.h>
int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
int sbi_emulate_csr_read(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch, ulong *csr_val)
{
int ret = 0;
ulong cen = -1UL;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U)
if (prev_mode == PRV_U)
cen = csr_read(CSR_SCOUNTEREN);
switch (csr_num) {
case CSR_HTIMEDELTA:
if (prev_mode == PRV_S && !virt)
*csr_val = sbi_timer_get_delta(scratch);
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLE:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1;
@@ -32,7 +46,8 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
case CSR_TIME:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*csr_val = sbi_timer_value(scratch);
*csr_val = (virt) ? sbi_timer_virt_value(scratch):
sbi_timer_value(scratch);
break;
case CSR_INSTRET:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
@@ -50,6 +65,12 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
*csr_val = csr_read(CSR_MHPMCOUNTER4);
break;
#if __riscv_xlen == 32
case CSR_HTIMEDELTAH:
if (prev_mode == PRV_S && !virt)
*csr_val = sbi_timer_get_delta(scratch) >> 32;
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLEH:
if (!((cen >> (CSR_CYCLE - CSR_CYCLE)) & 1))
return -1;
@@ -58,7 +79,8 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
case CSR_TIMEH:
if (!((cen >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*csr_val = sbi_timer_value(scratch) >> 32;
*csr_val = (virt) ? sbi_timer_virt_value(scratch) >> 32:
sbi_timer_value(scratch) >> 32;
break;
case CSR_INSTRETH:
if (!((cen >> (CSR_INSTRET - CSR_CYCLE)) & 1))
@@ -83,18 +105,35 @@ int sbi_emulate_csr_read(int csr_num, u32 hartid, ulong mstatus,
*csr_val = csr_read(CSR_MHPMEVENT4);
break;
default:
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", __func__,
hartid, csr_num);
return SBI_ENOTSUPP;
ret = SBI_ENOTSUPP;
break;
};
return 0;
if (ret)
sbi_dprintf(scratch, "%s: hartid%d: invalid csr_num=0x%x\n",
__func__, hartid, csr_num);
return ret;
}
int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
int sbi_emulate_csr_write(int csr_num, u32 hartid, struct sbi_trap_regs *regs,
struct sbi_scratch *scratch, ulong csr_val)
{
int ret = 0;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
switch (csr_num) {
case CSR_HTIMEDELTA:
if (prev_mode == PRV_S && !virt)
sbi_timer_set_delta(scratch, csr_val);
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLE:
csr_write(CSR_MCYCLE, csr_val);
break;
@@ -108,6 +147,12 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
csr_write(CSR_MHPMCOUNTER4, csr_val);
break;
#if __riscv_xlen == 32
case CSR_HTIMEDELTAH:
if (prev_mode == PRV_S && !virt)
sbi_timer_set_delta_upper(scratch, csr_val);
else
ret = SBI_ENOTSUPP;
break;
case CSR_CYCLEH:
csr_write(CSR_MCYCLEH, csr_val);
break;
@@ -128,10 +173,13 @@ int sbi_emulate_csr_write(int csr_num, u32 hartid, ulong mstatus,
csr_write(CSR_MHPMEVENT4, csr_val);
break;
default:
sbi_printf("%s: hartid%d: invalid csr_num=0x%x\n", __func__,
hartid, csr_num);
return SBI_ENOTSUPP;
ret = SBI_ENOTSUPP;
break;
};
return 0;
if (ret)
sbi_dprintf(scratch, "%s: hartid%d: invalid csr_num=0x%x\n",
__func__, hartid, csr_num);
return ret;
}

View File

@@ -20,7 +20,7 @@ void sbi_fifo_init(struct sbi_fifo *fifo, void *queue_mem, u16 entries,
fifo->entry_size = entry_size;
SPIN_LOCK_INIT(&fifo->qlock);
fifo->avail = fifo->tail = 0;
sbi_memset(fifo->queue, 0, entries * entry_size);
sbi_memset(fifo->queue, 0, (size_t)entries * entry_size);
}
/* Note: must be called with fifo->qlock held */
@@ -54,6 +54,21 @@ bool sbi_fifo_is_full(struct sbi_fifo *fifo)
return ret;
}
/* Note: must be called with fifo->qlock held */
static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
{
u32 head;
head = (u32)fifo->tail + fifo->avail;
if (head >= fifo->num_entries)
head = head - fifo->num_entries;
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
fifo->avail++;
}
/* Note: must be called with fifo->qlock held */
static inline bool __sbi_fifo_is_empty(struct sbi_fifo *fifo)
{
@@ -74,9 +89,11 @@ bool sbi_fifo_is_empty(struct sbi_fifo *fifo)
/* Note: must be called with fifo->qlock held */
static inline void __sbi_fifo_reset(struct sbi_fifo *fifo)
{
size_t size = (size_t)fifo->num_entries * fifo->entry_size;
fifo->avail = 0;
fifo->tail = 0;
sbi_memset(fifo->queue, 0, fifo->num_entries * fifo->entry_size);
sbi_memset(fifo->queue, 0, size);
}
bool sbi_fifo_reset(struct sbi_fifo *fifo)
@@ -107,7 +124,9 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
if (!fifo || !in)
return ret;
spin_lock(&fifo->qlock);
if (__sbi_fifo_is_empty(fifo)) {
spin_unlock(&fifo->qlock);
return ret;
@@ -118,12 +137,10 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
if (index >= fifo->num_entries)
index = index - fifo->num_entries;
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
ret = fptr(in, entry);
ret = fptr(in, entry);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
break;
} else if (ret == SBI_FIFO_RESET) {
__sbi_fifo_reset(fifo);
break;
}
}
spin_unlock(&fifo->qlock);
@@ -133,8 +150,6 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
{
u32 head;
if (!fifo || !data)
return SBI_EINVAL;
@@ -144,14 +159,7 @@ int sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
spin_unlock(&fifo->qlock);
return SBI_ENOSPC;
}
head = (u32)fifo->tail + fifo->avail;
if (head >= fifo->num_entries)
head = head - fifo->num_entries;
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
fifo->avail++;
__sbi_fifo_enqueue(fifo, data);
spin_unlock(&fifo->qlock);

View File

@@ -52,8 +52,6 @@ static int fp_init(u32 hartid)
{
#ifdef __riscv_flen
int i;
#else
unsigned long fd_mask;
#endif
if (!misa_extension('D') && !misa_extension('F'))
@@ -66,11 +64,6 @@ static int fp_init(u32 hartid)
for (i = 0; i < 32; i++)
init_fp_reg(i);
csr_write(CSR_FCSR, 0);
#else
fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
csr_clear(CSR_MISA, fd_mask);
if (csr_read(CSR_MISA) & fd_mask)
return SBI_ENOTSUPP;
#endif
return 0;
@@ -94,6 +87,14 @@ static int delegate_traps(struct sbi_scratch *scratch, u32 hartid)
(1U << CAUSE_LOAD_PAGE_FAULT) |
(1U << CAUSE_STORE_PAGE_FAULT);
/*
* If hypervisor extension available then we only handle
* hypervisor calls (i.e. ecalls from HS-mode) and we let
* HS-mode handle supervisor calls (i.e. ecalls from VS-mode)
*/
if (misa_extension('H'))
exceptions |= (1U << CAUSE_SUPERVISOR_ECALL);
csr_write(CSR_MIDELEG, interrupts);
csr_write(CSR_MEDELEG, exceptions);
@@ -240,9 +241,14 @@ void __attribute__((noreturn)) sbi_hart_hang(void)
void __attribute__((noreturn))
sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
unsigned long next_addr, unsigned long next_mode)
unsigned long next_addr, unsigned long next_mode,
bool next_virt)
{
#if __riscv_xlen == 32
unsigned long val, valH;
#else
unsigned long val;
#endif
switch (next_mode) {
case PRV_M:
@@ -262,7 +268,25 @@ sbi_hart_switch_mode(unsigned long arg0, unsigned long arg1,
val = csr_read(CSR_MSTATUS);
val = INSERT_FIELD(val, MSTATUS_MPP, next_mode);
val = INSERT_FIELD(val, MSTATUS_MPIE, 0);
#if __riscv_xlen == 32
if (misa_extension('H')) {
valH = csr_read(CSR_MSTATUSH);
valH = INSERT_FIELD(valH, MSTATUSH_MTL, 0);
if (next_virt)
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 1);
else
valH = INSERT_FIELD(valH, MSTATUSH_MPV, 0);
csr_write(CSR_MSTATUSH, valH);
}
#else
if (misa_extension('H')) {
val = INSERT_FIELD(val, MSTATUS_MTL, 0);
if (next_virt)
val = INSERT_FIELD(val, MSTATUS_MPV, 1);
else
val = INSERT_FIELD(val, MSTATUS_MPV, 0);
}
#endif
csr_write(CSR_MSTATUS, val);
csr_write(CSR_MEPC, next_addr);
@@ -320,12 +344,12 @@ struct sbi_scratch *sbi_hart_id_to_scratch(struct sbi_scratch *scratch,
}
#define COLDBOOT_WAIT_BITMAP_SIZE __riscv_xlen
static spinlock_t coldboot_wait_bitmap_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_wait_bitmap = 0;
static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
static unsigned long coldboot_done = 0;
static unsigned long coldboot_wait_bitmap = 0;
void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
unsigned long mipval;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if ((sbi_platform_hart_count(plat) <= hartid) ||
@@ -335,20 +359,27 @@ void sbi_hart_wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
do {
spin_lock(&coldboot_wait_bitmap_lock);
coldboot_wait_bitmap |= (1UL << hartid);
spin_unlock(&coldboot_wait_bitmap_lock);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Mark current HART as waiting */
coldboot_wait_bitmap |= (1UL << hartid);
/* Wait for coldboot to finish using WFI */
while (!coldboot_done) {
spin_unlock(&coldboot_lock);
wfi();
mipval = csr_read(CSR_MIP);
spin_lock(&coldboot_lock);
};
spin_lock(&coldboot_wait_bitmap_lock);
coldboot_wait_bitmap &= ~(1UL << hartid);
spin_unlock(&coldboot_wait_bitmap_lock);
} while (!(mipval && MIP_MSIP));
/* Unmark current HART as waiting */
coldboot_wait_bitmap &= ~(1UL << hartid);
csr_clear(CSR_MIP, MIP_MSIP);
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
/* Clear current HART IPI */
sbi_platform_ipi_clear(plat, hartid);
}
void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
@@ -356,11 +387,18 @@ void sbi_hart_wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
int max_hart = sbi_platform_hart_count(plat);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
/* Mark coldboot done */
coldboot_done = 1;
/* Send an IPI to all HARTs waiting for coldboot */
for (int i = 0; i < max_hart; i++) {
/* send an IPI to every other hart */
spin_lock(&coldboot_wait_bitmap_lock);
if ((i != hartid) && (coldboot_wait_bitmap & (1UL << i)))
sbi_platform_ipi_send(plat, i);
spin_unlock(&coldboot_wait_bitmap_lock);
}
/* Release coldboot lock */
spin_unlock(&coldboot_lock);
}

View File

@@ -36,9 +36,22 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
int csr_num = (u32)insn >> 20;
ulong csr_val, new_csr_val;
if (sbi_emulate_csr_read(csr_num, hartid, regs->mstatus, scratch,
&csr_val))
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
/*
* WFI always traps as illegal instruction when executed from
* VS/VU mode so we just forward it to HS-mode.
*/
#if __riscv_xlen == 32
if ((regs->mstatusH & MSTATUSH_MPV) &&
#else
if ((regs->mstatus & MSTATUS_MPV) &&
#endif
(insn & INSN_MASK_WFI) == INSN_MATCH_WFI)
return sbi_trap_redirect(regs, scratch,
regs->mepc, mcause, insn);
if (sbi_emulate_csr_read(csr_num, hartid, regs, scratch, &csr_val))
return truly_illegal_insn(insn, hartid, mcause,
regs, scratch);
do_write = rs1_num;
switch (GET_RM(insn)) {
@@ -66,7 +79,7 @@ static int system_opcode_insn(ulong insn, u32 hartid, ulong mcause,
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
};
if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs->mstatus,
if (do_write && sbi_emulate_csr_write(csr_num, hartid, regs,
scratch, new_csr_val))
return truly_illegal_insn(insn, hartid, mcause, regs, scratch);
@@ -116,11 +129,21 @@ int sbi_illegal_insn_handler(u32 hartid, ulong mcause,
struct sbi_trap_regs *regs,
struct sbi_scratch *scratch)
{
ulong insn = csr_read(mbadaddr);
ulong insn = csr_read(CSR_MTVAL);
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
struct unpriv_trap uptrap;
if (unlikely((insn & 3) != 3)) {
if (insn == 0)
insn = get_insn(regs->mepc, NULL);
if (insn == 0) {
insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch,
regs->mepc, uptrap.cause, uptrap.tval);
}
if ((insn & 3) != 3)
return truly_illegal_insn(insn, hartid, mcause, regs,
scratch);

View File

@@ -34,8 +34,13 @@ static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
misa_string(str, sizeof(str));
#ifdef OPENSBI_VERSION_GIT
sbi_printf("\nOpenSBI %s (%s %s)\n", OPENSBI_VERSION_GIT,
__DATE__, __TIME__);
#else
sbi_printf("\nOpenSBI v%d.%d (%s %s)\n", OPENSBI_VERSION_MAJOR,
OPENSBI_VERSION_MINOR, __DATE__, __TIME__);
#endif
sbi_printf(BANNER);
@@ -97,7 +102,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_wake_coldboot_harts(scratch, hartid);
sbi_hart_mark_available(hartid);
sbi_hart_switch_mode(hartid, scratch->next_arg1, scratch->next_addr,
scratch->next_mode);
scratch->next_mode, FALSE);
}
static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
@@ -142,7 +147,8 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
else
sbi_hart_switch_mode(hartid, scratch->next_arg1,
scratch->next_addr, scratch->next_mode);
scratch->next_addr,
scratch->next_mode, FALSE);
}
static atomic_t coldboot_lottery = ATOMIC_INITIALIZER(0);

View File

@@ -9,15 +9,13 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_unpriv.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_tlb.h>
static unsigned long ipi_data_off;
@@ -40,20 +38,22 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event,
remote_scratch = sbi_hart_id_to_scratch(scratch, hartid);
ipi_data = sbi_scratch_offset_ptr(remote_scratch, ipi_data_off);
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID) {
ret = sbi_tlb_fifo_update(remote_scratch, event, data);
if (ret > 0)
goto done;
else if (ret < 0)
event == SBI_IPI_EVENT_SFENCE_VMA_ASID ||
event == SBI_IPI_EVENT_FENCE_I ) {
ret = sbi_tlb_fifo_update(remote_scratch, hartid, data);
if (ret < 0)
return ret;
}
atomic_raw_set_bit(event, &ipi_data->ipi_type);
mb();
smp_wmb();
sbi_platform_ipi_send(plat, hartid);
if (event != SBI_IPI_EVENT_SOFT)
sbi_platform_ipi_sync(plat, hartid);
done:
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID ||
event == SBI_IPI_EVENT_FENCE_I ) {
sbi_tlb_fifo_sync(scratch);
}
return 0;
}
@@ -70,12 +70,13 @@ int sbi_ipi_send_many(struct sbi_scratch *scratch, struct unpriv_trap *uptrap,
return SBI_ETRAP;
}
/* send IPIs to every other hart on the set */
/* Send IPIs to every other hart on the set */
for (i = 0, m = mask; m; i++, m >>= 1)
if ((m & 1UL) && (i != hartid))
sbi_ipi_send(scratch, i, event, data);
/* If the current hart is on the set, send an IPI
/*
* If the current hart is on the set, send an IPI
* to it as well
*/
if (mask & (1UL << hartid))
@@ -91,7 +92,7 @@ void sbi_ipi_clear_smode(struct sbi_scratch *scratch)
void sbi_ipi_process(struct sbi_scratch *scratch)
{
volatile unsigned long ipi_type;
unsigned long ipi_type;
unsigned int ipi_event;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_ipi_data *ipi_data =
@@ -100,27 +101,32 @@ void sbi_ipi_process(struct sbi_scratch *scratch)
u32 hartid = sbi_current_hartid();
sbi_platform_ipi_clear(plat, hartid);
do {
ipi_type = ipi_data->ipi_type;
rmb();
ipi_event = __ffs(ipi_type);
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
ipi_event = 0;
while (ipi_type) {
if (!(ipi_type & 1UL))
goto skip;
switch (ipi_event) {
case SBI_IPI_EVENT_SOFT:
csr_set(CSR_MIP, MIP_SSIP);
break;
case SBI_IPI_EVENT_FENCE_I:
__asm__ __volatile("fence.i");
break;
case SBI_IPI_EVENT_SFENCE_VMA:
case SBI_IPI_EVENT_SFENCE_VMA_ASID:
sbi_tlb_fifo_process(scratch, ipi_event);
sbi_tlb_fifo_process(scratch);
break;
case SBI_IPI_EVENT_HALT:
sbi_hart_hang();
break;
default:
break;
};
ipi_type = atomic_raw_clear_bit(ipi_event, &ipi_data->ipi_type);
} while (ipi_type > 0);
skip:
ipi_type = ipi_type >> 1;
ipi_event++;
};
}
int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot)

View File

@@ -27,9 +27,18 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
{
union reg_data val;
struct unpriv_trap uptrap;
ulong insn = get_insn(regs->mepc, NULL);
ulong addr = csr_read(CSR_MTVAL);
int i, fp = 0, shift = 0, len = 0;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
len = 4;
@@ -41,12 +50,14 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
} else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
len = 4;
#endif
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
fp = 1;
len = 8;
} else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
fp = 1;
len = 4;
#endif
} else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
len = 2;
shift = 8 * (sizeof(ulong) - len);
@@ -71,6 +82,7 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
((insn >> SH_RD) & 0x1f)) {
len = 4;
shift = 8 * (sizeof(ulong) - len);
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
fp = 1;
len = 8;
@@ -87,27 +99,29 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
fp = 1;
len = 4;
#endif
#endif
#endif
} else
return SBI_EILL;
return sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, addr);
val.data_u64 = 0;
for (i = 0; i < len; i++) {
val.data_bytes[i] = load_u8((void *)(addr + i),
scratch, &uptrap);
if (uptrap.cause) {
sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
return 0;
}
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
}
if (!fp)
SET_RD(insn, regs, val.data_ulong << shift >> shift);
#ifdef __riscv_flen
else if (len == 8)
SET_F64_RD(insn, regs, val.data_u64);
else
SET_F32_RD(insn, regs, val.data_ulong);
#endif
regs->mepc += INSN_LEN(insn);
@@ -120,9 +134,18 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
{
union reg_data val;
struct unpriv_trap uptrap;
ulong insn = get_insn(regs->mepc, NULL);
ulong addr = csr_read(CSR_MTVAL);
int i, len = 0;
#if __riscv_xlen == 32
bool virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
#else
bool virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
#endif
ulong insn = get_insn(regs->mepc, virt, scratch, &uptrap);
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
val.data_ulong = GET_RS2(insn, regs);
@@ -132,12 +155,14 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
} else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
len = 8;
#endif
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
len = 8;
val.data_u64 = GET_F64_RS2(insn, regs);
} else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
len = 4;
val.data_ulong = GET_F32_RS2(insn, regs);
#endif
} else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
len = 2;
#ifdef __riscv_compressed
@@ -157,6 +182,7 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
((insn >> SH_RD) & 0x1f)) {
len = 4;
val.data_ulong = GET_RS2C(insn, regs);
#ifdef __riscv_flen
} else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
len = 8;
val.data_u64 = GET_F64_RS2S(insn, regs);
@@ -171,18 +197,18 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
len = 4;
val.data_ulong = GET_F32_RS2C(insn, regs);
#endif
#endif
#endif
} else
return SBI_EILL;
return sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, addr);
for (i = 0; i < len; i++) {
store_u8((void *)(addr + i), val.data_bytes[i],
scratch, &uptrap);
if (uptrap.cause) {
sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
return 0;
}
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
}
regs->mepc += INSN_LEN(insn);

View File

@@ -9,9 +9,12 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_timer.h>
static unsigned long time_delta_off;
#if __riscv_xlen == 32
u64 get_ticks(void)
{
@@ -44,6 +47,35 @@ u64 sbi_timer_value(struct sbi_scratch *scratch)
return get_ticks();
}
u64 sbi_timer_virt_value(struct sbi_scratch *scratch)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
return sbi_timer_value(scratch) + *time_delta;
}
u64 sbi_timer_get_delta(struct sbi_scratch *scratch)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
return *time_delta;
}
void sbi_timer_set_delta(struct sbi_scratch *scratch, ulong delta)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = (u64)delta;
}
void sbi_timer_set_delta_upper(struct sbi_scratch *scratch, ulong delta_upper)
{
u64 *time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta &= 0xffffffffULL;
*time_delta |= ((u64)delta_upper << 32);
}
void sbi_timer_event_stop(struct sbi_scratch *scratch)
{
sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
@@ -64,5 +96,20 @@ void sbi_timer_process(struct sbi_scratch *scratch)
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{
u64 *time_delta;
if (cold_boot) {
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
"TIME_DELTA");
if (!time_delta_off)
return SBI_ENOMEM;
} else {
if (!time_delta_off)
return SBI_ENOMEM;
}
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = 0;
return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot);
}

View File

@@ -9,122 +9,21 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_barrier.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_fifo.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
static unsigned long ipi_tlb_fifo_off;
static unsigned long ipi_tlb_fifo_mem_off;
static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
struct sbi_tlb_info *next)
{
unsigned long curr_end;
unsigned long next_end;
int ret = SBI_FIFO_UNCHANGED;
if (!curr || !next)
return ret;
next_end = next->start + next->size;
curr_end = curr->start + curr->size;
if (next->start <= curr->start && next_end > curr_end) {
curr->start = next->start;
curr->size = next->size;
ret = SBI_FIFO_UPDATED;
} else if (next->start >= curr->start && next_end <= curr_end) {
ret = SBI_FIFO_SKIP;
}
return ret;
}
/**
* Call back to decide if an inplace fifo update is required or next entry can
* can be skipped. Here are the different cases that are being handled.
*
* Case1:
* if next flush request range lies within one of the existing entry, skip
* the next entry.
* Case2:
* if flush request range in current fifo entry lies within next flush
* request, update the current entry.
* Case3:
if a complete vma flush is requested, then all entries can be deleted
and new request can be enqueued. This will not be done for ASID case
as that means we have to iterate again in the fifo to figure out which
entries belong to that ASID.
*/
static int sbi_tlb_fifo_update_cb(void *in, void *data)
{
struct sbi_tlb_info *curr;
struct sbi_tlb_info *next;
int ret = SBI_FIFO_UNCHANGED;
if (!in && !!data)
return ret;
curr = (struct sbi_tlb_info *)data;
next = (struct sbi_tlb_info *)in;
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
if (next->asid == curr->asid)
ret = __sbi_tlb_fifo_range_check(curr, next);
} else if (next->type == SBI_TLB_FLUSH_VMA &&
curr->type == SBI_TLB_FLUSH_VMA) {
if (next->size == SBI_TLB_FLUSH_ALL)
ret = SBI_FIFO_RESET;
else
ret = __sbi_tlb_fifo_range_check(curr, next);
}
return ret;
}
int sbi_tlb_fifo_update(struct sbi_scratch *scratch, u32 event, void *data)
{
int ret;
struct sbi_fifo *ipi_tlb_fifo;
struct sbi_tlb_info *tinfo = data;
ipi_tlb_fifo = sbi_scratch_offset_ptr(scratch,
ipi_tlb_fifo_off);
/*
* If address range to flush is too big then simply
* upgrade it to flush all because we can only flush
* 4KB at a time.
*/
if (tinfo->size >= SBI_TLB_FLUSH_MAX_SIZE) {
tinfo->start = 0;
tinfo->size = SBI_TLB_FLUSH_ALL;
}
ret = sbi_fifo_inplace_update(ipi_tlb_fifo, data,
sbi_tlb_fifo_update_cb);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
return 1;
}
while (sbi_fifo_enqueue(ipi_tlb_fifo, data) < 0) {
/**
* For now, Busy loop until there is space in the fifo.
* There may be case where target hart is also
* enqueue in source hart's fifo. Both hart may busy
* loop leading to a deadlock.
* TODO: Introduce a wait/wakeup event mechansim to handle
* this properly.
*/
__asm__ __volatile("nop");
__asm__ __volatile("nop");
}
return 0;
}
static unsigned long tlb_sync_off;
static unsigned long tlb_fifo_off;
static unsigned long tlb_fifo_mem_off;
static unsigned long tlb_range_flush_limit;
static void sbi_tlb_flush_all(void)
{
@@ -179,48 +78,241 @@ static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
}
}
void sbi_tlb_fifo_process(struct sbi_scratch *scratch, u32 event)
static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
{
if (tinfo->type == SBI_TLB_FLUSH_VMA) {
sbi_tlb_fifo_sfence_vma(tinfo);
} else if (tinfo->type == SBI_TLB_FLUSH_VMA_ASID) {
sbi_tlb_fifo_sfence_vma_asid(tinfo);
} else if (tinfo->type == SBI_ITLB_FLUSH)
__asm__ __volatile("fence.i");
else
sbi_printf("Invalid tlb flush request type [%lu]\n",
tinfo->type);
return;
}
static void sbi_tlb_entry_process(struct sbi_scratch *scratch,
struct sbi_tlb_info *tinfo)
{
u32 i;
u64 m;
struct sbi_scratch *rscratch = NULL;
unsigned long *rtlb_sync = NULL;
sbi_tlb_local_flush(tinfo);
for (i = 0, m = tinfo->shart_mask; m; i++, m >>= 1) {
if (!(m & 1UL))
continue;
rscratch = sbi_hart_id_to_scratch(scratch, i);
rtlb_sync = sbi_scratch_offset_ptr(rscratch, tlb_sync_off);
while (atomic_raw_xchg_ulong(rtlb_sync, 1)) ;
}
}
static void sbi_tlb_fifo_process_count(struct sbi_scratch *scratch, int count)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *ipi_tlb_fifo =
sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_off);
u32 deq_count = 0;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
sbi_tlb_entry_process(scratch, &tinfo);
deq_count++;
if (deq_count > count)
break;
while (!sbi_fifo_dequeue(ipi_tlb_fifo, &tinfo)) {
if (tinfo.type == SBI_TLB_FLUSH_VMA)
sbi_tlb_fifo_sfence_vma(&tinfo);
else if (tinfo.type == SBI_TLB_FLUSH_VMA_ASID)
sbi_tlb_fifo_sfence_vma_asid(&tinfo);
sbi_memset(&tinfo, 0, SBI_TLB_INFO_SIZE);
}
}
void sbi_tlb_fifo_process(struct sbi_scratch *scratch)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo))
sbi_tlb_entry_process(scratch, &tinfo);
}
void sbi_tlb_fifo_sync(struct sbi_scratch *scratch)
{
unsigned long *tlb_sync =
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
while (!atomic_raw_xchg_ulong(tlb_sync, 0)) {
/*
* While we are waiting for remote hart to set the sync,
* consume fifo requests to avoid deadlock.
*/
sbi_tlb_fifo_process_count(scratch, 1);
}
return;
}
static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
struct sbi_tlb_info *next)
{
unsigned long curr_end;
unsigned long next_end;
int ret = SBI_FIFO_UNCHANGED;
if (!curr || !next)
return ret;
next_end = next->start + next->size;
curr_end = curr->start + curr->size;
if (next->start <= curr->start && next_end > curr_end) {
curr->start = next->start;
curr->size = next->size;
curr->shart_mask = curr->shart_mask | next->shart_mask;
ret = SBI_FIFO_UPDATED;
} else if (next->start >= curr->start && next_end <= curr_end) {
curr->shart_mask = curr->shart_mask | next->shart_mask;
ret = SBI_FIFO_SKIP;
}
return ret;
}
/**
* Call back to decide if an inplace fifo update is required or next entry can
* can be skipped. Here are the different cases that are being handled.
*
* Case1:
* if next flush request range lies within one of the existing entry, skip
* the next entry.
* Case2:
* if flush request range in current fifo entry lies within next flush
* request, update the current entry.
*
* Note:
* We can not issue a fifo reset anymore if a complete vma flush is requested.
* This is because we are queueing FENCE.I requests as well now.
* To ease up the pressure in enqueue/fifo sync path, try to dequeue 1 element
* before continuing the while loop. This method is preferred over wfi/ipi because
* of MMIO cost involved in later method.
*/
static int sbi_tlb_fifo_update_cb(void *in, void *data)
{
struct sbi_tlb_info *curr;
struct sbi_tlb_info *next;
int ret = SBI_FIFO_UNCHANGED;
if (!in || !data)
return ret;
curr = (struct sbi_tlb_info *)data;
next = (struct sbi_tlb_info *)in;
if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
curr->type == SBI_TLB_FLUSH_VMA_ASID) {
if (next->asid == curr->asid)
ret = __sbi_tlb_fifo_range_check(curr, next);
} else if (next->type == SBI_TLB_FLUSH_VMA &&
curr->type == SBI_TLB_FLUSH_VMA) {
ret = __sbi_tlb_fifo_range_check(curr, next);
}
return ret;
}
int sbi_tlb_fifo_update(struct sbi_scratch *rscratch, u32 hartid, void *data)
{
int ret;
struct sbi_fifo *tlb_fifo_r;
struct sbi_scratch *lscratch;
struct sbi_tlb_info *tinfo = data;
u32 curr_hartid = sbi_current_hartid();
/*
* If address range to flush is too big then simply
* upgrade it to flush all because we can only flush
* 4KB at a time.
*/
if (tinfo->size > tlb_range_flush_limit) {
tinfo->start = 0;
tinfo->size = SBI_TLB_FLUSH_ALL;
}
/*
* If the request is to queue a tlb flush entry for itself
* then just do a local flush and return;
*/
if (hartid == curr_hartid) {
sbi_tlb_local_flush(tinfo);
return -1;
}
lscratch = sbi_hart_id_to_scratch(rscratch, curr_hartid);
tlb_fifo_r = sbi_scratch_offset_ptr(rscratch, tlb_fifo_off);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, sbi_tlb_fifo_update_cb);
if (ret != SBI_FIFO_UNCHANGED) {
return 1;
}
while (sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
/**
* For now, Busy loop until there is space in the fifo.
* There may be case where target hart is also
* enqueue in source hart's fifo. Both hart may busy
* loop leading to a deadlock.
* TODO: Introduce a wait/wakeup event mechanism to handle
* this properly.
*/
sbi_tlb_fifo_process_count(lscratch, 1);
sbi_dprintf(rscratch, "hart%d: hart%d tlb fifo full\n",
curr_hartid, hartid);
}
return 0;
}
int sbi_tlb_fifo_init(struct sbi_scratch *scratch, bool cold_boot)
{
void *ipi_tlb_mem;
struct sbi_fifo *ipi_tlb_q;
void *tlb_mem;
unsigned long *tlb_sync;
struct sbi_fifo *tlb_q;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (cold_boot) {
ipi_tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*ipi_tlb_q),
"IPI_TLB_FIFO");
if (!ipi_tlb_fifo_off)
tlb_sync_off = sbi_scratch_alloc_offset(sizeof(*tlb_sync),
"IPI_TLB_SYNC");
if (!tlb_sync_off)
return SBI_ENOMEM;
ipi_tlb_fifo_mem_off = sbi_scratch_alloc_offset(
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE,
"IPI_TLB_FIFO_MEM");
if (!ipi_tlb_fifo_mem_off) {
sbi_scratch_free_offset(ipi_tlb_fifo_off);
tlb_fifo_off = sbi_scratch_alloc_offset(sizeof(*tlb_q),
"IPI_TLB_FIFO");
if (!tlb_fifo_off) {
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;
}
tlb_fifo_mem_off = sbi_scratch_alloc_offset(
SBI_TLB_FIFO_NUM_ENTRIES * SBI_TLB_INFO_SIZE,
"IPI_TLB_FIFO_MEM");
if (!tlb_fifo_mem_off) {
sbi_scratch_free_offset(tlb_fifo_off);
sbi_scratch_free_offset(tlb_sync_off);
return SBI_ENOMEM;
}
tlb_range_flush_limit = sbi_platform_tlbr_flush_limit(plat);
} else {
if (!ipi_tlb_fifo_off ||
!ipi_tlb_fifo_mem_off)
if (!tlb_sync_off ||
!tlb_fifo_off ||
!tlb_fifo_mem_off)
return SBI_ENOMEM;
}
ipi_tlb_q = sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_off);
ipi_tlb_mem = sbi_scratch_offset_ptr(scratch, ipi_tlb_fifo_mem_off);
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
tlb_q = sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
tlb_mem = sbi_scratch_offset_ptr(scratch, tlb_fifo_mem_off);
sbi_fifo_init(ipi_tlb_q, ipi_tlb_mem,
*tlb_sync = 0;
sbi_fifo_init(tlb_q, tlb_mem,
SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);
return 0;

View File

@@ -79,41 +79,119 @@ static void __noreturn sbi_trap_error(const char *msg, int rc, u32 hartid,
int sbi_trap_redirect(struct sbi_trap_regs *regs, struct sbi_scratch *scratch,
ulong epc, ulong cause, ulong tval)
{
ulong new_mstatus, prev_mode;
ulong hstatus, vsstatus, prev_mode;
#if __riscv_xlen == 32
bool prev_virt = (regs->mstatusH & MSTATUSH_MPV) ? TRUE : FALSE;
bool prev_stage2 = (regs->mstatusH & MSTATUSH_MTL) ? TRUE : FALSE;
#else
bool prev_virt = (regs->mstatus & MSTATUS_MPV) ? TRUE : FALSE;
bool prev_stage2 = (regs->mstatus & MSTATUS_MTL) ? TRUE : FALSE;
#endif
/* By default, we redirect to HS-mode */
bool next_virt = FALSE;
/* Sanity check on previous mode */
prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_ENOTSUPP;
/* Update S-mode exception info */
csr_write(CSR_STVAL, tval);
csr_write(CSR_SEPC, epc);
csr_write(CSR_SCAUSE, cause);
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
if (misa_extension('H') && prev_virt && !prev_stage2) {
switch (cause) {
case CAUSE_FETCH_PAGE_FAULT:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
next_virt = TRUE;
break;
default:
break;
};
}
/* Set MEPC to S-mode exception vector base */
regs->mepc = csr_read(CSR_STVEC);
/* Update MSTATUS MPV and MTL bits */
#if __riscv_xlen == 32
regs->mstatusH &= ~MSTATUSH_MPV;
regs->mstatusH |= (next_virt) ? MSTATUSH_MPV : 0UL;
regs->mstatusH &= ~MSTATUSH_MTL;
#else
regs->mstatus &= ~MSTATUS_MPV;
regs->mstatus |= (next_virt) ? MSTATUS_MPV : 0UL;
regs->mstatus &= ~MSTATUS_MTL;
#endif
/* Initial value of new MSTATUS */
new_mstatus = regs->mstatus;
/* Update HSTATUS for VS/VU-mode to HS-mode transition */
if (misa_extension('H') && prev_virt && !next_virt) {
/* Update HSTATUS SP2P, SP2V, SPV, and STL bits */
hstatus = csr_read(CSR_HSTATUS);
hstatus &= ~HSTATUS_SP2P;
hstatus |= (regs->mstatus & MSTATUS_SPP) ? HSTATUS_SP2P : 0;
hstatus &= ~HSTATUS_SP2V;
hstatus |= (hstatus & HSTATUS_SPV) ? HSTATUS_SP2V : 0;
hstatus &= ~HSTATUS_SPV;
hstatus |= (prev_virt) ? HSTATUS_SPV : 0;
hstatus &= ~HSTATUS_STL;
hstatus |= (prev_stage2) ? HSTATUS_STL : 0;
csr_write(CSR_HSTATUS, hstatus);
}
/* Clear MPP, SPP, SPIE, and SIE */
new_mstatus &=
~(MSTATUS_MPP | MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE);
/* Update exception related CSRs */
if (next_virt) {
/* Update VS-mode exception info */
csr_write(CSR_VSTVAL, tval);
csr_write(CSR_VSEPC, epc);
csr_write(CSR_VSCAUSE, cause);
/* Set SPP */
if (prev_mode == PRV_S)
new_mstatus |= (1UL << MSTATUS_SPP_SHIFT);
/* Set MEPC to VS-mode exception vector base */
regs->mepc = csr_read(CSR_VSTVEC);
/* Set SPIE */
if (regs->mstatus & MSTATUS_SIE)
new_mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
/* Set MPP to VS-mode */
regs->mstatus &= ~MSTATUS_MPP;
regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
/* Set MPP */
new_mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
/* Get VS-mode SSTATUS CSR */
vsstatus = csr_read(CSR_VSSTATUS);
/* Set new value in MSTATUS */
regs->mstatus = new_mstatus;
/* Set SPP for VS-mode */
vsstatus &= ~SSTATUS_SPP;
if (prev_mode == PRV_S)
vsstatus |= (1UL << SSTATUS_SPP_SHIFT);
/* Set SPIE for VS-mode */
vsstatus &= ~SSTATUS_SPIE;
if (vsstatus & SSTATUS_SIE)
vsstatus |= (1UL << SSTATUS_SPIE_SHIFT);
/* Clear SIE for VS-mode */
vsstatus &= ~SSTATUS_SIE;
/* Update VS-mode SSTATUS CSR */
csr_write(CSR_VSSTATUS, vsstatus);
} else {
/* Update S-mode exception info */
csr_write(CSR_STVAL, tval);
csr_write(CSR_SEPC, epc);
csr_write(CSR_SCAUSE, cause);
/* Set MEPC to S-mode exception vector base */
regs->mepc = csr_read(CSR_STVEC);
/* Set MPP to S-mode */
regs->mstatus &= ~MSTATUS_MPP;
regs->mstatus |= (PRV_S << MSTATUS_MPP_SHIFT);
/* Set SPP for S-mode*/
regs->mstatus &= ~MSTATUS_SPP;
if (prev_mode == PRV_S)
regs->mstatus |= (1UL << MSTATUS_SPP_SHIFT);
/* Set SPIE for S-mode */
regs->mstatus &= ~MSTATUS_SPIE;
if (regs->mstatus & MSTATUS_SIE)
regs->mstatus |= (1UL << MSTATUS_SPIE_SHIFT);
/* Clear SIE for S-mode */
regs->mstatus &= ~MSTATUS_SIE;
}
return 0;
}
@@ -195,7 +273,8 @@ void sbi_trap_handler(struct sbi_trap_regs *regs, struct sbi_scratch *scratch)
break;
default:
/* If the trap came from S or U mode, redirect it there */
rc = sbi_trap_redirect(regs, scratch, regs->mepc, mcause, mtval);
rc = sbi_trap_redirect(regs, scratch, regs->mepc,
mcause, mtval);
break;
};

View File

@@ -51,7 +51,7 @@ void plic_fdt_fixup(void *fdt, const char *compat)
{
u32 *cells;
int i, cells_count;
u32 plic_off;
int plic_off;
plic_off = fdt_node_offset_by_compatible(fdt, 0, compat);
if (plic_off < 0)
@@ -68,7 +68,7 @@ void plic_fdt_fixup(void *fdt, const char *compat)
for (i = 0; i < (cells_count / 2); i++) {
if (fdt32_to_cpu(cells[2 * i + 1]) == IRQ_M_EXT)
cells[2 * i + 1] = fdt32_to_cpu(0xffffffff);
cells[2 * i + 1] = cpu_to_fdt32(0xffffffff);
}
}

View File

@@ -25,29 +25,6 @@ void clint_ipi_send(u32 target_hart)
writel(1, &clint_ipi[target_hart]);
}
void clint_ipi_sync(u32 target_hart)
{
u32 target_ipi, incoming_ipi;
u32 source_hart = sbi_current_hartid();
if (clint_ipi_hart_count <= target_hart)
return;
/* Wait until target HART has handled IPI */
incoming_ipi = 0;
while (1) {
target_ipi = readl(&clint_ipi[target_hart]);
if (!target_ipi)
break;
incoming_ipi |=
atomic_raw_xchg_uint(&clint_ipi[source_hart], 0);
}
if (incoming_ipi)
writel(incoming_ipi, &clint_ipi[source_hart]);
}
void clint_ipi_clear(u32 target_hart)
{
if (clint_ipi_hart_count <= target_hart)
@@ -85,16 +62,24 @@ static volatile void *clint_time_base;
static volatile u64 *clint_time_val;
static volatile u64 *clint_time_cmp;
static inline u32 clint_time_read_hi()
{
return readl_relaxed((u32 *)clint_time_val + 1);
}
u64 clint_timer_value(void)
{
#if __riscv_xlen == 64
return readq_relaxed(clint_time_val);
#else
u64 tmp;
tmp = readl_relaxed((void *)clint_time_val + 0x04);
tmp <<= 32;
tmp |= readl_relaxed(clint_time_val);
return tmp;
u32 lo, hi;
do {
hi = clint_time_read_hi();
lo = readl_relaxed(clint_time_val);
} while (hi != clint_time_read_hi());
return ((u64)hi << 32) | (u64)lo;
#endif
}

View File

@@ -0,0 +1,36 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Andes Technology Corporation
#
# Authors:
# Zong Li <zong@andestech.com>
# Nylon Chen <nylon7@andestech.com>
# Compiler flags
platform-cppflags-y =
platform-cflags-y =
platform-asflags-y =
platform-ldflags-y =
# Blobs to build
FW_TEXT_START=0x00000000
FW_DYNAMIC=y
FW_JUMP=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
FW_JUMP_ADDR=0x400000
else
FW_JUMP_ADDR=0x200000
endif
FW_JUMP_FDT_ADDR=0x2000000
FW_PAYLOAD=y
ifeq ($(PLATFORM_RISCV_XLEN), 32)
FW_PAYLOAD_OFFSET=0x400000
else
FW_PAYLOAD_OFFSET=0x200000
endif
FW_PAYLOAD_FDT_ADDR=0x2000000

View File

@@ -0,0 +1,11 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2019 Andes Technology Corporation
#
# Authors:
# Zong Li <zong@andestech.com>
# Nylon Chen <nylon7@andestech.com>
#
platform-objs-y += plicsw.o plmt.o platform.o

View File

@@ -0,0 +1,194 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/serial/uart8250.h>
#include <sbi_utils/irqchip/plic.h>
#include "platform.h"
#include "plmt.h"
#include "plicsw.h"
/* Platform final initialization. */
static int ae350_final_init(bool cold_boot)
{
void *fdt;
/* enable L1 cache */
uintptr_t mcache_ctl_val = csr_read(CSR_MCACHECTL);
if (!(mcache_ctl_val & V5_MCACHE_CTL_IC_EN))
mcache_ctl_val |= V5_MCACHE_CTL_IC_EN;
if (!(mcache_ctl_val & V5_MCACHE_CTL_DC_EN))
mcache_ctl_val |= V5_MCACHE_CTL_DC_EN;
if (!(mcache_ctl_val & V5_MCACHE_CTL_CCTL_SUEN))
mcache_ctl_val |= V5_MCACHE_CTL_CCTL_SUEN;
csr_write(CSR_MCACHECTL, mcache_ctl_val);
/* enable L2 cache */
uint32_t *l2c_ctl_base = (void *)AE350_L2C_ADDR + V5_L2C_CTL_OFFSET;
uint32_t l2c_ctl_val = *l2c_ctl_base;
if (!(l2c_ctl_val & V5_L2C_CTL_ENABLE_MASK))
l2c_ctl_val |= V5_L2C_CTL_ENABLE_MASK;
*l2c_ctl_base = l2c_ctl_val;
if (!cold_boot)
return 0;
fdt = sbi_scratch_thishart_arg1_ptr();
plic_fdt_fixup(fdt, "riscv,plic0");
return 0;
}
/* Get number of PMP regions for given HART. */
static u32 ae350_pmp_region_count(u32 hartid)
{
return 1;
}
/*
* Get PMP regions details (namely: protection, base address, and size) for
* a given HART.
*/
static int ae350_pmp_region_info(u32 hartid, u32 index, ulong *prot,
ulong *addr, ulong *log2size)
{
int ret = 0;
switch (index) {
case 0:
*prot = PMP_R | PMP_W | PMP_X;
*addr = 0;
*log2size = __riscv_xlen;
break;
default:
ret = -1;
break;
};
return ret;
}
/* Initialize the platform console. */
static int ae350_console_init(void)
{
return uart8250_init(AE350_UART_ADDR,
AE350_UART_FREQUENCY,
AE350_UART_BAUDRATE,
AE350_UART_REG_SHIFT,
AE350_UART_REG_WIDTH);
}
/* Initialize the platform interrupt controller for current HART. */
static int ae350_irqchip_init(bool cold_boot)
{
u32 hartid = sbi_current_hartid();
int ret;
if (cold_boot) {
ret = plic_cold_irqchip_init(AE350_PLIC_ADDR,
AE350_PLIC_NUM_SOURCES,
AE350_HART_COUNT);
if (ret)
return ret;
}
return plic_warm_irqchip_init(hartid, 2 * hartid, 2 * hartid + 1);
}
/* Initialize IPI for current HART. */
static int ae350_ipi_init(bool cold_boot)
{
int ret;
if (cold_boot) {
ret = plicsw_cold_ipi_init(AE350_PLICSW_ADDR,
AE350_HART_COUNT);
if (ret)
return ret;
}
return plicsw_warm_ipi_init();
}
/* Initialize platform timer for current HART. */
static int ae350_timer_init(bool cold_boot)
{
int ret;
if (cold_boot) {
ret = plmt_cold_timer_init(AE350_PLMT_ADDR,
AE350_HART_COUNT);
if (ret)
return ret;
}
return plmt_warm_timer_init();
}
/* Reboot the platform. */
static int ae350_system_reboot(u32 type)
{
/* For now nothing to do. */
sbi_printf("System reboot\n");
return 0;
}
/* Shutdown or poweroff the platform. */
static int ae350_system_shutdown(u32 type)
{
/* For now nothing to do. */
sbi_printf("System shutdown\n");
return 0;
}
/* Platform descriptor. */
const struct sbi_platform_operations platform_ops = {
.final_init = ae350_final_init,
.pmp_region_count = ae350_pmp_region_count,
.pmp_region_info = ae350_pmp_region_info,
.console_init = ae350_console_init,
.console_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,
.system_reboot = ae350_system_reboot,
.system_shutdown = ae350_system_shutdown
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "Andes AE350",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = AE350_HART_COUNT,
.hart_stack_size = AE350_HART_STACK_SIZE,
.disabled_hart_mask = 0,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -0,0 +1,67 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#ifndef _AE350_PLATFORM_H_
#define _AE350_PLATFORM_H_
#define AE350_HART_COUNT 4
#define AE350_HART_STACK_SIZE 8192
#define AE350_PLIC_ADDR 0xe4000000
#define AE350_PLIC_NUM_SOURCES 71
#define AE350_PLICSW_ADDR 0xe6400000
#define AE350_PLMT_ADDR 0xe6000000
#define AE350_L2C_ADDR 0xe0500000
#define AE350_UART_ADDR_OFFSET 0x20
#define AE350_UART_ADDR (0xf0300000 + AE350_UART_ADDR_OFFSET)
#define AE350_UART_FREQUENCY 19660800
#define AE350_UART_BAUDRATE 38400
#define AE350_UART_REG_SHIFT 2
#define AE350_UART_REG_WIDTH 0
/* nds mcache_ctl register*/
#define CSR_MCACHECTL 0x7ca
#define V5_MCACHE_CTL_IC_EN_OFFSET 0
#define V5_MCACHE_CTL_DC_EN_OFFSET 1
#define V5_MCACHE_CTL_IC_ECCEN_OFFSET 2
#define V5_MCACHE_CTL_DC_ECCEN_OFFSET 4
#define V5_MCACHE_CTL_IC_RWECC_OFFSET 6
#define V5_MCACHE_CTL_DC_RWECC_OFFSET 7
#define V5_MCACHE_CTL_CCTL_SUEN_OFFSET 8
#define V5_MCACHE_CTL_IC_EN (1UL << V5_MCACHE_CTL_IC_EN_OFFSET)
#define V5_MCACHE_CTL_DC_EN (1UL << V5_MCACHE_CTL_DC_EN_OFFSET)
#define V5_MCACHE_CTL_IC_RWECC (1UL << V5_MCACHE_CTL_IC_RWECC_OFFSET)
#define V5_MCACHE_CTL_DC_RWECC (1UL << V5_MCACHE_CTL_DC_RWECC_OFFSET)
#define V5_MCACHE_CTL_CCTL_SUEN (1UL << V5_MCACHE_CTL_CCTL_SUEN_OFFSET)
#define V5_L2C_CTL_OFFSET 0x8
#define V5_L2C_CTL_ENABLE_OFFSET 0
#define V5_L2C_CTL_IPFDPT_OFFSET 3
#define V5_L2C_CTL_DPFDPT_OFFSET 5
#define V5_L2C_CTL_TRAMOCTL_OFFSET 8
#define V5_L2C_CTL_TRAMICTL_OFFSET 10
#define V5_L2C_CTL_DRAMOCTL_OFFSET 11
#define V5_L2C_CTL_DRAMICTL_OFFSET 13
#define V5_L2C_CTL_ENABLE_MASK (1UL << V5_L2C_CTL_ENABLE_OFFSET)
#define V5_L2C_CTL_IPFDPT_MASK (3UL << V5_L2C_CTL_IPFDPT_OFFSET)
#define V5_L2C_CTL_DPFDPT_MASK (3UL << V5_L2C_CTL_DPFDPT_OFFSET)
#define V5_L2C_CTL_TRAMOCTL_MASK (3UL << V5_L2C_CTL_TRAMOCTL_OFFSET)
#define V5_L2C_CTL_TRAMICTL_MASK (1UL << V5_L2C_CTL_TRAMICTL_OFFSET)
#define V5_L2C_CTL_DRAMOCTL_MASK (3UL << V5_L2C_CTL_DRAMOCTL_OFFSET)
#define V5_L2C_CTL_DRAMICTL_MASK (1UL << V5_L2C_CTL_DRAMICTL_OFFSET)
#endif /* _AE350_PLATFORM_H_ */

View File

@@ -0,0 +1,145 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/sbi_types.h>
#include <sbi/sbi_hart.h>
#include <sbi/riscv_io.h>
#include "plicsw.h"
#include "platform.h"
static u32 plicsw_ipi_hart_count;
static struct plicsw plicsw_dev[AE350_HART_COUNT];
static inline void plicsw_claim(void)
{
u32 source_hart = sbi_current_hartid();
plicsw_dev[source_hart].source_id =
readl(plicsw_dev[source_hart].plicsw_claim);
}
static inline void plicsw_complete(void)
{
u32 source_hart = sbi_current_hartid();
u32 source = plicsw_dev[source_hart].source_id;
writel(source, plicsw_dev[source_hart].plicsw_claim);
}
static inline u32 plicsw_get_pending(u32 source_hart, u32 target_hart)
{
return readl(plicsw_dev[source_hart].plicsw_pending)
& (PLICSW_HART_MASK >> target_hart);
}
static inline void plic_sw_pending(u32 target_hart)
{
/*
* The pending array registers are w1s type.
* IPI pending array mapping as following:
*
* Pending array start address: base + 0x1000
* -------------------------------------
* | hart 3 | hart 2 | hart 1 | hart 0 |
* -------------------------------------
* Each hart X can send IPI to another hart by setting the
* corresponding bit in hart X own region(see the below).
*
* In each hart region:
* -----------------------------------------------
* | bit 7 | bit 6 | bit 5 | bit 4 | ... | bit 0 |
* -----------------------------------------------
* The bit 7 is used to send IPI to hart 0
* The bit 6 is used to send IPI to hart 1
* The bit 5 is used to send IPI to hart 2
* The bit 4 is used to send IPI to hart 3
*/
u32 source_hart = sbi_current_hartid();
u32 target_offset = (PLICSW_PENDING_PER_HART - 1) - target_hart;
u32 per_hart_offset = PLICSW_PENDING_PER_HART * source_hart;
u32 val = 1 << target_offset << per_hart_offset;
writel(val, plicsw_dev[source_hart].plicsw_pending);
}
void plicsw_ipi_send(u32 target_hart)
{
if (plicsw_ipi_hart_count <= target_hart)
return;
/* Set PLICSW IPI */
plic_sw_pending(target_hart);
}
void plicsw_ipi_clear(u32 target_hart)
{
if (plicsw_ipi_hart_count <= target_hart)
return;
/* Clear CLINT IPI */
plicsw_claim();
plicsw_complete();
}
int plicsw_warm_ipi_init(void)
{
u32 hartid = sbi_current_hartid();
if (!plicsw_dev[hartid].plicsw_pending
&& !plicsw_dev[hartid].plicsw_enable
&& !plicsw_dev[hartid].plicsw_claim)
return -1;
/* Clear PLICSW IPI */
plicsw_ipi_clear(hartid);
return 0;
}
int plicsw_cold_ipi_init(unsigned long base, u32 hart_count)
{
/* Setup source priority */
uint32_t *priority = (void *)base + PLICSW_PRIORITY_BASE;
for (int i = 0; i < AE350_HART_COUNT*PLICSW_PENDING_PER_HART; i++)
writel(1, &priority[i]);
/* Setup target enable.*/
uint32_t enable_mask = PLICSW_HART_MASK;
for (int i = 0; i < AE350_HART_COUNT; i++) {
uint32_t *enable = (void *)base + PLICSW_ENABLE_BASE
+ PLICSW_ENABLE_PER_HART * i;
writel(enable_mask, &enable[0]);
enable_mask >>= 1;
}
/* Figure-out PLICSW IPI register address */
plicsw_ipi_hart_count = hart_count;
for (u32 hartid = 0; hartid < AE350_HART_COUNT; hartid++) {
plicsw_dev[hartid].source_id = 0;
plicsw_dev[hartid].plicsw_pending =
(void *)base
+ PLICSW_PENDING_BASE
+ ((hartid / 4) * 4);
plicsw_dev[hartid].plicsw_enable =
(void *)base
+ PLICSW_ENABLE_BASE
+ PLICSW_ENABLE_PER_HART * hartid;
plicsw_dev[hartid].plicsw_claim =
(void *)base
+ PLICSW_CONTEXT_BASE
+ PLICSW_CONTEXT_CLAIM
+ PLICSW_CONTEXT_PER_HART * hartid;
}
return 0;
}

View File

@@ -0,0 +1,46 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#ifndef _AE350_PLICSW_H_
#define _AE350_PLICSW_H_
#define PLICSW_PRIORITY_BASE 0x4
#define PLICSW_PENDING_BASE 0x1000
#define PLICSW_PENDING_PER_HART 0x8
#define PLICSW_ENABLE_BASE 0x2000
#define PLICSW_ENABLE_PER_HART 0x80
#define PLICSW_CONTEXT_BASE 0x200000
#define PLICSW_CONTEXT_PER_HART 0x1000
#define PLICSW_CONTEXT_CLAIM 0x4
#define PLICSW_HART_MASK 0x80808080
struct plicsw {
u32 source_id;
volatile uint32_t *plicsw_pending;
volatile uint32_t *plicsw_enable;
volatile uint32_t *plicsw_claim;
};
void plicsw_ipi_send(u32 target_hart);
void plicsw_ipi_sync(u32 target_hart);
void plicsw_ipi_clear(u32 target_hart);
int plicsw_warm_ipi_init(void);
int plicsw_cold_ipi_init(unsigned long base, u32 hart_count);
#endif /* _AE350_PLICSW_H_ */

View File

@@ -0,0 +1,97 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
* Nylon Chen <nylon7@andestech.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_hart.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)
{
#if __riscv_xlen == 64
return readq_relaxed(plmt_time_val);
#else
u32 lo, hi;
do {
hi = readl_relaxed((void *)plmt_time_val + 0x04);
lo = readl_relaxed(plmt_time_val);
} while (hi != readl_relaxed((void *)plmt_time_val + 0x04));
return ((u64)hi << 32) | (u64)lo;
#endif
}
void plmt_timer_event_stop(void)
{
u32 target_hart = sbi_current_hartid();
if (plmt_time_hart_count <= target_hart)
return;
/* Clear PLMT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
#else
writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
#endif
}
void plmt_timer_event_start(u64 next_event)
{
u32 target_hart = sbi_current_hartid();
if (plmt_time_hart_count <= target_hart)
return;
/* Program PLMT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(next_event, &plmt_time_cmp[target_hart]);
#else
u32 mask = -1UL;
writel_relaxed(next_event & mask, &plmt_time_cmp[target_hart]);
writel_relaxed(next_event >> 32,
(void *)(&plmt_time_cmp[target_hart]) + 0x04);
#endif
}
int plmt_warm_timer_init(void)
{
u32 target_hart = sbi_current_hartid();
if (plmt_time_hart_count <= target_hart || !plmt_time_base)
return -1;
/* Clear PLMT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
#else
writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
#endif
return 0;
}
int plmt_cold_timer_init(unsigned long base, u32 hart_count)
{
plmt_time_hart_count = hart_count;
plmt_time_base = (void *)base;
plmt_time_val = (u64 *)(plmt_time_base);
plmt_time_cmp = (u64 *)(plmt_time_base + 0x8);
return 0;
}

View File

@@ -0,0 +1,23 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Andes Technology Corporation
*
* Authors:
* Zong Li <zong@andestech.com>
*/
#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);
#endif /* _AE350_PLMT_H_ */

View File

@@ -185,7 +185,6 @@ const struct sbi_platform_operations platform_ops = {
.irqchip_init = ariane_irqchip_init,
.ipi_init = ariane_ipi_init,
.ipi_send = clint_ipi_send,
.ipi_sync = clint_ipi_sync,
.ipi_clear = clint_ipi_clear,
.timer_init = ariane_timer_init,
.timer_value = clint_timer_value,

View File

@@ -7,5 +7,5 @@
# Damien Le Moal <damien.lemoal@wdc.com>
#
platform-objs-y += uarths.o sysctl.o platform.o
platform-objs-y += platform.o
platform-dtb-y += k210.dtb

View File

@@ -14,26 +14,42 @@
#include <sbi/sbi_console.h>
#include <sbi_utils/irqchip/plic.h>
#include <sbi_utils/sys/clint.h>
#include <sbi_utils/serial/sifive-uart.h>
#include "platform.h"
#include "uarths.h"
#define K210_UART_BAUDRATE 115200
static u32 k210_get_clk_freq(void)
{
u32 clksel0, pll0;
u64 pll0_freq, clkr0, clkf0, clkod0, div;
/*
* If the clock selector is not set, use the base frequency.
* Otherwise, use PLL0 frequency with a frequency divisor.
*/
clksel0 = k210_read_sysreg(K210_CLKSEL0);
if (!(clksel0 & 0x1))
return K210_CLK0_FREQ;
/*
* Get PLL0 frequency:
* freq = base frequency * clkf0 / (clkr0 * clkod0)
*/
pll0 = k210_read_sysreg(K210_PLL0);
clkr0 = 1 + (pll0 & 0x0000000f);
clkf0 = 1 + ((pll0 & 0x000003f0) >> 4);
clkod0 = 1 + ((pll0 & 0x00003c00) >> 10);
pll0_freq = clkf0 * K210_CLK0_FREQ / (clkr0 * clkod0);
/* Get the frequency divisor from the clock selector */
div = 2ULL << ((clksel0 & 0x00000006) >> 1);
return pll0_freq / div;
}
static int k210_console_init(void)
{
uarths_init(K210_UART_BAUDRATE, UARTHS_STOP_1);
return 0;
}
static void k210_console_putc(char c)
{
uarths_putc(c);
}
static int k210_console_getc(void)
{
return uarths_getc();
return sifive_uart_init(K210_UART_BASE_ADDR, k210_get_clk_freq(),
K210_UART_BAUDRATE);
}
static int k210_irqchip_init(bool cold_boot)
@@ -42,13 +58,14 @@ static int k210_irqchip_init(bool cold_boot)
u32 hartid = sbi_current_hartid();
if (cold_boot) {
rc = plic_cold_irqchip_init(PLIC_BASE_ADDR, PLIC_NUM_SOURCES,
rc = plic_cold_irqchip_init(K210_PLIC_BASE_ADDR,
K210_PLIC_NUM_SOURCES,
K210_HART_COUNT);
if (rc)
return rc;
}
return plic_warm_irqchip_init(hartid, (2 * hartid), (2 * hartid + 1));
return plic_warm_irqchip_init(hartid, hartid * 2, hartid * 2 + 1);
}
static int k210_ipi_init(bool cold_boot)
@@ -56,7 +73,8 @@ static int k210_ipi_init(bool cold_boot)
int rc;
if (cold_boot) {
rc = clint_cold_ipi_init(CLINT_BASE_ADDR, K210_HART_COUNT);
rc = clint_cold_ipi_init(K210_CLINT_BASE_ADDR,
K210_HART_COUNT);
if (rc)
return rc;
}
@@ -69,7 +87,8 @@ static int k210_timer_init(bool cold_boot)
int rc;
if (cold_boot) {
rc = clint_cold_timer_init(CLINT_BASE_ADDR, K210_HART_COUNT);
rc = clint_cold_timer_init(K210_CLINT_BASE_ADDR,
K210_HART_COUNT);
if (rc)
return rc;
}
@@ -95,14 +114,13 @@ static int k210_system_shutdown(u32 type)
const struct sbi_platform_operations platform_ops = {
.console_init = k210_console_init,
.console_putc = k210_console_putc,
.console_getc = k210_console_getc,
.console_putc = sifive_uart_putc,
.console_getc = sifive_uart_getc,
.irqchip_init = k210_irqchip_init,
.ipi_init = k210_ipi_init,
.ipi_send = clint_ipi_send,
.ipi_sync = clint_ipi_sync,
.ipi_clear = clint_ipi_clear,
.timer_init = k210_timer_init,

View File

@@ -1,178 +1,37 @@
/*
* SPDX-License-Identifier: Apache-2.0
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2018 Canaan Inc.
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Authors:
* Damien Le Moal <damien.lemoal@wdc.com>
*/
#ifndef _K210_PLATFORM_H_
#define _K210_PLATFORM_H_
#ifndef _PLATFORM_H_
#define _PLATFORM_H_
#include <sbi/riscv_asm.h>
/* clang-format off */
#include <sbi/riscv_io.h>
#define K210_HART_COUNT 2
#define K210_HART_STACK_SIZE 4096
/* Register base address */
#define K210_UART_BAUDRATE 115200
/* Under Coreplex */
#define CLINT_BASE_ADDR (0x02000000U)
#define PLIC_BASE_ADDR (0x0C000000U)
#define PLIC_NUM_CORES (K210_HART_COUNT)
#define K210_CLK0_FREQ 26000000UL
#define K210_PLIC_NUM_SOURCES 65
/* Under TileLink */
#define GPIOHS_BASE_ADDR (0x38001000U)
/* Registers base address */
#define K210_SYSCTL_BASE_ADDR 0x50440000ULL
#define K210_UART_BASE_ADDR 0x38000000ULL
#define K210_CLINT_BASE_ADDR 0x02000000ULL
#define K210_PLIC_BASE_ADDR 0x0C000000ULL
/* Under AXI 64 bit */
#define RAM_BASE_ADDR (0x80000000U)
#define RAM_SIZE (6 * 1024 * 1024U)
/* Registers */
#define K210_PLL0 0x08
#define K210_CLKSEL0 0x20
#define IO_BASE_ADDR (0x40000000U)
#define IO_SIZE (6 * 1024 * 1024U)
static inline u32 k210_read_sysreg(u32 reg)
{
return readl((volatile void *)(K210_SYSCTL_BASE_ADDR + reg));
}
#define AI_RAM_BASE_ADDR (0x80600000U)
#define AI_RAM_SIZE (2 * 1024 * 1024U)
#define AI_IO_BASE_ADDR (0x40600000U)
#define AI_IO_SIZE (2 * 1024 * 1024U)
#define AI_BASE_ADDR (0x40800000U)
#define AI_SIZE (12 * 1024 * 1024U)
#define FFT_BASE_ADDR (0x42000000U)
#define FFT_SIZE (4 * 1024 * 1024U)
#define ROM_BASE_ADDR (0x88000000U)
#define ROM_SIZE (128 * 1024U)
/* Under AHB 32 bit */
#define DMAC_BASE_ADDR (0x50000000U)
/* Under APB1 32 bit */
#define GPIO_BASE_ADDR (0x50200000U)
#define UART1_BASE_ADDR (0x50210000U)
#define UART2_BASE_ADDR (0x50220000U)
#define UART3_BASE_ADDR (0x50230000U)
#define SPI_SLAVE_BASE_ADDR (0x50240000U)
#define I2S0_BASE_ADDR (0x50250000U)
#define I2S1_BASE_ADDR (0x50260000U)
#define I2S2_BASE_ADDR (0x50270000U)
#define I2C0_BASE_ADDR (0x50280000U)
#define I2C1_BASE_ADDR (0x50290000U)
#define I2C2_BASE_ADDR (0x502A0000U)
#define FPIOA_BASE_ADDR (0x502B0000U)
#define SHA256_BASE_ADDR (0x502C0000U)
#define TIMER0_BASE_ADDR (0x502D0000U)
#define TIMER1_BASE_ADDR (0x502E0000U)
#define TIMER2_BASE_ADDR (0x502F0000U)
/* Under APB2 32 bit */
#define WDT0_BASE_ADDR (0x50400000U)
#define WDT1_BASE_ADDR (0x50410000U)
#define OTP_BASE_ADDR (0x50420000U)
#define DVP_BASE_ADDR (0x50430000U)
#define SYSCTL_BASE_ADDR (0x50440000U)
#define AES_BASE_ADDR (0x50450000U)
#define RTC_BASE_ADDR (0x50460000U)
/* Under APB3 32 bit */
#define SPI0_BASE_ADDR (0x52000000U)
#define SPI1_BASE_ADDR (0x53000000U)
#define SPI3_BASE_ADDR (0x54000000U)
#define read_cycle() csr_read(CSR_MCYCLE)
/*
* PLIC External Interrupt Numbers
*/
enum plic_irq {
IRQN_NO_INTERRUPT = 0, /*!< The non-existent interrupt */
IRQN_SPI0_INTERRUPT = 1, /*!< SPI0 interrupt */
IRQN_SPI1_INTERRUPT = 2, /*!< SPI1 interrupt */
IRQN_SPI_SLAVE_INTERRUPT = 3, /*!< SPI_SLAVE interrupt */
IRQN_SPI3_INTERRUPT = 4, /*!< SPI3 interrupt */
IRQN_I2S0_INTERRUPT = 5, /*!< I2S0 interrupt */
IRQN_I2S1_INTERRUPT = 6, /*!< I2S1 interrupt */
IRQN_I2S2_INTERRUPT = 7, /*!< I2S2 interrupt */
IRQN_I2C0_INTERRUPT = 8, /*!< I2C0 interrupt */
IRQN_I2C1_INTERRUPT = 9, /*!< I2C1 interrupt */
IRQN_I2C2_INTERRUPT = 10, /*!< I2C2 interrupt */
IRQN_UART1_INTERRUPT = 11, /*!< UART1 interrupt */
IRQN_UART2_INTERRUPT = 12, /*!< UART2 interrupt */
IRQN_UART3_INTERRUPT = 13, /*!< UART3 interrupt */
IRQN_TIMER0A_INTERRUPT = 14, /*!< TIMER0 channel 0 or 1 interrupt */
IRQN_TIMER0B_INTERRUPT = 15, /*!< TIMER0 channel 2 or 3 interrupt */
IRQN_TIMER1A_INTERRUPT = 16, /*!< TIMER1 channel 0 or 1 interrupt */
IRQN_TIMER1B_INTERRUPT = 17, /*!< TIMER1 channel 2 or 3 interrupt */
IRQN_TIMER2A_INTERRUPT = 18, /*!< TIMER2 channel 0 or 1 interrupt */
IRQN_TIMER2B_INTERRUPT = 19, /*!< TIMER2 channel 2 or 3 interrupt */
IRQN_RTC_INTERRUPT = 20, /*!< RTC tick and alarm interrupt */
IRQN_WDT0_INTERRUPT = 21, /*!< Watching dog timer0 interrupt */
IRQN_WDT1_INTERRUPT = 22, /*!< Watching dog timer1 interrupt */
IRQN_APB_GPIO_INTERRUPT = 23, /*!< APB GPIO interrupt */
IRQN_DVP_INTERRUPT = 24, /*!< Digital video port interrupt */
IRQN_AI_INTERRUPT = 25, /*!< AI accelerator interrupt */
IRQN_FFT_INTERRUPT = 26, /*!< FFT accelerator interrupt */
IRQN_DMA0_INTERRUPT = 27, /*!< DMA channel0 interrupt */
IRQN_DMA1_INTERRUPT = 28, /*!< DMA channel1 interrupt */
IRQN_DMA2_INTERRUPT = 29, /*!< DMA channel2 interrupt */
IRQN_DMA3_INTERRUPT = 30, /*!< DMA channel3 interrupt */
IRQN_DMA4_INTERRUPT = 31, /*!< DMA channel4 interrupt */
IRQN_DMA5_INTERRUPT = 32, /*!< DMA channel5 interrupt */
IRQN_UARTHS_INTERRUPT = 33, /*!< Hi-speed UART0 interrupt */
IRQN_GPIOHS0_INTERRUPT = 34, /*!< Hi-speed GPIO0 interrupt */
IRQN_GPIOHS1_INTERRUPT = 35, /*!< Hi-speed GPIO1 interrupt */
IRQN_GPIOHS2_INTERRUPT = 36, /*!< Hi-speed GPIO2 interrupt */
IRQN_GPIOHS3_INTERRUPT = 37, /*!< Hi-speed GPIO3 interrupt */
IRQN_GPIOHS4_INTERRUPT = 38, /*!< Hi-speed GPIO4 interrupt */
IRQN_GPIOHS5_INTERRUPT = 39, /*!< Hi-speed GPIO5 interrupt */
IRQN_GPIOHS6_INTERRUPT = 40, /*!< Hi-speed GPIO6 interrupt */
IRQN_GPIOHS7_INTERRUPT = 41, /*!< Hi-speed GPIO7 interrupt */
IRQN_GPIOHS8_INTERRUPT = 42, /*!< Hi-speed GPIO8 interrupt */
IRQN_GPIOHS9_INTERRUPT = 43, /*!< Hi-speed GPIO9 interrupt */
IRQN_GPIOHS10_INTERRUPT = 44, /*!< Hi-speed GPIO10 interrupt */
IRQN_GPIOHS11_INTERRUPT = 45, /*!< Hi-speed GPIO11 interrupt */
IRQN_GPIOHS12_INTERRUPT = 46, /*!< Hi-speed GPIO12 interrupt */
IRQN_GPIOHS13_INTERRUPT = 47, /*!< Hi-speed GPIO13 interrupt */
IRQN_GPIOHS14_INTERRUPT = 48, /*!< Hi-speed GPIO14 interrupt */
IRQN_GPIOHS15_INTERRUPT = 49, /*!< Hi-speed GPIO15 interrupt */
IRQN_GPIOHS16_INTERRUPT = 50, /*!< Hi-speed GPIO16 interrupt */
IRQN_GPIOHS17_INTERRUPT = 51, /*!< Hi-speed GPIO17 interrupt */
IRQN_GPIOHS18_INTERRUPT = 52, /*!< Hi-speed GPIO18 interrupt */
IRQN_GPIOHS19_INTERRUPT = 53, /*!< Hi-speed GPIO19 interrupt */
IRQN_GPIOHS20_INTERRUPT = 54, /*!< Hi-speed GPIO20 interrupt */
IRQN_GPIOHS21_INTERRUPT = 55, /*!< Hi-speed GPIO21 interrupt */
IRQN_GPIOHS22_INTERRUPT = 56, /*!< Hi-speed GPIO22 interrupt */
IRQN_GPIOHS23_INTERRUPT = 57, /*!< Hi-speed GPIO23 interrupt */
IRQN_GPIOHS24_INTERRUPT = 58, /*!< Hi-speed GPIO24 interrupt */
IRQN_GPIOHS25_INTERRUPT = 59, /*!< Hi-speed GPIO25 interrupt */
IRQN_GPIOHS26_INTERRUPT = 60, /*!< Hi-speed GPIO26 interrupt */
IRQN_GPIOHS27_INTERRUPT = 61, /*!< Hi-speed GPIO27 interrupt */
IRQN_GPIOHS28_INTERRUPT = 62, /*!< Hi-speed GPIO28 interrupt */
IRQN_GPIOHS29_INTERRUPT = 63, /*!< Hi-speed GPIO29 interrupt */
IRQN_GPIOHS30_INTERRUPT = 64, /*!< Hi-speed GPIO30 interrupt */
IRQN_GPIOHS31_INTERRUPT = 65, /*!< Hi-speed GPIO31 interrupt */
IRQN_MAX
};
/* IRQ number settings */
#define PLIC_NUM_SOURCES (IRQN_MAX - 1)
#define PLIC_NUM_PRIORITIES (7)
/* clang-format on */
#endif /* _PLATFORM_H_ */
#endif /* _K210_PLATFORM_H_ */

View File

@@ -1,57 +0,0 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2018 Canaan Inc.
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sbi/riscv_encoding.h>
#include "sysctl.h"
volatile sysctl_t *const sysctl = (volatile sysctl_t *)SYSCTL_BASE_ADDR;
#define SYSCTRL_CLOCK_FREQ_IN0 (26000000UL)
static u32 sysctl_pll0_get_freq(void)
{
u32 freq_in, nr, nf, od;
freq_in = SYSCTRL_CLOCK_FREQ_IN0;
nr = sysctl->pll0.clkr0 + 1;
nf = sysctl->pll0.clkf0 + 1;
od = sysctl->pll0.clkod0 + 1;
/*
* Get final PLL output freq
* FOUT = FIN / NR * NF / OD
* = (FIN * NF) / (NR * OD)
*/
return ((u64)freq_in * (u64)nf) / ((u64)nr * (u64)od);
}
u32 sysctl_get_cpu_freq(void)
{
int clock_source;
clock_source = (int)sysctl->clk_sel0.aclk_sel;
switch (clock_source) {
case 0:
return SYSCTRL_CLOCK_FREQ_IN0;
case 1:
return sysctl_pll0_get_freq() /
(2ULL << (int)sysctl->clk_sel0.aclk_divider_sel);
default:
return 0;
}
}

View File

@@ -1,794 +0,0 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2018 Canaan Inc.
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _K210_SYSCTL_H_
#define _K210_SYSCTL_H_
#include <sbi/sbi_types.h>
#include "platform.h"
/**
* System controller registers
*
* | Offset | Name | Description |
* |-----------|----------------|-------------------------------------|
* | 0x00 | git_id | Git short commit id |
* | 0x04 | clk_freq | System clock base frequency |
* | 0x08 | pll0 | PLL0 controller |
* | 0x0c | pll1 | PLL1 controller |
* | 0x10 | pll2 | PLL2 controller |
* | 0x14 | resv5 | Reserved |
* | 0x18 | pll_lock | PLL lock tester |
* | 0x1c | rom_error | AXI ROM detector |
* | 0x20 | clk_sel0 | Clock select controller0 |
* | 0x24 | clk_sel1 | Clock select controller1 |
* | 0x28 | clk_en_cent | Central clock enable |
* | 0x2c | clk_en_peri | Peripheral clock enable |
* | 0x30 | soft_reset | Soft reset ctrl |
* | 0x34 | peri_reset | Peripheral reset controller |
* | 0x38 | clk_th0 | Clock threshold controller 0 |
* | 0x3c | clk_th1 | Clock threshold controller 1 |
* | 0x40 | clk_th2 | Clock threshold controller 2 |
* | 0x44 | clk_th3 | Clock threshold controller 3 |
* | 0x48 | clk_th4 | Clock threshold controller 4 |
* | 0x4c | clk_th5 | Clock threshold controller 5 |
* | 0x50 | clk_th6 | Clock threshold controller 6 |
* | 0x54 | misc | Miscellaneous controller |
* | 0x58 | peri | Peripheral controller |
* | 0x5c | spi_sleep | SPI sleep controller |
* | 0x60 | reset_status | Reset source status |
* | 0x64 | dma_sel0 | DMA handshake selector |
* | 0x68 | dma_sel1 | DMA handshake selector |
* | 0x6c | power_sel | IO Power Mode Select controller |
* | 0x70 | resv28 | Reserved |
* | 0x74 | resv29 | Reserved |
* | 0x78 | resv30 | Reserved |
* | 0x7c | resv31 | Reserved |
*/
typedef enum _sysctl_pll_t {
SYSCTL_PLL0,
SYSCTL_PLL1,
SYSCTL_PLL2,
SYSCTL_PLL_MAX
} sysctl_pll_t;
typedef enum _sysctl_clock_source_t {
SYSCTL_SOURCE_IN0,
SYSCTL_SOURCE_PLL0,
SYSCTL_SOURCE_PLL1,
SYSCTL_SOURCE_PLL2,
SYSCTL_SOURCE_ACLK,
SYSCTL_SOURCE_MAX
} sysctl_clock_source_t;
typedef enum _sysctl_dma_channel_t {
SYSCTL_DMA_CHANNEL_0,
SYSCTL_DMA_CHANNEL_1,
SYSCTL_DMA_CHANNEL_2,
SYSCTL_DMA_CHANNEL_3,
SYSCTL_DMA_CHANNEL_4,
SYSCTL_DMA_CHANNEL_5,
SYSCTL_DMA_CHANNEL_MAX
} sysctl_dma_channel_t;
typedef enum _sysctl_dma_select_t {
SYSCTL_DMA_SELECT_SSI0_RX_REQ,
SYSCTL_DMA_SELECT_SSI0_TX_REQ,
SYSCTL_DMA_SELECT_SSI1_RX_REQ,
SYSCTL_DMA_SELECT_SSI1_TX_REQ,
SYSCTL_DMA_SELECT_SSI2_RX_REQ,
SYSCTL_DMA_SELECT_SSI2_TX_REQ,
SYSCTL_DMA_SELECT_SSI3_RX_REQ,
SYSCTL_DMA_SELECT_SSI3_TX_REQ,
SYSCTL_DMA_SELECT_I2C0_RX_REQ,
SYSCTL_DMA_SELECT_I2C0_TX_REQ,
SYSCTL_DMA_SELECT_I2C1_RX_REQ,
SYSCTL_DMA_SELECT_I2C1_TX_REQ,
SYSCTL_DMA_SELECT_I2C2_RX_REQ,
SYSCTL_DMA_SELECT_I2C2_TX_REQ,
SYSCTL_DMA_SELECT_UART1_RX_REQ,
SYSCTL_DMA_SELECT_UART1_TX_REQ,
SYSCTL_DMA_SELECT_UART2_RX_REQ,
SYSCTL_DMA_SELECT_UART2_TX_REQ,
SYSCTL_DMA_SELECT_UART3_RX_REQ,
SYSCTL_DMA_SELECT_UART3_TX_REQ,
SYSCTL_DMA_SELECT_AES_REQ,
SYSCTL_DMA_SELECT_SHA_RX_REQ,
SYSCTL_DMA_SELECT_AI_RX_REQ,
SYSCTL_DMA_SELECT_FFT_RX_REQ,
SYSCTL_DMA_SELECT_FFT_TX_REQ,
SYSCTL_DMA_SELECT_I2S0_TX_REQ,
SYSCTL_DMA_SELECT_I2S0_RX_REQ,
SYSCTL_DMA_SELECT_I2S1_TX_REQ,
SYSCTL_DMA_SELECT_I2S1_RX_REQ,
SYSCTL_DMA_SELECT_I2S2_TX_REQ,
SYSCTL_DMA_SELECT_I2S2_RX_REQ,
SYSCTL_DMA_SELECT_I2S0_BF_DIR_REQ,
SYSCTL_DMA_SELECT_I2S0_BF_VOICE_REQ,
SYSCTL_DMA_SELECT_MAX
} sysctl_dma_select_t;
/**
* System controller clock id
*/
typedef enum _sysctl_clock_t {
SYSCTL_CLOCK_PLL0,
SYSCTL_CLOCK_PLL1,
SYSCTL_CLOCK_PLL2,
SYSCTL_CLOCK_CPU,
SYSCTL_CLOCK_SRAM0,
SYSCTL_CLOCK_SRAM1,
SYSCTL_CLOCK_APB0,
SYSCTL_CLOCK_APB1,
SYSCTL_CLOCK_APB2,
SYSCTL_CLOCK_ROM,
SYSCTL_CLOCK_DMA,
SYSCTL_CLOCK_AI,
SYSCTL_CLOCK_DVP,
SYSCTL_CLOCK_FFT,
SYSCTL_CLOCK_GPIO,
SYSCTL_CLOCK_SPI0,
SYSCTL_CLOCK_SPI1,
SYSCTL_CLOCK_SPI2,
SYSCTL_CLOCK_SPI3,
SYSCTL_CLOCK_I2S0,
SYSCTL_CLOCK_I2S1,
SYSCTL_CLOCK_I2S2,
SYSCTL_CLOCK_I2C0,
SYSCTL_CLOCK_I2C1,
SYSCTL_CLOCK_I2C2,
SYSCTL_CLOCK_UART1,
SYSCTL_CLOCK_UART2,
SYSCTL_CLOCK_UART3,
SYSCTL_CLOCK_AES,
SYSCTL_CLOCK_FPIOA,
SYSCTL_CLOCK_TIMER0,
SYSCTL_CLOCK_TIMER1,
SYSCTL_CLOCK_TIMER2,
SYSCTL_CLOCK_WDT0,
SYSCTL_CLOCK_WDT1,
SYSCTL_CLOCK_SHA,
SYSCTL_CLOCK_OTP,
SYSCTL_CLOCK_RTC,
SYSCTL_CLOCK_ACLK = 40,
SYSCTL_CLOCK_HCLK,
SYSCTL_CLOCK_IN0,
SYSCTL_CLOCK_MAX
} sysctl_clock_t;
/**
* System controller clock select id
*/
typedef enum _sysctl_clock_select_t {
SYSCTL_CLOCK_SELECT_PLL0_BYPASS,
SYSCTL_CLOCK_SELECT_PLL1_BYPASS,
SYSCTL_CLOCK_SELECT_PLL2_BYPASS,
SYSCTL_CLOCK_SELECT_PLL2,
SYSCTL_CLOCK_SELECT_ACLK,
SYSCTL_CLOCK_SELECT_SPI3,
SYSCTL_CLOCK_SELECT_TIMER0,
SYSCTL_CLOCK_SELECT_TIMER1,
SYSCTL_CLOCK_SELECT_TIMER2,
SYSCTL_CLOCK_SELECT_SPI3_SAMPLE,
SYSCTL_CLOCK_SELECT_MAX = 11
} sysctl_clock_select_t;
/**
* System controller clock threshold id
*/
typedef enum _sysctl_threshold_t {
SYSCTL_THRESHOLD_ACLK,
SYSCTL_THRESHOLD_APB0,
SYSCTL_THRESHOLD_APB1,
SYSCTL_THRESHOLD_APB2,
SYSCTL_THRESHOLD_SRAM0,
SYSCTL_THRESHOLD_SRAM1,
SYSCTL_THRESHOLD_AI,
SYSCTL_THRESHOLD_DVP,
SYSCTL_THRESHOLD_ROM,
SYSCTL_THRESHOLD_SPI0,
SYSCTL_THRESHOLD_SPI1,
SYSCTL_THRESHOLD_SPI2,
SYSCTL_THRESHOLD_SPI3,
SYSCTL_THRESHOLD_TIMER0,
SYSCTL_THRESHOLD_TIMER1,
SYSCTL_THRESHOLD_TIMER2,
SYSCTL_THRESHOLD_I2S0,
SYSCTL_THRESHOLD_I2S1,
SYSCTL_THRESHOLD_I2S2,
SYSCTL_THRESHOLD_I2S0_M,
SYSCTL_THRESHOLD_I2S1_M,
SYSCTL_THRESHOLD_I2S2_M,
SYSCTL_THRESHOLD_I2C0,
SYSCTL_THRESHOLD_I2C1,
SYSCTL_THRESHOLD_I2C2,
SYSCTL_THRESHOLD_WDT0,
SYSCTL_THRESHOLD_WDT1,
SYSCTL_THRESHOLD_MAX = 28
} sysctl_threshold_t;
/**
* System controller reset control id
*/
typedef enum _sysctl_reset_t {
SYSCTL_RESET_SOC,
SYSCTL_RESET_ROM,
SYSCTL_RESET_DMA,
SYSCTL_RESET_AI,
SYSCTL_RESET_DVP,
SYSCTL_RESET_FFT,
SYSCTL_RESET_GPIO,
SYSCTL_RESET_SPI0,
SYSCTL_RESET_SPI1,
SYSCTL_RESET_SPI2,
SYSCTL_RESET_SPI3,
SYSCTL_RESET_I2S0,
SYSCTL_RESET_I2S1,
SYSCTL_RESET_I2S2,
SYSCTL_RESET_I2C0,
SYSCTL_RESET_I2C1,
SYSCTL_RESET_I2C2,
SYSCTL_RESET_UART1,
SYSCTL_RESET_UART2,
SYSCTL_RESET_UART3,
SYSCTL_RESET_AES,
SYSCTL_RESET_FPIOA,
SYSCTL_RESET_TIMER0,
SYSCTL_RESET_TIMER1,
SYSCTL_RESET_TIMER2,
SYSCTL_RESET_WDT0,
SYSCTL_RESET_WDT1,
SYSCTL_RESET_SHA,
SYSCTL_RESET_RTC,
SYSCTL_RESET_MAX = 31
} sysctl_reset_t;
typedef enum _sysctl_power_bank {
SYSCTL_POWER_BANK0,
SYSCTL_POWER_BANK1,
SYSCTL_POWER_BANK2,
SYSCTL_POWER_BANK3,
SYSCTL_POWER_BANK4,
SYSCTL_POWER_BANK5,
SYSCTL_POWER_BANK6,
SYSCTL_POWER_BANK7,
SYSCTL_POWER_BANK_MAX,
} sysctl_power_bank_t;
/**
* System controller reset control id
*/
typedef enum _sysctl_io_power_mode {
SYSCTL_POWER_V33,
SYSCTL_POWER_V18
} sysctl_io_power_mode_t;
/**
* Git short commit id
* No. 0 Register (0x00)
*/
typedef struct _sysctl_git_id {
u32 git_id : 32;
} __attribute__((packed, aligned(4))) sysctl_git_id_t;
/**
* System clock base frequency
* No. 1 Register (0x04)
*/
typedef struct _sysctl_clk_freq {
u32 clk_freq : 32;
} __attribute__((packed, aligned(4))) sysctl_clk_freq_t;
/**
* PLL0 controller
* No. 2 Register (0x08)
*/
typedef struct _sysctl_pll0 {
u32 clkr0 : 4;
u32 clkf0 : 6;
u32 clkod0 : 4;
u32 bwadj0 : 6;
u32 pll_reset0 : 1;
u32 pll_pwrd0 : 1;
u32 pll_intfb0 : 1;
u32 pll_bypass0 : 1;
u32 pll_test0 : 1;
u32 pll_out_en0 : 1;
u32 pll_test_en : 1;
u32 reserved : 5;
} __attribute__((packed, aligned(4))) sysctl_pll0_t;
/**
* PLL1 controller
* No. 3 Register (0x0c)
*/
typedef struct _sysctl_pll1 {
u32 clkr1 : 4;
u32 clkf1 : 6;
u32 clkod1 : 4;
u32 bwadj1 : 6;
u32 pll_reset1 : 1;
u32 pll_pwrd1 : 1;
u32 pll_intfb1 : 1;
u32 pll_bypass1 : 1;
u32 pll_test1 : 1;
u32 pll_out_en1 : 1;
u32 reserved : 6;
} __attribute__((packed, aligned(4))) sysctl_pll1_t;
/**
* PLL2 controller
* No. 4 Register (0x10)
*/
typedef struct _sysctl_pll2 {
u32 clkr2 : 4;
u32 clkf2 : 6;
u32 clkod2 : 4;
u32 bwadj2 : 6;
u32 pll_reset2 : 1;
u32 pll_pwrd2 : 1;
u32 pll_intfb2 : 1;
u32 pll_bypass2 : 1;
u32 pll_test2 : 1;
u32 pll_out_en2 : 1;
u32 pll_ckin_sel2 : 2;
u32 reserved : 4;
} __attribute__((packed, aligned(4))) sysctl_pll2_t;
/**
* PLL lock tester
* No. 6 Register (0x18)
*/
typedef struct _sysctl_pll_lock {
u32 pll_lock0 : 2;
u32 pll_slip_clear0 : 1;
u32 test_clk_out0 : 1;
u32 reserved0 : 4;
u32 pll_lock1 : 2;
u32 pll_slip_clear1 : 1;
u32 test_clk_out1 : 1;
u32 reserved1 : 4;
u32 pll_lock2 : 2;
u32 pll_slip_clear2 : 1;
u32 test_clk_out2 : 1;
u32 reserved2 : 12;
} __attribute__((packed, aligned(4))) sysctl_pll_lock_t;
/**
* AXI ROM detector
* No. 7 Register (0x1c)
*/
typedef struct _sysctl_rom_error {
u32 rom_mul_error : 1;
u32 rom_one_error : 1;
u32 reserved : 30;
} __attribute__((packed, aligned(4))) sysctl_rom_error_t;
/**
* Clock select controller0
* No. 8 Register (0x20)
*/
typedef struct _sysctl_clk_sel0 {
u32 aclk_sel : 1;
u32 aclk_divider_sel : 2;
u32 apb0_clk_sel : 3;
u32 apb1_clk_sel : 3;
u32 apb2_clk_sel : 3;
u32 spi3_clk_sel : 1;
u32 timer0_clk_sel : 1;
u32 timer1_clk_sel : 1;
u32 timer2_clk_sel : 1;
u32 reserved : 16;
} __attribute__((packed, aligned(4))) sysctl_clk_sel0_t;
/**
* Clock select controller1
* No. 9 Register (0x24)
*/
typedef struct _sysctl_clk_sel1 {
u32 spi3_sample_clk_sel : 1;
u32 reserved0 : 30;
u32 reserved1 : 1;
} __attribute__((packed, aligned(4))) sysctl_clk_sel1_t;
/**
* Central clock enable
* No. 10 Register (0x28)
*/
typedef struct _sysctl_clk_en_cent {
u32 cpu_clk_en : 1;
u32 sram0_clk_en : 1;
u32 sram1_clk_en : 1;
u32 apb0_clk_en : 1;
u32 apb1_clk_en : 1;
u32 apb2_clk_en : 1;
u32 reserved : 26;
} __attribute__((packed, aligned(4))) sysctl_clk_en_cent_t;
/**
* Peripheral clock enable
* No. 11 Register (0x2c)
*/
typedef struct _sysctl_clk_en_peri {
u32 rom_clk_en : 1;
u32 dma_clk_en : 1;
u32 ai_clk_en : 1;
u32 dvp_clk_en : 1;
u32 fft_clk_en : 1;
u32 gpio_clk_en : 1;
u32 spi0_clk_en : 1;
u32 spi1_clk_en : 1;
u32 spi2_clk_en : 1;
u32 spi3_clk_en : 1;
u32 i2s0_clk_en : 1;
u32 i2s1_clk_en : 1;
u32 i2s2_clk_en : 1;
u32 i2c0_clk_en : 1;
u32 i2c1_clk_en : 1;
u32 i2c2_clk_en : 1;
u32 uart1_clk_en : 1;
u32 uart2_clk_en : 1;
u32 uart3_clk_en : 1;
u32 aes_clk_en : 1;
u32 fpioa_clk_en : 1;
u32 timer0_clk_en : 1;
u32 timer1_clk_en : 1;
u32 timer2_clk_en : 1;
u32 wdt0_clk_en : 1;
u32 wdt1_clk_en : 1;
u32 sha_clk_en : 1;
u32 otp_clk_en : 1;
u32 reserved : 1;
u32 rtc_clk_en : 1;
u32 reserved0 : 2;
} __attribute__((packed, aligned(4))) sysctl_clk_en_peri_t;
/**
* Soft reset ctrl
* No. 12 Register (0x30)
*/
typedef struct _sysctl_soft_reset {
u32 soft_reset : 1;
u32 reserved : 31;
} __attribute__((packed, aligned(4))) sysctl_soft_reset_t;
/**
* Peripheral reset controller
* No. 13 Register (0x34)
*/
typedef struct _sysctl_peri_reset {
u32 rom_reset : 1;
u32 dma_reset : 1;
u32 ai_reset : 1;
u32 dvp_reset : 1;
u32 fft_reset : 1;
u32 gpio_reset : 1;
u32 spi0_reset : 1;
u32 spi1_reset : 1;
u32 spi2_reset : 1;
u32 spi3_reset : 1;
u32 i2s0_reset : 1;
u32 i2s1_reset : 1;
u32 i2s2_reset : 1;
u32 i2c0_reset : 1;
u32 i2c1_reset : 1;
u32 i2c2_reset : 1;
u32 uart1_reset : 1;
u32 uart2_reset : 1;
u32 uart3_reset : 1;
u32 aes_reset : 1;
u32 fpioa_reset : 1;
u32 timer0_reset : 1;
u32 timer1_reset : 1;
u32 timer2_reset : 1;
u32 wdt0_reset : 1;
u32 wdt1_reset : 1;
u32 sha_reset : 1;
u32 reserved : 2;
u32 rtc_reset : 1;
u32 reserved0 : 2;
} __attribute__((packed, aligned(4))) sysctl_peri_reset_t;
/**
* Clock threshold controller 0
* No. 14 Register (0x38)
*/
typedef struct _sysctl_clk_th0 {
u32 sram0_gclk_threshold : 4;
u32 sram1_gclk_threshold : 4;
u32 ai_gclk_threshold : 4;
u32 dvp_gclk_threshold : 4;
u32 rom_gclk_threshold : 4;
u32 reserved : 12;
} __attribute__((packed, aligned(4))) sysctl_clk_th0_t;
/**
* Clock threshold controller 1
* No. 15 Register (0x3c)
*/
typedef struct _sysctl_clk_th1 {
u32 spi0_clk_threshold : 8;
u32 spi1_clk_threshold : 8;
u32 spi2_clk_threshold : 8;
u32 spi3_clk_threshold : 8;
} __attribute__((packed, aligned(4))) sysctl_clk_th1_t;
/**
* Clock threshold controller 2
* No. 16 Register (0x40)
*/
typedef struct _sysctl_clk_th2 {
u32 timer0_clk_threshold : 8;
u32 timer1_clk_threshold : 8;
u32 timer2_clk_threshold : 8;
u32 reserved : 8;
} __attribute__((packed, aligned(4))) sysctl_clk_th2_t;
/**
* Clock threshold controller 3
* No. 17 Register (0x44)
*/
typedef struct _sysctl_clk_th3 {
u32 i2s0_clk_threshold : 16;
u32 i2s1_clk_threshold : 16;
} __attribute__((packed, aligned(4))) sysctl_clk_th3_t;
/**
* Clock threshold controller 4
* No. 18 Register (0x48)
*/
typedef struct _sysctl_clk_th4 {
u32 i2s2_clk_threshold : 16;
u32 i2s0_mclk_threshold : 8;
u32 i2s1_mclk_threshold : 8;
} __attribute__((packed, aligned(4))) sysctl_clk_th4_t;
/**
* Clock threshold controller 5
* No. 19 Register (0x4c)
*/
typedef struct _sysctl_clk_th5 {
u32 i2s2_mclk_threshold : 8;
u32 i2c0_clk_threshold : 8;
u32 i2c1_clk_threshold : 8;
u32 i2c2_clk_threshold : 8;
} __attribute__((packed, aligned(4))) sysctl_clk_th5_t;
/**
* Clock threshold controller 6
* No. 20 Register (0x50)
*/
typedef struct _sysctl_clk_th6 {
u32 wdt0_clk_threshold : 8;
u32 wdt1_clk_threshold : 8;
u32 reserved0 : 8;
u32 reserved1 : 8;
} __attribute__((packed, aligned(4))) sysctl_clk_th6_t;
/**
* Miscellaneous controller
* No. 21 Register (0x54)
*/
typedef struct _sysctl_misc {
u32 debug_sel : 6;
u32 reserved0 : 4;
u32 spi_dvp_data_enable : 1;
u32 reserved1 : 21;
} __attribute__((packed, aligned(4))) sysctl_misc_t;
/**
* Peripheral controller
* No. 22 Register (0x58)
*/
typedef struct _sysctl_peri {
u32 timer0_pause : 1;
u32 timer1_pause : 1;
u32 timer2_pause : 1;
u32 timer3_pause : 1;
u32 timer4_pause : 1;
u32 timer5_pause : 1;
u32 timer6_pause : 1;
u32 timer7_pause : 1;
u32 timer8_pause : 1;
u32 timer9_pause : 1;
u32 timer10_pause : 1;
u32 timer11_pause : 1;
u32 spi0_xip_en : 1;
u32 spi1_xip_en : 1;
u32 spi2_xip_en : 1;
u32 spi3_xip_en : 1;
u32 spi0_clk_bypass : 1;
u32 spi1_clk_bypass : 1;
u32 spi2_clk_bypass : 1;
u32 i2s0_clk_bypass : 1;
u32 i2s1_clk_bypass : 1;
u32 i2s2_clk_bypass : 1;
u32 jtag_clk_bypass : 1;
u32 dvp_clk_bypass : 1;
u32 debug_clk_bypass : 1;
u32 reserved0 : 1;
u32 reserved1 : 6;
} __attribute__((packed, aligned(4))) sysctl_peri_t;
/**
* SPI sleep controller
* No. 23 Register (0x5c)
*/
typedef struct _sysctl_spi_sleep {
u32 ssi0_sleep : 1;
u32 ssi1_sleep : 1;
u32 ssi2_sleep : 1;
u32 ssi3_sleep : 1;
u32 reserved : 28;
} __attribute__((packed, aligned(4))) sysctl_spi_sleep_t;
/**
* Reset source status
* No. 24 Register (0x60)
*/
typedef struct _sysctl_reset_status {
u32 reset_sts_clr : 1;
u32 pin_reset_sts : 1;
u32 wdt0_reset_sts : 1;
u32 wdt1_reset_sts : 1;
u32 soft_reset_sts : 1;
u32 reserved : 27;
} __attribute__((packed, aligned(4))) sysctl_reset_status_t;
/**
* DMA handshake selector
* No. 25 Register (0x64)
*/
typedef struct _sysctl_dma_sel0 {
u32 dma_sel0 : 6;
u32 dma_sel1 : 6;
u32 dma_sel2 : 6;
u32 dma_sel3 : 6;
u32 dma_sel4 : 6;
u32 reserved : 2;
} __attribute__((packed, aligned(4))) sysctl_dma_sel0_t;
/**
* DMA handshake selector
* No. 26 Register (0x68)
*/
typedef struct _sysctl_dma_sel1 {
u32 dma_sel5 : 6;
u32 reserved : 26;
} __attribute__((packed, aligned(4))) sysctl_dma_sel1_t;
/**
* IO Power Mode Select controller
* No. 27 Register (0x6c)
*/
typedef struct _sysctl_power_sel {
u32 power_mode_sel0 : 1;
u32 power_mode_sel1 : 1;
u32 power_mode_sel2 : 1;
u32 power_mode_sel3 : 1;
u32 power_mode_sel4 : 1;
u32 power_mode_sel5 : 1;
u32 power_mode_sel6 : 1;
u32 power_mode_sel7 : 1;
u32 reserved : 24;
} __attribute__((packed, aligned(4))) sysctl_power_sel_t;
/**
* System controller object
*
* The System controller is a peripheral device mapped in the
* internal memory map, discoverable in the Configuration String.
* It is responsible for low-level configuration of all system
* related peripheral device. It contain PLL controller, clock
* controller, reset controller, DMA handshake controller, SPI
* controller, timer controller, WDT controller and sleep
* controller.
*/
typedef struct _sysctl {
/* No. 0 (0x00): Git short commit id */
sysctl_git_id_t git_id;
/* No. 1 (0x04): System clock base frequency */
sysctl_clk_freq_t clk_freq;
/* No. 2 (0x08): PLL0 controller */
sysctl_pll0_t pll0;
/* No. 3 (0x0c): PLL1 controller */
sysctl_pll1_t pll1;
/* No. 4 (0x10): PLL2 controller */
sysctl_pll2_t pll2;
/* No. 5 (0x14): Reserved */
u32 resv5;
/* No. 6 (0x18): PLL lock tester */
sysctl_pll_lock_t pll_lock;
/* No. 7 (0x1c): AXI ROM detector */
sysctl_rom_error_t rom_error;
/* No. 8 (0x20): Clock select controller0 */
sysctl_clk_sel0_t clk_sel0;
/* No. 9 (0x24): Clock select controller1 */
sysctl_clk_sel1_t clk_sel1;
/* No. 10 (0x28): Central clock enable */
sysctl_clk_en_cent_t clk_en_cent;
/* No. 11 (0x2c): Peripheral clock enable */
sysctl_clk_en_peri_t clk_en_peri;
/* No. 12 (0x30): Soft reset ctrl */
sysctl_soft_reset_t soft_reset;
/* No. 13 (0x34): Peripheral reset controller */
sysctl_peri_reset_t peri_reset;
/* No. 14 (0x38): Clock threshold controller 0 */
sysctl_clk_th0_t clk_th0;
/* No. 15 (0x3c): Clock threshold controller 1 */
sysctl_clk_th1_t clk_th1;
/* No. 16 (0x40): Clock threshold controller 2 */
sysctl_clk_th2_t clk_th2;
/* No. 17 (0x44): Clock threshold controller 3 */
sysctl_clk_th3_t clk_th3;
/* No. 18 (0x48): Clock threshold controller 4 */
sysctl_clk_th4_t clk_th4;
/* No. 19 (0x4c): Clock threshold controller 5 */
sysctl_clk_th5_t clk_th5;
/* No. 20 (0x50): Clock threshold controller 6 */
sysctl_clk_th6_t clk_th6;
/* No. 21 (0x54): Miscellaneous controller */
sysctl_misc_t misc;
/* No. 22 (0x58): Peripheral controller */
sysctl_peri_t peri;
/* No. 23 (0x5c): SPI sleep controller */
sysctl_spi_sleep_t spi_sleep;
/* No. 24 (0x60): Reset source status */
sysctl_reset_status_t reset_status;
/* No. 25 (0x64): DMA handshake selector */
sysctl_dma_sel0_t dma_sel0;
/* No. 26 (0x68): DMA handshake selector */
sysctl_dma_sel1_t dma_sel1;
/* No. 27 (0x6c): IO Power Mode Select controller */
sysctl_power_sel_t power_sel;
/* No. 28 (0x70): Reserved */
u32 resv28;
/* No. 29 (0x74): Reserved */
u32 resv29;
/* No. 30 (0x78): Reserved */
u32 resv30;
/* No. 31 (0x7c): Reserved */
u32 resv31;
} __attribute__((packed, aligned(4))) sysctl_t;
/**
* Abstruct PLL struct
*/
typedef struct _sysctl_general_pll {
u32 clkr : 4;
u32 clkf : 6;
u32 clkod : 4;
u32 bwadj : 6;
u32 pll_reset : 1;
u32 pll_pwrd : 1;
u32 pll_intfb : 1;
u32 pll_bypass : 1;
u32 pll_test : 1;
u32 pll_out_en : 1;
u32 pll_ckin_sel : 2;
u32 reserved : 4;
} __attribute__((packed, aligned(4))) sysctl_general_pll_t;
/**
* Get frequency of CPU
* @return The frequency of the CPU
*/
u32 sysctl_get_cpu_freq(void);
#endif /* _K210_SYSCTL_H_ */

View File

@@ -1,64 +0,0 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2018 Canaan Inc.
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "sysctl.h"
#include "uarths.h"
static volatile struct uarths *const uarths =
(volatile struct uarths *)UARTHS_BASE_ADDR;
void uarths_init(u32 baud_rate, enum uarths_stopbit stopbit)
{
u32 freq = sysctl_get_cpu_freq();
u16 div = freq / baud_rate - 1;
/* Set UART registers */
uarths->div.div = div;
uarths->txctrl.nstop = stopbit;
uarths->txctrl.txen = 1;
uarths->rxctrl.rxen = 1;
uarths->txctrl.txcnt = 0;
uarths->rxctrl.rxcnt = 0;
uarths->ip.txwm = 1;
uarths->ip.rxwm = 0;
uarths->ie.txwm = 1;
uarths->ie.rxwm = 0;
/* Clear input */
if (!uarths->rxdata.empty)
(void)uarths_getc();
}
void uarths_putc(char c)
{
while (uarths->txdata.full)
;
uarths->txdata.data = (u8)c;
}
int uarths_getc(void)
{
struct uarths_rxdata rx = uarths->rxdata;
if (rx.empty)
return -1;
return rx.data;
}

View File

@@ -1,171 +0,0 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2018 Canaan Inc.
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Universal Asynchronous Receiver/Transmitter (UART)
* The UART peripheral supports the following features:
*
* - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start
* bit, 1 or 2 stop bits
*
* - 8-entry transmit and receive FIFO buffers with programmable
* watermark interrupts
*
* - 16× Rx oversampling with 2/3 majority voting per bit
*
* The UART peripheral does not support hardware flow control or
* other modem control signals, or synchronous serial data
* tranfesrs.
*
* UART RAM Layout
* | Address | Name | Description |
* |-----------|----------|---------------------------------|
* | 0x000 | txdata | Transmit data register |
* | 0x004 | rxdata | Receive data register |
* | 0x008 | txctrl | Transmit control register |
* | 0x00C | rxctrl | Receive control register |
* | 0x010 | ie | UART interrupt enable |
* | 0x014 | ip | UART Interrupt pending |
* | 0x018 | div | Baud rate divisor |
*/
#ifndef _K210_UARTHS_H_
#define _K210_UARTHS_H_
#include <sbi/sbi_types.h>
/* clang-format off */
/* Base register address */
#define UARTHS_BASE_ADDR (0x38000000U)
/* Register address offsets */
#define UARTHS_REG_TXFIFO 0x00
#define UARTHS_REG_RXFIFO 0x04
#define UARTHS_REG_TXCTRL 0x08
#define UARTHS_REG_RXCTRL 0x0c
#define UARTHS_REG_IE 0x10
#define UARTHS_REG_IP 0x14
#define UARTHS_REG_DIV 0x18
/* TXCTRL register */
#define UARTHS_TXEN 0x01
#define UARTHS_TXWM(x) (((x) & 0xffff) << 16)
/* RXCTRL register */
#define UARTHS_RXEN 0x01
#define UARTHS_RXWM(x) (((x) & 0xffff) << 16)
/* IP register */
#define UARTHS_IP_TXWM 0x01
#define UARTHS_IP_RXWM 0x02
/* clang-format on */
struct uarths_txdata {
/* Bits [7:0] is data */
u32 data : 8;
/* Bits [30:8] is 0 */
u32 zero : 23;
/* Bit 31 is full status */
u32 full : 1;
} __attribute__((packed, aligned(4)));
struct uarths_rxdata {
/* Bits [7:0] is data */
u32 data : 8;
/* Bits [30:8] is 0 */
u32 zero : 23;
/* Bit 31 is empty status */
u32 empty : 1;
} __attribute__((packed, aligned(4)));
struct uarths_txctrl {
/* Bit 0 is txen, controls whether the Tx channel is active. */
u32 txen : 1;
/* Bit 1 is nstop, 0 for one stop bit and 1 for two stop bits */
u32 nstop : 1;
/* Bits [15:2] is reserved */
u32 resv0 : 14;
/* Bits [18:16] is threshold of interrupt triggers */
u32 txcnt : 3;
/* Bits [31:19] is reserved */
u32 resv1 : 13;
} __attribute__((packed, aligned(4)));
struct uarths_rxctrl {
/* Bit 0 is txen, controls whether the Tx channel is active. */
u32 rxen : 1;
/* Bits [15:1] is reserved */
u32 resv0 : 15;
/* Bits [18:16] is threshold of interrupt triggers */
u32 rxcnt : 3;
/* Bits [31:19] is reserved */
u32 resv1 : 13;
} __attribute__((packed, aligned(4)));
struct uarths_ip {
/* Bit 0 is txwm, raised less than txcnt */
u32 txwm : 1;
/* Bit 1 is txwm, raised greater than rxcnt */
u32 rxwm : 1;
/* Bits [31:2] is 0 */
u32 zero : 30;
} __attribute__((packed, aligned(4)));
struct uarths_ie {
/* Bit 0 is txwm, raised less than txcnt */
u32 txwm : 1;
/* Bit 1 is txwm, raised greater than rxcnt */
u32 rxwm : 1;
/* Bits [31:2] is 0 */
u32 zero : 30;
} __attribute__((packed, aligned(4)));
struct uarths_div {
/* Bits [31:2] is baud rate divisor register */
u32 div : 16;
/* Bits [31:16] is 0 */
u32 zero : 16;
} __attribute__((packed, aligned(4)));
struct uarths {
/* Address offset 0x00 */
struct uarths_txdata txdata;
/* Address offset 0x04 */
struct uarths_rxdata rxdata;
/* Address offset 0x08 */
struct uarths_txctrl txctrl;
/* Address offset 0x0c */
struct uarths_rxctrl rxctrl;
/* Address offset 0x10 */
struct uarths_ie ie;
/* Address offset 0x14 */
struct uarths_ip ip;
/* Address offset 0x18 */
struct uarths_div div;
} __attribute__((packed, aligned(4)));
enum uarths_stopbit { UARTHS_STOP_1, UARTHS_STOP_2 };
void uarths_init(u32 baud_rate, enum uarths_stopbit stopbit);
void uarths_putc(char c);
int uarths_getc(void);
#endif /* _K210_UARTHS_H_ */

View File

@@ -136,7 +136,6 @@ const struct sbi_platform_operations platform_ops = {
.console_init = sifive_u_console_init,
.irqchip_init = sifive_u_irqchip_init,
.ipi_send = clint_ipi_send,
.ipi_sync = clint_ipi_sync,
.ipi_clear = clint_ipi_clear,
.ipi_init = sifive_u_ipi_init,
.timer_value = clint_timer_value,

View File

@@ -141,7 +141,6 @@ const struct sbi_platform_operations platform_ops = {
.console_init = virt_console_init,
.irqchip_init = virt_irqchip_init,
.ipi_send = clint_ipi_send,
.ipi_sync = clint_ipi_sync,
.ipi_clear = clint_ipi_clear,
.ipi_init = virt_ipi_init,
.timer_value = clint_timer_value,

View File

@@ -18,7 +18,7 @@ FW_TEXT_START=0x80000000
FW_DYNAMIC=y
FW_JUMP=y
FW_JUMP_ADDR=0x80200000
FW_JUMP_FDT_ADDR=0x82200000
FW_JUMP_FDT_ADDR=0x88000000
FW_PAYLOAD=y
FW_PAYLOAD_OFFSET=0x200000
FW_PAYLOAD_FDT_ADDR=0x82200000
FW_PAYLOAD_FDT_ADDR=0x88000000

View File

@@ -62,6 +62,12 @@ static void fu540_modify_dt(void *fdt)
char cpu_node[32] = "";
const char *mmu_type;
size = fdt_totalsize(fdt);
err = fdt_open_into(fdt, fdt, size + 256);
if (err < 0)
sbi_printf(
"Device Tree can't be expanded to accmodate new node");
for (i = 0; i < FU540_HART_COUNT; i++) {
sbi_sprintf(cpu_node, "/cpus/cpu@%d", i);
cpu_offset = fdt_path_offset(fdt, cpu_node);
@@ -70,14 +76,10 @@ static void fu540_modify_dt(void *fdt)
!strcmp(mmu_type, "riscv,sv48")))
continue;
else
fdt_setprop_string(fdt, cpu_offset, "status", "masked");
fdt_setprop_string(fdt, cpu_offset, "status",
"disabled");
memset(cpu_node, 0, sizeof(cpu_node));
}
size = fdt_totalsize(fdt);
err = fdt_open_into(fdt, fdt, size + 256);
if (err < 0)
sbi_printf(
"Device Tree can't be expanded to accmodate new node");
chosen_offset = fdt_path_offset(fdt, "/chosen");
fdt_setprop_string(fdt, chosen_offset, "stdout-path",
@@ -197,7 +199,6 @@ const struct sbi_platform_operations platform_ops = {
.console_init = fu540_console_init,
.irqchip_init = fu540_irqchip_init,
.ipi_send = clint_ipi_send,
.ipi_sync = clint_ipi_sync,
.ipi_clear = clint_ipi_clear,
.ipi_init = fu540_ipi_init,
.timer_value = clint_timer_value,

View File

@@ -124,15 +124,6 @@ static void platform_ipi_send(u32 target_hart)
clint_ipi_send(target_hart);
}
/*
* Wait for target HART to acknowledge IPI.
*/
static void platform_ipi_sync(u32 target_hart)
{
/* Example if the generic CLINT driver is used */
clint_ipi_sync(target_hart);
}
/*
* Clear IPI for a target HART.
*/
@@ -216,7 +207,6 @@ const struct sbi_platform_operations platform_ops = {
.console_init = platform_console_init,
.irqchip_init = platform_irqchip_init,
.ipi_send = platform_ipi_send,
.ipi_sync = platform_ipi_sync,
.ipi_clear = platform_ipi_clear,
.ipi_init = platform_ipi_init,
.timer_value = platform_timer_value,
@@ -234,5 +224,6 @@ const struct sbi_platform platform = {
.hart_count = 1,
.hart_stack_size = 4096,
.disabled_hart_mask = 0,
.tlb_range_flush_limit = 0,
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -83,17 +83,18 @@ BUILD_ARCHIVE_NAME="opensbi-${BUILD_VERSION_MAJOR}.${BUILD_VERSION_MINOR}-rv${BU
# Setup platform list
case "${BUILD_RISCV_XLEN}" in
32)
# Setup 32bit platform list
# Setup 32-bit platform list
BUILD_PLATFORM_SUBDIR=("qemu/virt")
BUILD_PLATFORM_SUBDIR+=("qemu/sifive_u")
;;
64)
# Setup 64bit platform list
# Setup 64-bit platform list
BUILD_PLATFORM_SUBDIR=("qemu/virt")
BUILD_PLATFORM_SUBDIR+=("qemu/sifive_u")
BUILD_PLATFORM_SUBDIR+=("sifive/fu540")
BUILD_PLATFORM_SUBDIR+=("kendryte/k210")
BUILD_PLATFORM_SUBDIR+=("ariane-fpga")
BUILD_PLATFORM_SUBDIR+=("andes/ae350")
;;
*)
echo "Invalid RISC-V XLEN"