From 6208975e237c9549cab50756c6291d3ecde953b7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 31 Dec 2020 09:52:12 -0700 Subject: tpm: cr50: Check for valid locality When the Cr50 starts up it doesn't have a valid locality. The driver sets it to -1 to indicate that. Tracking this allows cr50_i2c_cleanup() to avoid releasing a locality that was not claimed. However the helper functions that generate the flags use a u8 type which cannot support -1, so they return a locality of 0xff. Fix this by updating the type. With this, 'tpm startup TPM2_SU_CLEAR' works as expected. Signed-off-by: Simon Glass --- drivers/tpm/cr50_i2c.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index ce61b72d222..f53924a8fcb 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); } -- cgit v1.3.1 From 5372fc772ec0004297c080a0bd53f1871bd6b93a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 31 Dec 2020 09:52:13 -0700 Subject: tpm: cr50: Add a better description and more debug Update the TPM description to include the interrupt mechanicm since this is useful to know. Also add a warning if the TPM cannot be found and a debug line if it succeeds. Signed-off-by: Simon Glass --- drivers/tpm/cr50_i2c.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index f53924a8fcb..8b792409631 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -380,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 }; @@ -557,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) @@ -702,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; } -- cgit v1.3.1 From 3039fc7e964c75aba700538881b8b107c6e8792b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 31 Dec 2020 09:52:14 -0700 Subject: tpm: cr50: Rename driver to work with of-platdata Update the driver name to match the compatible string, so it can work with of-platdata. Signed-off-by: Simon Glass --- drivers/tpm/cr50_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index 8b792409631..b103a6fdc39 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -742,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, -- cgit v1.3.1 From d8e9a93895fb3ad710963ddef6a4cc7c43bd65f6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:22 -0700 Subject: cros_ec: Add a function for the hello message This is used several times in this file. Put it in a function to avoid code duplication. Also add a test for this function. There are no cros_ec tests at present, so it is time to update the code. Signed-off-by: Simon Glass --- arch/sandbox/include/asm/test.h | 14 +++++++++++++ drivers/misc/cros_ec.c | 46 +++++++++++++++++++++++++++-------------- drivers/misc/cros_ec_sandbox.c | 12 +++++++++++ include/cros_ec.h | 11 ++++++++++ test/dm/Makefile | 1 + test/dm/cros_ec.c | 32 ++++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 test/dm/cros_ec.c (limited to 'drivers') diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 05f66f700ca..8363ca73195 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -57,6 +57,12 @@ enum { SYSCON_COUNT }; +/** + */ +enum cros_ec_test_t { + CROSECT_BREAK_HELLO = BIT(1), +}; + /** * sandbox_i2c_set_test_mode() - set test mode for running unit tests * @@ -260,4 +266,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/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index f03b7d55d64..013c67e0464 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -591,6 +591,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; @@ -738,7 +757,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 +785,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 +808,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; diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 9fd6cc2086c..1922a9c1b96 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /* @@ -73,6 +74,7 @@ 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 */ struct ec_state { u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2]; @@ -84,6 +86,7 @@ struct ec_state { struct ec_keymatrix_entry *matrix; /* the key matrix info */ uint8_t keyscan[KEYBOARD_COLS]; bool recovery_req; + uint test_flags; } s_state, *g_state; /** @@ -295,6 +298,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; } @@ -518,6 +523,13 @@ void cros_ec_check_keyboard(struct udevice *dev) } } +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); diff --git a/include/cros_ec.h b/include/cros_ec.h index f187bd0d4b5..f57e0cc4501 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -497,4 +497,15 @@ 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); #endif diff --git a/test/dm/Makefile b/test/dm/Makefile index 46e076ed099..afcabfacc1b 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 diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c new file mode 100644 index 00000000000..823245ca70b --- /dev/null +++ b/test/dm/cros_ec.c @@ -0,0 +1,32 @@ +// 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); -- cgit v1.3.1 From 2525e53c2766a8731ebee9d13dd491a8ba0db2cb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:23 -0700 Subject: cros_ec: Tidy up a few delays Allow a longer time for the EC to reboot. Also use a constant for the hash delay time, so it is clear what it is for. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 013c67e0464..ce5fa5bee35 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 @@ -502,9 +506,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; @@ -622,18 +627,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; -- cgit v1.3.1 From 698e30f7a862ae6eb4754ef0d42b8dc8cf416edd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:24 -0700 Subject: cros_ec: Add run-time check for input buffer overflow This should not happen in normal operation, but the EC might have a bug, so add a run-time check just in case. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index ce5fa5bee35..e51ac874098 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -404,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); } } -- cgit v1.3.1 From 7791df576c4e0bcb0529850e14173d028ec37275 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:25 -0700 Subject: cros_ec: Add support for reading the SKU ID This allows reading strapping pins attached to the EC. Add an implementation for this. Signed-off-by: Simon Glass --- cmd/cros_ec.c | 10 ++++++++++ drivers/misc/cros_ec.c | 13 +++++++++++++ drivers/misc/cros_ec_sandbox.c | 7 +++++++ include/cros_ec.h | 8 ++++++++ test/dm/cros_ec.c | 17 +++++++++++++++++ 5 files changed, 55 insertions(+) (limited to 'drivers') diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index ce1f59a740c..4e85e184fee 100644 --- a/cmd/cros_ec.c +++ b/cmd/cros_ec.c @@ -352,6 +352,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; } @@ -382,6 +391,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/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index e51ac874098..80709be2f15 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1105,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; diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 1922a9c1b96..93243847048 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -473,6 +473,13 @@ 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; + } default: printf(" ** Unknown EC command %#02x\n", req_hdr->command); return -1; diff --git a/include/cros_ec.h b/include/cros_ec.h index f57e0cc4501..1154cdc52b8 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -329,6 +329,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. * diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c index 823245ca70b..3d0e5dc08d3 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -30,3 +30,20 @@ static int dm_test_cros_ec_hello(struct unit_test_state *uts) 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); -- cgit v1.3.1 From 8aec32f6abd722b141d96bc095999efa76bd0327 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:26 -0700 Subject: cros_ec: Support reading EC features The EC can support a variety of features and provides a way to find out what is available. Add support for this. Also update the feature list to the lastest available while we are here. This is at: https://chromium.googlesource.com/chromiumos/platform/ec/+/refs/heads/master/include/ec_commands.h Signed-off-by: Simon Glass --- cmd/cros_ec.c | 74 ++++++++++++++++++++++++++++++++++++++++++ drivers/misc/cros_ec.c | 26 +++++++++++---- drivers/misc/cros_ec_sandbox.c | 11 +++++++ include/cros_ec.h | 21 ++++++++++++ include/ec_commands.h | 45 ++++++++++++++++++++++--- test/dm/cros_ec.c | 28 ++++++++++++++++ 6 files changed, 195 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index 4e85e184fee..77656a2308c 100644 --- a/cmd/cros_ec.c +++ b/cmd/cros_ec.c @@ -94,6 +94,74 @@ 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 int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -140,6 +208,11 @@ 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 (0 == strcmp("curimage", cmd)) { enum ec_current_image image; @@ -379,6 +452,7 @@ 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 curimage Read CROS-EC current image\n" "crosec hash Read CROS-EC hash\n" "crosec reboot [rw | ro | cold] Reboot CROS-EC\n" diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 80709be2f15..fd2f2abd7e8 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1344,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; } /* diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 93243847048..7213313c1ac 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -480,6 +480,17 @@ static int process_cmd(struct ec_state *ec, 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); + resp->flags[1] = + EC_FEATURE_MASK_1(EC_FEATURE_UNIFIED_WAKE_MASKS) | + EC_FEATURE_MASK_1(EC_FEATURE_ISH); + len = sizeof(*resp); + break; + } default: printf(" ** Unknown EC command %#02x\n", req_hdr->command); return -1; diff --git a/include/cros_ec.h b/include/cros_ec.h index 1154cdc52b8..338878c3bed 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -516,4 +516,25 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable); * @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); + #endif diff --git a/include/ec_commands.h b/include/ec_commands.h index 444ba61e591..36f4a02f936 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/test/dm/cros_ec.c b/test/dm/cros_ec.c index 3d0e5dc08d3..a1ec9fccf3a 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -47,3 +47,31 @@ static int dm_test_cros_ec_sku_id(struct unit_test_state *uts) 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 | + 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("unified_wake_masks"); + ut_assert_nextline("ish"); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_cros_ec_features, UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From 3a6c994f3896d66e617acdf9bb58ffc4def08b71 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:28 -0700 Subject: cros_ec: Add support for switches On x86 platforms the EC provides a way to read 'switches', which are on/off values determined by the EC. Add a new driver method for this and implement it for LPC. Signed-off-by: Simon Glass --- arch/sandbox/include/asm/test.h | 1 + cmd/cros_ec.c | 41 +++++++++++++++++++++++++++++++++++++++++ drivers/misc/cros_ec.c | 16 ++++++++++++++++ drivers/misc/cros_ec_lpc.c | 7 +++++++ drivers/misc/cros_ec_sandbox.c | 10 ++++++++++ include/cros_ec.h | 19 +++++++++++++++++++ test/dm/cros_ec.c | 26 ++++++++++++++++++++++++++ 7 files changed, 120 insertions(+) (limited to 'drivers') diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 8363ca73195..1cb960ac240 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -61,6 +61,7 @@ enum { */ enum cros_ec_test_t { CROSECT_BREAK_HELLO = BIT(1), + CROSECT_LID_OPEN = BIT(2), }; /** diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index 77656a2308c..a222c75c17c 100644 --- a/cmd/cros_ec.c +++ b/cmd/cros_ec.c @@ -162,6 +162,41 @@ static int do_show_features(struct udevice *dev) 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 int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -211,6 +246,11 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, } 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)) { @@ -453,6 +493,7 @@ U_BOOT_CMD( "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" diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index fd2f2abd7e8..0bc28e882c9 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1557,6 +1557,22 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable) 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", diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c index e0002b9753f..f40375978dd 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 7213313c1ac..38a2614a993 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -75,6 +75,7 @@ struct ec_keymatrix_entry { * @keyscan: Current keyscan information (bit set for each row/column pressed) * @recovery_req: Keyboard recovery requested * @test_flags: Flags that control behaviour for tests + * @switches: Current switches value (EC_SWITCH_) */ struct ec_state { u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2]; @@ -541,6 +542,14 @@ 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); @@ -603,6 +612,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/include/cros_ec.h b/include/cros_ec.h index 26e3f3ba0cb..cb91343e3d8 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -279,6 +279,16 @@ struct dm_cros_ec_ops { * @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) \ @@ -577,4 +587,13 @@ int cros_ec_get_features(struct udevice *dev, u64 *featuresp); */ 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); + #endif diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c index a1ec9fccf3a..43774400a1e 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -75,3 +75,29 @@ static int dm_test_cros_ec_features(struct unit_test_state *uts) 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); -- cgit v1.3.1 From 3ae338299e1649ef9a38c45fcde864022c448a9e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:29 -0700 Subject: cros_ec: Show events in human-readable form Add a command to show the current events as a list of names. This is easier to decipher than a bit mask. Signed-off-by: Simon Glass --- cmd/cros_ec.c | 70 ++++++++++++++++++++++++++++++++++++++---- drivers/misc/cros_ec_sandbox.c | 12 +++++++- test/dm/cros_ec.c | 37 ++++++++++++++++++++++ 3 files changed, 112 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index a222c75c17c..eb5053d6424 100644 --- a/cmd/cros_ec.c +++ b/cmd/cros_ec.c @@ -197,6 +197,66 @@ static int do_show_switches(struct udevice *dev) 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[]) { @@ -303,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; @@ -498,6 +555,7 @@ U_BOOT_CMD( "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" diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 38a2614a993..845876cfb0c 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -364,10 +364,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; diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c index 43774400a1e..0da7548fd24 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -101,3 +101,40 @@ static int dm_test_cros_ec_switches(struct unit_test_state *uts) 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); -- cgit v1.3.1 From d9ffaef6fe25e7a29e63911fe1af5d18c9d77a45 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:30 -0700 Subject: cros_ec: Allow use with of-platdata Avoid reading the device tree when of-platdata is in use. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 0bc28e882c9..c22bb4b5b50 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1577,6 +1577,8 @@ 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, }; -- cgit v1.3.1 From 10f746591fba16a48f0e3d14641be09f01982807 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:31 -0700 Subject: cros_ec: Add vstore support The EC can store small amounts of data for the benefit of the verified boot process. Since the EC is seldom reset, this can allow the AP to store data that survives a reboot or a suspend/resume cycle. Add support for this. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 71 ++++++++++++++++++++++++++++++++++++++++++ drivers/misc/cros_ec_sandbox.c | 52 +++++++++++++++++++++++++++++-- include/cros_ec.h | 43 +++++++++++++++++++++++++ test/dm/cros_ec.c | 38 ++++++++++++++++++++++ 4 files changed, 202 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index c22bb4b5b50..ebfa7c41c25 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1557,6 +1557,77 @@ 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; diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 845876cfb0c..cb8adc4495a 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -62,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 * @@ -75,7 +84,7 @@ struct ec_keymatrix_entry { * @keyscan: Current keyscan information (bit set for each row/column pressed) * @recovery_req: Keyboard recovery requested * @test_flags: Flags that control behaviour for tests - * @switches: Current switches value (EC_SWITCH_) + * @slot_locked: Locked vstore slots (mask) */ struct ec_state { u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2]; @@ -88,6 +97,7 @@ struct ec_state { uint8_t keyscan[KEYBOARD_COLS]; bool recovery_req; uint test_flags; + struct vstore_slot slot[VSTORE_SLOT_COUNT]; } s_state, *g_state; /** @@ -495,13 +505,51 @@ static int process_cmd(struct ec_state *ec, 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_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; diff --git a/include/cros_ec.h b/include/cros_ec.h index cb91343e3d8..eddc23d48f8 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -596,4 +596,47 @@ int cros_ec_check_feature(struct udevice *dev, uint feature); */ 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/test/dm/cros_ec.c b/test/dm/cros_ec.c index 0da7548fd24..30cb70e0882 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -56,6 +56,7 @@ static int dm_test_cros_ec_features(struct unit_test_state *uts) 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); @@ -68,6 +69,7 @@ static int dm_test_cros_ec_features(struct unit_test_state *uts) 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(); @@ -138,3 +140,39 @@ static int dm_test_cros_ec_events(struct unit_test_state *uts) 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); -- cgit v1.3.1 From dfb5bfbc208699ae1b5fc8e17f65d862be3b4612 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:08 -0700 Subject: i2c: desigware: Add an alias for Intel Apollo Lake Add an alias so that this driver can be used in TPL on coral. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- drivers/i2c/designware_i2c_pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index ec0cdf62207..9e387737b6e 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, -- cgit v1.3.1 From d85f2c4f2970d0ec2f5f075de734afd11200d153 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:09 -0700 Subject: sandbox: Disable I2C emulators in SPL These cannot work with of-platdata since they currently need the devicetree at runtime. Disable the emulators and the sandbox I2C driver that needs them. We can enable these later, if needed for testing. Switch the of_plat_parent test over to use a simple bus instead. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- arch/sandbox/dts/sandbox.dtsi | 10 +++++++--- configs/sandbox_spl_defconfig | 1 - drivers/i2c/Makefile | 2 ++ test/dm/of_platdata.c | 8 ++++---- 4 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index d842f021760..dc933f3bfc7 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/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index d193b18f47e..61dae34a6a2 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/drivers/i2c/Makefile b/drivers/i2c/Makefile index 1aac5c481e2..29aab0f9e30 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/test/dm/of_platdata.c b/test/dm/of_platdata.c index cfc43a5b038..26c50922c56 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; } -- cgit v1.3.1 From 5c5992cb90cf9ca4d51e38d9a95a13c293904df5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:11 -0700 Subject: clk: Add debugging for return values Use the log_msg_ret() mechanism to get error-return information when clocks fail to probe, etc. Signed-off-by: Simon Glass --- drivers/clk/clk-uclass.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index b75056718bf..d5c4e3cbe51 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) -- cgit v1.3.1 From 0dc2bf2b6e6e7581e3307f3aa65d0ce310375511 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:12 -0700 Subject: clk: x86: Correct the driver name The current driver name does not match its compatible string, so of-platdata does not work correctly. Fix it. Signed-off-by: Simon Glass --- drivers/clk/intel/clk_intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/intel/clk_intel.c b/drivers/clk/intel/clk_intel.c index b633934d90a..46ccbb1d834 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, -- cgit v1.3.1 From 017d421828971f6adbfa6a1305b80da7d620c596 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:13 -0700 Subject: dm: core: Add a comment about pinctrl_select_state() The use of pinctrl in the core of driver model is useful but can provoke some strange behaviour. Add a comment to aid debugging. Signed-off-by: Simon Glass --- drivers/core/device.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/core/device.c b/drivers/core/device.c index aeab3836ed7..8629df8defb 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"); -- cgit v1.3.1 From ff5fa7d62655ae6c1873e17057c057566c81df0d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:14 -0700 Subject: dm: core: Update ofnode_read_fmap_entry() to read hashes At present this function uses the old format for reading hashes. Add support for the current format. Add a test while we are here. Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 10 ++++++++++ drivers/core/of_extra.c | 21 ++++++++++++--------- test/dm/Makefile | 1 + test/dm/of_extra.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 test/dm/of_extra.c (limited to 'drivers') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index f86cd0d3b27..e95f4631bf2 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/drivers/core/of_extra.c b/drivers/core/of_extra.c index 6420e6ec448..653344529e6 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/test/dm/Makefile b/test/dm/Makefile index afcabfacc1b..e70e50f4024 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -42,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/of_extra.c b/test/dm/of_extra.c new file mode 100644 index 00000000000..b19cd3787d8 --- /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); -- cgit v1.3.1 From 43db07507abdb54b6575345300c171b0486e46be Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 30 Dec 2020 18:07:48 +0100 Subject: sandbox: keep time offset when resetting The UEFI Self Certification Test (SCT) checks the SetTime() service with the following steps: * set date * reset * check date matches To be compliant the sandbox should keep the offset to the host RTC during resets. The implementation uses the environment variable UBOOT_SB_TIME_OFFSET to persist the offset. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- arch/sandbox/cpu/os.c | 25 +++++++++++++++++++++++++ doc/arch/sandbox.rst | 7 +++++++ drivers/rtc/i2c_rtc_emul.c | 4 +++- include/os.h | 18 ++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 80996a91ce7..3d8af0a52bb 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/doc/arch/sandbox.rst b/doc/arch/sandbox.rst index 1a7801af025..60ee1e0741a 100644 --- a/doc/arch/sandbox.rst +++ b/doc/arch/sandbox.rst @@ -131,6 +131,13 @@ available options. Some of these are described below: -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/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c index 5a2a154e653..f25b976e54d 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/include/os.h b/include/os.h index 0913b47b3a8..e192e32d592 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 -- cgit v1.3.1 From 168e313b5b128a0a2e55010875c1636dead38527 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 25 Jan 2021 12:57:14 +0100 Subject: sandbox: fill block device meta information Provide information about host backed block device. Mark the device created by 'host bind' as removable. Signed-off-by: Heinrich Schuchardt --- drivers/block/sandbox.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c index 34c26cda47e..f57f690d3c0 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; -- cgit v1.3.1