1139749Simp/*-
256505Speter * Device driver for Specialix range (SI/XIO) of serial line multiplexors.
356505Speter *
456505Speter * Copyright (C) 2000, Peter Wemm <peter@netplex.com.au>
556505Speter *
656505Speter * Redistribution and use in source and binary forms, with or without
756505Speter * modification, are permitted provided that the following conditions
856505Speter * are met:
956505Speter * 1. Redistributions of source code must retain the above copyright
1056505Speter *    notices, this list of conditions and the following disclaimer.
1156505Speter * 2. Redistributions in binary form must reproduce the above copyright
1256505Speter *    notices, this list of conditions and the following disclaimer in the
1356505Speter *    documentation and/or other materials provided with the distribution.
1456505Speter *
1556505Speter * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
1656505Speter * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1756505Speter * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
1856505Speter * NO EVENT SHALL THE AUTHORS BE LIABLE.
1956505Speter *
2056505Speter */
2156505Speter
22119419Sobrien#include <sys/cdefs.h>
23119419Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/si/si_isa.c 335087 2018-06-13 20:33:52Z dim $");
24119419Sobrien
2556505Speter#include "opt_debug_si.h"
2656505Speter
2756505Speter#include <sys/param.h>
2856505Speter#include <sys/systm.h>
2956505Speter#include <sys/kernel.h>
30129879Sphk#include <sys/module.h>
3156505Speter#include <sys/bus.h>
3256505Speter#include <machine/bus.h>
3356505Speter#include <sys/rman.h>
3456505Speter#include <machine/resource.h>
3556505Speter
3656505Speter#include <dev/si/sireg.h>
3756505Speter#include <dev/si/sivar.h>
3856505Speter
3956505Speter#include <isa/isavar.h>
4056505Speter
4156505Speter/* Look for a valid board at the given mem addr */
4256505Speterstatic int
4356505Spetersi_isa_probe(device_t dev)
4456505Speter{
4556505Speter	struct si_softc *sc;
4656505Speter	int type;
4756505Speter	u_int i, ramsize;
4856505Speter	volatile unsigned char was, *ux;
4956505Speter	volatile unsigned char *maddr;
5056505Speter	unsigned char *paddr;
5156505Speter	int unit;
5256505Speter
53100744Speter	/* No pnp support */
54100744Speter	if (isa_get_vendorid(dev))
55100744Speter		return (ENXIO);
56100744Speter
5756505Speter	sc = device_get_softc(dev);
5856505Speter	unit = device_get_unit(dev);
5956505Speter
6056505Speter	sc->sc_mem_rid = 0;
61296137Sjhibbits	sc->sc_mem_res = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY,
62296137Sjhibbits						     &sc->sc_mem_rid,
63296137Sjhibbits						     SIPROBEALLOC, RF_ACTIVE);
64100744Speter	if (!sc->sc_mem_res) {
65100744Speter		device_printf(dev, "cannot allocate memory resource\n");
6656505Speter		return ENXIO;
67100744Speter	}
68335087Sdim	paddr = (caddr_t)(uintptr_t)rman_get_start(sc->sc_mem_res);/* physical */
6956505Speter	maddr = rman_get_virtual(sc->sc_mem_res);	/* in kvm */
7056505Speter
7156505Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
7256505Speter		unit, maddr, paddr));
7356505Speter
7456505Speter	/*
7556505Speter	 * this is a lie, but it's easier than trying to handle caching
7656505Speter	 * and ram conflicts in the >1M and <16M region.
7756505Speter	 */
7856505Speter	if ((caddr_t)paddr < (caddr_t)0xA0000 ||
7956505Speter	    (caddr_t)paddr >= (caddr_t)0x100000) {
80100744Speter		device_printf(dev, "maddr (%p) out of range\n", paddr);
8156505Speter		goto fail;
8256505Speter	}
8356505Speter
84106572Sjhb	if (((uintptr_t)paddr & 0x7fff) != 0) {
85100744Speter		device_printf(dev, "maddr (%p) not on 32k boundary\n", paddr);
8656505Speter		goto fail;
8756505Speter	}
8856505Speter
8956505Speter	/* Is there anything out there? (0x17 is just an arbitrary number) */
9056505Speter	*maddr = 0x17;
9156505Speter	if (*maddr != 0x17) {
92100744Speter		device_printf(dev, "0x17 check fail at phys %p\n", paddr);
9356505Speter		goto fail;
9456505Speter	}
9556505Speter	/*
9656505Speter	 * Let's look first for a JET ISA card, since that's pretty easy
9756505Speter	 *
9856505Speter	 * All jet hosts are supposed to have this string in the IDROM,
9956505Speter	 * but it's not worth checking on self-IDing busses like PCI.
10056505Speter	 */
10156505Speter	{
10256505Speter		unsigned char *jet_chk_str = "JET HOST BY KEV#";
10356505Speter
10456505Speter		for (i = 0; i < strlen(jet_chk_str); i++)
10556505Speter			if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i))
10656505Speter				goto try_mk2;
10756505Speter	}
10856505Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET first check - 0x%x\n",
10956505Speter		unit, (*(maddr+SIJETIDBASE))));
11056505Speter	if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff))
11156505Speter		goto try_mk2;
11256505Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET second check - 0x%x\n",
11356505Speter		unit, (*(maddr+SIJETIDBASE+2))));
11456505Speter	if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8))
11556505Speter		goto try_mk2;
11656505Speter	/* It must be a Jet ISA or RIO card */
11756505Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET id check - 0x%x\n",
11856505Speter		unit, (*(maddr+SIUNIQID))));
11956505Speter	if ((*(maddr+SIUNIQID) & 0xf0) != 0x20)
12056505Speter		goto try_mk2;
12156505Speter	/* It must be a Jet ISA SI/XIO card */
12256505Speter	*(maddr + SIJETCONFIG) = 0;
12356505Speter	type = SIJETISA;
12456505Speter	ramsize = SIJET_RAMSIZE;
12556505Speter	goto got_card;
12656505Speter
12756505Spetertry_mk2:
12856505Speter	/*
12956505Speter	 * OK, now to see if whatever responded is really an SI card.
13056505Speter	 * Try for a MK II next (SIHOST2)
13156505Speter	 */
13256505Speter	for (i = SIPLSIG; i < SIPLSIG + 8; i++)
13356505Speter		if ((*(maddr+i) & 7) != (~(unsigned char)i & 7))
13456505Speter			goto try_mk1;
13556505Speter
13656505Speter	/* It must be an SIHOST2 */
13756505Speter	*(maddr + SIPLRESET) = 0;
13856505Speter	*(maddr + SIPLIRQCLR) = 0;
13956505Speter	*(maddr + SIPLIRQSET) = 0x10;
14056505Speter	type = SIHOST2;
14156505Speter	ramsize = SIHOST2_RAMSIZE;
14256505Speter	goto got_card;
14356505Speter
14456505Spetertry_mk1:
14556505Speter	/*
14656505Speter	 * Its not a MK II, so try for a MK I (SIHOST)
14756505Speter	 */
14856505Speter	*(maddr+SIRESET) = 0x0;		/* reset the card */
14956505Speter	*(maddr+SIINTCL) = 0x0;		/* clear int */
15056505Speter	*(maddr+SIRAM) = 0x17;
15156505Speter	if (*(maddr+SIRAM) != (unsigned char)0x17)
15256505Speter		goto fail;
15356505Speter	*(maddr+0x7ff8) = 0x17;
15456505Speter	if (*(maddr+0x7ff8) != (unsigned char)0x17) {
155100744Speter		device_printf(dev, "0x17 check fail at phys %p = 0x%x\n",
156100744Speter		    paddr+0x77f8, *(maddr+0x77f8));
15756505Speter		goto fail;
15856505Speter	}
15956505Speter
16056505Speter	/* It must be an SIHOST (maybe?) - there must be a better way XXX */
16156505Speter	type = SIHOST;
16256505Speter	ramsize = SIHOST_RAMSIZE;
16356505Speter
16456505Spetergot_card:
16556505Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
16656505Speter		unit, type));
16756505Speter	/* Try the acid test */
16856505Speter	ux = maddr + SIRAM;
16956505Speter	for (i = 0; i < ramsize; i++, ux++)
17056505Speter		*ux = (unsigned char)(i&0xff);
17156505Speter	ux = maddr + SIRAM;
17256505Speter	for (i = 0; i < ramsize; i++, ux++) {
17356505Speter		if ((was = *ux) != (unsigned char)(i&0xff)) {
174100744Speter			device_printf(dev,
175100744Speter			    "memtest fail at phys %p, was %x should be %x\n",
176100744Speter			    paddr + i, was, i & 0xff);
17756505Speter			goto fail;
17856505Speter		}
17956505Speter	}
18056505Speter
18156505Speter	/* clear out the RAM */
18256505Speter	ux = maddr + SIRAM;
18356505Speter	for (i = 0; i < ramsize; i++)
18456505Speter		*ux++ = 0;
18556505Speter	ux = maddr + SIRAM;
18656505Speter	for (i = 0; i < ramsize; i++) {
18756505Speter		if ((was = *ux++) != 0) {
188100744Speter			device_printf(dev, "clear fail at phys %p, was %x\n",
189100744Speter			    paddr + i, was);
19056505Speter			goto fail;
19156505Speter		}
19256505Speter	}
19356505Speter
19456505Speter	/*
19556505Speter	 * Success, we've found a valid board, now fill in
19656505Speter	 * the adapter structure.
19756505Speter	 */
19856505Speter	switch (type) {
19956505Speter	case SIHOST2:
20056505Speter		switch (isa_get_irq(dev)) {
20156505Speter		case 11:
20256505Speter		case 12:
20356505Speter		case 15:
20456505Speter			break;
20556505Speter		default:
206100744Speter			device_printf(dev,
207100744Speter			    "bad IRQ value - %d (11, 12, 15 allowed)\n",
208100744Speter			    isa_get_irq(dev));
20956505Speter			goto fail;
21056505Speter		}
21156505Speter		sc->sc_memsize = SIHOST2_MEMSIZE;
21256505Speter		break;
21356505Speter	case SIHOST:
21456505Speter		switch (isa_get_irq(dev)) {
21556505Speter		case 11:
21656505Speter		case 12:
21756505Speter		case 15:
21856505Speter			break;
21956505Speter		default:
220100744Speter			device_printf(dev,
221100744Speter			    "bad IRQ value - %d (11, 12, 15 allowed)\n",
222100744Speter			    isa_get_irq(dev));
223100744Speter			goto fail;
22456505Speter		}
22556505Speter		sc->sc_memsize = SIHOST_MEMSIZE;
22656505Speter		break;
22756505Speter	case SIJETISA:
22856505Speter		switch (isa_get_irq(dev)) {
22956505Speter		case 9:
23056505Speter		case 10:
23156505Speter		case 11:
23256505Speter		case 12:
23356505Speter		case 15:
23456505Speter			break;
23556505Speter		default:
236100744Speter			device_printf(dev,
237100744Speter			    "bad IRQ value - %d (9, 10, 11, 12, 15 allowed)\n",
238100744Speter			    isa_get_irq(dev));
239100744Speter			goto fail;
24056505Speter		}
24156505Speter		sc->sc_memsize = SIJETISA_MEMSIZE;
24256505Speter		break;
24356505Speter	case SIMCA:		/* MCA */
24456505Speter	default:
245100744Speter		device_printf(dev, "card type %d not supported\n", type);
24656505Speter		goto fail;
24756505Speter	}
24856505Speter	sc->sc_type = type;
24956505Speter	bus_release_resource(dev, SYS_RES_MEMORY,
25056505Speter			     sc->sc_mem_rid, sc->sc_mem_res);
25156505Speter	sc->sc_mem_res = 0;
25256505Speter	return (0);		/* success! */
25356505Speter
25456505Speterfail:
25556505Speter	if (sc->sc_mem_res) {
25656505Speter		bus_release_resource(dev, SYS_RES_MEMORY,
25756505Speter				     sc->sc_mem_rid, sc->sc_mem_res);
25856505Speter		sc->sc_mem_res = 0;
25956505Speter	}
26056505Speter	return(EINVAL);
26156505Speter}
26256505Speter
26356505Speterstatic int
26456505Spetersi_isa_attach(device_t dev)
26556505Speter{
26656505Speter	int error;
26756505Speter	void *ih;
26856505Speter	struct si_softc *sc;
26956505Speter
27056505Speter	error = 0;
27156505Speter	ih = NULL;
27256505Speter	sc = device_get_softc(dev);
27356505Speter
27456505Speter	sc->sc_mem_rid = 0;
275127135Snjl	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
276127135Snjl						&sc->sc_mem_rid,
277127135Snjl						RF_ACTIVE);
27856505Speter	if (!sc->sc_mem_res) {
27956505Speter		device_printf(dev, "couldn't map memory\n");
28056505Speter		goto fail;
28156505Speter	}
282335087Sdim	sc->sc_paddr = (caddr_t)(uintptr_t)rman_get_start(sc->sc_mem_res);
28356505Speter	sc->sc_maddr = rman_get_virtual(sc->sc_mem_res);
28456505Speter
28556505Speter	sc->sc_irq_rid = 0;
286127135Snjl	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
287127135Snjl						&sc->sc_irq_rid,
288127135Snjl						RF_ACTIVE | RF_SHAREABLE);
28956505Speter	if (!sc->sc_irq_res) {
29056505Speter		device_printf(dev, "couldn't allocate interrupt\n");
29156505Speter		goto fail;
29256505Speter	}
29356505Speter	sc->sc_irq = rman_get_start(sc->sc_irq_res);
29456505Speter	error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_TTY,
295166914Simp			       NULL, si_intr, sc, &ih);
29656505Speter	if (error) {
29756505Speter		device_printf(dev, "couldn't activate interrupt\n");
29856505Speter		goto fail;
29956505Speter	}
30056505Speter
30156505Speter	error = siattach(dev);
30256505Speter	if (error)
30356505Speter		goto fail;
30456505Speter	return (0);		/* success */
30556505Speter
30656505Speterfail:
30756505Speter	if (error == 0)
30856505Speter		error = ENXIO;
30956505Speter	if (sc->sc_irq_res) {
31056505Speter		if (ih)
31156505Speter			bus_teardown_intr(dev, sc->sc_irq_res, ih);
31256505Speter		bus_release_resource(dev, SYS_RES_IRQ,
31356505Speter				     sc->sc_irq_rid, sc->sc_irq_res);
31456505Speter		sc->sc_irq_res = 0;
31556505Speter	}
31656505Speter	if (sc->sc_mem_res) {
31756505Speter		bus_release_resource(dev, SYS_RES_MEMORY,
31856505Speter				     sc->sc_mem_rid, sc->sc_mem_res);
31956505Speter		sc->sc_mem_res = 0;
32056505Speter	}
32156505Speter	return (error);
32256505Speter}
32356505Speter
32456505Speterstatic device_method_t si_isa_methods[] = {
32556505Speter	/* Device interface */
32656505Speter	DEVMETHOD(device_probe,		si_isa_probe),
32756505Speter	DEVMETHOD(device_attach,	si_isa_attach),
32856505Speter
32956505Speter	{ 0, 0 }
33056505Speter};
33156505Speter
33256505Speterstatic driver_t si_isa_driver = {
33356505Speter	"si",
33456505Speter	si_isa_methods,
33556505Speter	sizeof(struct si_softc),
33656505Speter};
33756505Speter
33856505SpeterDRIVER_MODULE(si, isa, si_isa_driver, si_devclass, 0, 0);
339