summaryrefslogtreecommitdiff
path: root/common/fdt_decode.c
blob: d149bf2145b0be2711b7da7df786bbf6aa61056b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * Copyright (c) 2011 The Chromium OS Authors.
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
#include <serial.h>
#include <libfdt.h>
#include <fdt_support.h>
#include <fdt_decode.h>

/**
 * Look in the FDT for an alias with the given name and return its node.
 *
 * @param blob	FDT blob
 * @param name	alias name to look up
 * @return node offset if found, or an error code < 0 otherwise
 */
static int find_alias_node(const void *blob, const char *name)
{
	const char *path;
	int alias_node;

	alias_node = fdt_path_offset(blob, "/aliases");
	if (alias_node < 0)
		return alias_node;
	path = fdt_getprop(blob, alias_node, name, NULL);
	if (!path)
		return -FDT_ERR_NOTFOUND;
	return fdt_path_offset(blob, path);
}

/**
 * Look up an address property in a node and return it as an address.
 * The property must hold exactly one address with no trailing data.
 * This is only tested on 32-bit machines.
 *
 * @param blob	FDT blob
 * @param node	node to examine
 * @param prop_name	name of property to find
 * @return address, if found, or ADDR_T_NONE if not
 */
static addr_t get_addr(const void *blob, int node, const char *prop_name)
{
	const addr_t *cell;
	int len;

	cell = fdt_getprop(blob, node, prop_name, &len);
	if (cell && len != sizeof(addr_t))
		return addr_to_cpu(*cell);
	return ADDR_T_NONE;
}

/**
 * Look up a 32-bit integer property in a node and return it. The property
 * must have at least 4 bytes of data. The value of the first cell is
 * returned.
 *
 * @param blob	FDT blob
 * @param node	node to examine
 * @param prop_name	name of property to find
 * @param default_val	default value to return if the property is not found
 * @return integer value, if found, or default_val if not
 */
static s32 get_int(const void *blob, int node, const char *prop_name,
		s32 default_val)
{
	const s32 *cell;
	int len;

	cell = fdt_getprop(blob, node, prop_name, &len);
	if (cell && len >= sizeof(s32))
		return fdt32_to_cpu(cell[0]);
	return default_val;
}

/**
 * Checks whether a node is enabled.
 * This looks for a 'status' property. If this exists, then returns 1 if
 * the status is 'ok' and 0 otherwise. If there is no status property,
 * it returns the default value.
 *
 * @param blob	FDT blob
 * @param node	node to examine
 * @param default_val	default value to return if no 'status' property exists
 * @return integer value 0/1, if found, or default_val if not
 */
static int get_is_enabled(const void *blob, int node, int default_val)
{
	const char *cell;

	cell = fdt_getprop(blob, node, "status", NULL);
	if (cell)
		return 0 == strcmp(cell, "ok");
	return default_val;
}

void fdt_decode_uart_calc_divisor(struct fdt_uart *uart)
{
	if (uart->multiplier && uart->baudrate)
		uart->divisor = (uart->clock_freq +
				(uart->baudrate * (uart->multiplier / 2))) /
			(uart->multiplier * uart->baudrate);
}

int fdt_decode_uart_console(const void *blob, struct fdt_uart *uart,
		int default_baudrate)
{
	int node, i;

	node = find_alias_node(blob, "console");
	if (node < 0)
		return node;
	uart->reg = get_addr(blob, node, "reg");
	uart->id = get_int(blob, node, "id", 0);
	uart->reg_shift = get_int(blob, node, "reg_shift", 2);
	uart->baudrate = get_int(blob, node, "baudrate", default_baudrate);
	uart->clock_freq = get_int(blob, node, "clock-frequency", -1);
	uart->multiplier = get_int(blob, node, "multiplier", 16);
	uart->divisor = get_int(blob, node, "divisor", -1);
	uart->enabled = get_is_enabled(blob, node, 1);
	uart->interrupt = get_int(blob, node, "interrupts", -1);
	uart->silent = get_int(blob, node, "silent", 0);

	/* Calculate divisor if required */
	if (uart->divisor == -1)
		fdt_decode_uart_calc_divisor(uart);
	return 0;
}