xref: /netbsd-src/sys/arch/hppa/dev/lasi.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: lasi.c,v 1.5 2021/08/07 16:18:55 thorpej Exp $	*/
26d3ceb1dSskrll 
36d3ceb1dSskrll /*	$OpenBSD: lasi.c,v 1.4 2001/06/09 03:57:19 mickey Exp $	*/
46d3ceb1dSskrll 
56d3ceb1dSskrll /*
66d3ceb1dSskrll  * Copyright (c) 1998-2003 Michael Shalayeff
76d3ceb1dSskrll  * All rights reserved.
86d3ceb1dSskrll  *
96d3ceb1dSskrll  * Redistribution and use in source and binary forms, with or without
106d3ceb1dSskrll  * modification, are permitted provided that the following conditions
116d3ceb1dSskrll  * are met:
126d3ceb1dSskrll  * 1. Redistributions of source code must retain the above copyright
136d3ceb1dSskrll  *    notice, this list of conditions and the following disclaimer.
146d3ceb1dSskrll  * 2. Redistributions in binary form must reproduce the above copyright
156d3ceb1dSskrll  *    notice, this list of conditions and the following disclaimer in the
166d3ceb1dSskrll  *    documentation and/or other materials provided with the distribution.
176d3ceb1dSskrll  *
186d3ceb1dSskrll  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
196d3ceb1dSskrll  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
206d3ceb1dSskrll  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
216d3ceb1dSskrll  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
226d3ceb1dSskrll  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
236d3ceb1dSskrll  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
246d3ceb1dSskrll  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
256d3ceb1dSskrll  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
266d3ceb1dSskrll  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
276d3ceb1dSskrll  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
286d3ceb1dSskrll  * THE POSSIBILITY OF SUCH DAMAGE.
296d3ceb1dSskrll  */
306d3ceb1dSskrll 
316d3ceb1dSskrll #include <sys/cdefs.h>
32*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: lasi.c,v 1.5 2021/08/07 16:18:55 thorpej Exp $");
336d3ceb1dSskrll 
346d3ceb1dSskrll #undef LASIDEBUG
356d3ceb1dSskrll 
366d3ceb1dSskrll #include <sys/param.h>
376d3ceb1dSskrll #include <sys/systm.h>
386d3ceb1dSskrll #include <sys/device.h>
396d3ceb1dSskrll #include <sys/reboot.h>
406d3ceb1dSskrll 
416d3ceb1dSskrll #include <sys/bus.h>
426d3ceb1dSskrll #include <machine/iomod.h>
436d3ceb1dSskrll #include <machine/autoconf.h>
446d3ceb1dSskrll 
456d3ceb1dSskrll #include <hppa/dev/cpudevs.h>
466d3ceb1dSskrll 
476d3ceb1dSskrll #include <hppa/gsc/gscbusvar.h>
486d3ceb1dSskrll 
496d3ceb1dSskrll struct lasi_hwr {
506d3ceb1dSskrll 	uint32_t lasi_power;
516d3ceb1dSskrll #define	LASI_BLINK	0x01
526d3ceb1dSskrll #define	LASI_OFF	0x02
536d3ceb1dSskrll 	uint32_t lasi_error;
546d3ceb1dSskrll 	uint32_t lasi_version;
556d3ceb1dSskrll 	uint32_t lasi_reset;
566d3ceb1dSskrll 	uint32_t lasi_arbmask;
576d3ceb1dSskrll };
586d3ceb1dSskrll 
596d3ceb1dSskrll struct lasi_trs {
606d3ceb1dSskrll 	uint32_t lasi_irr;	/* int requset register */
616d3ceb1dSskrll 	uint32_t lasi_imr;	/* int mask register */
626d3ceb1dSskrll 	uint32_t lasi_ipr;	/* int pending register */
636d3ceb1dSskrll 	uint32_t lasi_icr;	/* int command? register */
646d3ceb1dSskrll 	uint32_t lasi_iar;	/* int acquire? register */
656d3ceb1dSskrll };
666d3ceb1dSskrll 
676d3ceb1dSskrll #define	LASI_BANK_SZ	0x200000
686d3ceb1dSskrll #define	LASI_REG_INT	0x100000
696d3ceb1dSskrll #define	LASI_REG_MISC	0x10c000
706d3ceb1dSskrll 
716d3ceb1dSskrll struct lasi_softc {
726d3ceb1dSskrll 	device_t sc_dev;
736d3ceb1dSskrll 
746d3ceb1dSskrll 	struct hppa_interrupt_register sc_ir;
756d3ceb1dSskrll 
766d3ceb1dSskrll 	struct lasi_hwr volatile *sc_hw;
776d3ceb1dSskrll 	struct lasi_trs volatile *sc_trs;
786d3ceb1dSskrll };
796d3ceb1dSskrll 
806d3ceb1dSskrll int	lasimatch(device_t, cfdata_t, void *);
816d3ceb1dSskrll void	lasiattach(device_t, device_t, void *);
826d3ceb1dSskrll 
836d3ceb1dSskrll CFATTACH_DECL_NEW(lasi, sizeof(struct lasi_softc),
846d3ceb1dSskrll     lasimatch, lasiattach, NULL, NULL);
856d3ceb1dSskrll 
866d3ceb1dSskrll extern struct cfdriver lasi_cd;
876d3ceb1dSskrll 
886d3ceb1dSskrll void	lasi_cold_hook(int);
896d3ceb1dSskrll 
906d3ceb1dSskrll /*
916d3ceb1dSskrll  * Before a module is matched, this fixes up its gsc_attach_args.
926d3ceb1dSskrll  */
936d3ceb1dSskrll static void lasi_fix_args(void *, struct gsc_attach_args *);
946d3ceb1dSskrll static void
lasi_fix_args(void * _sc,struct gsc_attach_args * ga)956d3ceb1dSskrll lasi_fix_args(void *_sc, struct gsc_attach_args *ga)
966d3ceb1dSskrll {
976d3ceb1dSskrll 	struct lasi_softc *sc = _sc;
986d3ceb1dSskrll 	hppa_hpa_t module_offset;
996d3ceb1dSskrll 
1006d3ceb1dSskrll 	/*
1016d3ceb1dSskrll 	 * Determine this module's interrupt bit.
1026d3ceb1dSskrll 	 */
1036d3ceb1dSskrll 	module_offset = ga->ga_hpa - (hppa_hpa_t) sc->sc_trs;
1046d3ceb1dSskrll 	ga->ga_irq = HPPACF_IRQ_UNDEF;
1056d3ceb1dSskrll #define LASI_IRQ(off, irq) if (module_offset == off) ga->ga_irq = irq
1066d3ceb1dSskrll 	LASI_IRQ(0x2000, 7);	/* lpt */
1076d3ceb1dSskrll 	LASI_IRQ(0x4000, 13);	/* harmony */
1086d3ceb1dSskrll 	LASI_IRQ(0x4040, 16);	/* harmony telephone0 */
1096d3ceb1dSskrll 	LASI_IRQ(0x4060, 17);	/* harmony telephone1 */
1106d3ceb1dSskrll 	LASI_IRQ(0x5000, 5);	/* com */
1116d3ceb1dSskrll 	LASI_IRQ(0x6000, 9);	/* osiop */
1126d3ceb1dSskrll 	LASI_IRQ(0x7000, 8);	/* ie */
1136d3ceb1dSskrll 	LASI_IRQ(0x8000, 26);	/* pckbc */
1146d3ceb1dSskrll 	LASI_IRQ(0xa000, 20);	/* fdc */
1156d3ceb1dSskrll #undef LASI_IRQ
1166d3ceb1dSskrll 
1176d3ceb1dSskrll 	/*
1186d3ceb1dSskrll 	 * If this is the Ethernet adapter, get its Ethernet address.
1196d3ceb1dSskrll 	 */
1206d3ceb1dSskrll 	if (module_offset == 0x7000) {
1216d3ceb1dSskrll 		pdcproc_lan_station_id(ga->ga_ether_address,
1226d3ceb1dSskrll 		    sizeof(ga->ga_ether_address), ga->ga_hpa);
1236d3ceb1dSskrll 	}
1246d3ceb1dSskrll }
1256d3ceb1dSskrll 
1266d3ceb1dSskrll int
lasimatch(device_t parent,cfdata_t cf,void * aux)1276d3ceb1dSskrll lasimatch(device_t parent, cfdata_t cf, void *aux)
1286d3ceb1dSskrll {
1296d3ceb1dSskrll 	struct confargs *ca = aux;
1306d3ceb1dSskrll 
1316d3ceb1dSskrll 	if (ca->ca_type.iodc_type != HPPA_TYPE_BHA ||
1326d3ceb1dSskrll 	    ca->ca_type.iodc_sv_model != HPPA_BHA_LASI)
1336d3ceb1dSskrll 		return 0;
1346d3ceb1dSskrll 
1356d3ceb1dSskrll 	/*
1366d3ceb1dSskrll 	 * Forcibly mask the HPA down to the start of the LASI
1376d3ceb1dSskrll 	 * chip address space.
1386d3ceb1dSskrll 	 */
1396d3ceb1dSskrll 	ca->ca_hpa &= ~(LASI_BANK_SZ - 1);
1406d3ceb1dSskrll 
1416d3ceb1dSskrll 	return 1;
1426d3ceb1dSskrll }
1436d3ceb1dSskrll 
1446d3ceb1dSskrll void
lasiattach(device_t parent,device_t self,void * aux)1456d3ceb1dSskrll lasiattach(device_t parent, device_t self, void *aux)
1466d3ceb1dSskrll {
1476d3ceb1dSskrll 	struct confargs *ca = aux;
1486d3ceb1dSskrll 	struct lasi_softc *sc = device_private(self);
1496d3ceb1dSskrll 	struct gsc_attach_args ga;
1506d3ceb1dSskrll 	struct cpu_info *ci = &cpus[0];
1516d3ceb1dSskrll 	bus_space_handle_t ioh;
1526d3ceb1dSskrll 	int s;
1536d3ceb1dSskrll 
1546d3ceb1dSskrll 	sc->sc_dev = self;
1556d3ceb1dSskrll 	/*
1566d3ceb1dSskrll 	 * Map the LASI interrupt registers.
1576d3ceb1dSskrll 	 */
1586d3ceb1dSskrll 	if (bus_space_map(ca->ca_iot, ca->ca_hpa + LASI_REG_INT,
1596d3ceb1dSskrll 			  sizeof(struct lasi_trs), 0, &ioh)) {
1606d3ceb1dSskrll 		aprint_error(": can't map interrupt registers\n");
1616d3ceb1dSskrll 		return;
1626d3ceb1dSskrll 	}
1636d3ceb1dSskrll 	sc->sc_trs = (struct lasi_trs *)ioh;
1646d3ceb1dSskrll 
1656d3ceb1dSskrll 	/*
1666d3ceb1dSskrll 	 * Map the LASI miscellaneous registers.
1676d3ceb1dSskrll 	 */
1686d3ceb1dSskrll 	if (bus_space_map(ca->ca_iot, ca->ca_hpa + LASI_REG_MISC,
1696d3ceb1dSskrll 			  sizeof(struct lasi_hwr), 0, &ioh)) {
1706d3ceb1dSskrll 		aprint_error(": can't map misc registers\n");
1716d3ceb1dSskrll 		return;
1726d3ceb1dSskrll 	}
1736d3ceb1dSskrll 	sc->sc_hw = (struct lasi_hwr *)ioh;
1746d3ceb1dSskrll 
1756d3ceb1dSskrll 	/* XXX should we reset the chip here? */
1766d3ceb1dSskrll 
1776d3ceb1dSskrll 	aprint_normal(": rev %d.%d\n", (sc->sc_hw->lasi_version & 0xf0) >> 4,
1786d3ceb1dSskrll 		sc->sc_hw->lasi_version & 0xf);
1796d3ceb1dSskrll 
1806d3ceb1dSskrll 	ca->ca_irq = hppa_intr_allocate_bit(&ci->ci_ir, ca->ca_irq);
1816d3ceb1dSskrll 	if (ca->ca_irq == HPPACF_IRQ_UNDEF) {
1826d3ceb1dSskrll 		aprint_error(": can't allocate interrupt\n");
1836d3ceb1dSskrll 		return;
1846d3ceb1dSskrll 	}
1856d3ceb1dSskrll 
1866d3ceb1dSskrll 	/* interrupts guts */
1876d3ceb1dSskrll 	s = splhigh();
1886d3ceb1dSskrll 	sc->sc_trs->lasi_iar = ci->ci_hpa | (31 - ca->ca_irq);
1896d3ceb1dSskrll 	sc->sc_trs->lasi_icr = 0;
1906d3ceb1dSskrll 	sc->sc_trs->lasi_imr = 0;
191fc85ec4fSskrll 	(void)sc->sc_trs->lasi_irr;
1926d3ceb1dSskrll 
1936d3ceb1dSskrll 	/* Establish the interrupt register. */
1946d3ceb1dSskrll 	hppa_interrupt_register_establish(ci, &sc->sc_ir);
1956d3ceb1dSskrll 	sc->sc_ir.ir_name = device_xname(self);
1966d3ceb1dSskrll 	sc->sc_ir.ir_mask = &sc->sc_trs->lasi_imr;
1976d3ceb1dSskrll 	sc->sc_ir.ir_req = &sc->sc_trs->lasi_irr;
1986d3ceb1dSskrll 	splx(s);
1996d3ceb1dSskrll 
2006d3ceb1dSskrll 	/* Attach the GSC bus. */
2016d3ceb1dSskrll 	ga.ga_ca = *ca;	/* clone from us */
2026d3ceb1dSskrll 	if (strcmp(device_xname(parent), "mainbus0") == 0) {
2036d3ceb1dSskrll 		ga.ga_dp.dp_bc[0] = ga.ga_dp.dp_bc[1];
2046d3ceb1dSskrll 		ga.ga_dp.dp_bc[1] = ga.ga_dp.dp_bc[2];
2056d3ceb1dSskrll 		ga.ga_dp.dp_bc[2] = ga.ga_dp.dp_bc[3];
2066d3ceb1dSskrll 		ga.ga_dp.dp_bc[3] = ga.ga_dp.dp_bc[4];
2076d3ceb1dSskrll 		ga.ga_dp.dp_bc[4] = ga.ga_dp.dp_bc[5];
2086d3ceb1dSskrll 		ga.ga_dp.dp_bc[5] = ga.ga_dp.dp_mod;
2096d3ceb1dSskrll 		ga.ga_dp.dp_mod = 0;
2106d3ceb1dSskrll 	}
2116d3ceb1dSskrll 
2126d3ceb1dSskrll 	ga.ga_name = "gsc";
2136d3ceb1dSskrll 	ga.ga_ir = &sc->sc_ir;
2146d3ceb1dSskrll 	ga.ga_fix_args = lasi_fix_args;
2156d3ceb1dSskrll 	ga.ga_fix_args_cookie = sc;
2166d3ceb1dSskrll 	ga.ga_scsi_target = 7; /* XXX */
217*c7fb772bSthorpej 	config_found(self, &ga, gscprint, CFARGS_NONE);
2186d3ceb1dSskrll 
2196d3ceb1dSskrll 	/* could be already set by power(4) */
2206d3ceb1dSskrll 	if (!cold_hook)
2216d3ceb1dSskrll 		cold_hook = lasi_cold_hook;
2226d3ceb1dSskrll }
2236d3ceb1dSskrll 
2246d3ceb1dSskrll void
lasi_cold_hook(int on)2256d3ceb1dSskrll lasi_cold_hook(int on)
2266d3ceb1dSskrll {
2276d3ceb1dSskrll 	struct lasi_softc *sc = device_private(lasi_cd.cd_devs[0]);
2286d3ceb1dSskrll 
2296d3ceb1dSskrll 	if (!sc)
2306d3ceb1dSskrll 		return;
2316d3ceb1dSskrll 
2326d3ceb1dSskrll 	switch (on) {
2336d3ceb1dSskrll 	case HPPA_COLD_COLD:
2346d3ceb1dSskrll 		sc->sc_hw->lasi_power = LASI_BLINK;
2356d3ceb1dSskrll 		break;
2366d3ceb1dSskrll 	case HPPA_COLD_HOT:
2376d3ceb1dSskrll 		sc->sc_hw->lasi_power = 0;
2386d3ceb1dSskrll 		break;
2396d3ceb1dSskrll 	case HPPA_COLD_OFF:
2406d3ceb1dSskrll 		sc->sc_hw->lasi_power = LASI_OFF;
2416d3ceb1dSskrll 		break;
2426d3ceb1dSskrll 	}
2436d3ceb1dSskrll }
244