102 Commits
v1.0 ... v1.1

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

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
2022-06-25 09:12:10 +05:30
Sergey Matyukevich
3f66465fb6 lib: pmu: allow to use the highest available counter
OpenSBI explicitly assumes that there is no pmu hardware counter with
index 1: hardware uses that bit for TM control. So OpenSBI filters
out that index in sanity checks. However OpenSBI also excludes that
counter when reports total amount of hardware counters to Linux. As
a result, Linux uses incomplete counters mask excluding the highest
available counter.

Return accurate number of counters, update the firmware counter
starting index, fix range checks that include num_hw_ctrs.

The simple test is to make sure that there is no counter multiplexing
in the following command:

$ perf stat -e \
	r8000000000000000,r8000000000000001,r8000000000000002,r8000000000000003, \
	r8000000000000004,r8000000000000005,r8000000000000006,r8000000000000007, \
	r8000000000000008,r8000000000000009,r800000000000000a,r800000000000000b, \
	r800000000000000c,r800000000000000d,r800000000000000e,r800000000000000f  \
	ls

Note that 16 firmware events with 16 counters won't require multiplexing.

Signed-off-by: Sergey Matyukevich <geomatsi@gmail.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-25 08:44:20 +05:30
Anup Patel
c6fdbcf83f include: sbi: Change spec version to 1.0
Now that SBI v1.0 specification is ratified, we change spec verion
implemented by OpenSBI to v1.0.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-24 08:54:59 +05:30
Samuel Holland
6f1fe98c2f lib: utils/timer: Remove Allwinner D1 CLINT compatibles
The allwinner,sun20i-d1-clint compatible string is not documented in any
official binding, so it should not be used by drivers.

The MSWI in the D1 CLINT is compatible with the ACLINT specification, so
it can take advantage of generic driver support. However, that is only
possible if the MSWI and MTIMER are split into separate DT nodes. This
means the final binding for this device is likely to be incompatible
with what is implemented here.

Remove this compatible string from the driver to prevent it from
appearing in a stable version and causing future issues.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-22 10:55:37 +05:30
Jan Remes
d76a196bfc lib: irqchip/plic: fix typo in plic_warm_irqchip_init
The second invocation of plic_context_init() incorrectly calls the
function with m_cntx_id instead of s_cntx_id. This breaks systems which
only have 1 external interrupt per hart.

Fixes: 8c362e7 ("lib: irqchip/plic: Factor out a context init function")
Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Samuel Holland <samuel@sholland.org>
2022-06-22 10:55:27 +05:30
Samuel Holland
7738345396 lib: utils/timer: Add a separate compatible for the D1 CLINT
The CLINT in the Allwinner D1 SoC apparently does not support 64-bit
MMIO access. A property was added to support this quirk (and that
property was copied to the ACLINT MTIMER code). However, since this
difference in behavior makes the D1 CLINT incompatible with the SiFive
CLINT's programming interface, a better solution is to use a separate
compatible string.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 09:20:59 +05:30
Anup Patel
c6530012d4 lib: utils: Remove CSRs that set/clear an IMSIC interrupt file bits
Based on architecture review committee feedback, the [m|s|vs]seteienum,
[m|s|vs]clreienum, [m|s|vs]seteipnum, and [m|s|vs]clreipnum CSRs are
removed in the latest AIA draft v0.3.0 specification.
(Refer, https://github.com/riscv/riscv-aia/releases/tag/0.3.0-draft.31)

These CSRs were mostly for software convenience and software can always
use [m|s|vs]iselect and [m|s|vs]ireg CSRs to update the IMSIC interrupt
file bits.

We update the IMSIC programming as-per above to match the latest AIA
draft specification.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-06-21 08:44:45 +05:30
dramforever
a07402ac9c lib: sbi: Fix tval and tinst for sbi_get_insn()
We should not change trap->tval to mepc because mtval already points to
the faulting portion of the emulated instruction fetch, which is also
what stval is expected to be.

In addition, htinst is only allowed to be zero for instruction access
faults or page faults, and is only allowed to be zero or a
psuedoinstruction for instruction guest-page faults. Fix trap->tinst for
these cases.

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:56 +05:30
dramforever
187127fb89 lib: sbi: Fixup tinst for exceptions in sbi_misaligned_*()
If there is an exception while emulating a misaligned load/store, fixup
uptrap.tinst before redirecting. Otherwise, HS-mode software may receive
an htinst describing the lbu/sb instruction that faulted during
emulation[1].

[1]: https://github.com/riscv-software-src/opensbi/issues/258

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:14 +05:30
dramforever
551c70c040 include: sbi: Add mtinst/htinst psuedoinstructions
Add psuedoinstruction encodings written to mtinst/htinst for faults
caused by implicit memory access for VS-stage address translation

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-21 08:31:04 +05:30
Samuel Holland
9dc5ec5c51 platform: Add HSM implementation for Allwinner D1
Allwinner D1 contains a "PPU" power domain controller which can
automatically power down/up the CPU power domain. This power domain
includes the C906 core along with its CLINT and PLIC.

This HSM implementation supports non-retentive hart suspend by:
  1) Saving/restoring state that is lost during hart suspend,
  2) Performing cache maintenance before/after hart suspend,
  3) Configuring wakeup sources before hart suspend, and
  4) Asking the PPU to power down the hart when it enters WFI.

Since this HSM implementation is for a single-core SoC, it does not need
to worry about concurrency or saving multiple instances of state.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:59:09 +05:30
Samuel Holland
5e5675874c lib: utils/irqchip: Add wrapper for T-HEAD PLIC delegation
The delegation bit is lost along with the rest of the PLIC state when
the CPU power domain in the Allwinner D1 is powered down, so the PLIC
needs to be re-delegated to S-mode during the hart resume path.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
69be3dff9d lib: utils/irqchip: Add FDT wrappers for PLIC save/restore functions
These functions save/restore the state of the PLIC associated with the
current hart. The context save/restore functions only manipulate a
single context, since most likely the M-mode context is unused and does
not need to be saved.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
2b79b694a8 lib: irqchip/plic: Add priority save/restore helpers
These can be used by platform code to save the PLIC priority state, if
it would otherwise be lost during non-retentive suspend. The platform
is responsible for allocating all necessary storage.

As a space optimization, store the saved priority values as 8-bit
integers, since that is large enough to hold any priority value on the
relevant platforms.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
415ecf28f7 lib: irqchip/plic: Add context save/restore helpers
These can be used by platform code to save the PLIC context state, if
it would otherwise be lost during non-retentive suspend. The platform
is responsible for allocating all necessary storage.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
8c362e7d06 lib: irqchip/plic: Factor out a context init function
This simplifies both the callers and the callees by removing duplicated
code and consolidating the error handling. It also fixes two bugs in the
process:
  1) ie_words was one too large when plic->num_src was a multiple of 32.
  2) plic_set_ie takes a 32-bit mask, not a Boolean value, so the FPGA
     platforms previously only enabled one out of every 32 interrupts.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
2ea7799d56 lib: irqchip/plic: Constify plic_data pointers
None of the functions modify the passed-in plic_data, so mark it const.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
79e42eb2d6 lib: sbi_hsm: Assume a consistent resume address
The suspend code needs to know the resume address for two reasons:
  1) Programming some hardware register or management firmware. Here we
     assume the hardware/firmware maintains its state between suspends,
     so it only needs to be programmed once at startup.
  2) When a non-retentive suspend request ends up being retentive, due
     to lack of hardware support, pending interrupt, or for some other
     reason. However, the behavior here is not platform-dependent, and
     this can be handled in the generic hart suspend function.

Since neither situation requires the platform-level suspend function to
know the resume address, stop passing it to that function. Instead,
handle the non-retentive to retentive situation generically.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Samuel Holland
b20ed9febe lib: sbi_hsm: Call a device hook during hart resume
Non-retentive suspend states may require platform-specific actions
during resume. For example, firmware may need to save and restore the
values of custom CSRs. Add a hook to support this.

Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-06-13 11:54:06 +05:30
Mayuresh Chitale
ce1d6188a2 platform: generic: add overrides for vendor extensions
Allow the vendor_ext_check and vendor_ext_provider APIs of the
generic platform to be overridden by other platforms

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:17:38 +05:30
dramforever
adc3388d76 lib: sbi_trap: Redirect exception based on hedeleg
HS-mode software can choose what exceptions to delegate to VS-mode using
the hedeleg CSR. Synthetic VS/VU-mode exceptions should also honor
hedeleg. They should be redirected to VS-mode if and only if delegated
by HS-mode.

Signed-off-by: dramforever <dramforever@live.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-13 11:02:49 +05:30
Samuel Holland
cb8271c8e4 lib: sbi_illegal_insn: Add emulation for fence.tso
While OpenC906 appears to properly decode `fence.tso` as a fence
instruction[1], the version of the C906 taped out in the Allwinner D1
does not, and raises illegal instruction.

Handle this errata by emulating `fence.tso` as `fence rw, rw`.

[1]: https://github.com/T-head-Semi/openc906/blob/30827e7f/C906_RTL_FACTORY/gen_rtl/idu/rtl/aq_idu_id_decd.v#L2097

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-06-01 17:20:20 +05:30
Samuel Holland
ff65bfec4e lib: sbi_illegal_insn: Constify illegal_insn_table
This table does not need to be modified at runtime.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:54:31 +05:30
Samuel Holland
295e5f3c69 lib: sbi_timer: Drop unnecessary get_platform_ticks wrapper
The device's timer_value callback is already the right prototype to use
for the get_time_val function pointer.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:43:03 +05:30
Samuel Holland
fab0379bb6 lib: utils/fdt: Require match data to be const
Match data stores hardware attributes which do not change at runtime, so
it does not need to be mutable. Make it const.

Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
2022-05-30 10:32:35 +05:30
Xiang W
f067bb84cf lib: sbi: fix system_opcode_insn
If the csr's operation comes from M mode, it should not be forwarded
to low-privilege processing, this patch fixes this problem.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-30 10:22:13 +05:30
Jan Remes
1bc67db80c lib: utils/fdt: rename fdt_parse_max_hart_id
The function returns the highest hart-id of the harts actually used in
the system (enabled). Change the name to reflect this fact.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:18:12 +05:30
Jan Remes
575bb4e8ca platform: generic: check if CPU node is enabled
Ignore CPU nodes in FDT which are not enabled.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:17:33 +05:30
Jan Remes
616da52e18 lib: utils: check if CPU node is enabled
Ignore CPU nodes in FDT that are not enabled.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:16:50 +05:30
Jan Remes
90a9dd2b22 lib: utils/fdt: introduce fdt_node_is_enabled()
If an FDT node contains a "status" property and this property is not
"ok" or "okay", this node should be ignored. Introduce a function that
checks this.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-14 10:16:24 +05:30
Jan Remes
851c14d455 lib: utils/irqchip: fix typo when checking for CPU node
Fix typo in irqchip_imsic_update_hartid_table() when checking for CPU
node.

Signed-off-by: Jan Remes <jan.remes@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
2022-05-13 09:58:54 +05:30
Anup Patel
9a7a677d5f platform: generic: Move Sifive platform overrides into own directory
Let us move SiFive platform overrides for FU540 and FU740 into a separate
directory so better maintainability. Other SoC vendors can also create
their own directory under platform/generic.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:23 +05:30
Anup Patel
a3a3c60b66 platform: generic: Generate platform override module list at compile-time
Instead of having platform override module list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:18 +05:30
Anup Patel
4eacd8229b lib: utils/gpio: Generate FDT gpio driver list at compile-time
Instead of having FDT gpio driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:27:12 +05:30
Anup Patel
998ed43fde lib: utils/i2c: Generate FDT i2c adapter driver list at compile-time
Instead of having FDT i2c adapter driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:45 +05:30
Anup Patel
4ee0c57969 lib: utils/ipi: Generate FDT ipi driver list at compile-time
Instead of having FDT ipi driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:35 +05:30
Anup Patel
3a69d12fc3 lib: utils/irqchip: Generate FDT irqchip driver list at compile-time
Instead of having FDT irqchip driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:27 +05:30
Anup Patel
bfeb305e0f lib: utils/timer: Generate FDT timer driver list at compile-time
Instead of having FDT timer driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:20 +05:30
Anup Patel
1e62705adc lib: utils/serial: Generate FDT serial driver list at compile-time
Instead of having FDT serial driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:13 +05:30
Anup Patel
73cf511914 lib: utils/reset: Generate FDT reset driver list at compile-time
Instead of having FDT reset driver list hard-coded in the C source,
we generate it using carray.sh at compile-time.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:06 +05:30
Anup Patel
7fb474b9dd Makefile: Add support for generating C array at compile time
Generating C array at compile time based on details provided by
objects.mk is a very useful feature which will help us compile
only a subset of drivers or modules.

We add a bash script (carray.sh) which takes array details and
object/variable list from command-line to generate a C source
containing array of object/variable pointers. We also extend
top-level makefile to use carray.sh whenever specified through
objects.mk.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:26:00 +05:30
Anup Patel
f726f2dc01 Makefile: Allow generated C source to be anywhere in build directory
The generated C source could be anywhere within build directory so
let us update the make rule to comple generated C source accordingly.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-13 09:25:50 +05:30
Anup Patel
023f0ad2d9 lib: sbi_platform: Add callback to populate HART extensions
We add platform specific extensions_init() callback which allows
platforms to populate HART extensions for each HART. For example,
the generic platform can populate HART extensions from HART ISA
string described in DeviceTree.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:28 +05:30
Anup Patel
994ace30f7 lib: sbi: Add sbi_hart_update_extension() function
We add sbi_hart_update_extension() function which allow platforms
to enable/disable hart extensions.

Signed-off-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:25 +05:30
Anup Patel
be4903ae00 lib: sbi: Detect hart features only once for each hart
Currently, the hart_detect_features() is called everytime a hart
is stopped and started again which is unnecessary work.

We update hart_detect_features() to detect hart features only
once for each hart.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:17:22 +05:30
Anup Patel
cad6c91045 lib: sbi: Convert hart features into hart extensions
Since past few years, we have been using "hart features" in OpenSBI
to represent all optionalities and multi-letter extensions defined
by the RISC-V specifications.

The RISC-V profiles specification has taken a different approach and
started assigning extension names for all optionalities which did not
have any extension name previously.
(Refer, https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc)

Inspired from the RISC-V profiles specification, we convert OpenSBI
hart features into hart extensions. Going forward, we align the
extension naming with RISC-V profiles specification. Currently, only
"time CSR" and "AIA CSR" have not been assigned extension name but
for everything else we have a name.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:16:30 +05:30
Anup Patel
a6ab94fdbf lib: sbi: Fix AIA feature detection
The AIA feature detection uses unnecessary goto which is not need
and AIA case in sbi_hart_feature_id2string() does not break. This
patch fixes both issues in AIA feature detection.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:06:57 +05:30
Anup Patel
97a17c2e5c lib: sbi: Remove MENVCFG hart feature
If a hart implements privileged spec v1.12 (or higher) then we can
safely assume that menvcfg CSR is present and we don't need MENVCFG
as a hart feature.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:06:19 +05:30
Anup Patel
dbc3d8f0ef lib: sbi: Remove MCOUNTINHIBT hart feature
If a hart implements privileged spec v1.11 (or higher) then we can
safely assume that mcountinhibit CSR is present and we don't need
MCOUNTINHIBT as a hart feature.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:05:37 +05:30
Anup Patel
d4b563c881 lib: sbi: Remove MCOUNTEREN and SCOUNTEREN hart features
If a hart implements privileged spec v1.10 (or higher) then we can
safely assume that [m|s]counteren CSR are present and we don't need
MCOUNTEREN and SCOUNTEREN as hart features.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:04:54 +05:30
Anup Patel
5b8b377178 lib: sbi: Update the name of ISA string printed at boot time
The ISA string printed at boot time is not the complete ISA string
representing all single letter and multi-letter extensions rather
it is base ISA string derived from misa CSR so let us update the
boot print accordingly.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:03:24 +05:30
Anup Patel
5a6be99cc5 lib: sbi: Remove 's' and 'u' from misa_string() output
Both 's' and 'u' are not treated as ISA extensions since these are
privilege modes so let's remove it from misa_string() output.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 10:02:28 +05:30
Anup Patel
1a754bb365 lib: sbi: Detect and print privileged spec version
It is possible to guess privileged spec versions based on the CSRs
that where introduced in different privileged spec versions. In
future, if we are not able guess privileged spec version then we
can have platform provide it.

We add privileged spec version as per-hart feature and try to guess
it based on presence of mcounteren, mcountinhibit, and menvcfg CSRs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-05-07 09:49:54 +05:30
Atish Patra
b0c9df514b lib: sbi: Fix mhpmeventh access for rv32 in absence of sscofpmf
MHPMEVENT3H-31H are defined in sscofpmf extension. Thus, they should be
accessed only if sscofpmf is present.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-07 09:40:59 +05:30
Jun Liang Tan
e576b3e620 include: sbi: Define SBI_PMU_HW_EVENT_MAX to 256
Increase maximum number of PMU hardware events that can be mapped
by OpenSBI to 256

Signed-off-by: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
Signed-off-by: Wei Liang Lim <weiliang.lim@linux.starfivetech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-05-07 09:37:42 +05:30
Anup Patel
474a9d4555 lib: sbi: Fix mstatus_init() for RV32 when Sscofpmf is not available
The mhpmevent3h to mhpmevent31h CSRs are available on RV32 only when
Sscofpmf extension is available so mstatus_init() should set this
CSRs only when Sscofpmf extension is available.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-04-28 19:39:01 +05:30
Atish Patra
d62f6da062 lib: sbi: Implement Sstc extension
Recently, Sstc extension was ratified. It defines stimecmp which allows
the supervisor mode to directly update the timecmp value without the
need of the SBI call. The hardware also can inject the S-mode timer
interrupt direclty to the supervisor without going through the M-mode.
To maintain backward compatibility with the older software, SBI call
now uses stimecmp directly if the hardware supports.

Implement the Sstc extension.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-28 11:45:21 +05:30
Atish Patra
4035ae94be docs: pmu: Improve the PMU DT bindings
The current DT binding description is misleading and confusing. Clarify
the text and provide more examples.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-28 11:40:15 +05:30
Dmitry Dunaev
9cd95e13bb lib: sbi/hart: preserve csr validation value
The OpenSBI hart init function hart_detect_features() try to read
important CSRs but reasign the last read value to the variable that
initially contains write probe value. So for series of CSRs (like
PMPADDRx) the second CSR probe value will became the initial value of
first probing CSR. To avoid of this issue the CSR read value should be
saved in different variable. In this configuration the count of PMP
will detect rightly if any PMPADDR is hardwired to zero.

Signed-off-by: Dmitry Dunaev <dunaich@mail.ru>
Signed-off-by: Anup Patel <anup@brainfault.org>
2022-04-17 14:43:08 +05:30
Vincent Chen
c1e47d0c3f include: correct the definition of MSTATUS_VS
Accordind to the RISC-V privileged specification, the VS filed is
mstatus[10:9] instead of mstatus[24:23]. Modify the MSTATUS_VS
to the correct value.

Reported-by: I-Cheng Cheng <i-cheng.cheng@sifive.com>
Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-17 14:30:19 +05:30
Zong Li
5c5cbb53a4 lib: utils/serial: support 'reg-offset' property
reg-offset property is used for offset to apply to the mapbase
from the start of the registers in 8250 UART. In Linux kernel,
it has been handled in 8250 UART driver.

dt-bindings:
<linux>/Documentation/devicetree/bindings/serial/8250.yaml

Signed-off-by: Zong Li <zong.li@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-17 13:57:48 +05:30
Mayuresh Chitale
3383d6a4d1 lib: irqchip/imsic: configure mstateen
When mstateen registers are implemented, the AIA related
configurations need to be done in mstateen for the IMSIC
initialization to succeed.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:17 +05:30
Mayuresh Chitale
d44568a0f2 lib: sbi: Detect Smstateen CSRs at boot-time
Extend HART feature detection to discover Smstateen CSRs at boot-time
and configure mstateen envcfg bit depending on availability of
menvcfg CSR.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:10 +05:30
Mayuresh Chitale
499601a4ff lib: sbi: Add Smstateen extension defines
Smstateen extension provides a mechanism to plug potential
covert channels which are opened by extensions that add to
processor state that may not get context-switched.

Signed-off-by: Mayuresh Chitale <mchitale@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-04-11 08:34:02 +05:30
Anup Patel
794986f87f lib: sbi: Enable Svpbmt extension in the menvcfg CSR
The menvcfg.PBMTE bit is read-only zero when Svpbmt extension is not
available so we try to enable menvcfg.PBMTE bit irrespective whether
Svpbmt is available or not.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:53:11 +05:30
Anup Patel
47d676570d lib: sbi: Enable Zicbo[m|z] extensions in the menvcfg CSR
The bits to configure/enable Zicbo[m|z] extensions in the menvcfg
CSR are WARL. We try to enable these bits irrespective whether
these extensions are available or not because writes to these
bits will be ignored if these extensions are not available.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:51:40 +05:30
Atish Patra
31fecad46d lib: sbi: Detect menvcfg CSR at boot time
We add the menvcfg CSR as a HART feature and detect it at boot time
using traping mechanism.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:50:48 +05:30
Anup Patel
722f80d8e9 include: Add defines for [m|h|s]envcfg CSRs
The latest RISC-V privileged specification introduces xenvcfg CSRs
to enable/disable certain features/extensions for lower privilege
modes. This patch adds defines for these new [m|h|s]envcfg CSRs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-04-05 08:50:17 +05:30
Xiang W
7924a0b220 include: Use static asserts for FW_DYNAMIC_INFO_xxx_OFFSET defines
Add static detection to prevent the modification of struct fw_dynamic_info
from forgetting the modification of FW_DYNAMIC_INFO_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:44:58 +05:30
Xiang W
1b42d3ace3 include: Use static asserts for SBI_SCRATCH_xxx_OFFSET defines
Add static detection to prevent the modification of struct sbi_scratch
from forgetting the modification of SBI_SCRATCH_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:44:54 +05:30
Xiang W
555bdb1cf3 include: Use static asserts for SBI_PLATFORM_xxx_OFFSET defines
Add static detection to prevent the modification of struct sbi_platform
from forgetting the modification of SBI_PLATFORM_xxx_OFFSET

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 09:07:44 +05:30
Xiang W
d552fc8d36 lib: Add error messages via conditional compilation for the future
On 128-bit machines, sbi_load_xx/sbi_store_xx needs to be improved.
Through this conditional compile, the corresponding implementation
can be prompted to be added.

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:54:12 +05:30
Xiang W
b6b7220a47 firmware: Fix code for accessing hart_count and stack_size
lwu exists under the current rv64 and should also exist under the rv128
in the future, so I modified the conditions of conditional compilation
so that it can adapt to the future situation

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:53:27 +05:30
Xiang W
2dfbd3c0e2 lib: pmp_set/pmp_get moved errors from runtime to compile time
pmp_set/pmp_get calculates the location of the CSR register separately
through conditional compilation. In the case of non-32-bit and 64-bit,
we can report an error directly through #error without putting it at
runtime

Signed-off-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-03-27 08:52:19 +05:30
Alistair Francis
4998a712b2 lib: utils: serial: Initial commit of xlnx-uartlite
Initial commit of the xlnx-uartlite device and FDT support. This was
tested by running OpenSBI on a modified QEMU virt machine using the
xlnx-uartlite for serial.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-28 09:50:09 +05:30
Anup Patel
f3f4604c19 lib: sbi: Add a simple external interrupt handling framework
Currently, the external interrupt handling is scattered between
sbi_init and sbi_trap. This patch moves all external interrupt
handling into a simple framework called sbi_irqchip.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-28 09:43:12 +05:30
Nikita Shubin
f2ccf2f783 lib: sbi: verbose sbi_domain_root_add_memregion
Be more verbose on region confict, print addresses in conflict.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-15 20:59:38 +05:30
Nikita Shubin
3a69cc1487 lib: sbi: fix typo in is_region_subset
Fix typo in is_region_subset, regB_end should be calculated from regB.

Signed-off-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-15 20:58:04 +05:30
Anup Patel
8e2ef4f7af lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups()
We should disable APLIC DT nodes in fdt_fixups() which are not
accessible to the next booting stage based on currently assigned
domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:39:15 +05:30
Anup Patel
34612193af lib: utils/irqchip: Add FDT based driver for APLIC
We add simple FDT irqchip driver for APLIC so that generic platform (and
other FDT based platforms) can utilize common APLIC initialization library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:39:01 +05:30
Anup Patel
99792653de lib: utils/irqchip: Add APLIC initialization library
We add simple APLIC initialization library which is independent of
hardware description format (FDT or ACPI). This APLIC initialization
library can be used by custom OpenSBI platform support to setup
APLIC domains.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:55 +05:30
Anup Patel
7127aaaaf7 lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups()
We should disable IMSIC DT nodes in fdt_fixups() which are not
accessible to the next booting stage based on currently assigned
domain.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:27 +05:30
Anup Patel
811da5c541 lib: utils/irqchip: Add FDT based driver for IMSIC
We add simple FDT irqchip driver for IMSIC so that generic platform
(and other FDT based platforms) can utilize common IMIC library.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:37:05 +05:30
Anup Patel
9f73669959 lib: utils/irqchip: Add IMSIC library
We add simple IMSIC library which is independent of hardware description
format (FDT or ACPI). This IMSIC library can be used by custom OpenSBI
platform support to setup IMSIC for external interrupts.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:36:24 +05:30
Anup Patel
55e79f823d lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts.
We can have IPIs based on external interrupts provided by devices
such as AIA IMSIC so we should enable mie.MEIE bit at appropriate
places in generic library.

Signed-off-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:35:45 +05:30
Anup Patel
10509405b2 include: sbi: Introduce nascent_init() platform callback
We introduce nascent_init() platform callback which will allow
platforms to do very early initialization of platform specific
per-HART CSRs and per-HART devices.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:34:24 +05:30
Anup Patel
5f56314618 lib: utils/irqchip: Allow multiple FDT irqchip drivers
We can have multiple FDT irqchip drivers to be probed when a RISC-V
system has different types of interrupt controller in a hierarchy.

This will be certainly the case when a RISC-V system has both
RISC-V AIA IMSIC and RISC-V AIA APLIC implemented.

We extend simple FDT irqchip framework to allow multiple FDT
irqchip drivers to be used for same RISC-V platform.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:34:08 +05:30
Anup Patel
222132f48c lib: sbi: Add sbi_trap_set_external_irqfn() API
This patch adds sbi_trap_set_external_irqfn() API which can be used by
OpenSBI platform code to set a callback function for external interrupts.
The RISC-V AIA IMSIC driver will use this API to implement inter-processor
interrupts on-top-of MSIs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:33:55 +05:30
Anup Patel
65b4c7c01e lib: sbi: Use AIA CSRs for local interrupts when available
We should use AIA CSRs to process local interrupts whenever AIA
is available.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:33:31 +05:30
Anup Patel
8f96070067 lib: sbi: Detect AIA CSRs at boot-time
We extend HART feature detection to discover AIA CSRs at boot-time.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:32:42 +05:30
Anup Patel
01250d0044 include: sbi: Add AIA related CSR defines
The RISC-V AIA specification improves handling of per-HART local
interrupts in a backward compatible manner. This patch adds defines
for the new RISC-V AIA CSRs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-02-15 20:32:07 +05:30
Jakub Luzny
ce4c0188d9 lib: utils/serial: Round UART8250 baud rate divisor to nearest integer
Previously, it was rounded down and that gives suboptimal results when
non-standard clock sources or baud rates are used.

Signed-off-by: Jakub Luzny <jakub.luzny@codasip.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 11:16:29 +05:30
Petro Karashchenko
6ad8917b7e lib: fix compilation when strings.h is included
In a systems that provide strings.h and it is included
together with sbi_bitops.h the compilation error appears.
The ffs() and fls() are provided by strings.h

Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 11:04:19 +05:30
Aurelien Jarno
5d53b55aa7 Makefile: fix build with binutils 2.38
From version 2.38, binutils default to ISA spec version 20191213. This
means that the csr read/write (csrr*/csrw*) instructions and fence.i
instruction has separated from the `I` extension, become two standalone
extensions: Zicsr and Zifencei. As the kernel uses those instruction,
this causes the following build failure:

 CC        lib/sbi/sbi_tlb.o
<<BUILDDIR>>/lib/sbi/sbi_tlb.c: Assembler messages:
<<BUILDDIR>>/lib/sbi/sbi_tlb.c:190: Error: unrecognized opcode `fence.i'
make: *** [Makefile:431: <<BUILDDIR>>/build/lib/sbi/sbi_tlb.o] Error 1

The fix is to specify those extensions explicitly in -march. However as
older binutils version do not support this, we first need to detect
that.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Alexandre Ghiti <alexandre.ghiti@canonical.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:47:24 +05:30
Atish Patra
a26dc609df lib: sbi: Disable interrupt and inhibit counting in M-mode during init
Currently, the mhpmevent CSRs are untouched during hart init during
cold/warm boot. Ideally, we should clear out all the bits except
overflow and MINH bit. That is required to disable overflow
interrupt and inhibit counting in M-mode to avoid any spurious
interrupts before perf start.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:10:28 +05:30
Atish Patra
3b7c204dca lib: sbi: Disable interrupt during config matching
PMU overflow interrupt should be disabled durinig initial configuration of
counters. They should be enabled while starting counters.

Fixes: 730f01bb41 ("lib: sbi: Support sscofpmf extension in OpenSBI")
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:08:57 +05:30
Atish Patra
632f59392b lib: sbi: Map only the counters enabled in hardware
The counter mapping in DT may be incorrect if all the counters specified
in the mapping are actually not physically present in the hardware.
OpenSBI should only keep a mapping of counters enabled in hardware and
defined in DT. This assume that all the programmable hpmcounters are
consecutive as it doesn't make sense to build a system with sparse
hpmcounters.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-02-04 10:07:07 +05:30
Jukka Laitinen
5d025eb235 lib: fix pointer of type 'void *' used in arithmetic
Using "void *" in arithmetic causes errors with strict compiler settings:
"error: pointer of type 'void *' used in arithmetic [-Werror=pointer-arith]"

Avoid these by calculating on "char *" where 1-byte data size is assumed.

Signed-off-by: Jukka Laitinen <jukkax@ssrc.tii.ae>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-01-21 21:58:12 +05:30
Aurelien Jarno
fb688d9e9d platform: sifive_fu740: fix reset when watchdog is running
When the watchdog is running the HiFive Unmatched board does not reboot
properly and shuts down itself a few seconds after reboot, in the early
stages of the u-boot loading. On a Linux kernel this happens when the
da9063_wdt module is loaded. This does not happen if the module is
unloaded before reboot or if the watchdog module is loaded with
"stop_on_reboot=1".

Fix that by stopping the watchdog before attempting to reset the board.
This is done by zeroing the TWDSCALE field of CONTROL_D register, unless
it was already set to 0.

Reported-by: Tianon Gravi <tianon@debian.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Nikita Shubin <n.shubin@yadro.com>
Tested-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-01-21 21:44:57 +05:30
Aurelien Jarno
8257262dbf platform: sifive_fu740: do not use a global in da9063_reset/shutdown
da9063_reset() and da9063_shutdown() take the chip address in argument
(like similar functions), but in practice use the da9063 global struct
instead. Fix that.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: Nikita Shubin <n.shubin@yadro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Xiang W <wxjstz@126.com>
2022-01-21 21:41:33 +05:30
Anup Patel
6dde43584f lib: utils/sys: Extend HTIF library to allow custom base address
Some of RISC-V emulators provide HTIF at fixed base address so for
such emulators users have to hard-code HTIF base address in the
linker script.

To address this problem, we let users optionally provide fixed HTIF
base address via platform support (or device tree).

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
2022-01-11 18:17:49 +05:30
Anup Patel
5b9960379f lib: utils/ipi: Fix size check in aclint_mswi_cold_init()
Currently, the ACLINT MSWI size check is forcing size to be at least
0x4000. This is inappropriate check because most systems will never
utilize full 16KB for a single ACLINT MSWI device so instead we should
check that ACLINT MSWI size is enough for on the associated HARTs.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Dong Du <Dd_nirvana@sjtu.edu.cn>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
2022-01-11 18:17:07 +05:30
107 changed files with 3376 additions and 573 deletions

View File

@@ -153,6 +153,9 @@ OPENSBI_LD_PIE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) $(USE_LD_FLAG) -fP
# Check whether the compiler supports -m(no-)save-restore
CC_SUPPORT_SAVE_RESTORE := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -mno-save-restore -x c /dev/null -o /dev/null 2>&1 | grep "\-save\-restore" >/dev/null && echo n || echo y)
# Check whether the assembler and the compiler support the Zicsr and Zifencei extensions
CC_SUPPORT_ZICSR_ZIFENCEI := $(shell $(CC) $(CLANG_TARGET) $(RELAX_FLAG) -nostdlib -march=rv$(OPENSBI_CC_XLEN)imafd_zicsr_zifencei -x c /dev/null -o /dev/null 2>&1 | grep "zicsr\|zifencei" > /dev/null && echo n || echo y)
# Build Info:
# OPENSBI_BUILD_TIME_STAMP -- the compilation time stamp
# OPENSBI_BUILD_COMPILER_VERSION -- the compiler version info
@@ -223,7 +226,11 @@ ifndef PLATFORM_RISCV_ABI
endif
ifndef PLATFORM_RISCV_ISA
ifneq ($(PLATFORM_RISCV_TOOLCHAIN_DEFAULT), 1)
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
ifeq ($(CC_SUPPORT_ZICSR_ZIFENCEI), y)
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc_zicsr_zifencei
else
PLATFORM_RISCV_ISA = rv$(PLATFORM_RISCV_XLEN)imafdc
endif
else
PLATFORM_RISCV_ISA = $(OPENSBI_CC_ISA)
endif
@@ -397,6 +404,10 @@ compile_d2c = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
$(if $($(2)-varprefix-$(3)),$(eval D2C_NAME_PREFIX := $($(2)-varprefix-$(3))),$(eval D2C_NAME_PREFIX := $(5))) \
$(if $($(2)-padding-$(3)),$(eval D2C_PADDING_BYTES := $($(2)-padding-$(3))),$(eval D2C_PADDING_BYTES := 0)) \
$(src_dir)/scripts/d2c.sh -i $(6) -a $(D2C_ALIGN_BYTES) -p $(D2C_NAME_PREFIX) -t $(D2C_PADDING_BYTES) > $(1)
compile_carray = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CARRAY $(subst $(build_dir)/,,$(1))"; \
$(eval CARRAY_VAR_LIST := $(carray-$(subst .c,,$(shell basename $(1)))-y)) \
$(src_dir)/scripts/carray.sh -i $(2) -l "$(CARRAY_VAR_LIST)" > $(1)
compile_gen_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " GEN-DEP $(subst $(build_dir)/,,$(1))"; \
echo "$(1:.dep=$(2)): $(3)" >> $(1)
@@ -430,6 +441,9 @@ $(build_dir)/%.dep: $(src_dir)/%.c
$(build_dir)/%.o: $(src_dir)/%.c
$(call compile_cc,$@,$<)
$(build_dir)/%.o: $(build_dir)/%.c
$(call compile_cc,$@,$<)
ifeq ($(BUILD_INFO),y)
$(build_dir)/lib/sbi/sbi_init.o: $(libsbi_dir)/sbi_init.c FORCE
$(call compile_cc,$@,$<)
@@ -441,6 +455,13 @@ $(build_dir)/%.dep: $(src_dir)/%.S
$(build_dir)/%.o: $(src_dir)/%.S
$(call compile_as,$@,$<)
$(build_dir)/%.dep: $(src_dir)/%.carray
$(call compile_gen_dep,$@,.c,$<)
$(call compile_gen_dep,$@,.o,$(@:.dep=.c))
$(build_dir)/%.c: $(src_dir)/%.carray
$(call compile_carray,$@,$<)
$(platform_build_dir)/%.bin: $(platform_build_dir)/%.elf
$(call compile_objcopy,$@,$<)
@@ -456,9 +477,6 @@ $(platform_build_dir)/%.dep: $(platform_src_dir)/%.c
$(platform_build_dir)/%.o: $(platform_src_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.o: $(platform_build_dir)/%.c
$(call compile_cc,$@,$<)
$(platform_build_dir)/%.dep: $(platform_src_dir)/%.S
$(call compile_as_dep,$@,$<)

View File

@@ -52,12 +52,11 @@ DTS Example1: (Single core, eg: Allwinner D1 - c906)
ranges;
clint0: clint@14000000 {
compatible = "riscv,clint0";
compatible = "allwinner,sun20i-d1-clint";
interrupts-extended = <
&cpu0_intc 3 &cpu0_intc 7
>;
reg = <0x0 0x14000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@10000000 {
@@ -163,7 +162,6 @@ DTS Example2: (Multi cores with soc reset-regs)
&cpu4_intc 3 &cpu4_intc 7
>;
reg = <0xff 0xdc000000 0x0 0x04000000>;
clint,has-no-64bit-mmio;
};
intc: interrupt-controller@ffd8000000 {

View File

@@ -51,37 +51,50 @@ shouldn't encode any raw event.
* **riscv,raw-event-to-mhpmcounters**(Optional) - It represents an ONE-to-MANY
or MANY-to-MANY mapping between the raw event(s) and all the MHPMCOUNTERx in
a bitmap format that can be used to monitor that raw event, which depends on
how the platform encodes the monitor events. Currently, only the following three
encoding methods are supported, encoding each event as a number, using a bitmap
to encode monitor events, and mixing the previous two methods. The information
is encoded in a table format where each row represent the specific raw event(s).
The first column represents a 64-bit selector value which can indicate an
monitor event ID (encoded by a number) or an event set (encoded by a bitmap).
In case of the latter, the lower bits used to encode a set of events should be
set to zero. The second column is a 64-bit selector mask where any bits used
for event encoding will be cleared. If a platform directly encodes each raw PMU
event as a unique ID, the value of select_mask will be 0xffffffff_ffffffff.
The third column represent a bitmap of all the MHPMCOUNTERx that can be used for
monitoring the specified event(s).
a bitmap format that can be used to monitor that raw event. The encoding of the
raw events are platform specific. The information is encoded in a table format
where each row represent the specific raw event(s). The first column is a 64bit
match value where the invariant bits of range of events are set. The second
column is a 64 bit mask that will have all the variant bits of the range of
events cleared. Every other bits should be set in the mask.
The third column is a 32bit value to represent bitmap of all MHPMCOUNTERx that
can monitor these set of event(s).
If a platform directly encodes each raw PMU event as a unique ID, the value of
select_mask must be 0xffffffff_ffffffff.
*Note:* A platform may choose to provide the mapping between event & counters
via platform hooks rather than the device tree.
### Example
### Example 1
```
pmu {
compatible = "riscv,pmu";
interrupts = <0x100>;
interrupt-parent = <&plic>
riscv,event-to-mhpmevent = <0x0000B 0x0000 0x0001>,
riscv,event-to-mhpmcounters = <0x00001 0x00001 0x00000001>,
<0x00002 0x00002 0x00000004>,
<0x00003 0x0000A 0x00000ff8>,
<0x10000 0x10033 0x000ff000>,
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
<0xffffffff 0xfffffff0 0xffffffff 0xfffffff0 0x00000ff0>,
/* For event ID 0x0002 */
riscv,raw-event-to-mhpmcounters = <0x0000 0x0002 0xffffffff 0xffffffff 0x00000f8>,
/* For event ID 0-4 */
<0x0 0x0 0xffffffff 0xfffffff0 0x00000ff0>,
/* For event ID 0xffffffff0000000f - 0xffffffff000000ff */
<0xffffffff 0x0 0xffffffff 0xffffff0f 0x00000ff0>,
};
```
### Example 2
```
/*
* For HiFive Unmatched board. The encodings can be found here
* https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
*/
pmu {
compatible = "riscv,pmu";
riscv,raw-event-to-mhpmcounters = <0x0 0x0 0xffffffff 0xfc0000ff 0xc>,
<0x0 0x1 0xffffffff 0xfff800ff 0xc>,
<0x0 0x2 0xffffffff 0xffffe0ff 0xc>;
};
```

View File

@@ -259,7 +259,7 @@ _bss_zero:
* s8 -> HART Stack Size
*/
lla a4, platform
#if __riscv_xlen == 64
#if __riscv_xlen > 32
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
#else

View File

@@ -75,6 +75,41 @@ struct fw_dynamic_info {
unsigned long boot_hart;
} __packed;
/**
* Prevent modification of struct fw_dynamic_info from affecting
* FW_DYNAMIC_INFO_xxx_OFFSET
*/
_Static_assert(
offsetof(struct fw_dynamic_info, magic)
== FW_DYNAMIC_INFO_MAGIC_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_MAGIC_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, version)
== FW_DYNAMIC_INFO_VERSION_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_VERSION_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, next_addr)
== FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_NEXT_ADDR_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, next_mode)
== FW_DYNAMIC_INFO_NEXT_MODE_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_NEXT_MODE_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, options)
== FW_DYNAMIC_INFO_OPTIONS_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_OPTIONS_OFFSET");
_Static_assert(
offsetof(struct fw_dynamic_info, boot_hart)
== FW_DYNAMIC_INFO_BOOT_HART_OFFSET,
"struct fw_dynamic_info definition has changed, please redefine "
"FW_DYNAMIC_INFO_BOOT_HART_OFFSET");
#endif
#endif

View File

@@ -25,7 +25,7 @@
#define MSTATUS_MPP (_UL(3) << MSTATUS_MPP_SHIFT)
#define MSTATUS_FS _UL(0x00006000)
#define MSTATUS_XS _UL(0x00018000)
#define MSTATUS_VS _UL(0x01800000)
#define MSTATUS_VS _UL(0x00000600)
#define MSTATUS_MPRV _UL(0x00020000)
#define MSTATUS_SUM _UL(0x00040000)
#define MSTATUS_MXR _UL(0x00080000)
@@ -173,6 +173,10 @@
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
#endif
#define TOPI_IID_SHIFT 16
#define TOPI_IID_MASK 0xfff
#define TOPI_IPRIO_MASK 0xff
#if __riscv_xlen == 64
#define MHPMEVENT_OF (_UL(1) << 63)
#define MHPMEVENT_MINH (_UL(1) << 62)
@@ -181,13 +185,14 @@
#define MHPMEVENT_VSINH (_UL(1) << 59)
#define MHPMEVENT_VUINH (_UL(1) << 58)
#else
#define MHPMEVENTH_OF (_UL(1) << 31)
#define MHPMEVENTH_OF (_ULL(1) << 31)
#define MHPMEVENTH_MINH (_ULL(1) << 30)
#define MHPMEVENTH_SINH (_ULL(1) << 29)
#define MHPMEVENTH_UINH (_ULL(1) << 28)
#define MHPMEVENTH_VSINH (_ULL(1) << 27)
#define MHPMEVENTH_VUINH (_ULL(1) << 26)
#define MHPMEVENT_OF (MHPMEVENTH_OF << 32)
#define MHPMEVENT_MINH (MHPMEVENTH_MINH << 32)
#define MHPMEVENT_SINH (MHPMEVENTH_SINH << 32)
#define MHPMEVENT_UINH (MHPMEVENTH_UINH << 32)
@@ -198,6 +203,22 @@
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
#if __riscv_xlen > 32
#define ENVCFG_STCE (_ULL(1) << 63)
#define ENVCFG_PBMTE (_ULL(1) << 62)
#else
#define ENVCFGH_STCE (_UL(1) << 31)
#define ENVCFGH_PBMTE (_UL(1) << 30)
#endif
#define ENVCFG_CBZE (_UL(1) << 7)
#define ENVCFG_CBCFE (_UL(1) << 6)
#define ENVCFG_CBIE_SHIFT 4
#define ENVCFG_CBIE (_UL(0x3) << ENVCFG_CBIE_SHIFT)
#define ENVCFG_CBIE_ILL _UL(0x0)
#define ENVCFG_CBIE_FLUSH _UL(0x1)
#define ENVCFG_CBIE_INV _UL(0x3)
#define ENVCFG_FIOM _UL(0x1)
/* ===== User-level CSRs ===== */
/* User Trap Setup (N-extension) */
@@ -293,6 +314,9 @@
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
/* Supervisor Configuration */
#define CSR_SENVCFG 0x10a
/* Supervisor Trap Handling */
#define CSR_SSCRATCH 0x140
#define CSR_SEPC 0x141
@@ -300,9 +324,31 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
/* Sstc extension */
#define CSR_STIMECMP 0x14D
#define CSR_STIMECMPH 0x15D
/* Supervisor Protection and Translation */
#define CSR_SATP 0x180
/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
#define CSR_SISELECT 0x150
#define CSR_SIREG 0x151
/* Supervisor-Level Interrupts (AIA) */
#define CSR_STOPEI 0x15c
#define CSR_STOPI 0xdb0
/* Supervisor-Level High-Half CSRs (AIA) */
#define CSR_SIEH 0x114
#define CSR_SIPH 0x154
/* Supervisor stateen CSRs */
#define CSR_SSTATEEN0 0x10C
#define CSR_SSTATEEN1 0x10D
#define CSR_SSTATEEN2 0x10E
#define CSR_SSTATEEN3 0x10F
/* ===== Hypervisor-level CSRs ===== */
/* Hypervisor Trap Setup (H-extension) */
@@ -313,6 +359,10 @@
#define CSR_HCOUNTEREN 0x606
#define CSR_HGEIE 0x607
/* Hypervisor Configuration */
#define CSR_HENVCFG 0x60a
#define CSR_HENVCFGH 0x61a
/* Hypervisor Trap Handling (H-extension) */
#define CSR_HTVAL 0x643
#define CSR_HIP 0x644
@@ -338,6 +388,39 @@
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
#define CSR_HVIEN 0x608
#define CSR_HVICTL 0x609
#define CSR_HVIPRIO1 0x646
#define CSR_HVIPRIO2 0x647
/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
#define CSR_VSISELECT 0x250
#define CSR_VSIREG 0x251
/* VS-Level Interrupts (H-extension with AIA) */
#define CSR_VSTOPEI 0x25c
#define CSR_VSTOPI 0xeb0
/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
#define CSR_HIDELEGH 0x613
#define CSR_HVIENH 0x618
#define CSR_HVIPH 0x655
#define CSR_HVIPRIO1H 0x656
#define CSR_HVIPRIO2H 0x657
#define CSR_VSIEH 0x214
#define CSR_VSIPH 0x254
/* Hypervisor stateen CSRs */
#define CSR_HSTATEEN0 0x60C
#define CSR_HSTATEEN0H 0x61C
#define CSR_HSTATEEN1 0x60D
#define CSR_HSTATEEN1H 0x61D
#define CSR_HSTATEEN2 0x60E
#define CSR_HSTATEEN2H 0x61E
#define CSR_HSTATEEN3 0x60F
#define CSR_HSTATEEN3H 0x61F
/* ===== Machine-level CSRs ===== */
/* Machine Information Registers */
@@ -356,6 +439,10 @@
#define CSR_MCOUNTEREN 0x306
#define CSR_MSTATUSH 0x310
/* Machine Configuration */
#define CSR_MENVCFG 0x30a
#define CSR_MENVCFGH 0x31a
/* Machine Trap Handling */
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
@@ -589,6 +676,36 @@
#define CSR_DSCRATCH0 0x7b2
#define CSR_DSCRATCH1 0x7b3
/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
#define CSR_MISELECT 0x350
#define CSR_MIREG 0x351
/* Machine-Level Interrupts (AIA) */
#define CSR_MTOPEI 0x35c
#define CSR_MTOPI 0xfb0
/* Virtual Interrupts for Supervisor Level (AIA) */
#define CSR_MVIEN 0x308
#define CSR_MVIP 0x309
/* Smstateen extension registers */
/* Machine stateen CSRs */
#define CSR_MSTATEEN0 0x30C
#define CSR_MSTATEEN0H 0x31C
#define CSR_MSTATEEN1 0x30D
#define CSR_MSTATEEN1H 0x31D
#define CSR_MSTATEEN2 0x30E
#define CSR_MSTATEEN2H 0x31E
#define CSR_MSTATEEN3 0x30F
#define CSR_MSTATEEN3H 0x31F
/* Machine-Level High-Half CSRs (AIA) */
#define CSR_MIDELEGH 0x313
#define CSR_MIEH 0x314
#define CSR_MVIENH 0x318
#define CSR_MVIPH 0x319
#define CSR_MIPH 0x354
/* ===== Trap/Exception Causes ===== */
#define CAUSE_MISALIGNED_FETCH 0x0
@@ -611,6 +728,23 @@
#define CAUSE_VIRTUAL_INST_FAULT 0x16
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
/* Common defines for all smstateen */
#define SMSTATEEN_MAX_COUNT 4
#define SMSTATEEN0_CS_SHIFT 0
#define SMSTATEEN0_CS (_ULL(1) << SMSTATEEN0_CS_SHIFT)
#define SMSTATEEN0_FCSR_SHIFT 1
#define SMSTATEEN0_FCSR (_ULL(1) << SMSTATEEN0_FCSR_SHIFT)
#define SMSTATEEN0_IMSIC_SHIFT 58
#define SMSTATEEN0_IMSIC (_ULL(1) << SMSTATEEN0_IMSIC_SHIFT)
#define SMSTATEEN0_AIA_SHIFT 59
#define SMSTATEEN0_AIA (_ULL(1) << SMSTATEEN0_AIA_SHIFT)
#define SMSTATEEN0_SVSLCT_SHIFT 60
#define SMSTATEEN0_SVSLCT (_ULL(1) << SMSTATEEN0_SVSLCT_SHIFT)
#define SMSTATEEN0_HSENVCFG_SHIFT 62
#define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT)
#define SMSTATEEN_STATEN_SHIFT 63
#define SMSTATEEN_STATEN (_ULL(1) << SMSTATEEN_STATEN_SHIFT)
/* ===== Instruction Encodings ===== */
#define INSN_MATCH_LB 0x3
@@ -686,6 +820,29 @@
#define INSN_MASK_WFI 0xffffff00
#define INSN_MATCH_WFI 0x10500000
#define INSN_MASK_FENCE_TSO 0xffffffff
#define INSN_MATCH_FENCE_TSO 0x8330000f
#if __riscv_xlen == 64
/* 64-bit read for VS-stage address translation (RV64) */
#define INSN_PSEUDO_VS_LOAD 0x00003000
/* 64-bit write for VS-stage address translation (RV64) */
#define INSN_PSEUDO_VS_STORE 0x00003020
#elif __riscv_xlen == 32
/* 32-bit read for VS-stage address translation (RV32) */
#define INSN_PSEUDO_VS_LOAD 0x00002000
/* 32-bit write for VS-stage address translation (RV32) */
#define INSN_PSEUDO_VS_STORE 0x00002020
#else
#error "Unexpected __riscv_xlen"
#endif
#define INSN_16BIT_MASK 0x3
#define INSN_32BIT_MASK 0x1c

View File

@@ -37,47 +37,12 @@
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
/**
* ffs - Find first bit set
* @x: the word to search
*
* This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
*/
static inline int ffs(int x)
{
int r = 1;
if (!x)
return 0;
if (!(x & 0xffff)) {
x >>= 16;
r += 16;
}
if (!(x & 0xff)) {
x >>= 8;
r += 8;
}
if (!(x & 0xf)) {
x >>= 4;
r += 4;
}
if (!(x & 3)) {
x >>= 2;
r += 2;
}
if (!(x & 1))
r += 1;
return r;
}
/**
* __ffs - find first bit in word.
* sbi_ffs - find first (less-significant) set bit in a long word.
* @word: The word to search
*
* Undefined if no bit exists, so code should check against 0 first.
*/
static inline int __ffs(unsigned long word)
static inline int sbi_ffs(unsigned long word)
{
int num = 0;
@@ -109,55 +74,20 @@ static inline int __ffs(unsigned long word)
}
/*
* ffz - find first zero in word.
* sbi_ffz - find first zero in word.
* @word: The word to search
*
* Undefined if no zero exists, so code should check against ~0UL first.
*/
#define ffz(x) __ffs(~(x))
#define sbi_ffz(x) sbi_ffs(~(x))
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static inline int fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u))
r -= 1;
return r;
}
/**
* __fls - find last (most-significant) set bit in a long word
* sbi_fls - find last (most-significant) set bit in a long word
* @word: the word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
static inline unsigned long __fls(unsigned long word)
static inline unsigned long sbi_fls(unsigned long word)
{
int num = BITS_PER_LONG - 1;

View File

@@ -174,7 +174,9 @@ int sbi_domain_register(struct sbi_domain *dom,
* Add a memory region to the root domain
* @param reg pointer to the memory region to be added
*
* @return 0 on success and negative error code on failure
* @return 0 on success
* @return SBI_EALREADY if memory region conflicts with existing
* @return SBI_EINVAL otherwise
*/
int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg);

View File

@@ -13,8 +13,8 @@
#include <sbi/sbi_types.h>
#include <sbi/sbi_list.h>
#define SBI_ECALL_VERSION_MAJOR 0
#define SBI_ECALL_VERSION_MINOR 3
#define SBI_ECALL_VERSION_MAJOR 1
#define SBI_ECALL_VERSION_MINOR 0
#define SBI_OPENSBI_IMPID 1
struct sbi_trap_regs;

View File

@@ -12,21 +12,33 @@
#include <sbi/sbi_types.h>
/** Possible feature flags of a hart */
enum sbi_hart_features {
/** Hart has S-mode counter enable */
SBI_HART_HAS_SCOUNTEREN = (1 << 0),
/** Hart has M-mode counter enable */
SBI_HART_HAS_MCOUNTEREN = (1 << 1),
/** Hart has counter inhibit CSR */
SBI_HART_HAS_MCOUNTINHIBIT = (1 << 2),
/** Hart has sscofpmf extension */
SBI_HART_HAS_SSCOFPMF = (1 << 3),
/** HART has timer csr implementation in hardware */
SBI_HART_HAS_TIME = (1 << 4),
/** Possible privileged specification versions of a hart */
enum sbi_hart_priv_versions {
/** Unknown privileged specification */
SBI_HART_PRIV_VER_UNKNOWN = 0,
/** Privileged specification v1.10 */
SBI_HART_PRIV_VER_1_10 = 1,
/** Privileged specification v1.11 */
SBI_HART_PRIV_VER_1_11 = 2,
/** Privileged specification v1.12 */
SBI_HART_PRIV_VER_1_12 = 3,
};
/** Last index of Hart features*/
SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_TIME,
/** Possible ISA extensions of a hart */
enum sbi_hart_extensions {
/** Hart has Sscofpmt extension */
SBI_HART_EXT_SSCOFPMF = 0,
/** HART has HW time CSR (extension name not available) */
SBI_HART_EXT_TIME,
/** HART has AIA CSRs (extension name not available) */
SBI_HART_EXT_AIA,
/** HART has Smstateen CSR **/
SBI_HART_EXT_SMSTATEEN,
/** HART has Sstc extension */
SBI_HART_EXT_SSTC,
/** Maximum index of Hart extension */
SBI_HART_EXT_MAX,
};
struct sbi_scratch;
@@ -48,9 +60,16 @@ unsigned long sbi_hart_pmp_granularity(struct sbi_scratch *scratch);
unsigned int sbi_hart_pmp_addrbits(struct sbi_scratch *scratch);
unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch);
int sbi_hart_pmp_configure(struct sbi_scratch *scratch);
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature);
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr);
int sbi_hart_priv_version(struct sbi_scratch *scratch);
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr);
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable);
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext);
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extension_str, int nestr);
void __attribute__((noreturn)) sbi_hart_hang(void);

View File

@@ -34,9 +34,17 @@ struct sbi_hsm_device {
* the hart resumes normal execution.
*
* For successful non-retentive suspend, the hart will resume from
* specified resume address
* the warm boot entry point.
*/
int (*hart_suspend)(u32 suspend_type, ulong raddr);
int (*hart_suspend)(u32 suspend_type);
/**
* Perform platform-specific actions to resume from a suspended state.
*
* This includes restoring any platform state that was lost during
* non-retentive suspend.
*/
void (*hart_resume)(void);
};
struct sbi_domain;

44
include/sbi/sbi_irqchip.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#ifndef __SBI_IRQCHIP_H__
#define __SBI_IRQCHIP_H__
#include <sbi/sbi_types.h>
struct sbi_scratch;
struct sbi_trap_regs;
/**
* Set external interrupt handling function
*
* This function is called by OpenSBI platform code to set a handler for
* external interrupts
*
* @param fn function pointer for handling external irqs
*/
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs));
/**
* Process external interrupts
*
* This function is called by sbi_trap_handler() to handle external
* interrupts.
*
* @param regs pointer for trap registers
*/
int sbi_irqchip_process(struct sbi_trap_regs *regs);
/** Initialize interrupt controllers */
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
/** Exit interrupt controllers */
void sbi_irqchip_exit(struct sbi_scratch *scratch);
#endif

View File

@@ -64,6 +64,9 @@ enum sbi_platform_features {
/** Platform functions */
struct sbi_platform_operations {
/* Platform nascent initialization */
int (*nascent_init)(void);
/** Platform early initialization */
int (*early_init)(bool cold_boot);
/** Platform final initialization */
@@ -86,6 +89,9 @@ struct sbi_platform_operations {
*/
int (*misa_get_xlen)(void);
/** Initialize (or populate) HART extensions for the platform */
int (*extensions_init)(void);
/** Initialize (or populate) domains for the platform */
int (*domains_init)(void);
@@ -172,6 +178,56 @@ struct sbi_platform {
const u32 *hart_index2id;
};
/**
* Prevent modification of struct sbi_platform from affecting
* SBI_PLATFORM_xxx_OFFSET
*/
_Static_assert(
offsetof(struct sbi_platform, opensbi_version)
== SBI_PLATFORM_OPENSBI_VERSION_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_OPENSBI_VERSION_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, platform_version)
== SBI_PLATFORM_VERSION_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_VERSION_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, name)
== SBI_PLATFORM_NAME_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_NAME_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, features)
== SBI_PLATFORM_FEATURES_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_FEATURES_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_count)
== SBI_PLATFORM_HART_COUNT_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_COUNT_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_stack_size)
== SBI_PLATFORM_HART_STACK_SIZE_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_STACK_SIZE_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, platform_ops_addr)
== SBI_PLATFORM_OPS_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_OPS_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, firmware_context)
== SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET");
_Static_assert(
offsetof(struct sbi_platform, hart_index2id)
== SBI_PLATFORM_HART_INDEX2ID_OFFSET,
"struct sbi_platform definition has changed, please redefine "
"SBI_PLATFORM_HART_INDEX2ID_OFFSET");
/** Get pointer to sbi_platform for sbi_scratch pointer */
#define sbi_platform_ptr(__s) \
((const struct sbi_platform *)((__s)->platform_addr))
@@ -299,6 +355,23 @@ static inline bool sbi_platform_hart_invalid(const struct sbi_platform *plat,
return FALSE;
}
/**
* Nascent (very early) initialization for current HART
*
* NOTE: This function can be used to do very early initialization of
* platform specific per-HART CSRs and devices.
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_nascent_init(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->nascent_init)
return sbi_platform_ops(plat)->nascent_init();
return 0;
}
/**
* Early initialization for current HART
*
@@ -383,6 +456,21 @@ static inline int sbi_platform_misa_xlen(const struct sbi_platform *plat)
return -1;
}
/**
* Initialize (or populate) HART extensions for the platform
*
* @param plat pointer to struct sbi_platform
*
* @return 0 on success and negative error code on failure
*/
static inline int sbi_platform_extensions_init(
const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->extensions_init)
return sbi_platform_ops(plat)->extensions_init();
return 0;
}
/**
* Initialize (or populate) domains for the platform
*

View File

@@ -17,7 +17,7 @@
/* Event related macros */
/* Maximum number of hardware events that can mapped by OpenSBI */
#define SBI_PMU_HW_EVENT_MAX 64
#define SBI_PMU_HW_EVENT_MAX 256
/* Maximum number of firmware events that can mapped by OpenSBI */
#define SBI_PMU_FW_EVENT_MAX 32

View File

@@ -73,6 +73,66 @@ struct sbi_scratch {
unsigned long options;
};
/**
* Prevent modification of struct sbi_scratch from affecting
* SBI_SCRATCH_xxx_OFFSET
*/
_Static_assert(
offsetof(struct sbi_scratch, fw_start)
== SBI_SCRATCH_FW_START_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_FW_START_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, fw_size)
== SBI_SCRATCH_FW_SIZE_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_FW_SIZE_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_arg1)
== SBI_SCRATCH_NEXT_ARG1_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_ARG1_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_addr)
== SBI_SCRATCH_NEXT_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, next_mode)
== SBI_SCRATCH_NEXT_MODE_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_NEXT_MODE_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, warmboot_addr)
== SBI_SCRATCH_WARMBOOT_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_WARMBOOT_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, platform_addr)
== SBI_SCRATCH_PLATFORM_ADDR_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_PLATFORM_ADDR_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, hartid_to_scratch)
== SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, trap_exit)
== SBI_SCRATCH_TRAP_EXIT_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TRAP_EXIT_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, tmp0)
== SBI_SCRATCH_TMP0_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_TMP0_OFFSET");
_Static_assert(
offsetof(struct sbi_scratch, options)
== SBI_SCRATCH_OPTIONS_OFFSET,
"struct sbi_scratch definition has changed, please redefine "
"SBI_SCRATCH_OPTIONS_OFFSET");
/** Possible options for OpenSBI library */
enum sbi_scratch_options {
/** Disable prints during boot */
@@ -104,11 +164,11 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size);
void sbi_scratch_free_offset(unsigned long offset);
/** Get pointer from offset in sbi_scratch */
#define sbi_scratch_offset_ptr(scratch, offset) ((void *)scratch + (offset))
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
/** Get pointer from offset in sbi_scratch for current HART */
#define sbi_scratch_thishart_offset_ptr(offset) \
((void *)sbi_scratch_thishart_ptr() + (offset))
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];

View File

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

View File

@@ -21,6 +21,30 @@
*/
void fdt_cpu_fixup(void *fdt);
/**
* Fix up the APLIC nodes in the device tree
*
* This routine disables APLIC nodes which are not accessible to the next
* booting stage based on currently assigned domain.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_aplic_fixup(void *fdt);
/**
* Fix up the IMSIC nodes in the device tree
*
* This routine disables IMSIC nodes which are not accessible to the next
* booting stage based on currently assigned domain.
*
* It is recommended that platform codes call this helper in their final_init()
*
* @param fdt: device tree blob
*/
void fdt_imsic_fixup(void *fdt);
/**
* Fix up the PLIC node in the device tree
*
@@ -64,8 +88,9 @@ int fdt_reserved_memory_nomap_fixup(void *fdt);
* General device tree fix-up
*
* This routine do all required device tree fix-ups for a typical platform.
* It fixes up the PLIC node and the reserved memory node in the device tree
* by calling the corresponding helper routines to accomplish the task.
* It fixes up the PLIC node, IMSIC nodes, APLIC nodes, and the reserved
* memory node in the device tree by calling the corresponding helper
* routines to accomplish the task.
*
* It is recommended that platform codes call this helper in their final_init()
*

View File

@@ -15,7 +15,7 @@
struct fdt_match {
const char *compatible;
void *data;
const void *data;
};
#define FDT_MAX_PHANDLE_ARGS 16
@@ -31,6 +31,7 @@ struct platform_uart_data {
unsigned long baud;
unsigned long reg_shift;
unsigned long reg_io_width;
unsigned long reg_offset;
};
const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
@@ -47,9 +48,11 @@ int fdt_parse_phandle_with_args(void *fdt, int nodeoff,
int fdt_get_node_addr_size(void *fdt, int node, int index,
uint64_t *addr, uint64_t *size);
bool fdt_node_is_enabled(void *fdt, int nodeoff);
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid);
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid);
int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq);
@@ -68,6 +71,19 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart);
struct aplic_data;
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic);
struct imsic_data;
bool fdt_check_imsic_mlevel(void *fdt);
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic);
struct plic_data;
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);

View File

@@ -12,6 +12,8 @@
#include <sbi_utils/gpio/gpio.h>
struct fdt_phandle_args;
/** FDT based GPIO driver */
struct fdt_gpio {
const struct fdt_match *match_table;

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IRQCHIP_APLIC_H__
#define __IRQCHIP_APLIC_H__
#include <sbi/sbi_types.h>
#define APLIC_MAX_DELEGATE 16
struct aplic_msicfg_data {
unsigned long lhxs;
unsigned long lhxw;
unsigned long hhxs;
unsigned long hhxw;
unsigned long base_addr;
};
struct aplic_delegate_data {
u32 first_irq;
u32 last_irq;
u32 child_index;
};
struct aplic_data {
unsigned long addr;
unsigned long size;
unsigned long num_idc;
unsigned long num_source;
bool targets_mmode;
bool has_msicfg_mmode;
struct aplic_msicfg_data msicfg_mmode;
bool has_msicfg_smode;
struct aplic_msicfg_data msicfg_smode;
struct aplic_delegate_data delegate[APLIC_MAX_DELEGATE];
};
int aplic_cold_irqchip_init(struct aplic_data *aplic);
#endif

View File

@@ -0,0 +1,22 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Samuel Holland <samuel@sholland.org>
*/
#ifndef __IRQCHIP_FDT_IRQCHIP_PLIC_H__
#define __IRQCHIP_FDT_IRQCHIP_PLIC_H__
#include <sbi/sbi_types.h>
void fdt_plic_priority_save(u8 *priority);
void fdt_plic_priority_restore(const u8 *priority);
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold);
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold);
void thead_plic_restore(void);
#endif

View File

@@ -0,0 +1,50 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __IRQCHIP_IMSIC_H__
#define __IRQCHIP_IMSIC_H__
#include <sbi/sbi_types.h>
#define IMSIC_MMIO_PAGE_SHIFT 12
#define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT)
#define IMSIC_MAX_REGS 16
struct imsic_regs {
unsigned long addr;
unsigned long size;
};
struct imsic_data {
bool targets_mmode;
u32 guest_index_bits;
u32 hart_index_bits;
u32 group_index_bits;
u32 group_index_shift;
unsigned long num_ids;
struct imsic_regs regs[IMSIC_MAX_REGS];
};
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file);
struct imsic_data *imsic_get_data(u32 hartid);
int imsic_get_target_file(u32 hartid);
void imsic_local_irqchip_init(void);
int imsic_warm_irqchip_init(void);
int imsic_data_check(struct imsic_data *imsic);
int imsic_cold_irqchip_init(struct imsic_data *imsic);
#endif

View File

@@ -17,13 +17,23 @@ struct plic_data {
unsigned long num_src;
};
int plic_warm_irqchip_init(struct plic_data *plic,
/* So far, priorities on all consumers of these functions fit in 8 bits. */
void plic_priority_save(const struct plic_data *plic, u8 *priority);
void plic_priority_restore(const struct plic_data *plic, const u8 *priority);
void plic_context_save(const struct plic_data *plic, int context_id,
u32 *enable, u32 *threshold);
void plic_context_restore(const struct plic_data *plic, int context_id,
const u32 *enable, u32 threshold);
int plic_context_init(const struct plic_data *plic, int context_id,
bool enable, u32 threshold);
int plic_warm_irqchip_init(const struct plic_data *plic,
int m_cntx_id, int s_cntx_id);
int plic_cold_irqchip_init(struct plic_data *plic);
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val);
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val);
int plic_cold_irqchip_init(const struct plic_data *plic);
#endif

View File

@@ -13,6 +13,6 @@
#include <sbi/sbi_types.h>
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width);
u32 reg_width, u32 reg_offset);
#endif

View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Western Digital Corporation or its affiliates.
*
* Authors:
* Alistair Francis <alistair.francis@wdc.com>
*/
#ifndef __SERIAL_XLNX_UARTLITE_H__
#define __SERIAL_XLNX_UARTLITE_H__
#include <sbi/sbi_types.h>
int xlnx_uartlite_init(unsigned long base);
#endif

View File

@@ -10,8 +10,12 @@
#include <sbi/sbi_types.h>
int htif_serial_init(void);
int htif_serial_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr);
int htif_system_reset_init(void);
int htif_system_reset_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr);
#endif

View File

@@ -32,6 +32,7 @@ libsbi-objs-y += sbi_hsm.o
libsbi-objs-y += sbi_illegal_insn.o
libsbi-objs-y += sbi_init.o
libsbi-objs-y += sbi_ipi.o
libsbi-objs-y += sbi_irqchip.o
libsbi-objs-y += sbi_misaligned_ldst.o
libsbi-objs-y += sbi_platform.o
libsbi-objs-y += sbi_pmu.o

View File

@@ -53,7 +53,7 @@ int misa_xlen(void)
void misa_string(int xlen, char *out, unsigned int out_sz)
{
unsigned int i, pos = 0;
const char valid_isa_order[] = "iemafdqclbjtpvnsuhkorwxyzg";
const char valid_isa_order[] = "iemafdqclbjtpvnhkorwxyzg";
if (!out)
return;
@@ -139,6 +139,10 @@ unsigned long csr_read_num(int csr_num)
switchcase_csr_read_4(CSR_MHPMCOUNTER4H, ret)
switchcase_csr_read_8(CSR_MHPMCOUNTER8H, ret)
switchcase_csr_read_16(CSR_MHPMCOUNTER16H, ret)
/**
* The CSR range MHPMEVENT[3-16]H are available only if sscofpmf
* extension is present. The caller must ensure that.
*/
switchcase_csr_read(CSR_MHPMEVENT3H, ret)
switchcase_csr_read_4(CSR_MHPMEVENT4H, ret)
switchcase_csr_read_8(CSR_MHPMEVENT8H, ret)
@@ -261,7 +265,7 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
return SBI_ENOTSUPP;
# error "Unexpected __riscv_xlen"
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
@@ -312,7 +316,7 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
return SBI_ENOTSUPP;
# error "Unexpected __riscv_xlen"
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;

View File

@@ -39,7 +39,7 @@ unsigned long find_first_bit(const unsigned long *addr,
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found:
return result + __ffs(tmp);
return result + sbi_ffs(tmp);
}
/**
@@ -69,7 +69,7 @@ unsigned long find_first_zero_bit(const unsigned long *addr,
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found:
return result + ffz(tmp);
return result + sbi_ffz(tmp);
}
/**
@@ -100,7 +100,7 @@ unsigned long find_last_bit(const unsigned long *addr,
tmp = addr[--words];
if (tmp) {
found:
return words * BITS_PER_LONG + __fls(tmp);
return words * BITS_PER_LONG + sbi_fls(tmp);
}
}
@@ -150,7 +150,7 @@ found_first:
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __ffs(tmp);
return result + sbi_ffs(tmp);
}
/**
@@ -196,5 +196,5 @@ found_first:
if (tmp == ~0UL) /* Are any bits zero? */
return result + size; /* Nope. */
found_middle:
return result + ffz(tmp);
return result + sbi_ffz(tmp);
}

View File

@@ -159,7 +159,7 @@ static bool is_region_subset(const struct sbi_domain_memregion *regA,
ulong regA_start = regA->base;
ulong regA_end = regA->base + (BIT(regA->order) - 1);
ulong regB_start = regB->base;
ulong regB_end = regB->base + (BIT(regA->order) - 1);
ulong regB_end = regB->base + (BIT(regB->order) - 1);
if ((regB_start <= regA_start) &&
(regA_start < regB_end) &&
@@ -471,8 +471,12 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
/* Check for conflicts */
sbi_domain_for_each_memregion(&root, nreg) {
if (is_region_conflict(reg, nreg))
return SBI_EINVAL;
if (is_region_conflict(reg, nreg)) {
sbi_printf("%s: is_region_conflict check failed"
" 0x%lx conflicts existing 0x%lx\n", __func__,
reg->base, nreg->base);
return SBI_EALREADY;
}
}
/* Append the memregion to root memregions */

View File

@@ -24,7 +24,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (prev_mode <= PRV_S) {
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN)) {
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10) {
cen &= csr_read(CSR_MCOUNTEREN);
if (virt)
cen &= csr_read(CSR_HCOUNTEREN);
@@ -33,7 +33,7 @@ static bool hpm_allowed(int hpm_num, ulong prev_mode, bool virt)
}
}
if (prev_mode == PRV_U) {
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
cen &= csr_read(CSR_SCOUNTEREN);
else
cen = 0;

View File

@@ -66,7 +66,7 @@ static inline void __sbi_fifo_enqueue(struct sbi_fifo *fifo, void *data)
if (head >= fifo->num_entries)
head = head - fifo->num_entries;
sbi_memcpy(fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
sbi_memcpy((char *)fifo->queue + head * fifo->entry_size, data, fifo->entry_size);
fifo->avail++;
}
@@ -142,7 +142,7 @@ int sbi_fifo_inplace_update(struct sbi_fifo *fifo, void *in,
index = fifo->tail + i;
if (index >= fifo->num_entries)
index -= fifo->num_entries;
entry = (void *)fifo->queue + (u32)index * fifo->entry_size;
entry = (char *)fifo->queue + (u32)index * fifo->entry_size;
ret = fptr(in, entry);
if (ret == SBI_FIFO_SKIP || ret == SBI_FIFO_UPDATED) {
@@ -184,7 +184,7 @@ int sbi_fifo_dequeue(struct sbi_fifo *fifo, void *data)
return SBI_ENOENT;
}
sbi_memcpy(data, fifo->queue + (u32)fifo->tail * fifo->entry_size,
sbi_memcpy(data, (char *)fifo->queue + (u32)fifo->tail * fifo->entry_size,
fifo->entry_size);
fifo->avail--;

View File

@@ -28,7 +28,9 @@ extern void __sbi_expected_trap_hext(void);
void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
struct hart_features {
unsigned long features;
bool detected;
int priv_version;
unsigned long extensions;
unsigned int pmp_count;
unsigned int pmp_addr_bits;
unsigned long pmp_gran;
@@ -39,7 +41,11 @@ static unsigned long hart_features_offset;
static void mstatus_init(struct sbi_scratch *scratch)
{
unsigned long mstatus_val = 0;
unsigned long menvcfg_val, mstatus_val = 0;
int cidx;
unsigned int num_mhpm = sbi_hart_mhpm_count(scratch);
uint64_t mhpmevent_init_val = 0;
uint64_t mstateen_val;
/* Enable FPU */
if (misa_extension('D') || misa_extension('F'))
@@ -53,7 +59,7 @@ static void mstatus_init(struct sbi_scratch *scratch)
/* Disable user mode usage of all perf counters except default ones (CY, TM, IR) */
if (misa_extension('S') &&
sbi_hart_has_feature(scratch, SBI_HART_HAS_SCOUNTEREN))
sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_SCOUNTEREN, 7);
/**
@@ -61,13 +67,107 @@ static void mstatus_init(struct sbi_scratch *scratch)
* Supervisor mode usage for all counters are enabled by default
* But counters will not run until mcountinhibit is set.
*/
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTEREN))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
/* All programmable counters will start running at runtime after S-mode request */
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
/**
* The mhpmeventn[h] CSR should be initialized with interrupt disabled
* and inhibited running in M-mode during init.
* To keep it simple, only contiguous mhpmcounters are supported as a
* platform with discontiguous mhpmcounters may not make much sense.
*/
mhpmevent_init_val |= (MHPMEVENT_OF | MHPMEVENT_MINH);
for (cidx = 0; cidx < num_mhpm; cidx++) {
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val & 0xFFFFFFFF);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + cidx,
mhpmevent_init_val >> BITS_PER_LONG);
#else
csr_write_num(CSR_MHPMEVENT3 + cidx, mhpmevent_init_val);
#endif
}
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMSTATEEN)) {
mstateen_val = csr_read(CSR_MSTATEEN0);
#if __riscv_xlen == 32
mstateen_val |= ((uint64_t)csr_read(CSR_MSTATEEN0H)) << 32;
#endif
mstateen_val |= SMSTATEEN_STATEN;
mstateen_val |= SMSTATEEN0_HSENVCFG;
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_AIA))
mstateen_val |= (SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
else
mstateen_val &= ~(SMSTATEEN0_AIA | SMSTATEEN0_SVSLCT |
SMSTATEEN0_IMSIC);
csr_write(CSR_MSTATEEN0, mstateen_val);
#if __riscv_xlen == 32
csr_write(CSR_MSTATEEN0H, mstateen_val >> 32);
#endif
}
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_12) {
menvcfg_val = csr_read(CSR_MENVCFG);
/*
* Set menvcfg.CBZE == 1
*
* If Zicboz extension is not available then writes to
* menvcfg.CBZE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBZE;
/*
* Set menvcfg.CBCFE == 1
*
* If Zicbom extension is not available then writes to
* menvcfg.CBCFE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBCFE;
/*
* Set menvcfg.CBIE == 3
*
* If Zicbom extension is not available then writes to
* menvcfg.CBIE will be ignored because it is a WARL field.
*/
menvcfg_val |= ENVCFG_CBIE_INV << ENVCFG_CBIE_SHIFT;
/*
* Set menvcfg.PBMTE == 1 for RV64 or RV128
*
* If Svpbmt extension is not available then menvcfg.PBMTE
* will be read-only zero.
*/
#if __riscv_xlen > 32
menvcfg_val |= ENVCFG_PBMTE;
#endif
/*
* The spec doesn't explicitly describe the reset value of menvcfg.
* Enable access to stimecmp if sstc extension is present in the
* hardware.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSTC)) {
#if __riscv_xlen == 32
unsigned long menvcfgh_val;
menvcfgh_val = csr_read(CSR_MENVCFGH);
menvcfgh_val |= ENVCFGH_STCE;
csr_write(CSR_MENVCFGH, menvcfgh_val);
#else
menvcfg_val |= ENVCFG_STCE;
#endif
}
csr_write(CSR_MENVCFG, menvcfg_val);
}
/* Disable all interrupts */
csr_write(CSR_MIE, 0);
@@ -108,7 +208,7 @@ static int delegate_traps(struct sbi_scratch *scratch)
/* Send M-mode interrupts and most exceptions to S-mode */
interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
interrupts |= MIP_LCOFIP;
exceptions = (1U << CAUSE_MISALIGNED_FETCH) | (1U << CAUSE_BREAKPOINT) |
@@ -234,103 +334,156 @@ int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
return 0;
}
/**
* Check whether a particular hart feature is available
*
* @param scratch pointer to the HART scratch space
* @param feature the feature to check
* @returns true (feature available) or false (feature not available)
*/
bool sbi_hart_has_feature(struct sbi_scratch *scratch, unsigned long feature)
int sbi_hart_priv_version(struct sbi_scratch *scratch)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->features & feature)
return hfeatures->priv_version;
}
void sbi_hart_get_priv_version_str(struct sbi_scratch *scratch,
char *version_str, int nvstr)
{
char *temp;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
switch (hfeatures->priv_version) {
case SBI_HART_PRIV_VER_1_10:
temp = "v1.10";
break;
case SBI_HART_PRIV_VER_1_11:
temp = "v1.11";
break;
case SBI_HART_PRIV_VER_1_12:
temp = "v1.12";
break;
default:
temp = "unknown";
break;
}
sbi_snprintf(version_str, nvstr, "%s", temp);
}
static inline void __sbi_hart_update_extension(
struct hart_features *hfeatures,
enum sbi_hart_extensions ext,
bool enable)
{
if (enable)
hfeatures->extensions |= BIT(ext);
else
hfeatures->extensions &= ~BIT(ext);
}
/**
* Enable/Disable a particular hart extension
*
* @param scratch pointer to the HART scratch space
* @param ext the extension number to check
* @param enable new state of hart extension
*/
void sbi_hart_update_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext,
bool enable)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
__sbi_hart_update_extension(hfeatures, ext, enable);
}
/**
* Check whether a particular hart extension is available
*
* @param scratch pointer to the HART scratch space
* @param ext the extension number to check
* @returns true (available) or false (not available)
*/
bool sbi_hart_has_extension(struct sbi_scratch *scratch,
enum sbi_hart_extensions ext)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
if (hfeatures->extensions & BIT(ext))
return true;
else
return false;
}
static unsigned long hart_get_features(struct sbi_scratch *scratch)
static inline char *sbi_hart_extension_id2string(int ext)
{
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
char *estr = NULL;
return hfeatures->features;
}
static inline char *sbi_hart_feature_id2string(unsigned long feature)
{
char *fstr = NULL;
if (!feature)
return NULL;
switch (feature) {
case SBI_HART_HAS_SCOUNTEREN:
fstr = "scounteren";
switch (ext) {
case SBI_HART_EXT_SSCOFPMF:
estr = "sscofpmf";
break;
case SBI_HART_HAS_MCOUNTEREN:
fstr = "mcounteren";
case SBI_HART_EXT_TIME:
estr = "time";
break;
case SBI_HART_HAS_MCOUNTINHIBIT:
fstr = "mcountinhibit";
case SBI_HART_EXT_AIA:
estr = "aia";
break;
case SBI_HART_HAS_SSCOFPMF:
fstr = "sscofpmf";
case SBI_HART_EXT_SSTC:
estr = "sstc";
break;
case SBI_HART_HAS_TIME:
fstr = "time";
case SBI_HART_EXT_SMSTATEEN:
estr = "smstateen";
break;
default:
break;
}
return fstr;
return estr;
}
/**
* Get the hart features in string format
* Get the hart extensions in string format
*
* @param scratch pointer to the HART scratch space
* @param features_str pointer to a char array where the features string will be
* updated
* @param nfstr length of the features_str. The feature string will be truncated
* if nfstr is not long enough.
* @param extensions_str pointer to a char array where the extensions string
* will be updated
* @param nestr length of the features_str. The feature string will be
* truncated if nestr is not long enough.
*/
void sbi_hart_get_features_str(struct sbi_scratch *scratch,
char *features_str, int nfstr)
void sbi_hart_get_extensions_str(struct sbi_scratch *scratch,
char *extensions_str, int nestr)
{
unsigned long features, feat = 1UL;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
int offset = 0, ext = 0;
char *temp;
int offset = 0;
if (!features_str || nfstr <= 0)
if (!extensions_str || nestr <= 0)
return;
sbi_memset(features_str, 0, nfstr);
sbi_memset(extensions_str, 0, nestr);
features = hart_get_features(scratch);
if (!features)
if (!hfeatures->extensions)
goto done;
do {
if (features & feat) {
temp = sbi_hart_feature_id2string(feat);
if (hfeatures->extensions & BIT(ext)) {
temp = sbi_hart_extension_id2string(ext);
if (temp) {
sbi_snprintf(features_str + offset, nfstr,
sbi_snprintf(extensions_str + offset,
nestr - offset,
"%s,", temp);
offset = offset + sbi_strlen(temp) + 1;
}
}
feat = feat << 1;
} while (feat <= SBI_HART_HAS_LAST_FEATURE);
ext++;
} while (ext < SBI_HART_EXT_MAX);
done:
if (offset)
features_str[offset - 1] = '\0';
extensions_str[offset - 1] = '\0';
else
sbi_strncpy(features_str, "none", nfstr);
sbi_strncpy(extensions_str, "none", nestr);
}
static unsigned long hart_pmp_get_allowed_addr(void)
@@ -368,7 +521,7 @@ static int hart_pmu_get_allowed_bits(void)
if (trap.cause)
return 0;
}
num_bits = __fls(val) + 1;
num_bits = sbi_fls(val) + 1;
#if __riscv_xlen == 32
csr_write_allowed(CSR_MHPMCOUNTER3H, (ulong)&trap, val);
if (!trap.cause) {
@@ -376,34 +529,39 @@ static int hart_pmu_get_allowed_bits(void)
if (trap.cause)
return num_bits;
}
num_bits += __fls(val) + 1;
num_bits += sbi_fls(val) + 1;
#endif
return num_bits;
}
static void hart_detect_features(struct sbi_scratch *scratch)
static int hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
struct hart_features *hfeatures;
unsigned long val;
struct hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
int rc;
/* Reset hart features */
hfeatures = sbi_scratch_offset_ptr(scratch, hart_features_offset);
hfeatures->features = 0;
/* If hart features already detected then do nothing */
if (hfeatures->detected)
return 0;
/* Clear hart features */
hfeatures->extensions = 0;
hfeatures->pmp_count = 0;
hfeatures->mhpm_count = 0;
#define __check_csr(__csr, __rdonly, __wrval, __field, __skip) \
val = csr_read_allowed(__csr, (ulong)&trap); \
oldval = csr_read_allowed(__csr, (ulong)&trap); \
if (!trap.cause) { \
if (__rdonly) { \
(hfeatures->__field)++; \
} else { \
csr_write_allowed(__csr, (ulong)&trap, __wrval);\
if (!trap.cause) { \
if (csr_swap(__csr, val) == __wrval) \
if (csr_swap(__csr, oldval) == __wrval) \
(hfeatures->__field)++; \
else \
goto __skip; \
@@ -439,8 +597,8 @@ static void hart_detect_features(struct sbi_scratch *scratch)
*/
val = hart_pmp_get_allowed_addr();
if (val) {
hfeatures->pmp_gran = 1 << (__ffs(val) + 2);
hfeatures->pmp_addr_bits = __fls(val) + 1;
hfeatures->pmp_gran = 1 << (sbi_ffs(val) + 2);
hfeatures->pmp_addr_bits = sbi_fls(val) + 1;
/* Detect number of PMP regions. At least PMPADDR0 should be implemented*/
__check_csr_64(CSR_PMPADDR0, 0, val, pmp_count, __pmp_skip);
}
@@ -469,43 +627,69 @@ __mhpm_skip:
#undef __check_csr_2
#undef __check_csr
/* Detect if hart supports SCOUNTEREN feature */
val = csr_read_allowed(CSR_SCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_SCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_SCOUNTEREN;
}
/* Detect if hart supports MCOUNTEREN feature */
/* Detect if hart supports Priv v1.10 */
val = csr_read_allowed(CSR_MCOUNTEREN, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_MCOUNTEREN, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MCOUNTEREN;
}
if (!trap.cause)
hfeatures->priv_version = SBI_HART_PRIV_VER_1_10;
/* Detect if hart supports MCOUNTINHIBIT feature */
/* Detect if hart supports Priv v1.11 */
val = csr_read_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap);
if (!trap.cause) {
csr_write_allowed(CSR_MCOUNTINHIBIT, (unsigned long)&trap, val);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MCOUNTINHIBIT;
}
if (!trap.cause &&
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_10))
hfeatures->priv_version = SBI_HART_PRIV_VER_1_11;
/* Detect if hart supports Priv v1.12 */
csr_read_allowed(CSR_MENVCFG, (unsigned long)&trap);
if (!trap.cause &&
(hfeatures->priv_version >= SBI_HART_PRIV_VER_1_11))
hfeatures->priv_version = SBI_HART_PRIV_VER_1_12;
/* Counter overflow/filtering is not useful without mcounter/inhibit */
if (hfeatures->features & SBI_HART_HAS_MCOUNTINHIBIT &&
hfeatures->features & SBI_HART_HAS_MCOUNTEREN) {
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
/* Detect if hart supports sscofpmf */
csr_read_allowed(CSR_SCOUNTOVF, (unsigned long)&trap);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_SSCOFPMF;
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSCOFPMF, true);
}
/* Detect if hart supports time CSR */
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_TIME;
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_TIME, true);
/* Detect if hart has AIA local interrupt CSRs */
csr_read_allowed(CSR_MTOPI, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_AIA, true);
/* Detect if hart supports stimecmp CSR(Sstc extension) */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
csr_read_allowed(CSR_STIMECMP, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SSTC, true);
}
/* Detect if hart supports mstateen CSRs */
if (hfeatures->priv_version >= SBI_HART_PRIV_VER_1_12) {
val = csr_read_allowed(CSR_MSTATEEN0, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_SMSTATEEN, true);
}
/* Let platform populate extensions */
rc = sbi_platform_extensions_init(sbi_platform_thishart_ptr());
if (rc)
return rc;
/* Mark hart feature detection done */
hfeatures->detected = true;
return 0;
}
int sbi_hart_reinit(struct sbi_scratch *scratch)
@@ -527,6 +711,8 @@ int sbi_hart_reinit(struct sbi_scratch *scratch)
int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
if (cold_boot) {
if (misa_extension('H'))
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
@@ -537,7 +723,9 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
return SBI_ENOMEM;
}
hart_detect_features(scratch);
rc = hart_detect_features(scratch);
if (rc)
return rc;
return sbi_hart_reinit(scratch);
}

View File

@@ -113,8 +113,8 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Set MSIE and MEIE bits to receive IPI */
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Wait for hart_add call*/
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
@@ -171,13 +171,19 @@ static int hsm_device_hart_stop(void)
return SBI_ENOTSUPP;
}
static int hsm_device_hart_suspend(u32 suspend_type, ulong raddr)
static int hsm_device_hart_suspend(u32 suspend_type)
{
if (hsm_dev && hsm_dev->hart_suspend)
return hsm_dev->hart_suspend(suspend_type, raddr);
return hsm_dev->hart_suspend(suspend_type);
return SBI_ENOTSUPP;
}
static void hsm_device_hart_resume(void)
{
if (hsm_dev && hsm_dev->hart_resume)
hsm_dev->hart_resume();
}
int sbi_hsm_init(struct sbi_scratch *scratch, u32 hartid, bool cold_boot)
{
u32 i;
@@ -313,7 +319,7 @@ int sbi_hsm_hart_stop(struct sbi_scratch *scratch, bool exitnow)
return 0;
}
static int __sbi_hsm_suspend_ret_default(struct sbi_scratch *scratch)
static int __sbi_hsm_suspend_default(struct sbi_scratch *scratch)
{
/* Wait for interrupt */
wfi();
@@ -353,23 +359,6 @@ static void __sbi_hsm_suspend_non_ret_restore(struct sbi_scratch *scratch)
csr_write(CSR_MIP, (hdata->saved_mip & (MIP_SSIP | MIP_STIP)));
}
static int __sbi_hsm_suspend_non_ret_default(struct sbi_scratch *scratch,
ulong raddr)
{
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
/* Wait for interrupt */
wfi();
/*
* Directly jump to warm reboot to simulate resume from a
* non-retentive suspend.
*/
jump_warmboot();
return 0;
}
void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
{
int oldstate;
@@ -384,6 +373,8 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
__func__, oldstate);
sbi_hart_hang();
}
hsm_device_hart_resume();
}
void sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch)
@@ -465,17 +456,28 @@ int sbi_hsm_hart_suspend(struct sbi_scratch *scratch, u32 suspend_type,
__sbi_hsm_suspend_non_ret_save(scratch);
/* Try platform specific suspend */
ret = hsm_device_hart_suspend(suspend_type, scratch->warmboot_addr);
ret = hsm_device_hart_suspend(suspend_type);
if (ret == SBI_ENOTSUPP) {
/* Try generic implementation of default suspend types */
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT) {
ret = __sbi_hsm_suspend_ret_default(scratch);
} else if (suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
ret = __sbi_hsm_suspend_non_ret_default(scratch,
scratch->warmboot_addr);
if (suspend_type == SBI_HSM_SUSPEND_RET_DEFAULT ||
suspend_type == SBI_HSM_SUSPEND_NON_RET_DEFAULT) {
ret = __sbi_hsm_suspend_default(scratch);
}
}
/*
* The platform may have coordinated a retentive suspend, or it may
* have exited early from a non-retentive suspend. Either way, the
* caller is not expecting a successful return, so jump to the warm
* boot entry point to simulate resume from a non-retentive suspend.
*/
if (ret == 0 && (suspend_type & SBI_HSM_SUSP_NON_RET_BIT)) {
void (*jump_warmboot)(void) =
(void (*)(void))scratch->warmboot_addr;
jump_warmboot();
}
fail_restore_state:
/*
* We might have successfully resumed from retentive suspend

View File

@@ -8,6 +8,7 @@
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_emulate_csr.h>
@@ -16,6 +17,7 @@
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_unpriv.h>
#include <sbi/sbi_console.h>
typedef int (*illegal_insn_func)(ulong insn, struct sbi_trap_regs *regs);
@@ -32,13 +34,31 @@ static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs)
return sbi_trap_redirect(regs, &trap);
}
static int misc_mem_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
/* Errata workaround: emulate `fence.tso` as `fence rw, rw`. */
if ((insn & INSN_MASK_FENCE_TSO) == INSN_MATCH_FENCE_TSO) {
smp_mb();
return 0;
}
return truly_illegal_insn(insn, regs);
}
static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
{
int do_write, rs1_num = (insn >> 15) & 0x1f;
ulong rs1_val = GET_RS1(insn, regs);
int csr_num = (u32)insn >> 20;
ulong prev_mode = (regs->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
ulong csr_val, new_csr_val;
if (prev_mode == PRV_M) {
sbi_printf("%s: Failed to access CSR %#x from M-mode",
__func__, csr_num);
return SBI_EFAIL;
}
/* TODO: Ensure that we got CSR read/write instruction */
if (sbi_emulate_csr_read(csr_num, regs, &csr_val))
@@ -80,11 +100,11 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
return 0;
}
static illegal_insn_func illegal_insn_table[32] = {
static const illegal_insn_func illegal_insn_table[32] = {
truly_illegal_insn, /* 0 */
truly_illegal_insn, /* 1 */
truly_illegal_insn, /* 2 */
truly_illegal_insn, /* 3 */
misc_mem_opcode_insn, /* 3 */
truly_illegal_insn, /* 4 */
truly_illegal_insn, /* 5 */
truly_illegal_insn, /* 6 */

View File

@@ -18,6 +18,7 @@
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_system.h>
@@ -138,10 +139,12 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
/* Boot HART details */
sbi_printf("Boot HART ID : %u\n", hartid);
sbi_printf("Boot HART Domain : %s\n", dom->name);
sbi_hart_get_priv_version_str(scratch, str, sizeof(str));
sbi_printf("Boot HART Priv Version : %s\n", str);
misa_string(xlen, str, sizeof(str));
sbi_printf("Boot HART ISA : %s\n", str);
sbi_hart_get_features_str(scratch, str, sizeof(str));
sbi_printf("Boot HART Features : %s\n", str);
sbi_printf("Boot HART Base ISA : %s\n", str);
sbi_hart_get_extensions_str(scratch, str, sizeof(str));
sbi_printf("Boot HART ISA Extensions : %s\n", str);
sbi_printf("Boot HART PMP Count : %d\n",
sbi_hart_pmp_count(scratch));
sbi_printf("Boot HART PMP Granularity : %lu\n",
@@ -165,8 +168,8 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
/* Save MIE CSR */
saved_mie = csr_read(CSR_MIE);
/* Set MSIE bit to receive IPI */
csr_set(CSR_MIE, MIP_MSIP);
/* Set MSIE and MEIE bits to receive IPI */
csr_set(CSR_MIE, MIP_MSIP | MIP_MEIP);
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
@@ -182,7 +185,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
do {
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & MIP_MSIP));
} while (!(cmip & (MIP_MSIP | MIP_MEIP)));
};
/* Acquire coldboot lock */
@@ -270,9 +273,9 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_boot_print_banner(scratch);
rc = sbi_platform_irqchip_init(plat, TRUE);
rc = sbi_irqchip_init(scratch, TRUE);
if (rc) {
sbi_printf("%s: platform irqchip init failed (error %d)\n",
sbi_printf("%s: irqchip init failed (error %d)\n",
__func__, rc);
sbi_hart_hang();
}
@@ -373,7 +376,7 @@ static void init_warm_startup(struct sbi_scratch *scratch, u32 hartid)
if (rc)
sbi_hart_hang();
rc = sbi_platform_irqchip_init(plat, FALSE);
rc = sbi_irqchip_init(scratch, FALSE);
if (rc)
sbi_hart_hang();
@@ -494,6 +497,14 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
if (next_mode_supported && atomic_xchg(&coldboot_lottery, 1) == 0)
coldboot = TRUE;
/*
* Do platform specific nascent (very early) initialization so
* that platform can initialize platform specific per-HART CSRs
* or per-HART devices.
*/
if (sbi_platform_nascent_init(plat))
sbi_hart_hang();
if (coldboot)
init_coldboot(scratch, hartid);
else
@@ -542,7 +553,7 @@ void __noreturn sbi_exit(struct sbi_scratch *scratch)
sbi_ipi_exit(scratch);
sbi_platform_irqchip_exit(plat);
sbi_irqchip_exit(scratch);
sbi_platform_final_exit(plat);

54
lib/sbi/sbi_irqchip.c Normal file
View File

@@ -0,0 +1,54 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <apatel@ventanamicro.com>
*/
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_platform.h>
static int default_irqfn(struct sbi_trap_regs *regs)
{
return SBI_ENODEV;
}
static int (*ext_irqfn)(struct sbi_trap_regs *regs) = default_irqfn;
void sbi_irqchip_set_irqfn(int (*fn)(struct sbi_trap_regs *regs))
{
if (fn)
ext_irqfn = fn;
}
int sbi_irqchip_process(struct sbi_trap_regs *regs)
{
return ext_irqfn(regs);
}
int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
rc = sbi_platform_irqchip_init(plat, cold_boot);
if (rc)
return rc;
if (ext_irqfn != default_irqfn)
csr_set(CSR_MIE, MIP_MEIP);
return 0;
}
void sbi_irqchip_exit(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (ext_irqfn != default_irqfn)
csr_clear(CSR_MIE, MIP_MEIP);
sbi_platform_irqchip_exit(plat);
}

View File

@@ -22,6 +22,18 @@ union reg_data {
u64 data_u64;
};
static ulong sbi_misaligned_tinst_fixup(ulong orig_tinst, ulong new_tinst,
ulong addr_offset)
{
if (new_tinst == INSN_PSEUDO_VS_LOAD ||
new_tinst == INSN_PSEUDO_VS_STORE)
return new_tinst;
else if (orig_tinst == 0)
return 0UL;
else
return orig_tinst | (addr_offset << SH_RS1);
}
int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
struct sbi_trap_regs *regs)
{
@@ -126,6 +138,8 @@ int sbi_misaligned_load_handler(ulong addr, ulong tval2, ulong tinst,
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
uptrap.tinst = sbi_misaligned_tinst_fixup(
tinst, uptrap.tinst, i);
return sbi_trap_redirect(regs, &uptrap);
}
}
@@ -238,6 +252,8 @@ int sbi_misaligned_store_handler(ulong addr, ulong tval2, ulong tinst,
&uptrap);
if (uptrap.cause) {
uptrap.epc = regs->mepc;
uptrap.tinst = sbi_misaligned_tinst_fixup(
tinst, uptrap.tinst, i);
return sbi_trap_redirect(regs, &uptrap);
}
}

View File

@@ -181,6 +181,9 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
int i = 0;
bool is_overlap;
struct sbi_pmu_hw_event *event = &hw_event_map[num_hw_events];
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
int hw_ctr_avail = sbi_hart_mhpm_count(scratch);
uint32_t ctr_avail_mask = ((uint32_t)(~0) >> (32 - (hw_ctr_avail + 3)));
/* The first two counters are reserved by priv spec */
if (eidx_start > SBI_PMU_HW_INSTRUCTIONS && (cmap & SBI_PMU_FIXED_CTR_MASK))
@@ -208,7 +211,8 @@ static int pmu_add_hw_event_map(u32 eidx_start, u32 eidx_end, u32 cmap,
}
event->select_mask = select_mask;
event->counters = cmap;
/* Map the only the counters that are available in the hardware */
event->counters = cmap & ctr_avail_mask;
event->select = select;
num_hw_events++;
@@ -252,7 +256,7 @@ static int pmu_ctr_enable_irq_hw(int ctr_idx)
#if __riscv_xlen == 32
mhpmevent_csr = CSR_MHPMEVENT3H + ctr_idx - 3;
of_mask = ~MHPMEVENTH_OF;
of_mask = (uint32_t)~MHPMEVENTH_OF;
#else
mhpmevent_csr = CSR_MHPMEVENT3 + ctr_idx - 3;
of_mask = ~MHPMEVENT_OF;
@@ -293,10 +297,10 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
unsigned long mctr_inhbt;
/* Make sure the counter index lies within the range and is not TM bit */
if (cidx > num_hw_ctrs || cidx == 1)
if (cidx >= num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
goto skip_inhibit_update;
/*
@@ -309,7 +313,7 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
__clear_bit(cidx, &mctr_inhbt);
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
pmu_ctr_enable_irq_hw(cidx);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
@@ -343,7 +347,7 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
int ret = SBI_EINVAL;
bool bUpdate = FALSE;
if (__fls(ctr_mask) >= total_ctrs)
if (sbi_fls(ctr_mask) >= total_ctrs)
return ret;
if (flags & SBI_PMU_START_FLAG_SET_INIT_VALUE)
@@ -368,13 +372,13 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long mctr_inhbt;
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
return 0;
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
/* Make sure the counter index lies within the range and is not TM bit */
if (cidx > num_hw_ctrs || cidx == 1)
if (cidx >= num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
if (!__test_bit(cidx, &mctr_inhbt)) {
@@ -400,7 +404,9 @@ static int pmu_reset_hw_mhpmevent(int ctr_idx)
return SBI_EFAIL;
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, 0);
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, 0);
#else
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, 0);
#endif
@@ -417,7 +423,7 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
uint32_t event_code;
unsigned long ctr_mask = cmask << cbase;
if (__fls(ctr_mask) >= total_ctrs)
if (sbi_fls(ctr_mask) >= total_ctrs)
return SBI_EINVAL;
for_each_set_bit_from(cbase, &ctr_mask, total_ctrs) {
@@ -466,16 +472,22 @@ static int pmu_update_hw_mhpmevent(struct sbi_pmu_hw_event *hw_evt, int ctr_idx,
if (!mhpmevent_val || ctr_idx < 3 || ctr_idx >= SBI_PMU_HW_CTR_MAX)
return SBI_EFAIL;
/* Always clear the OVF bit and inhibit countin of events in M-mode */
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) | MHPMEVENT_MINH;
/**
* Always set the OVF bit(disable interrupts) and inhibit counting of
* events in M-mode. The OVF bit should be enabled during the start call.
*/
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
mhpmevent_val = (mhpmevent_val & ~MHPMEVENT_SSCOF_MASK) |
MHPMEVENT_MINH | MHPMEVENT_OF;
/* Update the inhibit flags based on inhibit flags received from supervisor */
pmu_update_inhibit_flags(flags, &mhpmevent_val);
#if __riscv_xlen == 32
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val & 0xFFFFFFFF);
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3, mhpmevent_val >> BITS_PER_LONG);
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
csr_write_num(CSR_MHPMEVENT3H + ctr_idx - 3,
mhpmevent_val >> BITS_PER_LONG);
#else
csr_write_num(CSR_MHPMEVENT3 + ctr_idx - 3, mhpmevent_val);
#endif
@@ -504,7 +516,7 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
u32 hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (cbase > num_hw_ctrs)
if (cbase >= num_hw_ctrs)
return SBI_EINVAL;
/**
@@ -513,10 +525,10 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
*/
fixed_ctr = pmu_ctr_find_fixed_fw(event_idx);
if (fixed_ctr >= 0 &&
!sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
return fixed_ctr;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
mctr_inhbt = csr_read(CSR_MCOUNTINHIBIT);
for (i = 0; i < num_hw_events; i++) {
temp = &hw_event_map[i];
@@ -543,7 +555,7 @@ static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned lo
if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID)
continue;
/* If mcountinhibit is supported, the bit must be enabled */
if ((sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT)) &&
if ((sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) &&
!__test_bit(cbase, &mctr_inhbt))
continue;
/* We found a valid counter that is not started yet */
@@ -581,8 +593,8 @@ static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask, u32 hartid)
int fw_base;
unsigned long ctr_mask = cmask << cbase;
if (cbase <= num_hw_ctrs)
fw_base = num_hw_ctrs + 1;
if (cbase < num_hw_ctrs)
fw_base = num_hw_ctrs;
else
fw_base = cbase;
@@ -606,7 +618,7 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long tmp = cidx_mask << cidx_base;
/* Do a basic sanity check of counter base & mask */
if (__fls(tmp) >= total_ctrs || event_type >= SBI_PMU_EVENT_TYPE_MAX)
if (sbi_fls(tmp) >= total_ctrs || event_type >= SBI_PMU_EVENT_TYPE_MAX)
return SBI_EINVAL;
if (flags & SBI_PMU_CFG_FLAG_SKIP_MATCH) {
@@ -682,7 +694,7 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
return SBI_EINVAL;
/* We have 31 HW counters with 31 being the last index(MHPMCOUNTER31) */
if (cidx <= num_hw_ctrs) {
if (cidx < num_hw_ctrs) {
cinfo.type = SBI_PMU_CTR_TYPE_HW;
cinfo.csr = CSR_CYCLE + cidx;
/* mcycle & minstret are always 64 bit */
@@ -718,10 +730,11 @@ void sbi_pmu_exit(struct sbi_scratch *scratch)
{
u32 hartid = current_hartid();
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_MCOUNTINHIBIT))
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
csr_write(CSR_MCOUNTEREN, -1);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
pmu_reset_event_map(hartid);
}
@@ -736,7 +749,7 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
sbi_platform_pmu_init(plat);
/* mcycle & minstret is available always */
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 2;
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 3;
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
}

View File

@@ -149,8 +149,8 @@ void *sbi_memmove(void *dest, const void *src, size_t count)
count--;
}
} else {
temp1 = dest + count - 1;
temp2 = src + count - 1;
temp1 = (char *)dest + count - 1;
temp2 = (char *)src + count - 1;
while (count > 0) {
*temp1-- = *temp2--;

View File

@@ -44,11 +44,6 @@ static u64 get_ticks(void)
}
#endif
static u64 get_platform_ticks(void)
{
return timer_dev->timer_value();
}
static void nop_delay_fn(void *opaque)
{
cpu_relax();
@@ -124,16 +119,35 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
void sbi_timer_event_start(u64 next_event)
{
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
if (timer_dev && timer_dev->timer_event_start)
/**
* Update the stimecmp directly if available. This allows
* the older software to leverage sstc extension on newer hardware.
*/
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC)) {
#if __riscv_xlen == 32
csr_write(CSR_STIMECMP, next_event & 0xFFFFFFFF);
csr_write(CSR_STIMECMPH, next_event >> 32);
#else
csr_write(CSR_STIMECMP, next_event);
#endif
} else if (timer_dev && timer_dev->timer_event_start) {
timer_dev->timer_event_start(next_event);
csr_clear(CSR_MIP, MIP_STIP);
csr_clear(CSR_MIP, MIP_STIP);
}
csr_set(CSR_MIE, MIP_MTIP);
}
void sbi_timer_process(void)
{
csr_clear(CSR_MIE, MIP_MTIP);
csr_set(CSR_MIP, MIP_STIP);
/*
* If sstc extension is available, supervisor can receive the timer
* directly without M-mode come in between. This function should
* only invoked if M-mode programs the timer for its own purpose.
*/
if (!sbi_hart_has_extension(sbi_scratch_thishart_ptr(), SBI_HART_EXT_SSTC))
csr_set(CSR_MIP, MIP_STIP);
}
const struct sbi_timer_device *sbi_timer_get_device(void)
@@ -148,7 +162,7 @@ void sbi_timer_set_device(const struct sbi_timer_device *dev)
timer_dev = dev;
if (!get_time_val && timer_dev->timer_value)
get_time_val = get_platform_ticks;
get_time_val = timer_dev->timer_value;
}
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
@@ -161,7 +175,7 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
if (!time_delta_off)
return SBI_ENOMEM;
if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_TIME))
get_time_val = get_ticks;
} else {
if (!time_delta_off)

View File

@@ -15,6 +15,7 @@
#include <sbi/sbi_hart.h>
#include <sbi/sbi_illegal_insn.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_misaligned_ldst.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
@@ -98,17 +99,14 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
if (prev_mode != PRV_S && prev_mode != PRV_U)
return SBI_ENOTSUPP;
/* For certain exceptions from VS/VU-mode we redirect to VS-mode */
/* If exceptions came from VS/VU-mode, redirect to VS-mode if
* delegated in hedeleg
*/
if (misa_extension('H') && prev_virt) {
switch (trap->cause) {
case CAUSE_FETCH_PAGE_FAULT:
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
if ((trap->cause < __riscv_xlen) &&
(csr_read(CSR_HEDELEG) & BIT(trap->cause))) {
next_virt = TRUE;
break;
default:
break;
};
}
}
/* Update MSTATUS MPV bits */
@@ -195,6 +193,52 @@ int sbi_trap_redirect(struct sbi_trap_regs *regs,
return 0;
}
static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
{
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
case IRQ_M_EXT:
return sbi_irqchip_process(regs);
default:
return SBI_ENOENT;
};
return 0;
}
static int sbi_trap_aia_irq(struct sbi_trap_regs *regs, ulong mcause)
{
int rc;
unsigned long mtopi;
while ((mtopi = csr_read(CSR_MTOPI))) {
mtopi = mtopi >> TOPI_IID_SHIFT;
switch (mtopi) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
case IRQ_M_EXT:
rc = sbi_irqchip_process(regs);
if (rc)
return rc;
break;
default:
return SBI_ENOENT;
}
}
return 0;
}
/**
* Handle trap/interrupt
*
@@ -225,18 +269,15 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
}
if (mcause & (1UL << (__riscv_xlen - 1))) {
mcause &= ~(1UL << (__riscv_xlen - 1));
switch (mcause) {
case IRQ_M_TIMER:
sbi_timer_process();
break;
case IRQ_M_SOFT:
sbi_ipi_process();
break;
default:
msg = "unhandled external interrupt";
if (sbi_hart_has_extension(sbi_scratch_thishart_ptr(),
SBI_HART_EXT_AIA))
rc = sbi_trap_aia_irq(regs, mcause);
else
rc = sbi_trap_nonaia_irq(regs, mcause);
if (rc) {
msg = "unhandled local interrupt";
goto trap_error;
};
}
return regs;
}

View File

@@ -83,7 +83,7 @@ DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lwu)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u64, ld)
DEFINE_UNPRIVILEGED_STORE_FUNCTION(u64, sd)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, ld)
#else
#elif __riscv_xlen == 32
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(u32, lw)
DEFINE_UNPRIVILEGED_LOAD_FUNCTION(ulong, lw)
@@ -112,6 +112,8 @@ void sbi_store_u64(u64 *addr, u64 val,
if (trap->cause)
return;
}
#else
# error "Unexpected __riscv_xlen"
#endif
ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
@@ -147,15 +149,17 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
switch (trap->cause) {
case CAUSE_LOAD_ACCESS:
trap->cause = CAUSE_FETCH_ACCESS;
trap->tval = mepc;
trap->tinst = 0UL;
break;
case CAUSE_LOAD_PAGE_FAULT:
trap->cause = CAUSE_FETCH_PAGE_FAULT;
trap->tval = mepc;
trap->tinst = 0UL;
break;
case CAUSE_LOAD_GUEST_PAGE_FAULT:
trap->cause = CAUSE_FETCH_GUEST_PAGE_FAULT;
trap->tval = mepc;
if (trap->tinst != INSN_PSEUDO_VS_LOAD &&
trap->tinst != INSN_PSEUDO_VS_STORE)
trap->tinst = 0UL;
break;
default:
break;

View File

@@ -165,6 +165,9 @@ void fdt_domain_fixup(void *fdt)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, doffset))
continue;
fdt_nop_property(fdt, doffset, "opensbi-domain");
}
@@ -308,6 +311,9 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (err)
return err;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
sbi_hartmask_set_hart(val32, mask);
}
}
@@ -347,7 +353,7 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (val && len >= 4) {
cpu_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(*val));
if (cpu_offset >= 0)
if (cpu_offset >= 0 && fdt_node_is_enabled(fdt, cpu_offset))
fdt_parse_hart_id(fdt, cpu_offset, &val32);
} else {
if (domain_offset == *cold_domain_offset)
@@ -414,6 +420,9 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
if (SBI_HARTMASK_MAX_BITS <= val32)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (!val || len < 4)
return SBI_EINVAL;
@@ -460,6 +469,9 @@ int fdt_domains_populate(void *fdt)
if (hartid != cold_hartid)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (val && len >= 4)
cold_domain_offset = fdt_node_offset_by_phandle(fdt,

View File

@@ -38,6 +38,9 @@ void fdt_cpu_fixup(void *fdt)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
/*
* Disable a HART DT node if one of the following is true:
* 1. The HART is not assigned to the current domain
@@ -52,6 +55,43 @@ void fdt_cpu_fixup(void *fdt)
}
}
static void fdt_domain_based_fixup_one(void *fdt, int nodeoff)
{
int rc;
uint64_t reg_addr, reg_size;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return;
if (!sbi_domain_check_addr(dom, reg_addr, dom->next_mode,
SBI_DOMAIN_READ | SBI_DOMAIN_WRITE)) {
rc = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 32);
if (rc < 0)
return;
fdt_setprop_string(fdt, nodeoff, "status", "disabled");
}
}
void fdt_aplic_fixup(void *fdt)
{
int noff = 0;
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
"riscv,aplic")) >= 0)
fdt_domain_based_fixup_one(fdt, noff);
}
void fdt_imsic_fixup(void *fdt)
{
int noff = 0;
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
"riscv,imsics")) >= 0)
fdt_domain_based_fixup_one(fdt, noff);
}
void fdt_plic_fixup(void *fdt)
{
u32 *cells;
@@ -261,10 +301,12 @@ int fdt_reserved_memory_nomap_fixup(void *fdt)
void fdt_fixups(void *fdt)
{
fdt_aplic_fixup(fdt);
fdt_imsic_fixup(fdt);
fdt_plic_fixup(fdt);
fdt_reserved_memory_fixup(fdt);
fdt_pmu_fixup(fdt);
}

View File

@@ -13,12 +13,15 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/aplic.h>
#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/irqchip/plic.h>
#define DEFAULT_UART_FREQ 0
#define DEFAULT_UART_BAUD 115200
#define DEFAULT_UART_REG_SHIFT 0
#define DEFAULT_UART_REG_IO_WIDTH 1
#define DEFAULT_UART_REG_OFFSET 0
#define DEFAULT_SIFIVE_UART_FREQ 0
#define DEFAULT_SIFIVE_UART_BAUD 115200
@@ -213,6 +216,24 @@ int fdt_get_node_addr_size(void *fdt, int node, int index,
return 0;
}
bool fdt_node_is_enabled(void *fdt, int nodeoff)
{
int len;
const void *prop;
prop = fdt_getprop(fdt, nodeoff, "status", &len);
if (!prop)
return true;
if (!strncmp(prop, "okay", strlen("okay")))
return true;
if (!strncmp(prop, "ok", strlen("ok")))
return true;
return false;
}
int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
{
int len;
@@ -241,7 +262,7 @@ int fdt_parse_hart_id(void *fdt, int cpu_offset, u32 *hartid)
return 0;
}
int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
int fdt_parse_max_enabled_hart_id(void *fdt, u32 *max_hartid)
{
u32 hartid;
int err, cpu_offset, cpus_offset;
@@ -262,6 +283,9 @@ int fdt_parse_max_hart_id(void *fdt, u32 *max_hartid)
if (err)
continue;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
if (hartid > *max_hartid)
*max_hartid = hartid;
}
@@ -447,6 +471,12 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
else
uart->reg_io_width = DEFAULT_UART_REG_IO_WIDTH;
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "reg-offset", &len);
if (len > 0 && val)
uart->reg_offset = fdt32_to_cpu(*val);
else
uart->reg_offset = DEFAULT_UART_REG_OFFSET;
return 0;
}
@@ -465,6 +495,284 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
}
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
struct platform_uart_data *uart)
{
int rc;
uint64_t reg_addr, reg_size;
if (nodeoffset < 0 || !uart || !fdt)
return SBI_ENODEV;
rc = fdt_get_node_addr_size(fdt, nodeoffset, 0,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
uart->addr = reg_addr;
return 0;
}
int fdt_parse_aplic_node(void *fdt, int nodeoff, struct aplic_data *aplic)
{
bool child_found;
const fdt32_t *val;
const fdt32_t *del;
struct imsic_data imsic;
int i, j, d, dcnt, len, noff, rc;
uint64_t reg_addr, reg_size;
struct aplic_delegate_data *deleg;
if (nodeoff < 0 || !aplic || !fdt)
return SBI_ENODEV;
memset(aplic, 0, sizeof(*aplic));
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
return SBI_ENODEV;
aplic->addr = reg_addr;
aplic->size = reg_size;
val = fdt_getprop(fdt, nodeoff, "riscv,num-sources", &len);
if (len > 0)
aplic->num_source = fdt32_to_cpu(*val);
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
aplic->targets_mmode = true;
break;
}
}
aplic->num_idc = len / 2;
goto aplic_msi_parent_done;
}
val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
if (val && len >= sizeof(fdt32_t)) {
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
rc = fdt_parse_imsic_node(fdt, noff, &imsic);
if (rc)
return rc;
rc = imsic_data_check(&imsic);
if (rc)
return rc;
aplic->targets_mmode = imsic.targets_mmode;
if (imsic.targets_mmode) {
aplic->has_msicfg_mmode = true;
aplic->msicfg_mmode.lhxs = imsic.guest_index_bits;
aplic->msicfg_mmode.lhxw = imsic.hart_index_bits;
aplic->msicfg_mmode.hhxw = imsic.group_index_bits;
aplic->msicfg_mmode.hhxs = imsic.group_index_shift;
if (aplic->msicfg_mmode.hhxs <
(2 * IMSIC_MMIO_PAGE_SHIFT))
return SBI_EINVAL;
aplic->msicfg_mmode.hhxs -= 24;
aplic->msicfg_mmode.base_addr = imsic.regs[0].addr;
} else {
goto aplic_msi_parent_done;
}
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
if (!val || len < sizeof(fdt32_t))
goto aplic_msi_parent_done;
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
val = fdt_getprop(fdt, noff, "msi-parent", &len);
if (!val || len < sizeof(fdt32_t))
goto aplic_msi_parent_done;
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
rc = fdt_parse_imsic_node(fdt, noff, &imsic);
if (rc)
return rc;
rc = imsic_data_check(&imsic);
if (rc)
return rc;
if (!imsic.targets_mmode) {
aplic->has_msicfg_smode = true;
aplic->msicfg_smode.lhxs = imsic.guest_index_bits;
aplic->msicfg_smode.lhxw = imsic.hart_index_bits;
aplic->msicfg_smode.hhxw = imsic.group_index_bits;
aplic->msicfg_smode.hhxs = imsic.group_index_shift;
if (aplic->msicfg_smode.hhxs <
(2 * IMSIC_MMIO_PAGE_SHIFT))
return SBI_EINVAL;
aplic->msicfg_smode.hhxs -= 24;
aplic->msicfg_smode.base_addr = imsic.regs[0].addr;
}
}
aplic_msi_parent_done:
for (d = 0; d < APLIC_MAX_DELEGATE; d++) {
deleg = &aplic->delegate[d];
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
}
del = fdt_getprop(fdt, nodeoff, "riscv,delegate", &len);
if (!del || len < (3 * sizeof(fdt32_t)))
goto skip_delegate_parse;
d = 0;
dcnt = len / sizeof(fdt32_t);
for (i = 0; i < dcnt; i += 3) {
if (d >= APLIC_MAX_DELEGATE)
break;
deleg = &aplic->delegate[d];
deleg->first_irq = fdt32_to_cpu(del[i + 1]);
deleg->last_irq = fdt32_to_cpu(del[i + 2]);
deleg->child_index = 0;
child_found = false;
val = fdt_getprop(fdt, nodeoff, "riscv,children", &len);
if (!val || len < sizeof(fdt32_t)) {
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
continue;
}
len = len / sizeof(fdt32_t);
for (j = 0; j < len; j++) {
if (del[i] != val[j])
continue;
deleg->child_index = j;
child_found = true;
break;
}
if (child_found) {
d++;
} else {
deleg->first_irq = 0;
deleg->last_irq = 0;
deleg->child_index = 0;
}
}
skip_delegate_parse:
return 0;
}
bool fdt_check_imsic_mlevel(void *fdt)
{
const fdt32_t *val;
int i, len, noff = 0;
if (!fdt)
return false;
while ((noff = fdt_node_offset_by_compatible(fdt, noff,
"riscv,imsics")) >= 0) {
val = fdt_getprop(fdt, noff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT)
return true;
}
}
}
return false;
}
int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
{
const fdt32_t *val;
struct imsic_regs *regs;
uint64_t reg_addr, reg_size;
int i, rc, len, nr_parent_irqs;
if (nodeoff < 0 || !imsic || !fdt)
return SBI_ENODEV;
imsic->targets_mmode = false;
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
if (val && len > sizeof(fdt32_t)) {
len = len / sizeof(fdt32_t);
nr_parent_irqs = len / 2;
for (i = 0; i < len; i += 2) {
if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
imsic->targets_mmode = true;
break;
}
}
} else
return SBI_EINVAL;
val = fdt_getprop(fdt, nodeoff, "riscv,guest-index-bits", &len);
if (val && len > 0)
imsic->guest_index_bits = fdt32_to_cpu(*val);
else
imsic->guest_index_bits = 0;
val = fdt_getprop(fdt, nodeoff, "riscv,hart-index-bits", &len);
if (val && len > 0) {
imsic->hart_index_bits = fdt32_to_cpu(*val);
} else {
imsic->hart_index_bits = sbi_fls(nr_parent_irqs);
if ((1UL << imsic->hart_index_bits) < nr_parent_irqs)
imsic->hart_index_bits++;
}
val = fdt_getprop(fdt, nodeoff, "riscv,group-index-bits", &len);
if (val && len > 0)
imsic->group_index_bits = fdt32_to_cpu(*val);
else
imsic->group_index_bits = 0;
val = fdt_getprop(fdt, nodeoff, "riscv,group-index-shift", &len);
if (val && len > 0)
imsic->group_index_shift = fdt32_to_cpu(*val);
else
imsic->group_index_shift = 2 * IMSIC_MMIO_PAGE_SHIFT;
val = fdt_getprop(fdt, nodeoff, "riscv,num-ids", &len);
if (val && len > 0)
imsic->num_ids = fdt32_to_cpu(*val);
else
return SBI_EINVAL;
for (i = 0; i < IMSIC_MAX_REGS; i++) {
regs = &imsic->regs[i];
regs->addr = 0;
regs->size = 0;
}
for (i = 0; i < (IMSIC_MAX_REGS - 1); i++) {
regs = &imsic->regs[i];
rc = fdt_get_node_addr_size(fdt, nodeoff, i,
&reg_addr, &reg_size);
if (rc < 0 || !reg_addr || !reg_size)
break;
regs->addr = reg_addr;
regs->size = reg_size;
};
if (!imsic->regs[0].size)
return SBI_EINVAL;
return 0;
}
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
{
int len, rc;

View File

@@ -53,7 +53,7 @@ int fdt_pmu_fixup(void *fdt)
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmcounters");
fdt_delprop(fdt, pmu_offset, "riscv,event-to-mhpmevent");
fdt_delprop(fdt, pmu_offset, "riscv,raw-event-to-mhpmcounters");
if (!sbi_hart_has_feature(scratch, SBI_HART_HAS_SSCOFPMF))
if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SSCOFPMF))
fdt_delprop(fdt, pmu_offset, "interrupts-extended");
return 0;

View File

@@ -12,11 +12,9 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
extern struct fdt_gpio fdt_gpio_sifive;
static struct fdt_gpio *gpio_drivers[] = {
&fdt_gpio_sifive
};
/* List of FDT gpio drivers generated at compile time */
extern struct fdt_gpio *fdt_gpio_drivers[];
extern unsigned long fdt_gpio_drivers_size;
static struct fdt_gpio *fdt_gpio_driver(struct gpio_chip *chip)
{
@@ -25,9 +23,9 @@ static struct fdt_gpio *fdt_gpio_driver(struct gpio_chip *chip)
if (!chip)
return NULL;
for (pos = 0; pos < array_size(gpio_drivers); pos++) {
if (chip->driver == gpio_drivers[pos])
return gpio_drivers[pos];
for (pos = 0; pos < fdt_gpio_drivers_size; pos++) {
if (chip->driver == fdt_gpio_drivers[pos])
return fdt_gpio_drivers[pos];
}
return NULL;
@@ -49,8 +47,8 @@ static int fdt_gpio_init(void *fdt, u32 phandle)
return SBI_EINVAL;
/* Try all GPIO drivers one-by-one */
for (pos = 0; pos < array_size(gpio_drivers); pos++) {
drv = gpio_drivers[pos];
for (pos = 0; pos < fdt_gpio_drivers_size; pos++) {
drv = fdt_gpio_drivers[pos];
match = fdt_match_node(fdt, nodeoff, drv->match_table);
if (match && drv->init) {

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/gpio/fdt_gpio.h
TYPE: struct fdt_gpio
NAME: fdt_gpio_drivers

View File

@@ -8,5 +8,9 @@
#
libsbiutils-objs-y += gpio/fdt_gpio.o
libsbiutils-objs-y += gpio/fdt_gpio_drivers.o
carray-fdt_gpio_drivers-y += fdt_gpio_sifive
libsbiutils-objs-y += gpio/fdt_gpio_sifive.o
libsbiutils-objs-y += gpio/gpio.o

View File

@@ -16,13 +16,9 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/i2c/fdt_i2c.h>
#include <sbi/sbi_console.h>
extern struct fdt_i2c_adapter fdt_i2c_adapter_sifive;
static struct fdt_i2c_adapter *i2c_adapter_drivers[] = {
&fdt_i2c_adapter_sifive
};
/* List of FDT i2c adapter drivers generated at compile time */
extern struct fdt_i2c_adapter *fdt_i2c_adapter_drivers[];
extern unsigned long fdt_i2c_adapter_drivers_size;
static int fdt_i2c_adapter_init(void *fdt, int nodeoff)
{
@@ -31,8 +27,8 @@ static int fdt_i2c_adapter_init(void *fdt, int nodeoff)
const struct fdt_match *match;
/* Try all I2C drivers one-by-one */
for (pos = 0; pos < array_size(i2c_adapter_drivers); pos++) {
drv = i2c_adapter_drivers[pos];
for (pos = 0; pos < fdt_i2c_adapter_drivers_size; pos++) {
drv = fdt_i2c_adapter_drivers[pos];
match = fdt_match_node(fdt, nodeoff, drv->match_table);
if (match && drv->init) {
rc = drv->init(fdt, nodeoff, match);

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/i2c/fdt_i2c.h
TYPE: struct fdt_i2c_adapter
NAME: fdt_i2c_adapter_drivers

View File

@@ -56,13 +56,13 @@ extern struct fdt_i2c_adapter fdt_i2c_adapter_sifive;
static inline void sifive_i2c_setreg(struct sifive_i2c_adapter *adap,
uint8_t reg, uint8_t value)
{
writel(value, (volatile void *)adap->addr + reg);
writel(value, (volatile char *)adap->addr + reg);
}
static inline uint8_t sifive_i2c_getreg(struct sifive_i2c_adapter *adap,
uint8_t reg)
{
return readl((volatile void *)adap->addr + reg);
return readl((volatile char *)adap->addr + reg);
}
static int sifive_i2c_adapter_rxack(struct sifive_i2c_adapter *adap)

View File

@@ -8,5 +8,9 @@
#
libsbiutils-objs-y += i2c/i2c.o
libsbiutils-objs-y += i2c/fdt_i2c.o
libsbiutils-objs-y += i2c/fdt_i2c_adapter_drivers.o
carray-fdt_i2c_adapter_drivers-y += fdt_i2c_adapter_sifive
libsbiutils-objs-y += i2c/fdt_i2c_sifive.o

View File

@@ -74,7 +74,7 @@ int aclint_mswi_cold_init(struct aclint_mswi_data *mswi)
/* Sanity checks */
if (!mswi || (mswi->addr & (ACLINT_MSWI_ALIGN - 1)) ||
(mswi->size < ACLINT_MSWI_SIZE) ||
(mswi->size < (mswi->hart_count * sizeof(u32))) ||
(mswi->first_hartid >= SBI_HARTMASK_MAX_BITS) ||
(mswi->hart_count > ACLINT_MSWI_MAX_HARTS))
return SBI_EINVAL;

View File

@@ -12,11 +12,9 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/ipi/fdt_ipi.h>
extern struct fdt_ipi fdt_ipi_mswi;
static struct fdt_ipi *ipi_drivers[] = {
&fdt_ipi_mswi
};
/* List of FDT ipi drivers generated at compile time */
extern struct fdt_ipi *fdt_ipi_drivers[];
extern unsigned long fdt_ipi_drivers_size;
static struct fdt_ipi dummy = {
.match_table = NULL,
@@ -47,8 +45,8 @@ static int fdt_ipi_cold_init(void)
const struct fdt_match *match;
void *fdt = fdt_get_address();
for (pos = 0; pos < array_size(ipi_drivers); pos++) {
drv = ipi_drivers[pos];
for (pos = 0; pos < fdt_ipi_drivers_size; pos++) {
drv = fdt_ipi_drivers[pos];
noff = -1;
while ((noff = fdt_find_match(fdt, noff,

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/ipi/fdt_ipi.h
TYPE: struct fdt_ipi
NAME: fdt_ipi_drivers

View File

@@ -51,7 +51,7 @@ static int ipi_mswi_cold_init(void *fdt, int nodeoff,
return 0;
}
static unsigned long clint_offset = CLINT_MSWI_OFFSET;
static const unsigned long clint_offset = CLINT_MSWI_OFFSET;
static const struct fdt_match ipi_mswi_match[] = {
{ .compatible = "riscv,clint0", .data = &clint_offset },

View File

@@ -8,5 +8,9 @@
#
libsbiutils-objs-y += ipi/aclint_mswi.o
libsbiutils-objs-y += ipi/fdt_ipi.o
libsbiutils-objs-y += ipi/fdt_ipi_drivers.o
carray-fdt_ipi_drivers-y += fdt_ipi_mswi
libsbiutils-objs-y += ipi/fdt_ipi_mswi.o

279
lib/utils/irqchip/aplic.c Normal file
View File

@@ -0,0 +1,279 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi_utils/irqchip/aplic.h>
#define APLIC_MAX_IDC (1UL << 14)
#define APLIC_MAX_SOURCE 1024
#define APLIC_DOMAINCFG 0x0000
#define APLIC_DOMAINCFG_IE (1 << 8)
#define APLIC_DOMAINCFG_DM (1 << 2)
#define APLIC_DOMAINCFG_BE (1 << 0)
#define APLIC_SOURCECFG_BASE 0x0004
#define APLIC_SOURCECFG_D (1 << 10)
#define APLIC_SOURCECFG_CHILDIDX_MASK 0x000003ff
#define APLIC_SOURCECFG_SM_MASK 0x00000007
#define APLIC_SOURCECFG_SM_INACTIVE 0x0
#define APLIC_SOURCECFG_SM_DETACH 0x1
#define APLIC_SOURCECFG_SM_EDGE_RISE 0x4
#define APLIC_SOURCECFG_SM_EDGE_FALL 0x5
#define APLIC_SOURCECFG_SM_LEVEL_HIGH 0x6
#define APLIC_SOURCECFG_SM_LEVEL_LOW 0x7
#define APLIC_MMSICFGADDR 0x1bc0
#define APLIC_MMSICFGADDRH 0x1bc4
#define APLIC_SMSICFGADDR 0x1bc8
#define APLIC_SMSICFGADDRH 0x1bcc
#define APLIC_xMSICFGADDRH_L (1UL << 31)
#define APLIC_xMSICFGADDRH_HHXS_MASK 0x1f
#define APLIC_xMSICFGADDRH_HHXS_SHIFT 24
#define APLIC_xMSICFGADDRH_LHXS_MASK 0x7
#define APLIC_xMSICFGADDRH_LHXS_SHIFT 20
#define APLIC_xMSICFGADDRH_HHXW_MASK 0x7
#define APLIC_xMSICFGADDRH_HHXW_SHIFT 16
#define APLIC_xMSICFGADDRH_LHXW_MASK 0xf
#define APLIC_xMSICFGADDRH_LHXW_SHIFT 12
#define APLIC_xMSICFGADDRH_BAPPN_MASK 0xfff
#define APLIC_xMSICFGADDR_PPN_SHIFT 12
#define APLIC_xMSICFGADDR_PPN_HART(__lhxs) \
((1UL << (__lhxs)) - 1)
#define APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) \
((1UL << (__lhxw)) - 1)
#define APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs) \
((__lhxs))
#define APLIC_xMSICFGADDR_PPN_LHX(__lhxw, __lhxs) \
(APLIC_xMSICFGADDR_PPN_LHX_MASK(__lhxw) << \
APLIC_xMSICFGADDR_PPN_LHX_SHIFT(__lhxs))
#define APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) \
((1UL << (__hhxw)) - 1)
#define APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs) \
((__hhxs) + APLIC_xMSICFGADDR_PPN_SHIFT)
#define APLIC_xMSICFGADDR_PPN_HHX(__hhxw, __hhxs) \
(APLIC_xMSICFGADDR_PPN_HHX_MASK(__hhxw) << \
APLIC_xMSICFGADDR_PPN_HHX_SHIFT(__hhxs))
#define APLIC_SETIP_BASE 0x1c00
#define APLIC_SETIPNUM 0x1cdc
#define APLIC_CLRIP_BASE 0x1d00
#define APLIC_CLRIPNUM 0x1ddc
#define APLIC_SETIE_BASE 0x1e00
#define APLIC_SETIENUM 0x1edc
#define APLIC_CLRIE_BASE 0x1f00
#define APLIC_CLRIENUM 0x1fdc
#define APLIC_SETIPNUM_LE 0x2000
#define APLIC_SETIPNUM_BE 0x2004
#define APLIC_TARGET_BASE 0x3004
#define APLIC_TARGET_HART_IDX_SHIFT 18
#define APLIC_TARGET_HART_IDX_MASK 0x3fff
#define APLIC_TARGET_GUEST_IDX_SHIFT 12
#define APLIC_TARGET_GUEST_IDX_MASK 0x3f
#define APLIC_TARGET_IPRIO_MASK 0xff
#define APLIC_TARGET_EIID_MASK 0x7ff
#define APLIC_IDC_BASE 0x4000
#define APLIC_IDC_SIZE 32
#define APLIC_IDC_IDELIVERY 0x00
#define APLIC_IDC_IFORCE 0x04
#define APLIC_IDC_ITHRESHOLD 0x08
#define APLIC_IDC_TOPI 0x18
#define APLIC_IDC_TOPI_ID_SHIFT 16
#define APLIC_IDC_TOPI_ID_MASK 0x3ff
#define APLIC_IDC_TOPI_PRIO_MASK 0xff
#define APLIC_IDC_CLAIMI 0x1c
#define APLIC_DEFAULT_PRIORITY 1
#define APLIC_DISABLE_IDELIVERY 0
#define APLIC_ENABLE_IDELIVERY 1
#define APLIC_DISABLE_ITHRESHOLD 1
#define APLIC_ENABLE_ITHRESHOLD 0
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
void *msicfgaddr, void *msicfgaddrH)
{
u32 val;
unsigned long base_ppn;
/* Check if MSI config is already locked */
if (readl(msicfgaddrH) & APLIC_xMSICFGADDRH_L)
return;
/* Compute the MSI base PPN */
base_ppn = msicfg->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT;
base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(msicfg->lhxs);
base_ppn &= ~APLIC_xMSICFGADDR_PPN_LHX(msicfg->lhxw, msicfg->lhxs);
base_ppn &= ~APLIC_xMSICFGADDR_PPN_HHX(msicfg->hhxw, msicfg->hhxs);
/* Write the lower MSI config register */
writel((u32)base_ppn, msicfgaddr);
/* Write the upper MSI config register */
val = (((u64)base_ppn) >> 32) &
APLIC_xMSICFGADDRH_BAPPN_MASK;
val |= (msicfg->lhxw & APLIC_xMSICFGADDRH_LHXW_MASK)
<< APLIC_xMSICFGADDRH_LHXW_SHIFT;
val |= (msicfg->hhxw & APLIC_xMSICFGADDRH_HHXW_MASK)
<< APLIC_xMSICFGADDRH_HHXW_SHIFT;
val |= (msicfg->lhxs & APLIC_xMSICFGADDRH_LHXS_MASK)
<< APLIC_xMSICFGADDRH_LHXS_SHIFT;
val |= (msicfg->hhxs & APLIC_xMSICFGADDRH_HHXS_MASK)
<< APLIC_xMSICFGADDRH_HHXS_SHIFT;
writel(val, msicfgaddrH);
}
static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
{
if (APLIC_xMSICFGADDRH_LHXS_MASK < msicfg->lhxs)
return SBI_EINVAL;
if (APLIC_xMSICFGADDRH_LHXW_MASK < msicfg->lhxw)
return SBI_EINVAL;
if (APLIC_xMSICFGADDRH_HHXS_MASK < msicfg->hhxs)
return SBI_EINVAL;
if (APLIC_xMSICFGADDRH_HHXW_MASK < msicfg->hhxw)
return SBI_EINVAL;
return 0;
}
int aplic_cold_irqchip_init(struct aplic_data *aplic)
{
int rc;
u32 i, j, tmp;
struct sbi_domain_memregion reg;
struct aplic_delegate_data *deleg;
u32 first_deleg_irq, last_deleg_irq;
/* Sanity checks */
if (!aplic ||
!aplic->num_source || APLIC_MAX_SOURCE <= aplic->num_source ||
APLIC_MAX_IDC <= aplic->num_idc)
return SBI_EINVAL;
if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
rc = aplic_check_msicfg(&aplic->msicfg_mmode);
if (rc)
return rc;
}
if (aplic->targets_mmode && aplic->has_msicfg_smode) {
rc = aplic_check_msicfg(&aplic->msicfg_smode);
if (rc)
return rc;
}
/* Set domain configuration to 0 */
writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
/* Disable all interrupts */
for (i = 0; i <= aplic->num_source; i++)
writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
(i / 32) * sizeof(u32)));
/* Set interrupt type and priority for all interrupts */
for (i = 1; i <= aplic->num_source; i++) {
/* Set IRQ source configuration to 0 */
writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
(i - 1) * sizeof(u32)));
/* Set IRQ target hart index and priority to 1 */
writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
APLIC_TARGET_BASE +
(i - 1) * sizeof(u32)));
}
/* Configure IRQ delegation */
first_deleg_irq = -1U;
last_deleg_irq = 0;
for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
deleg = &aplic->delegate[i];
if (!deleg->first_irq || !deleg->last_irq)
continue;
if (aplic->num_source < deleg->first_irq ||
aplic->num_source < deleg->last_irq)
continue;
if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index)
continue;
if (deleg->first_irq > deleg->last_irq) {
tmp = deleg->first_irq;
deleg->first_irq = deleg->last_irq;
deleg->last_irq = tmp;
}
if (deleg->first_irq < first_deleg_irq)
first_deleg_irq = deleg->first_irq;
if (last_deleg_irq < deleg->last_irq)
last_deleg_irq = deleg->last_irq;
for (j = deleg->first_irq; j <= deleg->last_irq; j++)
writel(APLIC_SOURCECFG_D | deleg->child_index,
(void *)(aplic->addr + APLIC_SOURCECFG_BASE +
(j - 1) * sizeof(u32)));
}
/* Default initialization of IDC structures */
for (i = 0; i < aplic->num_idc; i++) {
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
APLIC_IDC_BASE +
(i * APLIC_IDC_SIZE) +
APLIC_IDC_ITHRESHOLD));
}
/* MSI configuration */
if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
aplic_writel_msicfg(&aplic->msicfg_mmode,
(void *)(aplic->addr + APLIC_MMSICFGADDR),
(void *)(aplic->addr + APLIC_MMSICFGADDRH));
}
if (aplic->targets_mmode && aplic->has_msicfg_smode) {
aplic_writel_msicfg(&aplic->msicfg_smode,
(void *)(aplic->addr + APLIC_SMSICFGADDR),
(void *)(aplic->addr + APLIC_SMSICFGADDRH));
}
/*
* Add APLIC region to the root domain if:
* 1) It targets M-mode of any HART directly or via MSIs
* 2) All interrupts are delegated to some child APLIC
*/
if (aplic->targets_mmode ||
((first_deleg_irq < last_deleg_irq) &&
(last_deleg_irq == aplic->num_source) &&
(first_deleg_irq == 1))) {
sbi_domain_memregion_init(aplic->addr, aplic->size,
SBI_DOMAIN_MEMREGION_MMIO, &reg);
rc = sbi_domain_root_add_memregion(&reg);
if (rc)
return rc;
}
return 0;
}

View File

@@ -12,38 +12,54 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
extern struct fdt_irqchip fdt_irqchip_plic;
/* List of FDT irqchip drivers generated at compile time */
extern struct fdt_irqchip *fdt_irqchip_drivers[];
extern unsigned long fdt_irqchip_drivers_size;
static struct fdt_irqchip *irqchip_drivers[] = {
&fdt_irqchip_plic
};
#define FDT_IRQCHIP_MAX_DRIVERS 8
static struct fdt_irqchip *current_driver = NULL;
static struct fdt_irqchip *current_drivers[FDT_IRQCHIP_MAX_DRIVERS] = {0};
static int current_drivers_count;
void fdt_irqchip_exit(void)
{
if (current_driver && current_driver->exit)
current_driver->exit();
int i;
for (i = 0; i < current_drivers_count; i++) {
if (!current_drivers[i] || !current_drivers[i]->exit)
continue;
current_drivers[i]->exit();
}
}
static int fdt_irqchip_warm_init(void)
{
if (current_driver && current_driver->warm_init)
return current_driver->warm_init();
int i, rc;
for (i = 0; i < current_drivers_count; i++) {
if (!current_drivers[i] || !current_drivers[i]->warm_init)
continue;
rc = current_drivers[i]->warm_init();
if (rc)
return rc;
}
return 0;
}
static int fdt_irqchip_cold_init(void)
{
bool drv_added;
int pos, noff, rc;
struct fdt_irqchip *drv;
const struct fdt_match *match;
void *fdt = fdt_get_address();
for (pos = 0; pos < array_size(irqchip_drivers); pos++) {
drv = irqchip_drivers[pos];
for (pos = 0; pos < fdt_irqchip_drivers_size; pos++) {
drv = fdt_irqchip_drivers[pos];
noff = -1;
drv_added = false;
while ((noff = fdt_find_match(fdt, noff,
drv->match_table, &match)) >= 0) {
if (drv->cold_init) {
@@ -53,10 +69,15 @@ static int fdt_irqchip_cold_init(void)
if (rc)
return rc;
}
current_driver = drv;
if (drv_added)
continue;
current_drivers[current_drivers_count++] = drv;
drv_added = true;
}
if (current_driver)
if (FDT_IRQCHIP_MAX_DRIVERS <= current_drivers_count)
break;
}

View File

@@ -0,0 +1,56 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_error.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
#include <sbi_utils/irqchip/aplic.h>
#define APLIC_MAX_NR 16
static unsigned long aplic_count = 0;
static struct aplic_data aplic[APLIC_MAX_NR];
static int irqchip_aplic_warm_init(void)
{
/* Nothing to do here. */
return 0;
}
static int irqchip_aplic_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct aplic_data *pd;
if (APLIC_MAX_NR <= aplic_count)
return SBI_ENOSPC;
pd = &aplic[aplic_count++];
rc = fdt_parse_aplic_node(fdt, nodeoff, pd);
if (rc)
return rc;
return aplic_cold_irqchip_init(pd);
}
static const struct fdt_match irqchip_aplic_match[] = {
{ .compatible = "riscv,aplic" },
{ },
};
struct fdt_irqchip fdt_irqchip_aplic = {
.match_table = irqchip_aplic_match,
.cold_init = irqchip_aplic_cold_init,
.warm_init = irqchip_aplic_warm_init,
.exit = NULL,
};

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/irqchip/fdt_irqchip.h
TYPE: struct fdt_irqchip
NAME: fdt_irqchip_drivers

View File

@@ -0,0 +1,106 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
#include <sbi_utils/irqchip/imsic.h>
#define IMSIC_MAX_NR 16
static unsigned long imsic_count = 0;
static struct imsic_data imsic[IMSIC_MAX_NR];
static int irqchip_imsic_update_hartid_table(void *fdt, int nodeoff,
struct imsic_data *id)
{
const fdt32_t *val;
u32 phandle, hwirq, hartid;
int i, err, count, cpu_offset, cpu_intc_offset;
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
if (!val || count < sizeof(fdt32_t))
return SBI_EINVAL;
count = count / sizeof(fdt32_t);
for (i = 0; i < count; i += 2) {
phandle = fdt32_to_cpu(val[i]);
hwirq = fdt32_to_cpu(val[i + 1]);
cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
if (cpu_intc_offset < 0)
continue;
cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
if (cpu_offset < 0)
continue;
err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
if (err)
return SBI_EINVAL;
if (SBI_HARTMASK_MAX_BITS <= hartid)
return SBI_EINVAL;
switch (hwirq) {
case IRQ_M_EXT:
err = imsic_map_hartid_to_data(hartid, id, i / 2);
if (err)
return err;
break;
default:
break;
}
}
return 0;
}
static int irqchip_imsic_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct imsic_data *id;
if (IMSIC_MAX_NR <= imsic_count)
return SBI_ENOSPC;
id = &imsic[imsic_count];
rc = fdt_parse_imsic_node(fdt, nodeoff, id);
if (rc)
return rc;
if (!id->targets_mmode)
return 0;
rc = irqchip_imsic_update_hartid_table(fdt, nodeoff, id);
if (rc)
return rc;
rc = imsic_cold_irqchip_init(id);
if (rc)
return rc;
imsic_count++;
return 0;
}
static const struct fdt_match irqchip_imsic_match[] = {
{ .compatible = "riscv,imsics" },
{ },
};
struct fdt_irqchip fdt_irqchip_imsic = {
.match_table = irqchip_imsic_match,
.cold_init = irqchip_imsic_cold_init,
.warm_init = imsic_warm_irqchip_init,
};

View File

@@ -24,6 +24,38 @@ static struct plic_data plic[PLIC_MAX_NR];
static struct plic_data *plic_hartid2data[SBI_HARTMASK_MAX_BITS];
static int plic_hartid2context[SBI_HARTMASK_MAX_BITS][2];
void fdt_plic_priority_save(u8 *priority)
{
struct plic_data *plic = plic_hartid2data[current_hartid()];
plic_priority_save(plic, priority);
}
void fdt_plic_priority_restore(const u8 *priority)
{
struct plic_data *plic = plic_hartid2data[current_hartid()];
plic_priority_restore(plic, priority);
}
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold)
{
u32 hartid = current_hartid();
plic_context_save(plic_hartid2data[hartid],
plic_hartid2context[hartid][smode],
enable, threshold);
}
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold)
{
u32 hartid = current_hartid();
plic_context_restore(plic_hartid2data[hartid],
plic_hartid2context[hartid][smode],
enable, threshold);
}
static int irqchip_plic_warm_init(void)
{
u32 hartid = current_hartid();
@@ -116,7 +148,14 @@ static int irqchip_plic_cold_init(void *fdt, int nodeoff,
static void thead_plic_plat_init(struct plic_data *pd)
{
writel_relaxed(BIT(0), (void *)pd->addr + THEAD_PLIC_CTRL_REG);
writel_relaxed(BIT(0), (char *)pd->addr + THEAD_PLIC_CTRL_REG);
}
void thead_plic_restore(void)
{
struct plic_data *plic = plic_hartid2data[current_hartid()];
thead_plic_plat_init(plic);
}
static const struct fdt_match irqchip_plic_match[] = {

326
lib/utils/irqchip/imsic.c Normal file
View File

@@ -0,0 +1,326 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
* Copyright (c) 2022 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
#include <sbi/sbi_error.h>
#include <sbi_utils/irqchip/imsic.h>
#define IMSIC_MMIO_PAGE_LE 0x00
#define IMSIC_MMIO_PAGE_BE 0x04
#define IMSIC_MIN_ID 63
#define IMSIC_MAX_ID 2047
#define IMSIC_EIDELIVERY 0x70
#define IMSIC_EITHRESHOLD 0x72
#define IMSIC_TOPEI 0x76
#define IMSIC_TOPEI_ID_SHIFT 16
#define IMSIC_TOPEI_ID_MASK 0x7ff
#define IMSIC_TOPEI_PRIO_MASK 0x7ff
#define IMSIC_EIP0 0x80
#define IMSIC_EIP63 0xbf
#define IMSIC_EIPx_BITS 32
#define IMSIC_EIE0 0xc0
#define IMSIC_EIE63 0xff
#define IMSIC_EIEx_BITS 32
#define IMSIC_DISABLE_EIDELIVERY 0
#define IMSIC_ENABLE_EIDELIVERY 1
#define IMSIC_DISABLE_EITHRESHOLD 1
#define IMSIC_ENABLE_EITHRESHOLD 0
#define IMSIC_IPI_ID 1
#define imsic_csr_write(__c, __v) \
do { \
csr_write(CSR_MISELECT, __c); \
csr_write(CSR_MIREG, __v); \
} while (0)
#define imsic_csr_read(__c) \
({ \
unsigned long __v; \
csr_write(CSR_MISELECT, __c); \
__v = csr_read(CSR_MIREG); \
__v; \
})
#define imsic_csr_set(__c, __v) \
do { \
csr_write(CSR_MISELECT, __c); \
csr_set(CSR_MIREG, __v); \
} while (0)
#define imsic_csr_clear(__c, __v) \
do { \
csr_write(CSR_MISELECT, __c); \
csr_clear(CSR_MIREG, __v); \
} while (0)
static struct imsic_data *imsic_hartid2data[SBI_HARTMASK_MAX_BITS];
static int imsic_hartid2file[SBI_HARTMASK_MAX_BITS];
int imsic_map_hartid_to_data(u32 hartid, struct imsic_data *imsic, int file)
{
if (!imsic || !imsic->targets_mmode ||
(SBI_HARTMASK_MAX_BITS <= hartid))
return SBI_EINVAL;
imsic_hartid2data[hartid] = imsic;
imsic_hartid2file[hartid] = file;
return 0;
}
struct imsic_data *imsic_get_data(u32 hartid)
{
if (SBI_HARTMASK_MAX_BITS <= hartid)
return NULL;
return imsic_hartid2data[hartid];
}
int imsic_get_target_file(u32 hartid)
{
if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
!imsic_hartid2data[hartid])
return SBI_ENOENT;
return imsic_hartid2file[hartid];
}
static int imsic_external_irqfn(struct sbi_trap_regs *regs)
{
ulong mirq;
while ((mirq = csr_swap(CSR_MTOPEI, 0))) {
mirq = (mirq >> IMSIC_TOPEI_ID_SHIFT);
switch (mirq) {
case IMSIC_IPI_ID:
sbi_ipi_process();
break;
default:
sbi_printf("%s: unhandled IRQ%d\n",
__func__, (u32)mirq);
break;
}
}
return 0;
}
static void imsic_ipi_send(u32 target_hart)
{
unsigned long reloff;
struct imsic_regs *regs;
struct imsic_data *data = imsic_hartid2data[target_hart];
int file = imsic_hartid2file[target_hart];
if (!data || !data->targets_mmode)
return;
regs = &data->regs[0];
reloff = file * (1UL << data->guest_index_bits) * IMSIC_MMIO_PAGE_SZ;
while (regs->size && (regs->size <= reloff)) {
reloff -= regs->size;
regs++;
}
if (regs->size && (reloff < regs->size))
writel(IMSIC_IPI_ID,
(void *)(regs->addr + reloff + IMSIC_MMIO_PAGE_LE));
}
static struct sbi_ipi_device imsic_ipi_device = {
.name = "aia-imsic",
.ipi_send = imsic_ipi_send
};
static void imsic_local_eix_update(unsigned long base_id,
unsigned long num_id, bool pend, bool val)
{
unsigned long i, isel, ireg;
unsigned long id = base_id, last_id = base_id + num_id;
while (id < last_id) {
isel = id / __riscv_xlen;
isel *= __riscv_xlen / IMSIC_EIPx_BITS;
isel += (pend) ? IMSIC_EIP0 : IMSIC_EIE0;
ireg = 0;
for (i = id & (__riscv_xlen - 1);
(id < last_id) && (i < __riscv_xlen); i++) {
ireg |= BIT(i);
id++;
}
if (val)
imsic_csr_set(isel, ireg);
else
imsic_csr_clear(isel, ireg);
}
}
void imsic_local_irqchip_init(void)
{
/*
* This function is expected to be called from:
* 1) nascent_init() platform callback which is called
* very early on each HART in boot-up path and and
* HSM resume path.
* 2) irqchip_init() platform callback which is called
* in boot-up path.
*/
/* Setup threshold to allow all enabled interrupts */
imsic_csr_write(IMSIC_EITHRESHOLD, IMSIC_ENABLE_EITHRESHOLD);
/* Enable interrupt delivery */
imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_ENABLE_EIDELIVERY);
/* Enable IPI */
imsic_local_eix_update(IMSIC_IPI_ID, 1, false, true);
}
int imsic_warm_irqchip_init(void)
{
struct imsic_data *imsic = imsic_hartid2data[current_hartid()];
/* Sanity checks */
if (!imsic || !imsic->targets_mmode)
return SBI_EINVAL;
/* Disable all interrupts */
imsic_local_eix_update(1, imsic->num_ids, false, false);
/* Clear IPI pending */
imsic_local_eix_update(IMSIC_IPI_ID, 1, true, false);
/* Local IMSIC initialization */
imsic_local_irqchip_init();
return 0;
}
int imsic_data_check(struct imsic_data *imsic)
{
u32 i, tmp;
unsigned long base_addr, addr, mask;
/* Sanity checks */
if (!imsic ||
(imsic->num_ids < IMSIC_MIN_ID) ||
(IMSIC_MAX_ID < imsic->num_ids))
return SBI_EINVAL;
tmp = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT;
if (tmp < imsic->guest_index_bits)
return SBI_EINVAL;
tmp = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT -
imsic->guest_index_bits;
if (tmp < imsic->hart_index_bits)
return SBI_EINVAL;
tmp = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT -
imsic->guest_index_bits - imsic->hart_index_bits;
if (tmp < imsic->group_index_bits)
return SBI_EINVAL;
tmp = IMSIC_MMIO_PAGE_SHIFT + imsic->guest_index_bits +
imsic->hart_index_bits;
if (imsic->group_index_shift < tmp)
return SBI_EINVAL;
tmp = imsic->group_index_bits + imsic->group_index_shift - 1;
if (tmp >= BITS_PER_LONG)
return SBI_EINVAL;
/*
* Number of interrupt identities should be 1 less than
* multiple of 63
*/
if ((imsic->num_ids & IMSIC_MIN_ID) != IMSIC_MIN_ID)
return SBI_EINVAL;
/* We should have at least one regset */
if (!imsic->regs[0].size)
return SBI_EINVAL;
/* Match patter of each regset */
base_addr = imsic->regs[0].addr;
base_addr &= ~((1UL << (imsic->guest_index_bits +
imsic->hart_index_bits +
IMSIC_MMIO_PAGE_SHIFT)) - 1);
base_addr &= ~(((1UL << imsic->group_index_bits) - 1) <<
imsic->group_index_shift);
for (i = 0; i < IMSIC_MAX_REGS && imsic->regs[i].size; i++) {
mask = (1UL << imsic->guest_index_bits) * IMSIC_MMIO_PAGE_SZ;
mask -= 1UL;
if (imsic->regs[i].size & mask)
return SBI_EINVAL;
addr = imsic->regs[i].addr;
addr &= ~((1UL << (imsic->guest_index_bits +
imsic->hart_index_bits +
IMSIC_MMIO_PAGE_SHIFT)) - 1);
addr &= ~(((1UL << imsic->group_index_bits) - 1) <<
imsic->group_index_shift);
if (base_addr != addr)
return SBI_EINVAL;
}
return 0;
}
int imsic_cold_irqchip_init(struct imsic_data *imsic)
{
int i, rc;
struct sbi_domain_memregion reg;
/* Sanity checks */
rc = imsic_data_check(imsic);
if (rc)
return rc;
/* We only initialize M-mode IMSIC */
if (!imsic->targets_mmode)
return SBI_EINVAL;
/* Setup external interrupt function for IMSIC */
sbi_irqchip_set_irqfn(imsic_external_irqfn);
/* Add IMSIC regions to the root domain */
for (i = 0; i < IMSIC_MAX_REGS && imsic->regs[i].size; i++) {
sbi_domain_memregion_init(imsic->regs[i].addr,
imsic->regs[i].size,
SBI_DOMAIN_MEMREGION_MMIO, &reg);
rc = sbi_domain_root_add_memregion(&reg);
if (rc)
return rc;
}
/* Register IPI device */
sbi_ipi_set_device(&imsic_ipi_device);
return 0;
}

View File

@@ -8,5 +8,17 @@
#
libsbiutils-objs-y += irqchip/fdt_irqchip.o
libsbiutils-objs-y += irqchip/fdt_irqchip_drivers.o
carray-fdt_irqchip_drivers-y += fdt_irqchip_aplic
libsbiutils-objs-y += irqchip/fdt_irqchip_aplic.o
carray-fdt_irqchip_drivers-y += fdt_irqchip_imsic
libsbiutils-objs-y += irqchip/fdt_irqchip_imsic.o
carray-fdt_irqchip_drivers-y += fdt_irqchip_plic
libsbiutils-objs-y += irqchip/fdt_irqchip_plic.o
libsbiutils-objs-y += irqchip/aplic.o
libsbiutils-objs-y += irqchip/imsic.o
libsbiutils-objs-y += irqchip/plic.o

View File

@@ -5,6 +5,7 @@
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
* Samuel Holland <samuel@sholland.org>
*/
#include <sbi/riscv_io.h>
@@ -21,71 +22,138 @@
#define PLIC_CONTEXT_BASE 0x200000
#define PLIC_CONTEXT_STRIDE 0x1000
static void plic_set_priority(struct plic_data *plic, u32 source, u32 val)
static u32 plic_get_priority(const struct plic_data *plic, u32 source)
{
volatile void *plic_priority = (void *)plic->addr +
volatile void *plic_priority = (char *)plic->addr +
PLIC_PRIORITY_BASE + 4 * source;
return readl(plic_priority);
}
static void plic_set_priority(const struct plic_data *plic, u32 source, u32 val)
{
volatile void *plic_priority = (char *)plic->addr +
PLIC_PRIORITY_BASE + 4 * source;
writel(val, plic_priority);
}
void plic_set_thresh(struct plic_data *plic, u32 cntxid, u32 val)
void plic_priority_save(const struct plic_data *plic, u8 *priority)
{
for (u32 i = 0; i < plic->num_src; i++)
priority[i] = plic_get_priority(plic, i);
}
void plic_priority_restore(const struct plic_data *plic, const u8 *priority)
{
for (u32 i = 0; i < plic->num_src; i++)
plic_set_priority(plic, i, priority[i]);
}
static u32 plic_get_thresh(const struct plic_data *plic, u32 cntxid)
{
volatile void *plic_thresh;
if (!plic)
return;
plic_thresh = (char *)plic->addr +
PLIC_CONTEXT_BASE + PLIC_CONTEXT_STRIDE * cntxid;
plic_thresh = (void *)plic->addr +
return readl(plic_thresh);
}
static void plic_set_thresh(const struct plic_data *plic, u32 cntxid, u32 val)
{
volatile void *plic_thresh;
plic_thresh = (char *)plic->addr +
PLIC_CONTEXT_BASE + PLIC_CONTEXT_STRIDE * cntxid;
writel(val, plic_thresh);
}
void plic_set_ie(struct plic_data *plic, u32 cntxid, u32 word_index, u32 val)
static u32 plic_get_ie(const struct plic_data *plic, u32 cntxid,
u32 word_index)
{
volatile void *plic_ie;
if (!plic)
return;
plic_ie = (char *)plic->addr +
PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid +
4 * word_index;
plic_ie = (void *)plic->addr +
PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid;
writel(val, plic_ie + word_index * 4);
return readl(plic_ie);
}
int plic_warm_irqchip_init(struct plic_data *plic,
int m_cntx_id, int s_cntx_id)
static void plic_set_ie(const struct plic_data *plic, u32 cntxid,
u32 word_index, u32 val)
{
size_t i, ie_words;
volatile void *plic_ie;
if (!plic)
plic_ie = (char *)plic->addr +
PLIC_ENABLE_BASE + PLIC_ENABLE_STRIDE * cntxid +
4 * word_index;
writel(val, plic_ie);
}
void plic_context_save(const struct plic_data *plic, int context_id,
u32 *enable, u32 *threshold)
{
u32 ie_words = (plic->num_src + 31) / 32;
for (u32 i = 0; i < ie_words; i++)
enable[i] = plic_get_ie(plic, context_id, i);
*threshold = plic_get_thresh(plic, context_id);
}
void plic_context_restore(const struct plic_data *plic, int context_id,
const u32 *enable, u32 threshold)
{
u32 ie_words = (plic->num_src + 31) / 32;
for (u32 i = 0; i < ie_words; i++)
plic_set_ie(plic, context_id, i, enable[i]);
plic_set_thresh(plic, context_id, threshold);
}
int plic_context_init(const struct plic_data *plic, int context_id,
bool enable, u32 threshold)
{
u32 ie_words, ie_value;
if (!plic || context_id < 0)
return SBI_EINVAL;
ie_words = plic->num_src / 32 + 1;
ie_words = (plic->num_src + 31) / 32;
ie_value = enable ? 0xffffffffU : 0U;
/* By default, disable all IRQs for M-mode of target HART */
if (m_cntx_id > -1) {
for (i = 0; i < ie_words; i++)
plic_set_ie(plic, m_cntx_id, i, 0);
}
for (u32 i = 0; i < ie_words; i++)
plic_set_ie(plic, context_id, i, ie_value);
/* By default, disable all IRQs for S-mode of target HART */
if (s_cntx_id > -1) {
for (i = 0; i < ie_words; i++)
plic_set_ie(plic, s_cntx_id, i, 0);
}
/* By default, disable M-mode threshold */
if (m_cntx_id > -1)
plic_set_thresh(plic, m_cntx_id, 0x7);
/* By default, disable S-mode threshold */
if (s_cntx_id > -1)
plic_set_thresh(plic, s_cntx_id, 0x7);
plic_set_thresh(plic, context_id, threshold);
return 0;
}
int plic_cold_irqchip_init(struct plic_data *plic)
int plic_warm_irqchip_init(const struct plic_data *plic,
int m_cntx_id, int s_cntx_id)
{
int ret;
/* By default, disable all IRQs for M-mode of target HART */
if (m_cntx_id > -1) {
ret = plic_context_init(plic, m_cntx_id, false, 0x7);
if (ret)
return ret;
}
/* By default, disable all IRQs for S-mode of target HART */
if (s_cntx_id > -1) {
ret = plic_context_init(plic, s_cntx_id, false, 0x7);
if (ret)
return ret;
}
return 0;
}
int plic_cold_irqchip_init(const struct plic_data *plic)
{
int i;

View File

@@ -13,21 +13,9 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/reset/fdt_reset.h>
extern struct fdt_reset fdt_poweroff_gpio;
extern struct fdt_reset fdt_reset_gpio;
extern struct fdt_reset fdt_reset_htif;
extern struct fdt_reset fdt_reset_sifive_test;
extern struct fdt_reset fdt_reset_sunxi_wdt;
extern struct fdt_reset fdt_reset_thead;
static struct fdt_reset *reset_drivers[] = {
&fdt_poweroff_gpio,
&fdt_reset_gpio,
&fdt_reset_htif,
&fdt_reset_sifive_test,
&fdt_reset_sunxi_wdt,
&fdt_reset_thead,
};
/* List of FDT reset drivers generated at compile time */
extern struct fdt_reset *fdt_reset_drivers[];
extern unsigned long fdt_reset_drivers_size;
int fdt_reset_driver_init(void *fdt, struct fdt_reset *drv)
{
@@ -54,6 +42,6 @@ void fdt_reset_init(void)
int pos;
void *fdt = fdt_get_address();
for (pos = 0; pos < array_size(reset_drivers); pos++)
fdt_reset_driver_init(fdt, reset_drivers[pos]);
for (pos = 0; pos < fdt_reset_drivers_size; pos++)
fdt_reset_driver_init(fdt, fdt_reset_drivers[pos]);
}

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/reset/fdt_reset.h
TYPE: struct fdt_reset
NAME: fdt_reset_drivers

View File

@@ -149,7 +149,7 @@ static int gpio_reset_init(void *fdt, int nodeoff,
}
static const struct fdt_match gpio_poweroff_match[] = {
{ .compatible = "gpio-poweroff", .data = (void *)FALSE },
{ .compatible = "gpio-poweroff", .data = (const void *)FALSE },
{ },
};
@@ -159,7 +159,7 @@ struct fdt_reset fdt_poweroff_gpio = {
};
static const struct fdt_match gpio_reset_match[] = {
{ .compatible = "gpio-restart", .data = (void *)TRUE },
{ .compatible = "gpio-restart", .data = (const void *)TRUE },
{ },
};

View File

@@ -14,7 +14,17 @@
static int htif_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
return htif_system_reset_init();
bool custom = false;
uint64_t fromhost_addr = 0, tohost_addr = 0;
if (!fdt_get_node_addr_size(fdt, nodeoff, 0, &fromhost_addr, NULL)) {
custom = true;
tohost_addr = fromhost_addr + sizeof(uint64_t);
}
fdt_get_node_addr_size(fdt, nodeoff, 1, &tohost_addr, NULL);
return htif_system_reset_init(custom, fromhost_addr, tohost_addr);
}
static const struct fdt_match htif_reset_match[] = {

View File

@@ -19,7 +19,7 @@
#define WDT_MODE_REG 0x18
static volatile void *sunxi_wdt_base;
static volatile char *sunxi_wdt_base;
static int sunxi_wdt_system_reset_check(u32 type, u32 reason)
{
@@ -59,7 +59,7 @@ static int sunxi_wdt_reset_init(void *fdt, int nodeoff,
if (rc < 0 || !reg_addr)
return SBI_ENODEV;
sunxi_wdt_base = (volatile void *)(unsigned long)reg_addr;
sunxi_wdt_base = (volatile char *)(unsigned long)reg_addr;
sbi_system_reset_add_device(&sunxi_wdt_reset);

View File

@@ -59,7 +59,7 @@ extern void __thead_pre_start_warm(void);
static int thead_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
void *p;
char *p;
const fdt64_t *val;
const fdt32_t *val_w;
int len, i;
@@ -91,7 +91,7 @@ static int thead_reset_init(void *fdt, int nodeoff,
/* Custom reset method for secondary harts */
val = fdt_getprop(fdt, nodeoff, "entry-reg", &len);
if (len > 0 && val) {
p = (void *)(ulong)fdt64_to_cpu(*val);
p = (char *)(ulong)fdt64_to_cpu(*val);
val_w = fdt_getprop(fdt, nodeoff, "entry-cnt", &len);
if (len > 0 && val_w) {

View File

@@ -8,9 +8,21 @@
#
libsbiutils-objs-y += reset/fdt_reset.o
libsbiutils-objs-y += reset/fdt_reset_drivers.o
carray-fdt_reset_drivers-y += fdt_poweroff_gpio
carray-fdt_reset_drivers-y += fdt_reset_gpio
libsbiutils-objs-y += reset/fdt_reset_gpio.o
carray-fdt_reset_drivers-y += fdt_reset_htif
libsbiutils-objs-y += reset/fdt_reset_htif.o
carray-fdt_reset_drivers-y += fdt_reset_sifive_test
libsbiutils-objs-y += reset/fdt_reset_sifive_test.o
carray-fdt_reset_drivers-y += fdt_reset_sunxi_wdt
libsbiutils-objs-y += reset/fdt_reset_sunxi_wdt.o
carray-fdt_reset_drivers-y += fdt_reset_thead
libsbiutils-objs-y += reset/fdt_reset_thead.o
libsbiutils-objs-y += reset/fdt_reset_thead_asm.o

View File

@@ -13,21 +13,9 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
extern struct fdt_serial fdt_serial_uart8250;
extern struct fdt_serial fdt_serial_sifive;
extern struct fdt_serial fdt_serial_litex;
extern struct fdt_serial fdt_serial_htif;
extern struct fdt_serial fdt_serial_shakti;
extern struct fdt_serial fdt_serial_gaisler;
static struct fdt_serial *serial_drivers[] = {
&fdt_serial_uart8250,
&fdt_serial_sifive,
&fdt_serial_litex,
&fdt_serial_htif,
&fdt_serial_shakti,
&fdt_serial_gaisler
};
/* List of FDT serial drivers generated at compile time */
extern struct fdt_serial *fdt_serial_drivers[];
extern unsigned long fdt_serial_drivers_size;
static struct fdt_serial dummy = {
.match_table = NULL,
@@ -62,8 +50,8 @@ int fdt_serial_init(void)
}
/* First check DT node pointed by stdout-path */
for (pos = 0; pos < array_size(serial_drivers) && -1 < noff; pos++) {
drv = serial_drivers[pos];
for (pos = 0; pos < fdt_serial_drivers_size && -1 < noff; pos++) {
drv = fdt_serial_drivers[pos];
match = fdt_match_node(fdt, noff, drv->match_table);
if (!match)
@@ -85,8 +73,8 @@ int fdt_serial_init(void)
goto done;
/* Lastly check all DT nodes */
for (pos = 0; pos < array_size(serial_drivers); pos++) {
drv = serial_drivers[pos];
for (pos = 0; pos < fdt_serial_drivers_size; pos++) {
drv = fdt_serial_drivers[pos];
noff = fdt_find_match(fdt, -1, drv->match_table, &match);
if (noff < 0)

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/serial/fdt_serial.h
TYPE: struct fdt_serial
NAME: fdt_serial_drivers

View File

@@ -19,7 +19,17 @@ static const struct fdt_match serial_htif_match[] = {
static int serial_htif_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
return htif_serial_init();
bool custom = false;
uint64_t fromhost_addr = 0, tohost_addr = 0;
if (!fdt_get_node_addr_size(fdt, nodeoff, 0, &fromhost_addr, NULL)) {
custom = true;
tohost_addr = fromhost_addr + sizeof(uint64_t);
}
fdt_get_node_addr_size(fdt, nodeoff, 1, &tohost_addr, NULL);
return htif_serial_init(custom, fromhost_addr, tohost_addr);
}
struct fdt_serial fdt_serial_htif = {

View File

@@ -22,7 +22,8 @@ static int serial_uart8250_init(void *fdt, int nodeoff,
return rc;
return uart8250_init(uart.addr, uart.freq, uart.baud,
uart.reg_shift, uart.reg_io_width);
uart.reg_shift, uart.reg_io_width,
uart.reg_offset);
}
static const struct fdt_match serial_uart8250_match[] = {

View File

@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Western Digital Corporation or its affiliates.
*
* Authors:
* Alistair Francis <alistair.francis@wdc.com>
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/serial/xlnx_uartlite.h>
static int serial_xlnx_uartlite_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct platform_uart_data uart;
rc = fdt_parse_xlnx_uartlite_node(fdt, nodeoff, &uart);
if (rc)
return rc;
return xlnx_uartlite_init(uart.addr);
}
static const struct fdt_match serial_xlnx_uartlite_match[] = {
{ .compatible = "xlnx,xps-uartlite-1.00.a" },
{ },
};
struct fdt_serial fdt_serial_xlnx_uartlite = {
.match_table = serial_xlnx_uartlite_match,
.init = serial_xlnx_uartlite_init,
};

View File

@@ -29,7 +29,7 @@
/* clang-format on */
static volatile void *uart_base;
static volatile char *uart_base;
static u32 get_reg(u32 num)
{
@@ -67,7 +67,7 @@ int gaisler_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
{
u32 ctrl;
uart_base = (volatile void *)base;
uart_base = (volatile char *)base;
/* Configure baudrate */
if (in_freq)

View File

@@ -8,14 +8,32 @@
#
libsbiutils-objs-y += serial/fdt_serial.o
libsbiutils-objs-y += serial/fdt_serial_drivers.o
carray-fdt_serial_drivers-y += fdt_serial_gaisler
libsbiutils-objs-y += serial/fdt_serial_gaisler.o
carray-fdt_serial_drivers-y += fdt_serial_htif
libsbiutils-objs-y += serial/fdt_serial_htif.o
carray-fdt_serial_drivers-y += fdt_serial_shakti
libsbiutils-objs-y += serial/fdt_serial_shakti.o
carray-fdt_serial_drivers-y += fdt_serial_sifive
libsbiutils-objs-y += serial/fdt_serial_sifive.o
carray-fdt_serial_drivers-y += fdt_serial_litex
libsbiutils-objs-y += serial/fdt_serial_litex.o
carray-fdt_serial_drivers-y += fdt_serial_uart8250
libsbiutils-objs-y += serial/fdt_serial_uart8250.o
carray-fdt_serial_drivers-y += fdt_serial_xlnx_uartlite
libsbiutils-objs-y += serial/fdt_serial_xlnx_uartlite.o
libsbiutils-objs-y += serial/gaisler-uart.o
libsbiutils-objs-y += serial/shakti-uart.o
libsbiutils-objs-y += serial/sifive-uart.o
libsbiutils-objs-y += serial/litex-uart.o
libsbiutils-objs-y += serial/uart8250.o
libsbiutils-objs-y += serial/xlnx-uartlite.o

View File

@@ -21,7 +21,7 @@
#define UART_TX_FULL 0x2
#define UART_RX_FULL 0x8
static volatile void *uart_base;
static volatile char *uart_base;
static void shakti_uart_putc(char ch)
{
@@ -46,7 +46,7 @@ static struct sbi_console_device shakti_console = {
int shakti_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
{
uart_base = (volatile void *)base;
uart_base = (volatile char *)base;
u16 baud = (u16)(in_freq/(16 * baudrate));
writew(baud, uart_base + REG_BAUD);

View File

@@ -29,7 +29,7 @@
/* clang-format on */
static volatile void *uart_base;
static volatile char *uart_base;
static u32 uart_in_freq;
static u32 uart_baudrate;
@@ -90,7 +90,7 @@ static struct sbi_console_device sifive_console = {
int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
{
uart_base = (volatile void *)base;
uart_base = (volatile char *)base;
uart_in_freq = in_freq;
uart_baudrate = baudrate;

View File

@@ -39,7 +39,7 @@
/* clang-format on */
static volatile void *uart8250_base;
static volatile char *uart8250_base;
static u32 uart8250_in_freq;
static u32 uart8250_baudrate;
static u32 uart8250_reg_width;
@@ -91,17 +91,17 @@ static struct sbi_console_device uart8250_console = {
};
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
u32 reg_width)
u32 reg_width, u32 reg_offset)
{
u16 bdiv;
uart8250_base = (volatile void *)base;
uart8250_base = (volatile char *)base + reg_offset;
uart8250_reg_shift = reg_shift;
uart8250_reg_width = reg_width;
uart8250_in_freq = in_freq;
uart8250_baudrate = baudrate;
bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) / (16 * uart8250_baudrate);
/* Disable all interrupts */
set_reg(UART_IER_OFFSET, 0x00);

View File

@@ -0,0 +1,67 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Western Digital Corporation or its affiliates.
*
* Authors:
* Alistair Francis <alistair.francis@wdc.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/serial/xlnx_uartlite.h>
/* clang-format off */
#define UART_RX_OFFSET 0x00
#define UART_TX_OFFSET 0x04
#define UART_STATUS_OFFSET 0x08
# define UART_STATUS_RXVALID 0x01
# define UART_STATUS_RXFULL 0x02
# define UART_STATUS_TXEMPTY 0x04
# define UART_STATUS_TXFULL 0x08
# define UART_STATUS_IE 0x10
# define UART_STATUS_OVERRUN 0x20
# define UART_STATUS_FRAME 0x40
# define UART_STATUS_PARITY 0x80
#define UART_CTRL_OFFSET 0x0C
# define UART_CTRL_RST_TX 0x01
# define UART_CTRL_RST_RX 0x02
# define UART_CTRL_IE 0x10
/* clang-format on */
static volatile char *xlnx_uartlite_base;
static void xlnx_uartlite_putc(char ch)
{
while((readb(xlnx_uartlite_base + UART_STATUS_OFFSET) & UART_STATUS_TXFULL))
;
writeb(ch, xlnx_uartlite_base + UART_TX_OFFSET);
}
static int xlnx_uartlite_getc(void)
{
u16 status = readb(xlnx_uartlite_base + UART_STATUS_OFFSET);
if (status & UART_STATUS_RXVALID)
return readb(xlnx_uartlite_base + UART_RX_OFFSET);
return -1;
}
static struct sbi_console_device xlnx_uartlite_console = {
.name = "xlnx-uartlite",
.console_putc = xlnx_uartlite_putc,
.console_getc = xlnx_uartlite_getc
};
int xlnx_uartlite_init(unsigned long base)
{
xlnx_uartlite_base = (volatile char *)base;
sbi_console_set_device(&xlnx_uartlite_console);
return 0;
}

View File

@@ -7,6 +7,7 @@
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_system.h>
#include <sbi_utils/sys/htif.h>
@@ -47,15 +48,46 @@
volatile uint64_t tohost __attribute__((section(".htif")));
volatile uint64_t fromhost __attribute__((section(".htif")));
static uint64_t *htif_fromhost = NULL;
static uint64_t *htif_tohost = NULL;
static bool htif_custom = false;
static int htif_console_buf;
static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
static inline uint64_t __read_tohost(void)
{
return (htif_custom) ? *htif_tohost : tohost;
}
static inline void __write_tohost(uint64_t val)
{
if (htif_custom)
*htif_tohost = val;
else
tohost = val;
}
static inline uint64_t __read_fromhost(void)
{
return (htif_custom) ? *htif_fromhost : fromhost;
}
static inline void __write_fromhost(uint64_t val)
{
if (htif_custom)
*htif_fromhost = val;
else
fromhost = val;
}
static void __check_fromhost()
{
uint64_t fh = fromhost;
uint64_t fh = __read_fromhost();
if (!fh)
return;
fromhost = 0;
__write_fromhost(0);
/* this should be from the console */
if (FROMHOST_DEV(fh) != HTIF_DEV_CONSOLE)
@@ -73,9 +105,26 @@ static void __check_fromhost()
static void __set_tohost(uint64_t dev, uint64_t cmd, uint64_t data)
{
while (tohost)
while (__read_tohost())
__check_fromhost();
tohost = TOHOST_CMD(dev, cmd, data);
__write_tohost(TOHOST_CMD(dev, cmd, data));
}
static int set_custom_addr(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr)
{
if (custom_addr) {
if (htif_custom &&
((custom_fromhost_addr != (unsigned long)htif_fromhost) ||
(custom_tohost_addr != (unsigned long)htif_tohost)))
return SBI_EINVAL;
htif_fromhost = (uint64_t *)custom_fromhost_addr;
htif_tohost = (uint64_t *)custom_tohost_addr;
htif_custom = true;
}
return 0;
}
#if __riscv_xlen == 32
@@ -148,10 +197,18 @@ static struct sbi_console_device htif_console = {
.console_getc = htif_getc
};
int htif_serial_init(void)
int htif_serial_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr)
{
sbi_console_set_device(&htif_console);
int rc;
rc = set_custom_addr(custom_addr, custom_fromhost_addr,
custom_tohost_addr);
if (rc)
return rc;
sbi_console_set_device(&htif_console);
return 0;
}
@@ -163,8 +220,8 @@ static int htif_system_reset_check(u32 type, u32 reason)
static void htif_system_reset(u32 type, u32 reason)
{
while (1) {
fromhost = 0;
tohost = 1;
__write_fromhost(0);
__write_tohost(1);
}
}
@@ -174,9 +231,17 @@ static struct sbi_system_reset_device htif_reset = {
.system_reset = htif_system_reset
};
int htif_system_reset_init(void)
int htif_system_reset_init(bool custom_addr,
unsigned long custom_fromhost_addr,
unsigned long custom_tohost_addr)
{
sbi_system_reset_add_device(&htif_reset);
int rc;
rc = set_custom_addr(custom_addr, custom_fromhost_addr,
custom_tohost_addr);
if (rc)
return rc;
sbi_system_reset_add_device(&htif_reset);
return 0;
}

View File

@@ -47,7 +47,7 @@ static u64 mtimer_time_rd32(volatile u64 *addr)
static void mtimer_time_wr32(bool timecmp, u64 value, volatile u64 *addr)
{
writel_relaxed((timecmp) ? -1U : 0U, (void *)(addr));
writel_relaxed((u32)(value >> 32), (void *)(addr) + 0x04);
writel_relaxed((u32)(value >> 32), (char *)(addr) + 0x04);
writel_relaxed((u32)value, (void *)(addr));
}
@@ -154,7 +154,7 @@ static int aclint_mtimer_add_regions(unsigned long addr, unsigned long size)
while (pos < end) {
rsize = pos & (MTIMER_ADD_REGION_ALIGN - 1);
if (rsize)
rsize = 1UL << __ffs(pos);
rsize = 1UL << sbi_ffs(pos);
else
rsize = ((end - pos) < MTIMER_ADD_REGION_ALIGN) ?
(end - pos) : MTIMER_ADD_REGION_ALIGN;

View File

@@ -12,11 +12,9 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/timer/fdt_timer.h>
extern struct fdt_timer fdt_timer_mtimer;
static struct fdt_timer *timer_drivers[] = {
&fdt_timer_mtimer
};
/* List of FDT timer drivers generated at compile time */
extern struct fdt_timer *fdt_timer_drivers[];
extern unsigned long fdt_timer_drivers_size;
static struct fdt_timer dummy = {
.match_table = NULL,
@@ -47,8 +45,8 @@ static int fdt_timer_cold_init(void)
const struct fdt_match *match;
void *fdt = fdt_get_address();
for (pos = 0; pos < array_size(timer_drivers); pos++) {
drv = timer_drivers[pos];
for (pos = 0; pos < fdt_timer_drivers_size; pos++) {
drv = fdt_timer_drivers[pos];
noff = -1;
while ((noff = fdt_find_match(fdt, noff,

View File

@@ -0,0 +1,3 @@
HEADER: sbi_utils/timer/fdt_timer.h
TYPE: struct fdt_timer
NAME: fdt_timer_drivers

View File

@@ -15,6 +15,11 @@
#define MTIMER_MAX_NR 16
struct timer_mtimer_quirks {
unsigned int mtime_offset;
bool has_64bit_mmio;
};
static unsigned long mtimer_count = 0;
static struct aclint_mtimer_data mtimer[MTIMER_MAX_NR];
static struct aclint_mtimer_data *mt_reference = NULL;
@@ -23,7 +28,7 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int i, rc;
unsigned long offset, addr[2], size[2];
unsigned long addr[2], size[2];
struct aclint_mtimer_data *mt;
if (MTIMER_MAX_NR <= mtimer_count)
@@ -43,28 +48,25 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
return rc;
if (match->data) { /* SiFive CLINT */
const struct timer_mtimer_quirks *quirks = match->data;
/* Set CLINT addresses */
mt->mtimecmp_addr = addr[0] + ACLINT_DEFAULT_MTIMECMP_OFFSET;
mt->mtimecmp_size = ACLINT_DEFAULT_MTIMECMP_SIZE;
mt->mtime_addr = addr[0] + ACLINT_DEFAULT_MTIME_OFFSET;
mt->mtime_size = size[0] - mt->mtimecmp_size;
/* Adjust MTIMER address and size for CLINT device */
offset = *((unsigned long *)match->data);
mt->mtime_addr += offset;
mt->mtimecmp_addr += offset;
mt->mtime_size -= offset;
/* Parse additional CLINT properties */
if (fdt_getprop(fdt, nodeoff, "clint,has-no-64bit-mmio", &rc))
mt->has_64bit_mmio = false;
mt->mtime_addr += quirks->mtime_offset;
mt->mtimecmp_addr += quirks->mtime_offset;
mt->mtime_size -= quirks->mtime_offset;
/* Apply additional CLINT quirks */
mt->has_64bit_mmio = quirks->has_64bit_mmio;
} else { /* RISC-V ACLINT MTIMER */
/* Set ACLINT MTIMER addresses */
mt->mtime_addr = addr[0];
mt->mtime_size = size[0];
mt->mtimecmp_addr = addr[1];
mt->mtimecmp_size = size[1];
/* Parse additional ACLINT MTIMER properties */
if (fdt_getprop(fdt, nodeoff, "mtimer,no-64bit-mmio", &rc))
mt->has_64bit_mmio = false;
}
/* Check if MTIMER device has shared MTIME address */
@@ -107,11 +109,14 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
return 0;
}
static unsigned long clint_offset = CLINT_MTIMER_OFFSET;
static const struct timer_mtimer_quirks sifive_clint_quirks = {
.mtime_offset = CLINT_MTIMER_OFFSET,
.has_64bit_mmio = true,
};
static const struct fdt_match timer_mtimer_match[] = {
{ .compatible = "riscv,clint0", .data = &clint_offset },
{ .compatible = "sifive,clint0", .data = &clint_offset },
{ .compatible = "riscv,clint0", .data = &sifive_clint_quirks },
{ .compatible = "sifive,clint0", .data = &sifive_clint_quirks },
{ .compatible = "riscv,aclint-mtimer" },
{ },
};

View File

@@ -8,5 +8,9 @@
#
libsbiutils-objs-y += timer/aclint_mtimer.o
libsbiutils-objs-y += timer/fdt_timer.o
libsbiutils-objs-y += timer/fdt_timer_drivers.o
carray-fdt_timer_drivers-y += fdt_timer_mtimer
libsbiutils-objs-y += timer/fdt_timer_mtimer.o

View File

@@ -69,7 +69,8 @@ static int ae350_console_init(void)
AE350_UART_FREQUENCY,
AE350_UART_BAUDRATE,
AE350_UART_REG_SHIFT,
AE350_UART_REG_WIDTH);
AE350_UART_REG_WIDTH,
AE350_UART_REG_OFFSET);
}
/* Initialize the platform interrupt controller for current HART. */

View File

@@ -28,6 +28,7 @@
#define AE350_UART_BAUDRATE 38400
#define AE350_UART_REG_SHIFT 2
#define AE350_UART_REG_WIDTH 0
#define AE350_UART_REG_OFFSET 0
/*Memory and Miscellaneous Registers*/
#define CSR_MILMB 0x7c0

View File

@@ -23,6 +23,7 @@
#define ARIANE_UART_BAUDRATE 115200
#define ARIANE_UART_REG_SHIFT 2
#define ARIANE_UART_REG_WIDTH 4
#define ARIANE_UART_REG_OFFSET 0
#define ARIANE_PLIC_ADDR 0xc000000
#define ARIANE_PLIC_NUM_SOURCES 3
#define ARIANE_HART_COUNT 1
@@ -92,29 +93,27 @@ static int ariane_console_init(void)
ARIANE_UART_FREQ,
ARIANE_UART_BAUDRATE,
ARIANE_UART_REG_SHIFT,
ARIANE_UART_REG_WIDTH);
ARIANE_UART_REG_WIDTH,
ARIANE_UART_REG_OFFSET);
}
static int plic_ariane_warm_irqchip_init(int m_cntx_id, int s_cntx_id)
{
size_t i, ie_words = ARIANE_PLIC_NUM_SOURCES / 32 + 1;
int ret;
/* By default, enable all IRQs for M-mode of target HART */
if (m_cntx_id > -1) {
for (i = 0; i < ie_words; i++)
plic_set_ie(&plic, m_cntx_id, i, 1);
ret = plic_context_init(&plic, m_cntx_id, true, 0x1);
if (ret)
return ret;
}
/* Enable all IRQs for S-mode of target HART */
if (s_cntx_id > -1) {
for (i = 0; i < ie_words; i++)
plic_set_ie(&plic, s_cntx_id, i, 1);
ret = plic_context_init(&plic, s_cntx_id, true, 0x0);
if (ret)
return ret;
}
/* By default, enable M-mode threshold */
if (m_cntx_id > -1)
plic_set_thresh(&plic, m_cntx_id, 1);
/* By default, disable S-mode threshold */
if (s_cntx_id > -1)
plic_set_thresh(&plic, s_cntx_id, 0);
return 0;
}

View File

@@ -22,6 +22,7 @@
#define OPENPITON_DEFAULT_UART_BAUDRATE 115200
#define OPENPITON_DEFAULT_UART_REG_SHIFT 0
#define OPENPITON_DEFAULT_UART_REG_WIDTH 1
#define OPENPITON_DEFAULT_UART_REG_OFFSET 0
#define OPENPITON_DEFAULT_PLIC_ADDR 0xfff1100000
#define OPENPITON_DEFAULT_PLIC_NUM_SOURCES 2
#define OPENPITON_DEFAULT_HART_COUNT 3
@@ -127,29 +128,27 @@ static int openpiton_console_init(void)
uart.freq,
uart.baud,
OPENPITON_DEFAULT_UART_REG_SHIFT,
OPENPITON_DEFAULT_UART_REG_WIDTH);
OPENPITON_DEFAULT_UART_REG_WIDTH,
OPENPITON_DEFAULT_UART_REG_OFFSET);
}
static int plic_openpiton_warm_irqchip_init(int m_cntx_id, int s_cntx_id)
{
size_t i, ie_words = plic.num_src / 32 + 1;
int ret;
/* By default, enable all IRQs for M-mode of target HART */
if (m_cntx_id > -1) {
for (i = 0; i < ie_words; i++)
plic_set_ie(&plic, m_cntx_id, i, 1);
ret = plic_context_init(&plic, m_cntx_id, true, 0x1);
if (ret)
return ret;
}
/* Enable all IRQs for S-mode of target HART */
if (s_cntx_id > -1) {
for (i = 0; i < ie_words; i++)
plic_set_ie(&plic, s_cntx_id, i, 1);
ret = plic_context_init(&plic, s_cntx_id, true, 0x0);
if (ret)
return ret;
}
/* By default, enable M-mode threshold */
if (m_cntx_id > -1)
plic_set_thresh(&plic, m_cntx_id, 1);
/* By default, disable S-mode threshold */
if (s_cntx_id > -1)
plic_set_thresh(&plic, s_cntx_id, 0);
return 0;
}

View File

@@ -0,0 +1,6 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
carray-platform_override_modules-y += sun20i_d1
platform-objs-y += allwinner/sun20i-d1.o

View File

@@ -0,0 +1,210 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Samuel Holland <samuel@sholland.org>
*/
#include <platform_override.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hsm.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip_plic.h>
#define SUN20I_D1_CCU_BASE ((void *)0x02001000)
#define SUN20I_D1_RISCV_CFG_BASE ((void *)0x06010000)
#define SUN20I_D1_PPU_BASE ((void *)0x07001000)
#define SUN20I_D1_PRCM_BASE ((void *)0x07010000)
/*
* CCU
*/
#define CCU_BGR_ENABLE (BIT(16) | BIT(0))
#define RISCV_CFG_BGR_REG 0xd0c
#define PPU_BGR_REG 0x1ac
/*
* CSRs
*/
#define CSR_MXSTATUS 0x7c0
#define CSR_MHCR 0x7c1
#define CSR_MCOR 0x7c2
#define CSR_MHINT 0x7c5
static unsigned long csr_mxstatus;
static unsigned long csr_mhcr;
static unsigned long csr_mhint;
static void sun20i_d1_csr_save(void)
{
/* Save custom CSRs. */
csr_mxstatus = csr_read(CSR_MXSTATUS);
csr_mhcr = csr_read(CSR_MHCR);
csr_mhint = csr_read(CSR_MHINT);
/* Flush and disable caches. */
csr_write(CSR_MCOR, 0x22);
csr_write(CSR_MHCR, 0x0);
}
static void sun20i_d1_csr_restore(void)
{
/* Invalidate caches and the branch predictor. */
csr_write(CSR_MCOR, 0x70013);
/* Restore custom CSRs, including the cache state. */
csr_write(CSR_MXSTATUS, csr_mxstatus);
csr_write(CSR_MHCR, csr_mhcr);
csr_write(CSR_MHINT, csr_mhint);
}
/*
* PLIC
*/
#define PLIC_SOURCES 176
#define PLIC_IE_WORDS ((PLIC_SOURCES + 31) / 32)
static u8 plic_priority[PLIC_SOURCES];
static u32 plic_sie[PLIC_IE_WORDS];
static u32 plic_threshold;
static void sun20i_d1_plic_save(void)
{
fdt_plic_context_save(true, plic_sie, &plic_threshold);
fdt_plic_priority_save(plic_priority);
}
static void sun20i_d1_plic_restore(void)
{
thead_plic_restore();
fdt_plic_priority_restore(plic_priority);
fdt_plic_context_restore(true, plic_sie, plic_threshold);
}
/*
* PPU
*/
#define PPU_PD_ACTIVE_CTRL 0x2c
static void sun20i_d1_ppu_save(void)
{
/* Enable MMIO access. Do not assume S-mode leaves the clock enabled. */
writel_relaxed(CCU_BGR_ENABLE, SUN20I_D1_PRCM_BASE + PPU_BGR_REG);
/* Activate automatic power-down during the next WFI. */
writel_relaxed(1, SUN20I_D1_PPU_BASE + PPU_PD_ACTIVE_CTRL);
}
static void sun20i_d1_ppu_restore(void)
{
/* Disable automatic power-down. */
writel_relaxed(0, SUN20I_D1_PPU_BASE + PPU_PD_ACTIVE_CTRL);
}
/*
* RISCV_CFG
*/
#define RESET_ENTRY_LO_REG 0x0004
#define RESET_ENTRY_HI_REG 0x0008
#define WAKEUP_EN_REG 0x0020
#define WAKEUP_MASK_REG(i) (0x0024 + 4 * (i))
static void sun20i_d1_riscv_cfg_save(void)
{
/* Enable MMIO access. Do not assume S-mode leaves the clock enabled. */
writel_relaxed(CCU_BGR_ENABLE, SUN20I_D1_CCU_BASE + RISCV_CFG_BGR_REG);
/*
* Copy the SIE bits to the wakeup registers. D1 has 160 "real"
* interrupt sources, numbered 16-175. These are the ones that map to
* the wakeup mask registers (the offset is for GIC compatibility). So
* copying SIE to the wakeup mask needs some bit manipulation.
*/
for (int i = 0; i < PLIC_IE_WORDS - 1; i++)
writel_relaxed(plic_sie[i] >> 16 | plic_sie[i + 1] << 16,
SUN20I_D1_RISCV_CFG_BASE + WAKEUP_MASK_REG(i));
/* Enable PPU wakeup for interrupts. */
writel_relaxed(1, SUN20I_D1_RISCV_CFG_BASE + WAKEUP_EN_REG);
}
static void sun20i_d1_riscv_cfg_restore(void)
{
/* Disable PPU wakeup for interrupts. */
writel_relaxed(0, SUN20I_D1_RISCV_CFG_BASE + WAKEUP_EN_REG);
}
static void sun20i_d1_riscv_cfg_init(void)
{
unsigned long entry = sbi_hartid_to_scratch(0)->warmboot_addr;
/* Enable MMIO access. */
writel_relaxed(CCU_BGR_ENABLE, SUN20I_D1_CCU_BASE + RISCV_CFG_BGR_REG);
/* Program the reset entry address. */
writel_relaxed((u32)entry, SUN20I_D1_RISCV_CFG_BASE + RESET_ENTRY_LO_REG);
writel_relaxed((u64)entry >> 32, SUN20I_D1_RISCV_CFG_BASE + RESET_ENTRY_HI_REG);
}
static int sun20i_d1_hart_suspend(u32 suspend_type)
{
/* Use the generic code for retentive suspend. */
if (!(suspend_type & SBI_HSM_SUSP_NON_RET_BIT))
return SBI_ENOTSUPP;
sun20i_d1_plic_save();
sun20i_d1_ppu_save();
sun20i_d1_riscv_cfg_save();
sun20i_d1_csr_save();
/*
* If no interrupt is pending, this will power down the CPU power
* domain. Otherwise, this will fall through, and the generic HSM
* code will jump to the resume address.
*/
wfi();
return 0;
}
static void sun20i_d1_hart_resume(void)
{
sun20i_d1_csr_restore();
sun20i_d1_riscv_cfg_restore();
sun20i_d1_ppu_restore();
sun20i_d1_plic_restore();
}
static const struct sbi_hsm_device sun20i_d1_ppu = {
.name = "sun20i-d1-ppu",
.hart_suspend = sun20i_d1_hart_suspend,
.hart_resume = sun20i_d1_hart_resume,
};
static int sun20i_d1_final_init(bool cold_boot, const struct fdt_match *match)
{
if (cold_boot) {
sun20i_d1_riscv_cfg_init();
sbi_hsm_set_device(&sun20i_d1_ppu);
}
return 0;
}
static const struct fdt_match sun20i_d1_match[] = {
{ .compatible = "allwinner,sun20i-d1" },
{ },
};
const struct platform_override sun20i_d1 = {
.match_table = sun20i_d1_match,
.final_init = sun20i_d1_final_init,
};

View File

@@ -11,6 +11,7 @@
#define __PLATFORM_OVERRIDE_H__
#include <sbi/sbi_types.h>
#include <sbi/sbi_trap.h>
struct platform_override {
const struct fdt_match *match_table;
@@ -21,6 +22,12 @@ struct platform_override {
void (*early_exit)(const struct fdt_match *match);
void (*final_exit)(const struct fdt_match *match);
int (*fdt_fixup)(void *fdt, const struct fdt_match *match);
int (*vendor_ext_check)(long extid, const struct fdt_match *match);
int (*vendor_ext_provider)(long extid, long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap,
const struct fdt_match *match);
};
#endif

View File

@@ -8,5 +8,4 @@
#
platform-objs-y += platform.o
platform-objs-y += sifive_fu540.o
platform-objs-y += sifive_fu740.o
platform-objs-y += platform_override_modules.o

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