11.24Sandvar/*	$NetBSD: amps.c,v 1.24 2025/01/02 16:09:32 andvar 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.24Sandvar__KERNEL_RCSID(0, "$NetBSD: amps.c,v 1.24 2025/01/02 16:09:32 andvar 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/conf.h>
491.1Sreinoud#include <sys/file.h>
501.1Sreinoud#include <sys/uio.h>
511.1Sreinoud#include <sys/kernel.h>
521.1Sreinoud#include <sys/syslog.h>
531.1Sreinoud#include <sys/types.h>
541.1Sreinoud#include <sys/device.h>
551.19Sdyoung#include <sys/bus.h>
561.1Sreinoud
571.2Sthorpej#include <machine/intr.h>
581.1Sreinoud#include <machine/io.h>
591.1Sreinoud#include <acorn32/podulebus/podulebus.h>
601.1Sreinoud#include <acorn32/podulebus/ampsreg.h>
611.1Sreinoud#include <dev/ic/comreg.h>
621.1Sreinoud#include <dev/ic/comvar.h>
631.1Sreinoud#include <dev/podulebus/podules.h>
641.1Sreinoud
651.1Sreinoud#include "locators.h"
661.1Sreinoud
671.1Sreinoud/*
681.24Sandvar * Atomwide Multi-port serial podule device.
691.1Sreinoud *
701.1Sreinoud * This probes and attaches the top level multi-port serial device to the
711.1Sreinoud * podulebus. It then configures the child com devices.
721.1Sreinoud */
731.1Sreinoud
741.1Sreinoud/*
751.1Sreinoud * Atomwide Multi-port serial card softc structure.
761.1Sreinoud *
771.1Sreinoud * Contains the device node, podule information and global information
781.1Sreinoud * required by the driver such as the card version and the interrupt mask.
791.1Sreinoud */
801.1Sreinoud
811.1Sreinoudstruct amps_softc {
821.20Schs	device_t		sc_dev;			/* device node */
831.1Sreinoud	podule_t 		*sc_podule;		/* Our podule info */
841.1Sreinoud	int 			sc_podule_number;	/* Our podule number */
851.1Sreinoud	bus_space_tag_t		sc_iot;			/* Bus tag */
861.1Sreinoud};
871.1Sreinoud
881.18Smattint	amps_probe(device_t, cfdata_t, void *);
891.18Smattvoid	amps_attach(device_t, device_t, void *);
901.1Sreinoud
911.20SchsCFATTACH_DECL_NEW(amps, sizeof(struct amps_softc),
921.6Sthorpej    amps_probe, amps_attach, NULL, NULL);
931.7Schs
941.7Schsint	amps_print(void *, const char *);
951.7Schsvoid	amps_shutdown(void *);
961.1Sreinoud
971.1Sreinoud/*
981.1Sreinoud * Attach arguments for child devices.
991.1Sreinoud * Pass the podule details, the parent softc and the channel
1001.1Sreinoud */
1011.1Sreinoud
1021.1Sreinoudstruct amps_attach_args {
1031.1Sreinoud	bus_space_tag_t aa_iot;			/* bus space tag */
1041.1Sreinoud	unsigned int aa_base;			/* base address for port */
1051.1Sreinoud	int aa_port;      			/* serial port number */
1061.1Sreinoud	podulebus_intr_handle_t aa_irq;		/* IRQ number */
1071.1Sreinoud};
1081.1Sreinoud
1091.1Sreinoud/*
1101.1Sreinoud * Define prototypes for custom bus space functions.
1111.1Sreinoud */
1121.1Sreinoud
1131.1Sreinoud/* Print function used during child config */
1141.1Sreinoud
1151.1Sreinoudint
1161.15Sdslamps_print(void *aux, const char *name)
1171.1Sreinoud{
1181.1Sreinoud	struct amps_attach_args *aa = aux;
1191.1Sreinoud
1201.1Sreinoud	if (!name)
1211.8Sthorpej		aprint_normal(", port %d", aa->aa_port);
1221.1Sreinoud
1231.1Sreinoud	return(QUIET);
1241.1Sreinoud}
1251.1Sreinoud
1261.1Sreinoud/*
1271.1Sreinoud * Card probe function
1281.1Sreinoud *
1291.1Sreinoud * Just match the manufacturer and podule ID's
1301.1Sreinoud */
1311.1Sreinoud
1321.1Sreinoudint
1331.18Smattamps_probe(device_t parent, cfdata_t cf, void *aux)
1341.1Sreinoud{
1351.18Smatt	struct podule_attach_args *pa = aux;
1361.1Sreinoud
1371.3Sbjh21	return (pa->pa_product == PODULE_ATOMWIDE_SERIAL);
1381.1Sreinoud}
1391.1Sreinoud
1401.1Sreinoud/*
1411.1Sreinoud * Card attach function
1421.1Sreinoud *
1431.1Sreinoud * Identify the card version and configure any children.
1441.1Sreinoud * Install a shutdown handler to kill interrupts on shutdown
1451.1Sreinoud */
1461.1Sreinoud
1471.1Sreinoudvoid
1481.18Smattamps_attach(device_t parent, device_t self, void *aux)
1491.1Sreinoud{
1501.18Smatt	struct amps_softc *sc = device_private(self);
1511.18Smatt	struct podule_attach_args *pa = aux;
1521.1Sreinoud	struct amps_attach_args aa;
1531.1Sreinoud
1541.1Sreinoud	/* Note the podule number and validate */
1551.1Sreinoud
1561.1Sreinoud	if (pa->pa_podule_number == -1)
1571.1Sreinoud		panic("Podule has disappeared !");
1581.1Sreinoud
1591.20Schs	sc->sc_dev = self;
1601.1Sreinoud	sc->sc_podule_number = pa->pa_podule_number;
1611.1Sreinoud	sc->sc_podule = pa->pa_podule;
1621.1Sreinoud	podules[sc->sc_podule_number].attached = 1;
1631.1Sreinoud
1641.1Sreinoud	sc->sc_iot = pa->pa_iot;
1651.1Sreinoud
1661.1Sreinoud	/* Install a clean up handler to make sure IRQ's are disabled */
1671.1Sreinoud/*	if (shutdownhook_establish(amps_shutdown, (void *)sc) == NULL)
1681.20Schs		panic("%s: Cannot install shutdown handler", device_xname(self));*/
1691.1Sreinoud
1701.1Sreinoud	/* Set the interrupt info for this podule */
1711.1Sreinoud
1721.1Sreinoud/*	sc->sc_podule->irq_addr = pa->pa_podule->slow_base +;*/	/* XXX */
1731.1Sreinoud/*	sc->sc_podule->irq_mask = ;*/
1741.1Sreinoud
1751.1Sreinoud	printf("\n");
1761.1Sreinoud
1771.1Sreinoud	/* Configure the children */
1781.1Sreinoud
1791.1Sreinoud	aa.aa_iot = sc->sc_iot;
1801.1Sreinoud	aa.aa_base = pa->pa_podule->slow_base + AMPS_BASE_OFFSET;
1811.1Sreinoud	aa.aa_base += MAX_AMPS_PORTS * AMPS_PORT_SPACING;
1821.1Sreinoud	aa.aa_irq = pa->pa_podule->interrupt;
1831.1Sreinoud	for (aa.aa_port = 0; aa.aa_port < MAX_AMPS_PORTS; ++aa.aa_port) {
1841.1Sreinoud		aa.aa_base -= AMPS_PORT_SPACING;
1851.23Sthorpej		config_found(self, &aa, amps_print, CFARGS_NONE);
1861.1Sreinoud	}
1871.1Sreinoud}
1881.1Sreinoud
1891.1Sreinoud/*
1901.1Sreinoud * Card shutdown function
1911.1Sreinoud *
1921.1Sreinoud * Called via do_shutdown_hooks() during kernel shutdown.
1931.1Sreinoud * Clear the cards's interrupt mask to stop any podule interrupts.
1941.1Sreinoud */
1951.1Sreinoud
1961.1Sreinoud/*void
1971.15Sdslamps_shutdown(void *arg)
1981.1Sreinoud{
1991.1Sreinoud}*/
2001.1Sreinoud
2011.1Sreinoud/*
2021.1Sreinoud * Atomwide Multi-Port Serial probe and attach code for the com device.
2031.1Sreinoud *
2041.1Sreinoud * This provides a different pair of probe and attach functions
2051.1Sreinoud * for attaching the com device (dev/ic/com.c) to the Atomwide serial card.
2061.1Sreinoud */
2071.1Sreinoud
2081.1Sreinoudstruct com_amps_softc {
2091.1Sreinoud	struct	com_softc sc_com;	/* real "com" softc */
2101.1Sreinoud	void	*sc_ih;			/* interrupt handler */
2111.1Sreinoud	struct	evcnt sc_intrcnt;	/* interrupt count */
2121.1Sreinoud};
2131.1Sreinoud
2141.1Sreinoud/* Prototypes for functions */
2151.1Sreinoud
2161.13Scubestatic int  com_amps_probe   (device_t, cfdata_t , void *);
2171.13Scubestatic void com_amps_attach  (device_t, device_t, void *);
2181.1Sreinoud
2191.1Sreinoud/* device attach structure */
2201.1Sreinoud
2211.13ScubeCFATTACH_DECL_NEW(com_amps, sizeof(struct com_amps_softc),
2221.5Sthorpej	com_amps_probe, com_amps_attach, NULL, NULL);
2231.1Sreinoud
2241.1Sreinoud/*
2251.1Sreinoud * Controller probe function
2261.1Sreinoud *
2271.1Sreinoud * Map all the required I/O space for this channel, make sure interrupts
2281.1Sreinoud * are disabled and probe the bus.
2291.1Sreinoud */
2301.1Sreinoud
2311.1Sreinoudint
2321.13Scubecom_amps_probe(device_t parent, cfdata_t cf, void *aux)
2331.1Sreinoud{
2341.1Sreinoud	bus_space_tag_t iot;
2351.1Sreinoud	bus_space_handle_t ioh;
2361.1Sreinoud	int iobase;
2371.1Sreinoud	int rv = 1;
2381.1Sreinoud	struct amps_attach_args *aa = aux;
2391.1Sreinoud
2401.1Sreinoud	iot = aa->aa_iot;
2411.1Sreinoud	iobase = aa->aa_base;
2421.1Sreinoud
2431.1Sreinoud	/* if it's in use as console, it's there. */
2441.1Sreinoud	if (!com_is_console(iot, iobase, 0)) {
2451.1Sreinoud		if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) {
2461.1Sreinoud			return 0;
2471.1Sreinoud		}
2481.1Sreinoud		/*
2491.1Sreinoud		 * We don't use the generic comprobe1() function as it
2501.1Sreinoud		 * is not good enough to identify which ports are present.
2511.1Sreinoud		 *
2521.1Sreinoud		 * Instead test for the presence of the scratch register
2531.1Sreinoud		 */
2541.1Sreinoud
2551.1Sreinoud		bus_space_write_1(iot, ioh, com_scratch, 0x55);
2561.1Sreinoud		bus_space_write_1(iot, ioh, com_ier, 0);
2571.1Sreinoud		(void)bus_space_read_1(iot, ioh, com_data);
2581.1Sreinoud		if (bus_space_read_1(iot, ioh, com_scratch) != 0x55)
2591.1Sreinoud			rv = 0;
2601.1Sreinoud		bus_space_write_1(iot, ioh, com_scratch, 0xaa);
2611.1Sreinoud		bus_space_write_1(iot, ioh, com_ier, 0);
2621.1Sreinoud		(void)bus_space_read_1(iot, ioh, com_data);
2631.1Sreinoud		if (bus_space_read_1(iot, ioh, com_scratch) != 0xaa)
2641.1Sreinoud			rv = 0;
2651.1Sreinoud
2661.1Sreinoud		bus_space_unmap(iot, ioh, COM_NPORTS);
2671.1Sreinoud	}
2681.1Sreinoud	return (rv);
2691.1Sreinoud}
2701.1Sreinoud
2711.1Sreinoud/*
2721.1Sreinoud * Controller attach function
2731.1Sreinoud *
2741.1Sreinoud * Map all the required I/O space for this port and attach the driver
2751.1Sreinoud * The generic attach will probe and attach any device.
2761.1Sreinoud * Install an interrupt handler and we are ready to rock.
2771.1Sreinoud */
2781.1Sreinoud
2791.1Sreinoudvoid
2801.13Scubecom_amps_attach(device_t parent, device_t self, void *aux)
2811.1Sreinoud{
2821.13Scube	struct com_amps_softc *asc = device_private(self);
2831.1Sreinoud	struct com_softc *sc = &asc->sc_com;
2841.1Sreinoud	u_int iobase;
2851.1Sreinoud	bus_space_tag_t iot;
2861.12Sgdamore	bus_space_handle_t ioh;
2871.1Sreinoud	struct amps_attach_args *aa = aux;
2881.1Sreinoud
2891.13Scube	sc->sc_dev = self;
2901.12Sgdamore	iot = aa->aa_iot;
2911.12Sgdamore	iobase = aa->aa_base;
2921.1Sreinoud
2931.12Sgdamore	if (!com_is_console(iot, iobase, &ioh)
2941.12Sgdamore	    && bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh))
2951.12Sgdamore		panic("comattach: io mapping failed");
2961.21Sthorpej	com_init_regs(&sc->sc_regs, iot, ioh, iobase);
2971.1Sreinoud
2981.1Sreinoud	sc->sc_frequency = AMPS_FREQ;
2991.1Sreinoud	com_attach_subr(sc);
3001.1Sreinoud
3011.1Sreinoud	evcnt_attach_dynamic(&asc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
3021.13Scube	    device_xname(self), "intr");
3031.1Sreinoud	asc->sc_ih = podulebus_irq_establish(aa->aa_irq, IPL_SERIAL, comintr,
3041.1Sreinoud	    sc, &asc->sc_intrcnt);
3051.1Sreinoud}
306