2 * (C) Copyright 2012 Lothar Waßmann <LW@KARO-electronics.de>
4 * See file CREDITS for list of people who contributed to this
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.
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.
21 #include <fdt_support.h>
23 #include <jffs2/load_kernel.h>
27 #ifdef CONFIG_MAX_DTB_SIZE
28 #define MAX_DTB_SIZE CONFIG_MAX_DTB_SIZE
30 #define MAX_DTB_SIZE SZ_64K
33 DECLARE_GLOBAL_DATA_PTR;
35 static void karo_set_fdtsize(void *fdt)
38 size_t fdtsize = getenv_ulong("fdtsize", 16, 0);
40 if (fdtsize == fdt_totalsize(fdt)) {
43 debug("FDT size changed from %u to %u\n",
44 fdtsize, fdt_totalsize(fdt));
46 snprintf(fdt_size, sizeof(fdt_size), "%08x", fdt_totalsize(fdt));
47 setenv("fdtsize", fdt_size);
50 void karo_fdt_move_fdt(void)
53 unsigned long fdt_addr = getenv_ulong("fdtaddr", 16, 0);
56 printf("fdtaddr is not set\n");
60 fdt = karo_fdt_load_dtb();
62 fdt = (void *)gd->fdt_blob;
64 printf("Compiled in FDT not found\n");
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);
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));
78 set_working_fdt_addr((void *)fdt_addr);
79 karo_set_fdtsize(fdt);
82 void karo_fdt_remove_node(void *blob, const char *node)
84 debug("Removing node '%s' from DT\n", node);
85 int off = fdt_path_offset(blob, node);
89 printf("Could not find node '%s': %d\n", node, off);
91 ret = fdt_del_node(blob, off);
93 printf("Failed to remove node '%s': %d\n",
96 karo_set_fdtsize(blob);
99 void karo_fdt_enable_node(void *blob, const char *node, int enable)
101 int off = fdt_path_offset(blob, node);
103 debug("%sabling node '%s'\n", enable ? "En" : "Dis", node);
105 printf("Could not find node '%s': %d\n", node, off);
108 fdt_set_node_status(blob, off,
109 enable ? FDT_STATUS_OKAY : FDT_STATUS_DISABLED, 0);
111 karo_set_fdtsize(blob);
114 static const char *karo_touchpanels[] = {
119 static void fdt_del_tp_node(void *blob, const char *name)
121 int offs = fdt_node_offset_by_compatible(blob, -1, name);
122 uint32_t ph1 = 0, ph2 = 0;
123 const uint32_t *prop;
126 debug("node '%s' not found: %d\n", name, offs);
130 prop = fdt_getprop(blob, offs, "reset-switch", NULL);
132 ph1 = fdt32_to_cpu(*prop);
134 prop = fdt_getprop(blob, offs, "wake-switch", NULL);
136 ph2 = fdt32_to_cpu(*prop);
138 debug("Removing node '%s' from DT\n", name);
139 fdt_del_node(blob, offs);
142 offs = fdt_node_offset_by_phandle(blob, ph1);
144 debug("Removing node %08x @ %08x\n", ph1, offs);
145 fdt_del_node(blob, offs);
149 offs = fdt_node_offset_by_phandle(blob, ph2);
151 debug("Removing node %08x @ %08x\n", ph2, offs);
152 fdt_del_node(blob, offs);
157 void karo_fdt_fixup_touchpanel(void *blob)
160 const char *model = getenv("touchpanel");
162 for (i = 0; i < ARRAY_SIZE(karo_touchpanels); i++) {
163 const char *tp = karo_touchpanels[i];
165 if (model != NULL && strcmp(model, tp) == 0)
168 tp = strchr(tp, ',');
169 if (tp != NULL && *tp != '\0' && strcmp(model, tp + 1) == 0)
172 fdt_del_tp_node(blob, karo_touchpanels[i]);
173 karo_set_fdtsize(blob);
177 void karo_fdt_fixup_usb_otg(void *blob, const char *compat, phys_addr_t offs)
179 const char *otg_mode = getenv("otg_mode");
182 debug("OTG mode is '%s'\n", otg_mode ? otg_mode : "<UNSET>");
184 off = fdt_node_offset_by_compat_reg(blob, compat, offs);
186 printf("Failed to find node %s@%08lx\n", compat, offs);
190 if (!otg_mode || strcmp(otg_mode, "device") != 0) {
191 printf("Deleting property gadget-device-name from node %s@%08lx\n",
193 fdt_delprop(blob, off, "gadget-device-name");
195 if (!otg_mode || strcmp(otg_mode, "host") != 0) {
196 printf("Deleting property host-device-name from node %s@%08lx\n",
198 fdt_delprop(blob, off, "host-device-name");
200 karo_set_fdtsize(blob);
203 void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs,
208 const uint32_t *phandle;
211 offset = fdt_node_offset_by_compat_reg(blob, compat, offs);
215 phandle = fdt_getprop(blob, offset, prop, NULL);
217 ph = fdt32_to_cpu(*phandle);
220 debug("Removing property '%s' from node %s@%08lx\n", prop, compat, offs);
221 ret = fdt_delprop(blob, offset, prop);
223 karo_set_fdtsize(blob);
228 offset = fdt_node_offset_by_phandle(blob, ph);
232 debug("Removing node @ %08x\n", offset);
233 fdt_del_node(blob, offset);
234 karo_set_fdtsize(blob);
237 static int karo_load_part(const char *part, void *addr, size_t len)
240 struct mtd_device *dev;
241 struct part_info *part_info;
244 debug("Initializing mtd_parts\n");
245 ret = mtdparts_init();
249 debug("Trying to find NAND partition '%s'\n", part);
250 ret = find_dev_and_part(part, &dev, &part_num,
253 printf("Failed to find flash partition '%s': %d\n",
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;
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);
268 printf("Failed to load partition '%s' to %p\n", part, addr);
271 debug("Read %u byte from partition '%s' @ offset %08x\n",
272 len, part, part_info->offset);
276 void *karo_fdt_load_dtb(void)
279 void *fdt = (void *)getenv_ulong("fdtaddr", 16, 0);
281 if (tstc() || !fdt) {
282 debug("aborting DTB load\n");
286 /* clear FDT header in memory */
289 ret = karo_load_part("dtb", fdt, MAX_DTB_SIZE);
291 printf("Failed to load dtb from flash: %d\n", ret);
295 if (fdt_check_header(fdt)) {
296 debug("No valid DTB in flash\n");
299 debug("Using DTB from flash\n");
300 karo_set_fdtsize(fdt);