1*c95a3ae2Sjmcneill /* $NetBSD: qcompas.c,v 1.1 2024/12/30 12:31:10 jmcneill Exp $ */ 2*c95a3ae2Sjmcneill /* $OpenBSD: qcpas.c,v 1.8 2024/11/08 21:13:34 landry Exp $ */ 3*c95a3ae2Sjmcneill /* 4*c95a3ae2Sjmcneill * Copyright (c) 2023 Patrick Wildt <patrick@blueri.se> 5*c95a3ae2Sjmcneill * 6*c95a3ae2Sjmcneill * Permission to use, copy, modify, and distribute this software for any 7*c95a3ae2Sjmcneill * purpose with or without fee is hereby granted, provided that the above 8*c95a3ae2Sjmcneill * copyright notice and this permission notice appear in all copies. 9*c95a3ae2Sjmcneill * 10*c95a3ae2Sjmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*c95a3ae2Sjmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*c95a3ae2Sjmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*c95a3ae2Sjmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*c95a3ae2Sjmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*c95a3ae2Sjmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*c95a3ae2Sjmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*c95a3ae2Sjmcneill */ 18*c95a3ae2Sjmcneill 19*c95a3ae2Sjmcneill #include <sys/param.h> 20*c95a3ae2Sjmcneill #include <sys/systm.h> 21*c95a3ae2Sjmcneill #include <sys/device.h> 22*c95a3ae2Sjmcneill #include <sys/kmem.h> 23*c95a3ae2Sjmcneill #include <sys/mutex.h> 24*c95a3ae2Sjmcneill #include <sys/condvar.h> 25*c95a3ae2Sjmcneill #include <sys/callout.h> 26*c95a3ae2Sjmcneill #include <sys/exec_elf.h> 27*c95a3ae2Sjmcneill 28*c95a3ae2Sjmcneill #include <dev/firmload.h> 29*c95a3ae2Sjmcneill #include <dev/sysmon/sysmonvar.h> 30*c95a3ae2Sjmcneill #include <dev/sysmon/sysmon_taskq.h> 31*c95a3ae2Sjmcneill 32*c95a3ae2Sjmcneill #include <dev/acpi/acpivar.h> 33*c95a3ae2Sjmcneill #include <dev/acpi/acpi_intr.h> 34*c95a3ae2Sjmcneill #include <dev/acpi/qcomipcc.h> 35*c95a3ae2Sjmcneill #include <dev/acpi/qcompep.h> 36*c95a3ae2Sjmcneill #include <dev/acpi/qcomscm.h> 37*c95a3ae2Sjmcneill #include <dev/acpi/qcomsmem.h> 38*c95a3ae2Sjmcneill #include <dev/acpi/qcomsmptp.h> 39*c95a3ae2Sjmcneill 40*c95a3ae2Sjmcneill #define DRIVER_NAME "qcompas" 41*c95a3ae2Sjmcneill 42*c95a3ae2Sjmcneill #define MDT_TYPE_MASK (7 << 24) 43*c95a3ae2Sjmcneill #define MDT_TYPE_HASH (2 << 24) 44*c95a3ae2Sjmcneill #define MDT_RELOCATABLE (1 << 27) 45*c95a3ae2Sjmcneill 46*c95a3ae2Sjmcneill extern struct arm32_bus_dma_tag arm_generic_dma_tag; 47*c95a3ae2Sjmcneill 48*c95a3ae2Sjmcneill enum qcpas_batt_sensor { 49*c95a3ae2Sjmcneill /* Battery sensors (must be first) */ 50*c95a3ae2Sjmcneill QCPAS_DVOLTAGE, 51*c95a3ae2Sjmcneill QCPAS_VOLTAGE, 52*c95a3ae2Sjmcneill QCPAS_DCAPACITY, 53*c95a3ae2Sjmcneill QCPAS_LFCCAPACITY, 54*c95a3ae2Sjmcneill QCPAS_CAPACITY, 55*c95a3ae2Sjmcneill QCPAS_CHARGERATE, 56*c95a3ae2Sjmcneill QCPAS_DISCHARGERATE, 57*c95a3ae2Sjmcneill QCPAS_CHARGING, 58*c95a3ae2Sjmcneill QCPAS_CHARGE_STATE, 59*c95a3ae2Sjmcneill QCPAS_DCYCLES, 60*c95a3ae2Sjmcneill QCPAS_TEMPERATURE, 61*c95a3ae2Sjmcneill /* AC adapter sensors */ 62*c95a3ae2Sjmcneill QCPAS_ACADAPTER, 63*c95a3ae2Sjmcneill /* Total number of sensors */ 64*c95a3ae2Sjmcneill QCPAS_NUM_SENSORS 65*c95a3ae2Sjmcneill }; 66*c95a3ae2Sjmcneill 67*c95a3ae2Sjmcneill struct qcpas_dmamem { 68*c95a3ae2Sjmcneill bus_dmamap_t tdm_map; 69*c95a3ae2Sjmcneill bus_dma_segment_t tdm_seg; 70*c95a3ae2Sjmcneill size_t tdm_size; 71*c95a3ae2Sjmcneill void *tdm_kva; 72*c95a3ae2Sjmcneill }; 73*c95a3ae2Sjmcneill #define QCPAS_DMA_MAP(_tdm) ((_tdm)->tdm_map) 74*c95a3ae2Sjmcneill #define QCPAS_DMA_LEN(_tdm) ((_tdm)->tdm_size) 75*c95a3ae2Sjmcneill #define QCPAS_DMA_DVA(_tdm) ((_tdm)->tdm_map->dm_segs[0].ds_addr) 76*c95a3ae2Sjmcneill #define QCPAS_DMA_KVA(_tdm) ((_tdm)->tdm_kva) 77*c95a3ae2Sjmcneill 78*c95a3ae2Sjmcneill struct qcpas_softc { 79*c95a3ae2Sjmcneill device_t sc_dev; 80*c95a3ae2Sjmcneill bus_dma_tag_t sc_dmat; 81*c95a3ae2Sjmcneill 82*c95a3ae2Sjmcneill char *sc_sub; 83*c95a3ae2Sjmcneill 84*c95a3ae2Sjmcneill void *sc_ih[5]; 85*c95a3ae2Sjmcneill 86*c95a3ae2Sjmcneill kmutex_t sc_ready_lock; 87*c95a3ae2Sjmcneill kcondvar_t sc_ready_cv; 88*c95a3ae2Sjmcneill bool sc_ready; 89*c95a3ae2Sjmcneill 90*c95a3ae2Sjmcneill paddr_t sc_mem_phys[2]; 91*c95a3ae2Sjmcneill size_t sc_mem_size[2]; 92*c95a3ae2Sjmcneill uint8_t *sc_mem_region[2]; 93*c95a3ae2Sjmcneill vaddr_t sc_mem_reloc[2]; 94*c95a3ae2Sjmcneill 95*c95a3ae2Sjmcneill const char *sc_fwname; 96*c95a3ae2Sjmcneill const char *sc_dtb_fwname; 97*c95a3ae2Sjmcneill uint32_t sc_pas_id; 98*c95a3ae2Sjmcneill uint32_t sc_dtb_pas_id; 99*c95a3ae2Sjmcneill uint32_t sc_lite_pas_id; 100*c95a3ae2Sjmcneill const char *sc_load_state; 101*c95a3ae2Sjmcneill uint32_t sc_glink_remote_pid; 102*c95a3ae2Sjmcneill uint32_t sc_crash_reason; 103*c95a3ae2Sjmcneill 104*c95a3ae2Sjmcneill struct qcpas_dmamem *sc_metadata[2]; 105*c95a3ae2Sjmcneill 106*c95a3ae2Sjmcneill /* GLINK */ 107*c95a3ae2Sjmcneill volatile uint32_t *sc_tx_tail; 108*c95a3ae2Sjmcneill volatile uint32_t *sc_tx_head; 109*c95a3ae2Sjmcneill volatile uint32_t *sc_rx_tail; 110*c95a3ae2Sjmcneill volatile uint32_t *sc_rx_head; 111*c95a3ae2Sjmcneill 112*c95a3ae2Sjmcneill uint32_t sc_tx_off; 113*c95a3ae2Sjmcneill uint32_t sc_rx_off; 114*c95a3ae2Sjmcneill 115*c95a3ae2Sjmcneill uint8_t *sc_tx_fifo; 116*c95a3ae2Sjmcneill int sc_tx_fifolen; 117*c95a3ae2Sjmcneill uint8_t *sc_rx_fifo; 118*c95a3ae2Sjmcneill int sc_rx_fifolen; 119*c95a3ae2Sjmcneill void *sc_glink_ih; 120*c95a3ae2Sjmcneill 121*c95a3ae2Sjmcneill void *sc_ipcc; 122*c95a3ae2Sjmcneill 123*c95a3ae2Sjmcneill uint32_t sc_glink_max_channel; 124*c95a3ae2Sjmcneill TAILQ_HEAD(,qcpas_glink_channel) sc_glink_channels; 125*c95a3ae2Sjmcneill 126*c95a3ae2Sjmcneill uint32_t sc_warning_capacity; 127*c95a3ae2Sjmcneill uint32_t sc_low_capacity; 128*c95a3ae2Sjmcneill uint32_t sc_power_state; 129*c95a3ae2Sjmcneill struct sysmon_envsys *sc_sme; 130*c95a3ae2Sjmcneill envsys_data_t sc_sens[QCPAS_NUM_SENSORS]; 131*c95a3ae2Sjmcneill struct sysmon_envsys *sc_sme_acadapter; 132*c95a3ae2Sjmcneill struct sysmon_pswitch sc_smpsw_acadapter; 133*c95a3ae2Sjmcneill callout_t sc_rtr_refresh; 134*c95a3ae2Sjmcneill }; 135*c95a3ae2Sjmcneill 136*c95a3ae2Sjmcneill static int qcpas_match(device_t, cfdata_t, void *); 137*c95a3ae2Sjmcneill static void qcpas_attach(device_t, device_t, void *); 138*c95a3ae2Sjmcneill 139*c95a3ae2Sjmcneill CFATTACH_DECL_NEW(qcompas, sizeof(struct qcpas_softc), 140*c95a3ae2Sjmcneill qcpas_match, qcpas_attach, NULL, NULL); 141*c95a3ae2Sjmcneill 142*c95a3ae2Sjmcneill static void qcpas_mountroot(device_t); 143*c95a3ae2Sjmcneill static void qcpas_firmload(void *); 144*c95a3ae2Sjmcneill static int qcpas_map_memory(struct qcpas_softc *); 145*c95a3ae2Sjmcneill static int qcpas_mdt_init(struct qcpas_softc *, int, u_char *, size_t); 146*c95a3ae2Sjmcneill static void qcpas_glink_attach(struct qcpas_softc *); 147*c95a3ae2Sjmcneill static void qcpas_glink_recv(void *); 148*c95a3ae2Sjmcneill static void qcpas_get_limits(struct sysmon_envsys *, envsys_data_t *, 149*c95a3ae2Sjmcneill sysmon_envsys_lim_t *, uint32_t *); 150*c95a3ae2Sjmcneill 151*c95a3ae2Sjmcneill static struct qcpas_dmamem * 152*c95a3ae2Sjmcneill qcpas_dmamem_alloc(struct qcpas_softc *, bus_size_t, bus_size_t); 153*c95a3ae2Sjmcneill static void qcpas_dmamem_free(struct qcpas_softc *, struct qcpas_dmamem *); 154*c95a3ae2Sjmcneill 155*c95a3ae2Sjmcneill static int qcpas_intr_wdog(void *); 156*c95a3ae2Sjmcneill static int qcpas_intr_fatal(void *); 157*c95a3ae2Sjmcneill static int qcpas_intr_ready(void *); 158*c95a3ae2Sjmcneill static int qcpas_intr_handover(void *); 159*c95a3ae2Sjmcneill static int qcpas_intr_stop_ack(void *); 160*c95a3ae2Sjmcneill 161*c95a3ae2Sjmcneill struct qcpas_mem_region { 162*c95a3ae2Sjmcneill bus_addr_t start; 163*c95a3ae2Sjmcneill bus_size_t size; 164*c95a3ae2Sjmcneill }; 165*c95a3ae2Sjmcneill 166*c95a3ae2Sjmcneill struct qcpas_data { 167*c95a3ae2Sjmcneill bus_addr_t reg_addr; 168*c95a3ae2Sjmcneill bus_size_t reg_size; 169*c95a3ae2Sjmcneill uint32_t pas_id; 170*c95a3ae2Sjmcneill uint32_t dtb_pas_id; 171*c95a3ae2Sjmcneill uint32_t lite_pas_id; 172*c95a3ae2Sjmcneill const char *load_state; 173*c95a3ae2Sjmcneill uint32_t glink_remote_pid; 174*c95a3ae2Sjmcneill struct qcpas_mem_region mem_region[2]; 175*c95a3ae2Sjmcneill const char *fwname; 176*c95a3ae2Sjmcneill const char *dtb_fwname; 177*c95a3ae2Sjmcneill uint32_t crash_reason; 178*c95a3ae2Sjmcneill }; 179*c95a3ae2Sjmcneill 180*c95a3ae2Sjmcneill static struct qcpas_data qcpas_x1e_data = { 181*c95a3ae2Sjmcneill .reg_addr = 0x30000000, 182*c95a3ae2Sjmcneill .reg_size = 0x100, 183*c95a3ae2Sjmcneill .pas_id = 1, 184*c95a3ae2Sjmcneill .dtb_pas_id = 36, 185*c95a3ae2Sjmcneill .lite_pas_id = 31, 186*c95a3ae2Sjmcneill .load_state = "adsp", 187*c95a3ae2Sjmcneill .glink_remote_pid = 2, 188*c95a3ae2Sjmcneill .mem_region = { 189*c95a3ae2Sjmcneill [0] = { .start = 0x87e00000, .size = 0x3a00000 }, 190*c95a3ae2Sjmcneill [1] = { .start = 0x8b800000, .size = 0x80000 }, 191*c95a3ae2Sjmcneill }, 192*c95a3ae2Sjmcneill .fwname = "qcadsp8380.mbn", 193*c95a3ae2Sjmcneill .dtb_fwname = "adsp_dtbs.elf", 194*c95a3ae2Sjmcneill .crash_reason = 423, 195*c95a3ae2Sjmcneill }; 196*c95a3ae2Sjmcneill 197*c95a3ae2Sjmcneill #define IPCC_CLIENT_LPASS 3 198*c95a3ae2Sjmcneill #define IPCC_MPROC_SIGNAL_GLINK_QMP 0 199*c95a3ae2Sjmcneill 200*c95a3ae2Sjmcneill static const struct device_compatible_entry compat_data[] = { 201*c95a3ae2Sjmcneill { .compat = "QCOM0C1B", .data = &qcpas_x1e_data }, 202*c95a3ae2Sjmcneill DEVICE_COMPAT_EOL 203*c95a3ae2Sjmcneill }; 204*c95a3ae2Sjmcneill 205*c95a3ae2Sjmcneill static int 206*c95a3ae2Sjmcneill qcpas_match(device_t parent, cfdata_t match, void *aux) 207*c95a3ae2Sjmcneill { 208*c95a3ae2Sjmcneill struct acpi_attach_args *aa = aux; 209*c95a3ae2Sjmcneill 210*c95a3ae2Sjmcneill return acpi_compatible_match(aa, compat_data); 211*c95a3ae2Sjmcneill } 212*c95a3ae2Sjmcneill 213*c95a3ae2Sjmcneill static void 214*c95a3ae2Sjmcneill qcpas_attach(device_t parent, device_t self, void *aux) 215*c95a3ae2Sjmcneill { 216*c95a3ae2Sjmcneill struct qcpas_softc *sc = device_private(self); 217*c95a3ae2Sjmcneill struct acpi_attach_args *aa = aux; 218*c95a3ae2Sjmcneill const struct qcpas_data *data; 219*c95a3ae2Sjmcneill struct acpi_resources res; 220*c95a3ae2Sjmcneill ACPI_STATUS rv; 221*c95a3ae2Sjmcneill int i; 222*c95a3ae2Sjmcneill 223*c95a3ae2Sjmcneill rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res, 224*c95a3ae2Sjmcneill &acpi_resource_parse_ops_default); 225*c95a3ae2Sjmcneill if (ACPI_FAILURE(rv)) { 226*c95a3ae2Sjmcneill return; 227*c95a3ae2Sjmcneill } 228*c95a3ae2Sjmcneill acpi_resource_cleanup(&res); 229*c95a3ae2Sjmcneill 230*c95a3ae2Sjmcneill data = acpi_compatible_lookup(aa, compat_data)->data; 231*c95a3ae2Sjmcneill 232*c95a3ae2Sjmcneill sc->sc_dev = self; 233*c95a3ae2Sjmcneill sc->sc_dmat = &arm_generic_dma_tag; 234*c95a3ae2Sjmcneill mutex_init(&sc->sc_ready_lock, MUTEX_DEFAULT, IPL_VM); 235*c95a3ae2Sjmcneill cv_init(&sc->sc_ready_cv, "qcpasrdy"); 236*c95a3ae2Sjmcneill 237*c95a3ae2Sjmcneill sc->sc_fwname = data->fwname; 238*c95a3ae2Sjmcneill sc->sc_dtb_fwname = data->dtb_fwname; 239*c95a3ae2Sjmcneill sc->sc_pas_id = data->pas_id; 240*c95a3ae2Sjmcneill sc->sc_dtb_pas_id = data->dtb_pas_id; 241*c95a3ae2Sjmcneill sc->sc_lite_pas_id = data->lite_pas_id; 242*c95a3ae2Sjmcneill sc->sc_load_state = data->load_state; 243*c95a3ae2Sjmcneill sc->sc_glink_remote_pid = data->glink_remote_pid; 244*c95a3ae2Sjmcneill sc->sc_crash_reason = data->crash_reason; 245*c95a3ae2Sjmcneill for (i = 0; i < __arraycount(sc->sc_mem_phys); i++) { 246*c95a3ae2Sjmcneill sc->sc_mem_phys[i] = data->mem_region[i].start; 247*c95a3ae2Sjmcneill KASSERT((sc->sc_mem_phys[i] & PAGE_MASK) == 0); 248*c95a3ae2Sjmcneill sc->sc_mem_size[i] = data->mem_region[i].size; 249*c95a3ae2Sjmcneill KASSERT((sc->sc_mem_size[i] & PAGE_MASK) == 0); 250*c95a3ae2Sjmcneill } 251*c95a3ae2Sjmcneill 252*c95a3ae2Sjmcneill rv = acpi_eval_string(aa->aa_node->ad_handle, "_SUB", &sc->sc_sub); 253*c95a3ae2Sjmcneill if (ACPI_FAILURE(rv)) { 254*c95a3ae2Sjmcneill aprint_error_dev(self, "failed to evaluate _SUB: %s\n", 255*c95a3ae2Sjmcneill AcpiFormatException(rv)); 256*c95a3ae2Sjmcneill return; 257*c95a3ae2Sjmcneill } 258*c95a3ae2Sjmcneill aprint_verbose_dev(self, "subsystem ID %s\n", sc->sc_sub); 259*c95a3ae2Sjmcneill 260*c95a3ae2Sjmcneill sc->sc_ih[0] = acpi_intr_establish(self, 261*c95a3ae2Sjmcneill (uint64_t)(uintptr_t)aa->aa_node->ad_handle, 262*c95a3ae2Sjmcneill IPL_VM, false, qcpas_intr_wdog, sc, device_xname(self)); 263*c95a3ae2Sjmcneill sc->sc_ih[1] = 264*c95a3ae2Sjmcneill qcsmptp_intr_establish(0, qcpas_intr_fatal, sc); 265*c95a3ae2Sjmcneill sc->sc_ih[2] = 266*c95a3ae2Sjmcneill qcsmptp_intr_establish(1, qcpas_intr_ready, sc); 267*c95a3ae2Sjmcneill sc->sc_ih[3] = 268*c95a3ae2Sjmcneill qcsmptp_intr_establish(2, qcpas_intr_handover, sc); 269*c95a3ae2Sjmcneill sc->sc_ih[4] = 270*c95a3ae2Sjmcneill qcsmptp_intr_establish(3, qcpas_intr_stop_ack, sc); 271*c95a3ae2Sjmcneill 272*c95a3ae2Sjmcneill if (qcpas_map_memory(sc) != 0) 273*c95a3ae2Sjmcneill return; 274*c95a3ae2Sjmcneill 275*c95a3ae2Sjmcneill config_mountroot(self, qcpas_mountroot); 276*c95a3ae2Sjmcneill } 277*c95a3ae2Sjmcneill 278*c95a3ae2Sjmcneill static void 279*c95a3ae2Sjmcneill qcpas_firmload(void *arg) 280*c95a3ae2Sjmcneill { 281*c95a3ae2Sjmcneill struct qcpas_softc *sc = arg; 282*c95a3ae2Sjmcneill firmware_handle_t fwh = NULL, dtb_fwh = NULL; 283*c95a3ae2Sjmcneill char fwname[128]; 284*c95a3ae2Sjmcneill size_t fwlen = 0, dtb_fwlen = 0; 285*c95a3ae2Sjmcneill u_char *fw = NULL, *dtb_fw = NULL; 286*c95a3ae2Sjmcneill int ret, error; 287*c95a3ae2Sjmcneill 288*c95a3ae2Sjmcneill snprintf(fwname, sizeof(fwname), "%s/%s", sc->sc_sub, sc->sc_fwname); 289*c95a3ae2Sjmcneill error = firmware_open(DRIVER_NAME, fwname, &fwh); 290*c95a3ae2Sjmcneill if (error == 0) { 291*c95a3ae2Sjmcneill fwlen = firmware_get_size(fwh); 292*c95a3ae2Sjmcneill fw = fwlen ? firmware_malloc(fwlen) : NULL; 293*c95a3ae2Sjmcneill error = fw == NULL ? ENOMEM : 294*c95a3ae2Sjmcneill firmware_read(fwh, 0, fw, fwlen); 295*c95a3ae2Sjmcneill } 296*c95a3ae2Sjmcneill if (error) { 297*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "failed to load %s/%s: %d\n", 298*c95a3ae2Sjmcneill DRIVER_NAME, fwname, error); 299*c95a3ae2Sjmcneill goto cleanup; 300*c95a3ae2Sjmcneill } 301*c95a3ae2Sjmcneill aprint_normal_dev(sc->sc_dev, "loading %s/%s\n", DRIVER_NAME, fwname); 302*c95a3ae2Sjmcneill 303*c95a3ae2Sjmcneill if (sc->sc_lite_pas_id) { 304*c95a3ae2Sjmcneill if (qcscm_pas_shutdown(sc->sc_lite_pas_id)) { 305*c95a3ae2Sjmcneill device_printf(sc->sc_dev, 306*c95a3ae2Sjmcneill "failed to shutdown lite firmware\n"); 307*c95a3ae2Sjmcneill } 308*c95a3ae2Sjmcneill } 309*c95a3ae2Sjmcneill 310*c95a3ae2Sjmcneill if (sc->sc_dtb_pas_id) { 311*c95a3ae2Sjmcneill snprintf(fwname, sizeof(fwname), "%s/%s", sc->sc_sub, 312*c95a3ae2Sjmcneill sc->sc_dtb_fwname); 313*c95a3ae2Sjmcneill error = firmware_open(DRIVER_NAME, fwname, &dtb_fwh); 314*c95a3ae2Sjmcneill if (error == 0) { 315*c95a3ae2Sjmcneill dtb_fwlen = firmware_get_size(dtb_fwh); 316*c95a3ae2Sjmcneill dtb_fw = dtb_fwlen ? firmware_malloc(dtb_fwlen) : NULL; 317*c95a3ae2Sjmcneill error = dtb_fw == NULL ? ENOMEM : 318*c95a3ae2Sjmcneill firmware_read(dtb_fwh, 0, dtb_fw, dtb_fwlen); 319*c95a3ae2Sjmcneill } 320*c95a3ae2Sjmcneill if (error) { 321*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "failed to load %s/%s: %d\n", 322*c95a3ae2Sjmcneill DRIVER_NAME, fwname, error); 323*c95a3ae2Sjmcneill goto cleanup; 324*c95a3ae2Sjmcneill } 325*c95a3ae2Sjmcneill aprint_normal_dev(sc->sc_dev, "loading %s/%s\n", DRIVER_NAME, fwname); 326*c95a3ae2Sjmcneill } 327*c95a3ae2Sjmcneill 328*c95a3ae2Sjmcneill if (sc->sc_load_state) { 329*c95a3ae2Sjmcneill char buf[64]; 330*c95a3ae2Sjmcneill snprintf(buf, sizeof(buf), 331*c95a3ae2Sjmcneill "{class: image, res: load_state, name: %s, val: on}", 332*c95a3ae2Sjmcneill sc->sc_load_state); 333*c95a3ae2Sjmcneill ret = qcaoss_send(buf, sizeof(buf)); 334*c95a3ae2Sjmcneill if (ret != 0) { 335*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "failed to toggle load state\n"); 336*c95a3ae2Sjmcneill goto cleanup; 337*c95a3ae2Sjmcneill } 338*c95a3ae2Sjmcneill } 339*c95a3ae2Sjmcneill 340*c95a3ae2Sjmcneill if (sc->sc_dtb_pas_id) { 341*c95a3ae2Sjmcneill qcpas_mdt_init(sc, sc->sc_dtb_pas_id, dtb_fw, dtb_fwlen); 342*c95a3ae2Sjmcneill } 343*c95a3ae2Sjmcneill 344*c95a3ae2Sjmcneill ret = qcpas_mdt_init(sc, sc->sc_pas_id, fw, fwlen); 345*c95a3ae2Sjmcneill if (ret != 0) { 346*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "failed to boot coprocessor\n"); 347*c95a3ae2Sjmcneill goto cleanup; 348*c95a3ae2Sjmcneill } 349*c95a3ae2Sjmcneill 350*c95a3ae2Sjmcneill qcpas_glink_attach(sc); 351*c95a3ae2Sjmcneill 352*c95a3ae2Sjmcneill /* Battery sensors */ 353*c95a3ae2Sjmcneill sc->sc_sme = sysmon_envsys_create(); 354*c95a3ae2Sjmcneill sc->sc_sme->sme_name = "battery"; 355*c95a3ae2Sjmcneill sc->sc_sme->sme_cookie = sc; 356*c95a3ae2Sjmcneill sc->sc_sme->sme_flags = SME_DISABLE_REFRESH; 357*c95a3ae2Sjmcneill sc->sc_sme->sme_class = SME_CLASS_BATTERY; 358*c95a3ae2Sjmcneill sc->sc_sme->sme_get_limits = qcpas_get_limits; 359*c95a3ae2Sjmcneill 360*c95a3ae2Sjmcneill /* AC adapter sensors */ 361*c95a3ae2Sjmcneill sc->sc_sme_acadapter = sysmon_envsys_create(); 362*c95a3ae2Sjmcneill sc->sc_sme_acadapter->sme_name = "charger"; 363*c95a3ae2Sjmcneill sc->sc_sme_acadapter->sme_cookie = sc; 364*c95a3ae2Sjmcneill sc->sc_sme_acadapter->sme_flags = SME_DISABLE_REFRESH; 365*c95a3ae2Sjmcneill sc->sc_sme_acadapter->sme_class = SME_CLASS_ACADAPTER; 366*c95a3ae2Sjmcneill 367*c95a3ae2Sjmcneill #define INIT_SENSOR(sme, idx, unit, str) \ 368*c95a3ae2Sjmcneill do { \ 369*c95a3ae2Sjmcneill strlcpy(sc->sc_sens[idx].desc, str, \ 370*c95a3ae2Sjmcneill sizeof(sc->sc_sens[0].desc)); \ 371*c95a3ae2Sjmcneill sc->sc_sens[idx].units = unit; \ 372*c95a3ae2Sjmcneill sc->sc_sens[idx].state = ENVSYS_SINVALID; \ 373*c95a3ae2Sjmcneill sysmon_envsys_sensor_attach(sme, \ 374*c95a3ae2Sjmcneill &sc->sc_sens[idx]); \ 375*c95a3ae2Sjmcneill } while (0) 376*c95a3ae2Sjmcneill 377*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage"); 378*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage"); 379*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_DCAPACITY, ENVSYS_SWATTHOUR, "design cap"); 380*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_LFCCAPACITY, ENVSYS_SWATTHOUR, "last full cap"); 381*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_CAPACITY, ENVSYS_SWATTHOUR, "charge"); 382*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_CHARGERATE, ENVSYS_SWATTS, "charge rate"); 383*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_DISCHARGERATE, ENVSYS_SWATTS, "discharge rate"); 384*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_CHARGING, ENVSYS_BATTERY_CHARGE, "charging"); 385*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_CHARGE_STATE, ENVSYS_BATTERY_CAPACITY, "charge state"); 386*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_DCYCLES, ENVSYS_INTEGER, "discharge cycles"); 387*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme, QCPAS_TEMPERATURE, ENVSYS_STEMP, "temperature"); 388*c95a3ae2Sjmcneill INIT_SENSOR(sc->sc_sme_acadapter, QCPAS_ACADAPTER, ENVSYS_INDICATOR, "connected"); 389*c95a3ae2Sjmcneill 390*c95a3ae2Sjmcneill #undef INIT_SENSOR 391*c95a3ae2Sjmcneill 392*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGE_STATE].value_cur = 393*c95a3ae2Sjmcneill ENVSYS_BATTERY_CAPACITY_NORMAL; 394*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CAPACITY].flags |= 395*c95a3ae2Sjmcneill ENVSYS_FPERCENT | ENVSYS_FVALID_MAX | ENVSYS_FMONLIMITS; 396*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGE_STATE].flags |= 397*c95a3ae2Sjmcneill ENVSYS_FMONSTCHANGED; 398*c95a3ae2Sjmcneill 399*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_VOLTAGE].flags = ENVSYS_FMONNOTSUPP; 400*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGERATE].flags = ENVSYS_FMONNOTSUPP; 401*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DISCHARGERATE].flags = ENVSYS_FMONNOTSUPP; 402*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DCAPACITY].flags = ENVSYS_FMONNOTSUPP; 403*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_LFCCAPACITY].flags = ENVSYS_FMONNOTSUPP; 404*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DVOLTAGE].flags = ENVSYS_FMONNOTSUPP; 405*c95a3ae2Sjmcneill 406*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; 407*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DISCHARGERATE].flags |= ENVSYS_FHAS_ENTROPY; 408*c95a3ae2Sjmcneill 409*c95a3ae2Sjmcneill sysmon_envsys_register(sc->sc_sme); 410*c95a3ae2Sjmcneill sysmon_envsys_register(sc->sc_sme_acadapter); 411*c95a3ae2Sjmcneill 412*c95a3ae2Sjmcneill sc->sc_smpsw_acadapter.smpsw_name = "acpiacad0"; 413*c95a3ae2Sjmcneill sc->sc_smpsw_acadapter.smpsw_type = PSWITCH_TYPE_ACADAPTER; 414*c95a3ae2Sjmcneill sysmon_pswitch_register(&sc->sc_smpsw_acadapter); 415*c95a3ae2Sjmcneill 416*c95a3ae2Sjmcneill cleanup: 417*c95a3ae2Sjmcneill if (dtb_fw != NULL) { 418*c95a3ae2Sjmcneill firmware_free(dtb_fw, dtb_fwlen); 419*c95a3ae2Sjmcneill } 420*c95a3ae2Sjmcneill if (fw != NULL) { 421*c95a3ae2Sjmcneill firmware_free(fw, fwlen); 422*c95a3ae2Sjmcneill } 423*c95a3ae2Sjmcneill if (dtb_fwh != NULL) { 424*c95a3ae2Sjmcneill firmware_close(dtb_fwh); 425*c95a3ae2Sjmcneill } 426*c95a3ae2Sjmcneill if (fwh != NULL) { 427*c95a3ae2Sjmcneill firmware_close(fwh); 428*c95a3ae2Sjmcneill } 429*c95a3ae2Sjmcneill } 430*c95a3ae2Sjmcneill 431*c95a3ae2Sjmcneill static void 432*c95a3ae2Sjmcneill qcpas_mountroot(device_t self) 433*c95a3ae2Sjmcneill { 434*c95a3ae2Sjmcneill struct qcpas_softc *sc = device_private(self); 435*c95a3ae2Sjmcneill 436*c95a3ae2Sjmcneill sysmon_task_queue_sched(0, qcpas_firmload, sc); 437*c95a3ae2Sjmcneill } 438*c95a3ae2Sjmcneill 439*c95a3ae2Sjmcneill static int 440*c95a3ae2Sjmcneill qcpas_map_memory(struct qcpas_softc *sc) 441*c95a3ae2Sjmcneill { 442*c95a3ae2Sjmcneill int i; 443*c95a3ae2Sjmcneill 444*c95a3ae2Sjmcneill for (i = 0; i < __arraycount(sc->sc_mem_phys); i++) { 445*c95a3ae2Sjmcneill paddr_t pa, epa; 446*c95a3ae2Sjmcneill vaddr_t va; 447*c95a3ae2Sjmcneill 448*c95a3ae2Sjmcneill if (sc->sc_mem_size[i] == 0) 449*c95a3ae2Sjmcneill break; 450*c95a3ae2Sjmcneill 451*c95a3ae2Sjmcneill va = uvm_km_alloc(kernel_map, sc->sc_mem_size[i], 0, UVM_KMF_VAONLY); 452*c95a3ae2Sjmcneill KASSERT(va != 0); 453*c95a3ae2Sjmcneill sc->sc_mem_region[i] = (void *)va; 454*c95a3ae2Sjmcneill 455*c95a3ae2Sjmcneill for (pa = sc->sc_mem_phys[i], epa = sc->sc_mem_phys[i] + sc->sc_mem_size[i]; 456*c95a3ae2Sjmcneill pa < epa; 457*c95a3ae2Sjmcneill pa += PAGE_SIZE, va += PAGE_SIZE) { 458*c95a3ae2Sjmcneill pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, PMAP_WRITE_COMBINE); 459*c95a3ae2Sjmcneill } 460*c95a3ae2Sjmcneill pmap_update(pmap_kernel()); 461*c95a3ae2Sjmcneill } 462*c95a3ae2Sjmcneill 463*c95a3ae2Sjmcneill return 0; 464*c95a3ae2Sjmcneill } 465*c95a3ae2Sjmcneill 466*c95a3ae2Sjmcneill static int 467*c95a3ae2Sjmcneill qcpas_mdt_init(struct qcpas_softc *sc, int pas_id, u_char *fw, size_t fwlen) 468*c95a3ae2Sjmcneill { 469*c95a3ae2Sjmcneill Elf32_Ehdr *ehdr; 470*c95a3ae2Sjmcneill Elf32_Phdr *phdr; 471*c95a3ae2Sjmcneill paddr_t minpa = -1, maxpa = 0; 472*c95a3ae2Sjmcneill int i, hashseg = 0, relocate = 0; 473*c95a3ae2Sjmcneill uint8_t *metadata; 474*c95a3ae2Sjmcneill int error; 475*c95a3ae2Sjmcneill ssize_t off; 476*c95a3ae2Sjmcneill int idx; 477*c95a3ae2Sjmcneill 478*c95a3ae2Sjmcneill if (pas_id == sc->sc_dtb_pas_id) 479*c95a3ae2Sjmcneill idx = 1; 480*c95a3ae2Sjmcneill else 481*c95a3ae2Sjmcneill idx = 0; 482*c95a3ae2Sjmcneill 483*c95a3ae2Sjmcneill ehdr = (Elf32_Ehdr *)fw; 484*c95a3ae2Sjmcneill phdr = (Elf32_Phdr *)&ehdr[1]; 485*c95a3ae2Sjmcneill 486*c95a3ae2Sjmcneill if (ehdr->e_phnum < 2 || phdr[0].p_type == PT_LOAD) 487*c95a3ae2Sjmcneill return EINVAL; 488*c95a3ae2Sjmcneill 489*c95a3ae2Sjmcneill for (i = 0; i < ehdr->e_phnum; i++) { 490*c95a3ae2Sjmcneill if ((phdr[i].p_flags & MDT_TYPE_MASK) == MDT_TYPE_HASH) { 491*c95a3ae2Sjmcneill if (i > 0 && !hashseg) 492*c95a3ae2Sjmcneill hashseg = i; 493*c95a3ae2Sjmcneill continue; 494*c95a3ae2Sjmcneill } 495*c95a3ae2Sjmcneill if (phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) 496*c95a3ae2Sjmcneill continue; 497*c95a3ae2Sjmcneill if (phdr[i].p_flags & MDT_RELOCATABLE) 498*c95a3ae2Sjmcneill relocate = 1; 499*c95a3ae2Sjmcneill if (phdr[i].p_paddr < minpa) 500*c95a3ae2Sjmcneill minpa = phdr[i].p_paddr; 501*c95a3ae2Sjmcneill if (phdr[i].p_paddr + phdr[i].p_memsz > maxpa) 502*c95a3ae2Sjmcneill maxpa = 503*c95a3ae2Sjmcneill roundup(phdr[i].p_paddr + phdr[i].p_memsz, 504*c95a3ae2Sjmcneill PAGE_SIZE); 505*c95a3ae2Sjmcneill } 506*c95a3ae2Sjmcneill 507*c95a3ae2Sjmcneill if (!hashseg) 508*c95a3ae2Sjmcneill return EINVAL; 509*c95a3ae2Sjmcneill 510*c95a3ae2Sjmcneill if (sc->sc_metadata[idx] == NULL) { 511*c95a3ae2Sjmcneill sc->sc_metadata[idx] = qcpas_dmamem_alloc(sc, phdr[0].p_filesz + 512*c95a3ae2Sjmcneill phdr[hashseg].p_filesz, PAGE_SIZE); 513*c95a3ae2Sjmcneill if (sc->sc_metadata[idx] == NULL) { 514*c95a3ae2Sjmcneill return EINVAL; 515*c95a3ae2Sjmcneill } 516*c95a3ae2Sjmcneill } 517*c95a3ae2Sjmcneill 518*c95a3ae2Sjmcneill metadata = QCPAS_DMA_KVA(sc->sc_metadata[idx]); 519*c95a3ae2Sjmcneill 520*c95a3ae2Sjmcneill memcpy(metadata, fw, phdr[0].p_filesz); 521*c95a3ae2Sjmcneill if (phdr[0].p_filesz + phdr[hashseg].p_filesz == fwlen) { 522*c95a3ae2Sjmcneill memcpy(metadata + phdr[0].p_filesz, 523*c95a3ae2Sjmcneill fw + phdr[0].p_filesz, phdr[hashseg].p_filesz); 524*c95a3ae2Sjmcneill } else if (phdr[hashseg].p_offset + phdr[hashseg].p_filesz <= fwlen) { 525*c95a3ae2Sjmcneill memcpy(metadata + phdr[0].p_filesz, 526*c95a3ae2Sjmcneill fw + phdr[hashseg].p_offset, phdr[hashseg].p_filesz); 527*c95a3ae2Sjmcneill } else { 528*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "metadata split segment not supported\n"); 529*c95a3ae2Sjmcneill return EINVAL; 530*c95a3ae2Sjmcneill } 531*c95a3ae2Sjmcneill 532*c95a3ae2Sjmcneill cpu_drain_writebuf(); 533*c95a3ae2Sjmcneill 534*c95a3ae2Sjmcneill error = qcscm_pas_init_image(pas_id, 535*c95a3ae2Sjmcneill QCPAS_DMA_DVA(sc->sc_metadata[idx])); 536*c95a3ae2Sjmcneill if (error != 0) { 537*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "init image failed: %d\n", error); 538*c95a3ae2Sjmcneill qcpas_dmamem_free(sc, sc->sc_metadata[idx]); 539*c95a3ae2Sjmcneill return error; 540*c95a3ae2Sjmcneill } 541*c95a3ae2Sjmcneill 542*c95a3ae2Sjmcneill if (relocate) { 543*c95a3ae2Sjmcneill if (qcscm_pas_mem_setup(pas_id, 544*c95a3ae2Sjmcneill sc->sc_mem_phys[idx], maxpa - minpa) != 0) { 545*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "mem setup failed\n"); 546*c95a3ae2Sjmcneill qcpas_dmamem_free(sc, sc->sc_metadata[idx]); 547*c95a3ae2Sjmcneill return EINVAL; 548*c95a3ae2Sjmcneill } 549*c95a3ae2Sjmcneill } 550*c95a3ae2Sjmcneill 551*c95a3ae2Sjmcneill sc->sc_mem_reloc[idx] = relocate ? minpa : sc->sc_mem_phys[idx]; 552*c95a3ae2Sjmcneill 553*c95a3ae2Sjmcneill for (i = 0; i < ehdr->e_phnum; i++) { 554*c95a3ae2Sjmcneill if ((phdr[i].p_flags & MDT_TYPE_MASK) == MDT_TYPE_HASH || 555*c95a3ae2Sjmcneill phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) 556*c95a3ae2Sjmcneill continue; 557*c95a3ae2Sjmcneill off = phdr[i].p_paddr - sc->sc_mem_reloc[idx]; 558*c95a3ae2Sjmcneill if (off < 0 || off + phdr[i].p_memsz > sc->sc_mem_size[0]) 559*c95a3ae2Sjmcneill return EINVAL; 560*c95a3ae2Sjmcneill if (phdr[i].p_filesz > phdr[i].p_memsz) 561*c95a3ae2Sjmcneill return EINVAL; 562*c95a3ae2Sjmcneill 563*c95a3ae2Sjmcneill if (phdr[i].p_filesz && phdr[i].p_offset < fwlen && 564*c95a3ae2Sjmcneill phdr[i].p_offset + phdr[i].p_filesz <= fwlen) { 565*c95a3ae2Sjmcneill memcpy(sc->sc_mem_region[idx] + off, 566*c95a3ae2Sjmcneill fw + phdr[i].p_offset, phdr[i].p_filesz); 567*c95a3ae2Sjmcneill } else if (phdr[i].p_filesz) { 568*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "firmware split segment not supported\n"); 569*c95a3ae2Sjmcneill return EINVAL; 570*c95a3ae2Sjmcneill } 571*c95a3ae2Sjmcneill 572*c95a3ae2Sjmcneill if (phdr[i].p_memsz > phdr[i].p_filesz) 573*c95a3ae2Sjmcneill memset(sc->sc_mem_region[idx] + off + phdr[i].p_filesz, 574*c95a3ae2Sjmcneill 0, phdr[i].p_memsz - phdr[i].p_filesz); 575*c95a3ae2Sjmcneill } 576*c95a3ae2Sjmcneill 577*c95a3ae2Sjmcneill cpu_drain_writebuf(); 578*c95a3ae2Sjmcneill 579*c95a3ae2Sjmcneill if (qcscm_pas_auth_and_reset(pas_id) != 0) { 580*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "auth and reset failed\n"); 581*c95a3ae2Sjmcneill qcpas_dmamem_free(sc, sc->sc_metadata[idx]); 582*c95a3ae2Sjmcneill return EINVAL; 583*c95a3ae2Sjmcneill } 584*c95a3ae2Sjmcneill 585*c95a3ae2Sjmcneill if (pas_id == sc->sc_dtb_pas_id) 586*c95a3ae2Sjmcneill return 0; 587*c95a3ae2Sjmcneill 588*c95a3ae2Sjmcneill mutex_enter(&sc->sc_ready_lock); 589*c95a3ae2Sjmcneill while (!sc->sc_ready) { 590*c95a3ae2Sjmcneill error = cv_timedwait(&sc->sc_ready_cv, &sc->sc_ready_lock, 591*c95a3ae2Sjmcneill hz * 5); 592*c95a3ae2Sjmcneill if (error == EWOULDBLOCK) { 593*c95a3ae2Sjmcneill break; 594*c95a3ae2Sjmcneill } 595*c95a3ae2Sjmcneill } 596*c95a3ae2Sjmcneill mutex_exit(&sc->sc_ready_lock); 597*c95a3ae2Sjmcneill if (!sc->sc_ready) { 598*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "timeout waiting for ready signal\n"); 599*c95a3ae2Sjmcneill return ETIMEDOUT; 600*c95a3ae2Sjmcneill } 601*c95a3ae2Sjmcneill 602*c95a3ae2Sjmcneill /* XXX: free metadata ? */ 603*c95a3ae2Sjmcneill 604*c95a3ae2Sjmcneill return 0; 605*c95a3ae2Sjmcneill } 606*c95a3ae2Sjmcneill 607*c95a3ae2Sjmcneill static struct qcpas_dmamem * 608*c95a3ae2Sjmcneill qcpas_dmamem_alloc(struct qcpas_softc *sc, bus_size_t size, bus_size_t align) 609*c95a3ae2Sjmcneill { 610*c95a3ae2Sjmcneill struct qcpas_dmamem *tdm; 611*c95a3ae2Sjmcneill int nsegs; 612*c95a3ae2Sjmcneill 613*c95a3ae2Sjmcneill tdm = kmem_zalloc(sizeof(*tdm), KM_SLEEP); 614*c95a3ae2Sjmcneill tdm->tdm_size = size; 615*c95a3ae2Sjmcneill 616*c95a3ae2Sjmcneill if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 617*c95a3ae2Sjmcneill BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0) 618*c95a3ae2Sjmcneill goto tdmfree; 619*c95a3ae2Sjmcneill 620*c95a3ae2Sjmcneill if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, 621*c95a3ae2Sjmcneill &tdm->tdm_seg, 1, &nsegs, BUS_DMA_WAITOK) != 0) 622*c95a3ae2Sjmcneill goto destroy; 623*c95a3ae2Sjmcneill 624*c95a3ae2Sjmcneill if (bus_dmamem_map(sc->sc_dmat, &tdm->tdm_seg, nsegs, size, 625*c95a3ae2Sjmcneill &tdm->tdm_kva, BUS_DMA_WAITOK | BUS_DMA_PREFETCHABLE) != 0) 626*c95a3ae2Sjmcneill goto free; 627*c95a3ae2Sjmcneill 628*c95a3ae2Sjmcneill if (bus_dmamap_load(sc->sc_dmat, tdm->tdm_map, tdm->tdm_kva, size, 629*c95a3ae2Sjmcneill NULL, BUS_DMA_WAITOK) != 0) 630*c95a3ae2Sjmcneill goto unmap; 631*c95a3ae2Sjmcneill 632*c95a3ae2Sjmcneill memset(tdm->tdm_kva, 0, size); 633*c95a3ae2Sjmcneill 634*c95a3ae2Sjmcneill return (tdm); 635*c95a3ae2Sjmcneill 636*c95a3ae2Sjmcneill unmap: 637*c95a3ae2Sjmcneill bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, size); 638*c95a3ae2Sjmcneill free: 639*c95a3ae2Sjmcneill bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); 640*c95a3ae2Sjmcneill destroy: 641*c95a3ae2Sjmcneill bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); 642*c95a3ae2Sjmcneill tdmfree: 643*c95a3ae2Sjmcneill kmem_free(tdm, sizeof(*tdm)); 644*c95a3ae2Sjmcneill 645*c95a3ae2Sjmcneill return (NULL); 646*c95a3ae2Sjmcneill } 647*c95a3ae2Sjmcneill 648*c95a3ae2Sjmcneill static void 649*c95a3ae2Sjmcneill qcpas_dmamem_free(struct qcpas_softc *sc, struct qcpas_dmamem *tdm) 650*c95a3ae2Sjmcneill { 651*c95a3ae2Sjmcneill bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, tdm->tdm_size); 652*c95a3ae2Sjmcneill bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); 653*c95a3ae2Sjmcneill bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); 654*c95a3ae2Sjmcneill kmem_free(tdm, sizeof(*tdm)); 655*c95a3ae2Sjmcneill } 656*c95a3ae2Sjmcneill 657*c95a3ae2Sjmcneill static void 658*c95a3ae2Sjmcneill qcpas_report_crash(struct qcpas_softc *sc, const char *source) 659*c95a3ae2Sjmcneill { 660*c95a3ae2Sjmcneill char *msg; 661*c95a3ae2Sjmcneill int size; 662*c95a3ae2Sjmcneill 663*c95a3ae2Sjmcneill msg = qcsmem_get(-1, sc->sc_crash_reason, &size); 664*c95a3ae2Sjmcneill if (msg == NULL || size <= 0) { 665*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "%s\n", source); 666*c95a3ae2Sjmcneill } else { 667*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "%s: \"%s\"\n", source, msg); 668*c95a3ae2Sjmcneill } 669*c95a3ae2Sjmcneill } 670*c95a3ae2Sjmcneill 671*c95a3ae2Sjmcneill static int 672*c95a3ae2Sjmcneill qcpas_intr_wdog(void *cookie) 673*c95a3ae2Sjmcneill { 674*c95a3ae2Sjmcneill struct qcpas_softc *sc = cookie; 675*c95a3ae2Sjmcneill 676*c95a3ae2Sjmcneill qcpas_report_crash(sc, "watchdog"); 677*c95a3ae2Sjmcneill 678*c95a3ae2Sjmcneill return 0; 679*c95a3ae2Sjmcneill } 680*c95a3ae2Sjmcneill 681*c95a3ae2Sjmcneill static int 682*c95a3ae2Sjmcneill qcpas_intr_fatal(void *cookie) 683*c95a3ae2Sjmcneill { 684*c95a3ae2Sjmcneill struct qcpas_softc *sc = cookie; 685*c95a3ae2Sjmcneill 686*c95a3ae2Sjmcneill qcpas_report_crash(sc, "fatal error"); 687*c95a3ae2Sjmcneill 688*c95a3ae2Sjmcneill return 0; 689*c95a3ae2Sjmcneill } 690*c95a3ae2Sjmcneill 691*c95a3ae2Sjmcneill static int 692*c95a3ae2Sjmcneill qcpas_intr_ready(void *cookie) 693*c95a3ae2Sjmcneill { 694*c95a3ae2Sjmcneill struct qcpas_softc *sc = cookie; 695*c95a3ae2Sjmcneill 696*c95a3ae2Sjmcneill aprint_debug_dev(sc->sc_dev, "%s\n", __func__); 697*c95a3ae2Sjmcneill 698*c95a3ae2Sjmcneill mutex_enter(&sc->sc_ready_lock); 699*c95a3ae2Sjmcneill sc->sc_ready = true; 700*c95a3ae2Sjmcneill cv_broadcast(&sc->sc_ready_cv); 701*c95a3ae2Sjmcneill mutex_exit(&sc->sc_ready_lock); 702*c95a3ae2Sjmcneill 703*c95a3ae2Sjmcneill return 0; 704*c95a3ae2Sjmcneill } 705*c95a3ae2Sjmcneill 706*c95a3ae2Sjmcneill static int 707*c95a3ae2Sjmcneill qcpas_intr_handover(void *cookie) 708*c95a3ae2Sjmcneill { 709*c95a3ae2Sjmcneill struct qcpas_softc *sc = cookie; 710*c95a3ae2Sjmcneill 711*c95a3ae2Sjmcneill aprint_debug_dev(sc->sc_dev, "%s\n", __func__); 712*c95a3ae2Sjmcneill 713*c95a3ae2Sjmcneill return 0; 714*c95a3ae2Sjmcneill } 715*c95a3ae2Sjmcneill 716*c95a3ae2Sjmcneill static int 717*c95a3ae2Sjmcneill qcpas_intr_stop_ack(void *cookie) 718*c95a3ae2Sjmcneill { 719*c95a3ae2Sjmcneill struct qcpas_softc *sc = cookie; 720*c95a3ae2Sjmcneill 721*c95a3ae2Sjmcneill aprint_debug_dev(sc->sc_dev, "%s\n", __func__); 722*c95a3ae2Sjmcneill 723*c95a3ae2Sjmcneill return 0; 724*c95a3ae2Sjmcneill } 725*c95a3ae2Sjmcneill 726*c95a3ae2Sjmcneill /* GLINK */ 727*c95a3ae2Sjmcneill 728*c95a3ae2Sjmcneill #define SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR 478 729*c95a3ae2Sjmcneill #define SMEM_GLINK_NATIVE_XPRT_FIFO_0 479 730*c95a3ae2Sjmcneill #define SMEM_GLINK_NATIVE_XPRT_FIFO_1 480 731*c95a3ae2Sjmcneill 732*c95a3ae2Sjmcneill struct glink_msg { 733*c95a3ae2Sjmcneill uint16_t cmd; 734*c95a3ae2Sjmcneill uint16_t param1; 735*c95a3ae2Sjmcneill uint32_t param2; 736*c95a3ae2Sjmcneill uint8_t data[]; 737*c95a3ae2Sjmcneill } __packed; 738*c95a3ae2Sjmcneill 739*c95a3ae2Sjmcneill struct qcpas_glink_intent_pair { 740*c95a3ae2Sjmcneill uint32_t size; 741*c95a3ae2Sjmcneill uint32_t iid; 742*c95a3ae2Sjmcneill } __packed; 743*c95a3ae2Sjmcneill 744*c95a3ae2Sjmcneill struct qcpas_glink_intent { 745*c95a3ae2Sjmcneill TAILQ_ENTRY(qcpas_glink_intent) it_q; 746*c95a3ae2Sjmcneill uint32_t it_id; 747*c95a3ae2Sjmcneill uint32_t it_size; 748*c95a3ae2Sjmcneill int it_inuse; 749*c95a3ae2Sjmcneill }; 750*c95a3ae2Sjmcneill 751*c95a3ae2Sjmcneill struct qcpas_glink_channel { 752*c95a3ae2Sjmcneill TAILQ_ENTRY(qcpas_glink_channel) ch_q; 753*c95a3ae2Sjmcneill struct qcpas_softc *ch_sc; 754*c95a3ae2Sjmcneill struct qcpas_glink_protocol *ch_proto; 755*c95a3ae2Sjmcneill uint32_t ch_rcid; 756*c95a3ae2Sjmcneill uint32_t ch_lcid; 757*c95a3ae2Sjmcneill uint32_t ch_max_intent; 758*c95a3ae2Sjmcneill TAILQ_HEAD(,qcpas_glink_intent) ch_l_intents; 759*c95a3ae2Sjmcneill TAILQ_HEAD(,qcpas_glink_intent) ch_r_intents; 760*c95a3ae2Sjmcneill }; 761*c95a3ae2Sjmcneill 762*c95a3ae2Sjmcneill #define GLINK_CMD_VERSION 0 763*c95a3ae2Sjmcneill #define GLINK_CMD_VERSION_ACK 1 764*c95a3ae2Sjmcneill #define GLINK_VERSION 1 765*c95a3ae2Sjmcneill #define GLINK_FEATURE_INTENT_REUSE (1 << 0) 766*c95a3ae2Sjmcneill #define GLINK_CMD_OPEN 2 767*c95a3ae2Sjmcneill #define GLINK_CMD_CLOSE 3 768*c95a3ae2Sjmcneill #define GLINK_CMD_OPEN_ACK 4 769*c95a3ae2Sjmcneill #define GLINK_CMD_INTENT 5 770*c95a3ae2Sjmcneill #define GLINK_CMD_RX_DONE 6 771*c95a3ae2Sjmcneill #define GLINK_CMD_RX_INTENT_REQ 7 772*c95a3ae2Sjmcneill #define GLINK_CMD_RX_INTENT_REQ_ACK 8 773*c95a3ae2Sjmcneill #define GLINK_CMD_TX_DATA 9 774*c95a3ae2Sjmcneill #define GLINK_CMD_CLOSE_ACK 11 775*c95a3ae2Sjmcneill #define GLINK_CMD_TX_DATA_CONT 12 776*c95a3ae2Sjmcneill #define GLINK_CMD_READ_NOTIF 13 777*c95a3ae2Sjmcneill #define GLINK_CMD_RX_DONE_W_REUSE 14 778*c95a3ae2Sjmcneill 779*c95a3ae2Sjmcneill static int qcpas_glink_intr(void *); 780*c95a3ae2Sjmcneill 781*c95a3ae2Sjmcneill static void qcpas_glink_tx(struct qcpas_softc *, uint8_t *, int); 782*c95a3ae2Sjmcneill static void qcpas_glink_tx_commit(struct qcpas_softc *); 783*c95a3ae2Sjmcneill static void qcpas_glink_rx(struct qcpas_softc *, uint8_t *, int); 784*c95a3ae2Sjmcneill static void qcpas_glink_rx_commit(struct qcpas_softc *); 785*c95a3ae2Sjmcneill 786*c95a3ae2Sjmcneill static void qcpas_glink_send(void *, void *, int); 787*c95a3ae2Sjmcneill 788*c95a3ae2Sjmcneill static int qcpas_pmic_rtr_init(void *); 789*c95a3ae2Sjmcneill static int qcpas_pmic_rtr_recv(void *, uint8_t *, int); 790*c95a3ae2Sjmcneill 791*c95a3ae2Sjmcneill struct qcpas_glink_protocol { 792*c95a3ae2Sjmcneill const char *name; 793*c95a3ae2Sjmcneill int (*init)(void *cookie); 794*c95a3ae2Sjmcneill int (*recv)(void *cookie, uint8_t *buf, int len); 795*c95a3ae2Sjmcneill } qcpas_glink_protocols[] = { 796*c95a3ae2Sjmcneill { "PMIC_RTR_ADSP_APPS", qcpas_pmic_rtr_init , qcpas_pmic_rtr_recv }, 797*c95a3ae2Sjmcneill }; 798*c95a3ae2Sjmcneill 799*c95a3ae2Sjmcneill static void 800*c95a3ae2Sjmcneill qcpas_glink_attach(struct qcpas_softc *sc) 801*c95a3ae2Sjmcneill { 802*c95a3ae2Sjmcneill uint32_t remote = sc->sc_glink_remote_pid; 803*c95a3ae2Sjmcneill uint32_t *descs; 804*c95a3ae2Sjmcneill int size; 805*c95a3ae2Sjmcneill 806*c95a3ae2Sjmcneill if (qcsmem_alloc(remote, SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, 32) != 0 || 807*c95a3ae2Sjmcneill qcsmem_alloc(remote, SMEM_GLINK_NATIVE_XPRT_FIFO_0, 16384) != 0) 808*c95a3ae2Sjmcneill return; 809*c95a3ae2Sjmcneill 810*c95a3ae2Sjmcneill descs = qcsmem_get(remote, SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, &size); 811*c95a3ae2Sjmcneill if (descs == NULL || size != 32) 812*c95a3ae2Sjmcneill return; 813*c95a3ae2Sjmcneill 814*c95a3ae2Sjmcneill sc->sc_tx_tail = &descs[0]; 815*c95a3ae2Sjmcneill sc->sc_tx_head = &descs[1]; 816*c95a3ae2Sjmcneill sc->sc_rx_tail = &descs[2]; 817*c95a3ae2Sjmcneill sc->sc_rx_head = &descs[3]; 818*c95a3ae2Sjmcneill 819*c95a3ae2Sjmcneill sc->sc_tx_fifo = qcsmem_get(remote, SMEM_GLINK_NATIVE_XPRT_FIFO_0, 820*c95a3ae2Sjmcneill &sc->sc_tx_fifolen); 821*c95a3ae2Sjmcneill if (sc->sc_tx_fifo == NULL) 822*c95a3ae2Sjmcneill return; 823*c95a3ae2Sjmcneill sc->sc_rx_fifo = qcsmem_get(remote, SMEM_GLINK_NATIVE_XPRT_FIFO_1, 824*c95a3ae2Sjmcneill &sc->sc_rx_fifolen); 825*c95a3ae2Sjmcneill if (sc->sc_rx_fifo == NULL) 826*c95a3ae2Sjmcneill return; 827*c95a3ae2Sjmcneill 828*c95a3ae2Sjmcneill sc->sc_ipcc = qcipcc_channel(IPCC_CLIENT_LPASS, 829*c95a3ae2Sjmcneill IPCC_MPROC_SIGNAL_GLINK_QMP); 830*c95a3ae2Sjmcneill if (sc->sc_ipcc == NULL) 831*c95a3ae2Sjmcneill return; 832*c95a3ae2Sjmcneill 833*c95a3ae2Sjmcneill TAILQ_INIT(&sc->sc_glink_channels); 834*c95a3ae2Sjmcneill 835*c95a3ae2Sjmcneill sc->sc_glink_ih = qcipcc_intr_establish(IPCC_CLIENT_LPASS, 836*c95a3ae2Sjmcneill IPCC_MPROC_SIGNAL_GLINK_QMP, IPL_VM, qcpas_glink_intr, sc); 837*c95a3ae2Sjmcneill if (sc->sc_glink_ih == NULL) 838*c95a3ae2Sjmcneill return; 839*c95a3ae2Sjmcneill 840*c95a3ae2Sjmcneill /* Expect peer to send initial message */ 841*c95a3ae2Sjmcneill } 842*c95a3ae2Sjmcneill 843*c95a3ae2Sjmcneill static void 844*c95a3ae2Sjmcneill qcpas_glink_rx(struct qcpas_softc *sc, uint8_t *buf, int len) 845*c95a3ae2Sjmcneill { 846*c95a3ae2Sjmcneill uint32_t head, tail; 847*c95a3ae2Sjmcneill int avail; 848*c95a3ae2Sjmcneill 849*c95a3ae2Sjmcneill head = *sc->sc_rx_head; 850*c95a3ae2Sjmcneill tail = *sc->sc_rx_tail + sc->sc_rx_off; 851*c95a3ae2Sjmcneill if (tail >= sc->sc_rx_fifolen) 852*c95a3ae2Sjmcneill tail -= sc->sc_rx_fifolen; 853*c95a3ae2Sjmcneill 854*c95a3ae2Sjmcneill /* Checked by caller */ 855*c95a3ae2Sjmcneill KASSERT(head != tail); 856*c95a3ae2Sjmcneill 857*c95a3ae2Sjmcneill if (head >= tail) 858*c95a3ae2Sjmcneill avail = head - tail; 859*c95a3ae2Sjmcneill else 860*c95a3ae2Sjmcneill avail = (sc->sc_rx_fifolen - tail) + head; 861*c95a3ae2Sjmcneill 862*c95a3ae2Sjmcneill /* Dumb, but should do. */ 863*c95a3ae2Sjmcneill KASSERT(avail >= len); 864*c95a3ae2Sjmcneill 865*c95a3ae2Sjmcneill while (len > 0) { 866*c95a3ae2Sjmcneill *buf = sc->sc_rx_fifo[tail]; 867*c95a3ae2Sjmcneill tail++; 868*c95a3ae2Sjmcneill if (tail >= sc->sc_rx_fifolen) 869*c95a3ae2Sjmcneill tail -= sc->sc_rx_fifolen; 870*c95a3ae2Sjmcneill buf++; 871*c95a3ae2Sjmcneill sc->sc_rx_off++; 872*c95a3ae2Sjmcneill len--; 873*c95a3ae2Sjmcneill } 874*c95a3ae2Sjmcneill } 875*c95a3ae2Sjmcneill 876*c95a3ae2Sjmcneill static void 877*c95a3ae2Sjmcneill qcpas_glink_rx_commit(struct qcpas_softc *sc) 878*c95a3ae2Sjmcneill { 879*c95a3ae2Sjmcneill uint32_t tail; 880*c95a3ae2Sjmcneill 881*c95a3ae2Sjmcneill tail = *sc->sc_rx_tail + roundup(sc->sc_rx_off, 8); 882*c95a3ae2Sjmcneill if (tail >= sc->sc_rx_fifolen) 883*c95a3ae2Sjmcneill tail -= sc->sc_rx_fifolen; 884*c95a3ae2Sjmcneill 885*c95a3ae2Sjmcneill membar_producer(); 886*c95a3ae2Sjmcneill *sc->sc_rx_tail = tail; 887*c95a3ae2Sjmcneill sc->sc_rx_off = 0; 888*c95a3ae2Sjmcneill } 889*c95a3ae2Sjmcneill 890*c95a3ae2Sjmcneill static void 891*c95a3ae2Sjmcneill qcpas_glink_tx(struct qcpas_softc *sc, uint8_t *buf, int len) 892*c95a3ae2Sjmcneill { 893*c95a3ae2Sjmcneill uint32_t head, tail; 894*c95a3ae2Sjmcneill int avail; 895*c95a3ae2Sjmcneill 896*c95a3ae2Sjmcneill head = *sc->sc_tx_head + sc->sc_tx_off; 897*c95a3ae2Sjmcneill if (head >= sc->sc_tx_fifolen) 898*c95a3ae2Sjmcneill head -= sc->sc_tx_fifolen; 899*c95a3ae2Sjmcneill tail = *sc->sc_tx_tail; 900*c95a3ae2Sjmcneill 901*c95a3ae2Sjmcneill if (head < tail) 902*c95a3ae2Sjmcneill avail = tail - head; 903*c95a3ae2Sjmcneill else 904*c95a3ae2Sjmcneill avail = (sc->sc_rx_fifolen - head) + tail; 905*c95a3ae2Sjmcneill 906*c95a3ae2Sjmcneill /* Dumb, but should do. */ 907*c95a3ae2Sjmcneill KASSERT(avail >= len); 908*c95a3ae2Sjmcneill 909*c95a3ae2Sjmcneill while (len > 0) { 910*c95a3ae2Sjmcneill sc->sc_tx_fifo[head] = *buf; 911*c95a3ae2Sjmcneill head++; 912*c95a3ae2Sjmcneill if (head >= sc->sc_tx_fifolen) 913*c95a3ae2Sjmcneill head -= sc->sc_tx_fifolen; 914*c95a3ae2Sjmcneill buf++; 915*c95a3ae2Sjmcneill sc->sc_tx_off++; 916*c95a3ae2Sjmcneill len--; 917*c95a3ae2Sjmcneill } 918*c95a3ae2Sjmcneill } 919*c95a3ae2Sjmcneill 920*c95a3ae2Sjmcneill static void 921*c95a3ae2Sjmcneill qcpas_glink_tx_commit(struct qcpas_softc *sc) 922*c95a3ae2Sjmcneill { 923*c95a3ae2Sjmcneill uint32_t head; 924*c95a3ae2Sjmcneill 925*c95a3ae2Sjmcneill head = *sc->sc_tx_head + roundup(sc->sc_tx_off, 8); 926*c95a3ae2Sjmcneill if (head >= sc->sc_tx_fifolen) 927*c95a3ae2Sjmcneill head -= sc->sc_tx_fifolen; 928*c95a3ae2Sjmcneill 929*c95a3ae2Sjmcneill membar_producer(); 930*c95a3ae2Sjmcneill *sc->sc_tx_head = head; 931*c95a3ae2Sjmcneill sc->sc_tx_off = 0; 932*c95a3ae2Sjmcneill qcipcc_send(sc->sc_ipcc); 933*c95a3ae2Sjmcneill } 934*c95a3ae2Sjmcneill 935*c95a3ae2Sjmcneill static void 936*c95a3ae2Sjmcneill qcpas_glink_send(void *cookie, void *buf, int len) 937*c95a3ae2Sjmcneill { 938*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch = cookie; 939*c95a3ae2Sjmcneill struct qcpas_softc *sc = ch->ch_sc; 940*c95a3ae2Sjmcneill struct qcpas_glink_intent *it; 941*c95a3ae2Sjmcneill struct glink_msg msg; 942*c95a3ae2Sjmcneill uint32_t chunk_size, left_size; 943*c95a3ae2Sjmcneill 944*c95a3ae2Sjmcneill TAILQ_FOREACH(it, &ch->ch_r_intents, it_q) { 945*c95a3ae2Sjmcneill if (!it->it_inuse) 946*c95a3ae2Sjmcneill break; 947*c95a3ae2Sjmcneill if (it->it_size < len) 948*c95a3ae2Sjmcneill continue; 949*c95a3ae2Sjmcneill } 950*c95a3ae2Sjmcneill if (it == NULL) { 951*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "all intents in use\n"); 952*c95a3ae2Sjmcneill return; 953*c95a3ae2Sjmcneill } 954*c95a3ae2Sjmcneill it->it_inuse = 1; 955*c95a3ae2Sjmcneill 956*c95a3ae2Sjmcneill msg.cmd = GLINK_CMD_TX_DATA; 957*c95a3ae2Sjmcneill msg.param1 = ch->ch_lcid; 958*c95a3ae2Sjmcneill msg.param2 = it->it_id; 959*c95a3ae2Sjmcneill 960*c95a3ae2Sjmcneill chunk_size = len; 961*c95a3ae2Sjmcneill left_size = 0; 962*c95a3ae2Sjmcneill 963*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&msg, sizeof(msg)); 964*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&chunk_size, sizeof(chunk_size)); 965*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&left_size, sizeof(left_size)); 966*c95a3ae2Sjmcneill qcpas_glink_tx(sc, buf, len); 967*c95a3ae2Sjmcneill qcpas_glink_tx_commit(sc); 968*c95a3ae2Sjmcneill } 969*c95a3ae2Sjmcneill 970*c95a3ae2Sjmcneill static void 971*c95a3ae2Sjmcneill qcpas_glink_recv_version(struct qcpas_softc *sc, uint32_t ver, 972*c95a3ae2Sjmcneill uint32_t features) 973*c95a3ae2Sjmcneill { 974*c95a3ae2Sjmcneill struct glink_msg msg; 975*c95a3ae2Sjmcneill 976*c95a3ae2Sjmcneill if (ver != GLINK_VERSION) { 977*c95a3ae2Sjmcneill device_printf(sc->sc_dev, 978*c95a3ae2Sjmcneill "unsupported glink version %u\n", ver); 979*c95a3ae2Sjmcneill return; 980*c95a3ae2Sjmcneill } 981*c95a3ae2Sjmcneill 982*c95a3ae2Sjmcneill msg.cmd = GLINK_CMD_VERSION_ACK; 983*c95a3ae2Sjmcneill msg.param1 = GLINK_VERSION; 984*c95a3ae2Sjmcneill msg.param2 = features & GLINK_FEATURE_INTENT_REUSE; 985*c95a3ae2Sjmcneill 986*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&msg, sizeof(msg)); 987*c95a3ae2Sjmcneill qcpas_glink_tx_commit(sc); 988*c95a3ae2Sjmcneill } 989*c95a3ae2Sjmcneill 990*c95a3ae2Sjmcneill static void 991*c95a3ae2Sjmcneill qcpas_glink_recv_open(struct qcpas_softc *sc, uint32_t rcid, uint32_t namelen) 992*c95a3ae2Sjmcneill { 993*c95a3ae2Sjmcneill struct qcpas_glink_protocol *proto = NULL; 994*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch; 995*c95a3ae2Sjmcneill struct glink_msg msg; 996*c95a3ae2Sjmcneill char *name; 997*c95a3ae2Sjmcneill int i, err; 998*c95a3ae2Sjmcneill 999*c95a3ae2Sjmcneill name = kmem_zalloc(namelen, KM_SLEEP); 1000*c95a3ae2Sjmcneill qcpas_glink_rx(sc, name, namelen); 1001*c95a3ae2Sjmcneill qcpas_glink_rx_commit(sc); 1002*c95a3ae2Sjmcneill 1003*c95a3ae2Sjmcneill TAILQ_FOREACH(ch, &sc->sc_glink_channels, ch_q) { 1004*c95a3ae2Sjmcneill if (ch->ch_rcid == rcid) { 1005*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "duplicate open for %s\n", 1006*c95a3ae2Sjmcneill name); 1007*c95a3ae2Sjmcneill kmem_free(name, namelen); 1008*c95a3ae2Sjmcneill return; 1009*c95a3ae2Sjmcneill } 1010*c95a3ae2Sjmcneill } 1011*c95a3ae2Sjmcneill 1012*c95a3ae2Sjmcneill for (i = 0; i < __arraycount(qcpas_glink_protocols); i++) { 1013*c95a3ae2Sjmcneill if (strcmp(qcpas_glink_protocols[i].name, name) != 0) 1014*c95a3ae2Sjmcneill continue; 1015*c95a3ae2Sjmcneill proto = &qcpas_glink_protocols[i]; 1016*c95a3ae2Sjmcneill break; 1017*c95a3ae2Sjmcneill } 1018*c95a3ae2Sjmcneill if (proto == NULL) { 1019*c95a3ae2Sjmcneill kmem_free(name, namelen); 1020*c95a3ae2Sjmcneill return; 1021*c95a3ae2Sjmcneill } 1022*c95a3ae2Sjmcneill 1023*c95a3ae2Sjmcneill ch = kmem_zalloc(sizeof(*ch), KM_SLEEP); 1024*c95a3ae2Sjmcneill ch->ch_sc = sc; 1025*c95a3ae2Sjmcneill ch->ch_proto = proto; 1026*c95a3ae2Sjmcneill ch->ch_rcid = rcid; 1027*c95a3ae2Sjmcneill ch->ch_lcid = ++sc->sc_glink_max_channel; 1028*c95a3ae2Sjmcneill TAILQ_INIT(&ch->ch_l_intents); 1029*c95a3ae2Sjmcneill TAILQ_INIT(&ch->ch_r_intents); 1030*c95a3ae2Sjmcneill TAILQ_INSERT_TAIL(&sc->sc_glink_channels, ch, ch_q); 1031*c95a3ae2Sjmcneill 1032*c95a3ae2Sjmcneill /* Assume we can leave HW dangling if proto init fails */ 1033*c95a3ae2Sjmcneill err = proto->init(ch); 1034*c95a3ae2Sjmcneill if (err) { 1035*c95a3ae2Sjmcneill TAILQ_REMOVE(&sc->sc_glink_channels, ch, ch_q); 1036*c95a3ae2Sjmcneill kmem_free(ch, sizeof(*ch)); 1037*c95a3ae2Sjmcneill kmem_free(name, namelen); 1038*c95a3ae2Sjmcneill return; 1039*c95a3ae2Sjmcneill } 1040*c95a3ae2Sjmcneill 1041*c95a3ae2Sjmcneill msg.cmd = GLINK_CMD_OPEN_ACK; 1042*c95a3ae2Sjmcneill msg.param1 = ch->ch_rcid; 1043*c95a3ae2Sjmcneill msg.param2 = 0; 1044*c95a3ae2Sjmcneill 1045*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&msg, sizeof(msg)); 1046*c95a3ae2Sjmcneill qcpas_glink_tx_commit(sc); 1047*c95a3ae2Sjmcneill 1048*c95a3ae2Sjmcneill msg.cmd = GLINK_CMD_OPEN; 1049*c95a3ae2Sjmcneill msg.param1 = ch->ch_lcid; 1050*c95a3ae2Sjmcneill msg.param2 = strlen(name) + 1; 1051*c95a3ae2Sjmcneill 1052*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&msg, sizeof(msg)); 1053*c95a3ae2Sjmcneill qcpas_glink_tx(sc, name, strlen(name) + 1); 1054*c95a3ae2Sjmcneill qcpas_glink_tx_commit(sc); 1055*c95a3ae2Sjmcneill 1056*c95a3ae2Sjmcneill kmem_free(name, namelen); 1057*c95a3ae2Sjmcneill } 1058*c95a3ae2Sjmcneill 1059*c95a3ae2Sjmcneill static void 1060*c95a3ae2Sjmcneill qcpas_glink_recv_open_ack(struct qcpas_softc *sc, uint32_t lcid) 1061*c95a3ae2Sjmcneill { 1062*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch; 1063*c95a3ae2Sjmcneill struct glink_msg msg; 1064*c95a3ae2Sjmcneill struct qcpas_glink_intent_pair intent; 1065*c95a3ae2Sjmcneill int i; 1066*c95a3ae2Sjmcneill 1067*c95a3ae2Sjmcneill TAILQ_FOREACH(ch, &sc->sc_glink_channels, ch_q) { 1068*c95a3ae2Sjmcneill if (ch->ch_lcid == lcid) 1069*c95a3ae2Sjmcneill break; 1070*c95a3ae2Sjmcneill } 1071*c95a3ae2Sjmcneill if (ch == NULL) { 1072*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "unknown channel %u for OPEN_ACK\n", 1073*c95a3ae2Sjmcneill lcid); 1074*c95a3ae2Sjmcneill return; 1075*c95a3ae2Sjmcneill } 1076*c95a3ae2Sjmcneill 1077*c95a3ae2Sjmcneill /* Respond with default intent now that channel is open */ 1078*c95a3ae2Sjmcneill for (i = 0; i < 5; i++) { 1079*c95a3ae2Sjmcneill struct qcpas_glink_intent *it; 1080*c95a3ae2Sjmcneill 1081*c95a3ae2Sjmcneill it = kmem_zalloc(sizeof(*it), KM_SLEEP); 1082*c95a3ae2Sjmcneill it->it_id = ++ch->ch_max_intent; 1083*c95a3ae2Sjmcneill it->it_size = 1024; 1084*c95a3ae2Sjmcneill TAILQ_INSERT_TAIL(&ch->ch_l_intents, it, it_q); 1085*c95a3ae2Sjmcneill 1086*c95a3ae2Sjmcneill msg.cmd = GLINK_CMD_INTENT; 1087*c95a3ae2Sjmcneill msg.param1 = ch->ch_lcid; 1088*c95a3ae2Sjmcneill msg.param2 = 1; 1089*c95a3ae2Sjmcneill intent.size = it->it_size; 1090*c95a3ae2Sjmcneill intent.iid = it->it_id; 1091*c95a3ae2Sjmcneill } 1092*c95a3ae2Sjmcneill 1093*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&msg, sizeof(msg)); 1094*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&intent, sizeof(intent)); 1095*c95a3ae2Sjmcneill qcpas_glink_tx_commit(sc); 1096*c95a3ae2Sjmcneill } 1097*c95a3ae2Sjmcneill 1098*c95a3ae2Sjmcneill static void 1099*c95a3ae2Sjmcneill qcpas_glink_recv_intent(struct qcpas_softc *sc, uint32_t rcid, uint32_t count) 1100*c95a3ae2Sjmcneill { 1101*c95a3ae2Sjmcneill struct qcpas_glink_intent_pair *intents; 1102*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch; 1103*c95a3ae2Sjmcneill struct qcpas_glink_intent *it; 1104*c95a3ae2Sjmcneill int i; 1105*c95a3ae2Sjmcneill 1106*c95a3ae2Sjmcneill intents = kmem_zalloc(sizeof(*intents) * count, KM_SLEEP); 1107*c95a3ae2Sjmcneill qcpas_glink_rx(sc, (char *)intents, sizeof(*intents) * count); 1108*c95a3ae2Sjmcneill qcpas_glink_rx_commit(sc); 1109*c95a3ae2Sjmcneill 1110*c95a3ae2Sjmcneill TAILQ_FOREACH(ch, &sc->sc_glink_channels, ch_q) { 1111*c95a3ae2Sjmcneill if (ch->ch_rcid == rcid) 1112*c95a3ae2Sjmcneill break; 1113*c95a3ae2Sjmcneill } 1114*c95a3ae2Sjmcneill if (ch == NULL) { 1115*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "unknown channel %u for INTENT\n", 1116*c95a3ae2Sjmcneill rcid); 1117*c95a3ae2Sjmcneill kmem_free(intents, sizeof(*intents) * count); 1118*c95a3ae2Sjmcneill return; 1119*c95a3ae2Sjmcneill } 1120*c95a3ae2Sjmcneill 1121*c95a3ae2Sjmcneill for (i = 0; i < count; i++) { 1122*c95a3ae2Sjmcneill it = kmem_zalloc(sizeof(*it), KM_SLEEP); 1123*c95a3ae2Sjmcneill it->it_id = intents[i].iid; 1124*c95a3ae2Sjmcneill it->it_size = intents[i].size; 1125*c95a3ae2Sjmcneill TAILQ_INSERT_TAIL(&ch->ch_r_intents, it, it_q); 1126*c95a3ae2Sjmcneill } 1127*c95a3ae2Sjmcneill 1128*c95a3ae2Sjmcneill kmem_free(intents, sizeof(*intents) * count); 1129*c95a3ae2Sjmcneill } 1130*c95a3ae2Sjmcneill 1131*c95a3ae2Sjmcneill static void 1132*c95a3ae2Sjmcneill qcpas_glink_recv_tx_data(struct qcpas_softc *sc, uint32_t rcid, uint32_t liid) 1133*c95a3ae2Sjmcneill { 1134*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch; 1135*c95a3ae2Sjmcneill struct qcpas_glink_intent *it; 1136*c95a3ae2Sjmcneill struct glink_msg msg; 1137*c95a3ae2Sjmcneill uint32_t chunk_size, left_size; 1138*c95a3ae2Sjmcneill char *buf; 1139*c95a3ae2Sjmcneill 1140*c95a3ae2Sjmcneill qcpas_glink_rx(sc, (char *)&chunk_size, sizeof(chunk_size)); 1141*c95a3ae2Sjmcneill qcpas_glink_rx(sc, (char *)&left_size, sizeof(left_size)); 1142*c95a3ae2Sjmcneill qcpas_glink_rx_commit(sc); 1143*c95a3ae2Sjmcneill 1144*c95a3ae2Sjmcneill buf = kmem_zalloc(chunk_size, KM_SLEEP); 1145*c95a3ae2Sjmcneill qcpas_glink_rx(sc, buf, chunk_size); 1146*c95a3ae2Sjmcneill qcpas_glink_rx_commit(sc); 1147*c95a3ae2Sjmcneill 1148*c95a3ae2Sjmcneill TAILQ_FOREACH(ch, &sc->sc_glink_channels, ch_q) { 1149*c95a3ae2Sjmcneill if (ch->ch_rcid == rcid) 1150*c95a3ae2Sjmcneill break; 1151*c95a3ae2Sjmcneill } 1152*c95a3ae2Sjmcneill if (ch == NULL) { 1153*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "unknown channel %u for TX_DATA\n", 1154*c95a3ae2Sjmcneill rcid); 1155*c95a3ae2Sjmcneill kmem_free(buf, chunk_size); 1156*c95a3ae2Sjmcneill return; 1157*c95a3ae2Sjmcneill } 1158*c95a3ae2Sjmcneill 1159*c95a3ae2Sjmcneill TAILQ_FOREACH(it, &ch->ch_l_intents, it_q) { 1160*c95a3ae2Sjmcneill if (it->it_id == liid) 1161*c95a3ae2Sjmcneill break; 1162*c95a3ae2Sjmcneill } 1163*c95a3ae2Sjmcneill if (it == NULL) { 1164*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "unknown intent %u for TX_DATA\n", 1165*c95a3ae2Sjmcneill liid); 1166*c95a3ae2Sjmcneill kmem_free(buf, chunk_size); 1167*c95a3ae2Sjmcneill return; 1168*c95a3ae2Sjmcneill } 1169*c95a3ae2Sjmcneill 1170*c95a3ae2Sjmcneill /* FIXME: handle message chunking */ 1171*c95a3ae2Sjmcneill KASSERT(left_size == 0); 1172*c95a3ae2Sjmcneill 1173*c95a3ae2Sjmcneill ch->ch_proto->recv(ch, buf, chunk_size); 1174*c95a3ae2Sjmcneill kmem_free(buf, chunk_size); 1175*c95a3ae2Sjmcneill 1176*c95a3ae2Sjmcneill if (!left_size) { 1177*c95a3ae2Sjmcneill msg.cmd = GLINK_CMD_RX_DONE_W_REUSE; 1178*c95a3ae2Sjmcneill msg.param1 = ch->ch_lcid; 1179*c95a3ae2Sjmcneill msg.param2 = it->it_id; 1180*c95a3ae2Sjmcneill 1181*c95a3ae2Sjmcneill qcpas_glink_tx(sc, (char *)&msg, sizeof(msg)); 1182*c95a3ae2Sjmcneill qcpas_glink_tx_commit(sc); 1183*c95a3ae2Sjmcneill } 1184*c95a3ae2Sjmcneill } 1185*c95a3ae2Sjmcneill 1186*c95a3ae2Sjmcneill static void 1187*c95a3ae2Sjmcneill qcpas_glink_recv_rx_done(struct qcpas_softc *sc, uint32_t rcid, uint32_t riid, 1188*c95a3ae2Sjmcneill int reuse) 1189*c95a3ae2Sjmcneill { 1190*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch; 1191*c95a3ae2Sjmcneill struct qcpas_glink_intent *it; 1192*c95a3ae2Sjmcneill 1193*c95a3ae2Sjmcneill TAILQ_FOREACH(ch, &sc->sc_glink_channels, ch_q) { 1194*c95a3ae2Sjmcneill if (ch->ch_rcid == rcid) 1195*c95a3ae2Sjmcneill break; 1196*c95a3ae2Sjmcneill } 1197*c95a3ae2Sjmcneill if (ch == NULL) { 1198*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "unknown channel %u for RX_DONE\n", 1199*c95a3ae2Sjmcneill rcid); 1200*c95a3ae2Sjmcneill return; 1201*c95a3ae2Sjmcneill } 1202*c95a3ae2Sjmcneill 1203*c95a3ae2Sjmcneill TAILQ_FOREACH(it, &ch->ch_r_intents, it_q) { 1204*c95a3ae2Sjmcneill if (it->it_id == riid) 1205*c95a3ae2Sjmcneill break; 1206*c95a3ae2Sjmcneill } 1207*c95a3ae2Sjmcneill if (it == NULL) { 1208*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "unknown intent %u for RX_DONE\n", 1209*c95a3ae2Sjmcneill riid); 1210*c95a3ae2Sjmcneill return; 1211*c95a3ae2Sjmcneill } 1212*c95a3ae2Sjmcneill 1213*c95a3ae2Sjmcneill /* FIXME: handle non-reuse */ 1214*c95a3ae2Sjmcneill KASSERT(reuse); 1215*c95a3ae2Sjmcneill 1216*c95a3ae2Sjmcneill KASSERT(it->it_inuse); 1217*c95a3ae2Sjmcneill it->it_inuse = 0; 1218*c95a3ae2Sjmcneill } 1219*c95a3ae2Sjmcneill 1220*c95a3ae2Sjmcneill static void 1221*c95a3ae2Sjmcneill qcpas_glink_recv(void *arg) 1222*c95a3ae2Sjmcneill { 1223*c95a3ae2Sjmcneill struct qcpas_softc *sc = arg; 1224*c95a3ae2Sjmcneill struct glink_msg msg; 1225*c95a3ae2Sjmcneill 1226*c95a3ae2Sjmcneill while (*sc->sc_rx_tail != *sc->sc_rx_head) { 1227*c95a3ae2Sjmcneill membar_consumer(); 1228*c95a3ae2Sjmcneill qcpas_glink_rx(sc, (uint8_t *)&msg, sizeof(msg)); 1229*c95a3ae2Sjmcneill qcpas_glink_rx_commit(sc); 1230*c95a3ae2Sjmcneill 1231*c95a3ae2Sjmcneill switch (msg.cmd) { 1232*c95a3ae2Sjmcneill case GLINK_CMD_VERSION: 1233*c95a3ae2Sjmcneill qcpas_glink_recv_version(sc, msg.param1, msg.param2); 1234*c95a3ae2Sjmcneill break; 1235*c95a3ae2Sjmcneill case GLINK_CMD_OPEN: 1236*c95a3ae2Sjmcneill qcpas_glink_recv_open(sc, msg.param1, msg.param2); 1237*c95a3ae2Sjmcneill break; 1238*c95a3ae2Sjmcneill case GLINK_CMD_OPEN_ACK: 1239*c95a3ae2Sjmcneill qcpas_glink_recv_open_ack(sc, msg.param1); 1240*c95a3ae2Sjmcneill break; 1241*c95a3ae2Sjmcneill case GLINK_CMD_INTENT: 1242*c95a3ae2Sjmcneill qcpas_glink_recv_intent(sc, msg.param1, msg.param2); 1243*c95a3ae2Sjmcneill break; 1244*c95a3ae2Sjmcneill case GLINK_CMD_RX_INTENT_REQ: 1245*c95a3ae2Sjmcneill /* Nothing to do so far */ 1246*c95a3ae2Sjmcneill break; 1247*c95a3ae2Sjmcneill case GLINK_CMD_TX_DATA: 1248*c95a3ae2Sjmcneill qcpas_glink_recv_tx_data(sc, msg.param1, msg.param2); 1249*c95a3ae2Sjmcneill break; 1250*c95a3ae2Sjmcneill case GLINK_CMD_RX_DONE: 1251*c95a3ae2Sjmcneill qcpas_glink_recv_rx_done(sc, msg.param1, msg.param2, 0); 1252*c95a3ae2Sjmcneill break; 1253*c95a3ae2Sjmcneill case GLINK_CMD_RX_DONE_W_REUSE: 1254*c95a3ae2Sjmcneill qcpas_glink_recv_rx_done(sc, msg.param1, msg.param2, 1); 1255*c95a3ae2Sjmcneill break; 1256*c95a3ae2Sjmcneill default: 1257*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "unknown cmd %u\n", msg.cmd); 1258*c95a3ae2Sjmcneill return; 1259*c95a3ae2Sjmcneill } 1260*c95a3ae2Sjmcneill } 1261*c95a3ae2Sjmcneill } 1262*c95a3ae2Sjmcneill 1263*c95a3ae2Sjmcneill static int 1264*c95a3ae2Sjmcneill qcpas_glink_intr(void *cookie) 1265*c95a3ae2Sjmcneill { 1266*c95a3ae2Sjmcneill struct qcpas_softc *sc = cookie; 1267*c95a3ae2Sjmcneill 1268*c95a3ae2Sjmcneill sysmon_task_queue_sched(0, qcpas_glink_recv, sc); 1269*c95a3ae2Sjmcneill 1270*c95a3ae2Sjmcneill return 1; 1271*c95a3ae2Sjmcneill } 1272*c95a3ae2Sjmcneill 1273*c95a3ae2Sjmcneill /* GLINK PMIC Router */ 1274*c95a3ae2Sjmcneill 1275*c95a3ae2Sjmcneill struct pmic_glink_hdr { 1276*c95a3ae2Sjmcneill uint32_t owner; 1277*c95a3ae2Sjmcneill #define PMIC_GLINK_OWNER_BATTMGR 32778 1278*c95a3ae2Sjmcneill #define PMIC_GLINK_OWNER_USBC 32779 1279*c95a3ae2Sjmcneill #define PMIC_GLINK_OWNER_USBC_PAN 32780 1280*c95a3ae2Sjmcneill uint32_t type; 1281*c95a3ae2Sjmcneill #define PMIC_GLINK_TYPE_REQ_RESP 1 1282*c95a3ae2Sjmcneill #define PMIC_GLINK_TYPE_NOTIFY 2 1283*c95a3ae2Sjmcneill uint32_t opcode; 1284*c95a3ae2Sjmcneill }; 1285*c95a3ae2Sjmcneill 1286*c95a3ae2Sjmcneill #define BATTMGR_OPCODE_BAT_STATUS 0x1 1287*c95a3ae2Sjmcneill #define BATTMGR_OPCODR_REQUEST_NOTIFICATION 0x4 1288*c95a3ae2Sjmcneill #define BATTMGR_OPCODE_NOTIF 0x7 1289*c95a3ae2Sjmcneill #define BATTMGR_OPCODE_BAT_INFO 0x9 1290*c95a3ae2Sjmcneill #define BATTMGR_OPCODE_BAT_DISCHARGE_TIME 0xc 1291*c95a3ae2Sjmcneill #define BATTMGR_OPCODE_BAT_CHARGE_TIME 0xd 1292*c95a3ae2Sjmcneill 1293*c95a3ae2Sjmcneill #define BATTMGR_NOTIF_BAT_PROPERTY 0x30 1294*c95a3ae2Sjmcneill #define BATTMGR_NOTIF_USB_PROPERTY 0x32 1295*c95a3ae2Sjmcneill #define BATTMGR_NOTIF_WLS_PROPERTY 0x34 1296*c95a3ae2Sjmcneill #define BATTMGR_NOTIF_BAT_STATUS 0x80 1297*c95a3ae2Sjmcneill #define BATTMGR_NOTIF_BAT_INFO 0x81 1298*c95a3ae2Sjmcneill 1299*c95a3ae2Sjmcneill #define BATTMGR_CHEMISTRY_LEN 4 1300*c95a3ae2Sjmcneill #define BATTMGR_STRING_LEN 128 1301*c95a3ae2Sjmcneill 1302*c95a3ae2Sjmcneill struct battmgr_bat_info { 1303*c95a3ae2Sjmcneill uint32_t power_unit; 1304*c95a3ae2Sjmcneill uint32_t design_capacity; 1305*c95a3ae2Sjmcneill uint32_t last_full_capacity; 1306*c95a3ae2Sjmcneill uint32_t battery_tech; 1307*c95a3ae2Sjmcneill uint32_t design_voltage; 1308*c95a3ae2Sjmcneill uint32_t capacity_low; 1309*c95a3ae2Sjmcneill uint32_t capacity_warning; 1310*c95a3ae2Sjmcneill uint32_t cycle_count; 1311*c95a3ae2Sjmcneill uint32_t accuracy; 1312*c95a3ae2Sjmcneill uint32_t max_sample_time_ms; 1313*c95a3ae2Sjmcneill uint32_t min_sample_time_ms; 1314*c95a3ae2Sjmcneill uint32_t max_average_interval_ms; 1315*c95a3ae2Sjmcneill uint32_t min_average_interval_ms; 1316*c95a3ae2Sjmcneill uint32_t capacity_granularity1; 1317*c95a3ae2Sjmcneill uint32_t capacity_granularity2; 1318*c95a3ae2Sjmcneill uint32_t swappable; 1319*c95a3ae2Sjmcneill uint32_t capabilities; 1320*c95a3ae2Sjmcneill char model_number[BATTMGR_STRING_LEN]; 1321*c95a3ae2Sjmcneill char serial_number[BATTMGR_STRING_LEN]; 1322*c95a3ae2Sjmcneill char battery_type[BATTMGR_STRING_LEN]; 1323*c95a3ae2Sjmcneill char oem_info[BATTMGR_STRING_LEN]; 1324*c95a3ae2Sjmcneill char battery_chemistry[BATTMGR_CHEMISTRY_LEN]; 1325*c95a3ae2Sjmcneill char uid[BATTMGR_STRING_LEN]; 1326*c95a3ae2Sjmcneill uint32_t critical_bias; 1327*c95a3ae2Sjmcneill uint8_t day; 1328*c95a3ae2Sjmcneill uint8_t month; 1329*c95a3ae2Sjmcneill uint16_t year; 1330*c95a3ae2Sjmcneill uint32_t battery_id; 1331*c95a3ae2Sjmcneill }; 1332*c95a3ae2Sjmcneill 1333*c95a3ae2Sjmcneill struct battmgr_bat_status { 1334*c95a3ae2Sjmcneill uint32_t battery_state; 1335*c95a3ae2Sjmcneill #define BATTMGR_BAT_STATE_DISCHARGE (1 << 0) 1336*c95a3ae2Sjmcneill #define BATTMGR_BAT_STATE_CHARGING (1 << 1) 1337*c95a3ae2Sjmcneill #define BATTMGR_BAT_STATE_CRITICAL_LOW (1 << 2) 1338*c95a3ae2Sjmcneill uint32_t capacity; 1339*c95a3ae2Sjmcneill int32_t rate; 1340*c95a3ae2Sjmcneill uint32_t battery_voltage; 1341*c95a3ae2Sjmcneill uint32_t power_state; 1342*c95a3ae2Sjmcneill #define BATTMGR_PWR_STATE_AC_ON (1 << 0) 1343*c95a3ae2Sjmcneill uint32_t charging_source; 1344*c95a3ae2Sjmcneill #define BATTMGR_CHARGING_SOURCE_AC 1 1345*c95a3ae2Sjmcneill #define BATTMGR_CHARGING_SOURCE_USB 2 1346*c95a3ae2Sjmcneill #define BATTMGR_CHARGING_SOURCE_WIRELESS 3 1347*c95a3ae2Sjmcneill uint32_t temperature; 1348*c95a3ae2Sjmcneill }; 1349*c95a3ae2Sjmcneill 1350*c95a3ae2Sjmcneill static void qcpas_pmic_rtr_refresh(void *); 1351*c95a3ae2Sjmcneill static void qcpas_pmic_rtr_bat_info(struct qcpas_softc *, 1352*c95a3ae2Sjmcneill struct battmgr_bat_info *); 1353*c95a3ae2Sjmcneill static void qcpas_pmic_rtr_bat_status(struct qcpas_softc *, 1354*c95a3ae2Sjmcneill struct battmgr_bat_status *); 1355*c95a3ae2Sjmcneill 1356*c95a3ae2Sjmcneill static void 1357*c95a3ae2Sjmcneill qcpas_pmic_rtr_battmgr_req_info(void *cookie) 1358*c95a3ae2Sjmcneill { 1359*c95a3ae2Sjmcneill struct { 1360*c95a3ae2Sjmcneill struct pmic_glink_hdr hdr; 1361*c95a3ae2Sjmcneill uint32_t battery_id; 1362*c95a3ae2Sjmcneill } msg; 1363*c95a3ae2Sjmcneill 1364*c95a3ae2Sjmcneill msg.hdr.owner = PMIC_GLINK_OWNER_BATTMGR; 1365*c95a3ae2Sjmcneill msg.hdr.type = PMIC_GLINK_TYPE_REQ_RESP; 1366*c95a3ae2Sjmcneill msg.hdr.opcode = BATTMGR_OPCODE_BAT_INFO; 1367*c95a3ae2Sjmcneill msg.battery_id = 0; 1368*c95a3ae2Sjmcneill qcpas_glink_send(cookie, &msg, sizeof(msg)); 1369*c95a3ae2Sjmcneill } 1370*c95a3ae2Sjmcneill 1371*c95a3ae2Sjmcneill static void 1372*c95a3ae2Sjmcneill qcpas_pmic_rtr_battmgr_req_status(void *cookie) 1373*c95a3ae2Sjmcneill { 1374*c95a3ae2Sjmcneill struct { 1375*c95a3ae2Sjmcneill struct pmic_glink_hdr hdr; 1376*c95a3ae2Sjmcneill uint32_t battery_id; 1377*c95a3ae2Sjmcneill } msg; 1378*c95a3ae2Sjmcneill 1379*c95a3ae2Sjmcneill msg.hdr.owner = PMIC_GLINK_OWNER_BATTMGR; 1380*c95a3ae2Sjmcneill msg.hdr.type = PMIC_GLINK_TYPE_REQ_RESP; 1381*c95a3ae2Sjmcneill msg.hdr.opcode = BATTMGR_OPCODE_BAT_STATUS; 1382*c95a3ae2Sjmcneill msg.battery_id = 0; 1383*c95a3ae2Sjmcneill qcpas_glink_send(cookie, &msg, sizeof(msg)); 1384*c95a3ae2Sjmcneill } 1385*c95a3ae2Sjmcneill 1386*c95a3ae2Sjmcneill static int 1387*c95a3ae2Sjmcneill qcpas_pmic_rtr_init(void *cookie) 1388*c95a3ae2Sjmcneill { 1389*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch = cookie; 1390*c95a3ae2Sjmcneill struct qcpas_softc *sc = ch->ch_sc; 1391*c95a3ae2Sjmcneill 1392*c95a3ae2Sjmcneill callout_init(&sc->sc_rtr_refresh, 0); 1393*c95a3ae2Sjmcneill callout_setfunc(&sc->sc_rtr_refresh, qcpas_pmic_rtr_refresh, ch); 1394*c95a3ae2Sjmcneill 1395*c95a3ae2Sjmcneill callout_schedule(&sc->sc_rtr_refresh, hz * 5); 1396*c95a3ae2Sjmcneill 1397*c95a3ae2Sjmcneill return 0; 1398*c95a3ae2Sjmcneill } 1399*c95a3ae2Sjmcneill 1400*c95a3ae2Sjmcneill static int 1401*c95a3ae2Sjmcneill qcpas_pmic_rtr_recv(void *cookie, uint8_t *buf, int len) 1402*c95a3ae2Sjmcneill { 1403*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch = cookie; 1404*c95a3ae2Sjmcneill struct qcpas_softc *sc = ch->ch_sc; 1405*c95a3ae2Sjmcneill struct pmic_glink_hdr hdr; 1406*c95a3ae2Sjmcneill uint32_t notification; 1407*c95a3ae2Sjmcneill 1408*c95a3ae2Sjmcneill if (len < sizeof(hdr)) { 1409*c95a3ae2Sjmcneill device_printf(sc->sc_dev, "pmic glink message too small\n"); 1410*c95a3ae2Sjmcneill return 0; 1411*c95a3ae2Sjmcneill } 1412*c95a3ae2Sjmcneill 1413*c95a3ae2Sjmcneill memcpy(&hdr, buf, sizeof(hdr)); 1414*c95a3ae2Sjmcneill 1415*c95a3ae2Sjmcneill switch (hdr.owner) { 1416*c95a3ae2Sjmcneill case PMIC_GLINK_OWNER_BATTMGR: 1417*c95a3ae2Sjmcneill switch (hdr.opcode) { 1418*c95a3ae2Sjmcneill case BATTMGR_OPCODE_NOTIF: 1419*c95a3ae2Sjmcneill if (len - sizeof(hdr) != sizeof(uint32_t)) { 1420*c95a3ae2Sjmcneill device_printf(sc->sc_dev, 1421*c95a3ae2Sjmcneill "invalid battgmr notification\n"); 1422*c95a3ae2Sjmcneill return 0; 1423*c95a3ae2Sjmcneill } 1424*c95a3ae2Sjmcneill memcpy(¬ification, buf + sizeof(hdr), 1425*c95a3ae2Sjmcneill sizeof(uint32_t)); 1426*c95a3ae2Sjmcneill switch (notification) { 1427*c95a3ae2Sjmcneill case BATTMGR_NOTIF_BAT_INFO: 1428*c95a3ae2Sjmcneill qcpas_pmic_rtr_battmgr_req_info(cookie); 1429*c95a3ae2Sjmcneill /* FALLTHROUGH */ 1430*c95a3ae2Sjmcneill case BATTMGR_NOTIF_BAT_STATUS: 1431*c95a3ae2Sjmcneill case BATTMGR_NOTIF_BAT_PROPERTY: 1432*c95a3ae2Sjmcneill qcpas_pmic_rtr_battmgr_req_status(cookie); 1433*c95a3ae2Sjmcneill break; 1434*c95a3ae2Sjmcneill default: 1435*c95a3ae2Sjmcneill aprint_debug_dev(sc->sc_dev, 1436*c95a3ae2Sjmcneill "unknown battmgr notification 0x%02x\n", 1437*c95a3ae2Sjmcneill notification); 1438*c95a3ae2Sjmcneill break; 1439*c95a3ae2Sjmcneill } 1440*c95a3ae2Sjmcneill break; 1441*c95a3ae2Sjmcneill case BATTMGR_OPCODE_BAT_INFO: { 1442*c95a3ae2Sjmcneill struct battmgr_bat_info *bat; 1443*c95a3ae2Sjmcneill if (len - sizeof(hdr) < sizeof(*bat)) { 1444*c95a3ae2Sjmcneill device_printf(sc->sc_dev, 1445*c95a3ae2Sjmcneill "invalid battgmr bat info\n"); 1446*c95a3ae2Sjmcneill return 0; 1447*c95a3ae2Sjmcneill } 1448*c95a3ae2Sjmcneill bat = kmem_alloc(sizeof(*bat), KM_SLEEP); 1449*c95a3ae2Sjmcneill memcpy(bat, buf + sizeof(hdr), sizeof(*bat)); 1450*c95a3ae2Sjmcneill qcpas_pmic_rtr_bat_info(sc, bat); 1451*c95a3ae2Sjmcneill kmem_free(bat, sizeof(*bat)); 1452*c95a3ae2Sjmcneill break; 1453*c95a3ae2Sjmcneill } 1454*c95a3ae2Sjmcneill case BATTMGR_OPCODE_BAT_STATUS: { 1455*c95a3ae2Sjmcneill struct battmgr_bat_status *bat; 1456*c95a3ae2Sjmcneill if (len - sizeof(hdr) != sizeof(*bat)) { 1457*c95a3ae2Sjmcneill device_printf(sc->sc_dev, 1458*c95a3ae2Sjmcneill "invalid battgmr bat status\n"); 1459*c95a3ae2Sjmcneill return 0; 1460*c95a3ae2Sjmcneill } 1461*c95a3ae2Sjmcneill bat = kmem_alloc(sizeof(*bat), KM_SLEEP); 1462*c95a3ae2Sjmcneill memcpy(bat, buf + sizeof(hdr), sizeof(*bat)); 1463*c95a3ae2Sjmcneill qcpas_pmic_rtr_bat_status(sc, bat); 1464*c95a3ae2Sjmcneill kmem_free(bat, sizeof(*bat)); 1465*c95a3ae2Sjmcneill break; 1466*c95a3ae2Sjmcneill } 1467*c95a3ae2Sjmcneill default: 1468*c95a3ae2Sjmcneill device_printf(sc->sc_dev, 1469*c95a3ae2Sjmcneill "unknown battmgr opcode 0x%02x\n", 1470*c95a3ae2Sjmcneill hdr.opcode); 1471*c95a3ae2Sjmcneill break; 1472*c95a3ae2Sjmcneill } 1473*c95a3ae2Sjmcneill break; 1474*c95a3ae2Sjmcneill default: 1475*c95a3ae2Sjmcneill device_printf(sc->sc_dev, 1476*c95a3ae2Sjmcneill "unknown pmic glink owner 0x%04x\n", 1477*c95a3ae2Sjmcneill hdr.owner); 1478*c95a3ae2Sjmcneill break; 1479*c95a3ae2Sjmcneill } 1480*c95a3ae2Sjmcneill 1481*c95a3ae2Sjmcneill return 0; 1482*c95a3ae2Sjmcneill } 1483*c95a3ae2Sjmcneill 1484*c95a3ae2Sjmcneill static void 1485*c95a3ae2Sjmcneill qcpas_pmic_rtr_refresh(void *arg) 1486*c95a3ae2Sjmcneill { 1487*c95a3ae2Sjmcneill struct qcpas_glink_channel *ch = arg; 1488*c95a3ae2Sjmcneill struct qcpas_softc *sc = ch->ch_sc; 1489*c95a3ae2Sjmcneill 1490*c95a3ae2Sjmcneill qcpas_pmic_rtr_battmgr_req_status(ch); 1491*c95a3ae2Sjmcneill 1492*c95a3ae2Sjmcneill callout_schedule(&sc->sc_rtr_refresh, hz * 5); 1493*c95a3ae2Sjmcneill } 1494*c95a3ae2Sjmcneill 1495*c95a3ae2Sjmcneill static void 1496*c95a3ae2Sjmcneill qcpas_pmic_rtr_bat_info(struct qcpas_softc *sc, struct battmgr_bat_info *bat) 1497*c95a3ae2Sjmcneill { 1498*c95a3ae2Sjmcneill sc->sc_warning_capacity = bat->capacity_warning; 1499*c95a3ae2Sjmcneill sc->sc_low_capacity = bat->capacity_low; 1500*c95a3ae2Sjmcneill 1501*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DCAPACITY].value_cur = 1502*c95a3ae2Sjmcneill bat->design_capacity * 1000; 1503*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DCAPACITY].state = ENVSYS_SVALID; 1504*c95a3ae2Sjmcneill 1505*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_LFCCAPACITY].value_cur = 1506*c95a3ae2Sjmcneill bat->last_full_capacity * 1000; 1507*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_LFCCAPACITY].state = ENVSYS_SVALID; 1508*c95a3ae2Sjmcneill 1509*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DVOLTAGE].value_cur = 1510*c95a3ae2Sjmcneill bat->design_voltage * 1000; 1511*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DVOLTAGE].state = ENVSYS_SVALID; 1512*c95a3ae2Sjmcneill 1513*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DCYCLES].value_cur = 1514*c95a3ae2Sjmcneill bat->cycle_count; 1515*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DCYCLES].state = ENVSYS_SVALID; 1516*c95a3ae2Sjmcneill 1517*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CAPACITY].value_max = 1518*c95a3ae2Sjmcneill bat->last_full_capacity * 1000; 1519*c95a3ae2Sjmcneill sysmon_envsys_update_limits(sc->sc_sme, 1520*c95a3ae2Sjmcneill &sc->sc_sens[QCPAS_CAPACITY]); 1521*c95a3ae2Sjmcneill } 1522*c95a3ae2Sjmcneill 1523*c95a3ae2Sjmcneill void 1524*c95a3ae2Sjmcneill qcpas_pmic_rtr_bat_status(struct qcpas_softc *sc, 1525*c95a3ae2Sjmcneill struct battmgr_bat_status *bat) 1526*c95a3ae2Sjmcneill { 1527*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGING].value_cur = 1528*c95a3ae2Sjmcneill (bat->battery_state & BATTMGR_BAT_STATE_CHARGING) != 0; 1529*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGING].state = ENVSYS_SVALID; 1530*c95a3ae2Sjmcneill if ((bat->battery_state & BATTMGR_BAT_STATE_CHARGING) != 0) { 1531*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGERATE].value_cur = 1532*c95a3ae2Sjmcneill abs(bat->rate) * 1000; 1533*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGERATE].state = ENVSYS_SVALID; 1534*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DISCHARGERATE].state = ENVSYS_SINVALID; 1535*c95a3ae2Sjmcneill } else if ((bat->battery_state & BATTMGR_BAT_STATE_DISCHARGE) != 0) { 1536*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGERATE].state = ENVSYS_SINVALID; 1537*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DISCHARGERATE].value_cur = 1538*c95a3ae2Sjmcneill abs(bat->rate) * 1000; 1539*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DISCHARGERATE].state = ENVSYS_SVALID; 1540*c95a3ae2Sjmcneill } else { 1541*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_DISCHARGERATE].state = ENVSYS_SINVALID; 1542*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGERATE].state = ENVSYS_SINVALID; 1543*c95a3ae2Sjmcneill } 1544*c95a3ae2Sjmcneill 1545*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_VOLTAGE].value_cur = 1546*c95a3ae2Sjmcneill bat->battery_voltage * 1000; 1547*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_VOLTAGE].state = ENVSYS_SVALID; 1548*c95a3ae2Sjmcneill 1549*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_TEMPERATURE].value_cur = 1550*c95a3ae2Sjmcneill (bat->temperature * 10000) + 273150000; 1551*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_TEMPERATURE].state = ENVSYS_SVALID; 1552*c95a3ae2Sjmcneill 1553*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CAPACITY].value_cur = 1554*c95a3ae2Sjmcneill bat->capacity * 1000; 1555*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CAPACITY].state = ENVSYS_SVALID; 1556*c95a3ae2Sjmcneill 1557*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGE_STATE].value_cur = 1558*c95a3ae2Sjmcneill ENVSYS_BATTERY_CAPACITY_NORMAL; 1559*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGE_STATE].state = ENVSYS_SVALID; 1560*c95a3ae2Sjmcneill 1561*c95a3ae2Sjmcneill if (bat->capacity < sc->sc_warning_capacity) { 1562*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CAPACITY].state = ENVSYS_SWARNUNDER; 1563*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGE_STATE].value_cur = 1564*c95a3ae2Sjmcneill ENVSYS_BATTERY_CAPACITY_WARNING; 1565*c95a3ae2Sjmcneill } 1566*c95a3ae2Sjmcneill 1567*c95a3ae2Sjmcneill if (bat->capacity < sc->sc_low_capacity) { 1568*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CAPACITY].state = ENVSYS_SCRITUNDER; 1569*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGE_STATE].value_cur = 1570*c95a3ae2Sjmcneill ENVSYS_BATTERY_CAPACITY_LOW; 1571*c95a3ae2Sjmcneill } 1572*c95a3ae2Sjmcneill 1573*c95a3ae2Sjmcneill if ((bat->battery_state & BATTMGR_BAT_STATE_CRITICAL_LOW) != 0) { 1574*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CAPACITY].state = ENVSYS_SCRITICAL; 1575*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_CHARGE_STATE].value_cur = 1576*c95a3ae2Sjmcneill ENVSYS_BATTERY_CAPACITY_CRITICAL; 1577*c95a3ae2Sjmcneill } 1578*c95a3ae2Sjmcneill 1579*c95a3ae2Sjmcneill if ((bat->power_state & BATTMGR_PWR_STATE_AC_ON) != 1580*c95a3ae2Sjmcneill (sc->sc_power_state & BATTMGR_PWR_STATE_AC_ON)) { 1581*c95a3ae2Sjmcneill sysmon_pswitch_event(&sc->sc_smpsw_acadapter, 1582*c95a3ae2Sjmcneill (bat->power_state & BATTMGR_PWR_STATE_AC_ON) != 0 ? 1583*c95a3ae2Sjmcneill PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED); 1584*c95a3ae2Sjmcneill 1585*c95a3ae2Sjmcneill aprint_debug_dev(sc->sc_dev, "AC adapter %sconnected\n", 1586*c95a3ae2Sjmcneill (bat->power_state & BATTMGR_PWR_STATE_AC_ON) == 0 ? 1587*c95a3ae2Sjmcneill "not " : ""); 1588*c95a3ae2Sjmcneill } 1589*c95a3ae2Sjmcneill 1590*c95a3ae2Sjmcneill sc->sc_power_state = bat->power_state; 1591*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_ACADAPTER].value_cur = 1592*c95a3ae2Sjmcneill (bat->power_state & BATTMGR_PWR_STATE_AC_ON) != 0; 1593*c95a3ae2Sjmcneill sc->sc_sens[QCPAS_ACADAPTER].state = ENVSYS_SVALID; 1594*c95a3ae2Sjmcneill } 1595*c95a3ae2Sjmcneill 1596*c95a3ae2Sjmcneill static void 1597*c95a3ae2Sjmcneill qcpas_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 1598*c95a3ae2Sjmcneill sysmon_envsys_lim_t *limits, uint32_t *props) 1599*c95a3ae2Sjmcneill { 1600*c95a3ae2Sjmcneill struct qcpas_softc *sc = sme->sme_cookie; 1601*c95a3ae2Sjmcneill 1602*c95a3ae2Sjmcneill if (edata->sensor != QCPAS_CAPACITY) { 1603*c95a3ae2Sjmcneill return; 1604*c95a3ae2Sjmcneill } 1605*c95a3ae2Sjmcneill 1606*c95a3ae2Sjmcneill limits->sel_critmin = sc->sc_low_capacity * 1000; 1607*c95a3ae2Sjmcneill limits->sel_warnmin = sc->sc_warning_capacity * 1000; 1608*c95a3ae2Sjmcneill 1609*c95a3ae2Sjmcneill *props |= PROP_BATTCAP | PROP_BATTWARN | PROP_DRIVER_LIMITS; 1610*c95a3ae2Sjmcneill } 1611