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