forked from Mirrors/opensbi

This is not used anywhere. Drop it. Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Anup Patel <anup.patel@wdc.com>
140 lines
3.4 KiB
C
140 lines
3.4 KiB
C
/*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2019 Andes Technology Corporation
|
|
*
|
|
* Authors:
|
|
* Zong Li <zong@andestech.com>
|
|
* Nylon Chen <nylon7@andestech.com>
|
|
*/
|
|
|
|
#include <sbi/riscv_asm.h>
|
|
#include <sbi/riscv_io.h>
|
|
#include <sbi/sbi_types.h>
|
|
#include "plicsw.h"
|
|
#include "platform.h"
|
|
|
|
static u32 plicsw_ipi_hart_count;
|
|
static struct plicsw plicsw_dev[AE350_HART_COUNT];
|
|
|
|
static inline void plicsw_claim(void)
|
|
{
|
|
u32 source_hart = current_hartid();
|
|
|
|
plicsw_dev[source_hart].source_id =
|
|
readl(plicsw_dev[source_hart].plicsw_claim);
|
|
}
|
|
|
|
static inline void plicsw_complete(void)
|
|
{
|
|
u32 source_hart = current_hartid();
|
|
u32 source = plicsw_dev[source_hart].source_id;
|
|
|
|
writel(source, plicsw_dev[source_hart].plicsw_claim);
|
|
}
|
|
|
|
static inline void plic_sw_pending(u32 target_hart)
|
|
{
|
|
/*
|
|
* The pending array registers are w1s type.
|
|
* IPI pending array mapping as following:
|
|
*
|
|
* Pending array start address: base + 0x1000
|
|
* -------------------------------------
|
|
* | hart 3 | hart 2 | hart 1 | hart 0 |
|
|
* -------------------------------------
|
|
* Each hart X can send IPI to another hart by setting the
|
|
* corresponding bit in hart X own region(see the below).
|
|
*
|
|
* In each hart region:
|
|
* -----------------------------------------------
|
|
* | bit 7 | bit 6 | bit 5 | bit 4 | ... | bit 0 |
|
|
* -----------------------------------------------
|
|
* The bit 7 is used to send IPI to hart 0
|
|
* The bit 6 is used to send IPI to hart 1
|
|
* The bit 5 is used to send IPI to hart 2
|
|
* The bit 4 is used to send IPI to hart 3
|
|
*/
|
|
u32 source_hart = current_hartid();
|
|
u32 target_offset = (PLICSW_PENDING_PER_HART - 1) - target_hart;
|
|
u32 per_hart_offset = PLICSW_PENDING_PER_HART * source_hart;
|
|
u32 val = 1 << target_offset << per_hart_offset;
|
|
|
|
writel(val, plicsw_dev[source_hart].plicsw_pending);
|
|
}
|
|
|
|
void plicsw_ipi_send(u32 target_hart)
|
|
{
|
|
if (plicsw_ipi_hart_count <= target_hart)
|
|
return;
|
|
|
|
/* Set PLICSW IPI */
|
|
plic_sw_pending(target_hart);
|
|
}
|
|
|
|
void plicsw_ipi_clear(u32 target_hart)
|
|
{
|
|
if (plicsw_ipi_hart_count <= target_hart)
|
|
return;
|
|
|
|
/* Clear PLICSW IPI */
|
|
plicsw_claim();
|
|
plicsw_complete();
|
|
}
|
|
|
|
int plicsw_warm_ipi_init(void)
|
|
{
|
|
u32 hartid = current_hartid();
|
|
|
|
if (!plicsw_dev[hartid].plicsw_pending
|
|
&& !plicsw_dev[hartid].plicsw_enable
|
|
&& !plicsw_dev[hartid].plicsw_claim)
|
|
return -1;
|
|
|
|
/* Clear PLICSW IPI */
|
|
plicsw_ipi_clear(hartid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int plicsw_cold_ipi_init(unsigned long base, u32 hart_count)
|
|
{
|
|
/* Setup source priority */
|
|
uint32_t *priority = (void *)base + PLICSW_PRIORITY_BASE;
|
|
|
|
for (int i = 0; i < AE350_HART_COUNT * PLICSW_PENDING_PER_HART; i++)
|
|
writel(1, &priority[i]);
|
|
|
|
/* Setup target enable */
|
|
uint32_t enable_mask = PLICSW_HART_MASK;
|
|
|
|
for (int i = 0; i < AE350_HART_COUNT; i++) {
|
|
uint32_t *enable = (void *)base + PLICSW_ENABLE_BASE
|
|
+ PLICSW_ENABLE_PER_HART * i;
|
|
writel(enable_mask, &enable[0]);
|
|
enable_mask >>= 1;
|
|
}
|
|
|
|
/* Figure-out PLICSW IPI register address */
|
|
plicsw_ipi_hart_count = hart_count;
|
|
|
|
for (u32 hartid = 0; hartid < AE350_HART_COUNT; hartid++) {
|
|
plicsw_dev[hartid].source_id = 0;
|
|
plicsw_dev[hartid].plicsw_pending =
|
|
(void *)base
|
|
+ PLICSW_PENDING_BASE
|
|
+ ((hartid / 4) * 4);
|
|
plicsw_dev[hartid].plicsw_enable =
|
|
(void *)base
|
|
+ PLICSW_ENABLE_BASE
|
|
+ PLICSW_ENABLE_PER_HART * hartid;
|
|
plicsw_dev[hartid].plicsw_claim =
|
|
(void *)base
|
|
+ PLICSW_CONTEXT_BASE
|
|
+ PLICSW_CONTEXT_CLAIM
|
|
+ PLICSW_CONTEXT_PER_HART * hartid;
|
|
}
|
|
|
|
return 0;
|
|
}
|