Browse Source

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

Tom Rini 7 years ago
parent
commit
15616a0aa5
61 changed files with 1638 additions and 62 deletions
  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
 endif
 
 
 ifneq ($(CONFIG_TEGRA),)
 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)
 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
 u-boot-nodtb-tegra.bin: spl/u-boot-spl u-boot-nodtb.bin FORCE
 	$(call if_changed,pad_cat)
 	$(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
 u-boot-dtb-tegra.bin: u-boot-tegra.bin FORCE
 	$(call if_changed,copy)
 	$(call if_changed,copy)
+endif  # binman
 endif
 endif
 
 
 OBJCOPYFLAGS_u-boot-app.efi := $(OBJCOPYFLAGS_EFI)
 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.
 # limit ourselves to the sections we want in the .bin.
 ifdef CONFIG_ARM64
 ifdef CONFIG_ARM64
 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .data \
 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
 else
 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \
 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
 endif
 
 
 # if a dtb section exists we always have to include it
 # 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*)));
 		KEEP(*(SORT(.u_boot_list*)));
 	}
 	}
 
 
+	. = ALIGN(4);
+	.binman_sym_table : {
+		__binman_sym_start = .;
+		KEEP(*(SORT(.binman_sym*)));
+		__binman_sym_end = .;
+	}
+
 	. = ALIGN(4);
 	. = ALIGN(4);
 
 
 	__image_copy_end = .;
 	__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+
  * SPDX-License-Identifier:	GPL-2.0+
  */
  */
 
 
+#include "tegra-u-boot.dtsi"
+
 / {
 / {
 	host1x@50000000 {
 	host1x@50000000 {
 		u-boot,dm-pre-reloc;
 		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 OF_CONTROL
 	select VIDCONSOLE_AS_LCD if DM_VIDEO
 	select VIDCONSOLE_AS_LCD if DM_VIDEO
 	select BOARD_EARLY_INIT_F
 	select BOARD_EARLY_INIT_F
+	select BINMAN
 	imply CRC32_VERIFY
 	imply CRC32_VERIFY
 
 
 config TEGRA_NO_BPMP
 config TEGRA_NO_BPMP

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

@@ -75,4 +75,10 @@
 		regulator-min-microvolt = <3300000>;
 		regulator-min-microvolt = <3300000>;
 		regulator-max-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 <common.h>
+#include <binman_sym.h>
 #include <dm.h>
 #include <dm.h>
 #include <spl.h>
 #include <spl.h>
 #include <asm/u-boot.h>
 #include <asm/u-boot.h>
@@ -32,6 +33,9 @@ DECLARE_GLOBAL_DATA_PTR;
 
 
 u32 *boot_params_ptr = NULL;
 u32 *boot_params_ptr = NULL;
 
 
+/* See spl.h for information about this */
+binman_sym_declare(ulong, u_boot_any, pos);
+
 /* Define board data structure */
 /* Define board data structure */
 static bd_t bdata __attribute__ ((section(".data")));
 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)
 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->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->os = IH_OS_U_BOOT;
 	spl_image->name = "U-Boot";
 	spl_image->name = "U-Boot";
 }
 }

+ 15 - 4
common/spl/spl_ram.c

@@ -11,6 +11,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  * SPDX-License-Identifier:	GPL-2.0+
  */
  */
 #include <common.h>
 #include <common.h>
+#include <binman_sym.h>
+#include <mapmem.h>
 #include <spl.h>
 #include <spl.h>
 #include <libfdt.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;
 		load.read = spl_ram_load_read;
 		spl_load_simple_fit(spl_image, &load, 0, header);
 		spl_load_simple_fit(spl_image, &load, 0, header);
 	} else {
 	} else {
+		ulong u_boot_pos = binman_sym(ulong, u_boot_any, pos);
+
 		debug("Legacy image\n");
 		debug("Legacy image\n");
 		/*
 		/*
 		 * Get the header.  It will point to an address defined by
 		 * Get the header.  It will point to an address defined by
 		 * handoff which will tell where the image located inside
 		 * 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);
 		spl_parse_image_header(spl_image, header);
 	}
 	}

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

@@ -2,7 +2,8 @@ Voltage/Current regulator
 
 
 Binding:
 Binding:
 The regulator devices don't use the "compatible" property. The binding is done
 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 array of 'struct pmic_child_info' with the prefixes and compatible drivers.
 The bind is done by calling function: pmic_bind_childs().
 The bind is done by calling function: pmic_bind_childs().
 Example drivers:
 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, ...
 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:
 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-min-microvolt: a minimum allowed Voltage value
 - regulator-max-microvolt: a maximum allowed Voltage value
 - regulator-max-microvolt: a maximum allowed Voltage value
 - regulator-min-microamp: a minimum allowed Current 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.h>
 #include <dm/device-internal.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <dm/lists.h>
+#include <dm/uclass-internal.h>
 
 
 static const char *if_typename_str[IF_TYPE_COUNT] = {
 static const char *if_typename_str[IF_TYPE_COUNT] = {
 	[IF_TYPE_IDE]		= "ide",
 	[IF_TYPE_IDE]		= "ide",
@@ -331,7 +332,7 @@ int blk_first_device(int if_type, struct udevice **devp)
 	struct blk_desc *desc;
 	struct blk_desc *desc;
 	int ret;
 	int ret;
 
 
-	ret = uclass_first_device(UCLASS_BLK, devp);
+	ret = uclass_find_first_device(UCLASS_BLK, devp);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 	if (!*devp)
 	if (!*devp)
@@ -340,7 +341,7 @@ int blk_first_device(int if_type, struct udevice **devp)
 		desc = dev_get_uclass_platdata(*devp);
 		desc = dev_get_uclass_platdata(*devp);
 		if (desc->if_type == if_type)
 		if (desc->if_type == if_type)
 			return 0;
 			return 0;
-		ret = uclass_next_device(devp);
+		ret = uclass_find_next_device(devp);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 	} while (*devp);
 	} while (*devp);
@@ -356,7 +357,7 @@ int blk_next_device(struct udevice **devp)
 	desc = dev_get_uclass_platdata(*devp);
 	desc = dev_get_uclass_platdata(*devp);
 	if_type = desc->if_type;
 	if_type = desc->if_type;
 	do {
 	do {
-		ret = uclass_next_device(devp);
+		ret = uclass_find_next_device(devp);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 		if (!*devp)
 		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
 	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
 	SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed
 	via an I2C interface.
 	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_RN5T567) += rn5t567.o
 obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
 obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
 obj-$(CONFIG_PMIC_S5M8767) += s5m8767.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_PALMAS) += palmas.o
 obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
 obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
 obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.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 driver *drv;
 	struct udevice *child;
 	struct udevice *child;
 	const char *node_name;
 	const char *node_name;
+	const char *reg_name;
 	int bind_count = 0;
 	int bind_count = 0;
 	ofnode node;
 	ofnode node;
 	int prefix_len;
 	int prefix_len;
@@ -44,8 +45,14 @@ int pmic_bind_children(struct udevice *pmic, ofnode parent,
 			debug("  - compatible prefix: '%s'\n", info->prefix);
 			debug("  - compatible prefix: '%s'\n", info->prefix);
 
 
 			prefix_len = strlen(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);
 			drv = lists_driver_lookup_name(info->driver);
 			if (!drv) {
 			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
 	LP87565 series of PMICs have 4 single phase BUCKs that can also
 	be configured in multi phase modes. The driver implements
 	be configured in multi phase modes. The driver implements
 	get/set api for value and enable.
 	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_PBIAS) += pbias_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_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[])
 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;
 	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_BUCK_DRIVER		"sandbox_buck"
 #define SANDBOX_OF_BUCK_PREFIX		"buck"
 #define SANDBOX_OF_BUCK_PREFIX		"buck"
 
 
-#define SANDBOX_BUCK_COUNT	2
+#define SANDBOX_BUCK_COUNT	3
 #define SANDBOX_LDO_COUNT	2
 #define SANDBOX_LDO_COUNT	2
 /*
 /*
  * Sandbox PMIC registers:
  * Sandbox PMIC registers:
@@ -109,6 +109,9 @@ enum {
 #define SANDBOX_BUCK1_PLATNAME	"SUPPLY_1.2V"
 #define SANDBOX_BUCK1_PLATNAME	"SUPPLY_1.2V"
 #define SANDBOX_BUCK2_DEVNAME	"buck2"
 #define SANDBOX_BUCK2_DEVNAME	"buck2"
 #define SANDBOX_BUCK2_PLATNAME	"SUPPLY_3.3V"
 #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 */
 /* LDO names */
 #define SANDBOX_LDO1_DEVNAME	"ldo1"
 #define SANDBOX_LDO1_DEVNAME	"ldo1"
 #define SANDBOX_LDO1_PLATNAME	"VDD_EMMC_1.8V"
 #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_
 #ifndef	_SPL_H_
 #define	_SPL_H_
 #define	_SPL_H_
 
 
+#include <binman_sym.h>
+
 /* Platform-specific defines */
 /* Platform-specific defines */
 #include <linux/compiler.h>
 #include <linux/compiler.h>
 #include <asm/spl.h>
 #include <asm/spl.h>
@@ -51,6 +53,15 @@ struct spl_load_info {
 		      void *buf);
 		      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_load_simple_fit() - Loads a fit image from a device.
  * @spl_image:	Image description to set up
  * @spl_image:	Image description to set up

+ 2 - 0
test/dm/regulator.c

@@ -27,6 +27,7 @@ DECLARE_GLOBAL_DATA_PTR;
 enum {
 enum {
 	BUCK1,
 	BUCK1,
 	BUCK2,
 	BUCK2,
+	BUCK3,
 	LDO1,
 	LDO1,
 	LDO2,
 	LDO2,
 	OUTPUT_COUNT,
 	OUTPUT_COUNT,
@@ -42,6 +43,7 @@ static const char *regulator_names[OUTPUT_COUNT][OUTPUT_NAME_COUNT] = {
 	/* devname, platname */
 	/* devname, platname */
 	{ SANDBOX_BUCK1_DEVNAME, SANDBOX_BUCK1_PLATNAME },
 	{ SANDBOX_BUCK1_DEVNAME, SANDBOX_BUCK1_PLATNAME },
 	{ SANDBOX_BUCK2_DEVNAME, SANDBOX_BUCK2_PLATNAME },
 	{ SANDBOX_BUCK2_DEVNAME, SANDBOX_BUCK2_PLATNAME },
+	{ SANDBOX_BUCK3_DEVNAME, SANDBOX_BUCK3_PLATNAME },
 	{ SANDBOX_LDO1_DEVNAME, SANDBOX_LDO1_PLATNAME},
 	{ SANDBOX_LDO1_DEVNAME, SANDBOX_LDO1_PLATNAME},
 	{ SANDBOX_LDO2_DEVNAME, SANDBOX_LDO2_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
 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.
 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
 7. BuildImage() - builds the image and writes it to a file. This is the final
 step.
 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)
    # 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
 Code coverage
 -------------
 -------------
 
 
@@ -543,7 +572,8 @@ To do
 
 
 Some ideas:
 Some ideas:
 - Fill out the device tree to include the final position and size of each
 - 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
 - Use of-platdata to make the information available to code that is unable
   to use device tree (such as a very small SPL image)
   to use device tree (such as a very small SPL image)
 - Write an image map to a text file
 - Write an image map to a text file

+ 8 - 3
tools/binman/binman.py

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

+ 3 - 0
tools/binman/control.py

@@ -12,6 +12,7 @@ import sys
 import tools
 import tools
 
 
 import command
 import command
+import elf
 import fdt
 import fdt
 import fdt_util
 import fdt_util
 from image import Image
 from image import Image
@@ -89,6 +90,7 @@ def Binman(options, args):
 
 
     try:
     try:
         tout.Init(options.verbosity)
         tout.Init(options.verbosity)
+        elf.debug = options.debug
         try:
         try:
             tools.SetInputDirs(options.indir)
             tools.SetInputDirs(options.indir)
             tools.PrepareOutputDir(options.outdir, options.preserve)
             tools.PrepareOutputDir(options.outdir, options.preserve)
@@ -109,6 +111,7 @@ def Binman(options, args):
                 image.CheckSize()
                 image.CheckSize()
                 image.CheckEntries()
                 image.CheckEntries()
                 image.ProcessEntryContents()
                 image.ProcessEntryContents()
+                image.WriteSymbols()
                 image.BuildImage()
                 image.BuildImage()
         finally:
         finally:
             tools.FinaliseOutputDir()
             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):
     def ProcessContents(self):
         pass
         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
 # Entry-type module for spl/u-boot-spl.bin
 #
 #
 
 
+import elf
+
 from entry import Entry
 from entry import Entry
 from blob import Entry_blob
 from blob import Entry_blob
 
 
 class Entry_u_boot_spl(Entry_blob):
 class Entry_u_boot_spl(Entry_blob):
     def __init__(self, image, etype, node):
     def __init__(self, image, etype, node):
         Entry_blob.__init__(self, image, etype, node)
         Entry_blob.__init__(self, image, etype, node)
+        self.elf_fname = 'spl/u-boot-spl'
 
 
     def GetDefaultFilename(self):
     def GetDefaultFilename(self):
         return 'spl/u-boot-spl.bin'
         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 command
+import elf
 from entry import Entry
 from entry import Entry
 from blob import Entry_blob
 from blob import Entry_blob
 import tools
 import tools
@@ -19,8 +20,8 @@ class Entry_u_boot_spl_bss_pad(Entry_blob):
 
 
     def ObtainContents(self):
     def ObtainContents(self):
         fname = tools.GetInputFilename('spl/u-boot-spl')
         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.data = chr(0) * bss_size
         self.contents_size = 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 struct
 
 
 import command
 import command
+import elf
 from entry import Entry
 from entry import Entry
 from blob import Entry_blob
 from blob import Entry_blob
 import fdt_util
 import fdt_util
@@ -31,11 +32,9 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
     def ObtainContents(self):
     def ObtainContents(self):
         # Figure out where to put the microcode pointer
         # Figure out where to put the microcode pointer
         fname = tools.GetInputFilename(self.elf_fname)
         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'):
         elif not fdt_util.GetBool(self._node, 'optional-ucode'):
             self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
             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 cmdline
 import command
 import command
 import control
 import control
+import elf
 import fdt
 import fdt
 import fdt_util
 import fdt_util
 import tools
 import tools
@@ -28,11 +29,12 @@ import tout
 # Contents of test files, corresponding to different entry types
 # Contents of test files, corresponding to different entry types
 U_BOOT_DATA           = '1234'
 U_BOOT_DATA           = '1234'
 U_BOOT_IMG_DATA       = 'img'
 U_BOOT_IMG_DATA       = 'img'
-U_BOOT_SPL_DATA       = '567'
+U_BOOT_SPL_DATA       = '56780123456789abcde'
 BLOB_DATA             = '89'
 BLOB_DATA             = '89'
 ME_DATA               = '0abcd'
 ME_DATA               = '0abcd'
 VGA_DATA              = 'vga'
 VGA_DATA              = 'vga'
 U_BOOT_DTB_DATA       = 'udtb'
 U_BOOT_DTB_DATA       = 'udtb'
+U_BOOT_SPL_DTB_DATA   = 'spldtb'
 X86_START16_DATA      = 'start16'
 X86_START16_DATA      = 'start16'
 X86_START16_SPL_DATA  = 'start16spl'
 X86_START16_SPL_DATA  = 'start16spl'
 U_BOOT_NODTB_DATA     = 'nodtb with microcode pointer somewhere in here'
 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('me.bin', ME_DATA)
         TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
         TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
         TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_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('u-boot-x86-16bit.bin', X86_START16_DATA)
         TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
         TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
                                       X86_START16_SPL_DATA)
                                       X86_START16_SPL_DATA)
@@ -134,7 +137,10 @@ class TestFunctional(unittest.TestCase):
         Returns:
         Returns:
             Return value (0 for success)
             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.pager = 'binman-invalid-pager'
         options.build_dir = self._indir
         options.build_dir = self._indir
 
 
@@ -142,14 +148,16 @@ class TestFunctional(unittest.TestCase):
         # options.verbosity = tout.DEBUG
         # options.verbosity = tout.DEBUG
         return control.Binman(options, args)
         return control.Binman(options, args)
 
 
-    def _DoTestFile(self, fname):
+    def _DoTestFile(self, fname, debug=False):
         """Run binman with a given test file
         """Run binman with a given test file
 
 
         Args:
         Args:
             fname: Device tree source filename to use (e.g. 05_simple.dts)
             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'):
     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
         """Set up a new test device-tree file
         """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, len(result.stderr))
         self.assertEqual(0, result.return_code)
         self.assertEqual(0, result.return_code)
 
 
-    # Not yet available.
     def testBoard(self):
     def testBoard(self):
         """Test that we can run it with a specific board"""
         """Test that we can run it with a specific board"""
         self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
         self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
@@ -362,6 +369,10 @@ class TestFunctional(unittest.TestCase):
         data = self._DoReadFile('05_simple.dts')
         data = self._DoReadFile('05_simple.dts')
         self.assertEqual(U_BOOT_DATA, data)
         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):
     def testDual(self):
         """Test that we can handle creating two images
         """Test that we can handle creating two images
 
 
@@ -563,8 +574,10 @@ class TestFunctional(unittest.TestCase):
 
 
     def testImagePadByte(self):
     def testImagePadByte(self):
         """Test that the image pad byte can be specified"""
         """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')
         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):
     def testImageName(self):
         """Test that image files can be named"""
         """Test that image files can be named"""
@@ -586,7 +599,7 @@ class TestFunctional(unittest.TestCase):
     def testPackSorted(self):
     def testPackSorted(self):
         """Test that entries can be sorted"""
         """Test that entries can be sorted"""
         data = self._DoReadFile('24_sorted.dts')
         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)
                          U_BOOT_DATA, data)
 
 
     def testPackZeroPosition(self):
     def testPackZeroPosition(self):
@@ -614,14 +627,14 @@ class TestFunctional(unittest.TestCase):
         with self.assertRaises(ValueError) as e:
         with self.assertRaises(ValueError) as e:
             self._DoTestFile('28_pack_4gb_outside.dts')
             self._DoTestFile('28_pack_4gb_outside.dts')
         self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside "
         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))
                       str(e.exception))
 
 
     def testPackX86Rom(self):
     def testPackX86Rom(self):
         """Test that a basic x86 ROM can be created"""
         """Test that a basic x86 ROM can be created"""
         data = self._DoReadFile('29_x86-rom.dts')
         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):
     def testPackX86RomMeNoDesc(self):
         """Test that an invalid Intel descriptor entry is detected"""
         """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')
         data = self._DoReadFile('47_spl_bss_pad.dts')
         self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
         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):
     def testPackStart16Spl(self):
         """Test that an image with an x86 start16 region can be created"""
         """Test that an image with an x86 start16 region can be created"""
         data = self._DoReadFile('48_x86-start16-spl.dts')
         data = self._DoReadFile('48_x86-start16-spl.dts')
@@ -862,6 +882,32 @@ class TestFunctional(unittest.TestCase):
         data = self._DoReadFile('50_intel_mrc.dts')
         data = self._DoReadFile('50_intel_mrc.dts')
         self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
         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__":
 if __name__ == "__main__":
     unittest.main()
     unittest.main()

+ 76 - 3
tools/binman/image.py

@@ -6,8 +6,12 @@
 # Class for an image, the output of binman
 # Class for an image, the output of binman
 #
 #
 
 
+from __future__ import print_function
+
 from collections import OrderedDict
 from collections import OrderedDict
 from operator import attrgetter
 from operator import attrgetter
+import re
+import sys
 
 
 import fdt_util
 import fdt_util
 import tools
 import tools
@@ -45,7 +49,7 @@ class Image:
              address.
              address.
         _entries: OrderedDict() of entries
         _entries: OrderedDict() of entries
     """
     """
-    def __init__(self, name, node):
+    def __init__(self, name, node, test=False):
         global entry
         global entry
         global Entry
         global Entry
         import entry
         import entry
@@ -64,8 +68,9 @@ class Image:
         self._end_4gb = False
         self._end_4gb = False
         self._entries = OrderedDict()
         self._entries = OrderedDict()
 
 
-        self._ReadNode()
-        self._ReadEntries()
+        if not test:
+            self._ReadNode()
+            self._ReadEntries()
 
 
     def _ReadNode(self):
     def _ReadNode(self):
         """Read properties from the image node"""
         """Read properties from the image node"""
@@ -119,6 +124,14 @@ class Image:
         """
         """
         raise ValueError("Image '%s': %s" % (self._node.path, msg))
         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):
     def _ReadEntries(self):
         for node in self._node.subnodes:
         for node in self._node.subnodes:
             self._entries[node.name] = Entry.Create(self, node)
             self._entries[node.name] = Entry.Create(self, node)
@@ -220,6 +233,11 @@ class Image:
         for entry in self._entries.values():
         for entry in self._entries.values():
             entry.ProcessContents()
             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):
     def BuildImage(self):
         """Write the image to a file"""
         """Write the image to a file"""
         fname = tools.GetOutputFilename(self._filename)
         fname = tools.GetOutputFilename(self._filename)
@@ -230,3 +248,58 @@ class Image:
                 data = entry.GetData()
                 data = entry.GetData()
                 fd.seek(self._pad_before + entry.pos - self._skip_at_start)
                 fd.seek(self._pad_before + entry.pos - self._skip_at_start)
                 fd.write(data)
                 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 {
 		u-boot {
-			pos = <12>;
+			pos = <20>;
 		};
 		};
 	};
 	};
 };
 };

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

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

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

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

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

@@ -7,13 +7,13 @@
 	binman {
 	binman {
 		sort-by-pos;
 		sort-by-pos;
 		end-at-4gb;
 		end-at-4gb;
-		size = <16>;
+		size = <32>;
 		u-boot {
 		u-boot {
-			pos = <0xfffffff0>;
+			pos = <0xffffffe0>;
 		};
 		};
 
 
 		u-boot-spl {
 		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
 CFLAGS := -march=i386 -m32 -nostdlib -I ../../../include
 
 
 LDS_UCODE := -T u_boot_ucode_ptr.lds
 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)
 all: $(TARGETS)
 
 
@@ -24,6 +28,18 @@ u_boot_ucode_ptr: u_boot_ucode_ptr.c
 bss_data: CFLAGS += bss_data.lds
 bss_data: CFLAGS += bss_data.lds
 bss_data: bss_data.c
 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:
 clean:
 	rm -f $(TARGETS)
 	rm -f $(TARGETS)
 
 

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

@@ -4,7 +4,7 @@
  * SPDX-License-Identifier:     GPL-2.0+
  * SPDX-License-Identifier:     GPL-2.0+
  *
  *
  * Simple program to create a _dt_ucode_base_size symbol which can be read
  * 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];
 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+
  * SPDX-License-Identifier:     GPL-2.0+
  *
  *
  * Simple program to create a _dt_ucode_base_size symbol which can be read
  * 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]
 static unsigned long _dt_ucode_base_size[2]