26 Commits

Author SHA1 Message Date
Chao Wei
adc7ba17f3 Fixbug, compile error without debug option
Signed-off-by: Chao Wei <chao.wei@sophgo.com>
2025-11-06 14:25:59 +08:00
Chao Wei
6eef399cfc SG2042: add virtual global timer device driver
Add a virtual global timer device driver. It uses a global timer
register as timer counter, and it uses mtimecmp CSR of clint as
interrupt source.
Using this virtul timer resolves dual way timer sync issue.
On dual way system, we should enable this driver and on single way
system, we should use standard risc-v clint timer.

1. Add a virtual global timer device driver, it is probed by fdt

	sg2042-global-mtimer@70300101c0 {
		compatible = "sophgo,sg2042-global-mtimer";
		reg = < 0x00000070 0x300101c0 0x00000000 0x00000008
			0x00000070 0xac000000 0x00000000 0x00200000>;
		clock-frequency = <50000000 50000000>;
	};

Its compatible should be "sophgo,sg2042-global-mtimer".
And the first region delcared in reg prop is the address of global
timer. The second region delcared in reg prop is the base of clint
timers.
The first clock in clock-frequency is the actual frequency of global
timer, the second clock is the actual frequency of clint timer.

2. Add a quirk in platform specific code.
Add a function sbi_platform_force_emulate_time_csr, it indicates if
opensbi should skip time CSR detection and make software in
supervisor and user mode use emulated time CSR.

Signed-off-by: Chao Wei <chao.wei@sophgo.com>
2025-10-14 17:54:32 +08:00
Chao Wei
506f47f9fa fixbug, syntax error on gcc15
Signed-off-by: Chao Wei <chao.wei@sophgo.com>
2025-07-30 10:12:31 +08:00
Inochi Amaoto
3745939ceb lib: ipi/timer: in favor of upstream linux settings
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
2023-09-25 10:51:41 +08:00
haijiao.liu
44fdaafcb4 platform: generic: allwinner: Clear the overflow generated during the deletion process
Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2023-08-15 17:23:02 +08:00
Xiang W
a82a033c74 fix hart_stack_size change 2023-08-15 11:46:23 +08:00
haijiao.liu
270f27b81b platform: generic: allwinner: fix OV process for T-HEAD
T-HEAD c9xx pmu only needs to clear OV bits of MCOUNTEROF when MOIP bit
of MIP is set, so correct the MIP value check to avoid race conditions
during processing interrupt.

In addition, the S-mode scounterof only have OV bit set when the related
bits of MCOUNTERWEN is set, so also configure MCOUNTERWEN to allow kernel
to access valid SCOUNTEROF.

Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2023-08-14 10:45:04 +08:00
haijiao.liu
f89d688f60 lib: sbi_pmu: ensure update hpm counter before starting
When detecting features of PMU, the hpm counter may be written to some
value, this will cause some unexpected behavior in some cases. So ensure
the hpm counter is updated before starting the counter.

Signed-off-by: haijiao.liu <haijiao.liu@sophgo.com>
2023-08-14 10:45:04 +08:00
haijiao.liu@sophgo.com
4826e4f743 SG2042: spinlock: Fix deadlock issue
This problem was found on sg2042 server platform with the litmus test.

This patch is based on Guo Ren's patch [1].

[1] c53925298d

riscv: qspinlock: errata: Add ERRATA_THEAD_WRITE_ONCE fixup
The early version of T-Head C9xx cores has a store merge buffer
delay problem. The store merge buffer could improve the store queue
performance by merging multi-store requests, but when there are not
continued store requests, the prior single store request would be
waiting in the store queue for a long time. That would cause
significant problems for communication between multi-cores. This
problem was found on sg2042 & th1520 platforms with the qspinlock
lock torture test.

So appending a fence w.o could immediately flush the store merge
buffer and let other cores see the write result.

This will apply the WRITE_ONCE errata to handle the non-standard
behavior via appending a fence w.o instruction for WRITE_ONCE().

Signed-off-by: haijiao.liu@sophgo.com <haijiao.liu@sophgo.com>
2023-08-09 18:36:18 +08:00
chunzhi.lin
d06c0a7858 lib:utils:support pisces's system reboot
pisces system reboot will ecall gpio chip but not watchdog, and pull up cpu gpio5 to tell
CPLD. CPLD will help for cold reboot.
Add the function, gpio chip will pull up gpio16 after chip is probed.

Signed-off-by: chunzhi.lin <chunzhi.lin@sophgo.com>
2023-06-29 14:02:49 +08:00
chunzhi.lin
d21bf89240 lib:utils:add reset and gpio device 2023-06-25 14:15:01 +08:00
haijiao.liu@sophgo.com
9af30e56df Fix system cannot boot when the some CPU status is set to disabled 2023-06-14 18:10:10 +08:00
xiaoguang.xing
d0b705e19c platform:generic:sophgo: Allow the harts of chip0 as cold boot hart 2023-06-10 10:49:27 +08:00
haijiao.liu@sophgo.com
546bc50f9a set tlb fifo entry number to 128 2023-06-07 16:52:52 +08:00
haijiao.liu@sophgo.com
4aab6f3263 set scratch and stack size to 8K 2023-06-07 16:52:52 +08:00
xiaoguang.xing
e1d3b68eeb barrier: add more stronger constraint 2023-05-29 10:00:22 +08:00
xiaoguang.xing
19622b6c93 platform: generic: sophgo: add cold_boot_allowed callback 2023-05-23 16:44:43 +08:00
chunzhi.lin
60142dc80c util:reset:mango-reset device support to X4 and milkv 2023-04-23 14:05:41 +08:00
chunzhi.lin
31087f36d7 lib:utils:delete mango-reset device node after register it 2023-04-13 11:13:19 +08:00
Chao Wei
58f9b858c5 lib: sbi_trap: optimize i-utlb workaround speed 2023-04-11 17:25:23 +08:00
xiaoguang.xing
be6e558f66 lib: sbi_trap: Workaroud for cpu still using i-utlb when into m mode 2023-04-04 17:17:46 +08:00
xiaoguang.xing
0e87f899c3 lib:sbi_tlb: Increase tlb fifo entry number
When tlb fifo is full, it takes more fails.
This makes lots of lock contention and
consumes much cpu time in sbi.
2023-03-29 10:12:01 +08:00
chunzhi.lin
0b5c942ee9 lib:utils:add sophgo-mcu, power management device 2023-03-20 21:29:01 +08:00
Inochi Amaoto
64fb41e927 lib: sbi_trap: change flush tlb in all cases
As flush tlb in interrupt and mode switch is not enough. Flush tlb
in all cases.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
2023-03-19 08:20:10 +08:00
xiaoguang.xing
b210bc000c lib: sbi: Optimize sbi_tlb and sbi_ipi
This patch comes from:
[PATCH v4 0/4] Miscellaneous about sbi_tlb and sbi_ipi
http://lists.infradead.org/pipermail/opensbi/2023-February/004402.html
2023-03-18 18:43:21 +08:00
Inochi Amaoto
35fb234d39 platform: generic: sophgo: add mango soc support
The mango cpu of sophgo is a 64 cores C920 CPU. The board with mango can
have at most two sockets. The CPU have the following features:

 1) support RV64GCV
 2) one seperate timer each cluster
 3) T-HEAD pmu device

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
2023-03-18 18:42:09 +08:00
110 changed files with 1814 additions and 1815 deletions

View File

@@ -401,10 +401,10 @@ merge_deps = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
cat $(2) > $(1)
copy_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " COPY $(subst $(build_dir)/,,$(1))"; \
cp -L -f $(2) $(1)
cp -f $(2) $(1)
inst_file = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
cp -L -f $(2) $(1)
cp -f $(2) $(1)
inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
mkdir -p $(1)/$(3); \
for file in $(4) ; do \
@@ -413,12 +413,12 @@ inst_file_list = $(CMD_PREFIX)if [ ! -z "$(4)" ]; then \
dest_dir=`dirname $$dest_file`; \
echo " INSTALL "$(3)"/"`echo $$rel_file`; \
mkdir -p $$dest_dir; \
cp -L -f $$file $$dest_file; \
cp -f $$file $$dest_file; \
done \
fi
inst_header_dir = $(CMD_PREFIX)mkdir -p $(1); \
echo " INSTALL $(subst $(install_root_dir)/,,$(1))"; \
cp -L -rf $(2) $(1)
cp -rf $(2) $(1)
compile_cpp_dep = $(CMD_PREFIX)mkdir -p `dirname $(1)`; \
echo " CPP-DEP $(subst $(build_dir)/,,$(1))"; \
printf %s `dirname $(1)`/ > $(1) && \

View File

@@ -1,15 +1,11 @@
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
========================================================
![RISC-V OpenSBI](docs/riscv_opensbi_logo_final_color.png)
Copyright and License
---------------------
The OpenSBI project is:
* Copyright (c) 2019 Western Digital Corporation or its affiliates
* Copyright (c) 2023 RISC-V International
The OpenSBI project is copyright (c) 2019 Western Digital Corporation
or its affiliates and other contributors.
It is distributed under the terms of the BSD 2-clause license
("Simplified BSD License" or "FreeBSD License", SPDX: *BSD-2-Clause*).

View File

@@ -43,18 +43,18 @@ follows:
When using the default *FW_JUMP_FDT_ADDR* with *PLATFORM=generic*, you must
ensure *FW_JUMP_FDT_ADDR* is set high enough to avoid overwriting the kernel.
You can use the following method (e.g., using bash or zsh):
You can use the following method.
```
${CROSS_COMPILE}objdump -h $KERNEL_ELF | sort -k 5,5 | awk -n '
/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' |
(( `tail -1` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) &&
echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR
${CROSS_COMPILE}objdump -h $KERNEL_ELF | sort -k 5,5 | awk -n '/^ +[0-9]+ /\
{addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' \
| (( `tail -1` > 0x2200000 )) && echo fdt overlaps kernel,\
increase FW_JUMP_FDT_ADDR
${LLVM}objdump -h --show-lma $KERNEL_ELF | sort -k 5,5 | awk -n '
/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}' |
(( `tail -1` > (FW_JUMP_FDT_ADDR - FW_JUMP_ADDR) )) &&
echo fdt overlaps kernel, increase FW_JUMP_FDT_ADDR
${LLVM}objdump -h --show-lma $KERNEL_ELF | sort -k 5,5 | \
awk -n '/^ +[0-9]+ / {addr="0x"$3; size="0x"$5; printf "0x""%x\n",addr+size}'\
| (( `tail -1` > 0x2200000 )) && echo fdt overlaps kernel,\
increase FW_JUMP_FDT_ADDR
```
*FW_JUMP* Example

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -79,12 +79,13 @@ _try_lottery:
lla t0, __rel_dyn_start
lla t1, __rel_dyn_end
beq t0, t1, _relocate_done
j 5f
2:
REG_L t5, REGBYTES(t0) /* t5 <-- relocation info:type */
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
li t3, R_RISCV_RELATIVE /* reloc type R_RISCV_RELATIVE */
bne t5, t3, 3f
REG_L t3, 0(t0)
REG_L t5, (REGBYTES * 2)(t0) /* t5 <-- addend */
REG_L t3, -(REGBYTES*3)(t0)
REG_L t5, -(REGBYTES)(t0) /* t5 <-- addend */
add t5, t5, t2
add t3, t3, t2
REG_S t5, 0(t3) /* store runtime address to the GOT entry */
@@ -94,17 +95,18 @@ _try_lottery:
lla t4, __dyn_sym_start
4:
REG_L t5, -(REGBYTES*2)(t0) /* t5 <-- relocation info:type */
srli t6, t5, SYM_INDEX /* t6 <--- sym table index */
andi t5, t5, 0xFF /* t5 <--- relocation type */
li t3, RELOC_TYPE
bne t5, t3, 5f
/* address R_RISCV_64 or R_RISCV_32 cases*/
REG_L t3, 0(t0)
REG_L t3, -(REGBYTES*3)(t0)
li t5, SYM_SIZE
mul t6, t6, t5
add s5, t4, t6
REG_L t6, (REGBYTES * 2)(t0) /* t0 <-- addend */
REG_L t6, -(REGBYTES)(t0) /* t0 <-- addend */
REG_L t5, REGBYTES(s5)
add t5, t5, t6
add t5, t5, t2 /* t5 <-- location to fix up in RAM */
@@ -112,8 +114,8 @@ _try_lottery:
REG_S t5, 0(t3) /* store runtime address to the variable */
5:
addi t0, t0, (REGBYTES * 3)
blt t0, t1, 2b
addi t0, t0, (REGBYTES*3)
ble t0, t1, 2b
j _relocate_done
_wait_relocate_copy_done:
j _wait_for_boot_hart
@@ -255,28 +257,20 @@ _bss_zero:
/* Preload HART details
* s7 -> HART Count
* s8 -> HART Stack Size
* s9 -> Heap Size
* s10 -> Heap Offset
*/
lla a4, platform
#if __riscv_xlen > 32
lwu s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lwu s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
lwu s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4)
#else
lw s7, SBI_PLATFORM_HART_COUNT_OFFSET(a4)
lw s8, SBI_PLATFORM_HART_STACK_SIZE_OFFSET(a4)
lw s9, SBI_PLATFORM_HEAP_SIZE_OFFSET(a4)
#endif
/* Setup scratch space for all the HARTs*/
lla tp, _fw_end
mul a5, s7, s8
add tp, tp, a5
/* Setup heap base address */
lla s10, _fw_start
sub s10, tp, s10
add tp, tp, s9
/* Keep a copy of tp */
add t3, tp, zero
/* Counter */
@@ -291,11 +285,8 @@ _scratch_init:
* t3 -> the firmware end address
* s7 -> HART count
* s8 -> HART stack size
* s9 -> Heap Size
* s10 -> Heap Offset
*/
add tp, t3, zero
sub tp, tp, s9
mul a5, s8, t1
sub tp, tp, a5
li a5, SBI_SCRATCH_SIZE
@@ -313,10 +304,6 @@ _scratch_init:
REG_L a5, 0(a4)
REG_S a5, SBI_SCRATCH_FW_RW_OFFSET(tp)
/* Store fw_heap_offset and fw_heap_size in scratch space */
REG_S s10, SBI_SCRATCH_FW_HEAP_OFFSET(tp)
REG_S s9, SBI_SCRATCH_FW_HEAP_SIZE_OFFSET(tp)
/* Store next arg1 in scratch space */
MOV_3R s0, a0, s1, a1, s2, a2
call fw_next_arg1
@@ -443,6 +430,13 @@ _start_warm:
/* Disable all interrupts */
csrw CSR_MIE, zero
/*
* Only clear the MIP_SSIP and MIP_STIP. For the platform like QEMU,
* If we clear other interrupts like MIP_SEIP and the pendings of
* PLIC still exist, the QEMU may not set it back immediately.
*/
li t0, (MIP_SSIP | MIP_STIP)
csrc CSR_MIP, t0
/* Find HART count and HART stack size */
lla a4, platform
@@ -471,8 +465,9 @@ _start_warm:
add s9, s9, 4
add a4, a4, 1
blt a4, s7, 1b
li a4, -1
2: add s6, a4, zero
3: bge s6, s7, _start_hang
3: bgeu s6, s7, _start_hang
/* Find the scratch space based on HART index */
lla tp, _fw_end
@@ -762,6 +757,8 @@ memcmp:
.globl _trap_handler
.globl _trap_exit
_trap_handler:
sfence.vma zero, t0
TRAP_SAVE_AND_SETUP_SP_T0
TRAP_SAVE_MEPC_MSTATUS 0

View File

@@ -25,30 +25,39 @@
#define mb() RISCV_FENCE(iorw,iorw)
/* Read Memory barrier */
#define rmb() RISCV_FENCE(ir,ir)
#define rmb() RISCV_FENCE(ir,iorw)
/* Write Memory barrier */
#define wmb() RISCV_FENCE(ow,ow)
#define wmb() RISCV_FENCE(iorw,ow)
/* SMP Read & Write Memory barrier */
#define smp_mb() RISCV_FENCE(rw,rw)
/* SMP Read Memory barrier */
#define smp_rmb() RISCV_FENCE(r,r)
#define smp_rmb() RISCV_FENCE(r,rw)
/* SMP Write Memory barrier */
#define smp_wmb() RISCV_FENCE(w,w)
#define smp_wmb() RISCV_FENCE(rw,w)
/* CPU relax for busy loop */
#define cpu_relax() asm volatile ("" : : : "memory")
/* clang-format on */
#ifdef CONFIG_PLATFORM_SOPHGO_MANGO
#define __smp_store_release(p, v) \
do { \
RISCV_FENCE(rw, w); \
*(p) = (v); \
RISCV_FENCE(w, rw); \
} while (0)
#else
#define __smp_store_release(p, v) \
do { \
RISCV_FENCE(rw, w); \
*(p) = (v); \
} while (0)
#endif
#define __smp_load_acquire(p) \
({ \

View File

@@ -223,6 +223,8 @@
#define ENVCFG_CBIE_INV _UL(0x3)
#define ENVCFG_FIOM _UL(0x1)
#define MCOUNTEREN_TM (_UL(1) << 1)
/* ===== User-level CSRs ===== */
/* User Trap Setup (N-extension) */

View File

@@ -12,7 +12,13 @@
#include <sbi/sbi_types.h>
#define BITS_PER_LONG (8 * __SIZEOF_LONG__)
#if __SIZEOF_POINTER__ == 8
#define BITS_PER_LONG 64
#elif __SIZEOF_POINTER__ == 4
#define BITS_PER_LONG 32
#else
#error "Unexpected __SIZEOF_POINTER__"
#endif
#define EXTRACT_FIELD(val, which) \
(((val) & (which)) / ((which) & ~((which)-1)))

View File

@@ -1,35 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#ifndef __SBI_CPPC_H__
#define __SBI_CPPC_H__
#include <sbi/sbi_types.h>
/** CPPC device */
struct sbi_cppc_device {
/** Name of the CPPC device */
char name[32];
/** probe - returns register width if implemented, 0 otherwise */
int (*cppc_probe)(unsigned long reg);
/** read the cppc register*/
int (*cppc_read)(unsigned long reg, uint64_t *val);
/** write to the cppc register*/
int (*cppc_write)(unsigned long reg, uint64_t val);
};
int sbi_cppc_probe(unsigned long reg);
int sbi_cppc_read(unsigned long reg, uint64_t *val);
int sbi_cppc_write(unsigned long reg, uint64_t val);
const struct sbi_cppc_device *sbi_cppc_get_device(void);
void sbi_cppc_set_device(const struct sbi_cppc_device *dev);
#endif

View File

@@ -122,15 +122,17 @@ struct sbi_domain {
bool system_reset_allowed;
/** Is domain allowed to suspend the system */
bool system_suspend_allowed;
/** Identifies whether to include the firmware region */
bool fw_region_inited;
};
/** The root domain instance */
extern struct sbi_domain root;
/** HART id to domain table */
extern struct sbi_domain *hartid_to_domain_table[];
/** Get pointer to sbi_domain from HART id */
struct sbi_domain *sbi_hartid_to_domain(u32 hartid);
#define sbi_hartid_to_domain(__hartid) \
hartid_to_domain_table[__hartid]
/** Get pointer to sbi_domain for current HART */
#define sbi_domain_thishart_ptr() \

View File

@@ -21,46 +21,10 @@ struct sbi_trap_regs;
struct sbi_trap_info;
struct sbi_ecall_extension {
/* head is used by the extension list */
struct sbi_dlist head;
/*
* extid_start and extid_end specify the range for this extension. As
* the initial range may be wider than the valid runtime range, the
* register_extensions callback is responsible for narrowing the range
* before other callbacks may be invoked.
*/
unsigned long extid_start;
unsigned long extid_end;
/*
* register_extensions
*
* Calls sbi_ecall_register_extension() one or more times to register
* extension ID range(s) which should be handled by this extension.
* More than one sbi_ecall_extension struct and
* sbi_ecall_register_extension() call is necessary when the supported
* extension ID ranges have gaps. Additionally, extension availability
* must be checked before registering, which means, when this callback
* returns, only valid extension IDs from the initial range, which are
* also available, have been registered.
*/
int (* register_extensions)(void);
/*
* probe
*
* Implements the Base extension's probe function for the extension. As
* the register_extensions callback ensures that no other extension
* callbacks will be invoked when the extension is not available, then
* probe can never fail. However, an extension may choose to set
* out_val to a nonzero value other than one. In those cases, it should
* implement this callback.
*/
int (* probe)(unsigned long extid, unsigned long *out_val);
/*
* handle
*
* This is the extension handler. register_extensions ensures it is
* never invoked with an invalid or unavailable extension ID.
*/
int (* handle)(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,

View File

@@ -31,7 +31,6 @@
#define SBI_EXT_PMU 0x504D55
#define SBI_EXT_DBCN 0x4442434E
#define SBI_EXT_SUSP 0x53555350
#define SBI_EXT_CPPC 0x43505043
/* SBI function IDs for BASE extension*/
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -215,10 +214,10 @@ enum sbi_pmu_ctr_type {
};
/* Helper macros to decode event idx */
#define SBI_PMU_EVENT_IDX_OFFSET 20
#define SBI_PMU_EVENT_IDX_MASK 0xFFFFF
#define SBI_PMU_EVENT_IDX_TYPE_OFFSET 16
#define SBI_PMU_EVENT_IDX_TYPE_MASK (0xF << SBI_PMU_EVENT_IDX_TYPE_OFFSET)
#define SBI_PMU_EVENT_IDX_CODE_MASK 0xFFFF
#define SBI_PMU_EVENT_IDX_TYPE_MASK 0xF0000
#define SBI_PMU_EVENT_RAW_IDX 0x20000
#define SBI_PMU_EVENT_IDX_INVALID 0xFFFFFFFF
@@ -257,39 +256,6 @@ enum sbi_pmu_ctr_type {
#define SBI_SUSP_SLEEP_TYPE_LAST SBI_SUSP_SLEEP_TYPE_SUSPEND
#define SBI_SUSP_PLATFORM_SLEEP_START 0x80000000
/* SBI function IDs for CPPC extension */
#define SBI_EXT_CPPC_PROBE 0x0
#define SBI_EXT_CPPC_READ 0x1
#define SBI_EXT_CPPC_READ_HI 0x2
#define SBI_EXT_CPPC_WRITE 0x3
enum sbi_cppc_reg_id {
SBI_CPPC_HIGHEST_PERF = 0x00000000,
SBI_CPPC_NOMINAL_PERF = 0x00000001,
SBI_CPPC_LOW_NON_LINEAR_PERF = 0x00000002,
SBI_CPPC_LOWEST_PERF = 0x00000003,
SBI_CPPC_GUARANTEED_PERF = 0x00000004,
SBI_CPPC_DESIRED_PERF = 0x00000005,
SBI_CPPC_MIN_PERF = 0x00000006,
SBI_CPPC_MAX_PERF = 0x00000007,
SBI_CPPC_PERF_REDUC_TOLERANCE = 0x00000008,
SBI_CPPC_TIME_WINDOW = 0x00000009,
SBI_CPPC_CTR_WRAP_TIME = 0x0000000A,
SBI_CPPC_REFERENCE_CTR = 0x0000000B,
SBI_CPPC_DELIVERED_CTR = 0x0000000C,
SBI_CPPC_PERF_LIMITED = 0x0000000D,
SBI_CPPC_ENABLE = 0x0000000E,
SBI_CPPC_AUTO_SEL_ENABLE = 0x0000000F,
SBI_CPPC_AUTO_ACT_WINDOW = 0x00000010,
SBI_CPPC_ENERGY_PERF_PREFERENCE = 0x00000011,
SBI_CPPC_REFERENCE_PERF = 0x00000012,
SBI_CPPC_LOWEST_FREQ = 0x00000013,
SBI_CPPC_NOMINAL_FREQ = 0x00000014,
SBI_CPPC_ACPI_LAST = SBI_CPPC_NOMINAL_FREQ,
SBI_CPPC_TRANSITION_LATENCY = 0x80000000,
SBI_CPPC_NON_ACPI_LAST = SBI_CPPC_TRANSITION_LATENCY,
};
/* SBI base specification related macros */
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f

View File

@@ -1,44 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel<apatel@ventanamicro.com>
*/
#ifndef __SBI_HEAP_H__
#define __SBI_HEAP_H__
#include <sbi/sbi_types.h>
struct sbi_scratch;
/** Allocate from heap area */
void *sbi_malloc(size_t size);
/** Zero allocate from heap area */
void *sbi_zalloc(size_t size);
/** Allocate array from heap area */
static inline void *sbi_calloc(size_t nitems, size_t size)
{
return sbi_zalloc(nitems * size);
}
/** Free-up to heap area */
void sbi_free(void *ptr);
/** Amount (in bytes) of free space in the heap area */
unsigned long sbi_heap_free_space(void);
/** Amount (in bytes) of used space in the heap area */
unsigned long sbi_heap_used_space(void);
/** Amount (in bytes) of reserved space in the heap area */
unsigned long sbi_heap_reserved_space(void);
/** Initialize heap area */
int sbi_heap_init(struct sbi_scratch *scratch);
#endif

View File

@@ -16,8 +16,6 @@ struct sbi_scratch;
void __noreturn sbi_init(struct sbi_scratch *scratch);
unsigned long sbi_entry_count(u32 hartid);
unsigned long sbi_init_count(u32 hartid);
void __noreturn sbi_exit(struct sbi_scratch *scratch);

View File

@@ -30,12 +30,6 @@ struct sbi_ipi_device {
void (*ipi_clear)(u32 target_hart);
};
enum sbi_ipi_update_type {
SBI_IPI_UPDATE_SUCCESS,
SBI_IPI_UPDATE_BREAK,
SBI_IPI_UPDATE_RETRY,
};
struct sbi_scratch;
/** IPI event operations or callbacks */
@@ -47,10 +41,10 @@ struct sbi_ipi_event_ops {
* Update callback to save/enqueue data for remote HART
* Note: This is an optional callback and it is called just before
* triggering IPI to remote HART.
* @return < 0, error or failure
* @return SBI_IPI_UPDATE_SUCCESS, success
* @return SBI_IPI_UPDATE_BREAK, break IPI, done on local hart
* @return SBI_IPI_UPDATE_RETRY, need retry
* @return 0 success
* @return -1 break IPI, done on local hart
* @return -2 need retry
*/
int (* update)(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,

View File

@@ -31,7 +31,7 @@ struct sbi_dlist _lname = SBI_LIST_HEAD_INIT(_lname)
#define SBI_INIT_LIST_HEAD(ptr) \
do { \
(ptr)->next = ptr; (ptr)->prev = ptr; \
} while (0)
} while (0);
static inline void __sbi_list_add(struct sbi_dlist *new,
struct sbi_dlist *prev,

View File

@@ -29,16 +29,12 @@
#define SBI_PLATFORM_HART_COUNT_OFFSET (0x50)
/** Offset of hart_stack_size in struct sbi_platform */
#define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
/** Offset of heap_size in struct sbi_platform */
#define SBI_PLATFORM_HEAP_SIZE_OFFSET (0x58)
/** Offset of reserved in struct sbi_platform */
#define SBI_PLATFORM_RESERVED_OFFSET (0x5c)
/** Offset of platform_ops_addr in struct sbi_platform */
#define SBI_PLATFORM_OPS_OFFSET (0x60)
#define SBI_PLATFORM_OPS_OFFSET (0x58)
/** Offset of firmware_context in struct sbi_platform */
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x58 + __SIZEOF_POINTER__)
/** Offset of hart_index2id in struct sbi_platform */
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x60 + (__SIZEOF_POINTER__ * 2))
#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x58 + (__SIZEOF_POINTER__ * 2))
#define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT (1UL << 12)
@@ -72,6 +68,9 @@ struct sbi_platform_operations {
/* Check if specified HART is allowed to do cold boot */
bool (*cold_boot_allowed)(u32 hartid);
/* Check if platform force emulate time csr, instead of using csr directly */
bool (*force_emulate_time_csr)(void);
/* Platform nascent initialization */
int (*nascent_init)(void);
@@ -142,10 +141,6 @@ struct sbi_platform_operations {
/** Platform default per-HART stack size for exception/interrupt handling */
#define SBI_PLATFORM_DEFAULT_HART_STACK_SIZE 8192
/** Platform default heap size */
#define SBI_PLATFORM_DEFAULT_HEAP_SIZE(__num_hart) \
(0x8000 + 0x800 * (__num_hart))
/** Representation of a platform */
struct sbi_platform {
/**
@@ -168,10 +163,6 @@ struct sbi_platform {
u32 hart_count;
/** Per-HART stack size for exception/interrupt handling */
u32 hart_stack_size;
/** Size of heap shared by all HARTs */
u32 heap_size;
/** Reserved for future use */
u32 reserved;
/** Pointer to sbi platform operations */
unsigned long platform_ops_addr;
/** Pointer to system firmware specific context */
@@ -388,6 +379,20 @@ static inline bool sbi_platform_cold_boot_allowed(
return true;
}
/**
* Check whether given platform should force emulate time CSR
*
* @param plat pointer to struct sbi_platform
*
* @return true such platform force emulate time CSR, false otherwise
*/
static inline bool sbi_platform_force_emulate_time_csr(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->force_emulate_time_csr)
return sbi_platform_ops(plat)->force_emulate_time_csr();
return false;
}
/**
* Nascent (very early) initialization for current HART
*

View File

@@ -20,32 +20,28 @@
#define SBI_SCRATCH_FW_SIZE_OFFSET (1 * __SIZEOF_POINTER__)
/** Offset (in sbi_scratch) of the R/W Offset */
#define SBI_SCRATCH_FW_RW_OFFSET (2 * __SIZEOF_POINTER__)
/** Offset of fw_heap_offset member in sbi_scratch */
#define SBI_SCRATCH_FW_HEAP_OFFSET (3 * __SIZEOF_POINTER__)
/** Offset of fw_heap_size_offset member in sbi_scratch */
#define SBI_SCRATCH_FW_HEAP_SIZE_OFFSET (4 * __SIZEOF_POINTER__)
/** Offset of next_arg1 member in sbi_scratch */
#define SBI_SCRATCH_NEXT_ARG1_OFFSET (5 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_NEXT_ARG1_OFFSET (3 * __SIZEOF_POINTER__)
/** Offset of next_addr member in sbi_scratch */
#define SBI_SCRATCH_NEXT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_NEXT_ADDR_OFFSET (4 * __SIZEOF_POINTER__)
/** Offset of next_mode member in sbi_scratch */
#define SBI_SCRATCH_NEXT_MODE_OFFSET (7 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_NEXT_MODE_OFFSET (5 * __SIZEOF_POINTER__)
/** Offset of warmboot_addr member in sbi_scratch */
#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (8 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_WARMBOOT_ADDR_OFFSET (6 * __SIZEOF_POINTER__)
/** Offset of platform_addr member in sbi_scratch */
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (9 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_PLATFORM_ADDR_OFFSET (7 * __SIZEOF_POINTER__)
/** Offset of hartid_to_scratch member in sbi_scratch */
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (10 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_HARTID_TO_SCRATCH_OFFSET (8 * __SIZEOF_POINTER__)
/** Offset of trap_exit member in sbi_scratch */
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (11 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_TRAP_EXIT_OFFSET (9 * __SIZEOF_POINTER__)
/** Offset of tmp0 member in sbi_scratch */
#define SBI_SCRATCH_TMP0_OFFSET (12 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_TMP0_OFFSET (10 * __SIZEOF_POINTER__)
/** Offset of options member in sbi_scratch */
#define SBI_SCRATCH_OPTIONS_OFFSET (13 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_OPTIONS_OFFSET (11 * __SIZEOF_POINTER__)
/** Offset of extra space in sbi_scratch */
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (14 * __SIZEOF_POINTER__)
#define SBI_SCRATCH_EXTRA_SPACE_OFFSET (12 * __SIZEOF_POINTER__)
/** Maximum size of sbi_scratch (4KB) */
#define SBI_SCRATCH_SIZE (0x1000)
#define SBI_SCRATCH_SIZE (0x2000)
/* clang-format on */
@@ -61,10 +57,6 @@ struct sbi_scratch {
unsigned long fw_size;
/** Offset (in bytes) of the R/W section */
unsigned long fw_rw_offset;
/** Offset (in bytes) of the heap area */
unsigned long fw_heap_offset;
/** Size (in bytes) of the heap area */
unsigned long fw_heap_size;
/** Arg1 (or 'a1' register) of next booting stage for this HART */
unsigned long next_arg1;
/** Address of next booting stage for this HART */
@@ -175,9 +167,6 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size);
/** Free-up extra space in sbi_scratch */
void sbi_scratch_free_offset(unsigned long offset);
/** Amount (in bytes) of used space in in sbi_scratch */
unsigned long sbi_scratch_used_space(void);
/** Get pointer from offset in sbi_scratch */
#define sbi_scratch_offset_ptr(scratch, offset) (void *)((char *)(scratch) + (offset))
@@ -185,23 +174,6 @@ unsigned long sbi_scratch_used_space(void);
#define sbi_scratch_thishart_offset_ptr(offset) \
(void *)((char *)sbi_scratch_thishart_ptr() + (offset))
/** Allocate offset for a data type in sbi_scratch */
#define sbi_scratch_alloc_type_offset(__type) \
sbi_scratch_alloc_offset(sizeof(__type))
/** Read a data type from sbi_scratch at given offset */
#define sbi_scratch_read_type(__scratch, __type, __offset) \
({ \
*((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))); \
})
/** Write a data type to sbi_scratch at given offset */
#define sbi_scratch_write_type(__scratch, __type, __offset, __ptr) \
do { \
*((__type *)sbi_scratch_offset_ptr((__scratch), (__offset))) \
= (__type)(__ptr); \
} while (0)
/** HART id to scratch table */
extern struct sbi_scratch *hartid_to_scratch_table[];

View File

@@ -48,14 +48,7 @@ struct sbi_system_suspend_device {
/** Name of the system suspend device */
char name[32];
/**
* Check whether sleep type is supported by the device
*
* Returns 0 when @sleep_type supported, SBI_ERR_INVALID_PARAM
* when @sleep_type is reserved, or SBI_ERR_NOT_SUPPORTED when
* @sleep_type is not reserved and is implemented, but the
* platform doesn't support it due to missing dependencies.
*/
/* Check whether sleep type is supported by the device */
int (*system_suspend_check)(u32 sleep_type);
/**

View File

@@ -20,7 +20,7 @@
/* clang-format on */
#define SBI_TLB_FIFO_NUM_ENTRIES 8
#define SBI_TLB_FIFO_NUM_ENTRIES 128
struct sbi_scratch;

View File

@@ -44,7 +44,11 @@ typedef unsigned long long uint64_t;
#error "Unexpected __riscv_xlen"
#endif
#if __STDC_VERSION__ < 202000L
typedef int bool;
#define true 1
#define false 0
#endif
typedef unsigned long ulong;
typedef unsigned long uintptr_t;
typedef unsigned long size_t;
@@ -61,9 +65,6 @@ typedef uint32_t be32_t;
typedef uint64_t le64_t;
typedef uint64_t be64_t;
#define true 1
#define false 0
#define NULL ((void *)0)
#define __packed __attribute__((packed))

View File

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

View File

@@ -93,6 +93,20 @@ void fdt_plic_fixup(void *fdt);
*/
int fdt_reserved_memory_fixup(void *fdt);
/**
* Fix up the reserved memory subnodes in the device tree
*
* This routine adds the no-map property to the reserved memory subnodes so
* that the OS does not map those PMP protected memory regions.
*
* Platform codes must call this helper in their final_init() after fdt_fixups()
* if the OS should not map the PMP protected reserved regions.
*
* @param fdt: device tree blob
* @return zero on success and -ve on failure
*/
int fdt_reserved_memory_nomap_fixup(void *fdt);
/**
* General device tree fix-up
*

View File

@@ -38,7 +38,7 @@ enum semihosting_open_mode {
#ifdef CONFIG_SERIAL_SEMIHOSTING
int semihosting_init(void);
int semihosting_enabled(void);
bool semihosting_enabled(void);
#else
static inline int semihosting_init(void) { return SBI_ENODEV; }
static inline int semihosting_enabled(void) { return 0; }

View File

@@ -35,6 +35,7 @@ struct aclint_mtimer_data {
u32 hart_count;
bool has_64bit_mmio;
bool has_shared_mtime;
bool use_extern_domain;
/* Private details (initialized and used by ACLINT MTIMER library) */
struct aclint_mtimer_data *time_delta_reference;
unsigned long time_delta_computed;

View File

@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2025 SOPHGO Corporation
*
* Authors:
* Chao Wei <chao.wei@sophgo.com>
*/
#ifndef __SG2042_GMT_H__
#define __SG2042_GMT_H__
int sg2042gmt_cold_timer_init(unsigned long mtimer_base,
unsigned long mtimecmp_base,
unsigned long mtimecmp_size,
unsigned long delcared_freq,
unsigned long actual_freq,
unsigned long timecmp_freq);
int sg2042gmt_warm_timer_init(void);
#endif /* __SG2042_GMT_H__ */

View File

@@ -34,10 +34,6 @@ config SBI_ECALL_DBCN
bool "Debug Console extension"
default y
config SBI_ECALL_CPPC
bool "CPPC extension"
default y
config SBI_ECALL_LEGACY
bool "SBI v0.1 legacy extensions"
default y

View File

@@ -43,9 +43,6 @@ libsbi-objs-$(CONFIG_SBI_ECALL_PMU) += sbi_ecall_pmu.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_DBCN) += ecall_dbcn
libsbi-objs-$(CONFIG_SBI_ECALL_DBCN) += sbi_ecall_dbcn.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_CPPC) += ecall_cppc
libsbi-objs-$(CONFIG_SBI_ECALL_CPPC) += sbi_ecall_cppc.o
carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_LEGACY) += ecall_legacy
libsbi-objs-$(CONFIG_SBI_ECALL_LEGACY) += sbi_ecall_legacy.o
@@ -59,7 +56,6 @@ libsbi-objs-y += sbi_domain.o
libsbi-objs-y += sbi_emulate_csr.o
libsbi-objs-y += sbi_fifo.o
libsbi-objs-y += sbi_hart.o
libsbi-objs-y += sbi_heap.o
libsbi-objs-y += sbi_math.o
libsbi-objs-y += sbi_hfence.o
libsbi-objs-y += sbi_hsm.o
@@ -78,4 +74,3 @@ libsbi-objs-y += sbi_tlb.o
libsbi-objs-y += sbi_trap.o
libsbi-objs-y += sbi_unpriv.o
libsbi-objs-y += sbi_expected_trap.o
libsbi-objs-y += sbi_cppc.o

View File

@@ -152,7 +152,7 @@ unsigned long csr_read_num(int csr_num)
default:
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
break;
}
};
return ret;
@@ -220,7 +220,7 @@ void csr_write_num(int csr_num, unsigned long val)
default:
sbi_panic("%s: Unknown CSR %#x", __func__, csr_num);
break;
}
};
#undef switchcase_csr_write_64
#undef switchcase_csr_write_32

View File

@@ -481,11 +481,5 @@ void sbi_console_set_device(const struct sbi_console_device *dev)
int sbi_console_init(struct sbi_scratch *scratch)
{
int rc = sbi_platform_console_init(sbi_platform_ptr(scratch));
/* console is not a necessary device */
if (rc == SBI_ENODEV)
return 0;
return rc;
return sbi_platform_console_init(sbi_platform_ptr(scratch));
}

View File

@@ -1,110 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_cppc.h>
static const struct sbi_cppc_device *cppc_dev = NULL;
const struct sbi_cppc_device *sbi_cppc_get_device(void)
{
return cppc_dev;
}
void sbi_cppc_set_device(const struct sbi_cppc_device *dev)
{
if (!dev || cppc_dev)
return;
cppc_dev = dev;
}
static bool sbi_cppc_is_reserved(unsigned long reg)
{
if ((reg > SBI_CPPC_ACPI_LAST && reg < SBI_CPPC_TRANSITION_LATENCY) ||
reg > SBI_CPPC_NON_ACPI_LAST)
return true;
return false;
}
static bool sbi_cppc_readable(unsigned long reg)
{
/* there are no write-only cppc registers currently */
return true;
}
static bool sbi_cppc_writable(unsigned long reg)
{
switch (reg) {
case SBI_CPPC_HIGHEST_PERF:
case SBI_CPPC_NOMINAL_PERF:
case SBI_CPPC_LOW_NON_LINEAR_PERF:
case SBI_CPPC_LOWEST_PERF:
case SBI_CPPC_GUARANTEED_PERF:
case SBI_CPPC_CTR_WRAP_TIME:
case SBI_CPPC_REFERENCE_CTR:
case SBI_CPPC_DELIVERED_CTR:
case SBI_CPPC_REFERENCE_PERF:
case SBI_CPPC_LOWEST_FREQ:
case SBI_CPPC_NOMINAL_FREQ:
case SBI_CPPC_TRANSITION_LATENCY:
return false;
}
return true;
}
int sbi_cppc_probe(unsigned long reg)
{
if (!cppc_dev || !cppc_dev->cppc_probe)
return SBI_EFAIL;
/* Check whether register is reserved */
if (sbi_cppc_is_reserved(reg))
return SBI_ERR_INVALID_PARAM;
return cppc_dev->cppc_probe(reg);
}
int sbi_cppc_read(unsigned long reg, uint64_t *val)
{
int ret;
if (!cppc_dev || !cppc_dev->cppc_read)
return SBI_EFAIL;
/* Check whether register is implemented */
ret = sbi_cppc_probe(reg);
if (ret <= 0)
return SBI_ERR_NOT_SUPPORTED;
/* Check whether the register is write-only */
if (!sbi_cppc_readable(reg))
return SBI_ERR_DENIED;
return cppc_dev->cppc_read(reg, val);
}
int sbi_cppc_write(unsigned long reg, uint64_t val)
{
int ret;
if (!cppc_dev || !cppc_dev->cppc_write)
return SBI_EFAIL;
/* Check whether register is implemented */
ret = sbi_cppc_probe(reg);
if (ret <= 0)
return SBI_ERR_NOT_SUPPORTED;
/* Check whether the register is read-only */
if (!sbi_cppc_writable(reg))
return SBI_ERR_DENIED;
return cppc_dev->cppc_write(reg, val);
}

View File

@@ -11,7 +11,6 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_math.h>
#include <sbi/sbi_platform.h>
@@ -23,45 +22,25 @@
* the array to be null-terminated.
*/
struct sbi_domain *domidx_to_domain_table[SBI_DOMAIN_MAX_INDEX + 1] = { 0 };
struct sbi_domain *hartid_to_domain_table[SBI_HARTMASK_MAX_BITS] = { 0 };
static u32 domain_count = 0;
static bool domain_finalized = false;
static struct sbi_hartmask root_hmask = { 0 };
#define ROOT_REGION_MAX 16
static u32 root_memregs_count = 0;
static struct sbi_domain_memregion root_fw_region;
static struct sbi_domain_memregion root_memregs[ROOT_REGION_MAX + 1] = { 0 };
struct sbi_domain root = {
.name = "root",
.possible_harts = NULL,
.regions = NULL,
.possible_harts = &root_hmask,
.regions = root_memregs,
.system_reset_allowed = true,
.system_suspend_allowed = true,
.fw_region_inited = false,
};
static unsigned long domain_hart_ptr_offset;
struct sbi_domain *sbi_hartid_to_domain(u32 hartid)
{
struct sbi_scratch *scratch;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch || !domain_hart_ptr_offset)
return NULL;
return sbi_scratch_read_type(scratch, void *, domain_hart_ptr_offset);
}
static void update_hartid_to_domain(u32 hartid, struct sbi_domain *dom)
{
struct sbi_scratch *scratch;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return;
sbi_scratch_write_type(scratch, void *, domain_hart_ptr_offset, dom);
}
bool sbi_domain_is_assigned_hart(const struct sbi_domain *dom, u32 hartid)
{
if (dom)
@@ -90,6 +69,14 @@ ulong sbi_domain_get_assigned_hartmask(const struct sbi_domain *dom,
return ret;
}
static void domain_memregion_initfw(struct sbi_domain_memregion *reg)
{
if (!reg)
return;
sbi_memcpy(reg, &root_fw_region, sizeof(*reg));
}
void sbi_domain_memregion_init(unsigned long addr,
unsigned long size,
unsigned long flags,
@@ -268,6 +255,7 @@ static int sanitize_domain(const struct sbi_platform *plat,
struct sbi_domain *dom)
{
u32 i, j, count;
bool have_fw_reg;
struct sbi_domain_memregion treg, *reg, *reg1;
/* Check possible HARTs */
@@ -282,7 +270,7 @@ static int sanitize_domain(const struct sbi_platform *plat,
"hart %d\n", __func__, dom->name, i);
return SBI_EINVAL;
}
}
};
/* Check memory regions */
if (!dom->regions) {
@@ -300,13 +288,17 @@ static int sanitize_domain(const struct sbi_platform *plat,
}
}
/* Count memory regions */
/* Count memory regions and check presence of firmware region */
count = 0;
sbi_domain_for_each_memregion(dom, reg)
have_fw_reg = false;
sbi_domain_for_each_memregion(dom, reg) {
if (reg->order == root_fw_region.order &&
reg->base == root_fw_region.base &&
reg->flags == root_fw_region.flags)
have_fw_reg = true;
count++;
/* Check presence of firmware regions */
if (!dom->fw_region_inited) {
}
if (!have_fw_reg) {
sbi_printf("%s: %s does not have firmware region\n",
__func__, dom->name);
return SBI_EINVAL;
@@ -472,7 +464,7 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
default:
sbi_printf("Unknown\n");
break;
}
};
sbi_printf("Domain%d SysReset %s: %s\n",
dom->index, suffix, (dom->system_reset_allowed) ? "yes" : "no");
@@ -542,11 +534,11 @@ int sbi_domain_register(struct sbi_domain *dom,
if (!sbi_hartmask_test_hart(i, dom->possible_harts))
continue;
tdom = sbi_hartid_to_domain(i);
tdom = hartid_to_domain_table[i];
if (tdom)
sbi_hartmask_clear_hart(i,
&tdom->assigned_harts);
update_hartid_to_domain(i, dom);
hartid_to_domain_table[i] = dom;
sbi_hartmask_set_hart(i, &dom->assigned_harts);
/*
@@ -572,7 +564,8 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
const struct sbi_platform *plat = sbi_platform_thishart_ptr();
/* Sanity checks */
if (!reg || domain_finalized || !root.regions ||
if (!reg || domain_finalized ||
(root.regions != root_memregs) ||
(ROOT_REGION_MAX <= root_memregs_count))
return SBI_EINVAL;
@@ -587,10 +580,10 @@ int sbi_domain_root_add_memregion(const struct sbi_domain_memregion *reg)
}
/* Append the memregion to root memregions */
nreg = &root.regions[root_memregs_count];
nreg = &root_memregs[root_memregs_count];
sbi_memcpy(nreg, reg, sizeof(*reg));
root_memregs_count++;
root.regions[root_memregs_count].order = 0;
root_memregs[root_memregs_count].order = 0;
/* Sort and optimize root regions */
do {
@@ -720,9 +713,6 @@ int sbi_domain_finalize(struct sbi_scratch *scratch, u32 cold_hartid)
int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
{
u32 i;
int rc;
struct sbi_hartmask *root_hmask;
struct sbi_domain_memregion *root_memregs;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->fw_rw_offset == 0 ||
@@ -738,31 +728,12 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
return SBI_EINVAL;
}
domain_hart_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!domain_hart_ptr_offset)
return SBI_ENOMEM;
root_memregs = sbi_calloc(sizeof(*root_memregs), ROOT_REGION_MAX + 1);
if (!root_memregs) {
sbi_printf("%s: no memory for root regions\n", __func__);
rc = SBI_ENOMEM;
goto fail_free_domain_hart_ptr_offset;
}
root.regions = root_memregs;
root_hmask = sbi_zalloc(sizeof(*root_hmask));
if (!root_hmask) {
sbi_printf("%s: no memory for root hartmask\n", __func__);
rc = SBI_ENOMEM;
goto fail_free_root_memregs;
}
root.possible_harts = root_hmask;
/* Root domain firmware memory region */
sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
(SBI_DOMAIN_MEMREGION_M_READABLE |
SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
&root_memregs[root_memregs_count++]);
&root_fw_region);
domain_memregion_initfw(&root_memregs[root_memregs_count++]);
sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
(scratch->fw_size - scratch->fw_rw_offset),
@@ -770,8 +741,6 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
SBI_DOMAIN_MEMREGION_M_WRITABLE),
&root_memregs[root_memregs_count++]);
root.fw_region_inited = true;
/* Root domain allow everything memory region */
sbi_domain_memregion_init(0, ~0UL,
(SBI_DOMAIN_MEMREGION_READABLE |
@@ -794,21 +763,8 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
if (sbi_platform_hart_invalid(plat, i))
continue;
sbi_hartmask_set_hart(i, root_hmask);
sbi_hartmask_set_hart(i, &root_hmask);
}
/* Finally register the root domain */
rc = sbi_domain_register(&root, root_hmask);
if (rc)
goto fail_free_root_hmask;
return 0;
fail_free_root_hmask:
sbi_free(root_hmask);
fail_free_root_memregs:
sbi_free(root_memregs);
fail_free_domain_hart_ptr_offset:
sbi_scratch_free_offset(domain_hart_ptr_offset);
return rc;
return sbi_domain_register(&root, &root_hmask);
}

View File

@@ -120,9 +120,7 @@ int sbi_ecall_handler(struct sbi_trap_regs *regs)
trap.epc = regs->mepc;
sbi_trap_redirect(regs, &trap);
} else {
if (ret < SBI_LAST_ERR ||
(extension_id != SBI_EXT_0_1_CONSOLE_GETCHAR &&
SBI_SUCCESS < ret)) {
if (ret < SBI_LAST_ERR || SBI_SUCCESS < ret) {
sbi_printf("%s: Invalid error %d for ext=0x%lx "
"func=0x%lx\n", __func__, ret,
extension_id, func_id);
@@ -154,10 +152,7 @@ int sbi_ecall_init(void)
for (i = 0; i < sbi_ecall_exts_size; i++) {
ext = sbi_ecall_exts[i];
ret = SBI_ENODEV;
if (ext->register_extensions)
ret = ext->register_extensions();
ret = sbi_ecall_register_extension(ext);
if (ret)
return ret;
}

View File

@@ -72,16 +72,8 @@ static int sbi_ecall_base_handler(unsigned long extid, unsigned long funcid,
return ret;
}
struct sbi_ecall_extension ecall_base;
static int sbi_ecall_base_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_base);
}
struct sbi_ecall_extension ecall_base = {
.extid_start = SBI_EXT_BASE,
.extid_end = SBI_EXT_BASE,
.register_extensions = sbi_ecall_base_register_extensions,
.handle = sbi_ecall_base_handler,
.extid_start = SBI_EXT_BASE,
.extid_end = SBI_EXT_BASE,
.handle = sbi_ecall_base_handler,
};

View File

@@ -1,67 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
*/
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_trap.h>
#include <sbi/sbi_cppc.h>
static int sbi_ecall_cppc_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
int ret = 0;
uint64_t temp;
switch (funcid) {
case SBI_EXT_CPPC_READ:
ret = sbi_cppc_read(regs->a0, &temp);
*out_val = temp;
break;
case SBI_EXT_CPPC_READ_HI:
#if __riscv_xlen == 32
ret = sbi_cppc_read(regs->a0, &temp);
*out_val = temp >> 32;
#else
*out_val = 0;
#endif
break;
case SBI_EXT_CPPC_WRITE:
ret = sbi_cppc_write(regs->a0, regs->a1);
break;
case SBI_EXT_CPPC_PROBE:
ret = sbi_cppc_probe(regs->a0);
if (ret >= 0) {
*out_val = ret;
ret = 0;
}
break;
default:
ret = SBI_ENOTSUPP;
}
return ret;
}
struct sbi_ecall_extension ecall_cppc;
static int sbi_ecall_cppc_register_extensions(void)
{
if (!sbi_cppc_get_device())
return 0;
return sbi_ecall_register_extension(&ecall_cppc);
}
struct sbi_ecall_extension ecall_cppc = {
.extid_start = SBI_EXT_CPPC,
.extid_end = SBI_EXT_CPPC,
.register_extensions = sbi_ecall_cppc_register_extensions,
.handle = sbi_ecall_cppc_handler,
};

View File

@@ -34,14 +34,11 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
* Based on above, we simply fail if the upper 32bits of
* the physical address (i.e. a2 register) is non-zero on
* RV32.
*
* Analogously, we fail if the upper 64bit of the
* physical address (i.e. a2 register) is non-zero on
* RV64.
*/
#if __riscv_xlen == 32
if (regs->a2)
return SBI_ERR_FAILED;
#endif
if (!sbi_domain_check_addr_range(sbi_domain_thishart_ptr(),
regs->a1, regs->a0, smode,
SBI_DOMAIN_READ|SBI_DOMAIN_WRITE))
@@ -61,19 +58,15 @@ static int sbi_ecall_dbcn_handler(unsigned long extid, unsigned long funcid,
return SBI_ENOTSUPP;
}
struct sbi_ecall_extension ecall_dbcn;
static int sbi_ecall_dbcn_register_extensions(void)
static int sbi_ecall_dbcn_probe(unsigned long extid, unsigned long *out_val)
{
if (!sbi_console_get_device())
return 0;
return sbi_ecall_register_extension(&ecall_dbcn);
*out_val = sbi_console_get_device() ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_dbcn = {
.extid_start = SBI_EXT_DBCN,
.extid_end = SBI_EXT_DBCN,
.register_extensions = sbi_ecall_dbcn_register_extensions,
.handle = sbi_ecall_dbcn_handler,
.extid_start = SBI_EXT_DBCN,
.extid_end = SBI_EXT_DBCN,
.handle = sbi_ecall_dbcn_handler,
.probe = sbi_ecall_dbcn_probe,
};

View File

@@ -54,16 +54,8 @@ static int sbi_ecall_hsm_handler(unsigned long extid, unsigned long funcid,
return ret;
}
struct sbi_ecall_extension ecall_hsm;
static int sbi_ecall_hsm_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_hsm);
}
struct sbi_ecall_extension ecall_hsm = {
.extid_start = SBI_EXT_HSM,
.extid_end = SBI_EXT_HSM,
.register_extensions = sbi_ecall_hsm_register_extensions,
.handle = sbi_ecall_hsm_handler,
.extid_start = SBI_EXT_HSM,
.extid_end = SBI_EXT_HSM,
.handle = sbi_ecall_hsm_handler,
};

View File

@@ -29,16 +29,8 @@ static int sbi_ecall_ipi_handler(unsigned long extid, unsigned long funcid,
return ret;
}
struct sbi_ecall_extension ecall_ipi;
static int sbi_ecall_ipi_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_ipi);
}
struct sbi_ecall_extension ecall_ipi = {
.extid_start = SBI_EXT_IPI,
.extid_end = SBI_EXT_IPI,
.register_extensions = sbi_ecall_ipi_register_extensions,
.handle = sbi_ecall_ipi_handler,
.extid_start = SBI_EXT_IPI,
.extid_end = SBI_EXT_IPI,
.handle = sbi_ecall_ipi_handler,
};

View File

@@ -112,21 +112,13 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
break;
default:
ret = SBI_ENOTSUPP;
}
};
return ret;
}
struct sbi_ecall_extension ecall_legacy;
static int sbi_ecall_legacy_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_legacy);
}
struct sbi_ecall_extension ecall_legacy = {
.extid_start = SBI_EXT_0_1_SET_TIMER,
.extid_end = SBI_EXT_0_1_SHUTDOWN,
.register_extensions = sbi_ecall_legacy_register_extensions,
.handle = sbi_ecall_legacy_handler,
.extid_start = SBI_EXT_0_1_SET_TIMER,
.extid_end = SBI_EXT_0_1_SHUTDOWN,
.handle = sbi_ecall_legacy_handler,
};

View File

@@ -76,21 +76,21 @@ static int sbi_ecall_pmu_handler(unsigned long extid, unsigned long funcid,
break;
default:
ret = SBI_ENOTSUPP;
}
};
return ret;
}
struct sbi_ecall_extension ecall_pmu;
static int sbi_ecall_pmu_register_extensions(void)
static int sbi_ecall_pmu_probe(unsigned long extid, unsigned long *out_val)
{
return sbi_ecall_register_extension(&ecall_pmu);
/* PMU extension is always enabled */
*out_val = 1;
return 0;
}
struct sbi_ecall_extension ecall_pmu = {
.extid_start = SBI_EXT_PMU,
.extid_end = SBI_EXT_PMU,
.register_extensions = sbi_ecall_pmu_register_extensions,
.handle = sbi_ecall_pmu_handler,
.extid_start = SBI_EXT_PMU,
.extid_end = SBI_EXT_PMU,
.handle = sbi_ecall_pmu_handler,
.probe = sbi_ecall_pmu_probe,
};

View File

@@ -74,21 +74,13 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
break;
default:
ret = SBI_ENOTSUPP;
}
};
return ret;
}
struct sbi_ecall_extension ecall_rfence;
static int sbi_ecall_rfence_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_rfence);
}
struct sbi_ecall_extension ecall_rfence = {
.extid_start = SBI_EXT_RFENCE,
.extid_end = SBI_EXT_RFENCE,
.register_extensions = sbi_ecall_rfence_register_extensions,
.handle = sbi_ecall_rfence_handler,
.extid_start = SBI_EXT_RFENCE,
.extid_end = SBI_EXT_RFENCE,
.handle = sbi_ecall_rfence_handler,
};

View File

@@ -48,36 +48,28 @@ static int sbi_ecall_srst_handler(unsigned long extid, unsigned long funcid,
return SBI_ENOTSUPP;
}
static bool srst_available(void)
static int sbi_ecall_srst_probe(unsigned long extid, unsigned long *out_val)
{
u32 type;
u32 type, count = 0;
/*
* At least one standard reset types should be supported by
* the platform for SBI SRST extension to be usable.
*/
for (type = 0; type <= SBI_SRST_RESET_TYPE_LAST; type++) {
if (sbi_system_reset_supported(type,
SBI_SRST_RESET_REASON_NONE))
return true;
count++;
}
return false;
}
struct sbi_ecall_extension ecall_srst;
static int sbi_ecall_srst_register_extensions(void)
{
if (!srst_available())
return 0;
return sbi_ecall_register_extension(&ecall_srst);
*out_val = (count) ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_srst = {
.extid_start = SBI_EXT_SRST,
.extid_end = SBI_EXT_SRST,
.register_extensions = sbi_ecall_srst_register_extensions,
.handle = sbi_ecall_srst_handler,
.extid_start = SBI_EXT_SRST,
.extid_end = SBI_EXT_SRST,
.handle = sbi_ecall_srst_handler,
.probe = sbi_ecall_srst_probe,
};

View File

@@ -23,9 +23,9 @@ static int sbi_ecall_susp_handler(unsigned long extid, unsigned long funcid,
return ret;
}
static bool susp_available(void)
static int sbi_ecall_susp_probe(unsigned long extid, unsigned long *out_val)
{
u32 type;
u32 type, count = 0;
/*
* At least one suspend type should be supported by the
@@ -33,25 +33,16 @@ static bool susp_available(void)
*/
for (type = 0; type <= SBI_SUSP_SLEEP_TYPE_LAST; type++) {
if (sbi_system_suspend_supported(type))
return true;
count++;
}
return false;
}
struct sbi_ecall_extension ecall_susp;
static int sbi_ecall_susp_register_extensions(void)
{
if (!susp_available())
return 0;
return sbi_ecall_register_extension(&ecall_susp);
*out_val = count ? 1 : 0;
return 0;
}
struct sbi_ecall_extension ecall_susp = {
.extid_start = SBI_EXT_SUSP,
.extid_end = SBI_EXT_SUSP,
.register_extensions = sbi_ecall_susp_register_extensions,
.handle = sbi_ecall_susp_handler,
.extid_start = SBI_EXT_SUSP,
.extid_end = SBI_EXT_SUSP,
.handle = sbi_ecall_susp_handler,
.probe = sbi_ecall_susp_probe,
};

View File

@@ -33,16 +33,8 @@ static int sbi_ecall_time_handler(unsigned long extid, unsigned long funcid,
return ret;
}
struct sbi_ecall_extension ecall_time;
static int sbi_ecall_time_register_extensions(void)
{
return sbi_ecall_register_extension(&ecall_time);
}
struct sbi_ecall_extension ecall_time = {
.extid_start = SBI_EXT_TIME,
.extid_end = SBI_EXT_TIME,
.register_extensions = sbi_ecall_time_register_extensions,
.handle = sbi_ecall_time_handler,
.extid_start = SBI_EXT_TIME,
.extid_end = SBI_EXT_TIME,
.handle = sbi_ecall_time_handler,
};

View File

@@ -22,34 +22,34 @@ static inline unsigned long sbi_ecall_vendor_id(void)
(SBI_EXT_VENDOR_END - SBI_EXT_VENDOR_START));
}
static int sbi_ecall_vendor_probe(unsigned long extid,
unsigned long *out_val)
{
if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()) ||
extid != sbi_ecall_vendor_id())
*out_val = 0;
else
*out_val = 1;
return 0;
}
static int sbi_ecall_vendor_handler(unsigned long extid, unsigned long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_val,
struct sbi_trap_info *out_trap)
{
if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()) ||
extid != sbi_ecall_vendor_id())
return SBI_ERR_NOT_SUPPORTED;
return sbi_platform_vendor_ext_provider(sbi_platform_thishart_ptr(),
funcid, regs,
out_val, out_trap);
}
struct sbi_ecall_extension ecall_vendor;
static int sbi_ecall_vendor_register_extensions(void)
{
unsigned long extid = sbi_ecall_vendor_id();
if (!sbi_platform_vendor_ext_check(sbi_platform_thishart_ptr()))
return 0;
ecall_vendor.extid_start = extid;
ecall_vendor.extid_end = extid;
return sbi_ecall_register_extension(&ecall_vendor);
}
struct sbi_ecall_extension ecall_vendor = {
.extid_start = SBI_EXT_VENDOR_START,
.extid_end = SBI_EXT_VENDOR_END,
.register_extensions = sbi_ecall_vendor_register_extensions,
.handle = sbi_ecall_vendor_handler,
.extid_start = SBI_EXT_VENDOR_START,
.extid_end = SBI_EXT_VENDOR_END,
.probe = sbi_ecall_vendor_probe,
.handle = sbi_ecall_vendor_handler,
};

View File

@@ -149,7 +149,7 @@ int sbi_emulate_csr_read(int csr_num, struct sbi_trap_regs *regs,
default:
ret = SBI_ENOTSUPP;
break;
}
};
if (ret)
sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",
@@ -187,7 +187,7 @@ int sbi_emulate_csr_write(int csr_num, struct sbi_trap_regs *regs,
default:
ret = SBI_ENOTSUPP;
break;
}
};
if (ret)
sbi_dprintf("%s: hartid%d: invalid csr_num=0x%x\n",

View File

@@ -33,6 +33,7 @@ static unsigned long hart_features_offset;
static void mstatus_init(struct sbi_scratch *scratch)
{
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
unsigned long menvcfg_val, mstatus_val = 0;
int cidx;
unsigned int num_mhpm = sbi_hart_mhpm_count(scratch);
@@ -62,6 +63,11 @@ static void mstatus_init(struct sbi_scratch *scratch)
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
if (sbi_platform_force_emulate_time_csr(plat)) {
csr_clear(CSR_MCOUNTEREN, MCOUNTEREN_TM);
csr_clear(CSR_SCOUNTEREN, MCOUNTEREN_TM);
}
/* All programmable counters will start running at runtime after S-mode request */
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
@@ -558,6 +564,7 @@ static int hart_pmu_get_allowed_bits(void)
static int hart_detect_features(struct sbi_scratch *scratch)
{
struct sbi_trap_info trap = {0};
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_hart_features *hfeatures =
sbi_scratch_offset_ptr(scratch, hart_features_offset);
unsigned long val, oldval;
@@ -673,10 +680,12 @@ __mhpm_skip:
}
/* Detect if hart supports time CSR */
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
__sbi_hart_update_extension(hfeatures,
SBI_HART_EXT_TIME, true);
if (!sbi_platform_force_emulate_time_csr(plat)) {
csr_read_allowed(CSR_TIME, (unsigned long)&trap);
if (!trap.cause)
__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);
@@ -733,12 +742,6 @@ int sbi_hart_init(struct sbi_scratch *scratch, bool cold_boot)
{
int rc;
/*
* Clear mip CSR before proceeding with init to avoid any spurious
* external interrupts in S-mode.
*/
csr_write(CSR_MIP, 0);
if (cold_boot) {
if (misa_extension('H'))
sbi_hart_expected_trap = &__sbi_expected_trap_hext;

View File

@@ -1,206 +0,0 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Ventana Micro Systems Inc.
*
* Authors:
* Anup Patel<apatel@ventanamicro.com>
*/
#include <sbi/riscv_locks.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_list.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>
/* Alignment of heap base address and size */
#define HEAP_BASE_ALIGN 1024
/* Minimum size and alignment of heap allocations */
#define HEAP_ALLOC_ALIGN 64
#define HEAP_HOUSEKEEPING_FACTOR 16
struct heap_node {
struct sbi_dlist head;
unsigned long addr;
unsigned long size;
};
struct heap_control {
spinlock_t lock;
unsigned long base;
unsigned long size;
unsigned long hkbase;
unsigned long hksize;
struct sbi_dlist free_node_list;
struct sbi_dlist free_space_list;
struct sbi_dlist used_space_list;
};
static struct heap_control hpctrl;
void *sbi_malloc(size_t size)
{
void *ret = NULL;
struct heap_node *n, *np;
if (!size)
return NULL;
size += HEAP_ALLOC_ALIGN - 1;
size &= ~((unsigned long)HEAP_ALLOC_ALIGN - 1);
spin_lock(&hpctrl.lock);
np = NULL;
sbi_list_for_each_entry(n, &hpctrl.free_space_list, head) {
if (size <= n->size) {
np = n;
break;
}
}
if (np) {
if ((size < np->size) &&
!sbi_list_empty(&hpctrl.free_node_list)) {
n = sbi_list_first_entry(&hpctrl.free_node_list,
struct heap_node, head);
sbi_list_del(&n->head);
n->addr = np->addr + np->size - size;
n->size = size;
np->size -= size;
sbi_list_add_tail(&n->head, &hpctrl.used_space_list);
ret = (void *)n->addr;
} else if (size == np->size) {
sbi_list_del(&np->head);
sbi_list_add_tail(&np->head, &hpctrl.used_space_list);
ret = (void *)np->addr;
}
}
spin_unlock(&hpctrl.lock);
return ret;
}
void *sbi_zalloc(size_t size)
{
void *ret = sbi_malloc(size);
if (ret)
sbi_memset(ret, 0, size);
return ret;
}
void sbi_free(void *ptr)
{
struct heap_node *n, *np;
if (!ptr)
return;
spin_lock(&hpctrl.lock);
np = NULL;
sbi_list_for_each_entry(n, &hpctrl.used_space_list, head) {
if ((n->addr <= (unsigned long)ptr) &&
((unsigned long)ptr < (n->addr + n->size))) {
np = n;
break;
}
}
if (!np) {
spin_unlock(&hpctrl.lock);
return;
}
sbi_list_del(&np->head);
sbi_list_for_each_entry(n, &hpctrl.free_space_list, head) {
if ((np->addr + np->size) == n->addr) {
n->addr = np->addr;
n->size += np->size;
sbi_list_add_tail(&np->head, &hpctrl.free_node_list);
np = NULL;
break;
} else if (np->addr == (n->addr + n->size)) {
n->size += np->size;
sbi_list_add_tail(&np->head, &hpctrl.free_node_list);
np = NULL;
break;
} else if ((n->addr + n->size) < np->addr) {
sbi_list_add(&np->head, &n->head);
np = NULL;
break;
}
}
if (np)
sbi_list_add_tail(&np->head, &hpctrl.free_space_list);
spin_unlock(&hpctrl.lock);
}
unsigned long sbi_heap_free_space(void)
{
struct heap_node *n;
unsigned long ret = 0;
spin_lock(&hpctrl.lock);
sbi_list_for_each_entry(n, &hpctrl.free_space_list, head)
ret += n->size;
spin_unlock(&hpctrl.lock);
return ret;
}
unsigned long sbi_heap_used_space(void)
{
return hpctrl.size - hpctrl.hksize - sbi_heap_free_space();
}
unsigned long sbi_heap_reserved_space(void)
{
return hpctrl.hksize;
}
int sbi_heap_init(struct sbi_scratch *scratch)
{
unsigned long i;
struct heap_node *n;
/* Sanity checks on heap offset and size */
if (!scratch->fw_heap_size ||
(scratch->fw_heap_size & (HEAP_BASE_ALIGN - 1)) ||
(scratch->fw_heap_offset < scratch->fw_rw_offset) ||
(scratch->fw_size < (scratch->fw_heap_offset + scratch->fw_heap_size)) ||
(scratch->fw_heap_offset & (HEAP_BASE_ALIGN - 1)))
return SBI_EINVAL;
/* Initialize heap control */
SPIN_LOCK_INIT(hpctrl.lock);
hpctrl.base = scratch->fw_start + scratch->fw_heap_offset;
hpctrl.size = scratch->fw_heap_size;
hpctrl.hkbase = hpctrl.base;
hpctrl.hksize = hpctrl.size / HEAP_HOUSEKEEPING_FACTOR;
hpctrl.hksize &= ~((unsigned long)HEAP_BASE_ALIGN - 1);
SBI_INIT_LIST_HEAD(&hpctrl.free_node_list);
SBI_INIT_LIST_HEAD(&hpctrl.free_space_list);
SBI_INIT_LIST_HEAD(&hpctrl.used_space_list);
/* Prepare free node list */
for (i = 0; i < (hpctrl.hksize / sizeof(*n)); i++) {
n = (struct heap_node *)(hpctrl.hkbase + (sizeof(*n) * i));
SBI_INIT_LIST_HEAD(&n->head);
n->addr = n->size = 0;
sbi_list_add_tail(&n->head, &hpctrl.free_node_list);
}
/* Prepare free space list */
n = sbi_list_first_entry(&hpctrl.free_node_list,
struct heap_node, head);
sbi_list_del(&n->head);
n->addr = hpctrl.hkbase + hpctrl.hksize;
n->size = hpctrl.size - hpctrl.hksize;
sbi_list_add_tail(&n->head, &hpctrl.free_space_list);
return 0;
}

View File

@@ -172,7 +172,7 @@ static void sbi_hsm_hart_wait(struct sbi_scratch *scratch, u32 hartid)
/* Wait for state transition requested by sbi_hsm_hart_start() */
while (atomic_read(&hdata->state) != SBI_HSM_STATE_START_PENDING) {
wfi();
}
};
/* Restore MIE CSR */
csr_write(CSR_MIE, saved_mie);
@@ -301,7 +301,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
const struct sbi_domain *dom,
u32 hartid, ulong saddr, ulong smode, ulong arg1)
{
unsigned long init_count, entry_count;
unsigned long init_count;
unsigned int hstate;
struct sbi_scratch *rscratch;
struct sbi_hsm_data *hdata;
@@ -325,8 +325,6 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
return SBI_EINVAL;
init_count = sbi_init_count(hartid);
entry_count = sbi_entry_count(hartid);
rscratch->next_arg1 = arg1;
rscratch->next_addr = saddr;
rscratch->next_mode = smode;
@@ -352,7 +350,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
goto err;
}
if ((hsm_device_has_hart_hotplug() && (entry_count == init_count)) ||
if (hsm_device_has_hart_hotplug() ||
(hsm_device_has_hart_secondary_boot() && !init_count)) {
rc = hsm_device_hart_start(hartid, scratch->warmboot_addr);
} else {

View File

@@ -90,7 +90,7 @@ static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs)
break;
default:
return truly_illegal_insn(insn, regs);
}
};
if (do_write && sbi_emulate_csr_write(csr_num, regs, new_csr_val))
return truly_illegal_insn(insn, regs);

View File

@@ -12,12 +12,10 @@
#include <sbi/riscv_barrier.h>
#include <sbi/riscv_locks.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_cppc.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_irqchip.h>
@@ -72,7 +70,6 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
const struct sbi_console_device *cdev;
const struct sbi_system_reset_device *srdev;
const struct sbi_system_suspend_device *susp_dev;
const struct sbi_cppc_device *cppc_dev;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
@@ -110,29 +107,12 @@ static void sbi_boot_print_general(struct sbi_scratch *scratch)
susp_dev = sbi_system_suspend_get_device();
sbi_printf("Platform Suspend Device : %s\n",
(susp_dev) ? susp_dev->name : "---");
cppc_dev = sbi_cppc_get_device();
sbi_printf("Platform CPPC Device : %s\n",
(cppc_dev) ? cppc_dev->name : "---");
/* Firmware details */
sbi_printf("Firmware Base : 0x%lx\n", scratch->fw_start);
sbi_printf("Firmware Size : %d KB\n",
(u32)(scratch->fw_size / 1024));
sbi_printf("Firmware RW Offset : 0x%lx\n", scratch->fw_rw_offset);
sbi_printf("Firmware RW Size : %d KB\n",
(u32)((scratch->fw_size - scratch->fw_rw_offset) / 1024));
sbi_printf("Firmware Heap Offset : 0x%lx\n", scratch->fw_heap_offset);
sbi_printf("Firmware Heap Size : "
"%d KB (total), %d KB (reserved), %d KB (used), %d KB (free)\n",
(u32)(scratch->fw_heap_size / 1024),
(u32)(sbi_heap_reserved_space() / 1024),
(u32)(sbi_heap_used_space() / 1024),
(u32)(sbi_heap_free_space() / 1024));
sbi_printf("Firmware Scratch Size : "
"%d B (total), %d B (used), %d B (free)\n",
SBI_SCRATCH_SIZE,
(u32)sbi_scratch_used_space(),
(u32)(SBI_SCRATCH_SIZE - sbi_scratch_used_space()));
/* SBI details */
sbi_printf("Runtime SBI Version : %d.%d\n",
@@ -215,7 +195,7 @@ static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
wfi();
cmip = csr_read(CSR_MIP);
} while (!(cmip & (MIP_MSIP | MIP_MEIP)));
}
};
/* Acquire coldboot lock */
spin_lock(&coldboot_lock);
@@ -258,13 +238,12 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch, u32 hartid)
spin_unlock(&coldboot_lock);
}
static unsigned long entry_count_offset;
static unsigned long init_count_offset;
static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
{
int rc;
unsigned long *count;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
/* Note: This has to be first thing in coldboot init sequence */
@@ -273,26 +252,14 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
/* Note: This has to be second thing in coldboot init sequence */
rc = sbi_heap_init(scratch);
if (rc)
sbi_hart_hang();
/* Note: This has to be the third thing in coldboot init sequence */
rc = sbi_domain_init(scratch, hartid);
if (rc)
sbi_hart_hang();
entry_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__);
if (!entry_count_offset)
sbi_hart_hang();
init_count_offset = sbi_scratch_alloc_offset(__SIZEOF_POINTER__);
if (!init_count_offset)
sbi_hart_hang();
count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
(*count)++;
rc = sbi_hsm_init(scratch, hartid, true);
if (rc)
sbi_hart_hang();
@@ -310,11 +277,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
rc = sbi_pmu_init(scratch, true);
if (rc) {
sbi_printf("%s: pmu init failed (error %d)\n",
__func__, rc);
if (rc)
sbi_hart_hang();
}
sbi_boot_print_banner(scratch);
@@ -343,6 +307,12 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
rc = sbi_ecall_init();
if (rc) {
sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
/*
* Note: Finalize domains after HSM initialization so that we
* can startup non-root domains.
@@ -364,9 +334,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
}
/*
* Note: Platform final initialization should be after finalizing
* domains so that it sees correct domain assignment and PMP
* configuration for FDT fixups.
* Note: Platform final initialization should be last so that
* it sees correct domain assignment and PMP configuration.
*/
rc = sbi_platform_final_init(plat, true);
if (rc) {
@@ -375,17 +344,6 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
sbi_hart_hang();
}
/*
* Note: Ecall initialization should be after platform final
* initialization so that all available platform devices are
* already registered.
*/
rc = sbi_ecall_init();
if (rc) {
sbi_printf("%s: ecall init failed (error %d)\n", __func__, rc);
sbi_hart_hang();
}
sbi_boot_print_general(scratch);
sbi_boot_print_domains(scratch);
@@ -394,8 +352,8 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
wake_coldboot_harts(scratch, hartid);
count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*count)++;
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hsm_hart_start_finish(scratch, hartid);
}
@@ -404,15 +362,12 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
u32 hartid)
{
int rc;
unsigned long *count;
unsigned long *init_count;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (!entry_count_offset || !init_count_offset)
if (!init_count_offset)
sbi_hart_hang();
count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
(*count)++;
rc = sbi_hsm_init(scratch, hartid, false);
if (rc)
sbi_hart_hang();
@@ -453,8 +408,8 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
if (rc)
sbi_hart_hang();
count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*count)++;
init_count = sbi_scratch_offset_ptr(scratch, init_count_offset);
(*init_count)++;
sbi_hsm_hart_start_finish(scratch, hartid);
}
@@ -566,23 +521,6 @@ void __noreturn sbi_init(struct sbi_scratch *scratch)
init_warmboot(scratch, hartid);
}
unsigned long sbi_entry_count(u32 hartid)
{
struct sbi_scratch *scratch;
unsigned long *entry_count;
if (!entry_count_offset)
return 0;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return 0;
entry_count = sbi_scratch_offset_ptr(scratch, entry_count_offset);
return *entry_count;
}
unsigned long sbi_init_count(u32 hartid)
{
struct sbi_scratch *scratch;

View File

@@ -15,6 +15,7 @@
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
@@ -31,7 +32,7 @@ static unsigned long ipi_data_off;
static const struct sbi_ipi_device *ipi_dev = NULL;
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
static int sbi_ipi_update(struct sbi_scratch *scratch, u32 remote_hartid,
u32 event, void *data)
{
int ret;
@@ -53,7 +54,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
if (ipi_ops->update) {
ret = ipi_ops->update(scratch, remote_scratch,
remote_hartid, data);
if (ret != SBI_IPI_UPDATE_SUCCESS)
if (ret < 0)
return ret;
}
@@ -77,7 +78,7 @@ static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event)
const struct sbi_ipi_event_ops *ipi_ops;
if ((SBI_IPI_EVENT_MAX <= event) ||
!ipi_ops_array[event])
!ipi_ops_array[event])
return SBI_EINVAL;
ipi_ops = ipi_ops_array[event];
@@ -94,14 +95,13 @@ static int sbi_ipi_sync(struct sbi_scratch *scratch, u32 event)
*/
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
{
int rc;
bool retry_needed;
int rc, done;
ulong i, m;
struct sbi_hartmask target_mask = {0};
struct sbi_hartmask retry_mask = {0};
struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
/* Find the target harts */
if (hbase != -1UL) {
rc = sbi_hsm_hart_interruptible_mask(dom, hbase, &m);
if (rc)
@@ -123,19 +123,19 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
}
}
/* Send IPIs */
retry_mask = target_mask;
do {
retry_needed = false;
sbi_hartmask_for_each_hart(i, &target_mask) {
rc = sbi_ipi_send(scratch, i, event, data);
if (rc == SBI_IPI_UPDATE_RETRY)
retry_needed = true;
done = true;
sbi_hartmask_for_each_hart(i, &retry_mask) {
rc = sbi_ipi_update(scratch, i, event, data);
if (rc == -2)
done = false;
else
sbi_hartmask_clear_hart(i, &target_mask);
sbi_hartmask_clear_hart(i, &retry_mask);
}
} while (retry_needed);
} while (!done);
/* Sync IPIs */
/* sync IPIs */
sbi_ipi_sync(scratch, event);
return 0;
@@ -223,14 +223,17 @@ void sbi_ipi_process(void)
ipi_type = atomic_raw_xchg_ulong(&ipi_data->ipi_type, 0);
ipi_event = 0;
while (ipi_type) {
if (ipi_type & 1UL) {
ipi_ops = ipi_ops_array[ipi_event];
if (ipi_ops && ipi_ops->process)
ipi_ops->process(scratch);
}
if (!(ipi_type & 1UL))
goto skip;
ipi_ops = ipi_ops_array[ipi_event];
if (ipi_ops && ipi_ops->process)
ipi_ops->process(scratch);
skip:
ipi_type = ipi_type >> 1;
ipi_event++;
}
};
}
int sbi_ipi_raw_send(u32 target_hart)

View File

@@ -12,7 +12,7 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_scratch.h>
@@ -50,43 +50,27 @@ union sbi_pmu_ctr_info {
};
};
#if SBI_PMU_FW_CTR_MAX >= BITS_PER_LONG
#error "Can't handle firmware counters beyond BITS_PER_LONG"
#endif
/** Per-HART state of the PMU counters */
struct sbi_pmu_hart_state {
/* HART to which this state belongs */
uint32_t hartid;
/* Counter to enabled event mapping */
uint32_t active_events[SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX];
/* Bitmap of firmware counters started */
unsigned long fw_counters_started;
/*
* Counter values for SBI firmware events and event codes
* for platform firmware events. Both are mutually exclusive
* and hence can optimally share the same memory.
*/
uint64_t fw_counters_data[SBI_PMU_FW_CTR_MAX];
};
/** Offset of pointer to PMU HART state in scratch space */
static unsigned long phs_ptr_offset;
#define pmu_get_hart_state_ptr(__scratch) \
sbi_scratch_read_type((__scratch), void *, phs_ptr_offset)
#define pmu_thishart_state_ptr() \
pmu_get_hart_state_ptr(sbi_scratch_thishart_ptr())
#define pmu_set_hart_state_ptr(__scratch, __phs) \
sbi_scratch_write_type((__scratch), void *, phs_ptr_offset, (__phs))
/* Platform specific PMU device */
static const struct sbi_pmu_device *pmu_dev = NULL;
/* Mapping between event range and possible counters */
static struct sbi_pmu_hw_event *hw_event_map;
static struct sbi_pmu_hw_event hw_event_map[SBI_PMU_HW_EVENT_MAX] = {0};
/* counter to enabled event mapping */
static uint32_t active_events[SBI_HARTMASK_MAX_BITS][SBI_PMU_HW_CTR_MAX + SBI_PMU_FW_CTR_MAX];
/* Bitmap of firmware counters started on each HART */
#if SBI_PMU_FW_CTR_MAX >= BITS_PER_LONG
#error "Can't handle firmware counters beyond BITS_PER_LONG"
#endif
static unsigned long fw_counters_started[SBI_HARTMASK_MAX_BITS];
/*
* Counter values for SBI firmware events and event codes for platform
* firmware events. Both are mutually exclusive and hence can optimally share
* the same memory.
*/
static uint64_t fw_counters_data[SBI_HARTMASK_MAX_BITS][SBI_PMU_FW_CTR_MAX] = {0};
/* Maximum number of hardware events available */
static uint32_t num_hw_events;
@@ -97,8 +81,7 @@ static uint32_t num_hw_ctrs;
static uint32_t total_ctrs;
/* Helper macros to retrieve event idx and code type */
#define get_cidx_type(x) \
(((x) & SBI_PMU_EVENT_IDX_TYPE_MASK) >> SBI_PMU_EVENT_IDX_TYPE_OFFSET)
#define get_cidx_type(x) ((x & SBI_PMU_EVENT_IDX_TYPE_MASK) >> 16)
#define get_cidx_code(x) (x & SBI_PMU_EVENT_IDX_CODE_MASK)
/**
@@ -127,13 +110,13 @@ static bool pmu_event_select_overlap(struct sbi_pmu_hw_event *evt,
return false;
}
static int pmu_event_validate(struct sbi_pmu_hart_state *phs,
unsigned long event_idx, uint64_t edata)
static int pmu_event_validate(unsigned long event_idx, uint64_t edata)
{
uint32_t event_idx_type = get_cidx_type(event_idx);
uint32_t event_idx_code = get_cidx_code(event_idx);
uint32_t event_idx_code_max = -1;
uint32_t cache_ops_result, cache_ops_id, cache_id;
u32 hartid = current_hartid();
switch(event_idx_type) {
case SBI_PMU_EVENT_TYPE_HW:
@@ -147,7 +130,7 @@ static int pmu_event_validate(struct sbi_pmu_hart_state *phs,
if (SBI_PMU_FW_PLATFORM == event_idx_code &&
pmu_dev && pmu_dev->fw_event_validate_encoding)
return pmu_dev->fw_event_validate_encoding(phs->hartid,
return pmu_dev->fw_event_validate_encoding(hartid,
edata);
else
event_idx_code_max = SBI_PMU_FW_MAX;
@@ -181,16 +164,16 @@ static int pmu_event_validate(struct sbi_pmu_hart_state *phs,
return SBI_EINVAL;
}
static int pmu_ctr_validate(struct sbi_pmu_hart_state *phs,
uint32_t cidx, uint32_t *event_idx_code)
static int pmu_ctr_validate(uint32_t cidx, uint32_t *event_idx_code)
{
uint32_t event_idx_val;
uint32_t event_idx_type;
u32 hartid = current_hartid();
if (cidx >= total_ctrs)
return SBI_EINVAL;
event_idx_val = phs->active_events[cidx];
event_idx_val = active_events[hartid][cidx];
event_idx_type = get_cidx_type(event_idx_val);
if (event_idx_val == SBI_PMU_EVENT_IDX_INVALID ||
event_idx_type >= SBI_PMU_EVENT_TYPE_MAX)
@@ -205,9 +188,9 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
{
int event_idx_type;
uint32_t event_code;
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
u32 hartid = current_hartid();
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type != SBI_PMU_EVENT_TYPE_FW)
return SBI_EINVAL;
@@ -218,13 +201,13 @@ int sbi_pmu_ctr_fw_read(uint32_t cidx, uint64_t *cval)
if (SBI_PMU_FW_PLATFORM == event_code) {
if (pmu_dev && pmu_dev->fw_counter_read_value)
*cval = pmu_dev->fw_counter_read_value(phs->hartid,
*cval = pmu_dev->fw_counter_read_value(hartid,
cidx -
num_hw_ctrs);
else
*cval = 0;
} else
*cval = phs->fw_counters_data[cidx - num_hw_ctrs];
*cval = fw_counters_data[hartid][cidx - num_hw_ctrs];
return 0;
}
@@ -354,8 +337,11 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
if (cidx >= num_hw_ctrs || cidx == 1)
return SBI_EINVAL;
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11)
goto skip_inhibit_update;
if (sbi_hart_priv_version(scratch) < SBI_HART_PRIV_VER_1_11) {
if (ival_update)
pmu_ctr_write_hw(cidx, ival);
return 0;
}
/*
* Some of the hardware may not support mcountinhibit but perf stat
@@ -371,12 +357,12 @@ static int pmu_ctr_start_hw(uint32_t cidx, uint64_t ival, bool ival_update)
pmu_ctr_enable_irq_hw(cidx);
if (pmu_dev && pmu_dev->hw_counter_enable_irq)
pmu_dev->hw_counter_enable_irq(cidx);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
skip_inhibit_update:
if (ival_update)
pmu_ctr_write_hw(cidx, ival);
csr_write(CSR_MCOUNTINHIBIT, mctr_inhbt);
return 0;
}
@@ -392,11 +378,12 @@ int sbi_pmu_irq_bit(void)
return 0;
}
static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs,
uint32_t cidx, uint32_t event_code,
static int pmu_ctr_start_fw(uint32_t cidx, uint32_t event_code,
uint64_t event_data, uint64_t ival,
bool ival_update)
{
u32 hartid = current_hartid();
if ((event_code >= SBI_PMU_FW_MAX &&
event_code <= SBI_PMU_FW_RESERVED_MAX) ||
event_code > SBI_PMU_FW_PLATFORM)
@@ -410,19 +397,18 @@ static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs,
}
if (ival_update)
pmu_dev->fw_counter_write_value(phs->hartid,
pmu_dev->fw_counter_write_value(hartid,
cidx - num_hw_ctrs,
ival);
return pmu_dev->fw_counter_start(phs->hartid,
cidx - num_hw_ctrs,
return pmu_dev->fw_counter_start(hartid, cidx - num_hw_ctrs,
event_data);
} else {
if (ival_update)
phs->fw_counters_data[cidx - num_hw_ctrs] = ival;
fw_counters_data[hartid][cidx - num_hw_ctrs] = ival;
}
phs->fw_counters_started |= BIT(cidx - num_hw_ctrs);
fw_counters_started[hartid] |= BIT(cidx - num_hw_ctrs);
return 0;
}
@@ -430,7 +416,7 @@ static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs,
int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
unsigned long flags, uint64_t ival)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
u32 hartid = current_hartid();
int event_idx_type;
uint32_t event_code;
int ret = SBI_EINVAL;
@@ -446,16 +432,16 @@ int sbi_pmu_ctr_start(unsigned long cbase, unsigned long cmask,
for_each_set_bit(i, &cmask, total_ctrs) {
cidx = i + cbase;
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
/* Continue the start operation for other counters */
continue;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW) {
edata = (event_code == SBI_PMU_FW_PLATFORM) ?
phs->fw_counters_data[cidx - num_hw_ctrs]
fw_counters_data[hartid][cidx - num_hw_ctrs]
: 0x0;
ret = pmu_ctr_start_fw(phs, cidx, event_code, edata,
ival, bUpdate);
ret = pmu_ctr_start_fw(cidx, event_code, edata, ival,
bUpdate);
}
else
ret = pmu_ctr_start_hw(cidx, ival, bUpdate);
@@ -486,9 +472,9 @@ static int pmu_ctr_stop_hw(uint32_t cidx)
return SBI_EALREADY_STOPPED;
}
static int pmu_ctr_stop_fw(struct sbi_pmu_hart_state *phs,
uint32_t cidx, uint32_t event_code)
static int pmu_ctr_stop_fw(uint32_t cidx, uint32_t event_code)
{
u32 hartid = current_hartid();
int ret;
if ((event_code >= SBI_PMU_FW_MAX &&
@@ -498,12 +484,12 @@ static int pmu_ctr_stop_fw(struct sbi_pmu_hart_state *phs,
if (SBI_PMU_FW_PLATFORM == event_code &&
pmu_dev && pmu_dev->fw_counter_stop) {
ret = pmu_dev->fw_counter_stop(phs->hartid, cidx - num_hw_ctrs);
ret = pmu_dev->fw_counter_stop(hartid, cidx - num_hw_ctrs);
if (ret)
return ret;
}
phs->fw_counters_started &= ~BIT(cidx - num_hw_ctrs);
fw_counters_started[current_hartid()] &= ~BIT(cidx - num_hw_ctrs);
return 0;
}
@@ -527,7 +513,7 @@ static int pmu_reset_hw_mhpmevent(int ctr_idx)
int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
unsigned long flag)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
u32 hartid = current_hartid();
int ret = SBI_EINVAL;
int event_idx_type;
uint32_t event_code;
@@ -538,18 +524,21 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
for_each_set_bit(i, &cmask, total_ctrs) {
cidx = i + cbase;
event_idx_type = pmu_ctr_validate(phs, cidx, &event_code);
event_idx_type = pmu_ctr_validate(cidx, &event_code);
if (event_idx_type < 0)
/* Continue the stop operation for other counters */
continue;
else if (event_idx_type == SBI_PMU_EVENT_TYPE_FW)
ret = pmu_ctr_stop_fw(phs, cidx, event_code);
ret = pmu_ctr_stop_fw(cidx, event_code);
else
ret = pmu_ctr_stop_hw(cidx);
if (cidx > (CSR_INSTRET - CSR_CYCLE) && flag & SBI_PMU_STOP_FLAG_RESET) {
phs->active_events[cidx] = SBI_PMU_EVENT_IDX_INVALID;
if (flag & SBI_PMU_STOP_FLAG_RESET) {
if (pmu_dev && pmu_dev->hw_counter_disable_irq)
pmu_dev->hw_counter_disable_irq(cidx);
active_events[hartid][cidx] = SBI_PMU_EVENT_IDX_INVALID;
pmu_reset_hw_mhpmevent(cidx);
}
}
@@ -620,15 +609,14 @@ static int pmu_ctr_find_fixed_fw(unsigned long evt_idx_code)
return SBI_EINVAL;
}
static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
unsigned long cbase, unsigned long cmask,
unsigned long flags,
static int pmu_ctr_find_hw(unsigned long cbase, unsigned long cmask, unsigned long flags,
unsigned long event_idx, uint64_t data)
{
unsigned long ctr_mask;
int i, ret = 0, fixed_ctr, ctr_idx = SBI_ENOTSUPP;
struct sbi_pmu_hw_event *temp;
unsigned long mctr_inhbt = 0;
u32 hartid = current_hartid();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (cbase >= num_hw_ctrs)
@@ -667,7 +655,7 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
* Some of the platform may not support mcountinhibit.
* Checking the active_events is enough for them
*/
if (phs->active_events[cbase] != SBI_PMU_EVENT_IDX_INVALID)
if (active_events[hartid][cbase] != SBI_PMU_EVENT_IDX_INVALID)
continue;
/* If mcountinhibit is supported, the bit must be enabled */
if ((sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) &&
@@ -702,9 +690,8 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
* Thus, select the first available fw counter after sanity
* check.
*/
static int pmu_ctr_find_fw(struct sbi_pmu_hart_state *phs,
unsigned long cbase, unsigned long cmask,
uint32_t event_code, uint64_t edata)
static int pmu_ctr_find_fw(unsigned long cbase, unsigned long cmask,
uint32_t event_code, u32 hartid, uint64_t edata)
{
int i, cidx;
@@ -717,11 +704,11 @@ static int pmu_ctr_find_fw(struct sbi_pmu_hart_state *phs,
cidx = i + cbase;
if (cidx < num_hw_ctrs || total_ctrs <= cidx)
continue;
if (phs->active_events[i] != SBI_PMU_EVENT_IDX_INVALID)
if (active_events[hartid][i] != SBI_PMU_EVENT_IDX_INVALID)
continue;
if (SBI_PMU_FW_PLATFORM == event_code &&
pmu_dev && pmu_dev->fw_counter_match_encoding) {
if (!pmu_dev->fw_counter_match_encoding(phs->hartid,
if (!pmu_dev->fw_counter_match_encoding(hartid,
cidx - num_hw_ctrs,
edata))
continue;
@@ -737,15 +724,15 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
unsigned long flags, unsigned long event_idx,
uint64_t event_data)
{
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
int ret, event_type, ctr_idx = SBI_ENOTSUPP;
u32 event_code;
int ret, ctr_idx = SBI_ENOTSUPP;
u32 event_code, hartid = current_hartid();
int event_type;
/* Do a basic sanity check of counter base & mask */
if ((cidx_base + sbi_fls(cidx_mask)) >= total_ctrs)
return SBI_EINVAL;
event_type = pmu_event_validate(phs, event_idx, event_data);
event_type = pmu_event_validate(event_idx, event_data);
if (event_type < 0)
return SBI_EINVAL;
event_code = get_cidx_code(event_idx);
@@ -754,34 +741,29 @@ int sbi_pmu_ctr_cfg_match(unsigned long cidx_base, unsigned long cidx_mask,
/* The caller wants to skip the match because it already knows the
* counter idx for the given event. Verify that the counter idx
* is still valid.
* As per the specification, we should "unconditionally select
* the first counter from the set of counters specified by the
* counter_idx_base and counter_idx_mask".
*/
unsigned long cidx_first = cidx_base + sbi_ffs(cidx_mask);
if (phs->active_events[cidx_first] == SBI_PMU_EVENT_IDX_INVALID)
if (active_events[hartid][cidx_base] == SBI_PMU_EVENT_IDX_INVALID)
return SBI_EINVAL;
ctr_idx = cidx_first;
ctr_idx = cidx_base;
goto skip_match;
}
if (event_type == SBI_PMU_EVENT_TYPE_FW) {
/* Any firmware counter can be used track any firmware event */
ctr_idx = pmu_ctr_find_fw(phs, cidx_base, cidx_mask,
event_code, event_data);
ctr_idx = pmu_ctr_find_fw(cidx_base, cidx_mask, event_code,
hartid, event_data);
if (event_code == SBI_PMU_FW_PLATFORM)
phs->fw_counters_data[ctr_idx - num_hw_ctrs] =
fw_counters_data[hartid][ctr_idx - num_hw_ctrs] =
event_data;
} else {
ctr_idx = pmu_ctr_find_hw(phs, cidx_base, cidx_mask, flags,
event_idx, event_data);
ctr_idx = pmu_ctr_find_hw(cidx_base, cidx_mask, flags, event_idx,
event_data);
}
if (ctr_idx < 0)
return SBI_ENOTSUPP;
phs->active_events[ctr_idx] = event_idx;
active_events[hartid][ctr_idx] = event_idx;
skip_match:
if (event_type == SBI_PMU_EVENT_TYPE_HW) {
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
@@ -790,17 +772,16 @@ skip_match:
pmu_ctr_start_hw(ctr_idx, 0, false);
} else if (event_type == SBI_PMU_EVENT_TYPE_FW) {
if (flags & SBI_PMU_CFG_FLAG_CLEAR_VALUE)
phs->fw_counters_data[ctr_idx - num_hw_ctrs] = 0;
fw_counters_data[hartid][ctr_idx - num_hw_ctrs] = 0;
if (flags & SBI_PMU_CFG_FLAG_AUTO_START) {
if (SBI_PMU_FW_PLATFORM == event_code &&
pmu_dev && pmu_dev->fw_counter_start) {
ret = pmu_dev->fw_counter_start(
phs->hartid,
ret = pmu_dev->fw_counter_start(hartid,
ctr_idx - num_hw_ctrs, event_data);
if (ret)
return ret;
}
phs->fw_counters_started |= BIT(ctr_idx - num_hw_ctrs);
fw_counters_started[hartid] |= BIT(ctr_idx - num_hw_ctrs);
}
}
@@ -809,20 +790,19 @@ skip_match:
int sbi_pmu_ctr_incr_fw(enum sbi_pmu_fw_event_code_id fw_id)
{
u32 cidx;
u32 cidx, hartid = current_hartid();
uint64_t *fcounter = NULL;
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
if (likely(!phs->fw_counters_started))
if (likely(!fw_counters_started[hartid]))
return 0;
if (unlikely(fw_id >= SBI_PMU_FW_MAX))
return SBI_EINVAL;
for (cidx = num_hw_ctrs; cidx < total_ctrs; cidx++) {
if (get_cidx_code(phs->active_events[cidx]) == fw_id &&
(phs->fw_counters_started & BIT(cidx - num_hw_ctrs))) {
fcounter = &phs->fw_counters_data[cidx - num_hw_ctrs];
if (get_cidx_code(active_events[hartid][cidx]) == fw_id &&
(fw_counters_started[hartid] & BIT(cidx - num_hw_ctrs))) {
fcounter = &fw_counters_data[hartid][cidx - num_hw_ctrs];
break;
}
}
@@ -874,16 +854,16 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
return 0;
}
static void pmu_reset_event_map(struct sbi_pmu_hart_state *phs)
static void pmu_reset_event_map(u32 hartid)
{
int j;
/* Initialize the counter to event mapping table */
for (j = 3; j < total_ctrs; j++)
phs->active_events[j] = SBI_PMU_EVENT_IDX_INVALID;
active_events[hartid][j] = SBI_PMU_EVENT_IDX_INVALID;
for (j = 0; j < SBI_PMU_FW_CTR_MAX; j++)
phs->fw_counters_data[j] = 0;
phs->fw_counters_started = 0;
fw_counters_data[hartid][j] = 0;
fw_counters_started[hartid] = 0;
}
const struct sbi_pmu_device *sbi_pmu_get_device(void)
@@ -901,32 +881,27 @@ void sbi_pmu_set_device(const struct sbi_pmu_device *dev)
void sbi_pmu_exit(struct sbi_scratch *scratch)
{
u32 hartid = current_hartid();
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11)
csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8);
if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10)
csr_write(CSR_MCOUNTEREN, -1);
pmu_reset_event_map(pmu_get_hart_state_ptr(scratch));
if (sbi_platform_force_emulate_time_csr(plat))
csr_clear(CSR_MCOUNTEREN, MCOUNTEREN_TM);
pmu_reset_event_map(hartid);
}
int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
{
struct sbi_pmu_hart_state *phs;
const struct sbi_platform *plat;
u32 hartid = current_hartid();
if (cold_boot) {
hw_event_map = sbi_calloc(sizeof(*hw_event_map),
SBI_PMU_HW_EVENT_MAX);
if (!hw_event_map)
return SBI_ENOMEM;
phs_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!phs_ptr_offset) {
sbi_free(hw_event_map);
return SBI_ENOMEM;
}
plat = sbi_platform_ptr(scratch);
/* Initialize hw pmu events */
sbi_platform_pmu_init(plat);
@@ -936,23 +911,14 @@ int sbi_pmu_init(struct sbi_scratch *scratch, bool cold_boot)
total_ctrs = num_hw_ctrs + SBI_PMU_FW_CTR_MAX;
}
phs = pmu_get_hart_state_ptr(scratch);
if (!phs) {
phs = sbi_zalloc(sizeof(*phs));
if (!phs)
return SBI_ENOMEM;
phs->hartid = current_hartid();
pmu_set_hart_state_ptr(scratch, phs);
}
pmu_reset_event_map(phs);
pmu_reset_event_map(hartid);
/* First three counters are fixed by the priv spec and we enable it by default */
phs->active_events[0] = (SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET) |
SBI_PMU_HW_CPU_CYCLES;
phs->active_events[1] = SBI_PMU_EVENT_IDX_INVALID;
phs->active_events[2] = (SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_TYPE_OFFSET) |
SBI_PMU_HW_INSTRUCTIONS;
active_events[hartid][0] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_OFFSET |
SBI_PMU_HW_CPU_CYCLES;
active_events[hartid][1] = SBI_PMU_EVENT_IDX_INVALID;
active_events[hartid][2] = SBI_PMU_EVENT_TYPE_HW << SBI_PMU_EVENT_IDX_OFFSET |
SBI_PMU_HW_INSTRUCTIONS;
return 0;
}

View File

@@ -59,8 +59,8 @@ unsigned long sbi_scratch_alloc_offset(unsigned long size)
if (!size)
return 0;
size += __SIZEOF_POINTER__ - 1;
size &= ~((unsigned long)__SIZEOF_POINTER__ - 1);
if (size & (__SIZEOF_POINTER__ - 1))
size = (size & ~(__SIZEOF_POINTER__ - 1)) + __SIZEOF_POINTER__;
spin_lock(&extra_lock);
@@ -97,14 +97,3 @@ void sbi_scratch_free_offset(unsigned long offset)
* brain-dead allocator.
*/
}
unsigned long sbi_scratch_used_space(void)
{
unsigned long ret = 0;
spin_lock(&extra_lock);
ret = extra_offset;
spin_unlock(&extra_lock);
return ret;
}

View File

@@ -111,7 +111,7 @@ void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev)
static int sbi_system_suspend_test_check(u32 sleep_type)
{
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? 0 : SBI_EINVAL;
return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND;
}
static int sbi_system_suspend_test_suspend(u32 sleep_type,
@@ -142,29 +142,27 @@ void sbi_system_suspend_test_enable(void)
bool sbi_system_suspend_supported(u32 sleep_type)
{
return suspend_dev && suspend_dev->system_suspend_check &&
suspend_dev->system_suspend_check(sleep_type) == 0;
suspend_dev->system_suspend_check(sleep_type);
}
int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
{
int ret = SBI_ENOTSUPP;
const struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
void (*jump_warmboot)(void) = (void (*)(void))scratch->warmboot_addr;
unsigned int hartid = current_hartid();
unsigned long prev_mode;
unsigned long i;
int ret;
if (!dom || !dom->system_suspend_allowed)
return SBI_EFAIL;
if (!suspend_dev || !suspend_dev->system_suspend ||
!suspend_dev->system_suspend_check)
if (!suspend_dev || !suspend_dev->system_suspend)
return SBI_EFAIL;
ret = suspend_dev->system_suspend_check(sleep_type);
if (ret != SBI_OK)
return ret;
if (!sbi_system_suspend_supported(sleep_type))
return SBI_ENOTSUPP;
prev_mode = (csr_read(CSR_MSTATUS) & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
if (prev_mode != PRV_S && prev_mode != PRV_U)

View File

@@ -211,7 +211,7 @@ static void tlb_pmu_incr_fw_ctr(struct sbi_tlb_info *data)
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_ASID_SENT);
}
static void tlb_entry_process(struct sbi_tlb_info *tinfo)
static void tlb_process_helper(struct sbi_tlb_info *tinfo)
{
u32 rhartid;
struct sbi_scratch *rscratch = NULL;
@@ -229,29 +229,29 @@ static void tlb_entry_process(struct sbi_tlb_info *tinfo)
}
}
static bool tlb_process_once(struct sbi_scratch *scratch)
static int tlb_process_once(struct sbi_scratch *scratch)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
if (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
tlb_entry_process(&tinfo);
return true;
tlb_process_helper(&tinfo);
return 0;
}
return false;
return -1;
}
static void tlb_process(struct sbi_scratch *scratch)
{
while (tlb_process_once(scratch));
while (!tlb_process_once(scratch));
}
static void tlb_sync(struct sbi_scratch *scratch)
{
atomic_t *tlb_sync =
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
while (atomic_read(tlb_sync) > 0) {
/*
@@ -357,13 +357,12 @@ static int tlb_update(struct sbi_scratch *scratch,
*/
if (remote_hartid == curr_hartid) {
tinfo->local_fn(tinfo);
return SBI_IPI_UPDATE_BREAK;
return -1;
}
tlb_fifo_r = sbi_scratch_offset_ptr(remote_scratch, tlb_fifo_off);
ret = sbi_fifo_inplace_update(tlb_fifo_r, data, tlb_update_cb);
if (ret == SBI_FIFO_UNCHANGED && sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
/**
* For now, Busy loop until there is space in the fifo.
@@ -376,13 +375,13 @@ static int tlb_update(struct sbi_scratch *scratch,
tlb_process_once(scratch);
sbi_dprintf("hart%d: hart%d tlb fifo full\n",
curr_hartid, remote_hartid);
return SBI_IPI_UPDATE_RETRY;
return -2;
}
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
atomic_add_return(tlb_sync, 1);
return SBI_IPI_UPDATE_SUCCESS;
return 0;
}
static struct sbi_ipi_event_ops tlb_ops = {
@@ -450,7 +449,7 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
tlb_q = sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
tlb_mem = sbi_scratch_offset_ptr(scratch, tlb_fifo_mem_off);
ATOMIC_INIT(tlb_sync, 0);
tlb_sync->counter = 0;
sbi_fifo_init(tlb_q, tlb_mem,
SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);

View File

@@ -212,7 +212,7 @@ static int sbi_trap_nonaia_irq(struct sbi_trap_regs *regs, ulong mcause)
return sbi_irqchip_process(regs);
default:
return SBI_ENOENT;
}
};
return 0;
}
@@ -320,7 +320,7 @@ struct sbi_trap_regs *sbi_trap_handler(struct sbi_trap_regs *regs)
rc = sbi_trap_redirect(regs, &trap);
break;
}
};
trap_error:
if (rc)

View File

@@ -163,7 +163,7 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
break;
default:
break;
}
};
return insn;
}

View File

@@ -13,7 +13,6 @@
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_domain.h>
#include <sbi_utils/fdt/fdt_helper.h>
@@ -220,13 +219,14 @@ skip_device_disable:
fdt_nop_node(fdt, poffset);
}
#define FDT_DOMAIN_MAX_COUNT 8
#define FDT_DOMAIN_REGION_MAX_COUNT 16
struct parse_region_data {
struct sbi_domain *dom;
u32 region_count;
u32 max_regions;
};
static u32 fdt_domains_count;
static struct sbi_domain fdt_domains[FDT_DOMAIN_MAX_COUNT];
static struct sbi_hartmask fdt_masks[FDT_DOMAIN_MAX_COUNT];
static struct sbi_domain_memregion
fdt_regions[FDT_DOMAIN_MAX_COUNT][FDT_DOMAIN_REGION_MAX_COUNT + 1];
static int __fdt_parse_region(void *fdt, int domain_offset,
int region_offset, u32 region_access,
@@ -236,7 +236,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
u32 val32;
u64 val64;
const u32 *val;
struct parse_region_data *preg = opaque;
u32 *region_count = opaque;
struct sbi_domain_memregion *region;
/*
@@ -252,9 +252,9 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
return SBI_EINVAL;
/* Find next region of the domain */
if (preg->max_regions <= preg->region_count)
return SBI_ENOSPC;
region = &preg->dom->regions[preg->region_count];
if (FDT_DOMAIN_REGION_MAX_COUNT <= *region_count)
return SBI_EINVAL;
region = &fdt_regions[fdt_domains_count][*region_count];
/* Read "base" DT property */
val = fdt_getprop(fdt, region_offset, "base", &len);
@@ -278,7 +278,7 @@ static int __fdt_parse_region(void *fdt, int domain_offset,
if (fdt_get_property(fdt, region_offset, "mmio", NULL))
region->flags |= SBI_DOMAIN_MEMREGION_MMIO;
preg->region_count++;
(*region_count)++;
return 0;
}
@@ -291,30 +291,16 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
struct sbi_domain *dom;
struct sbi_hartmask *mask;
struct sbi_hartmask assign_mask;
struct parse_region_data preg;
int *cold_domain_offset = opaque;
struct sbi_domain_memregion *reg;
int i, err = 0, len, cpus_offset, cpu_offset, doffset;
struct sbi_domain_memregion *reg, *regions;
int i, err, len, cpus_offset, cpu_offset, doffset;
dom = sbi_zalloc(sizeof(*dom));
if (!dom)
return SBI_ENOMEM;
dom->regions = sbi_calloc(sizeof(*dom->regions),
FDT_DOMAIN_REGION_MAX_COUNT + 1);
if (!dom->regions) {
err = SBI_ENOMEM;
goto fail_free_domain;
}
preg.dom = dom;
preg.region_count = 0;
preg.max_regions = FDT_DOMAIN_REGION_MAX_COUNT;
mask = sbi_zalloc(sizeof(*mask));
if (!mask) {
err = SBI_ENOMEM;
goto fail_free_regions;
}
/* Sanity check on maximum domains we can handle */
if (FDT_DOMAIN_MAX_COUNT <= fdt_domains_count)
return SBI_EINVAL;
dom = &fdt_domains[fdt_domains_count];
mask = &fdt_masks[fdt_domains_count];
regions = &fdt_regions[fdt_domains_count][0];
/* Read DT node name */
strncpy(dom->name, fdt_get_name(fdt, domain_offset, NULL),
@@ -330,14 +316,12 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
for (i = 0; i < len; i++) {
cpu_offset = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(val[i]));
if (cpu_offset < 0) {
err = cpu_offset;
goto fail_free_all;
}
if (cpu_offset < 0)
return cpu_offset;
err = fdt_parse_hart_id(fdt, cpu_offset, &val32);
if (err)
goto fail_free_all;
return err;
if (!fdt_node_is_enabled(fdt, cpu_offset))
continue;
@@ -347,10 +331,14 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
}
/* Setup memregions from DT */
err = fdt_iterate_each_memregion(fdt, domain_offset, &preg,
val32 = 0;
memset(regions, 0,
sizeof(*regions) * (FDT_DOMAIN_REGION_MAX_COUNT + 1));
dom->regions = regions;
err = fdt_iterate_each_memregion(fdt, domain_offset, &val32,
__fdt_parse_region);
if (err)
goto fail_free_all;
return err;
/*
* Copy over root domain memregions which don't allow
@@ -366,13 +354,10 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
(reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) ||
(reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE))
continue;
if (preg.max_regions <= preg.region_count) {
err = SBI_EINVAL;
goto fail_free_all;
}
memcpy(&dom->regions[preg.region_count++], reg, sizeof(*reg));
if (FDT_DOMAIN_REGION_MAX_COUNT <= val32)
return SBI_EINVAL;
memcpy(&regions[val32++], reg, sizeof(*reg));
}
dom->fw_region_inited = root.fw_region_inited;
/* Read "boot-hart" DT property */
val32 = -1U;
@@ -441,10 +426,8 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
/* Find /cpus DT node */
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0) {
err = cpus_offset;
goto fail_free_all;
}
if (cpus_offset < 0)
return cpus_offset;
/* HART to domain assignment mask based on CPU DT nodes */
sbi_hartmask_clear_all(&assign_mask);
@@ -460,35 +443,22 @@ static int __fdt_parse_domain(void *fdt, int domain_offset, void *opaque)
continue;
val = fdt_getprop(fdt, cpu_offset, "opensbi-domain", &len);
if (!val || len < 4) {
err = SBI_EINVAL;
goto fail_free_all;
}
if (!val || len < 4)
return SBI_EINVAL;
doffset = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (doffset < 0) {
err = doffset;
goto fail_free_all;
}
if (doffset < 0)
return doffset;
if (doffset == domain_offset)
sbi_hartmask_set_hart(val32, &assign_mask);
}
/* Increment domains count */
fdt_domains_count++;
/* Register the domain */
err = sbi_domain_register(dom, &assign_mask);
if (err)
goto fail_free_all;
return 0;
fail_free_all:
sbi_free(mask);
fail_free_regions:
sbi_free(dom->regions);
fail_free_domain:
sbi_free(dom);
return err;
return sbi_domain_register(dom, &assign_mask);
}
int fdt_domains_populate(void *fdt)

View File

@@ -210,7 +210,7 @@ void fdt_plic_fixup(void *fdt)
static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
unsigned long size, int index,
int parent)
int parent, bool no_map)
{
int na = fdt_address_cells(fdt, 0);
int ns = fdt_size_cells(fdt, 0);
@@ -239,14 +239,16 @@ static int fdt_resv_memory_update_node(void *fdt, unsigned long addr,
if (subnode < 0)
return subnode;
/*
* Tell operating system not to create a virtual
* mapping of the region as part of its standard
* mapping of system memory.
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
if (no_map) {
/*
* Tell operating system not to create a virtual
* mapping of the region as part of its standard
* mapping of system memory.
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
}
/* encode the <reg> property value */
val = reg;
@@ -284,6 +286,7 @@ int fdt_reserved_memory_fixup(void *fdt)
{
struct sbi_domain_memregion *reg;
struct sbi_domain *dom = sbi_domain_thishart_ptr();
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
unsigned long filtered_base[PMP_COUNT] = { 0 };
unsigned char filtered_order[PMP_COUNT] = { 0 };
unsigned long addr, size;
@@ -352,7 +355,7 @@ int fdt_reserved_memory_fixup(void *fdt)
if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
continue;
if (i >= PMP_COUNT) {
if (i > PMP_COUNT) {
sbi_printf("%s: Too many memory regions to fixup.\n",
__func__);
return SBI_ENOSPC;
@@ -379,7 +382,33 @@ int fdt_reserved_memory_fixup(void *fdt)
for (j = 0; j < i; j++) {
addr = filtered_base[j];
size = 1UL << filtered_order[j];
fdt_resv_memory_update_node(fdt, addr, size, j, parent);
fdt_resv_memory_update_node(fdt, addr, size, j, parent,
(sbi_hart_pmp_count(scratch))
? false : true);
}
return 0;
}
int fdt_reserved_memory_nomap_fixup(void *fdt)
{
int parent, subnode;
int err;
/* Locate the reserved memory node */
parent = fdt_path_offset(fdt, "/reserved-memory");
if (parent < 0)
return parent;
fdt_for_each_subnode(subnode, fdt, parent) {
/*
* Tell operating system not to create a virtual
* mapping of the region as part of its standard
* mapping of system memory.
*/
err = fdt_setprop_empty(fdt, subnode, "no-map");
if (err < 0)
return err;
}
return 0;

View File

@@ -689,7 +689,7 @@ int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
break;
regs->addr = reg_addr;
regs->size = reg_size;
}
};
if (!imsic->regs[0].size)
return SBI_EINVAL;

View File

@@ -14,6 +14,10 @@ config FDT_GPIO_SIFIVE
bool "SiFive GPIO FDT driver"
default n
config FDT_GPIO_SOPHGO
bool "Sophgo GPIO FDT driver"
default n
config FDT_GPIO_STARFIVE
bool "StarFive GPIO FDT driver"
default n

View File

@@ -9,10 +9,11 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#define SIFIVE_GPIO_CHIP_MAX 2
#define SIFIVE_GPIO_PINS_MIN 1
#define SIFIVE_GPIO_PINS_MAX 32
#define SIFIVE_GPIO_PINS_DEF 16
@@ -26,6 +27,9 @@ struct sifive_gpio_chip {
struct gpio_chip chip;
};
static unsigned int sifive_gpio_chip_count;
static struct sifive_gpio_chip sifive_gpio_chip_array[SIFIVE_GPIO_CHIP_MAX];
static int sifive_gpio_direction_output(struct gpio_pin *gp, int value)
{
unsigned int v;
@@ -69,15 +73,13 @@ static int sifive_gpio_init(void *fdt, int nodeoff, u32 phandle,
struct sifive_gpio_chip *chip;
uint64_t addr;
chip = sbi_zalloc(sizeof(*chip));
if (!chip)
return SBI_ENOMEM;
if (SIFIVE_GPIO_CHIP_MAX <= sifive_gpio_chip_count)
return SBI_ENOSPC;
chip = &sifive_gpio_chip_array[sifive_gpio_chip_count];
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc) {
sbi_free(chip);
if (rc)
return rc;
}
chip->addr = addr;
chip->chip.driver = &fdt_gpio_sifive;
@@ -86,11 +88,10 @@ static int sifive_gpio_init(void *fdt, int nodeoff, u32 phandle,
chip->chip.direction_output = sifive_gpio_direction_output;
chip->chip.set = sifive_gpio_set;
rc = gpio_chip_add(&chip->chip);
if (rc) {
sbi_free(chip);
if (rc)
return rc;
}
sifive_gpio_chip_count++;
return 0;
}

View File

@@ -0,0 +1,157 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Sophgo
*
* Author:
* Chunzhi Lin <chunzhi.lin@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#define SOPHGO_GPIO_CHIP_MAX 3
#define SOPHGO_GPIO_PINS_MIN 0
#define SOPHGO_GPIO_PINS_MAX 31
#define SOPHGO_GPIO_PINS_DEF 16
#define SOPHGO_GPIO_SWPORTA_DR_OFFSET 0x00
#define SOPHGO_GPIO_SWPORTA_DDR_OFFSET 0x04
#define SOPHGO_GPIO_SWPORTA_CTL_OFFSET 0x08
#define SOPHGO_GPIO_BIT(offset) (1U << (offset))
#define SOPHGO_GPIO_STARTUP_FLAG SOPHGO_GPIO_BIT(16)
struct sophgo_gpio_chip {
unsigned long addr;
struct gpio_chip chip;
};
static unsigned int sophgo_gpio_chip_count;
static struct sophgo_gpio_chip sophgo_gpio_chip_array[SOPHGO_GPIO_CHIP_MAX];
static int sophgo_gpio_direction_output(struct gpio_pin *gp, int value)
{
unsigned int v;
struct sophgo_gpio_chip *chip =
container_of(gp->chip, struct sophgo_gpio_chip, chip);
v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET));
v |= SOPHGO_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET));
v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
if (!value)
v &= ~SOPHGO_GPIO_BIT(gp->offset);
else
v |= SOPHGO_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
return 0;
}
static void sophgo_gpio_set(struct gpio_pin *gp, int value)
{
unsigned int v;
struct sophgo_gpio_chip *chip =
container_of(gp->chip, struct sophgo_gpio_chip, chip);
v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
if (!value)
v &= ~SOPHGO_GPIO_BIT(gp->offset);
else
v |= SOPHGO_GPIO_BIT(gp->offset);
writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
return;
}
static int sophgo_gpio_addr_get(void *fdt, int nodeoff, unsigned long *addr)
{
int parent, len;
unsigned long addr_high, addr_low;
const fdt32_t *prop_addr;
parent = fdt_parent_offset(fdt, nodeoff);
if (parent < 0)
return parent;
prop_addr = fdt_getprop(fdt, parent, "reg", &len);
if (!prop_addr)
return SBI_ENODEV;
addr_high = fdt32_to_cpu(*prop_addr++);
addr_low = fdt32_to_cpu(*prop_addr);
*addr = addr_high << 32 | addr_low;
return 0;
}
static void sophgo_system_normal_startup_flag(unsigned long addr)
{
unsigned int v;
v = readl((volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET));
v |= SOPHGO_GPIO_STARTUP_FLAG;
writel(v, (volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET));
v = readl((volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
v |= SOPHGO_GPIO_STARTUP_FLAG;
writel(v, (volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET));
}
extern struct fdt_gpio fdt_gpio_sophgo;
static int sophgo_gpio_init(void *fdt, int nodeoff, u32 phandle,
const struct fdt_match *match)
{
int rc;
struct sophgo_gpio_chip *chip;
unsigned long addr;
if (SOPHGO_GPIO_CHIP_MAX <= sophgo_gpio_chip_count) {
rc = SBI_ENOSPC;
return rc;
}
chip = &sophgo_gpio_chip_array[sophgo_gpio_chip_count];
rc = sophgo_gpio_addr_get(fdt, nodeoff, &addr);
if (rc)
return rc;
chip->addr = addr;
chip->chip.driver = &fdt_gpio_sophgo;
chip->chip.id = phandle;
chip->chip.ngpio = SOPHGO_GPIO_PINS_MAX;
chip->chip.direction_output = sophgo_gpio_direction_output;
chip->chip.set = sophgo_gpio_set;
rc = gpio_chip_add(&chip->chip);
if (rc)
return rc;
sophgo_gpio_chip_count++;
sophgo_system_normal_startup_flag(addr);
return 0;
}
static const struct fdt_match sophgo_gpio_match[] = {
{ .compatible = "sophgo,gpio0" },
{ },
};
struct fdt_gpio fdt_gpio_sophgo = {
.match_table = sophgo_gpio_match,
.xlate = fdt_gpio_simple_xlate,
.init = sophgo_gpio_init,
};

View File

@@ -9,11 +9,11 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#define STARFIVE_GPIO_CHIP_MAX 2
#define STARFIVE_GPIO_PINS_DEF 64
#define STARFIVE_GPIO_OUTVAL 0x40
#define STARFIVE_GPIO_MASK 0xff
@@ -25,6 +25,9 @@ struct starfive_gpio_chip {
struct gpio_chip chip;
};
static unsigned int starfive_gpio_chip_count;
static struct starfive_gpio_chip starfive_gpio_chip_array[STARFIVE_GPIO_CHIP_MAX];
static int starfive_gpio_direction_output(struct gpio_pin *gp, int value)
{
u32 val;
@@ -79,15 +82,13 @@ static int starfive_gpio_init(void *fdt, int nodeoff, u32 phandle,
struct starfive_gpio_chip *chip;
u64 addr;
chip = sbi_zalloc(sizeof(*chip));
if (!chip)
return SBI_ENOMEM;
if (starfive_gpio_chip_count >= STARFIVE_GPIO_CHIP_MAX)
return SBI_ENOSPC;
chip = &starfive_gpio_chip_array[starfive_gpio_chip_count];
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc) {
sbi_free(chip);
if (rc)
return rc;
}
chip->addr = addr;
chip->chip.driver = &fdt_gpio_starfive;
@@ -96,11 +97,10 @@ static int starfive_gpio_init(void *fdt, int nodeoff, u32 phandle,
chip->chip.direction_output = starfive_gpio_direction_output;
chip->chip.set = starfive_gpio_set;
rc = gpio_chip_add(&chip->chip);
if (rc) {
sbi_free(chip);
if (rc)
return rc;
}
starfive_gpio_chip_count++;
return 0;
}

View File

@@ -13,6 +13,9 @@ libsbiutils-objs-$(CONFIG_FDT_GPIO) += gpio/fdt_gpio_drivers.o
carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_SIFIVE) += fdt_gpio_sifive
libsbiutils-objs-$(CONFIG_FDT_GPIO_SIFIVE) += gpio/fdt_gpio_sifive.o
carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_SOPHGO) += fdt_gpio_sophgo
libsbiutils-objs-$(CONFIG_FDT_GPIO_SOPHGO) += gpio/fdt_gpio_sophgo.o
carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_STARFIVE) += fdt_gpio_starfive
libsbiutils-objs-$(CONFIG_FDT_GPIO_STARFIVE) += gpio/fdt_gpio_starfive.o

View File

@@ -9,12 +9,17 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_string.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/i2c/dw_i2c.h>
#include <sbi_utils/i2c/fdt_i2c.h>
#define FDT_DW_I2C_ADAPTER_MAX 7
static unsigned int fdt_dw_i2c_adapter_count;
static struct dw_i2c_adapter
fdt_dw_i2c_adapter_array[FDT_DW_I2C_ADAPTER_MAX];
extern struct fdt_i2c_adapter fdt_i2c_adapter_dw;
static int fdt_dw_i2c_init(void *fdt, int nodeoff,
@@ -24,24 +29,23 @@ static int fdt_dw_i2c_init(void *fdt, int nodeoff,
struct dw_i2c_adapter *adapter;
u64 addr;
adapter = sbi_zalloc(sizeof(*adapter));
if (!adapter)
return SBI_ENOMEM;
if (fdt_dw_i2c_adapter_count >= FDT_DW_I2C_ADAPTER_MAX)
return SBI_ENOSPC;
adapter = &fdt_dw_i2c_adapter_array[fdt_dw_i2c_adapter_count];
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc) {
sbi_free(adapter);
if (rc)
return rc;
}
adapter->addr = addr;
adapter->adapter.driver = &fdt_i2c_adapter_dw;
rc = dw_i2c_init(&adapter->adapter, nodeoff);
if (rc) {
sbi_free(adapter);
if (rc)
return rc;
}
fdt_dw_i2c_adapter_count++;
return 0;
}

View File

@@ -9,11 +9,12 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_timer.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/i2c/fdt_i2c.h>
#define SIFIVE_I2C_ADAPTER_MAX 2
#define SIFIVE_I2C_PRELO 0x00
#define SIFIVE_I2C_PREHI 0x04
#define SIFIVE_I2C_CTR 0x08
@@ -46,6 +47,10 @@ struct sifive_i2c_adapter {
struct i2c_adapter adapter;
};
static unsigned int sifive_i2c_adapter_count;
static struct sifive_i2c_adapter
sifive_i2c_adapter_array[SIFIVE_I2C_ADAPTER_MAX];
extern struct fdt_i2c_adapter fdt_i2c_adapter_sifive;
static inline void sifive_i2c_setreg(struct sifive_i2c_adapter *adap,
@@ -239,15 +244,14 @@ static int sifive_i2c_init(void *fdt, int nodeoff,
struct sifive_i2c_adapter *adapter;
uint64_t addr;
adapter = sbi_zalloc(sizeof(*adapter));
if (!adapter)
return SBI_ENOMEM;
if (sifive_i2c_adapter_count >= SIFIVE_I2C_ADAPTER_MAX)
return SBI_ENOSPC;
adapter = &sifive_i2c_adapter_array[sifive_i2c_adapter_count];
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc) {
sbi_free(adapter);
if (rc)
return rc;
}
adapter->addr = addr;
adapter->adapter.driver = &fdt_i2c_adapter_sifive;
@@ -255,11 +259,10 @@ static int sifive_i2c_init(void *fdt, int nodeoff,
adapter->adapter.write = sifive_i2c_adapter_write;
adapter->adapter.read = sifive_i2c_adapter_read;
rc = i2c_adapter_add(&adapter->adapter);
if (rc) {
sbi_free(adapter);
if (rc)
return rc;
}
sifive_i2c_adapter_count++;
return 0;
}

View File

@@ -12,30 +12,21 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
#include <sbi_utils/ipi/aclint_mswi.h>
static unsigned long mswi_ptr_offset;
#define mswi_get_hart_data_ptr(__scratch) \
sbi_scratch_read_type((__scratch), void *, mswi_ptr_offset)
#define mswi_set_hart_data_ptr(__scratch, __mswi) \
sbi_scratch_write_type((__scratch), void *, mswi_ptr_offset, (__mswi))
static struct aclint_mswi_data *mswi_hartid2data[SBI_HARTMASK_MAX_BITS];
static void mswi_ipi_send(u32 target_hart)
{
u32 *msip;
struct sbi_scratch *scratch;
struct aclint_mswi_data *mswi;
scratch = sbi_hartid_to_scratch(target_hart);
if (!scratch)
if (SBI_HARTMASK_MAX_BITS <= target_hart)
return;
mswi = mswi_get_hart_data_ptr(scratch);
mswi = mswi_hartid2data[target_hart];
if (!mswi)
return;
@@ -47,14 +38,11 @@ static void mswi_ipi_send(u32 target_hart)
static void mswi_ipi_clear(u32 target_hart)
{
u32 *msip;
struct sbi_scratch *scratch;
struct aclint_mswi_data *mswi;
scratch = sbi_hartid_to_scratch(target_hart);
if (!scratch)
if (SBI_HARTMASK_MAX_BITS <= target_hart)
return;
mswi = mswi_get_hart_data_ptr(scratch);
mswi = mswi_hartid2data[target_hart];
if (!mswi)
return;
@@ -81,30 +69,19 @@ int aclint_mswi_cold_init(struct aclint_mswi_data *mswi)
{
u32 i;
int rc;
struct sbi_scratch *scratch;
unsigned long pos, region_size;
struct sbi_domain_memregion reg;
/* Sanity checks */
if (!mswi || (mswi->addr & (ACLINT_MSWI_ALIGN - 1)) ||
(mswi->size < (mswi->hart_count * sizeof(u32))) ||
(!mswi->hart_count || mswi->hart_count > ACLINT_MSWI_MAX_HARTS))
(mswi->first_hartid >= SBI_HARTMASK_MAX_BITS) ||
(mswi->hart_count > ACLINT_MSWI_MAX_HARTS))
return SBI_EINVAL;
/* Allocate scratch space pointer */
if (!mswi_ptr_offset) {
mswi_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!mswi_ptr_offset)
return SBI_ENOMEM;
}
/* Update MSWI pointer in scratch space */
for (i = 0; i < mswi->hart_count; i++) {
scratch = sbi_hartid_to_scratch(mswi->first_hartid + i);
if (!scratch)
return SBI_ENOENT;
mswi_set_hart_data_ptr(scratch, mswi);
}
/* Update MSWI hartid table */
for (i = 0; i < mswi->hart_count; i++)
mswi_hartid2data[mswi->first_hartid + i] = mswi;
/* Add MSWI regions to the root domain */
for (pos = 0; pos < mswi->size; pos += ACLINT_MSWI_ALIGN) {

View File

@@ -16,17 +16,24 @@
extern struct fdt_ipi *fdt_ipi_drivers[];
extern unsigned long fdt_ipi_drivers_size;
static struct fdt_ipi *current_driver = NULL;
static struct fdt_ipi dummy = {
.match_table = NULL,
.cold_init = NULL,
.warm_init = NULL,
.exit = NULL,
};
static struct fdt_ipi *current_driver = &dummy;
void fdt_ipi_exit(void)
{
if (current_driver && current_driver->exit)
if (current_driver->exit)
current_driver->exit();
}
static int fdt_ipi_warm_init(void)
{
if (current_driver && current_driver->warm_init)
if (current_driver->warm_init)
return current_driver->warm_init();
return 0;
}
@@ -44,28 +51,20 @@ static int fdt_ipi_cold_init(void)
noff = -1;
while ((noff = fdt_find_match(fdt, noff,
drv->match_table, &match)) >= 0) {
/* drv->cold_init must not be NULL */
if (drv->cold_init == NULL)
return SBI_EFAIL;
rc = drv->cold_init(fdt, noff, match);
if (rc == SBI_ENODEV)
continue;
if (rc)
return rc;
if (drv->cold_init) {
rc = drv->cold_init(fdt, noff, match);
if (rc == SBI_ENODEV)
continue;
if (rc)
return rc;
}
current_driver = drv;
/*
* We will have multiple IPI devices on multi-die or
* multi-socket systems so we cannot break here.
*/
}
if (current_driver != &dummy)
break;
}
/*
* On some single-hart system there is no need for ipi,
* so we cannot return a failure here
*/
return 0;
}

View File

@@ -8,11 +8,15 @@
*/
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/ipi/fdt_ipi.h>
#include <sbi_utils/ipi/aclint_mswi.h>
#define MSWI_MAX_NR 16
static unsigned long mswi_count = 0;
static struct aclint_mswi_data mswi[MSWI_MAX_NR];
static int ipi_mswi_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
@@ -20,17 +24,15 @@ static int ipi_mswi_cold_init(void *fdt, int nodeoff,
unsigned long offset;
struct aclint_mswi_data *ms;
ms = sbi_zalloc(sizeof(*ms));
if (!ms)
return SBI_ENOMEM;
if (MSWI_MAX_NR <= mswi_count)
return SBI_ENOSPC;
ms = &mswi[mswi_count];
rc = fdt_parse_aclint_node(fdt, nodeoff, false,
&ms->addr, &ms->size, NULL, NULL,
&ms->first_hartid, &ms->hart_count);
if (rc) {
sbi_free(ms);
if (rc)
return rc;
}
if (match->data) {
/* Adjust MSWI address and size for CLINT device */
@@ -42,11 +44,10 @@ static int ipi_mswi_cold_init(void *fdt, int nodeoff,
}
rc = aclint_mswi_cold_init(ms);
if (rc) {
sbi_free(ms);
if (rc)
return rc;
}
mswi_count++;
return 0;
}
@@ -56,6 +57,8 @@ static const struct fdt_match ipi_mswi_match[] = {
{ .compatible = "riscv,clint0", .data = &clint_offset },
{ .compatible = "sifive,clint0", .data = &clint_offset },
{ .compatible = "thead,c900-clint", .data = &clint_offset },
{ .compatible = "sophgo,sg2042-clint-mswi", .data = &clint_offset },
{ .compatible = "thead,c900-clint-mswi", .data = &clint_offset },
{ .compatible = "riscv,aclint-mswi" },
{ },
};

View File

@@ -11,11 +11,15 @@
#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.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. */
@@ -28,23 +32,15 @@ static int irqchip_aplic_cold_init(void *fdt, int nodeoff,
int rc;
struct aplic_data *pd;
pd = sbi_zalloc(sizeof(*pd));
if (!pd)
return SBI_ENOMEM;
if (APLIC_MAX_NR <= aplic_count)
return SBI_ENOSPC;
pd = &aplic[aplic_count++];
rc = fdt_parse_aplic_node(fdt, nodeoff, pd);
if (rc)
goto fail_free_data;
return rc;
rc = aplic_cold_irqchip_init(pd);
if (rc)
goto fail_free_data;
return 0;
fail_free_data:
sbi_free(pd);
return rc;
return aplic_cold_irqchip_init(pd);
}
static const struct fdt_match irqchip_aplic_match[] = {

View File

@@ -11,11 +11,16 @@
#include <libfdt.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.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)
{
@@ -43,6 +48,8 @@ static int irqchip_imsic_update_hartid_table(void *fdt, int nodeoff,
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:
@@ -64,27 +71,27 @@ static int irqchip_imsic_cold_init(void *fdt, int nodeoff,
int rc;
struct imsic_data *id;
id = sbi_zalloc(sizeof(*id));
if (!id)
return SBI_ENOMEM;
if (IMSIC_MAX_NR <= imsic_count)
return SBI_ENOSPC;
id = &imsic[imsic_count];
rc = fdt_parse_imsic_node(fdt, nodeoff, id);
if (rc || !id->targets_mmode)
goto fail_free_data;
rc = imsic_cold_irqchip_init(id);
if (rc)
goto fail_free_data;
return rc;
if (!id->targets_mmode)
return 0;
rc = irqchip_imsic_update_hartid_table(fdt, nodeoff, id);
if (rc)
goto fail_free_data;
return rc;
rc = imsic_cold_irqchip_init(id);
if (rc)
return rc;
imsic_count++;
return 0;
fail_free_data:
sbi_free(id);
return rc;
}
static const struct fdt_match irqchip_imsic_match[] = {

View File

@@ -11,78 +11,59 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_hartmask.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
#include <sbi_utils/irqchip/plic.h>
static unsigned long plic_ptr_offset;
#define PLIC_MAX_NR 16
#define plic_get_hart_data_ptr(__scratch) \
sbi_scratch_read_type((__scratch), void *, plic_ptr_offset)
static unsigned long plic_count = 0;
static struct plic_data plic[PLIC_MAX_NR];
#define plic_set_hart_data_ptr(__scratch, __plic) \
sbi_scratch_write_type((__scratch), void *, plic_ptr_offset, (__plic))
static unsigned long plic_mcontext_offset;
#define plic_get_hart_mcontext(__scratch) \
(sbi_scratch_read_type((__scratch), long, plic_mcontext_offset) - 1)
#define plic_set_hart_mcontext(__scratch, __mctx) \
sbi_scratch_write_type((__scratch), long, plic_mcontext_offset, (__mctx) + 1)
static unsigned long plic_scontext_offset;
#define plic_get_hart_scontext(__scratch) \
(sbi_scratch_read_type((__scratch), long, plic_scontext_offset) - 1)
#define plic_set_hart_scontext(__scratch, __sctx) \
sbi_scratch_write_type((__scratch), long, plic_scontext_offset, (__sctx) + 1)
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, u32 num)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
struct plic_data *plic = plic_hartid2data[current_hartid()];
plic_priority_save(plic_get_hart_data_ptr(scratch), priority, num);
plic_priority_save(plic, priority, num);
}
void fdt_plic_priority_restore(const u8 *priority, u32 num)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
struct plic_data *plic = plic_hartid2data[current_hartid()];
plic_priority_restore(plic_get_hart_data_ptr(scratch), priority, num);
plic_priority_restore(plic, priority, num);
}
void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold, u32 num)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
u32 hartid = current_hartid();
plic_context_save(plic_get_hart_data_ptr(scratch),
smode ? plic_get_hart_scontext(scratch) :
plic_get_hart_mcontext(scratch),
plic_context_save(plic_hartid2data[hartid],
plic_hartid2context[hartid][smode],
enable, threshold, num);
}
void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold,
u32 num)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
u32 hartid = current_hartid();
plic_context_restore(plic_get_hart_data_ptr(scratch),
smode ? plic_get_hart_scontext(scratch) :
plic_get_hart_mcontext(scratch),
plic_context_restore(plic_hartid2data[hartid],
plic_hartid2context[hartid][smode],
enable, threshold, num);
}
static int irqchip_plic_warm_init(void)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
u32 hartid = current_hartid();
return plic_warm_irqchip_init(plic_get_hart_data_ptr(scratch),
plic_get_hart_mcontext(scratch),
plic_get_hart_scontext(scratch));
return plic_warm_irqchip_init(plic_hartid2data[hartid],
plic_hartid2context[hartid][0],
plic_hartid2context[hartid][1]);
}
static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff,
@@ -90,7 +71,6 @@ static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff,
{
const fdt32_t *val;
u32 phandle, hwirq, hartid;
struct sbi_scratch *scratch;
int i, err, count, cpu_offset, cpu_intc_offset;
val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
@@ -114,17 +94,16 @@ static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff,
if (err)
continue;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
if (SBI_HARTMASK_MAX_BITS <= hartid)
continue;
plic_set_hart_data_ptr(scratch, pd);
plic_hartid2data[hartid] = pd;
switch (hwirq) {
case IRQ_M_EXT:
plic_set_hart_mcontext(scratch, i / 2);
plic_hartid2context[hartid][0] = i / 2;
break;
case IRQ_S_EXT:
plic_set_hart_scontext(scratch, i / 2);
plic_hartid2context[hartid][1] = i / 2;
break;
}
}
@@ -135,34 +114,16 @@ static int irqchip_plic_update_hartid_table(void *fdt, int nodeoff,
static int irqchip_plic_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
int i, rc;
struct plic_data *pd;
if (!plic_ptr_offset) {
plic_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!plic_ptr_offset)
return SBI_ENOMEM;
}
if (!plic_mcontext_offset) {
plic_mcontext_offset = sbi_scratch_alloc_type_offset(long);
if (!plic_mcontext_offset)
return SBI_ENOMEM;
}
if (!plic_scontext_offset) {
plic_scontext_offset = sbi_scratch_alloc_type_offset(long);
if (!plic_scontext_offset)
return SBI_ENOMEM;
}
pd = sbi_zalloc(sizeof(*pd));
if (!pd)
return SBI_ENOMEM;
if (PLIC_MAX_NR <= plic_count)
return SBI_ENOSPC;
pd = &plic[plic_count++];
rc = fdt_parse_plic_node(fdt, nodeoff, pd);
if (rc)
goto fail_free_data;
return rc;
if (match->data) {
void (*plic_plat_init)(struct plic_data *) = match->data;
@@ -171,17 +132,17 @@ static int irqchip_plic_cold_init(void *fdt, int nodeoff,
rc = plic_cold_irqchip_init(pd);
if (rc)
goto fail_free_data;
return rc;
rc = irqchip_plic_update_hartid_table(fdt, nodeoff, pd);
if (rc)
goto fail_free_data;
if (plic_count == 1) {
for (i = 0; i < SBI_HARTMASK_MAX_BITS; i++) {
plic_hartid2data[i] = NULL;
plic_hartid2context[i][0] = -1;
plic_hartid2context[i][1] = -1;
}
}
return 0;
fail_free_data:
sbi_free(pd);
return rc;
return irqchip_plic_update_hartid_table(fdt, nodeoff, pd);
}
#define THEAD_PLIC_CTRL_REG 0x1ffffc
@@ -193,8 +154,7 @@ static void thead_plic_plat_init(struct plic_data *pd)
void thead_plic_restore(void)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
struct plic_data *plic = plic_get_hart_data_ptr(scratch);
struct plic_data *plic = plic_hartid2data[current_hartid()];
thead_plic_plat_init(plic);
}

View File

@@ -13,10 +13,10 @@
#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/sbi_scratch.h>
#include <sbi_utils/irqchip/imsic.h>
#define IMSIC_MMIO_PAGE_LE 0x00
@@ -79,65 +79,33 @@ do { \
csr_clear(CSR_MIREG, __v); \
} while (0)
static unsigned long imsic_ptr_offset;
#define imsic_get_hart_data_ptr(__scratch) \
sbi_scratch_read_type((__scratch), void *, imsic_ptr_offset)
#define imsic_set_hart_data_ptr(__scratch, __imsic) \
sbi_scratch_write_type((__scratch), void *, imsic_ptr_offset, (__imsic))
static unsigned long imsic_file_offset;
#define imsic_get_hart_file(__scratch) \
sbi_scratch_read_type((__scratch), long, imsic_file_offset)
#define imsic_set_hart_file(__scratch, __file) \
sbi_scratch_write_type((__scratch), long, imsic_file_offset, (__file))
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)
{
struct sbi_scratch *scratch;
if (!imsic || !imsic->targets_mmode)
if (!imsic || !imsic->targets_mmode ||
(SBI_HARTMASK_MAX_BITS <= hartid))
return SBI_EINVAL;
/*
* We don't need to fail if scratch pointer is not available
* because we might be dealing with hartid of a HART disabled
* in device tree. For HARTs disabled in device tree, the
* imsic_get_data() and imsic_get_target_file() will anyway
* fail.
*/
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
return 0;
imsic_set_hart_data_ptr(scratch, imsic);
imsic_set_hart_file(scratch, file);
imsic_hartid2data[hartid] = imsic;
imsic_hartid2file[hartid] = file;
return 0;
}
struct imsic_data *imsic_get_data(u32 hartid)
{
struct sbi_scratch *scratch;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
if (SBI_HARTMASK_MAX_BITS <= hartid)
return NULL;
return imsic_get_hart_data_ptr(scratch);
return imsic_hartid2data[hartid];
}
int imsic_get_target_file(u32 hartid)
{
struct sbi_scratch *scratch;
scratch = sbi_hartid_to_scratch(hartid);
if (!scratch)
if ((SBI_HARTMASK_MAX_BITS <= hartid) ||
!imsic_hartid2data[hartid])
return SBI_ENOENT;
return imsic_get_hart_file(scratch);
return imsic_hartid2file[hartid];
}
static int imsic_external_irqfn(struct sbi_trap_regs *regs)
@@ -165,16 +133,9 @@ static void imsic_ipi_send(u32 target_hart)
{
unsigned long reloff;
struct imsic_regs *regs;
struct imsic_data *data;
struct sbi_scratch *scratch;
int file;
struct imsic_data *data = imsic_hartid2data[target_hart];
int file = imsic_hartid2file[target_hart];
scratch = sbi_hartid_to_scratch(target_hart);
if (!scratch)
return;
data = imsic_get_hart_data_ptr(scratch);
file = imsic_get_hart_file(scratch);
if (!data || !data->targets_mmode)
return;
@@ -243,7 +204,7 @@ void imsic_local_irqchip_init(void)
int imsic_warm_irqchip_init(void)
{
struct imsic_data *imsic = imsic_get_data(current_hartid());
struct imsic_data *imsic = imsic_hartid2data[current_hartid()];
/* Sanity checks */
if (!imsic || !imsic->targets_mmode)
@@ -345,20 +306,6 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
if (!imsic->targets_mmode)
return SBI_EINVAL;
/* Allocate scratch space pointer */
if (!imsic_ptr_offset) {
imsic_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!imsic_ptr_offset)
return SBI_ENOMEM;
}
/* Allocate scratch space file */
if (!imsic_file_offset) {
imsic_file_offset = sbi_scratch_alloc_type_offset(long);
if (!imsic_file_offset)
return SBI_ENOMEM;
}
/* Setup external interrupt function for IMSIC */
sbi_irqchip_set_irqfn(imsic_external_irqfn);

View File

@@ -404,7 +404,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto,
name, name_len, poffset,
&phandle_prop,
sizeof(phandle_prop));
}
};
/**
* overlay_fixup_phandle - Set an overlay phandle to the base one

View File

@@ -29,6 +29,21 @@ config FDT_RESET_SIFIVE_TEST
select SYS_SIFIVE_TEST
default n
config FDT_RESET_SOPHGO_CPLD
bool "Sophgo CPLD FDT reset driver"
select SYS_SOPHGO_CPLD
default n
config FDT_RESET_SOPHGO_MCU
bool "Sophgo MCU FDT reset driver"
select SYS_SOPHGO_MCU
default n
config FDT_RESET_SOPHGO_WDT
bool "Sophgo WDT FDT reset driver"
select SYS_SOPHGO_WDT
default n
config FDT_RESET_SUNXI_WDT
bool "Sunxi WDT FDT reset driver"
default n

View File

@@ -0,0 +1,167 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Sophgo
*
* Authors:
* Chunzhi Lin <chunzhi.lin@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/gpio/fdt_gpio.h>
#include <sbi_utils/reset/fdt_reset.h>
struct cpld_reset {
struct gpio_pin pin;
u32 active_delay;
u32 inactive_delay;
};
static struct cpld_reset poweroff = {
.active_delay = 300,
.inactive_delay = 300
};
static struct cpld_reset reboot = {
.active_delay = 300,
.inactive_delay = 300
};
static struct cpld_reset *cpld_reset_get(bool is_poweroff, u32 type)
{
struct cpld_reset *reset = NULL;
switch (type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
if (is_poweroff)
reset = &poweroff;
break;
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
if (!is_poweroff)
reset = &reboot;
break;
}
if (reset && !reset->pin.chip)
reset = NULL;
return reset;
}
static void cpld_reset_exec(struct cpld_reset *reset)
{
if (reset) {
/* drive it active, also inactive->active edge */
gpio_direction_output(&reset->pin, 1);
sbi_timer_mdelay(reset->active_delay);
/* drive inactive, also active->inactive edge */
gpio_set(&reset->pin, 0);
sbi_timer_mdelay(reset->inactive_delay);
}
/* hang !!! */
sbi_hart_hang();
}
static int cpld_system_poweroff_check(u32 type, u32 reason)
{
if (cpld_reset_get(true, type))
return 128;
return 0;
}
static void cpld_system_poweroff(u32 type, u32 reason)
{
cpld_reset_exec(cpld_reset_get(true, type));
}
static struct sbi_system_reset_device mango_reset_gpio_poweroff = {
.name = "mango-cpld",
.system_reset_check = cpld_system_poweroff_check,
.system_reset = cpld_system_poweroff
};
static int cpld_system_reboot_check(u32 type, u32 reason)
{
if (cpld_reset_get(false, type))
return 128;
return 0;
}
static void cpld_system_reboot(u32 type, u32 reason)
{
cpld_reset_exec(cpld_reset_get(false, type));
}
static struct sbi_system_reset_device mango_reset_gpio_reboot = {
.name = "mango-cpld",
.system_reset_check = cpld_system_reboot_check,
.system_reset = cpld_system_reboot
};
static int mango_cpld_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc, len;
const fdt32_t *val;
bool is_poweroff = (ulong)match->data;
struct cpld_reset *reset = (is_poweroff) ? &poweroff : &reboot;
const char *dir_prop = "output";
rc = fdt_gpio_pin_get(fdt, nodeoff, 0, &reset->pin);
if (rc)
goto out;
if (fdt_getprop(fdt, nodeoff, dir_prop, &len)) {
rc = gpio_direction_output(&reset->pin, 0);
if (rc)
goto out;
}
val = fdt_getprop(fdt, nodeoff, "active-delay-ms", &len);
if (len > 0)
reset->active_delay = fdt32_to_cpu(*val);
val = fdt_getprop(fdt, nodeoff, "inactive-delay-ms", &len);
if (len > 0)
reset->inactive_delay = fdt32_to_cpu(*val);
if (is_poweroff)
sbi_system_reset_add_device(&mango_reset_gpio_poweroff);
else
sbi_system_reset_add_device(&mango_reset_gpio_reboot);
out:
fdt_del_node(fdt, nodeoff);
return rc;
}
static const struct fdt_match mango_cpld_poweroff_match[] = {
{ .compatible = "mango,cpld-poweroff", .data = (void *)true},
{ },
};
struct fdt_reset fdt_reset_sophgo_cpld_poweroff = {
.match_table = mango_cpld_poweroff_match,
.init = mango_cpld_reset_init,
};
static const struct fdt_match mango_cpld_reboot_match[] = {
{ .compatible = "mango,cpld-reboot", .data = (void *)false},
{ },
};
struct fdt_reset fdt_reset_sophgo_cpld_reboot = {
.match_table = mango_cpld_reboot_match,
.init = mango_cpld_reset_init,
};

View File

@@ -0,0 +1,157 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Lin Chunzhi <chunzhi.lin@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_types.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/reset/fdt_reset.h>
#include <sbi_utils/i2c/fdt_i2c.h>
#define MANGO_BOARD_TYPE 0x80
#define MANGO_BOARD_TYPE_MASK 1 << 7
#define REG_MCU_BOARD_TYPE 0x00
#define REG_MCU_CMD 0x03
#define CMD_POWEROFF 0x02
#define CMD_RESET 0x03
#define CMD_REBOOT 0x07
static struct {
struct i2c_adapter *adapter;
uint32_t reg;
} mango;
static int mango_system_reset_check(u32 type, u32 reason)
{
switch (type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
return 1;
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
return 255;
}
return 0;
}
static inline int mango_sanity_check(struct i2c_adapter *adap, uint32_t reg)
{
static uint8_t val;
int ret;
/* check board type*/
ret = i2c_adapter_reg_read(adap, reg, REG_MCU_BOARD_TYPE, &val);
if (ret)
return ret;
if ((val & MANGO_BOARD_TYPE_MASK) != MANGO_BOARD_TYPE)
return SBI_ENODEV;
return 0;
}
static inline int mango_shutdown(struct i2c_adapter *adap, uint32_t reg)
{
int ret;
ret = i2c_adapter_reg_write(adap, reg, REG_MCU_CMD, CMD_POWEROFF);
if (ret)
return ret;
return 0;
}
static inline int mango_reset(struct i2c_adapter *adap, uint32_t reg)
{
int ret;
ret = i2c_adapter_reg_write(adap, reg, REG_MCU_CMD, CMD_REBOOT);
if (ret)
return ret;
return 0;
}
static void mango_system_reset(u32 type, u32 reason)
{
struct i2c_adapter *adap = mango.adapter;
uint32_t reg = mango.reg;
int ret;
if (adap) {
/* sanity check */
ret = mango_sanity_check(adap, reg);
if (ret) {
sbi_printf("%s: chip is not mango\n", __func__);
goto skip_reset;
}
switch (type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
mango_shutdown(adap, reg);
break;
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
mango_reset(adap, reg);
break;
}
}
skip_reset:
sbi_hart_hang();
}
static struct sbi_system_reset_device mango_reset_i2c = {
.name = "mango-reset",
.system_reset_check = mango_system_reset_check,
.system_reset = mango_system_reset
};
static int mango_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc, i2c_bus;
struct i2c_adapter *adapter;
uint64_t addr;
/* we are mango,mcu node */
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
if (rc)
return rc;
mango.reg = addr;
/* find i2c bus parent node */
i2c_bus = fdt_parent_offset(fdt, nodeoff);
if (i2c_bus < 0)
return i2c_bus;
/* i2c adapter get */
rc = fdt_i2c_adapter_get(fdt, i2c_bus, &adapter);
if (rc)
return rc;
mango.adapter = adapter;
sbi_system_reset_add_device(&mango_reset_i2c);
fdt_del_node(fdt, nodeoff);
return 0;
}
static const struct fdt_match mango_reset_match[] = {
{ .compatible = "mango,reset", .data = (void *)true},
{ },
};
struct fdt_reset fdt_reset_sophgo_mcu = {
.match_table = mango_reset_match,
.init = mango_reset_init,
};

View File

@@ -0,0 +1,123 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2023 Sophgo
*
* Authors:
* Chunzhi Lin <chunzhi.lin@sophgo.com>
*/
#include <libfdt.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_system.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/reset/fdt_reset.h>
#define TOP_BASE 0x7030010000
#define SOPHGO_TOP_CTRL_REG_OFFSET 0x008
#define REG_BIT(offset) (1U << (offset))
#define BIT_MASK_TOP_CTRL_SW_ROOT_RESET_EN REG_BIT(2)
#define SOPHGO_WDT_CR_REG_OFFSET 0x00
#define SOPHGO_WDT_TORR_REG_OFFSET 0x04
#define SOPHGO_WDT_CRR_REG_OFFSET 0x0C
static volatile char *sophgo_wdt_base;
static volatile char *sophgo_top_base;
static void sophgo_wdt_system_reset(u32 type, u32 reason)
{
u32 val;
val = readl(sophgo_top_base + SOPHGO_TOP_CTRL_REG_OFFSET);
writel((val | BIT_MASK_TOP_CTRL_SW_ROOT_RESET_EN),
sophgo_top_base + SOPHGO_TOP_CTRL_REG_OFFSET);
sbi_timer_udelay(1);
/*next reset time = 2^(16 + 0x0b) / 100M = 1.34s */
writel(0x0b, sophgo_wdt_base + SOPHGO_WDT_TORR_REG_OFFSET);
sbi_timer_udelay(1);
/* a safety feature for counter restart register */
writel(0x76, sophgo_wdt_base + SOPHGO_WDT_CRR_REG_OFFSET);
sbi_timer_udelay(1);
/* reset pluse length: 32 pclk cycles; enable wdt */
writel(0x11, sophgo_wdt_base + SOPHGO_WDT_CR_REG_OFFSET);
return;
}
static int sophgo_wdt_system_reset_check(u32 type, u32 reason)
{
switch (type) {
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
return 1;
}
return 0;
}
static int sophgo_wdt_system_get_top_base(void *fdt,
int nodeoff, unsigned long *addr)
{
const fdt32_t *val;
int len, noff;
noff = 0;
val = fdt_getprop(fdt, nodeoff, "subctrl-syscon", &len);
if (val || len >= sizeof(fdt32_t)) {
noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
if (noff < 0)
return noff;
}
return fdt_get_node_addr_size(fdt, noff, 0, addr, NULL);
}
static struct sbi_system_reset_device mango_reset_wdt = {
.name = "mango-wdt",
.system_reset_check = sophgo_wdt_system_reset_check,
.system_reset = sophgo_wdt_system_reset,
};
static int mango_wdt_reset_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
unsigned long wdt_addr, top_addr;
int rc;
rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &wdt_addr, NULL);
if (rc < 0 || !wdt_addr) {
return SBI_ENODEV;
}
sophgo_wdt_base = (volatile char *)(unsigned long)wdt_addr;
rc = sophgo_wdt_system_get_top_base(fdt, nodeoff, &top_addr);
if (rc < 0 || !top_addr)
return SBI_ENODEV;
sophgo_top_base = (volatile char *)(unsigned long)top_addr;
sbi_system_reset_add_device(&mango_reset_wdt);
return 0;
}
static const struct fdt_match mango_wdt_reset_match[] = {
{ .compatible = "mango,wdt-reset", .data = (void *)true},
{ },
};
struct fdt_reset fdt_reset_sophgo_wdt = {
.match_table = mango_wdt_reset_match,
.init = mango_wdt_reset_init,
};

View File

@@ -23,6 +23,16 @@ libsbiutils-objs-$(CONFIG_FDT_RESET_HTIF) += reset/fdt_reset_htif.o
carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SIFIVE_TEST) += fdt_reset_sifive_test
libsbiutils-objs-$(CONFIG_FDT_RESET_SIFIVE_TEST) += reset/fdt_reset_sifive_test.o
carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += fdt_reset_sophgo_cpld_poweroff
carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += fdt_reset_sophgo_cpld_reboot
libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += reset/fdt_reset_sophgo_cpld.o
carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SOPHGO_MCU) += fdt_reset_sophgo_mcu
libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_MCU) += reset/fdt_reset_sophgo_mcu.o
carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SOPHGO_WDT) += fdt_reset_sophgo_wdt
libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_WDT) += reset/fdt_reset_sophgo_wdt.o
carray-fdt_reset_drivers-$(CONFIG_FDT_RESET_SUNXI_WDT) += fdt_reset_sunxi_wdt
libsbiutils-objs-$(CONFIG_FDT_RESET_SUNXI_WDT) += reset/fdt_reset_sunxi_wdt.o

View File

@@ -17,6 +17,13 @@
extern struct fdt_serial *fdt_serial_drivers[];
extern unsigned long fdt_serial_drivers_size;
static struct fdt_serial dummy = {
.match_table = NULL,
.init = NULL,
};
static struct fdt_serial *current_driver = &dummy;
int fdt_serial_init(void)
{
const void *prop;
@@ -50,16 +57,21 @@ int fdt_serial_init(void)
if (!match)
continue;
/* drv->init must not be NULL */
if (drv->init == NULL)
return SBI_EFAIL;
rc = drv->init(fdt, noff, match);
if (rc == SBI_ENODEV)
continue;
return rc;
if (drv->init) {
rc = drv->init(fdt, noff, match);
if (rc == SBI_ENODEV)
continue;
if (rc)
return rc;
}
current_driver = drv;
break;
}
/* Check if we found desired driver */
if (current_driver != &dummy)
goto done;
/* Lastly check all DT nodes */
for (pos = 0; pos < fdt_serial_drivers_size; pos++) {
drv = fdt_serial_drivers[pos];
@@ -68,15 +80,17 @@ int fdt_serial_init(void)
if (noff < 0)
continue;
/* drv->init must not be NULL */
if (drv->init == NULL)
return SBI_EFAIL;
rc = drv->init(fdt, noff, match);
if (rc == SBI_ENODEV)
continue;
return rc;
if (drv->init) {
rc = drv->init(fdt, noff, match);
if (rc == SBI_ENODEV)
continue;
if (rc)
return rc;
}
current_driver = drv;
break;
}
return SBI_ENODEV;
done:
return 0;
}

View File

@@ -19,6 +19,11 @@ config FDT_TIMER_PLMT
select TIMER_PLMT
default n
config FDT_TIMER_SG2042_GMT
bool "SOPHGO SG2042 global mtimer FDT driver"
select TIMER_SG2042_GMT
default n
endif
config TIMER_MTIMER
@@ -29,4 +34,8 @@ config TIMER_PLMT
bool "Andes PLMT support"
default n
config TIMER_SG2042_GMT
bool "SOPHGO SG2042 GMT support"
default n
endmenu

View File

@@ -13,17 +13,12 @@
#include <sbi/sbi_bitops.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_timer.h>
#include <sbi_utils/timer/aclint_mtimer.h>
static unsigned long mtimer_ptr_offset;
#define mtimer_get_hart_data_ptr(__scratch) \
sbi_scratch_read_type((__scratch), void *, mtimer_ptr_offset)
#define mtimer_set_hart_data_ptr(__scratch, __mtimer) \
sbi_scratch_write_type((__scratch), void *, mtimer_ptr_offset, (__mtimer))
static struct aclint_mtimer_data *mtimer_hartid2data[SBI_HARTMASK_MAX_BITS];
#if __riscv_xlen != 32
static u64 mtimer_time_rd64(volatile u64 *addr)
@@ -58,54 +53,30 @@ static void mtimer_time_wr32(bool timecmp, u64 value, volatile u64 *addr)
static u64 mtimer_value(void)
{
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
struct aclint_mtimer_data *mt;
mt = mtimer_get_hart_data_ptr(scratch);
if (!mt)
return 0;
struct aclint_mtimer_data *mt = mtimer_hartid2data[current_hartid()];
u64 *time_val = (void *)mt->mtime_addr;
/* Read MTIMER Time Value */
return mt->time_rd((void *)mt->mtime_addr);
return mt->time_rd(time_val);
}
static void mtimer_event_stop(void)
{
u32 target_hart = current_hartid();
struct sbi_scratch *scratch;
struct aclint_mtimer_data *mt;
u64 *time_cmp;
scratch = sbi_hartid_to_scratch(target_hart);
if (!scratch)
return;
mt = mtimer_get_hart_data_ptr(scratch);
if (!mt)
return;
struct aclint_mtimer_data *mt = mtimer_hartid2data[target_hart];
u64 *time_cmp = (void *)mt->mtimecmp_addr;
/* Clear MTIMER Time Compare */
time_cmp = (void *)mt->mtimecmp_addr;
mt->time_wr(true, -1ULL, &time_cmp[target_hart - mt->first_hartid]);
}
static void mtimer_event_start(u64 next_event)
{
u32 target_hart = current_hartid();
struct sbi_scratch *scratch;
struct aclint_mtimer_data *mt;
u64 *time_cmp;
scratch = sbi_hartid_to_scratch(target_hart);
if (!scratch)
return;
mt = mtimer_get_hart_data_ptr(scratch);
if (!mt)
return;
struct aclint_mtimer_data *mt = mtimer_hartid2data[target_hart];
u64 *time_cmp = (void *)mt->mtimecmp_addr;
/* Program MTIMER Time Compare */
time_cmp = (void *)mt->mtimecmp_addr;
mt->time_wr(true, next_event,
&time_cmp[target_hart - mt->first_hartid]);
}
@@ -155,14 +126,8 @@ int aclint_mtimer_warm_init(void)
{
u64 *mt_time_cmp;
u32 target_hart = current_hartid();
struct sbi_scratch *scratch;
struct aclint_mtimer_data *mt;
struct aclint_mtimer_data *mt = mtimer_hartid2data[target_hart];
scratch = sbi_hartid_to_scratch(target_hart);
if (!scratch)
return SBI_ENOENT;
mt = mtimer_get_hart_data_ptr(scratch);
if (!mt)
return SBI_ENODEV;
@@ -182,7 +147,6 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
{
u32 i;
int rc;
struct sbi_scratch *scratch;
/* Sanity checks */
if (!mt ||
@@ -191,18 +155,12 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
(mt->mtime_size && (mt->mtime_size & (ACLINT_MTIMER_ALIGN - 1))) ||
(mt->mtimecmp_addr & (ACLINT_MTIMER_ALIGN - 1)) ||
(mt->mtimecmp_size & (ACLINT_MTIMER_ALIGN - 1)) ||
(mt->first_hartid >= SBI_HARTMASK_MAX_BITS) ||
(mt->hart_count > ACLINT_MTIMER_MAX_HARTS))
return SBI_EINVAL;
if (reference && mt->mtime_freq != reference->mtime_freq)
return SBI_EINVAL;
/* Allocate scratch space pointer */
if (!mtimer_ptr_offset) {
mtimer_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!mtimer_ptr_offset)
return SBI_ENOMEM;
}
/* Initialize private data */
aclint_mtimer_set_reference(mt, reference);
mt->time_rd = mtimer_time_rd32;
@@ -216,13 +174,9 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
}
#endif
/* Update MTIMER pointer in scratch space */
for (i = 0; i < mt->hart_count; i++) {
scratch = sbi_hartid_to_scratch(mt->first_hartid + i);
if (!scratch)
return SBI_ENOENT;
mtimer_set_hart_data_ptr(scratch, mt);
}
/* Update MTIMER hartid table */
for (i = 0; i < mt->hart_count; i++)
mtimer_hartid2data[mt->first_hartid + i] = mt;
if (!mt->mtime_size) {
/* Disable reading mtime when mtime is not available */
@@ -248,7 +202,7 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
SBI_DOMAIN_MEMREGION_M_WRITABLE));
if (rc)
return rc;
} else {
} else if (!mt->use_extern_domain) {
rc = sbi_domain_root_add_memrange(mt->mtime_addr,
mt->mtime_size, MTIMER_REGION_ALIGN,
(SBI_DOMAIN_MEMREGION_MMIO |

View File

@@ -16,17 +16,24 @@
extern struct fdt_timer *fdt_timer_drivers[];
extern unsigned long fdt_timer_drivers_size;
static struct fdt_timer *current_driver = NULL;
static struct fdt_timer dummy = {
.match_table = NULL,
.cold_init = NULL,
.warm_init = NULL,
.exit = NULL,
};
static struct fdt_timer *current_driver = &dummy;
void fdt_timer_exit(void)
{
if (current_driver && current_driver->exit)
if (current_driver->exit)
current_driver->exit();
}
static int fdt_timer_warm_init(void)
{
if (current_driver && current_driver->warm_init)
if (current_driver->warm_init)
return current_driver->warm_init();
return 0;
}
@@ -44,28 +51,20 @@ static int fdt_timer_cold_init(void)
noff = -1;
while ((noff = fdt_find_match(fdt, noff,
drv->match_table, &match)) >= 0) {
/* drv->cold_init must not be NULL */
if (drv->cold_init == NULL)
return SBI_EFAIL;
rc = drv->cold_init(fdt, noff, match);
if (rc == SBI_ENODEV)
continue;
if (rc)
return rc;
if (drv->cold_init) {
rc = drv->cold_init(fdt, noff, match);
if (rc == SBI_ENODEV)
continue;
if (rc)
return rc;
}
current_driver = drv;
/*
* We will have multiple timer devices on multi-die or
* multi-socket systems so we cannot break here.
*/
}
if (current_driver != &dummy)
break;
}
/*
* We can't fail here since systems with Sstc might not provide
* mtimer/clint DT node in the device tree.
*/
return 0;
}

View File

@@ -9,54 +9,45 @@
#include <libfdt.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_list.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/timer/aclint_mtimer.h>
#define MTIMER_MAX_NR 32
struct timer_mtimer_quirks {
unsigned int mtime_offset;
bool has_64bit_mmio;
bool without_mtime;
bool use_extern_domain;
};
struct timer_mtimer_node {
struct sbi_dlist head;
struct aclint_mtimer_data data;
};
static SBI_LIST_HEAD(mtn_list);
static unsigned long mtimer_count = 0;
static struct aclint_mtimer_data mtimer[MTIMER_MAX_NR];
static struct aclint_mtimer_data *mt_reference = NULL;
static int timer_mtimer_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
int i, rc;
unsigned long addr[2], size[2];
struct timer_mtimer_node *mtn, *n;
struct aclint_mtimer_data *mt;
mtn = sbi_zalloc(sizeof(*mtn));
if (!mtn)
return SBI_ENOMEM;
mt = &mtn->data;
if (MTIMER_MAX_NR <= mtimer_count)
return SBI_ENOSPC;
mt = &mtimer[mtimer_count];
rc = fdt_parse_aclint_node(fdt, nodeoff, true,
&addr[0], &size[0], &addr[1], &size[1],
&mt->first_hartid, &mt->hart_count);
if (rc) {
sbi_free(mtn);
if (rc)
return rc;
}
mt->has_64bit_mmio = true;
mt->has_shared_mtime = false;
rc = fdt_parse_timebase_frequency(fdt, &mt->mtime_freq);
if (rc) {
sbi_free(mtn);
if (rc)
return rc;
}
if (match->data) { /* SiFive CLINT */
const struct timer_mtimer_quirks *quirks = match->data;
@@ -76,6 +67,7 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
mt->mtimecmp_addr += quirks->mtime_offset;
/* Apply additional CLINT quirks */
mt->has_64bit_mmio = quirks->has_64bit_mmio;
mt->use_extern_domain = quirks->use_extern_domain;
} else { /* RISC-V ACLINT MTIMER */
/* Set ACLINT MTIMER addresses */
mt->mtime_addr = addr[0];
@@ -87,8 +79,8 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
/* Check if MTIMER device has shared MTIME address */
if (mt->mtime_size) {
mt->has_shared_mtime = false;
sbi_list_for_each_entry(n, &mtn_list, head) {
if (n->data.mtime_addr == mt->mtime_addr) {
for (i = 0; i < mtimer_count; i++) {
if (mtimer[i].mtime_addr == mt->mtime_addr) {
mt->has_shared_mtime = true;
break;
}
@@ -100,10 +92,8 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
/* Initialize the MTIMER device */
rc = aclint_mtimer_cold_init(mt, mt_reference);
if (rc) {
sbi_free(mtn);
if (rc)
return rc;
}
/*
* Select first MTIMER device with no associated HARTs as our
@@ -118,17 +108,16 @@ static int timer_mtimer_cold_init(void *fdt, int nodeoff,
* Set reference for already propbed MTIMER devices
* with non-shared MTIME
*/
sbi_list_for_each_entry(n, &mtn_list, head) {
if (!n->data.has_shared_mtime)
aclint_mtimer_set_reference(&n->data, mt);
}
for (i = 0; i < mtimer_count; i++)
if (!mtimer[i].has_shared_mtime)
aclint_mtimer_set_reference(&mtimer[i], mt);
}
/* Explicitly sync-up MTIMER devices not associated with any HARTs */
if (!mt->hart_count)
aclint_mtimer_sync(mt);
sbi_list_add_tail(&mtn->head, &mtn_list);
mtimer_count++;
return 0;
}
@@ -142,10 +131,20 @@ static const struct timer_mtimer_quirks thead_clint_quirks = {
.without_mtime = true,
};
static const struct timer_mtimer_quirks thead_clint_sep_quirks = {
.mtime_offset = CLINT_MTIMER_OFFSET,
.without_mtime = true,
.use_extern_domain = true,
};
static const struct fdt_match timer_mtimer_match[] = {
{ .compatible = "riscv,clint0", .data = &sifive_clint_quirks },
{ .compatible = "sifive,clint0", .data = &sifive_clint_quirks },
{ .compatible = "thead,c900-clint", .data = &thead_clint_quirks },
{ .compatible = "thead,c900-clint-mtimer",
.data = &thead_clint_sep_quirks },
{ .compatible = "sophgo,sg2042-clint-mtimer",
.data = &thead_clint_sep_quirks },
{ .compatible = "riscv,aclint-mtimer" },
{ },
};

View File

@@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Andes Technology Corporation
*
* Authors:
* Yu Chien Peter Lin <peterlin@andestech.com>
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/timer/sg2042_gmt.h>
#include <sbi/sbi_error.h>
#include <libfdt.h>
static int fdt_sg2042gmt_cold_timer_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int err;
unsigned long mtimer_base, mtimer_size,
mtimecmp_base, mtimecmp_size,
declared_freq, actual_freq, timecmp_freq;
const fdt32_t *val;
int len;
err = fdt_get_node_addr_size(fdt, nodeoff, 0, &mtimer_base, &mtimer_size);
if (err)
return err;
err = fdt_get_node_addr_size(fdt, nodeoff, 1, &mtimecmp_base, &mtimecmp_size);
if (err)
return err;
err = fdt_parse_timebase_frequency(fdt, &declared_freq);
if (err)
return err;
val = (fdt32_t *)fdt_getprop(fdt, nodeoff, "clock-frequency", &len);
if (len < 8 || val == NULL)
return SBI_EINVAL;
actual_freq = fdt32_to_cpu(*val);
timecmp_freq = fdt32_to_cpu(*(val + 1));
return sg2042gmt_cold_timer_init(mtimer_base,
mtimecmp_base, mtimecmp_size,
declared_freq, actual_freq, timecmp_freq);
}
static const struct fdt_match timer_sg2042gmt_match[] = {
{ .compatible = "sophgo,sg2042-global-mtimer" },
{},
};
struct fdt_timer fdt_timer_sg2042_gmt = {
.match_table = timer_sg2042gmt_match,
.cold_init = fdt_sg2042gmt_cold_timer_init,
.warm_init = sg2042gmt_warm_timer_init,
.exit = NULL,
};

View File

@@ -9,6 +9,7 @@
libsbiutils-objs-$(CONFIG_TIMER_MTIMER) += timer/aclint_mtimer.o
libsbiutils-objs-$(CONFIG_TIMER_PLMT) += timer/andes_plmt.o
libsbiutils-objs-$(CONFIG_TIMER_SG2042_GMT) += timer/sg2042_gmt.o
libsbiutils-objs-$(CONFIG_FDT_TIMER) += timer/fdt_timer.o
libsbiutils-objs-$(CONFIG_FDT_TIMER) += timer/fdt_timer_drivers.o
@@ -18,3 +19,6 @@ libsbiutils-objs-$(CONFIG_FDT_TIMER_MTIMER) += timer/fdt_timer_mtimer.o
carray-fdt_timer_drivers-$(CONFIG_FDT_TIMER_PLMT) += fdt_timer_plmt
libsbiutils-objs-$(CONFIG_FDT_TIMER_PLMT) += timer/fdt_timer_plmt.o
carray-fdt_timer_drivers-$(CONFIG_FDT_TIMER_SG2042_GMT) += fdt_timer_sg2042_gmt
libsbiutils-objs-$(CONFIG_FDT_TIMER_SG2042_GMT) += timer/fdt_timer_sg2042_gmt.o

View File

@@ -0,0 +1,135 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 Andes Technology Corporation
*
* Authors:
* Yu Chien Peter Lin <peterlin@andestech.com>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_timer.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/timer/sg2042_gmt.h>
struct sg2042gmt_data {
unsigned long mtimer_base;
unsigned long mtimecmp_base;
unsigned long mtimecmp_size;
unsigned long declared_freq;
unsigned long actual_freq;
unsigned long timecmp_freq;
} sg2042gmt;
#define SG2042GMT_TIMECMP_CLUSTER_SIZE 0x10000
#define SG2042GMT_TIMECMP_CLUSTER_CORE_COUNT 4
static void *timecmp_addr(unsigned int hart_id)
{
unsigned int cluster_id = hart_id / SG2042GMT_TIMECMP_CLUSTER_CORE_COUNT;
unsigned int cluster_offset = hart_id % SG2042GMT_TIMECMP_CLUSTER_CORE_COUNT;
return (void *)(sg2042gmt.mtimecmp_base + 0x4000 +
cluster_id * SG2042GMT_TIMECMP_CLUSTER_SIZE +
cluster_offset * 8);
}
static u64 sg2042gmt_timer_value(void)
{
u64 global_timer = readq_relaxed((void *)sg2042gmt.mtimer_base);
/* convert global timer to declared frequency */
return global_timer / (sg2042gmt.actual_freq / sg2042gmt.declared_freq);
}
static void sg2042gmt_timer_event_stop(void)
{
unsigned int hart_id = current_hartid();
writel_relaxed(-1U, timecmp_addr(hart_id));
writel_relaxed(-1U, timecmp_addr(hart_id) + 4);
}
static void sg2042gmt_timer_event_start(u64 next_event)
{
unsigned int hart_id = current_hartid();
u64 global_timer = readq_relaxed((void *)sg2042gmt.mtimer_base);
u64 clint_timer = csr_read(CSR_TIME);
u64 delta_global_timer, delta_clint_timer;
delta_global_timer =
(next_event * (sg2042gmt.actual_freq / sg2042gmt.declared_freq)) - global_timer;
delta_clint_timer = delta_global_timer * (sg2042gmt.timecmp_freq / sg2042gmt.actual_freq);
next_event = clint_timer + delta_clint_timer;
writel_relaxed(next_event >> 32, timecmp_addr(hart_id) + 4);
writel_relaxed(next_event & 0xffffffff, timecmp_addr(hart_id));
}
static struct sbi_timer_device sg2042gmt_timer = {
.name = "sg2042gmt",
.timer_freq = 50000000,
.timer_value = sg2042gmt_timer_value,
.timer_event_start = sg2042gmt_timer_event_start,
.timer_event_stop = sg2042gmt_timer_event_stop
};
int sg2042gmt_cold_timer_init(unsigned long mtimer_base,
unsigned long mtimecmp_base,
unsigned long mtimecmp_size,
unsigned long declared_freq,
unsigned long actual_freq,
unsigned long timecmp_freq)
{
int err;
/* Add SG2042 GMT timer and time compare region to the root domain */
#if 0
err = sbi_domain_root_add_memrange(
mtimer_base, 4096, 4096,
SBI_DOMAIN_MEMREGION_MMIO | SBI_DOMAIN_MEMREGION_READABLE);
if (err) {
sbi_printf("add timer to root domain failed\n");
return err;
}
#endif
err = sbi_domain_root_add_memrange(
mtimecmp_base, mtimecmp_size, 4096,
SBI_DOMAIN_MEMREGION_MMIO |
SBI_DOMAIN_MEMREGION_READABLE |
SBI_DOMAIN_MEMREGION_WRITEABLE);
if (err) {
return err;
}
sg2042gmt_timer.timer_freq = declared_freq;
sg2042gmt.mtimer_base = mtimer_base;
sg2042gmt.mtimecmp_base = mtimecmp_base;
sg2042gmt.mtimecmp_size = mtimecmp_size;
sg2042gmt.declared_freq = declared_freq;
sg2042gmt.actual_freq = actual_freq;
sg2042gmt.timecmp_freq = timecmp_freq;
sbi_timer_set_device(&sg2042gmt_timer);
return 0;
}
int sg2042gmt_warm_timer_init(void)
{
if (!sg2042gmt.mtimer_base)
return SBI_ENODEV;
sg2042gmt_timer_event_stop();
return 0;
}

View File

@@ -185,6 +185,5 @@ const struct sbi_platform platform = {
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = ARIANE_HART_COUNT,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(ARIANE_HART_COUNT),
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -220,7 +220,5 @@ const struct sbi_platform platform = {
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = OPENPITON_DEFAULT_HART_COUNT,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.heap_size =
SBI_PLATFORM_DEFAULT_HEAP_SIZE(OPENPITON_DEFAULT_HART_COUNT),
.platform_ops_addr = (unsigned long)&platform_ops
};

View File

@@ -36,7 +36,6 @@ config PLATFORM_ANDES_AE350
config PLATFORM_RENESAS_RZFIVE
bool "Renesas RZ/Five support"
select ANDES45_PMA
select ANDES_SBI
default n
config PLATFORM_SIFIVE_FU540
@@ -52,6 +51,10 @@ config PLATFORM_STARFIVE_JH7110
bool "StarFive JH7110 support"
default n
config PLATFORM_SOPHGO_MANGO
bool "Sophgo MANGO support"
default n
source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
endif

View File

@@ -239,9 +239,17 @@ static void thead_c9xx_pmu_ctr_enable_irq(uint32_t ctr_idx)
* Otherwise, there will be race conditions where we may clear the bit
* the software is yet to handle the interrupt.
*/
if (!(mip_val & THEAD_C9XX_MIP_MOIP))
if (mip_val & THEAD_C9XX_MIP_MOIP)
csr_clear(THEAD_C9XX_CSR_MCOUNTEROF, BIT(ctr_idx));
/**
* This register is described in c9xx document as the control register
* for enabling writes to the superuser state counter. However, if the
* corresponding bit is not set to 1, scounterof will always read as 0
* when the counter register overflows.
*/
csr_set(THEAD_C9XX_CSR_MCOUNTERWEN, BIT(ctr_idx));
/**
* SSCOFPMF uses the OF bit for enabling/disabling the interrupt,
* while the C9XX has designated enable bits.
@@ -252,6 +260,16 @@ static void thead_c9xx_pmu_ctr_enable_irq(uint32_t ctr_idx)
static void thead_c9xx_pmu_ctr_disable_irq(uint32_t ctr_idx)
{
unsigned long mip_val;
if (ctr_idx >= SBI_PMU_HW_CTR_MAX)
return;
mip_val = csr_read(CSR_MIP);
if (mip_val & THEAD_C9XX_MIP_MOIP)
csr_clear(THEAD_C9XX_CSR_MCOUNTEROF, BIT(ctr_idx));
csr_clear(THEAD_C9XX_CSR_MCOUNTERWEN, BIT(ctr_idx));
csr_clear(THEAD_C9XX_CSR_MCOUNTERINTEN, BIT(ctr_idx));
}

View File

@@ -3,7 +3,3 @@
config ANDES45_PMA
bool "Andes PMA support"
default n
config ANDES_SBI
bool "Andes SBI support"
default n

View File

@@ -1,51 +0,0 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (C) 2023 Renesas Electronics Corp.
*
*/
#include <andes/andes45.h>
#include <andes/andes_sbi.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_error.h>
enum sbi_ext_andes_fid {
SBI_EXT_ANDES_FID0 = 0, /* Reserved for future use */
SBI_EXT_ANDES_IOCP_SW_WORKAROUND,
};
static bool andes45_cache_controllable(void)
{
return (((csr_read(CSR_MICM_CFG) & MICM_CFG_ISZ_MASK) ||
(csr_read(CSR_MDCM_CFG) & MDCM_CFG_DSZ_MASK)) &&
(csr_read(CSR_MMSC_CFG) & MMSC_CFG_CCTLCSR_MASK) &&
(csr_read(CSR_MCACHE_CTL) & MCACHE_CTL_CCTL_SUEN_MASK) &&
misa_extension('U'));
}
static bool andes45_iocp_disabled(void)
{
return (csr_read(CSR_MMSC_CFG) & MMSC_IOCP_MASK) ? false : true;
}
static bool andes45_apply_iocp_sw_workaround(void)
{
return andes45_cache_controllable() & andes45_iocp_disabled();
}
int andes_sbi_vendor_ext_provider(long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap,
const struct fdt_match *match)
{
switch (funcid) {
case SBI_EXT_ANDES_IOCP_SW_WORKAROUND:
*out_value = andes45_apply_iocp_sw_workaround();
break;
default:
return SBI_EINVAL;
}
return 0;
}

View File

@@ -6,4 +6,3 @@ carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350
platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o
platform-objs-$(CONFIG_ANDES45_PMA) += andes/andes45-pma.o
platform-objs-$(CONFIG_ANDES_SBI) += andes/andes_sbi.o

View File

@@ -4,8 +4,10 @@ CONFIG_PLATFORM_RENESAS_RZFIVE=y
CONFIG_PLATFORM_SIFIVE_FU540=y
CONFIG_PLATFORM_SIFIVE_FU740=y
CONFIG_PLATFORM_STARFIVE_JH7110=y
CONFIG_PLATFORM_SOPHGO_MANGO=y
CONFIG_FDT_GPIO=y
CONFIG_FDT_GPIO_SIFIVE=y
CONFIG_FDT_GPIO_SOPHGO=y
CONFIG_FDT_GPIO_STARFIVE=y
CONFIG_FDT_I2C=y
CONFIG_FDT_I2C_SIFIVE=y
@@ -22,6 +24,9 @@ CONFIG_FDT_RESET_ATCWDT200=y
CONFIG_FDT_RESET_GPIO=y
CONFIG_FDT_RESET_HTIF=y
CONFIG_FDT_RESET_SIFIVE_TEST=y
CONFIG_FDT_RESET_SOPHGO_CPLD=y
CONFIG_FDT_RESET_SOPHGO_MCU=y
CONFIG_FDT_RESET_SOPHGO_WDT=y
CONFIG_FDT_RESET_SUNXI_WDT=y
CONFIG_FDT_RESET_THEAD=y
CONFIG_FDT_SERIAL=y
@@ -37,4 +42,5 @@ CONFIG_FDT_SERIAL_XILINX_UARTLITE=y
CONFIG_FDT_TIMER=y
CONFIG_FDT_TIMER_MTIMER=y
CONFIG_FDT_TIMER_PLMT=y
CONFIG_FDT_TIMER_SG2042_GMT=y
CONFIG_SERIAL_SEMIHOSTING=y

View File

@@ -4,26 +4,7 @@
#define CSR_MARCHID_MICROID 0xfff
/* Memory and Miscellaneous Registers */
#define CSR_MCACHE_CTL 0x7ca
#define CSR_MCCTLCOMMAND 0x7cc
/* Configuration Control & Status Registers */
#define CSR_MICM_CFG 0xfc0
#define CSR_MDCM_CFG 0xfc1
#define CSR_MMSC_CFG 0xfc2
#define MICM_CFG_ISZ_OFFSET 6
#define MICM_CFG_ISZ_MASK (0x7 << MICM_CFG_ISZ_OFFSET)
#define MDCM_CFG_DSZ_OFFSET 6
#define MDCM_CFG_DSZ_MASK (0x7 << MDCM_CFG_DSZ_OFFSET)
#define MMSC_CFG_CCTLCSR_OFFSET 16
#define MMSC_CFG_CCTLCSR_MASK (0x1 << MMSC_CFG_CCTLCSR_OFFSET)
#define MMSC_IOCP_OFFSET 47
#define MMSC_IOCP_MASK (0x1ULL << MMSC_IOCP_OFFSET)
#define MCACHE_CTL_CCTL_SUEN_OFFSET 8
#define MCACHE_CTL_CCTL_SUEN_MASK (0x1 << MCACHE_CTL_CCTL_SUEN_OFFSET)
#define CSR_MCACHE_CTL 0x7ca
#define CSR_MCCTLCOMMAND 0x7cc
#endif /* _RISCV_ANDES45_H */

View File

@@ -1,15 +0,0 @@
// SPDX-License-Identifier: BSD-2-Clause
#ifndef _RISCV_ANDES_SBI_H
#define _RISCV_ANDES_SBI_H
#include <sbi/sbi_trap.h>
#include <sbi_utils/fdt/fdt_helper.h>
int andes_sbi_vendor_ext_provider(long funcid,
const struct sbi_trap_regs *regs,
unsigned long *out_value,
struct sbi_trap_info *out_trap,
const struct fdt_match *match);
#endif /* _RISCV_ANDES_SBI_H */

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