1/* $NetBSD: mainbus.c,v 1.1 2024/01/02 07:40:59 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.1 2024/01/02 07:40:59 thorpej Exp $"); 34 35#define _VIRT68K_BUS_DMA_PRIVATE 36#define _VIRT68K_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 <machine/bootinfo.h> 46#include <machine/cpu.h> 47 48#include <virt68k/dev/mainbusvar.h> 49 50struct virt68k_bus_dma_tag _mainbus_dma_tag = { 51 NULL, 52 _bus_dmamap_create, 53 _bus_dmamap_destroy, 54 _bus_dmamap_load_direct, 55 _bus_dmamap_load_mbuf_direct, 56 _bus_dmamap_load_uio_direct, 57 _bus_dmamap_load_raw_direct, 58 _bus_dmamap_unload, 59 NULL, /* Set up at run-time */ 60 _bus_dmamem_alloc, 61 _bus_dmamem_free, 62 _bus_dmamem_map, 63 _bus_dmamem_unmap, 64 _bus_dmamem_mmap 65}; 66 67struct virt68k_bus_space_tag _mainbus_space_tag = { 68 NULL, 69 _bus_space_map, 70 _bus_space_unmap, 71 _bus_space_peek_1, 72 _bus_space_peek_2, 73 _bus_space_peek_4, 74 _bus_space_poke_1, 75 _bus_space_poke_2, 76 _bus_space_poke_4 77}; 78 79static int 80mainbus_print(void *aux, const char *cp) 81{ 82 struct mainbus_attach_args *ma = aux; 83 84 if (cp) { 85 aprint_normal("%s at %s", ma->ma_compatible, cp); 86 } 87 88 aprint_normal(" addr 0x%lx", ma->ma_addr); 89 90 return UNCONF; 91} 92 93static int 94mainbus_match(device_t parent __unused, cfdata_t cf __unused, 95 void *args __unused) 96{ 97 static int mainbus_matched; 98 99 if (mainbus_matched) 100 return 0; 101 102 return (mainbus_matched = 1); 103} 104 105static bool 106mainbus_attach_gfpic(struct bi_record *bi, void *v) 107{ 108 struct mainbus_attach_args ma = { 109 .ma_st = &_mainbus_space_tag, 110 .ma_dmat = &_mainbus_dma_tag, 111 }; 112 device_t self = v; 113 struct bi_virt_dev *vd = bootinfo_dataptr(bi); 114 int i; 115 116 if (bi->bi_tag == BI_VIRT_GF_PIC_BASE) { 117 for (i = 0; i < NPIC; i++) { 118 ma.ma_compatible = "google,goldfish-pic"; 119 ma.ma_addr = vd->vd_mmio_base + (i * 0x1000); 120 ma.ma_size = 0x1000; 121 ma.ma_irq = vd->vd_irq_base + i; 122 config_found(self, &ma, mainbus_print, CFARGS_NONE); 123 } 124 return false; /* done searching */ 125 } 126 return true; /* keep searching */ 127} 128 129static bool 130mainbus_attach_gfother(struct bi_record *bi, void *v) 131{ 132 struct mainbus_attach_args ma = { 133 .ma_st = &_mainbus_space_tag, 134 .ma_dmat = &_mainbus_dma_tag, 135 }; 136 device_t self = v; 137 struct bi_virt_dev *vd = bootinfo_dataptr(bi); 138 int i; 139 140 switch (bi->bi_tag) { 141 case BI_VIRT_GF_RTC_BASE: 142 /* 143 * There are 2 Goldfish RTC instances on the virt68k 144 * platform: 145 * 146 * 1- This is used as the system timer / hard-clock. 147 * 2- This is used as the TODR. 148 */ 149 for (i = 0; i < 2; i++) { 150 ma.ma_compatible = (i == 0) 151 ? "netbsd,goldfish-rtc-hardclock" 152 : "google,goldfish-rtc"; 153 ma.ma_addr = vd->vd_mmio_base + (i * 0x1000); 154 ma.ma_size = 0x1000; 155 ma.ma_irq = vd->vd_irq_base + i; 156 config_found(self, &ma, mainbus_print, CFARGS_NONE); 157 } 158 break; 159 160 case BI_VIRT_GF_TTY_BASE: 161 ma.ma_compatible = "google,goldfish-tty"; 162 ma.ma_addr = vd->vd_mmio_base; 163 ma.ma_size = 0x1000; 164 ma.ma_irq = vd->vd_irq_base; 165 config_found(self, &ma, mainbus_print, CFARGS_NONE); 166 break; 167 } 168 169 return true; /* keep searching */ 170} 171 172#define VIRTIO_MMIO_DEVICE_ID 0x008 173 174static void 175mainbus_attach_virtio(device_t self, struct mainbus_attach_args *ma) 176{ 177 bus_space_handle_t bsh; 178 uint32_t val; 179 180 /* 181 * Probe the virtio slot to see if there's actually something 182 * there before we claim that it is "found". 183 */ 184 if (bus_space_map(ma->ma_st, ma->ma_addr, ma->ma_size, 0, &bsh) != 0) { 185 aprint_error_dev(self, 186 "unable to map virtio slot @ 0x%lx\n", ma->ma_addr); 187 return; 188 } 189 val = bus_space_read_4(ma->ma_st, bsh, VIRTIO_MMIO_DEVICE_ID); 190 bus_space_unmap(ma->ma_st, bsh, ma->ma_size); 191 192 if (val != 0) { 193 config_found(self, ma, mainbus_print, CFARGS_NONE); 194 } 195} 196 197static bool 198mainbus_attach_other(struct bi_record *bi, void *v) 199{ 200 struct mainbus_attach_args ma = { 201 .ma_st = &_mainbus_space_tag, 202 .ma_dmat = &_mainbus_dma_tag, 203 }; 204 device_t self = v; 205 struct bi_virt_dev *vd = bootinfo_dataptr(bi); 206 int i; 207 208 switch (bi->bi_tag) { 209 case BI_VIRT_QEMU_VERSION: 210 case BI_VIRT_GF_PIC_BASE: 211 case BI_VIRT_GF_RTC_BASE: 212 case BI_VIRT_GF_TTY_BASE: 213 /* Handled elsewhere. */ 214 break; 215 216 case BI_VIRT_VIRTIO_BASE: 217 for (i = 0; i < (32 * 4); i++) { 218 ma.ma_compatible = "virtio,mmio"; 219 ma.ma_addr = vd->vd_mmio_base + (i * 0x200); 220 ma.ma_size = 0x200; 221 ma.ma_irq = vd->vd_irq_base + i; 222 mainbus_attach_virtio(self, &ma); 223 } 224 break; 225 226 case BI_VIRT_CTRL_BASE: 227 ma.ma_compatible = "netbsd,qemu-virt-ctrl"; /* XXX */ 228 ma.ma_addr = vd->vd_mmio_base; 229 ma.ma_size = 0x1000; 230 ma.ma_irq = vd->vd_irq_base; 231 config_found(self, &ma, mainbus_print, CFARGS_NONE); 232 break; 233 234 default: 235 if (bi->bi_tag >= BI_MACHDEP(0)) { 236 aprint_error_dev(self, 237 "unknown bootinfo tag: 0x%08x\n", bi->bi_tag); 238 } 239 break; 240 } 241 return true; /* keep searching */ 242} 243 244static void 245mainbus_attach(device_t parent __unused, device_t self, void *args __unused) 246{ 247 248 printf("\n"); 249 250 _mainbus_dma_tag._dmamap_sync = 251 (mmutype == MMU_68040) ? _bus_dmamap_sync_0460 252 : _bus_dmamap_sync_030; 253 254 /* Attach the PICs first. */ 255 bootinfo_enumerate(mainbus_attach_gfpic, self); 256 257 /* Attach the reset of the Goldfish devices next. */ 258 bootinfo_enumerate(mainbus_attach_gfother, self); 259 260 /* Now the rest. */ 261 bootinfo_enumerate(mainbus_attach_other, self); 262} 263 264int 265mainbus_compatible_match(const struct mainbus_attach_args * const ma, 266 const struct device_compatible_entry * driver_compats) 267{ 268 const char *device_compats[1] = { 269 [0] = ma->ma_compatible, 270 }; 271 return device_compatible_match(device_compats, 272 __arraycount(device_compats), driver_compats); 273} 274 275const struct device_compatible_entry * 276mainbus_compatible_lookup(const struct mainbus_attach_args * const ma, 277 const struct device_compatible_entry * driver_compats) 278{ 279 const char *device_compats[1] = { 280 [0] = ma->ma_compatible, 281 }; 282 return device_compatible_lookup(device_compats, 283 __arraycount(device_compats), driver_compats); 284} 285 286CFATTACH_DECL_NEW(mainbus, 0, 287 mainbus_match, mainbus_attach, NULL, NULL); 288