浏览代码

Merge tag 'dm-pull-30jan21' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm

tpm fixes for coral
binman fixes support for symbols in sub-sections
support for additional cros_ec commands
various minor fixes / tweaks
Tom Rini 3 年之前
父节点
当前提交
242ef48ea7
共有 62 个文件被更改,包括 1487 次插入137 次删除
  1. 8 5
      Kconfig
  2. 25 0
      arch/sandbox/cpu/os.c
  3. 1 1
      arch/sandbox/cpu/start.c
  4. 7 3
      arch/sandbox/dts/sandbox.dtsi
  5. 10 0
      arch/sandbox/dts/test.dts
  6. 15 0
      arch/sandbox/include/asm/test.h
  7. 1 1
      arch/x86/cpu/i386/cpu.c
  8. 1 1
      arch/x86/cpu/start.S
  9. 20 1
      arch/x86/dts/chromebook_coral.dts
  10. 3 0
      arch/x86/include/asm/arch-apollolake/iomap.h
  11. 189 6
      cmd/cros_ec.c
  12. 1 0
      configs/chromebook_coral_defconfig
  13. 0 1
      configs/sandbox_spl_defconfig
  14. 1 0
      disk/part.c
  15. 21 14
      doc/arch/sandbox.rst
  16. 11 0
      drivers/block/sandbox.c
  17. 11 5
      drivers/clk/clk-uclass.c
  18. 2 2
      drivers/clk/intel/clk_intel.c
  19. 9 0
      drivers/core/device.c
  20. 12 9
      drivers/core/of_extra.c
  21. 2 0
      drivers/i2c/Makefile
  22. 2 0
      drivers/i2c/designware_i2c_pci.c
  23. 172 28
      drivers/misc/cros_ec.c
  24. 7 0
      drivers/misc/cros_ec_lpc.c
  25. 99 1
      drivers/misc/cros_ec_sandbox.c
  26. 3 1
      drivers/rtc/i2c_rtc_emul.c
  27. 32 10
      drivers/tpm/cr50_i2c.c
  28. 142 0
      include/cros_ec.h
  29. 1 0
      include/ctype.h
  30. 1 1
      include/dm/device.h
  31. 2 3
      include/dm/read.h
  32. 41 4
      include/ec_commands.h
  33. 18 0
      include/os.h
  34. 2 0
      lib/binman.c
  35. 2 0
      test/dm/Makefile
  36. 178 0
      test/dm/cros_ec.c
  37. 38 0
      test/dm/of_extra.c
  38. 4 4
      test/dm/of_platdata.c
  39. 1 2
      tools/binman/README
  40. 2 1
      tools/binman/control.py
  41. 2 1
      tools/binman/elf.py
  42. 3 1
      tools/binman/elf_test.py
  43. 1 2
      tools/binman/entry.py
  44. 4 0
      tools/binman/etype/blob.py
  45. 4 0
      tools/binman/etype/files.py
  46. 57 9
      tools/binman/etype/section.py
  47. 0 1
      tools/binman/etype/u_boot_spl_bss_pad.py
  48. 1 1
      tools/binman/etype/u_boot_spl_nodtb.py
  49. 13 2
      tools/binman/etype/vblock.py
  50. 2 2
      tools/binman/fmap_util.py
  51. 108 2
      tools/binman/ftest.py
  52. 54 8
      tools/binman/image.py
  53. 10 0
      tools/binman/state.py
  54. 1 1
      tools/binman/test/084_files.dts
  55. 22 0
      tools/binman/test/187_symbols_sub.dts
  56. 21 0
      tools/binman/test/188_image_entryarg.dts
  57. 31 0
      tools/binman/test/189_vblock_content.dts
  58. 12 0
      tools/binman/test/190_files_align.dts
  59. 23 0
      tools/binman/test/191_read_image_skip.dts
  60. 13 2
      tools/dtoc/fdt.py
  61. 6 0
      tools/dtoc/test_fdt.py
  62. 2 1
      tools/patman/tools.py

+ 8 - 5
Kconfig

@@ -217,22 +217,25 @@ config SYS_MALLOC_LEN
 	  TODO: Use for other architectures
 
 config SPL_SYS_MALLOC_F_LEN
-	hex "Size of malloc() pool in SPL before relocation"
+	hex "Size of malloc() pool in SPL"
 	depends on SYS_MALLOC_F && SPL
 	default 0x2800 if RCAR_GEN3
 	default SYS_MALLOC_F_LEN
 	help
-	  Before relocation, memory is very limited on many platforms. Still,
+	  In SPL memory is very limited on many platforms. Still,
 	  we can provide a small malloc() pool if needed. Driver model in
 	  particular needs this to operate, so that it can allocate the
 	  initial serial device and any others that are needed.
 
+	  It is possible to enable CONFIG_SYS_SPL_MALLOC_START to start a new
+	  malloc() region in SDRAM once it is inited.
+
 config TPL_SYS_MALLOC_F_LEN
-	hex "Size of malloc() pool in TPL before relocation"
+	hex "Size of malloc() pool in TPL"
 	depends on SYS_MALLOC_F && TPL
-	default SYS_MALLOC_F_LEN
+	default SPL_SYS_MALLOC_F_LEN
 	help
-	  Before relocation, memory is very limited on many platforms. Still,
+	  In TPL memory is very limited on many platforms. Still,
 	  we can provide a small malloc() pool if needed. Driver model in
 	  particular needs this to operate, so that it can allocate the
 	  initial serial device and any others that are needed.

+ 25 - 0
arch/sandbox/cpu/os.c

@@ -32,6 +32,9 @@
 #include <os.h>
 #include <rtc_def.h>
 
+/* Environment variable for time offset */
+#define ENV_TIME_OFFSET "UBOOT_SB_TIME_OFFSET"
+
 /* Operating System Interface */
 
 struct os_mem_hdr {
@@ -798,6 +801,28 @@ int os_spl_to_uboot(const char *fname)
 	return os_jump_to_file(fname);
 }
 
+long os_get_time_offset(void)
+{
+	const char *offset;
+
+	offset = getenv(ENV_TIME_OFFSET);
+	if (offset)
+		return strtol(offset, NULL, 0);
+	return 0;
+}
+
+void os_set_time_offset(long offset)
+{
+	char buf[21];
+	int ret;
+
+	snprintf(buf, sizeof(buf), "%ld", offset);
+	ret = setenv(ENV_TIME_OFFSET, buf, true);
+	if (ret)
+		printf("Could not set environment variable %s\n",
+		       ENV_TIME_OFFSET);
+}
+
 void os_localtime(struct rtc_time *rt)
 {
 	time_t t = time(NULL);

+ 1 - 1
arch/sandbox/cpu/start.c

@@ -215,7 +215,7 @@ static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state,
 	if (!p)
 		p = fname + strlen(fname);
 	len -= p - fname;
-	snprintf(p, len, fmt, p);
+	snprintf(p, len, fmt);
 	state->fdt_fname = fname;
 
 	return 0;

+ 7 - 3
arch/sandbox/dts/sandbox.dtsi

@@ -260,10 +260,14 @@
 		stringarray = "pre-proper";
 	};
 
-	spl-test7 {
+	test-bus {
+		compatible = "simple-bus";
 		u-boot,dm-spl;
-		compatible = "sandbox,spl-test";
-		stringarray = "spl";
+		spl-test7 {
+			u-boot,dm-spl;
+			compatible = "sandbox,spl-test";
+			stringarray = "spl";
+		};
 	};
 
 	square {

+ 10 - 0
arch/sandbox/dts/test.dts

@@ -90,6 +90,16 @@
 			wp-ro {
 				image-pos = <0xf000>;
 				size = <0x1000>;
+				used = <0x884>;
+				compress = "lz4";
+				uncomp-size = <0xcf8>;
+				hash {
+					algo = "sha256";
+					value = [00 01 02 03 04 05 06 07
+						08 09 0a 0b 0c 0d 0e 0f
+						10 11 12 13 14 15 16 17
+						18 19 1a 1b 1c 1d 1e 1f];
+				};
 			};
 			rw {
 				image-pos = <0x10000>;

+ 15 - 0
arch/sandbox/include/asm/test.h

@@ -57,6 +57,13 @@ enum {
 	SYSCON_COUNT
 };
 
+/**
+ */
+enum cros_ec_test_t {
+	CROSECT_BREAK_HELLO	= BIT(1),
+	CROSECT_LID_OPEN	= BIT(2),
+};
+
 /**
  * sandbox_i2c_set_test_mode() - set test mode for running unit tests
  *
@@ -260,4 +267,12 @@ uint sandbox_pci_read_bar(u32 barval, int type, uint size);
  */
 void sandbox_set_enable_memio(bool enable);
 
+/**
+ * sandbox_cros_ec_set_test_flags() - Set behaviour for testing purposes
+ *
+ * @dev: Device to check
+ * @flags: Flags to control behaviour (CROSECT_...)
+ */
+void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags);
+
 #endif

+ 1 - 1
arch/x86/cpu/i386/cpu.c

@@ -175,7 +175,7 @@ void arch_setup_gd(gd_t *new_gd)
  * Per Intel FSP external architecture specification, before calling any FSP
  * APIs, we need make sure the system is in flat 32-bit mode and both the code
  * and data selectors should have full 4GB access range. Here we reuse the one
- * we used in arch/x86/cpu/start16.S, and reload the segement registers.
+ * we used in arch/x86/cpu/start16.S, and reload the segment registers.
  */
 void setup_fsp_gdt(void)
 {

+ 1 - 1
arch/x86/cpu/start.S

@@ -77,7 +77,7 @@ _start:
 	lgdt	gdt_ptr2
 #endif
 
-	/* Load the segement registers to match the GDT loaded in start16.S */
+	/* Load the segment registers to match the GDT loaded in start16.S */
 	movl	$(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax
 	movw	%ax, %fs
 	movw	%ax, %ds

+ 20 - 1
arch/x86/dts/chromebook_coral.dts

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /dts-v1/;
 
+#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/gpio/x86-gpio.h>
 
 /include/ "skeleton.dtsi"
@@ -99,6 +100,7 @@
 	clk: clock {
 		compatible = "intel,apl-clk";
 		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
 	};
 
 	cpus {
@@ -139,6 +141,7 @@
 	};
 
 	acpi_gpe: general-purpose-events {
+		u-boot,dm-pre-reloc;
 		reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
 		compatible = "intel,acpi-gpe";
 		interrupt-controller;
@@ -417,8 +420,10 @@
 		};
 
 		i2c_2: i2c2@16,2 {
-			compatible = "intel,apl-i2c";
+			compatible = "intel,apl-i2c", "snps,designware-i2c-pci";
 			reg = <0x0200b210 0 0 0 0>;
+			early-regs = <IOMAP_I2C2_BASE 0x1000>;
+			u-boot,dm-pre-reloc;
 			#address-cells = <1>;
 			#size-cells = <0>;
 			clock-frequency = <400000>;
@@ -429,6 +434,7 @@
 			tpm: tpm@50 {
 				reg = <0x50>;
 				compatible = "google,cr50";
+				u-boot,dm-pre-reloc;
 				u-boot,i2c-offset-len = <0>;
 				ready-gpios = <&gpio_n 28 GPIO_ACTIVE_LOW>;
 				interrupts-extended = <&acpi_gpe GPIO_28_IRQ
@@ -583,6 +589,7 @@
 				u-boot,dm-pre-reloc;
 				cros_ec: cros-ec {
 					u-boot,dm-pre-proper;
+					u-boot,dm-vpl;
 					compatible = "google,cros-ec-lpc";
 					reg = <0x204 1 0x200 1 0x880 0x80>;
 
@@ -637,6 +644,7 @@
 				PAD_CFG0_TX_DISABLE | PAD_CFG0_ROUTE_IOAPIC |
 				PAD_CFG0_TRIG_LEVEL | PAD_CFG0_RX_POL_INVERT)
 			(PAD_CFG1_PULL_NONE | PAD_CFG1_IOSSTATE_TXD_RXE)
+		PAD_CFG_GPI(GPIO_25, UP_20K, DEEP)	 /* unused */
 
 		/*
 		 * WLAN_PE_RST - default to deasserted just in case FSP
@@ -657,6 +665,11 @@
 		PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1)	 /* LPC_AD3 */
 		PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1) /* LPC_CLKRUN_N */
 		PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1) /* LPC_FRAME_N */
+
+		PAD_CFG_GPI(GPIO_101, NONE, DEEP) /* FST_IO2 -- MEM_CONFIG0 */
+		PAD_CFG_GPI(GPIO_102, NONE, DEEP) /* FST_IO3 -- MEM_CONFIG1 */
+		PAD_CFG_GPI(GPIO_38, NONE, DEEP) /* LPSS_UART0_RXD - MEM_CONFIG2*/
+		PAD_CFG_GPI(GPIO_45, NONE, DEEP) /* LPSS_UART1_CTS - MEM_CONFIG3 */
 		>;
 };
 
@@ -1210,3 +1223,9 @@
 		PAD_CFG_GPI(GPIO_73, UP_20K, DEEP)	 /* GP_CAMERASB11 */
 	>;
 };
+
+&rtc {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	u-boot,dm-pre-reloc;
+};

+ 3 - 0
arch/x86/include/asm/arch-apollolake/iomap.h

@@ -33,6 +33,9 @@
 #define SRAM_SIZE_2		(4 * KiB)
 #endif
 
+/* Early address for I2C port 2 */
+#define IOMAP_I2C2_BASE		(0xfe020000 + 2 * 0x1000)
+
 /*
  * Use UART2. To use UART1 you need to set '2' to '1', change device tree serial
  * node name and 'reg' property, and update CONFIG_DEBUG_UART_BASE.

+ 189 - 6
cmd/cros_ec.c

@@ -94,6 +94,169 @@ static int do_read_write(struct udevice *dev, int is_write, int argc,
 	return 0;
 }
 
+static const char *const feat_name[64] = {
+	"limited",
+	"flash",
+	"pwm_fan",
+	"pwm_keyb",
+	"lightbar",
+	"led",
+	"motion_sense",
+	"keyb",
+	"pstore",
+	"port80",
+	"thermal",
+	"bklight_switch",
+	"wifi_switch",
+	"host_events",
+	"gpio",
+	"i2c",
+	"charger",
+	"battery",
+	"smart_battery",
+	"hang_detect",
+	"pmu",
+	"sub_mcu",
+	"usb_pd",
+	"usb_mux",
+	"motion_sense_fifo",
+	"vstore",
+	"usbc_ss_mux_virtual",
+	"rtc",
+	"fingerprint",
+	"touchpad",
+	"rwsig",
+	"device_event",
+	"unified_wake_masks",
+	"host_event64",
+	"exec_in_ram",
+	"cec",
+	"motion_sense_tight_timestamps",
+	"refined_tablet_mode_hysteresis",
+	"efs2",
+	"scp",
+	"ish",
+	"typec_cmd",
+	"typec_require_ap_mode_entry",
+	"typec_mux_require_ap_ack",
+};
+
+static int do_show_features(struct udevice *dev)
+{
+	u64 feat;
+	int ret;
+	uint i;
+
+	ret = cros_ec_get_features(dev, &feat);
+	if (ret)
+		return ret;
+	for (i = 0; i < ARRAY_SIZE(feat_name); i++) {
+		if (feat & (1ULL << i)) {
+			if (feat_name[i])
+				printf("%s\n", feat_name[i]);
+			else
+				printf("unknown %d\n", i);
+		}
+	}
+
+	return 0;
+}
+
+static const char *const switch_name[8] = {
+	"lid open",
+	"power button pressed",
+	"write-protect disabled",
+	NULL,
+	"dedicated recovery",
+	NULL,
+	NULL,
+	NULL,
+};
+
+static int do_show_switches(struct udevice *dev)
+{
+	uint switches;
+	int ret;
+	uint i;
+
+	ret = cros_ec_get_switches(dev);
+	if (ret < 0)
+		return log_msg_ret("get", ret);
+	switches = ret;
+	for (i = 0; i < ARRAY_SIZE(switch_name); i++) {
+		uint mask = 1 << i;
+
+		if (switches & mask) {
+			if (switch_name[i])
+				printf("%s\n", switch_name[i]);
+			else
+				printf("unknown %02x\n", mask);
+		}
+	}
+
+	return 0;
+}
+
+static const char *const event_name[] = {
+	"lid_closed",
+	"lid_open",
+	"power_button",
+	"ac_connected",
+	"ac_disconnected",
+	"battery_low",
+	"battery_critical",
+	"battery",
+	"thermal_threshold",
+	"device",
+	"thermal",
+	"usb_charger",
+	"key_pressed",
+	"interface_ready",
+	"keyboard_recovery",
+	"thermal_shutdown",
+	"battery_shutdown",
+	"throttle_start",
+	"throttle_stop",
+	"hang_detect",
+	"hang_reboot",
+	"pd_mcu",
+	"battery_status",
+	"panic",
+	"keyboard_fastboot",
+	"rtc",
+	"mkbp",
+	"usb_mux",
+	"mode_change",
+	"keyboard_recovery_hw_reinit",
+	"extended",
+	"invalid",
+};
+
+static int do_show_events(struct udevice *dev)
+{
+	u32 events;
+	int ret;
+	uint i;
+
+	ret = cros_ec_get_host_events(dev, &events);
+	if (ret)
+		return ret;
+	printf("%08x\n", events);
+	for (i = 0; i < ARRAY_SIZE(event_name); i++) {
+		enum host_event_code code = i + 1;
+		u64 mask = EC_HOST_EVENT_MASK(code);
+
+		if (events & mask) {
+			if (event_name[i])
+				printf("%s\n", event_name[i]);
+			else
+				printf("unknown code %#x\n", code);
+		}
+	}
+
+	return 0;
+}
+
 static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
 		      char *const argv[])
 {
@@ -140,6 +303,16 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
 		}
 		printf("rows     = %u\n", info.rows);
 		printf("cols     = %u\n", info.cols);
+	} else if (!strcmp("features", cmd)) {
+		ret = do_show_features(dev);
+
+		if (ret)
+			printf("Error: %d\n", ret);
+	} else if (!strcmp("switches", cmd)) {
+		ret = do_show_switches(dev);
+
+		if (ret)
+			printf("Error: %d\n", ret);
 	} else if (0 == strcmp("curimage", cmd)) {
 		enum ec_current_image image;
 
@@ -190,13 +363,10 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
 			return 1;
 		}
 	} else if (0 == strcmp("events", cmd)) {
-		uint32_t events;
+		ret = do_show_events(dev);
 
-		if (cros_ec_get_host_events(dev, &events)) {
-			debug("%s: Could not read host events\n", __func__);
-			return 1;
-		}
-		printf("0x%08x\n", events);
+		if (ret)
+			printf("Error: %d\n", ret);
 	} else if (0 == strcmp("clrevents", cmd)) {
 		uint32_t events = 0x7fffffff;
 
@@ -352,6 +522,15 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc,
 			debug("%s: Could not access LDO%d\n", __func__, index);
 			return ret;
 		}
+	} else if (!strcmp("sku", cmd)) {
+		ret = cros_ec_get_sku_id(dev);
+
+		if (ret >= 0) {
+			printf("%d\n", ret);
+			ret = 0;
+		} else {
+			printf("Error: %d\n", ret);
+		}
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -370,10 +549,13 @@ U_BOOT_CMD(
 	"init                Re-init CROS-EC (done on startup automatically)\n"
 	"crosec id                  Read CROS-EC ID\n"
 	"crosec info                Read CROS-EC info\n"
+	"crosec features            Read CROS-EC features\n"
+	"crosec switches            Read CROS-EC switches\n"
 	"crosec curimage            Read CROS-EC current image\n"
 	"crosec hash                Read CROS-EC hash\n"
 	"crosec reboot [rw | ro | cold]  Reboot CROS-EC\n"
 	"crosec events              Read CROS-EC host events\n"
+	"crosec eventsb             Read CROS-EC host events_b\n"
 	"crosec clrevents [mask]    Clear CROS-EC host events\n"
 	"crosec regioninfo <ro|rw>  Read image info\n"
 	"crosec flashinfo           Read flash info\n"
@@ -382,6 +564,7 @@ U_BOOT_CMD(
 	"crosec write <ro|rw> <addr> [<size>]  Write EC image\n"
 	"crosec vbnvcontext [hexstring]        Read [write] VbNvContext from EC\n"
 	"crosec ldo <idx> [<state>] Switch/Read LDO state\n"
+	"crosec sku                 Read board SKU ID\n"
 	"crosec test                run tests on cros_ec\n"
 	"crosec version             Read CROS-EC version"
 );

+ 1 - 0
configs/chromebook_coral_defconfig

@@ -29,6 +29,7 @@ CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_SPL_BOOTSTAGE_RECORD_COUNT=10
 CONFIG_BOOTSTAGE_STASH=y
 CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS_SUBST=y
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_LOGF_FUNC=y
 CONFIG_SPL_LOG=y

+ 0 - 1
configs/sandbox_spl_defconfig

@@ -101,7 +101,6 @@ CONFIG_SYSCON=y
 CONFIG_SPL_SYSCON=y
 CONFIG_DEVRES=y
 CONFIG_DEBUG_DEVRES=y
-# CONFIG_SPL_SIMPLE_BUS is not set
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
 CONFIG_AXI=y

+ 1 - 0
disk/part.c

@@ -150,6 +150,7 @@ void dev_print (struct blk_desc *dev_desc)
 	case IF_TYPE_USB:
 	case IF_TYPE_NVME:
 	case IF_TYPE_PVBLOCK:
+	case IF_TYPE_HOST:
 		printf ("Vendor: %s Rev: %s Prod: %s\n",
 			dev_desc->vendor,
 			dev_desc->revision,

+ 21 - 14
doc/arch/sandbox.rst

@@ -99,37 +99,44 @@ Command-line Options
 Various options are available, mostly for test purposes. Use -h to see
 available options. Some of these are described below:
 
-* -t, --terminal <arg>
-  - The terminal is normally in what is called 'raw-with-sigs' mode. This means
+-t, --terminal <arg>
+  The terminal is normally in what is called 'raw-with-sigs' mode. This means
   that you can use arrow keys for command editing and history, but if you
   press Ctrl-C, U-Boot will exit instead of handling this as a keypress.
   Other options are 'raw' (so Ctrl-C is handled within U-Boot) and 'cooked'
   (where the terminal is in cooked mode and cursor keys will not work, Ctrl-C
   will exit).
 
-* -l
-  - Show the LCD emulation window.
+-l
+  Show the LCD emulation window.
 
-* -d <device_tree>
-  - A device tree binary file can be provided with -d. If you edit the source
+-d <device_tree>
+  A device tree binary file can be provided with -d. If you edit the source
   (it is stored at arch/sandbox/dts/sandbox.dts) you must rebuild U-Boot to
   recreate the binary file.
 
-* -D
-  - To use the default device tree, use -D.
+-D
+  To use the default device tree, use -D.
 
-* -T
-  - To use the test device tree, use -T.
+-T
+  To use the test device tree, use -T.
 
-* -c [<cmd>;]<cmd>
-  - To execute commands directly, use the -c option. You can specify a single
+-c [<cmd>;]<cmd>
+  To execute commands directly, use the -c option. You can specify a single
   command, or multiple commands separated by a semicolon, as is normal in
   U-Boot. Be careful with quoting as the shell will normally process and
   swallow quotes. When -c is used, U-Boot exits after the command is complete,
   but you can force it to go to interactive mode instead with -i.
 
-* -i
-  - Go to interactive mode after executing the commands specified by -c.
+-i
+  Go to interactive mode after executing the commands specified by -c.
+
+Environment Variables
+---------------------
+
+UBOOT_SB_TIME_OFFSET
+    This environment variable stores the offset of the emulated real time clock
+    to the host's real time clock in seconds. The offset defaults to zero.
 
 Memory Emulation
 ----------------

+ 11 - 0
drivers/block/sandbox.c

@@ -92,6 +92,7 @@ int host_dev_bind(int devnum, char *filename)
 {
 	struct host_block_dev *host_dev;
 	struct udevice *dev;
+	struct blk_desc *desc;
 	char dev_name[20], *str, *fname;
 	int ret, fd;
 
@@ -143,6 +144,12 @@ int host_dev_bind(int devnum, char *filename)
 		goto err_file;
 	}
 
+	desc = blk_get_devnum_by_type(IF_TYPE_HOST, devnum);
+	desc->removable = 1;
+	snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
+	snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
+	snprintf(desc->revision, BLK_REV_SIZE, "1.0");
+
 	return 0;
 err_file:
 	os_close(fd);
@@ -187,6 +194,10 @@ int host_dev_bind(int dev, char *filename)
 	blk_dev->block_write = host_block_write;
 	blk_dev->devnum = dev;
 	blk_dev->part_type = PART_TYPE_UNKNOWN;
+	blk_dev->removable = 1;
+	snprintf(blk_dev->vendor, BLK_VEN_SIZE, "U-Boot");
+	snprintf(blk_dev->product, BLK_PRD_SIZE, "hostfile");
+	snprintf(blk_dev->revision, BLK_REV_SIZE, "1.0");
 	part_init(blk_dev);
 
 	return 0;

+ 11 - 5
drivers/clk/clk-uclass.c

@@ -83,7 +83,7 @@ static int clk_get_by_index_tail(int ret, ofnode node,
 	if (ret) {
 		debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
 		      __func__, ret);
-		return ret;
+		return log_msg_ret("get", ret);
 	}
 
 	clk->dev = dev_clk;
@@ -96,14 +96,15 @@ static int clk_get_by_index_tail(int ret, ofnode node,
 		ret = clk_of_xlate_default(clk, args);
 	if (ret) {
 		debug("of_xlate() failed: %d\n", ret);
-		return ret;
+		return log_msg_ret("xlate", ret);
 	}
 
 	return clk_request(dev_clk, clk);
 err:
 	debug("%s: Node '%s', property '%s', failed to request CLK index %d: %d\n",
 	      __func__, ofnode_get_name(node), list_name, index, ret);
-	return ret;
+
+	return log_msg_ret("prop", ret);
 }
 
 static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
@@ -122,7 +123,7 @@ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
 	if (ret) {
 		debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
 		      __func__, ret);
-		return ret;
+		return log_ret(ret);
 	}
 
 
@@ -470,6 +471,7 @@ int clk_free(struct clk *clk)
 ulong clk_get_rate(struct clk *clk)
 {
 	const struct clk_ops *ops;
+	int ret;
 
 	debug("%s(clk=%p)\n", __func__, clk);
 	if (!clk_valid(clk))
@@ -479,7 +481,11 @@ ulong clk_get_rate(struct clk *clk)
 	if (!ops->get_rate)
 		return -ENOSYS;
 
-	return ops->get_rate(clk);
+	ret = ops->get_rate(clk);
+	if (ret)
+		return log_ret(ret);
+
+	return 0;
 }
 
 struct clk *clk_get_parent(struct clk *clk)

+ 2 - 2
drivers/clk/intel/clk_intel.c

@@ -29,8 +29,8 @@ static const struct udevice_id intel_clk_ids[] = {
 	{ }
 };
 
-U_BOOT_DRIVER(clk_intel) = {
-	.name		= "clk_intel",
+U_BOOT_DRIVER(intel_apl_clk) = {
+	.name		= "intel_apl_clk",
 	.id		= UCLASS_CLK,
 	.of_match	= intel_clk_ids,
 	.ops		= &intel_clk_ops,

+ 9 - 0
drivers/core/device.c

@@ -462,6 +462,15 @@ int device_probe(struct udevice *dev)
 	 * continue regardless of the result of pinctrl. Don't process pinctrl
 	 * settings for pinctrl devices since the device may not yet be
 	 * probed.
+	 *
+	 * This call can produce some non-intuitive results. For example, on an
+	 * x86 device where dev is the main PCI bus, the pinctrl device may be
+	 * child or grandchild of that bus, meaning that the child will be
+	 * probed here. If the child happens to be the P2SB and the pinctrl
+	 * device is a child of that, then both the pinctrl and P2SB will be
+	 * probed by this call. This works because the DM_FLAG_ACTIVATED flag
+	 * is set just above. However, the PCI bus' probe() method and
+	 * associated uclass methods have not yet been called.
 	 */
 	if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
 		pinctrl_select_state(dev, "default");

+ 12 - 9
drivers/core/of_extra.c

@@ -14,16 +14,17 @@
 int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry)
 {
 	const char *prop;
+	ofnode subnode;
 
 	if (ofnode_read_u32(node, "image-pos", &entry->offset)) {
 		debug("Node '%s' has bad/missing 'image-pos' property\n",
 		      ofnode_get_name(node));
-		return log_ret(-ENOENT);
+		return log_msg_ret("image-pos", -ENOENT);
 	}
 	if (ofnode_read_u32(node, "size", &entry->length)) {
 		debug("Node '%s' has bad/missing 'size' property\n",
 		      ofnode_get_name(node));
-		return log_ret(-ENOENT);
+		return log_msg_ret("size", -ENOENT);
 	}
 	entry->used = ofnode_read_s32_default(node, "used", entry->length);
 	prop = ofnode_read_string(node, "compress");
@@ -31,18 +32,20 @@ int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry)
 		if (!strcmp(prop, "lz4"))
 			entry->compress_algo = FMAP_COMPRESS_LZ4;
 		else
-			return log_msg_ret("Unknown compression algo",
-					   -EINVAL);
+			return log_msg_ret("compression algo", -EINVAL);
 	} else {
 		entry->compress_algo = FMAP_COMPRESS_NONE;
 	}
 	entry->unc_length = ofnode_read_s32_default(node, "uncomp-size",
 						    entry->length);
-	prop = ofnode_read_string(node, "hash");
-	if (prop)
-		entry->hash_size = strlen(prop);
-	entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
-	entry->hash = (uint8_t *)prop;
+	subnode = ofnode_find_subnode(node, "hash");
+	if (ofnode_valid(subnode)) {
+		prop = ofnode_read_prop(subnode, "value", &entry->hash_size);
+
+		/* Assume it is sha256 */
+		entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE;
+		entry->hash = (uint8_t *)prop;
+	}
 
 	return 0;
 }

+ 2 - 0
drivers/i2c/Makefile

@@ -39,7 +39,9 @@ obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
 obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
 obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o
+ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
+endif
 obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
 obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
 obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o

+ 2 - 0
drivers/i2c/designware_i2c_pci.c

@@ -192,6 +192,8 @@ static const struct udevice_id designware_i2c_pci_ids[] = {
 	{ }
 };
 
+DM_DRIVER_ALIAS(i2c_designware_pci, intel_apl_i2c)
+
 U_BOOT_DRIVER(i2c_designware_pci) = {
 	.name	= "i2c_designware_pci",
 	.id	= UCLASS_I2C,

+ 172 - 28
drivers/misc/cros_ec.c

@@ -44,6 +44,10 @@ enum {
 	CROS_EC_CMD_TIMEOUT_MS	= 5000,
 	/* Timeout waiting for a synchronous hash to be recomputed */
 	CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
+
+	/* Wait 10 ms between attempts to check if EC's hash is ready */
+	CROS_EC_HASH_CHECK_DELAY_MS = 10,
+
 };
 
 #define INVALID_HCMD 0xFF
@@ -400,6 +404,8 @@ static int ec_command(struct udevice *dev, uint cmd, int cmd_version,
 		 */
 		if (din && in_buffer) {
 			assert(len <= din_len);
+			if (len > din_len)
+				return -ENOSPC;
 			memmove(din, in_buffer, len);
 		}
 	}
@@ -502,9 +508,10 @@ static int cros_ec_wait_on_hash_done(struct udevice *dev,
 
 	start = get_timer(0);
 	while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) {
-		mdelay(50);	/* Insert some reasonable delay */
+		mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
 
 		p->cmd = EC_VBOOT_HASH_GET;
+
 		if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, p, sizeof(*p), hash,
 			       sizeof(*hash)) < 0)
 			return -1;
@@ -591,6 +598,25 @@ static int cros_ec_invalidate_hash(struct udevice *dev)
 	return 0;
 }
 
+int cros_ec_hello(struct udevice *dev, uint *handshakep)
+{
+	struct ec_params_hello req;
+	struct ec_response_hello *resp;
+
+	req.in_data = 0x12345678;
+	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
+			     (uint8_t **)&resp, sizeof(*resp)) < 0)
+		return -EIO;
+	if (resp->out_data != req.in_data + 0x01020304) {
+		printf("Received invalid handshake %x\n", resp->out_data);
+		if (handshakep)
+			*handshakep = req.in_data;
+		return -ENOTSYNC;
+	}
+
+	return 0;
+}
+
 int cros_ec_reboot(struct udevice *dev, enum ec_reboot_cmd cmd, uint8_t flags)
 {
 	struct ec_params_reboot_ec p;
@@ -603,18 +629,23 @@ int cros_ec_reboot(struct udevice *dev, enum ec_reboot_cmd cmd, uint8_t flags)
 		return -1;
 
 	if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) {
+		ulong start;
+
 		/*
 		 * EC reboot will take place immediately so delay to allow it
 		 * to complete.  Note that some reboot types (EC_REBOOT_COLD)
 		 * will reboot the AP as well, in which case we won't actually
 		 * get to this point.
 		 */
-		/*
-		 * TODO(rspangler@chromium.org): Would be nice if we had a
-		 * better way to determine when the reboot is complete.  Could
-		 * we poll a memory-mapped LPC value?
-		 */
-		udelay(50000);
+		mdelay(50);
+		start = get_timer(0);
+		while (cros_ec_hello(dev, NULL)) {
+			if (get_timer(start) > 3000) {
+				log_err("EC did not return from reboot\n");
+				return -ETIMEDOUT;
+			}
+			mdelay(5);
+		}
 	}
 
 	return 0;
@@ -738,7 +769,6 @@ static int cros_ec_check_version(struct udevice *dev)
 {
 	struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
 	struct ec_params_hello req;
-	struct ec_response_hello *resp;
 
 	struct dm_cros_ec_ops *ops;
 	int ret;
@@ -767,14 +797,14 @@ static int cros_ec_check_version(struct udevice *dev)
 	/* Try sending a version 3 packet */
 	cdev->protocol_version = 3;
 	req.in_data = 0;
-	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
-			     (uint8_t **)&resp, sizeof(*resp)) > 0)
+	ret = cros_ec_hello(dev, NULL);
+	if (!ret || ret == -ENOTSYNC)
 		return 0;
 
 	/* Try sending a version 2 packet */
 	cdev->protocol_version = 2;
-	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
-			     (uint8_t **)&resp, sizeof(*resp)) > 0)
+	ret = cros_ec_hello(dev, NULL);
+	if (!ret || ret == -ENOTSYNC)
 		return 0;
 
 	/*
@@ -790,18 +820,16 @@ static int cros_ec_check_version(struct udevice *dev)
 
 int cros_ec_test(struct udevice *dev)
 {
-	struct ec_params_hello req;
-	struct ec_response_hello *resp;
+	uint out_data;
+	int ret;
 
-	req.in_data = 0x12345678;
-	if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req),
-		       (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) {
+	ret = cros_ec_hello(dev, &out_data);
+	if (ret == -ENOTSYNC) {
+		printf("Received invalid handshake %x\n", out_data);
+		return ret;
+	} else if (ret) {
 		printf("ec_command_inptr() returned error\n");
-		return -1;
-	}
-	if (resp->out_data != req.in_data + 0x01020304) {
-		printf("Received invalid handshake %x\n", resp->out_data);
-		return -1;
+		return ret;
 	}
 
 	return 0;
@@ -1077,6 +1105,19 @@ int cros_ec_flash_update_rw(struct udevice *dev, const uint8_t *image,
 	return 0;
 }
 
+int cros_ec_get_sku_id(struct udevice *dev)
+{
+	struct ec_sku_id_info *r;
+	int ret;
+
+	ret = ec_command_inptr(dev, EC_CMD_GET_SKU_ID, 0, NULL, 0,
+			       (uint8_t **)&r, sizeof(*r));
+	if (ret != sizeof(*r))
+		return -ret;
+
+	return r->sku_id;
+}
+
 int cros_ec_read_nvdata(struct udevice *dev, uint8_t *block, int size)
 {
 	struct ec_params_vbnvcontext p;
@@ -1303,19 +1344,33 @@ int cros_ec_i2c_tunnel(struct udevice *dev, int port, struct i2c_msg *in,
 	return 0;
 }
 
-int cros_ec_check_feature(struct udevice *dev, int feature)
+int cros_ec_get_features(struct udevice *dev, u64 *featuresp)
 {
 	struct ec_response_get_features r;
 	int rv;
 
-	rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, &r, sizeof(r), NULL, 0);
-	if (rv)
-		return rv;
+	rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, NULL, 0, &r, sizeof(r));
+	if (rv != sizeof(r))
+		return -EIO;
+	*featuresp = r.flags[0] | (u64)r.flags[1] << 32;
+
+	return 0;
+}
+
+int cros_ec_check_feature(struct udevice *dev, uint feature)
+{
+	struct ec_response_get_features r;
+	int rv;
+
+	rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, NULL, 0, &r, sizeof(r));
+	if (rv != sizeof(r))
+		return -EIO;
 
 	if (feature >= 8 * sizeof(r.flags))
-		return -1;
+		return -EINVAL;
 
-	return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature);
+	return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature) ? true :
+		 false;
 }
 
 /*
@@ -1502,10 +1557,99 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable)
 	return 0;
 }
 
+int cros_ec_vstore_supported(struct udevice *dev)
+{
+	return cros_ec_check_feature(dev, EC_FEATURE_VSTORE);
+}
+
+int cros_ec_vstore_info(struct udevice *dev, u32 *lockedp)
+{
+	struct ec_response_vstore_info *resp;
+
+	if (ec_command_inptr(dev, EC_CMD_VSTORE_INFO, 0, NULL, 0,
+			     (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
+		return -EIO;
+
+	if (lockedp)
+		*lockedp = resp->slot_locked;
+
+	return resp->slot_count;
+}
+
+/*
+ * cros_ec_vstore_read - Read data from EC vstore slot
+ *
+ * @slot: vstore slot to read from
+ * @data: buffer to store read data, must be EC_VSTORE_SLOT_SIZE bytes
+ */
+int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data)
+{
+	struct ec_params_vstore_read req;
+	struct ec_response_vstore_read *resp;
+
+	req.slot = slot;
+	if (ec_command_inptr(dev, EC_CMD_VSTORE_READ, 0, &req, sizeof(req),
+			     (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
+		return -EIO;
+
+	if (!data || req.slot >= EC_VSTORE_SLOT_MAX)
+		return -EINVAL;
+
+	memcpy(data, resp->data, sizeof(resp->data));
+
+	return 0;
+}
+
+/*
+ * cros_ec_vstore_write - Save data into EC vstore slot
+ *
+ * @slot: vstore slot to write into
+ * @data: data to write
+ * @size: size of data in bytes
+ *
+ * Maximum size of data is EC_VSTORE_SLOT_SIZE.  It is the callers
+ * responsibility to check the number of implemented slots by
+ * querying the vstore info.
+ */
+int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data,
+			 size_t size)
+{
+	struct ec_params_vstore_write req;
+
+	if (slot >= EC_VSTORE_SLOT_MAX || size > EC_VSTORE_SLOT_SIZE)
+		return -EINVAL;
+
+	req.slot = slot;
+	memcpy(req.data, data, size);
+
+	if (ec_command(dev, EC_CMD_VSTORE_WRITE, 0, &req, sizeof(req), NULL, 0))
+		return -EIO;
+
+	return 0;
+}
+
+int cros_ec_get_switches(struct udevice *dev)
+{
+	struct dm_cros_ec_ops *ops;
+	int ret;
+
+	ops = dm_cros_ec_get_ops(dev);
+	if (!ops->get_switches)
+		return -ENOSYS;
+
+	ret = ops->get_switches(dev);
+	if (ret < 0)
+		return log_msg_ret("get", ret);
+
+	return ret;
+}
+
 UCLASS_DRIVER(cros_ec) = {
 	.id		= UCLASS_CROS_EC,
 	.name		= "cros-ec",
 	.per_device_auto	= sizeof(struct cros_ec_dev),
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
 	.post_bind	= dm_scan_fdt_dev,
+#endif
 	.flags		= DM_UC_FLAG_ALLOC_PRIV_DMA,
 };

+ 7 - 0
drivers/misc/cros_ec_lpc.c

@@ -207,6 +207,12 @@ int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob)
 	return 0;
 }
 
+/* Return the byte of EC switch states */
+static int cros_ec_lpc_get_switches(struct udevice *dev)
+{
+	return inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SWITCHES);
+}
+
 /*
  * Test if LPC command args are supported.
  *
@@ -239,6 +245,7 @@ static struct dm_cros_ec_ops cros_ec_ops = {
 	.packet = cros_ec_lpc_packet,
 	.command = cros_ec_lpc_command,
 	.check_version = cros_ec_lpc_check_version,
+	.get_switches = cros_ec_lpc_get_switches,
 };
 
 static const struct udevice_id cros_ec_ids[] = {

+ 99 - 1
drivers/misc/cros_ec_sandbox.c

@@ -18,6 +18,7 @@
 #include <asm/malloc.h>
 #include <asm/state.h>
 #include <asm/sdl.h>
+#include <asm/test.h>
 #include <linux/input.h>
 
 /*
@@ -61,6 +62,15 @@ struct ec_keymatrix_entry {
 	int keycode;	/* corresponding linux key code */
 };
 
+enum {
+	VSTORE_SLOT_COUNT	= 4,
+};
+
+struct vstore_slot {
+	bool locked;
+	u8 data[EC_VSTORE_SLOT_SIZE];
+};
+
 /**
  * struct ec_state - Information about the EC state
  *
@@ -73,6 +83,8 @@ struct ec_keymatrix_entry {
  * @matrix: Information about keyboard matrix
  * @keyscan: Current keyscan information (bit set for each row/column pressed)
  * @recovery_req: Keyboard recovery requested
+ * @test_flags: Flags that control behaviour for tests
+ * @slot_locked: Locked vstore slots (mask)
  */
 struct ec_state {
 	u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2];
@@ -84,6 +96,8 @@ struct ec_state {
 	struct ec_keymatrix_entry *matrix;	/* the key matrix info */
 	uint8_t keyscan[KEYBOARD_COLS];
 	bool recovery_req;
+	uint test_flags;
+	struct vstore_slot slot[VSTORE_SLOT_COUNT];
 } s_state, *g_state;
 
 /**
@@ -295,6 +309,8 @@ static int process_cmd(struct ec_state *ec,
 		struct ec_response_hello *resp = resp_data;
 
 		resp->out_data = req->in_data + 0x01020304;
+		if (ec->test_flags & CROSECT_BREAK_HELLO)
+			resp->out_data++;
 		len = sizeof(*resp);
 		break;
 	}
@@ -358,10 +374,20 @@ static int process_cmd(struct ec_state *ec,
 			resp->mask |= EC_HOST_EVENT_MASK(
 					EC_HOST_EVENT_KEYBOARD_RECOVERY);
 		}
-
+		if (ec->test_flags & CROSECT_LID_OPEN)
+			resp->mask |=
+				EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN);
 		len = sizeof(*resp);
 		break;
 	}
+	case EC_CMD_HOST_EVENT_CLEAR_B: {
+		const struct ec_params_host_event_mask *req = req_data;
+
+		if (req->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN))
+			ec->test_flags &= ~CROSECT_LID_OPEN;
+		len = 0;
+		break;
+		}
 	case EC_CMD_VBOOT_HASH: {
 		const struct ec_params_vboot_hash *req = req_data;
 		struct ec_response_vboot_hash *resp = resp_data;
@@ -468,6 +494,62 @@ static int process_cmd(struct ec_state *ec,
 		len = sizeof(*resp);
 		break;
 	}
+	case EC_CMD_GET_SKU_ID: {
+		struct ec_sku_id_info *resp = resp_data;
+
+		resp->sku_id = 1234;
+		len = sizeof(*resp);
+		break;
+	}
+	case EC_CMD_GET_FEATURES: {
+		struct ec_response_get_features *resp = resp_data;
+
+		resp->flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FLASH) |
+			EC_FEATURE_MASK_0(EC_FEATURE_I2C) |
+			EC_FEATURE_MASK_0(EC_FEATURE_VSTORE);
+		resp->flags[1] =
+			EC_FEATURE_MASK_1(EC_FEATURE_UNIFIED_WAKE_MASKS) |
+			EC_FEATURE_MASK_1(EC_FEATURE_ISH);
+		len = sizeof(*resp);
+		break;
+	}
+	case EC_CMD_VSTORE_INFO: {
+		struct ec_response_vstore_info *resp = resp_data;
+		int i;
+
+		resp->slot_count = VSTORE_SLOT_COUNT;
+		resp->slot_locked = 0;
+		for (i = 0; i < VSTORE_SLOT_COUNT; i++) {
+			if (ec->slot[i].locked)
+				resp->slot_locked |= 1 << i;
+		}
+		len = sizeof(*resp);
+		break;
+	};
+	case EC_CMD_VSTORE_WRITE: {
+		const struct ec_params_vstore_write *req = req_data;
+		struct vstore_slot *slot;
+
+		if (req->slot >= EC_VSTORE_SLOT_MAX)
+			return -EINVAL;
+		slot = &ec->slot[req->slot];
+		slot->locked = true;
+		memcpy(slot->data, req->data, EC_VSTORE_SLOT_SIZE);
+		len = 0;
+		break;
+	}
+	case EC_CMD_VSTORE_READ: {
+		const struct ec_params_vstore_read *req = req_data;
+		struct ec_response_vstore_read *resp = resp_data;
+		struct vstore_slot *slot;
+
+		if (req->slot >= EC_VSTORE_SLOT_MAX)
+			return -EINVAL;
+		slot = &ec->slot[req->slot];
+		memcpy(resp->data, slot->data, EC_VSTORE_SLOT_SIZE);
+		len = sizeof(*resp);
+		break;
+	}
 	default:
 		printf("   ** Unknown EC command %#02x\n", req_hdr->command);
 		return -1;
@@ -518,6 +600,21 @@ void cros_ec_check_keyboard(struct udevice *dev)
 	}
 }
 
+/* Return the byte of EC switch states */
+static int cros_ec_sandbox_get_switches(struct udevice *dev)
+{
+	struct ec_state *ec = dev_get_priv(dev);
+
+	return ec->test_flags & CROSECT_LID_OPEN ? EC_SWITCH_LID_OPEN : 0;
+}
+
+void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags)
+{
+	struct ec_state *ec = dev_get_priv(dev);
+
+	ec->test_flags = flags;
+}
+
 int cros_ec_probe(struct udevice *dev)
 {
 	struct ec_state *ec = dev_get_priv(dev);
@@ -573,6 +670,7 @@ int cros_ec_probe(struct udevice *dev)
 
 struct dm_cros_ec_ops cros_ec_ops = {
 	.packet = cros_ec_sandbox_packet,
+	.get_switches = cros_ec_sandbox_get_switches,
 };
 
 static const struct udevice_id cros_ec_ids[] = {

+ 3 - 1
drivers/rtc/i2c_rtc_emul.c

@@ -57,6 +57,7 @@ long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
 	plat->use_system_time = use_system_time;
 	if (offset != -1)
 		plat->offset = offset;
+	os_set_time_offset(plat->offset);
 
 	return old_offset;
 }
@@ -80,7 +81,7 @@ static void reset_time(struct udevice *dev)
 
 	os_localtime(&now);
 	plat->base_time = rtc_mktime(&now);
-	plat->offset = 0;
+	plat->offset = os_get_time_offset();
 	plat->use_system_time = true;
 }
 
@@ -115,6 +116,7 @@ static int sandbox_i2c_rtc_set(struct udevice *dev, const struct rtc_time *time)
 		now = plat->base_time;
 	}
 	plat->offset = rtc_mktime(time) - now;
+	os_set_time_offset(plat->offset);
 
 	return 0;
 }

+ 32 - 10
drivers/tpm/cr50_i2c.c

@@ -183,23 +183,31 @@ static int cr50_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer,
 	return cr50_i2c_wait_tpm_ready(dev);
 }
 
-static inline u8 tpm_access(u8 locality)
+static inline u8 tpm_access(int locality)
 {
+	if (locality == -1)
+		locality = 0;
 	return 0x0 | (locality << 4);
 }
 
-static inline u8 tpm_sts(u8 locality)
+static inline u8 tpm_sts(int locality)
 {
+	if (locality == -1)
+		locality = 0;
 	return 0x1 | (locality << 4);
 }
 
-static inline u8 tpm_data_fifo(u8 locality)
+static inline u8 tpm_data_fifo(int locality)
 {
+	if (locality == -1)
+		locality = 0;
 	return 0x5 | (locality << 4);
 }
 
-static inline u8 tpm_did_vid(u8 locality)
+static inline u8 tpm_did_vid(int locality)
 {
+	if (locality == -1)
+		locality = 0;
 	return 0x6 | (locality << 4);
 }
 
@@ -372,7 +380,6 @@ out_err:
 static int cr50_i2c_send(struct udevice *dev, const u8 *buf, size_t len)
 {
 	struct cr50_priv *priv = dev_get_priv(dev);
-
 	int status;
 	size_t burstcnt, limit, sent = 0;
 	u8 tpm_go[4] = { TPM_STS_GO };
@@ -549,9 +556,23 @@ static int cr50_i2c_get_desc(struct udevice *dev, char *buf, int size)
 {
 	struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
 	struct cr50_priv *priv = dev_get_priv(dev);
+	int len;
+
+	len = snprintf(buf, size, "cr50 TPM 2.0 (i2c %02x id %x), ",
+		       chip->chip_addr, priv->vendor >> 16);
+	if (priv->use_irq) {
+		len += snprintf(buf + len, size - len, "irq=%s/%ld",
+				priv->irq.dev->name, priv->irq.id);
+	} else if (dm_gpio_is_valid(&priv->ready_gpio)) {
+		len += snprintf(buf + len, size - len, "gpio=%s/%u",
+				priv->ready_gpio.dev->name,
+				priv->ready_gpio.offset);
+	} else {
+		len += snprintf(buf + len, size - len, "delay=%d",
+				TIMEOUT_NO_IRQ_US);
+	}
 
-	return snprintf(buf, size, "cr50 TPM 2.0 (i2c %02x id %x) irq=%d",
-			chip->chip_addr, priv->vendor >> 16, priv->use_irq);
+	return len;
 }
 
 static int cr50_i2c_open(struct udevice *dev)
@@ -694,11 +715,12 @@ static int cr50_i2c_probe(struct udevice *dev)
 		mdelay(10);
 	}
 	if (vendor != CR50_DID_VID) {
-		log_debug("DID_VID %08x not recognised\n", vendor);
+		log_warning("DID_VID %08x not recognised\n", vendor);
 		return log_msg_ret("vendor-id", -EXDEV);
 	}
 	priv->vendor = vendor;
 	priv->locality = -1;
+	log_debug("Cr50 ready\n");
 
 	return 0;
 }
@@ -720,8 +742,8 @@ static const struct udevice_id cr50_i2c_ids[] = {
 	{ }
 };
 
-U_BOOT_DRIVER(cr50_i2c) = {
-	.name   = "cr50_i2c",
+U_BOOT_DRIVER(google_cr50) = {
+	.name   = "google_cr50",
 	.id     = UCLASS_TPM,
 	.of_match = cr50_i2c_ids,
 	.ops    = &cr50_i2c_ops,

+ 142 - 0
include/cros_ec.h

@@ -234,11 +234,61 @@ int cros_ec_flash_update_rw(struct udevice *dev, const uint8_t  *image,
 struct udevice *board_get_cros_ec_dev(void);
 
 struct dm_cros_ec_ops {
+	/**
+	 * check_version() - Check the protocol version being used (optional)
+	 *
+	 * If provided, this function should check that the EC can be supported
+	 * by the driver. If not provided, HELLO messages will be sent to try
+	 * to determine the protocol version.
+	 *
+	 * @dev: Device to check
+	 * @return 0 if the protocol is valid, -ve if not supported
+	 */
 	int (*check_version)(struct udevice *dev);
+
+	/**
+	 * command() - Old-style command interface
+	 *
+	 * This sends a command and receives a response (deprecated, use
+	 * packet())
+	 *
+	 * @dev: Device to use
+	 * @cmd: Command to send (only supports 0-0xff)
+	 * @cmd_version: Version of command to send (often 0)
+	 * @dout: Output data (may be NULL If dout_len=0)
+	 * @dout_len: Length of output data excluding 4-byte header
+	 * @dinp: On input, set to point to input data, often struct
+	 *	cros_ec_dev->din - typically this is left alone but may be
+	 *	updated by the driver
+	 * @din_len: Maximum length of response
+	 * @return number of bytes in response, or -ve on error
+	 */
 	int (*command)(struct udevice *dev, uint8_t cmd, int cmd_version,
 		       const uint8_t *dout, int dout_len,
 		       uint8_t **dinp, int din_len);
+
+	/**
+	 * packet() - New-style command interface
+	 *
+	 * This interface is preferred over command(), since it is typically
+	 * easier to implement.
+	 *
+	 * @dev: Device to use
+	 * @out_bytes: Number of bytes to send (from struct cros_ec_dev->dout)
+	 * @in_bytes: Maximum number of bytes to expect in response
+	 * @return number of bytes in response, or -ve on error
+	 */
 	int (*packet)(struct udevice *dev, int out_bytes, int in_bytes);
+
+	/**
+	 * get_switches() - Get value of EC switches
+	 *
+	 * This is currently supported on the LPC EC.
+	 *
+	 * @dev: Device to use
+	 * @return current switches value, or -ENOSYS if not supported
+	 */
+	int (*get_switches)(struct udevice *dev);
 };
 
 #define dm_cros_ec_get_ops(dev) \
@@ -329,6 +379,14 @@ int cros_ec_flash_write(struct udevice *dev, const uint8_t *data,
 int cros_ec_flash_offset(struct udevice *dev, enum ec_flash_region region,
 			 uint32_t *offset, uint32_t *size);
 
+/**
+ * cros_ec_get_sku_id() - Read the SKU ID
+ *
+ * @dev: CROS-EC device
+ * return SKU ID, or -ve on error
+ */
+int cros_ec_get_sku_id(struct udevice *dev);
+
 /**
  * Read/write non-volatile data from/to a CROS-EC device.
  *
@@ -497,4 +555,88 @@ int cros_ec_get_lid_shutdown_mask(struct udevice *dev);
  */
 int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable);
 
+/**
+ * cros_ec_hello() - Send a hello message
+ *
+ * Sends a message with a fixed input value and checks that the expected output
+ * value is received
+ *
+ * @dev: CROS-EC device
+ * @handshakep: If non-NULL, returns received handshake value on error
+ * @return 0 if OK, -ve on error
+ */
+int cros_ec_hello(struct udevice *dev, uint *handshakep);
+
+/**
+ * cros_ec_get_features() - Get the set of features provided by the EC
+ *
+ * See enum ec_feature_code for the list of available features
+ *
+ * @dev: CROS-EC device
+ * @featuresp: Returns a bitmask of supported features
+ * @return 0 if OK, -ve on error
+ */
+int cros_ec_get_features(struct udevice *dev, u64 *featuresp);
+
+/**
+ * cros_ec_check_feature() - Check if a feature is supported
+ *
+ * @dev: CROS-EC device
+ * @feature: Feature number to check (enum ec_feature_code)
+ * @return true if supported, false if not, -ve on error
+ */
+int cros_ec_check_feature(struct udevice *dev, uint feature);
+
+/**
+ * cros_ec_get_switches() - Get switches value
+ *
+ * @dev: CROS-EC device
+ * @return switches value, or -ENOSYS if not supported, or other -ve value on
+ *	other error
+ */
+int cros_ec_get_switches(struct udevice *dev);
+
+/**
+ * cros_ec_vstore_supported() - Check if vstore is supported
+ *
+ * @dev: CROS-EC device
+ * @return false if not supported, true if supported, -ve on error
+ */
+int cros_ec_vstore_supported(struct udevice *dev);
+
+/**
+ * cros_ec_vstore_info() - Get vstore information
+ *
+ * @dev: CROS-EC device
+ * @lockedp: mask of locked slots
+ * @return number of vstore slots supported by the EC,, -ve on error
+ */
+int cros_ec_vstore_info(struct udevice *dev, u32 *lockedp);
+
+/**
+ * cros_ec_vstore_read() - Read data from EC vstore slot
+ *
+ * @dev: CROS-EC device
+ * @slot: vstore slot to read from
+ * @data: buffer to store read data, must be EC_VSTORE_SLOT_SIZE bytes
+ * @return 0 if OK, -ve on error
+ */
+int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data);
+
+/**
+ * cros_ec_vstore_write() - Save data into EC vstore slot
+ *
+ * The maximum size of data is EC_VSTORE_SLOT_SIZE.  It is the caller's
+ * responsibility to check the number of implemented slots by querying the
+ * vstore info.
+ *
+ * @dev: CROS-EC device
+ * @slot: vstore slot to write into
+ * @data: data to write
+ * @size: size of data in bytes
+ * @return 0 if OK, -ve on error
+ */
+int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data,
+			 size_t size);
+
 #endif

+ 1 - 0
include/ctype.h

@@ -0,0 +1 @@
+linux/ctype.h

+ 1 - 1
include/dm/device.h

@@ -111,7 +111,7 @@ enum {
  * probe method if the device has a device tree node.
  *
  * All three of plat, priv and uclass_priv can be allocated by the
- * driver, or you can use the auto_alloc_size members of struct driver and
+ * driver, or you can use the auto members of struct driver and
  * struct uclass_driver to have driver model do this automatically.
  *
  * @driver: The driver used by this device

+ 2 - 3
include/dm/read.h

@@ -30,8 +30,7 @@ static inline const struct device_node *dev_np(const struct udevice *dev)
 }
 #endif
 
-#ifndef CONFIG_DM_DEV_READ_INLINE
-
+#if !defined(CONFIG_DM_DEV_READ_INLINE) || CONFIG_IS_ENABLED(OF_PLATDATA)
 /**
  * dev_read_u32() - read a 32-bit integer from a device's DT property
  *
@@ -1007,7 +1006,7 @@ static inline u64 dev_translate_dma_address(const struct udevice *dev,
 
 static inline int dev_read_alias_highest_id(const char *stem)
 {
-	if (!CONFIG_IS_ENABLED(OF_LIBFDT))
+	if (!CONFIG_IS_ENABLED(OF_LIBFDT) || !gd->fdt_blob)
 		return -1;
 	return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
 }

+ 41 - 4
include/ec_commands.h

@@ -1101,13 +1101,50 @@ enum ec_feature_code {
 	EC_FEATURE_DEVICE_EVENT = 31,
 	/* EC supports the unified wake masks for LPC/eSPI systems */
 	EC_FEATURE_UNIFIED_WAKE_MASKS = 32,
+	/* EC supports 64-bit host events */
+	EC_FEATURE_HOST_EVENT64 = 33,
+	/* EC runs code in RAM (not in place, a.k.a. XIP) */
+	EC_FEATURE_EXEC_IN_RAM = 34,
+	/* EC supports CEC commands */
+	EC_FEATURE_CEC = 35,
+	/* EC supports tight sensor timestamping. */
+	EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36,
+	/*
+	 * EC supports tablet mode detection aligned to Chrome and allows
+	 * setting of threshold by host command using
+	 * MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE.
+	 */
+	EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37,
+	/*
+	 * Early Firmware Selection ver.2. Enabled by CONFIG_VBOOT_EFS2.
+	 * Note this is a RO feature. So, a query (EC_CMD_GET_FEATURES) should
+	 * be sent to RO to be precise.
+	 */
+	EC_FEATURE_EFS2 = 38,
+	/* The MCU is a System Companion Processor (SCP). */
+	EC_FEATURE_SCP = 39,
+	/* The MCU is an Integrated Sensor Hub */
+	EC_FEATURE_ISH = 40,
+	/* New TCPMv2 TYPEC_ prefaced commands supported */
+	EC_FEATURE_TYPEC_CMD = 41,
+	/*
+	 * The EC will wait for direction from the AP to enter Type-C alternate
+	 * modes or USB4.
+	 */
+	EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY = 42,
+	/*
+	 * The EC will wait for an acknowledge from the AP after setting the
+	 * mux.
+	 */
+	EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK = 43,
 };
 
-#define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32))
-#define EC_FEATURE_MASK_1(event_code) (1UL << (event_code - 32))
-struct __ec_align4 ec_response_get_features {
+#define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32)
+#define EC_FEATURE_MASK_1(event_code) BIT(event_code - 32)
+
+struct ec_response_get_features {
 	uint32_t flags[2];
-};
+} __ec_align4;
 
 /*****************************************************************************/
 /* Get the board's SKU ID from EC */

+ 18 - 0
include/os.h

@@ -424,4 +424,22 @@ int os_setup_signal_handlers(void);
  */
 void os_signal_action(int sig, unsigned long pc);
 
+/**
+ * os_get_time_offset() - get time offset
+ *
+ * Get the time offset from environment variable UBOOT_SB_TIME_OFFSET.
+ *
+ * Return:	offset in seconds
+ */
+long os_get_time_offset(void);
+
+/**
+ * os_set_time_offset() - set time offset
+ *
+ * Save the time offset in environment variable UBOOT_SB_TIME_OFFSET.
+ *
+ * @offset:	offset in seconds
+ */
+void os_set_time_offset(long offset);
+
 #endif

+ 2 - 0
lib/binman.c

@@ -145,6 +145,8 @@ int binman_init(void)
 	if (ret)
 		return log_msg_ret("node", -ENOENT);
 	binman_set_rom_offset(ROM_OFFSET_NONE);
+	log_debug("binman: Selected image node '%s'\n",
+		  ofnode_get_name(binman->image));
 
 	return 0;
 }

+ 2 - 0
test/dm/Makefile

@@ -24,6 +24,7 @@ obj-$(CONFIG_BLK) += blk.o
 obj-$(CONFIG_BUTTON) += button.o
 obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o
 obj-$(CONFIG_CLK) += clk.o clk_ccf.o
+obj-$(CONFIG_CROS_EC) += cros_ec.o
 obj-$(CONFIG_DEVRES) += devres.o
 obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o
 obj-$(CONFIG_DM_ETH) += eth.o
@@ -41,6 +42,7 @@ obj-y += fdtdec.o
 obj-$(CONFIG_UT_DM) += nop.o
 obj-y += ofnode.o
 obj-y += ofread.o
+obj-y += of_extra.o
 obj-$(CONFIG_OSD) += osd.o
 obj-$(CONFIG_DM_VIDEO) += panel.o
 obj-$(CONFIG_DM_PCI) += pci.o

+ 178 - 0
test/dm/cros_ec.c

@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2021 Google LLC
+ */
+
+#include <common.h>
+#include <cros_ec.h>
+#include <dm.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+static int dm_test_cros_ec_hello(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	uint val;
+
+	ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
+
+	ut_assertok(cros_ec_hello(dev, NULL));
+
+	val = 0xdead1357;
+	ut_assertok(cros_ec_hello(dev, &val));
+	ut_asserteq(0xdead1357, val);
+
+	sandbox_cros_ec_set_test_flags(dev, CROSECT_BREAK_HELLO);
+	ut_asserteq(-ENOTSYNC, cros_ec_hello(dev, &val));
+	ut_asserteq(0x12345678, val);
+
+	return 0;
+}
+DM_TEST(dm_test_cros_ec_hello, UT_TESTF_SCAN_FDT);
+
+static int dm_test_cros_ec_sku_id(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
+	ut_asserteq(1234, cros_ec_get_sku_id(dev));
+
+	/* try the command */
+	console_record_reset();
+	ut_assertok(run_command("crosec sku", 0));
+	ut_assert_nextline("1234");
+	ut_assert_console_end();
+
+	return 0;
+}
+DM_TEST(dm_test_cros_ec_sku_id, UT_TESTF_SCAN_FDT);
+
+static int dm_test_cros_ec_features(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	u64 feat;
+
+	ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
+	ut_assertok(cros_ec_get_features(dev, &feat));
+	ut_asserteq_64(1U << EC_FEATURE_FLASH | 1U << EC_FEATURE_I2C |
+		1u << EC_FEATURE_VSTORE |
+		1ULL << EC_FEATURE_UNIFIED_WAKE_MASKS | 1ULL << EC_FEATURE_ISH,
+		feat);
+
+	ut_asserteq(true, cros_ec_check_feature(dev, EC_FEATURE_I2C));
+	ut_asserteq(false, cros_ec_check_feature(dev, EC_FEATURE_MOTION_SENSE));
+	ut_asserteq(true, cros_ec_check_feature(dev, EC_FEATURE_ISH));
+
+	/* try the command */
+	console_record_reset();
+	ut_assertok(run_command("crosec features", 0));
+	ut_assert_nextline("flash");
+	ut_assert_nextline("i2c");
+	ut_assert_nextline("vstore");
+	ut_assert_nextline("unified_wake_masks");
+	ut_assert_nextline("ish");
+	ut_assert_console_end();
+
+	return 0;
+}
+DM_TEST(dm_test_cros_ec_features, UT_TESTF_SCAN_FDT);
+
+static int dm_test_cros_ec_switches(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
+	ut_asserteq(0, cros_ec_get_switches(dev));
+
+	/* try the command */
+	console_record_reset();
+	ut_assertok(run_command("crosec switches", 0));
+	ut_assert_console_end();
+
+	/* Open the lid and check the switch changes */
+	sandbox_cros_ec_set_test_flags(dev, CROSECT_LID_OPEN);
+	ut_asserteq(EC_SWITCH_LID_OPEN, cros_ec_get_switches(dev));
+
+	/* try the command */
+	console_record_reset();
+	ut_assertok(run_command("crosec switches", 0));
+	ut_assert_nextline("lid open");
+	ut_assert_console_end();
+
+	return 0;
+}
+DM_TEST(dm_test_cros_ec_switches, UT_TESTF_SCAN_FDT);
+
+static int dm_test_cros_ec_events(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	u32 events;
+
+	ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
+	ut_assertok(cros_ec_get_host_events(dev, &events));
+	ut_asserteq(0, events);
+
+	/* try the command */
+	console_record_reset();
+	ut_assertok(run_command("crosec events", 0));
+	ut_assert_nextline("00000000");
+	ut_assert_console_end();
+
+	/* Open the lid and check the event appears */
+	sandbox_cros_ec_set_test_flags(dev, CROSECT_LID_OPEN);
+	ut_assertok(cros_ec_get_host_events(dev, &events));
+	ut_asserteq(EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN), events);
+
+	/* try the command */
+	console_record_reset();
+	ut_assertok(run_command("crosec events", 0));
+	ut_assert_nextline("00000002");
+	ut_assert_nextline("lid_open");
+	ut_assert_console_end();
+
+	/* Clear the event */
+	ut_assertok(cros_ec_clear_host_events(dev,
+		EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN)));
+	ut_assertok(cros_ec_get_host_events(dev, &events));
+	ut_asserteq(0, events);
+
+	return 0;
+}
+DM_TEST(dm_test_cros_ec_events, UT_TESTF_SCAN_FDT);
+
+static int dm_test_cros_ec_vstore(struct unit_test_state *uts)
+{
+	const int size = EC_VSTORE_SLOT_SIZE;
+	u8 test_data[size], data[size];
+	struct udevice *dev;
+	u32 locked;
+	int i;
+
+	ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev));
+	ut_asserteq(true, cros_ec_vstore_supported(dev));
+
+	ut_asserteq(4, cros_ec_vstore_info(dev, &locked));
+	ut_asserteq(0, locked);
+
+	/* Write some data */
+	for (i = 0; i < size; i++)
+		test_data[i] = ' ' + i;
+	ut_assertok(cros_ec_vstore_write(dev, 2, test_data, size));
+
+	/* Check it is locked */
+	ut_asserteq(4, cros_ec_vstore_info(dev, &locked));
+	ut_asserteq(1 << 2, locked);
+
+	/* Read it back and compare */
+	ut_assertok(cros_ec_vstore_read(dev, 2, data));
+	ut_asserteq_mem(test_data, data, size);
+
+	/* Try another slot to make sure it is empty */
+	ut_assertok(cros_ec_vstore_read(dev, 0, data));
+	for (i = 0; i < size; i++)
+		ut_asserteq(0, data[i]);
+
+	return 0;
+}
+DM_TEST(dm_test_cros_ec_vstore, UT_TESTF_SCAN_FDT);

+ 38 - 0
test/dm/of_extra.c

@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/of_extra.h>
+#include <dm/test.h>
+#include <test/ut.h>
+#include <u-boot/sha256.h>
+
+static int dm_test_ofnode_read_fmap_entry(struct unit_test_state *uts)
+{
+	const char hash_expect[] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+		0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+		0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+	};
+	struct fmap_entry entry;
+	ofnode node;
+
+	node = ofnode_path("/cros-ec/flash/wp-ro");
+	ut_assertok(ofnode_read_fmap_entry(node, &entry));
+	ut_asserteq(0xf000, entry.offset);
+	ut_asserteq(0x1000, entry.length);
+	ut_asserteq(0x884, entry.used);
+	ut_asserteq(FMAP_COMPRESS_LZ4, entry.compress_algo);
+	ut_asserteq(0xcf8, entry.unc_length);
+	ut_asserteq(FMAP_HASH_SHA256, entry.hash_algo);
+	ut_asserteq(SHA256_SUM_LEN, entry.hash_size);
+	ut_asserteq_mem(hash_expect, entry.hash, SHA256_SUM_LEN);
+
+	return 0;
+}
+DM_TEST(dm_test_ofnode_read_fmap_entry, 0);

+ 4 - 4
test/dm/of_platdata.c

@@ -210,11 +210,11 @@ DM_TEST(dm_test_of_plat_phandle, UT_TESTF_SCAN_PDATA);
 /* Test that device parents are correctly set up */
 static int dm_test_of_plat_parent(struct unit_test_state *uts)
 {
-	struct udevice *rtc, *i2c;
+	struct udevice *dev, *bus;
 
-	ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc));
-	ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c));
-	ut_asserteq_ptr(i2c, dev_get_parent(rtc));
+	ut_assertok(uclass_first_device_err(UCLASS_SIMPLE_BUS, &bus));
+	ut_assertok(device_first_child_err(bus, &dev));
+	ut_asserteq_ptr(bus, dev_get_parent(dev));
 
 	return 0;
 }

+ 1 - 2
tools/binman/README

@@ -1050,10 +1050,9 @@ Some ideas:
 - Allow easy building of images by specifying just the board name
 - Support building an image for a board (-b) more completely, with a
   configurable build directory
-- Support adding FITs to an image
-- Support for ARM Trusted Firmware (ATF)
 - Detect invalid properties in nodes
 - Sort the fdtmap by offset
+- Output temporary files to a different directory
 
 --
 Simon Glass <sjg@chromium.org>

+ 2 - 1
tools/binman/control.py

@@ -244,7 +244,8 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
             if not os.path.exists(fname):
                 os.makedirs(fname)
             fname = os.path.join(fname, 'root')
-        tout.Notice("Write entry '%s' to '%s'" % (entry.GetPath(), fname))
+        tout.Notice("Write entry '%s' size %x to '%s'" %
+                    (entry.GetPath(), len(data), fname))
         tools.WriteFile(fname, data)
     return einfos
 

+ 2 - 1
tools/binman/elf.py

@@ -132,7 +132,8 @@ def LookupAndWriteSymbols(elf_fname, entry, section):
                                  (msg, sym.size))
 
             # Look up the symbol in our entry tables.
-            value = section.LookupSymbol(name, sym.weak, msg, base.address)
+            value = section.GetImage().LookupImageSymbol(name, sym.weak, msg,
+                                                         base.address)
             if value is None:
                 value = -1
                 pack_string = pack_string.lower()

+ 3 - 1
tools/binman/elf_test.py

@@ -45,10 +45,12 @@ class FakeSection:
     def GetPath(self):
         return 'section_path'
 
-    def LookupSymbol(self, name, weak, msg, base_addr):
+    def LookupImageSymbol(self, name, weak, msg, base_addr):
         """Fake implementation which returns the same value for all symbols"""
         return self.sym_value
 
+    def GetImage(self):
+        return self
 
 def BuildElfTestFiles(target_dir):
     """Build ELF files used for testing in binman

+ 1 - 2
tools/binman/entry.py

@@ -434,8 +434,7 @@ class Entry(object):
                 missing.append(prop.name)
             values.append(value)
         if missing:
-            self.Raise('Missing required properties/entry args: %s' %
-                       (', '.join(missing)))
+            self.GetImage().MissingArgs(self, missing)
         return values
 
     def GetPath(self):

+ 4 - 0
tools/binman/etype/blob.py

@@ -66,3 +66,7 @@ class Entry_blob(Entry):
 
     def GetDefaultFilename(self):
         return self._filename
+
+    def ProcessContents(self):
+        # The blob may have changed due to WriteSymbols()
+        return self.ProcessContentsUpdate(self.data)

+ 4 - 0
tools/binman/etype/files.py

@@ -22,6 +22,7 @@ class Entry_files(Entry_section):
         - files-compress: Compression algorithm to use:
             none: No compression
             lz4: Use lz4 compression (via 'lz4' command-line utility)
+        - files-align: Align each file to the given alignment
 
     This entry reads a number of files and places each in a separate sub-entry
     within this entry. To access these you need to enable device-tree updates
@@ -38,6 +39,7 @@ class Entry_files(Entry_section):
             self.Raise("Missing 'pattern' property")
         self._files_compress = fdt_util.GetString(self._node, 'files-compress',
                                                   'none')
+        self._files_align = fdt_util.GetInt(self._node, 'files-align');
         self._require_matches = fdt_util.GetBool(self._node,
                                                 'require-matches')
 
@@ -55,6 +57,8 @@ class Entry_files(Entry_section):
             state.AddString(subnode, 'type', 'blob')
             state.AddString(subnode, 'filename', fname)
             state.AddString(subnode, 'compress', self._files_compress)
+            if self._files_align:
+                state.AddInt(subnode, 'align', self._files_align)
 
         # Read entries again, now that we have some
         self._ReadEntries()

+ 57 - 9
tools/binman/etype/section.py

@@ -385,7 +385,7 @@ class Entry_section(Entry):
                 return entry.GetData()
         source_entry.Raise("Cannot find entry for node '%s'" % node.name)
 
-    def LookupSymbol(self, sym_name, optional, msg, base_addr):
+    def LookupSymbol(self, sym_name, optional, msg, base_addr, entries=None):
         """Look up a symbol in an ELF file
 
         Looks up a symbol in an ELF file. Only entry types which come from an
@@ -428,18 +428,20 @@ class Entry_section(Entry):
                              (msg, sym_name))
         entry_name, prop_name = m.groups()
         entry_name = entry_name.replace('_', '-')
-        entry = self._entries.get(entry_name)
+        if not entries:
+            entries = self._entries
+        entry = entries.get(entry_name)
         if not entry:
             if entry_name.endswith('-any'):
                 root = entry_name[:-4]
-                for name in self._entries:
+                for name in entries:
                     if name.startswith(root):
                         rest = name[len(root):]
                         if rest in ['', '-img', '-nodtb']:
-                            entry = self._entries[name]
+                            entry = entries[name]
         if not entry:
             err = ("%s: Entry '%s' not found in list (%s)" %
-                   (msg, entry_name, ','.join(self._entries.keys())))
+                   (msg, entry_name, ','.join(entries.keys())))
             if optional:
                 print('Warning: %s' % err, file=sys.stderr)
                 return None
@@ -603,10 +605,12 @@ class Entry_section(Entry):
     def ReadData(self, decomp=True):
         tout.Info("ReadData path='%s'" % self.GetPath())
         parent_data = self.section.ReadData(True)
-        tout.Info('%s: Reading data from offset %#x-%#x, size %#x' %
-                  (self.GetPath(), self.offset, self.offset + self.size,
-                   self.size))
-        data = parent_data[self.offset:self.offset + self.size]
+        offset = self.offset - self.section._skip_at_start
+        data = parent_data[offset:offset + self.size]
+        tout.Info(
+            '%s: Reading data from offset %#x-%#x (real %#x), size %#x, got %#x' %
+                  (self.GetPath(), self.offset, self.offset + self.size, offset,
+                   self.size, len(data)))
         return data
 
     def ReadChildData(self, child, decomp=True):
@@ -648,3 +652,47 @@ class Entry_section(Entry):
         """
         for entry in self._entries.values():
             entry.CheckMissing(missing_list)
+
+    def _CollectEntries(self, entries, entries_by_name, add_entry):
+        """Collect all the entries in an section
+
+        This builds up a dict of entries in this section and all subsections.
+        Entries are indexed by path and by name.
+
+        Since all paths are unique, entries will not have any conflicts. However
+        entries_by_name make have conflicts if two entries have the same name
+        (e.g. with different parent sections). In this case, an entry at a
+        higher level in the hierarchy will win over a lower-level entry.
+
+        Args:
+            entries: dict to put entries:
+                key: entry path
+                value: Entry object
+            entries_by_name: dict to put entries
+                key: entry name
+                value: Entry object
+            add_entry: Entry to add
+        """
+        entries[add_entry.GetPath()] = add_entry
+        to_add = add_entry.GetEntries()
+        if to_add:
+            for entry in to_add.values():
+                entries[entry.GetPath()] = entry
+            for entry in to_add.values():
+                self._CollectEntries(entries, entries_by_name, entry)
+        entries_by_name[add_entry.name] = add_entry
+
+    def MissingArgs(self, entry, missing):
+        """Report a missing argument, if enabled
+
+        For entries which require arguments, this reports an error if some are
+        missing. If missing entries are being ignored (e.g. because we read the
+        entry from an image rather than creating it), this function does
+        nothing.
+
+        Args:
+            missing: List of missing properties / entry args, each a string
+        """
+        if not self._ignore_missing:
+            entry.Raise('Missing required properties/entry args: %s' %
+                       (', '.join(missing)))

+ 0 - 1
tools/binman/etype/u_boot_spl_bss_pad.py

@@ -9,7 +9,6 @@
 
 from binman import elf
 from binman.entry import Entry
-from patman import command
 from binman.etype.blob import Entry_blob
 from patman import tools
 

+ 1 - 1
tools/binman/etype/u_boot_spl_nodtb.py

@@ -2,7 +2,7 @@
 # Copyright (c) 2016 Google, Inc
 # Written by Simon Glass <sjg@chromium.org>
 #
-# Entry-type module for 'u-boot-nodtb.bin'
+# Entry-type module for 'u-boot-spl-nodtb.bin'
 #
 
 from binman.entry import Entry

+ 13 - 2
tools/binman/etype/vblock.py

@@ -49,7 +49,7 @@ class Entry_vblock(Entry):
             EntryArg('kernelkey', str),
             EntryArg('preamble-flags', int)])
 
-    def ObtainContents(self):
+    def GetVblock(self):
         # Join up the data files to be signed
         input_data = b''
         for entry_phandle in self.content:
@@ -76,5 +76,16 @@ class Entry_vblock(Entry):
         ]
         #out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
         stdout = tools.Run('futility', *args)
-        self.SetContents(tools.ReadFile(output_fname))
+        return tools.ReadFile(output_fname)
+
+    def ObtainContents(self):
+        data = self.GetVblock()
+        if data is False:
+            return False
+        self.SetContents(data)
         return True
+
+    def ProcessContents(self):
+        # The blob may have changed due to WriteSymbols()
+        data = self.GetVblock()
+        return self.ProcessContentsUpdate(data)

+ 2 - 2
tools/binman/fmap_util.py

@@ -53,8 +53,8 @@ FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES)
 
 
 def NameToFmap(name):
-    if type(name) == bytes and sys.version_info[0] >= 3:
-        name = name.decode('utf-8')  # pragma: no cover (for Python 2)
+    if type(name) == bytes:
+        name = name.decode('utf-8')
     return name.replace('\0', '').replace('-', '_').upper()
 
 def ConvertName(field_names, fields):

+ 108 - 2
tools/binman/ftest.py

@@ -1638,15 +1638,37 @@ class TestFunctional(unittest.TestCase):
                       str(e.exception))
 
     def _HandleVblockCommand(self, pipe_list):
-        """Fake calls to the futility utility"""
+        """Fake calls to the futility utility
+
+        The expected pipe is:
+
+           [('futility', 'vbutil_firmware', '--vblock',
+             'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
+             '--signprivate', 'devkeys/firmware_data_key.vbprivk',
+             '--version', '1', '--fv', 'input.vblock', '--kernelkey',
+             'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
+
+        This writes to the output file (here, 'vblock.vblock'). If
+        self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
+        of the input data (here, 'input.vblock').
+        """
         if pipe_list[0][0] == 'futility':
             fname = pipe_list[0][3]
             with open(fname, 'wb') as fd:
-                fd.write(VBLOCK_DATA)
+                if self._hash_data:
+                    infile = pipe_list[0][11]
+                    m = hashlib.sha256()
+                    data = tools.ReadFile(infile)
+                    m.update(data)
+                    fd.write(m.digest())
+                else:
+                    fd.write(VBLOCK_DATA)
+
             return command.CommandResult()
 
     def testVblock(self):
         """Test for the Chromium OS Verified Boot Block"""
+        self._hash_data = False
         command.test_result = self._HandleVblockCommand
         entry_args = {
             'keydir': 'devkeys',
@@ -1677,6 +1699,29 @@ class TestFunctional(unittest.TestCase):
         self.assertIn("Node '/binman/vblock': Cannot find entry for node "
                       "'other'", str(e.exception))
 
+    def testVblockContent(self):
+        """Test that the vblock signs the right data"""
+        self._hash_data = True
+        command.test_result = self._HandleVblockCommand
+        entry_args = {
+            'keydir': 'devkeys',
+        }
+        data = self._DoReadFileDtb(
+            '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
+            entry_args=entry_args)[0]
+        hashlen = 32  # SHA256 hash is 32 bytes
+        self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
+        hashval = data[-hashlen:]
+        dtb = data[len(U_BOOT_DATA):-hashlen]
+
+        expected_data = U_BOOT_DATA + dtb
+
+        # The hashval should be a hash of the dtb
+        m = hashlib.sha256()
+        m.update(expected_data)
+        expected_hashval = m.digest()
+        self.assertEqual(expected_hashval, hashval)
+
     def testTpl(self):
         """Test that an image with TPL and its device tree can be created"""
         # ELF file with a '__bss_size' symbol
@@ -4139,6 +4184,67 @@ class TestFunctional(unittest.TestCase):
             }
         self.assertEqual(expected, props)
 
+    def testSymbolsSubsection(self):
+        """Test binman can assign symbols from a subsection"""
+        elf_fname = self.ElfTestFile('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_offset'].address, addr)
+
+        self._SetupSplElf('u_boot_binman_syms')
+        data = self._DoReadFile('187_symbols_sub.dts')
+        sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
+        expected = (sym_values + U_BOOT_SPL_DATA[20:] +
+                    tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
+                    U_BOOT_SPL_DATA[20:])
+        self.assertEqual(expected, data)
+
+    def testReadImageEntryArg(self):
+        """Test reading an image that would need an entry arg to generate"""
+        entry_args = {
+            'cros-ec-rw-path': 'ecrw.bin',
+        }
+        data = self.data = self._DoReadFileDtb(
+            '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
+            entry_args=entry_args)
+
+        image_fname = tools.GetOutputFilename('image.bin')
+        orig_image = control.images['image']
+
+        # This should not generate an error about the missing 'cros-ec-rw-path'
+        # since we are reading the image from a file. Compare with
+        # testEntryArgsRequired()
+        image = Image.FromFile(image_fname)
+        self.assertEqual(orig_image.GetEntries().keys(),
+                         image.GetEntries().keys())
+
+    def testFilesAlign(self):
+        """Test alignment with files"""
+        data = self._DoReadFile('190_files_align.dts')
+
+        # The first string is 15 bytes so will align to 16
+        expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
+        self.assertEqual(expect, data)
+
+    def testReadImageSkip(self):
+        """Test reading an image and accessing its FDT map"""
+        data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        orig_image = control.images['image']
+        image = Image.FromFile(image_fname)
+        self.assertEqual(orig_image.GetEntries().keys(),
+                         image.GetEntries().keys())
+
+        orig_entry = orig_image.GetEntries()['fdtmap']
+        entry = image.GetEntries()['fdtmap']
+        self.assertEqual(orig_entry.offset, entry.offset)
+        self.assertEqual(orig_entry.size, entry.size)
+        self.assertEqual(16, entry.image_pos)
+
+        u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
+
+        self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
+
 
 if __name__ == "__main__":
     unittest.main()

+ 54 - 8
tools/binman/image.py

@@ -43,8 +43,13 @@ class Image(section.Entry_section):
         test: True if this is being called from a test of Images. This this case
             there is no device tree defining the structure of the section, so
             we create a section manually.
+        ignore_missing: Ignore any missing entry arguments (i.e. don't raise an
+            exception). This should be used if the Image is being loaded from
+            a file rather than generated. In that case we obviously don't need
+            the entry arguments since the contents already exists.
     """
-    def __init__(self, name, node, copy_to_orig=True, test=False):
+    def __init__(self, name, node, copy_to_orig=True, test=False,
+                 ignore_missing=False):
         super().__init__(None, 'section', node, test=test)
         self.copy_to_orig = copy_to_orig
         self.name = 'main-section'
@@ -53,6 +58,7 @@ class Image(section.Entry_section):
         self.fdtmap_dtb = None
         self.fdtmap_data = None
         self.allow_repack = False
+        self._ignore_missing = ignore_missing
         if not test:
             self.ReadNode()
 
@@ -100,7 +106,7 @@ class Image(section.Entry_section):
 
         # Return an Image with the associated nodes
         root = dtb.GetRoot()
-        image = Image('image', root, copy_to_orig=False)
+        image = Image('image', root, copy_to_orig=False, ignore_missing=True)
 
         image.image_node = fdt_util.GetString(root, 'image-node', 'image')
         image.fdtmap_dtb = dtb
@@ -130,12 +136,7 @@ class Image(section.Entry_section):
         Returns:
             True if the new data size is OK, False if expansion is needed
         """
-        sizes_ok = True
-        for entry in self._entries.values():
-            if not entry.ProcessContents():
-                sizes_ok = False
-                tout.Debug("Entry '%s' size change" % self._node.path)
-        return sizes_ok
+        return super().ProcessContents()
 
     def WriteSymbols(self):
         """Write symbol values into binary files for access at run time"""
@@ -324,3 +325,48 @@ class Image(section.Entry_section):
             _DoLine(lines, _EntryToStrings(entry))
             selected_entries.append(entry)
         return selected_entries, lines, widths
+
+    def LookupImageSymbol(self, sym_name, optional, msg, base_addr):
+        """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.
+
+        This searches through this image including all of its subsections.
+
+        At present the only entry properties supported are:
+            offset
+            image_pos - 'base_addr' is added if this is not an end-at-4gb image
+            size
+
+        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_offset). 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_offset 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
+            base_addr: Base address of image. This is added to the returned
+                image_pos in most cases so that the returned position indicates
+                where the targeted entry/binary has actually been loaded. But
+                if end-at-4gb is used, this is not done, since the binary is
+                already assumed to be linked to the ROM position and using
+                execute-in-place (XIP).
+
+        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
+        """
+        entries = OrderedDict()
+        entries_by_name = {}
+        self._CollectEntries(entries, entries_by_name, self)
+        return self.LookupSymbol(sym_name, optional, msg, base_addr,
+                                 entries_by_name)

+ 10 - 0
tools/binman/state.py

@@ -314,6 +314,16 @@ def AddString(node, prop, value):
     for n in GetUpdateNodes(node):
         n.AddString(prop, value)
 
+def AddInt(node, prop, value):
+    """Add a new string property to affected device trees
+
+    Args:
+        prop_name: Name of property
+        val: Integer value of property
+    """
+    for n in GetUpdateNodes(node):
+        n.AddInt(prop, value)
+
 def SetInt(node, prop, value, for_repack=False):
     """Update an integer property in affected device trees with an integer value
 

+ 1 - 1
tools/binman/test/084_files.dts

@@ -5,7 +5,7 @@
 	binman {
 		files {
 			pattern = "files/*.dat";
-			compress = "none";
+			files-compress = "none";
 		};
 	};
 };

+ 22 - 0
tools/binman/test/187_symbols_sub.dts

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

+ 21 - 0
tools/binman/test/188_image_entryarg.dts

@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		size = <0xc00>;
+		u-boot {
+		};
+		cros-ec-rw {
+		};
+		fdtmap {
+		};
+		image-header {
+			location = "end";
+		};
+	};
+};

+ 31 - 0
tools/binman/test/189_vblock_content.dts

@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u_boot: u-boot {
+		};
+
+		dtb: u-boot-dtb {
+		};
+
+		/*
+		 * Put the vblock after the dtb so that the dtb is updated
+		 * before the vblock reads its data. At present binman does not
+		 * understand dependencies between entries, but simply
+		 * iterates again when it thinks something needs to be
+		 * recalculated.
+		 */
+		vblock {
+			content = <&u_boot &dtb>;
+			keyblock = "firmware.keyblock";
+			signprivate = "firmware_data_key.vbprivk";
+			version = <1>;
+			kernelkey = "kernel_subkey.vbpubk";
+			preamble-flags = <1>;
+		};
+	};
+};

+ 12 - 0
tools/binman/test/190_files_align.dts

@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+	binman {
+		files {
+			pattern = "files/*.dat";
+			files-compress = "none";
+			files-align = <4>;
+		};
+	};
+};

+ 23 - 0
tools/binman/test/191_read_image_skip.dts

@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		end-at-4gb;
+		size = <0x400>;
+		section {
+			size = <0x10>;
+			u-boot {
+			};
+		};
+		fdtmap {
+		};
+		image-header {
+			location = "end";
+		};
+	};
+};

+ 13 - 2
tools/dtoc/fdt.py

@@ -460,10 +460,21 @@ class Node:
             prop_name: Name of property to add
             val: String value of property
         """
-        if sys.version_info[0] >= 3:  # pragma: no cover
-            val = bytes(val, 'utf-8')
+        val = bytes(val, 'utf-8')
         self.AddData(prop_name, val + b'\0')
 
+    def AddInt(self, prop_name, val):
+        """Add a new integer property to a node
+
+        The device tree is marked dirty so that the value will be written to
+        the blob on the next sync.
+
+        Args:
+            prop_name: Name of property to add
+            val: Integer value of property
+        """
+        self.AddData(prop_name, struct.pack('>I', val))
+
     def AddSubnode(self, name):
         """Add a new subnode to the node
 

+ 6 - 0
tools/dtoc/test_fdt.py

@@ -397,6 +397,12 @@ class TestProp(unittest.TestCase):
         data = self.fdt.getprop(self.node.Offset(), 'one')
         self.assertEqual(1, fdt32_to_cpu(data))
 
+        val = 1234
+        self.node.AddInt('integer', val)
+        self.dtb.Sync(auto_resize=True)
+        data = self.fdt.getprop(self.node.Offset(), 'integer')
+        self.assertEqual(val, fdt32_to_cpu(data))
+
         val = '123' + chr(0) + '456'
         self.node.AddString('string', val)
         self.dtb.Sync(auto_resize=True)

+ 2 - 1
tools/patman/tools.py

@@ -476,7 +476,8 @@ def Compress(indata, algo, with_header=True):
     fname = GetOutputFilename('%s.comp.tmp' % algo)
     WriteFile(fname, indata)
     if algo == 'lz4':
-        data = Run('lz4', '--no-frame-crc', '-c', fname, binary=True)
+        data = Run('lz4', '--no-frame-crc', '-B4', '-5', '-c', fname,
+                   binary=True)
     # cbfstool uses a very old version of lzma
     elif algo == 'lzma':
         outfname = GetOutputFilename('%s.comp.otmp' % algo)