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 fdt_addr = CONFIG_SYS_FDT_ADDR;
57 printf("fdtaddr is not set; using default: %08lx\n",
61 fdt = karo_fdt_load_dtb();
63 fdt = (void *)gd->fdt_blob;
65 printf("Compiled in FDT not found\n");
68 debug("Checking FDT header @ %p\n", fdt);
69 if (fdt_check_header(fdt)) {
70 printf("ERROR: No valid DTB found at %p\n", fdt);
73 printf("No DTB in flash; using default DTB\n");
74 debug("Moving FDT from %p..%p to %08lx..%08lx\n",
75 fdt, fdt + fdt_totalsize(fdt) - 1,
76 fdt_addr, fdt_addr + fdt_totalsize(fdt) - 1);
77 memmove((void *)fdt_addr, fdt, fdt_totalsize(fdt));
79 set_working_fdt_addr((void *)fdt_addr);
80 karo_set_fdtsize(fdt);
83 void karo_fdt_remove_node(void *blob, const char *node)
85 debug("Removing node '%s' from DT\n", node);
86 int off = fdt_path_offset(blob, node);
90 printf("Could not find node '%s': %d\n", node, off);
92 ret = fdt_del_node(blob, off);
94 printf("Failed to remove node '%s': %d\n",
97 karo_set_fdtsize(blob);
100 void karo_fdt_enable_node(void *blob, const char *node, int enable)
102 int off = fdt_path_offset(blob, node);
104 debug("%sabling node '%s'\n", enable ? "En" : "Dis", node);
106 printf("Could not find node '%s': %d\n", node, off);
109 fdt_set_node_status(blob, off,
110 enable ? FDT_STATUS_OKAY : FDT_STATUS_DISABLED, 0);
112 karo_set_fdtsize(blob);
115 static const char *karo_touchpanels[] = {
120 static void fdt_del_tp_node(void *blob, const char *name)
122 int offs = fdt_node_offset_by_compatible(blob, -1, name);
123 uint32_t ph1 = 0, ph2 = 0;
124 const uint32_t *prop;
127 debug("node '%s' not found: %d\n", name, offs);
131 prop = fdt_getprop(blob, offs, "reset-switch", NULL);
133 ph1 = fdt32_to_cpu(*prop);
135 prop = fdt_getprop(blob, offs, "wake-switch", NULL);
137 ph2 = fdt32_to_cpu(*prop);
139 debug("Removing node '%s' from DT\n", name);
140 fdt_del_node(blob, offs);
143 offs = fdt_node_offset_by_phandle(blob, ph1);
145 debug("Removing node %08x @ %08x\n", ph1, offs);
146 fdt_del_node(blob, offs);
150 offs = fdt_node_offset_by_phandle(blob, ph2);
152 debug("Removing node %08x @ %08x\n", ph2, offs);
153 fdt_del_node(blob, offs);
158 void karo_fdt_fixup_touchpanel(void *blob)
161 const char *model = getenv("touchpanel");
163 for (i = 0; i < ARRAY_SIZE(karo_touchpanels); i++) {
164 const char *tp = karo_touchpanels[i];
166 if (model != NULL && strcmp(model, tp) == 0)
169 tp = strchr(tp, ',');
170 if (tp != NULL && *tp != '\0' && strcmp(model, tp + 1) == 0)
173 fdt_del_tp_node(blob, karo_touchpanels[i]);
174 karo_set_fdtsize(blob);
178 void karo_fdt_fixup_usb_otg(void *blob, const char *compat, phys_addr_t offs)
180 const char *otg_mode = getenv("otg_mode");
183 debug("OTG mode is '%s'\n", otg_mode ? otg_mode : "<UNSET>");
185 off = fdt_node_offset_by_compat_reg(blob, compat, offs);
187 printf("Failed to find node %s@%08lx\n", compat, offs);
191 if (!otg_mode || strcmp(otg_mode, "device") != 0) {
192 printf("Deleting property gadget-device-name from node %s@%08lx\n",
194 fdt_delprop(blob, off, "gadget-device-name");
196 if (!otg_mode || strcmp(otg_mode, "host") != 0) {
197 printf("Deleting property host-device-name from node %s@%08lx\n",
199 fdt_delprop(blob, off, "host-device-name");
201 karo_set_fdtsize(blob);
204 void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs,
209 const uint32_t *phandle;
212 offset = fdt_node_offset_by_compat_reg(blob, compat, offs);
216 phandle = fdt_getprop(blob, offset, prop, NULL);
218 ph = fdt32_to_cpu(*phandle);
221 debug("Removing property '%s' from node %s@%08lx\n", prop, compat, offs);
222 ret = fdt_delprop(blob, offset, prop);
224 karo_set_fdtsize(blob);
229 offset = fdt_node_offset_by_phandle(blob, ph);
233 debug("Removing node @ %08x\n", offset);
234 fdt_del_node(blob, offset);
235 karo_set_fdtsize(blob);
238 static int karo_load_part(const char *part, void *addr, size_t len)
241 struct mtd_device *dev;
242 struct part_info *part_info;
245 debug("Initializing mtd_parts\n");
246 ret = mtdparts_init();
250 debug("Trying to find NAND partition '%s'\n", part);
251 ret = find_dev_and_part(part, &dev, &part_num,
254 printf("Failed to find flash partition '%s': %d\n",
259 debug("Found partition '%s': offset=%08x size=%08x\n",
260 part, part_info->offset, part_info->size);
261 if (part_info->size < len) {
262 printf("Warning: partition '%s' smaller than requested size: %u; truncating data to %u byte\n",
263 part, len, part_info->size);
264 len = part_info->size;
266 debug("Reading NAND partition '%s' to %p\n", part, addr);
267 ret = nand_read_skip_bad(&nand_info[0], part_info->offset, &len, addr);
269 printf("Failed to load partition '%s' to %p\n", part, addr);
272 debug("Read %u byte from partition '%s' @ offset %08x\n",
273 len, part, part_info->offset);
277 void *karo_fdt_load_dtb(void)
280 void *fdt = (void *)getenv_ulong("fdtaddr", 16, 0);
282 if (tstc() || !fdt) {
283 debug("aborting DTB load\n");
287 /* clear FDT header in memory */
290 ret = karo_load_part("dtb", fdt, MAX_DTB_SIZE);
292 printf("Failed to load dtb from flash: %d\n", ret);
296 if (fdt_check_header(fdt)) {
297 debug("No valid DTB in flash\n");
300 debug("Using DTB from flash\n");
301 karo_set_fdtsize(fdt);