/** * Fix-up the kernel device tree so the bridge pd_n and rst_n gpios accurately * reflect the current board rev. */ static void ft_board_setup_gpios(void *blob, bd_t *bd) { int ret, rev, np, len; const struct fdt_property *prop; /* Do nothing for newer boards */ rev = board_get_revision(); if (rev < 4 || rev == 6) return; /* * If this is an older board, replace powerdown-gpio contents with that * of reset-gpio and delete reset-gpio from the dt. */ np = fdtdec_next_compatible(blob, 0, COMPAT_NXP_PTN3460); if (np < 0) { debug("%s: Could not find COMPAT_NXP_PTN3460\n", __func__); return; } prop = fdt_get_property(blob, np, "reset-gpio", &len); if (!prop) { debug("%s: Could not get property err=%d\n", __func__, len); return; } ret = fdt_setprop_inplace(blob, np, "powerdown-gpio", prop->data, len); if (ret) { debug("%s: Could not setprop inplace err=%d\n", __func__, ret); return; } ret = fdt_delprop(blob, np, "reset-gpio"); if (ret) { debug("%s: Could not delprop err=%d\n", __func__, ret); return; } }
static void __init process_memory_node(const void *fdt, int node, const char *name, u32 address_cells, u32 size_cells) { const struct fdt_property *prop; int i; int banks; const __be32 *cell; paddr_t start, size; u32 reg_cells = address_cells + size_cells; if ( address_cells < 1 || size_cells < 1 ) { printk("fdt: node `%s': invalid #address-cells or #size-cells", name); return; } prop = fdt_get_property(fdt, node, "reg", NULL); if ( !prop ) { printk("fdt: node `%s': missing `reg' property\n", name); return; } cell = (const __be32 *)prop->data; banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof (u32)); for ( i = 0; i < banks && bootinfo.mem.nr_banks < NR_MEM_BANKS; i++ ) { device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); if ( !size ) continue; bootinfo.mem.bank[bootinfo.mem.nr_banks].start = start; bootinfo.mem.bank[bootinfo.mem.nr_banks].size = size; bootinfo.mem.nr_banks++; } }
void do_fixup_by_prop(void *fdt, const char *pname, const void *pval, int plen, const char *prop, const void *val, int len, int create) { int off; #if defined(DEBUG) int i; debug("Updating property '%s' = ", prop); for (i = 0; i < len; i++) debug(" %.2x", *(u8*)(val+i)); debug("\n"); #endif off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen); while (off != -FDT_ERR_NOTFOUND) { if (create || (fdt_get_property(fdt, off, prop, 0) != NULL)) { fdt_setprop(fdt, off, prop, val, len); //if( strcmp(pname, "cpu_type") == 0) printf("find node and set, %s", (char *)pname); } off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen); } }
static QEMUDevice *find_interrupt_parent(QEMUDevice *dev) { const struct fdt_property *p; QEMUDevice *parent; uint32_t phandle; int len; p = fdt_get_property(dev->dt, dev->node_offset, "interrupt-parent", &len); if (!p) return NULL; if (len != 4) { invalid_devtree(dev, "bad/missing interrupt-parent"); return NULL; } phandle = fdt32_to_cpu(*(uint32_t *)p->data); parent = find_device_by_phandle(phandle); if (!parent) { invalid_devtree(dev, "interrupt-parent not found"); } check_interrupt_cells(parent); return parent; }
/** * at91_clk_sub_device_bind() - for the at91 clock driver * Recursively bind its children as clk devices. * * @return: 0 on success, or negative error code on failure */ int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name) { const void *fdt = gd->fdt_blob; int offset = dev_of_offset(dev); bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC); const char *name; int ret; for (offset = fdt_first_subnode(fdt, offset); offset > 0; offset = fdt_next_subnode(fdt, offset)) { if (pre_reloc_only && !fdt_getprop(fdt, offset, "u-boot,dm-pre-reloc", NULL)) continue; /* * If this node has "compatible" property, this is not * a clock sub-node, but a normal device. skip. */ fdt_get_property(fdt, offset, "compatible", &ret); if (ret >= 0) continue; if (ret != -FDT_ERR_NOTFOUND) return ret; name = fdt_get_name(fdt, offset, NULL); if (!name) return -EINVAL; ret = device_bind_driver_to_node(dev, drv_name, name, offset, NULL); if (ret) return ret; } return 0; }
int fdtparse_get_gpio(const void *fdt, int offset, const char *name, struct fdt_gpio *gpio) { const struct fdt_property *prop; int len; fdt32_t *cell; prop = fdt_get_property(fdt, offset, name, &len); if (len < 0) { return len; } /* GPIO cells have 3 fields */ if (len != 3*sizeof(uint32_t)) { return -FDT_ERR_BADLAYOUT; } cell = (fdt32_t *) prop->data; /* cell[0] is gpio path, cell[1] is number, cell[2] is flags */ gpio->gpio = fdt32_to_cpu(cell[1]); gpio->flags = fdt32_to_cpu(cell[2]); return 0; }
int main(int argc, char *argv[]) { const struct fdt_property *prop; void *fdt; int offset; int subnode1_offset; const void *val; int lenerr; test_init(argc, argv); fdt = load_blob_arg(argc, argv); prop = fdt_get_property(fdt, 0, "nonexistant-property", &lenerr); check_error("fdt_get_property(\"nonexistant-property\")", lenerr); val = fdt_getprop(fdt, 0, "nonexistant-property", &lenerr); check_error("fdt_getprop(\"nonexistant-property\"", lenerr); subnode1_offset = fdt_subnode_offset(fdt, 0, "subnode@1"); if (subnode1_offset < 0) FAIL("Couldn't find subnode1: %s", fdt_strerror(subnode1_offset)); val = fdt_getprop(fdt, subnode1_offset, "prop-str", &lenerr); check_error("fdt_getprop(\"prop-str\")", lenerr); offset = fdt_subnode_offset(fdt, 0, "nonexistant-subnode"); check_error("fdt_subnode_offset(\"nonexistant-subnode\")", offset); offset = fdt_subnode_offset(fdt, 0, "subsubnode"); check_error("fdt_subnode_offset(\"subsubnode\")", offset); offset = fdt_path_offset(fdt, "/nonexistant-subnode"); check_error("fdt_path_offset(\"/nonexistant-subnode\")", offset); PASS(); }
static int uniphier_sd_probe(struct udevice *dev) { struct uniphier_sd_priv *priv = dev_get_priv(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); fdt_addr_t base; struct clk clk; int ret; base = dev_get_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; priv->regbase = devm_ioremap(dev, base, SZ_2K); if (!priv->regbase) return -ENOMEM; ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) { dev_err(dev, "failed to get host clock\n"); return ret; } /* set to max rate */ priv->mclk = clk_set_rate(&clk, ULONG_MAX); if (IS_ERR_VALUE(priv->mclk)) { dev_err(dev, "failed to set rate for host clock\n"); clk_free(&clk); return priv->mclk; } ret = clk_enable(&clk); clk_free(&clk); if (ret) { dev_err(dev, "failed to enable host clock\n"); return ret; } priv->cfg.name = dev->name; priv->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS; switch (fdtdec_get_int(gd->fdt_blob, dev->of_offset, "bus-width", 1)) { case 8: priv->cfg.host_caps |= MMC_MODE_8BIT; break; case 4: priv->cfg.host_caps |= MMC_MODE_4BIT; break; case 1: break; default: dev_err(dev, "Invalid \"bus-width\" value\n"); return -EINVAL; } if (fdt_get_property(gd->fdt_blob, dev->of_offset, "non-removable", NULL)) priv->caps |= UNIPHIER_SD_CAP_NONREMOVABLE; priv->version = readl(priv->regbase + UNIPHIER_SD_VERSION) & UNIPHIER_SD_VERSION_IP; dev_dbg(dev, "version %x\n", priv->version); if (priv->version >= 0x10) { priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL; priv->caps |= UNIPHIER_SD_CAP_DIV1024; } uniphier_sd_host_init(priv); priv->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; priv->cfg.f_min = priv->mclk / (priv->caps & UNIPHIER_SD_CAP_DIV1024 ? 1024 : 512); priv->cfg.f_max = priv->mclk; priv->cfg.b_max = U32_MAX; /* max value of UNIPHIER_SD_SECCNT */ priv->mmc = mmc_create(&priv->cfg, priv); if (!priv->mmc) return -EIO; upriv->mmc = priv->mmc; priv->mmc->dev = dev; return 0; }
void __init video_init(void) { int node, depth; u32 address_cells, size_cells; struct lfb_prop lfbp; unsigned char *lfb; paddr_t hdlcd_start, hdlcd_size; paddr_t framebuffer_start, framebuffer_size; const struct fdt_property *prop; const u32 *cell; const char *mode_string; char _mode_string[16]; int bytes_per_pixel = 4; struct color_masks *c = NULL; struct modeline *videomode = NULL; int i; if ( find_compatible_node("arm,hdlcd", &node, &depth, &address_cells, &size_cells) <= 0 ) return; prop = fdt_get_property(device_tree_flattened, node, "reg", NULL); if ( !prop ) return; cell = (const u32 *)prop->data; device_tree_get_reg(&cell, address_cells, size_cells, &hdlcd_start, &hdlcd_size); prop = fdt_get_property(device_tree_flattened, node, "framebuffer", NULL); if ( !prop ) return; cell = (const u32 *)prop->data; device_tree_get_reg(&cell, address_cells, size_cells, &framebuffer_start, &framebuffer_size); if ( !hdlcd_start ) { printk(KERN_ERR "HDLCD address missing from device tree, disabling driver\n"); return; } if ( !hdlcd_start || !framebuffer_start ) { printk(KERN_ERR "HDLCD: framebuffer address missing from device tree, disabling driver\n"); return; } mode_string = fdt_getprop(device_tree_flattened, node, "mode", NULL); if ( !mode_string ) { get_color_masks("32", &c); memcpy(_mode_string, "1280x1024@60", strlen("1280x1024@60") + 1); bytes_per_pixel = 4; } else if ( strlen(mode_string) < strlen("800x600@60") || strlen(mode_string) > sizeof(_mode_string) - 1 ) { printk(KERN_ERR "HDLCD: invalid modeline=%s\n", mode_string); return; } else { char *s = strchr(mode_string, '-'); if ( !s ) { printk(KERN_INFO "HDLCD: bpp not found in modeline %s, assume 32 bpp\n", mode_string); get_color_masks("32", &c); memcpy(_mode_string, mode_string, strlen(mode_string) + 1); bytes_per_pixel = 4; } else { if ( strlen(s) < 6 ) { printk(KERN_ERR "HDLCD: invalid mode %s\n", mode_string); return; } s++; if ( get_color_masks(s, &c) < 0 ) { printk(KERN_WARNING "HDLCD: unsupported bpp %s\n", s); return; } bytes_per_pixel = simple_strtoll(s, NULL, 10) / 8; } i = s - mode_string - 1; memcpy(_mode_string, mode_string, i); memcpy(_mode_string + i, mode_string + i + 3, 4); } for ( i = 0; i < ARRAY_SIZE(videomodes); i++ ) { if ( !strcmp(_mode_string, videomodes[i].mode) ) { videomode = &videomodes[i]; break; } } if ( !videomode ) { printk(KERN_WARNING "HDLCD: unsupported videomode %s\n", _mode_string); return; } if ( framebuffer_size < bytes_per_pixel * videomode->xres * videomode->yres ) { printk(KERN_ERR "HDLCD: the framebuffer is too small, disabling the HDLCD driver\n"); return; } printk(KERN_INFO "Initializing HDLCD driver\n"); lfb = ioremap_wc(framebuffer_start, framebuffer_size); if ( !lfb ) { printk(KERN_ERR "Couldn't map the framebuffer\n"); return; } memset(lfb, 0x00, bytes_per_pixel * videomode->xres * videomode->yres); /* uses FIXMAP_MISC */ set_pixclock(videomode->pixclock); set_fixmap(FIXMAP_MISC, hdlcd_start >> PAGE_SHIFT, DEV_SHARED); HDLCD[HDLCD_COMMAND] = 0; HDLCD[HDLCD_LINELENGTH] = videomode->xres * bytes_per_pixel; HDLCD[HDLCD_LINECOUNT] = videomode->yres - 1; HDLCD[HDLCD_LINEPITCH] = videomode->xres * bytes_per_pixel; HDLCD[HDLCD_PF] = ((bytes_per_pixel - 1) << 3); HDLCD[HDLCD_INTMASK] = 0; HDLCD[HDLCD_FBBASE] = framebuffer_start; HDLCD[HDLCD_BUS] = 0xf00 | (1 << 4); HDLCD[HDLCD_VBACK] = videomode->vback - 1; HDLCD[HDLCD_VSYNC] = videomode->vsync - 1; HDLCD[HDLCD_VDATA] = videomode->yres - 1; HDLCD[HDLCD_VFRONT] = videomode->vfront - 1; HDLCD[HDLCD_HBACK] = videomode->hback - 1; HDLCD[HDLCD_HSYNC] = videomode->hsync - 1; HDLCD[HDLCD_HDATA] = videomode->xres - 1; HDLCD[HDLCD_HFRONT] = videomode->hfront - 1; HDLCD[HDLCD_POLARITIES] = (1 << 2) | (1 << 3); HDLCD[HDLCD_RED] = (c->red_size << 8) | c->red_shift; HDLCD[HDLCD_GREEN] = (c->green_size << 8) | c->green_shift; HDLCD[HDLCD_BLUE] = (c->blue_size << 8) | c->blue_shift; HDLCD[HDLCD_COMMAND] = 1; clear_fixmap(FIXMAP_MISC); lfbp.pixel_on = (((1 << c->red_size) - 1) << c->red_shift) | (((1 << c->green_size) - 1) << c->green_shift) | (((1 << c->blue_size) - 1) << c->blue_shift); lfbp.lfb = lfb; lfbp.font = &font_vga_8x16; lfbp.bits_per_pixel = bytes_per_pixel*8; lfbp.bytes_per_line = bytes_per_pixel*videomode->xres; lfbp.width = videomode->xres; lfbp.height = videomode->yres; lfbp.flush = hdlcd_flush; lfbp.text_columns = videomode->xres / 8; lfbp.text_rows = videomode->yres / 16; if ( lfb_init(&lfbp) < 0 ) return; video_puts = lfb_scroll_puts; }
/* * Check if the /secure-chosen node in the DT contains an stdout-path value * for which we have a compatible driver. If so, switch the console to * this device. */ void configure_console_from_dt(unsigned long phys_fdt) { const struct dt_driver *dt_drv; const struct serial_driver *sdrv; const struct fdt_property *prop; struct serial_chip *dev; char *stdout_data; const char *uart; const char *parms = NULL; void *fdt; int offs; char *p; if (!phys_fdt) return; fdt = phys_to_virt(phys_fdt, MEM_AREA_IO_NSEC); if (!fdt) panic(); offs = fdt_path_offset(fdt, "/secure-chosen"); if (offs < 0) return; prop = fdt_get_property(fdt, offs, "stdout-path", NULL); if (!prop) { /* * /secure-chosen node present but no stdout-path property * means we don't want any console output */ IMSG("Switching off console"); register_serial_console(NULL); return; } stdout_data = strdup(prop->data); if (!stdout_data) return; p = strchr(stdout_data, ':'); if (p) { *p = '\0'; parms = p + 1; } /* stdout-path may refer to an alias */ uart = fdt_get_alias(fdt, stdout_data); if (!uart) { /* Not an alias, assume we have a node path */ uart = stdout_data; } offs = fdt_path_offset(fdt, uart); if (offs < 0) goto out; dt_drv = dt_find_compatible_driver(fdt, offs); if (!dt_drv) goto out; sdrv = (const struct serial_driver *)dt_drv->driver; if (!sdrv) goto out; dev = sdrv->dev_alloc(); if (!dev) goto out; /* * If the console is the same as the early console, dev_init() might * clear pending data. Flush to avoid that. */ console_flush(); if (sdrv->dev_init(dev, fdt, offs, parms) < 0) { sdrv->dev_free(dev); goto out; } IMSG("Switching console to device: %s", uart); register_serial_console(dev); out: free(stdout_data); }
static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat) { int err; qemu_irq irq; hwaddr base; int offset; DeviceState *dev; char *dev_type = NULL; int is_intc; int i; dev = fdt_create_qdev_from_compat(compat, &dev_type); if (!dev) { DB_PRINT("no match found for %s\n", compat); return 1; } /* FIXME: attach to the sysbus instead */ object_property_add_child(container_get(qdev_get_machine(), "/unattached"), qemu_fdt_get_node_name(fdti->fdt, node_path), OBJECT(dev), NULL); fdt_init_set_opaque(fdti, node_path, dev); /* connect nic if appropriate */ static int nics; if (object_property_find(OBJECT(dev), "mac", NULL)) { qdev_set_nic_properties(dev, &nd_table[nics]); if (nd_table[nics].instantiated) { DB_PRINT("NIC instantiated: %s\n", dev_type); nics++; } } offset = fdt_path_offset(fdti->fdt, node_path); for (offset = fdt_first_property_offset(fdti->fdt, offset); offset != -FDT_ERR_NOTFOUND; offset = fdt_next_property_offset(fdti->fdt, offset)) { const char *propname; int len; const void *val = fdt_getprop_by_offset(fdti->fdt, offset, &propname, &len); propname = trim_vendor(propname); ObjectProperty *p = object_property_find(OBJECT(dev), propname, NULL); if (p) { DB_PRINT("matched property: %s of type %s, len %d\n", propname, p->type, len); } if (!p) { continue; } /* FIXME: handle generically using accessors and stuff */ if (!strcmp(p->type, "uint8") || !strcmp(p->type, "uint16") || !strcmp(p->type, "uint32") || !strcmp(p->type, "uint64")) { uint64_t offset = (!strcmp(propname, "reg")) ? fdt_get_parent_base(node_path, fdti) : 0; object_property_set_int(OBJECT(dev), get_int_be(val, len) + offset, propname, &error_abort); DB_PRINT("set property %s to %#llx\n", propname, (long long unsigned int)get_int_be(val, len)); } else if (!strcmp(p->type, "bool")) { object_property_set_bool(OBJECT(dev), !!get_int_be(val, len), propname, &error_abort); DB_PRINT("set property %s to %#llx\n", propname, (long long unsigned int)get_int_be(val, len)); } else if (!strncmp(p->type, "link", 4)) { char target_node_path[DT_PATH_LENGTH]; DeviceState *linked_dev; if (qemu_fdt_get_node_by_phandle(fdti->fdt, target_node_path, get_int_be(val, len))) { abort(); } while (!fdt_init_has_opaque(fdti, target_node_path)) { fdt_init_yield(fdti); } linked_dev = fdt_init_get_opaque(fdti, target_node_path); object_property_set_link(OBJECT(dev), OBJECT(linked_dev), propname, &error_abort); } else if (!strcmp(p->type, "string")) { object_property_set_str(OBJECT(dev), strndup(val, len), propname, &error_abort); } } qdev_init_nofail(dev); /* map slave attachment */ base = qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg", 0, false, &error_abort); base += fdt_get_parent_base(node_path, fdti); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); { int len; fdt_get_property(fdti->fdt, fdt_path_offset(fdti->fdt, node_path), "interrupt-controller", &len); is_intc = len >= 0; DB_PRINT("is interrupt controller: %c\n", is_intc ? 'y' : 'n'); } /* connect irq */ for (i = 0; ; ++i) { char irq_info[1024]; irq = fdt_get_irq_info(fdti, node_path, i, &err, irq_info); /* INTCs inferr their top level, if no IRQ connection specified */ if (err && is_intc) { irq = fdti->irq_base; sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); fprintf(stderr, "FDT: (%s) connected top level irq %s\n", dev_type, irq_info); break; } if (!err) { sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); fprintf(stderr, "FDT: (%s) connected irq %s\n", dev_type, irq_info); } else { break; } } if (dev_type) { g_free(dev_type); } return 0; }
void fdt_fixup_ethernet(void *fdt) { int i = 0, j, prop; char *tmp, *end; char mac[16]; const char *path; unsigned char mac_addr[ARP_HLEN]; int offset; #ifdef FDT_SEQ_MACADDR_FROM_ENV int nodeoff; const struct fdt_property *fdt_prop; #endif if (fdt_path_offset(fdt, "/aliases") < 0) return; /* Cycle through all aliases */ for (prop = 0; ; prop++) { const char *name; /* FDT might have been edited, recompute the offset */ offset = fdt_first_property_offset(fdt, fdt_path_offset(fdt, "/aliases")); /* Select property number 'prop' */ for (j = 0; j < prop; j++) offset = fdt_next_property_offset(fdt, offset); if (offset < 0) break; path = fdt_getprop_by_offset(fdt, offset, &name, NULL); if (!strncmp(name, "ethernet", 8)) { /* Treat plain "ethernet" same as "ethernet0". */ if (!strcmp(name, "ethernet") #ifdef FDT_SEQ_MACADDR_FROM_ENV || !strcmp(name, "ethernet0") #endif ) i = 0; #ifndef FDT_SEQ_MACADDR_FROM_ENV else i = trailing_strtol(name); #endif if (i != -1) { if (i == 0) strcpy(mac, "ethaddr"); else sprintf(mac, "eth%daddr", i); } else { continue; } #ifdef FDT_SEQ_MACADDR_FROM_ENV nodeoff = fdt_path_offset(fdt, path); fdt_prop = fdt_get_property(fdt, nodeoff, "status", NULL); if (fdt_prop && !strcmp(fdt_prop->data, "disabled")) continue; i++; #endif tmp = env_get(mac); if (!tmp) continue; for (j = 0; j < 6; j++) { mac_addr[j] = tmp ? simple_strtoul(tmp, &end, 16) : 0; if (tmp) tmp = (*end) ? end + 1 : end; } do_fixup_by_path(fdt, path, "mac-address", &mac_addr, 6, 0); do_fixup_by_path(fdt, path, "local-mac-address", &mac_addr, 6, 1); } } }
static int sun4i_spi_parse_pins(struct udevice *dev) { const void *fdt = gd->fdt_blob; const char *pin_name; const fdt32_t *list; u32 phandle; int drive, pull = 0, pin, i; int offset; int size; list = fdt_getprop(fdt, dev_of_offset(dev), "pinctrl-0", &size); if (!list) { printf("WARNING: sun4i_spi: cannot find pinctrl-0 node\n"); return -EINVAL; } while (size) { phandle = fdt32_to_cpu(*list++); size -= sizeof(*list); offset = fdt_node_offset_by_phandle(fdt, phandle); if (offset < 0) return offset; drive = fdt_getprop_u32_default_node(fdt, offset, 0, "drive-strength", 0); if (drive) { if (drive <= 10) drive = 0; else if (drive <= 20) drive = 1; else if (drive <= 30) drive = 2; else drive = 3; } else { drive = fdt_getprop_u32_default_node(fdt, offset, 0, "allwinner,drive", 0); drive = min(drive, 3); } if (fdt_get_property(fdt, offset, "bias-disable", NULL)) pull = 0; else if (fdt_get_property(fdt, offset, "bias-pull-up", NULL)) pull = 1; else if (fdt_get_property(fdt, offset, "bias-pull-down", NULL)) pull = 2; else pull = fdt_getprop_u32_default_node(fdt, offset, 0, "allwinner,pull", 0); pull = min(pull, 2); for (i = 0; ; i++) { pin_name = fdt_stringlist_get(fdt, offset, "pins", i, NULL); if (!pin_name) { pin_name = fdt_stringlist_get(fdt, offset, "allwinner,pins", i, NULL); if (!pin_name) break; } pin = name_to_gpio(pin_name); if (pin < 0) break; sunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0); sunxi_gpio_set_drv(pin, drive); sunxi_gpio_set_pull(pin, pull); } } return 0; }
static void fixup_irqs(void) { QEMUDevice *dev; QEMUDevice *parent; const struct fdt_property *prop; int len; int i; qemu_irq parent_irq; int is_qemu_irq = 0; uint32_t *data; for (dev = first_device; dev; dev = dev->next) { if (dev->dc->num_irqs) { parent = find_interrupt_parent(dev); if (!parent) { prop = fdt_get_property(dev->dt, dev->node_offset, "qemu,interrupts", &len); if (!prop) { invalid_devtree(dev, "missing interrupt-parent"); continue; } if (len != dev->dc->num_irqs * 8) { invalid_devtree(dev, "bad interrupts"); continue; } is_qemu_irq = 1; } else { prop = fdt_get_property(dev->dt, dev->node_offset, "interrupts", &len); if (!prop || len != dev->dc->num_irqs * 4) { invalid_devtree(dev, "bad/missing interrupts"); continue; } is_qemu_irq = 0; } data = (uint32_t *)prop->data; /* FIXME: Need to handle interrupt remapping. */ for (i = 0; i < dev->dc->num_irqs; i++) { uint32_t parent_irq_num; if (is_qemu_irq) { parent = find_device_by_phandle(fdt32_to_cpu(*data)); data++; if (!parent) { invalid_devtree(dev, "bad qemu,interrupts"); } check_interrupt_cells(parent); } parent_irq_num = fdt32_to_cpu(*data); data++; if (parent_irq_num >= parent->irq_sink_count) { invalid_devtree(dev, "bad interrupt number"); continue; } parent_irq = parent->irq_sink[parent_irq_num]; dev->irq[i] = parent_irq; if (dev->irqp[i]) *(dev->irqp[i]) = parent_irq; } } } }
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); }
static int unifykey_item_dt_parse(const void* dt_addr,int nodeoffset,int id,char *item_path) { struct key_item_t *temp_item=NULL; char *propdata; struct fdt_property *prop; int count; temp_item = unifykey_item + id; propdata = (char*)fdt_getprop(dt_addr, nodeoffset, "key-encrypt", NULL); if (propdata) { count = strlen(propdata); if ( count > KEY_UNIFY_TYPE_LEN_MAX ) { KM_ERR("key-encrypt [%s] too long\n", propdata); return __LINE__; } memcpy(temp_item->encType, propdata, count); } propdata = (char*)fdt_getprop(dt_addr, nodeoffset, "key-name",NULL); if (!propdata) { printf("%s get key-name fail,%s:%d\n",item_path,__func__,__LINE__); return __LINE__; } count = strlen(propdata); if (count >= KEY_UNIFY_NAME_LEN) { KM_ERR("key-name strlen (%d) > max(%d) at key_%d\n", count, KEY_UNIFY_NAME_LEN - 1, id); return __LINE__; } memcpy(temp_item->name, propdata, count); temp_item->name[count] = 0; propdata = (char*)fdt_getprop(dt_addr, nodeoffset, "key-device",NULL); if (!propdata) { KM_ERR("%s get key-device fail at key_%d\n",item_path, id); return __LINE__; } if (strcmp(propdata,UNIFYKEY_DEVICE_EFUSEKEY) == 0) { temp_item->dev = KEY_M_EFUSE_NORMAL; } else if(strcmp(propdata,UNIFYKEY_DEVICE_SECURESKEY) == 0){ temp_item->dev = KEY_M_SECURE_KEY; } else if(strcmp(propdata,UNIFYKEY_DEVICE_NORMAL) == 0){ temp_item->dev = KEY_M_NORAML_KEY; } else{ KM_ERR("key-device %s is unknown at key_%d\n", propdata, id); return __LINE__; } propdata = (char*)fdt_getprop((const void *)dt_addr, nodeoffset, "key-type",NULL); if (!propdata) //prop 'key-type' not configured, default to raw except special names { strcpy(temp_item->keyType, "raw"); } else { const int keyTypeLen = strlen(propdata); if (keyTypeLen > KEY_UNIFY_TYPE_LEN_MAX) { KM_ERR("key[%s]cfg key-type[%s] sz %d > max %d\n", temp_item->name, propdata, keyTypeLen, KEY_UNIFY_TYPE_LEN_MAX); return __LINE__; } strcpy(temp_item->keyType, propdata); } #if 0 propdata = (char*)fdt_getprop((const void *)dt_addr, nodeoffset, "key-dataformat",NULL); if (!propdata) { KM_ERR("%s get key-dataformat fail at key_%d\n",item_path, id); return __LINE__; } #endif prop = (struct fdt_property*)fdt_get_property((const void *)dt_addr,nodeoffset,"key-permit",NULL) ; if (!prop) { KM_ERR("%s get key-permit fail at key_%d\n",item_path, id); return __LINE__; } temp_item->permit = 0; const int propLen = prop->len > 512 ? strnlen(prop->data, 512) : prop->len; if (fdt_stringlist_contains(prop->data, propLen, UNIFYKEY_PERMIT_READ)) { temp_item->permit |= KEY_M_PERMIT_READ; } if (fdt_stringlist_contains(prop->data, propLen, UNIFYKEY_PERMIT_WRITE)) { temp_item->permit |= KEY_M_PERMIT_WRITE; } if (fdt_stringlist_contains(prop->data, propLen, UNIFYKEY_PERMIT_DEL)) { temp_item->permit |= KEY_M_PERMIT_DEL; } temp_item->id = id; KM_DBG("key[%02d] keyname %s, %d\n", id, temp_item->name, temp_item->dev); return 0; }
int fdt_psci(void *fdt) { #if defined(CONFIG_ARMV7_PSCI) || defined(CONFIG_ARMV8_PSCI) || \ defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI) int nodeoff; unsigned int psci_ver = 0; int tmp; nodeoff = fdt_path_offset(fdt, "/cpus"); if (nodeoff < 0) { printf("couldn't find /cpus\n"); return nodeoff; } /* add 'enable-method = "psci"' to each cpu node */ for (tmp = fdt_first_subnode(fdt, nodeoff); tmp >= 0; tmp = fdt_next_subnode(fdt, tmp)) { const struct fdt_property *prop; int len; prop = fdt_get_property(fdt, tmp, "device_type", &len); if (!prop) continue; if (len < 4) continue; if (strcmp(prop->data, "cpu")) continue; /* * Not checking rv here, our approach is to skip over errors in * individual cpu nodes, hopefully some of the nodes are * processed correctly and those will boot */ fdt_setprop_string(fdt, tmp, "enable-method", "psci"); } nodeoff = fdt_path_offset(fdt, "/psci"); if (nodeoff >= 0) goto init_psci_node; nodeoff = fdt_path_offset(fdt, "/"); if (nodeoff < 0) return nodeoff; nodeoff = fdt_add_subnode(fdt, nodeoff, "psci"); if (nodeoff < 0) return nodeoff; init_psci_node: #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT psci_ver = sec_firmware_support_psci_version(); #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI) psci_ver = ARM_PSCI_VER_1_0; #endif if (psci_ver >= ARM_PSCI_VER_1_0) { tmp = fdt_setprop_string(fdt, nodeoff, "compatible", "arm,psci-1.0"); if (tmp) return tmp; } if (psci_ver >= ARM_PSCI_VER_0_2) { tmp = fdt_appendprop_string(fdt, nodeoff, "compatible", "arm,psci-0.2"); if (tmp) return tmp; } #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT /* * The Secure firmware framework isn't able to support PSCI version 0.1. */ if (psci_ver < ARM_PSCI_VER_0_2) { tmp = fdt_appendprop_string(fdt, nodeoff, "compatible", "arm,psci"); if (tmp) return tmp; tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend", ARM_PSCI_FN_CPU_SUSPEND); if (tmp) return tmp; tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off", ARM_PSCI_FN_CPU_OFF); if (tmp) return tmp; tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on", ARM_PSCI_FN_CPU_ON); if (tmp) return tmp; tmp = fdt_setprop_u32(fdt, nodeoff, "migrate", ARM_PSCI_FN_MIGRATE); if (tmp) return tmp; } #endif tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc"); if (tmp) return tmp; #endif return 0; }
void update_partial_goods_dtb_nodes(void *fdt) { int i; int tbl_sz = sizeof(table) / sizeof(struct partial_goods); int parent_offset = 0; int subnode_offset = 0; int ret = 0; int prop_len = 0; uint32_t reg = readl(QFPROM_PTE_PART_ADDR); uint32_t prop_type = 0; struct subnode_list *subnode_lst = NULL; const struct fdt_property *prop = NULL; const char *replace_str = NULL; /* * The PTE register bits 23 to 27 have the partial goods * info, extract the partial goods value before using */ reg = (reg & 0x0f800000) >> 23; /* If none of the DTB needs update */ if (!reg) return; ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt)); if (ret != 0) { dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret); ASSERT(0); } for (i = 0; i < tbl_sz; i++) { if (reg == table[i].val) { /* Find the Parent node */ ret = fdt_path_offset(fdt, table[i].parent_node); if (ret < 0) { dprintf(CRITICAL, "Failed to get parent node: %s\terrno:%d\n", table[i].parent_node, ret); ASSERT(0); } parent_offset = ret; /* Find the subnode */ subnode_lst = table[i].subnode; while (subnode_lst->subnode) { ret = fdt_subnode_offset(fdt, parent_offset, subnode_lst->subnode); if (ret < 0) { dprintf(CRITICAL, "Failed to get subnode: %s\terrno:%d\n", subnode_lst->subnode, ret); ASSERT(0); } subnode_offset = ret; /* Find the property node and its length */ prop = fdt_get_property(fdt, subnode_offset, subnode_lst->property, &prop_len); if (!prop) { dprintf(CRITICAL, "Failed to get property: %s\terrno: %d\n", subnode_lst->property, prop_len); ASSERT(0); } /* * Replace the property value based on the property * length and type */ if (!(strncmp(subnode_lst->property, "device_type", sizeof(subnode_lst->property)))) prop_type = DEVICE_TYPE; else if ((!strncmp(subnode_lst->property, "status", sizeof(subnode_lst->property)))) prop_type = STATUS_TYPE; else { dprintf(CRITICAL, "%s: Property type is not supported\n", subnode_lst->property); ASSERT(0); } switch (prop_type) { case DEVICE_TYPE: replace_str = "nak"; break; case STATUS_TYPE: if (prop_len == sizeof("ok")) replace_str = "no"; else if (prop_len == sizeof("okay")) replace_str = "dsbl"; else { dprintf(CRITICAL, "Property value length: %u is invalid for property: %s\n", prop_len, subnode_lst->property); ASSERT(0); } break; default: /* Control would not come here, as this gets taken care while setting property type */ break; }; /* Replace the property with new value */ ret = fdt_setprop_inplace(fdt, subnode_offset, subnode_lst->property, (const void *)replace_str, prop_len); if (!ret) dprintf(INFO, "Updated device tree property: %s @ %s node\n", subnode_lst->property, subnode_lst->subnode); else { dprintf(CRITICAL, "Failed to update property: %s: error no: %d\n", subnode_lst->property, ret); ASSERT(0); } subnode_lst++; } } } fdt_pack(fdt); }
//__attribute__((no_sanitize("all"))) void kernel_start(uintptr_t magic, uintptr_t addrin) { kprintf("Magic %zx addrin %zx\n",magic,addrin); __init_sanity_checks(); cpu_print_current_el(); //its a "RAM address 0" const struct fdt_property *prop; int addr_cells = 0, size_cells = 0; int proplen; //TODO find this somewhere ?.. although it is at memory 0x00 uint64_t fdt_addr=0x40000000; char *fdt=(char*)fdt_addr; //OK so these get overidden in the for loop which should return a map of memory and not just a single one uint64_t addr = 0; uint64_t size = 0; //checks both magic and version if ( fdt_check_header(fdt) != 0 ) { kprint("FDT Header check failed\r\n"); return; } size_cells = fdt_size_cells(fdt,0); print_le_named32("size_cells :",(char *)&size_cells); addr_cells = fdt_address_cells(fdt, 0);//fdt32_ld((const fdt32_t *)prop->data); print_le_named32("addr_cells :",(char *)&addr_cells); const int mem_offset = fdt_path_offset(fdt, "/memory"); if (mem_offset < 0) return; print_le_named32("mem_offset :",(char *)&mem_offset); prop = fdt_get_property(fdt, mem_offset, "reg", &proplen); int cellslen = (int)sizeof(uint32_t) * (addr_cells + size_cells); for (int i = 0; i < proplen / cellslen; ++i) { for (int j = 0; j < addr_cells; ++j) { int offset = (cellslen * i) + (sizeof(uint32_t) * j); addr |= (uint64_t)fdt32_ld((const fdt32_t *)((char *)prop->data + offset)) << ((addr_cells - j - 1) * 32); } for (int j = 0; j < size_cells; ++j) { int offset = (cellslen * i) + (sizeof(uint32_t) * (j + addr_cells)); size |= (uint64_t)fdt32_ld((const fdt32_t *)((char *)prop->data + offset)) << ((size_cells - j - 1) * 32); } } print_le_named64("RAM BASE :",(char *)&addr); print_le_named64("RAM SIZE :",(char *)&size); uint64_t mem_end=addr+size; extern char _end; uintptr_t free_mem_begin = reinterpret_cast<uintptr_t>(&_end); //ok now its sane free_mem_begin += _move_symbols(free_mem_begin); // Initialize .bss _init_bss(); // Instantiate machine size_t memsize = mem_end - free_mem_begin; __machine = os::Machine::create((void*)free_mem_begin, memsize); _init_elf_parser(); // Begin portable HAL initialization __machine->init(); // Initialize system calls _init_syscalls(); //probably not very sane! cpu_debug_enable(); cpu_fiq_enable(); cpu_irq_enable(); cpu_serror_enable(); aarch64::init_libc((uintptr_t)fdt_addr); }