mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-19 02:54:24 +00:00

Modify the FDT buffer for Rockchip devices to 384KiB. This is done to allow us to pass mainline devicetrees with symbols through Arm Trusted Firmware. 384KiB was chosen as 512KiB is very near the maximum supported with the current reserved memory. As of kernel version 6.13, the largest devicetree with symbols enabled is 215KiB, and the largest Rockchip devicetree with symbols enabled is 176KiB (rk3588-evb1-v10.dtb). Change-Id: Iea9343d7a30ee26cad3ee5cc848980a93873ae34 Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
256 lines
5.3 KiB
C
256 lines
5.3 KiB
C
/*
|
|
* Copyright (c) 2016-2025, 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 0x60000
|
|
static uint64_t fdt_buffer[FDT_BUFFER_SIZE / 8];
|
|
|
|
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);
|
|
}
|