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