From 64fe343c03dd1b86c342efde97c3cd94f56d84f6 Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Thu, 12 Jul 2018 08:58:38 +0100 Subject: [PATCH 1/3] rpi3: Concatenate BL1 and FIP automatically Add a new default makefile target to concatenate BL1 and the FIP and generate armstub8.bin. This way it isn't needed to do it manually. Documentation updated to reflect the changes. Change-Id: Id5b5b1b7b9f87767db63fd01180ddfea855a7207 Signed-off-by: Antonio Nino Diaz --- docs/plat/rpi3.rst | 22 ++++++---------------- plat/rpi3/platform.mk | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/docs/plat/rpi3.rst b/docs/plat/rpi3.rst index 5ac908539..0ba564d81 100644 --- a/docs/plat/rpi3.rst +++ b/docs/plat/rpi3.rst @@ -196,29 +196,19 @@ Then compile TF-A. For a AArch32 kernel, use the following command line: CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \ RPI3_BL33_IN_AARCH32=1 \ - BL33=../rpi3-arm-tf-bootstrap/aarch32/el2-bootstrap.bin \ - all fip + BL33=../rpi3-arm-tf-bootstrap/aarch32/el2-bootstrap.bin For a AArch64 kernel, use this other command line: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \ - BL33=../rpi3-arm-tf-bootstrap/aarch64/el2-bootstrap.bin \ - all fip + BL33=../rpi3-arm-tf-bootstrap/aarch64/el2-bootstrap.bin -Then, join BL1 and the FIP with the following instructions (replace ``release`` -by ``debug`` if you set the build option ``DEBUG=1``): - -.. code:: shell - - cp build/rpi3/release/bl1.bin bl1.pad.bin - truncate --size=131072 bl1.pad.bin - cat bl1.pad.bin build/rpi3/release/fip.bin > armstub8.bin - -The resulting file, ``armstub8.bin``, contains BL1 and the FIP in the place they -need to be for TF-A to boot correctly. Now, follow the instructions in -`Setup SD card`_. +The build system concatenates BL1 and the FIP so that the addresses match the +ones in the memory map. The resulting file is ``armstub8.bin``, located in the +build folder (e.g. ``build/rpi3/debug/armstub8.bin``). Now, follow the +instructions in `Setup SD card`_. The following build options are supported: diff --git a/plat/rpi3/platform.mk b/plat/rpi3/platform.mk index df19705e6..fa7e5eb7f 100644 --- a/plat/rpi3/platform.mk +++ b/plat/rpi3/platform.mk @@ -54,6 +54,26 @@ else TF_CFLAGS_aarch64 += -mtune=cortex-a53 endif +# Platform Makefile target +# ------------------------ + +RPI3_BL1_PAD_BIN := ${BUILD_PLAT}/bl1_pad.bin +RPI3_ARMSTUB8_BIN := ${BUILD_PLAT}/armstub8.bin + +# Add new default target when compiling this platform +all: armstub + +# This target concatenates BL1 and the FIP so that the base addresses match the +# ones defined in the memory map +armstub: bl1 fip + @echo " CAT $@" + ${Q}cp ${BUILD_PLAT}/bl1.bin ${RPI3_BL1_PAD_BIN} + ${Q}truncate --size=131072 ${RPI3_BL1_PAD_BIN} + ${Q}cat ${RPI3_BL1_PAD_BIN} ${BUILD_PLAT}/fip.bin > ${RPI3_ARMSTUB8_BIN} + @${ECHO_BLANK_LINE} + @echo "Built $@ successfully" + @${ECHO_BLANK_LINE} + # Build config flags # ------------------ From 42ba8f747b154fbc349bfbccd47b5fdd6b4f6d81 Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Sat, 14 Jul 2018 02:15:51 +0100 Subject: [PATCH 2/3] 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 --- plat/rpi3/rpi3_hw.h | 30 +++++++++++++-------- plat/rpi3/rpi3_pm.c | 63 ++++++++++++++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 32 deletions(-) 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, }; From 4f2f66a280534c249ad8624e1492610355cfc60c Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Thu, 12 Jul 2018 13:38:53 +0100 Subject: [PATCH 3/3] rpi3: Detect board revision Implement VideoCore mailbox interface driver and use it to get the board revision identifier. For now it is only used to print the model for debug purposes. This wiki contains the documentation of the mailbox interface: https://github.com/raspberrypi/firmware/wiki Change-Id: I11943b99b52cc1409f4a195ebe58eb44ae5b1d6c Signed-off-by: Antonio Nino Diaz --- plat/rpi3/platform.mk | 3 +- plat/rpi3/rpi3_bl1_setup.c | 34 +++++++++ plat/rpi3/rpi3_hw.h | 21 ++++++ plat/rpi3/rpi3_mbox.c | 146 +++++++++++++++++++++++++++++++++++++ plat/rpi3/rpi3_private.h | 3 + 5 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 plat/rpi3/rpi3_mbox.c diff --git a/plat/rpi3/platform.mk b/plat/rpi3/platform.mk index fa7e5eb7f..5990f2753 100644 --- a/plat/rpi3/platform.mk +++ b/plat/rpi3/platform.mk @@ -20,7 +20,8 @@ BL1_SOURCES += drivers/io/io_fip.c \ plat/common/aarch64/platform_mp_stack.S \ plat/rpi3/aarch64/plat_helpers.S \ plat/rpi3/rpi3_bl1_setup.c \ - plat/rpi3/rpi3_io_storage.c + plat/rpi3/rpi3_io_storage.c \ + plat/rpi3/rpi3_mbox.c BL2_SOURCES += common/desc_image_load.c \ drivers/io/io_fip.c \ diff --git a/plat/rpi3/rpi3_bl1_setup.c b/plat/rpi3/rpi3_bl1_setup.c index c98715b9a..39bb33256 100644 --- a/plat/rpi3/rpi3_bl1_setup.c +++ b/plat/rpi3/rpi3_bl1_setup.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,39 @@ void bl1_plat_arch_setup(void) void bl1_platform_setup(void) { + uint32_t __unused rev; + int __unused rc; + + rc = rpi3_vc_hardware_get_board_revision(&rev); + + if (rc == 0) { + const char __unused *model, __unused *info; + + switch (rev) { + case 0xA02082: + model = "Raspberry Pi 3 Model B"; + info = "(1GB, Sony, UK)"; + break; + case 0xA22082: + model = "Raspberry Pi 3 Model B"; + info = "(1GB, Embest, China)"; + break; + case 0xA020D3: + model = "Raspberry Pi 3 Model B+"; + info = "(1GB, Sony, UK)"; + break; + default: + model = "Unknown"; + info = "(Unknown)"; + ERROR("rpi3: Unknown board revision 0x%08x\n", rev); + break; + } + + NOTICE("rpi3: Detected: %s %s [0x%08x]\n", model, info, rev); + } else { + ERROR("rpi3: Unable to detect board revision\n"); + } + /* Initialise the IO layer and register platform IO devices */ plat_rpi3_io_setup(); } diff --git a/plat/rpi3/rpi3_hw.h b/plat/rpi3/rpi3_hw.h index f411acbca..a83a0ad16 100644 --- a/plat/rpi3/rpi3_hw.h +++ b/plat/rpi3/rpi3_hw.h @@ -16,6 +16,27 @@ #define RPI3_IO_BASE ULL(0x3F000000) #define RPI3_IO_SIZE ULL(0x01000000) +/* + * ARM <-> VideoCore mailboxes + */ +#define RPI3_MBOX_OFFSET ULL(0x0000B880) +#define RPI3_MBOX_BASE (RPI3_IO_BASE + RPI3_MBOX_OFFSET) +/* VideoCore -> ARM */ +#define RPI3_MBOX0_READ_OFFSET ULL(0x00000000) +#define RPI3_MBOX0_PEEK_OFFSET ULL(0x00000010) +#define RPI3_MBOX0_SENDER_OFFSET ULL(0x00000014) +#define RPI3_MBOX0_STATUS_OFFSET ULL(0x00000018) +#define RPI3_MBOX0_CONFIG_OFFSET ULL(0x0000001C) +/* ARM -> VideoCore */ +#define RPI3_MBOX1_WRITE_OFFSET ULL(0x00000020) +#define RPI3_MBOX1_PEEK_OFFSET ULL(0x00000030) +#define RPI3_MBOX1_SENDER_OFFSET ULL(0x00000034) +#define RPI3_MBOX1_STATUS_OFFSET ULL(0x00000038) +#define RPI3_MBOX1_CONFIG_OFFSET ULL(0x0000003C) +/* Mailbox status constants */ +#define RPI3_MBOX_STATUS_FULL_MASK U(0x80000000) /* Set if full */ +#define RPI3_MBOX_STATUS_EMPTY_MASK U(0x40000000) /* Set if empty */ + /* * Power management, reset controller, watchdog. */ diff --git a/plat/rpi3/rpi3_mbox.c b/plat/rpi3/rpi3_mbox.c new file mode 100644 index 000000000..77e17af6b --- /dev/null +++ b/plat/rpi3/rpi3_mbox.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include "rpi3_hw.h" + +/* This struct must be aligned to 16 bytes */ +typedef struct __packed __aligned(16) rpi3_mbox_request { + uint32_t size; /* Buffer size in bytes */ + uint32_t code; /* Request/response code */ + uint32_t tags[0]; +} rpi3_mbox_request_t; + +#define RPI3_MBOX_BUFFER_SIZE U(256) +static uint8_t __aligned(16) rpi3_mbox_buffer[RPI3_MBOX_BUFFER_SIZE]; + +/* Constants to perform a request/check the status of a request. */ +#define RPI3_MBOX_PROCESS_REQUEST U(0x00000000) +#define RPI3_MBOX_REQUEST_SUCCESSFUL U(0x80000000) +#define RPI3_MBOX_REQUEST_ERROR U(0x80000001) + +/* Command constants */ +#define RPI3_TAG_HARDWARE_GET_BOARD_REVISION U(0x00010002) +#define RPI3_TAG_END U(0x00000000) + +#define RPI3_TAG_REQUEST U(0x00000000) +#define RPI3_TAG_IS_RESPONSE U(0x80000000) /* Set if response */ +#define RPI3_TAG_RESPONSE_LENGTH_MASK U(0x7FFFFFFF) + +#define RPI3_CHANNEL_ARM_TO_VC U(0x8) +#define RPI3_CHANNEL_MASK U(0xF) + +#define RPI3_MAILBOX_MAX_RETRIES U(1000000) + +/******************************************************************************* + * Helpers to send requests to the VideoCore using the mailboxes. + ******************************************************************************/ +static void rpi3_vc_mailbox_request_send(void) +{ + uint32_t st, data; + uintptr_t resp_addr, addr; + unsigned int retries; + + /* This is the location of the request buffer */ + addr = (uintptr_t) &rpi3_mbox_buffer; + + /* Make sure that the changes are seen by the VideoCore */ + flush_dcache_range(addr, RPI3_MBOX_BUFFER_SIZE); + + /* Wait until the outbound mailbox is empty */ + retries = 0U; + + do { + st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX1_STATUS_OFFSET); + + retries++; + if (retries == RPI3_MAILBOX_MAX_RETRIES) { + ERROR("rpi3: mbox: Send request timeout\n"); + return; + } + + } while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) == 0U); + + /* Send base address of this message to start request */ + mmio_write_32(RPI3_MBOX_BASE + RPI3_MBOX1_WRITE_OFFSET, + RPI3_CHANNEL_ARM_TO_VC | (uint32_t) addr); + + /* Wait until the inbound mailbox isn't empty */ + retries = 0U; + + do { + st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_STATUS_OFFSET); + + retries++; + if (retries == RPI3_MAILBOX_MAX_RETRIES) { + ERROR("rpi3: mbox: Receive response timeout\n"); + return; + } + + } while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) != 0U); + + /* Get location and channel */ + data = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_READ_OFFSET); + + if ((data & RPI3_CHANNEL_MASK) != RPI3_CHANNEL_ARM_TO_VC) { + ERROR("rpi3: mbox: Wrong channel: 0x%08x\n", data); + panic(); + } + + resp_addr = (uintptr_t)(data & ~RPI3_CHANNEL_MASK); + if (addr != resp_addr) { + ERROR("rpi3: mbox: Unexpected address: 0x%08x\n", data); + panic(); + } + + /* Make sure that the data seen by the CPU is up to date */ + inv_dcache_range(addr, RPI3_MBOX_BUFFER_SIZE); +} + +/******************************************************************************* + * Request board revision. Returns the revision and 0 on success, -1 on error. + ******************************************************************************/ +int rpi3_vc_hardware_get_board_revision(uint32_t *revision) +{ + uint32_t tag_request_size = sizeof(uint32_t); + rpi3_mbox_request_t *req = (rpi3_mbox_request_t *) rpi3_mbox_buffer; + + assert(revision != NULL); + + VERBOSE("rpi3: mbox: Sending request at %p\n", (void *)req); + + req->size = sizeof(rpi3_mbox_buffer); + req->code = RPI3_MBOX_PROCESS_REQUEST; + + req->tags[0] = RPI3_TAG_HARDWARE_GET_BOARD_REVISION; + req->tags[1] = tag_request_size; /* Space available for the response */ + req->tags[2] = RPI3_TAG_REQUEST; + req->tags[3] = 0; /* Placeholder for the response */ + + req->tags[4] = RPI3_TAG_END; + + rpi3_vc_mailbox_request_send(); + + if (req->code != RPI3_MBOX_REQUEST_SUCCESSFUL) { + ERROR("rpi3: mbox: Code = 0x%08x\n", req->code); + return -1; + } + + if (req->tags[2] != (RPI3_TAG_IS_RESPONSE | tag_request_size)) { + ERROR("rpi3: mbox: get board revision failed (0x%08x)\n", + req->tags[2]); + return -1; + } + + *revision = req->tags[3]; + + return 0; +} diff --git a/plat/rpi3/rpi3_private.h b/plat/rpi3/rpi3_private.h index a9fbfe479..9d1744e3f 100644 --- a/plat/rpi3/rpi3_private.h +++ b/plat/rpi3/rpi3_private.h @@ -33,4 +33,7 @@ uint32_t rpi3_get_spsr_for_bl33_entry(void); /* IO storage utility functions */ void plat_rpi3_io_setup(void); +/* VideoCore firmware commands */ +int rpi3_vc_hardware_get_board_revision(uint32_t *revision); + #endif /*__RPI3_PRIVATE_H__ */