123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- /*
- * 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;
- }
|