Files
opensbi/lib/utils/timer/fdt_timer_mtimer.c
Inochi Amaoto ba29293dc9 lib: utils/timer: mtimer: only use regname for aclint
The parser will fail if the timer is clint timer and has regname
property. As the regname is only meaningful for aclint, it is more
robust to only check regname for aclint timer.

Fixes: 6112d58 ("lib: utils/fdt: Allow to use reg-names when parsing ACLINT")
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-12-27 11:57:33 +05:30

171 lines
4.4 KiB
C

/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_heap.h>
#include <sbi/sbi_list.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/timer/aclint_mtimer.h>
struct timer_mtimer_quirks {
bool is_clint;
unsigned int clint_mtime_offset;
bool clint_without_mtime;
bool has_64bit_mmio;
};
struct timer_mtimer_node {
struct sbi_dlist head;
struct aclint_mtimer_data data;
};
static SBI_LIST_HEAD(mtn_list);
static struct aclint_mtimer_data *mt_reference = NULL;
static int timer_mtimer_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
unsigned long addr[2], size[2];
struct timer_mtimer_node *mtn, *n;
struct aclint_mtimer_data *mt;
const struct timer_mtimer_quirks *quirks = match->data;
bool is_clint = quirks && quirks->is_clint;
mtn = sbi_zalloc(sizeof(*mtn));
if (!mtn)
return SBI_ENOMEM;
mt = &mtn->data;
rc = fdt_parse_aclint_node(fdt, nodeoff, true, !is_clint,
&addr[0], &size[0], &addr[1], &size[1],
&mt->first_hartid, &mt->hart_count);
if (rc) {
sbi_free(mtn);
return rc;
}
mt->has_64bit_mmio = true;
mt->has_shared_mtime = false;
rc = fdt_parse_timebase_frequency(fdt, &mt->mtime_freq);
if (rc) {
sbi_free(mtn);
return rc;
}
if (is_clint) { /* SiFive CLINT */
/* Set CLINT addresses */
mt->mtimecmp_addr = addr[0] + ACLINT_DEFAULT_MTIMECMP_OFFSET;
mt->mtimecmp_size = ACLINT_DEFAULT_MTIMECMP_SIZE;
if (!quirks->clint_without_mtime) {
mt->mtime_addr = addr[0] + ACLINT_DEFAULT_MTIME_OFFSET;
mt->mtime_size = size[0] - mt->mtimecmp_size;
/* Adjust MTIMER address and size for CLINT device */
mt->mtime_addr += quirks->clint_mtime_offset;
mt->mtime_size -= quirks->clint_mtime_offset;
} else {
mt->mtime_addr = mt->mtime_size = 0;
}
mt->mtimecmp_addr += quirks->clint_mtime_offset;
} else { /* RISC-V ACLINT MTIMER */
/* Set ACLINT MTIMER addresses */
mt->mtime_addr = addr[0];
mt->mtime_size = size[0];
mt->mtimecmp_addr = addr[1];
mt->mtimecmp_size = size[1];
}
/* Apply additional quirks */
if (quirks) {
mt->has_64bit_mmio = quirks->has_64bit_mmio;
}
/* Check if MTIMER device has shared MTIME address */
if (mt->mtime_size) {
mt->has_shared_mtime = false;
sbi_list_for_each_entry(n, &mtn_list, head) {
if (n->data.mtime_addr == mt->mtime_addr) {
mt->has_shared_mtime = true;
break;
}
}
} else {
/* Assume shared time CSR */
mt->has_shared_mtime = true;
}
/* Initialize the MTIMER device */
rc = aclint_mtimer_cold_init(mt, mt_reference);
if (rc) {
sbi_free(mtn);
return rc;
}
/*
* Select first MTIMER device with no associated HARTs as our
* reference MTIMER device. This is only a temporary strategy
* of selecting reference MTIMER device. In future, we might
* define an optional DT property or some other mechanism to
* help us select the reference MTIMER device.
*/
if (!mt->hart_count && !mt_reference) {
mt_reference = mt;
/*
* Set reference for already propbed MTIMER devices
* with non-shared MTIME
*/
sbi_list_for_each_entry(n, &mtn_list, head) {
if (!n->data.has_shared_mtime)
aclint_mtimer_set_reference(&n->data, mt);
}
}
/* Explicitly sync-up MTIMER devices not associated with any HARTs */
if (!mt->hart_count)
aclint_mtimer_sync(mt);
sbi_list_add_tail(&mtn->head, &mtn_list);
return 0;
}
static const struct timer_mtimer_quirks sifive_clint_quirks = {
.is_clint = true,
.clint_mtime_offset = CLINT_MTIMER_OFFSET,
.has_64bit_mmio = true,
};
static const struct timer_mtimer_quirks thead_clint_quirks = {
.is_clint = true,
.clint_mtime_offset = CLINT_MTIMER_OFFSET,
.clint_without_mtime = true,
};
static const struct timer_mtimer_quirks thead_aclint_quirks = {
.has_64bit_mmio = false,
};
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-aclint-mtimer",
.data = &thead_aclint_quirks },
{ .compatible = "riscv,aclint-mtimer" },
{ },
};
struct fdt_timer fdt_timer_mtimer = {
.match_table = timer_mtimer_match,
.cold_init = timer_mtimer_cold_init,
.warm_init = aclint_mtimer_warm_init,
.exit = NULL,
};