From: Anup Patel <apatel@ventanamicro.com>
To: opensbi@lists.infradead.org
Subject: [PATCH 09/13] lib: utils/irqchip: Add FDT based driver for IMSIC
Date: Tue, 4 Jan 2022 15:43:19 +0530 [thread overview]
Message-ID: <20220104101323.127564-7-apatel@ventanamicro.com> (raw)
In-Reply-To: <20220104101323.127564-1-apatel@ventanamicro.com>
We add simple FDT irqchip driver for IMSIC so that generic platform
(and other FDT based platforms) can utilize common IMIC library.
Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
---
include/sbi_utils/fdt/fdt_helper.h | 6 ++
lib/utils/fdt/fdt_helper.c | 103 +++++++++++++++++++++++++
lib/utils/irqchip/fdt_irqchip.c | 2 +
lib/utils/irqchip/fdt_irqchip_imsic.c | 106 ++++++++++++++++++++++++++
lib/utils/irqchip/objects.mk | 1 +
platform/generic/platform.c | 12 +++
6 files changed, 230 insertions(+)
create mode 100644 lib/utils/irqchip/fdt_irqchip_imsic.c
diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 24fee7a..4c8d29e 100644
--- a/include/sbi_utils/fdt/fdt_helper.h
+++ b/include/sbi_utils/fdt/fdt_helper.h
@@ -68,6 +68,12 @@ int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
const char *compatible);
+struct imsic_data;
+
+bool fdt_check_imsic_mlevel(void *fdt);
+
+int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic);
+
struct plic_data;
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic);
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index 5bf4021..e2782b6 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -13,6 +13,7 @@
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/irqchip/plic.h>
#define DEFAULT_UART_FREQ 0
@@ -465,6 +466,108 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
}
+bool fdt_check_imsic_mlevel(void *fdt)
+{
+ const fdt32_t *val;
+ int i, len, noff = 0;
+
+ if (!fdt)
+ return false;
+
+ while ((noff = fdt_node_offset_by_compatible(fdt, noff,
+ "riscv,imsics")) >= 0) {
+ val = fdt_getprop(fdt, noff, "interrupts-extended", &len);
+ if (val && len > sizeof(fdt32_t)) {
+ len = len / sizeof(fdt32_t);
+ for (i = 0; i < len; i += 2) {
+ if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+int fdt_parse_imsic_node(void *fdt, int nodeoff, struct imsic_data *imsic)
+{
+ const fdt32_t *val;
+ struct imsic_regs *regs;
+ uint64_t reg_addr, reg_size;
+ int i, rc, len, nr_parent_irqs;
+
+ if (nodeoff < 0 || !imsic || !fdt)
+ return SBI_ENODEV;
+
+ imsic->targets_mmode = false;
+ val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
+ if (val && len > sizeof(fdt32_t)) {
+ len = len / sizeof(fdt32_t);
+ nr_parent_irqs = len / 2;
+ for (i = 0; i < len; i += 2) {
+ if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
+ imsic->targets_mmode = true;
+ break;
+ }
+ }
+ } else
+ return SBI_EINVAL;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,guest-index-bits", &len);
+ if (val && len > 0)
+ imsic->guest_index_bits = fdt32_to_cpu(*val);
+ else
+ imsic->guest_index_bits = 0;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,hart-index-bits", &len);
+ if (val && len > 0) {
+ imsic->hart_index_bits = fdt32_to_cpu(*val);
+ } else {
+ imsic->hart_index_bits = __fls(nr_parent_irqs);
+ if ((1UL << imsic->hart_index_bits) < nr_parent_irqs)
+ imsic->hart_index_bits++;
+ }
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,group-index-bits", &len);
+ if (val && len > 0)
+ imsic->group_index_bits = fdt32_to_cpu(*val);
+ else
+ imsic->group_index_bits = 0;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,group-index-shift", &len);
+ if (val && len > 0)
+ imsic->group_index_shift = fdt32_to_cpu(*val);
+ else
+ imsic->group_index_shift = 2 * IMSIC_MMIO_PAGE_SHIFT;
+
+ val = fdt_getprop(fdt, nodeoff, "riscv,num-ids", &len);
+ if (val && len > 0)
+ imsic->num_ids = fdt32_to_cpu(*val);
+ else
+ return SBI_EINVAL;
+
+ for (i = 0; i < IMSIC_MAX_REGS; i++) {
+ regs = &imsic->regs[i];
+ regs->addr = 0;
+ regs->size = 0;
+ }
+
+ for (i = 0; i < (IMSIC_MAX_REGS - 1); i++) {
+ regs = &imsic->regs[i];
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, i,
+ ®_addr, ®_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ break;
+ regs->addr = reg_addr;
+ regs->size = reg_size;
+ };
+ if (!imsic->regs[0].size)
+ return SBI_EINVAL;
+
+ return 0;
+}
+
int fdt_parse_plic_node(void *fdt, int nodeoffset, struct plic_data *plic)
{
int len, rc;
diff --git a/lib/utils/irqchip/fdt_irqchip.c b/lib/utils/irqchip/fdt_irqchip.c
index bf6969a..cf64a2e 100644
--- a/lib/utils/irqchip/fdt_irqchip.c
+++ b/lib/utils/irqchip/fdt_irqchip.c
@@ -12,9 +12,11 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
+extern struct fdt_irqchip fdt_irqchip_imsic;
extern struct fdt_irqchip fdt_irqchip_plic;
static struct fdt_irqchip *irqchip_drivers[] = {
+ &fdt_irqchip_imsic,
&fdt_irqchip_plic
};
diff --git a/lib/utils/irqchip/fdt_irqchip_imsic.c b/lib/utils/irqchip/fdt_irqchip_imsic.c
new file mode 100644
index 0000000..b6962be
--- /dev/null
+++ b/lib/utils/irqchip/fdt_irqchip_imsic.c
@@ -0,0 +1,106 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ * Copyright (c) 2022 Ventana Micro Systems Inc.
+ *
+ * Authors:
+ * Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hartmask.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/irqchip/fdt_irqchip.h>
+#include <sbi_utils/irqchip/imsic.h>
+
+#define IMSIC_MAX_NR 16
+
+static unsigned long imsic_count = 0;
+static struct imsic_data imsic[IMSIC_MAX_NR];
+
+static int irqchip_imsic_update_hartid_table(void *fdt, int nodeoff,
+ struct imsic_data *id)
+{
+ const fdt32_t *val;
+ u32 phandle, hwirq, hartid;
+ int i, err, count, cpu_offset, cpu_intc_offset;
+
+ val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
+ if (!val || count < sizeof(fdt32_t))
+ return SBI_EINVAL;
+ count = count / sizeof(fdt32_t);
+
+ for (i = 0; i < count; i += 2) {
+ phandle = fdt32_to_cpu(val[i]);
+ hwirq = fdt32_to_cpu(val[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;
+
+ err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+ if (err)
+ return SBI_EINVAL;
+ if (SBI_HARTMASK_MAX_BITS <= hartid)
+ return SBI_EINVAL;
+
+ switch (hwirq) {
+ case IRQ_M_EXT:
+ err = imsic_map_hartid_to_data(hartid, id, i / 2);
+ if (err)
+ return err;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int irqchip_imsic_cold_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct imsic_data *id;
+
+ if (IMSIC_MAX_NR <= imsic_count)
+ return SBI_ENOSPC;
+ id = &imsic[imsic_count];
+
+ rc = fdt_parse_imsic_node(fdt, nodeoff, id);
+ if (rc)
+ return rc;
+ if (!id->targets_mmode)
+ return 0;
+
+ rc = irqchip_imsic_update_hartid_table(fdt, nodeoff, id);
+ if (rc)
+ return rc;
+
+ rc = imsic_cold_irqchip_init(id);
+ if (rc)
+ return rc;
+
+ imsic_count++;
+
+ return 0;
+}
+
+static const struct fdt_match irqchip_imsic_match[] = {
+ { .compatible = "riscv,imsics" },
+ { },
+};
+
+struct fdt_irqchip fdt_irqchip_imsic = {
+ .match_table = irqchip_imsic_match,
+ .cold_init = irqchip_imsic_cold_init,
+ .warm_init = imsic_warm_irqchip_init,
+};
diff --git a/lib/utils/irqchip/objects.mk b/lib/utils/irqchip/objects.mk
index 76a3c94..ae6f255 100644
--- a/lib/utils/irqchip/objects.mk
+++ b/lib/utils/irqchip/objects.mk
@@ -8,6 +8,7 @@
#
libsbiutils-objs-y += irqchip/fdt_irqchip.o
+libsbiutils-objs-y += irqchip/fdt_irqchip_imsic.o
libsbiutils-objs-y += irqchip/fdt_irqchip_plic.o
libsbiutils-objs-y += irqchip/imsic.o
libsbiutils-objs-y += irqchip/plic.o
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index bc6e761..8a4fb70 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -18,6 +18,7 @@
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_pmu.h>
#include <sbi_utils/irqchip/fdt_irqchip.h>
+#include <sbi_utils/irqchip/imsic.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/ipi/fdt_ipi.h>
@@ -56,6 +57,7 @@ static void fw_platform_lookup_special(void *fdt, int root_offset)
}
extern struct sbi_platform platform;
+static bool platform_has_mlevel_imsic = false;
static u32 generic_hart_index2id[SBI_HARTMASK_MAX_BITS] = { 0 };
/*
@@ -110,6 +112,8 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
platform.hart_count = hart_count;
+ platform_has_mlevel_imsic = fdt_check_imsic_mlevel(fdt);
+
/* Return original FDT pointer */
return arg1;
@@ -118,6 +122,13 @@ fail:
wfi();
}
+static int generic_nascent_init(void)
+{
+ if (platform_has_mlevel_imsic)
+ imsic_local_irqchip_init();
+ return 0;
+}
+
static int generic_early_init(bool cold_boot)
{
if (!generic_plat || !generic_plat->early_init)
@@ -210,6 +221,7 @@ static uint64_t generic_pmu_xlate_to_mhpmevent(uint32_t event_idx,
}
const struct sbi_platform_operations platform_ops = {
+ .nascent_init = generic_nascent_init,
.early_init = generic_early_init,
.final_init = generic_final_init,
.early_exit = generic_early_exit,
--
2.25.1
next prev parent reply other threads:[~2022-01-04 10:13 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-04 10:13 [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Anup Patel
2022-01-04 10:13 ` [PATCH 04/13] lib: sbi: Add sbi_trap_set_external_irqfn() API Anup Patel
2022-01-04 10:13 ` [PATCH 05/13] lib: utils/irqchip: Allow multiple FDT irqchip drivers Anup Patel
2022-02-08 8:54 ` Atish Patra
2022-01-04 10:13 ` [PATCH 06/13] include: sbi: Introduce nascent_init() platform callback Anup Patel
2022-02-08 9:07 ` Atish Patra
2022-02-09 12:07 ` Anup Patel
2022-01-04 10:13 ` [PATCH 07/13] lib: sbi: Enable mie.MEIE bit for IPIs based on external interrupts Anup Patel
2022-02-08 9:03 ` Atish Patra
2022-02-09 12:30 ` Anup Patel
2022-01-04 10:13 ` [PATCH 08/13] lib: utils/irqchip: Add IMSIC library Anup Patel
2022-01-19 16:08 ` Xiang W
2022-01-19 16:12 ` Jessica Clarke
2022-01-19 16:14 ` Xiang W
2022-01-04 10:13 ` Anup Patel [this message]
2022-01-04 10:13 ` [PATCH 10/13] lib: utils: Disable appropriate IMSIC DT nodes in fdt_fixups() Anup Patel
2022-02-08 9:12 ` Atish Patra
2022-02-09 12:46 ` Anup Patel
2022-01-04 10:13 ` [PATCH 11/13] lib: utils/irqchip: Add APLIC initialization library Anup Patel
2022-01-04 10:13 ` [PATCH 12/13] lib: utils/irqchip: Add FDT based driver for APLIC Anup Patel
2022-01-04 10:13 ` [PATCH 13/13] lib: utils: Disable appropriate APLIC DT nodes in fdt_fixups() Anup Patel
2022-02-08 9:13 ` Atish Patra
2022-01-19 15:57 ` [PATCH 03/13] lib: sbi: Use AIA CSRs for local interrupts when available Xiang W
2022-02-09 11:40 ` Anup Patel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220104101323.127564-7-apatel@ventanamicro.com \
--to=apatel@ventanamicro.com \
--cc=opensbi@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.