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