Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: mainbus.c,v 1.6 2026/04/26 13:34:26 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2023 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.6 2026/04/26 13:34:26 thorpej Exp $");
     34 
     35 #define _M68K_BUS_DMA_PRIVATE
     36 #define _M68K_BUS_SPACE_PRIVATE
     37 
     38 #include <sys/param.h>
     39 #include <sys/kernel.h>
     40 #include <sys/systm.h>
     41 #include <sys/device.h>
     42 #include <sys/bus.h>
     43 #include <sys/intr.h>
     44 
     45 #include <m68k/linux_bootinfo.h>
     46 #include <machine/cpu.h>
     47 
     48 #include <virt68k/dev/mainbusvar.h>
     49 
     50 struct m68k_bus_dma_tag _mainbus_dma_tag = {
     51 	NULL,
     52 	0,
     53 	_bus_dmamap_create,
     54 	_bus_dmamap_destroy,
     55 	_bus_dmamap_load_direct,
     56 	_bus_dmamap_load_mbuf_direct,
     57 	_bus_dmamap_load_uio_direct,
     58 	_bus_dmamap_load_raw_direct,
     59 	_bus_dmamap_unload,
     60 	_bus_dmamap_sync,
     61 	_bus_dmamem_alloc,
     62 	_bus_dmamem_free,
     63 	_bus_dmamem_map,
     64 	_bus_dmamem_unmap,
     65 	_bus_dmamem_mmap
     66 };
     67 
     68 static int
     69 mainbus_print(void *aux, const char *cp)
     70 {
     71 	struct mainbus_attach_args *ma = aux;
     72 
     73 	if (cp) {
     74 		aprint_normal("%s at %s", ma->ma_compatible, cp);
     75 	}
     76 
     77 	aprint_normal(" addr 0x%lx", ma->ma_addr);
     78 
     79 	return UNCONF;
     80 }
     81 
     82 static int
     83 mainbus_match(device_t parent __unused, cfdata_t cf __unused,
     84     void *args __unused)
     85 {
     86 	static int mainbus_matched;
     87 
     88 	if (mainbus_matched)
     89 		return 0;
     90 
     91 	return (mainbus_matched = 1);
     92 }
     93 
     94 static bool
     95 mainbus_attach_gfpic(struct bi_record *bi, void *v)
     96 {
     97 	struct mainbus_attach_args ma = {
     98 		.ma_st = &m68k_simple_bus_space,
     99 		.ma_dmat = &_mainbus_dma_tag,
    100 	};
    101 	device_t self = v;
    102 	struct bi_virt_dev *vd = bootinfo_dataptr(bi);
    103 	int i;
    104 
    105 	if (bi->bi_tag == BI_VIRT_GF_PIC_BASE) {
    106 		for (i = 0; i < NPIC; i++) {
    107 			ma.ma_compatible = "google,goldfish-pic";
    108 			ma.ma_addr = vd->vd_mmio_base + (i * 0x1000);
    109 			ma.ma_size = 0x1000;
    110 			ma.ma_irq  = vd->vd_irq_base + i;
    111 			config_found(self, &ma, mainbus_print, CFARGS_NONE);
    112 		}
    113 		return false;	/* done searching */
    114 	}
    115 	return true;		/* keep searching */
    116 }
    117 
    118 static bool
    119 mainbus_attach_gfother(struct bi_record *bi, void *v)
    120 {
    121 	struct mainbus_attach_args ma = {
    122 		.ma_st = &m68k_simple_bus_space,
    123 		.ma_dmat = &_mainbus_dma_tag,
    124 	};
    125 	device_t self = v;
    126 	struct bi_virt_dev *vd = bootinfo_dataptr(bi);
    127 	int i;
    128 
    129 	switch (bi->bi_tag) {
    130 	case BI_VIRT_GF_RTC_BASE:
    131 		/*
    132 		 * There are 2 Goldfish RTC instances on the virt68k
    133 		 * platform:
    134 		 *
    135 		 * 1- This is used as the system timer / hard-clock.
    136 		 * 2- This is used as the TODR.
    137 		 */
    138 		for (i = 0; i < 2; i++) {
    139 			ma.ma_compatible = (i == 0)
    140 			    ? "netbsd,goldfish-rtc-hardclock"
    141 			    : "google,goldfish-rtc";
    142 			ma.ma_addr = vd->vd_mmio_base + (i * 0x1000);
    143 			ma.ma_size = 0x1000;
    144 			ma.ma_irq  = vd->vd_irq_base + i;
    145 			config_found(self, &ma, mainbus_print, CFARGS_NONE);
    146 		}
    147 		break;
    148 
    149 	case BI_VIRT_GF_TTY_BASE:
    150 		ma.ma_compatible = "google,goldfish-tty";
    151 		ma.ma_addr = vd->vd_mmio_base;
    152 		ma.ma_size = 0x1000;
    153 		ma.ma_irq  = vd->vd_irq_base;
    154 		config_found(self, &ma, mainbus_print, CFARGS_NONE);
    155 		break;
    156 	}
    157 
    158 	return true;		/* keep searching */
    159 }
    160 
    161 #define	VIRTIO_MMIO_DEVICE_ID	0x008
    162 
    163 static void
    164 mainbus_attach_virtio(device_t self, struct mainbus_attach_args *ma)
    165 {
    166 	bus_space_handle_t bsh;
    167 	uint32_t val;
    168 
    169 	/*
    170 	 * Probe the virtio slot to see if there's actually something
    171 	 * there before we claim that it is "found".
    172 	 */
    173 	if (bus_space_map(ma->ma_st, ma->ma_addr, ma->ma_size, 0, &bsh) != 0) {
    174 		aprint_error_dev(self,
    175 		    "unable to map virtio slot @ 0x%lx\n", ma->ma_addr);
    176 		return;
    177 	}
    178 	val = bus_space_read_4(ma->ma_st, bsh, VIRTIO_MMIO_DEVICE_ID);
    179 	bus_space_unmap(ma->ma_st, bsh, ma->ma_size);
    180 
    181 	if (val != 0) {
    182 		config_found(self, ma, mainbus_print, CFARGS_NONE);
    183 	}
    184 }
    185 
    186 static bool
    187 mainbus_attach_other(struct bi_record *bi, void *v)
    188 {
    189 	struct mainbus_attach_args ma = {
    190 		.ma_st = &m68k_simple_bus_space,
    191 		.ma_dmat = &_mainbus_dma_tag,
    192 	};
    193 	device_t self = v;
    194 	struct bi_virt_dev *vd = bootinfo_dataptr(bi);
    195 	int i;
    196 
    197 	switch (bi->bi_tag) {
    198 	case BI_VIRT_QEMU_VERSION:
    199 	case BI_VIRT_GF_PIC_BASE:
    200 	case BI_VIRT_GF_RTC_BASE:
    201 	case BI_VIRT_GF_TTY_BASE:
    202 		/* Handled elsewhere. */
    203 		break;
    204 
    205 	case BI_VIRT_VIRTIO_BASE:
    206 		for (i = 0; i < (32 * 4); i++) {
    207 			ma.ma_compatible = "virtio,mmio";
    208 			ma.ma_addr = vd->vd_mmio_base + (i * 0x200);
    209 			ma.ma_size = 0x200;
    210 			ma.ma_irq  = vd->vd_irq_base + i;
    211 			mainbus_attach_virtio(self, &ma);
    212 		}
    213 		break;
    214 
    215 	case BI_VIRT_CTRL_BASE:
    216 		ma.ma_compatible = "netbsd,qemu-virt-ctrl";	/* XXX */
    217 		ma.ma_addr = vd->vd_mmio_base;
    218 		ma.ma_size = 0x1000;
    219 		ma.ma_irq  = vd->vd_irq_base;
    220 		config_found(self, &ma, mainbus_print, CFARGS_NONE);
    221 		break;
    222 
    223 	default:
    224 		if (bi->bi_tag >= BI_MACHDEP(0)) {
    225 			aprint_error_dev(self,
    226 			    "unknown bootinfo tag: 0x%08x\n", bi->bi_tag);
    227 		}
    228 		break;
    229 	}
    230 	return true;		/* keep searching */
    231 }
    232 
    233 static void
    234 mainbus_attach(device_t parent __unused, device_t self, void *args __unused)
    235 {
    236 
    237 	printf("\n");
    238 
    239 	/* Attach the PICs first. */
    240 	bootinfo_enumerate(mainbus_attach_gfpic, self);
    241 
    242 	/* Attach the reset of the Goldfish devices next. */
    243 	bootinfo_enumerate(mainbus_attach_gfother, self);
    244 
    245 	/* Now the rest. */
    246 	bootinfo_enumerate(mainbus_attach_other, self);
    247 }
    248 
    249 int
    250 mainbus_compatible_match(const struct mainbus_attach_args * const ma,
    251    const struct device_compatible_entry * driver_compats)
    252 {
    253 	return device_compatible_match_strlist(ma->ma_compatible,
    254 	    strlen(ma->ma_compatible) + 1, driver_compats);
    255 }
    256 
    257 const struct device_compatible_entry *
    258 mainbus_compatible_lookup(const struct mainbus_attach_args * const ma,
    259     const struct device_compatible_entry * driver_compats)
    260 {
    261 	return device_compatible_lookup_strlist(ma->ma_compatible,
    262 	    strlen(ma->ma_compatible) + 1, driver_compats);
    263 }
    264 
    265 CFATTACH_DECL_NEW(mainbus, 0,
    266     mainbus_match, mainbus_attach, NULL, NULL);
    267