Commit 42ba8f74 authored by Antonio Nino Diaz's avatar Antonio Nino Diaz
Browse files

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: default avatarAntonio Nino Diaz <antonio.ninodiaz@arm.com>
parent 64fe343c
/* /*
* 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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
...@@ -16,13 +16,6 @@ ...@@ -16,13 +16,6 @@
#define RPI3_IO_BASE ULL(0x3F000000) #define RPI3_IO_BASE ULL(0x3F000000)
#define RPI3_IO_SIZE ULL(0x01000000) #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. * Power management, reset controller, watchdog.
*/ */
...@@ -30,11 +23,26 @@ ...@@ -30,11 +23,26 @@
#define RPI3_PM_BASE (RPI3_IO_BASE + RPI3_IO_PM_OFFSET) #define RPI3_PM_BASE (RPI3_IO_BASE + RPI3_IO_PM_OFFSET)
/* Registers on top of RPI3_PM_BASE. */ /* Registers on top of RPI3_PM_BASE. */
#define RPI3_PM_RSTC_OFFSET ULL(0x0000001C) #define RPI3_PM_RSTC_OFFSET ULL(0x0000001C)
#define RPI3_PM_RSTS_OFFSET ULL(0x00000020)
#define RPI3_PM_WDOG_OFFSET ULL(0x00000024) #define RPI3_PM_WDOG_OFFSET ULL(0x00000024)
/* Watchdog constants */ /* Watchdog constants */
#define RPI3_PM_PASSWORD ULL(0x5A000000) #define RPI3_PM_PASSWORD U(0x5A000000)
#define RPI3_PM_RSTC_WRCFG_MASK ULL(0x00000030) #define RPI3_PM_RSTC_WRCFG_MASK U(0x00000030)
#define RPI3_PM_RSTC_WRCFG_FULL_RESET ULL(0x00000020) #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 * Local interrupt controller
......
/* /*
* 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 * SPDX-License-Identifier: BSD-3-Clause
*/ */
...@@ -150,41 +150,61 @@ void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state) ...@@ -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)
/* Setup watchdog for reset */
static const uintptr_t base = RPI3_PM_BASE; static void __dead2 rpi3_watchdog_reset(void)
{
uint32_t rstc; uint32_t rstc;
INFO("rpi3: PSCI System Reset: invoking watchdog reset\n");
console_flush(); console_flush();
rstc = mmio_read_32(base + RPI3_PM_RSTC_OFFSET); dsbsy();
rstc &= ~RPI3_PM_RSTC_WRCFG_MASK; isb();
rstc |= RPI3_PM_RSTC_WRCFG_FULL_RESET;
dmbst();
/* mmio_write_32(RPI3_PM_BASE + RPI3_PM_WDOG_OFFSET,
* Watchdog timer = Timer clock / 16
* Password (31:16) | Value (11:0)
*/
mmio_write_32(base + RPI3_PM_WDOG_OFFSET,
RPI3_PM_PASSWORD | RESET_TIMEOUT); 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 (;;) { for (;;) {
wfi(); 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. * Platform handlers and setup function.
******************************************************************************/ ******************************************************************************/
...@@ -192,6 +212,7 @@ static const plat_psci_ops_t plat_rpi3_psci_pm_ops = { ...@@ -192,6 +212,7 @@ static const plat_psci_ops_t plat_rpi3_psci_pm_ops = {
.cpu_standby = rpi3_cpu_standby, .cpu_standby = rpi3_cpu_standby,
.pwr_domain_on = rpi3_pwr_domain_on, .pwr_domain_on = rpi3_pwr_domain_on,
.pwr_domain_on_finish = rpi3_pwr_domain_on_finish, .pwr_domain_on_finish = rpi3_pwr_domain_on_finish,
.system_off = rpi3_system_off,
.system_reset = rpi3_system_reset, .system_reset = rpi3_system_reset,
.validate_power_state = rpi3_validate_power_state, .validate_power_state = rpi3_validate_power_state,
}; };
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment