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