git: 7fead5f144a8 - main - qcom_gcc: begin refactoring sys/dev/qcom_gcc to support multiple chipsets
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 08 Apr 2025 03:47:26 UTC
The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=7fead5f144a874a317cba29130a76a11629903ea commit 7fead5f144a874a317cba29130a76a11629903ea Author: Adrian Chadd <adrian@FreeBSD.org> AuthorDate: 2025-04-05 03:59:58 +0000 Commit: Adrian Chadd <adrian@FreeBSD.org> CommitDate: 2025-04-08 03:44:52 +0000 qcom_gcc: begin refactoring sys/dev/qcom_gcc to support multiple chipsets Although the driver structure is almost supportive of multiple chipsets, there's a lot of subtle hard coded IPQ4018 assumptions here. This is a partial refactor of the driver in order to have a single qcom_gcc driver that will eventually support multiple chipsets. * rename qcom_gcc_ipq4018 -> qcom_gcc * remove the ipq4018 specific naming from things * create a table to drive probe/attach, with a chipset id to use during attach * migrate the clock register accessors to not be ipq4018 specific * migrate the reset register accessors to not be ipq4018 specific Note this won't compile (yet) for an arm64 kernel because there's a hard-coded clock tree for an earlier 64 bit MSM part in sys/arm64/qualcomm/qcom_gcc.c . That will need to be rolled into this driver. Differential Revision: https://reviews.freebsd.org/D49683 --- sys/arm/conf/std.qca | 2 +- sys/arm/qualcomm/std.ipq4018 | 22 ++-- sys/dev/qcom_gcc/qcom_gcc_clock.c | 98 ++++++++++++++++ sys/dev/qcom_gcc/qcom_gcc_ipq4018.h | 41 +++++++ sys/dev/qcom_gcc/qcom_gcc_ipq4018_clock.c | 71 ++---------- sys/dev/qcom_gcc/qcom_gcc_ipq4018_reset.c | 20 ++-- .../{qcom_gcc_ipq4018.c => qcom_gcc_main.c} | 124 ++++++++++++++------- sys/dev/qcom_gcc/qcom_gcc_reset.c | 64 +++++++++++ .../{qcom_gcc_ipq4018_var.h => qcom_gcc_var.h} | 41 ++++--- 9 files changed, 350 insertions(+), 133 deletions(-) diff --git a/sys/arm/conf/std.qca b/sys/arm/conf/std.qca index 24e6601f0939..ea6912606517 100644 --- a/sys/arm/conf/std.qca +++ b/sys/arm/conf/std.qca @@ -46,7 +46,7 @@ device mpcore_timer device psci # Clock/Reset provider -device qcom_gcc_ipq4018 +device qcom_gcc # TLMM (gpio/pinmux) device gpio diff --git a/sys/arm/qualcomm/std.ipq4018 b/sys/arm/qualcomm/std.ipq4018 index 6360a3ce25db..89d2cb546bf3 100644 --- a/sys/arm/qualcomm/std.ipq4018 +++ b/sys/arm/qualcomm/std.ipq4018 @@ -34,17 +34,19 @@ dev/qcom_rnd/qcom_rnd.c optional qcom_rnd dev/qcom_qup/qcom_spi.c optional qcom_qup_spi dev/qcom_qup/qcom_spi_hw.c optional qcom_qup_spi -dev/qcom_gcc/qcom_gcc_ipq4018.c optional qcom_gcc_ipq4018 -dev/qcom_gcc/qcom_gcc_ipq4018_reset.c optional qcom_gcc_ipq4018 -dev/qcom_gcc/qcom_gcc_ipq4018_clock.c optional qcom_gcc_ipq4018 +dev/qcom_gcc/qcom_gcc_main.c optional qcom_gcc +dev/qcom_gcc/qcom_gcc_clock.c optional qcom_gcc +dev/qcom_gcc/qcom_gcc_reset.c optional qcom_gcc +dev/qcom_gcc/qcom_gcc_ipq4018_reset.c optional qcom_gcc +dev/qcom_gcc/qcom_gcc_ipq4018_clock.c optional qcom_gcc -dev/qcom_clk/qcom_clk_fepll.c optional qcom_gcc_ipq4018 -dev/qcom_clk/qcom_clk_fdiv.c optional qcom_gcc_ipq4018 -dev/qcom_clk/qcom_clk_apssdiv.c optional qcom_gcc_ipq4018 -dev/qcom_clk/qcom_clk_freqtbl.c optional qcom_gcc_ipq4018 -dev/qcom_clk/qcom_clk_rcg2.c optional qcom_gcc_ipq4018 -dev/qcom_clk/qcom_clk_branch2.c optional qcom_gcc_ipq4018 -dev/qcom_clk/qcom_clk_ro_div.c optional qcom_gcc_ipq4018 +dev/qcom_clk/qcom_clk_fepll.c optional qcom_gcc +dev/qcom_clk/qcom_clk_fdiv.c optional qcom_gcc +dev/qcom_clk/qcom_clk_apssdiv.c optional qcom_gcc +dev/qcom_clk/qcom_clk_freqtbl.c optional qcom_gcc +dev/qcom_clk/qcom_clk_rcg2.c optional qcom_gcc +dev/qcom_clk/qcom_clk_branch2.c optional qcom_gcc +dev/qcom_clk/qcom_clk_ro_div.c optional qcom_gcc dev/qcom_tlmm/qcom_tlmm_debug.c optional qcom_tlmm_ipq4018 dev/qcom_tlmm/qcom_tlmm_ipq4018.c optional qcom_tlmm_ipq4018 diff --git a/sys/dev/qcom_gcc/qcom_gcc_clock.c b/sys/dev/qcom_gcc/qcom_gcc_clock.c new file mode 100644 index 000000000000..c8c10b0c5172 --- /dev/null +++ b/sys/dev/qcom_gcc/qcom_gcc_clock.c @@ -0,0 +1,98 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025, 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. + */ + +#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 "qcom_gcc_var.h" + +int +qcom_gcc_clock_read(device_t dev, bus_addr_t addr, uint32_t *val) +{ + struct qcom_gcc_softc *sc; + + sc = device_get_softc(dev); + *val = bus_read_4(sc->reg, addr); + return (0); +} + +int +qcom_gcc_clock_write(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct qcom_gcc_softc *sc; + + sc = device_get_softc(dev); + bus_write_4(sc->reg, addr, val); + return (0); +} + +int +qcom_gcc_clock_modify(device_t dev, bus_addr_t addr, + uint32_t clear_mask, uint32_t set_mask) +{ + struct qcom_gcc_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + reg = bus_read_4(sc->reg, addr); + reg &= clear_mask; + reg |= set_mask; + bus_write_4(sc->reg, addr, reg); + return (0); +} + +void +qcom_gcc_clock_lock(device_t dev) +{ + struct qcom_gcc_softc *sc; + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} + +void +qcom_gcc_clock_unlock(device_t dev) +{ + struct qcom_gcc_softc *sc; + + sc = device_get_softc(dev); + mtx_unlock(&sc->mtx); +} diff --git a/sys/dev/qcom_gcc/qcom_gcc_ipq4018.h b/sys/dev/qcom_gcc/qcom_gcc_ipq4018.h new file mode 100644 index 000000000000..2b5bfa453766 --- /dev/null +++ b/sys/dev/qcom_gcc/qcom_gcc_ipq4018.h @@ -0,0 +1,41 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 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. + */ + +#ifndef __QCOM_GCC_IPQ4018_H__ +#define __QCOM_GCC_IPQ4018_H__ + +/* + * reset block + */ +extern void qcom_gcc_ipq4018_hwreset_init(struct qcom_gcc_softc *); + +/* + * clock block + */ +extern void qcom_gcc_ipq4018_clock_setup(struct qcom_gcc_softc *); + +#endif /* __QCOM_GCC_IPQ4018_H__ */ diff --git a/sys/dev/qcom_gcc/qcom_gcc_ipq4018_clock.c b/sys/dev/qcom_gcc/qcom_gcc_ipq4018_clock.c index 6441cf3e6ae5..3135c3cd685e 100644 --- a/sys/dev/qcom_gcc/qcom_gcc_ipq4018_clock.c +++ b/sys/dev/qcom_gcc/qcom_gcc_ipq4018_clock.c @@ -59,8 +59,8 @@ #include <dev/qcom_clk/qcom_clk_branch2.h> #include <dev/qcom_clk/qcom_clk_ro_div.h> -#include "qcom_gcc_ipq4018_var.h" - +#include "qcom_gcc_var.h" +#include "qcom_gcc_ipq4018.h" /* Fixed rate clock. */ #define F_RATE(_id, cname, _freq) \ @@ -624,7 +624,7 @@ static struct qcom_clk_branch2_def branch2_tbl[] = { }; static void -qcom_gcc_ipq4018_clock_init_fepll(struct qcom_gcc_ipq4018_softc *sc) +qcom_gcc_ipq4018_clock_init_fepll(struct qcom_gcc_softc *sc) { int i, rv; @@ -636,7 +636,7 @@ qcom_gcc_ipq4018_clock_init_fepll(struct qcom_gcc_ipq4018_softc *sc) } static void -qcom_gcc_ipq4018_clock_init_fdiv(struct qcom_gcc_ipq4018_softc *sc) +qcom_gcc_ipq4018_clock_init_fdiv(struct qcom_gcc_softc *sc) { int i, rv; @@ -648,7 +648,7 @@ qcom_gcc_ipq4018_clock_init_fdiv(struct qcom_gcc_ipq4018_softc *sc) } static void -qcom_gcc_ipq4018_clock_init_apssdiv(struct qcom_gcc_ipq4018_softc *sc) +qcom_gcc_ipq4018_clock_init_apssdiv(struct qcom_gcc_softc *sc) { int i, rv; @@ -660,7 +660,7 @@ qcom_gcc_ipq4018_clock_init_apssdiv(struct qcom_gcc_ipq4018_softc *sc) } static void -qcom_gcc_ipq4018_clock_init_rcg2(struct qcom_gcc_ipq4018_softc *sc) +qcom_gcc_ipq4018_clock_init_rcg2(struct qcom_gcc_softc *sc) { int i, rv; @@ -672,7 +672,7 @@ qcom_gcc_ipq4018_clock_init_rcg2(struct qcom_gcc_ipq4018_softc *sc) } static void -qcom_gcc_ipq4018_clock_init_branch2(struct qcom_gcc_ipq4018_softc *sc) +qcom_gcc_ipq4018_clock_init_branch2(struct qcom_gcc_softc *sc) { int i, rv; @@ -684,7 +684,7 @@ qcom_gcc_ipq4018_clock_init_branch2(struct qcom_gcc_ipq4018_softc *sc) } static void -qcom_gcc_ipq4018_clock_init_ro_div(struct qcom_gcc_ipq4018_softc *sc) +qcom_gcc_ipq4018_clock_init_ro_div(struct qcom_gcc_softc *sc) { int i, rv; @@ -695,43 +695,8 @@ qcom_gcc_ipq4018_clock_init_ro_div(struct qcom_gcc_ipq4018_softc *sc) } } -int -qcom_gcc_ipq4018_clock_read(device_t dev, bus_addr_t addr, uint32_t *val) -{ - struct qcom_gcc_ipq4018_softc *sc; - - sc = device_get_softc(dev); - *val = bus_read_4(sc->reg, addr); - return (0); -} - -int -qcom_gcc_ipq4018_clock_write(device_t dev, bus_addr_t addr, uint32_t val) -{ - struct qcom_gcc_ipq4018_softc *sc; - - sc = device_get_softc(dev); - bus_write_4(sc->reg, addr, val); - return (0); -} - -int -qcom_gcc_ipq4018_clock_modify(device_t dev, bus_addr_t addr, - uint32_t clear_mask, uint32_t set_mask) -{ - struct qcom_gcc_ipq4018_softc *sc; - uint32_t reg; - - sc = device_get_softc(dev); - reg = bus_read_4(sc->reg, addr); - reg &= clear_mask; - reg |= set_mask; - bus_write_4(sc->reg, addr, reg); - return (0); -} - void -qcom_gcc_ipq4018_clock_setup(struct qcom_gcc_ipq4018_softc *sc) +qcom_gcc_ipq4018_clock_setup(struct qcom_gcc_softc *sc) { sc->clkdom = clkdom_create(sc->dev); @@ -747,21 +712,3 @@ qcom_gcc_ipq4018_clock_setup(struct qcom_gcc_ipq4018_softc *sc) /* Finalise clock tree */ clkdom_finit(sc->clkdom); } - -void -qcom_gcc_ipq4018_clock_lock(device_t dev) -{ - struct qcom_gcc_ipq4018_softc *sc; - - sc = device_get_softc(dev); - mtx_lock(&sc->mtx); -} - -void -qcom_gcc_ipq4018_clock_unlock(device_t dev) -{ - struct qcom_gcc_ipq4018_softc *sc; - - sc = device_get_softc(dev); - mtx_unlock(&sc->mtx); -} diff --git a/sys/dev/qcom_gcc/qcom_gcc_ipq4018_reset.c b/sys/dev/qcom_gcc/qcom_gcc_ipq4018_reset.c index ae2236d7fca7..f99d1d9ad9f1 100644 --- a/sys/dev/qcom_gcc/qcom_gcc_ipq4018_reset.c +++ b/sys/dev/qcom_gcc/qcom_gcc_ipq4018_reset.c @@ -50,10 +50,10 @@ #include <dt-bindings/clock/qcom,gcc-ipq4019.h> -#include "qcom_gcc_ipq4018_var.h" +#include "qcom_gcc_var.h" +#include "qcom_gcc_ipq4018.h" - -static const struct qcom_gcc_ipq4018_reset_entry gcc_ipq4019_reset_list[] = { +static const struct qcom_gcc_reset_entry gcc_ipq4019_reset_list[] = { [WIFI0_CPU_INIT_RESET] = { 0x1f008, 5 }, [WIFI0_RADIO_SRIF_RESET] = { 0x1f008, 4 }, [WIFI0_RADIO_WARM_RESET] = { 0x1f008, 3 }, @@ -127,10 +127,10 @@ static const struct qcom_gcc_ipq4018_reset_entry gcc_ipq4019_reset_list[] = { [GCC_SPDM_BCR] = {0x25000, 0}, }; -int +static int qcom_gcc_ipq4018_hwreset_assert(device_t dev, intptr_t id, bool reset) { - struct qcom_gcc_ipq4018_softc *sc; + struct qcom_gcc_softc *sc; uint32_t reg; sc = device_get_softc(dev); @@ -151,10 +151,10 @@ qcom_gcc_ipq4018_hwreset_assert(device_t dev, intptr_t id, bool reset) return (0); } -int +static int qcom_gcc_ipq4018_hwreset_is_asserted(device_t dev, intptr_t id, bool *reset) { - struct qcom_gcc_ipq4018_softc *sc; + struct qcom_gcc_softc *sc; uint32_t reg; sc = device_get_softc(dev); @@ -175,3 +175,9 @@ qcom_gcc_ipq4018_hwreset_is_asserted(device_t dev, intptr_t id, bool *reset) return (0); } +void +qcom_gcc_ipq4018_hwreset_init(struct qcom_gcc_softc *sc) +{ + sc->sc_cb.hw_reset_assert = qcom_gcc_ipq4018_hwreset_assert; + sc->sc_cb.hw_reset_is_asserted = qcom_gcc_ipq4018_hwreset_is_asserted; +} diff --git a/sys/dev/qcom_gcc/qcom_gcc_ipq4018.c b/sys/dev/qcom_gcc/qcom_gcc_main.c similarity index 51% rename from sys/dev/qcom_gcc/qcom_gcc_ipq4018.c rename to sys/dev/qcom_gcc/qcom_gcc_main.c index 5980d8ebe893..3950bd985feb 100644 --- a/sys/dev/qcom_gcc/qcom_gcc_ipq4018.c +++ b/sys/dev/qcom_gcc/qcom_gcc_main.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2021, Adrian Chadd <adrian@FreeBSD.org> + * Copyright (c) 2025, Adrian Chadd <adrian@FreeBSD.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,7 +25,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* Driver for Qualcomm IPQ4018 clock and reset device */ +/* Driver for Qualcomm clock/reset trees */ #include <sys/param.h> #include <sys/kernel.h> @@ -49,19 +49,29 @@ #include "clkdev_if.h" #include "hwreset_if.h" -#include <dt-bindings/clock/qcom,gcc-ipq4019.h> +#include "qcom_gcc_var.h" +#include "qcom_gcc_ipq4018.h" -#include "qcom_gcc_ipq4018_var.h" +static int qcom_gcc_modevent(module_t, int, void *); +static int qcom_gcc_probe(device_t); +static int qcom_gcc_attach(device_t); +static int qcom_gcc_detach(device_t); -static int qcom_gcc_ipq4018_modevent(module_t, int, void *); +struct qcom_gcc_chipset_list_entry { + const char *ofw; + const char *desc; + qcom_gcc_chipset_t chipset; +}; -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 struct qcom_gcc_chipset_list_entry qcom_gcc_chipset_list[] = { + { "qcom,gcc-ipq4019", "Qualcomm IPQ4018 Clock/Reset Controller", + QCOM_GCC_CHIPSET_IPQ4018 }, + { NULL, NULL, 0 }, +}; static int -qcom_gcc_ipq4018_modevent(module_t mod, int type, void *unused) +qcom_gcc_modevent(module_t mod, int type, void *unused) { int error; @@ -81,37 +91,64 @@ qcom_gcc_ipq4018_modevent(module_t mod, int type, void *unused) } static int -qcom_gcc_ipq4018_probe(device_t dev) +qcom_gcc_probe(device_t dev) { + struct qcom_gcc_softc *sc; + int i; + + sc = device_get_softc(dev); + if (! ofw_bus_status_okay(dev)) return (ENXIO); - if (ofw_bus_is_compatible(dev, "qcom,gcc-ipq4019") == 0) - return (ENXIO); + for (i = 0; qcom_gcc_chipset_list[i].ofw != NULL; i++) { + const struct qcom_gcc_chipset_list_entry *ce; - return (0); + ce = &qcom_gcc_chipset_list[i]; + if (ofw_bus_is_compatible(dev, ce->ofw) == 0) + continue; + device_set_desc(dev, ce->desc); + sc->sc_chipset = ce->chipset; + return (0); + } + + return (ENXIO); } static int -qcom_gcc_ipq4018_attach(device_t dev) +qcom_gcc_attach(device_t dev) { - struct qcom_gcc_ipq4018_softc *sc; + struct qcom_gcc_softc *sc; + size_t mem_sz; sc = device_get_softc(dev); /* Found a compatible device! */ sc->dev = dev; + /* + * Setup the hardware callbacks, before any further initialisation + * is performed. + */ + switch (sc->sc_chipset) { + case QCOM_GCC_CHIPSET_IPQ4018: + qcom_gcc_ipq4018_hwreset_init(sc); + mem_sz = 0x60000; + break; + case QCOM_GCC_CHIPSET_NONE: + device_printf(dev, "Invalid chipset (%d)\n", sc->sc_chipset); + return (ENXIO); + } + sc->reg_rid = 0; + sc->reg = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, - &sc->reg_rid, 0x60000, RF_ACTIVE); + &sc->reg_rid, mem_sz, 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); /* @@ -122,15 +159,22 @@ qcom_gcc_ipq4018_attach(device_t dev) /* * Setup and register as a clock provider. */ - qcom_gcc_ipq4018_clock_setup(sc); + switch (sc->sc_chipset) { + case QCOM_GCC_CHIPSET_IPQ4018: + qcom_gcc_ipq4018_clock_setup(sc); + break; + case QCOM_GCC_CHIPSET_NONE: + device_printf(dev, "Invalid chipset (%d)\n", sc->sc_chipset); + return (ENXIO); + } return (0); } static int -qcom_gcc_ipq4018_detach(device_t dev) +qcom_gcc_detach(device_t dev) { - struct qcom_gcc_ipq4018_softc *sc; + struct qcom_gcc_softc *sc; sc = device_get_softc(dev); @@ -145,34 +189,34 @@ qcom_gcc_ipq4018_detach(device_t dev) return (0); } -static device_method_t qcom_gcc_ipq4018_methods[] = { +static device_method_t qcom_gcc_methods[] = { /* Device methods. */ - DEVMETHOD(device_probe, qcom_gcc_ipq4018_probe), - DEVMETHOD(device_attach, qcom_gcc_ipq4018_attach), - DEVMETHOD(device_detach, qcom_gcc_ipq4018_detach), + DEVMETHOD(device_probe, qcom_gcc_probe), + DEVMETHOD(device_attach, qcom_gcc_attach), + DEVMETHOD(device_detach, qcom_gcc_detach), /* Reset interface */ - DEVMETHOD(hwreset_assert, qcom_gcc_ipq4018_hwreset_assert), - DEVMETHOD(hwreset_is_asserted, qcom_gcc_ipq4018_hwreset_is_asserted), + DEVMETHOD(hwreset_assert, qcom_gcc_hwreset_assert), + DEVMETHOD(hwreset_is_asserted, qcom_gcc_hwreset_is_asserted), /* Clock interface */ - DEVMETHOD(clkdev_read_4, qcom_gcc_ipq4018_clock_read), - DEVMETHOD(clkdev_write_4, qcom_gcc_ipq4018_clock_write), - DEVMETHOD(clkdev_modify_4, qcom_gcc_ipq4018_clock_modify), - DEVMETHOD(clkdev_device_lock, qcom_gcc_ipq4018_clock_lock), - DEVMETHOD(clkdev_device_unlock, qcom_gcc_ipq4018_clock_unlock), + DEVMETHOD(clkdev_read_4, qcom_gcc_clock_read), + DEVMETHOD(clkdev_write_4, qcom_gcc_clock_write), + DEVMETHOD(clkdev_modify_4, qcom_gcc_clock_modify), + DEVMETHOD(clkdev_device_lock, qcom_gcc_clock_lock), + DEVMETHOD(clkdev_device_unlock, qcom_gcc_clock_unlock), DEVMETHOD_END }; -static driver_t qcom_gcc_ipq4018_driver = { +static driver_t qcom_gcc_driver = { "qcom_gcc", - qcom_gcc_ipq4018_methods, - sizeof(struct qcom_gcc_ipq4018_softc) + qcom_gcc_methods, + sizeof(struct qcom_gcc_softc) }; -EARLY_DRIVER_MODULE(qcom_gcc_ipq4018, simplebus, qcom_gcc_ipq4018_driver, - qcom_gcc_ipq4018_modevent, NULL, BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); -EARLY_DRIVER_MODULE(qcom_gcc_ipq4018, ofwbus, qcom_gcc_ipq4018_driver, - qcom_gcc_ipq4018_modevent, NULL, BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); -MODULE_VERSION(qcom_gcc_ipq4018, 1); +EARLY_DRIVER_MODULE(qcom_gcc, simplebus, qcom_gcc_driver, + qcom_gcc_modevent, NULL, BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); +EARLY_DRIVER_MODULE(qcom_gcc, ofwbus, qcom_gcc_driver, + qcom_gcc_modevent, NULL, BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); +MODULE_VERSION(qcom_gcc, 1); diff --git a/sys/dev/qcom_gcc/qcom_gcc_reset.c b/sys/dev/qcom_gcc/qcom_gcc_reset.c new file mode 100644 index 000000000000..05ea817fbcc4 --- /dev/null +++ b/sys/dev/qcom_gcc/qcom_gcc_reset.c @@ -0,0 +1,64 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#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/hwreset/hwreset.h> + +#include "hwreset_if.h" + +#include "qcom_gcc_var.h" + +int +qcom_gcc_hwreset_assert(device_t dev, intptr_t id, bool reset) +{ + struct qcom_gcc_softc *sc = device_get_softc(dev); + return (sc->sc_cb.hw_reset_assert(dev, id, reset)); +} + +int +qcom_gcc_hwreset_is_asserted(device_t dev, intptr_t id, bool *reset) +{ + struct qcom_gcc_softc *sc = device_get_softc(dev); + + return (sc->sc_cb.hw_reset_is_asserted(dev, id, reset)); +} diff --git a/sys/dev/qcom_gcc/qcom_gcc_ipq4018_var.h b/sys/dev/qcom_gcc/qcom_gcc_var.h similarity index 63% rename from sys/dev/qcom_gcc/qcom_gcc_ipq4018_var.h rename to sys/dev/qcom_gcc/qcom_gcc_var.h index b3c54f1a7f73..2d4e969e1134 100644 --- a/sys/dev/qcom_gcc/qcom_gcc_ipq4018_var.h +++ b/sys/dev/qcom_gcc/qcom_gcc_var.h @@ -25,41 +25,56 @@ * SUCH DAMAGE. */ -#ifndef __QCOM_GCC_IPQ4018_VAR_H__ -#define __QCOM_GCC_IPQ4018_VAR_H__ +#ifndef __QCOM_GCC_VAR_H__ +#define __QCOM_GCC_VAR_H__ -struct qcom_gcc_ipq4018_reset_entry { +typedef enum { + QCOM_GCC_CHIPSET_NONE = 0, + QCOM_GCC_CHIPSET_IPQ4018 = 1, +} qcom_gcc_chipset_t; + +struct qcom_gcc_reset_entry { uint32_t reg; uint32_t bit; }; -struct qcom_gcc_ipq4018_softc { +struct qcom_gcc_hw_callbacks { + /* Reset block */ + int (*hw_reset_assert)(device_t, intptr_t, bool); + int (*hw_reset_is_asserted)(device_t, intptr_t, bool *); + + /* Clock block */ +}; + +struct qcom_gcc_softc { device_t dev; int reg_rid; struct resource *reg; struct mtx mtx; struct clkdom *clkdom; + qcom_gcc_chipset_t sc_chipset; + struct qcom_gcc_hw_callbacks sc_cb; }; /* * reset block */ -extern int qcom_gcc_ipq4018_hwreset_assert(device_t dev, intptr_t id, +extern int qcom_gcc_hwreset_assert(device_t dev, intptr_t id, bool reset); -extern int qcom_gcc_ipq4018_hwreset_is_asserted(device_t dev, intptr_t id, +extern int qcom_gcc_hwreset_is_asserted(device_t dev, intptr_t id, bool *reset); /* * clock block */ -extern int qcom_gcc_ipq4018_clock_read(device_t dev, bus_addr_t addr, +extern int qcom_gcc_clock_read(device_t dev, bus_addr_t addr, uint32_t *val); -extern int qcom_gcc_ipq4018_clock_write(device_t dev, bus_addr_t addr, +extern int qcom_gcc_clock_write(device_t dev, bus_addr_t addr, uint32_t val); -extern int qcom_gcc_ipq4018_clock_modify(device_t dev, bus_addr_t addr, +extern int qcom_gcc_clock_modify(device_t dev, bus_addr_t addr, uint32_t clear_mask, uint32_t set_mask); -extern void qcom_gcc_ipq4018_clock_setup(struct qcom_gcc_ipq4018_softc *sc); -extern void qcom_gcc_ipq4018_clock_lock(device_t dev); -extern void qcom_gcc_ipq4018_clock_unlock(device_t dev); +extern void qcom_gcc_clock_setup(struct qcom_gcc_softc *sc); +extern void qcom_gcc_clock_lock(device_t dev); +extern void qcom_gcc_clock_unlock(device_t dev); -#endif /* __QCOM_GCC_IPQ4018_VAR_H__ */ +#endif /* __QCOM_GCC_VAR_H__ */