Commit 370b6c5c4d764192399a220095a2dd1054314147
1 parent
0eb2acee39
Exists in
master
and in
50 other branches
sandbox: Correct data sizes and printf() strings in fdtdec.c
There are a few wwrnings in this file when building for sandbox. Addresses coming from the device tree need to be treated as ulong as elsewhere in U-Boot and we must use map_sysmem() to convert to a pointer when needed. Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Hung-ying Tyan <tyanh@chromium.org>
Showing 1 changed file with 4 additions and 4 deletions Inline Diff
lib/fdtdec.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2011 The Chromium OS Authors. | 2 | * Copyright (c) 2011 The Chromium OS Authors. |
3 | * SPDX-License-Identifier: GPL-2.0+ | 3 | * SPDX-License-Identifier: GPL-2.0+ |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <common.h> | 6 | #include <common.h> |
7 | #include <serial.h> | 7 | #include <serial.h> |
8 | #include <libfdt.h> | 8 | #include <libfdt.h> |
9 | #include <fdtdec.h> | 9 | #include <fdtdec.h> |
10 | 10 | ||
11 | #include <asm/gpio.h> | 11 | #include <asm/gpio.h> |
12 | 12 | ||
13 | DECLARE_GLOBAL_DATA_PTR; | 13 | DECLARE_GLOBAL_DATA_PTR; |
14 | 14 | ||
15 | /* | 15 | /* |
16 | * Here are the type we know about. One day we might allow drivers to | 16 | * Here are the type we know about. One day we might allow drivers to |
17 | * register. For now we just put them here. The COMPAT macro allows us to | 17 | * register. For now we just put them here. The COMPAT macro allows us to |
18 | * turn this into a sparse list later, and keeps the ID with the name. | 18 | * turn this into a sparse list later, and keeps the ID with the name. |
19 | */ | 19 | */ |
20 | #define COMPAT(id, name) name | 20 | #define COMPAT(id, name) name |
21 | static const char * const compat_names[COMPAT_COUNT] = { | 21 | static const char * const compat_names[COMPAT_COUNT] = { |
22 | COMPAT(UNKNOWN, "<none>"), | 22 | COMPAT(UNKNOWN, "<none>"), |
23 | COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"), | 23 | COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"), |
24 | COMPAT(NVIDIA_TEGRA30_USB, "nvidia,tegra30-ehci"), | 24 | COMPAT(NVIDIA_TEGRA30_USB, "nvidia,tegra30-ehci"), |
25 | COMPAT(NVIDIA_TEGRA114_USB, "nvidia,tegra114-ehci"), | 25 | COMPAT(NVIDIA_TEGRA114_USB, "nvidia,tegra114-ehci"), |
26 | COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"), | 26 | COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"), |
27 | COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"), | 27 | COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"), |
28 | COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"), | 28 | COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"), |
29 | COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"), | 29 | COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"), |
30 | COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"), | 30 | COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"), |
31 | COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"), | 31 | COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"), |
32 | COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"), | 32 | COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"), |
33 | COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), | 33 | COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"), |
34 | COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"), | 34 | COMPAT(NVIDIA_TEGRA20_DC, "nvidia,tegra20-dc"), |
35 | COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"), | 35 | COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"), |
36 | COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"), | 36 | COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"), |
37 | COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"), | 37 | COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"), |
38 | COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"), | 38 | COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"), |
39 | COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"), | 39 | COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"), |
40 | COMPAT(SMSC_LAN9215, "smsc,lan9215"), | 40 | COMPAT(SMSC_LAN9215, "smsc,lan9215"), |
41 | COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"), | 41 | COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"), |
42 | COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"), | 42 | COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"), |
43 | COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"), | 43 | COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"), |
44 | COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"), | 44 | COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"), |
45 | COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"), | 45 | COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"), |
46 | COMPAT(GOOGLE_CROS_EC, "google,cros-ec"), | 46 | COMPAT(GOOGLE_CROS_EC, "google,cros-ec"), |
47 | COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"), | 47 | COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"), |
48 | COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"), | 48 | COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"), |
49 | COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"), | 49 | COMPAT(SAMSUNG_EXYNOS5_XHCI, "samsung,exynos5250-xhci"), |
50 | COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), | 50 | COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), |
51 | COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"), | 51 | COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"), |
52 | COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), | 52 | COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), |
53 | COMPAT(SAMSUNG_EXYNOS_FIMD, "samsung,exynos-fimd"), | 53 | COMPAT(SAMSUNG_EXYNOS_FIMD, "samsung,exynos-fimd"), |
54 | COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"), | 54 | COMPAT(SAMSUNG_EXYNOS5_DP, "samsung,exynos5-dp"), |
55 | COMPAT(SAMSUNG_EXYNOS5_DWMMC, "samsung,exynos5250-dwmmc"), | 55 | COMPAT(SAMSUNG_EXYNOS5_DWMMC, "samsung,exynos5250-dwmmc"), |
56 | COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"), | 56 | COMPAT(SAMSUNG_EXYNOS_SERIAL, "samsung,exynos4210-uart"), |
57 | COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), | 57 | COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), |
58 | COMPAT(GENERIC_SPI_FLASH, "spi-flash"), | 58 | COMPAT(GENERIC_SPI_FLASH, "spi-flash"), |
59 | COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), | 59 | COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), |
60 | COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"), | 60 | COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"), |
61 | COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"), | 61 | COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"), |
62 | COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), | 62 | COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), |
63 | }; | 63 | }; |
64 | 64 | ||
65 | const char *fdtdec_get_compatible(enum fdt_compat_id id) | 65 | const char *fdtdec_get_compatible(enum fdt_compat_id id) |
66 | { | 66 | { |
67 | /* We allow reading of the 'unknown' ID for testing purposes */ | 67 | /* We allow reading of the 'unknown' ID for testing purposes */ |
68 | assert(id >= 0 && id < COMPAT_COUNT); | 68 | assert(id >= 0 && id < COMPAT_COUNT); |
69 | return compat_names[id]; | 69 | return compat_names[id]; |
70 | } | 70 | } |
71 | 71 | ||
72 | fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, | 72 | fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, |
73 | const char *prop_name, fdt_size_t *sizep) | 73 | const char *prop_name, fdt_size_t *sizep) |
74 | { | 74 | { |
75 | const fdt_addr_t *cell; | 75 | const fdt_addr_t *cell; |
76 | int len; | 76 | int len; |
77 | 77 | ||
78 | debug("%s: %s: ", __func__, prop_name); | 78 | debug("%s: %s: ", __func__, prop_name); |
79 | cell = fdt_getprop(blob, node, prop_name, &len); | 79 | cell = fdt_getprop(blob, node, prop_name, &len); |
80 | if (cell && ((!sizep && len == sizeof(fdt_addr_t)) || | 80 | if (cell && ((!sizep && len == sizeof(fdt_addr_t)) || |
81 | len == sizeof(fdt_addr_t) * 2)) { | 81 | len == sizeof(fdt_addr_t) * 2)) { |
82 | fdt_addr_t addr = fdt_addr_to_cpu(*cell); | 82 | fdt_addr_t addr = fdt_addr_to_cpu(*cell); |
83 | if (sizep) { | 83 | if (sizep) { |
84 | const fdt_size_t *size; | 84 | const fdt_size_t *size; |
85 | 85 | ||
86 | size = (fdt_size_t *)((char *)cell + | 86 | size = (fdt_size_t *)((char *)cell + |
87 | sizeof(fdt_addr_t)); | 87 | sizeof(fdt_addr_t)); |
88 | *sizep = fdt_size_to_cpu(*size); | 88 | *sizep = fdt_size_to_cpu(*size); |
89 | debug("addr=%p, size=%p\n", (void *)addr, | 89 | debug("addr=%08lx, size=%08x\n", |
90 | (void *)*sizep); | 90 | (ulong)addr, *sizep); |
91 | } else { | 91 | } else { |
92 | debug("%p\n", (void *)addr); | 92 | debug("%08lx\n", (ulong)addr); |
93 | } | 93 | } |
94 | return addr; | 94 | return addr; |
95 | } | 95 | } |
96 | debug("(not found)\n"); | 96 | debug("(not found)\n"); |
97 | return FDT_ADDR_T_NONE; | 97 | return FDT_ADDR_T_NONE; |
98 | } | 98 | } |
99 | 99 | ||
100 | fdt_addr_t fdtdec_get_addr(const void *blob, int node, | 100 | fdt_addr_t fdtdec_get_addr(const void *blob, int node, |
101 | const char *prop_name) | 101 | const char *prop_name) |
102 | { | 102 | { |
103 | return fdtdec_get_addr_size(blob, node, prop_name, NULL); | 103 | return fdtdec_get_addr_size(blob, node, prop_name, NULL); |
104 | } | 104 | } |
105 | 105 | ||
106 | s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, | 106 | s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, |
107 | s32 default_val) | 107 | s32 default_val) |
108 | { | 108 | { |
109 | const s32 *cell; | 109 | const s32 *cell; |
110 | int len; | 110 | int len; |
111 | 111 | ||
112 | debug("%s: %s: ", __func__, prop_name); | 112 | debug("%s: %s: ", __func__, prop_name); |
113 | cell = fdt_getprop(blob, node, prop_name, &len); | 113 | cell = fdt_getprop(blob, node, prop_name, &len); |
114 | if (cell && len >= sizeof(s32)) { | 114 | if (cell && len >= sizeof(s32)) { |
115 | s32 val = fdt32_to_cpu(cell[0]); | 115 | s32 val = fdt32_to_cpu(cell[0]); |
116 | 116 | ||
117 | debug("%#x (%d)\n", val, val); | 117 | debug("%#x (%d)\n", val, val); |
118 | return val; | 118 | return val; |
119 | } | 119 | } |
120 | debug("(not found)\n"); | 120 | debug("(not found)\n"); |
121 | return default_val; | 121 | return default_val; |
122 | } | 122 | } |
123 | 123 | ||
124 | uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, | 124 | uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, |
125 | uint64_t default_val) | 125 | uint64_t default_val) |
126 | { | 126 | { |
127 | const uint64_t *cell64; | 127 | const uint64_t *cell64; |
128 | int length; | 128 | int length; |
129 | 129 | ||
130 | cell64 = fdt_getprop(blob, node, prop_name, &length); | 130 | cell64 = fdt_getprop(blob, node, prop_name, &length); |
131 | if (!cell64 || length < sizeof(*cell64)) | 131 | if (!cell64 || length < sizeof(*cell64)) |
132 | return default_val; | 132 | return default_val; |
133 | 133 | ||
134 | return fdt64_to_cpu(*cell64); | 134 | return fdt64_to_cpu(*cell64); |
135 | } | 135 | } |
136 | 136 | ||
137 | int fdtdec_get_is_enabled(const void *blob, int node) | 137 | int fdtdec_get_is_enabled(const void *blob, int node) |
138 | { | 138 | { |
139 | const char *cell; | 139 | const char *cell; |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * It should say "okay", so only allow that. Some fdts use "ok" but | 142 | * It should say "okay", so only allow that. Some fdts use "ok" but |
143 | * this is a bug. Please fix your device tree source file. See here | 143 | * this is a bug. Please fix your device tree source file. See here |
144 | * for discussion: | 144 | * for discussion: |
145 | * | 145 | * |
146 | * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html | 146 | * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html |
147 | */ | 147 | */ |
148 | cell = fdt_getprop(blob, node, "status", NULL); | 148 | cell = fdt_getprop(blob, node, "status", NULL); |
149 | if (cell) | 149 | if (cell) |
150 | return 0 == strcmp(cell, "okay"); | 150 | return 0 == strcmp(cell, "okay"); |
151 | return 1; | 151 | return 1; |
152 | } | 152 | } |
153 | 153 | ||
154 | enum fdt_compat_id fdtdec_lookup(const void *blob, int node) | 154 | enum fdt_compat_id fdtdec_lookup(const void *blob, int node) |
155 | { | 155 | { |
156 | enum fdt_compat_id id; | 156 | enum fdt_compat_id id; |
157 | 157 | ||
158 | /* Search our drivers */ | 158 | /* Search our drivers */ |
159 | for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++) | 159 | for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++) |
160 | if (0 == fdt_node_check_compatible(blob, node, | 160 | if (0 == fdt_node_check_compatible(blob, node, |
161 | compat_names[id])) | 161 | compat_names[id])) |
162 | return id; | 162 | return id; |
163 | return COMPAT_UNKNOWN; | 163 | return COMPAT_UNKNOWN; |
164 | } | 164 | } |
165 | 165 | ||
166 | int fdtdec_next_compatible(const void *blob, int node, | 166 | int fdtdec_next_compatible(const void *blob, int node, |
167 | enum fdt_compat_id id) | 167 | enum fdt_compat_id id) |
168 | { | 168 | { |
169 | return fdt_node_offset_by_compatible(blob, node, compat_names[id]); | 169 | return fdt_node_offset_by_compatible(blob, node, compat_names[id]); |
170 | } | 170 | } |
171 | 171 | ||
172 | int fdtdec_next_compatible_subnode(const void *blob, int node, | 172 | int fdtdec_next_compatible_subnode(const void *blob, int node, |
173 | enum fdt_compat_id id, int *depthp) | 173 | enum fdt_compat_id id, int *depthp) |
174 | { | 174 | { |
175 | do { | 175 | do { |
176 | node = fdt_next_node(blob, node, depthp); | 176 | node = fdt_next_node(blob, node, depthp); |
177 | } while (*depthp > 1); | 177 | } while (*depthp > 1); |
178 | 178 | ||
179 | /* If this is a direct subnode, and compatible, return it */ | 179 | /* If this is a direct subnode, and compatible, return it */ |
180 | if (*depthp == 1 && 0 == fdt_node_check_compatible( | 180 | if (*depthp == 1 && 0 == fdt_node_check_compatible( |
181 | blob, node, compat_names[id])) | 181 | blob, node, compat_names[id])) |
182 | return node; | 182 | return node; |
183 | 183 | ||
184 | return -FDT_ERR_NOTFOUND; | 184 | return -FDT_ERR_NOTFOUND; |
185 | } | 185 | } |
186 | 186 | ||
187 | int fdtdec_next_alias(const void *blob, const char *name, | 187 | int fdtdec_next_alias(const void *blob, const char *name, |
188 | enum fdt_compat_id id, int *upto) | 188 | enum fdt_compat_id id, int *upto) |
189 | { | 189 | { |
190 | #define MAX_STR_LEN 20 | 190 | #define MAX_STR_LEN 20 |
191 | char str[MAX_STR_LEN + 20]; | 191 | char str[MAX_STR_LEN + 20]; |
192 | int node, err; | 192 | int node, err; |
193 | 193 | ||
194 | /* snprintf() is not available */ | 194 | /* snprintf() is not available */ |
195 | assert(strlen(name) < MAX_STR_LEN); | 195 | assert(strlen(name) < MAX_STR_LEN); |
196 | sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto); | 196 | sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto); |
197 | node = fdt_path_offset(blob, str); | 197 | node = fdt_path_offset(blob, str); |
198 | if (node < 0) | 198 | if (node < 0) |
199 | return node; | 199 | return node; |
200 | err = fdt_node_check_compatible(blob, node, compat_names[id]); | 200 | err = fdt_node_check_compatible(blob, node, compat_names[id]); |
201 | if (err < 0) | 201 | if (err < 0) |
202 | return err; | 202 | return err; |
203 | if (err) | 203 | if (err) |
204 | return -FDT_ERR_NOTFOUND; | 204 | return -FDT_ERR_NOTFOUND; |
205 | (*upto)++; | 205 | (*upto)++; |
206 | return node; | 206 | return node; |
207 | } | 207 | } |
208 | 208 | ||
209 | int fdtdec_find_aliases_for_id(const void *blob, const char *name, | 209 | int fdtdec_find_aliases_for_id(const void *blob, const char *name, |
210 | enum fdt_compat_id id, int *node_list, int maxcount) | 210 | enum fdt_compat_id id, int *node_list, int maxcount) |
211 | { | 211 | { |
212 | memset(node_list, '\0', sizeof(*node_list) * maxcount); | 212 | memset(node_list, '\0', sizeof(*node_list) * maxcount); |
213 | 213 | ||
214 | return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount); | 214 | return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount); |
215 | } | 215 | } |
216 | 216 | ||
217 | /* TODO: Can we tighten this code up a little? */ | 217 | /* TODO: Can we tighten this code up a little? */ |
218 | int fdtdec_add_aliases_for_id(const void *blob, const char *name, | 218 | int fdtdec_add_aliases_for_id(const void *blob, const char *name, |
219 | enum fdt_compat_id id, int *node_list, int maxcount) | 219 | enum fdt_compat_id id, int *node_list, int maxcount) |
220 | { | 220 | { |
221 | int name_len = strlen(name); | 221 | int name_len = strlen(name); |
222 | int nodes[maxcount]; | 222 | int nodes[maxcount]; |
223 | int num_found = 0; | 223 | int num_found = 0; |
224 | int offset, node; | 224 | int offset, node; |
225 | int alias_node; | 225 | int alias_node; |
226 | int count; | 226 | int count; |
227 | int i, j; | 227 | int i, j; |
228 | 228 | ||
229 | /* find the alias node if present */ | 229 | /* find the alias node if present */ |
230 | alias_node = fdt_path_offset(blob, "/aliases"); | 230 | alias_node = fdt_path_offset(blob, "/aliases"); |
231 | 231 | ||
232 | /* | 232 | /* |
233 | * start with nothing, and we can assume that the root node can't | 233 | * start with nothing, and we can assume that the root node can't |
234 | * match | 234 | * match |
235 | */ | 235 | */ |
236 | memset(nodes, '\0', sizeof(nodes)); | 236 | memset(nodes, '\0', sizeof(nodes)); |
237 | 237 | ||
238 | /* First find all the compatible nodes */ | 238 | /* First find all the compatible nodes */ |
239 | for (node = count = 0; node >= 0 && count < maxcount;) { | 239 | for (node = count = 0; node >= 0 && count < maxcount;) { |
240 | node = fdtdec_next_compatible(blob, node, id); | 240 | node = fdtdec_next_compatible(blob, node, id); |
241 | if (node >= 0) | 241 | if (node >= 0) |
242 | nodes[count++] = node; | 242 | nodes[count++] = node; |
243 | } | 243 | } |
244 | if (node >= 0) | 244 | if (node >= 0) |
245 | debug("%s: warning: maxcount exceeded with alias '%s'\n", | 245 | debug("%s: warning: maxcount exceeded with alias '%s'\n", |
246 | __func__, name); | 246 | __func__, name); |
247 | 247 | ||
248 | /* Now find all the aliases */ | 248 | /* Now find all the aliases */ |
249 | for (offset = fdt_first_property_offset(blob, alias_node); | 249 | for (offset = fdt_first_property_offset(blob, alias_node); |
250 | offset > 0; | 250 | offset > 0; |
251 | offset = fdt_next_property_offset(blob, offset)) { | 251 | offset = fdt_next_property_offset(blob, offset)) { |
252 | const struct fdt_property *prop; | 252 | const struct fdt_property *prop; |
253 | const char *path; | 253 | const char *path; |
254 | int number; | 254 | int number; |
255 | int found; | 255 | int found; |
256 | 256 | ||
257 | node = 0; | 257 | node = 0; |
258 | prop = fdt_get_property_by_offset(blob, offset, NULL); | 258 | prop = fdt_get_property_by_offset(blob, offset, NULL); |
259 | path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); | 259 | path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); |
260 | if (prop->len && 0 == strncmp(path, name, name_len)) | 260 | if (prop->len && 0 == strncmp(path, name, name_len)) |
261 | node = fdt_path_offset(blob, prop->data); | 261 | node = fdt_path_offset(blob, prop->data); |
262 | if (node <= 0) | 262 | if (node <= 0) |
263 | continue; | 263 | continue; |
264 | 264 | ||
265 | /* Get the alias number */ | 265 | /* Get the alias number */ |
266 | number = simple_strtoul(path + name_len, NULL, 10); | 266 | number = simple_strtoul(path + name_len, NULL, 10); |
267 | if (number < 0 || number >= maxcount) { | 267 | if (number < 0 || number >= maxcount) { |
268 | debug("%s: warning: alias '%s' is out of range\n", | 268 | debug("%s: warning: alias '%s' is out of range\n", |
269 | __func__, path); | 269 | __func__, path); |
270 | continue; | 270 | continue; |
271 | } | 271 | } |
272 | 272 | ||
273 | /* Make sure the node we found is actually in our list! */ | 273 | /* Make sure the node we found is actually in our list! */ |
274 | found = -1; | 274 | found = -1; |
275 | for (j = 0; j < count; j++) | 275 | for (j = 0; j < count; j++) |
276 | if (nodes[j] == node) { | 276 | if (nodes[j] == node) { |
277 | found = j; | 277 | found = j; |
278 | break; | 278 | break; |
279 | } | 279 | } |
280 | 280 | ||
281 | if (found == -1) { | 281 | if (found == -1) { |
282 | debug("%s: warning: alias '%s' points to a node " | 282 | debug("%s: warning: alias '%s' points to a node " |
283 | "'%s' that is missing or is not compatible " | 283 | "'%s' that is missing or is not compatible " |
284 | " with '%s'\n", __func__, path, | 284 | " with '%s'\n", __func__, path, |
285 | fdt_get_name(blob, node, NULL), | 285 | fdt_get_name(blob, node, NULL), |
286 | compat_names[id]); | 286 | compat_names[id]); |
287 | continue; | 287 | continue; |
288 | } | 288 | } |
289 | 289 | ||
290 | /* | 290 | /* |
291 | * Add this node to our list in the right place, and mark | 291 | * Add this node to our list in the right place, and mark |
292 | * it as done. | 292 | * it as done. |
293 | */ | 293 | */ |
294 | if (fdtdec_get_is_enabled(blob, node)) { | 294 | if (fdtdec_get_is_enabled(blob, node)) { |
295 | if (node_list[number]) { | 295 | if (node_list[number]) { |
296 | debug("%s: warning: alias '%s' requires that " | 296 | debug("%s: warning: alias '%s' requires that " |
297 | "a node be placed in the list in a " | 297 | "a node be placed in the list in a " |
298 | "position which is already filled by " | 298 | "position which is already filled by " |
299 | "node '%s'\n", __func__, path, | 299 | "node '%s'\n", __func__, path, |
300 | fdt_get_name(blob, node, NULL)); | 300 | fdt_get_name(blob, node, NULL)); |
301 | continue; | 301 | continue; |
302 | } | 302 | } |
303 | node_list[number] = node; | 303 | node_list[number] = node; |
304 | if (number >= num_found) | 304 | if (number >= num_found) |
305 | num_found = number + 1; | 305 | num_found = number + 1; |
306 | } | 306 | } |
307 | nodes[found] = 0; | 307 | nodes[found] = 0; |
308 | } | 308 | } |
309 | 309 | ||
310 | /* Add any nodes not mentioned by an alias */ | 310 | /* Add any nodes not mentioned by an alias */ |
311 | for (i = j = 0; i < maxcount; i++) { | 311 | for (i = j = 0; i < maxcount; i++) { |
312 | if (!node_list[i]) { | 312 | if (!node_list[i]) { |
313 | for (; j < maxcount; j++) | 313 | for (; j < maxcount; j++) |
314 | if (nodes[j] && | 314 | if (nodes[j] && |
315 | fdtdec_get_is_enabled(blob, nodes[j])) | 315 | fdtdec_get_is_enabled(blob, nodes[j])) |
316 | break; | 316 | break; |
317 | 317 | ||
318 | /* Have we run out of nodes to add? */ | 318 | /* Have we run out of nodes to add? */ |
319 | if (j == maxcount) | 319 | if (j == maxcount) |
320 | break; | 320 | break; |
321 | 321 | ||
322 | assert(!node_list[i]); | 322 | assert(!node_list[i]); |
323 | node_list[i] = nodes[j++]; | 323 | node_list[i] = nodes[j++]; |
324 | if (i >= num_found) | 324 | if (i >= num_found) |
325 | num_found = i + 1; | 325 | num_found = i + 1; |
326 | } | 326 | } |
327 | } | 327 | } |
328 | 328 | ||
329 | return num_found; | 329 | return num_found; |
330 | } | 330 | } |
331 | 331 | ||
332 | int fdtdec_check_fdt(void) | 332 | int fdtdec_check_fdt(void) |
333 | { | 333 | { |
334 | /* | 334 | /* |
335 | * We must have an FDT, but we cannot panic() yet since the console | 335 | * We must have an FDT, but we cannot panic() yet since the console |
336 | * is not ready. So for now, just assert(). Boards which need an early | 336 | * is not ready. So for now, just assert(). Boards which need an early |
337 | * FDT (prior to console ready) will need to make their own | 337 | * FDT (prior to console ready) will need to make their own |
338 | * arrangements and do their own checks. | 338 | * arrangements and do their own checks. |
339 | */ | 339 | */ |
340 | assert(!fdtdec_prepare_fdt()); | 340 | assert(!fdtdec_prepare_fdt()); |
341 | return 0; | 341 | return 0; |
342 | } | 342 | } |
343 | 343 | ||
344 | /* | 344 | /* |
345 | * This function is a little odd in that it accesses global data. At some | 345 | * This function is a little odd in that it accesses global data. At some |
346 | * point if the architecture board.c files merge this will make more sense. | 346 | * point if the architecture board.c files merge this will make more sense. |
347 | * Even now, it is common code. | 347 | * Even now, it is common code. |
348 | */ | 348 | */ |
349 | int fdtdec_prepare_fdt(void) | 349 | int fdtdec_prepare_fdt(void) |
350 | { | 350 | { |
351 | if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) || | 351 | if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) || |
352 | fdt_check_header(gd->fdt_blob)) { | 352 | fdt_check_header(gd->fdt_blob)) { |
353 | printf("No valid FDT found - please append one to U-Boot " | 353 | printf("No valid FDT found - please append one to U-Boot " |
354 | "binary, use u-boot-dtb.bin or define " | 354 | "binary, use u-boot-dtb.bin or define " |
355 | "CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n"); | 355 | "CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n"); |
356 | return -1; | 356 | return -1; |
357 | } | 357 | } |
358 | return 0; | 358 | return 0; |
359 | } | 359 | } |
360 | 360 | ||
361 | int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) | 361 | int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name) |
362 | { | 362 | { |
363 | const u32 *phandle; | 363 | const u32 *phandle; |
364 | int lookup; | 364 | int lookup; |
365 | 365 | ||
366 | debug("%s: %s\n", __func__, prop_name); | 366 | debug("%s: %s\n", __func__, prop_name); |
367 | phandle = fdt_getprop(blob, node, prop_name, NULL); | 367 | phandle = fdt_getprop(blob, node, prop_name, NULL); |
368 | if (!phandle) | 368 | if (!phandle) |
369 | return -FDT_ERR_NOTFOUND; | 369 | return -FDT_ERR_NOTFOUND; |
370 | 370 | ||
371 | lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle)); | 371 | lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle)); |
372 | return lookup; | 372 | return lookup; |
373 | } | 373 | } |
374 | 374 | ||
375 | /** | 375 | /** |
376 | * Look up a property in a node and check that it has a minimum length. | 376 | * Look up a property in a node and check that it has a minimum length. |
377 | * | 377 | * |
378 | * @param blob FDT blob | 378 | * @param blob FDT blob |
379 | * @param node node to examine | 379 | * @param node node to examine |
380 | * @param prop_name name of property to find | 380 | * @param prop_name name of property to find |
381 | * @param min_len minimum property length in bytes | 381 | * @param min_len minimum property length in bytes |
382 | * @param err 0 if ok, or -FDT_ERR_NOTFOUND if the property is not | 382 | * @param err 0 if ok, or -FDT_ERR_NOTFOUND if the property is not |
383 | found, or -FDT_ERR_BADLAYOUT if not enough data | 383 | found, or -FDT_ERR_BADLAYOUT if not enough data |
384 | * @return pointer to cell, which is only valid if err == 0 | 384 | * @return pointer to cell, which is only valid if err == 0 |
385 | */ | 385 | */ |
386 | static const void *get_prop_check_min_len(const void *blob, int node, | 386 | static const void *get_prop_check_min_len(const void *blob, int node, |
387 | const char *prop_name, int min_len, int *err) | 387 | const char *prop_name, int min_len, int *err) |
388 | { | 388 | { |
389 | const void *cell; | 389 | const void *cell; |
390 | int len; | 390 | int len; |
391 | 391 | ||
392 | debug("%s: %s\n", __func__, prop_name); | 392 | debug("%s: %s\n", __func__, prop_name); |
393 | cell = fdt_getprop(blob, node, prop_name, &len); | 393 | cell = fdt_getprop(blob, node, prop_name, &len); |
394 | if (!cell) | 394 | if (!cell) |
395 | *err = -FDT_ERR_NOTFOUND; | 395 | *err = -FDT_ERR_NOTFOUND; |
396 | else if (len < min_len) | 396 | else if (len < min_len) |
397 | *err = -FDT_ERR_BADLAYOUT; | 397 | *err = -FDT_ERR_BADLAYOUT; |
398 | else | 398 | else |
399 | *err = 0; | 399 | *err = 0; |
400 | return cell; | 400 | return cell; |
401 | } | 401 | } |
402 | 402 | ||
403 | int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, | 403 | int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, |
404 | u32 *array, int count) | 404 | u32 *array, int count) |
405 | { | 405 | { |
406 | const u32 *cell; | 406 | const u32 *cell; |
407 | int i, err = 0; | 407 | int i, err = 0; |
408 | 408 | ||
409 | debug("%s: %s\n", __func__, prop_name); | 409 | debug("%s: %s\n", __func__, prop_name); |
410 | cell = get_prop_check_min_len(blob, node, prop_name, | 410 | cell = get_prop_check_min_len(blob, node, prop_name, |
411 | sizeof(u32) * count, &err); | 411 | sizeof(u32) * count, &err); |
412 | if (!err) { | 412 | if (!err) { |
413 | for (i = 0; i < count; i++) | 413 | for (i = 0; i < count; i++) |
414 | array[i] = fdt32_to_cpu(cell[i]); | 414 | array[i] = fdt32_to_cpu(cell[i]); |
415 | } | 415 | } |
416 | return err; | 416 | return err; |
417 | } | 417 | } |
418 | 418 | ||
419 | const u32 *fdtdec_locate_array(const void *blob, int node, | 419 | const u32 *fdtdec_locate_array(const void *blob, int node, |
420 | const char *prop_name, int count) | 420 | const char *prop_name, int count) |
421 | { | 421 | { |
422 | const u32 *cell; | 422 | const u32 *cell; |
423 | int err; | 423 | int err; |
424 | 424 | ||
425 | cell = get_prop_check_min_len(blob, node, prop_name, | 425 | cell = get_prop_check_min_len(blob, node, prop_name, |
426 | sizeof(u32) * count, &err); | 426 | sizeof(u32) * count, &err); |
427 | return err ? NULL : cell; | 427 | return err ? NULL : cell; |
428 | } | 428 | } |
429 | 429 | ||
430 | int fdtdec_get_bool(const void *blob, int node, const char *prop_name) | 430 | int fdtdec_get_bool(const void *blob, int node, const char *prop_name) |
431 | { | 431 | { |
432 | const s32 *cell; | 432 | const s32 *cell; |
433 | int len; | 433 | int len; |
434 | 434 | ||
435 | debug("%s: %s\n", __func__, prop_name); | 435 | debug("%s: %s\n", __func__, prop_name); |
436 | cell = fdt_getprop(blob, node, prop_name, &len); | 436 | cell = fdt_getprop(blob, node, prop_name, &len); |
437 | return cell != NULL; | 437 | return cell != NULL; |
438 | } | 438 | } |
439 | 439 | ||
440 | /** | 440 | /** |
441 | * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no | 441 | * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no |
442 | * terminating item. | 442 | * terminating item. |
443 | * | 443 | * |
444 | * @param blob FDT blob to use | 444 | * @param blob FDT blob to use |
445 | * @param node Node to look at | 445 | * @param node Node to look at |
446 | * @param prop_name Node property name | 446 | * @param prop_name Node property name |
447 | * @param gpio Array of gpio elements to fill from FDT. This will be | 447 | * @param gpio Array of gpio elements to fill from FDT. This will be |
448 | * untouched if either 0 or an error is returned | 448 | * untouched if either 0 or an error is returned |
449 | * @param max_count Maximum number of elements allowed | 449 | * @param max_count Maximum number of elements allowed |
450 | * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would | 450 | * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would |
451 | * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. | 451 | * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. |
452 | */ | 452 | */ |
453 | int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name, | 453 | int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name, |
454 | struct fdt_gpio_state *gpio, int max_count) | 454 | struct fdt_gpio_state *gpio, int max_count) |
455 | { | 455 | { |
456 | const struct fdt_property *prop; | 456 | const struct fdt_property *prop; |
457 | const u32 *cell; | 457 | const u32 *cell; |
458 | const char *name; | 458 | const char *name; |
459 | int len, i; | 459 | int len, i; |
460 | 460 | ||
461 | debug("%s: %s\n", __func__, prop_name); | 461 | debug("%s: %s\n", __func__, prop_name); |
462 | assert(max_count > 0); | 462 | assert(max_count > 0); |
463 | prop = fdt_get_property(blob, node, prop_name, &len); | 463 | prop = fdt_get_property(blob, node, prop_name, &len); |
464 | if (!prop) { | 464 | if (!prop) { |
465 | debug("%s: property '%s' missing\n", __func__, prop_name); | 465 | debug("%s: property '%s' missing\n", __func__, prop_name); |
466 | return -FDT_ERR_NOTFOUND; | 466 | return -FDT_ERR_NOTFOUND; |
467 | } | 467 | } |
468 | 468 | ||
469 | /* We will use the name to tag the GPIO */ | 469 | /* We will use the name to tag the GPIO */ |
470 | name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); | 470 | name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); |
471 | cell = (u32 *)prop->data; | 471 | cell = (u32 *)prop->data; |
472 | len /= sizeof(u32) * 3; /* 3 cells per GPIO record */ | 472 | len /= sizeof(u32) * 3; /* 3 cells per GPIO record */ |
473 | if (len > max_count) { | 473 | if (len > max_count) { |
474 | debug(" %s: too many GPIOs / cells for " | 474 | debug(" %s: too many GPIOs / cells for " |
475 | "property '%s'\n", __func__, prop_name); | 475 | "property '%s'\n", __func__, prop_name); |
476 | return -FDT_ERR_BADLAYOUT; | 476 | return -FDT_ERR_BADLAYOUT; |
477 | } | 477 | } |
478 | 478 | ||
479 | /* Read out the GPIO data from the cells */ | 479 | /* Read out the GPIO data from the cells */ |
480 | for (i = 0; i < len; i++, cell += 3) { | 480 | for (i = 0; i < len; i++, cell += 3) { |
481 | gpio[i].gpio = fdt32_to_cpu(cell[1]); | 481 | gpio[i].gpio = fdt32_to_cpu(cell[1]); |
482 | gpio[i].flags = fdt32_to_cpu(cell[2]); | 482 | gpio[i].flags = fdt32_to_cpu(cell[2]); |
483 | gpio[i].name = name; | 483 | gpio[i].name = name; |
484 | } | 484 | } |
485 | 485 | ||
486 | return len; | 486 | return len; |
487 | } | 487 | } |
488 | 488 | ||
489 | int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, | 489 | int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, |
490 | struct fdt_gpio_state *gpio) | 490 | struct fdt_gpio_state *gpio) |
491 | { | 491 | { |
492 | int err; | 492 | int err; |
493 | 493 | ||
494 | debug("%s: %s\n", __func__, prop_name); | 494 | debug("%s: %s\n", __func__, prop_name); |
495 | gpio->gpio = FDT_GPIO_NONE; | 495 | gpio->gpio = FDT_GPIO_NONE; |
496 | gpio->name = NULL; | 496 | gpio->name = NULL; |
497 | err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1); | 497 | err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1); |
498 | return err == 1 ? 0 : err; | 498 | return err == 1 ? 0 : err; |
499 | } | 499 | } |
500 | 500 | ||
501 | int fdtdec_get_gpio(struct fdt_gpio_state *gpio) | 501 | int fdtdec_get_gpio(struct fdt_gpio_state *gpio) |
502 | { | 502 | { |
503 | int val; | 503 | int val; |
504 | 504 | ||
505 | if (!fdt_gpio_isvalid(gpio)) | 505 | if (!fdt_gpio_isvalid(gpio)) |
506 | return -1; | 506 | return -1; |
507 | 507 | ||
508 | val = gpio_get_value(gpio->gpio); | 508 | val = gpio_get_value(gpio->gpio); |
509 | return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; | 509 | return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; |
510 | } | 510 | } |
511 | 511 | ||
512 | int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val) | 512 | int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val) |
513 | { | 513 | { |
514 | if (!fdt_gpio_isvalid(gpio)) | 514 | if (!fdt_gpio_isvalid(gpio)) |
515 | return -1; | 515 | return -1; |
516 | 516 | ||
517 | val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; | 517 | val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; |
518 | return gpio_set_value(gpio->gpio, val); | 518 | return gpio_set_value(gpio->gpio, val); |
519 | } | 519 | } |
520 | 520 | ||
521 | int fdtdec_setup_gpio(struct fdt_gpio_state *gpio) | 521 | int fdtdec_setup_gpio(struct fdt_gpio_state *gpio) |
522 | { | 522 | { |
523 | /* | 523 | /* |
524 | * Return success if there is no GPIO defined. This is used for | 524 | * Return success if there is no GPIO defined. This is used for |
525 | * optional GPIOs) | 525 | * optional GPIOs) |
526 | */ | 526 | */ |
527 | if (!fdt_gpio_isvalid(gpio)) | 527 | if (!fdt_gpio_isvalid(gpio)) |
528 | return 0; | 528 | return 0; |
529 | 529 | ||
530 | if (gpio_request(gpio->gpio, gpio->name)) | 530 | if (gpio_request(gpio->gpio, gpio->name)) |
531 | return -1; | 531 | return -1; |
532 | return 0; | 532 | return 0; |
533 | } | 533 | } |
534 | 534 | ||
535 | int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, | 535 | int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, |
536 | u8 *array, int count) | 536 | u8 *array, int count) |
537 | { | 537 | { |
538 | const u8 *cell; | 538 | const u8 *cell; |
539 | int err; | 539 | int err; |
540 | 540 | ||
541 | cell = get_prop_check_min_len(blob, node, prop_name, count, &err); | 541 | cell = get_prop_check_min_len(blob, node, prop_name, count, &err); |
542 | if (!err) | 542 | if (!err) |
543 | memcpy(array, cell, count); | 543 | memcpy(array, cell, count); |
544 | return err; | 544 | return err; |
545 | } | 545 | } |
546 | 546 | ||
547 | const u8 *fdtdec_locate_byte_array(const void *blob, int node, | 547 | const u8 *fdtdec_locate_byte_array(const void *blob, int node, |
548 | const char *prop_name, int count) | 548 | const char *prop_name, int count) |
549 | { | 549 | { |
550 | const u8 *cell; | 550 | const u8 *cell; |
551 | int err; | 551 | int err; |
552 | 552 | ||
553 | cell = get_prop_check_min_len(blob, node, prop_name, count, &err); | 553 | cell = get_prop_check_min_len(blob, node, prop_name, count, &err); |
554 | if (err) | 554 | if (err) |
555 | return NULL; | 555 | return NULL; |
556 | return cell; | 556 | return cell; |
557 | } | 557 | } |
558 | 558 | ||
559 | int fdtdec_get_config_int(const void *blob, const char *prop_name, | 559 | int fdtdec_get_config_int(const void *blob, const char *prop_name, |
560 | int default_val) | 560 | int default_val) |
561 | { | 561 | { |
562 | int config_node; | 562 | int config_node; |
563 | 563 | ||
564 | debug("%s: %s\n", __func__, prop_name); | 564 | debug("%s: %s\n", __func__, prop_name); |
565 | config_node = fdt_path_offset(blob, "/config"); | 565 | config_node = fdt_path_offset(blob, "/config"); |
566 | if (config_node < 0) | 566 | if (config_node < 0) |
567 | return default_val; | 567 | return default_val; |
568 | return fdtdec_get_int(blob, config_node, prop_name, default_val); | 568 | return fdtdec_get_int(blob, config_node, prop_name, default_val); |
569 | } | 569 | } |
570 | 570 | ||
571 | int fdtdec_get_config_bool(const void *blob, const char *prop_name) | 571 | int fdtdec_get_config_bool(const void *blob, const char *prop_name) |
572 | { | 572 | { |
573 | int config_node; | 573 | int config_node; |
574 | const void *prop; | 574 | const void *prop; |
575 | 575 | ||
576 | debug("%s: %s\n", __func__, prop_name); | 576 | debug("%s: %s\n", __func__, prop_name); |
577 | config_node = fdt_path_offset(blob, "/config"); | 577 | config_node = fdt_path_offset(blob, "/config"); |
578 | if (config_node < 0) | 578 | if (config_node < 0) |
579 | return 0; | 579 | return 0; |
580 | prop = fdt_get_property(blob, config_node, prop_name, NULL); | 580 | prop = fdt_get_property(blob, config_node, prop_name, NULL); |
581 | 581 | ||
582 | return prop != NULL; | 582 | return prop != NULL; |
583 | } | 583 | } |
584 | 584 | ||
585 | char *fdtdec_get_config_string(const void *blob, const char *prop_name) | 585 | char *fdtdec_get_config_string(const void *blob, const char *prop_name) |
586 | { | 586 | { |
587 | const char *nodep; | 587 | const char *nodep; |
588 | int nodeoffset; | 588 | int nodeoffset; |
589 | int len; | 589 | int len; |
590 | 590 | ||
591 | debug("%s: %s\n", __func__, prop_name); | 591 | debug("%s: %s\n", __func__, prop_name); |
592 | nodeoffset = fdt_path_offset(blob, "/config"); | 592 | nodeoffset = fdt_path_offset(blob, "/config"); |
593 | if (nodeoffset < 0) | 593 | if (nodeoffset < 0) |
594 | return NULL; | 594 | return NULL; |
595 | 595 | ||
596 | nodep = fdt_getprop(blob, nodeoffset, prop_name, &len); | 596 | nodep = fdt_getprop(blob, nodeoffset, prop_name, &len); |
597 | if (!nodep) | 597 | if (!nodep) |
598 | return NULL; | 598 | return NULL; |
599 | 599 | ||
600 | return (char *)nodep; | 600 | return (char *)nodep; |
601 | } | 601 | } |
602 | 602 | ||
603 | int fdtdec_decode_region(const void *blob, int node, | 603 | int fdtdec_decode_region(const void *blob, int node, |
604 | const char *prop_name, void **ptrp, size_t *size) | 604 | const char *prop_name, void **ptrp, size_t *size) |
605 | { | 605 | { |
606 | const fdt_addr_t *cell; | 606 | const fdt_addr_t *cell; |
607 | int len; | 607 | int len; |
608 | 608 | ||
609 | debug("%s: %s\n", __func__, prop_name); | 609 | debug("%s: %s\n", __func__, prop_name); |
610 | cell = fdt_getprop(blob, node, prop_name, &len); | 610 | cell = fdt_getprop(blob, node, prop_name, &len); |
611 | if (!cell || (len != sizeof(fdt_addr_t) * 2)) | 611 | if (!cell || (len != sizeof(fdt_addr_t) * 2)) |
612 | return -1; | 612 | return -1; |
613 | 613 | ||
614 | *ptrp = (void *)fdt_addr_to_cpu(*cell); | 614 | *ptrp = map_sysmem(fdt_addr_to_cpu(*cell), *size); |
615 | *size = fdt_size_to_cpu(cell[1]); | 615 | *size = fdt_size_to_cpu(cell[1]); |
616 | debug("%s: size=%zx\n", __func__, *size); | 616 | debug("%s: size=%zx\n", __func__, *size); |
617 | return 0; | 617 | return 0; |
618 | } | 618 | } |
619 | 619 |