const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp) { uint32_t tag; const struct fdt_property *prop; int namestroff; int offset, nextoffset; int err; if (((err = fdt_check_header(fdt)) != 0) || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) goto fail; nextoffset = err; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: err = -FDT_ERR_TRUNCATED; goto fail; case FDT_BEGIN_NODE: case FDT_END_NODE: case FDT_NOP: break; case FDT_PROP: err = -FDT_ERR_BADSTRUCTURE; prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); if (! prop) goto fail; namestroff = fdt32_to_cpu(prop->nameoff); if (strcmp(fdt_string(fdt, namestroff), name) == 0) { /* Found it! */ int len = fdt32_to_cpu(prop->len); prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)+len); if (! prop) goto fail; if (lenp) *lenp = len; return prop; } break; default: err = -FDT_ERR_BADSTRUCTURE; goto fail; } } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); err = -FDT_ERR_NOTFOUND; fail: if (lenp) *lenp = err; return NULL; }
int fit_config_check_sig(const void *fit, int noffset, int required_keynode, char **err_msgp) { char * const exc_prop[] = {"data"}; const char *prop, *end, *name; struct image_sign_info info; const uint32_t *strings; uint8_t *fit_value; int fit_value_len; int max_regions; int i, prop_len; char path[200]; int count; debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(), fit_get_name(fit, noffset, NULL), fit_get_name(gd_fdt_blob(), required_keynode, NULL)); *err_msgp = NULL; if (fit_image_setup_verify(&info, fit, noffset, required_keynode, err_msgp)) return -1; if (fit_image_hash_get_value(fit, noffset, &fit_value, &fit_value_len)) { *err_msgp = "Can't get hash value property"; return -1; } /* Count the number of strings in the property */ prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len); end = prop ? prop + prop_len : prop; for (name = prop, count = 0; name < end; name++) if (!*name) count++; if (!count) { *err_msgp = "Can't get hashed-nodes property"; return -1; } /* Add a sanity check here since we are using the stack */ if (count > IMAGE_MAX_HASHED_NODES) { *err_msgp = "Number of hashed nodes exceeds maximum"; return -1; } /* Create a list of node names from those strings */ char *node_inc[count]; debug("Hash nodes (%d):\n", count); for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) { debug(" '%s'\n", name); node_inc[i] = (char *)name; } /* * Each node can generate one region for each sub-node. Allow for * 7 sub-nodes (hash@1, signature@1, etc.) and some extra. */ max_regions = 20 + count * 7; struct fdt_region fdt_regions[max_regions]; /* Get a list of regions to hash */ count = fdt_find_regions(fit, node_inc, count, exc_prop, ARRAY_SIZE(exc_prop), fdt_regions, max_regions - 1, path, sizeof(path), 0); if (count < 0) { *err_msgp = "Failed to hash configuration"; return -1; } if (count == 0) { *err_msgp = "No data to hash"; return -1; } if (count >= max_regions - 1) { *err_msgp = "Too many hash regions"; return -1; } /* Add the strings */ strings = fdt_getprop(fit, noffset, "hashed-strings", NULL); if (strings) { fdt_regions[count].offset = fdt_off_dt_strings(fit) + fdt32_to_cpu(strings[0]); fdt_regions[count].size = fdt32_to_cpu(strings[1]); count++; } /* Allocate the region list on the stack */ struct image_region region[count]; fit_region_make_list(fit, fdt_regions, count, region); if (info.crypto->verify(&info, region, count, fit_value, fit_value_len)) { *err_msgp = "Verification failed"; return -1; } return 0; }
int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { char buf[64]; struct uart_class *class; phandle_t node, chosen; pcell_t shift, br, rclk; u_long start, size; int err; uart_bus_space_mem = fdtbus_bs_tag; uart_bus_space_io = NULL; /* Allow overriding the FDT uning the environment. */ class = &uart_ns8250_class; err = uart_getenv(devtype, di, class); if (!err) return (0); if (devtype != UART_DEV_CONSOLE) return (ENXIO); /* * Retrieve /chosen/std{in,out}. */ if ((chosen = OF_finddevice("/chosen")) == 0) return (ENXIO); if (OF_getprop(chosen, "stdin", buf, sizeof(buf)) <= 0) return (ENXIO); if ((node = OF_finddevice(buf)) == 0) return (ENXIO); if (OF_getprop(chosen, "stdout", buf, sizeof(buf)) <= 0) return (ENXIO); if (OF_finddevice(buf) != node) /* Only stdin == stdout is supported. */ return (ENXIO); /* * Retrieve serial attributes. */ uart_fdt_get_shift(node, &shift); if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0) br = 0; br = fdt32_to_cpu(br); if ((err = uart_fdt_get_clock(node, &rclk)) != 0) return (err); /* * Finalize configuration. */ class = &uart_quicc_class; if (fdt_is_compatible(node, "ns16550")) class = &uart_ns8250_class; di->bas.chan = 0; di->bas.regshft = (u_int)shift; di->baudrate = 0; di->bas.rclk = (u_int)rclk; di->ops = uart_getops(class); di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; di->bas.bst = uart_bus_space_mem; err = fdt_regsize(node, &start, &size); if (err) return (ENXIO); start += fdt_immr_va; return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh)); }
static int stm32_sdmmc2_dt_get_config(void) { int sdmmc_node; void *fdt = NULL; const fdt32_t *cuint; if (fdt_get_address(&fdt) == 0) { return -FDT_ERR_NOTFOUND; } if (fdt == NULL) { return -FDT_ERR_NOTFOUND; } sdmmc_node = fdt_node_offset_by_compatible(fdt, -1, DT_SDMMC2_COMPAT); while (sdmmc_node != -FDT_ERR_NOTFOUND) { cuint = fdt_getprop(fdt, sdmmc_node, "reg", NULL); if (cuint == NULL) { continue; } if (fdt32_to_cpu(*cuint) == sdmmc2_params.reg_base) { break; } sdmmc_node = fdt_node_offset_by_compatible(fdt, sdmmc_node, DT_SDMMC2_COMPAT); } if (sdmmc_node == -FDT_ERR_NOTFOUND) { return -FDT_ERR_NOTFOUND; } if (fdt_get_status(sdmmc_node) == DT_DISABLED) { return -FDT_ERR_NOTFOUND; } if (dt_set_pinctrl_config(sdmmc_node) != 0) { return -FDT_ERR_BADVALUE; } cuint = fdt_getprop(fdt, sdmmc_node, "clocks", NULL); if (cuint == NULL) { return -FDT_ERR_NOTFOUND; } cuint++; sdmmc2_params.clock_id = fdt32_to_cpu(*cuint); cuint = fdt_getprop(fdt, sdmmc_node, "resets", NULL); if (cuint == NULL) { return -FDT_ERR_NOTFOUND; } cuint++; sdmmc2_params.reset_id = fdt32_to_cpu(*cuint); if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) { sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0; } if ((fdt_getprop(fdt, sdmmc_node, "st,sig-dir", NULL)) != NULL) { sdmmc2_params.dirpol = SDMMC_POWER_DIRPOL; } if ((fdt_getprop(fdt, sdmmc_node, "st,neg-edge", NULL)) != NULL) { sdmmc2_params.negedge = SDMMC_CLKCR_NEGEDGE; } cuint = fdt_getprop(fdt, sdmmc_node, "bus-width", NULL); if (cuint != NULL) { switch (fdt32_to_cpu(*cuint)) { case 4: sdmmc2_params.bus_width = MMC_BUS_WIDTH_4; break; case 8: sdmmc2_params.bus_width = MMC_BUS_WIDTH_8; break; default: break; } } return 0; }
/** * display_fdt_by_regions() - Display regions of an FDT source * * This dumps an FDT as source, but only certain regions of it. This is the * final stage of the grep - we have a list of regions we want to display, * and this function displays them. * * @disp: Display structure, holding info about our options * @blob: FDT blob to display * @region: List of regions to display * @count: Number of regions */ static int display_fdt_by_regions(struct display_info *disp, const void *blob, struct fdt_region region[], int count) { struct fdt_region *reg = region, *reg_end = region + count; uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob); int base = fdt_off_dt_struct(blob); int version = fdt_version(blob); int offset, nextoffset; int tag, depth, shift; FILE *f = disp->fout; uint64_t addr, size; int in_region; int file_ofs; int i; if (disp->show_dts_version) fprintf(f, "/dts-v1/;\n"); if (disp->header) { fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob)); fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob), fdt_totalsize(blob)); fprintf(f, "// off_dt_struct:\t0x%x\n", fdt_off_dt_struct(blob)); fprintf(f, "// off_dt_strings:\t0x%x\n", fdt_off_dt_strings(blob)); fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); fprintf(f, "// version:\t\t%d\n", version); fprintf(f, "// last_comp_version:\t%d\n", fdt_last_comp_version(blob)); if (version >= 2) { fprintf(f, "// boot_cpuid_phys:\t0x%x\n", fdt_boot_cpuid_phys(blob)); } if (version >= 3) { fprintf(f, "// size_dt_strings:\t0x%x\n", fdt_size_dt_strings(blob)); } if (version >= 17) { fprintf(f, "// size_dt_struct:\t0x%x\n", fdt_size_dt_struct(blob)); } fprintf(f, "\n"); } if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) { const struct fdt_reserve_entry *p_rsvmap; p_rsvmap = (const struct fdt_reserve_entry *) ((const char *)blob + off_mem_rsvmap); for (i = 0; ; i++) { addr = fdt64_to_cpu(p_rsvmap[i].address); size = fdt64_to_cpu(p_rsvmap[i].size); if (addr == 0 && size == 0) break; fprintf(f, "/memreserve/ %llx %llx;\n", (unsigned long long)addr, (unsigned long long)size); } } depth = 0; nextoffset = 0; shift = 4; /* 4 spaces per indent */ do { const struct fdt_property *prop; const char *name; int show; int len; offset = nextoffset; /* * Work out the file offset of this offset, and decide * whether it is in the region list or not */ file_ofs = base + offset; if (reg < reg_end && file_ofs >= reg->offset + reg->size) reg++; in_region = reg < reg_end && file_ofs >= reg->offset && file_ofs < reg->offset + reg->size; tag = fdt_next_tag(blob, offset, &nextoffset); if (tag == FDT_END) break; show = in_region || disp->all; if (show && disp->diff) fprintf(f, "%c", in_region ? '+' : '-'); if (!show) { /* Do this here to avoid 'if (show)' in every 'case' */ if (tag == FDT_BEGIN_NODE) depth++; else if (tag == FDT_END_NODE) depth--; continue; } if (tag != FDT_END) { if (disp->show_addr) fprintf(f, "%4x: ", file_ofs); if (disp->show_offset) fprintf(f, "%4x: ", file_ofs - base); } /* Green means included, red means excluded */ if (disp->colour) print_ansi_colour(f, in_region ? COL_GREEN : COL_RED); switch (tag) { case FDT_PROP: prop = fdt_get_property_by_offset(blob, offset, NULL); name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); fprintf(f, "%*s%s", depth * shift, "", name); utilfdt_print_data(prop->data, fdt32_to_cpu(prop->len)); fprintf(f, ";"); break; case FDT_NOP: fprintf(f, "%*s// [NOP]", depth * shift, ""); break; case FDT_BEGIN_NODE: name = fdt_get_name(blob, offset, &len); fprintf(f, "%*s%s {", depth++ * shift, "", *name ? name : "/"); break; case FDT_END_NODE: fprintf(f, "%*s};", --depth * shift, ""); break; } /* Reset colour back to normal before end of line */ if (disp->colour) print_ansi_colour(f, COL_NONE); fprintf(f, "\n"); } while (1); /* Print a list of strings if requested */ if (disp->list_strings) { const char *str; int str_base = fdt_off_dt_strings(blob); for (offset = 0; offset < fdt_size_dt_strings(blob); offset += strlen(str) + 1) { str = fdt_string(blob, offset); int len = strlen(str) + 1; int show; /* Only print strings that are in the region */ file_ofs = str_base + offset; in_region = reg < reg_end && file_ofs >= reg->offset && file_ofs + len < reg->offset + reg->size; show = in_region || disp->all; if (show && disp->diff) printf("%c", in_region ? '+' : '-'); if (disp->show_addr) printf("%4x: ", file_ofs); if (disp->show_offset) printf("%4x: ", offset); printf("%s\n", str); } } return 0; }
static void compare_structure(const void *fdt1, const void *fdt2) { int nextoffset1 = 0, nextoffset2 = 0; int offset1, offset2; uint32_t tag1, tag2; const char *name1, *name2; int err; const struct fdt_property *prop1, *prop2; int len1, len2; while (1) { do { offset1 = nextoffset1; tag1 = fdt_next_tag(fdt1, offset1, &nextoffset1); } while (tag1 == FDT_NOP); do { offset2 = nextoffset2; tag2 = fdt_next_tag(fdt2, offset2, &nextoffset2); } while (tag2 == FDT_NOP); if (tag1 != tag2) MISMATCH("Tag mismatch (%d != %d) at (%d, %d)", tag1, tag2, offset1, offset2); switch (tag1) { case FDT_BEGIN_NODE: name1 = fdt_get_name(fdt1, offset1, &err); if (!name1) FAIL("fdt_get_name(fdt1, %d, ..): %s", offset1, fdt_strerror(err)); name2 = fdt_get_name(fdt2, offset2, NULL); if (!name2) FAIL("fdt_get_name(fdt2, %d, ..): %s", offset2, fdt_strerror(err)); if (!streq(name1, name2)) MISMATCH("Name mismatch (\"%s\" != \"%s\") at (%d, %d)", name1, name2, offset1, offset2); break; case FDT_PROP: prop1 = fdt_offset_ptr(fdt1, offset1, sizeof(*prop1)); if (!prop1) FAIL("Could get fdt1 property at %d", offset1); prop2 = fdt_offset_ptr(fdt2, offset2, sizeof(*prop2)); if (!prop2) FAIL("Could get fdt2 property at %d", offset2); name1 = fdt_string(fdt1, fdt32_to_cpu(prop1->nameoff)); name2 = fdt_string(fdt2, fdt32_to_cpu(prop2->nameoff)); if (!streq(name1, name2)) MISMATCH("Property name mismatch \"%s\" != \"%s\" " "at (%d, %d)", name1, name2, offset1, offset2); len1 = fdt32_to_cpu(prop1->len); len2 = fdt32_to_cpu(prop2->len); if (len1 != len2) MISMATCH("Property length mismatch %u != %u " "at (%d, %d)", len1, len2, offset1, offset2); if (memcmp(prop1->data, prop2->data, len1) != 0) MISMATCH("Property value mismatch at (%d, %d)", offset1, offset2); break; case FDT_END: return; } } }
void am335x_dmtimer1ms_init_systick(void) { const void *fdt = fdtparse_get_blob(); struct am335x_dmtimer_1ms *regs; int offset, len; fdt32_t *cell; const struct fdt_property *interrupts; uint32_t interrupt_num; uint32_t tldr_val; /* HACK: Simply use the first DMTimer 1ms */ offset = fdt_node_offset_by_compatible(fdt, -1, AM335X_DMTIMER_1MS_COMPAT); if (offset < 0) { panic_print("DMTimer 1ms not found"); } regs = fdtparse_get_addr32(fdt, offset, "regs"); if (!regs) { panic_print("DMTimer 1ms registers not found"); } /* Get interrupt number */ interrupts = fdt_get_property(fdt, offset, "interrupts", &len); /* Make sure there is room for one interrupt */ if (len < 0 || len < sizeof(fdt32_t)) { panic_print("Unable to get DMTimer 1ms interrupt number"); } cell = (fdt32_t *) interrupts->data; /* There is a single interrupt */ interrupt_num = fdt32_to_cpu(cell[0]); /* Select master oscillator as clock */ if (clocks_set_param(fdt, offset, "ti,clock-select", AM335X_DMTIMER_1MS_CLK_M_OSC)) { panic_print("Unable to set DMTimer 1ms clock source"); } /* Enable module clock */ if (clocks_enable(fdt, offset, "clocks")) { panic_print("Unable to enable DMTimer 1ms module clock"); } if (!TIMER_CNT_PER_SYSTICK) { panic_print("Unable to achieve system tick frequency"); } /* * We want TIMER_CNT_PER_SYSTICK timer counts between the * load value and overflow. */ tldr_val = (1LL << 32) - TIMER_CNT_PER_SYSTICK; raw_mem_write(®s->tldr, tldr_val); /* Force reload of counter */ raw_mem_write(®s->ttgr, 1); /* Enable overflow interrupt */ raw_mem_set_bits(®s->tier, AM335X_DMTIMER_TIER_OVF_IT_EN); /* Register and enable interrupt. Pass registers to handler */ if (am335x_interrupt_register(fdt, offset, interrupt_num, dmtimer1ms_systick_handler, regs)) { panic_print("Unable to register DMTimer 1ms interrupt"); } if (am335x_interrupt_enable(fdt, offset, interrupt_num)) { panic_print("Unable to enable DMTimer 1ms interrupt"); } /* Start timer free running */ raw_mem_write(®s->tclr, AM335X_DMTIMER_TCLR_ST | AM335X_DMTIMER_TCLR_AR); }
/* * fdt_get_reg - Fill buffer by information from DT */ static phys_size_t fdt_get_reg(const void *fdt, int nodeoffset, void *buf, const u32 *cell, int n) { int i = 0, b, banks; int parent_offset = fdt_parent_offset(fdt, nodeoffset); int address_cells = fdt_address_cells(fdt, parent_offset); int size_cells = fdt_size_cells(fdt, parent_offset); char *p = buf; u64 val; u64 vals; debug("%s: addr_cells=%x, size_cell=%x, buf=%p, cell=%p\n", __func__, address_cells, size_cells, buf, cell); /* Check memory bank setup */ banks = n % (address_cells + size_cells); if (banks) panic("Incorrect memory setup cells=%d, ac=%d, sc=%d\n", n, address_cells, size_cells); banks = n / (address_cells + size_cells); for (b = 0; b < banks; b++) { debug("%s: Bank #%d:\n", __func__, b); if (address_cells == 2) { val = cell[i + 1]; val <<= 32; val |= cell[i]; val = fdt64_to_cpu(val); debug("%s: addr64=%llx, ptr=%p, cell=%p\n", __func__, val, p, &cell[i]); *(phys_addr_t *)p = val; } else { debug("%s: addr32=%x, ptr=%p\n", __func__, fdt32_to_cpu(cell[i]), p); *(phys_addr_t *)p = fdt32_to_cpu(cell[i]); } p += sizeof(phys_addr_t); i += address_cells; debug("%s: pa=%p, i=%x, size=%zu\n", __func__, p, i, sizeof(phys_addr_t)); if (size_cells == 2) { vals = cell[i + 1]; vals <<= 32; vals |= cell[i]; vals = fdt64_to_cpu(vals); debug("%s: size64=%llx, ptr=%p, cell=%p\n", __func__, vals, p, &cell[i]); *(phys_size_t *)p = vals; } else { debug("%s: size32=%x, ptr=%p\n", __func__, fdt32_to_cpu(cell[i]), p); *(phys_size_t *)p = fdt32_to_cpu(cell[i]); } p += sizeof(phys_size_t); i += size_cells; debug("%s: ps=%p, i=%x, size=%zu\n", __func__, p, i, sizeof(phys_size_t)); } /* Return the first address size */ return *(phys_size_t *)((char *)buf + sizeof(phys_addr_t)); }
/* * Convert and fold provided ATAGs into the provided FDT. * * REturn values: * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt */ int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; uint32_t mem_reg_property[2 * NR_BANKS];//default =8 int memcount = 0; int ret; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } } if (memcount) setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount); return fdt_pack(fdt); }
void fixup_memory(struct sys_info *si) { struct mem_region *curmr; uint32_t addr_cells, size_cells; uint32_t *addr_cellsp, *reg, *size_cellsp; int err, i, len, memory, realmrno, root; uint8_t *buf, *sb; root = fdt_path_offset(fdtp, "/"); if (root < 0) { sprintf(command_errbuf, "Could not find root node !"); return; } memory = fdt_path_offset(fdtp, "/memory"); if (memory <= 0) { /* Create proper '/memory' node. */ memory = fdt_add_subnode(fdtp, root, "memory"); if (memory <= 0) { sprintf(command_errbuf, "Could not fixup '/memory' " "node, error code : %d!\n", memory); return; } err = fdt_setprop(fdtp, memory, "device_type", "memory", sizeof("memory")); if (err < 0) return; } addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", NULL); size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); if (addr_cellsp == NULL || size_cellsp == NULL) { sprintf(command_errbuf, "Could not fixup '/memory' node : " "%s %s property not found in root node!\n", (!addr_cellsp) ? "#address-cells" : "", (!size_cellsp) ? "#size-cells" : ""); return; } addr_cells = fdt32_to_cpu(*addr_cellsp); size_cells = fdt32_to_cpu(*size_cellsp); /* Count valid memory regions entries in sysinfo. */ realmrno = si->mr_no; for (i = 0; i < si->mr_no; i++) if (si->mr[i].start == 0 && si->mr[i].size == 0) realmrno--; if (realmrno == 0) { sprintf(command_errbuf, "Could not fixup '/memory' node : " "sysinfo doesn't contain valid memory regions info!\n"); return; } if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg", &len)) != NULL) { if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0) /* * Do not apply fixup if existing 'reg' property * seems to be valid. */ return; } len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); sb = buf = (uint8_t *)malloc(len); if (!buf) return; bzero(buf, len); for (i = 0; i < si->mr_no; i++) { curmr = &si->mr[i]; if (curmr->size != 0) { /* Ensure endianess, and put cells into a buffer */ if (addr_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(curmr->start); else *(uint32_t *)buf = cpu_to_fdt32(curmr->start); buf += sizeof(uint32_t) * addr_cells; if (size_cells == 2) *(uint64_t *)buf = cpu_to_fdt64(curmr->size); else *(uint32_t *)buf = cpu_to_fdt32(curmr->size); buf += sizeof(uint32_t) * size_cells; } } /* Set property */ if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); }
static void prop_get_fdt(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj); Error *err = NULL; int fdt_offset_next, fdt_offset, fdt_depth; void *fdt; if (!drc->fdt) { visit_start_struct(v, NULL, NULL, name, 0, &err); if (!err) { visit_end_struct(v, &err); } error_propagate(errp, err); return; } fdt = drc->fdt; fdt_offset = drc->fdt_start_offset; fdt_depth = 0; do { const char *name = NULL; const struct fdt_property *prop = NULL; int prop_len = 0, name_len = 0; uint32_t tag; tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next); switch (tag) { case FDT_BEGIN_NODE: fdt_depth++; name = fdt_get_name(fdt, fdt_offset, &name_len); visit_start_struct(v, NULL, NULL, name, 0, &err); if (err) { error_propagate(errp, err); return; } break; case FDT_END_NODE: /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */ g_assert(fdt_depth > 0); visit_end_struct(v, &err); if (err) { error_propagate(errp, err); return; } fdt_depth--; break; case FDT_PROP: { int i; prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len); name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); visit_start_list(v, name, &err); if (err) { error_propagate(errp, err); return; } for (i = 0; i < prop_len; i++) { visit_type_uint8(v, (uint8_t *)&prop->data[i], NULL, &err); if (err) { error_propagate(errp, err); return; } } visit_end_list(v, &err); if (err) { error_propagate(errp, err); return; } break; } default: error_setg(&error_abort, "device FDT in unexpected state: %d", tag); } fdt_offset = fdt_offset_next; } while (fdt_depth != 0); }
/** * omap_ehci_attach - driver entry point, sets up the ECHI controller/driver * @dev: the new device handle * * Sets up bus spaces, interrupt handles, etc for the EHCI controller. It also * parses the resource hints and calls omap_ehci_init() to initialise the * H/W. * * LOCKING: * none * * RETURNS: * 0 on success or a positive error code on failure. */ static int omap_ehci_attach(device_t dev) { struct omap_ehci_softc *isc = device_get_softc(dev); phandle_t node; /* 3 ports with 3 cells per port */ pcell_t phyconf[3 * 3]; pcell_t *phyconf_ptr; ehci_softc_t *sc = &isc->base; int err; int rid; int len, tuple_size; int i; /* initialise some bus fields */ sc->sc_bus.parent = dev; sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = EHCI_MAX_DEVICES; /* save the device */ isc->sc_dev = dev; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev), &ehci_iterate_hw_softc)) { return (ENOMEM); } /* When the EHCI driver is added to the tree it is expected that 3 * memory resources and 1 interrupt resource is assigned. The memory * resources should be: * 0 => EHCI register range * 1 => UHH register range * 2 => TLL register range * * The interrupt resource is just the single interupt for the controller. */ /* Allocate resource for the EHCI register set */ rid = 0; sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_io_res) { device_printf(dev, "Error: Could not map EHCI memory\n"); goto error; } /* Request an interrupt resource */ rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(dev, "Error: could not allocate irq\n"); goto error; } /* Allocate resource for the UHH register set */ rid = 1; isc->uhh_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!isc->uhh_mem_res) { device_printf(dev, "Error: Could not map UHH memory\n"); goto error; } /* Allocate resource for the TLL register set */ rid = 2; isc->tll_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!isc->tll_mem_res) { device_printf(dev, "Error: Could not map TLL memory\n"); goto error; } /* Add this device as a child of the USBus device */ sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); if (!sc->sc_bus.bdev) { device_printf(dev, "Error: could not add USB device\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); device_set_desc(sc->sc_bus.bdev, OMAP_EHCI_HC_DEVSTR); /* Set the vendor name */ sprintf(sc->sc_vendor, "Texas Instruments"); /* Get the GPIO device, we may need this if the driver needs to toggle * some pins for external PHY resets. */ isc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (isc->sc_gpio_dev == NULL) { device_printf(dev, "Error: failed to get the GPIO device\n"); goto error; } /* Set the defaults for the hints */ for (i = 0; i < 3; i++) { isc->phy_reset[i] = 0; isc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN; isc->reset_gpio_pin[i] = -1; } tuple_size = sizeof(pcell_t) * 3; node = ofw_bus_get_node(dev); len = OF_getprop(node, "phy-config", phyconf, sizeof(phyconf)); if (len > 0) { if (len % tuple_size) goto error; if ((len / tuple_size) != 3) goto error; phyconf_ptr = phyconf; for (i = 0; i < 3; i++) { isc->port_mode[i] = fdt32_to_cpu(*phyconf_ptr); isc->phy_reset[i] = fdt32_to_cpu(*(phyconf_ptr + 1)); isc->reset_gpio_pin[i] = fdt32_to_cpu(*(phyconf_ptr + 2)); phyconf_ptr += 3; } } /* Initialise the ECHI registers */ err = omap_ehci_init(isc); if (err) { device_printf(dev, "Error: could not setup OMAP EHCI, %d\n", err); goto error; } /* Set the tag and size of the register set in the EHCI context */ sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); /* Setup the interrupt */ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); if (err) { device_printf(dev, "Error: could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; goto error; } /* Finally we are ready to kick off the ECHI host controller */ err = ehci_init(sc); if (err == 0) { err = device_probe_and_attach(sc->sc_bus.bdev); } if (err) { device_printf(dev, "Error: USB init failed err=%d\n", err); goto error; } return (0); error: omap_ehci_detach(dev); return (ENXIO); }
static int mv_twsi_attach(device_t dev) { struct mv_twsi_softc *sc; phandle_t child, iicbusnode; device_t childdev; struct iicbus_ivar *devi; char dname[32]; /* 32 is taken from struct u_device */ uint32_t paddr; int len, error; sc = device_get_softc(dev); sc->dev = dev; bzero(baud_rate, sizeof(baud_rate)); mtx_init(&sc->mutex, device_get_nameunit(dev), MV_TWSI_NAME, MTX_DEF); /* Allocate IO resources */ if (bus_alloc_resources(dev, res_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); mv_twsi_detach(dev); return (ENXIO); } mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_SLOW, &baud_rate[IIC_SLOW]); mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_FAST, &baud_rate[IIC_FAST]); if (bootverbose) device_printf(dev, "calculated baud rates are:\n" " %" PRIu32 " kHz (M=%d, N=%d) for slow,\n" " %" PRIu32 " kHz (M=%d, N=%d) for fast.\n", baud_rate[IIC_SLOW].raw / 1000, baud_rate[IIC_SLOW].m, baud_rate[IIC_SLOW].n, baud_rate[IIC_FAST].raw / 1000, baud_rate[IIC_FAST].m, baud_rate[IIC_FAST].n); sc->iicbus = device_add_child(dev, IICBUS_DEVNAME, -1); if (sc->iicbus == NULL) { device_printf(dev, "could not add iicbus child\n"); mv_twsi_detach(dev); return (ENXIO); } /* Attach iicbus. */ bus_generic_attach(dev); iicbusnode = 0; /* Find iicbus as the child devices in the device tree. */ for (child = OF_child(ofw_bus_get_node(dev)); child != 0; child = OF_peer(child)) { len = OF_getproplen(child, "model"); if (len <= 0 || len > sizeof(dname) - 1) continue; error = OF_getprop(child, "model", &dname, len); dname[len + 1] = '\0'; if (error == -1) continue; len = strlen(dname); if (len == strlen(IICBUS_DEVNAME) && strncasecmp(dname, IICBUS_DEVNAME, len) == 0) { iicbusnode = child; break; } } if (iicbusnode == 0) goto attach_end; /* Attach child devices onto iicbus. */ for (child = OF_child(iicbusnode); child != 0; child = OF_peer(child)) { /* Get slave address. */ error = OF_getprop(child, "i2c-address", &paddr, sizeof(paddr)); if (error == -1) error = OF_getprop(child, "reg", &paddr, sizeof(paddr)); if (error == -1) continue; /* Get device driver name. */ len = OF_getproplen(child, "model"); if (len <= 0 || len > sizeof(dname) - 1) continue; OF_getprop(child, "model", &dname, len); dname[len + 1] = '\0'; if (bootverbose) device_printf(dev, "adding a device %s at %d.\n", dname, fdt32_to_cpu(paddr)); childdev = BUS_ADD_CHILD(sc->iicbus, 0, dname, -1); devi = IICBUS_IVAR(childdev); devi->addr = fdt32_to_cpu(paddr); } attach_end: bus_generic_attach(sc->iicbus); return (0); }
void dt_platform_init_fdt(void *fdt) { int rv; system_fdt = fdt; printf("fdt_platform_init %p\n", fdt); // Check header if ((rv = fdt_check_header(fdt))) { panic("Bad FDT: %s\n", fdt_strerror(rv)); } // Process memory reservations printf("rsv %p\n", fdt); int num_rsv = fdt_num_mem_rsv(fdt); for (int i = 0; i < num_rsv; i++) { printf("get\n"); gd_memory_map_entry ent; ent.type = gd_reserved_memory_type; ent.attributes = 0; fdt_get_mem_rsv(fdt, i, &ent.physical_start, &ent.size); printf("got\n"); ent.virtual_start = ent.physical_start; printf("Adding reserved memory region: %" PRIX64 " len=%" PRIX64 "\n", ent.physical_start, ent.size); mmap_add_entry(ent); } // Process root note memory entries printf("root\n"); int root = fdt_next_node(fdt, -1, NULL); unsigned addr_cells = fdt_address_cells(fdt, root); unsigned size_cells = fdt_size_cells(fdt, root); unsigned cells = addr_cells + size_cells; int mem_offs = fdt_subnode_offset(fdt, root, "memory"); if (mem_offs < 0) { panic("Unable to locate memory node (%s)\n", fdt_strerror(mem_offs)); } int memlen; const uint32_t *p = fdt_getprop(system_fdt, mem_offs, "reg", &memlen); for (int i = 0; i < memlen / 4; i+= cells) { uint64_t base_addr = 0, base_size = 0; if (addr_cells == 1) { base_addr = fdt32_to_cpu(p[i]); } else if (addr_cells == 2) { base_addr = fdt64_to_cpu(((uint64_t) p[i + 1]) << 32 | p[i]); } if (size_cells == 1) { base_size = fdt32_to_cpu(p[i + addr_cells]); } else if (size_cells == 2) { base_size = fdt64_to_cpu(((uint64_t) p[i + addr_cells + 1]) << 32 | p[i + addr_cells]); } printf("Adding memory range %16" PRIX64 " len %16" PRIX64 "\n", base_addr, base_size); gd_memory_map_entry ent = { 0 }; ent.type = gd_conventional_memory; ent.attributes = 0; ent.virtual_start = ent.physical_start = base_addr; ent.size = base_size; mmap_add_entry(ent); } dt_root = add_device_fdt(NULL, fdt, root, 0); }
/* * Recursively print (a portion of) the fdt. The depth parameter * determines how deeply nested the fdt is printed. */ static int fdt_print(const char *pathp, char *prop, int depth) { static char tabs[MAX_LEVEL+1] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; const void *nodep; /* property node pointer */ int nodeoffset; /* node offset from libfdt */ int nextoffset; /* next node offset from libfdt */ uint32_t tag; /* tag */ int len; /* length of the property */ int level = 0; /* keep track of nesting level */ const struct fdt_property *fdt_prop; nodeoffset = fdt_path_offset (fdt, pathp); if (nodeoffset < 0) { /* * Not found or something else bad happened. */ printf ("libfdt fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); return 1; } /* * The user passed in a property as well as node path. * Print only the given property and then return. */ if (prop) { nodep = fdt_getprop (fdt, nodeoffset, prop, &len); if (len == 0) { /* no property value */ printf("%s %s\n", pathp, prop); return 0; } else if (len > 0) { printf("%s=", prop); print_data (nodep, len); printf("\n"); return 0; } else { printf ("libfdt fdt_getprop(): %s\n", fdt_strerror(len)); return 1; } } /* * The user passed in a node path and no property, * print the node and all subnodes. */ while(level >= 0) { tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); switch(tag) { case FDT_BEGIN_NODE: pathp = fdt_get_name(fdt, nodeoffset, NULL); if (level <= depth) { if (pathp == NULL) pathp = "/* NULL pointer error */"; if (*pathp == '\0') pathp = "/"; /* root is nameless */ printf("%s%s {\n", &tabs[MAX_LEVEL - level], pathp); } level++; if (level >= MAX_LEVEL) { printf("Nested too deep, aborting.\n"); return 1; } break; case FDT_END_NODE: level--; if (level <= depth) printf("%s};\n", &tabs[MAX_LEVEL - level]); if (level == 0) { level = -1; /* exit the loop */ } break; case FDT_PROP: fdt_prop = fdt_offset_ptr(fdt, nodeoffset, sizeof(*fdt_prop)); pathp = fdt_string(fdt, fdt32_to_cpu(fdt_prop->nameoff)); len = fdt32_to_cpu(fdt_prop->len); nodep = fdt_prop->data; if (len < 0) { printf ("libfdt fdt_getprop(): %s\n", fdt_strerror(len)); return 1; } else if (len == 0) { /* the property has no value */ if (level <= depth) printf("%s%s;\n", &tabs[MAX_LEVEL - level], pathp); } else { if (level <= depth) { printf("%s%s=", &tabs[MAX_LEVEL - level], pathp); print_data (nodep, len); printf(";\n"); } } break; case FDT_NOP: printf("/* NOP */\n", &tabs[MAX_LEVEL - level]); break; case FDT_END: return 1; default: if (level <= depth) printf("Unknown tag 0x%08X\n", tag); return 1; } nodeoffset = nextoffset; } return 0; }
STATIC VOID DumpFdt ( IN VOID* FdtBlob ) { struct fdt_header *bph; UINT32 off_dt; UINT32 off_str; CONST CHAR8* p_struct; CONST CHAR8* p_strings; CONST CHAR8* p; CONST CHAR8* s; CONST CHAR8* t; UINT32 tag; UINTN sz; UINTN depth; UINTN shift; UINT32 version; { // Can 'memreserve' be printed by below code? INTN num = fdt_num_mem_rsv (FdtBlob); INTN i, err; UINT64 addr = 0, size = 0; for (i = 0; i < num; i++) { err = fdt_get_mem_rsv (FdtBlob, i, &addr, &size); if (err) { DEBUG ((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i)); } else { Print (L"/memreserve/ \t0x%lx \t0x%lx;\n", addr, size); } } } depth = 0; shift = 4; bph = FdtBlob; off_dt = fdt32_to_cpu (bph->off_dt_struct); off_str = fdt32_to_cpu (bph->off_dt_strings); p_struct = (CONST CHAR8*)FdtBlob + off_dt; p_strings = (CONST CHAR8*)FdtBlob + off_str; version = fdt32_to_cpu (bph->version); p = p_struct; while ((tag = fdt32_to_cpu (GET_CELL (p))) != FDT_END) { if (tag == FDT_BEGIN_NODE) { s = p; p = PALIGN (p + AsciiStrLen (s) + 1, 4); if (*s == '\0') s = "/"; Print (L"%*s%a {\n", depth * shift, L" ", s); depth++; continue; } if (tag == FDT_END_NODE) { depth--; Print (L"%*s};\n", depth * shift, L" "); continue; } if (tag == FDT_NOP) { Print (L"%*s// [NOP]\n", depth * shift, L" "); continue; } if (tag != FDT_PROP) { Print (L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag); break; } sz = fdt32_to_cpu (GET_CELL (p)); s = p_strings + fdt32_to_cpu (GET_CELL (p)); if (version < 16 && sz >= 8) p = PALIGN (p, 8); t = p; p = PALIGN (p + sz, 4); Print (L"%*s%a", depth * shift, L" ", s); PrintData (t, sz); Print (L";\n"); } }
int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, char * const exc_prop[], int exc_prop_count, struct fdt_region region[], int max_regions, char *path, int path_len, int add_string_tab) { int stack[FDT_MAX_DEPTH]; char *end; int nextoffset = 0; uint32_t tag; int count = 0; int start = -1; int depth = -1; int want = 0; int base = fdt_off_dt_struct(fdt); end = path; *end = '\0'; do { const struct fdt_property *prop; const char *name; const char *str; int include = 0; int stop_at = 0; int offset; int len; offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); stop_at = nextoffset; switch (tag) { case FDT_PROP: include = want >= 2; stop_at = offset; prop = fdt_get_property_by_offset(fdt, offset, NULL); str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); if (str_in_list(str, exc_prop, exc_prop_count)) include = 0; break; case FDT_NOP: include = want >= 2; stop_at = offset; break; case FDT_BEGIN_NODE: depth++; if (depth == FDT_MAX_DEPTH) return -FDT_ERR_BADSTRUCTURE; name = fdt_get_name(fdt, offset, &len); if (end - path + 2 + len >= path_len) return -FDT_ERR_NOSPACE; if (end != path + 1) *end++ = '/'; strcpy(end, name); end += len; stack[depth] = want; if (want == 1) stop_at = offset; if (str_in_list(path, inc, inc_count)) want = 2; else if (want) want--; else stop_at = offset; include = want; break; case FDT_END_NODE: include = want; want = stack[depth--]; while (end > path && *--end != '/') ; *end = '\0'; break; case FDT_END: include = 1; break; } if (include && start == -1) { /* Should we merge with previous? */ if (count && count <= max_regions && offset == region[count - 1].offset + region[count - 1].size - base) start = region[--count].offset - base; else start = offset; } if (!include && start != -1) { if (count < max_regions) { region[count].offset = base + start; region[count].size = stop_at - start; } count++; start = -1; } } while (tag != FDT_END); if (nextoffset != fdt_size_dt_struct(fdt)) return -FDT_ERR_BADLAYOUT; /* Add a region for the END tag and the string table */ if (count < max_regions) { region[count].offset = base + start; region[count].size = nextoffset - start; if (add_string_tab) region[count].size += fdt_size_dt_strings(fdt); } count++; return count; }
/* * Convert and fold provided ATAGs into the provided FDT. * * REturn values: * = 0 -> pretend success * = 1 -> bad ATAG (may retry with another possible ATAG pointer) * < 0 -> error from libfdt */ int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } else if (atag->hdr.tag == ATAG_BLUETOOTH) { setprop_values(fdt, "/chosen", "linux,bt_mac", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MSM_WIFI) { #define NVS_MAX_SIZE 0x800U #define NVS_LEN_OFFSET 0x0C #define NVS_DATA_OFFSET 0x40 char append[] = "\nsd_oobonly=1\nbtc_params80=0\nbtc_params6=30\n"; __u32 len = 0; __u32 full_len = (atag->hdr.size-2)*sizeof(__u32); // check that we have enought space for get len if (full_len > NVS_LEN_OFFSET) memcpy(&len, (unsigned char *)(&atag->u) + NVS_LEN_OFFSET, sizeof(len)); // len is less than full block size if (len > (NVS_MAX_SIZE - NVS_DATA_OFFSET)) len = (NVS_MAX_SIZE - NVS_DATA_OFFSET); // len is less than atag block size if (len > full_len) len = full_len; // we have enought space for add additional params if ((len + strlen(append) + 1) <= full_len) { // block is finished by zero if (((unsigned char *)(&atag->u))[NVS_DATA_OFFSET + len] == 0) len --; //copy additional params memcpy( (unsigned char *)(&atag->u) + NVS_DATA_OFFSET + len, append, strlen(append) + 1 ); len += strlen(append); len ++; } // finaly save new wifi calibration setprop_values(fdt, "/chosen", "linux,wifi-calibration", (unsigned char *)(&atag->u) + NVS_DATA_OFFSET, len); } else if (atag->hdr.tag == ATAG_MSM_AWB_CAL) { setprop_values(fdt, "/chosen", "linux,awb_cal", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MFG_GPIO_TABLE) { setprop_values(fdt, "/chosen", "linux,gpio_table", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MSM_PARTITION) { setprop_values(fdt, "/chosen", "linux,msm_partitions", (unsigned char *)(&atag->u), (atag->hdr.size-2)*sizeof(__u32)); } else if (atag->hdr.tag == ATAG_MEMSIZE) { setprop_cell(fdt, "/chosen", "linux,memsize", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_ALS) { setprop_cell(fdt, "/chosen", "linux,als_calibration", atag->u.als_kadc.kadc); } else if (atag->hdr.tag == ATAG_ENGINEERID) { setprop_cell(fdt, "/chosen", "linux,engineerid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_SMI) { setprop_cell(fdt, "/chosen", "linux,smi", atag->u.mem.size); } else if (atag->hdr.tag == ATAG_HWID) { setprop_cell(fdt, "/chosen", "linux,hwid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_SKUID) { setprop_cell(fdt, "/chosen", "linux,skuid", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_HERO_PANEL_TYPE) { setprop_cell(fdt, "/chosen", "linux,panel_type", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_GS) { setprop_cell(fdt, "/chosen", "linux,gs_calibration", atag->u.revision.rev); } else if (atag->hdr.tag == ATAG_REVISION) { __u32 revision[2]; revision[0] = cpu_to_fdt32(atag->u.revision.rev); revision[1] = cpu_to_fdt32(atag->u.revision.rev); if (atag->hdr.size > 3) { revision[1] = cpu_to_fdt32(atag->u.revision.rev2); } setprop_values(fdt, "/chosen", "linux,revision", revision, sizeof(revision)); } else if (atag->hdr.tag == ATAG_PS) { __u32 ps_settings[2]; ps_settings[0] = cpu_to_fdt32(atag->u.serialnr.low); ps_settings[1] = cpu_to_fdt32(atag->u.serialnr.high); setprop_values(fdt, "/chosen", "linux,ps_calibration", ps_settings, sizeof(ps_settings)); } else if (atag->hdr.tag == ATAG_PS_TYPE) { setprop_cell(fdt, "/chosen", "linux,ps_type", atag->u.revision.rev); } } if (memcount) { setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } return fdt_pack(fdt); }
int fit_list_images(void *fit, int images_offset) { int node; int count; const char *description; for(count = 0,node = fdt_first_subnode(fit, images_offset); node >= 0; node = fdt_next_subnode(fit, node), count++) { printf("\n === Image (%d) - %s ===\n", count, fdt_get_name(fit, node, NULL)); description = fdt_getprop(fit, node, "description", NULL); if(!description) { description = "Unavailable"; } const char *type = fdt_getprop(fit, node, "type", NULL); const char *compression = fdt_getprop(fit, node, "compression", NULL); int data_len = 0; const void *data = fdt_getprop(fit, node, "data", &data_len); char *length = "Unavailable"; char len_buf[32]; if(data) { snprintf(len_buf, 32, "%d", data_len); length = len_buf; } const char *arch = fdt_getprop(fit, node, "arch", NULL); const char *os = fdt_getprop(fit, node, "os", NULL); const fdt32_t *load_addr = fdt_getprop(fit, node, "load", NULL); int32_t load = 0; if(load_addr) { load = fdt32_to_cpu(*load_addr); } const fdt32_t *entry_addr = fdt_getprop(fit, node, "entry", NULL); int32_t entry = 0; if(entry_addr) { entry = fdt32_to_cpu(*entry_addr); } printf(" Description : %s\n", description); printf(" Type : %s\n", type); printf(" Compression : %s\n", compression); printf(" Length (bytes): %s\n", length); if(arch) { printf(" Architecture : %s\n", arch); } if(os) { printf(" OS : %s\n", os); } if(load_addr) { printf(" Load Address : 0x%08x\n", load); } if(entry_addr) { printf(" Entry Address : 0x%08x\n", entry); } // Check all hashes. int hash_node; int hash_count = 0; for(hash_count = 0, hash_node = fdt_first_subnode(fit, node); hash_node >= 0; hash_node = fdt_next_subnode(fit, hash_node), hash_count++) { printf(" === Hash %d ===\n", hash_count); const char *algo = fdt_getprop(fit, hash_node, "algo", NULL); int val_len; const unsigned char *value = fdt_getprop(fit, hash_node, "value", &val_len); char digest[20*2+2]; char val[8]; int i; strcpy(digest, ""); for(i = 0; i < val_len; i++) { sprintf(val, "%02x", value[i]); strcat(digest, val); } digest[2*val_len] = '\0'; printf(" Algorithm : %s\n", algo); printf(" Digest : %s\n", digest); calculate_hash(data, data_len, algo, digest, &i); char *verify = "FAILED"; if(!memcmp(value, digest, val_len)) { verify = "OK"; } printf(" Verify : %s\n", verify); } } }
static int hammerhead_choose_dtb(const char *dtb_img, off_t dtb_len, char **dtb_buf, off_t *dtb_length) { char *dtb = (char*)dtb_img; char *dtb_end = dtb + dtb_len; FILE *f; struct msm_id devid, dtb_id; char *bestmatch_tag = NULL; size_t id_read = 0; uint32_t bestmatch_tag_size; uint32_t bestmatch_soc_rev_id = INVALID_SOC_REV_ID; uint32_t bestmatch_board_rev_id = INVALID_SOC_REV_ID; f = fopen("/proc/device-tree/qcom,msm-id", "r"); if(!f) { fprintf(stderr, "DTB: Couldn't open /proc/device-tree/qcom,msm-id!\n"); return 0; } id_read = fread(&devid, 1, sizeof(struct msm_id), f); fclose(f); devid.platform_id = fdt32_to_cpu(devid.platform_id); devid.hardware_id = fdt32_to_cpu(devid.hardware_id); devid.soc_rev = fdt32_to_cpu(devid.soc_rev); if(id_read > 12) devid.board_rev = fdt32_to_cpu(devid.board_rev); else devid.board_rev = 0; printf("DTB: platform %u hw %u soc 0x%x board %u\n", devid.platform_id, devid.hardware_id, devid.soc_rev, devid.board_rev); while(dtb + sizeof(struct fdt_header) < dtb_end) { uint32_t dtb_soc_rev_id; struct fdt_header dtb_hdr; uint32_t dtb_size; /* the DTB could be unaligned, so extract the header, * and operate on it separately */ memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header)); if (fdt_check_header((const void *)&dtb_hdr) != 0 || (dtb + fdt_totalsize((const void *)&dtb_hdr) > dtb_end)) { fprintf(stderr, "DTB: Invalid dtb header!\n"); break; } dtb_size = fdt_totalsize(&dtb_hdr); if(hammerhead_dtb_compatible(dtb, &devid, &dtb_id)) { if (dtb_id.soc_rev == devid.soc_rev && dtb_id.board_rev == devid.board_rev) { *dtb_buf = xmalloc(dtb_size); memcpy(*dtb_buf, dtb, dtb_size); *dtb_length = dtb_size; printf("DTB: match 0x%x %u, my id 0x%x %u, len %u\n", dtb_id.soc_rev, dtb_id.board_rev, devid.soc_rev, devid.board_rev, dtb_size); return 1; } else if(dtb_id.soc_rev <= devid.soc_rev && dtb_id.board_rev < devid.board_rev) { if((bestmatch_soc_rev_id == INVALID_SOC_REV_ID) || (bestmatch_soc_rev_id < dtb_id.soc_rev) || (bestmatch_soc_rev_id == dtb_id.soc_rev && bestmatch_board_rev_id < dtb_id.board_rev)) { bestmatch_tag = dtb; bestmatch_tag_size = dtb_size; bestmatch_soc_rev_id = dtb_id.soc_rev; bestmatch_board_rev_id = dtb_id.board_rev; } } } /* goto the next device tree if any */ dtb += dtb_size; // try to skip padding in standalone dtb.img files while(dtb < dtb_end && *dtb == 0) ++dtb; } if(bestmatch_tag) { printf("DTB: bestmatch 0x%x %u, my id 0x%x %u\n", bestmatch_soc_rev_id, bestmatch_board_rev_id, devid.soc_rev, devid.board_rev); *dtb_buf = xmalloc(bestmatch_tag_size); memcpy(*dtb_buf, bestmatch_tag, bestmatch_tag_size); *dtb_length = bestmatch_tag_size; return 1; } return 0; }
static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list) { int root_offset; const void *prop = NULL; const char *plat_prop = NULL; const char *board_prop = NULL; const char *pmic_prop = NULL; char *model = NULL; struct dt_entry *cur_dt_entry; struct dt_entry *dt_entry_array = NULL; struct board_id *board_data = NULL; struct plat_id *platform_data = NULL; struct pmic_id *pmic_data = NULL; int len; int len_board_id; int len_plat_id; int min_plat_id_len = 0; int len_pmic_id; uint32_t dtb_ver; uint32_t num_entries = 0; uint32_t i, j, k, n; uint32_t msm_data_count; uint32_t board_data_count; uint32_t pmic_data_count; root_offset = fdt_path_offset(dtb, "/"); if (root_offset < 0) return false; prop = fdt_getprop(dtb, root_offset, "model", &len); if (prop && len > 0) { model = (char *) malloc(sizeof(char) * len); ASSERT(model); strlcpy(model, prop, len); } else { dprintf(INFO, "model does not exist in device tree\n"); } /* Find the pmic-id prop from DTB , if pmic-id is present then * the DTB is version 3, otherwise find the board-id prop from DTB , * if board-id is present then the DTB is version 2 */ pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id); board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id); if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) { if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE)) { dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n", len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE); return false; } dtb_ver = DEV_TREE_VERSION_V3; min_plat_id_len = PLAT_ID_SIZE; } else if (board_prop && len_board_id > 0) { if (len_board_id % BOARD_ID_SIZE) { dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n", len_board_id, BOARD_ID_SIZE); return false; } dtb_ver = DEV_TREE_VERSION_V2; min_plat_id_len = PLAT_ID_SIZE; } else { dtb_ver = DEV_TREE_VERSION_V1; min_plat_id_len = DT_ENTRY_V1_SIZE; } /* Get the msm-id prop from DTB */ plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id); if (!plat_prop || len_plat_id <= 0) { dprintf(INFO, "qcom,msm-id entry not found\n"); return false; } else if (len_plat_id % min_plat_id_len) { dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n", len_plat_id, min_plat_id_len); return false; } /* * If DTB version is '1' look for <x y z> pair in the DTB * x: platform_id * y: variant_id * z: SOC rev */ if (dtb_ver == DEV_TREE_VERSION_V1) { cur_dt_entry = (struct dt_entry *) malloc(sizeof(struct dt_entry)); if (!cur_dt_entry) { dprintf(CRITICAL, "Out of memory\n"); return false; } memset(cur_dt_entry, 0, sizeof(struct dt_entry)); while (len_plat_id) { cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id); cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id); cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev); cur_dt_entry->board_hw_subtype = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18; cur_dt_entry->pmic_rev[0] = board_pmic_target(0); cur_dt_entry->pmic_rev[1] = board_pmic_target(1); cur_dt_entry->pmic_rev[2] = board_pmic_target(2); cur_dt_entry->pmic_rev[3] = board_pmic_target(3); cur_dt_entry->offset = (uint32_t)dtb; cur_dt_entry->size = dtb_size; dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n", *model ? model : "unknown", cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev); if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) { dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n", cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev, board_platform_id(), board_hardware_id(), board_soc_version()); } else { dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u 0x%x> != <%u %u 0x%x>\n", cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev, board_platform_id(), board_hardware_id(), board_soc_version()); plat_prop += DT_ENTRY_V1_SIZE; len_plat_id -= DT_ENTRY_V1_SIZE; continue; } } free(cur_dt_entry); }
/* TODO: Can we tighten this code up a little? */ int fdtdec_add_aliases_for_id(const void *blob, const char *name, enum fdt_compat_id id, int *node_list, int maxcount) { int name_len = strlen(name); int nodes[maxcount]; int num_found = 0; int offset, node; int alias_node; int count; int i, j; /* find the alias node if present */ alias_node = fdt_path_offset(blob, "/aliases"); /* * start with nothing, and we can assume that the root node can't * match */ memset(nodes, '\0', sizeof(nodes)); /* First find all the compatible nodes */ for (node = count = 0; node >= 0 && count < maxcount;) { node = fdtdec_next_compatible(blob, node, id); if (node >= 0) nodes[count++] = node; } if (node >= 0) debug("%s: warning: maxcount exceeded with alias '%s'\n", __func__, name); /* Now find all the aliases */ for (offset = fdt_first_property_offset(blob, alias_node); offset > 0; offset = fdt_next_property_offset(blob, offset)) { const struct fdt_property *prop; const char *path; int number; int found; node = 0; prop = fdt_get_property_by_offset(blob, offset, NULL); path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); if (prop->len && 0 == strncmp(path, name, name_len)) node = fdt_path_offset(blob, prop->data); if (node <= 0) continue; /* Get the alias number */ number = simple_strtoul(path + name_len, NULL, 10); if (number < 0 || number >= maxcount) { debug("%s: warning: alias '%s' is out of range\n", __func__, path); continue; } /* Make sure the node we found is actually in our list! */ found = -1; for (j = 0; j < count; j++) if (nodes[j] == node) { found = j; break; } if (found == -1) { debug("%s: warning: alias '%s' points to a node " "'%s' that is missing or is not compatible " " with '%s'\n", __func__, path, fdt_get_name(blob, node, NULL), compat_names[id]); continue; } /* * Add this node to our list in the right place, and mark * it as done. */ if (fdtdec_get_is_enabled(blob, node)) { if (node_list[number]) { debug("%s: warning: alias '%s' requires that " "a node be placed in the list in a " "position which is already filled by " "node '%s'\n", __func__, path, fdt_get_name(blob, node, NULL)); continue; } node_list[number] = node; if (number >= num_found) num_found = number + 1; } nodes[found] = 0; } /* Add any nodes not mentioned by an alias */ for (i = j = 0; i < maxcount; i++) { if (!node_list[i]) { for (; j < maxcount; j++) if (nodes[j] && fdtdec_get_is_enabled(blob, nodes[j])) break; /* Have we run out of nodes to add? */ if (j == maxcount) break; assert(!node_list[i]); node_list[i] = nodes[j++]; if (i >= num_found) num_found = i + 1; } } return num_found; }
int fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc) { phandle_t phy_node; pcell_t phy_handle, phy_reg; uint32_t i; device_t parent, child; if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, sizeof(phy_handle)) <= 0) return (ENXIO); phy_node = OF_node_from_xref(phy_handle); if (OF_getprop(phy_node, "reg", (void *)&phy_reg, sizeof(phy_reg)) <= 0) return (ENXIO); *phy_addr = fdt32_to_cpu(phy_reg); /* * Search for softc used to communicate with phy. */ /* * Step 1: Search for ancestor of the phy-node with a "phy-handle" * property set. */ phy_node = OF_parent(phy_node); while (phy_node != 0) { if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle, sizeof(phy_handle)) > 0) break; phy_node = OF_parent(phy_node); } if (phy_node == 0) return (ENXIO); /* * Step 2: For each device with the same parent and name as ours * compare its node with the one found in step 1, ancestor of phy * node (stored in phy_node). */ parent = device_get_parent(dev); i = 0; child = device_find_child(parent, device_get_name(dev), i); while (child != NULL) { if (ofw_bus_get_node(child) == phy_node) break; i++; child = device_find_child(parent, device_get_name(dev), i); } if (child == NULL) return (ENXIO); /* * Use softc of the device found. */ *phy_sc = (void *)device_get_softc(child); return (0); }
int atags_to_fdt(void *atag_list, void *fdt, int total_space) { struct tag *atag = atag_list; /* In the case of 64 bits memory size, need to reserve 2 cells for * address and size for each bank */ /* IAMROOT-12A: * ------------ * 64비트 시스템의 경우 한 개 뱅크당 주소와 사이즈((2 + 2) x sizeof(int32)) */ uint32_t mem_reg_property[2 * 2 * NR_BANKS]; int memcount = 0; int ret, memsize; /* make sure we've got an aligned pointer */ if ((u32)atag_list & 0x3) return 1; /* IAMROOT-12A: * ------------ * atag/DTB 포인터에서 DTB 매직넘버를 발견하면 이미 DTB가 존재하는 것으로 파악이되어 * ATAG를 컨버전할 필요 없으므로 성공으로 리턴 */ /* if we get a DTB here we're done already */ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) return 0; /* IAMROOT-12A: * ------------ * 처음에 오는 태크가 ATAG_CORE가 아니거나 사이즈가 맞지않으면 실패(1)로 리턴 */ /* validate the ATAG */ if (atag->hdr.tag != ATAG_CORE || (atag->hdr.size != tag_size(tag_core) && atag->hdr.size != 2)) return 1; /* let's give it all the room it could need */ ret = fdt_open_into(fdt, fdt, total_space); if (ret < 0) return ret; /* IAMROOT-12A: * ------------ * atag_list는 atag 개채의 묶음. * for_each_tag()를 수행 시 atag에 하나의 ATAG를 가리키는 포인터가 담김 * 태그는 3개(ATAG_CMDLINE, ATAG_MEM, ATAG_INITRD2)만 디바이스트리로 컨버전 * - ATAG_CMDLINE(cmdline) ---> DTB:/chosen 노드 -> bootargs 프로퍼티 * - ATAG_MEM(u.mem.start & u.mem.size x N뱅크) ---> DTB:/memory 노드 -> reg 프로퍼티 * - ATAG_INITRD2(u.initrd.start & u.initrd.size) ---> DTB:/chosen 노드 -> linux,initrd-start * ---> DTB:/chosen 노드 -> linux,initrd-end */ for_each_tag(atag, atag_list) { if (atag->hdr.tag == ATAG_CMDLINE) { /* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in * the device tree and in the tags, the one from the * tags will be chosen. */ if (do_extend_cmdline) merge_fdt_bootargs(fdt, atag->u.cmdline.cmdline); else setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; if (!atag->u.mem.size) continue; memsize = get_cell_size(fdt); /* IAMROOT-12A: * ------------ * memsize=2인 경우 64비트 * ATAG_MEM은 여러 개가 존재할 수 있다. */ if (memsize == 2) { /* if memsize is 2, that means that * each data needs 2 cells of 32 bits, * so the data are 64 bits */ uint64_t *mem_reg_prop64 = (uint64_t *)mem_reg_property; mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.start); mem_reg_prop64[memcount++] = cpu_to_fdt64(atag->u.mem.size); } else { mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } } else if (atag->hdr.tag == ATAG_INITRD2) { uint32_t initrd_start, initrd_size; initrd_start = atag->u.initrd.start; initrd_size = atag->u.initrd.size; setprop_cell(fdt, "/chosen", "linux,initrd-start", initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end", initrd_start + initrd_size); } } if (memcount) { setprop(fdt, "/memory", "reg", mem_reg_property, 4 * memcount * memsize); } return fdt_pack(fdt); }
static void dump_blob(void *blob, bool debug) { uintptr_t blob_off = (uintptr_t)blob; struct fdt_header *bph = blob; uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap); uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct); uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings); struct fdt_reserve_entry *p_rsvmap = (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap); const char *p_struct = (const char *)blob + off_dt; /* Get offset to the strings */ const char *p_strings = (const char *)blob + off_str; uint32_t version = fdt32_to_cpu(bph->version); uint32_t totalsize = fdt32_to_cpu(bph->totalsize); uint32_t tag; const char *p, *s, *t; int depth, sz, shift; int i; uint64_t addr, size; char *buffer; buffer = (char *)malloc(MAX_LEN); depth = 0; shift = 4; uint32_t off_total_size = fdt32_to_cpu(bph->totalsize); /* TODO: Remove this additional info. Do I need it? */ dprintf(buffer, "totalsize: %d\n", off_total_size); dprintf(buffer, "// magic:\t\t0x%x\n", fdt32_to_cpu(bph->magic)); dprintf(buffer, "// totalsize:\t\t0x%x (%d)\n", totalsize, totalsize); dprintf(buffer, "// off_dt_struct:\t0x%x\n", off_dt); dprintf(buffer, "// off_dt_strings:\t0x%x\n", off_str); dprintf(buffer, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap); dprintf(buffer, "// version:\t\t%d\n", version); dprintf(buffer, "// last_comp_version:\t%d\n", fdt32_to_cpu(bph->last_comp_version)); if (version >= 2) dprintf(buffer, "// boot_cpuid_phys:\t0x%x\n", fdt32_to_cpu(bph->boot_cpuid_phys)); if (version >= 3) dprintf(buffer, "// size_dt_strings:\t0x%x\n", fdt32_to_cpu(bph->size_dt_strings)); if (version >= 17) dprintf(buffer, "// size_dt_struct:\t0x%x\n", fdt32_to_cpu(bph->size_dt_struct)); dprintf(buffer, "\n"); for (i = 0; ; i++) { addr = fdt64_to_cpu(p_rsvmap[i].address); size = fdt64_to_cpu(p_rsvmap[i].size); if (addr == 0 && size == 0) break; dprintf(buffer, "/memreserve/ %#llx %#llx;\n", (unsigned long long)addr, (unsigned long long)size); } p = p_struct; while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) { dumpf("%04zx: tag: 0x%08x (%s)\n", (uintptr_t)p - blob_off - 4, tag, tagname(tag)); if (tag == FDT_BEGIN_NODE) { s = p; p = PALIGN(p + strlen(s) + 1, 4); if (*s == '\0') s = "/"; dprintf(buffer, "%*s%s {\n", depth * shift, "", s); depth++; continue; } if (tag == FDT_END_NODE) { depth--; dprintf(buffer, "%*s};\n", depth * shift, ""); continue; } if (tag == FDT_NOP) { dprintf(buffer, "%*s// [NOP]\n", depth * shift, ""); continue; } if (tag != FDT_PROP) { fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag); break; } /* sz - length of the returned values in bytes */ sz = fdt32_to_cpu(GET_CELL(p)); /* s - pointer to the property name */ s = p_strings + fdt32_to_cpu(GET_CELL(p)); if (version < 16 && sz >= 8) p = PALIGN(p, 8); t = p; p = PALIGN(p + sz, 4); dumpf("%04zx: string: %s\n", (uintptr_t)s - blob_off, s); dumpf("%04zx: value\n", (uintptr_t)t - blob_off); dprintf(buffer, "%*s%s", depth * shift, "", s); my_utilfdt_print_data(t, sz, buffer); dprintf(buffer, ";\n"); } printf("%s", buffer); }