#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.6 2026/04/26 13:34:26 thorpej Exp $");
#define _M68K_BUS_DMA_PRIVATE
#define _M68K_BUS_SPACE_PRIVATE
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <sys/intr.h>
#include <m68k/linux_bootinfo.h>
#include <machine/cpu.h>
#include <virt68k/dev/mainbusvar.h>
struct m68k_bus_dma_tag _mainbus_dma_tag = {
NULL,
0,
_bus_dmamap_create,
_bus_dmamap_destroy,
_bus_dmamap_load_direct,
_bus_dmamap_load_mbuf_direct,
_bus_dmamap_load_uio_direct,
_bus_dmamap_load_raw_direct,
_bus_dmamap_unload,
_bus_dmamap_sync,
_bus_dmamem_alloc,
_bus_dmamem_free,
_bus_dmamem_map,
_bus_dmamem_unmap,
_bus_dmamem_mmap
};
static int
mainbus_print(void *aux, const char *cp)
{
struct mainbus_attach_args *ma = aux;
if (cp) {
aprint_normal("%s at %s", ma->ma_compatible, cp);
}
aprint_normal(" addr 0x%lx", ma->ma_addr);
return UNCONF;
}
static int
mainbus_match(device_t parent __unused, cfdata_t cf __unused,
void *args __unused)
{
static int mainbus_matched;
if (mainbus_matched)
return 0;
return (mainbus_matched = 1);
}
static bool
mainbus_attach_gfpic(struct bi_record *bi, void *v)
{
struct mainbus_attach_args ma = {
.ma_st = &m68k_simple_bus_space,
.ma_dmat = &_mainbus_dma_tag,
};
device_t self = v;
struct bi_virt_dev *vd = bootinfo_dataptr(bi);
int i;
if (bi->bi_tag == BI_VIRT_GF_PIC_BASE) {
for (i = 0; i < NPIC; i++) {
ma.ma_compatible = "google,goldfish-pic";
ma.ma_addr = vd->vd_mmio_base + (i * 0x1000);
ma.ma_size = 0x1000;
ma.ma_irq = vd->vd_irq_base + i;
config_found(self, &ma, mainbus_print, CFARGS_NONE);
}
return false;
}
return true;
}
static bool
mainbus_attach_gfother(struct bi_record *bi, void *v)
{
struct mainbus_attach_args ma = {
.ma_st = &m68k_simple_bus_space,
.ma_dmat = &_mainbus_dma_tag,
};
device_t self = v;
struct bi_virt_dev *vd = bootinfo_dataptr(bi);
int i;
switch (bi->bi_tag) {
case BI_VIRT_GF_RTC_BASE:
for (i = 0; i < 2; i++) {
ma.ma_compatible = (i == 0)
? "netbsd,goldfish-rtc-hardclock"
: "google,goldfish-rtc";
ma.ma_addr = vd->vd_mmio_base + (i * 0x1000);
ma.ma_size = 0x1000;
ma.ma_irq = vd->vd_irq_base + i;
config_found(self, &ma, mainbus_print, CFARGS_NONE);
}
break;
case BI_VIRT_GF_TTY_BASE:
ma.ma_compatible = "google,goldfish-tty";
ma.ma_addr = vd->vd_mmio_base;
ma.ma_size = 0x1000;
ma.ma_irq = vd->vd_irq_base;
config_found(self, &ma, mainbus_print, CFARGS_NONE);
break;
}
return true;
}
#define VIRTIO_MMIO_DEVICE_ID 0x008
static void
mainbus_attach_virtio(device_t self, struct mainbus_attach_args *ma)
{
bus_space_handle_t bsh;
uint32_t val;
if (bus_space_map(ma->ma_st, ma->ma_addr, ma->ma_size, 0, &bsh) != 0) {
aprint_error_dev(self,
"unable to map virtio slot @ 0x%lx\n", ma->ma_addr);
return;
}
val = bus_space_read_4(ma->ma_st, bsh, VIRTIO_MMIO_DEVICE_ID);
bus_space_unmap(ma->ma_st, bsh, ma->ma_size);
if (val != 0) {
config_found(self, ma, mainbus_print, CFARGS_NONE);
}
}
static bool
mainbus_attach_other(struct bi_record *bi, void *v)
{
struct mainbus_attach_args ma = {
.ma_st = &m68k_simple_bus_space,
.ma_dmat = &_mainbus_dma_tag,
};
device_t self = v;
struct bi_virt_dev *vd = bootinfo_dataptr(bi);
int i;
switch (bi->bi_tag) {
case BI_VIRT_QEMU_VERSION:
case BI_VIRT_GF_PIC_BASE:
case BI_VIRT_GF_RTC_BASE:
case BI_VIRT_GF_TTY_BASE:
break;
case BI_VIRT_VIRTIO_BASE:
for (i = 0; i < (32 * 4); i++) {
ma.ma_compatible = "virtio,mmio";
ma.ma_addr = vd->vd_mmio_base + (i * 0x200);
ma.ma_size = 0x200;
ma.ma_irq = vd->vd_irq_base + i;
mainbus_attach_virtio(self, &ma);
}
break;
case BI_VIRT_CTRL_BASE:
ma.ma_compatible = "netbsd,qemu-virt-ctrl";
ma.ma_addr = vd->vd_mmio_base;
ma.ma_size = 0x1000;
ma.ma_irq = vd->vd_irq_base;
config_found(self, &ma, mainbus_print, CFARGS_NONE);
break;
default:
if (bi->bi_tag >= BI_MACHDEP(0)) {
aprint_error_dev(self,
"unknown bootinfo tag: 0x%08x\n", bi->bi_tag);
}
break;
}
return true;
}
static void
mainbus_attach(device_t parent __unused, device_t self, void *args __unused)
{
printf("\n");
bootinfo_enumerate(mainbus_attach_gfpic, self);
bootinfo_enumerate(mainbus_attach_gfother, self);
bootinfo_enumerate(mainbus_attach_other, self);
}
int
mainbus_compatible_match(const struct mainbus_attach_args * const ma,
const struct device_compatible_entry * driver_compats)
{
return device_compatible_match_strlist(ma->ma_compatible,
strlen(ma->ma_compatible) + 1, driver_compats);
}
const struct device_compatible_entry *
mainbus_compatible_lookup(const struct mainbus_attach_args * const ma,
const struct device_compatible_entry * driver_compats)
{
return device_compatible_lookup_strlist(ma->ma_compatible,
strlen(ma->ma_compatible) + 1, driver_compats);
}
CFATTACH_DECL_NEW(mainbus, 0,
mainbus_match, mainbus_attach, NULL, NULL);