xref: /openbsd-src/sys/arch/arm64/dev/aplsart.c (revision ea87a8bf468d59502d176fee1979ff5c974b6942)
1 /*	$OpenBSD: aplsart.c,v 1.4 2022/11/11 11:45:10 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/extent.h>
22 #include <sys/malloc.h>
23 #include <sys/mutex.h>
24 
25 #include <machine/intr.h>
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 
29 #include <dev/ofw/openfirm.h>
30 #include <dev/ofw/fdt.h>
31 #include <dev/ofw/ofw_power.h>
32 
33 #define SART2_CONFIG(idx)	(0x0000 + 4 * (idx))
34 #define  SART2_CONFIG_FLAGS_MASK	0xff000000
35 #define  SART2_CONFIG_FLAGS_ALLOW	0xff000000
36 #define SART2_ADDR(idx)		(0x0040 + 4 * (idx))
37 
38 #define SART3_CONFIG(idx)	(0x0000 + 4 * (idx))
39 #define  SART3_CONFIG_FLAGS_MASK	0x000000ff
40 #define  SART3_CONFIG_FLAGS_ALLOW	0x000000ff
41 #define SART3_ADDR(idx)		(0x0040 + 4 * (idx))
42 #define SART3_SIZE(idx)		(0x0080 + 4 * (idx))
43 
44 #define SART_NUM_ENTRIES	16
45 #define SART_ADDR_SHIFT		12
46 #define SART_SIZE_SHIFT		12
47 
48 #define HREAD4(sc, reg)							\
49 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
50 #define HWRITE4(sc, reg, val)						\
51 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
52 
53 struct aplsart_softc {
54 	struct device		sc_dev;
55 	bus_space_tag_t		sc_iot;
56 	bus_space_handle_t	sc_ioh;
57 	int			sc_node;
58 	uint32_t		sc_phandle;
59 	int			sc_version;
60 };
61 
62 int	aplsart_match(struct device *, void *, void *);
63 void	aplsart_attach(struct device *, struct device *, void *);
64 int	aplsart_activate(struct device *, int);
65 
66 const struct cfattach aplsart_ca = {
67 	sizeof (struct aplsart_softc), aplsart_match, aplsart_attach, NULL,
68 	aplsart_activate
69 };
70 
71 struct cfdriver aplsart_cd = {
72 	NULL, "aplsart", DV_DULL
73 };
74 
75 int
aplsart_match(struct device * parent,void * match,void * aux)76 aplsart_match(struct device *parent, void *match, void *aux)
77 {
78 	struct fdt_attach_args *faa = aux;
79 
80 	return OF_is_compatible(faa->fa_node, "apple,t6000-sart") ||
81 	    OF_is_compatible(faa->fa_node, "apple,t8103-sart");
82 }
83 
84 void
aplsart_attach(struct device * parent,struct device * self,void * aux)85 aplsart_attach(struct device *parent, struct device *self, void *aux)
86 {
87 	struct aplsart_softc *sc = (struct aplsart_softc *)self;
88 	struct fdt_attach_args *faa = aux;
89 
90 	if (faa->fa_nreg < 1) {
91 		printf(": no registers\n");
92 		return;
93 	}
94 
95 	sc->sc_iot = faa->fa_iot;
96 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
97 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
98 		printf(": can't map registers\n");
99 		return;
100 	}
101 
102 	sc->sc_node = faa->fa_node;
103 	sc->sc_phandle = OF_getpropint(faa->fa_node, "phandle", 0);
104 
105 	if (OF_is_compatible(sc->sc_node, "apple,t8103-sart"))
106 		sc->sc_version = 2;
107 	if (OF_is_compatible(sc->sc_node, "apple,t6000-sart"))
108 		sc->sc_version = 3;
109 
110 	power_domain_enable_all(sc->sc_node);
111 
112 	printf("\n");
113 }
114 
115 int
aplsart_activate(struct device * self,int act)116 aplsart_activate(struct device *self, int act)
117 {
118 	struct aplsart_softc *sc = (struct aplsart_softc *)self;
119 
120 	switch (act) {
121 	case DVACT_POWERDOWN:
122 		power_domain_disable_all(sc->sc_node);
123 		break;
124 	case DVACT_RESUME:
125 		power_domain_enable_all(sc->sc_node);
126 		break;
127 	}
128 
129 	return 0;
130 }
131 
132 int
aplsart2_map(struct aplsart_softc * sc,bus_addr_t addr,bus_size_t size)133 aplsart2_map(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size)
134 {
135 	uint32_t conf;
136 	int i;
137 
138 	for (i = 0; i < SART_NUM_ENTRIES; i++) {
139 		conf = HREAD4(sc, SART2_CONFIG(i));
140 		if (conf & SART2_CONFIG_FLAGS_MASK)
141 			continue;
142 
143 		HWRITE4(sc, SART2_ADDR(i), addr >> SART_ADDR_SHIFT);
144 		HWRITE4(sc, SART2_CONFIG(i),
145 		    size >> SART_SIZE_SHIFT | SART2_CONFIG_FLAGS_ALLOW);
146 		return 0;
147 	}
148 
149 	return ENOENT;
150 }
151 
152 int
aplsart3_map(struct aplsart_softc * sc,bus_addr_t addr,bus_size_t size)153 aplsart3_map(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size)
154 {
155 	uint32_t conf;
156 	int i;
157 
158 	for (i = 0; i < SART_NUM_ENTRIES; i++) {
159 		conf = HREAD4(sc, SART3_CONFIG(i));
160 		if (conf & SART3_CONFIG_FLAGS_MASK)
161 			continue;
162 
163 		HWRITE4(sc, SART3_ADDR(i), addr >> SART_ADDR_SHIFT);
164 		HWRITE4(sc, SART3_SIZE(i), size >> SART_SIZE_SHIFT);
165 		HWRITE4(sc, SART3_CONFIG(i), SART3_CONFIG_FLAGS_ALLOW);
166 		return 0;
167 	}
168 
169 	return ENOENT;
170 }
171 
172 int
aplsart_map(uint32_t phandle,bus_addr_t addr,bus_size_t size)173 aplsart_map(uint32_t phandle, bus_addr_t addr, bus_size_t size)
174 {
175 	struct aplsart_softc *sc;
176 	int i;
177 
178 	for (i = 0; i < aplsart_cd.cd_ndevs; i++) {
179 		sc = (struct aplsart_softc *)aplsart_cd.cd_devs[i];
180 
181 		if (sc->sc_phandle == phandle) {
182 			if (sc->sc_version == 2)
183 				return aplsart2_map(sc, addr, size);
184 			else
185 				return aplsart3_map(sc, addr, size);
186 		}
187 	}
188 
189 	return ENXIO;
190 }
191 
192 int
aplsart2_unmap(struct aplsart_softc * sc,bus_addr_t addr,bus_size_t size)193 aplsart2_unmap(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size)
194 {
195 	int i;
196 
197 	for (i = 0; i < SART_NUM_ENTRIES; i++) {
198 		if (HREAD4(sc, SART2_ADDR(i)) != (addr >> SART_ADDR_SHIFT))
199 			continue;
200 
201 		HWRITE4(sc, SART2_ADDR(i), 0);
202 		HWRITE4(sc, SART2_CONFIG(i), 0);
203 		return 0;
204 	}
205 
206 	return ENOENT;
207 }
208 
209 int
aplsart3_unmap(struct aplsart_softc * sc,bus_addr_t addr,bus_size_t size)210 aplsart3_unmap(struct aplsart_softc *sc, bus_addr_t addr, bus_size_t size)
211 {
212 	int i;
213 
214 	for (i = 0; i < SART_NUM_ENTRIES; i++) {
215 		if (HREAD4(sc, SART3_ADDR(i)) != (addr >> SART_ADDR_SHIFT))
216 			continue;
217 
218 		HWRITE4(sc, SART3_ADDR(i), 0);
219 		HWRITE4(sc, SART3_SIZE(i), 0);
220 		HWRITE4(sc, SART3_CONFIG(i), 0);
221 		return 0;
222 	}
223 
224 	return ENOENT;
225 }
226 
227 int
aplsart_unmap(uint32_t phandle,bus_addr_t addr,bus_size_t size)228 aplsart_unmap(uint32_t phandle, bus_addr_t addr, bus_size_t size)
229 {
230 	struct aplsart_softc *sc;
231 	int i;
232 
233 	for (i = 0; i < aplsart_cd.cd_ndevs; i++) {
234 		sc = (struct aplsart_softc *)aplsart_cd.cd_devs[i];
235 
236 		if (sc->sc_phandle == phandle) {
237 			if (sc->sc_version == 2)
238 				return aplsart2_unmap(sc, addr, size);
239 			else
240 				return aplsart3_unmap(sc, addr, size);
241 		}
242 	}
243 
244 	return ENXIO;
245 }
246