amps.c revision 1.10
11.10Sdrochner/*	$NetBSD: amps.c,v 1.10 2004/09/13 15:14:12 drochner Exp $	*/
21.1Sreinoud
31.1Sreinoud/*-
41.1Sreinoud * Copyright (c) 1997 The NetBSD Foundation, Inc.
51.1Sreinoud * All rights reserved.
61.1Sreinoud *
71.1Sreinoud * This code is derived from software contributed to The NetBSD Foundation
81.1Sreinoud * by Mark Brinicombe of Causality Limited.
91.1Sreinoud *
101.1Sreinoud * Redistribution and use in source and binary forms, with or without
111.1Sreinoud * modification, are permitted provided that the following conditions
121.1Sreinoud * are met:
131.1Sreinoud * 1. Redistributions of source code must retain the above copyright
141.1Sreinoud *    notice, this list of conditions and the following disclaimer.
151.1Sreinoud * 2. Redistributions in binary form must reproduce the above copyright
161.1Sreinoud *    notice, this list of conditions and the following disclaimer in the
171.1Sreinoud *    documentation and/or other materials provided with the distribution.
181.1Sreinoud * 3. All advertising materials mentioning features or use of this software
191.1Sreinoud *    must display the following acknowledgement:
201.1Sreinoud *	This product includes software developed by the NetBSD
211.1Sreinoud *	Foundation, Inc. and its contributors.
221.1Sreinoud * 4. Neither the name of The NetBSD Foundation nor the names of its
231.1Sreinoud *    contributors may be used to endorse or promote products derived
241.1Sreinoud *    from this software without specific prior written permission.
251.1Sreinoud *
261.1Sreinoud * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
271.1Sreinoud * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
281.1Sreinoud * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
291.1Sreinoud * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
301.1Sreinoud * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
311.1Sreinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
321.1Sreinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
331.1Sreinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
341.1Sreinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
351.1Sreinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
361.1Sreinoud * POSSIBILITY OF SUCH DAMAGE.
371.1Sreinoud *
381.1Sreinoud * Card driver and probe and attach functions to use generic 16550 com
391.1Sreinoud * driver for the Atomwide multiport serial podule
401.1Sreinoud */
411.1Sreinoud
421.1Sreinoud/*
431.1Sreinoud * Thanks to Martin Coulson, Atomwide, for providing the hardware
441.1Sreinoud */
451.9Slukem
461.9Slukem#include <sys/cdefs.h>
471.10Sdrochner__KERNEL_RCSID(0, "$NetBSD: amps.c,v 1.10 2004/09/13 15:14:12 drochner Exp $");
481.1Sreinoud
491.1Sreinoud#include <sys/param.h>
501.1Sreinoud#include <sys/systm.h>
511.1Sreinoud#include <sys/ioctl.h>
521.1Sreinoud#include <sys/select.h>
531.1Sreinoud#include <sys/tty.h>
541.1Sreinoud#include <sys/proc.h>
551.1Sreinoud#include <sys/user.h>
561.1Sreinoud#include <sys/conf.h>
571.1Sreinoud#include <sys/file.h>
581.1Sreinoud#include <sys/uio.h>
591.1Sreinoud#include <sys/kernel.h>
601.1Sreinoud#include <sys/syslog.h>
611.1Sreinoud#include <sys/types.h>
621.1Sreinoud#include <sys/device.h>
631.1Sreinoud
641.2Sthorpej#include <machine/intr.h>
651.1Sreinoud#include <machine/io.h>
661.1Sreinoud#include <machine/bus.h>
671.1Sreinoud#include <acorn32/podulebus/podulebus.h>
681.1Sreinoud#include <acorn32/podulebus/ampsreg.h>
691.1Sreinoud#include <dev/ic/comreg.h>
701.1Sreinoud#include <dev/ic/comvar.h>
711.1Sreinoud#include <dev/podulebus/podules.h>
721.1Sreinoud
731.1Sreinoud#include "locators.h"
741.1Sreinoud
751.1Sreinoud/*
761.1Sreinoud * Atomwide Mulit-port serial podule device.
771.1Sreinoud *
781.1Sreinoud * This probes and attaches the top level multi-port serial device to the
791.1Sreinoud * podulebus. It then configures the child com devices.
801.1Sreinoud */
811.1Sreinoud
821.1Sreinoud/*
831.1Sreinoud * Atomwide Multi-port serial card softc structure.
841.1Sreinoud *
851.1Sreinoud * Contains the device node, podule information and global information
861.1Sreinoud * required by the driver such as the card version and the interrupt mask.
871.1Sreinoud */
881.1Sreinoud
891.1Sreinoudstruct amps_softc {
901.1Sreinoud	struct device		sc_dev;			/* device node */
911.1Sreinoud	podule_t 		*sc_podule;		/* Our podule info */
921.1Sreinoud	int 			sc_podule_number;	/* Our podule number */
931.1Sreinoud	bus_space_tag_t		sc_iot;			/* Bus tag */
941.1Sreinoud};
951.1Sreinoud
961.7Schsint	amps_probe(struct device *, struct cfdata *, void *);
971.7Schsvoid	amps_attach(struct device *, struct device *, void *);
981.1Sreinoud
991.5SthorpejCFATTACH_DECL(amps, sizeof(struct amps_softc),
1001.6Sthorpej    amps_probe, amps_attach, NULL, NULL);
1011.7Schs
1021.7Schsint	amps_print(void *, const char *);
1031.7Schsvoid	amps_shutdown(void *);
1041.1Sreinoud
1051.1Sreinoud/*
1061.1Sreinoud * Attach arguments for child devices.
1071.1Sreinoud * Pass the podule details, the parent softc and the channel
1081.1Sreinoud */
1091.1Sreinoud
1101.1Sreinoudstruct amps_attach_args {
1111.1Sreinoud	bus_space_tag_t aa_iot;			/* bus space tag */
1121.1Sreinoud	unsigned int aa_base;			/* base address for port */
1131.1Sreinoud	int aa_port;      			/* serial port number */
1141.1Sreinoud	podulebus_intr_handle_t aa_irq;		/* IRQ number */
1151.1Sreinoud};
1161.1Sreinoud
1171.1Sreinoud/*
1181.1Sreinoud * Define prototypes for custom bus space functions.
1191.1Sreinoud */
1201.1Sreinoud
1211.1Sreinoud/* Print function used during child config */
1221.1Sreinoud
1231.1Sreinoudint
1241.1Sreinoudamps_print(aux, name)
1251.1Sreinoud	void *aux;
1261.1Sreinoud	const char *name;
1271.1Sreinoud{
1281.1Sreinoud	struct amps_attach_args *aa = aux;
1291.1Sreinoud
1301.1Sreinoud	if (!name)
1311.8Sthorpej		aprint_normal(", port %d", aa->aa_port);
1321.1Sreinoud
1331.1Sreinoud	return(QUIET);
1341.1Sreinoud}
1351.1Sreinoud
1361.1Sreinoud/*
1371.1Sreinoud * Card probe function
1381.1Sreinoud *
1391.1Sreinoud * Just match the manufacturer and podule ID's
1401.1Sreinoud */
1411.1Sreinoud
1421.1Sreinoudint
1431.1Sreinoudamps_probe(parent, cf, aux)
1441.1Sreinoud	struct device *parent;
1451.1Sreinoud	struct cfdata *cf;
1461.1Sreinoud	void *aux;
1471.1Sreinoud{
1481.1Sreinoud	struct podule_attach_args *pa = (void *)aux;
1491.1Sreinoud
1501.3Sbjh21	return (pa->pa_product == PODULE_ATOMWIDE_SERIAL);
1511.1Sreinoud}
1521.1Sreinoud
1531.1Sreinoud/*
1541.1Sreinoud * Card attach function
1551.1Sreinoud *
1561.1Sreinoud * Identify the card version and configure any children.
1571.1Sreinoud * Install a shutdown handler to kill interrupts on shutdown
1581.1Sreinoud */
1591.1Sreinoud
1601.1Sreinoudvoid
1611.1Sreinoudamps_attach(parent, self, aux)
1621.1Sreinoud	struct device *parent, *self;
1631.1Sreinoud	void *aux;
1641.1Sreinoud{
1651.1Sreinoud	struct amps_softc *sc = (void *)self;
1661.1Sreinoud	struct podule_attach_args *pa = (void *)aux;
1671.1Sreinoud	struct amps_attach_args aa;
1681.1Sreinoud
1691.1Sreinoud	/* Note the podule number and validate */
1701.1Sreinoud
1711.1Sreinoud	if (pa->pa_podule_number == -1)
1721.1Sreinoud		panic("Podule has disappeared !");
1731.1Sreinoud
1741.1Sreinoud	sc->sc_podule_number = pa->pa_podule_number;
1751.1Sreinoud	sc->sc_podule = pa->pa_podule;
1761.1Sreinoud	podules[sc->sc_podule_number].attached = 1;
1771.1Sreinoud
1781.1Sreinoud	sc->sc_iot = pa->pa_iot;
1791.1Sreinoud
1801.1Sreinoud	/* Install a clean up handler to make sure IRQ's are disabled */
1811.1Sreinoud/*	if (shutdownhook_establish(amps_shutdown, (void *)sc) == NULL)
1821.1Sreinoud		panic("%s: Cannot install shutdown handler", self->dv_xname);*/
1831.1Sreinoud
1841.1Sreinoud	/* Set the interrupt info for this podule */
1851.1Sreinoud
1861.1Sreinoud/*	sc->sc_podule->irq_addr = pa->pa_podule->slow_base +;*/	/* XXX */
1871.1Sreinoud/*	sc->sc_podule->irq_mask = ;*/
1881.1Sreinoud
1891.1Sreinoud	printf("\n");
1901.1Sreinoud
1911.1Sreinoud	/* Configure the children */
1921.1Sreinoud
1931.1Sreinoud	aa.aa_iot = sc->sc_iot;
1941.1Sreinoud	aa.aa_base = pa->pa_podule->slow_base + AMPS_BASE_OFFSET;
1951.1Sreinoud	aa.aa_base += MAX_AMPS_PORTS * AMPS_PORT_SPACING;
1961.1Sreinoud	aa.aa_irq = pa->pa_podule->interrupt;
1971.1Sreinoud	for (aa.aa_port = 0; aa.aa_port < MAX_AMPS_PORTS; ++aa.aa_port) {
1981.1Sreinoud		aa.aa_base -= AMPS_PORT_SPACING;
1991.10Sdrochner		config_found(self, &aa, amps_print);
2001.1Sreinoud	}
2011.1Sreinoud}
2021.1Sreinoud
2031.1Sreinoud/*
2041.1Sreinoud * Card shutdown function
2051.1Sreinoud *
2061.1Sreinoud * Called via do_shutdown_hooks() during kernel shutdown.
2071.1Sreinoud * Clear the cards's interrupt mask to stop any podule interrupts.
2081.1Sreinoud */
2091.1Sreinoud
2101.1Sreinoud/*void
2111.1Sreinoudamps_shutdown(arg)
2121.1Sreinoud	void *arg;
2131.1Sreinoud{
2141.1Sreinoud}*/
2151.1Sreinoud
2161.1Sreinoud/*
2171.1Sreinoud * Atomwide Multi-Port Serial probe and attach code for the com device.
2181.1Sreinoud *
2191.1Sreinoud * This provides a different pair of probe and attach functions
2201.1Sreinoud * for attaching the com device (dev/ic/com.c) to the Atomwide serial card.
2211.1Sreinoud */
2221.1Sreinoud
2231.1Sreinoudstruct com_amps_softc {
2241.1Sreinoud	struct	com_softc sc_com;	/* real "com" softc */
2251.1Sreinoud	void	*sc_ih;			/* interrupt handler */
2261.1Sreinoud	struct	evcnt sc_intrcnt;	/* interrupt count */
2271.1Sreinoud};
2281.1Sreinoud
2291.1Sreinoud/* Prototypes for functions */
2301.1Sreinoud
2311.1Sreinoudstatic int  com_amps_probe   __P((struct device *, struct cfdata *, void *));
2321.1Sreinoudstatic void com_amps_attach  __P((struct device *, struct device *, void *));
2331.1Sreinoud
2341.1Sreinoud/* device attach structure */
2351.1Sreinoud
2361.5SthorpejCFATTACH_DECL(com_amps, sizeof(struct com_amps_softc),
2371.5Sthorpej	com_amps_probe, com_amps_attach, NULL, NULL);
2381.1Sreinoud
2391.1Sreinoud/*
2401.1Sreinoud * Controller probe function
2411.1Sreinoud *
2421.1Sreinoud * Map all the required I/O space for this channel, make sure interrupts
2431.1Sreinoud * are disabled and probe the bus.
2441.1Sreinoud */
2451.1Sreinoud
2461.1Sreinoudint
2471.1Sreinoudcom_amps_probe(parent, cf, aux)
2481.1Sreinoud	struct device *parent;
2491.1Sreinoud	struct cfdata *cf;
2501.1Sreinoud	void *aux;
2511.1Sreinoud{
2521.1Sreinoud	bus_space_tag_t iot;
2531.1Sreinoud	bus_space_handle_t ioh;
2541.1Sreinoud	int iobase;
2551.1Sreinoud	int rv = 1;
2561.1Sreinoud	struct amps_attach_args *aa = aux;
2571.1Sreinoud
2581.1Sreinoud	iot = aa->aa_iot;
2591.1Sreinoud	iobase = aa->aa_base;
2601.1Sreinoud
2611.1Sreinoud	/* if it's in use as console, it's there. */
2621.1Sreinoud	if (!com_is_console(iot, iobase, 0)) {
2631.1Sreinoud		if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) {
2641.1Sreinoud			return 0;
2651.1Sreinoud		}
2661.1Sreinoud		/*
2671.1Sreinoud		 * We don't use the generic comprobe1() function as it
2681.1Sreinoud		 * is not good enough to identify which ports are present.
2691.1Sreinoud		 *
2701.1Sreinoud		 * Instead test for the presence of the scratch register
2711.1Sreinoud		 */
2721.1Sreinoud
2731.1Sreinoud		bus_space_write_1(iot, ioh, com_scratch, 0x55);
2741.1Sreinoud		bus_space_write_1(iot, ioh, com_ier, 0);
2751.1Sreinoud		(void)bus_space_read_1(iot, ioh, com_data);
2761.1Sreinoud		if (bus_space_read_1(iot, ioh, com_scratch) != 0x55)
2771.1Sreinoud			rv = 0;
2781.1Sreinoud		bus_space_write_1(iot, ioh, com_scratch, 0xaa);
2791.1Sreinoud		bus_space_write_1(iot, ioh, com_ier, 0);
2801.1Sreinoud		(void)bus_space_read_1(iot, ioh, com_data);
2811.1Sreinoud		if (bus_space_read_1(iot, ioh, com_scratch) != 0xaa)
2821.1Sreinoud			rv = 0;
2831.1Sreinoud
2841.1Sreinoud		bus_space_unmap(iot, ioh, COM_NPORTS);
2851.1Sreinoud	}
2861.1Sreinoud	return (rv);
2871.1Sreinoud}
2881.1Sreinoud
2891.1Sreinoud/*
2901.1Sreinoud * Controller attach function
2911.1Sreinoud *
2921.1Sreinoud * Map all the required I/O space for this port and attach the driver
2931.1Sreinoud * The generic attach will probe and attach any device.
2941.1Sreinoud * Install an interrupt handler and we are ready to rock.
2951.1Sreinoud */
2961.1Sreinoud
2971.1Sreinoudvoid
2981.1Sreinoudcom_amps_attach(parent, self, aux)
2991.1Sreinoud	struct device *parent, *self;
3001.1Sreinoud	void *aux;
3011.1Sreinoud{
3021.1Sreinoud	struct com_amps_softc *asc = (void *)self;
3031.1Sreinoud	struct com_softc *sc = &asc->sc_com;
3041.1Sreinoud	u_int iobase;
3051.1Sreinoud	bus_space_tag_t iot;
3061.1Sreinoud	struct amps_attach_args *aa = aux;
3071.1Sreinoud
3081.1Sreinoud	iot = sc->sc_iot = aa->aa_iot;
3091.1Sreinoud	iobase = sc->sc_iobase = aa->aa_base;
3101.1Sreinoud
3111.1Sreinoud	if (!com_is_console(iot, iobase, &sc->sc_ioh)
3121.1Sreinoud		&& bus_space_map(iot, iobase, COM_NPORTS, 0, &sc->sc_ioh))
3131.1Sreinoud			panic("comattach: io mapping failed");
3141.1Sreinoud
3151.1Sreinoud	sc->sc_frequency = AMPS_FREQ;
3161.1Sreinoud	com_attach_subr(sc);
3171.1Sreinoud
3181.1Sreinoud	evcnt_attach_dynamic(&asc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
3191.1Sreinoud	    self->dv_xname, "intr");
3201.1Sreinoud	asc->sc_ih = podulebus_irq_establish(aa->aa_irq, IPL_SERIAL, comintr,
3211.1Sreinoud	    sc, &asc->sc_intrcnt);
3221.1Sreinoud}
323