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
+