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