]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/karo/common/fdt.c
use fdt32_to_cpu() for DT property conversions
[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         fdt_del_node_and_alias(blob, node);
86         karo_set_fdtsize(blob);
87 }
88
89 static const char *karo_touchpanels[] = {
90         "ti,tsc2007",
91         "edt,edt-ft5x06",
92 };
93
94 static void fdt_del_tp_node(void *blob, const char *name)
95 {
96         int offs = fdt_node_offset_by_compatible(blob, -1, name);
97         uint32_t ph1 = 0, ph2 = 0;
98         const uint32_t *prop;
99
100         if (offs < 0) {
101                 debug("node '%s' not found: %d\n", name, offs);
102                 return;
103         }
104
105         prop = fdt_getprop(blob, offs, "reset-switch", NULL);
106         if (prop)
107                 ph1 = fdt32_to_cpu(*prop);
108
109         prop = fdt_getprop(blob, offs, "wake-switch", NULL);
110         if (prop)
111                 ph2 = fdt32_to_cpu(*prop);
112
113         debug("Removing node '%s' from DT\n", name);
114         fdt_del_node(blob, offs);
115
116         if (ph1) {
117                 offs = fdt_node_offset_by_phandle(blob, ph1);
118                 if (offs > 0) {
119                         debug("Removing node %08x @ %08x\n", ph1, offs);
120                         fdt_del_node(blob, offs);
121                 }
122         }
123         if (ph2) {
124                 offs = fdt_node_offset_by_phandle(blob, ph2);
125                 if (offs > 0) {
126                         debug("Removing node %08x @ %08x\n", ph2, offs);
127                         fdt_del_node(blob, offs);
128                 }
129         }
130 }
131
132 void karo_fdt_fixup_touchpanel(void *blob)
133 {
134         int i;
135         const char *model = getenv("touchpanel");
136
137         for (i = 0; i < ARRAY_SIZE(karo_touchpanels); i++) {
138                 const char *tp = karo_touchpanels[i];
139
140                 if (model != NULL && strcmp(model, tp) == 0)
141                         continue;
142
143                 tp = strchr(tp, ',');
144                 if (tp != NULL && *tp != '\0' && strcmp(model, tp + 1) == 0)
145                         continue;
146
147                 fdt_del_tp_node(blob, karo_touchpanels[i]);
148                 karo_set_fdtsize(blob);
149         }
150 }
151
152 void karo_fdt_fixup_usb_otg(void *blob)
153 {
154         const char *otg_mode = getenv("otg_mode");
155         int usbphy = 2;
156
157         if (otg_mode == NULL || strcmp(otg_mode, "host") != 0) {
158                 karo_fdt_remove_node(blob, "usbh1");
159                 usbphy--;
160         }
161         if (otg_mode == NULL || strcmp(otg_mode, "device") != 0) {
162                 karo_fdt_remove_node(blob, "usbotg");
163                 usbphy--;
164         }
165         if (!usbphy) {
166                 karo_fdt_remove_node(blob, "usbphy");
167         }
168         karo_set_fdtsize(blob);
169 }
170
171 void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs,
172                         const char *prop)
173 {
174         int ret;
175         int offset;
176         const uint32_t *phandle;
177         uint32_t ph = 0;
178
179         offset = fdt_node_offset_by_compat_reg(blob, compat, offs);
180         if (offset <= 0)
181                 return;
182
183         phandle = fdt_getprop(blob, offset, "transceiver-switch", NULL);
184         if (phandle) {
185                 ph = fdt32_to_cpu(*phandle);
186         }
187
188         debug("Removing property '%s' from node %s@%08lx\n", prop, compat, offs);
189         ret = fdt_delprop(blob, offset, prop);
190         if (ret == 0)
191                 karo_set_fdtsize(blob);
192
193         if (!ph)
194                 return;
195
196         offset = fdt_node_offset_by_phandle(blob, ph);
197         if (offset <= 0)
198                 return;
199
200         debug("Removing node @ %08x\n", offset);
201         fdt_del_node(blob, offset);
202         karo_set_fdtsize(blob);
203 }
204
205 static int karo_load_part(const char *part, void *addr, size_t len)
206 {
207         int ret;
208         struct mtd_device *dev;
209         struct part_info *part_info;
210         u8 part_num;
211
212         debug("Initializing mtd_parts\n");
213         ret = mtdparts_init();
214         if (ret)
215                 return ret;
216
217         debug("Trying to find NAND partition '%s'\n", part);
218         ret = find_dev_and_part(part, &dev, &part_num,
219                                 &part_info);
220         if (ret) {
221                 printf("Failed to find flash partition '%s': %d\n",
222                         part, ret);
223
224                 return ret;
225         }
226         debug("Found partition '%s': offset=%08x size=%08x\n",
227                 part, part_info->offset, part_info->size);
228         if (part_info->size < len) {
229                 printf("Warning: partition '%s' smaller than requested size: %u; truncating data to %u byte\n",
230                         part, len, part_info->size);
231                 len = part_info->size;
232         }
233         debug("Reading NAND partition '%s' to %p\n", part, addr);
234         ret = nand_read_skip_bad(&nand_info[0], part_info->offset, &len, addr);
235         if (ret) {
236                 printf("Failed to load partition '%s' to %p\n", part, addr);
237                 return ret;
238         }
239         debug("Read %u byte from partition '%s' @ offset %08x\n",
240                 len, part, part_info->offset);
241         return 0;
242 }
243
244 void *karo_fdt_load_dtb(void)
245 {
246         int ret;
247         void *fdt = (void *)getenv_ulong("fdtaddr", 16, 0);
248
249         if (tstc() || !fdt) {
250                 debug("aborting DTB load\n");
251                 return NULL;
252         }
253
254         /* clear FDT header in memory */
255         memset(fdt, 0, 4);
256
257         ret = karo_load_part("dtb", fdt, MAX_DTB_SIZE);
258         if (ret) {
259                 printf("Failed to load dtb from flash: %d\n", ret);
260                 return NULL;
261         }
262
263         if (fdt_check_header(fdt)) {
264                 debug("No valid DTB in flash\n");
265                 return NULL;
266         }
267         debug("Using DTB from flash\n");
268         karo_set_fdtsize(fdt);
269         return fdt;
270 }