diff options
Diffstat (limited to 'lib/utils')
| -rw-r--r-- | lib/utils/fdt/fdt_helper.c | 54 | ||||
| -rw-r--r-- | lib/utils/ipi/Kconfig | 9 | ||||
| -rw-r--r-- | lib/utils/ipi/andes_plicsw.c | 137 | ||||
| -rw-r--r-- | lib/utils/ipi/fdt_ipi_plicsw.c | 47 | ||||
| -rw-r--r-- | lib/utils/ipi/objects.mk | 4 |
5 files changed, 251 insertions, 0 deletions
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c index ce52fca8..d390436c 100644 --- a/lib/utils/fdt/fdt_helper.c +++ b/lib/utils/fdt/fdt_helper.c @@ -889,6 +889,60 @@ int fdt_parse_plmt_node(void *fdt, int nodeoffset, unsigned long *plmt_base, return 0; } +int fdt_parse_plicsw_node(void *fdt, int nodeoffset, unsigned long *plicsw_base, + unsigned long *size, u32 *hart_count) +{ + const fdt32_t *val; + int rc, i, count; + uint64_t reg_addr, reg_size, cpu_offset, cpu_intc_offset; + u32 phandle, hwirq, hartid, hcount; + + if (nodeoffset < 0 || !fdt || !plicsw_base || + !hart_count || !size) + return SBI_EINVAL; + + rc = fdt_get_node_addr_size(fdt, nodeoffset, 0, + ®_addr, ®_size); + if (rc < 0 || !plicsw_base || !size) + return SBI_ENODEV; + *plicsw_base = reg_addr; + *size = reg_size; + + val = fdt_getprop(fdt, nodeoffset, "interrupts-extended", &count); + if (!val || count < sizeof(fdt32_t)) + return 0; + count = count / sizeof(fdt32_t); + + hcount = 0; + for (i = 0; i < (count / 2); i++) { + phandle = fdt32_to_cpu(val[2 * i]); + hwirq = fdt32_to_cpu(val[2 * i + 1]); + + cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle); + if (cpu_intc_offset < 0) + continue; + + cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset); + if (cpu_intc_offset < 0) + continue; + + rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid); + + if (rc) + continue; + + if (SBI_HARTMASK_MAX_BITS <= hartid) + continue; + + if (hwirq == IRQ_M_SOFT) + hcount++; + } + + *hart_count = hcount; + + return 0; +} + int fdt_parse_compat_addr(void *fdt, uint64_t *addr, const char *compatible) { diff --git a/lib/utils/ipi/Kconfig b/lib/utils/ipi/Kconfig index efc89601..37188527 100644 --- a/lib/utils/ipi/Kconfig +++ b/lib/utils/ipi/Kconfig @@ -14,10 +14,19 @@ config FDT_IPI_MSWI select IPI_MSWI default n +config FDT_IPI_PLICSW + bool "Andes PLICSW FDT driver" + select IPI_PLICSW + default n + endif config IPI_MSWI bool "ACLINT MSWI support" default n +config IPI_PLICSW + bool "Andes PLICSW support" + default n + endmenu diff --git a/lib/utils/ipi/andes_plicsw.c b/lib/utils/ipi/andes_plicsw.c new file mode 100644 index 00000000..db25ae23 --- /dev/null +++ b/lib/utils/ipi/andes_plicsw.c @@ -0,0 +1,137 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Andes Technology Corporation + * + * Authors: + * Zong Li <[email protected]> + * Nylon Chen <[email protected]> + * Leo Yu-Chi Liang <[email protected]> + * Yu Chien Peter Lin <[email protected]> + */ + +#include <sbi/riscv_asm.h> +#include <sbi/riscv_io.h> +#include <sbi/sbi_domain.h> +#include <sbi/sbi_ipi.h> +#include <sbi_utils/ipi/andes_plicsw.h> + +struct plicsw_data plicsw; + +static inline void plicsw_claim(void) +{ + u32 hartid = current_hartid(); + + if (plicsw.hart_count <= hartid) + ebreak(); + + plicsw.source_id[hartid] = + readl((void *)plicsw.addr + PLICSW_CONTEXT_BASE + + PLICSW_CONTEXT_CLAIM + PLICSW_CONTEXT_STRIDE * hartid); +} + +static inline void plicsw_complete(void) +{ + u32 hartid = current_hartid(); + u32 source = plicsw.source_id[hartid]; + + writel(source, (void *)plicsw.addr + PLICSW_CONTEXT_BASE + + PLICSW_CONTEXT_CLAIM + + PLICSW_CONTEXT_STRIDE * hartid); +} + +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 + * --------------------------------- + * | hart3 | hart2 | hart1 | hart0 | + * --------------------------------- + * Each hartX can send IPI to another hart by setting the + * bitY to its own region (see the below). + * + * In each hartX region: + * <---------- PICSW_PENDING_STRIDE --------> + * | bit7 | ... | bit3 | bit2 | bit1 | bit0 | + * ------------------------------------------ + * The bitY of hartX region indicates that hartX sends an + * IPI to hartY. + */ + u32 hartid = current_hartid(); + u32 word_index = hartid / 4; + u32 per_hart_offset = PLICSW_PENDING_STRIDE * hartid; + u32 val = 1 << target_hart << per_hart_offset; + + writel(val, (void *)plicsw.addr + PLICSW_PENDING_BASE + word_index * 4); +} + +static void plicsw_ipi_send(u32 target_hart) +{ + if (plicsw.hart_count <= target_hart) + ebreak(); + + /* Set PLICSW IPI */ + plic_sw_pending(target_hart); +} + +static void plicsw_ipi_clear(u32 target_hart) +{ + if (plicsw.hart_count <= target_hart) + ebreak(); + + /* Clear PLICSW IPI */ + plicsw_claim(); + plicsw_complete(); +} + +static struct sbi_ipi_device plicsw_ipi = { + .name = "andes_plicsw", + .ipi_send = plicsw_ipi_send, + .ipi_clear = plicsw_ipi_clear +}; + +int plicsw_warm_ipi_init(void) +{ + u32 hartid = current_hartid(); + + /* Clear PLICSW IPI */ + plicsw_ipi_clear(hartid); + + return 0; +} + +int plicsw_cold_ipi_init(struct plicsw_data *plicsw) +{ + int rc; + + /* Setup source priority */ + uint32_t *priority = (void *)plicsw->addr + PLICSW_PRIORITY_BASE; + + for (int i = 0; i < plicsw->hart_count; i++) + writel(1, &priority[i]); + + /* Setup target enable */ + uint32_t enable_mask = PLICSW_HART_MASK; + + for (int i = 0; i < plicsw->hart_count; i++) { + uint32_t *enable = (void *)plicsw->addr + PLICSW_ENABLE_BASE + + PLICSW_ENABLE_STRIDE * i; + writel(enable_mask, enable); + writel(enable_mask, enable + 1); + enable_mask <<= 1; + } + + /* Add PLICSW region to the root domain */ + rc = sbi_domain_root_add_memrange(plicsw->addr, plicsw->size, + PLICSW_REGION_ALIGN, + SBI_DOMAIN_MEMREGION_MMIO); + if (rc) + return rc; + + sbi_ipi_set_device(&plicsw_ipi); + + return 0; +} diff --git a/lib/utils/ipi/fdt_ipi_plicsw.c b/lib/utils/ipi/fdt_ipi_plicsw.c new file mode 100644 index 00000000..bf29bfc1 --- /dev/null +++ b/lib/utils/ipi/fdt_ipi_plicsw.c @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Andes Technology Corporation + * + * Authors: + * Zong Li <[email protected]> + * Nylon Chen <[email protected]> + * Leo Yu-Chi Liang <[email protected]> + * Yu Chien Peter Lin <[email protected]> + */ + +#include <sbi/riscv_io.h> +#include <sbi_utils/fdt/fdt_helper.h> +#include <sbi_utils/ipi/fdt_ipi.h> +#include <sbi_utils/ipi/andes_plicsw.h> + +extern struct plicsw_data plicsw; + +int fdt_plicsw_cold_ipi_init(void *fdt, int nodeoff, + const struct fdt_match *match) +{ + int rc; + + rc = fdt_parse_plicsw_node(fdt, nodeoff, &plicsw.addr, &plicsw.size, + &plicsw.hart_count); + if (rc) + return rc; + + rc = plicsw_cold_ipi_init(&plicsw); + if (rc) + return rc; + + return 0; +} + +static const struct fdt_match ipi_plicsw_match[] = { + { .compatible = "andestech,plicsw" }, + {}, +}; + +struct fdt_ipi fdt_ipi_plicsw = { + .match_table = ipi_plicsw_match, + .cold_init = fdt_plicsw_cold_ipi_init, + .warm_init = plicsw_warm_ipi_init, + .exit = NULL, +}; diff --git a/lib/utils/ipi/objects.mk b/lib/utils/ipi/objects.mk index 0600cac4..999e7bd9 100644 --- a/lib/utils/ipi/objects.mk +++ b/lib/utils/ipi/objects.mk @@ -8,9 +8,13 @@ # libsbiutils-objs-$(CONFIG_IPI_MSWI) += ipi/aclint_mswi.o +libsbiutils-objs-$(CONFIG_IPI_PLICSW) += ipi/andes_plicsw.o libsbiutils-objs-$(CONFIG_FDT_IPI) += ipi/fdt_ipi.o libsbiutils-objs-$(CONFIG_FDT_IPI) += ipi/fdt_ipi_drivers.o carray-fdt_ipi_drivers-$(CONFIG_FDT_IPI_MSWI) += fdt_ipi_mswi libsbiutils-objs-$(CONFIG_FDT_IPI_MSWI) += ipi/fdt_ipi_mswi.o + +carray-fdt_ipi_drivers-$(CONFIG_FDT_IPI_PLICSW) += fdt_ipi_plicsw +libsbiutils-objs-$(CONFIG_FDT_IPI_PLICSW) += ipi/fdt_ipi_plicsw.o |
