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 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 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 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 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 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 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 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 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 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