diff --git a/plat/rpi3/rpi3_hw.h b/plat/rpi3/rpi3_hw.h index 70272e003..f411acbca 100644 --- a/plat/rpi3/rpi3_hw.h +++ b/plat/rpi3/rpi3_hw.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -16,13 +16,6 @@ #define RPI3_IO_BASE ULL(0x3F000000) #define RPI3_IO_SIZE ULL(0x01000000) -/* - * Serial port (called 'Mini UART' in the BCM docucmentation). - */ -#define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040) -#define RPI3_MINI_UART_BASE (RPI3_IO_BASE + RPI3_IO_MINI_UART_OFFSET) -#define RPI3_MINI_UART_CLK_IN_HZ ULL(500000000) - /* * Power management, reset controller, watchdog. */ @@ -30,11 +23,26 @@ #define RPI3_PM_BASE (RPI3_IO_BASE + RPI3_IO_PM_OFFSET) /* Registers on top of RPI3_PM_BASE. */ #define RPI3_PM_RSTC_OFFSET ULL(0x0000001C) +#define RPI3_PM_RSTS_OFFSET ULL(0x00000020) #define RPI3_PM_WDOG_OFFSET ULL(0x00000024) /* Watchdog constants */ -#define RPI3_PM_PASSWORD ULL(0x5A000000) -#define RPI3_PM_RSTC_WRCFG_MASK ULL(0x00000030) -#define RPI3_PM_RSTC_WRCFG_FULL_RESET ULL(0x00000020) +#define RPI3_PM_PASSWORD U(0x5A000000) +#define RPI3_PM_RSTC_WRCFG_MASK U(0x00000030) +#define RPI3_PM_RSTC_WRCFG_FULL_RESET U(0x00000020) +/* + * The RSTS register is used by the VideoCore firmware when booting the + * Raspberry Pi to know which partition to boot from. The partition value is + * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware + * to indicate halt. + */ +#define RPI3_PM_RSTS_WRCFG_HALT U(0x00000555) + +/* + * Serial port (called 'Mini UART' in the BCM docucmentation). + */ +#define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040) +#define RPI3_MINI_UART_BASE (RPI3_IO_BASE + RPI3_IO_MINI_UART_OFFSET) +#define RPI3_MINI_UART_CLK_IN_HZ ULL(500000000) /* * Local interrupt controller diff --git a/plat/rpi3/rpi3_pm.c b/plat/rpi3/rpi3_pm.c index 1d067fb13..96948580e 100644 --- a/plat/rpi3/rpi3_pm.c +++ b/plat/rpi3/rpi3_pm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -150,41 +150,61 @@ void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state) } /******************************************************************************* - * Platform handler to reboot the system + * Platform handlers for system reset and system off. ******************************************************************************/ -#define RESET_TIMEOUT 10 -static void __dead2 rpi3_system_reset(void) +/* 10 ticks (Watchdog timer = Timer clock / 16) */ +#define RESET_TIMEOUT U(10) + +static void __dead2 rpi3_watchdog_reset(void) { - /* Setup watchdog for reset */ - - static const uintptr_t base = RPI3_PM_BASE; uint32_t rstc; - INFO("rpi3: PSCI System Reset: invoking watchdog reset\n"); - console_flush(); - rstc = mmio_read_32(base + RPI3_PM_RSTC_OFFSET); - rstc &= ~RPI3_PM_RSTC_WRCFG_MASK; - rstc |= RPI3_PM_RSTC_WRCFG_FULL_RESET; + dsbsy(); + isb(); - dmbst(); - - /* - * Watchdog timer = Timer clock / 16 - * Password (31:16) | Value (11:0) - */ - mmio_write_32(base + RPI3_PM_WDOG_OFFSET, + mmio_write_32(RPI3_PM_BASE + RPI3_PM_WDOG_OFFSET, RPI3_PM_PASSWORD | RESET_TIMEOUT); - mmio_write_32(base + RPI3_PM_RSTC_OFFSET, - RPI3_PM_PASSWORD | rstc); + + rstc = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET); + rstc &= ~RPI3_PM_RSTC_WRCFG_MASK; + rstc |= RPI3_PM_PASSWORD | RPI3_PM_RSTC_WRCFG_FULL_RESET; + mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET, rstc); for (;;) { wfi(); } } +static void __dead2 rpi3_system_reset(void) +{ + INFO("rpi3: PSCI_SYSTEM_RESET: Invoking watchdog reset\n"); + + rpi3_watchdog_reset(); +} + +static void __dead2 rpi3_system_off(void) +{ + uint32_t rsts; + + INFO("rpi3: PSCI_SYSTEM_OFF: Invoking watchdog reset\n"); + + /* + * This function doesn't actually make the Raspberry Pi turn itself off, + * the hardware doesn't allow it. It simply reboots it and the RSTS + * value tells the bootcode.bin firmware not to continue the regular + * bootflow and to stay in a low power mode. + */ + + rsts = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET); + rsts |= RPI3_PM_PASSWORD | RPI3_PM_RSTS_WRCFG_HALT; + mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET, rsts); + + rpi3_watchdog_reset(); +} + /******************************************************************************* * Platform handlers and setup function. ******************************************************************************/ @@ -192,6 +212,7 @@ static const plat_psci_ops_t plat_rpi3_psci_pm_ops = { .cpu_standby = rpi3_cpu_standby, .pwr_domain_on = rpi3_pwr_domain_on, .pwr_domain_on_finish = rpi3_pwr_domain_on_finish, + .system_off = rpi3_system_off, .system_reset = rpi3_system_reset, .validate_power_state = rpi3_validate_power_state, };