diff --git a/Kconfig b/Kconfig index 6dc20ed25b..86f0a39bb0 100644 --- a/Kconfig +++ b/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. diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 80996a91ce..3d8af0a52b 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -32,6 +32,9 @@ #include #include +/* 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); diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 2d18d9debc..2542580974 100644 --- a/arch/sandbox/cpu/start.c +++ b/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; diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index d842f02176..dc933f3bfc 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/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 { diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index f86cd0d3b2..e95f4631bf 100644 --- a/arch/sandbox/dts/test.dts +++ b/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>; diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 05f66f700c..1cb960ac24 100644 --- a/arch/sandbox/include/asm/test.h +++ b/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 diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index 7517b756f4..6fa0f4d32b 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/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) { diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 3b6ed37bc0..3d0d95295f 100644 --- a/arch/x86/cpu/start.S +++ b/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 diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts index a846022095..9319123c0c 100644 --- a/arch/x86/dts/chromebook_coral.dts +++ b/arch/x86/dts/chromebook_coral.dts @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /dts-v1/; +#include #include /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 = ; 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 = ; + 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; +}; diff --git a/arch/x86/include/asm/arch-apollolake/iomap.h b/arch/x86/include/asm/arch-apollolake/iomap.h index 21c5f33021..a4ea150707 100644 --- a/arch/x86/include/asm/arch-apollolake/iomap.h +++ b/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. diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index ce1f59a740..eb5053d642 100644 --- a/cmd/cros_ec.c +++ b/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 Read image info\n" "crosec flashinfo Read flash info\n" @@ -382,6 +564,7 @@ U_BOOT_CMD( "crosec write [] Write EC image\n" "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n" "crosec ldo [] 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" ); diff --git a/configs/chromebook_coral_defconfig b/configs/chromebook_coral_defconfig index 05e6ce6493..ab73a0a88c 100644 --- a/configs/chromebook_coral_defconfig +++ b/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 diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index d193b18f47..61dae34a6a 100644 --- a/configs/sandbox_spl_defconfig +++ b/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 diff --git a/disk/part.c b/disk/part.c index b69fd345f3..85b1af55e2 100644 --- a/disk/part.c +++ b/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, diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst index 4674c420ac..60ee1e0741 100644 --- a/doc/arch/sandbox.rst +++ b/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 - - The terminal is normally in what is called 'raw-with-sigs' mode. This means +-t, --terminal + 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 - - A device tree binary file can be provided with -d. If you edit the source +-d + 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 [;] - - To execute commands directly, use the -c option. You can specify a single +-c [;] + 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 ---------------- diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c index 34c26cda47..f57f690d3c 100644 --- a/drivers/block/sandbox.c +++ b/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; diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index b75056718b..d5c4e3cbe5 100644 --- a/drivers/clk/clk-uclass.c +++ b/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) diff --git a/drivers/clk/intel/clk_intel.c b/drivers/clk/intel/clk_intel.c index b633934d90..46ccbb1d83 100644 --- a/drivers/clk/intel/clk_intel.c +++ b/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, diff --git a/drivers/core/device.c b/drivers/core/device.c index aeab3836ed..8629df8def 100644 --- a/drivers/core/device.c +++ b/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"); diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c index 6420e6ec44..653344529e 100644 --- a/drivers/core/of_extra.c +++ b/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; } diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 1aac5c481e..29aab0f9e3 100644 --- a/drivers/i2c/Makefile +++ b/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 diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index ec0cdf6220..9e387737b6 100644 --- a/drivers/i2c/designware_i2c_pci.c +++ b/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, diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index f03b7d55d6..ebfa7c41c2 100644 --- a/drivers/misc/cros_ec.c +++ b/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, }; diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c index e0002b9753..f40375978d 100644 --- a/drivers/misc/cros_ec_lpc.c +++ b/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[] = { diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 9fd6cc2086..cb8adc4495 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /* @@ -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[] = { diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c index 5a2a154e65..f25b976e54 100644 --- a/drivers/rtc/i2c_rtc_emul.c +++ b/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; } diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index ce61b72d22..b103a6fdc3 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/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; - return snprintf(buf, size, "cr50 TPM 2.0 (i2c %02x id %x) irq=%d", - chip->chip_addr, priv->vendor >> 16, priv->use_irq); + 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 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, diff --git a/include/cros_ec.h b/include/cros_ec.h index f187bd0d4b..eddc23d48f 100644 --- a/include/cros_ec.h +++ b/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 diff --git a/include/ctype.h b/include/ctype.h new file mode 120000 index 0000000000..9e43f9c6c6 --- /dev/null +++ b/include/ctype.h @@ -0,0 +1 @@ +linux/ctype.h \ No newline at end of file diff --git a/include/dm/device.h b/include/dm/device.h index f5b4cd6876..e665558444 100644 --- a/include/dm/device.h +++ b/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 diff --git a/include/dm/read.h b/include/dm/read.h index c875e11a13..03ba98232a 100644 --- a/include/dm/read.h +++ b/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); } diff --git a/include/ec_commands.h b/include/ec_commands.h index 444ba61e59..36f4a02f93 100644 --- a/include/ec_commands.h +++ b/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 */ diff --git a/include/os.h b/include/os.h index 0913b47b3a..e192e32d59 100644 --- a/include/os.h +++ b/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 diff --git a/lib/binman.c b/lib/binman.c index f415df3054..6040ec8924 100644 --- a/lib/binman.c +++ b/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; } diff --git a/test/dm/Makefile b/test/dm/Makefile index 46e076ed09..e70e50f402 100644 --- a/test/dm/Makefile +++ b/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 diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c new file mode 100644 index 0000000000..30cb70e088 --- /dev/null +++ b/test/dm/cros_ec.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2021 Google LLC + */ + +#include +#include +#include +#include +#include +#include + +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); diff --git a/test/dm/of_extra.c b/test/dm/of_extra.c new file mode 100644 index 0000000000..b19cd3787d --- /dev/null +++ b/test/dm/of_extra.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include + +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); diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c index cfc43a5b03..26c50922c5 100644 --- a/test/dm/of_platdata.c +++ b/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; } diff --git a/tools/binman/README b/tools/binman/README index de1eedfc3f..a00c902616 100644 --- a/tools/binman/README +++ b/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 diff --git a/tools/binman/control.py b/tools/binman/control.py index 072417f364..1952b2abf4 100644 --- a/tools/binman/control.py +++ b/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 diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 249074a334..03b49d7163 100644 --- a/tools/binman/elf.py +++ b/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() diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index e3d218a89e..7a128018d9 100644 --- a/tools/binman/elf_test.py +++ b/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 diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 2be0d8e053..d58a730f3d 100644 --- a/tools/binman/entry.py +++ b/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): diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py index 301ac55e3b..81756c326d 100644 --- a/tools/binman/etype/blob.py +++ b/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) diff --git a/tools/binman/etype/files.py b/tools/binman/etype/files.py index ce3832e3cd..1feebd0510 100644 --- a/tools/binman/etype/files.py +++ b/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() diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index 3dd5f58c4c..1ceadef13f 100644 --- a/tools/binman/etype/section.py +++ b/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))) diff --git a/tools/binman/etype/u_boot_spl_bss_pad.py b/tools/binman/etype/u_boot_spl_bss_pad.py index 596b2bed97..df15cd24ce 100644 --- a/tools/binman/etype/u_boot_spl_bss_pad.py +++ b/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 diff --git a/tools/binman/etype/u_boot_spl_nodtb.py b/tools/binman/etype/u_boot_spl_nodtb.py index 6f4529396d..c154cfde57 100644 --- a/tools/binman/etype/u_boot_spl_nodtb.py +++ b/tools/binman/etype/u_boot_spl_nodtb.py @@ -2,7 +2,7 @@ # Copyright (c) 2016 Google, Inc # Written by Simon Glass # -# Entry-type module for 'u-boot-nodtb.bin' +# Entry-type module for 'u-boot-spl-nodtb.bin' # from binman.entry import Entry diff --git a/tools/binman/etype/vblock.py b/tools/binman/etype/vblock.py index f734fbaec4..eba5351dd5 100644 --- a/tools/binman/etype/vblock.py +++ b/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) diff --git a/tools/binman/fmap_util.py b/tools/binman/fmap_util.py index b03fc28fbb..8277619768 100644 --- a/tools/binman/fmap_util.py +++ b/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): diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index e753a342c8..814e91d42e 100644 --- a/tools/binman/ftest.py +++ b/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('_prop_ where is the name of + the entry and is the property to find (e.g. + _binman_u_boot_prop_offset). As a special case, you can append + _any to 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) diff --git a/tools/binman/state.py b/tools/binman/state.py index 36bc513535..bb3e36ea7a 100644 --- a/tools/binman/state.py +++ b/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 diff --git a/tools/binman/test/084_files.dts b/tools/binman/test/084_files.dts index 83ddb78f8e..8f09afd24e 100644 --- a/tools/binman/test/084_files.dts +++ b/tools/binman/test/084_files.dts @@ -5,7 +5,7 @@ binman { files { pattern = "files/*.dat"; - compress = "none"; + files-compress = "none"; }; }; }; diff --git a/tools/binman/test/187_symbols_sub.dts b/tools/binman/test/187_symbols_sub.dts new file mode 100644 index 0000000000..54511a7371 --- /dev/null +++ b/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"; + }; + }; +}; diff --git a/tools/binman/test/188_image_entryarg.dts b/tools/binman/test/188_image_entryarg.dts new file mode 100644 index 0000000000..29d8149162 --- /dev/null +++ b/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"; + }; + }; +}; diff --git a/tools/binman/test/189_vblock_content.dts b/tools/binman/test/189_vblock_content.dts new file mode 100644 index 0000000000..dcc74449c1 --- /dev/null +++ b/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>; + }; + }; +}; diff --git a/tools/binman/test/190_files_align.dts b/tools/binman/test/190_files_align.dts new file mode 100644 index 0000000000..213ba966d3 --- /dev/null +++ b/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>; + }; + }; +}; diff --git a/tools/binman/test/191_read_image_skip.dts b/tools/binman/test/191_read_image_skip.dts new file mode 100644 index 0000000000..31df518fae --- /dev/null +++ b/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"; + }; + }; +}; diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index 4a78c73725..25ce5136eb 100644 --- a/tools/dtoc/fdt.py +++ b/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 diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py index dc6943f733..e8fbbd5d10 100755 --- a/tools/dtoc/test_fdt.py +++ b/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) diff --git a/tools/patman/tools.py b/tools/patman/tools.py index d8e01a3e60..10997e4386 100644 --- a/tools/patman/tools.py +++ b/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)