aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Chadd <adrian@FreeBSD.org>2021-10-20 05:33:27 +0000
committerAdrian Chadd <adrian@FreeBSD.org>2021-11-04 16:02:21 +0000
commit6325f105aad2d6d8ba08efe5aff1c860cc7df198 (patch)
treed6f4522ca9a24a3b18a0b2be27744b333221a47c
parentaa80581c195eb3d29caa632213f363041be36c1f (diff)
downloadsrc-6325f105aad2d6d8ba08efe5aff1c860cc7df198.tar.gz
src-6325f105aad2d6d8ba08efe5aff1c860cc7df198.zip
ipq4018: toggle ps-hold to allow SoC reset
This is enough to allow this ASUS router to reboot successfully. I tried the watchdog path and although it fires, it isn't rebooting! It's just hanging, likely somewhere in TZ. Tested: * ASUS RT-AC58U router, IPQ4019 Reviewed by: andrew, manu, imp Differential Revision: https://reviews.freebsd.org/D32723
-rw-r--r--sys/arm/qualcomm/ipq4018_machdep.c42
-rw-r--r--sys/arm/qualcomm/ipq4018_reg.h3
2 files changed, 45 insertions, 0 deletions
diff --git a/sys/arm/qualcomm/ipq4018_machdep.c b/sys/arm/qualcomm/ipq4018_machdep.c
index b3f841575ebb..39510c8294ae 100644
--- a/sys/arm/qualcomm/ipq4018_machdep.c
+++ b/sys/arm/qualcomm/ipq4018_machdep.c
@@ -36,10 +36,12 @@ __FBSDID("$FreeBSD$");
#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 @@ ipq4018_devmap_init(platform_t plat)
* 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)
+ ;
}
/*
diff --git a/sys/arm/qualcomm/ipq4018_reg.h b/sys/arm/qualcomm/ipq4018_reg.h
index 945d650dcfd6..9c09605eab1a 100644
--- a/sys/arm/qualcomm/ipq4018_reg.h
+++ b/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