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