xref: /openbsd-src/sys/arch/sparc64/dev/fhc.c (revision 8a1e8ccaf72b414f303ec266a1bf09741dab5c4c)
1*8a1e8ccaSmiod /*	$OpenBSD: fhc.c,v 1.22 2024/03/29 21:29:33 miod Exp $	*/
2f63ee831Sjason 
3f63ee831Sjason /*
4f63ee831Sjason  * Copyright (c) 2004 Jason L. Wright (jason@thought.net)
5f63ee831Sjason  * All rights reserved.
6f63ee831Sjason  *
7f63ee831Sjason  * Redistribution and use in source and binary forms, with or without
8f63ee831Sjason  * modification, are permitted provided that the following conditions
9f63ee831Sjason  * are met:
10f63ee831Sjason  * 1. Redistributions of source code must retain the above copyright
11f63ee831Sjason  *    notice, this list of conditions and the following disclaimer.
12f63ee831Sjason  * 2. Redistributions in binary form must reproduce the above copyright
13f63ee831Sjason  *    notice, this list of conditions and the following disclaimer in the
14f63ee831Sjason  *    documentation and/or other materials provided with the distribution.
15f63ee831Sjason  *
16f63ee831Sjason  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17f63ee831Sjason  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18f63ee831Sjason  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19f63ee831Sjason  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20f63ee831Sjason  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21f63ee831Sjason  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22f63ee831Sjason  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f63ee831Sjason  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24f63ee831Sjason  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25f63ee831Sjason  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26f63ee831Sjason  * POSSIBILITY OF SUCH DAMAGE.
27f63ee831Sjason  */
28f63ee831Sjason 
29f63ee831Sjason #include <sys/param.h>
30f63ee831Sjason #include <sys/systm.h>
31f63ee831Sjason #include <sys/kernel.h>
32f63ee831Sjason #include <sys/device.h>
33f63ee831Sjason #include <sys/conf.h>
34f63ee831Sjason #include <sys/timeout.h>
35f63ee831Sjason #include <sys/malloc.h>
36f63ee831Sjason 
37f63ee831Sjason #include <machine/bus.h>
38f63ee831Sjason #include <machine/autoconf.h>
39f63ee831Sjason #include <machine/openfirm.h>
40f63ee831Sjason 
4109338432Sjason #include <sparc64/dev/fhcreg.h>
42f63ee831Sjason #include <sparc64/dev/fhcvar.h>
4309338432Sjason #include <sparc64/dev/iommureg.h>
44f63ee831Sjason 
45f63ee831Sjason struct cfdriver fhc_cd = {
46f63ee831Sjason 	NULL, "fhc", DV_DULL
47f63ee831Sjason };
48f63ee831Sjason 
49f63ee831Sjason int	fhc_print(void *, const char *);
50f63ee831Sjason 
51f63ee831Sjason bus_space_tag_t fhc_alloc_bus_tag(struct fhc_softc *);
52f63ee831Sjason int _fhc_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t, bus_size_t,
53f63ee831Sjason     int, bus_space_handle_t *);
5409338432Sjason void *fhc_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
5509338432Sjason     int (*)(void *), void *, const char *);
5609338432Sjason bus_space_handle_t *fhc_find_intr_handle(struct fhc_softc *, int);
579f31f4f7Sjason void fhc_led_blink(void *, int);
58f63ee831Sjason 
59f63ee831Sjason void
fhc_attach(struct fhc_softc * sc)60f63ee831Sjason fhc_attach(struct fhc_softc *sc)
61f63ee831Sjason {
62f63ee831Sjason 	int node0, node;
63c7a321c7Sjason 	u_int32_t ctrl;
64f63ee831Sjason 
6511618695Sjason 	printf(" board %d: %s\n", sc->sc_board,
66d435f11cSjason 	    getpropstring(sc->sc_node, "board-model"));
67f63ee831Sjason 
68f63ee831Sjason 	sc->sc_cbt = fhc_alloc_bus_tag(sc);
69f63ee831Sjason 
702af5f99fSjason 	sc->sc_ign = sc->sc_board << 1;
712af5f99fSjason 	bus_space_write_4(sc->sc_bt, sc->sc_ireg, FHC_I_IGN, sc->sc_ign);
722af5f99fSjason 	sc->sc_ign = bus_space_read_4(sc->sc_bt, sc->sc_ireg, FHC_I_IGN);
732af5f99fSjason 
74c7a321c7Sjason 	ctrl = bus_space_read_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL);
75c7a321c7Sjason 	if (!sc->sc_is_central)
76c7a321c7Sjason 		ctrl |= FHC_P_CTRL_IXIST;
77c7a321c7Sjason 	ctrl &= ~(FHC_P_CTRL_AOFF | FHC_P_CTRL_BOFF | FHC_P_CTRL_SLINE);
78c7a321c7Sjason 	bus_space_write_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL, ctrl);
79c7a321c7Sjason 	bus_space_read_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL);
80c7a321c7Sjason 
81c7a321c7Sjason 	/* clear interrupts */
82c7a321c7Sjason 	bus_space_write_4(sc->sc_bt, sc->sc_freg, FHC_F_ICLR, 0);
83c7a321c7Sjason 	bus_space_read_4(sc->sc_bt, sc->sc_freg, FHC_F_ICLR);
84c7a321c7Sjason 	bus_space_write_4(sc->sc_bt, sc->sc_sreg, FHC_S_ICLR, 0);
85c7a321c7Sjason 	bus_space_read_4(sc->sc_bt, sc->sc_sreg, FHC_S_ICLR);
86c7a321c7Sjason 	bus_space_write_4(sc->sc_bt, sc->sc_ureg, FHC_U_ICLR, 0);
87c7a321c7Sjason 	bus_space_read_4(sc->sc_bt, sc->sc_ureg, FHC_U_ICLR);
88c7a321c7Sjason 	bus_space_write_4(sc->sc_bt, sc->sc_treg, FHC_T_ICLR, 0);
89c7a321c7Sjason 	bus_space_read_4(sc->sc_bt, sc->sc_treg, FHC_T_ICLR);
90c7a321c7Sjason 
91f63ee831Sjason 	getprop(sc->sc_node, "ranges", sizeof(struct fhc_range),
92f63ee831Sjason 	    &sc->sc_nrange, (void **)&sc->sc_range);
93f63ee831Sjason 
94f63ee831Sjason 	node0 = firstchild(sc->sc_node);
95f63ee831Sjason 	for (node = node0; node; node = nextsibling(node)) {
96f63ee831Sjason 		struct fhc_attach_args fa;
97f63ee831Sjason 
98b4088691Skettenis 		if (!checkstatus(node))
99b4088691Skettenis 			continue;
100b4088691Skettenis 
101f63ee831Sjason 		bzero(&fa, sizeof(fa));
102f63ee831Sjason 
103f63ee831Sjason 		fa.fa_node = node;
104f63ee831Sjason 		fa.fa_bustag = sc->sc_cbt;
105f63ee831Sjason 
106f63ee831Sjason 		if (fhc_get_string(fa.fa_node, "name", &fa.fa_name)) {
107f63ee831Sjason 			printf("can't fetch name for node 0x%x\n", node);
108f63ee831Sjason 			continue;
109f63ee831Sjason 		}
110f63ee831Sjason 		getprop(node, "reg", sizeof(struct fhc_reg),
111f63ee831Sjason 		    &fa.fa_nreg, (void **)&fa.fa_reg);
11209338432Sjason 		getprop(node, "interrupts", sizeof(int),
11309338432Sjason 		    &fa.fa_nintr, (void **)&fa.fa_intr);
114b150d549Sjason 		getprop(node, "address", sizeof(*fa.fa_promvaddrs),
115b150d549Sjason 		    &fa.fa_npromvaddrs, (void **)&fa.fa_promvaddrs);
116f63ee831Sjason 
117f63ee831Sjason 		(void)config_found(&sc->sc_dv, (void *)&fa, fhc_print);
118f63ee831Sjason 
119f8e6c425Stedu 		free(fa.fa_name, M_DEVBUF, 0);
120f8e6c425Stedu 		free(fa.fa_reg, M_DEVBUF, 0);
121f8e6c425Stedu 		free(fa.fa_intr, M_DEVBUF, 0);
122f8e6c425Stedu 		free(fa.fa_promvaddrs, M_DEVBUF, 0);
123f63ee831Sjason 	}
124cbf7153bSjason 
1259f31f4f7Sjason 	sc->sc_blink.bl_func = fhc_led_blink;
1269f31f4f7Sjason 	sc->sc_blink.bl_arg = sc;
1279f31f4f7Sjason 	blink_led_register(&sc->sc_blink);
128f63ee831Sjason }
129f63ee831Sjason 
130f63ee831Sjason int
fhc_print(void * args,const char * busname)131f63ee831Sjason fhc_print(void *args, const char *busname)
132f63ee831Sjason {
133f63ee831Sjason 	struct fhc_attach_args *fa = args;
134f63ee831Sjason 	char *class;
135f63ee831Sjason 
136f63ee831Sjason 	if (busname != NULL) {
137909f848aSkettenis 		printf("\"%s\" at %s", fa->fa_name, busname);
138f63ee831Sjason 		class = getpropstring(fa->fa_node, "device_type");
139f63ee831Sjason 		if (*class != '\0')
140f63ee831Sjason 			printf(" class %s", class);
141f63ee831Sjason 	}
142f63ee831Sjason 	return (UNCONF);
143f63ee831Sjason }
144f63ee831Sjason 
145f63ee831Sjason int
fhc_get_string(int node,char * name,char ** buf)146f63ee831Sjason fhc_get_string(int node, char *name, char **buf)
147f63ee831Sjason {
148f63ee831Sjason 	int len;
149f63ee831Sjason 
150f63ee831Sjason 	len = getproplen(node, name);
151f63ee831Sjason 	if (len < 0)
152f63ee831Sjason 		return (len);
153f63ee831Sjason 	*buf = (char *)malloc(len + 1, M_DEVBUF, M_NOWAIT);
154f1cc154aSjason 	if (*buf == NULL)
155f63ee831Sjason 		return (-1);
156f63ee831Sjason 
157f63ee831Sjason 	if (len != 0)
158f63ee831Sjason 		getpropstringA(node, name, *buf);
159f63ee831Sjason 	(*buf)[len] = '\0';
160f63ee831Sjason 	return (0);
161f63ee831Sjason }
162f63ee831Sjason 
163f63ee831Sjason bus_space_tag_t
fhc_alloc_bus_tag(struct fhc_softc * sc)164f63ee831Sjason fhc_alloc_bus_tag(struct fhc_softc *sc)
165f63ee831Sjason {
166f63ee831Sjason 	struct sparc_bus_space_tag *bt;
167f63ee831Sjason 
168bc9397c2Skrw 	bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO);
169f63ee831Sjason 	if (bt == NULL)
170f63ee831Sjason 		panic("fhc: couldn't alloc bus tag");
171f63ee831Sjason 
172ec13f893Smiod 	strlcpy(bt->name, sc->sc_dv.dv_xname, sizeof(bt->name));
173f63ee831Sjason 	bt->cookie = sc;
174f63ee831Sjason 	bt->parent = sc->sc_bt;
175f63ee831Sjason 	bt->asi = bt->parent->asi;
176f63ee831Sjason 	bt->sasi = bt->parent->sasi;
177f63ee831Sjason 	bt->sparc_bus_map = _fhc_bus_map;
178f63ee831Sjason 	/* XXX bt->sparc_bus_mmap = fhc_bus_mmap; */
17909338432Sjason 	bt->sparc_intr_establish = fhc_intr_establish;
180f63ee831Sjason 	return (bt);
181f63ee831Sjason }
182f63ee831Sjason 
183f63ee831Sjason int
_fhc_bus_map(bus_space_tag_t t,bus_space_tag_t t0,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * hp)184f63ee831Sjason _fhc_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t addr,
185f63ee831Sjason     bus_size_t size, int flags, bus_space_handle_t *hp)
186f63ee831Sjason {
187f63ee831Sjason 	struct fhc_softc *sc = t->cookie;
188f63ee831Sjason 	int64_t slot = BUS_ADDR_IOSPACE(addr);
189f63ee831Sjason 	int64_t offset = BUS_ADDR_PADDR(addr);
190f63ee831Sjason 	int i;
191f63ee831Sjason 
192f63ee831Sjason 	if (t->parent == NULL || t->parent->sparc_bus_map == NULL) {
193f63ee831Sjason 		printf("\n_fhc_bus_map: invalid parent");
194f63ee831Sjason 		return (EINVAL);
195f63ee831Sjason 	}
196f63ee831Sjason 
197f63ee831Sjason 	if (flags & BUS_SPACE_MAP_PROMADDRESS)
198f63ee831Sjason 		return ((*t->parent->sparc_bus_map)(t, t0, addr,
199f63ee831Sjason 		    size, flags, hp));
200f63ee831Sjason 
201f63ee831Sjason 	for (i = 0; i < sc->sc_nrange; i++) {
202f63ee831Sjason 		bus_addr_t paddr;
203f63ee831Sjason 
204f63ee831Sjason 		if (sc->sc_range[i].cspace != slot)
205f63ee831Sjason 			continue;
206f63ee831Sjason 
207f63ee831Sjason 		paddr = offset - sc->sc_range[i].coffset;
208f63ee831Sjason 		paddr += sc->sc_range[i].poffset;
209f63ee831Sjason 		paddr |= ((bus_addr_t)sc->sc_range[i].pspace << 32);
210f63ee831Sjason 
2114e302ebeSjason 		return ((*t->parent->sparc_bus_map)(t->parent, t0, paddr,
212f63ee831Sjason 		    size, flags, hp));
213f63ee831Sjason 	}
214f63ee831Sjason 
215f63ee831Sjason 	return (EINVAL);
216f63ee831Sjason }
21709338432Sjason 
21809338432Sjason bus_space_handle_t *
fhc_find_intr_handle(struct fhc_softc * sc,int ino)219fa5ef511Skettenis fhc_find_intr_handle(struct fhc_softc *sc, int ino)
22009338432Sjason {
221fa5ef511Skettenis 	switch (FHC_INO(ino)) {
222fa5ef511Skettenis 	case FHC_F_INO:
223fa5ef511Skettenis 		return &sc->sc_freg;
224fa5ef511Skettenis 	case FHC_S_INO:
225fa5ef511Skettenis 		return &sc->sc_sreg;
226fa5ef511Skettenis 	case FHC_U_INO:
227fa5ef511Skettenis 		return &sc->sc_ureg;
228fa5ef511Skettenis 	case FHC_T_INO:
229fa5ef511Skettenis 		return &sc->sc_treg;
230fa5ef511Skettenis 	default:
231fa5ef511Skettenis 		break;
23209338432Sjason 	}
23309338432Sjason 
23409338432Sjason 	return (NULL);
23509338432Sjason }
23609338432Sjason 
23709338432Sjason void *
fhc_intr_establish(bus_space_tag_t t,bus_space_tag_t t0,int ihandle,int level,int flags,int (* handler)(void *),void * arg,const char * what)23809338432Sjason fhc_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
23909338432Sjason     int level, int flags, int (*handler)(void *), void *arg, const char *what)
24009338432Sjason {
24109338432Sjason 	struct fhc_softc *sc = t->cookie;
24209338432Sjason 	volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
24309338432Sjason 	struct intrhand *ih;
24441cccc39Sjason 	long vec;
24509338432Sjason 
24609338432Sjason 	if (level == IPL_NONE)
24709338432Sjason 		level = INTLEV(ihandle);
24809338432Sjason 	if (level == IPL_NONE) {
24909338432Sjason 		printf(": no IPL, setting IPL 2.\n");
25009338432Sjason 		level = 2;
25109338432Sjason 	}
25209338432Sjason 
25309338432Sjason 	if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
25409338432Sjason 		bus_space_handle_t *hp;
25509338432Sjason 		struct fhc_intr_reg *intrregs;
25609338432Sjason 
25709338432Sjason 		hp = fhc_find_intr_handle(sc, ihandle);
25809338432Sjason 		if (hp == NULL) {
25909338432Sjason 			printf(": can't find intr handle\n");
26009338432Sjason 			return (NULL);
26109338432Sjason 		}
26209338432Sjason 
26309338432Sjason 		intrregs = bus_space_vaddr(sc->sc_bt, *hp);
26409338432Sjason 		intrmapptr = &intrregs->imap;
26509338432Sjason 		intrclrptr = &intrregs->iclr;
2662af5f99fSjason 		vec = ((sc->sc_ign << INTMAP_IGN_SHIFT) & INTMAP_IGN) |
2672af5f99fSjason 		    INTINO(ihandle);
26841cccc39Sjason 	} else
26941cccc39Sjason 		vec = INTVEC(ihandle);
27009338432Sjason 
27141cccc39Sjason 	ih = bus_intr_allocate(t0, handler, arg, vec, level, intrmapptr,
27241cccc39Sjason 	    intrclrptr, what);
27309338432Sjason 	if (ih == NULL)
27409338432Sjason 		return (NULL);
27509338432Sjason 
276*8a1e8ccaSmiod 	intr_establish(ih);
27709338432Sjason 
27809338432Sjason 	if (intrmapptr != NULL) {
27909338432Sjason 		u_int64_t r;
28009338432Sjason 
28109338432Sjason 		r = *intrmapptr;
28209338432Sjason 		r |= INTMAP_V;
28309338432Sjason 		*intrmapptr = r;
28409338432Sjason 		r = *intrmapptr;
28509338432Sjason 		ih->ih_number |= r & INTMAP_INR;
28609338432Sjason 	}
28709338432Sjason 
28809338432Sjason 	return (ih);
28909338432Sjason }
290cbf7153bSjason 
291cbf7153bSjason void
fhc_led_blink(void * vsc,int on)2929f31f4f7Sjason fhc_led_blink(void *vsc, int on)
293cbf7153bSjason {
294cbf7153bSjason 	struct fhc_softc *sc = vsc;
2959f31f4f7Sjason 	int s;
296cbf7153bSjason 	u_int32_t r;
297cbf7153bSjason 
298cbf7153bSjason 	s = splhigh();
299cbf7153bSjason 	r = bus_space_read_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL);
3009f31f4f7Sjason 	if (on)
3019f31f4f7Sjason 		r |= FHC_P_CTRL_RLED;
3029f31f4f7Sjason 	else
3039f31f4f7Sjason 		r &= ~FHC_P_CTRL_RLED;
304cbf7153bSjason 	r &= ~(FHC_P_CTRL_AOFF | FHC_P_CTRL_BOFF | FHC_P_CTRL_SLINE);
305cbf7153bSjason 	bus_space_write_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL, r);
306cbf7153bSjason 	bus_space_read_4(sc->sc_bt, sc->sc_preg, FHC_P_CTRL);
307cbf7153bSjason 	splx(s);
308cbf7153bSjason }
309