diff --git a/sys/arm64/conf/std.qcom b/sys/arm64/conf/std.qcom --- a/sys/arm64/conf/std.qcom +++ b/sys/arm64/conf/std.qcom @@ -4,6 +4,8 @@ # Qualcomm Snapdragon drivers device qcom_gcc # Global Clock Controller +device qcom_rng # Pseudo Random Number Generator +device qcom_mdio # MDIO support # Serial (COM) ports device uart_msm # Qualcomm MSM UART driver diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -618,6 +618,8 @@ # Qualcomm arm64/qualcomm/qcom_gcc.c optional qcom_gcc fdt +dev/qcom_rnd/qcom_rnd.c optional qcom_rng fdt +dev/qcom_mdio/qcom_mdio_ipq4018.c optional qcom_mdio fdt mdio mii # RockChip Drivers arm64/rockchip/rk3328_codec.c optional fdt rk3328codec soc_rockchip_rk3328 diff --git a/sys/dev/qcom_mdio/qcom_mdio_ipq4018.c b/sys/dev/qcom_mdio/qcom_mdio_ipq4018.c --- a/sys/dev/qcom_mdio/qcom_mdio_ipq4018.c +++ b/sys/dev/qcom_mdio/qcom_mdio_ipq4018.c @@ -273,6 +273,9 @@ DEVMETHOD(device_attach, qcom_mdio_ipq4018_attach), DEVMETHOD(device_detach, qcom_mdio_ipq4018_detach), + /* Bus interface */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + /* MDIO interface */ DEVMETHOD(mdio_readreg, qcom_mdio_ipq4018_readreg), DEVMETHOD(mdio_writereg, qcom_mdio_ipq4018_writereg), diff --git a/sys/dev/qcom_rnd/qcom_rnd.c b/sys/dev/qcom_rnd/qcom_rnd.c --- a/sys/dev/qcom_rnd/qcom_rnd.c +++ b/sys/dev/qcom_rnd/qcom_rnd.c @@ -2,6 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2021, Adrian Chadd + * Copyright (c) 2022, Bjoern A. Zeeb * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,15 +33,14 @@ #include #include -#include #include -#include +#include #include +#include #include #include #include -#include #include #include @@ -49,64 +49,96 @@ #include #include -#include +#include "qcom_rnd_reg.h" struct qcom_rnd_softc { - device_t dev; + device_t dev; int reg_rid; struct resource *reg; }; -static int qcom_rnd_modevent(module_t, int, void *); - -static int qcom_rnd_probe(device_t); -static int qcom_rnd_attach(device_t); -static int qcom_rnd_detach(device_t); - -static int qcom_rnd_harvest(struct qcom_rnd_softc *, void *, size_t *); -static unsigned qcom_rnd_read(void *, unsigned); - -static struct random_source random_qcom_rnd = { - .rs_ident = "Qualcomm Entropy Adapter", - .rs_source = RANDOM_PURE_QUALCOMM, - .rs_read = qcom_rnd_read, -}; - /* Kludge for API limitations of random(4). */ static _Atomic(struct qcom_rnd_softc *) g_qcom_rnd_softc; static int -qcom_rnd_modevent(module_t mod, int type, void *unused) +qcom_rnd_harvest(struct qcom_rnd_softc *sc, void *buf, size_t *sz) { - int error; + /* + * Add data to buf until we either run out of entropy or we + * fill the buffer. + * + * Note - be mindful of the provided buffer size; we're reading + * 4 bytes at a time but we only want to supply up to the max + * buffer size, so don't write past it! + */ + size_t rz = 0; + uint32_t reg; - switch (type) { - case MOD_LOAD: - case MOD_QUIESCE: - case MOD_UNLOAD: - case MOD_SHUTDOWN: - error = 0; - break; - default: - error = EOPNOTSUPP; - break; + while (rz < *sz) { + bus_barrier(sc->reg, 0, rman_get_size(sc->reg), + BUS_SPACE_BARRIER_READ); + reg = bus_read_4(sc->reg, QCOM_RND_PRNG_STATUS); + if ((reg & QCOM_RND_PRNG_STATUS_DATA_AVAIL) == 0) + break; + reg = bus_read_4(sc->reg, QCOM_RND_PRNG_DATA_OUT); + memcpy(((char *) buf) + rz, ®, sizeof(uint32_t)); + rz += sizeof(uint32_t); } - return (error); + if (rz == 0) + return (EAGAIN); + *sz = rz; + return (0); +} + +static unsigned +qcom_rnd_read(void *buf, unsigned usz) +{ + struct qcom_rnd_softc *sc; + size_t sz; + int error; + + sc = g_qcom_rnd_softc; + if (sc == NULL) + return (0); + + sz = usz; + error = qcom_rnd_harvest(sc, buf, &sz); + if (error != 0) + return (0); + + return (sz); } +static struct random_source random_qcom_rnd = { + .rs_ident = "Qualcomm Entropy Adapter", + .rs_source = RANDOM_PURE_QUALCOMM, + .rs_read = qcom_rnd_read, +}; + +static const struct ofw_compat_data qcom_prng_compat_data[] = { + {"qcom,prng", (uintptr_t)"Qualcomm PRNG"}, +#ifdef __notyet__ + {"qcom,prng-ee", (uintptr_t)"Qualcomm PRNG-EE"}, +#endif + { NULL, 0 } +}; + static int qcom_rnd_probe(device_t dev) { - if (! ofw_bus_status_okay(dev)) { - return (ENXIO); - } + const struct ofw_compat_data *compat; - if (ofw_bus_is_compatible(dev, "qcom,prng") == 0) { + if (!ofw_bus_status_okay(dev)) return (ENXIO); + + compat = ofw_bus_search_compatible(dev, qcom_prng_compat_data); + if (compat->ocd_str != NULL) { + device_set_desc(dev, (const char *)compat->ocd_data); + return (BUS_PROBE_DEFAULT); } - return (0); + return (ENXIO); } static int @@ -116,54 +148,50 @@ uint32_t reg; sc = device_get_softc(dev); - - - /* Found a compatible device! */ - sc->dev = dev; exp = NULL; if (!atomic_compare_exchange_strong_explicit(&g_qcom_rnd_softc, &exp, - sc, memory_order_release, memory_order_acquire)) { + sc, memory_order_release, memory_order_acquire)) return (ENXIO); - } sc->reg_rid = 0; - sc->reg = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, - &sc->reg_rid, 0x140, RF_ACTIVE); + sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->reg_rid, + RF_SHAREABLE | RF_ACTIVE); if (sc->reg == NULL) { - device_printf(dev, "Couldn't allocate memory resource!\n"); + device_printf(dev, "Failed to allocate memory resource!\n"); return (ENXIO); } - device_set_desc(dev, "Qualcomm PRNG"); - - /* - * Check to see whether the PRNG has already been setup or not. - */ - bus_barrier(sc->reg, 0, 0x120, BUS_SPACE_BARRIER_READ); + return (0); + /* Check to see whether the PRNG is already setup. */ + /* XXX this is still racy? */ + bus_barrier(sc->reg, 0, rman_get_size(sc->reg), BUS_SPACE_BARRIER_READ); reg = bus_read_4(sc->reg, QCOM_RND_PRNG_CONFIG); - if (reg & QCOM_RND_PRNG_CONFIG_HW_ENABLE) { - device_printf(dev, "PRNG HW already enabled\n"); - } else { - /* - * Do PRNG setup and then enable it. - */ +/* XXX-BZ this panics */ + if ((reg & QCOM_RND_PRNG_CONFIG_HW_ENABLE) == 0) { + + /* Do PRNG setup and then enable it. */ reg = bus_read_4(sc->reg, QCOM_RND_PRNG_LFSR_CFG); reg &= QCOM_RND_PRNG_LFSR_CFG_MASK; reg |= QCOM_RND_PRNG_LFSR_CFG_CLOCKS; bus_write_4(sc->reg, QCOM_RND_PRNG_LFSR_CFG, reg); - bus_barrier(sc->reg, 0, 0x120, BUS_SPACE_BARRIER_WRITE); + bus_barrier(sc->reg, 0, rman_get_size(sc->reg), + BUS_SPACE_BARRIER_WRITE); reg = bus_read_4(sc->reg, QCOM_RND_PRNG_CONFIG); reg |= QCOM_RND_PRNG_CONFIG_HW_ENABLE; bus_write_4(sc->reg, QCOM_RND_PRNG_CONFIG, reg); - bus_barrier(sc->reg, 0, 0x120, BUS_SPACE_BARRIER_WRITE); + bus_barrier(sc->reg, 0, rman_get_size(sc->reg), + BUS_SPACE_BARRIER_WRITE); + } else { + device_printf(dev, "PRNG HW already enabled\n"); + /* XXX we should clear up and error? */ } random_source_register(&random_qcom_rnd); - return (0); + return (0); } static int @@ -177,62 +205,15 @@ ("only one global instance at a time")); random_source_deregister(&random_qcom_rnd); - if (sc->reg != NULL) { - bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->reg_rid, sc->reg); - } - atomic_store_explicit(&g_qcom_rnd_softc, NULL, memory_order_release); - return (0); -} -static int -qcom_rnd_harvest(struct qcom_rnd_softc *sc, void *buf, size_t *sz) -{ - /* - * Add data to buf until we either run out of entropy or we - * fill the buffer. - * - * Note - be mindful of the provided buffer size; we're reading - * 4 bytes at a time but we only want to supply up to the max - * buffer size, so don't write past it! - */ - size_t rz = 0; - uint32_t reg; + if (sc->reg != NULL) + bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->reg_rid, sc->reg); - while (rz < *sz) { - bus_barrier(sc->reg, 0, 0x120, BUS_SPACE_BARRIER_READ); - reg = bus_read_4(sc->reg, QCOM_RND_PRNG_STATUS); - if ((reg & QCOM_RND_PRNG_STATUS_DATA_AVAIL) == 0) - break; - reg = bus_read_4(sc->reg, QCOM_RND_PRNG_DATA_OUT); - memcpy(((char *) buf) + rz, ®, sizeof(uint32_t)); - rz += sizeof(uint32_t); - } + atomic_store_explicit(&g_qcom_rnd_softc, NULL, memory_order_release); - if (rz == 0) - return (EAGAIN); - *sz = rz; return (0); } -static unsigned -qcom_rnd_read(void *buf, unsigned usz) -{ - struct qcom_rnd_softc *sc; - size_t sz; - int error; - - sc = g_qcom_rnd_softc; - if (sc == NULL) - return (0); - - sz = usz; - error = qcom_rnd_harvest(sc, buf, &sz); - if (error != 0) - return (0); - - return (sz); -} - static device_method_t qcom_rnd_methods[] = { /* Device methods. */ DEVMETHOD(device_probe, qcom_rnd_probe), @@ -248,9 +229,7 @@ sizeof(struct qcom_rnd_softc) }; -DRIVER_MODULE(qcom_rnd_random, simplebus, qcom_rnd_driver, - qcom_rnd_modevent, 0); -DRIVER_MODULE(qcom_rnd_random, ofwbus, qcom_rnd_driver, - qcom_rnd_modevent, 0); +DRIVER_MODULE(qcom_rnd_random, simplebus, qcom_rnd_driver, NULL, NULL); +DRIVER_MODULE(qcom_rnd_random, ofwbus, qcom_rnd_driver, NULL, NULL); MODULE_DEPEND(qcom_rnd_random, random_device, 1, 1, 1); MODULE_VERSION(qcom_rnd_random, 1);