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