Compare commits
26 Commits
v1.3.1
...
sg2042-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adc7ba17f3 | ||
|
|
6eef399cfc | ||
|
|
506f47f9fa | ||
|
|
3745939ceb | ||
|
|
44fdaafcb4 | ||
|
|
a82a033c74 | ||
|
|
270f27b81b | ||
|
|
f89d688f60 | ||
|
|
4826e4f743 | ||
|
|
d06c0a7858 | ||
|
|
d21bf89240 | ||
|
|
9af30e56df | ||
|
|
d0b705e19c | ||
|
|
546bc50f9a | ||
|
|
4aab6f3263 | ||
|
|
e1d3b68eeb | ||
|
|
19622b6c93 | ||
|
|
60142dc80c | ||
|
|
31087f36d7 | ||
|
|
58f9b858c5 | ||
|
|
be6e558f66 | ||
|
|
0e87f899c3 | ||
|
|
0b5c942ee9 | ||
|
|
64fb41e927 | ||
|
|
b210bc000c | ||
|
|
35fb234d39 |
8
Makefile
8
Makefile
@@ -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) && \
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
RISC-V Open Source Supervisor Binary Interface (OpenSBI)
|
||||
========================================================
|
||||
|
||||

|
||||
|
||||
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*).
|
||||
|
||||
@@ -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 |
@@ -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
|
||||
|
||||
@@ -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) \
|
||||
({ \
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
@@ -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() \
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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[];
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#define SBI_TLB_FIFO_NUM_ENTRIES 8
|
||||
#define SBI_TLB_FIFO_NUM_ENTRIES 128
|
||||
|
||||
struct sbi_scratch;
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
21
include/sbi_utils/timer/sg2042_gmt.h
Normal file
21
include/sbi_utils/timer/sg2042_gmt.h
Normal 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__ */
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,60 +881,44 @@ 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);
|
||||
|
||||
/* mcycle & minstret is available always */
|
||||
num_hw_ctrs = sbi_hart_mhpm_count(scratch) + 3;
|
||||
if (num_hw_ctrs > SBI_PMU_HW_CTR_MAX)
|
||||
return SBI_EINVAL;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -163,7 +163,7 @@ ulong sbi_get_insn(ulong mepc, struct sbi_trap_info *trap)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return insn;
|
||||
}
|
||||
|
||||
@@ -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(®ions[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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ config FDT_GPIO
|
||||
|
||||
if FDT_GPIO
|
||||
|
||||
config FDT_GPIO_DESIGNWARE
|
||||
bool "DesignWare GPIO driver"
|
||||
default n
|
||||
|
||||
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
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2022 SiFive
|
||||
*
|
||||
* GPIO driver for Synopsys DesignWare APB GPIO
|
||||
*
|
||||
* Authors:
|
||||
* Ben Dooks <ben.dooks@sifive.com>
|
||||
*/
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
#include <sbi_utils/gpio/fdt_gpio.h>
|
||||
|
||||
#define DW_GPIO_CHIP_MAX 4 /* need 1 per bank in use */
|
||||
#define DW_GPIO_PINS_MAX 32
|
||||
|
||||
#define DW_GPIO_DDR 0x4
|
||||
#define DW_GPIO_DR 0x0
|
||||
#define DW_GPIO_BIT(_b) (1UL << (_b))
|
||||
|
||||
struct dw_gpio_chip {
|
||||
void *dr;
|
||||
void *ext;
|
||||
struct gpio_chip chip;
|
||||
};
|
||||
|
||||
extern struct fdt_gpio fdt_gpio_designware;
|
||||
|
||||
static unsigned int dw_gpio_chip_count;
|
||||
static struct dw_gpio_chip dw_gpio_chip_array[DW_GPIO_CHIP_MAX];
|
||||
|
||||
#define pin_to_chip(__p) container_of((__p)->chip, struct dw_gpio_chip, chip);
|
||||
|
||||
static int dw_gpio_direction_output(struct gpio_pin *gp, int value)
|
||||
{
|
||||
struct dw_gpio_chip *chip = pin_to_chip(gp);
|
||||
unsigned long v;
|
||||
|
||||
v = readl(chip->dr + DW_GPIO_DR);
|
||||
if (!value)
|
||||
v &= ~DW_GPIO_BIT(gp->offset);
|
||||
else
|
||||
v |= DW_GPIO_BIT(gp->offset);
|
||||
writel(v, chip->dr + DW_GPIO_DR);
|
||||
|
||||
/* the DR is output only so we can set it then the DDR to set
|
||||
* the data direction, to avoid glitches.
|
||||
*/
|
||||
v = readl(chip->dr + DW_GPIO_DDR);
|
||||
v |= DW_GPIO_BIT(gp->offset);
|
||||
writel(v, chip->dr + DW_GPIO_DDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_gpio_set(struct gpio_pin *gp, int value)
|
||||
{
|
||||
struct dw_gpio_chip *chip = pin_to_chip(gp);
|
||||
unsigned long v;
|
||||
|
||||
v = readl(chip->dr + DW_GPIO_DR);
|
||||
if (!value)
|
||||
v &= ~DW_GPIO_BIT(gp->offset);
|
||||
else
|
||||
v |= DW_GPIO_BIT(gp->offset);
|
||||
writel(v, chip->dr + DW_GPIO_DR);
|
||||
}
|
||||
|
||||
/* notes:
|
||||
* each sub node is a bank and has ngpios or snpns,nr-gpios and a reg property
|
||||
* with the compatible `snps,dw-apb-gpio-port`.
|
||||
* bank A is the only one with irq support but we're not using it here
|
||||
*/
|
||||
|
||||
static int dw_gpio_init_bank(void *fdt, int nodeoff, u32 phandle,
|
||||
const struct fdt_match *match)
|
||||
{
|
||||
struct dw_gpio_chip *chip;
|
||||
const fdt32_t *val;
|
||||
uint64_t addr;
|
||||
int rc, poff, nr_pins, bank, len;
|
||||
|
||||
if (dw_gpio_chip_count >= DW_GPIO_CHIP_MAX)
|
||||
return SBI_ENOSPC;
|
||||
|
||||
/* need to get parent for the address property */
|
||||
poff = fdt_parent_offset(fdt, nodeoff);
|
||||
if (poff < 0)
|
||||
return SBI_EINVAL;
|
||||
|
||||
rc = fdt_get_node_addr_size(fdt, poff, 0, &addr, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
val = fdt_getprop(fdt, nodeoff, "reg", &len);
|
||||
if (!val || len <= 0)
|
||||
return SBI_EINVAL;
|
||||
bank = fdt32_to_cpu(*val);
|
||||
|
||||
val = fdt_getprop(fdt, nodeoff, "snps,nr-gpios", &len);
|
||||
if (!val)
|
||||
val = fdt_getprop(fdt, nodeoff, "ngpios", &len);
|
||||
if (!val || len <= 0)
|
||||
return SBI_EINVAL;
|
||||
nr_pins = fdt32_to_cpu(*val);
|
||||
|
||||
chip = &dw_gpio_chip_array[dw_gpio_chip_count];
|
||||
|
||||
chip->dr = (void *)(uintptr_t)addr + (bank * 0xc);
|
||||
chip->ext = (void *)(uintptr_t)addr + (bank * 4) + 0x50;
|
||||
chip->chip.driver = &fdt_gpio_designware;
|
||||
chip->chip.id = phandle;
|
||||
chip->chip.ngpio = nr_pins;
|
||||
chip->chip.set = dw_gpio_set;
|
||||
chip->chip.direction_output = dw_gpio_direction_output;
|
||||
rc = gpio_chip_add(&chip->chip);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
dw_gpio_chip_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* since we're only probed when used, match on port not main controller node */
|
||||
static const struct fdt_match dw_gpio_match[] = {
|
||||
{ .compatible = "snps,dw-apb-gpio-port" },
|
||||
{ },
|
||||
};
|
||||
|
||||
struct fdt_gpio fdt_gpio_designware = {
|
||||
.match_table = dw_gpio_match,
|
||||
.xlate = fdt_gpio_simple_xlate,
|
||||
.init = dw_gpio_init_bank,
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
157
lib/utils/gpio/fdt_gpio_sophgo.c
Normal file
157
lib/utils/gpio/fdt_gpio_sophgo.c
Normal 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,
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
libsbiutils-objs-$(CONFIG_FDT_GPIO) += gpio/fdt_gpio.o
|
||||
libsbiutils-objs-$(CONFIG_FDT_GPIO) += gpio/fdt_gpio_drivers.o
|
||||
|
||||
carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_DESIGNWARE) += fdt_gpio_designware
|
||||
libsbiutils-objs-$(CONFIG_FDT_GPIO_DESIGNWARE) += gpio/fdt_gpio_designware.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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,35 +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);
|
||||
/*
|
||||
* We don't need to fail if scratch pointer is not available
|
||||
* because we might be dealing with hartid of a HART disabled
|
||||
* in the device tree.
|
||||
*/
|
||||
if (!scratch)
|
||||
continue;
|
||||
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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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" },
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
167
lib/utils/reset/fdt_reset_sophgo_cpld.c
Normal file
167
lib/utils/reset/fdt_reset_sophgo_cpld.c
Normal 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,
|
||||
};
|
||||
157
lib/utils/reset/fdt_reset_sophgo_mcu.c
Normal file
157
lib/utils/reset/fdt_reset_sophgo_mcu.c
Normal 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,
|
||||
};
|
||||
123
lib/utils/reset/fdt_reset_sophgo_wdt.c
Normal file
123
lib/utils/reset/fdt_reset_sophgo_wdt.c
Normal 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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,18 +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);
|
||||
/*
|
||||
* We don't need to fail if scratch pointer is not available
|
||||
* because we might be dealing with hartid of a HART disabled
|
||||
* in the device tree.
|
||||
*/
|
||||
if (!scratch)
|
||||
continue;
|
||||
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 */
|
||||
@@ -253,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 |
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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" },
|
||||
{ },
|
||||
};
|
||||
|
||||
61
lib/utils/timer/fdt_timer_sg2042_gmt.c
Normal file
61
lib/utils/timer/fdt_timer_sg2042_gmt.c
Normal 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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
135
lib/utils/timer/sg2042_gmt.c
Normal file
135
lib/utils/timer/sg2042_gmt.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,3 @@
|
||||
config ANDES45_PMA
|
||||
bool "Andes PMA support"
|
||||
default n
|
||||
|
||||
config ANDES_SBI
|
||||
bool "Andes SBI support"
|
||||
default n
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -4,9 +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_DESIGNWARE=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
|
||||
@@ -23,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
|
||||
@@ -38,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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user