1 1.1 jmcneill /* $NetBS$ */ 2 1.1 jmcneill /* $OpenBSD: qcipcc.c,v 1.2 2023/05/19 20:54:55 patrick Exp $ */ 3 1.1 jmcneill /* 4 1.1 jmcneill * Copyright (c) 2023 Patrick Wildt <patrick (at) blueri.se> 5 1.1 jmcneill * 6 1.1 jmcneill * Permission to use, copy, modify, and distribute this software for any 7 1.1 jmcneill * purpose with or without fee is hereby granted, provided that the above 8 1.1 jmcneill * copyright notice and this permission notice appear in all copies. 9 1.1 jmcneill * 10 1.1 jmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 1.1 jmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 1.1 jmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 1.1 jmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 1.1 jmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 1.1 jmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 1.1 jmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 1.1 jmcneill */ 18 1.1 jmcneill 19 1.1 jmcneill #include <sys/param.h> 20 1.1 jmcneill #include <sys/systm.h> 21 1.1 jmcneill #include <sys/device.h> 22 1.1 jmcneill #include <sys/kmem.h> 23 1.1 jmcneill 24 1.1 jmcneill #include <dev/acpi/acpivar.h> 25 1.1 jmcneill #include <dev/acpi/acpi_intr.h> 26 1.1 jmcneill #include <dev/acpi/qcomipcc.h> 27 1.1 jmcneill 28 1.1 jmcneill #define IPCC_SEND_ID 0x0c 29 1.1 jmcneill #define IPCC_RECV_ID 0x10 30 1.1 jmcneill #define IPCC_RECV_SIGNAL_ENABLE 0x14 31 1.1 jmcneill #define IPCC_RECV_SIGNAL_DISABLE 0x18 32 1.1 jmcneill #define IPCC_RECV_SIGNAL_CLEAR 0x1c 33 1.1 jmcneill 34 1.1 jmcneill #define IPCC_SIGNAL_ID_MASK __BITS(15,0) 35 1.1 jmcneill #define IPCC_CLIENT_ID_MASK __BITS(31,16) 36 1.1 jmcneill 37 1.1 jmcneill #define HREAD4(sc, reg) \ 38 1.1 jmcneill bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) 39 1.1 jmcneill #define HWRITE4(sc, reg, val) \ 40 1.1 jmcneill bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 41 1.1 jmcneill 42 1.1 jmcneill struct qcipcc_intrhand { 43 1.1 jmcneill TAILQ_ENTRY(qcipcc_intrhand) ih_q; 44 1.1 jmcneill int (*ih_func)(void *); 45 1.1 jmcneill void *ih_arg; 46 1.1 jmcneill void *ih_sc; 47 1.1 jmcneill uint32_t ih_client_id; 48 1.1 jmcneill uint32_t ih_signal_id; 49 1.1 jmcneill }; 50 1.1 jmcneill 51 1.1 jmcneill struct qcipcc_softc { 52 1.1 jmcneill device_t sc_dev; 53 1.1 jmcneill bus_space_tag_t sc_iot; 54 1.1 jmcneill bus_space_handle_t sc_ioh; 55 1.1 jmcneill 56 1.1 jmcneill void *sc_ih; 57 1.1 jmcneill 58 1.1 jmcneill TAILQ_HEAD(,qcipcc_intrhand) sc_intrq; 59 1.1 jmcneill }; 60 1.1 jmcneill 61 1.1 jmcneill static struct qcipcc_softc *qcipcc = NULL; 62 1.1 jmcneill 63 1.1 jmcneill struct qcipcc_channel { 64 1.1 jmcneill struct qcipcc_softc *ch_sc; 65 1.1 jmcneill uint32_t ch_client_id; 66 1.1 jmcneill uint32_t ch_signal_id; 67 1.1 jmcneill }; 68 1.1 jmcneill 69 1.1 jmcneill #define QCIPCC_8380_BASE 0x00408000 70 1.1 jmcneill #define QCIPCC_SIZE 0x1000 71 1.1 jmcneill 72 1.1 jmcneill static const struct device_compatible_entry compat_data[] = { 73 1.1 jmcneill { .compat = "QCOM06C2", .value = QCIPCC_8380_BASE }, 74 1.1 jmcneill DEVICE_COMPAT_EOL 75 1.1 jmcneill }; 76 1.1 jmcneill 77 1.1 jmcneill static int qcipcc_match(device_t, cfdata_t, void *); 78 1.1 jmcneill static void qcipcc_attach(device_t, device_t, void *); 79 1.1 jmcneill static int qcipcc_intr(void *); 80 1.1 jmcneill 81 1.1 jmcneill CFATTACH_DECL_NEW(qcomipcc, sizeof(struct qcipcc_softc), 82 1.1 jmcneill qcipcc_match, qcipcc_attach, NULL, NULL); 83 1.1 jmcneill 84 1.1 jmcneill static int 85 1.1 jmcneill qcipcc_match(device_t parent, cfdata_t match, void *aux) 86 1.1 jmcneill { 87 1.1 jmcneill struct acpi_attach_args *aa = aux; 88 1.1 jmcneill 89 1.1 jmcneill return acpi_compatible_match(aa, compat_data); 90 1.1 jmcneill } 91 1.1 jmcneill 92 1.1 jmcneill static void 93 1.1 jmcneill qcipcc_attach(device_t parent, device_t self, void *aux) 94 1.1 jmcneill { 95 1.1 jmcneill struct qcipcc_softc *sc = device_private(self); 96 1.1 jmcneill struct acpi_attach_args *aa = aux; 97 1.1 jmcneill ACPI_HANDLE hdl; 98 1.1 jmcneill struct acpi_resources res; 99 1.1 jmcneill struct acpi_irq *irq; 100 1.1 jmcneill bus_addr_t base_addr; 101 1.1 jmcneill ACPI_STATUS rv; 102 1.1 jmcneill 103 1.1 jmcneill if (qcipcc != NULL) { 104 1.1 jmcneill aprint_error(": already attached!\n"); 105 1.1 jmcneill return; 106 1.1 jmcneill } 107 1.1 jmcneill 108 1.1 jmcneill hdl = aa->aa_node->ad_handle; 109 1.1 jmcneill rv = acpi_resource_parse(self, hdl, "_CRS", &res, 110 1.1 jmcneill &acpi_resource_parse_ops_default); 111 1.1 jmcneill if (ACPI_FAILURE(rv)) { 112 1.1 jmcneill return; 113 1.1 jmcneill } 114 1.1 jmcneill 115 1.1 jmcneill irq = acpi_res_irq(&res, 0); 116 1.1 jmcneill if (irq == NULL) { 117 1.1 jmcneill aprint_error_dev(self, "couldn't find irq resource\n"); 118 1.1 jmcneill goto done; 119 1.1 jmcneill } 120 1.1 jmcneill 121 1.1 jmcneill base_addr = acpi_compatible_lookup(aa, compat_data)->value; 122 1.1 jmcneill 123 1.1 jmcneill sc->sc_dev = self; 124 1.1 jmcneill sc->sc_iot = aa->aa_memt; 125 1.1 jmcneill if (bus_space_map(sc->sc_iot, base_addr, QCIPCC_SIZE, 126 1.1 jmcneill BUS_SPACE_MAP_NONPOSTED, &sc->sc_ioh) != 0) { 127 1.1 jmcneill aprint_error_dev(self, "couldn't map registers\n"); 128 1.1 jmcneill goto done; 129 1.1 jmcneill } 130 1.1 jmcneill 131 1.1 jmcneill TAILQ_INIT(&sc->sc_intrq); 132 1.1 jmcneill 133 1.1 jmcneill sc->sc_ih = acpi_intr_establish(self, 134 1.1 jmcneill (uint64_t)(uintptr_t)hdl, 135 1.1 jmcneill IPL_VM, false, qcipcc_intr, sc, device_xname(self)); 136 1.1 jmcneill if (sc->sc_ih == NULL) { 137 1.1 jmcneill aprint_error_dev(self, 138 1.1 jmcneill "couldn't establish interrupt\n"); 139 1.1 jmcneill goto done; 140 1.1 jmcneill } 141 1.1 jmcneill 142 1.1 jmcneill qcipcc = sc; 143 1.1 jmcneill 144 1.1 jmcneill done: 145 1.1 jmcneill acpi_resource_cleanup(&res); 146 1.1 jmcneill } 147 1.1 jmcneill 148 1.1 jmcneill static int 149 1.1 jmcneill qcipcc_intr(void *arg) 150 1.1 jmcneill { 151 1.1 jmcneill struct qcipcc_softc *sc = arg; 152 1.1 jmcneill struct qcipcc_intrhand *ih; 153 1.1 jmcneill uint16_t client_id, signal_id; 154 1.1 jmcneill uint32_t reg; 155 1.1 jmcneill int handled = 0; 156 1.1 jmcneill 157 1.1 jmcneill while ((reg = HREAD4(sc, IPCC_RECV_ID)) != ~0) { 158 1.1 jmcneill HWRITE4(sc, IPCC_RECV_SIGNAL_CLEAR, reg); 159 1.1 jmcneill 160 1.1 jmcneill client_id = __SHIFTOUT(reg, IPCC_CLIENT_ID_MASK); 161 1.1 jmcneill signal_id = __SHIFTOUT(reg, IPCC_SIGNAL_ID_MASK); 162 1.1 jmcneill 163 1.1 jmcneill TAILQ_FOREACH(ih, &sc->sc_intrq, ih_q) { 164 1.1 jmcneill if (ih->ih_client_id != client_id || 165 1.1 jmcneill ih->ih_signal_id != signal_id) 166 1.1 jmcneill continue; 167 1.1 jmcneill ih->ih_func(ih->ih_arg); 168 1.1 jmcneill handled = 1; 169 1.1 jmcneill } 170 1.1 jmcneill } 171 1.1 jmcneill 172 1.1 jmcneill return handled; 173 1.1 jmcneill } 174 1.1 jmcneill 175 1.1 jmcneill void * 176 1.1 jmcneill qcipcc_intr_establish(uint16_t client_id, uint16_t signal_id, int ipl, 177 1.1 jmcneill int (*func)(void *), void *arg) 178 1.1 jmcneill { 179 1.1 jmcneill struct qcipcc_softc *sc = qcipcc; 180 1.1 jmcneill struct qcipcc_intrhand *ih; 181 1.1 jmcneill 182 1.1 jmcneill if (sc == NULL) { 183 1.1 jmcneill return NULL; 184 1.1 jmcneill } 185 1.1 jmcneill 186 1.1 jmcneill ih = kmem_zalloc(sizeof(*ih), KM_SLEEP); 187 1.1 jmcneill ih->ih_func = func; 188 1.1 jmcneill ih->ih_arg = arg; 189 1.1 jmcneill ih->ih_sc = sc; 190 1.1 jmcneill ih->ih_client_id = client_id; 191 1.1 jmcneill ih->ih_signal_id = signal_id; 192 1.1 jmcneill TAILQ_INSERT_TAIL(&sc->sc_intrq, ih, ih_q); 193 1.1 jmcneill 194 1.1 jmcneill qcipcc_intr_enable(ih); 195 1.1 jmcneill 196 1.1 jmcneill return ih; 197 1.1 jmcneill } 198 1.1 jmcneill 199 1.1 jmcneill void 200 1.1 jmcneill qcipcc_intr_disestablish(void *cookie) 201 1.1 jmcneill { 202 1.1 jmcneill struct qcipcc_intrhand *ih = cookie; 203 1.1 jmcneill struct qcipcc_softc *sc = ih->ih_sc; 204 1.1 jmcneill 205 1.1 jmcneill qcipcc_intr_disable(ih); 206 1.1 jmcneill 207 1.1 jmcneill TAILQ_REMOVE(&sc->sc_intrq, ih, ih_q); 208 1.1 jmcneill kmem_free(ih, sizeof(*ih)); 209 1.1 jmcneill } 210 1.1 jmcneill 211 1.1 jmcneill void 212 1.1 jmcneill qcipcc_intr_enable(void *cookie) 213 1.1 jmcneill { 214 1.1 jmcneill struct qcipcc_intrhand *ih = cookie; 215 1.1 jmcneill struct qcipcc_softc *sc = ih->ih_sc; 216 1.1 jmcneill 217 1.1 jmcneill HWRITE4(sc, IPCC_RECV_SIGNAL_ENABLE, 218 1.1 jmcneill __SHIFTIN(ih->ih_client_id, IPCC_CLIENT_ID_MASK) | 219 1.1 jmcneill __SHIFTIN(ih->ih_signal_id, IPCC_SIGNAL_ID_MASK)); 220 1.1 jmcneill } 221 1.1 jmcneill 222 1.1 jmcneill void 223 1.1 jmcneill qcipcc_intr_disable(void *cookie) 224 1.1 jmcneill { 225 1.1 jmcneill struct qcipcc_intrhand *ih = cookie; 226 1.1 jmcneill struct qcipcc_softc *sc = ih->ih_sc; 227 1.1 jmcneill 228 1.1 jmcneill HWRITE4(sc, IPCC_RECV_SIGNAL_DISABLE, 229 1.1 jmcneill __SHIFTIN(ih->ih_client_id, IPCC_CLIENT_ID_MASK) | 230 1.1 jmcneill __SHIFTIN(ih->ih_signal_id, IPCC_SIGNAL_ID_MASK)); 231 1.1 jmcneill } 232 1.1 jmcneill 233 1.1 jmcneill void * 234 1.1 jmcneill qcipcc_channel(uint16_t client_id, uint16_t signal_id) 235 1.1 jmcneill { 236 1.1 jmcneill struct qcipcc_softc *sc = qcipcc; 237 1.1 jmcneill struct qcipcc_channel *ch; 238 1.1 jmcneill 239 1.1 jmcneill if (qcipcc == NULL) { 240 1.1 jmcneill return NULL; 241 1.1 jmcneill } 242 1.1 jmcneill 243 1.1 jmcneill ch = kmem_zalloc(sizeof(*ch), KM_SLEEP); 244 1.1 jmcneill ch->ch_sc = sc; 245 1.1 jmcneill ch->ch_client_id = client_id; 246 1.1 jmcneill ch->ch_signal_id = signal_id; 247 1.1 jmcneill 248 1.1 jmcneill return ch; 249 1.1 jmcneill } 250 1.1 jmcneill 251 1.1 jmcneill int 252 1.1 jmcneill qcipcc_send(void *cookie) 253 1.1 jmcneill { 254 1.1 jmcneill struct qcipcc_channel *ch = cookie; 255 1.1 jmcneill struct qcipcc_softc *sc = ch->ch_sc; 256 1.1 jmcneill 257 1.1 jmcneill HWRITE4(sc, IPCC_SEND_ID, 258 1.1 jmcneill __SHIFTIN(ch->ch_client_id, IPCC_CLIENT_ID_MASK) | 259 1.1 jmcneill __SHIFTIN(ch->ch_signal_id, IPCC_SIGNAL_ID_MASK)); 260 1.1 jmcneill 261 1.1 jmcneill return 0; 262 1.1 jmcneill } 263