rpi3: Implement PSCI_SYSTEM_OFF

This implementation doesn't actually turn the system off, it simply
reboots it and prevents it from booting while keeping it in a low power
mode.

Change-Id: I7f72c9f43f25ba0341db052bc2be4774c88a7ea3
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
This commit is contained in:
Antonio Nino Diaz 2018-07-14 02:15:51 +01:00
parent 64fe343c03
commit 42ba8f747b
2 changed files with 61 additions and 32 deletions

View File

@ -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

View File

@ -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,
};