Files
opensbi/lib/utils/timer/andes_plmt.c
Yu Chien Peter Lin d36709fcaf lib: utils: timer/ipi: Update memregion flags for PLMT and PLICSW
This patch adds unspecified permission flags for the PLICSW region
and updates the permission of the PLMT region.

With this update, both regions will become M-mode only read/write
regions in the root domain.

  Domain0 Region00: 0x00000000f0300000-0x00000000f0300fff M: (I,R,W) S/U: (R,W)
  Domain0 Region01: 0x0000000000040000-0x000000000005ffff M: (R,W) S/U: ()
  Domain0 Region02: 0x0000000000000000-0x000000000003ffff M: (R,X) S/U: ()
> Domain0 Region03: 0x00000000e6000000-0x00000000e60fffff M: (I,R,W) S/U: ()
> Domain0 Region04: 0x00000000e6400000-0x00000000e67fffff M: (I,R,W) S/U: ()
  Domain0 Region05: 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)

The PMP rules of AE350-AX65 (single-core) w/ Smepmp:

  p/x $pmpcfg0
  $1 = {0x1f9b9b9d9b1e00,
  pmp0cfg = {0x0},
                    L--AAXWR
  pmp1cfg = {0x1e} (00011110), pmpaddr1: 0xf0300000 ~   0xf0300fff  (UART1)
  pmp2cfg = {0x9b} (10011011), pmpaddr2:    0x40000 ~      0x5ffff
  pmp3cfg = {0x9d} (10011101), pmpaddr3:        0x0 ~      0x3ffff
  pmp4cfg = {0x9b} (10011011), pmpaddr4: 0xe6000000 ~   0xe60fffff  (PLMT)
  pmp5cfg = {0x9b} (10011011), pmpaddr5: 0xe6400000 ~   0xe67fffff  (PLICSW)
  pmp6cfg = {0x1f} (00011111), pmpaddr6:        0x0 ~ 0xffffffffff
  pmp7cfg = {0x0 }}

The PMP rules of AE350-AX45MP (qual-core) w/o Smepmp:

  p/x $pmpcfg0
  $1 = {0x1f181818181b,
                     L--AAXWR
  pmp0cfg = {0x1b}, (00011011), pmpaddr0: 0xf0300000 ~  0xf0300fff  (UART1)
  pmp1cfg = {0x18}, (00011000), pmpaddr1:    0x40000 ~     0x5ffff
  pmp2cfg = {0x18}, (00011000), pmpaddr2:        0x0 ~     0x3ffff
  pmp3cfg = {0x18}, (00011000), pmpaddr3: 0xe6000000 ~  0xe60fffff  (PLMT)
  pmp4cfg = {0x18}, (00011000), pmpaddr4: 0xe6400000 ~  0xe67fffff  (PLICSW)
  pmp5cfg = {0x1f}, (00011111), pmpaddr5:        0x0 ~ 0x1ffffffff
  pmp6cfg = {0x0 }}

Note that starting from this patch, we restrict the S/U-mode read
permission to the PLMT region, since we should read the TIME CSR
in a lower privilege mode.

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2023-10-06 16:53:26 +05:30

108 lines
2.2 KiB
C

/*
* 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_utils/timer/andes_plmt.h>
struct plmt_data plmt;
static u64 plmt_timer_value(void)
{
#if __riscv_xlen == 64
return readq_relaxed(plmt.time_val);
#else
u32 lo, hi;
do {
hi = readl_relaxed((void *)plmt.time_val + 0x04);
lo = readl_relaxed(plmt.time_val);
} while (hi != readl_relaxed((void *)plmt.time_val + 0x04));
return ((u64)hi << 32) | (u64)lo;
#endif
}
static void plmt_timer_event_stop(void)
{
u32 target_hart = current_hartid();
if (plmt.hart_count <= target_hart)
ebreak();
/* Clear PLMT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(-1ULL, &plmt.time_cmp[target_hart]);
#else
writel_relaxed(-1UL, &plmt.time_cmp[target_hart]);
writel_relaxed(-1UL, (void *)(&plmt.time_cmp[target_hart]) + 0x04);
#endif
}
static void plmt_timer_event_start(u64 next_event)
{
u32 target_hart = current_hartid();
if (plmt.hart_count <= target_hart)
ebreak();
/* Program PLMT Time Compare */
#if __riscv_xlen == 64
writeq_relaxed(next_event, &plmt.time_cmp[target_hart]);
#else
u32 mask = -1UL;
writel_relaxed(next_event & mask, &plmt.time_cmp[target_hart]);
writel_relaxed(next_event >> 32,
(void *)(&plmt.time_cmp[target_hart]) + 0x04);
#endif
}
static struct sbi_timer_device plmt_timer = {
.name = "andes_plmt",
.timer_freq = DEFAULT_AE350_PLMT_FREQ,
.timer_value = plmt_timer_value,
.timer_event_start = plmt_timer_event_start,
.timer_event_stop = plmt_timer_event_stop
};
int plmt_cold_timer_init(struct plmt_data *plmt)
{
int rc;
/* Add PLMT region to the root domain */
rc = sbi_domain_root_add_memrange(
(unsigned long)plmt->time_val, plmt->size,
PLMT_REGION_ALIGN,
SBI_DOMAIN_MEMREGION_MMIO |
SBI_DOMAIN_MEMREGION_M_READABLE |
SBI_DOMAIN_MEMREGION_M_WRITABLE);
if (rc)
return rc;
plmt_timer.timer_freq = plmt->timer_freq;
sbi_timer_set_device(&plmt_timer);
return 0;
}
int plmt_warm_timer_init(void)
{
if (!plmt.time_val)
return SBI_ENODEV;
plmt_timer_event_stop();
return 0;
}