diff options
author | Adrian Chadd <adrian@FreeBSD.org> | 2021-10-20 05:33:27 +0000 |
---|---|---|
committer | Adrian Chadd <adrian@FreeBSD.org> | 2021-11-04 16:02:21 +0000 |
commit | 6325f105aad2d6d8ba08efe5aff1c860cc7df198 (patch) | |
tree | d6f4522ca9a24a3b18a0b2be27744b333221a47c | |
parent | aa80581c195eb3d29caa632213f363041be36c1f (diff) | |
download | src-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.c | 42 | ||||
-rw-r--r-- | sys/arm/qualcomm/ipq4018_reg.h | 3 |
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 |