git: b12a863a1e14 - main - ipq4018: add initial reset driver support for the clock/reset controller.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 04 Nov 2021 16:02:56 UTC
The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=b12a863a1e14610f6b145f235aa7452602038f9a commit b12a863a1e14610f6b145f235aa7452602038f9a Author: Adrian Chadd <adrian@FreeBSD.org> AuthorDate: 2021-10-31 03:43:27 +0000 Commit: Adrian Chadd <adrian@FreeBSD.org> CommitDate: 2021-11-04 16:02:41 +0000 ipq4018: add initial reset driver support for the clock/reset controller. This implements the "reset controller" side of the clock/reset controller. It's a simple array of registers and bits to set. The register table itself comes from Linux; the rest of the code is a reimplementation. It doesn't yet implement or expose the clock side - I have a lot of reverse engineering to do before that! Reviewed by: andrew, manu, imp Differential Revision: https://reviews.freebsd.org/D32723 Obtained from: Linux (registers) --- sys/arm/qualcomm/qcom_gcc_ipq4018.c | 167 +++++++++++++++++++++++++++ sys/arm/qualcomm/qcom_gcc_ipq4018_reset.c | 181 ++++++++++++++++++++++++++++++ sys/arm/qualcomm/qcom_gcc_ipq4018_var.h | 50 +++++++++ sys/arm/qualcomm/std.ipq4018 | 3 + 4 files changed, 401 insertions(+) diff --git a/sys/arm/qualcomm/qcom_gcc_ipq4018.c b/sys/arm/qualcomm/qcom_gcc_ipq4018.c new file mode 100644 index 000000000000..3002ae32a597 --- /dev/null +++ b/sys/arm/qualcomm/qcom_gcc_ipq4018.c @@ -0,0 +1,167 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021, Adrian Chadd <adrian@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Driver for Qualcomm IPQ4018 clock and reset device */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/sglist.h> +#include <sys/random.h> +#include <sys/stdatomic.h> +#include <sys/mutex.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <dev/extres/hwreset/hwreset.h> + +#include "hwreset_if.h" + +#include <dt-bindings/clock/qcom,gcc-ipq4019.h> + +#include <arm/qualcomm/qcom_gcc_ipq4018_var.h> + + +static int qcom_gcc_ipq4018_modevent(module_t, int, void *); + +static int qcom_gcc_ipq4018_probe(device_t); +static int qcom_gcc_ipq4018_attach(device_t); +static int qcom_gcc_ipq4018_detach(device_t); + +static int +qcom_gcc_ipq4018_modevent(module_t mod, int type, void *unused) +{ + int error; + + switch (type) { + case MOD_LOAD: + case MOD_QUIESCE: + case MOD_UNLOAD: + case MOD_SHUTDOWN: + error = 0; + break; + default: + error = EOPNOTSUPP; + break; + } + + return (error); +} + +static int +qcom_gcc_ipq4018_probe(device_t dev) +{ + if (! ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_is_compatible(dev, "qcom,gcc-ipq4019") == 0) + return (ENXIO); + + return (0); +} + +static int +qcom_gcc_ipq4018_attach(device_t dev) +{ + struct qcom_gcc_ipq4018_softc *sc; + + sc = device_get_softc(dev); + + /* Found a compatible device! */ + sc->dev = dev; + + sc->reg_rid = 0; + sc->reg = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, + &sc->reg_rid, 0x60000, RF_ACTIVE); + if (sc->reg == NULL) { + device_printf(dev, "Couldn't allocate memory resource!\n"); + return (ENXIO); + } + + device_set_desc(dev, "Qualcomm IPQ4018 Clock/Reset Controller"); + + mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + /* + * Register as a reset provider. + */ + hwreset_register_ofw_provider(dev); + + return (0); +} + +static int +qcom_gcc_ipq4018_detach(device_t dev) +{ + struct qcom_gcc_ipq4018_softc *sc; + + sc = device_get_softc(dev); + + if (sc->reg != NULL) { + bus_release_resource(sc->dev, SYS_RES_MEMORY, + sc->reg_rid, sc->reg); + } + return (0); +} + +static device_method_t qcom_gcc_ipq4018_methods[] = { + /* Device methods. */ + DEVMETHOD(device_probe, qcom_gcc_ipq4018_probe), + DEVMETHOD(device_attach, qcom_gcc_ipq4018_attach), + DEVMETHOD(device_detach, qcom_gcc_ipq4018_detach), + + /* Reset interface */ + DEVMETHOD(hwreset_assert, qcom_gcc_ipq4018_hwreset_assert), + DEVMETHOD(hwreset_is_asserted, qcom_gcc_ipq4018_hwreset_is_asserted), + + DEVMETHOD_END +}; + +static driver_t qcom_gcc_ipq4018_driver = { + "qcom_gcc", + qcom_gcc_ipq4018_methods, + sizeof(struct qcom_gcc_ipq4018_softc) +}; +static devclass_t qcom_gcc_ipq4018_devclass; + +EARLY_DRIVER_MODULE(qcom_gcc_ipq4018, simplebus, qcom_gcc_ipq4018_driver, + qcom_gcc_ipq4018_devclass, qcom_gcc_ipq4018_modevent, 0, + BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); +EARLY_DRIVER_MODULE(qcom_gcc_ipq4018, ofwbus, qcom_gcc_ipq4018_driver, + qcom_gcc_ipq4018_devclass, qcom_gcc_ipq4018_modevent, 0, + BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(qcom_gcc_ipq4018_random, 1); diff --git a/sys/arm/qualcomm/qcom_gcc_ipq4018_reset.c b/sys/arm/qualcomm/qcom_gcc_ipq4018_reset.c new file mode 100644 index 000000000000..754e7636ff6e --- /dev/null +++ b/sys/arm/qualcomm/qcom_gcc_ipq4018_reset.c @@ -0,0 +1,181 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021, Adrian Chadd <adrian@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Driver for Qualcomm IPQ4018 clock and reset device */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/sglist.h> +#include <sys/random.h> +#include <sys/stdatomic.h> +#include <sys/mutex.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <dev/extres/hwreset/hwreset.h> + +#include "hwreset_if.h" + +#include <dt-bindings/clock/qcom,gcc-ipq4019.h> + +#include <arm/qualcomm/qcom_gcc_ipq4018_var.h> + + +static const struct qcom_gcc_ipq4018_reset_entry gcc_ipq4019_reset_list[] = { + [WIFI0_CPU_INIT_RESET] = { 0x1f008, 5 }, + [WIFI0_RADIO_SRIF_RESET] = { 0x1f008, 4 }, + [WIFI0_RADIO_WARM_RESET] = { 0x1f008, 3 }, + [WIFI0_RADIO_COLD_RESET] = { 0x1f008, 2 }, + [WIFI0_CORE_WARM_RESET] = { 0x1f008, 1 }, + [WIFI0_CORE_COLD_RESET] = { 0x1f008, 0 }, + [WIFI1_CPU_INIT_RESET] = { 0x20008, 5 }, + [WIFI1_RADIO_SRIF_RESET] = { 0x20008, 4 }, + [WIFI1_RADIO_WARM_RESET] = { 0x20008, 3 }, + [WIFI1_RADIO_COLD_RESET] = { 0x20008, 2 }, + [WIFI1_CORE_WARM_RESET] = { 0x20008, 1 }, + [WIFI1_CORE_COLD_RESET] = { 0x20008, 0 }, + [USB3_UNIPHY_PHY_ARES] = { 0x1e038, 5 }, + [USB3_HSPHY_POR_ARES] = { 0x1e038, 4 }, + [USB3_HSPHY_S_ARES] = { 0x1e038, 2 }, + [USB2_HSPHY_POR_ARES] = { 0x1e01c, 4 }, + [USB2_HSPHY_S_ARES] = { 0x1e01c, 2 }, + [PCIE_PHY_AHB_ARES] = { 0x1d010, 11 }, + [PCIE_AHB_ARES] = { 0x1d010, 10 }, + [PCIE_PWR_ARES] = { 0x1d010, 9 }, + [PCIE_PIPE_STICKY_ARES] = { 0x1d010, 8 }, + [PCIE_AXI_M_STICKY_ARES] = { 0x1d010, 7 }, + [PCIE_PHY_ARES] = { 0x1d010, 6 }, + [PCIE_PARF_XPU_ARES] = { 0x1d010, 5 }, + [PCIE_AXI_S_XPU_ARES] = { 0x1d010, 4 }, + [PCIE_AXI_M_VMIDMT_ARES] = { 0x1d010, 3 }, + [PCIE_PIPE_ARES] = { 0x1d010, 2 }, + [PCIE_AXI_S_ARES] = { 0x1d010, 1 }, + [PCIE_AXI_M_ARES] = { 0x1d010, 0 }, + [ESS_RESET] = { 0x12008, 0}, + [GCC_BLSP1_BCR] = {0x01000, 0}, + [GCC_BLSP1_QUP1_BCR] = {0x02000, 0}, + [GCC_BLSP1_UART1_BCR] = {0x02038, 0}, + [GCC_BLSP1_QUP2_BCR] = {0x03008, 0}, + [GCC_BLSP1_UART2_BCR] = {0x03028, 0}, + [GCC_BIMC_BCR] = {0x04000, 0}, + [GCC_TLMM_BCR] = {0x05000, 0}, + [GCC_IMEM_BCR] = {0x0E000, 0}, + [GCC_ESS_BCR] = {0x12008, 0}, + [GCC_PRNG_BCR] = {0x13000, 0}, + [GCC_BOOT_ROM_BCR] = {0x13008, 0}, + [GCC_CRYPTO_BCR] = {0x16000, 0}, + [GCC_SDCC1_BCR] = {0x18000, 0}, + [GCC_SEC_CTRL_BCR] = {0x1A000, 0}, + [GCC_AUDIO_BCR] = {0x1B008, 0}, + [GCC_QPIC_BCR] = {0x1C000, 0}, + [GCC_PCIE_BCR] = {0x1D000, 0}, + [GCC_USB2_BCR] = {0x1E008, 0}, + [GCC_USB2_PHY_BCR] = {0x1E018, 0}, + [GCC_USB3_BCR] = {0x1E024, 0}, + [GCC_USB3_PHY_BCR] = {0x1E034, 0}, + [GCC_SYSTEM_NOC_BCR] = {0x21000, 0}, + [GCC_PCNOC_BCR] = {0x2102C, 0}, + [GCC_DCD_BCR] = {0x21038, 0}, + [GCC_SNOC_BUS_TIMEOUT0_BCR] = {0x21064, 0}, + [GCC_SNOC_BUS_TIMEOUT1_BCR] = {0x2106C, 0}, + [GCC_SNOC_BUS_TIMEOUT2_BCR] = {0x21074, 0}, + [GCC_SNOC_BUS_TIMEOUT3_BCR] = {0x2107C, 0}, + [GCC_PCNOC_BUS_TIMEOUT0_BCR] = {0x21084, 0}, + [GCC_PCNOC_BUS_TIMEOUT1_BCR] = {0x2108C, 0}, + [GCC_PCNOC_BUS_TIMEOUT2_BCR] = {0x21094, 0}, + [GCC_PCNOC_BUS_TIMEOUT3_BCR] = {0x2109C, 0}, + [GCC_PCNOC_BUS_TIMEOUT4_BCR] = {0x210A4, 0}, + [GCC_PCNOC_BUS_TIMEOUT5_BCR] = {0x210AC, 0}, + [GCC_PCNOC_BUS_TIMEOUT6_BCR] = {0x210B4, 0}, + [GCC_PCNOC_BUS_TIMEOUT7_BCR] = {0x210BC, 0}, + [GCC_PCNOC_BUS_TIMEOUT8_BCR] = {0x210C4, 0}, + [GCC_PCNOC_BUS_TIMEOUT9_BCR] = {0x210CC, 0}, + [GCC_TCSR_BCR] = {0x22000, 0}, + [GCC_MPM_BCR] = {0x24000, 0}, + [GCC_SPDM_BCR] = {0x25000, 0}, +}; + +int +qcom_gcc_ipq4018_hwreset_assert(device_t dev, intptr_t id, bool reset) +{ + struct qcom_gcc_ipq4018_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + + if (id > nitems(gcc_ipq4019_reset_list)) { + device_printf(dev, "%s: invalid id (%d)\n", __func__, id); + return (EINVAL); + } + + device_printf(dev, "%s: called; id=%d, reset=%d\n", __func__, id, reset); + mtx_lock(&sc->mtx); + reg = bus_read_4(sc->reg, gcc_ipq4019_reset_list[id].reg); + if (reset) + reg |= (1U << gcc_ipq4019_reset_list[id].bit); + else + reg &= ~(1U << gcc_ipq4019_reset_list[id].bit); + bus_write_4(sc->reg, gcc_ipq4019_reset_list[id].reg, reg); + mtx_unlock(&sc->mtx); + return (0); +} + +int +qcom_gcc_ipq4018_hwreset_is_asserted(device_t dev, intptr_t id, bool *reset) +{ + struct qcom_gcc_ipq4018_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + + if (id > nitems(gcc_ipq4019_reset_list)) { + device_printf(dev, "%s: invalid id (%d)\n", __func__, id); + return (EINVAL); + } + mtx_lock(&sc->mtx); + reg = bus_read_4(sc->reg, gcc_ipq4019_reset_list[id].reg); + if (reg & ((1U << gcc_ipq4019_reset_list[id].bit))) + *reset = true; + else + *reset = false; + mtx_unlock(&sc->mtx); + + device_printf(dev, "called; id=%d\n", id); + return (0); +} + diff --git a/sys/arm/qualcomm/qcom_gcc_ipq4018_var.h b/sys/arm/qualcomm/qcom_gcc_ipq4018_var.h new file mode 100644 index 000000000000..3997e1860e43 --- /dev/null +++ b/sys/arm/qualcomm/qcom_gcc_ipq4018_var.h @@ -0,0 +1,50 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __QCOM_GCC_IPQ4018_VAR_H__ +#define __QCOM_GCC_IPQ4018_VAR_H__ + +struct qcom_gcc_ipq4018_reset_entry { + uint32_t reg; + uint32_t bit; +}; + +struct qcom_gcc_ipq4018_softc { + device_t dev; + int reg_rid; + struct resource *reg; + struct mtx mtx; +}; + +extern int qcom_gcc_ipq4018_hwreset_assert(device_t dev, intptr_t id, + bool reset); +extern int qcom_gcc_ipq4018_hwreset_is_asserted(device_t dev, intptr_t id, + bool *reset); + +#endif /* __QCOM_GCC_IPQ4018_VAR_H__ */ diff --git a/sys/arm/qualcomm/std.ipq4018 b/sys/arm/qualcomm/std.ipq4018 index 099fd81b5171..7e8ac39e7222 100644 --- a/sys/arm/qualcomm/std.ipq4018 +++ b/sys/arm/qualcomm/std.ipq4018 @@ -4,3 +4,6 @@ arm/qualcomm/qcom_scm_legacy.c standard arm/qualcomm/qcom_cpu_kpssv2.c optional smp dev/qcom_rnd/qcom_rnd.c optional qcom_rnd +arm/qualcomm/qcom_gcc_ipq4018.c optional qcom_gcc_ipq4018 +arm/qualcomm/qcom_gcc_ipq4018_reset.c optional qcom_gcc_ipq4018 +