1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <errno.h> 9*91f16700Schasinglulu #include <limits.h> 10*91f16700Schasinglulu #include <string.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <lib/bl_aux_params/bl_aux_params.h> 13*91f16700Schasinglulu #include <common/bl_common.h> 14*91f16700Schasinglulu #include <common/debug.h> 15*91f16700Schasinglulu #include <drivers/console.h> 16*91f16700Schasinglulu #include <drivers/gpio.h> 17*91f16700Schasinglulu #include <libfdt.h> 18*91f16700Schasinglulu #include <lib/coreboot.h> 19*91f16700Schasinglulu #include <lib/mmio.h> 20*91f16700Schasinglulu #include <plat/common/platform.h> 21*91f16700Schasinglulu 22*91f16700Schasinglulu #include <plat_params.h> 23*91f16700Schasinglulu #include <plat_private.h> 24*91f16700Schasinglulu 25*91f16700Schasinglulu static struct bl_aux_gpio_info rst_gpio = { .index = UINT_MAX } ; 26*91f16700Schasinglulu static struct bl_aux_gpio_info poweroff_gpio = { .index = UINT_MAX }; 27*91f16700Schasinglulu static struct bl_aux_gpio_info suspend_gpio[10]; 28*91f16700Schasinglulu uint32_t suspend_gpio_cnt; 29*91f16700Schasinglulu static struct bl_aux_rk_apio_info suspend_apio; 30*91f16700Schasinglulu 31*91f16700Schasinglulu #if COREBOOT 32*91f16700Schasinglulu static int dt_process_fdt(u_register_t param_from_bl2) 33*91f16700Schasinglulu { 34*91f16700Schasinglulu return -ENODEV; 35*91f16700Schasinglulu } 36*91f16700Schasinglulu #else 37*91f16700Schasinglulu static uint32_t rk_uart_base = PLAT_RK_UART_BASE; 38*91f16700Schasinglulu static uint32_t rk_uart_baudrate = PLAT_RK_UART_BAUDRATE; 39*91f16700Schasinglulu static uint32_t rk_uart_clock = PLAT_RK_UART_CLOCK; 40*91f16700Schasinglulu #define FDT_BUFFER_SIZE 0x20000 41*91f16700Schasinglulu static uint64_t fdt_buffer[FDT_BUFFER_SIZE / 8]; 42*91f16700Schasinglulu 43*91f16700Schasinglulu void *plat_get_fdt(void) 44*91f16700Schasinglulu { 45*91f16700Schasinglulu return &fdt_buffer[0]; 46*91f16700Schasinglulu } 47*91f16700Schasinglulu 48*91f16700Schasinglulu static void plat_rockchip_dt_process_fdt_uart(void *fdt) 49*91f16700Schasinglulu { 50*91f16700Schasinglulu const char *path_name = "/chosen"; 51*91f16700Schasinglulu const char *prop_name = "stdout-path"; 52*91f16700Schasinglulu int node_offset; 53*91f16700Schasinglulu int stdout_path_len; 54*91f16700Schasinglulu const char *stdout_path; 55*91f16700Schasinglulu const char *separator; 56*91f16700Schasinglulu const char *baud_start; 57*91f16700Schasinglulu char serial_char; 58*91f16700Schasinglulu int serial_no; 59*91f16700Schasinglulu uint32_t uart_base; 60*91f16700Schasinglulu uint32_t baud; 61*91f16700Schasinglulu 62*91f16700Schasinglulu node_offset = fdt_path_offset(fdt, path_name); 63*91f16700Schasinglulu if (node_offset < 0) 64*91f16700Schasinglulu return; 65*91f16700Schasinglulu 66*91f16700Schasinglulu stdout_path = fdt_getprop(fdt, node_offset, prop_name, 67*91f16700Schasinglulu &stdout_path_len); 68*91f16700Schasinglulu if (stdout_path == NULL) 69*91f16700Schasinglulu return; 70*91f16700Schasinglulu 71*91f16700Schasinglulu /* 72*91f16700Schasinglulu * We expect something like: 73*91f16700Schasinglulu * "serial0:baudrate" 74*91f16700Schasinglulu */ 75*91f16700Schasinglulu if (strncmp("serial", stdout_path, 6) != 0) 76*91f16700Schasinglulu return; 77*91f16700Schasinglulu 78*91f16700Schasinglulu serial_char = stdout_path[6]; 79*91f16700Schasinglulu serial_no = serial_char - '0'; 80*91f16700Schasinglulu 81*91f16700Schasinglulu switch (serial_no) { 82*91f16700Schasinglulu case 0: 83*91f16700Schasinglulu uart_base = UART0_BASE; 84*91f16700Schasinglulu break; 85*91f16700Schasinglulu case 1: 86*91f16700Schasinglulu uart_base = UART1_BASE; 87*91f16700Schasinglulu break; 88*91f16700Schasinglulu case 2: 89*91f16700Schasinglulu uart_base = UART2_BASE; 90*91f16700Schasinglulu break; 91*91f16700Schasinglulu #ifdef UART3_BASE 92*91f16700Schasinglulu case 3: 93*91f16700Schasinglulu uart_base = UART3_BASE; 94*91f16700Schasinglulu break; 95*91f16700Schasinglulu #endif 96*91f16700Schasinglulu #ifdef UART4_BASE 97*91f16700Schasinglulu case 4: 98*91f16700Schasinglulu uart_base = UART4_BASE; 99*91f16700Schasinglulu break; 100*91f16700Schasinglulu #endif 101*91f16700Schasinglulu #ifdef UART5_BASE 102*91f16700Schasinglulu case 5: 103*91f16700Schasinglulu uart_base = UART5_BASE; 104*91f16700Schasinglulu break; 105*91f16700Schasinglulu #endif 106*91f16700Schasinglulu default: 107*91f16700Schasinglulu return; 108*91f16700Schasinglulu } 109*91f16700Schasinglulu 110*91f16700Schasinglulu rk_uart_base = uart_base; 111*91f16700Schasinglulu 112*91f16700Schasinglulu separator = strchr(stdout_path, ':'); 113*91f16700Schasinglulu if (!separator) 114*91f16700Schasinglulu return; 115*91f16700Schasinglulu 116*91f16700Schasinglulu baud = 0; 117*91f16700Schasinglulu baud_start = separator + 1; 118*91f16700Schasinglulu while (*baud_start != '\0') { 119*91f16700Schasinglulu /* 120*91f16700Schasinglulu * uart binding is <baud>{<parity>{<bits>{...}}} 121*91f16700Schasinglulu * So the baudrate either is the whole string, or 122*91f16700Schasinglulu * we end in the parity characters. 123*91f16700Schasinglulu */ 124*91f16700Schasinglulu if (*baud_start == 'n' || *baud_start == 'o' || 125*91f16700Schasinglulu *baud_start == 'e') 126*91f16700Schasinglulu break; 127*91f16700Schasinglulu 128*91f16700Schasinglulu baud = baud * 10 + (*baud_start - '0'); 129*91f16700Schasinglulu baud_start++; 130*91f16700Schasinglulu } 131*91f16700Schasinglulu 132*91f16700Schasinglulu rk_uart_baudrate = baud; 133*91f16700Schasinglulu } 134*91f16700Schasinglulu 135*91f16700Schasinglulu static int dt_process_fdt(u_register_t param_from_bl2) 136*91f16700Schasinglulu { 137*91f16700Schasinglulu void *fdt = plat_get_fdt(); 138*91f16700Schasinglulu int ret; 139*91f16700Schasinglulu 140*91f16700Schasinglulu ret = fdt_open_into((void *)param_from_bl2, fdt, FDT_BUFFER_SIZE); 141*91f16700Schasinglulu if (ret < 0) 142*91f16700Schasinglulu return ret; 143*91f16700Schasinglulu 144*91f16700Schasinglulu plat_rockchip_dt_process_fdt_uart(fdt); 145*91f16700Schasinglulu 146*91f16700Schasinglulu return 0; 147*91f16700Schasinglulu } 148*91f16700Schasinglulu #endif 149*91f16700Schasinglulu 150*91f16700Schasinglulu uint32_t rockchip_get_uart_base(void) 151*91f16700Schasinglulu { 152*91f16700Schasinglulu #if COREBOOT 153*91f16700Schasinglulu return coreboot_serial.baseaddr; 154*91f16700Schasinglulu #else 155*91f16700Schasinglulu return rk_uart_base; 156*91f16700Schasinglulu #endif 157*91f16700Schasinglulu } 158*91f16700Schasinglulu 159*91f16700Schasinglulu uint32_t rockchip_get_uart_baudrate(void) 160*91f16700Schasinglulu { 161*91f16700Schasinglulu #if COREBOOT 162*91f16700Schasinglulu return coreboot_serial.baud; 163*91f16700Schasinglulu #else 164*91f16700Schasinglulu return rk_uart_baudrate; 165*91f16700Schasinglulu #endif 166*91f16700Schasinglulu } 167*91f16700Schasinglulu 168*91f16700Schasinglulu uint32_t rockchip_get_uart_clock(void) 169*91f16700Schasinglulu { 170*91f16700Schasinglulu #if COREBOOT 171*91f16700Schasinglulu return coreboot_serial.input_hertz; 172*91f16700Schasinglulu #else 173*91f16700Schasinglulu return rk_uart_clock; 174*91f16700Schasinglulu #endif 175*91f16700Schasinglulu } 176*91f16700Schasinglulu 177*91f16700Schasinglulu struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void) 178*91f16700Schasinglulu { 179*91f16700Schasinglulu if (rst_gpio.index == UINT_MAX) 180*91f16700Schasinglulu return NULL; 181*91f16700Schasinglulu 182*91f16700Schasinglulu return &rst_gpio; 183*91f16700Schasinglulu } 184*91f16700Schasinglulu 185*91f16700Schasinglulu struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void) 186*91f16700Schasinglulu { 187*91f16700Schasinglulu if (poweroff_gpio.index == UINT_MAX) 188*91f16700Schasinglulu return NULL; 189*91f16700Schasinglulu 190*91f16700Schasinglulu return &poweroff_gpio; 191*91f16700Schasinglulu } 192*91f16700Schasinglulu 193*91f16700Schasinglulu struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count) 194*91f16700Schasinglulu { 195*91f16700Schasinglulu *count = suspend_gpio_cnt; 196*91f16700Schasinglulu 197*91f16700Schasinglulu return &suspend_gpio[0]; 198*91f16700Schasinglulu } 199*91f16700Schasinglulu 200*91f16700Schasinglulu struct bl_aux_rk_apio_info *plat_get_rockchip_suspend_apio(void) 201*91f16700Schasinglulu { 202*91f16700Schasinglulu return &suspend_apio; 203*91f16700Schasinglulu } 204*91f16700Schasinglulu 205*91f16700Schasinglulu static bool rk_aux_param_handler(struct bl_aux_param_header *param) 206*91f16700Schasinglulu { 207*91f16700Schasinglulu /* Store platform parameters for later processing if needed. */ 208*91f16700Schasinglulu switch (param->type) { 209*91f16700Schasinglulu case BL_AUX_PARAM_RK_RESET_GPIO: 210*91f16700Schasinglulu rst_gpio = ((struct bl_aux_param_gpio *)param)->gpio; 211*91f16700Schasinglulu return true; 212*91f16700Schasinglulu case BL_AUX_PARAM_RK_POWEROFF_GPIO: 213*91f16700Schasinglulu poweroff_gpio = ((struct bl_aux_param_gpio *)param)->gpio; 214*91f16700Schasinglulu return true; 215*91f16700Schasinglulu case BL_AUX_PARAM_RK_SUSPEND_GPIO: 216*91f16700Schasinglulu if (suspend_gpio_cnt >= ARRAY_SIZE(suspend_gpio)) { 217*91f16700Schasinglulu ERROR("Exceeded the supported suspend GPIO number.\n"); 218*91f16700Schasinglulu return true; 219*91f16700Schasinglulu } 220*91f16700Schasinglulu suspend_gpio[suspend_gpio_cnt++] = 221*91f16700Schasinglulu ((struct bl_aux_param_gpio *)param)->gpio; 222*91f16700Schasinglulu return true; 223*91f16700Schasinglulu case BL_AUX_PARAM_RK_SUSPEND_APIO: 224*91f16700Schasinglulu suspend_apio = ((struct bl_aux_param_rk_apio *)param)->apio; 225*91f16700Schasinglulu return true; 226*91f16700Schasinglulu } 227*91f16700Schasinglulu 228*91f16700Schasinglulu return false; 229*91f16700Schasinglulu } 230*91f16700Schasinglulu 231*91f16700Schasinglulu void params_early_setup(u_register_t plat_param_from_bl2) 232*91f16700Schasinglulu { 233*91f16700Schasinglulu int ret; 234*91f16700Schasinglulu 235*91f16700Schasinglulu /* 236*91f16700Schasinglulu * Test if this is a FDT passed as a platform-specific parameter 237*91f16700Schasinglulu * block. 238*91f16700Schasinglulu */ 239*91f16700Schasinglulu ret = dt_process_fdt(plat_param_from_bl2); 240*91f16700Schasinglulu if (!ret) { 241*91f16700Schasinglulu return; 242*91f16700Schasinglulu } else if (ret != -FDT_ERR_BADMAGIC) { 243*91f16700Schasinglulu /* 244*91f16700Schasinglulu * If we found an FDT but couldn't parse it (e.g. corrupt, not 245*91f16700Schasinglulu * enough space), return and don't attempt to parse the param 246*91f16700Schasinglulu * as something else, since we know that will also fail. All 247*91f16700Schasinglulu * we're doing is setting up UART, this doesn't need to be 248*91f16700Schasinglulu * fatal. 249*91f16700Schasinglulu */ 250*91f16700Schasinglulu WARN("%s: found FDT but could not parse: error %d\n", 251*91f16700Schasinglulu __func__, ret); 252*91f16700Schasinglulu return; 253*91f16700Schasinglulu } 254*91f16700Schasinglulu 255*91f16700Schasinglulu bl_aux_params_parse(plat_param_from_bl2, rk_aux_param_handler); 256*91f16700Schasinglulu } 257