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 fdt_del_node_and_alias(blob, node);
86 karo_set_fdtsize(blob);
89 static const char *karo_touchpanels[] = {
94 static void fdt_del_tp_node(void *blob, const char *name)
96 int offs = fdt_node_offset_by_compatible(blob, -1, name);
97 uint32_t ph1 = 0, ph2 = 0;
101 debug("node '%s' not found: %d\n", name, offs);
105 prop = fdt_getprop(blob, offs, "reset-switch", NULL);
107 ph1 = fdt32_to_cpu(*prop);
109 prop = fdt_getprop(blob, offs, "wake-switch", NULL);
111 ph2 = fdt32_to_cpu(*prop);
113 debug("Removing node '%s' from DT\n", name);
114 fdt_del_node(blob, offs);
117 offs = fdt_node_offset_by_phandle(blob, ph1);
119 debug("Removing node %08x @ %08x\n", ph1, offs);
120 fdt_del_node(blob, offs);
124 offs = fdt_node_offset_by_phandle(blob, ph2);
126 debug("Removing node %08x @ %08x\n", ph2, offs);
127 fdt_del_node(blob, offs);
132 void karo_fdt_fixup_touchpanel(void *blob)
135 const char *model = getenv("touchpanel");
137 for (i = 0; i < ARRAY_SIZE(karo_touchpanels); i++) {
138 const char *tp = karo_touchpanels[i];
140 if (model != NULL && strcmp(model, tp) == 0)
143 tp = strchr(tp, ',');
144 if (tp != NULL && *tp != '\0' && strcmp(model, tp + 1) == 0)
147 fdt_del_tp_node(blob, karo_touchpanels[i]);
148 karo_set_fdtsize(blob);
152 void karo_fdt_fixup_usb_otg(void *blob)
154 const char *otg_mode = getenv("otg_mode");
157 if (otg_mode == NULL || strcmp(otg_mode, "host") != 0) {
158 karo_fdt_remove_node(blob, "usbh1");
161 if (otg_mode == NULL || strcmp(otg_mode, "device") != 0) {
162 karo_fdt_remove_node(blob, "usbotg");
166 karo_fdt_remove_node(blob, "usbphy");
168 karo_set_fdtsize(blob);
171 void karo_fdt_del_prop(void *blob, const char *compat, phys_addr_t offs,
176 const uint32_t *phandle;
179 offset = fdt_node_offset_by_compat_reg(blob, compat, offs);
183 phandle = fdt_getprop(blob, offset, "transceiver-switch", NULL);
185 ph = fdt32_to_cpu(*phandle);
188 debug("Removing property '%s' from node %s@%08lx\n", prop, compat, offs);
189 ret = fdt_delprop(blob, offset, prop);
191 karo_set_fdtsize(blob);
196 offset = fdt_node_offset_by_phandle(blob, ph);
200 debug("Removing node @ %08x\n", offset);
201 fdt_del_node(blob, offset);
202 karo_set_fdtsize(blob);
205 static int karo_load_part(const char *part, void *addr, size_t len)
208 struct mtd_device *dev;
209 struct part_info *part_info;
212 debug("Initializing mtd_parts\n");
213 ret = mtdparts_init();
217 debug("Trying to find NAND partition '%s'\n", part);
218 ret = find_dev_and_part(part, &dev, &part_num,
221 printf("Failed to find flash partition '%s': %d\n",
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;
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);
236 printf("Failed to load partition '%s' to %p\n", part, addr);
239 debug("Read %u byte from partition '%s' @ offset %08x\n",
240 len, part, part_info->offset);
244 void *karo_fdt_load_dtb(void)
247 void *fdt = (void *)getenv_ulong("fdtaddr", 16, 0);
249 if (tstc() || !fdt) {
250 debug("aborting DTB load\n");
254 /* clear FDT header in memory */
257 ret = karo_load_part("dtb", fdt, MAX_DTB_SIZE);
259 printf("Failed to load dtb from flash: %d\n", ret);
263 if (fdt_check_header(fdt)) {
264 debug("No valid DTB in flash\n");
267 debug("Using DTB from flash\n");
268 karo_set_fdtsize(fdt);