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