Bläddra i källkod

Merge git://git.denx.de/u-boot-dm

Tom Rini 7 år sedan
förälder
incheckning
15616a0aa5
61 ändrade filer med 1638 tillägg och 62 borttagningar
  1. 6 0
      Makefile
  2. 4 2
      arch/arm/config.mk
  3. 7 0
      arch/arm/cpu/u-boot-spl.lds
  4. 40 0
      arch/arm/dts/tegra-u-boot.dtsi
  5. 3 0
      arch/arm/dts/tegra114-u-boot.dtsi
  6. 2 0
      arch/arm/dts/tegra124-nyan-big-u-boot.dtsi
  7. 3 0
      arch/arm/dts/tegra124-u-boot.dtsi
  8. 3 8
      arch/arm/dts/tegra20-u-boot.dtsi
  9. 3 0
      arch/arm/dts/tegra210-u-boot.dtsi
  10. 3 0
      arch/arm/dts/tegra30-u-boot.dtsi
  11. 1 0
      arch/arm/mach-tegra/Kconfig
  12. 6 0
      arch/sandbox/dts/sandbox_pmic.dtsi
  13. 14 2
      common/spl/spl.c
  14. 15 4
      common/spl/spl_ram.c
  15. 14 2
      doc/device-tree-bindings/regulator/regulator.txt
  16. 4 3
      drivers/block/blk-uclass.c
  17. 8 0
      drivers/power/pmic/Kconfig
  18. 1 0
      drivers/power/pmic/Makefile
  19. 9 2
      drivers/power/pmic/pmic-uclass.c
  20. 98 0
      drivers/power/pmic/pmic_tps65910_dm.c
  21. 8 0
      drivers/power/regulator/Kconfig
  22. 1 0
      drivers/power/regulator/Makefile
  23. 459 0
      drivers/power/regulator/tps65910_regulator.c
  24. 1 1
      drivers/sysreset/sysreset-uclass.c
  25. 93 0
      include/binman_sym.h
  26. 4 1
      include/power/sandbox_pmic.h
  27. 130 0
      include/power/tps65910_pmic.h
  28. 11 0
      include/spl.h
  29. 2 0
      test/dm/regulator.c
  30. 31 1
      tools/binman/README
  31. 8 3
      tools/binman/binman.py
  32. 3 0
      tools/binman/control.py
  33. 129 0
      tools/binman/elf.py
  34. 122 0
      tools/binman/elf_test.py
  35. 8 0
      tools/binman/etype/entry.py
  36. 6 0
      tools/binman/etype/u_boot_spl.py
  37. 4 3
      tools/binman/etype/u_boot_spl_bss_pad.py
  38. 17 0
      tools/binman/etype/u_boot_spl_dtb.py
  39. 17 0
      tools/binman/etype/u_boot_spl_nodtb.py
  40. 4 5
      tools/binman/etype/u_boot_with_ucode_ptr.py
  41. 57 11
      tools/binman/ftest.py
  42. 76 3
      tools/binman/image.py
  43. 46 0
      tools/binman/image_test.py
  44. 1 1
      tools/binman/test/21_image_pad.dts
  45. 2 2
      tools/binman/test/24_sorted.dts
  46. 2 2
      tools/binman/test/28_pack_4gb_outside.dts
  47. 3 3
      tools/binman/test/29_x86-rom.dts
  48. 13 0
      tools/binman/test/51_u_boot_spl_dtb.dts
  49. 11 0
      tools/binman/test/52_u_boot_spl_nodtb.dts
  50. 20 0
      tools/binman/test/53_symbols.dts
  51. 17 1
      tools/binman/test/Makefile
  52. 1 1
      tools/binman/test/bss_data.c
  53. BIN
      tools/binman/test/u_boot_binman_syms
  54. 14 0
      tools/binman/test/u_boot_binman_syms.c
  55. 30 0
      tools/binman/test/u_boot_binman_syms.lds
  56. BIN
      tools/binman/test/u_boot_binman_syms_bad
  57. 1 0
      tools/binman/test/u_boot_binman_syms_bad.c
  58. 29 0
      tools/binman/test/u_boot_binman_syms_bad.lds
  59. BIN
      tools/binman/test/u_boot_binman_syms_size
  60. 12 0
      tools/binman/test/u_boot_binman_syms_size.c
  61. 1 1
      tools/binman/test/u_boot_ucode_ptr.c

+ 6 - 0
Makefile

@@ -1149,6 +1149,11 @@ u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE
 endif
 
 ifneq ($(CONFIG_TEGRA),)
+ifneq ($(CONFIG_BINMAN),)
+u-boot-dtb-tegra.bin u-boot-tegra.bin u-boot-nodtb-tegra.bin: \
+		spl/u-boot-spl u-boot.bin FORCE
+	$(call if_changed,binman)
+else
 OBJCOPYFLAGS_u-boot-nodtb-tegra.bin = -O binary --pad-to=$(CONFIG_SYS_TEXT_BASE)
 u-boot-nodtb-tegra.bin: spl/u-boot-spl u-boot-nodtb.bin FORCE
 	$(call if_changed,pad_cat)
@@ -1159,6 +1164,7 @@ u-boot-tegra.bin: spl/u-boot-spl u-boot.bin FORCE
 
 u-boot-dtb-tegra.bin: u-boot-tegra.bin FORCE
 	$(call if_changed,copy)
+endif  # binman
 endif
 
 OBJCOPYFLAGS_u-boot-app.efi := $(OBJCOPYFLAGS_EFI)

+ 4 - 2
arch/arm/config.mk

@@ -136,10 +136,12 @@ endif
 # limit ourselves to the sections we want in the .bin.
 ifdef CONFIG_ARM64
 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .data \
-		-j .u_boot_list -j .rela.dyn -j .got -j .got.plt
+		-j .u_boot_list -j .rela.dyn -j .got -j .got.plt \
+		-j .binman_sym_table
 else
 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \
-		-j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn
+		-j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn \
+		-j .binman_sym_table
 endif
 
 # if a dtb section exists we always have to include it

+ 7 - 0
arch/arm/cpu/u-boot-spl.lds

@@ -36,6 +36,13 @@ SECTIONS
 		KEEP(*(SORT(.u_boot_list*)));
 	}
 
+	. = ALIGN(4);
+	.binman_sym_table : {
+		__binman_sym_start = .;
+		KEEP(*(SORT(.binman_sym*)));
+		__binman_sym_end = .;
+	}
+
 	. = ALIGN(4);
 
 	__image_copy_end = .;

+ 40 - 0
arch/arm/dts/tegra-u-boot.dtsi

@@ -0,0 +1,40 @@
+#include <config.h>
+
+/ {
+	binman {
+		multiple-images;
+		image1 {
+			filename = "u-boot-tegra.bin";
+			pad-byte = <0xff>;
+			u-boot-spl {
+			};
+			u-boot {
+				pos = <(CONFIG_SYS_TEXT_BASE -
+					CONFIG_SPL_TEXT_BASE)>;
+			};
+		};
+
+		/* Same as image1 - some tools still expect the -dtb suffix */
+		image2 {
+			filename = "u-boot-dtb-tegra.bin";
+			pad-byte = <0xff>;
+			u-boot-spl {
+			};
+			u-boot {
+				pos = <(CONFIG_SYS_TEXT_BASE -
+					CONFIG_SPL_TEXT_BASE)>;
+			};
+		};
+
+		image3 {
+			filename = "u-boot-nodtb-tegra.bin";
+			pad-byte = <0xff>;
+			u-boot-spl {
+			};
+			u-boot-nodtb {
+				pos = <(CONFIG_SYS_TEXT_BASE -
+					CONFIG_SPL_TEXT_BASE)>;
+			};
+		};
+	};
+};

+ 3 - 0
arch/arm/dts/tegra114-u-boot.dtsi

@@ -0,0 +1,3 @@
+#include <config.h>
+
+#include "tegra-u-boot.dtsi"

+ 2 - 0
arch/arm/dts/tegra124-nyan-big-u-boot.dtsi

@@ -5,6 +5,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#include "tegra-u-boot.dtsi"
+
 / {
 	host1x@50000000 {
 		u-boot,dm-pre-reloc;

+ 3 - 0
arch/arm/dts/tegra124-u-boot.dtsi

@@ -0,0 +1,3 @@
+#include <config.h>
+
+#include "tegra-u-boot.dtsi"

+ 3 - 8
arch/arm/dts/tegra20-u-boot.dtsi

@@ -1,8 +1,3 @@
-/ {
-	host1x@50000000 {
-		u-boot,dm-pre-reloc;
-		dc@54200000 {
-			u-boot,dm-pre-reloc;
-		};
-	};
-};
+#include <config.h>
+
+#include "tegra-u-boot.dtsi"

+ 3 - 0
arch/arm/dts/tegra210-u-boot.dtsi

@@ -0,0 +1,3 @@
+#include <config.h>
+
+#include "tegra-u-boot.dtsi"

+ 3 - 0
arch/arm/dts/tegra30-u-boot.dtsi

@@ -0,0 +1,3 @@
+#include <config.h>
+
+#include "tegra-u-boot.dtsi"

+ 1 - 0
arch/arm/mach-tegra/Kconfig

@@ -38,6 +38,7 @@ config TEGRA_COMMON
 	select OF_CONTROL
 	select VIDCONSOLE_AS_LCD if DM_VIDEO
 	select BOARD_EARLY_INIT_F
+	select BINMAN
 	imply CRC32_VERIFY
 
 config TEGRA_NO_BPMP

+ 6 - 0
arch/sandbox/dts/sandbox_pmic.dtsi

@@ -75,4 +75,10 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 	};
+
+	no_match_by_nodename {
+		regulator-name = "buck_SUPPLY_1.5V";
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <1500000>;
+	};
 };

+ 14 - 2
common/spl/spl.c

@@ -8,6 +8,7 @@
  */
 
 #include <common.h>
+#include <binman_sym.h>
 #include <dm.h>
 #include <spl.h>
 #include <asm/u-boot.h>
@@ -32,6 +33,9 @@ DECLARE_GLOBAL_DATA_PTR;
 
 u32 *boot_params_ptr = NULL;
 
+/* See spl.h for information about this */
+binman_sym_declare(ulong, u_boot_any, pos);
+
 /* Define board data structure */
 static bd_t bdata __attribute__ ((section(".data")));
 
@@ -120,9 +124,17 @@ __weak void spl_board_prepare_for_boot(void)
 
 void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
 {
+	ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
+
 	spl_image->size = CONFIG_SYS_MONITOR_LEN;
-	spl_image->entry_point = CONFIG_SYS_UBOOT_START;
-	spl_image->load_addr = CONFIG_SYS_TEXT_BASE;
+	if (u_boot_pos != BINMAN_SYM_MISSING) {
+		/* biman does not support separate entry addresses at present */
+		spl_image->entry_point = u_boot_pos;
+		spl_image->load_addr = u_boot_pos;
+	} else {
+		spl_image->entry_point = CONFIG_SYS_UBOOT_START;
+		spl_image->load_addr = CONFIG_SYS_TEXT_BASE;
+	}
 	spl_image->os = IH_OS_U_BOOT;
 	spl_image->name = "U-Boot";
 }

+ 15 - 4
common/spl/spl_ram.c

@@ -11,6 +11,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 #include <common.h>
+#include <binman_sym.h>
+#include <mapmem.h>
 #include <spl.h>
 #include <libfdt.h>
 
@@ -48,15 +50,24 @@ static int spl_ram_load_image(struct spl_image_info *spl_image,
 		load.read = spl_ram_load_read;
 		spl_load_simple_fit(spl_image, &load, 0, header);
 	} else {
+		ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
+
 		debug("Legacy image\n");
 		/*
 		 * Get the header.  It will point to an address defined by
 		 * handoff which will tell where the image located inside
-		 * the flash. For now, it will temporary fixed to address
-		 * pointed by U-Boot.
+		 * the flash.
 		 */
-		header = (struct image_header *)
-			(CONFIG_SYS_TEXT_BASE -	sizeof(struct image_header));
+		debug("u_boot_pos = %lx\n", u_boot_pos);
+		if (u_boot_pos == BINMAN_SYM_MISSING) {
+			/*
+			 * No binman support or no information. For now, fix it
+			 * to the address pointed to by U-Boot.
+			 */
+			u_boot_pos = CONFIG_SYS_TEXT_BASE -
+					sizeof(struct image_header);
+		}
+		header = (struct image_header *)map_sysmem(u_boot_pos, 0);
 
 		spl_parse_image_header(spl_image, header);
 	}

+ 14 - 2
doc/device-tree-bindings/regulator/regulator.txt

@@ -2,7 +2,8 @@ Voltage/Current regulator
 
 Binding:
 The regulator devices don't use the "compatible" property. The binding is done
-by the prefix of regulator node's name. Usually the pmic I/O driver will provide
+by the prefix of regulator node's name, or, if this fails, by the prefix of the
+regulator's "regulator-name" property. Usually the pmic I/O driver will provide
 the array of 'struct pmic_child_info' with the prefixes and compatible drivers.
 The bind is done by calling function: pmic_bind_childs().
 Example drivers:
@@ -15,8 +16,19 @@ For the node name e.g.: "prefix[:alpha:]num { ... }":
 
 Example the prefix "ldo" will pass for: "ldo1", "ldo@1", "ldoreg@1, ...
 
+Binding by means of the node's name is preferred. However if the node names
+would produce ambiguous prefixes (like "regulator@1" and "regualtor@11") and you
+can't or do not want to change them then binding against the "regulator-name"
+property is possible. The syntax for the prefix of the "regulator-name" property
+is the same as the one for the regulator's node name.
+Use case: a regulator named "regulator@1" to be bound to a driver named
+"LDO_DRV" and a regulator named "regualator@11" to be bound to an other driver
+named "BOOST_DRV". Using prefix "regualtor@1" for driver matching would load
+the same driver for both regulators, hence the prefix is ambiguous.
+
 Optional properties:
-- regulator-name: a string, required by the regulator uclass
+- regulator-name: a string, required by the regulator uclass, used for driver
+                  binding if binding by node's name prefix fails
 - regulator-min-microvolt: a minimum allowed Voltage value
 - regulator-max-microvolt: a maximum allowed Voltage value
 - regulator-min-microamp: a minimum allowed Current value

+ 4 - 3
drivers/block/blk-uclass.c

@@ -10,6 +10,7 @@
 #include <dm.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
+#include <dm/uclass-internal.h>
 
 static const char *if_typename_str[IF_TYPE_COUNT] = {
 	[IF_TYPE_IDE]		= "ide",
@@ -331,7 +332,7 @@ int blk_first_device(int if_type, struct udevice **devp)
 	struct blk_desc *desc;
 	int ret;
 
-	ret = uclass_first_device(UCLASS_BLK, devp);
+	ret = uclass_find_first_device(UCLASS_BLK, devp);
 	if (ret)
 		return ret;
 	if (!*devp)
@@ -340,7 +341,7 @@ int blk_first_device(int if_type, struct udevice **devp)
 		desc = dev_get_uclass_platdata(*devp);
 		if (desc->if_type == if_type)
 			return 0;
-		ret = uclass_next_device(devp);
+		ret = uclass_find_next_device(devp);
 		if (ret)
 			return ret;
 	} while (*devp);
@@ -356,7 +357,7 @@ int blk_next_device(struct udevice **devp)
 	desc = dev_get_uclass_platdata(*devp);
 	if_type = desc->if_type;
 	do {
-		ret = uclass_next_device(devp);
+		ret = uclass_find_next_device(devp);
 		if (ret)
 			return ret;
 		if (!*devp)

+ 8 - 0
drivers/power/pmic/Kconfig

@@ -201,3 +201,11 @@ config POWER_MC34VR500
 	The MC34VR500 is used in conjunction with the FSL T1 and LS1 series
 	SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed
 	via an I2C interface.
+
+config DM_PMIC_TPS65910
+	bool "Enable driver for Texas Instruments TPS65910 PMIC"
+	depends on DM_PMIC
+	---help---
+	The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost
+	DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO
+	pmic children.

+ 1 - 0
drivers/power/pmic/Makefile

@@ -19,6 +19,7 @@ obj-$(CONFIG_PMIC_RK8XX) += rk8xx.o
 obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o
 obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
 obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
+obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o
 obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o
 obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
 obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o

+ 9 - 2
drivers/power/pmic/pmic-uclass.c

@@ -26,6 +26,7 @@ int pmic_bind_children(struct udevice *pmic, ofnode parent,
 	struct driver *drv;
 	struct udevice *child;
 	const char *node_name;
+	const char *reg_name;
 	int bind_count = 0;
 	ofnode node;
 	int prefix_len;
@@ -44,8 +45,14 @@ int pmic_bind_children(struct udevice *pmic, ofnode parent,
 			debug("  - compatible prefix: '%s'\n", info->prefix);
 
 			prefix_len = strlen(info->prefix);
-			if (strncmp(info->prefix, node_name, prefix_len))
-				continue;
+			if (strncmp(info->prefix, node_name, prefix_len)) {
+				reg_name = ofnode_read_string(node,
+							      "regulator-name");
+				if (!reg_name)
+					continue;
+				if (strncmp(info->prefix, reg_name, prefix_len))
+					continue;
+			}
 
 			drv = lists_driver_lookup_name(info->driver);
 			if (!drv) {

+ 98 - 0
drivers/power/pmic/pmic_tps65910_dm.c

@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65910_pmic.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+	{ .prefix = "ldo_", .driver = TPS65910_LDO_DRIVER },
+	{ .prefix = "buck_", .driver = TPS65910_BUCK_DRIVER },
+	{ .prefix = "boost_", .driver = TPS65910_BOOST_DRIVER },
+	{ },
+};
+
+static int pmic_tps65910_reg_count(struct udevice *dev)
+{
+	return TPS65910_NUM_REGS;
+}
+
+static int pmic_tps65910_write(struct udevice *dev, uint reg, const u8 *buffer,
+			       int len)
+{
+	int ret;
+
+	ret = dm_i2c_write(dev, reg, buffer, len);
+	if (ret)
+		error("%s write error on register %02x\n", dev->name, reg);
+
+	return ret;
+}
+
+static int pmic_tps65910_read(struct udevice *dev, uint reg, u8 *buffer,
+			      int len)
+{
+	int ret;
+
+	ret = dm_i2c_read(dev, reg, buffer, len);
+	if (ret)
+		error("%s read error on register %02x\n", dev->name, reg);
+
+	return ret;
+}
+
+static int pmic_tps65910_bind(struct udevice *dev)
+{
+	ofnode regulators_node;
+	int children;
+
+	regulators_node = dev_read_subnode(dev, "regulators");
+	if (!ofnode_valid(regulators_node)) {
+		debug("%s regulators subnode not found\n", dev->name);
+		return -EINVAL;
+	}
+
+	children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+	if (!children)
+		debug("%s has no children (regulators)\n", dev->name);
+
+	return 0;
+}
+
+static int pmic_tps65910_probe(struct udevice *dev)
+{
+	/* use I2C control interface instead of I2C smartreflex interface to
+	 * access smartrefelex registers VDD1_OP_REG, VDD1_SR_REG, VDD2_OP_REG
+	 * and VDD2_SR_REG
+	 */
+	return pmic_clrsetbits(dev, TPS65910_REG_DEVICE_CTRL, 0,
+			       TPS65910_I2C_SEL_MASK);
+}
+
+static struct dm_pmic_ops pmic_tps65910_ops = {
+	.reg_count = pmic_tps65910_reg_count,
+	.read = pmic_tps65910_read,
+	.write = pmic_tps65910_write,
+};
+
+static const struct udevice_id pmic_tps65910_match[] = {
+	{ .compatible = "ti,tps65910" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(pmic_tps65910) = {
+	.name = "pmic_tps65910",
+	.id = UCLASS_PMIC,
+	.of_match = pmic_tps65910_match,
+	.bind = pmic_tps65910_bind,
+	.probe = pmic_tps65910_probe,
+	.ops = &pmic_tps65910_ops,
+};

+ 8 - 0
drivers/power/regulator/Kconfig

@@ -188,3 +188,11 @@ config DM_REGULATOR_LP87565
 	LP87565 series of PMICs have 4 single phase BUCKs that can also
 	be configured in multi phase modes. The driver implements
 	get/set api for value and enable.
+
+config DM_REGULATOR_TPS65910
+	bool "Enable driver for TPS65910 PMIC regulators"
+	depends on DM_PMIC_TPS65910
+	---help---
+	The TPS65910 PMIC provides 4 SMPSs and 8 LDOs. This driver supports all
+	regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements
+	the get/set api for value and enable.

+ 1 - 0
drivers/power/regulator/Makefile

@@ -21,3 +21,4 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o
+obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o

+ 459 - 0
drivers/power/regulator/tps65910_regulator.c

@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65910_pmic.h>
+
+#define VOUT_CHOICE_COUNT 4
+
+/*
+ * struct regulator_props - Properties of a LDO and VIO SMPS regulator
+ *
+ * All of these regulators allow setting one out of four output voltages.
+ * These output voltages are only achievable when supplying the regulator
+ * with a minimum input voltage.
+ *
+ * @vin_min[]: minimum supply input voltage in uV required to achieve the
+ *             corresponding vout[] voltage
+ * @vout[]:    regulator output voltage in uV
+ * @reg:       I2C register used to set regulator voltage
+ */
+struct regulator_props {
+	int vin_min[VOUT_CHOICE_COUNT];
+	int vout[VOUT_CHOICE_COUNT];
+	int reg;
+};
+
+static const struct regulator_props ldo_props_vdig1 = {
+	.vin_min = { 1700000, 2100000, 2700000, 3200000 },
+	.vout = { 1200000, 1500000, 1800000, 2700000 },
+	.reg = TPS65910_REG_VDIG1
+};
+
+static const struct regulator_props ldo_props_vdig2 = {
+	.vin_min = { 1700000, 1700000, 1700000, 2700000 },
+	.vout = { 1000000, 1100000, 1200000, 1800000 },
+	.reg = TPS65910_REG_VDIG2
+};
+
+static const struct regulator_props ldo_props_vpll = {
+	.vin_min = { 2700000, 2700000, 2700000, 3000000 },
+	.vout = { 1000000, 1100000, 1800000, 2500000 },
+	.reg = TPS65910_REG_VPLL
+};
+
+static const struct regulator_props ldo_props_vdac = {
+	.vin_min = { 2700000, 3000000, 3200000, 3200000 },
+	.vout = { 1800000, 2600000, 2800000, 2850000 },
+	.reg = TPS65910_REG_VDAC
+};
+
+static const struct regulator_props ldo_props_vaux1 = {
+	.vin_min = { 2700000, 3200000, 3200000, 3200000 },
+	.vout = { 1800000, 2500000, 2800000, 2850000 },
+	.reg = TPS65910_REG_VAUX1
+};
+
+static const struct regulator_props ldo_props_vaux2 = {
+	.vin_min = { 2700000, 3200000, 3200000, 3600000 },
+	.vout = { 1800000, 2800000, 2900000, 3300000 },
+	.reg = TPS65910_REG_VAUX2
+};
+
+static const struct regulator_props ldo_props_vaux33 = {
+	.vin_min = { 2700000, 2700000, 3200000, 3600000 },
+	.vout = { 1800000, 2000000, 2800000, 3300000 },
+	.reg = TPS65910_REG_VAUX33
+};
+
+static const struct regulator_props ldo_props_vmmc = {
+	.vin_min = { 2700000, 3200000, 3200000, 3600000 },
+	.vout = { 1800000, 2800000, 3000000, 3300000 },
+	.reg = TPS65910_REG_VMMC
+};
+
+static const struct regulator_props smps_props_vio = {
+	.vin_min = { 3200000, 3200000, 4000000, 4400000 },
+	.vout = { 1500000, 1800000, 2500000, 3300000 },
+	.reg = TPS65910_REG_VIO
+};
+
+/* lookup table of control registers indexed by regulator unit number */
+static const int ctrl_regs[] = {
+	TPS65910_REG_VRTC,
+	TPS65910_REG_VIO,
+	TPS65910_REG_VDD1,
+	TPS65910_REG_VDD2,
+	TPS65910_REG_VDD3,
+	TPS65910_REG_VDIG1,
+	TPS65910_REG_VDIG2,
+	TPS65910_REG_VPLL,
+	TPS65910_REG_VDAC,
+	TPS65910_REG_VAUX1,
+	TPS65910_REG_VAUX2,
+	TPS65910_REG_VAUX33,
+	TPS65910_REG_VMMC
+};
+
+/* supply names as used in DT */
+static const char * const supply_names[] = {
+	"vccio-supply",
+	"vcc1-supply",
+	"vcc2-supply",
+	"vcc3-supply",
+	"vcc4-supply",
+	"vcc5-supply",
+	"vcc6-supply",
+	"vcc7-supply"
+};
+
+/* lookup table of regulator supplies indexed by regulator unit number */
+static const int regulator_supplies[] = {
+	TPS65910_SUPPLY_VCC7,
+	TPS65910_SUPPLY_VCCIO,
+	TPS65910_SUPPLY_VCC1,
+	TPS65910_SUPPLY_VCC2,
+	TPS65910_SUPPLY_VCC7,
+	TPS65910_SUPPLY_VCC6,
+	TPS65910_SUPPLY_VCC6,
+	TPS65910_SUPPLY_VCC5,
+	TPS65910_SUPPLY_VCC5,
+	TPS65910_SUPPLY_VCC4,
+	TPS65910_SUPPLY_VCC4,
+	TPS65910_SUPPLY_VCC3,
+	TPS65910_SUPPLY_VCC3
+};
+
+static int get_ctrl_reg_from_unit_addr(const uint unit_addr)
+{
+	if (unit_addr < ARRAY_SIZE(ctrl_regs))
+		return ctrl_regs[unit_addr];
+	return -ENXIO;
+}
+
+static int tps65910_regulator_get_value(struct udevice *dev,
+					const struct regulator_props *rgp)
+{
+	int sel, val, vout;
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+	int vin = pdata->supply;
+
+	val = pmic_reg_read(dev->parent, rgp->reg);
+	if (val < 0)
+		return val;
+	sel = (val & TPS65910_SEL_MASK) >> 2;
+	vout = (vin >= *(rgp->vin_min + sel)) ? *(rgp->vout + sel) : 0;
+	vout = ((val & TPS65910_SUPPLY_STATE_MASK) == 1) ? vout : 0;
+
+	return vout;
+}
+
+static int tps65910_ldo_get_value(struct udevice *dev)
+{
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+	int vin;
+
+	if (!pdata)
+		return 0;
+	vin = pdata->supply;
+
+	switch (pdata->unit) {
+	case TPS65910_UNIT_VRTC:
+		/* VRTC is fixed and can't be turned off */
+		return (vin >= 2500000) ? 1830000 : 0;
+	case TPS65910_UNIT_VDIG1:
+		return tps65910_regulator_get_value(dev, &ldo_props_vdig1);
+	case TPS65910_UNIT_VDIG2:
+		return tps65910_regulator_get_value(dev, &ldo_props_vdig2);
+	case TPS65910_UNIT_VPLL:
+		return tps65910_regulator_get_value(dev, &ldo_props_vpll);
+	case TPS65910_UNIT_VDAC:
+		return tps65910_regulator_get_value(dev, &ldo_props_vdac);
+	case TPS65910_UNIT_VAUX1:
+		return tps65910_regulator_get_value(dev, &ldo_props_vaux1);
+	case TPS65910_UNIT_VAUX2:
+		return tps65910_regulator_get_value(dev, &ldo_props_vaux2);
+	case TPS65910_UNIT_VAUX33:
+		return tps65910_regulator_get_value(dev, &ldo_props_vaux33);
+	case TPS65910_UNIT_VMMC:
+		return tps65910_regulator_get_value(dev, &ldo_props_vmmc);
+	default:
+		return 0;
+	}
+}
+
+static int tps65910_regulator_set_value(struct udevice *dev,
+					const struct regulator_props *ldo,
+					int uV)
+{
+	int val;
+	int sel = 0;
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+
+	do {
+		/* we only allow exact voltage matches */
+		if (uV == *(ldo->vout + sel))
+			break;
+	} while (++sel < VOUT_CHOICE_COUNT);
+	if (sel == VOUT_CHOICE_COUNT)
+		return -EINVAL;
+	if (pdata->supply < *(ldo->vin_min + sel))
+		return -EINVAL;
+
+	val = pmic_reg_read(dev->parent, ldo->reg);
+	if (val < 0)
+		return val;
+	val &= ~TPS65910_SEL_MASK;
+	val |= sel << 2;
+	return pmic_reg_write(dev->parent, ldo->reg, val);
+}
+
+static int tps65910_ldo_set_value(struct udevice *dev, int uV)
+{
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+	int vin = pdata->supply;
+
+	switch (pdata->unit) {
+	case TPS65910_UNIT_VRTC:
+		/* VRTC is fixed to 1.83V and can't be turned off */
+		if (vin < 2500000)
+			return -EINVAL;
+		return 0;
+	case TPS65910_UNIT_VDIG1:
+		return tps65910_regulator_set_value(dev, &ldo_props_vdig1, uV);
+	case TPS65910_UNIT_VDIG2:
+		return tps65910_regulator_set_value(dev, &ldo_props_vdig2, uV);
+	case TPS65910_UNIT_VPLL:
+		return tps65910_regulator_set_value(dev, &ldo_props_vpll, uV);
+	case TPS65910_UNIT_VDAC:
+		return tps65910_regulator_set_value(dev, &ldo_props_vdac, uV);
+	case TPS65910_UNIT_VAUX1:
+		return tps65910_regulator_set_value(dev, &ldo_props_vaux1, uV);
+	case TPS65910_UNIT_VAUX2:
+		return tps65910_regulator_set_value(dev, &ldo_props_vaux2, uV);
+	case TPS65910_UNIT_VAUX33:
+		return tps65910_regulator_set_value(dev, &ldo_props_vaux33, uV);
+	case TPS65910_UNIT_VMMC:
+		return tps65910_regulator_set_value(dev, &ldo_props_vmmc, uV);
+	default:
+		return 0;
+	}
+}
+
+static int tps65910_get_enable(struct udevice *dev)
+{
+	int reg, val;
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+
+	reg = get_ctrl_reg_from_unit_addr(pdata->unit);
+	if (reg < 0)
+		return reg;
+
+	val = pmic_reg_read(dev->parent, reg);
+	if (val < 0)
+		return val;
+
+	/* bits 1:0 of regulator control register define state */
+	return ((val & TPS65910_SUPPLY_STATE_MASK) == 1);
+}
+
+static int tps65910_set_enable(struct udevice *dev, bool enable)
+{
+	int reg;
+	uint clr, set;
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+
+	reg = get_ctrl_reg_from_unit_addr(pdata->unit);
+	if (reg < 0)
+		return reg;
+
+	if (enable) {
+		clr = TPS65910_SUPPLY_STATE_MASK & ~TPS65910_SUPPLY_STATE_ON;
+		set = TPS65910_SUPPLY_STATE_MASK & TPS65910_SUPPLY_STATE_ON;
+	} else {
+		clr = TPS65910_SUPPLY_STATE_MASK & ~TPS65910_SUPPLY_STATE_OFF;
+		set = TPS65910_SUPPLY_STATE_MASK & TPS65910_SUPPLY_STATE_OFF;
+	}
+	return pmic_clrsetbits(dev->parent, reg, clr, set);
+}
+
+static int buck_get_vdd1_vdd2_value(struct udevice *dev, int reg_vdd)
+{
+	int gain;
+	int val = pmic_reg_read(dev, reg_vdd);
+
+	if (val < 0)
+		return val;
+	gain = (val & TPS65910_GAIN_SEL_MASK) >> 6;
+	gain = (gain == 0) ? 1 : gain;
+	val = pmic_reg_read(dev, reg_vdd + 1);
+	if (val < 0)
+		return val;
+	if (val & TPS65910_VDD_SR_MASK)
+		/* use smart reflex value instead */
+		val = pmic_reg_read(dev, reg_vdd + 2);
+	if (val < 0)
+		return val;
+	return (562500 + (val & TPS65910_VDD_SEL_MASK) * 12500) * gain;
+}
+
+static int tps65910_buck_get_value(struct udevice *dev)
+{
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+
+	switch (pdata->unit) {
+	case TPS65910_UNIT_VIO:
+		return tps65910_regulator_get_value(dev, &smps_props_vio);
+	case TPS65910_UNIT_VDD1:
+		return buck_get_vdd1_vdd2_value(dev->parent, TPS65910_REG_VDD1);
+	case TPS65910_UNIT_VDD2:
+		return buck_get_vdd1_vdd2_value(dev->parent, TPS65910_REG_VDD2);
+	default:
+		return 0;
+	}
+}
+
+static int buck_set_vdd1_vdd2_value(struct udevice *dev, int uV)
+{
+	int ret, reg_vdd, gain;
+	int val;
+	struct dm_regulator_uclass_platdata *uc_pdata;
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+
+	switch (pdata->unit) {
+	case TPS65910_UNIT_VDD1:
+		reg_vdd = TPS65910_REG_VDD1;
+		break;
+	case TPS65910_UNIT_VDD2:
+		reg_vdd = TPS65910_REG_VDD2;
+		break;
+	default:
+		return -EINVAL;
+	}
+	uc_pdata = dev_get_uclass_platdata(dev);
+
+	/* check setpoint is within limits */
+	if (uV < uc_pdata->min_uV) {
+		error("voltage %duV for %s too low\n", uV, dev->name);
+		return -EINVAL;
+	}
+	if (uV > uc_pdata->max_uV) {
+		error("voltage %duV for %s too high\n", uV, dev->name);
+		return -EINVAL;
+	}
+
+	val = pmic_reg_read(dev->parent, reg_vdd);
+	if (val < 0)
+		return val;
+	gain = (val & TPS65910_GAIN_SEL_MASK) >> 6;
+	gain = (gain == 0) ? 1 : gain;
+	val = ((uV / gain) - 562500) / 12500;
+	if (val < TPS65910_VDD_SEL_MIN || val > TPS65910_VDD_SEL_MAX)
+		/*
+		 * Neither do we change the gain, nor do we allow shutdown or
+		 * any approximate value (for now)
+		 */
+		return -EPERM;
+	val &= TPS65910_VDD_SEL_MASK;
+	ret = pmic_reg_write(dev->parent, reg_vdd + 1, val);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+static int tps65910_buck_set_value(struct udevice *dev, int uV)
+{
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+
+	if (pdata->unit == TPS65910_UNIT_VIO)
+		return tps65910_regulator_set_value(dev, &smps_props_vio, uV);
+
+	return buck_set_vdd1_vdd2_value(dev, uV);
+}
+
+static int tps65910_boost_get_value(struct udevice *dev)
+{
+	int vout;
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+
+	vout = (pdata->supply >= 3000000) ? 5000000 : 0;
+	return vout;
+}
+
+static int tps65910_regulator_ofdata_to_platdata(struct udevice *dev)
+{
+	struct udevice *supply;
+	int ret;
+	const char *supply_name;
+	struct tps65910_regulator_pdata *pdata = dev_get_platdata(dev);
+
+	pdata->unit = dev_get_driver_data(dev);
+	if (pdata->unit > TPS65910_UNIT_VMMC)
+		return -EINVAL;
+	supply_name = supply_names[regulator_supplies[pdata->unit]];
+
+	debug("Looking up supply power %s\n", supply_name);
+	ret = device_get_supply_regulator(dev->parent, supply_name, &supply);
+	if (ret) {
+		debug("  missing supply power %s\n", supply_name);
+		return ret;
+	}
+	pdata->supply = regulator_get_value(supply);
+	if (pdata->supply < 0) {
+		debug("  invalid supply voltage for regulator %s\n",
+		      supply->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct dm_regulator_ops tps65910_boost_ops = {
+	.get_value  = tps65910_boost_get_value,
+	.get_enable = tps65910_get_enable,
+	.set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_boost) = {
+	.name = TPS65910_BOOST_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &tps65910_boost_ops,
+	.platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata),
+	.ofdata_to_platdata = tps65910_regulator_ofdata_to_platdata,
+};
+
+static const struct dm_regulator_ops tps65910_buck_ops = {
+	.get_value  = tps65910_buck_get_value,
+	.set_value  = tps65910_buck_set_value,
+	.get_enable = tps65910_get_enable,
+	.set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_buck) = {
+	.name = TPS65910_BUCK_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &tps65910_buck_ops,
+	.platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata),
+	.ofdata_to_platdata = tps65910_regulator_ofdata_to_platdata,
+};
+
+static const struct dm_regulator_ops tps65910_ldo_ops = {
+	.get_value  = tps65910_ldo_get_value,
+	.set_value  = tps65910_ldo_set_value,
+	.get_enable = tps65910_get_enable,
+	.set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_ldo) = {
+	.name = TPS65910_LDO_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &tps65910_ldo_ops,
+	.platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata),
+	.ofdata_to_platdata = tps65910_regulator_ofdata_to_platdata,
+};

+ 1 - 1
drivers/sysreset/sysreset-uclass.c

@@ -70,7 +70,7 @@ void reset_cpu(ulong addr)
 
 int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	sysreset_walk_halt(SYSRESET_WARM);
+	sysreset_walk_halt(SYSRESET_COLD);
 
 	return 0;
 }

+ 93 - 0
include/binman_sym.h

@@ -0,0 +1,93 @@
+/*
+ * Symbol access for symbols set up by binman as part of the build.
+ *
+ * This allows C code to access the position of a particular part of the image
+ * assembled by binman.
+ *
+ * Copyright (c) 2017 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __BINMAN_SYM_H
+#define __BINMAN_SYM_H
+
+#define BINMAN_SYM_MISSING	(-1UL)
+
+#ifdef CONFIG_BINMAN
+
+/**
+ * binman_symname() - Internal fnuction to get a binman symbol name
+ *
+ * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl')
+ * @_prop_name: Property value to get from that entry (e.g. 'pos')
+ * @returns name of the symbol for that entry and property
+ */
+#define binman_symname(_entry_name, _prop_name) \
+	_binman_ ## _entry_name ## _prop_ ## _prop_name
+
+/**
+ * binman_sym_declare() - Declare a symbol that will be used at run-time
+ *
+ * @_type: Type f the symbol (e.g. unsigned long)
+ * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl')
+ * @_prop_name: Property value to get from that entry (e.g. 'pos')
+ */
+#define binman_sym_declare(_type, _entry_name, _prop_name) \
+	_type binman_symname(_entry_name, _prop_name) \
+		__attribute__((aligned(4), unused, section(".binman_sym")))
+
+/**
+ * binman_sym_extern() - Declare a extern symbol that will be used at run-time
+ *
+ * @_type: Type f the symbol (e.g. unsigned long)
+ * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl')
+ * @_prop_name: Property value to get from that entry (e.g. 'pos')
+ */
+#define binman_sym_extern(_type, _entry_name, _prop_name) \
+	extern _type binman_symname(_entry_name, _prop_name) \
+		__attribute__((aligned(4), unused, section(".binman_sym")))
+
+/**
+ * binman_sym_declare_optional() - Declare an optional symbol
+ *
+ * If this symbol cannot be provided by binman, an error will not be generated.
+ * Instead the image will be assigned the value BINMAN_SYM_MISSING.
+ *
+ * @_type: Type f the symbol (e.g. unsigned long)
+ * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl')
+ * @_prop_name: Property value to get from that entry (e.g. 'pos')
+ */
+#define binman_sym_declare_optional(_type, _entry_name, _prop_name) \
+	_type binman_symname(_entry_name, _prop_name) \
+		__attribute__((aligned(4), weak, unused, \
+		section(".binman_sym")))
+
+/**
+ * binman_sym() - Access a previously declared symbol
+ *
+ * This is used to get the value of a symbol. E.g.:
+ *
+ *    ulong address = binman_sym(ulong, u_boot_spl, pos);
+ *
+ * @_type: Type f the symbol (e.g. unsigned long)
+ * @entry_name: Name of the entry to look for (e.g. 'u_boot_spl')
+ * @_prop_name: Property value to get from that entry (e.g. 'pos')
+ * @returns value of that property (filled in by binman)
+ */
+#define binman_sym(_type, _entry_name, _prop_name) \
+	(*(_type *)&binman_symname(_entry_name, _prop_name))
+
+#else /* !BINMAN */
+
+#define binman_sym_declare(_type, _entry_name, _prop_name)
+
+#define binman_sym_declare_optional(_type, _entry_name, _prop_name)
+
+#define binman_sym_extern(_type, _entry_name, _prop_name)
+
+#define binman_sym(_type, _entry_name, _prop_name) BINMAN_SYM_MISSING
+
+#endif /* BINMAN */
+
+#endif

+ 4 - 1
include/power/sandbox_pmic.h

@@ -13,7 +13,7 @@
 #define SANDBOX_BUCK_DRIVER		"sandbox_buck"
 #define SANDBOX_OF_BUCK_PREFIX		"buck"
 
-#define SANDBOX_BUCK_COUNT	2
+#define SANDBOX_BUCK_COUNT	3
 #define SANDBOX_LDO_COUNT	2
 /*
  * Sandbox PMIC registers:
@@ -109,6 +109,9 @@ enum {
 #define SANDBOX_BUCK1_PLATNAME	"SUPPLY_1.2V"
 #define SANDBOX_BUCK2_DEVNAME	"buck2"
 #define SANDBOX_BUCK2_PLATNAME	"SUPPLY_3.3V"
+/* BUCK3: for testing fallback regulator prefix matching during bind */
+#define SANDBOX_BUCK3_DEVNAME	"no_match_by_nodename"
+#define SANDBOX_BUCK3_PLATNAME	"buck_SUPPLY_1.5V"
 /* LDO names */
 #define SANDBOX_LDO1_DEVNAME	"ldo1"
 #define SANDBOX_LDO1_PLATNAME	"VDD_EMMC_1.8V"

+ 130 - 0
include/power/tps65910_pmic.h

@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __TPS65910_PMIC_H_
+#define __TPS65910_PMIC_H_
+
+#define TPS65910_I2C_SEL_MASK		(0x1 << 4)
+#define TPS65910_VDD_SR_MASK		(0x1 << 7)
+#define TPS65910_GAIN_SEL_MASK		(0x3 << 6)
+#define TPS65910_VDD_SEL_MASK		0x7f
+#define TPS65910_VDD_SEL_MIN		3
+#define TPS65910_VDD_SEL_MAX		75
+#define TPS65910_SEL_MASK		(0x3 << 2)
+#define TPS65910_SUPPLY_STATE_MASK	0x3
+#define TPS65910_SUPPLY_STATE_OFF	0x0
+#define TPS65910_SUPPLY_STATE_ON	0x1
+
+/* i2c registers */
+enum {
+	TPS65910_REG_RTC_SEC			= 0x00,
+	TPS65910_REG_RTC_MIN,
+	TPS65910_REG_RTC_HOUR,
+	TPS65910_REG_RTC_DAY,
+	TPS65910_REG_RTC_MONTH,
+	TPS65910_REG_RTC_YEAR,
+	TPS65910_REG_RTC_WEEK,
+	TPS65910_REG_RTC_ALARM_SEC		= 0x08,
+	TPS65910_REG_RTC_ALARM_MIN,
+	TPS65910_REG_RTC_ALARM_HOUR,
+	TPS65910_REG_RTC_ALARM_DAY,
+	TPS65910_REG_RTC_ALARM_MONTH,
+	TPS65910_REG_RTC_ALARM_YEAR,
+	TPS65910_REG_RTC_CTRL			= 0x10,
+	TPS65910_REG_RTC_STAT,
+	TPS65910_REG_RTC_INT,
+	TPS65910_REG_RTC_COMP_LSB,
+	TPS65910_REG_RTC_COMP_MSB,
+	TPS65910_REG_RTC_RESISTOR_PRG,
+	TPS65910_REG_RTC_RESET_STAT,
+	TPS65910_REG_BACKUP1,
+	TPS65910_REG_BACKUP2,
+	TPS65910_REG_BACKUP3,
+	TPS65910_REG_BACKUP4,
+	TPS65910_REG_BACKUP5,
+	TPS65910_REG_PUADEN,
+	TPS65910_REG_REF,
+	TPS65910_REG_VRTC,
+	TPS65910_REG_VIO			= 0x20,
+	TPS65910_REG_VDD1,
+	TPS65910_REG_VDD1_VAL,
+	TPS65910_REG_VDD1_VAL_SR,
+	TPS65910_REG_VDD2,
+	TPS65910_REG_VDD2_VAL,
+	TPS65910_REG_VDD2_VAL_SR,
+	TPS65910_REG_VDD3,
+	TPS65910_REG_VDIG1			= 0x30,
+	TPS65910_REG_VDIG2,
+	TPS65910_REG_VAUX1,
+	TPS65910_REG_VAUX2,
+	TPS65910_REG_VAUX33,
+	TPS65910_REG_VMMC,
+	TPS65910_REG_VPLL,
+	TPS65910_REG_VDAC,
+	TPS65910_REG_THERM,
+	TPS65910_REG_BATTERY_BACKUP_CHARGE,
+	TPS65910_REG_DCDC_CTRL			= 0x3e,
+	TPS65910_REG_DEVICE_CTRL,
+	TPS65910_REG_DEVICE_CTRL2,
+	TPS65910_REG_SLEEP_KEEP_LDO_ON,
+	TPS65910_REG_SLEEP_KEEP_RES_ON,
+	TPS65910_REG_SLEEP_SET_LDO_OFF,
+	TPS65910_REG_SLEEP_SET_RES_OFF,
+	TPS65910_REG_EN1_LDO_ASS,
+	TPS65910_REG_EM1_SMPS_ASS,
+	TPS65910_REG_EN2_LDO_ASS,
+	TPS65910_REG_EM2_SMPS_ASS,
+	TPS65910_REG_INT_STAT			= 0x50,
+	TPS65910_REG_INT_MASK,
+	TPS65910_REG_INT_STAT2,
+	TPS65910_REG_INT_MASK2,
+	TPS65910_REG_GPIO			= 0x60,
+	TPS65910_REG_JTAGREVNUM			= 0x80,
+	TPS65910_NUM_REGS
+};
+
+/* chip supplies */
+enum {
+	TPS65910_SUPPLY_VCCIO	= 0x00,
+	TPS65910_SUPPLY_VCC1,
+	TPS65910_SUPPLY_VCC2,
+	TPS65910_SUPPLY_VCC3,
+	TPS65910_SUPPLY_VCC4,
+	TPS65910_SUPPLY_VCC5,
+	TPS65910_SUPPLY_VCC6,
+	TPS65910_SUPPLY_VCC7,
+	TPS65910_NUM_SUPPLIES
+};
+
+/* regulator unit numbers */
+enum {
+	TPS65910_UNIT_VRTC = 0x00,
+	TPS65910_UNIT_VIO,
+	TPS65910_UNIT_VDD1,
+	TPS65910_UNIT_VDD2,
+	TPS65910_UNIT_VDD3,
+	TPS65910_UNIT_VDIG1,
+	TPS65910_UNIT_VDIG2,
+	TPS65910_UNIT_VPLL,
+	TPS65910_UNIT_VDAC,
+	TPS65910_UNIT_VAUX1,
+	TPS65910_UNIT_VAUX2,
+	TPS65910_UNIT_VAUX33,
+	TPS65910_UNIT_VMMC,
+};
+
+/* platform data */
+struct tps65910_regulator_pdata {
+	u32 supply;	/* regulator supply voltage in uV */
+	uint unit;	/* unit-address according to DT */
+};
+
+/* driver names */
+#define TPS65910_BUCK_DRIVER	"tps65910_buck"
+#define TPS65910_BOOST_DRIVER	"tps65910_boost"
+#define TPS65910_LDO_DRIVER	"tps65910_ldo"
+
+#endif /* __TPS65910_PMIC_H_ */

+ 11 - 0
include/spl.h

@@ -7,6 +7,8 @@
 #ifndef	_SPL_H_
 #define	_SPL_H_
 
+#include <binman_sym.h>
+
 /* Platform-specific defines */
 #include <linux/compiler.h>
 #include <asm/spl.h>
@@ -51,6 +53,15 @@ struct spl_load_info {
 		      void *buf);
 };
 
+/*
+ * We need to know the position of U-Boot in memory so we can jump to it. We
+ * allow any U-Boot binary to be used (u-boot.bin, u-boot-nodtb.bin,
+ * u-boot.img), hence the '_any'. These is no checking here that the correct
+ * image is found. For * example if u-boot.img is used we don't check that
+ * spl_parse_image_header() can parse a valid header.
+ */
+binman_sym_extern(ulong, u_boot_any, pos);
+
 /**
  * spl_load_simple_fit() - Loads a fit image from a device.
  * @spl_image:	Image description to set up

+ 2 - 0
test/dm/regulator.c

@@ -27,6 +27,7 @@ DECLARE_GLOBAL_DATA_PTR;
 enum {
 	BUCK1,
 	BUCK2,
+	BUCK3,
 	LDO1,
 	LDO2,
 	OUTPUT_COUNT,
@@ -42,6 +43,7 @@ static const char *regulator_names[OUTPUT_COUNT][OUTPUT_NAME_COUNT] = {
 	/* devname, platname */
 	{ SANDBOX_BUCK1_DEVNAME, SANDBOX_BUCK1_PLATNAME },
 	{ SANDBOX_BUCK2_DEVNAME, SANDBOX_BUCK2_PLATNAME },
+	{ SANDBOX_BUCK3_DEVNAME, SANDBOX_BUCK3_PLATNAME },
 	{ SANDBOX_LDO1_DEVNAME, SANDBOX_LDO1_PLATNAME},
 	{ SANDBOX_LDO2_DEVNAME, SANDBOX_LDO2_PLATNAME},
 };

+ 31 - 1
tools/binman/README

@@ -439,6 +439,8 @@ contents of an entry in some way. For example, it would be possible to create
 an entry containing a hash of the contents of some other entries. At this
 stage the position and size of entries should not be adjusted.
 
+6. WriteEntryInfo()
+
 7. BuildImage() - builds the image and writes it to a file. This is the final
 step.
 
@@ -471,6 +473,33 @@ the 'warning' line in scripts/Makefile.lib to see what it has found:
    # u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
 
 
+Access to binman entry positions at run time
+--------------------------------------------
+
+Binman assembles images and determines where each entry is placed in the image.
+This information may be useful to U-Boot at run time. For example, in SPL it
+is useful to be able to find the location of U-Boot so that it can be executed
+when SPL is finished.
+
+Binman allows you to declare symbols in the SPL image which are filled in
+with their correct values during the build. For example:
+
+    binman_sym_declare(ulong, u_boot_any, pos);
+
+declares a ulong value which will be assigned to the position of any U-Boot
+image (u-boot.bin, u-boot.img, u-boot-nodtb.bin) that is present in the image.
+You can access this value with something like:
+
+    ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
+
+Thus u_boot_pos will be set to the position of U-Boot in memory, assuming that
+the whole image has been loaded, or is available in flash. You can then jump to
+that address to start U-Boot.
+
+At present this feature is only supported in SPL. In principle it is possible
+to fill in such symbols in U-Boot proper, as well.
+
+
 Code coverage
 -------------
 
@@ -543,7 +572,8 @@ To do
 
 Some ideas:
 - Fill out the device tree to include the final position and size of each
-  entry (since the input file may not always specify these)
+  entry (since the input file may not always specify these). See also
+  'Access to binman entry positions at run time' above
 - Use of-platdata to make the information available to code that is unable
   to use device tree (such as a very small SPL image)
 - Write an image map to a text file

+ 8 - 3
tools/binman/binman.py

@@ -31,11 +31,13 @@ import cmdline
 import command
 import control
 
-def RunTests():
+def RunTests(debug):
     """Run the functional tests and any embedded doctests"""
+    import elf_test
     import entry_test
     import fdt_test
     import ftest
+    import image_test
     import test
     import doctest
 
@@ -45,12 +47,15 @@ def RunTests():
         suite.run(result)
 
     sys.argv = [sys.argv[0]]
+    if debug:
+        sys.argv.append('-D')
 
     # Run the entry tests first ,since these need to be the first to import the
     # 'entry' module.
     suite = unittest.TestLoader().loadTestsFromTestCase(entry_test.TestEntry)
     suite.run(result)
-    for module in (ftest.TestFunctional, fdt_test.TestFdt):
+    for module in (ftest.TestFunctional, fdt_test.TestFdt, elf_test.TestElf,
+                   image_test.TestImage):
         suite = unittest.TestLoader().loadTestsFromTestCase(module)
         suite.run(result)
 
@@ -110,7 +115,7 @@ def RunBinman(options, args):
         sys.tracebacklimit = 0
 
     if options.test:
-        ret_code = RunTests()
+        ret_code = RunTests(options.debug)
 
     elif options.test_coverage:
         RunTestCoverage()

+ 3 - 0
tools/binman/control.py

@@ -12,6 +12,7 @@ import sys
 import tools
 
 import command
+import elf
 import fdt
 import fdt_util
 from image import Image
@@ -89,6 +90,7 @@ def Binman(options, args):
 
     try:
         tout.Init(options.verbosity)
+        elf.debug = options.debug
         try:
             tools.SetInputDirs(options.indir)
             tools.PrepareOutputDir(options.outdir, options.preserve)
@@ -109,6 +111,7 @@ def Binman(options, args):
                 image.CheckSize()
                 image.CheckEntries()
                 image.ProcessEntryContents()
+                image.WriteSymbols()
                 image.BuildImage()
         finally:
             tools.FinaliseOutputDir()

+ 129 - 0
tools/binman/elf.py

@@ -0,0 +1,129 @@
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+# Handle various things related to ELF images
+#
+
+from collections import namedtuple, OrderedDict
+import command
+import os
+import re
+import struct
+
+import tools
+
+# This is enabled from control.py
+debug = False
+
+Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak'])
+
+
+def GetSymbols(fname, patterns):
+    """Get the symbols from an ELF file
+
+    Args:
+        fname: Filename of the ELF file to read
+        patterns: List of regex patterns to search for, each a string
+
+    Returns:
+        None, if the file does not exist, or Dict:
+          key: Name of symbol
+          value: Hex value of symbol
+    """
+    stdout = command.Output('objdump', '-t', fname, raise_on_error=False)
+    lines = stdout.splitlines()
+    if patterns:
+        re_syms = re.compile('|'.join(patterns))
+    else:
+        re_syms = None
+    syms = {}
+    syms_started = False
+    for line in lines:
+        if not line or not syms_started:
+            if 'SYMBOL TABLE' in line:
+                syms_started = True
+            line = None  # Otherwise code coverage complains about 'continue'
+            continue
+        if re_syms and not re_syms.search(line):
+            continue
+
+        space_pos = line.find(' ')
+        value, rest = line[:space_pos], line[space_pos + 1:]
+        flags = rest[:7]
+        parts = rest[7:].split()
+        section, size =  parts[:2]
+        if len(parts) > 2:
+            name = parts[2]
+            syms[name] = Symbol(section, int(value, 16), int(size,16),
+                                flags[1] == 'w')
+    return syms
+
+def GetSymbolAddress(fname, sym_name):
+    """Get a value of a symbol from an ELF file
+
+    Args:
+        fname: Filename of the ELF file to read
+        patterns: List of regex patterns to search for, each a string
+
+    Returns:
+        Symbol value (as an integer) or None if not found
+    """
+    syms = GetSymbols(fname, [sym_name])
+    sym = syms.get(sym_name)
+    if not sym:
+        return None
+    return sym.address
+
+def LookupAndWriteSymbols(elf_fname, entry, image):
+    """Replace all symbols in an entry with their correct values
+
+    The entry contents is updated so that values for referenced symbols will be
+    visible at run time. This is done by finding out the symbols positions in
+    the entry (using the ELF file) and replacing them with values from binman's
+    data structures.
+
+    Args:
+        elf_fname: Filename of ELF image containing the symbol information for
+            entry
+        entry: Entry to process
+        image: Image which can be used to lookup symbol values
+    """
+    fname = tools.GetInputFilename(elf_fname)
+    syms = GetSymbols(fname, ['image', 'binman'])
+    if not syms:
+        return
+    base = syms.get('__image_copy_start')
+    if not base:
+        return
+    for name, sym in syms.iteritems():
+        if name.startswith('_binman'):
+            msg = ("Image '%s': Symbol '%s'\n   in entry '%s'" %
+                   (image.GetPath(), name, entry.GetPath()))
+            offset = sym.address - base.address
+            if offset < 0 or offset + sym.size > entry.contents_size:
+                raise ValueError('%s has offset %x (size %x) but the contents '
+                                 'size is %x' % (entry.GetPath(), offset,
+                                                 sym.size, entry.contents_size))
+            if sym.size == 4:
+                pack_string = '<I'
+            elif sym.size == 8:
+                pack_string = '<Q'
+            else:
+                raise ValueError('%s has size %d: only 4 and 8 are supported' %
+                                 (msg, sym.size))
+
+            # Look up the symbol in our entry tables.
+            value = image.LookupSymbol(name, sym.weak, msg)
+            if value is not None:
+                value += base.address
+            else:
+                value = -1
+                pack_string = pack_string.lower()
+            value_bytes = struct.pack(pack_string, value)
+            if debug:
+                print('%s:\n   insert %s, offset %x, value %x, length %d' %
+                      (msg, name, offset, value, len(value_bytes)))
+            entry.data = (entry.data[:offset] + value_bytes +
+                        entry.data[offset + sym.size:])

+ 122 - 0
tools/binman/elf_test.py

@@ -0,0 +1,122 @@
+#
+# Copyright (c) 2017 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+# Test for the elf module
+
+from contextlib import contextmanager
+import os
+import sys
+import unittest
+
+try:
+  from StringIO import StringIO
+except ImportError:
+  from io import StringIO
+
+import elf
+
+binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
+
+# Use this to suppress stdout/stderr output:
+# with capture_sys_output() as (stdout, stderr)
+#   ...do something...
+@contextmanager
+def capture_sys_output():
+  capture_out, capture_err = StringIO(), StringIO()
+  old_out, old_err = sys.stdout, sys.stderr
+  try:
+    sys.stdout, sys.stderr = capture_out, capture_err
+    yield capture_out, capture_err
+  finally:
+    sys.stdout, sys.stderr = old_out, old_err
+
+
+class FakeEntry:
+    def __init__(self, contents_size):
+        self.contents_size = contents_size
+        self.data = 'a' * contents_size
+
+    def GetPath(self):
+        return 'entry_path'
+
+class FakeImage:
+    def __init__(self, sym_value=1):
+        self.sym_value = sym_value
+
+    def GetPath(self):
+        return 'image_path'
+
+    def LookupSymbol(self, name, weak, msg):
+        return self.sym_value
+
+class TestElf(unittest.TestCase):
+    def testAllSymbols(self):
+        fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
+        syms = elf.GetSymbols(fname, [])
+        self.assertIn('.ucode', syms)
+
+    def testRegexSymbols(self):
+        fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
+        syms = elf.GetSymbols(fname, ['ucode'])
+        self.assertIn('.ucode', syms)
+        syms = elf.GetSymbols(fname, ['missing'])
+        self.assertNotIn('.ucode', syms)
+        syms = elf.GetSymbols(fname, ['missing', 'ucode'])
+        self.assertIn('.ucode', syms)
+
+    def testMissingFile(self):
+        entry = FakeEntry(10)
+        image = FakeImage()
+        with self.assertRaises(ValueError) as e:
+            syms = elf.LookupAndWriteSymbols('missing-file', entry, image)
+        self.assertIn("Filename 'missing-file' not found in input path",
+                      str(e.exception))
+
+    def testOutsideFile(self):
+        entry = FakeEntry(10)
+        image = FakeImage()
+        elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
+        with self.assertRaises(ValueError) as e:
+            syms = elf.LookupAndWriteSymbols(elf_fname, entry, image)
+        self.assertIn('entry_path has offset 4 (size 8) but the contents size '
+                      'is a', str(e.exception))
+
+    def testMissingImageStart(self):
+        entry = FakeEntry(10)
+        image = FakeImage()
+        elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_bad')
+        self.assertEqual(elf.LookupAndWriteSymbols(elf_fname, entry, image),
+                         None)
+
+    def testBadSymbolSize(self):
+        entry = FakeEntry(10)
+        image = FakeImage()
+        elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_size')
+        with self.assertRaises(ValueError) as e:
+            syms = elf.LookupAndWriteSymbols(elf_fname, entry, image)
+        self.assertIn('has size 1: only 4 and 8 are supported',
+                      str(e.exception))
+
+    def testNoValue(self):
+        entry = FakeEntry(20)
+        image = FakeImage(sym_value=None)
+        elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
+        syms = elf.LookupAndWriteSymbols(elf_fname, entry, image)
+        self.assertEqual(chr(255) * 16 + 'a' * 4, entry.data)
+
+    def testDebug(self):
+        elf.debug = True
+        entry = FakeEntry(20)
+        image = FakeImage()
+        elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
+        with capture_sys_output() as (stdout, stderr):
+            syms = elf.LookupAndWriteSymbols(elf_fname, entry, image)
+        elf.debug = False
+        self.assertTrue(len(stdout.getvalue()) > 0)
+
+
+if __name__ == '__main__':
+    unittest.main()

+ 8 - 0
tools/binman/etype/entry.py

@@ -198,3 +198,11 @@ class Entry(object):
 
     def ProcessContents(self):
         pass
+
+    def WriteSymbols(self, image):
+        """Write symbol values into binary files for access at run time
+
+        Args:
+          image: Image containing the entry
+        """
+        pass

+ 6 - 0
tools/binman/etype/u_boot_spl.py

@@ -6,12 +6,18 @@
 # Entry-type module for spl/u-boot-spl.bin
 #
 
+import elf
+
 from entry import Entry
 from blob import Entry_blob
 
 class Entry_u_boot_spl(Entry_blob):
     def __init__(self, image, etype, node):
         Entry_blob.__init__(self, image, etype, node)
+        self.elf_fname = 'spl/u-boot-spl'
 
     def GetDefaultFilename(self):
         return 'spl/u-boot-spl.bin'
+
+    def WriteSymbols(self, image):
+        elf.LookupAndWriteSymbols(self.elf_fname, self, image)

+ 4 - 3
tools/binman/etype/u_boot_spl_bss_pad.py

@@ -9,6 +9,7 @@
 #
 
 import command
+import elf
 from entry import Entry
 from blob import Entry_blob
 import tools
@@ -19,8 +20,8 @@ class Entry_u_boot_spl_bss_pad(Entry_blob):
 
     def ObtainContents(self):
         fname = tools.GetInputFilename('spl/u-boot-spl')
-        args = [['nm', fname], ['grep', '__bss_size']]
-        out = command.RunPipe(args, capture=True).stdout.splitlines()
-        bss_size = int(out[0].split()[0], 16)
+        bss_size = elf.GetSymbolAddress(fname, '__bss_size')
+        if not bss_size:
+            self.Raise('Expected __bss_size symbol in spl/u-boot-spl')
         self.data = chr(0) * bss_size
         self.contents_size = bss_size

+ 17 - 0
tools/binman/etype/u_boot_spl_dtb.py

@@ -0,0 +1,17 @@
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+# Entry-type module for U-Boot device tree
+#
+
+from entry import Entry
+from blob import Entry_blob
+
+class Entry_u_boot_spl_dtb(Entry_blob):
+    def __init__(self, image, etype, node):
+        Entry_blob.__init__(self, image, etype, node)
+
+    def GetDefaultFilename(self):
+        return 'spl/u-boot-spl.dtb'

+ 17 - 0
tools/binman/etype/u_boot_spl_nodtb.py

@@ -0,0 +1,17 @@
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+# Entry-type module for 'u-boot-nodtb.bin'
+#
+
+from entry import Entry
+from blob import Entry_blob
+
+class Entry_u_boot_spl_nodtb(Entry_blob):
+    def __init__(self, image, etype, node):
+        Entry_blob.__init__(self, image, etype, node)
+
+    def GetDefaultFilename(self):
+        return 'spl/u-boot-spl-nodtb.bin'

+ 4 - 5
tools/binman/etype/u_boot_with_ucode_ptr.py

@@ -9,6 +9,7 @@
 import struct
 
 import command
+import elf
 from entry import Entry
 from blob import Entry_blob
 import fdt_util
@@ -31,11 +32,9 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
     def ObtainContents(self):
         # Figure out where to put the microcode pointer
         fname = tools.GetInputFilename(self.elf_fname)
-        args = [['nm', fname], ['grep', '-w', '_dt_ucode_base_size']]
-        out = (command.RunPipe(args, capture=True, raise_on_error=False).
-               stdout.splitlines())
-        if len(out) == 1:
-            self.target_pos = int(out[0].split()[0], 16)
+        sym = elf.GetSymbolAddress(fname, '_dt_ucode_base_size')
+        if sym:
+           self.target_pos = sym
         elif not fdt_util.GetBool(self._node, 'optional-ucode'):
             self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
 

+ 57 - 11
tools/binman/ftest.py

@@ -20,6 +20,7 @@ import binman
 import cmdline
 import command
 import control
+import elf
 import fdt
 import fdt_util
 import tools
@@ -28,11 +29,12 @@ import tout
 # Contents of test files, corresponding to different entry types
 U_BOOT_DATA           = '1234'
 U_BOOT_IMG_DATA       = 'img'
-U_BOOT_SPL_DATA       = '567'
+U_BOOT_SPL_DATA       = '56780123456789abcde'
 BLOB_DATA             = '89'
 ME_DATA               = '0abcd'
 VGA_DATA              = 'vga'
 U_BOOT_DTB_DATA       = 'udtb'
+U_BOOT_SPL_DTB_DATA   = 'spldtb'
 X86_START16_DATA      = 'start16'
 X86_START16_SPL_DATA  = 'start16spl'
 U_BOOT_NODTB_DATA     = 'nodtb with microcode pointer somewhere in here'
@@ -76,6 +78,7 @@ class TestFunctional(unittest.TestCase):
         TestFunctional._MakeInputFile('me.bin', ME_DATA)
         TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
         TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
+        TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
         TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
         TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
                                       X86_START16_SPL_DATA)
@@ -134,7 +137,10 @@ class TestFunctional(unittest.TestCase):
         Returns:
             Return value (0 for success)
         """
-        (options, args) = cmdline.ParseArgs(list(args))
+        args = list(args)
+        if '-D' in sys.argv:
+            args = args + ['-D']
+        (options, args) = cmdline.ParseArgs(args)
         options.pager = 'binman-invalid-pager'
         options.build_dir = self._indir
 
@@ -142,14 +148,16 @@ class TestFunctional(unittest.TestCase):
         # options.verbosity = tout.DEBUG
         return control.Binman(options, args)
 
-    def _DoTestFile(self, fname):
+    def _DoTestFile(self, fname, debug=False):
         """Run binman with a given test file
 
         Args:
             fname: Device tree source filename to use (e.g. 05_simple.dts)
         """
-        return self._DoBinman('-p', '-I', self._indir,
-                              '-d', self.TestFile(fname))
+        args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
+        if debug:
+            args.append('-D')
+        return self._DoBinman(*args)
 
     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
         """Set up a new test device-tree file
@@ -302,7 +310,6 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(0, len(result.stderr))
         self.assertEqual(0, result.return_code)
 
-    # Not yet available.
     def testBoard(self):
         """Test that we can run it with a specific board"""
         self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
@@ -362,6 +369,10 @@ class TestFunctional(unittest.TestCase):
         data = self._DoReadFile('05_simple.dts')
         self.assertEqual(U_BOOT_DATA, data)
 
+    def testSimpleDebug(self):
+        """Test a simple binman run with debugging enabled"""
+        data = self._DoTestFile('05_simple.dts', debug=True)
+
     def testDual(self):
         """Test that we can handle creating two images
 
@@ -563,8 +574,10 @@ class TestFunctional(unittest.TestCase):
 
     def testImagePadByte(self):
         """Test that the image pad byte can be specified"""
+        with open(self.TestFile('bss_data')) as fd:
+            TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
         data = self._DoReadFile('21_image_pad.dts')
-        self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 9) + U_BOOT_DATA, data)
+        self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
 
     def testImageName(self):
         """Test that image files can be named"""
@@ -586,7 +599,7 @@ class TestFunctional(unittest.TestCase):
     def testPackSorted(self):
         """Test that entries can be sorted"""
         data = self._DoReadFile('24_sorted.dts')
-        self.assertEqual(chr(0) * 5 + U_BOOT_SPL_DATA + chr(0) * 2 +
+        self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
                          U_BOOT_DATA, data)
 
     def testPackZeroPosition(self):
@@ -614,14 +627,14 @@ class TestFunctional(unittest.TestCase):
         with self.assertRaises(ValueError) as e:
             self._DoTestFile('28_pack_4gb_outside.dts')
         self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside "
-                      "the image starting at 0xfffffff0 (4294967280)",
+                      "the image starting at 0xffffffe0 (4294967264)",
                       str(e.exception))
 
     def testPackX86Rom(self):
         """Test that a basic x86 ROM can be created"""
         data = self._DoReadFile('29_x86-rom.dts')
-        self.assertEqual(U_BOOT_DATA + chr(0) * 3 + U_BOOT_SPL_DATA +
-                         chr(0) * 6, data)
+        self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
+                         chr(0) * 2, data)
 
     def testPackX86RomMeNoDesc(self):
         """Test that an invalid Intel descriptor entry is detected"""
@@ -835,6 +848,13 @@ class TestFunctional(unittest.TestCase):
         data = self._DoReadFile('47_spl_bss_pad.dts')
         self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
 
+        with open(self.TestFile('u_boot_ucode_ptr')) as fd:
+            TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
+        with self.assertRaises(ValueError) as e:
+            data = self._DoReadFile('47_spl_bss_pad.dts')
+        self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
+                      str(e.exception))
+
     def testPackStart16Spl(self):
         """Test that an image with an x86 start16 region can be created"""
         data = self._DoReadFile('48_x86-start16-spl.dts')
@@ -862,6 +882,32 @@ class TestFunctional(unittest.TestCase):
         data = self._DoReadFile('50_intel_mrc.dts')
         self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
 
+    def testSplDtb(self):
+        """Test that an image with spl/u-boot-spl.dtb can be created"""
+        data = self._DoReadFile('51_u_boot_spl_dtb.dts')
+        self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
+
+    def testSplNoDtb(self):
+        """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
+        data = self._DoReadFile('52_u_boot_spl_nodtb.dts')
+        self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
+
+    def testSymbols(self):
+        """Test binman can assign symbols embedded in U-Boot"""
+        elf_fname = self.TestFile('u_boot_binman_syms')
+        syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
+        addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
+        self.assertEqual(syms['_binman_u_boot_spl_prop_pos'].address, addr)
+
+        with open(self.TestFile('u_boot_binman_syms')) as fd:
+            TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
+        data = self._DoReadFile('53_symbols.dts')
+        sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
+        expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
+                    U_BOOT_DATA +
+                    sym_values + U_BOOT_SPL_DATA[16:])
+        self.assertEqual(expected, data)
+
 
 if __name__ == "__main__":
     unittest.main()

+ 76 - 3
tools/binman/image.py

@@ -6,8 +6,12 @@
 # Class for an image, the output of binman
 #
 
+from __future__ import print_function
+
 from collections import OrderedDict
 from operator import attrgetter
+import re
+import sys
 
 import fdt_util
 import tools
@@ -45,7 +49,7 @@ class Image:
              address.
         _entries: OrderedDict() of entries
     """
-    def __init__(self, name, node):
+    def __init__(self, name, node, test=False):
         global entry
         global Entry
         import entry
@@ -64,8 +68,9 @@ class Image:
         self._end_4gb = False
         self._entries = OrderedDict()
 
-        self._ReadNode()
-        self._ReadEntries()
+        if not test:
+            self._ReadNode()
+            self._ReadEntries()
 
     def _ReadNode(self):
         """Read properties from the image node"""
@@ -119,6 +124,14 @@ class Image:
         """
         raise ValueError("Image '%s': %s" % (self._node.path, msg))
 
+    def GetPath(self):
+        """Get the path of an image (in the FDT)
+
+        Returns:
+            Full path of the node for this image
+        """
+        return self._node.path
+
     def _ReadEntries(self):
         for node in self._node.subnodes:
             self._entries[node.name] = Entry.Create(self, node)
@@ -220,6 +233,11 @@ class Image:
         for entry in self._entries.values():
             entry.ProcessContents()
 
+    def WriteSymbols(self):
+        """Write symbol values into binary files for access at run time"""
+        for entry in self._entries.values():
+            entry.WriteSymbols(self)
+
     def BuildImage(self):
         """Write the image to a file"""
         fname = tools.GetOutputFilename(self._filename)
@@ -230,3 +248,58 @@ class Image:
                 data = entry.GetData()
                 fd.seek(self._pad_before + entry.pos - self._skip_at_start)
                 fd.write(data)
+
+    def LookupSymbol(self, sym_name, optional, msg):
+        """Look up a symbol in an ELF file
+
+        Looks up a symbol in an ELF file. Only entry types which come from an
+        ELF image can be used by this function.
+
+        At present the only entry property supported is pos.
+
+        Args:
+            sym_name: Symbol name in the ELF file to look up in the format
+                _binman_<entry>_prop_<property> where <entry> is the name of
+                the entry and <property> is the property to find (e.g.
+                _binman_u_boot_prop_pos). As a special case, you can append
+                _any to <entry> to have it search for any matching entry. E.g.
+                _binman_u_boot_any_prop_pos will match entries called u-boot,
+                u-boot-img and u-boot-nodtb)
+            optional: True if the symbol is optional. If False this function
+                will raise if the symbol is not found
+            msg: Message to display if an error occurs
+
+        Returns:
+            Value that should be assigned to that symbol, or None if it was
+                optional and not found
+
+        Raises:
+            ValueError if the symbol is invalid or not found, or references a
+                property which is not supported
+        """
+        m = re.match(r'^_binman_(\w+)_prop_(\w+)$', sym_name)
+        if not m:
+            raise ValueError("%s: Symbol '%s' has invalid format" %
+                             (msg, sym_name))
+        entry_name, prop_name = m.groups()
+        entry_name = entry_name.replace('_', '-')
+        entry = self._entries.get(entry_name)
+        if not entry:
+            if entry_name.endswith('-any'):
+                root = entry_name[:-4]
+                for name in self._entries:
+                    if name.startswith(root):
+                        rest = name[len(root):]
+                        if rest in ['', '-img', '-nodtb']:
+                            entry = self._entries[name]
+        if not entry:
+            err = ("%s: Entry '%s' not found in list (%s)" %
+                   (msg, entry_name, ','.join(self._entries.keys())))
+            if optional:
+                print('Warning: %s' % err, file=sys.stderr)
+                return None
+            raise ValueError(err)
+        if prop_name == 'pos':
+            return entry.pos
+        else:
+            raise ValueError("%s: No such property '%s'" % (msg, prop_name))

+ 46 - 0
tools/binman/image_test.py

@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2017 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+# Test for the image module
+
+import unittest
+
+from image import Image
+from elf_test import capture_sys_output
+
+class TestImage(unittest.TestCase):
+    def testInvalidFormat(self):
+        image = Image('name', 'node', test=True)
+        with self.assertRaises(ValueError) as e:
+            image.LookupSymbol('_binman_something_prop_', False, 'msg')
+        self.assertIn(
+            "msg: Symbol '_binman_something_prop_' has invalid format",
+            str(e.exception))
+
+    def testMissingSymbol(self):
+        image = Image('name', 'node', test=True)
+        image._entries = {}
+        with self.assertRaises(ValueError) as e:
+            image.LookupSymbol('_binman_type_prop_pname', False, 'msg')
+        self.assertIn("msg: Entry 'type' not found in list ()",
+                      str(e.exception))
+
+    def testMissingSymbolOptional(self):
+        image = Image('name', 'node', test=True)
+        image._entries = {}
+        with capture_sys_output() as (stdout, stderr):
+            val = image.LookupSymbol('_binman_type_prop_pname', True, 'msg')
+        self.assertEqual(val, None)
+        self.assertEqual("Warning: msg: Entry 'type' not found in list ()\n",
+                         stderr.getvalue())
+        self.assertEqual('', stdout.getvalue())
+
+    def testBadProperty(self):
+        image = Image('name', 'node', test=True)
+        image._entries = {'u-boot': 1}
+        with self.assertRaises(ValueError) as e:
+            image.LookupSymbol('_binman_u_boot_prop_bad', False, 'msg')
+        self.assertIn("msg: No such property 'bad", str(e.exception))

+ 1 - 1
tools/binman/test/21_image_pad.dts

@@ -10,7 +10,7 @@
 		};
 
 		u-boot {
-			pos = <12>;
+			pos = <20>;
 		};
 	};
 };

+ 2 - 2
tools/binman/test/24_sorted.dts

@@ -7,11 +7,11 @@
 	binman {
 		sort-by-pos;
 		u-boot {
-			pos = <10>;
+			pos = <22>;
 		};
 
 		u-boot-spl {
-			pos = <5>;
+			pos = <1>;
 		};
 	};
 };

+ 2 - 2
tools/binman/test/28_pack_4gb_outside.dts

@@ -7,13 +7,13 @@
 	binman {
 		sort-by-pos;
 		end-at-4gb;
-		size = <16>;
+		size = <32>;
 		u-boot {
 			pos = <0>;
 		};
 
 		u-boot-spl {
-			pos = <0xfffffff7>;
+			pos = <0xffffffeb>;
 		};
 	};
 };

+ 3 - 3
tools/binman/test/29_x86-rom.dts

@@ -7,13 +7,13 @@
 	binman {
 		sort-by-pos;
 		end-at-4gb;
-		size = <16>;
+		size = <32>;
 		u-boot {
-			pos = <0xfffffff0>;
+			pos = <0xffffffe0>;
 		};
 
 		u-boot-spl {
-			pos = <0xfffffff7>;
+			pos = <0xffffffeb>;
 		};
 	};
 };

+ 13 - 0
tools/binman/test/51_u_boot_spl_dtb.dts

@@ -0,0 +1,13 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		size = <16>;
+
+		u-boot-spl-dtb {
+		};
+	};
+};

+ 11 - 0
tools/binman/test/52_u_boot_spl_nodtb.dts

@@ -0,0 +1,11 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot-spl-nodtb {
+		};
+	};
+};

+ 20 - 0
tools/binman/test/53_symbols.dts

@@ -0,0 +1,20 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		pad-byte = <0xff>;
+		u-boot-spl {
+		};
+
+		u-boot {
+			pos = <20>;
+		};
+
+		u-boot-spl2 {
+			type = "u-boot-spl";
+		};
+	};
+};

+ 17 - 1
tools/binman/test/Makefile

@@ -10,8 +10,12 @@
 CFLAGS := -march=i386 -m32 -nostdlib -I ../../../include
 
 LDS_UCODE := -T u_boot_ucode_ptr.lds
+LDS_BINMAN := -T u_boot_binman_syms.lds
+LDS_BINMAN_BAD := -T u_boot_binman_syms_bad.lds
 
-TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data
+TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \
+	u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \
+	u_boot_binman_syms_size
 
 all: $(TARGETS)
 
@@ -24,6 +28,18 @@ u_boot_ucode_ptr: u_boot_ucode_ptr.c
 bss_data: CFLAGS += bss_data.lds
 bss_data: bss_data.c
 
+u_boot_binman_syms.bin: u_boot_binman_syms
+	objcopy -O binary $< -R .note.gnu.build-id $@
+
+u_boot_binman_syms: CFLAGS += $(LDS_BINMAN)
+u_boot_binman_syms: u_boot_binman_syms.c
+
+u_boot_binman_syms_bad: CFLAGS += $(LDS_BINMAN_BAD)
+u_boot_binman_syms_bad: u_boot_binman_syms_bad.c
+
+u_boot_binman_syms_size: CFLAGS += $(LDS_BINMAN)
+u_boot_binman_syms_size: u_boot_binman_syms_size.c
+
 clean:
 	rm -f $(TARGETS)
 

+ 1 - 1
tools/binman/test/bss_data.c

@@ -4,7 +4,7 @@
  * SPDX-License-Identifier:     GPL-2.0+
  *
  * Simple program to create a _dt_ucode_base_size symbol which can be read
- * by 'nm'. This is used by binman tests.
+ * by binutils. This is used by binman tests.
  */
 
 int bss_data[10];

BIN
tools/binman/test/u_boot_binman_syms


+ 14 - 0
tools/binman/test/u_boot_binman_syms.c

@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2017 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Simple program to create some binman symbols. This is used by binman tests.
+ */
+
+#define CONFIG_BINMAN
+#include <binman_sym.h>
+
+binman_sym_declare(unsigned long, u_boot_spl, pos);
+binman_sym_declare(unsigned long long, u_boot_spl2, pos);
+binman_sym_declare(unsigned long, u_boot_any, pos);

+ 30 - 0
tools/binman/test/u_boot_binman_syms.lds

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0x00000000;
+	_start = .;
+
+	. = ALIGN(4);
+	.text :
+	{
+		__image_copy_start = .;
+		*(.text*)
+	}
+
+	. = ALIGN(4);
+	.binman_sym_table : {
+		__binman_sym_start = .;
+		KEEP(*(SORT(.binman_sym*)));
+		__binman_sym_end = .;
+	}
+
+}

BIN
tools/binman/test/u_boot_binman_syms_bad


+ 1 - 0
tools/binman/test/u_boot_binman_syms_bad.c

@@ -0,0 +1 @@
+u_boot_binman_syms.c

+ 29 - 0
tools/binman/test/u_boot_binman_syms_bad.lds

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0x00000000;
+	_start = .;
+
+	. = ALIGN(4);
+	.text :
+	{
+		*(.text*)
+	}
+
+	. = ALIGN(4);
+	.binman_sym_table : {
+		__binman_sym_start = .;
+		KEEP(*(SORT(.binman_sym*)));
+		__binman_sym_end = .;
+	}
+
+}

BIN
tools/binman/test/u_boot_binman_syms_size


+ 12 - 0
tools/binman/test/u_boot_binman_syms_size.c

@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Simple program to create some binman symbols. This is used by binman tests.
+ */
+
+#define CONFIG_BINMAN
+#include <binman_sym.h>
+
+binman_sym_declare(char, u_boot_spl, pos);

+ 1 - 1
tools/binman/test/u_boot_ucode_ptr.c

@@ -4,7 +4,7 @@
  * SPDX-License-Identifier:     GPL-2.0+
  *
  * Simple program to create a _dt_ucode_base_size symbol which can be read
- * by 'nm'. This is used by binman tests.
+ * by binutils. This is used by binman tests.
  */
 
 static unsigned long _dt_ucode_base_size[2]