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
50 struct 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
67 struct 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
79 static int
mainbus_print(void * aux,const char * cp)80 mainbus_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
93 static int
mainbus_match(device_t parent __unused,cfdata_t cf __unused,void * args __unused)94 mainbus_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
105 static bool
mainbus_attach_gfpic(struct bi_record * bi,void * v)106 mainbus_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
129 static bool
mainbus_attach_gfother(struct bi_record * bi,void * v)130 mainbus_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
174 static void
mainbus_attach_virtio(device_t self,struct mainbus_attach_args * ma)175 mainbus_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
197 static bool
mainbus_attach_other(struct bi_record * bi,void * v)198 mainbus_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
244 static void
mainbus_attach(device_t parent __unused,device_t self,void * args __unused)245 mainbus_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
264 int
mainbus_compatible_match(const struct mainbus_attach_args * const ma,const struct device_compatible_entry * driver_compats)265 mainbus_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
275 const struct device_compatible_entry *
mainbus_compatible_lookup(const struct mainbus_attach_args * const ma,const struct device_compatible_entry * driver_compats)276 mainbus_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
286 CFATTACH_DECL_NEW(mainbus, 0,
287 mainbus_match, mainbus_attach, NULL, NULL);
288