From fe62c2037e1c325af9b89215dcb1fc6e5b9ab677 Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 23 May 2023 14:10:27 +0000 Subject: [PATCH] Add qcaoss(4), a driver for the Always On Subsystem found on Qualcomm SoCs. This subsystem typically provides an interface for clocks and regulators not controlled via RPMH. We will use it to switch the load state of the ADSP co-processor. Surprisingly, or maybe not, the interface uses ASCII text that kind of looks like JSON. ok kettenis@ --- sys/arch/arm64/conf/GENERIC | 3 +- sys/arch/arm64/conf/RAMDISK | 3 +- sys/dev/fdt/files.fdt | 7 +- sys/dev/fdt/qcaoss.c | 215 ++++++++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 sys/dev/fdt/qcaoss.c diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC index 158e9d21e4d..fe24e7cec6a 100644 --- a/sys/arch/arm64/conf/GENERIC +++ b/sys/arch/arm64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.271 2023/05/19 21:26:09 patrick Exp $ +# $OpenBSD: GENERIC,v 1.272 2023/05/23 14:10:27 patrick Exp $ # # GENERIC machine description file # @@ -320,6 +320,7 @@ dwmshc* at fdt? sdmmc* at dwmshc? # Qualcomm SoCs +qcaoss* at fdt? qcdwusb* at fdt? qcgpio* at acpi? qcgpio* at fdt? early 1 diff --git a/sys/arch/arm64/conf/RAMDISK b/sys/arch/arm64/conf/RAMDISK index a33a70a1c83..02a0a1e1121 100644 --- a/sys/arch/arm64/conf/RAMDISK +++ b/sys/arch/arm64/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.204 2023/05/19 21:26:09 patrick Exp $ +# $OpenBSD: RAMDISK,v 1.205 2023/05/23 14:10:27 patrick Exp $ machine arm64 maxusers 4 @@ -244,6 +244,7 @@ dwmshc* at fdt? sdmmc* at dwmshc? # Qualcomm SoCs +qcaoss* at fdt? qcdwusb* at fdt? qcgpio* at acpi? qcgpio* at fdt? early 1 diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 1d19d5a00e2..ff108428512 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.191 2023/05/19 21:26:10 patrick Exp $ +# $OpenBSD: files.fdt,v 1.192 2023/05/23 14:10:27 patrick Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -664,6 +664,11 @@ device tascodec attach tascodec at i2c file dev/fdt/tascodec.c tascodec +# Qualcomm Always On Subsystem +device qcaoss +attach qcaoss at fdt +file dev/fdt/qcaoss.c qcaoss + device qcdwusb: fdt attach qcdwusb at fdt file dev/fdt/qcdwusb.c qcdwusb diff --git a/sys/dev/fdt/qcaoss.c b/sys/dev/fdt/qcaoss.c new file mode 100644 index 00000000000..ee666589122 --- /dev/null +++ b/sys/dev/fdt/qcaoss.c @@ -0,0 +1,215 @@ +/* $OpenBSD: qcaoss.c,v 1.1 2023/05/23 14:10:27 patrick Exp $ */ +/* + * Copyright (c) 2023 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define AOSS_DESC_MAGIC 0x0 +#define AOSS_DESC_VERSION 0x4 +#define AOSS_DESC_FEATURES 0x8 +#define AOSS_DESC_UCORE_LINK_STATE 0xc +#define AOSS_DESC_UCORE_LINK_STATE_ACK 0x10 +#define AOSS_DESC_UCORE_CH_STATE 0x14 +#define AOSS_DESC_UCORE_CH_STATE_ACK 0x18 +#define AOSS_DESC_UCORE_MBOX_SIZE 0x1c +#define AOSS_DESC_UCORE_MBOX_OFFSET 0x20 +#define AOSS_DESC_MCORE_LINK_STATE 0x24 +#define AOSS_DESC_MCORE_LINK_STATE_ACK 0x28 +#define AOSS_DESC_MCORE_CH_STATE 0x2c +#define AOSS_DESC_MCORE_CH_STATE_ACK 0x30 +#define AOSS_DESC_MCORE_MBOX_SIZE 0x34 +#define AOSS_DESC_MCORE_MBOX_OFFSET 0x38 + +#define AOSS_MAGIC 0x4d41494c +#define AOSS_VERSION 1 + +#define AOSS_STATE_UP (0xffffU << 0) +#define AOSS_STATE_DOWN (0xffffU << 16) + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +struct qcaoss_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + size_t sc_offset; + size_t sc_size; + + struct mbox_channel *sc_mc; +}; + +struct qcaoss_softc *qcaoss_sc; + +int qcaoss_match(struct device *, void *, void *); +void qcaoss_attach(struct device *, struct device *, void *); + +const struct cfattach qcaoss_ca = { + sizeof (struct qcaoss_softc), qcaoss_match, qcaoss_attach +}; + +struct cfdriver qcaoss_cd = { + NULL, "qcaoss", DV_DULL +}; + +int +qcaoss_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "qcom,aoss-qmp"); +} + +void +qcaoss_attach(struct device *parent, struct device *self, void *aux) +{ + struct qcaoss_softc *sc = (struct qcaoss_softc *)self; + struct fdt_attach_args *faa = aux; + int i; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } + + sc->sc_mc = mbox_channel_idx(faa->fa_node, 0, NULL); + if (sc->sc_mc == NULL) { + bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); + printf(": can't find mbox\n"); + return; + } + + if (HREAD4(sc, AOSS_DESC_MAGIC) != AOSS_MAGIC || + HREAD4(sc, AOSS_DESC_VERSION) != AOSS_VERSION) { + printf(": invalid QMP info\n"); + return; + } + + sc->sc_offset = HREAD4(sc, AOSS_DESC_MCORE_MBOX_OFFSET); + sc->sc_size = HREAD4(sc, AOSS_DESC_MCORE_MBOX_SIZE); + if (sc->sc_size == 0) { + printf(": invalid mailbox size\n"); + return; + } + + HWRITE4(sc, AOSS_DESC_UCORE_LINK_STATE_ACK, + HREAD4(sc, AOSS_DESC_UCORE_LINK_STATE)); + + HWRITE4(sc, AOSS_DESC_MCORE_LINK_STATE, AOSS_STATE_UP); + mbox_send(sc->sc_mc, NULL, 0); + + for (i = 1000; i > 0; i--) { + if (HREAD4(sc, AOSS_DESC_MCORE_LINK_STATE_ACK) == AOSS_STATE_UP) + break; + delay(1000); + } + if (i == 0) { + printf(": didn't get link state ack\n"); + return; + } + + HWRITE4(sc, AOSS_DESC_MCORE_CH_STATE, AOSS_STATE_UP); + mbox_send(sc->sc_mc, NULL, 0); + + for (i = 1000; i > 0; i--) { + if (HREAD4(sc, AOSS_DESC_UCORE_CH_STATE) == AOSS_STATE_UP) + break; + delay(1000); + } + if (i == 0) { + printf(": didn't get open channel\n"); + return; + } + + HWRITE4(sc, AOSS_DESC_UCORE_CH_STATE_ACK, AOSS_STATE_UP); + mbox_send(sc->sc_mc, NULL, 0); + + for (i = 1000; i > 0; i--) { + if (HREAD4(sc, AOSS_DESC_MCORE_CH_STATE_ACK) == AOSS_STATE_UP) + break; + delay(1000); + } + if (i == 0) { + printf(": didn't get channel ack\n"); + return; + } + + printf("\n"); + + qcaoss_sc = sc; +} + +int +qcaoss_send(char *data, size_t len) +{ + struct qcaoss_softc *sc = qcaoss_sc; + uint32_t reg; + int i; + + if (sc == NULL) + return ENXIO; + + if (data == NULL || sizeof(uint32_t) + len > sc->sc_size || + (len % sizeof(uint32_t)) != 0) + return EINVAL; + + /* Write data first, needs to be 32-bit access. */ + for (i = 0; i < len; i += 4) { + memcpy(®, data + i, sizeof(reg)); + HWRITE4(sc, sc->sc_offset + sizeof(uint32_t) + i, reg); + } + + /* Commit transaction by writing length. */ + HWRITE4(sc, sc->sc_offset, len); + + /* Assert it's stored and inform peer. */ + KASSERT(HREAD4(sc, sc->sc_offset) == len); + mbox_send(sc->sc_mc, NULL, 0); + + for (i = 1000; i > 0; i--) { + if (HREAD4(sc, sc->sc_offset) == 0) + break; + delay(1000); + } + if (i == 0) { + printf("%s: timeout sending message\n", sc->sc_dev.dv_xname); + HWRITE4(sc, sc->sc_offset, 0); + return ETIMEDOUT; + } + + return 0; +} -- 2.20.1