void fdt_fsl_mc_fixup_iommu_map_entry(void *blob) { u32 *prop; u32 iommu_map[4]; int offset; int lenp; /* find fsl-mc node */ offset = fdt_path_offset(blob, "/soc/fsl-mc"); if (offset < 0) offset = fdt_path_offset(blob, "/fsl-mc"); if (offset < 0) { printf("%s: fsl-mc: ERR: fsl-mc node not found in DT, err %d\n", __func__, offset); return; } prop = fdt_getprop_w(blob, offset, "iommu-map", &lenp); if (!prop) { debug("%s: fsl-mc: ERR: missing iommu-map in fsl-mc bus node\n", __func__); return; } iommu_map[0] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_START); iommu_map[1] = *++prop; iommu_map[2] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_START); iommu_map[3] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_END - FSL_DPAA2_STREAM_ID_START + 1); fdt_setprop_inplace(blob, offset, "iommu-map", iommu_map, sizeof(iommu_map)); }
static int ft_hs_fixup_sram(void *fdt, bd_t *bd) { const char *path; int offs; int ret; u32 temp[2]; /* * Update SRAM reservations on secure devices. The OCMC RAM * is always reserved for secure use from the start of that * memory region */ path = "/ocp/ocmcram@40300000/sram-hs"; offs = fdt_path_offset(fdt, path); if (offs < 0) { debug("Node %s not found.\n", path); return 0; } /* relative start offset */ temp[0] = cpu_to_fdt32(0); /* reservation size */ temp[1] = cpu_to_fdt32(max(CONFIG_SECURE_BOOT_SRAM, CONFIG_SECURE_RUN_SRAM)); fdt_delprop(fdt, offs, "reg"); ret = fdt_setprop(fdt, offs, "reg", temp, 2 * sizeof(u32)); if (ret < 0) { printf("Could not add reg property to node %s: %s\n", path, fdt_strerror(ret)); return ret; } return 0; }
static void generate_irq_prop(void *fdt, u8 irq, enum irq_type irq_type) { u32 irq_prop[] = { cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI), cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE), cpu_to_fdt32(irq_type) }; _FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop))); }
static void generate_irq_prop(void *fdt, u8 irq) { u32 irq_prop[] = { cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI), cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE), cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI), }; _FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop))); }
/* * 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[16]; 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) { setprop_string(fdt, "/chosen", "bootargs", atag->u.cmdline.cmdline); } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/sizeof(uint32_t)) 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); }
static void nop_region(void *start, int len) { uint32_t *p; for (p = start; (void *)p < (start + len); p++) *p = cpu_to_fdt32(FDT_NOP); }
struct data data_append_integer(struct data d, uint64_t value, int bits) { uint8_t value_8; uint16_t value_16; uint32_t value_32; uint64_t value_64; switch (bits) { case 8: value_8 = value; return data_append_data(d, &value_8, 1); case 16: value_16 = cpu_to_fdt16(value); return data_append_data(d, &value_16, 2); case 32: value_32 = cpu_to_fdt32(value); return data_append_data(d, &value_32, 4); case 64: value_64 = cpu_to_fdt64(value); return data_append_data(d, &value_64, 8); default: die("Invalid literal size (%d)\n", bits); } }
static void _fdt_nop_region(void *start, int len) { fdt32_t *p; for (p = start; (char *)p < ((char *)start + len); p++) *p = cpu_to_fdt32(FDT_NOP); }
void do_fixup_by_prop_u32(void *fdt, const char *pname, const void *pval, int plen, const char *prop, u32 val, int create) { val = cpu_to_fdt32(val); do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create); }
static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, pcell_t *intr) { fdt_pic_decode_t intr_decode; phandle_t intr_offset; int i, rv, interrupt, trig, pol; intr_offset = OF_xref_phandle(iparent); for (i = 0; i < icells; i++) intr[i] = cpu_to_fdt32(intr[i]); for (i = 0; fdt_pic_table[i] != NULL; i++) { intr_decode = fdt_pic_table[i]; rv = intr_decode(intr_offset, intr, &interrupt, &trig, &pol); if (rv == 0) { /* This was recognized as our PIC and decoded. */ interrupt = FDT_MAP_IRQ(intr_parent, interrupt); return (interrupt); } } /* Not in table, so guess */ interrupt = FDT_MAP_IRQ(intr_parent, fdt32_to_cpu(intr[0])); return (interrupt); }
int intr_fdt_map_irq(phandle_t iparent, pcell_t *intr, int icells) { fdt_pic_decode_t intr_decode; phandle_t intr_parent; int i, rv, interrupt, trig, pol; intr_parent = OF_node_from_xref(iparent); for (i = 0; i < icells; i++) intr[i] = cpu_to_fdt32(intr[i]); for (i = 0; fdt_pic_table[i] != NULL; i++) { intr_decode = fdt_pic_table[i]; rv = intr_decode(intr_parent, intr, &interrupt, &trig, &pol); if (rv == 0) { /* This was recognized as our PIC and decoded. */ interrupt = FDT_MAP_IRQ(intr_parent, interrupt); return (interrupt); } } /* Not in table, so guess */ interrupt = FDT_MAP_IRQ(intr_parent, fdt32_to_cpu(intr[0])); return (interrupt); }
int fdt_finish(void *fdt) { int err = check_header_sw(fdt); char *p = (char *)fdt; uint32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; if (err) return err; /* Add terminator */ end = grab_space(fdt, sizeof(*end)); if (! end) return -FDT_ERR_NOSPACE; *end = cpu_to_fdt32(FDT_END); /* Relocate the string table */ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); fdt_set_off_dt_strings(fdt, newstroffset); /* Walk the structure, correcting string offsets */ offset = 0; while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { if (tag == FDT_PROP) { struct fdt_property *prop = fdt_offset_ptr_w(fdt, offset, sizeof(*prop)); int nameoff; if (! prop) return -FDT_ERR_BADSTRUCTURE; nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } /* Finally, adjust the header */ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); fdt_set_magic(fdt, FDT_MAGIC); return 0; }
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; phandle = cpu_to_fdt32(phandle); return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", &phandle, sizeof(phandle)); }
/* * Increase u32 value at pos by offset */ static void fdt_increase_u32(void *pos, uint32_t offset) { uint32_t val; memcpy(&val, pos, sizeof(val)); val = cpu_to_fdt32(fdt32_to_cpu(val) + offset); memcpy(pos, &val, sizeof(val)); }
int fdt_finish(void *fdt) { char *p = (char *)fdt; uint32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; FDT_SW_CHECK_HEADER(fdt); end = _fdt_grab_space(fdt, sizeof(*end)); if (! end) return -FDT_ERR_NOSPACE; *end = cpu_to_fdt32(FDT_END); oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); fdt_set_off_dt_strings(fdt, newstroffset); offset = 0; while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { if (tag == FDT_PROP) { struct fdt_property *prop = _fdt_offset_ptr_w(fdt, offset); int nameoff; nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } if (nextoffset < 0) return nextoffset; fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); fdt_set_magic(fdt, FDT_MAGIC); return 0; }
static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, BIGNUM *num, int num_bits) { int nwords = num_bits / 32; int size; uint32_t *buf, *ptr; BIGNUM *tmp, *big2, *big32, *big2_32; BN_CTX *ctx; int ret; tmp = BN_new(); big2 = BN_new(); big32 = BN_new(); big2_32 = BN_new(); if (!tmp || !big2 || !big32 || !big2_32) { fprintf(stderr, "Out of memory (bignum)\n"); return -ENOMEM; } ctx = BN_CTX_new(); if (!tmp) { fprintf(stderr, "Out of memory (bignum context)\n"); return -ENOMEM; } BN_set_word(big2, 2L); BN_set_word(big32, 32L); BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ size = nwords * sizeof(uint32_t); buf = malloc(size); if (!buf) { fprintf(stderr, "Out of memory (%d bytes)\n", size); return -ENOMEM; } /* Write out modulus as big endian array of integers */ for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ *ptr = cpu_to_fdt32(BN_get_word(tmp)); BN_rshift(num, num, 32); /* N = N/B */ } /* * We try signing with successively increasing size values, so this * might fail several times */ ret = fdt_setprop(blob, noffset, prop_name, buf, size); if (ret) return -FDT_ERR_NOSPACE; free(buf); BN_free(tmp); BN_free(big2); BN_free(big32); BN_free(big2_32); return ret; }
static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, BIGNUM *num, int num_bits) { int nwords = num_bits / 32; int size; uint32_t *buf, *ptr; BIGNUM *tmp, *big2, *big32, *big2_32; BN_CTX *ctx; int ret; tmp = BN_new(); big2 = BN_new(); big32 = BN_new(); big2_32 = BN_new(); if (!tmp || !big2 || !big32 || !big2_32) { fprintf(stderr, "Out of memory (bignum)\n"); return -ENOMEM; } ctx = BN_CTX_new(); if (!tmp) { fprintf(stderr, "Out of memory (bignum context)\n"); return -ENOMEM; } BN_set_word(big2, 2L); BN_set_word(big32, 32L); BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ size = nwords * sizeof(uint32_t); buf = malloc(size); if (!buf) { fprintf(stderr, "Out of memory (%d bytes)\n", size); return -ENOMEM; } /* Write out modulus as big endian array of integers */ for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ *ptr = cpu_to_fdt32(BN_get_word(tmp)); BN_rshift(num, num, 32); /* N = N/B */ } ret = fdt_setprop(blob, noffset, prop_name, buf, size); if (ret) { fprintf(stderr, "Failed to write public key to FIT\n"); return -ENOSPC; } free(buf); BN_free(tmp); BN_free(big2); BN_free(big32); BN_free(big2_32); return ret; }
static int __init fdt_bus_default_translate(__be32 *addr, u64 offset, int na) { u64 a = of_read_number(addr, na); memset(addr, 0, na * 4); a += offset; if (na > 1) addr[na - 2] = cpu_to_fdt32(a >> 32); addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu); return 0; }
int fdt_property(void *fdt, const char *name, const void *val, int len) { struct fdt_property *prop; int nameoff; FDT_SW_CHECK_HEADER(fdt); nameoff = _fdt_find_add_string(fdt, name); if (nameoff == 0) return -FDT_ERR_NOSPACE; prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); if (! prop) return -FDT_ERR_NOSPACE; prop->tag = cpu_to_fdt32(FDT_PROP); prop->nameoff = cpu_to_fdt32(nameoff); prop->len = cpu_to_fdt32(len); memcpy(prop->data, val, len); return 0; }
static void generate_virtio_mmio_node(void *fdt, struct virtio_mmio *vmmio) { char dev_name[DEVICE_NAME_MAX_LEN]; u64 addr = vmmio->addr; u64 reg_prop[] = { cpu_to_fdt64(addr), cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE) }; u32 irq_prop[] = { cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI), cpu_to_fdt32(vmmio->irq - GIC_SPI_IRQ_BASE), cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI), }; snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr); _FDT(fdt_begin_node(fdt, dev_name)); _FDT(fdt_property_string(fdt, "compatible", "virtio,mmio")); _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop))); _FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop))); _FDT(fdt_end_node(fdt)); }
int fdt_end_node(void *fdt) { uint32_t *en; FDT_SW_CHECK_HEADER(fdt); en = _fdt_grab_space(fdt, FDT_TAGSIZE); if (! en) return -FDT_ERR_NOSPACE; *en = cpu_to_fdt32(FDT_END_NODE); return 0; }
int fdt_property(void *fdt, const char *name, const void *val, int len) { struct fdt_property *prop; int err = check_header_sw(fdt); int nameoff; if (err) return err; nameoff = find_add_string(fdt, name); if (nameoff == 0) return -FDT_ERR_NOSPACE; prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE)); if (! prop) return -FDT_ERR_NOSPACE; prop->tag = cpu_to_fdt32(FDT_PROP); prop->nameoff = cpu_to_fdt32(nameoff); prop->len = cpu_to_fdt32(len); memcpy(prop->data, val, len); return 0; }
static int mc_fixup_mac_addr(void *blob, int nodeoffset, const char *propname, struct eth_device *eth_dev, enum mc_fixup_type type) { int err = 0, len = 0, size, i; unsigned char env_enetaddr[ARP_HLEN]; unsigned int enetaddr_32[ARP_HLEN]; void *val = NULL; switch (type) { case MC_FIXUP_DPL: /* DPL likes its addresses on 32 * ARP_HLEN bits */ for (i = 0; i < ARP_HLEN; i++) enetaddr_32[i] = cpu_to_fdt32(eth_dev->enetaddr[i]); val = enetaddr_32; len = sizeof(enetaddr_32); break; case MC_FIXUP_DPC: val = eth_dev->enetaddr; len = ARP_HLEN; break; } /* MAC address property present */ if (fdt_get_property(blob, nodeoffset, propname, NULL)) { /* u-boot MAC addr randomly assigned - leave the present one */ if (!eth_env_get_enetaddr_by_index("eth", eth_dev->index, env_enetaddr)) return err; } else { size = MC_DT_INCREASE_SIZE + strlen(propname) + len; /* make room for mac address property */ err = fdt_increase_size(blob, size); if (err) { printf("fdt_increase_size: err=%s\n", fdt_strerror(err)); return err; } } err = fdt_setprop(blob, nodeoffset, propname, val, len); if (err) { printf("fdt_setprop: err=%s\n", fdt_strerror(err)); return err; } return err; }
int fdt_begin_node(void *fdt, const char *name) { struct fdt_node_header *nh; int namelen = strlen(name) + 1; FDT_SW_CHECK_HEADER(fdt); nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); if (! nh) return -FDT_ERR_NOSPACE; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memcpy(nh->name, name, namelen); return 0; }
/* * fdt_pack_reg - pack address and size array into the "reg"-suitable stream */ static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size, int n) { int i; int address_cells = fdt_address_cells(fdt, 0); int size_cells = fdt_size_cells(fdt, 0); char *p = buf; for (i = 0; i < n; i++) { if (address_cells == 2) *(fdt64_t *)p = cpu_to_fdt64(address[i]); else *(fdt32_t *)p = cpu_to_fdt32(address[i]); p += 4 * address_cells; if (size_cells == 2) *(fdt64_t *)p = cpu_to_fdt64(size[i]); else *(fdt32_t *)p = cpu_to_fdt32(size[i]); p += 4 * size_cells; } return p - (char *)buf; }
int fdt_end_node(void *fdt) { uint32_t *en; int err = check_header_sw(fdt); if (err) return err; en = grab_space(fdt, FDT_TAGSIZE); if (! en) return -FDT_ERR_NOSPACE; *en = cpu_to_fdt32(FDT_END_NODE); return 0; }
int fdt_begin_node(void *fdt, const char *name) { struct fdt_node_header *nh; int err = check_header_sw(fdt); int namelen = strlen(name) + 1; if (err) return err; nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE)); if (! nh) return -FDT_ERR_NOSPACE; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memcpy(nh->name, name, namelen); return 0; }
static void __ft_tsec_fixup(void *blob, bd_t *bd, const char *alias, int phy_addr) { const char *phy_type = "sgmii"; const u32 *ph; int off; int err; off = fdt_path_offset(blob, alias); if (off < 0) { printf("WARNING: could not find %s alias: %s.\n", alias, fdt_strerror(off)); return; } err = fdt_setprop(blob, off, "phy-connection-type", phy_type, strlen(phy_type) + 1); if (err) { printf("WARNING: could not set phy-connection-type for %s: " "%s.\n", alias, fdt_strerror(err)); return; } ph = (u32 *)fdt_getprop(blob, off, "phy-handle", 0); if (!ph) { printf("WARNING: could not get phy-handle for %s.\n", alias); return; } off = fdt_node_offset_by_phandle(blob, *ph); if (off < 0) { printf("WARNING: could not get phy node for %s: %s\n", alias, fdt_strerror(off)); return; } phy_addr = cpu_to_fdt32(phy_addr); err = fdt_setprop(blob, off, "reg", &phy_addr, sizeof(phy_addr)); if (err < 0) { printf("WARNING: could not set phy node's reg for %s: " "%s.\n", alias, fdt_strerror(err)); return; } }
/* Get the value of a property of a package. */ static ssize_t ofw_fdt_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf, size_t buflen) { const void *prop; const char *name; int len, offset; uint32_t cpuid; offset = fdt_phandle_offset(package); if (offset < 0) return (-1); prop = fdt_getprop(fdtp, offset, propname, &len); if (prop == NULL && strcmp(propname, "name") == 0) { /* Emulate the 'name' property */ name = fdt_get_name(fdtp, offset, &len); strncpy(buf, name, buflen); if (len + 1 > buflen) len = buflen; return (len + 1); } if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) { if (strcmp(propname, "fdtbootcpu") == 0) { cpuid = cpu_to_fdt32(fdt_boot_cpuid_phys(fdtp)); len = sizeof(cpuid); prop = &cpuid; } if (strcmp(propname, "fdtmemreserv") == 0) { prop = (char *)fdtp + fdt_off_mem_rsvmap(fdtp); len = sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp); } } if (prop == NULL) return (-1); if (len > buflen) len = buflen; bcopy(prop, buf, len); return (len); }
/* * Process one entry in __fixups__ { } node * @fixups is property value, array of NUL-terminated strings * with fixup locations * @fixups_len length of the fixups array in bytes * @phandle is value for these locations */ static int fdt_do_one_fixup(void *fdtp, const char *fixups, int fixups_len, int phandle) { void *fixup_pos; uint32_t val; val = cpu_to_fdt32(phandle); while (fixups_len > 0) { fixup_pos = fdt_get_fixup_location(fdtp, fixups); if (fixup_pos != NULL) memcpy(fixup_pos, &val, sizeof(val)); fixups_len -= strlen(fixups) + 1; fixups += strlen(fixups) + 1; } return (0); }