1
0
mirror of https://github.com/openbsd/src.git synced 2025-12-05 23:44:37 +00:00

Add sgmsi(4), a driver for the MSI controller implementation on Sophgo

SG2042 SoCs.

ok jca@
This commit is contained in:
kettenis
2025-12-02 19:57:29 +00:00
parent 34ab2854f6
commit 93358888f7
4 changed files with 206 additions and 3 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,192 @@
/* $OpenBSD: sgmsi.c,v 1.1 2025/12/02 19:57:29 kettenis Exp $ */
/*
* Copyright (c) 2025 Mark Kettenis <kettenis@openbsd.org>
*
* 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/intr.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/fdt.h>
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);
}