Compare commits
26 Commits
sg2042-v1.
...
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 |
@@ -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
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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" },
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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" },
|
||||
{ },
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
98
platform/generic/sophgo/mango.c
Normal file
98
platform/generic/sophgo/mango.c
Normal 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,
|
||||
};
|
||||
6
platform/generic/sophgo/objects.mk
Normal file
6
platform/generic/sophgo/objects.mk
Normal 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
|
||||
Reference in New Issue
Block a user