aboutsummaryrefslogtreecommitdiffstats
path: root/roms/opensbi/platform/andes/ae350/plicsw.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/opensbi/platform/andes/ae350/plicsw.c')
-rw-r--r--roms/opensbi/platform/andes/ae350/plicsw.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/roms/opensbi/platform/andes/ae350/plicsw.c b/roms/opensbi/platform/andes/ae350/plicsw.c
new file mode 100644
index 000000000..d07df28c8
--- /dev/null
+++ b/roms/opensbi/platform/andes/ae350/plicsw.c
@@ -0,0 +1,145 @@
+/*
+ * 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 u32 plicsw_get_pending(u32 source_hart, u32 target_hart)
+{
+ return readl(plicsw_dev[source_hart].plicsw_pending)
+ & (PLICSW_HART_MASK >> target_hart);
+}
+
+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 CLINT 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;
+}