Page MenuHomeFreeBSD

D32723.id98012.diff
No OneTemporary

D32723.id98012.diff

Index: sys/arm/conf/ASUS_AC1300
===================================================================
--- sys/arm/conf/ASUS_AC1300
+++ sys/arm/conf/ASUS_AC1300
@@ -38,8 +38,7 @@
options LINUX_BOOT_ABI
options SCHED_ULE
-# DEFINITELY not ready for SMP yet!
-# options SMP
+options SMP
options PLATFORM
device loop
@@ -50,3 +49,4 @@
device ether
device mii
device bpf
+
Index: sys/arm/conf/std.qca
===================================================================
--- sys/arm/conf/std.qca
+++ sys/arm/conf/std.qca
@@ -12,6 +12,18 @@
device uart
device uart_msm # Qualcomm MSM UART driver
+# EXT_RESOURCES pseudo devices
+options EXT_RESOURCES
+device clk
+device phy
+device hwreset
+device nvmem
+device regulator
+device syscon
+
+# Random
+device qcom_rnd
+
device gic
# MMC/SD/SDIO Card slot support
@@ -22,6 +34,12 @@
device generic_timer
device mpcore_timer
+# PSCI - SMC calls, needed for qualcomm SCM
+device psci
+
+# Clock/Reset provider
+device qcom_gcc_ipq4018
+
options FDT
# Disable CP14 work in DDB as TZ won't let us by default
Index: sys/arm/qualcomm/ipq4018_machdep.c
===================================================================
--- sys/arm/qualcomm/ipq4018_machdep.c
+++ sys/arm/qualcomm/ipq4018_machdep.c
@@ -36,10 +36,12 @@
#include <sys/reboot.h>
#include <sys/devmap.h>
#include <sys/physmem.h>
+#include <sys/lock.h>
#include <vm/vm.h>
#include <machine/bus.h>
+#include <machine/fdt.h>
#include <machine/intr.h>
#include <machine/machdep.h>
#include <machine/platformvar.h>
@@ -94,12 +96,52 @@
* a call to pmap_mapdev() when the bus space code is doing its thing.
*/
devmap_add_entry(IPQ4018_MEM_UART1_START, IPQ4018_MEM_UART1_SIZE);
+
+ /*
+ * This covers a bunch of the reset block, which includes the PS-HOLD
+ * register for dropping power.
+ */
+ devmap_add_entry(IPQ4018_MEM_PSHOLD_START, IPQ4018_MEM_PSHOLD_SIZE);
+
return (0);
}
+/*
+ * This toggles the PS-HOLD register which on most IPQ devices will toggle
+ * the power control block and reset the SoC.
+ *
+ * However, there are apparently some units out there where this is not
+ * appropriate and instead the watchdog needs to be used.
+ *
+ * For now since there's only going to be one or two initial supported boards
+ * this will be fine. But if this doesn't reboot cleanly, now you know.
+ */
+static void
+ipq4018_cpu_reset_pshold(void)
+{
+ bus_space_handle_t pshold;
+
+ printf("%s: called\n", __func__);
+
+ bus_space_map(fdtbus_bs_tag, IPQ4018_MEM_PSHOLD_START,
+ IPQ4018_MEM_PSHOLD_SIZE, 0, &pshold);
+ bus_space_write_4(fdtbus_bs_tag, pshold, 0, 0);
+ bus_space_barrier(fdtbus_bs_tag, pshold, 0, 0x4,
+ BUS_SPACE_BARRIER_WRITE);
+}
+
static void
ipq4018_cpu_reset(platform_t plat)
{
+ spinlock_enter();
+ dsb();
+
+ ipq4018_cpu_reset_pshold();
+
+ /* Spin */
+ printf("%s: spinning\n", __func__);
+ while(1)
+ ;
}
/*
Index: sys/arm/qualcomm/ipq4018_mp.c
===================================================================
--- sys/arm/qualcomm/ipq4018_mp.c
+++ sys/arm/qualcomm/ipq4018_mp.c
@@ -35,27 +35,82 @@
#include <sys/bus.h>
#include <sys/reboot.h>
#include <sys/devmap.h>
+#include <sys/smp.h>
#include <vm/vm.h>
+#include <machine/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/machdep.h>
#include <machine/platformvar.h>
+#include <machine/smp.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_cpu.h>
#include <arm/qualcomm/ipq4018_machdep.h>
+#include <arm/qualcomm/qcom_scm_legacy.h>
+#include <arm/qualcomm/qcom_cpu_kpssv2.h>
#include "platform_if.h"
void
ipq4018_mp_setmaxid(platform_t plat)
{
+ int ncpu;
+
+ /* If we've already set the global vars don't bother to do it again. */
+ if (mp_ncpus != 0)
+ return;
+
+ /* Read current CP15 Cache Size ID Register */
+ ncpu = cp15_l2ctlr_get();
+ ncpu = CPUV7_L2CTLR_NPROC(ncpu);
+
+ mp_ncpus = ncpu;
+ mp_maxid = ncpu - 1;
+
+ printf("SMP: ncpu=%d\n", ncpu);
+}
+
+static boolean_t
+ipq4018_start_ap(u_int id, phandle_t node, u_int addr_cells, pcell_t *arg)
+{
+
+ /*
+ * For the IPQ401x we assume the enable method is
+ * "qcom,kpss-acc-v2". If this path gets turned into
+ * something more generic for other 32 bit qualcomm
+ * SoCs then we'll likely want to turn this into a
+ * switch based on "enable-method".
+ */
+ return qcom_cpu_kpssv2_regulator_start(id, node);
}
void
ipq4018_mp_start_ap(platform_t plat)
{
+ int ret;
+
+ /*
+ * First step - SCM call to set the cold boot address to mpentry, so
+ * CPUs hopefully start in the MP path.
+ */
+ ret = qcom_scm_legacy_mp_set_cold_boot_address((vm_offset_t) mpentry);
+ if (ret != 0)
+ panic("%s: Couldn't set cold boot address via SCM "
+ "(error 0x%08x)", __func__, ret);
+
+ /*
+ * Next step - loop over the CPU nodes and do the per-CPU setup
+ * required to power on the CPUs themselves.
+ */
+ ofw_cpu_early_foreach(ipq4018_start_ap, true);
+
+ /*
+ * The next set of IPIs to the CPUs will wake them up and enter
+ * mpentry.
+ */
}
Index: sys/arm/qualcomm/ipq4018_reg.h
===================================================================
--- sys/arm/qualcomm/ipq4018_reg.h
+++ sys/arm/qualcomm/ipq4018_reg.h
@@ -39,4 +39,7 @@
#define IPQ4018_MEM_UART1_START 0x078af000
#define IPQ4018_MEM_UART1_SIZE 0x00001000
+#define IPQ4018_MEM_PSHOLD_START 0x004ab000
+#define IPQ4018_MEM_PSHOLD_SIZE 0x00001000
+
#endif
Index: sys/arm/qualcomm/qcom_cpu_kpssv2.h
===================================================================
--- sys/arm/qualcomm/qcom_cpu_kpssv2.h
+++ sys/arm/qualcomm/qcom_cpu_kpssv2.h
@@ -27,16 +27,9 @@
* $FreeBSD$
*/
-#ifndef IPQ4018_REG_H
-#define IPQ4018_REG_H
+#ifndef __QCOM_CPU_KPSSV2_H__
+#define __QCOM_CPU_KPSSV2_H__
-#define IPQ4018_MEM_SMEM_START 0x87e00000
-#define IPQ4018_MEM_SMEM_SIZE 0x00080000
+extern boolean_t qcom_cpu_kpssv2_regulator_start(u_int id, phandle_t node);
-#define IPQ4018_MEM_TZ_START 0x87e80000
-#define IPQ4018_MEM_TZ_SIZE 0x00180000
-
-#define IPQ4018_MEM_UART1_START 0x078af000
-#define IPQ4018_MEM_UART1_SIZE 0x00001000
-
-#endif
+#endif /* __QCOM_CPU_KPSSV2_H__ */
Index: sys/arm/qualcomm/qcom_cpu_kpssv2.c
===================================================================
--- /dev/null
+++ sys/arm/qualcomm/qcom_cpu_kpssv2.c
@@ -0,0 +1,211 @@
+/*-
+ * 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.
+ */
+
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/reboot.h>
+#include <sys/devmap.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/machdep.h>
+#include <machine/platformvar.h>
+#include <machine/smp.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_cpu.h>
+
+#include <arm/qualcomm/qcom_cpu_kpssv2_reg.h>
+#include <arm/qualcomm/qcom_cpu_kpssv2.h>
+
+#include "platform_if.h"
+
+/*
+ * Since DELAY() hangs this early, we need some way to
+ * delay things to settle.
+ */
+static inline void
+loop_delay(int usec)
+{
+ int lcount = usec * 100000;
+
+ for (volatile int i = 0; i < lcount; i++)
+ ;
+}
+
+/*
+ * This is the KPSSv2 (eg IPQ4018) regulator path for CPU
+ * and shared L2 cache power-on.
+ */
+boolean_t
+qcom_cpu_kpssv2_regulator_start(u_int id, phandle_t node)
+{
+ phandle_t acc_phandle, l2_phandle, saw_phandle;
+ bus_space_tag_t acc_tag, saw_tag;
+ bus_space_handle_t acc_handle, saw_handle;
+ bus_size_t acc_sz, saw_sz;
+ ssize_t sret;
+ int ret;
+ uint32_t reg_val;
+
+ /*
+ * We don't need to power up CPU 0! This will power it
+ * down first and ... then everything hangs.
+ */
+ if (id == 0)
+ return true;
+
+ /*
+ * Walk the qcom,acc and next-level-cache entries to find their
+ * child phandles and thus regulators.
+ *
+ * The qcom,acc is a phandle to a node.
+ *
+ * The next-level-cache actually is a phandle through to a qcom,saw
+ * entry.
+ */
+ sret = OF_getencprop(node, "qcom,acc", (void *) &acc_phandle,
+ sizeof(acc_phandle));
+ if (sret != sizeof(acc_phandle))
+ panic("***couldn't get phandle for qcom,acc");
+ acc_phandle = OF_node_from_xref(acc_phandle);
+
+ sret = OF_getencprop(node, "next-level-cache", (void *) &l2_phandle,
+ sizeof(l2_phandle));
+ if (sret != sizeof(l2_phandle))
+ panic("***couldn't get phandle for next-level-cache");
+ l2_phandle = OF_node_from_xref(l2_phandle);
+
+ sret = OF_getencprop(l2_phandle, "qcom,saw", (void *) &saw_phandle,
+ sizeof(saw_phandle));
+ if (sret != sizeof(saw_phandle))
+ panic("***couldn't get phandle for qcom,saw");
+ l2_phandle = OF_node_from_xref(l2_phandle);
+
+ /*
+ * Now that we have the phandles referencing the correct locations,
+ * do some KVA mappings so we can go access the registers.
+ */
+ ret = OF_decode_addr(acc_phandle, 0, &acc_tag, &acc_handle, &acc_sz);
+ if (ret != 0)
+ panic("*** couldn't map qcom,acc space (%d)", ret);
+ ret = OF_decode_addr(saw_phandle, 0, &saw_tag, &saw_handle, &saw_sz);
+ if (ret != 0)
+ panic("*** couldn't map next-level-cache -> "
+ "qcom,saw space (%d)", ret);
+
+ /*
+ * Power sequencing to ensure the cores are off, then power them on
+ * and bring them out of reset.
+ */
+
+ /*
+ * BHS: off
+ * LDO: bypassed, powered off
+ */
+ reg_val = (64 << QCOM_APC_PWR_GATE_CTL_BHS_CNT_SHIFT)
+ | (0x3f << QCOM_APC_PWR_GATE_CTL_LDO_PWR_DWN_SHIFT)
+ | QCOM_APC_PWR_GATE_CTL_BHS_EN;
+ bus_space_write_4(acc_tag, acc_handle, QCOM_APC_PWR_GATE_CTL, reg_val);
+ mb();
+ /* Settle time */
+ loop_delay(1);
+
+ /*
+ * Start up BHS segments.
+ */
+ reg_val |= 0x3f << QCOM_APC_PWR_GATE_CTL_BHS_SEG_SHIFT;
+ bus_space_write_4(acc_tag, acc_handle, QCOM_APC_PWR_GATE_CTL, reg_val);
+ mb();
+ /* Settle time */
+ loop_delay(1);
+
+ /*
+ * Switch on the LDO bypass; BHS will now supply power.
+ */
+ reg_val |= 0x3f << QCOM_APC_PWR_GATE_CTL_LDO_BYP_SHIFT;
+ bus_space_write_4(acc_tag, acc_handle, QCOM_APC_PWR_GATE_CTL, reg_val);
+
+ /*
+ * Shared L2 regulator control.
+ */
+ bus_space_write_4(saw_tag, saw_handle, QCOM_APCS_SAW2_2_VCTL, 0x10003);
+ mb();
+ /* Settle time */
+ loop_delay(50);
+
+ /*
+ * Put the core in reset.
+ */
+ reg_val = QCOM_APCS_CPU_PWR_CTL_COREPOR_RST
+ | QCOM_APCS_CPU_PWR_CTL_CLAMP;
+ bus_space_write_4(acc_tag, acc_handle, QCOM_APCS_CPU_PWR_CTL, reg_val);
+ mb();
+ loop_delay(2);
+
+ /*
+ * Remove power-down clamp.
+ */
+ reg_val &= ~QCOM_APCS_CPU_PWR_CTL_CLAMP;
+ bus_space_write_4(acc_tag, acc_handle, QCOM_APCS_CPU_PWR_CTL, reg_val);
+ mb();
+ loop_delay(2);
+
+ /*
+ * Clear core power reset.
+ */
+ reg_val &= ~QCOM_APCS_CPU_PWR_CTL_COREPOR_RST;
+ bus_space_write_4(acc_tag, acc_handle, QCOM_APCS_CPU_PWR_CTL, reg_val);
+ mb();
+
+ /*
+ * The power is ready, the core is out of reset, signal the core
+ * to power up.
+ */
+ reg_val |= QCOM_APCS_CPU_PWR_CTL_CORE_PWRD_UP;
+ bus_space_write_4(acc_tag, acc_handle, QCOM_APCS_CPU_PWR_CTL, reg_val);
+ mb();
+
+ /*
+ * Finished with these KVA mappings, so release them.
+ */
+ bus_space_unmap(acc_tag, acc_handle, acc_sz);
+ bus_space_unmap(saw_tag, saw_handle, saw_sz);
+
+ return true;
+}
Index: sys/arm/qualcomm/qcom_cpu_kpssv2_reg.h
===================================================================
--- sys/arm/qualcomm/qcom_cpu_kpssv2_reg.h
+++ sys/arm/qualcomm/qcom_cpu_kpssv2_reg.h
@@ -27,16 +27,32 @@
* $FreeBSD$
*/
-#ifndef IPQ4018_REG_H
-#define IPQ4018_REG_H
+#ifndef __QCOM_CPU_KPSSV2_REG_H__
+#define __QCOM_CPU_KPSSV2_REG_H__
-#define IPQ4018_MEM_SMEM_START 0x87e00000
-#define IPQ4018_MEM_SMEM_SIZE 0x00080000
-#define IPQ4018_MEM_TZ_START 0x87e80000
-#define IPQ4018_MEM_TZ_SIZE 0x00180000
+/*
+ * APCS CPU core regulator registers.
+ */
+#define QCOM_APCS_CPU_PWR_CTL 0x04
+#define QCOM_APCS_CPU_PWR_CTL_PLL_CLAMP (1U << 8)
+#define QCOM_APCS_CPU_PWR_CTL_CORE_PWRD_UP (1U << 7)
+#define QCOM_APCS_CPU_PWR_CTL_COREPOR_RST (1U << 5)
+#define QCOM_APCS_CPU_PWR_CTL_CORE_RST (1U << 4)
+#define QCOM_APCS_CPU_PWR_CTL_L2DT_SLP (1U << 3)
+#define QCOM_APCS_CPU_PWR_CTL_CLAMP (1U << 0)
+
+#define QCOM_APC_PWR_GATE_CTL 0x14
+#define QCOM_APC_PWR_GATE_CTL_BHS_CNT_SHIFT 24
+#define QCOM_APC_PWR_GATE_CTL_LDO_PWR_DWN_SHIFT 16
+#define QCOM_APC_PWR_GATE_CTL_LDO_BYP_SHIFT 8
+#define QCOM_APC_PWR_GATE_CTL_BHS_SEG_SHIFT 1
+#define QCOM_APC_PWR_GATE_CTL_BHS_EN (1U << 0)
-#define IPQ4018_MEM_UART1_START 0x078af000
-#define IPQ4018_MEM_UART1_SIZE 0x00001000
-#endif
+/*
+ * L2 cache regulator registers.
+ */
+#define QCOM_APCS_SAW2_2_VCTL 0x1c
+
+#endif /* __QCOM_CPU_KPSSV2_REG_H__ */
Index: sys/arm/qualcomm/qcom_gcc_ipq4018.c
===================================================================
--- /dev/null
+++ 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);
Index: sys/arm/qualcomm/qcom_gcc_ipq4018_clock.c
===================================================================
--- /dev/null
+++ sys/arm/qualcomm/qcom_gcc_ipq4018_clock.c
@@ -0,0 +1,82 @@
+/*-
+ * 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 <dt-bindings/clock/qcom,gcc-ipq4019.h>
+
+#include <arm/qualcomm/qcom_gcc_ipq4018_var.h>
+
+
+/*
+ * Fixed frequency clock sources:
+ *
+ * P_XO - 48MHz
+ * sleep-clk - is really 32KHz, although older DTS have it as 32.768KHz
+ */
+
+/*
+ * PLL derived sources:
+ *
+ * P_FEPLL125 - 125MHz
+ * P_FEPLL125DLY - 125MHz
+ * P_FEPLL200 - 200MHz
+ * P_FEPLL500 - 500MHz
+ * P_FEPLLWCSS2G - TBD
+ * P_FEPLLWCSS5G - TBD
+ *
+ * Then there are two DDR PLLs which are treated/configured slightly
+ * differently:
+ *
+ * P_DDRPLLAPSS - TBD
+ * P_DDRPLLSDCC - TBD
+ */
+
+/*
+ * Interesting stuff in Linux whilst I reverse engineer + figure it out:
+ * /sys/kernel/debug/clk
+ */
Index: sys/arm/qualcomm/qcom_gcc_ipq4018_reset.c
===================================================================
--- /dev/null
+++ 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);
+}
+
Index: sys/arm/qualcomm/qcom_gcc_ipq4018_var.h
===================================================================
--- sys/arm/qualcomm/qcom_gcc_ipq4018_var.h
+++ sys/arm/qualcomm/qcom_gcc_ipq4018_var.h
@@ -27,16 +27,24 @@
* $FreeBSD$
*/
-#ifndef IPQ4018_REG_H
-#define IPQ4018_REG_H
+#ifndef __QCOM_GCC_IPQ4018_VAR_H__
+#define __QCOM_GCC_IPQ4018_VAR_H__
-#define IPQ4018_MEM_SMEM_START 0x87e00000
-#define IPQ4018_MEM_SMEM_SIZE 0x00080000
+struct qcom_gcc_ipq4018_reset_entry {
+ uint32_t reg;
+ uint32_t bit;
+};
-#define IPQ4018_MEM_TZ_START 0x87e80000
-#define IPQ4018_MEM_TZ_SIZE 0x00180000
+struct qcom_gcc_ipq4018_softc {
+ device_t dev;
+ int reg_rid;
+ struct resource *reg;
+ struct mtx mtx;
+};
-#define IPQ4018_MEM_UART1_START 0x078af000
-#define IPQ4018_MEM_UART1_SIZE 0x00001000
+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
+#endif /* __QCOM_GCC_IPQ4018_VAR_H__ */
Index: sys/arm/qualcomm/qcom_scm_defs.h
===================================================================
--- /dev/null
+++ sys/arm/qualcomm/qcom_scm_defs.h
@@ -0,0 +1,122 @@
+/*-
+ * 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_SCM_DEFS_H__
+#define __QCOM_SCM_DEFS_H__
+
+/*
+ * Maximum SCM arguments and return values.
+ */
+#define MAX_QCOM_SCM_ARGS 10
+#define MAX_QCOM_SCM_RETS 3
+
+/*
+ * SCM argument type definitions.
+ */
+#define QCOM_SCM_ARGTYPE_VAL 0x00
+#define QCOM_SCM_ARGTYPE_RO 0x01
+#define QCOM_SCM_ARGTYPE_RW 0x02
+#define QCOM_SCM_ARGTYPE_BUFVAL 0x03
+
+/*
+ * SCM calls + arguments.
+ */
+#define QCOM_SCM_SVC_BOOT 0x01
+#define QCOM_SCM_BOOT_SET_ADDR 0x01
+#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
+#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
+#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
+#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
+
+/* Flags for QCOM_SCM_BOOT_SET_ADDR argv[0] */
+/* Note: no COLDBOOT for CPU0, it's already booted */
+#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
+#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
+#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
+#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
+#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
+#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
+#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
+
+#define QCOM_SCM_SVC_PIL 0x02
+#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
+#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x02
+#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x05
+#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06
+#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
+#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a
+
+#define QCOM_SCM_SVC_IO 0x05
+#define QCOM_SCM_IO_READ 0x01
+#define QCOM_SCM_IO_WRITE 0x02
+
+/*
+ * Fetch SCM call availability information.
+ */
+#define QCOM_SCM_SVC_INFO 0x06
+#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x01
+
+#define QCOM_SCM_SVC_MP 0x0c
+#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03
+#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04
+#define QCOM_SCM_MP_VIDEO_VAR 0x08
+#define QCOM_SCM_MP_ASSIGN 0x16
+
+#define QCOM_SCM_SVC_OCMEM 0x0f
+#define QCOM_SCM_OCMEM_LOCK_CMD 0x01
+#define QCOM_SCM_OCMEM_UNLOCK_CMD 0x02
+
+#define QCOM_SCM_SVC_ES 0x10
+#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03
+#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04
+
+#define QCOM_SCM_SVC_HDCP 0x11
+#define QCOM_SCM_HDCP_INVOKE 0x01
+
+#define QCOM_SCM_SVC_LMH 0x13
+#define QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE 0x01
+#define QCOM_SCM_LMH_LIMIT_DCVSH 0x10
+
+#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
+#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
+
+/*
+ * Return values from the SCM calls.
+ */
+#define QCOM_SCM_RETVAL_V2_EBUSY -12
+#define QCOM_SCM_RETVAL_ENOMEM -5
+#define QCOM_SCM_RETVAL_EOPNOTSUPP -4
+#define QCOM_SCM_RETVAL_EINVAL_ADDR -3
+#define QCOM_SCM_RETVAL_EINVAL_ARG -2
+#define QCOM_SCM_RETVAL_ERROR -1
+#define QCOM_SCM_RETVAL_INTERRUPTED 1
+
+#endif /* __QCOM_SCM_DEFS_H__ */
Index: sys/arm/qualcomm/qcom_scm_legacy.h
===================================================================
--- sys/arm/qualcomm/qcom_scm_legacy.h
+++ sys/arm/qualcomm/qcom_scm_legacy.h
@@ -27,16 +27,15 @@
* $FreeBSD$
*/
-#ifndef IPQ4018_REG_H
-#define IPQ4018_REG_H
+#ifndef __QCOM_SCM_LEGACY_H__
+#define __QCOM_SCM_LEGACY_H__
-#define IPQ4018_MEM_SMEM_START 0x87e00000
-#define IPQ4018_MEM_SMEM_SIZE 0x00080000
-
-#define IPQ4018_MEM_TZ_START 0x87e80000
-#define IPQ4018_MEM_TZ_SIZE 0x00180000
+/*
+ * These functions are specific to the 32 bit legacy SCM interface
+ * used by the IPQ806x and IPQ401x SoCs.
+ */
-#define IPQ4018_MEM_UART1_START 0x078af000
-#define IPQ4018_MEM_UART1_SIZE 0x00001000
+extern uint32_t qcom_scm_legacy_mp_set_cold_boot_address(
+ vm_offset_t mp_entry_func);
-#endif
+#endif /* __QCOM_SCM_LEGACY_H__ */
Index: sys/arm/qualcomm/qcom_scm_legacy.c
===================================================================
--- sys/arm/qualcomm/qcom_scm_legacy.c
+++ sys/arm/qualcomm/qcom_scm_legacy.c
@@ -35,27 +35,54 @@
#include <sys/bus.h>
#include <sys/reboot.h>
#include <sys/devmap.h>
+#include <sys/smp.h>
#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/machdep.h>
-#include <machine/platformvar.h>
+#include <machine/smp.h>
-#include <dev/fdt/fdt_common.h>
-#include <dev/ofw/openfirm.h>
+#include <arm/qualcomm/qcom_scm_defs.h>
+#include <arm/qualcomm/qcom_scm_legacy_defs.h>
+#include <arm/qualcomm/qcom_scm_legacy.h>
-#include <arm/qualcomm/ipq4018_machdep.h>
+#include <dev/psci/smccc.h>
-#include "platform_if.h"
-
-void
-ipq4018_mp_setmaxid(platform_t plat)
+/*
+ * Set the cold boot address for (later) a mask of CPUs.
+ *
+ * Don't set it for CPU0, that CPU is the boot CPU and is already alive.
+ *
+ * For now it sets it on CPU1..3.
+ *
+ * This works on the IPQ4019 as tested; the retval is 0x0.
+ */
+uint32_t
+qcom_scm_legacy_mp_set_cold_boot_address(vm_offset_t mp_entry_func)
{
-}
+ struct arm_smccc_res res;
+ int ret;
+ int context_id;
-void
-ipq4018_mp_start_ap(platform_t plat)
-{
+ uint32_t scm_arg0 = QCOM_SCM_LEGACY_ATOMIC_ID(QCOM_SCM_SVC_BOOT,
+ QCOM_SCM_BOOT_SET_ADDR, 2);
+
+ uint32_t scm_arg1 = QCOM_SCM_FLAG_COLDBOOT_CPU1
+ | QCOM_SCM_FLAG_COLDBOOT_CPU2
+ | QCOM_SCM_FLAG_COLDBOOT_CPU3;
+ uint32_t scm_arg2 = pmap_kextract((vm_offset_t)mp_entry_func);
+
+ ret = arm_smccc_smc(scm_arg0, (uint32_t) &context_id, scm_arg1,
+ scm_arg2, 0, 0, 0, 0, &res);
+
+ if (ret == 0 && res.a0 == 0)
+ return (0);
+ printf("%s: called; error; ret=0x%08x; retval[0]=0x%08x\n",
+ __func__, ret, res.a0);
+
+ return (0);
}
Index: sys/arm/qualcomm/qcom_scm_legacy_defs.h
===================================================================
--- /dev/null
+++ sys/arm/qualcomm/qcom_scm_legacy_defs.h
@@ -0,0 +1,149 @@
+/*-
+ * 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_SCM_LEGACY_DEFS_H__
+#define __QCOM_SCM_LEGACY_DEFS_H__
+
+/*
+ * These definitions are specific to the 32 bit legacy SCM interface
+ * used by the IPQ806x and IPQ401x SoCs.
+ */
+
+/*
+ * Mapping of the SCM service/command fields into the a0 argument
+ * in an SMC instruction call.
+ *
+ * This is particular to the legacy SCM interface, and is not the
+ * same as the non-legacy 32/64 bit FNID mapping layout.
+ */
+#define QCOM_SCM_LEGACY_SMC_FNID(s, c) (((s) << 10) | ((c) & 0x3ff))
+
+/*
+ * There are two kinds of SCM calls in this legacy path.
+ *
+ * The first kind are the normal ones - up to a defined max of arguments,
+ * a defined max of responses and some identifiers for all of it.
+ * They can be issues in parallel on different cores, can be interrupted,
+ * etc.
+ *
+ * The second kind are what are termed "atomic" SCM calls -
+ * up to 5 argument DWORDs, up to 3 response DWORDs, done atomically,
+ * not interruptable/parallel.
+ *
+ * The former use the structures below to represent the request and response
+ * in memory. The latter use defines and a direct SMC call with the
+ * arguments in registers.
+ */
+
+struct qcom_scm_legacy_smc_args {
+ uint32_t args[8];
+};
+
+/*
+ * Atomic SCM call command/response buffer definitions.
+ */
+#define QCOM_SCM_LEGACY_ATOMIC_MAX_ARGCOUNT 5
+#define QCOM_SCM_LEGACY_CLASS_REGISTER (0x2 << 8)
+#define QCOM_SCM_LEGACY_MASK_IRQS (1U << 5)
+
+/*
+ * Mapping an SCM service/command/argcount into the a0 register
+ * for an SMC instruction call.
+ */
+#define QCOM_SCM_LEGACY_ATOMIC_ID(svc, cmd, n) \
+ ((QCOM_SCM_LEGACY_SMC_FNID((svc), cmd) << 12) | \
+ QCOM_SCM_LEGACY_CLASS_REGISTER | \
+ QCOM_SCM_LEGACY_MASK_IRQS | \
+ ((n) & 0xf))
+
+/*
+ * Legacy command/response buffer definitions.
+ *
+ * The legacy path contains up to the defined maximum arguments
+ * but only a single command/response pair per call.
+ *
+ * A command and response buffer is laid out in memory as such:
+ *
+ * | command header |
+ * | (buffer payload) |
+ * | response header |
+ * | (response payload) |
+ */
+
+/*
+ * The command header.
+ *
+ * len - the length of the total command and response, including
+ * the headers.
+ *
+ * buf_offset - the offset inside the buffer, starting at the
+ * beginning of this command header, where the command buffer
+ * is found. The end is the byte before the response_header_offset.
+ *
+ * response_header_offset - the offset inside the buffer where
+ * the response header is found.
+ *
+ * id - the QCOM_SCM_LEGACY_SMC_FNID() - service/command ids
+ */
+struct qcom_scm_legacy_command_header {
+ uint32_t len;
+ uint32_t buf_offset;
+ uint32_t response_header_offset;
+ uint32_t id;
+};
+
+/*
+ * The response header.
+ *
+ * This is found immediately after the command header and command
+ * buffer payload.
+ *
+ * len - the total amount of memory available for the response.
+ * Linux doesn't set this; it always passes in a response
+ * buffer large enough to store MAX_QCOM_SCM_RETS * DWORD
+ * bytes.
+ *
+ * It's also possible this is set by the firmware.
+ *
+ * buf_offset - start of response buffer, relative to the beginning
+ * of the command header. This also isn't set in Linux before
+ * calling the SMC instruction, but it is checked afterwards
+ * to assemble a pointer to the response data. The firmware
+ * likely sets this.
+ *
+ * is_complete - true if complete. Linux loops over DMA sync to
+ * check if this is complete even after the SMC call returns.
+ */
+struct qcom_scm_legacy_response_header {
+ uint32_t len;
+ uint32_t buf_offset;
+ uint32_t is_complete;
+};
+
+#endif /* __QCOM_SCM_LEGACY_DEFS_H__ */
Index: sys/arm/qualcomm/std.ipq4018
===================================================================
--- sys/arm/qualcomm/std.ipq4018
+++ sys/arm/qualcomm/std.ipq4018
@@ -1,2 +1,10 @@
arm/qualcomm/ipq4018_machdep.c standard
arm/qualcomm/ipq4018_mp.c optional smp
+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
+arm/qualcomm/qcom_gcc_ipq4018_clock.c optional qcom_gcc_ipq4018
+
Index: sys/dev/qcom_rnd/qcom_rnd.c
===================================================================
--- /dev/null
+++ sys/dev/qcom_rnd/qcom_rnd.c
@@ -0,0 +1,257 @@
+/*-
+ * 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 MSM entropy 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 <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/random/randomdev.h>
+#include <dev/random/random_harvestq.h>
+
+#include <dev/qcom_rnd/qcom_rnd_reg.h>
+
+struct qcom_rnd_softc {
+ 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)
+{
+ 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_rnd_probe(device_t dev)
+{
+ if (! ofw_bus_status_okay(dev)) {
+ return (ENXIO);
+ }
+
+ if (ofw_bus_is_compatible(dev, "qcom,prng") == 0) {
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+qcom_rnd_attach(device_t dev)
+{
+ struct qcom_rnd_softc *sc, *exp;
+ 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)) {
+ return (ENXIO);
+ }
+
+ sc->reg_rid = 0;
+ sc->reg = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY,
+ &sc->reg_rid, 0x140, RF_ACTIVE);
+ if (sc->reg == NULL) {
+ device_printf(dev, "Couldn't 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);
+ 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.
+ */
+ 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);
+
+ 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);
+ }
+
+ random_source_register(&random_qcom_rnd);
+ return (0);
+
+}
+
+static int
+qcom_rnd_detach(device_t dev)
+{
+ struct qcom_rnd_softc *sc;
+
+ sc = device_get_softc(dev);
+ KASSERT(
+ atomic_load_explicit(&g_qcom_rnd_softc, memory_order_acquire) == sc,
+ ("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;
+
+ 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, &reg, sizeof(uint32_t));
+ rz += sizeof(uint32_t);
+ }
+
+ 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),
+ DEVMETHOD(device_attach, qcom_rnd_attach),
+ DEVMETHOD(device_detach, qcom_rnd_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t qcom_rnd_driver = {
+ "qcom_rnd",
+ qcom_rnd_methods,
+ sizeof(struct qcom_rnd_softc)
+};
+static devclass_t qcom_rnd_devclass;
+
+DRIVER_MODULE(qcom_rnd_random, simplebus, qcom_rnd_driver, qcom_rnd_devclass,
+ qcom_rnd_modevent, 0);
+DRIVER_MODULE(qcom_rnd_random, ofwbus, qcom_rnd_driver, qcom_rnd_devclass,
+ qcom_rnd_modevent, 0);
+MODULE_DEPEND(qcom_rnd_random, random_device, 1, 1, 1);
+MODULE_VERSION(qcom_rnd_random, 1);
Index: sys/dev/qcom_rnd/qcom_rnd_reg.h
===================================================================
--- /dev/null
+++ sys/dev/qcom_rnd/qcom_rnd_reg.h
@@ -0,0 +1,43 @@
+/*-
+ * 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.
+ */
+
+#ifndef __QCOM_RND_REG_H__
+#define __QCOM_RND_REG_H__
+
+#define QCOM_RND_PRNG_DATA_OUT 0x0000
+
+#define QCOM_RND_PRNG_STATUS 0x0004
+#define QCOM_RND_PRNG_STATUS_DATA_AVAIL (1 << 0)
+
+#define QCOM_RND_PRNG_LFSR_CFG 0x0100
+#define QCOM_RND_PRNG_LFSR_CFG_MASK 0x0000ffff
+#define QCOM_RND_PRNG_LFSR_CFG_CLOCKS 0x0000dddd
+
+#define QCOM_RND_PRNG_CONFIG 0x0104
+#define QCOM_RND_PRNG_CONFIG_HW_ENABLE (1 << 1)
+
+#endif /* __QCOM_RND_REG_H__ */
Index: sys/sys/random.h
===================================================================
--- sys/sys/random.h
+++ sys/sys/random.h
@@ -102,6 +102,7 @@
RANDOM_PURE_DARN,
RANDOM_PURE_TPM,
RANDOM_PURE_VMGENID,
+ RANDOM_PURE_QUALCOMM,
ENTROPYSOURCE
};
_Static_assert(ENTROPYSOURCE <= 32,

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 9, 5:14 AM (11 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28541539
Default Alt Text
D32723.id98012.diff (50 KB)

Event Timeline