26 Commits

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

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

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

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

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

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

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

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

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

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

[1] c53925298d

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

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

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

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

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

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

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

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

View File

@@ -467,7 +467,7 @@ _start_warm:
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
@@ -757,6 +757,8 @@ memcmp:
.globl _trap_handler
.globl _trap_exit
_trap_handler:
sfence.vma zero, t0
TRAP_SAVE_AND_SETUP_SP_T0
TRAP_SAVE_MEPC_MSTATUS 0

View File

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

View File

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

View File

@@ -41,6 +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 success
* @return -1 break IPI, done on local hart
* @return -2 need retry
*/
int (* update)(struct sbi_scratch *scratch,
struct sbi_scratch *remote_scratch,

View File

@@ -68,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);
@@ -376,6 +379,20 @@ static inline bool sbi_platform_cold_boot_allowed(
return true;
}
/**
* Check whether given platform should force emulate time CSR
*
* @param plat pointer to struct sbi_platform
*
* @return true such platform force emulate time CSR, false otherwise
*/
static inline bool sbi_platform_force_emulate_time_csr(const struct sbi_platform *plat)
{
if (plat && sbi_platform_ops(plat)->force_emulate_time_csr)
return sbi_platform_ops(plat)->force_emulate_time_csr();
return false;
}
/**
* Nascent (very early) initialization for current HART
*

View File

@@ -41,7 +41,7 @@
/** Offset of extra space in sbi_scratch */
#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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);

View File

@@ -15,6 +15,7 @@
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart.h>
#include <sbi/sbi_hartmask.h>
#include <sbi/sbi_hsm.h>
#include <sbi/sbi_init.h>
#include <sbi/sbi_ipi.h>
@@ -31,7 +32,7 @@ static unsigned long ipi_data_off;
static const struct sbi_ipi_device *ipi_dev = NULL;
static const struct sbi_ipi_event_ops *ipi_ops_array[SBI_IPI_EVENT_MAX];
static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
static int sbi_ipi_update(struct sbi_scratch *scratch, u32 remote_hartid,
u32 event, void *data)
{
int ret;
@@ -69,6 +70,18 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
return 0;
}
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])
return SBI_EINVAL;
ipi_ops = ipi_ops_array[event];
if (ipi_ops->sync)
ipi_ops->sync(scratch);
@@ -82,8 +95,10 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartid,
*/
int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
{
int rc;
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();
@@ -93,23 +108,36 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data)
return rc;
m &= hmask;
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
sbi_hartmask_set_hart(i, &target_mask);
}
} else {
hbase = 0;
while (!sbi_hsm_hart_interruptible_mask(dom, hbase, &m)) {
/* Send IPIs */
for (i = hbase; m; i++, m >>= 1) {
if (m & 1UL)
sbi_ipi_send(scratch, i, event, data);
sbi_hartmask_set_hart(i, &target_mask);
}
hbase += BITS_PER_LONG;
}
}
retry_mask = target_mask;
do {
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, &retry_mask);
}
} while (!done);
/* sync IPIs */
sbi_ipi_sync(scratch, event);
return 0;
}

View File

@@ -337,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
@@ -354,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;
}
@@ -532,6 +535,9 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask,
ret = pmu_ctr_stop_hw(cidx);
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);
}
@@ -876,12 +882,17 @@ 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);
if (sbi_platform_force_emulate_time_csr(plat))
csr_clear(CSR_MCOUNTEREN, MCOUNTEREN_TM);
pmu_reset_event_map(hartid);
}

View File

@@ -211,11 +211,11 @@ 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;
unsigned long *rtlb_sync = NULL;
atomic_t *rtlb_sync = NULL;
tinfo->local_fn(tinfo);
@@ -225,47 +225,40 @@ static void tlb_entry_process(struct sbi_tlb_info *tinfo)
continue;
rtlb_sync = sbi_scratch_offset_ptr(rscratch, tlb_sync_off);
while (atomic_raw_xchg_ulong(rtlb_sync, 1)) ;
atomic_sub_return(rtlb_sync, 1);
}
}
static void tlb_process_count(struct sbi_scratch *scratch, int count)
static int tlb_process_once(struct sbi_scratch *scratch)
{
struct sbi_tlb_info tinfo;
unsigned int deq_count = 0;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
tlb_entry_process(&tinfo);
deq_count++;
if (deq_count > count)
break;
if (!sbi_fifo_dequeue(tlb_fifo, &tinfo)) {
tlb_process_helper(&tinfo);
return 0;
}
return -1;
}
static void tlb_process(struct sbi_scratch *scratch)
{
struct sbi_tlb_info tinfo;
struct sbi_fifo *tlb_fifo =
sbi_scratch_offset_ptr(scratch, tlb_fifo_off);
while (!sbi_fifo_dequeue(tlb_fifo, &tinfo))
tlb_entry_process(&tinfo);
while (!tlb_process_once(scratch));
}
static void tlb_sync(struct sbi_scratch *scratch)
{
unsigned long *tlb_sync =
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
atomic_t *tlb_sync =
sbi_scratch_offset_ptr(scratch, tlb_sync_off);
while (!atomic_raw_xchg_ulong(tlb_sync, 0)) {
while (atomic_read(tlb_sync) > 0) {
/*
* While we are waiting for remote hart to set the sync,
* consume fifo requests to avoid deadlock.
*/
tlb_process_count(scratch, 1);
tlb_process_once(scratch);
}
return;
@@ -343,6 +336,7 @@ static int tlb_update(struct sbi_scratch *scratch,
u32 remote_hartid, void *data)
{
int ret;
atomic_t *tlb_sync;
struct sbi_fifo *tlb_fifo_r;
struct sbi_tlb_info *tinfo = data;
u32 curr_hartid = current_hartid();
@@ -369,11 +363,7 @@ static int tlb_update(struct sbi_scratch *scratch,
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) {
return 1;
}
while (sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
if (ret == SBI_FIFO_UNCHANGED && sbi_fifo_enqueue(tlb_fifo_r, data) < 0) {
/**
* For now, Busy loop until there is space in the fifo.
* There may be case where target hart is also
@@ -382,11 +372,15 @@ static int tlb_update(struct sbi_scratch *scratch,
* TODO: Introduce a wait/wakeup event mechanism to handle
* this properly.
*/
tlb_process_count(scratch, 1);
tlb_process_once(scratch);
sbi_dprintf("hart%d: hart%d tlb fifo full\n",
curr_hartid, remote_hartid);
return -2;
}
tlb_sync = sbi_scratch_offset_ptr(scratch, tlb_sync_off);
atomic_add_return(tlb_sync, 1);
return 0;
}
@@ -413,7 +407,7 @@ int sbi_tlb_init(struct sbi_scratch *scratch, bool cold_boot)
{
int ret;
void *tlb_mem;
unsigned long *tlb_sync;
atomic_t *tlb_sync;
struct sbi_fifo *tlb_q;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
@@ -455,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);
*tlb_sync = 0;
tlb_sync->counter = 0;
sbi_fifo_init(tlb_q, tlb_mem,
SBI_TLB_FIFO_NUM_ENTRIES, SBI_TLB_INFO_SIZE);

View File

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

View File

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

View File

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

View File

@@ -57,6 +57,8 @@ static const struct fdt_match ipi_mswi_match[] = {
{ .compatible = "riscv,clint0", .data = &clint_offset },
{ .compatible = "sifive,clint0", .data = &clint_offset },
{ .compatible = "thead,c900-clint", .data = &clint_offset },
{ .compatible = "sophgo,sg2042-clint-mswi", .data = &clint_offset },
{ .compatible = "thead,c900-clint-mswi", .data = &clint_offset },
{ .compatible = "riscv,aclint-mswi" },
{ },
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -202,7 +202,7 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt,
SBI_DOMAIN_MEMREGION_M_WRITABLE));
if (rc)
return rc;
} else {
} else if (!mt->use_extern_domain) {
rc = sbi_domain_root_add_memrange(mt->mtime_addr,
mt->mtime_size, MTIMER_REGION_ALIGN,
(SBI_DOMAIN_MEMREGION_MMIO |

View File

@@ -13,12 +13,13 @@
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/timer/aclint_mtimer.h>
#define MTIMER_MAX_NR 16
#define MTIMER_MAX_NR 32
struct timer_mtimer_quirks {
unsigned int mtime_offset;
bool has_64bit_mmio;
bool without_mtime;
bool use_extern_domain;
};
static unsigned long mtimer_count = 0;
@@ -66,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];
@@ -129,10 +131,20 @@ static const struct timer_mtimer_quirks thead_clint_quirks = {
.without_mtime = true,
};
static const struct timer_mtimer_quirks thead_clint_sep_quirks = {
.mtime_offset = CLINT_MTIMER_OFFSET,
.without_mtime = true,
.use_extern_domain = true,
};
static const struct fdt_match timer_mtimer_match[] = {
{ .compatible = "riscv,clint0", .data = &sifive_clint_quirks },
{ .compatible = "sifive,clint0", .data = &sifive_clint_quirks },
{ .compatible = "thead,c900-clint", .data = &thead_clint_quirks },
{ .compatible = "thead,c900-clint-mtimer",
.data = &thead_clint_sep_quirks },
{ .compatible = "sophgo,sg2042-clint-mtimer",
.data = &thead_clint_sep_quirks },
{ .compatible = "riscv,aclint-mtimer" },
{ },
};

View File

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

View File

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

View File

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

View File

@@ -51,6 +51,10 @@ config PLATFORM_STARFIVE_JH7110
bool "StarFive JH7110 support"
default n
config PLATFORM_SOPHGO_MANGO
bool "Sophgo MANGO support"
default n
source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
endif

View File

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

View File

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

View File

@@ -19,6 +19,7 @@ struct platform_override {
u64 (*features)(const struct fdt_match *match);
u64 (*tlbr_flush_limit)(const struct fdt_match *match);
bool (*cold_boot_allowed)(u32 hartid, const struct fdt_match *match);
bool (*force_emulate_time_csr)(const struct fdt_match *match);
int (*early_init)(bool cold_boot, const struct fdt_match *match);
int (*final_init)(bool cold_boot, const struct fdt_match *match);
void (*early_exit)(const struct fdt_match *match);

View File

@@ -124,4 +124,6 @@
#define THEAD_C9XX_IRQ_PMU_OVF 17
#define THEAD_C9XX_MIP_MOIP (_UL(1) << THEAD_C9XX_IRQ_PMU_OVF)
extern const struct sbi_pmu_device thead_c9xx_pmu_device;
#endif

View File

@@ -134,6 +134,14 @@ static bool generic_cold_boot_allowed(u32 hartid)
return true;
}
static bool generic_force_emulate_time_csr(void)
{
if (generic_plat && generic_plat->force_emulate_time_csr)
return generic_plat->force_emulate_time_csr(generic_plat_match);
return false;
}
static int generic_nascent_init(void)
{
if (platform_has_mlevel_imsic)
@@ -284,6 +292,7 @@ static int generic_console_init(void)
const struct sbi_platform_operations platform_ops = {
.cold_boot_allowed = generic_cold_boot_allowed,
.force_emulate_time_csr = generic_force_emulate_time_csr,
.nascent_init = generic_nascent_init,
.early_init = generic_early_init,
.final_init = generic_final_init,

View File

@@ -0,0 +1,98 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)
*
* Authors:
* Inochi Amaoto <inochiama@outlook.com>
* YuQing Cai <caiyuqing_hz@163.com>
* ZhenYu Zhang <1204122531@qq.com>
*/
#include <platform_override.h>
#include <thead_c9xx.h>
#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_pmu.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_platform.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/timer/aclint_mtimer.h>
#include <libfdt.h>
#define SOPHGO_MANGO_TIMER_BASE 0x70ac000000UL
#define SOPHGO_MANGO_TIMER_OFFSET 0x10000UL
extern struct sbi_platform platform;
static u32 selected_hartid = -1;
static bool force_emulate_time_csr;
static bool mango_cold_boot_allowed(u32 hartid,
const struct fdt_match *match)
{
if (selected_hartid != -1)
return (selected_hartid == hartid);
return (hartid < 64);
}
int mango_early_init(bool cold_boot, const struct fdt_match *match)
{
const struct sbi_platform * plat = sbi_platform_thishart_ptr();
/*
* Sophgo mango board use seperate 16/32 timers while initiating,
* merge them as a single domain to avoid wasting.
*/
if (cold_boot)
return sbi_domain_root_add_memrange(SOPHGO_MANGO_TIMER_BASE,
SOPHGO_MANGO_TIMER_OFFSET *
sbi_platform_hart_count(plat),
MTIMER_REGION_ALIGN,
(SBI_DOMAIN_MEMREGION_MMIO |
SBI_DOMAIN_MEMREGION_M_READABLE |
SBI_DOMAIN_MEMREGION_M_WRITABLE));
return 0;
}
static int mango_extensions_init(const struct fdt_match *match,
struct sbi_hart_features *hfeatures)
{
sbi_pmu_set_device(&thead_c9xx_pmu_device);
/* auto-detection doesn't work on t-head c9xx cores */
hfeatures->mhpm_count = 29;
hfeatures->mhpm_bits = 64;
return 0;
}
static void mango_fw_init(void *fdt, const struct fdt_match *match)
{
platform.hart_stack_size = 16384;
if (fdt_node_offset_by_compatible(fdt, 0, "sophgo,sg2042-global-mtimer") > 0)
force_emulate_time_csr = true;
else
force_emulate_time_csr = false;
}
static bool mango_force_emulate_time_csr(const struct fdt_match *match)
{
return force_emulate_time_csr;
}
static const struct fdt_match sophgo_mango_match[] = {
{ .compatible = "sophgo,mango" },
{ },
};
const struct platform_override sophgo_mango = {
.match_table = sophgo_mango_match,
.fw_init = mango_fw_init,
.cold_boot_allowed = mango_cold_boot_allowed,
.force_emulate_time_csr = mango_force_emulate_time_csr,
.early_init = mango_early_init,
.extensions_init = mango_extensions_init,
};

View File

@@ -0,0 +1,6 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#
carray-platform_override_modules-$(CONFIG_PLATFORM_SOPHGO_MANGO) += sophgo_mango
platform-objs-$(CONFIG_PLATFORM_SOPHGO_MANGO) += sophgo/mango.o