diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/Kconfig | 14 | ||||
-rw-r--r-- | drivers/core/fdtaddr.c | 6 | ||||
-rw-r--r-- | drivers/core/of_access.c | 65 | ||||
-rw-r--r-- | drivers/core/ofnode.c | 183 | ||||
-rw-r--r-- | drivers/core/read.c | 6 | ||||
-rw-r--r-- | drivers/core/util.c | 2 | ||||
-rw-r--r-- | drivers/misc/cros_ec_sandbox.c | 9 | ||||
-rw-r--r-- | drivers/pci/pci-uclass.c | 2 | ||||
-rw-r--r-- | drivers/pci/pci_mvebu.c | 3 | ||||
-rw-r--r-- | drivers/pci/pci_tegra.c | 2 | ||||
-rw-r--r-- | drivers/pci/pcie_mediatek.c | 4 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 2 | ||||
-rw-r--r-- | drivers/serial/ns16550.c | 21 |
13 files changed, 282 insertions, 37 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index f0d848f45d8..fe5c41d57ec 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -14,7 +14,7 @@ config SPL_DM help Enable driver model in SPL. You will need to provide a suitable malloc() implementation. If you are not using the - full malloc() enabled by CFG_SYS_SPL_MALLOC_START, + full malloc() enabled by CFG_SPL_SYS_MALLOC_START, consider using CONFIG_SPL_SYS_MALLOC_SIMPLE. In that case you must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size. In most cases driver model will only allocate a few uclasses @@ -27,12 +27,12 @@ config TPL_DM help Enable driver model in TPL. You will need to provide a suitable malloc() implementation. If you are not using the - full malloc() enabled by CFG_SYS_SPL_MALLOC_START, + full malloc() enabled by CFG_TPL_SYS_MALLOC_START, consider using CONFIG_TPL_SYS_MALLOC_SIMPLE. In that case you - must provide CONFIG_SPL_SYS_MALLOC_F_LEN to set the size. + must provide CONFIG_TPL_SYS_MALLOC_F_LEN to set the size. In most cases driver model will only allocate a few uclasses - and devices in SPL, so 1KB should be enough. See - CONFIG_SPL_SYS_MALLOC_F_LEN for more details on how to enable it. + and devices in TPL, so 1KB should be enough. See + CONFIG_TPL_SYS_MALLOC_F_LEN for more details on how to enable it. Disable this for very small implementations. config VPL_DM @@ -42,8 +42,8 @@ config VPL_DM help Enable driver model in VPL. You will need to provide a suitable malloc() implementation. If you are not using the - full malloc() enabled by CFG_SYS_SPL_MALLOC_START, - consider using CONFIG_SPL_SYS_MALLOC_SIMPLE. + full malloc() enabled by CFG_TPL_SYS_MALLOC_START, + consider using CONFIG_TPL_SYS_MALLOC_SIMPLE. config DM_WARN bool "Enable warnings in driver model" diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c index 546db675aaf..b79d138c419 100644 --- a/drivers/core/fdtaddr.c +++ b/drivers/core/fdtaddr.c @@ -215,7 +215,7 @@ void *devfdt_map_physmem(const struct udevice *dev, unsigned long size) return map_physmem(addr, size, MAP_NOCACHE); } -fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev) +fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep) { ulong addr; @@ -226,12 +226,12 @@ fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev) int ret; ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32, - "reg", &pci_addr); + "reg", &pci_addr, sizep); if (ret) { /* try if there is any i/o-mapped register */ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_IO, "reg", - &pci_addr); + &pci_addr, sizep); if (ret) return FDT_ADDR_T_NONE; } diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 1bb4d8eab70..c8db743f529 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -1040,3 +1040,68 @@ int of_add_subnode(struct device_node *parent, const char *name, int len, return 0; } + +int __of_remove_property(struct device_node *np, struct property *prop) +{ + struct property **next; + + for (next = &np->properties; *next; next = &(*next)->next) { + if (*next == prop) + break; + } + if (!*next) + return -ENODEV; + + /* found the node */ + *next = prop->next; + + return 0; +} + +int of_remove_property(struct device_node *np, struct property *prop) +{ + int rc; + + mutex_lock(&of_mutex); + + rc = __of_remove_property(np, prop); + + mutex_unlock(&of_mutex); + + return rc; +} + +int of_remove_node(struct device_node *to_remove) +{ + struct device_node *parent = to_remove->parent; + struct device_node *np, *prev; + + if (!parent) + return -EPERM; + prev = NULL; + __for_each_child_of_node(parent, np) { + if (np == to_remove) + break; + prev = np; + } + if (!np) + return -EFAULT; + + /* if there is a previous node, link it to this one's sibling */ + if (prev) + prev->sibling = np->sibling; + else + parent->child = np->sibling; + + /* + * don't free it, since if this is an unflattened tree, all the memory + * was alloced in one block; this pointer will be somewhere in the + * middle of that + * + * TODO(sjg@chromium.org): Consider marking nodes as 'allocated'? + * + * free(np); + */ + + return 0; +} diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 2cafa7bca5b..29a42945102 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -47,6 +47,17 @@ static int oftree_find(const void *fdt) return -1; } +static int check_tree_count(void) +{ + if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) { + log_warning("Too many registered device trees (max %d)\n", + CONFIG_OFNODE_MULTI_TREE_MAX); + return -E2BIG; + } + + return 0; +} + static oftree oftree_ensure(void *fdt) { oftree tree; @@ -69,11 +80,8 @@ static oftree oftree_ensure(void *fdt) if (gd->flags & GD_FLG_RELOC) { i = oftree_find(fdt); if (i == -1) { - if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) { - log_warning("Too many registered device trees (max %d)\n", - CONFIG_OFNODE_MULTI_TREE_MAX); + if (check_tree_count()) return oftree_null(); - } /* register the new tree */ i = oftree_count++; @@ -92,6 +100,41 @@ static oftree oftree_ensure(void *fdt) return tree; } +int oftree_new(oftree *treep) +{ + oftree tree = oftree_null(); + int ret; + + if (of_live_active()) { + struct device_node *root; + + ret = of_live_create_empty(&root); + if (ret) + return log_msg_ret("liv", ret); + tree = oftree_from_np(root); + } else { + const int size = 1024; + void *fdt; + + ret = check_tree_count(); + if (ret) + return log_msg_ret("fla", ret); + + /* register the new tree with a small size */ + fdt = malloc(size); + if (!fdt) + return log_msg_ret("fla", -ENOMEM); + ret = fdt_create_empty_tree(fdt, size); + if (ret) + return log_msg_ret("fla", -EINVAL); + oftree_list[oftree_count++] = fdt; + tree.fdt = fdt; + } + *treep = tree; + + return 0; +} + void oftree_dispose(oftree tree) { if (of_live_active()) @@ -193,8 +236,31 @@ static inline int oftree_find(const void *fdt) return 0; } +int oftree_new(oftree *treep) +{ + return -ENOSYS; +} + #endif /* OFNODE_MULTI_TREE */ +int oftree_to_fdt(oftree tree, struct abuf *buf) +{ + int ret; + + if (of_live_active()) { + ret = of_live_flatten(ofnode_to_np(oftree_root(tree)), buf); + if (ret) + return log_msg_ret("flt", ret); + } else { + void *fdt = oftree_lookup_fdt(tree); + + abuf_init(buf); + abuf_set(buf, fdt, fdt_totalsize(fdt)); + } + + return 0; +} + /** * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree) * @@ -425,12 +491,12 @@ u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def) bool ofnode_read_bool(ofnode node, const char *propname) { - const void *prop; + bool prop; assert(ofnode_valid(node)); debug("%s: %s: ", __func__, propname); - prop = ofnode_get_property(node, propname, NULL); + prop = ofnode_has_property(node, propname); debug("%s\n", prop ? "true" : "false"); @@ -1102,6 +1168,14 @@ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp) propname, lenp); } +bool ofnode_has_property(ofnode node, const char *propname) +{ + if (ofnode_is_np(node)) + return of_find_property(ofnode_to_np(node), propname, NULL); + else + return ofnode_get_property(node, propname, NULL); +} + int ofnode_first_property(ofnode node, struct ofprop *prop) { prop->node = node; @@ -1196,7 +1270,8 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, } int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, - const char *propname, struct fdt_pci_addr *addr) + const char *propname, struct fdt_pci_addr *addr, + fdt_size_t *size) { const fdt32_t *cell; int len; @@ -1224,14 +1299,18 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, (ulong)fdt32_to_cpu(cell[1]), (ulong)fdt32_to_cpu(cell[2])); if ((fdt32_to_cpu(*cell) & type) == type) { + const unaligned_fdt64_t *ptr; + addr->phys_hi = fdt32_to_cpu(cell[0]); addr->phys_mid = fdt32_to_cpu(cell[1]); addr->phys_lo = fdt32_to_cpu(cell[2]); + ptr = (const unaligned_fdt64_t *)(cell + 3); + if (size) + *size = fdt64_to_cpu(*ptr); break; } - cell += (FDT_PCI_ADDR_CELLS + - FDT_PCI_SIZE_CELLS); + cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS; } if (i == num) { @@ -1547,7 +1626,46 @@ int ofnode_write_u32(ofnode node, const char *propname, u32 value) return -ENOMEM; *val = cpu_to_fdt32(value); - return ofnode_write_prop(node, propname, val, sizeof(value), false); + return ofnode_write_prop(node, propname, val, sizeof(value), true); +} + +int ofnode_write_u64(ofnode node, const char *propname, u64 value) +{ + fdt64_t *val; + + assert(ofnode_valid(node)); + + log_debug("%s = %llx", propname, (unsigned long long)value); + val = malloc(sizeof(*val)); + if (!val) + return -ENOMEM; + *val = cpu_to_fdt64(value); + + return ofnode_write_prop(node, propname, val, sizeof(value), true); +} + +int ofnode_write_bool(ofnode node, const char *propname, bool value) +{ + if (value) + return ofnode_write_prop(node, propname, NULL, 0, false); + else + return ofnode_delete_prop(node, propname); +} + +int ofnode_delete_prop(ofnode node, const char *propname) +{ + if (ofnode_is_np(node)) { + struct property *prop; + int len; + + prop = of_find_property(ofnode_to_np(node), propname, &len); + if (prop) + return of_remove_property(ofnode_to_np(node), prop); + return 0; + } else { + return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node), + propname); + } } int ofnode_set_enabled(ofnode node, bool value) @@ -1731,7 +1849,30 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep) return ret; /* 0 or -EEXIST */ } -int ofnode_copy_props(ofnode src, ofnode dst) +int ofnode_delete(ofnode *nodep) +{ + ofnode node = *nodep; + int ret; + + assert(ofnode_valid(node)); + if (ofnode_is_np(node)) { + ret = of_remove_node(ofnode_to_np(node)); + } else { + void *fdt = ofnode_to_fdt(node); + int offset = ofnode_to_offset(node); + + ret = fdt_del_node(fdt, offset); + if (ret) + ret = -EFAULT; + } + if (ret) + return ret; + *nodep = ofnode_null(); + + return 0; +} + +int ofnode_copy_props(ofnode dst, ofnode src) { struct ofprop prop; @@ -1754,3 +1895,23 @@ int ofnode_copy_props(ofnode src, ofnode dst) return 0; } + +int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src, + ofnode *nodep) +{ + ofnode node; + int ret; + + ret = ofnode_add_subnode(dst_parent, name, &node); + if (ret) { + if (ret == -EEXIST) + *nodep = node; + return log_msg_ret("add", ret); + } + ret = ofnode_copy_props(node, src); + if (ret) + return log_msg_ret("cpy", ret); + *nodep = node; + + return 0; +} diff --git a/drivers/core/read.c b/drivers/core/read.c index 49066b59cda..419013451f0 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -405,13 +405,15 @@ int dev_read_alias_highest_id(const char *stem) return fdtdec_get_alias_highest_id(gd->fdt_blob, stem); } -fdt_addr_t dev_read_addr_pci(const struct udevice *dev) +fdt_addr_t dev_read_addr_pci(const struct udevice *dev, fdt_size_t *sizep) { ulong addr; addr = dev_read_addr(dev); + if (sizep) + *sizep = 0; if (addr == FDT_ADDR_T_NONE && !of_live_active()) - addr = devfdt_get_addr_pci(dev); + addr = devfdt_get_addr_pci(dev, sizep); return addr; } diff --git a/drivers/core/util.c b/drivers/core/util.c index aa60fdd15bc..81497df85ff 100644 --- a/drivers/core/util.c +++ b/drivers/core/util.c @@ -30,7 +30,7 @@ int pci_get_devfn(struct udevice *dev) /* Extract the devfn from fdt_pci_addr */ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG, - "reg", &addr); + "reg", &addr, NULL); if (ret) { if (ret != -ENOENT) return -EINVAL; diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 8dbe0b188a4..1201535f4af 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -81,6 +81,7 @@ struct ec_pwm_channel { /** * struct ec_state - Information about the EC state * + * @valid: true if this struct contains valid state data * @vbnv_context: Vboot context data stored by EC * @ec_config: FDT config information about the EC (e.g. flashmap) * @flash_data: Contents of flash memory @@ -95,6 +96,7 @@ struct ec_pwm_channel { * @pwm: Information per PWM channel */ struct ec_state { + bool valid; u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2]; struct fdt_cros_ec ec_config; uint8_t *flash_data; @@ -145,6 +147,7 @@ static int cros_ec_read_state(const void *blob, int node) memcpy(ec->flash_data, prop, len); debug("%s: Loaded EC flash data size %#x\n", __func__, len); } + ec->valid = true; return 0; } @@ -589,6 +592,7 @@ static int process_cmd(struct ec_state *ec, printf(" ** Unknown EC command %#02x\n", req_hdr->command); return -1; } + debug(" - EC command %#0x, result %d\n", req_hdr->command, len); return len; } @@ -675,7 +679,10 @@ int cros_ec_probe(struct udevice *dev) ofnode node; int err; - memcpy(ec, &s_state, sizeof(*ec)); + if (s_state.valid) + memcpy(ec, &s_state, sizeof(*ec)); + else + ec->current_image = EC_IMAGE_RO; err = cros_ec_decode_ec_flash(dev, &ec->ec_config); if (err) { debug("%s: Cannot device EC flash\n", __func__); diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index ae7350aaff9..e0d01f6a85d 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -123,7 +123,7 @@ static void pci_dev_find_ofnode(struct udevice *bus, phys_addr_t bdf, dev_for_each_subnode(node, bus) { ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", - &addr); + &addr, NULL); if (ret) continue; diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 3697cd8d652..83559550e6f 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -641,7 +641,8 @@ static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pci pcie->is_x4 = true; /* devfn is in bits [15:8], see PCI_DEV usage */ - ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr); + ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr, + NULL); if (ret < 0) { printf("%s: property \"reg\" is invalid\n", pcie->name); goto err; diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 131c21b7684..d6374a58e33 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -462,7 +462,7 @@ static int tegra_pcie_parse_port_info(ofnode node, uint *index, uint *lanes) *lanes = err; - err = ofnode_read_pci_addr(node, 0, "reg", &addr); + err = ofnode_read_pci_addr(node, 0, "reg", &addr, NULL); if (err < 0) { pr_err("failed to parse \"reg\" property\n"); return err; diff --git a/drivers/pci/pcie_mediatek.c b/drivers/pci/pcie_mediatek.c index ed25a10bcf0..f0f34b5d119 100644 --- a/drivers/pci/pcie_mediatek.c +++ b/drivers/pci/pcie_mediatek.c @@ -661,7 +661,7 @@ static int mtk_pcie_probe(struct udevice *dev) if (!ofnode_is_enabled(subnode)) continue; - err = ofnode_read_pci_addr(subnode, 0, "reg", &addr); + err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL); if (err) return err; @@ -700,7 +700,7 @@ static int mtk_pcie_probe_v2(struct udevice *dev) if (!ofnode_is_enabled(subnode)) continue; - err = ofnode_read_pci_addr(subnode, 0, "reg", &addr); + err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL); if (err) return err; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 6cb6598f3d2..9f0f84c9b42 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -160,7 +160,6 @@ config SERIAL_PROBE_ALL config SPL_DM_SERIAL bool "Enable Driver Model for serial drivers in SPL" depends on DM_SERIAL && SPL_DM - select SYS_SPL_MALLOC_F default y help Enable driver model for serial in SPL. This replaces @@ -171,7 +170,6 @@ config SPL_DM_SERIAL config TPL_DM_SERIAL bool "Enable Driver Model for serial drivers in TPL" depends on DM_SERIAL && TPL_DM - select SYS_TPL_MALLOC_F default y if TPL && DM_SERIAL help Enable driver model for serial in TPL. This replaces diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index eab9537fbae..6deb1d8ddc5 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -13,6 +13,7 @@ #include <ns16550.h> #include <reset.h> #include <serial.h> +#include <spl.h> #include <watchdog.h> #include <asm/global_data.h> #include <linux/err.h> @@ -472,6 +473,10 @@ static int ns16550_serial_getinfo(struct udevice *dev, struct ns16550 *const com_port = dev_get_priv(dev); struct ns16550_plat *plat = com_port->plat; + /* save code size */ + if (!spl_in_proper()) + return -ENOSYS; + info->type = SERIAL_CHIP_16550_COMPATIBLE; #ifdef CONFIG_SYS_NS16550_PORT_MAPPED info->addr_space = SERIAL_ADDRESS_SPACE_IO; @@ -479,6 +484,7 @@ static int ns16550_serial_getinfo(struct udevice *dev, info->addr_space = SERIAL_ADDRESS_SPACE_MEMORY; #endif info->addr = plat->base; + info->size = plat->size; info->reg_width = plat->reg_width; info->reg_shift = plat->reg_shift; info->reg_offset = plat->reg_offset; @@ -487,7 +493,8 @@ static int ns16550_serial_getinfo(struct udevice *dev, return 0; } -static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base) +static int ns16550_serial_assign_base(struct ns16550_plat *plat, + fdt_addr_t base, fdt_size_t size) { if (base == FDT_ADDR_T_NONE) return -EINVAL; @@ -497,6 +504,7 @@ static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base #else plat->base = (unsigned long)map_physmem(base, 0, MAP_NOCACHE); #endif + plat->size = size; return 0; } @@ -507,6 +515,7 @@ int ns16550_serial_probe(struct udevice *dev) struct ns16550 *const com_port = dev_get_priv(dev); struct reset_ctl_bulk reset_bulk; fdt_addr_t addr; + fdt_addr_t size; int ret; /* @@ -514,8 +523,8 @@ int ns16550_serial_probe(struct udevice *dev) * or via a PCI bridge, assign plat->base before probing hardware. */ if (device_is_on_pci_bus(dev)) { - addr = devfdt_get_addr_pci(dev); - ret = ns16550_serial_assign_base(plat, addr); + addr = devfdt_get_addr_pci(dev, &size); + ret = ns16550_serial_assign_base(plat, addr, size); if (ret) return ret; } @@ -542,12 +551,14 @@ int ns16550_serial_of_to_plat(struct udevice *dev) { struct ns16550_plat *plat = dev_get_plat(dev); const u32 port_type = dev_get_driver_data(dev); + fdt_size_t size = 0; fdt_addr_t addr; struct clk clk; int err; - addr = dev_read_addr(dev); - err = ns16550_serial_assign_base(plat, addr); + addr = spl_in_proper() ? dev_read_addr_size(dev, &size) : + dev_read_addr(dev); + err = ns16550_serial_assign_base(plat, addr, size); if (err && !device_is_on_pci_bus(dev)) return err; |