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