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