1*3944ff70Sthorpej /* $NetBSD: fhc.c,v 1.11 2022/01/22 11:49:17 thorpej Exp $ */
239a57b1cSmrg /* $OpenBSD: fhc.c,v 1.17 2010/11/11 17:58:23 miod Exp $ */
339a57b1cSmrg
439a57b1cSmrg /*
539a57b1cSmrg * Copyright (c) 2004 Jason L. Wright (jason@thought.net)
639a57b1cSmrg * All rights reserved.
739a57b1cSmrg *
839a57b1cSmrg * Redistribution and use in source and binary forms, with or without
939a57b1cSmrg * modification, are permitted provided that the following conditions
1039a57b1cSmrg * are met:
1139a57b1cSmrg * 1. Redistributions of source code must retain the above copyright
1239a57b1cSmrg * notice, this list of conditions and the following disclaimer.
1339a57b1cSmrg * 2. Redistributions in binary form must reproduce the above copyright
1439a57b1cSmrg * notice, this list of conditions and the following disclaimer in the
1539a57b1cSmrg * documentation and/or other materials provided with the distribution.
1639a57b1cSmrg *
1739a57b1cSmrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1839a57b1cSmrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1939a57b1cSmrg * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2039a57b1cSmrg * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2139a57b1cSmrg * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2239a57b1cSmrg * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2339a57b1cSmrg * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2439a57b1cSmrg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2539a57b1cSmrg * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2639a57b1cSmrg * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2739a57b1cSmrg * POSSIBILITY OF SUCH DAMAGE.
2839a57b1cSmrg */
2939a57b1cSmrg
30f72d1cdaSmrg #include <sys/cdefs.h>
31*3944ff70Sthorpej __KERNEL_RCSID(0, "$NetBSD: fhc.c,v 1.11 2022/01/22 11:49:17 thorpej Exp $");
32f72d1cdaSmrg
3339a57b1cSmrg #include <sys/types.h>
3439a57b1cSmrg #include <sys/param.h>
3539a57b1cSmrg #include <sys/systm.h>
3639a57b1cSmrg #include <sys/kernel.h>
3739a57b1cSmrg #include <sys/device.h>
3839a57b1cSmrg #include <sys/conf.h>
3939a57b1cSmrg #include <sys/malloc.h>
40fc256c4aSthorpej #include <sys/kmem.h>
4139a57b1cSmrg #include <sys/bus.h>
4239a57b1cSmrg
4339a57b1cSmrg #include <machine/autoconf.h>
4439a57b1cSmrg #include <machine/openfirm.h>
4539a57b1cSmrg
4639a57b1cSmrg #include <sparc64/dev/fhcreg.h>
4739a57b1cSmrg #include <sparc64/dev/fhcvar.h>
4839a57b1cSmrg #include <sparc64/dev/iommureg.h>
4939a57b1cSmrg
5039a57b1cSmrg int fhc_print(void *, const char *);
5139a57b1cSmrg
5239a57b1cSmrg bus_space_tag_t fhc_alloc_bus_tag(struct fhc_softc *);
5339a57b1cSmrg int _fhc_bus_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, vaddr_t,
5439a57b1cSmrg bus_space_handle_t *);
5539a57b1cSmrg void *fhc_intr_establish(bus_space_tag_t, int, int,
5639a57b1cSmrg int (*)(void *), void *, void (*)(void));
5739a57b1cSmrg bus_space_handle_t *fhc_find_intr_handle(struct fhc_softc *, int);
5839a57b1cSmrg
5939a57b1cSmrg void
fhc_attach(struct fhc_softc * sc)6039a57b1cSmrg fhc_attach(struct fhc_softc *sc)
6139a57b1cSmrg {
6239a57b1cSmrg int node0, node;
6339a57b1cSmrg u_int32_t ctrl;
6439a57b1cSmrg
6539a57b1cSmrg printf(" board %d: %s\n", sc->sc_board,
6639a57b1cSmrg prom_getpropstring(sc->sc_node, "board-model"));
6739a57b1cSmrg
6839a57b1cSmrg sc->sc_cbt = fhc_alloc_bus_tag(sc);
6939a57b1cSmrg
7039a57b1cSmrg sc->sc_ign = sc->sc_board << 1;
7139a57b1cSmrg bus_space_write_4(sc->sc_bt, sc->sc_ireg, FHC_I_IGN, sc->sc_ign);
7239a57b1cSmrg sc->sc_ign = bus_space_read_4(sc->sc_bt, sc->sc_ireg, FHC_I_IGN);
7339a57b1cSmrg
7439a57b1cSmrg ctrl = bus_space_read_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL);
7539a57b1cSmrg if (!sc->sc_is_central)
7639a57b1cSmrg ctrl |= FHC_P_CTRL_IXIST;
7739a57b1cSmrg ctrl &= ~(FHC_P_CTRL_AOFF | FHC_P_CTRL_BOFF | FHC_P_CTRL_SLINE);
7839a57b1cSmrg bus_space_write_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL, ctrl);
7939a57b1cSmrg bus_space_read_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL);
8039a57b1cSmrg
8139a57b1cSmrg /* clear interrupts */
8239a57b1cSmrg bus_space_write_4(sc->sc_bt, sc->sc_freg, FHC_F_ICLR, 0);
8339a57b1cSmrg bus_space_read_4(sc->sc_bt, sc->sc_freg, FHC_F_ICLR);
8439a57b1cSmrg bus_space_write_4(sc->sc_bt, sc->sc_sreg, FHC_S_ICLR, 0);
8539a57b1cSmrg bus_space_read_4(sc->sc_bt, sc->sc_sreg, FHC_S_ICLR);
8639a57b1cSmrg bus_space_write_4(sc->sc_bt, sc->sc_ureg, FHC_U_ICLR, 0);
8739a57b1cSmrg bus_space_read_4(sc->sc_bt, sc->sc_ureg, FHC_U_ICLR);
8839a57b1cSmrg bus_space_write_4(sc->sc_bt, sc->sc_treg, FHC_T_ICLR, 0);
8939a57b1cSmrg bus_space_read_4(sc->sc_bt, sc->sc_treg, FHC_T_ICLR);
9039a57b1cSmrg
9139a57b1cSmrg prom_getprop(sc->sc_node, "ranges", sizeof(struct fhc_range),
9239a57b1cSmrg &sc->sc_nrange, (void **)&sc->sc_range);
9339a57b1cSmrg
94*3944ff70Sthorpej devhandle_t selfh = device_handle(sc->sc_dev);
9539a57b1cSmrg node0 = firstchild(sc->sc_node);
9639a57b1cSmrg for (node = node0; node; node = nextsibling(node)) {
9739a57b1cSmrg struct fhc_attach_args fa;
9839a57b1cSmrg
9939a57b1cSmrg #if 0
10039a57b1cSmrg if (!checkstatus(node))
10139a57b1cSmrg continue;
10239a57b1cSmrg #endif
10339a57b1cSmrg
10439a57b1cSmrg bzero(&fa, sizeof(fa));
10539a57b1cSmrg
10639a57b1cSmrg fa.fa_node = node;
10739a57b1cSmrg fa.fa_bustag = sc->sc_cbt;
10839a57b1cSmrg
10939a57b1cSmrg if (fhc_get_string(fa.fa_node, "name", &fa.fa_name)) {
11039a57b1cSmrg printf("can't fetch name for node 0x%x\n", node);
11139a57b1cSmrg continue;
11239a57b1cSmrg }
11339a57b1cSmrg prom_getprop(node, "reg", sizeof(struct fhc_reg),
11439a57b1cSmrg &fa.fa_nreg, (void **)&fa.fa_reg);
11539a57b1cSmrg prom_getprop(node, "interrupts", sizeof(int),
11639a57b1cSmrg &fa.fa_nintr, (void **)&fa.fa_intr);
11739a57b1cSmrg prom_getprop(node, "address", sizeof(*fa.fa_promvaddrs),
11839a57b1cSmrg &fa.fa_npromvaddrs, (void **)&fa.fa_promvaddrs);
11939a57b1cSmrg
1202685996bSthorpej (void)config_found(sc->sc_dev, (void *)&fa, fhc_print,
121*3944ff70Sthorpej CFARGS(.devhandle = prom_node_to_devhandle(selfh, node)));
12239a57b1cSmrg
12339a57b1cSmrg if (fa.fa_name != NULL)
12439a57b1cSmrg free(fa.fa_name, M_DEVBUF);
12539a57b1cSmrg if (fa.fa_reg != NULL)
12639a57b1cSmrg free(fa.fa_reg, M_DEVBUF);
12739a57b1cSmrg if (fa.fa_intr != NULL)
12839a57b1cSmrg free(fa.fa_intr, M_DEVBUF);
12939a57b1cSmrg if (fa.fa_promvaddrs != NULL)
13039a57b1cSmrg free(fa.fa_promvaddrs, M_DEVBUF);
13139a57b1cSmrg }
13239a57b1cSmrg }
13339a57b1cSmrg
13439a57b1cSmrg int
fhc_print(void * args,const char * busname)13539a57b1cSmrg fhc_print(void *args, const char *busname)
13639a57b1cSmrg {
13739a57b1cSmrg struct fhc_attach_args *fa = args;
13839a57b1cSmrg char *class;
13939a57b1cSmrg
14039a57b1cSmrg if (busname != NULL) {
14139a57b1cSmrg printf("\"%s\" at %s", fa->fa_name, busname);
14239a57b1cSmrg class = prom_getpropstring(fa->fa_node, "device_type");
14339a57b1cSmrg if (*class != '\0')
14439a57b1cSmrg printf(" class %s", class);
14539a57b1cSmrg }
14639a57b1cSmrg return (UNCONF);
14739a57b1cSmrg }
14839a57b1cSmrg
14939a57b1cSmrg int
fhc_get_string(int node,const char * name,char ** buf)15039a57b1cSmrg fhc_get_string(int node, const char *name, char **buf)
15139a57b1cSmrg {
15239a57b1cSmrg int len;
15339a57b1cSmrg
15439a57b1cSmrg len = prom_getproplen(node, name);
15539a57b1cSmrg if (len < 0)
15639a57b1cSmrg return (len);
157d47bcd29Schs *buf = (char *)malloc(len + 1, M_DEVBUF, M_WAITOK);
15839a57b1cSmrg if (len != 0)
15939a57b1cSmrg prom_getpropstringA(node, name, *buf, len + 1);
16039a57b1cSmrg (*buf)[len] = '\0';
16139a57b1cSmrg return (0);
16239a57b1cSmrg }
16339a57b1cSmrg
16439a57b1cSmrg bus_space_tag_t
fhc_alloc_bus_tag(struct fhc_softc * sc)16539a57b1cSmrg fhc_alloc_bus_tag(struct fhc_softc *sc)
16639a57b1cSmrg {
16739a57b1cSmrg struct sparc_bus_space_tag *bt;
16839a57b1cSmrg
169fc256c4aSthorpej bt = kmem_zalloc(sizeof(*bt), KM_SLEEP);
17039a57b1cSmrg bt->cookie = sc;
17139a57b1cSmrg bt->parent = sc->sc_bt;
17239a57b1cSmrg bt->type = 0; /* XXX asi? */
17339a57b1cSmrg bt->sparc_bus_map = _fhc_bus_map;
17439a57b1cSmrg /* XXX bt->sparc_bus_mmap = fhc_bus_mmap; */
17539a57b1cSmrg bt->sparc_intr_establish = fhc_intr_establish;
17639a57b1cSmrg return (bt);
17739a57b1cSmrg }
17839a57b1cSmrg
17939a57b1cSmrg int
_fhc_bus_map(bus_space_tag_t t,bus_addr_t addr,bus_size_t size,int flags,vaddr_t unused,bus_space_handle_t * hp)18039a57b1cSmrg _fhc_bus_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
18139a57b1cSmrg int flags, vaddr_t unused, bus_space_handle_t *hp)
18239a57b1cSmrg {
18339a57b1cSmrg struct fhc_softc *sc = t->cookie;
18439a57b1cSmrg int64_t slot = BUS_ADDR_IOSPACE(addr);
18539a57b1cSmrg int64_t offset = BUS_ADDR_PADDR(addr);
18639a57b1cSmrg int i;
18739a57b1cSmrg
18839a57b1cSmrg if (t->parent == NULL || t->parent->sparc_bus_map == NULL) {
18939a57b1cSmrg printf("\n_fhc_bus_map: invalid parent");
19039a57b1cSmrg return (EINVAL);
19139a57b1cSmrg }
19239a57b1cSmrg
19339a57b1cSmrg for (i = 0; i < sc->sc_nrange; i++) {
19439a57b1cSmrg bus_addr_t paddr;
19539a57b1cSmrg
19639a57b1cSmrg if (sc->sc_range[i].cspace != slot)
19739a57b1cSmrg continue;
19839a57b1cSmrg
19939a57b1cSmrg paddr = offset - sc->sc_range[i].coffset;
20039a57b1cSmrg paddr += sc->sc_range[i].poffset;
20139a57b1cSmrg paddr |= ((bus_addr_t)sc->sc_range[i].pspace << 32);
20239a57b1cSmrg
20339a57b1cSmrg return bus_space_map(t->parent, paddr, size, flags, hp);
20439a57b1cSmrg }
20539a57b1cSmrg
20639a57b1cSmrg return (EINVAL);
20739a57b1cSmrg }
20839a57b1cSmrg
20939a57b1cSmrg bus_space_handle_t *
fhc_find_intr_handle(struct fhc_softc * sc,int ino)21039a57b1cSmrg fhc_find_intr_handle(struct fhc_softc *sc, int ino)
21139a57b1cSmrg {
21239a57b1cSmrg switch (FHC_INO(ino)) {
21339a57b1cSmrg case FHC_F_INO:
21439a57b1cSmrg return &sc->sc_freg;
21539a57b1cSmrg case FHC_S_INO:
21639a57b1cSmrg return &sc->sc_sreg;
21739a57b1cSmrg case FHC_U_INO:
21839a57b1cSmrg return &sc->sc_ureg;
21939a57b1cSmrg case FHC_T_INO:
22039a57b1cSmrg return &sc->sc_treg;
22139a57b1cSmrg default:
22239a57b1cSmrg break;
22339a57b1cSmrg }
22439a57b1cSmrg
22539a57b1cSmrg return (NULL);
22639a57b1cSmrg }
22739a57b1cSmrg
22839a57b1cSmrg void *
fhc_intr_establish(bus_space_tag_t t,int ihandle,int level,int (* handler)(void *),void * arg,void (* fastvec)(void))22939a57b1cSmrg fhc_intr_establish(bus_space_tag_t t, int ihandle, int level,
23039a57b1cSmrg int (*handler)(void *), void *arg, void (*fastvec)(void) /* ignored */)
23139a57b1cSmrg {
23239a57b1cSmrg struct fhc_softc *sc = t->cookie;
23339a57b1cSmrg volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
23439a57b1cSmrg struct intrhand *ih;
23539a57b1cSmrg long vec;
23639a57b1cSmrg bus_space_handle_t *hp;
23739a57b1cSmrg struct fhc_intr_reg *intrregs;
23839a57b1cSmrg
23939a57b1cSmrg hp = fhc_find_intr_handle(sc, ihandle);
24039a57b1cSmrg if (hp == NULL) {
24139a57b1cSmrg printf(": can't find intr handle\n");
24239a57b1cSmrg return (NULL);
24339a57b1cSmrg }
24439a57b1cSmrg
24539a57b1cSmrg intrregs = bus_space_vaddr(sc->sc_bt, *hp);
24639a57b1cSmrg intrmapptr = &intrregs->imap;
24739a57b1cSmrg intrclrptr = &intrregs->iclr;
24839a57b1cSmrg vec = ((sc->sc_ign << INTMAP_IGN_SHIFT) & INTMAP_IGN) |
24939a57b1cSmrg INTINO(ihandle);
25039a57b1cSmrg
2517820dc41Spalle ih = intrhand_alloc();
25239a57b1cSmrg
25339a57b1cSmrg ih->ih_ivec = ihandle;
25439a57b1cSmrg
25539a57b1cSmrg /* Register the map and clear intr registers */
25639a57b1cSmrg ih->ih_map = intrmapptr;
25739a57b1cSmrg ih->ih_clr = intrclrptr;
25839a57b1cSmrg
25939a57b1cSmrg ih->ih_fun = handler;
26039a57b1cSmrg ih->ih_arg = arg;
26139a57b1cSmrg ih->ih_pil = level;
26239a57b1cSmrg ih->ih_number = vec;
26339a57b1cSmrg
26439a57b1cSmrg intr_establish(ih->ih_pil, level != IPL_VM, ih);
26539a57b1cSmrg
26639a57b1cSmrg /*
26739a57b1cSmrg * XXXX --- we really should use bus_space for this.
26839a57b1cSmrg */
26939a57b1cSmrg if (intrmapptr != NULL) {
27039a57b1cSmrg u_int64_t r;
27139a57b1cSmrg
27239a57b1cSmrg r = *intrmapptr;
2734e9cb6ccSjdc r |= INTMAP_V | (CPU_UPAID << INTMAP_TID_SHIFT);
27439a57b1cSmrg *intrmapptr = r;
27539a57b1cSmrg r = *intrmapptr;
27639a57b1cSmrg ih->ih_number |= r & INTMAP_INR;
27739a57b1cSmrg }
27839a57b1cSmrg
27939a57b1cSmrg return (ih);
28039a57b1cSmrg }
281