xref: /netbsd-src/sys/arch/acorn32/podulebus/amps.c (revision f95e34a191dbd39b53f354c1ad28185f4af346b3)
1 /*	$NetBSD: amps.c,v 1.24 2025/01/02 16:09:32 andvar Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Mark Brinicombe of Causality Limited.
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  * Card driver and probe and attach functions to use generic 16550 com
32  * driver for the Atomwide multiport serial podule
33  */
34 
35 /*
36  * Thanks to Martin Coulson, Atomwide, for providing the hardware
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: amps.c,v 1.24 2025/01/02 16:09:32 andvar Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/ioctl.h>
45 #include <sys/select.h>
46 #include <sys/tty.h>
47 #include <sys/proc.h>
48 #include <sys/conf.h>
49 #include <sys/file.h>
50 #include <sys/uio.h>
51 #include <sys/kernel.h>
52 #include <sys/syslog.h>
53 #include <sys/types.h>
54 #include <sys/device.h>
55 #include <sys/bus.h>
56 
57 #include <machine/intr.h>
58 #include <machine/io.h>
59 #include <acorn32/podulebus/podulebus.h>
60 #include <acorn32/podulebus/ampsreg.h>
61 #include <dev/ic/comreg.h>
62 #include <dev/ic/comvar.h>
63 #include <dev/podulebus/podules.h>
64 
65 #include "locators.h"
66 
67 /*
68  * Atomwide Multi-port serial podule device.
69  *
70  * This probes and attaches the top level multi-port serial device to the
71  * podulebus. It then configures the child com devices.
72  */
73 
74 /*
75  * Atomwide Multi-port serial card softc structure.
76  *
77  * Contains the device node, podule information and global information
78  * required by the driver such as the card version and the interrupt mask.
79  */
80 
81 struct amps_softc {
82 	device_t		sc_dev;			/* device node */
83 	podule_t 		*sc_podule;		/* Our podule info */
84 	int 			sc_podule_number;	/* Our podule number */
85 	bus_space_tag_t		sc_iot;			/* Bus tag */
86 };
87 
88 int	amps_probe(device_t, cfdata_t, void *);
89 void	amps_attach(device_t, device_t, void *);
90 
91 CFATTACH_DECL_NEW(amps, sizeof(struct amps_softc),
92     amps_probe, amps_attach, NULL, NULL);
93 
94 int	amps_print(void *, const char *);
95 void	amps_shutdown(void *);
96 
97 /*
98  * Attach arguments for child devices.
99  * Pass the podule details, the parent softc and the channel
100  */
101 
102 struct amps_attach_args {
103 	bus_space_tag_t aa_iot;			/* bus space tag */
104 	unsigned int aa_base;			/* base address for port */
105 	int aa_port;      			/* serial port number */
106 	podulebus_intr_handle_t aa_irq;		/* IRQ number */
107 };
108 
109 /*
110  * Define prototypes for custom bus space functions.
111  */
112 
113 /* Print function used during child config */
114 
115 int
116 amps_print(void *aux, const char *name)
117 {
118 	struct amps_attach_args *aa = aux;
119 
120 	if (!name)
121 		aprint_normal(", port %d", aa->aa_port);
122 
123 	return(QUIET);
124 }
125 
126 /*
127  * Card probe function
128  *
129  * Just match the manufacturer and podule ID's
130  */
131 
132 int
133 amps_probe(device_t parent, cfdata_t cf, void *aux)
134 {
135 	struct podule_attach_args *pa = aux;
136 
137 	return (pa->pa_product == PODULE_ATOMWIDE_SERIAL);
138 }
139 
140 /*
141  * Card attach function
142  *
143  * Identify the card version and configure any children.
144  * Install a shutdown handler to kill interrupts on shutdown
145  */
146 
147 void
148 amps_attach(device_t parent, device_t self, void *aux)
149 {
150 	struct amps_softc *sc = device_private(self);
151 	struct podule_attach_args *pa = aux;
152 	struct amps_attach_args aa;
153 
154 	/* Note the podule number and validate */
155 
156 	if (pa->pa_podule_number == -1)
157 		panic("Podule has disappeared !");
158 
159 	sc->sc_dev = self;
160 	sc->sc_podule_number = pa->pa_podule_number;
161 	sc->sc_podule = pa->pa_podule;
162 	podules[sc->sc_podule_number].attached = 1;
163 
164 	sc->sc_iot = pa->pa_iot;
165 
166 	/* Install a clean up handler to make sure IRQ's are disabled */
167 /*	if (shutdownhook_establish(amps_shutdown, (void *)sc) == NULL)
168 		panic("%s: Cannot install shutdown handler", device_xname(self));*/
169 
170 	/* Set the interrupt info for this podule */
171 
172 /*	sc->sc_podule->irq_addr = pa->pa_podule->slow_base +;*/	/* XXX */
173 /*	sc->sc_podule->irq_mask = ;*/
174 
175 	printf("\n");
176 
177 	/* Configure the children */
178 
179 	aa.aa_iot = sc->sc_iot;
180 	aa.aa_base = pa->pa_podule->slow_base + AMPS_BASE_OFFSET;
181 	aa.aa_base += MAX_AMPS_PORTS * AMPS_PORT_SPACING;
182 	aa.aa_irq = pa->pa_podule->interrupt;
183 	for (aa.aa_port = 0; aa.aa_port < MAX_AMPS_PORTS; ++aa.aa_port) {
184 		aa.aa_base -= AMPS_PORT_SPACING;
185 		config_found(self, &aa, amps_print, CFARGS_NONE);
186 	}
187 }
188 
189 /*
190  * Card shutdown function
191  *
192  * Called via do_shutdown_hooks() during kernel shutdown.
193  * Clear the cards's interrupt mask to stop any podule interrupts.
194  */
195 
196 /*void
197 amps_shutdown(void *arg)
198 {
199 }*/
200 
201 /*
202  * Atomwide Multi-Port Serial probe and attach code for the com device.
203  *
204  * This provides a different pair of probe and attach functions
205  * for attaching the com device (dev/ic/com.c) to the Atomwide serial card.
206  */
207 
208 struct com_amps_softc {
209 	struct	com_softc sc_com;	/* real "com" softc */
210 	void	*sc_ih;			/* interrupt handler */
211 	struct	evcnt sc_intrcnt;	/* interrupt count */
212 };
213 
214 /* Prototypes for functions */
215 
216 static int  com_amps_probe   (device_t, cfdata_t , void *);
217 static void com_amps_attach  (device_t, device_t, void *);
218 
219 /* device attach structure */
220 
221 CFATTACH_DECL_NEW(com_amps, sizeof(struct com_amps_softc),
222 	com_amps_probe, com_amps_attach, NULL, NULL);
223 
224 /*
225  * Controller probe function
226  *
227  * Map all the required I/O space for this channel, make sure interrupts
228  * are disabled and probe the bus.
229  */
230 
231 int
232 com_amps_probe(device_t parent, cfdata_t cf, void *aux)
233 {
234 	bus_space_tag_t iot;
235 	bus_space_handle_t ioh;
236 	int iobase;
237 	int rv = 1;
238 	struct amps_attach_args *aa = aux;
239 
240 	iot = aa->aa_iot;
241 	iobase = aa->aa_base;
242 
243 	/* if it's in use as console, it's there. */
244 	if (!com_is_console(iot, iobase, 0)) {
245 		if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) {
246 			return 0;
247 		}
248 		/*
249 		 * We don't use the generic comprobe1() function as it
250 		 * is not good enough to identify which ports are present.
251 		 *
252 		 * Instead test for the presence of the scratch register
253 		 */
254 
255 		bus_space_write_1(iot, ioh, com_scratch, 0x55);
256 		bus_space_write_1(iot, ioh, com_ier, 0);
257 		(void)bus_space_read_1(iot, ioh, com_data);
258 		if (bus_space_read_1(iot, ioh, com_scratch) != 0x55)
259 			rv = 0;
260 		bus_space_write_1(iot, ioh, com_scratch, 0xaa);
261 		bus_space_write_1(iot, ioh, com_ier, 0);
262 		(void)bus_space_read_1(iot, ioh, com_data);
263 		if (bus_space_read_1(iot, ioh, com_scratch) != 0xaa)
264 			rv = 0;
265 
266 		bus_space_unmap(iot, ioh, COM_NPORTS);
267 	}
268 	return (rv);
269 }
270 
271 /*
272  * Controller attach function
273  *
274  * Map all the required I/O space for this port and attach the driver
275  * The generic attach will probe and attach any device.
276  * Install an interrupt handler and we are ready to rock.
277  */
278 
279 void
280 com_amps_attach(device_t parent, device_t self, void *aux)
281 {
282 	struct com_amps_softc *asc = device_private(self);
283 	struct com_softc *sc = &asc->sc_com;
284 	u_int iobase;
285 	bus_space_tag_t iot;
286 	bus_space_handle_t ioh;
287 	struct amps_attach_args *aa = aux;
288 
289 	sc->sc_dev = self;
290 	iot = aa->aa_iot;
291 	iobase = aa->aa_base;
292 
293 	if (!com_is_console(iot, iobase, &ioh)
294 	    && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh))
295 		panic("comattach: io mapping failed");
296 	com_init_regs(&sc->sc_regs, iot, ioh, iobase);
297 
298 	sc->sc_frequency = AMPS_FREQ;
299 	com_attach_subr(sc);
300 
301 	evcnt_attach_dynamic(&asc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
302 	    device_xname(self), "intr");
303 	asc->sc_ih = podulebus_irq_establish(aa->aa_irq, IPL_SERIAL, comintr,
304 	    sc, &asc->sc_intrcnt);
305 }
306