diff --git a/sys/arch/riscv64/conf/GENERIC b/sys/arch/riscv64/conf/GENERIC index 9ab52540d9e..7b37947013a 100644 --- a/sys/arch/riscv64/conf/GENERIC +++ b/sys/arch/riscv64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.53 2025/06/28 04:21:15 kevlo Exp $ +# $OpenBSD: GENERIC,v 1.54 2025/12/02 19:57:29 kettenis Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -62,6 +62,9 @@ gpio* at mpfgpio? mpfiic* at fdt? iic* at mpfiic? +# Sophgo SoCs +sgmsi* at fdt? + # SiFive SoCs sfclock* at fdt? early 1 # PRCI sfcc* at fdt? early 1 # L2 Cache Controller diff --git a/sys/arch/riscv64/conf/RAMDISK b/sys/arch/riscv64/conf/RAMDISK index a8d17e05099..cd0d7be6f78 100644 --- a/sys/arch/riscv64/conf/RAMDISK +++ b/sys/arch/riscv64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.46 2025/06/28 12:43:17 kevlo Exp $ +# $OpenBSD: RAMDISK,v 1.47 2025/12/02 19:57:29 kettenis Exp $ machine riscv64 maxusers 4 @@ -55,6 +55,9 @@ gpio* at mpfgpio? mpfiic* at fdt? iic* at mpfiic? +# Sophgo SoCs +sgmsi* at fdt? + # SiFive SoCs sfclock* at fdt? early 1 # PRCI sfcc* at fdt? early 1 # L2 Cache Controller diff --git a/sys/arch/riscv64/conf/files.riscv64 b/sys/arch/riscv64/conf/files.riscv64 index 179fa5edd2b..251e5d8e544 100644 --- a/sys/arch/riscv64/conf/files.riscv64 +++ b/sys/arch/riscv64/conf/files.riscv64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.riscv64,v 1.30 2025/04/26 11:01:55 visa Exp $ +# $OpenBSD: files.riscv64,v 1.31 2025/12/02 19:57:29 kettenis Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -120,6 +120,11 @@ device sfuart attach sfuart at fdt file arch/riscv64/dev/sfuart.c sfuart +# Sophgo MSI controller +device sgmsi +attach sgmsi at fdt +file arch/riscv64/dev/sgmsi.c sgmsi + # StarFive clock controller device stfclock attach stfclock at fdt diff --git a/sys/arch/riscv64/dev/sgmsi.c b/sys/arch/riscv64/dev/sgmsi.c new file mode 100644 index 00000000000..1e44a867f4a --- /dev/null +++ b/sys/arch/riscv64/dev/sgmsi.c @@ -0,0 +1,192 @@ +/* $OpenBSD: sgmsi.c,v 1.1 2025/12/02 19:57:29 kettenis Exp $ */ +/* + * Copyright (c) 2025 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +struct sgmsi_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_clr_ioh; + + uint32_t sc_msi_mask; + bus_addr_t sc_msi_addr; + uint32_t sc_msi_range[4]; + struct interrupt_controller sc_msi_ic; +}; + +struct sgmsi_intrhand { + struct sgmsi_softc *ih_sc; + int (*ih_func)(void *); + void *ih_arg; + int ih_msi; + struct interrupt_controller *ih_ic; + void *ih_cookie; +}; + +int sgmsi_match(struct device *, void *, void *); +void sgmsi_attach(struct device *, struct device *, void *); + +const struct cfattach sgmsi_ca = { + sizeof (struct sgmsi_softc), sgmsi_match, sgmsi_attach +}; + +struct cfdriver sgmsi_cd = { + NULL, "sgmsi", DV_DULL +}; + +void *sgmsi_intr_establish_msi(void *, uint64_t *, uint64_t *, + int, struct cpu_info *, int (*)(void *), void *, char *); +void sgmsi_intr_disestablish_msi(void *); +void sgmsi_barrier(void *); + +int +sgmsi_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "sophgo,sg2042-msi"); +} + +void +sgmsi_attach(struct device *parent, struct device *self, void *aux) +{ + struct sgmsi_softc *sc = (struct sgmsi_softc *)self; + struct fdt_attach_args *faa = aux; + int idx; + + if (OF_getpropintarray(faa->fa_node, "msi-ranges", sc->sc_msi_range, + sizeof(sc->sc_msi_range)) != sizeof(sc->sc_msi_range)) { + printf(": invalid msi-ranges property\n"); + return; + } + sc->sc_msi_mask = (1UL << sc->sc_msi_range[3]) - 1; + + idx = OF_getindex(faa->fa_node, "doorbell", "reg-names"); + if (idx < 0 || idx >= faa->fa_nreg) { + printf(": no doorbell registers\n"); + return; + } + sc->sc_msi_addr = faa->fa_reg[idx].addr; + + sc->sc_iot = faa->fa_iot; + idx = OF_getindex(faa->fa_node, "clr", "reg-names"); + if (idx < 0 || idx >= faa->fa_nreg) { + printf(": no clr registers\n"); + return; + } + if (bus_space_map(sc->sc_iot, faa->fa_reg[idx].addr, + faa->fa_reg[idx].size, 0, &sc->sc_clr_ioh)) { + printf(": can't map registers\n"); + return; + } + printf("\n"); + + sc->sc_msi_ic.ic_node = faa->fa_node; + sc->sc_msi_ic.ic_cookie = sc; + sc->sc_msi_ic.ic_establish_msi = sgmsi_intr_establish_msi; + sc->sc_msi_ic.ic_disestablish = sgmsi_intr_disestablish_msi; + sc->sc_msi_ic.ic_barrier = sgmsi_barrier; + fdt_intr_register(&sc->sc_msi_ic); +} + +int +sgmsi_intr(void *arg) +{ + struct sgmsi_intrhand *ih = arg; + struct sgmsi_softc *sc = ih->ih_sc; + + /* ACK the interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_clr_ioh, 0, (1U << ih->ih_msi)); + + return ih->ih_func(ih->ih_arg); +} + +extern LIST_HEAD(, interrupt_controller) interrupt_controllers; + +void * +sgmsi_intr_establish_msi(void *cookie, uint64_t *addr, uint64_t *data, + int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name) +{ + struct sgmsi_softc *sc = cookie; + struct sgmsi_intrhand *ih; + struct interrupt_controller *ic; + uint32_t cells[2]; + int msi; + + msi = ffs(sc->sc_msi_mask) - 1; + if (msi == -1) + return NULL; + cells[0] = sc->sc_msi_range[1] + msi; + cells[1] = sc->sc_msi_range[2]; + + /* Lookup the parent interrupt controller. */ + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_phandle == sc->sc_msi_range[0]) + break; + } + if (ic == NULL) + return NULL; + + ih = malloc(sizeof(struct sgmsi_intrhand), M_DEVBUF, M_WAITOK); + ih->ih_sc = sc; + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_msi = msi; + ih->ih_ic = ic; + ih->ih_cookie = ic->ic_establish(ic->ic_cookie, cells, level, + ci, sgmsi_intr, ih, name); + if (ih->ih_cookie == NULL) { + free(ih, M_DEVBUF, sizeof(*ih)); + return NULL; + } + sc->sc_msi_mask &= ~(1U << ih->ih_msi); + + /* ACK the interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_clr_ioh, 0, (1U << ih->ih_msi)); + + *addr = sc->sc_msi_addr; + *data = (1U << ih->ih_msi); + return ih; +} + +void +sgmsi_intr_disestablish_msi(void *cookie) +{ + struct sgmsi_intrhand *ih = cookie; + + ih->ih_ic->ic_disestablish(ih->ih_cookie); + ih->ih_sc->sc_msi_mask |= (1U << ih->ih_msi); + free(ih, M_DEVBUF, sizeof(*ih)); +} + +void +sgmsi_barrier(void *cookie) +{ + struct sgmsi_intrhand *ih = cookie; + + ih->ih_ic->ic_barrier(ih->ih_cookie); +}