diff options
Diffstat (limited to 'sys/dev/qcom_gcc')
-rw-r--r-- | sys/dev/qcom_gcc/qcom_gcc_clock.c | 98 | ||||
-rw-r--r-- | sys/dev/qcom_gcc/qcom_gcc_ipq4018.h | 41 | ||||
-rw-r--r-- | sys/dev/qcom_gcc/qcom_gcc_ipq4018_clock.c | 84 | ||||
-rw-r--r-- | sys/dev/qcom_gcc/qcom_gcc_ipq4018_reset.c | 20 | ||||
-rw-r--r-- | sys/dev/qcom_gcc/qcom_gcc_main.c (renamed from sys/dev/qcom_gcc/qcom_gcc_ipq4018.c) | 124 | ||||
-rw-r--r-- | sys/dev/qcom_gcc/qcom_gcc_reset.c | 64 | ||||
-rw-r--r-- | sys/dev/qcom_gcc/qcom_gcc_var.h (renamed from sys/dev/qcom_gcc/qcom_gcc_ipq4018_var.h) | 41 |
7 files changed, 346 insertions, 126 deletions
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..ce67b2898efb 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) \ @@ -578,7 +578,7 @@ static struct qcom_clk_branch2_def branch2_tbl[] = { 0x1e00c, 0, 0, 0, 0x1e00c, QCOM_CLK_BRANCH2_BRANCH_HALT, false, 0), F_BRANCH2(GCC_USB2_SLEEP_CLK, "gcc_usb2_sleep_clk", - "gcc_sleep_clk_src", 0x1e010, 0, 0, 0, 0x1e010, + "sleep_clk", 0x1e010, 0, 0, 0, 0x1e010, QCOM_CLK_BRANCH2_BRANCH_HALT, false, 0), F_BRANCH2(GCC_USB2_MOCK_UTMI_CLK, "gcc_usb2_mock_utmi_clk", @@ -588,7 +588,7 @@ static struct qcom_clk_branch2_def branch2_tbl[] = { F_BRANCH2(GCC_USB3_MASTER_CLK, "gcc_usb3_master_clk", "fepll125", 0x1e028, 0, 0, 0, 0x1e028, QCOM_CLK_BRANCH2_BRANCH_HALT, false, 0), - F_BRANCH2(GCC_USB3_SLEEP_CLK, "gcc_usb3_sleep_clk", "gcc_sleep_clk_src", + F_BRANCH2(GCC_USB3_SLEEP_CLK, "gcc_usb3_sleep_clk", "sleep_clk", 0x1e02c, 0, 0, 0, 0x1e02c, QCOM_CLK_BRANCH2_BRANCH_HALT, false, 0), F_BRANCH2(GCC_USB3_MOCK_UTMI_CLK, "gcc_usb3_mock_utmi_clk", @@ -602,7 +602,12 @@ static struct qcom_clk_branch2_def branch2_tbl[] = { F_BRANCH2(GCC_WCSS2G_REF_CLK, "gcc_wcss2g_ref_clk", "xo", 0x1f00c, 0, 0, 0, 0x1f00c, QCOM_CLK_BRANCH2_BRANCH_HALT, false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT), - F_BRANCH2(GCC_WCSS2G_RTC_CLK, "gcc_wcss2g_rtc_clk", "gcc_sleep_clk_src", + /* + * TODO: figure out whether gcc_sleep_clk_src -> sleep_clk is right; + * will need to go consult the openwrt ipq4018 device tree / code + * again! + */ + F_BRANCH2(GCC_WCSS2G_RTC_CLK, "gcc_wcss2g_rtc_clk", "sleep_clk", 0x1f010, 0, 0, 0, 0x1f010, QCOM_CLK_BRANCH2_BRANCH_HALT, false, 0), @@ -613,7 +618,7 @@ static struct qcom_clk_branch2_def branch2_tbl[] = { F_BRANCH2(GCC_WCSS5G_REF_CLK, "gcc_wcss5g_ref_clk", "xo", 0x1f00c, 0, 0, 0, 0x2000c, QCOM_CLK_BRANCH2_BRANCH_HALT, false, QCOM_CLK_BRANCH2_FLAGS_SET_RATE_PARENT), - F_BRANCH2(GCC_WCSS5G_RTC_CLK, "gcc_wcss5g_rtc_clk", "gcc_sleep_clk_src", + F_BRANCH2(GCC_WCSS5G_RTC_CLK, "gcc_wcss5g_rtc_clk", "sleep_clk", 0x1f010, 0, 0, 0, 0x20010, QCOM_CLK_BRANCH2_BRANCH_HALT, false, 0), @@ -624,7 +629,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 +641,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 +653,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 +665,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 +677,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 +689,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 +700,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 +717,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 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 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__ */ |