amps.c revision 1.15
11.15Sdsl/*	$NetBSD: amps.c,v 1.15 2009/03/14 15:35:58 dsl 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 *
191.1Sreinoud * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.1Sreinoud * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.1Sreinoud * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.1Sreinoud * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.1Sreinoud * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.1Sreinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.1Sreinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.1Sreinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.1Sreinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.1Sreinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.1Sreinoud * POSSIBILITY OF SUCH DAMAGE.
301.1Sreinoud *
311.1Sreinoud * Card driver and probe and attach functions to use generic 16550 com
321.1Sreinoud * driver for the Atomwide multiport serial podule
331.1Sreinoud */
341.1Sreinoud
351.1Sreinoud/*
361.1Sreinoud * Thanks to Martin Coulson, Atomwide, for providing the hardware
371.1Sreinoud */
381.9Slukem
391.9Slukem#include <sys/cdefs.h>
401.15Sdsl__KERNEL_RCSID(0, "$NetBSD: amps.c,v 1.15 2009/03/14 15:35:58 dsl Exp $");
411.1Sreinoud
421.1Sreinoud#include <sys/param.h>
431.1Sreinoud#include <sys/systm.h>
441.1Sreinoud#include <sys/ioctl.h>
451.1Sreinoud#include <sys/select.h>
461.1Sreinoud#include <sys/tty.h>
471.1Sreinoud#include <sys/proc.h>
481.1Sreinoud#include <sys/user.h>
491.1Sreinoud#include <sys/conf.h>
501.1Sreinoud#include <sys/file.h>
511.1Sreinoud#include <sys/uio.h>
521.1Sreinoud#include <sys/kernel.h>
531.1Sreinoud#include <sys/syslog.h>
541.1Sreinoud#include <sys/types.h>
551.1Sreinoud#include <sys/device.h>
561.1Sreinoud
571.2Sthorpej#include <machine/intr.h>
581.1Sreinoud#include <machine/io.h>
591.1Sreinoud#include <machine/bus.h>
601.1Sreinoud#include <acorn32/podulebus/podulebus.h>
611.1Sreinoud#include <acorn32/podulebus/ampsreg.h>
621.1Sreinoud#include <dev/ic/comreg.h>
631.1Sreinoud#include <dev/ic/comvar.h>
641.1Sreinoud#include <dev/podulebus/podules.h>
651.1Sreinoud
661.1Sreinoud#include "locators.h"
671.1Sreinoud
681.1Sreinoud/*
691.1Sreinoud * Atomwide Mulit-port serial podule device.
701.1Sreinoud *
711.1Sreinoud * This probes and attaches the top level multi-port serial device to the
721.1Sreinoud * podulebus. It then configures the child com devices.
731.1Sreinoud */
741.1Sreinoud
751.1Sreinoud/*
761.1Sreinoud * Atomwide Multi-port serial card softc structure.
771.1Sreinoud *
781.1Sreinoud * Contains the device node, podule information and global information
791.1Sreinoud * required by the driver such as the card version and the interrupt mask.
801.1Sreinoud */
811.1Sreinoud
821.1Sreinoudstruct amps_softc {
831.1Sreinoud	struct device		sc_dev;			/* device node */
841.1Sreinoud	podule_t 		*sc_podule;		/* Our podule info */
851.1Sreinoud	int 			sc_podule_number;	/* Our podule number */
861.1Sreinoud	bus_space_tag_t		sc_iot;			/* Bus tag */
871.1Sreinoud};
881.1Sreinoud
891.7Schsint	amps_probe(struct device *, struct cfdata *, void *);
901.7Schsvoid	amps_attach(struct device *, struct device *, void *);
911.1Sreinoud
921.5SthorpejCFATTACH_DECL(amps, sizeof(struct amps_softc),
931.6Sthorpej    amps_probe, amps_attach, NULL, NULL);
941.7Schs
951.7Schsint	amps_print(void *, const char *);
961.7Schsvoid	amps_shutdown(void *);
971.1Sreinoud
981.1Sreinoud/*
991.1Sreinoud * Attach arguments for child devices.
1001.1Sreinoud * Pass the podule details, the parent softc and the channel
1011.1Sreinoud */
1021.1Sreinoud
1031.1Sreinoudstruct amps_attach_args {
1041.1Sreinoud	bus_space_tag_t aa_iot;			/* bus space tag */
1051.1Sreinoud	unsigned int aa_base;			/* base address for port */
1061.1Sreinoud	int aa_port;      			/* serial port number */
1071.1Sreinoud	podulebus_intr_handle_t aa_irq;		/* IRQ number */
1081.1Sreinoud};
1091.1Sreinoud
1101.1Sreinoud/*
1111.1Sreinoud * Define prototypes for custom bus space functions.
1121.1Sreinoud */
1131.1Sreinoud
1141.1Sreinoud/* Print function used during child config */
1151.1Sreinoud
1161.1Sreinoudint
1171.15Sdslamps_print(void *aux, const char *name)
1181.1Sreinoud{
1191.1Sreinoud	struct amps_attach_args *aa = aux;
1201.1Sreinoud
1211.1Sreinoud	if (!name)
1221.8Sthorpej		aprint_normal(", port %d", aa->aa_port);
1231.1Sreinoud
1241.1Sreinoud	return(QUIET);
1251.1Sreinoud}
1261.1Sreinoud
1271.1Sreinoud/*
1281.1Sreinoud * Card probe function
1291.1Sreinoud *
1301.1Sreinoud * Just match the manufacturer and podule ID's
1311.1Sreinoud */
1321.1Sreinoud
1331.1Sreinoudint
1341.15Sdslamps_probe(struct device *parent, struct cfdata *cf, void *aux)
1351.1Sreinoud{
1361.1Sreinoud	struct podule_attach_args *pa = (void *)aux;
1371.1Sreinoud
1381.3Sbjh21	return (pa->pa_product == PODULE_ATOMWIDE_SERIAL);
1391.1Sreinoud}
1401.1Sreinoud
1411.1Sreinoud/*
1421.1Sreinoud * Card attach function
1431.1Sreinoud *
1441.1Sreinoud * Identify the card version and configure any children.
1451.1Sreinoud * Install a shutdown handler to kill interrupts on shutdown
1461.1Sreinoud */
1471.1Sreinoud
1481.1Sreinoudvoid
1491.1Sreinoudamps_attach(parent, self, aux)
1501.1Sreinoud	struct device *parent, *self;
1511.1Sreinoud	void *aux;
1521.1Sreinoud{
1531.1Sreinoud	struct amps_softc *sc = (void *)self;
1541.1Sreinoud	struct podule_attach_args *pa = (void *)aux;
1551.1Sreinoud	struct amps_attach_args aa;
1561.1Sreinoud
1571.1Sreinoud	/* Note the podule number and validate */
1581.1Sreinoud
1591.1Sreinoud	if (pa->pa_podule_number == -1)
1601.1Sreinoud		panic("Podule has disappeared !");
1611.1Sreinoud
1621.1Sreinoud	sc->sc_podule_number = pa->pa_podule_number;
1631.1Sreinoud	sc->sc_podule = pa->pa_podule;
1641.1Sreinoud	podules[sc->sc_podule_number].attached = 1;
1651.1Sreinoud
1661.1Sreinoud	sc->sc_iot = pa->pa_iot;
1671.1Sreinoud
1681.1Sreinoud	/* Install a clean up handler to make sure IRQ's are disabled */
1691.1Sreinoud/*	if (shutdownhook_establish(amps_shutdown, (void *)sc) == NULL)
1701.1Sreinoud		panic("%s: Cannot install shutdown handler", self->dv_xname);*/
1711.1Sreinoud
1721.1Sreinoud	/* Set the interrupt info for this podule */
1731.1Sreinoud
1741.1Sreinoud/*	sc->sc_podule->irq_addr = pa->pa_podule->slow_base +;*/	/* XXX */
1751.1Sreinoud/*	sc->sc_podule->irq_mask = ;*/
1761.1Sreinoud
1771.1Sreinoud	printf("\n");
1781.1Sreinoud
1791.1Sreinoud	/* Configure the children */
1801.1Sreinoud
1811.1Sreinoud	aa.aa_iot = sc->sc_iot;
1821.1Sreinoud	aa.aa_base = pa->pa_podule->slow_base + AMPS_BASE_OFFSET;
1831.1Sreinoud	aa.aa_base += MAX_AMPS_PORTS * AMPS_PORT_SPACING;
1841.1Sreinoud	aa.aa_irq = pa->pa_podule->interrupt;
1851.1Sreinoud	for (aa.aa_port = 0; aa.aa_port < MAX_AMPS_PORTS; ++aa.aa_port) {
1861.1Sreinoud		aa.aa_base -= AMPS_PORT_SPACING;
1871.10Sdrochner		config_found(self, &aa, amps_print);
1881.1Sreinoud	}
1891.1Sreinoud}
1901.1Sreinoud
1911.1Sreinoud/*
1921.1Sreinoud * Card shutdown function
1931.1Sreinoud *
1941.1Sreinoud * Called via do_shutdown_hooks() during kernel shutdown.
1951.1Sreinoud * Clear the cards's interrupt mask to stop any podule interrupts.
1961.1Sreinoud */
1971.1Sreinoud
1981.1Sreinoud/*void
1991.15Sdslamps_shutdown(void *arg)
2001.1Sreinoud{
2011.1Sreinoud}*/
2021.1Sreinoud
2031.1Sreinoud/*
2041.1Sreinoud * Atomwide Multi-Port Serial probe and attach code for the com device.
2051.1Sreinoud *
2061.1Sreinoud * This provides a different pair of probe and attach functions
2071.1Sreinoud * for attaching the com device (dev/ic/com.c) to the Atomwide serial card.
2081.1Sreinoud */
2091.1Sreinoud
2101.1Sreinoudstruct com_amps_softc {
2111.1Sreinoud	struct	com_softc sc_com;	/* real "com" softc */
2121.1Sreinoud	void	*sc_ih;			/* interrupt handler */
2131.1Sreinoud	struct	evcnt sc_intrcnt;	/* interrupt count */
2141.1Sreinoud};
2151.1Sreinoud
2161.1Sreinoud/* Prototypes for functions */
2171.1Sreinoud
2181.13Scubestatic int  com_amps_probe   (device_t, cfdata_t , void *);
2191.13Scubestatic void com_amps_attach  (device_t, device_t, void *);
2201.1Sreinoud
2211.1Sreinoud/* device attach structure */
2221.1Sreinoud
2231.13ScubeCFATTACH_DECL_NEW(com_amps, sizeof(struct com_amps_softc),
2241.5Sthorpej	com_amps_probe, com_amps_attach, NULL, NULL);
2251.1Sreinoud
2261.1Sreinoud/*
2271.1Sreinoud * Controller probe function
2281.1Sreinoud *
2291.1Sreinoud * Map all the required I/O space for this channel, make sure interrupts
2301.1Sreinoud * are disabled and probe the bus.
2311.1Sreinoud */
2321.1Sreinoud
2331.1Sreinoudint
2341.13Scubecom_amps_probe(device_t parent, cfdata_t cf, void *aux)
2351.1Sreinoud{
2361.1Sreinoud	bus_space_tag_t iot;
2371.1Sreinoud	bus_space_handle_t ioh;
2381.1Sreinoud	int iobase;
2391.1Sreinoud	int rv = 1;
2401.1Sreinoud	struct amps_attach_args *aa = aux;
2411.1Sreinoud
2421.1Sreinoud	iot = aa->aa_iot;
2431.1Sreinoud	iobase = aa->aa_base;
2441.1Sreinoud
2451.1Sreinoud	/* if it's in use as console, it's there. */
2461.1Sreinoud	if (!com_is_console(iot, iobase, 0)) {
2471.1Sreinoud		if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) {
2481.1Sreinoud			return 0;
2491.1Sreinoud		}
2501.1Sreinoud		/*
2511.1Sreinoud		 * We don't use the generic comprobe1() function as it
2521.1Sreinoud		 * is not good enough to identify which ports are present.
2531.1Sreinoud		 *
2541.1Sreinoud		 * Instead test for the presence of the scratch register
2551.1Sreinoud		 */
2561.1Sreinoud
2571.1Sreinoud		bus_space_write_1(iot, ioh, com_scratch, 0x55);
2581.1Sreinoud		bus_space_write_1(iot, ioh, com_ier, 0);
2591.1Sreinoud		(void)bus_space_read_1(iot, ioh, com_data);
2601.1Sreinoud		if (bus_space_read_1(iot, ioh, com_scratch) != 0x55)
2611.1Sreinoud			rv = 0;
2621.1Sreinoud		bus_space_write_1(iot, ioh, com_scratch, 0xaa);
2631.1Sreinoud		bus_space_write_1(iot, ioh, com_ier, 0);
2641.1Sreinoud		(void)bus_space_read_1(iot, ioh, com_data);
2651.1Sreinoud		if (bus_space_read_1(iot, ioh, com_scratch) != 0xaa)
2661.1Sreinoud			rv = 0;
2671.1Sreinoud
2681.1Sreinoud		bus_space_unmap(iot, ioh, COM_NPORTS);
2691.1Sreinoud	}
2701.1Sreinoud	return (rv);
2711.1Sreinoud}
2721.1Sreinoud
2731.1Sreinoud/*
2741.1Sreinoud * Controller attach function
2751.1Sreinoud *
2761.1Sreinoud * Map all the required I/O space for this port and attach the driver
2771.1Sreinoud * The generic attach will probe and attach any device.
2781.1Sreinoud * Install an interrupt handler and we are ready to rock.
2791.1Sreinoud */
2801.1Sreinoud
2811.1Sreinoudvoid
2821.13Scubecom_amps_attach(device_t parent, device_t self, void *aux)
2831.1Sreinoud{
2841.13Scube	struct com_amps_softc *asc = device_private(self);
2851.1Sreinoud	struct com_softc *sc = &asc->sc_com;
2861.1Sreinoud	u_int iobase;
2871.1Sreinoud	bus_space_tag_t iot;
2881.12Sgdamore	bus_space_handle_t ioh;
2891.1Sreinoud	struct amps_attach_args *aa = aux;
2901.1Sreinoud
2911.13Scube	sc->sc_dev = self;
2921.12Sgdamore	iot = aa->aa_iot;
2931.12Sgdamore	iobase = aa->aa_base;
2941.1Sreinoud
2951.12Sgdamore	if (!com_is_console(iot, iobase, &ioh)
2961.12Sgdamore	    && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh))
2971.12Sgdamore		panic("comattach: io mapping failed");
2981.12Sgdamore	COM_INIT_REGS(sc->sc_regs, iot, ioh, iobase);
2991.1Sreinoud
3001.1Sreinoud	sc->sc_frequency = AMPS_FREQ;
3011.1Sreinoud	com_attach_subr(sc);
3021.1Sreinoud
3031.1Sreinoud	evcnt_attach_dynamic(&asc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
3041.13Scube	    device_xname(self), "intr");
3051.1Sreinoud	asc->sc_ih = podulebus_irq_establish(aa->aa_irq, IPL_SERIAL, comintr,
3061.1Sreinoud	    sc, &asc->sc_intrcnt);
3071.1Sreinoud}
308