]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/karo/common/fdt.c
FDT: fix handling of otg_mode DT fixup
[karo-tx-uboot.git] / board / karo / common / fdt.c
1 /*
2  * (C) Copyright 2012 Lothar Waßmann <LW@KARO-electronics.de>
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16 */
17
18 #include <common.h>
19 #include <errno.h>
20 #include <libfdt.h>
21 #include <fdt_support.h>
22 #include <nand.h>
23 #include <jffs2/load_kernel.h>
24
25 #include "karo.h"
26
27 #ifdef CONFIG_MAX_DTB_SIZE
28 #define MAX_DTB_SIZE    CONFIG_MAX_DTB_SIZE
29 #else
30 #define MAX_DTB_SIZE    SZ_64K
31 #endif
32
33 DECLARE_GLOBAL_DATA_PTR;
34
35 static void karo_set_fdtsize(void *fdt)
36 {
37         char fdt_size[9];
38         size_t fdtsize = getenv_ulong("fdtsize", 16, 0);
39
40         if (fdtsize == fdt_totalsize(fdt)) {
41                 return;
42         }
43         debug("FDT size changed from %u to %u\n",
44                 fdtsize, fdt_totalsize(fdt));
45
46         snprintf(fdt_size, sizeof(fdt_size), "%08x", fdt_totalsize(fdt));
47         setenv("fdtsize", fdt_size);
48 }
49
50 void karo_fdt_move_fdt(void)
51 {
52         void *fdt;
53         unsigned long fdt_addr = getenv_ulong("fdtaddr", 16, 0);
54
55         if (!fdt_addr) {
56                 printf("fdtaddr is not set\n");
57                 return;
58         }
59
60         fdt = karo_fdt_load_dtb();
61         if (fdt == NULL) {
62                 fdt = (void *)gd->fdt_blob;
63                 if (fdt == NULL) {
64                         printf("Compiled in FDT not found\n");
65                         return;
66                 }
67                 debug("Checking FDT header @ %p\n", fdt);
68                 if (fdt_check_header(fdt)) {
69                         printf("ERROR: No valid DTB found at %p\n", fdt);
70                         return;
71                 }
72                 printf("No DTB in flash; using default DTB\n");
73                 debug("Moving FDT from %p..%p to %08lx..%08lx\n",
74                         fdt, fdt + fdt_totalsize(fdt) - 1,
75                         fdt_addr, fdt_addr + fdt_totalsize(fdt) - 1);
76                 memmove((void *)fdt_addr, fdt, fdt_totalsize(fdt));
77         }
78         set_working_fdt_addr((void *)fdt_addr);
79         karo_set_fdtsize(fdt);
80 }
81
82 void karo_fdt_remove_node(void *blob, const char *node)
83 {
84         debug("Removing node '%s' from DT\n", node);
85         int off = fdt_path_offset(blob, node);
86         int ret;
87
88         if (off < 0) {
89                 printf("Could not find node '%s': %d\n", node, off);
90         } else {
91                 ret = fdt_del_node(blob, off);
92                 if (ret)
93                         printf("Failed to remove node '%s': %d\n",
94                                 node, ret);
95         }
96         karo_set_fdtsize(blob);
97 }
98
99 void karo_fdt_enable_node(void *blob, const char *node, int enable)
100 {
101         int off = fdt_path_offset(blob, node);
102
103         debug("%sabling node '%s'\n", enable ? "En" : "Dis", node);
104         if (off < 0) {
105                 printf("Could not find node '%s': %d\n", node, off);
106                 return;
107         }
108         fdt_set_node_status(blob, off,
109                         enable ? FDT_STATUS_OKAY : FDT_STATUS_DISABLED, 0);
110
111         karo_set_fdtsize(blob);
112 }
113
114 static const char *karo_touchpanels[] = {
115         "ti,tsc2007",
116         "edt,edt-ft5x06",
117 };
118
119 static void fdt_del_tp_node(void *blob, const char *name)
120 {
121         int offs = fdt_node_offset_by_compatible(blob, -1, name);
122         uint32_t ph1 = 0, ph2 = 0;
123         const uint32_t *prop;
124
125         if (offs < 0) {
126                 debug("node '%s' not found: %d\n", name, offs);
127                 return;
128         }
129
130         prop = fdt_getprop(blob, offs, "reset-switch", NULL);
131         if (prop)
132                 ph1 = fdt32_to_cpu(*prop);
133
134         prop = fdt_getprop(blob, offs, "wake-switch", NULL);
135         if (prop)
136                 ph2 = fdt32_to_cpu(*prop);
137
138         debug("Removing node '%s' from DT\n", name);
139         fdt_del_node(blob, offs);
140
141         if (ph1) {
142                 offs = fdt_node_offset_by_phandle(blob, ph1);
143                 if (offs > 0) {
144                         debug("Removing node %08x @ %08x\n", ph1, offs);
145                         fdt_del_node(blob, offs);
146                 }
147         }
148         if (ph2) {
149                 offs = fdt_node_offset_by_phandle(blob, ph2);
150                 if (offs > 0) {
151                         debug("Removing node %08x @ %08x\n", ph2, offs);
152                         fdt_del_node(blob, offs);
153                 }
154         }
155 }
156
157 void karo_fdt_fixup_touchpanel(void *blob)
158 {
159         int i;
160         const char *model = getenv("touchpanel");
161
162         for (i = 0; i < ARRAY_SIZE(karo_touchpanels); i++) {
163                 const char *tp = karo_touchpanels[i];
164
165                 if (model != NULL && strcmp(model, tp) == 0)
166                         continue;
167
168                 tp = strchr(tp, ',');
169                 if (tp != NULL && *tp != '\0' && strcmp(model, tp + 1) == 0)
170                         continue;
171
172                 fdt_del_tp_node(blob, karo_touchpanels[i]);
173                 karo_set_fdtsize(blob);
174         }
175 }
176
177 void karo_fdt_fixup_usb_otg(void *blob, const char *compat, phys_addr_t offs)
178 {
179         const char *otg_mode = getenv("otg_mode");
180         int off;
181
182         debug("OTG mode is '%s'\n", otg_mode ? otg_mode : "<UNSET>");
183
184         off = fdt_node_offset_by_compat_reg(blob, compat, offs);
185         if (off < 0) {
186                 printf("Failed to find node %s@%08lx\n", compat, offs);
187                 return;
188         }
189
190         if (!otg_mode || strcmp(otg_mode, "device") != 0) {
191                 printf("Deleting property gadget-device-name from node %s@%08lx\n",
192                         compat, offs);
193                 fdt_delprop(blob, off, "gadget-device-name");
194         }
195         if (!otg_mode || strcmp(otg_mode, "host") != 0) {
196                 printf("Deleting property host-device-name from node %s@%08lx\n",
197                         compat, offs);
198                 fdt_delprop(blob, off, "host-device-name");
199         }
200         karo_set_fdtsize(blob);
201 }
202
203 void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs,
204                         const char *prop)
205 {
206         int ret;
207         int offset;
208         const uint32_t *phandle;
209         uint32_t ph = 0;
210
211         offset = fdt_node_offset_by_compat_reg(blob, compat, offs);
212         if (offset <= 0)
213                 return;
214
215         phandle = fdt_getprop(blob, offset, prop, NULL);
216         if (phandle) {
217                 ph = fdt32_to_cpu(*phandle);
218         }
219
220         debug("Removing property '%s' from node %s@%08lx\n", prop, compat, offs);
221         ret = fdt_delprop(blob, offset, prop);
222         if (ret == 0)
223                 karo_set_fdtsize(blob);
224
225         if (!ph)
226                 return;
227
228         offset = fdt_node_offset_by_phandle(blob, ph);
229         if (offset <= 0)
230                 return;
231
232         debug("Removing node @ %08x\n", offset);
233         fdt_del_node(blob, offset);
234         karo_set_fdtsize(blob);
235 }
236
237 static int karo_load_part(const char *part, void *addr, size_t len)
238 {
239         int ret;
240         struct mtd_device *dev;
241         struct part_info *part_info;
242         u8 part_num;
243
244         debug("Initializing mtd_parts\n");
245         ret = mtdparts_init();
246         if (ret)
247                 return ret;
248
249         debug("Trying to find NAND partition '%s'\n", part);
250         ret = find_dev_and_part(part, &dev, &part_num,
251                                 &part_info);
252         if (ret) {
253                 printf("Failed to find flash partition '%s': %d\n",
254                         part, ret);
255
256                 return ret;
257         }
258         debug("Found partition '%s': offset=%08x size=%08x\n",
259                 part, part_info->offset, part_info->size);
260         if (part_info->size < len) {
261                 printf("Warning: partition '%s' smaller than requested size: %u; truncating data to %u byte\n",
262                         part, len, part_info->size);
263                 len = part_info->size;
264         }
265         debug("Reading NAND partition '%s' to %p\n", part, addr);
266         ret = nand_read_skip_bad(&nand_info[0], part_info->offset, &len, addr);
267         if (ret) {
268                 printf("Failed to load partition '%s' to %p\n", part, addr);
269                 return ret;
270         }
271         debug("Read %u byte from partition '%s' @ offset %08x\n",
272                 len, part, part_info->offset);
273         return 0;
274 }
275
276 void *karo_fdt_load_dtb(void)
277 {
278         int ret;
279         void *fdt = (void *)getenv_ulong("fdtaddr", 16, 0);
280
281         if (tstc() || !fdt) {
282                 debug("aborting DTB load\n");
283                 return NULL;
284         }
285
286         /* clear FDT header in memory */
287         memset(fdt, 0, 4);
288
289         ret = karo_load_part("dtb", fdt, MAX_DTB_SIZE);
290         if (ret) {
291                 printf("Failed to load dtb from flash: %d\n", ret);
292                 return NULL;
293         }
294
295         if (fdt_check_header(fdt)) {
296                 debug("No valid DTB in flash\n");
297                 return NULL;
298         }
299         debug("Using DTB from flash\n");
300         karo_set_fdtsize(fdt);
301         return fdt;
302 }