mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-08-14 00:17:02 +02:00
When we parse the param from BL2, we try to parse it as a FDT and then, if that fails, as aux params. However, we don't sufficiently distinguish between failure modes in the first step: specifically, if we are given an FDT with good magic that we can't parse for some other reason (e.g. not enough space in our buffer), we still attempt to parse it as aux params even though that's guaranteed to fatal. Instead, we should either fail with a more descriptive message or continue to boot without parsing the FDT. This patch takes the latter approach, since all we currently get from the FDT is non-critical UART params. Signed-off-by: Thomas Hebb <tommyhebb@gmail.com> Change-Id: I1e98f1fcda4f78e6b45e86956288bafe58b113e4
257 lines
5.3 KiB
C
257 lines
5.3 KiB
C
/*
|
|
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
|
|
#include <lib/bl_aux_params/bl_aux_params.h>
|
|
#include <common/bl_common.h>
|
|
#include <common/debug.h>
|
|
#include <drivers/console.h>
|
|
#include <drivers/gpio.h>
|
|
#include <libfdt.h>
|
|
#include <lib/coreboot.h>
|
|
#include <lib/mmio.h>
|
|
#include <plat/common/platform.h>
|
|
|
|
#include <plat_params.h>
|
|
#include <plat_private.h>
|
|
|
|
static struct bl_aux_gpio_info rst_gpio = { .index = UINT_MAX } ;
|
|
static struct bl_aux_gpio_info poweroff_gpio = { .index = UINT_MAX };
|
|
static struct bl_aux_gpio_info suspend_gpio[10];
|
|
uint32_t suspend_gpio_cnt;
|
|
static struct bl_aux_rk_apio_info suspend_apio;
|
|
|
|
#if COREBOOT
|
|
static int dt_process_fdt(u_register_t param_from_bl2)
|
|
{
|
|
return -ENODEV;
|
|
}
|
|
#else
|
|
static uint32_t rk_uart_base = PLAT_RK_UART_BASE;
|
|
static uint32_t rk_uart_baudrate = PLAT_RK_UART_BAUDRATE;
|
|
static uint32_t rk_uart_clock = PLAT_RK_UART_CLOCK;
|
|
#define FDT_BUFFER_SIZE 0x20000
|
|
static uint8_t fdt_buffer[FDT_BUFFER_SIZE];
|
|
|
|
void *plat_get_fdt(void)
|
|
{
|
|
return &fdt_buffer[0];
|
|
}
|
|
|
|
static void plat_rockchip_dt_process_fdt_uart(void *fdt)
|
|
{
|
|
const char *path_name = "/chosen";
|
|
const char *prop_name = "stdout-path";
|
|
int node_offset;
|
|
int stdout_path_len;
|
|
const char *stdout_path;
|
|
const char *separator;
|
|
const char *baud_start;
|
|
char serial_char;
|
|
int serial_no;
|
|
uint32_t uart_base;
|
|
uint32_t baud;
|
|
|
|
node_offset = fdt_path_offset(fdt, path_name);
|
|
if (node_offset < 0)
|
|
return;
|
|
|
|
stdout_path = fdt_getprop(fdt, node_offset, prop_name,
|
|
&stdout_path_len);
|
|
if (stdout_path == NULL)
|
|
return;
|
|
|
|
/*
|
|
* We expect something like:
|
|
* "serial0:baudrate"
|
|
*/
|
|
if (strncmp("serial", stdout_path, 6) != 0)
|
|
return;
|
|
|
|
serial_char = stdout_path[6];
|
|
serial_no = serial_char - '0';
|
|
|
|
switch (serial_no) {
|
|
case 0:
|
|
uart_base = UART0_BASE;
|
|
break;
|
|
case 1:
|
|
uart_base = UART1_BASE;
|
|
break;
|
|
case 2:
|
|
uart_base = UART2_BASE;
|
|
break;
|
|
#ifdef UART3_BASE
|
|
case 3:
|
|
uart_base = UART3_BASE;
|
|
break;
|
|
#endif
|
|
#ifdef UART4_BASE
|
|
case 4:
|
|
uart_base = UART4_BASE;
|
|
break;
|
|
#endif
|
|
#ifdef UART5_BASE
|
|
case 5:
|
|
uart_base = UART5_BASE;
|
|
break;
|
|
#endif
|
|
default:
|
|
return;
|
|
}
|
|
|
|
rk_uart_base = uart_base;
|
|
|
|
separator = strchr(stdout_path, ':');
|
|
if (!separator)
|
|
return;
|
|
|
|
baud = 0;
|
|
baud_start = separator + 1;
|
|
while (*baud_start != '\0') {
|
|
/*
|
|
* uart binding is <baud>{<parity>{<bits>{...}}}
|
|
* So the baudrate either is the whole string, or
|
|
* we end in the parity characters.
|
|
*/
|
|
if (*baud_start == 'n' || *baud_start == 'o' ||
|
|
*baud_start == 'e')
|
|
break;
|
|
|
|
baud = baud * 10 + (*baud_start - '0');
|
|
baud_start++;
|
|
}
|
|
|
|
rk_uart_baudrate = baud;
|
|
}
|
|
|
|
static int dt_process_fdt(u_register_t param_from_bl2)
|
|
{
|
|
void *fdt = plat_get_fdt();
|
|
int ret;
|
|
|
|
ret = fdt_open_into((void *)param_from_bl2, fdt, FDT_BUFFER_SIZE);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
plat_rockchip_dt_process_fdt_uart(fdt);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
uint32_t rockchip_get_uart_base(void)
|
|
{
|
|
#if COREBOOT
|
|
return coreboot_serial.baseaddr;
|
|
#else
|
|
return rk_uart_base;
|
|
#endif
|
|
}
|
|
|
|
uint32_t rockchip_get_uart_baudrate(void)
|
|
{
|
|
#if COREBOOT
|
|
return coreboot_serial.baud;
|
|
#else
|
|
return rk_uart_baudrate;
|
|
#endif
|
|
}
|
|
|
|
uint32_t rockchip_get_uart_clock(void)
|
|
{
|
|
#if COREBOOT
|
|
return coreboot_serial.input_hertz;
|
|
#else
|
|
return rk_uart_clock;
|
|
#endif
|
|
}
|
|
|
|
struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void)
|
|
{
|
|
if (rst_gpio.index == UINT_MAX)
|
|
return NULL;
|
|
|
|
return &rst_gpio;
|
|
}
|
|
|
|
struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void)
|
|
{
|
|
if (poweroff_gpio.index == UINT_MAX)
|
|
return NULL;
|
|
|
|
return &poweroff_gpio;
|
|
}
|
|
|
|
struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count)
|
|
{
|
|
*count = suspend_gpio_cnt;
|
|
|
|
return &suspend_gpio[0];
|
|
}
|
|
|
|
struct bl_aux_rk_apio_info *plat_get_rockchip_suspend_apio(void)
|
|
{
|
|
return &suspend_apio;
|
|
}
|
|
|
|
static bool rk_aux_param_handler(struct bl_aux_param_header *param)
|
|
{
|
|
/* Store platform parameters for later processing if needed. */
|
|
switch (param->type) {
|
|
case BL_AUX_PARAM_RK_RESET_GPIO:
|
|
rst_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
|
|
return true;
|
|
case BL_AUX_PARAM_RK_POWEROFF_GPIO:
|
|
poweroff_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
|
|
return true;
|
|
case BL_AUX_PARAM_RK_SUSPEND_GPIO:
|
|
if (suspend_gpio_cnt >= ARRAY_SIZE(suspend_gpio)) {
|
|
ERROR("Exceeded the supported suspend GPIO number.\n");
|
|
return true;
|
|
}
|
|
suspend_gpio[suspend_gpio_cnt++] =
|
|
((struct bl_aux_param_gpio *)param)->gpio;
|
|
return true;
|
|
case BL_AUX_PARAM_RK_SUSPEND_APIO:
|
|
suspend_apio = ((struct bl_aux_param_rk_apio *)param)->apio;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void params_early_setup(u_register_t plat_param_from_bl2)
|
|
{
|
|
int ret;
|
|
|
|
/*
|
|
* Test if this is a FDT passed as a platform-specific parameter
|
|
* block.
|
|
*/
|
|
ret = dt_process_fdt(plat_param_from_bl2);
|
|
if (!ret) {
|
|
return;
|
|
} else if (ret != -FDT_ERR_BADMAGIC) {
|
|
/*
|
|
* If we found an FDT but couldn't parse it (e.g. corrupt, not
|
|
* enough space), return and don't attempt to parse the param
|
|
* as something else, since we know that will also fail. All
|
|
* we're doing is setting up UART, this doesn't need to be
|
|
* fatal.
|
|
*/
|
|
WARN("%s: found FDT but could not parse: error %d\n",
|
|
__func__, ret);
|
|
return;
|
|
}
|
|
|
|
bl_aux_params_parse(plat_param_from_bl2, rk_aux_param_handler);
|
|
}
|