diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index c22bb4b5b5..ebfa7c41c2 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 845876cfb0..cb8adc4495 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 cb91343e3d..eddc23d48f 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 0da7548fd2..30cb70e088 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);