xref: /netbsd-src/sys/arch/sparc64/dev/fhc.c (revision 3944ff70a48a86bb622139705a33f8ef461e24f7)
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