1*e5fbc36aSthorpej /* $NetBSD: mace.c,v 1.27 2023/12/20 15:29:07 thorpej Exp $ */
263b59c4dSsekiya
363b59c4dSsekiya /*
463b59c4dSsekiya * Copyright (c) 2003 Christopher Sekiya
563b59c4dSsekiya * Copyright (c) 2002,2003 Rafal K. Boni
663b59c4dSsekiya * Copyright (c) 2000 Soren S. Jorvang
763b59c4dSsekiya * All rights reserved.
863b59c4dSsekiya *
963b59c4dSsekiya * Redistribution and use in source and binary forms, with or without
1063b59c4dSsekiya * modification, are permitted provided that the following conditions
1163b59c4dSsekiya * are met:
1263b59c4dSsekiya * 1. Redistributions of source code must retain the above copyright
1363b59c4dSsekiya * notice, this list of conditions and the following disclaimer.
1463b59c4dSsekiya * 2. Redistributions in binary form must reproduce the above copyright
1563b59c4dSsekiya * notice, this list of conditions and the following disclaimer in the
1663b59c4dSsekiya * documentation and/or other materials provided with the distribution.
1763b59c4dSsekiya * 3. All advertising materials mentioning features or use of this software
1863b59c4dSsekiya * must display the following acknowledgement:
1963b59c4dSsekiya * This product includes software developed for the
2063b59c4dSsekiya * NetBSD Project. See http://www.NetBSD.org/ for
2163b59c4dSsekiya * information about NetBSD.
2263b59c4dSsekiya * 4. The name of the author may not be used to endorse or promote products
2363b59c4dSsekiya * derived from this software without specific prior written permission.
2463b59c4dSsekiya *
2563b59c4dSsekiya * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2663b59c4dSsekiya * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2763b59c4dSsekiya * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2863b59c4dSsekiya * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2963b59c4dSsekiya * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3063b59c4dSsekiya * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3163b59c4dSsekiya * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3263b59c4dSsekiya * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3363b59c4dSsekiya * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3463b59c4dSsekiya * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3563b59c4dSsekiya */
3663b59c4dSsekiya
3763b59c4dSsekiya /*
3863b59c4dSsekiya * O2 MACE
3963b59c4dSsekiya *
4063b59c4dSsekiya * The MACE is weird -- although it is a 32-bit device, writes only seem to
4163b59c4dSsekiya * work properly if they are 64-bit-at-once writes (at least, out in ISA
4263b59c4dSsekiya * space and probably MEC space -- the PCI stuff seems to be okay with _4).
4363b59c4dSsekiya * Therefore, the _8* routines are used even though the top 32 bits are
4463b59c4dSsekiya * thrown away.
4563b59c4dSsekiya */
4663b59c4dSsekiya
4763b59c4dSsekiya #include <sys/cdefs.h>
48*e5fbc36aSthorpej __KERNEL_RCSID(0, "$NetBSD: mace.c,v 1.27 2023/12/20 15:29:07 thorpej Exp $");
4963b59c4dSsekiya
5063b59c4dSsekiya #include <sys/param.h>
5163b59c4dSsekiya #include <sys/systm.h>
5263b59c4dSsekiya #include <sys/device.h>
5363b59c4dSsekiya #include <sys/callout.h>
5463b59c4dSsekiya #include <sys/mbuf.h>
5563b59c4dSsekiya #include <sys/kernel.h>
5663b59c4dSsekiya #include <sys/socket.h>
5763b59c4dSsekiya #include <sys/ioctl.h>
5863b59c4dSsekiya #include <sys/errno.h>
5963b59c4dSsekiya #include <sys/syslog.h>
6063b59c4dSsekiya
6163b59c4dSsekiya #include <uvm/uvm_extern.h>
6263b59c4dSsekiya
63cf10107dSdyoung #include <sys/bus.h>
6463b59c4dSsekiya #include <machine/cpu.h>
6563b59c4dSsekiya #include <machine/locore.h>
6663b59c4dSsekiya #include <machine/autoconf.h>
6763b59c4dSsekiya #include <machine/machtype.h>
6863b59c4dSsekiya
6963b59c4dSsekiya #include <sgimips/mace/macevar.h>
7063b59c4dSsekiya #include <sgimips/mace/macereg.h>
7163b59c4dSsekiya #include <sgimips/dev/crimevar.h>
7263b59c4dSsekiya #include <sgimips/dev/crimereg.h>
7363b59c4dSsekiya
7463b59c4dSsekiya #include "locators.h"
7563b59c4dSsekiya
7663b59c4dSsekiya #define MACE_NINTR 32 /* actually only 8, but interrupts are shared */
7763b59c4dSsekiya
7863b59c4dSsekiya struct {
7963b59c4dSsekiya unsigned int irq;
8063b59c4dSsekiya unsigned int intrmask;
8163b59c4dSsekiya int (*func)(void *);
8263b59c4dSsekiya void *arg;
8343f42bdbStsutsui struct evcnt evcnt;
8443f42bdbStsutsui char evname[32];
8563b59c4dSsekiya } maceintrtab[MACE_NINTR];
8663b59c4dSsekiya
8763b59c4dSsekiya struct mace_softc {
88f0b7a070Smacallan device_t sc_dev;
8963b59c4dSsekiya
9063b59c4dSsekiya bus_space_tag_t iot;
9163b59c4dSsekiya bus_space_handle_t ioh;
9263b59c4dSsekiya bus_dma_tag_t dmat; /* 32KB ring buffers, 4KB segments, for ISA */
9363b59c4dSsekiya int nsegs;
9463b59c4dSsekiya bus_dma_segment_t seg;
9563b59c4dSsekiya bus_dmamap_t map;
9663b59c4dSsekiya
9763b59c4dSsekiya void *isa_ringbuffer;
9863b59c4dSsekiya };
9963b59c4dSsekiya
100cbab9cadSchs static int mace_match(device_t, cfdata_t, void *);
101cbab9cadSchs static void mace_attach(device_t, device_t, void *);
10263b59c4dSsekiya static int mace_print(void *, const char *);
103cbab9cadSchs static int mace_search(device_t, cfdata_t, const int *, void *);
10463b59c4dSsekiya
105f0b7a070Smacallan CFATTACH_DECL_NEW(mace, sizeof(struct mace_softc),
10663b59c4dSsekiya mace_match, mace_attach, NULL, NULL);
10763b59c4dSsekiya
108eb488f67Smacallan static void mace_isa_bus_mem_init(bus_space_tag_t, void *);
109eb488f67Smacallan
110eb488f67Smacallan static struct mips_bus_space mace_isa_mbst;
111eb488f67Smacallan bus_space_tag_t mace_isa_memt = NULL;
112eb488f67Smacallan static int mace_isa_init = 0;
113eb488f67Smacallan
11463b59c4dSsekiya #if defined(BLINK)
11588ab7da9Sad static callout_t mace_blink_ch;
11663b59c4dSsekiya static void mace_blink(void *);
11763b59c4dSsekiya #endif
11863b59c4dSsekiya
11963b59c4dSsekiya static int
mace_match(device_t parent,struct cfdata * match,void * aux)120f0b7a070Smacallan mace_match(device_t parent, struct cfdata *match, void *aux)
12163b59c4dSsekiya {
12263b59c4dSsekiya
12363b59c4dSsekiya /*
12463b59c4dSsekiya * The MACE is in the O2.
12563b59c4dSsekiya */
12663b59c4dSsekiya if (mach_type == MACH_SGI_IP32)
1271db87857Stsutsui return 1;
12863b59c4dSsekiya
1291db87857Stsutsui return 0;
13063b59c4dSsekiya }
13163b59c4dSsekiya
132eb488f67Smacallan void
mace_init_bus(void)133eb488f67Smacallan mace_init_bus(void)
134eb488f67Smacallan {
135eb488f67Smacallan if (mace_isa_init == 1)
136eb488f67Smacallan return;
137eb488f67Smacallan mace_isa_init = 1;
138eb488f67Smacallan mace_isa_bus_mem_init(&mace_isa_mbst, NULL);
139eb488f67Smacallan mace_isa_memt = &mace_isa_mbst;
140eb488f67Smacallan }
141eb488f67Smacallan
14263b59c4dSsekiya static void
mace_attach(device_t parent,device_t self,void * aux)143f0b7a070Smacallan mace_attach(device_t parent, device_t self, void *aux)
14463b59c4dSsekiya {
145f0b7a070Smacallan struct mace_softc *sc = device_private(self);
14663b59c4dSsekiya struct mainbus_attach_args *ma = aux;
1471db87857Stsutsui uint32_t scratch;
14863b59c4dSsekiya
149f0b7a070Smacallan sc->sc_dev = self;
15088ab7da9Sad #ifdef BLINK
15188ab7da9Sad callout_init(&mace_blink_ch, 0);
15288ab7da9Sad #endif
15388ab7da9Sad
154eb488f67Smacallan sc->iot = normal_memt; /* for mace registers */
15563b59c4dSsekiya sc->dmat = &sgimips_default_bus_dma_tag;
15663b59c4dSsekiya
15763b59c4dSsekiya if (bus_space_map(sc->iot, ma->ma_addr, 0,
15863b59c4dSsekiya BUS_SPACE_MAP_LINEAR, &sc->ioh))
15963b59c4dSsekiya panic("mace_attach: could not allocate memory\n");
16063b59c4dSsekiya
16163b59c4dSsekiya aprint_normal("\n");
16263b59c4dSsekiya
163cbab9cadSchs aprint_debug("%s: isa sts %#"PRIx64"\n", device_xname(self),
16463b59c4dSsekiya bus_space_read_8(sc->iot, sc->ioh, MACE_ISA_INT_STATUS));
165cbab9cadSchs aprint_debug("%s: isa msk %#"PRIx64"\n", device_xname(self),
16663b59c4dSsekiya bus_space_read_8(sc->iot, sc->ioh, MACE_ISA_INT_MASK));
16763b59c4dSsekiya
168eb488f67Smacallan mace_init_bus();
169eb488f67Smacallan
17063b59c4dSsekiya /*
171dd9aa161Sjmcneill * Turn on most ISA interrupts. These are actually masked and
17263b59c4dSsekiya * registered via the CRIME, as the MACE ISA interrupt mask is
17363b59c4dSsekiya * really whacky and nigh on impossible to map to a sane autoconfig
174ed55554cSjmcneill * scheme. We do, however, turn off the count/compare timer and RTC
175dd9aa161Sjmcneill * interrupts as they are unused and conflict with the PS/2
176dd9aa161Sjmcneill * keyboard and mouse interrupts.
17763b59c4dSsekiya */
17863b59c4dSsekiya
179ed55554cSjmcneill bus_space_write_8(sc->iot, sc->ioh, MACE_ISA_INT_MASK, 0xffff0aff);
18063b59c4dSsekiya bus_space_write_8(sc->iot, sc->ioh, MACE_ISA_INT_STATUS, 0);
18163b59c4dSsekiya
18263b59c4dSsekiya /* set up LED for solid green or blink, if that's your fancy */
18363b59c4dSsekiya scratch = bus_space_read_8(sc->iot, sc->ioh, MACE_ISA_FLASH_NIC_REG);
18463b59c4dSsekiya scratch |= MACE_ISA_LED_RED;
18563b59c4dSsekiya scratch &= ~(MACE_ISA_LED_GREEN);
18663b59c4dSsekiya bus_space_write_8(sc->iot, sc->ioh, MACE_ISA_FLASH_NIC_REG, scratch);
18763b59c4dSsekiya
18863b59c4dSsekiya #if defined(BLINK)
18963b59c4dSsekiya mace_blink(sc);
19063b59c4dSsekiya #endif
19163b59c4dSsekiya
19263b59c4dSsekiya /* Initialize the maceintr elements to sane values */
19363b59c4dSsekiya for (scratch = 0; scratch < MACE_NINTR; scratch++) {
19463b59c4dSsekiya maceintrtab[scratch].func = NULL;
19563b59c4dSsekiya maceintrtab[scratch].irq = 0;
19663b59c4dSsekiya }
19763b59c4dSsekiya
1982685996bSthorpej config_search(self, NULL,
199c7fb772bSthorpej CFARGS(.search = mace_search));
20063b59c4dSsekiya }
20163b59c4dSsekiya
20263b59c4dSsekiya
20363b59c4dSsekiya static int
mace_print(void * aux,const char * pnp)20463b59c4dSsekiya mace_print(void *aux, const char *pnp)
20563b59c4dSsekiya {
20663b59c4dSsekiya struct mace_attach_args *maa = aux;
20763b59c4dSsekiya
20863b59c4dSsekiya if (pnp != 0)
20963b59c4dSsekiya return QUIET;
21063b59c4dSsekiya
21163b59c4dSsekiya if (maa->maa_offset != MACECF_OFFSET_DEFAULT)
21263b59c4dSsekiya aprint_normal(" offset 0x%lx", maa->maa_offset);
21363b59c4dSsekiya if (maa->maa_intr != MACECF_INTR_DEFAULT)
21463b59c4dSsekiya aprint_normal(" intr %d", maa->maa_intr);
21563b59c4dSsekiya if (maa->maa_offset != MACECF_INTRMASK_DEFAULT)
21663b59c4dSsekiya aprint_normal(" intrmask 0x%x", maa->maa_intrmask);
21763b59c4dSsekiya
21863b59c4dSsekiya return UNCONF;
21963b59c4dSsekiya }
22063b59c4dSsekiya
22163b59c4dSsekiya static int
mace_search(device_t parent,struct cfdata * cf,const int * ldesc,void * aux)222cbab9cadSchs mace_search(device_t parent, struct cfdata *cf, const int *ldesc, void *aux)
22363b59c4dSsekiya {
224f0b7a070Smacallan struct mace_softc *sc = device_private(parent);
22563b59c4dSsekiya struct mace_attach_args maa;
22663b59c4dSsekiya int tryagain;
22763b59c4dSsekiya
22863b59c4dSsekiya do {
22963b59c4dSsekiya maa.maa_offset = cf->cf_loc[MACECF_OFFSET];
23063b59c4dSsekiya maa.maa_intr = cf->cf_loc[MACECF_INTR];
23163b59c4dSsekiya maa.maa_intrmask = cf->cf_loc[MACECF_INTRMASK];
232eb488f67Smacallan maa.maa_st = normal_memt;
23363b59c4dSsekiya maa.maa_sh = sc->ioh; /* XXX */
23463b59c4dSsekiya maa.maa_dmat = &sgimips_default_bus_dma_tag;
23563b59c4dSsekiya maa.isa_ringbuffer = sc->isa_ringbuffer;
23663b59c4dSsekiya
23763b59c4dSsekiya tryagain = 0;
2382685996bSthorpej if (config_probe(parent, cf, &maa)) {
239c7fb772bSthorpej config_attach(parent, cf, &maa, mace_print, CFARGS_NONE);
24063b59c4dSsekiya tryagain = (cf->cf_fstate == FSTATE_STAR);
24163b59c4dSsekiya }
24263b59c4dSsekiya
24363b59c4dSsekiya } while (tryagain);
24463b59c4dSsekiya
24563b59c4dSsekiya return 0;
24663b59c4dSsekiya }
24763b59c4dSsekiya
24863b59c4dSsekiya void *
mace_intr_establish(int intr,int level,int (* func)(void *),void * arg)24963b59c4dSsekiya mace_intr_establish(int intr, int level, int (*func)(void *), void *arg)
25063b59c4dSsekiya {
25163b59c4dSsekiya int i;
25263b59c4dSsekiya
2538590eac4Ssekiya if (intr < 0 || intr >= 16)
25463b59c4dSsekiya panic("invalid interrupt number");
25563b59c4dSsekiya
25663b59c4dSsekiya for (i = 0; i < MACE_NINTR; i++)
2570d31ac44Stsutsui if (maceintrtab[i].func == NULL) {
2580d31ac44Stsutsui maceintrtab[i].func = func;
2590d31ac44Stsutsui maceintrtab[i].arg = arg;
2600d31ac44Stsutsui maceintrtab[i].irq = (1 << intr);
2610d31ac44Stsutsui maceintrtab[i].intrmask = level;
26243f42bdbStsutsui snprintf(maceintrtab[i].evname,
26343f42bdbStsutsui sizeof(maceintrtab[i].evname),
26465162b9fSmacallan "intr %d lv 0x%x", intr, level);
26543f42bdbStsutsui evcnt_attach_dynamic(&maceintrtab[i].evcnt,
26643f42bdbStsutsui EVCNT_TYPE_INTR, NULL,
26743f42bdbStsutsui "mace", maceintrtab[i].evname);
26863b59c4dSsekiya break;
26963b59c4dSsekiya }
27063b59c4dSsekiya
27163b59c4dSsekiya crime_intr_mask(intr);
272ca2b1874Stsutsui aprint_debug("mace: established interrupt %d (level %x)\n",
27363b59c4dSsekiya intr, level);
2740d31ac44Stsutsui return (void *)&maceintrtab[i];
27563b59c4dSsekiya }
27663b59c4dSsekiya
27763b59c4dSsekiya void
mace_intr_disestablish(void * cookie)2788590eac4Ssekiya mace_intr_disestablish(void *cookie)
2798590eac4Ssekiya {
2808590eac4Ssekiya int intr = -1, level = 0, irq = 0, i;
2818590eac4Ssekiya
2828590eac4Ssekiya for (i = 0; i < MACE_NINTR; i++)
2838590eac4Ssekiya if (&maceintrtab[i] == cookie) {
2848590eac4Ssekiya evcnt_detach(&maceintrtab[i].evcnt);
2858590eac4Ssekiya for (intr = 0;
2868590eac4Ssekiya maceintrtab[i].irq == (1 << intr); intr++);
2878590eac4Ssekiya level = maceintrtab[i].intrmask;
2888590eac4Ssekiya irq = maceintrtab[i].irq;
2898590eac4Ssekiya
2908590eac4Ssekiya maceintrtab[i].irq = 0;
2918590eac4Ssekiya maceintrtab[i].intrmask = 0;
2928590eac4Ssekiya maceintrtab[i].func = NULL;
2938590eac4Ssekiya maceintrtab[i].arg = NULL;
2941db87857Stsutsui memset(&maceintrtab[i].evcnt, 0, sizeof (struct evcnt));
2951db87857Stsutsui memset(&maceintrtab[i].evname, 0,
2968590eac4Ssekiya sizeof (maceintrtab[i].evname));
2978590eac4Ssekiya break;
2988590eac4Ssekiya }
2998590eac4Ssekiya if (intr == -1)
3008590eac4Ssekiya panic("mace: lost maceintrtab");
3018590eac4Ssekiya
3021ca33155Ssekiya /* do not do an unmask when irq is shared. */
3038590eac4Ssekiya for (i = 0; i < MACE_NINTR; i++)
304983534e9Smrg if (maceintrtab[i].func != NULL && maceintrtab[i].irq == irq)
3058590eac4Ssekiya break;
3068590eac4Ssekiya if (i == MACE_NINTR)
3078590eac4Ssekiya crime_intr_unmask(intr);
308ca2b1874Stsutsui aprint_debug("mace: disestablished interrupt %d (level %x)\n",
3098590eac4Ssekiya intr, level);
3108590eac4Ssekiya }
3118590eac4Ssekiya
3128590eac4Ssekiya void
mace_intr(int irqs)31363b59c4dSsekiya mace_intr(int irqs)
31463b59c4dSsekiya {
315d07fd968Smrg uint64_t isa_irq;
31663b59c4dSsekiya int i;
31763b59c4dSsekiya
31863b59c4dSsekiya /* irq 4 is the ISA cascade interrupt. Must handle with care. */
31963b59c4dSsekiya if (irqs & (1 << 4)) {
320bfeedbc2Smacallan isa_irq = mips3_ld(MIPS_PHYS_TO_KSEG1(MACE_BASE
32163b59c4dSsekiya + MACE_ISA_INT_STATUS));
32263b59c4dSsekiya for (i = 0; i < MACE_NINTR; i++) {
32363b59c4dSsekiya if ((maceintrtab[i].irq == (1 << 4)) &&
32463b59c4dSsekiya (isa_irq & maceintrtab[i].intrmask)) {
32563b59c4dSsekiya (maceintrtab[i].func)(maceintrtab[i].arg);
32643f42bdbStsutsui maceintrtab[i].evcnt.ev_count++;
32763b59c4dSsekiya }
32863b59c4dSsekiya }
32963b59c4dSsekiya irqs &= ~(1 << 4);
33063b59c4dSsekiya }
33163b59c4dSsekiya
33263b59c4dSsekiya for (i = 0; i < MACE_NINTR; i++)
33343f42bdbStsutsui if ((irqs & maceintrtab[i].irq)) {
33463b59c4dSsekiya (maceintrtab[i].func)(maceintrtab[i].arg);
33543f42bdbStsutsui maceintrtab[i].evcnt.ev_count++;
33643f42bdbStsutsui }
33763b59c4dSsekiya }
33863b59c4dSsekiya
33963b59c4dSsekiya #if defined(BLINK)
34063b59c4dSsekiya static void
mace_blink(void * self)34163b59c4dSsekiya mace_blink(void *self)
34263b59c4dSsekiya {
343cbab9cadSchs struct mace_softc *sc = device_private(self);
34463b59c4dSsekiya register int s;
34563b59c4dSsekiya int value;
34663b59c4dSsekiya
34763b59c4dSsekiya s = splhigh();
34863b59c4dSsekiya value = bus_space_read_8(sc->iot, sc->ioh, MACE_ISA_FLASH_NIC_REG);
34963b59c4dSsekiya value ^= MACE_ISA_LED_GREEN;
35063b59c4dSsekiya bus_space_write_8(sc->iot, sc->ioh, MACE_ISA_FLASH_NIC_REG, value);
35163b59c4dSsekiya splx(s);
35263b59c4dSsekiya /*
35363b59c4dSsekiya * Blink rate is:
35463b59c4dSsekiya * full cycle every second if completely idle (loadav = 0)
35563b59c4dSsekiya * full cycle every 2 seconds if loadav = 1
35663b59c4dSsekiya * full cycle every 3 seconds if loadav = 2
35763b59c4dSsekiya * etc.
35863b59c4dSsekiya */
35963b59c4dSsekiya s = (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1));
36063b59c4dSsekiya callout_reset(&mace_blink_ch, s, mace_blink, sc);
36163b59c4dSsekiya
36263b59c4dSsekiya }
36363b59c4dSsekiya #endif
364eb488f67Smacallan
365eb488f67Smacallan #define CHIP mace_isa
366eb488f67Smacallan #define CHIP_MEM /* defined */
367eb488f67Smacallan #define CHIP_ALIGN_STRIDE 8
368eb488f67Smacallan #define CHIP_ACCESS_SIZE 8
369eb488f67Smacallan #define CHIP_W1_BUS_START(v) 0x00000000UL
370eb488f67Smacallan #define CHIP_W1_BUS_END(v) 0xffffffffUL
371eb488f67Smacallan #define CHIP_W1_SYS_START(v) 0x00000000UL
372eb488f67Smacallan #define CHIP_W1_SYS_END(v) 0xffffffffUL
373eb488f67Smacallan
374eb488f67Smacallan #include <mips/mips/bus_space_alignstride_chipdep.c>
375