params_setup.c 5.26 KB
Newer Older
1
/*
2
 * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
4
 * SPDX-License-Identifier: BSD-3-Clause
5
6
7
 */

#include <assert.h>
8
#include <errno.h>
9
#include <limits.h>
10
11
#include <string.h>

12
#include <lib/bl_aux_params/bl_aux_params.h>
13
14
15
16
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/console.h>
#include <drivers/gpio.h>
17
#include <libfdt.h>
18
19
20
21
#include <lib/coreboot.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>

22
23
24
#include <plat_params.h>
#include <plat_private.h>

25
26
static struct bl_aux_gpio_info rst_gpio = { .index = UINT_MAX } ;
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
35
36
{
	return -ENODEV;
}
#else
37
38
39
static uint32_t rk_uart_base = PLAT_RK_UART_BASE;
static uint32_t rk_uart_baudrate = PLAT_RK_UART_BAUDRATE;
static uint32_t rk_uart_clock = PLAT_RK_UART_CLOCK;
40
41
#define FDT_BUFFER_SIZE 0x20000
static uint8_t fdt_buffer[FDT_BUFFER_SIZE];
42
43
44
45
46
47

void *plat_get_fdt(void)
{
	return &fdt_buffer[0];
}

48
49
50
51
52
53
54
static void plat_rockchip_dt_process_fdt_uart(void *fdt)
{
	const char *path_name = "/chosen";
	const char *prop_name = "stdout-path";
	int node_offset;
	int stdout_path_len;
	const char *stdout_path;
55
56
	const char *separator;
	const char *baud_start;
57
58
59
	char serial_char;
	int serial_no;
	uint32_t uart_base;
60
	uint32_t baud;
61
62
63
64
65
66
67
68
69
70
71
72

	node_offset = fdt_path_offset(fdt, path_name);
	if (node_offset < 0)
		return;

	stdout_path = fdt_getprop(fdt, node_offset, prop_name,
				  &stdout_path_len);
	if (stdout_path == NULL)
		return;

	/*
	 * We expect something like:
73
	 *   "serial0:baudrate"
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
	 */
	if (strncmp("serial", stdout_path, 6) != 0)
		return;

	serial_char = stdout_path[6];
	serial_no = serial_char - '0';

	switch (serial_no) {
	case 0:
		uart_base = UART0_BASE;
		break;
	case 1:
		uart_base = UART1_BASE;
		break;
	case 2:
		uart_base = UART2_BASE;
		break;
#ifdef UART3_BASE
	case 3:
		uart_base = UART3_BASE;
		break;
#endif
#ifdef UART4_BASE
	case 4:
		uart_base = UART4_BASE;
		break;
100
101
102
103
104
#endif
#ifdef UART5_BASE
	case 5:
		uart_base = UART5_BASE;
		break;
105
106
107
108
109
110
#endif
	default:
		return;
	}

	rk_uart_base = uart_base;
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

	separator = strchr(stdout_path, ':');
	if (!separator)
		return;

	baud = 0;
	baud_start = separator + 1;
	while (*baud_start != '\0') {
		/*
		 * uart binding is <baud>{<parity>{<bits>{...}}}
		 * So the baudrate either is the whole string, or
		 * we end in the parity characters.
		 */
		if (*baud_start == 'n' || *baud_start == 'o' ||
		    *baud_start == 'e')
			break;

		baud = baud * 10 + (*baud_start - '0');
		baud_start++;
	}

	rk_uart_baudrate = baud;
133
134
}

135
static int dt_process_fdt(u_register_t param_from_bl2)
136
137
138
139
{
	void *fdt = plat_get_fdt();
	int ret;

140
	ret = fdt_open_into((void *)param_from_bl2, fdt, FDT_BUFFER_SIZE);
141
142
143
	if (ret < 0)
		return ret;

144
145
	plat_rockchip_dt_process_fdt_uart(fdt);

146
147
148
149
	return 0;
}
#endif

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
uint32_t rockchip_get_uart_base(void)
{
#if COREBOOT
	return coreboot_serial.baseaddr;
#else
	return rk_uart_base;
#endif
}

uint32_t rockchip_get_uart_baudrate(void)
{
#if COREBOOT
	return coreboot_serial.baud;
#else
	return rk_uart_baudrate;
#endif
}

uint32_t rockchip_get_uart_clock(void)
{
#if COREBOOT
	return coreboot_serial.input_hertz;
#else
	return rk_uart_clock;
#endif
}

177
struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void)
178
{
179
180
181
	if (rst_gpio.index == UINT_MAX)
		return NULL;

182
	return &rst_gpio;
183
184
}

185
struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void)
186
{
187
188
189
	if (poweroff_gpio.index == UINT_MAX)
		return NULL;

190
	return &poweroff_gpio;
191
192
}

193
struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count)
194
195
196
197
198
199
{
	*count = suspend_gpio_cnt;

	return &suspend_gpio[0];
}

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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
	/* Store platform parameters for later processing if needed. */
	switch (param->type) {
	case BL_AUX_PARAM_RK_RESET_GPIO:
		rst_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
		return true;
	case BL_AUX_PARAM_RK_POWEROFF_GPIO:
		poweroff_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
		return true;
	case BL_AUX_PARAM_RK_SUSPEND_GPIO:
		if (suspend_gpio_cnt >= ARRAY_SIZE(suspend_gpio)) {
			ERROR("Exceeded the supported suspend GPIO number.\n");
			return true;
		}
		suspend_gpio[suspend_gpio_cnt++] =
			((struct bl_aux_param_gpio *)param)->gpio;
		return true;
	case BL_AUX_PARAM_RK_SUSPEND_APIO:
		suspend_apio = ((struct bl_aux_param_rk_apio *)param)->apio;
		return true;
	}
227

228
229
230
231
232
	return false;
}

void params_early_setup(u_register_t plat_param_from_bl2)
{
233
234
	int ret;

235
236
237
238
	/*
	 * Test if this is a FDT passed as a platform-specific parameter
	 * block.
	 */
239
240
241
242
243
244
245
246
247
248
249
250
251
	ret = dt_process_fdt(plat_param_from_bl2);
	if (!ret) {
		return;
	} else if (ret != -FDT_ERR_BADMAGIC) {
		/*
		 * If we found an FDT but couldn't parse it (e.g. corrupt, not
		 * enough space), return and don't attempt to parse the param
		 * as something else, since we know that will also fail. All
		 * we're doing is setting up UART, this doesn't need to be
		 * fatal.
		 */
		WARN("%s: found FDT but could not parse: error %d\n",
		     __func__, ret);
252
		return;
253
	}
254

255
	bl_aux_params_parse(plat_param_from_bl2, rk_aux_param_handler);
256
}