diff options
Diffstat (limited to 'plat/rockchip/common/params_setup.c')
-rw-r--r-- | plat/rockchip/common/params_setup.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c new file mode 100644 index 0000000..68054ad --- /dev/null +++ b/plat/rockchip/common/params_setup.c @@ -0,0 +1,256 @@ +/* + * 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 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); +} |