1*5b1af194Sjmcneill /* $NetBSD: qcompep.c,v 1.2 2025/01/08 22:58:05 jmcneill Exp $ */ 2c95a3ae2Sjmcneill /* $OpenBSD: qcaoss.c,v 1.1 2023/05/23 14:10:27 patrick Exp $ */ 3*5b1af194Sjmcneill /* $OpenBSD: qccpucp.c,v 1.1 2024/11/16 21:17:54 tobhe Exp $ */ 4c95a3ae2Sjmcneill /* 5c95a3ae2Sjmcneill * Copyright (c) 2023 Patrick Wildt <patrick@blueri.se> 6*5b1af194Sjmcneill * Copyright (c) 2024 Tobias Heider <tobhe@openbsd.org> 7c95a3ae2Sjmcneill * 8c95a3ae2Sjmcneill * Permission to use, copy, modify, and distribute this software for any 9c95a3ae2Sjmcneill * purpose with or without fee is hereby granted, provided that the above 10c95a3ae2Sjmcneill * copyright notice and this permission notice appear in all copies. 11c95a3ae2Sjmcneill * 12c95a3ae2Sjmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13c95a3ae2Sjmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14c95a3ae2Sjmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15c95a3ae2Sjmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16c95a3ae2Sjmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17c95a3ae2Sjmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18c95a3ae2Sjmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19c95a3ae2Sjmcneill */ 20c95a3ae2Sjmcneill 21c95a3ae2Sjmcneill #include <sys/param.h> 22c95a3ae2Sjmcneill #include <sys/systm.h> 23c95a3ae2Sjmcneill #include <sys/device.h> 24c95a3ae2Sjmcneill #include <sys/kmem.h> 25c95a3ae2Sjmcneill 26c95a3ae2Sjmcneill #include <dev/acpi/acpivar.h> 27c95a3ae2Sjmcneill #include <dev/acpi/qcompep.h> 28c95a3ae2Sjmcneill #include <dev/acpi/qcomipcc.h> 29c95a3ae2Sjmcneill 30*5b1af194Sjmcneill #include <dev/ic/scmi.h> 31*5b1af194Sjmcneill 32c95a3ae2Sjmcneill #define AOSS_DESC_MAGIC 0x0 33c95a3ae2Sjmcneill #define AOSS_DESC_VERSION 0x4 34c95a3ae2Sjmcneill #define AOSS_DESC_FEATURES 0x8 35c95a3ae2Sjmcneill #define AOSS_DESC_UCORE_LINK_STATE 0xc 36c95a3ae2Sjmcneill #define AOSS_DESC_UCORE_LINK_STATE_ACK 0x10 37c95a3ae2Sjmcneill #define AOSS_DESC_UCORE_CH_STATE 0x14 38c95a3ae2Sjmcneill #define AOSS_DESC_UCORE_CH_STATE_ACK 0x18 39c95a3ae2Sjmcneill #define AOSS_DESC_UCORE_MBOX_SIZE 0x1c 40c95a3ae2Sjmcneill #define AOSS_DESC_UCORE_MBOX_OFFSET 0x20 41c95a3ae2Sjmcneill #define AOSS_DESC_MCORE_LINK_STATE 0x24 42c95a3ae2Sjmcneill #define AOSS_DESC_MCORE_LINK_STATE_ACK 0x28 43c95a3ae2Sjmcneill #define AOSS_DESC_MCORE_CH_STATE 0x2c 44c95a3ae2Sjmcneill #define AOSS_DESC_MCORE_CH_STATE_ACK 0x30 45c95a3ae2Sjmcneill #define AOSS_DESC_MCORE_MBOX_SIZE 0x34 46c95a3ae2Sjmcneill #define AOSS_DESC_MCORE_MBOX_OFFSET 0x38 47c95a3ae2Sjmcneill 48c95a3ae2Sjmcneill #define AOSS_MAGIC 0x4d41494c 49c95a3ae2Sjmcneill #define AOSS_VERSION 1 50c95a3ae2Sjmcneill 51c95a3ae2Sjmcneill #define AOSS_STATE_UP (0xffffU << 0) 52c95a3ae2Sjmcneill #define AOSS_STATE_DOWN (0xffffU << 16) 53c95a3ae2Sjmcneill 54c95a3ae2Sjmcneill #define AOSSREAD4(sc, reg) \ 55c95a3ae2Sjmcneill bus_space_read_4((sc)->sc_iot, (sc)->sc_aoss_ioh, (reg)) 56c95a3ae2Sjmcneill #define AOSSWRITE4(sc, reg, val) \ 57c95a3ae2Sjmcneill bus_space_write_4((sc)->sc_iot, (sc)->sc_aoss_ioh, (reg), (val)) 58c95a3ae2Sjmcneill 59*5b1af194Sjmcneill #define CPUCP_REG_CMD(i) (0x104 + ((i) * 8)) 60*5b1af194Sjmcneill #define CPUCP_MASK_CMD 0xffffffffffffffffULL 61*5b1af194Sjmcneill #define CPUCP_REG_RX_MAP 0x4000 62*5b1af194Sjmcneill #define CPUCP_REG_RX_STAT 0x4400 63*5b1af194Sjmcneill #define CPUCP_REG_RX_CLEAR 0x4800 64*5b1af194Sjmcneill #define CPUCP_REG_RX_EN 0x4C00 65*5b1af194Sjmcneill 66*5b1af194Sjmcneill #define RXREAD8(sc, reg) \ 67*5b1af194Sjmcneill (bus_space_read_8((sc)->sc_iot, (sc)->sc_cpucp_rx_ioh, (reg))) 68*5b1af194Sjmcneill #define RXWRITE8(sc, reg, val) \ 69*5b1af194Sjmcneill bus_space_write_8((sc)->sc_iot, (sc)->sc_cpucp_rx_ioh, (reg), (val)) 70*5b1af194Sjmcneill 71*5b1af194Sjmcneill #define TXWRITE4(sc, reg, val) \ 72*5b1af194Sjmcneill bus_space_write_4((sc)->sc_iot, (sc)->sc_cpucp_tx_ioh, (reg), (val)) 73*5b1af194Sjmcneill 74*5b1af194Sjmcneill 75c95a3ae2Sjmcneill struct qcpep_data { 76c95a3ae2Sjmcneill bus_addr_t aoss_base; 77c95a3ae2Sjmcneill bus_size_t aoss_size; 78c95a3ae2Sjmcneill uint32_t aoss_client_id; 79c95a3ae2Sjmcneill uint32_t aoss_signal_id; 80*5b1af194Sjmcneill bus_addr_t cpucp_rx_base; 81*5b1af194Sjmcneill bus_size_t cpucp_rx_size; 82*5b1af194Sjmcneill bus_addr_t cpucp_tx_base; 83*5b1af194Sjmcneill bus_size_t cpucp_tx_size; 84*5b1af194Sjmcneill bus_addr_t cpucp_shmem_base; 85*5b1af194Sjmcneill bus_size_t cpucp_shmem_size; 86c95a3ae2Sjmcneill }; 87c95a3ae2Sjmcneill 88c95a3ae2Sjmcneill struct qcpep_softc { 89c95a3ae2Sjmcneill device_t sc_dev; 90c95a3ae2Sjmcneill bus_space_tag_t sc_iot; 91c95a3ae2Sjmcneill 92c95a3ae2Sjmcneill const struct qcpep_data *sc_data; 93c95a3ae2Sjmcneill 94c95a3ae2Sjmcneill bus_space_handle_t sc_aoss_ioh; 95c95a3ae2Sjmcneill size_t sc_aoss_offset; 96c95a3ae2Sjmcneill size_t sc_aoss_size; 97c95a3ae2Sjmcneill void * sc_aoss_ipcc; 98*5b1af194Sjmcneill 99*5b1af194Sjmcneill bus_space_handle_t sc_cpucp_rx_ioh; 100*5b1af194Sjmcneill bus_space_handle_t sc_cpucp_tx_ioh; 101*5b1af194Sjmcneill 102*5b1af194Sjmcneill struct scmi_softc sc_scmi; 103c95a3ae2Sjmcneill }; 104c95a3ae2Sjmcneill 105c95a3ae2Sjmcneill struct qcpep_softc *qcpep_sc; 106c95a3ae2Sjmcneill 107c95a3ae2Sjmcneill static const struct qcpep_data qcpep_x1e_data = { 108c95a3ae2Sjmcneill .aoss_base = 0x0c300000, 109c95a3ae2Sjmcneill .aoss_size = 0x400, 110c95a3ae2Sjmcneill .aoss_client_id = 0, /* IPCC_CLIENT_AOP */ 111c95a3ae2Sjmcneill .aoss_signal_id = 0, /* IPCC_MPROC_SIGNAL_GLINK_QMP */ 112*5b1af194Sjmcneill .cpucp_rx_base = 0x17430000, 113*5b1af194Sjmcneill .cpucp_rx_size = 0x10000, 114*5b1af194Sjmcneill .cpucp_tx_base = 0x18830000, 115*5b1af194Sjmcneill .cpucp_tx_size = 0x10000, 116*5b1af194Sjmcneill .cpucp_shmem_base = 0x18b4e000, 117*5b1af194Sjmcneill .cpucp_shmem_size = 0x400, 118c95a3ae2Sjmcneill }; 119c95a3ae2Sjmcneill 120c95a3ae2Sjmcneill static const struct device_compatible_entry compat_data[] = { 121c95a3ae2Sjmcneill { .compat = "QCOM0C17", .data = &qcpep_x1e_data }, 122c95a3ae2Sjmcneill DEVICE_COMPAT_EOL 123c95a3ae2Sjmcneill }; 124c95a3ae2Sjmcneill 125c95a3ae2Sjmcneill static int qcpep_match(device_t, cfdata_t, void *); 126c95a3ae2Sjmcneill static void qcpep_attach(device_t, device_t, void *); 127c95a3ae2Sjmcneill 128c95a3ae2Sjmcneill CFATTACH_DECL_NEW(qcompep, sizeof(struct qcpep_softc), 129c95a3ae2Sjmcneill qcpep_match, qcpep_attach, NULL, NULL); 130c95a3ae2Sjmcneill 131c95a3ae2Sjmcneill static int 132c95a3ae2Sjmcneill qcpep_match(device_t parent, cfdata_t match, void *aux) 133c95a3ae2Sjmcneill { 134c95a3ae2Sjmcneill struct acpi_attach_args *aa = aux; 135c95a3ae2Sjmcneill 136c95a3ae2Sjmcneill return acpi_compatible_match(aa, compat_data); 137c95a3ae2Sjmcneill } 138c95a3ae2Sjmcneill 139c95a3ae2Sjmcneill static void 140c95a3ae2Sjmcneill qcpep_attach(device_t parent, device_t self, void *aux) 141c95a3ae2Sjmcneill { 142c95a3ae2Sjmcneill struct qcpep_softc *sc = device_private(self); 143c95a3ae2Sjmcneill struct acpi_attach_args *aa = aux; 144*5b1af194Sjmcneill CPU_INFO_ITERATOR cii; 145*5b1af194Sjmcneill struct cpu_info *ci; 146c95a3ae2Sjmcneill struct acpi_resources res; 147*5b1af194Sjmcneill uint8_t *scmi_shmem; 148c95a3ae2Sjmcneill ACPI_STATUS rv; 149*5b1af194Sjmcneill int i, last_pkg;; 150c95a3ae2Sjmcneill 151c95a3ae2Sjmcneill rv = acpi_resource_parse(self, aa->aa_node->ad_handle, 152c95a3ae2Sjmcneill "_CRS", &res, &acpi_resource_parse_ops_default); 153c95a3ae2Sjmcneill if (ACPI_FAILURE(rv)) { 154c95a3ae2Sjmcneill return; 155c95a3ae2Sjmcneill } 156c95a3ae2Sjmcneill acpi_resource_cleanup(&res); 157c95a3ae2Sjmcneill 158c95a3ae2Sjmcneill sc->sc_dev = self; 159c95a3ae2Sjmcneill sc->sc_iot = aa->aa_memt; 160c95a3ae2Sjmcneill sc->sc_data = acpi_compatible_lookup(aa, compat_data)->data; 161c95a3ae2Sjmcneill 162c95a3ae2Sjmcneill if (bus_space_map(sc->sc_iot, sc->sc_data->aoss_base, 163c95a3ae2Sjmcneill sc->sc_data->aoss_size, BUS_SPACE_MAP_NONPOSTED, &sc->sc_aoss_ioh)) { 164*5b1af194Sjmcneill aprint_error_dev(self, "couldn't map aoss registers\n"); 165*5b1af194Sjmcneill return; 166*5b1af194Sjmcneill } 167*5b1af194Sjmcneill if (bus_space_map(sc->sc_iot, sc->sc_data->cpucp_rx_base, 168*5b1af194Sjmcneill sc->sc_data->cpucp_rx_size, BUS_SPACE_MAP_NONPOSTED, 169*5b1af194Sjmcneill &sc->sc_cpucp_rx_ioh)) { 170*5b1af194Sjmcneill aprint_error_dev(self, "couldn't map cpucp rx registers\n"); 171*5b1af194Sjmcneill return; 172*5b1af194Sjmcneill } 173*5b1af194Sjmcneill if (bus_space_map(sc->sc_iot, sc->sc_data->cpucp_tx_base, 174*5b1af194Sjmcneill sc->sc_data->cpucp_tx_size, BUS_SPACE_MAP_NONPOSTED, 175*5b1af194Sjmcneill &sc->sc_cpucp_tx_ioh)) { 176*5b1af194Sjmcneill aprint_error_dev(self, "couldn't map cpucp tx registers\n"); 177c95a3ae2Sjmcneill return; 178c95a3ae2Sjmcneill } 179c95a3ae2Sjmcneill 180c95a3ae2Sjmcneill sc->sc_aoss_ipcc = qcipcc_channel(sc->sc_data->aoss_client_id, 181c95a3ae2Sjmcneill sc->sc_data->aoss_signal_id); 182c95a3ae2Sjmcneill if (sc->sc_aoss_ipcc == NULL) { 183c95a3ae2Sjmcneill aprint_error_dev(self, "couldn't find ipcc mailbox\n"); 184c95a3ae2Sjmcneill return; 185c95a3ae2Sjmcneill } 186c95a3ae2Sjmcneill 187c95a3ae2Sjmcneill if (AOSSREAD4(sc, AOSS_DESC_MAGIC) != AOSS_MAGIC || 188c95a3ae2Sjmcneill AOSSREAD4(sc, AOSS_DESC_VERSION) != AOSS_VERSION) { 189c95a3ae2Sjmcneill aprint_error_dev(self, "invalid QMP info\n"); 190c95a3ae2Sjmcneill return; 191c95a3ae2Sjmcneill } 192c95a3ae2Sjmcneill 193c95a3ae2Sjmcneill sc->sc_aoss_offset = AOSSREAD4(sc, AOSS_DESC_MCORE_MBOX_OFFSET); 194c95a3ae2Sjmcneill sc->sc_aoss_size = AOSSREAD4(sc, AOSS_DESC_MCORE_MBOX_SIZE); 195c95a3ae2Sjmcneill if (sc->sc_aoss_size == 0) { 196c95a3ae2Sjmcneill aprint_error_dev(self, "invalid AOSS mailbox size\n"); 197c95a3ae2Sjmcneill return; 198c95a3ae2Sjmcneill } 199c95a3ae2Sjmcneill 200c95a3ae2Sjmcneill AOSSWRITE4(sc, AOSS_DESC_UCORE_LINK_STATE_ACK, 201c95a3ae2Sjmcneill AOSSREAD4(sc, AOSS_DESC_UCORE_LINK_STATE)); 202c95a3ae2Sjmcneill 203c95a3ae2Sjmcneill AOSSWRITE4(sc, AOSS_DESC_MCORE_LINK_STATE, AOSS_STATE_UP); 204c95a3ae2Sjmcneill qcipcc_send(sc->sc_aoss_ipcc); 205c95a3ae2Sjmcneill 206c95a3ae2Sjmcneill for (i = 1000; i > 0; i--) { 207c95a3ae2Sjmcneill if (AOSSREAD4(sc, AOSS_DESC_MCORE_LINK_STATE_ACK) == AOSS_STATE_UP) 208c95a3ae2Sjmcneill break; 209c95a3ae2Sjmcneill delay(1000); 210c95a3ae2Sjmcneill } 211c95a3ae2Sjmcneill if (i == 0) { 212c95a3ae2Sjmcneill aprint_error_dev(self, "didn't get link state ack\n"); 213c95a3ae2Sjmcneill return; 214c95a3ae2Sjmcneill } 215c95a3ae2Sjmcneill 216c95a3ae2Sjmcneill AOSSWRITE4(sc, AOSS_DESC_MCORE_CH_STATE, AOSS_STATE_UP); 217c95a3ae2Sjmcneill qcipcc_send(sc->sc_aoss_ipcc); 218c95a3ae2Sjmcneill 219c95a3ae2Sjmcneill for (i = 1000; i > 0; i--) { 220c95a3ae2Sjmcneill if (AOSSREAD4(sc, AOSS_DESC_UCORE_CH_STATE) == AOSS_STATE_UP) 221c95a3ae2Sjmcneill break; 222c95a3ae2Sjmcneill delay(1000); 223c95a3ae2Sjmcneill } 224c95a3ae2Sjmcneill if (i == 0) { 225c95a3ae2Sjmcneill aprint_error_dev(self, "didn't get open channel\n"); 226c95a3ae2Sjmcneill return; 227c95a3ae2Sjmcneill } 228c95a3ae2Sjmcneill 229c95a3ae2Sjmcneill AOSSWRITE4(sc, AOSS_DESC_UCORE_CH_STATE_ACK, AOSS_STATE_UP); 230c95a3ae2Sjmcneill qcipcc_send(sc->sc_aoss_ipcc); 231c95a3ae2Sjmcneill 232c95a3ae2Sjmcneill for (i = 1000; i > 0; i--) { 233c95a3ae2Sjmcneill if (AOSSREAD4(sc, AOSS_DESC_MCORE_CH_STATE_ACK) == AOSS_STATE_UP) 234c95a3ae2Sjmcneill break; 235c95a3ae2Sjmcneill delay(1000); 236c95a3ae2Sjmcneill } 237c95a3ae2Sjmcneill if (i == 0) { 238c95a3ae2Sjmcneill aprint_error_dev(self, "didn't get channel ack\n"); 239c95a3ae2Sjmcneill return; 240c95a3ae2Sjmcneill } 241c95a3ae2Sjmcneill 242*5b1af194Sjmcneill RXWRITE8(sc, CPUCP_REG_RX_EN, 0); 243*5b1af194Sjmcneill RXWRITE8(sc, CPUCP_REG_RX_CLEAR, 0); 244*5b1af194Sjmcneill RXWRITE8(sc, CPUCP_REG_RX_MAP, 0); 245*5b1af194Sjmcneill RXWRITE8(sc, CPUCP_REG_RX_MAP, CPUCP_MASK_CMD); 246*5b1af194Sjmcneill 247c95a3ae2Sjmcneill qcpep_sc = sc; 248*5b1af194Sjmcneill 249*5b1af194Sjmcneill /* SCMI setup */ 250*5b1af194Sjmcneill scmi_shmem = AcpiOsMapMemory(sc->sc_data->cpucp_shmem_base, 251*5b1af194Sjmcneill sc->sc_data->cpucp_shmem_size); 252*5b1af194Sjmcneill if (scmi_shmem == NULL) { 253*5b1af194Sjmcneill aprint_error_dev(self, "couldn't map SCMI shared memory\n"); 254*5b1af194Sjmcneill return; 255*5b1af194Sjmcneill } 256*5b1af194Sjmcneill 257*5b1af194Sjmcneill sc->sc_scmi.sc_dev = self; 258*5b1af194Sjmcneill sc->sc_scmi.sc_iot = sc->sc_iot; 259*5b1af194Sjmcneill sc->sc_scmi.sc_shmem_tx = (struct scmi_shmem *)(scmi_shmem + 0x000); 260*5b1af194Sjmcneill sc->sc_scmi.sc_shmem_rx = (struct scmi_shmem *)(scmi_shmem + 0x200); 261*5b1af194Sjmcneill sc->sc_scmi.sc_mbox_tx = qccpucp_channel(0); 262*5b1af194Sjmcneill sc->sc_scmi.sc_mbox_tx_send = qccpucp_send; 263*5b1af194Sjmcneill sc->sc_scmi.sc_mbox_rx = qccpucp_channel(2); 264*5b1af194Sjmcneill sc->sc_scmi.sc_mbox_rx_send = qccpucp_send; 265*5b1af194Sjmcneill /* Build performance domain to CPU map. */ 266*5b1af194Sjmcneill sc->sc_scmi.sc_perf_ndmap = 0; 267*5b1af194Sjmcneill last_pkg = -1; 268*5b1af194Sjmcneill for (CPU_INFO_FOREACH(cii, ci)) { 269*5b1af194Sjmcneill if (ci->ci_package_id != last_pkg) { 270*5b1af194Sjmcneill sc->sc_scmi.sc_perf_ndmap++; 271*5b1af194Sjmcneill last_pkg = ci->ci_package_id; 272*5b1af194Sjmcneill } 273*5b1af194Sjmcneill } 274*5b1af194Sjmcneill sc->sc_scmi.sc_perf_dmap = kmem_zalloc( 275*5b1af194Sjmcneill sizeof(*sc->sc_scmi.sc_perf_dmap) * sc->sc_scmi.sc_perf_ndmap, 276*5b1af194Sjmcneill KM_SLEEP); 277*5b1af194Sjmcneill last_pkg = -1; 278*5b1af194Sjmcneill i = 0; 279*5b1af194Sjmcneill for (CPU_INFO_FOREACH(cii, ci)) { 280*5b1af194Sjmcneill if (ci->ci_package_id != last_pkg) { 281*5b1af194Sjmcneill sc->sc_scmi.sc_perf_dmap[i].pm_domain = i; 282*5b1af194Sjmcneill sc->sc_scmi.sc_perf_dmap[i].pm_ci = ci; 283*5b1af194Sjmcneill last_pkg = ci->ci_package_id; 284*5b1af194Sjmcneill i++; 285*5b1af194Sjmcneill } 286*5b1af194Sjmcneill } 287*5b1af194Sjmcneill if (scmi_init_mbox(&sc->sc_scmi) != 0) { 288*5b1af194Sjmcneill aprint_error_dev(self, "couldn't setup SCMI\n"); 289*5b1af194Sjmcneill return; 290*5b1af194Sjmcneill } 291*5b1af194Sjmcneill scmi_attach_perf(&sc->sc_scmi); 292c95a3ae2Sjmcneill } 293c95a3ae2Sjmcneill 294c95a3ae2Sjmcneill int 295c95a3ae2Sjmcneill qcaoss_send(char *data, size_t len) 296c95a3ae2Sjmcneill { 297c95a3ae2Sjmcneill struct qcpep_softc *sc = qcpep_sc; 298c95a3ae2Sjmcneill uint32_t reg; 299c95a3ae2Sjmcneill int i; 300c95a3ae2Sjmcneill 301c95a3ae2Sjmcneill if (sc == NULL) 302c95a3ae2Sjmcneill return ENXIO; 303c95a3ae2Sjmcneill 304c95a3ae2Sjmcneill if (data == NULL || sizeof(uint32_t) + len > sc->sc_aoss_size || 305c95a3ae2Sjmcneill (len % sizeof(uint32_t)) != 0) 306c95a3ae2Sjmcneill return EINVAL; 307c95a3ae2Sjmcneill 308c95a3ae2Sjmcneill /* Write data first, needs to be 32-bit access. */ 309c95a3ae2Sjmcneill for (i = 0; i < len; i += 4) { 310c95a3ae2Sjmcneill memcpy(®, data + i, sizeof(reg)); 311c95a3ae2Sjmcneill AOSSWRITE4(sc, sc->sc_aoss_offset + sizeof(uint32_t) + i, reg); 312c95a3ae2Sjmcneill } 313c95a3ae2Sjmcneill 314c95a3ae2Sjmcneill /* Commit transaction by writing length. */ 315c95a3ae2Sjmcneill AOSSWRITE4(sc, sc->sc_aoss_offset, len); 316c95a3ae2Sjmcneill 317c95a3ae2Sjmcneill /* Assert it's stored and inform peer. */ 318c95a3ae2Sjmcneill if (AOSSREAD4(sc, sc->sc_aoss_offset) != len) { 319c95a3ae2Sjmcneill device_printf(sc->sc_dev, 320c95a3ae2Sjmcneill "aoss message readback failed\n"); 321c95a3ae2Sjmcneill } 322c95a3ae2Sjmcneill qcipcc_send(sc->sc_aoss_ipcc); 323c95a3ae2Sjmcneill 324c95a3ae2Sjmcneill for (i = 1000; i > 0; i--) { 325c95a3ae2Sjmcneill if (AOSSREAD4(sc, sc->sc_aoss_offset) == 0) 326c95a3ae2Sjmcneill break; 327c95a3ae2Sjmcneill delay(1000); 328c95a3ae2Sjmcneill } 329c95a3ae2Sjmcneill if (i == 0) { 330c95a3ae2Sjmcneill device_printf(sc->sc_dev, "timeout sending message\n"); 331c95a3ae2Sjmcneill AOSSWRITE4(sc, sc->sc_aoss_offset, 0); 332c95a3ae2Sjmcneill return ETIMEDOUT; 333c95a3ae2Sjmcneill } 334c95a3ae2Sjmcneill 335c95a3ae2Sjmcneill return 0; 336c95a3ae2Sjmcneill } 337*5b1af194Sjmcneill 338*5b1af194Sjmcneill void * 339*5b1af194Sjmcneill qccpucp_channel(u_int id) 340*5b1af194Sjmcneill { 341*5b1af194Sjmcneill struct qcpep_softc *sc = qcpep_sc; 342*5b1af194Sjmcneill uint64_t val; 343*5b1af194Sjmcneill 344*5b1af194Sjmcneill if (sc == NULL || id > 2) { 345*5b1af194Sjmcneill return NULL; 346*5b1af194Sjmcneill } 347*5b1af194Sjmcneill 348*5b1af194Sjmcneill val = RXREAD8(sc, CPUCP_REG_RX_EN); 349*5b1af194Sjmcneill val |= (1 << id); 350*5b1af194Sjmcneill RXWRITE8(sc, CPUCP_REG_RX_EN, val); 351*5b1af194Sjmcneill 352*5b1af194Sjmcneill return (void *)(uintptr_t)(id + 1); 353*5b1af194Sjmcneill } 354*5b1af194Sjmcneill 355*5b1af194Sjmcneill int 356*5b1af194Sjmcneill qccpucp_send(void *cookie) 357*5b1af194Sjmcneill { 358*5b1af194Sjmcneill struct qcpep_softc *sc = qcpep_sc; 359*5b1af194Sjmcneill uintptr_t id = (uintptr_t)cookie - 1; 360*5b1af194Sjmcneill 361*5b1af194Sjmcneill TXWRITE4(sc, CPUCP_REG_CMD(id), 0); 362*5b1af194Sjmcneill 363*5b1af194Sjmcneill return 0; 364*5b1af194Sjmcneill } 365