cros_ec: Support reading EC features
authorSimon Glass <sjg@chromium.org>
Sat, 16 Jan 2021 21:52:26 +0000 (14:52 -0700)
committerSimon Glass <sjg@chromium.org>
Sat, 30 Jan 2021 21:25:41 +0000 (14:25 -0700)
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 <sjg@chromium.org>
cmd/cros_ec.c
drivers/misc/cros_ec.c
drivers/misc/cros_ec_sandbox.c
include/cros_ec.h
include/ec_commands.h
test/dm/cros_ec.c

index 4e85e18..77656a2 100644 (file)
@@ -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"
index 80709be..fd2f2ab 100644 (file)
@@ -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;
 }
 
 /*
index 9324384..7213313 100644 (file)
@@ -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;
index 1154cdc..338878c 100644 (file)
@@ -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
index 444ba61..36f4a02 100644 (file)
@@ -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 */
index 3d0e5dc..a1ec9fc 100644 (file)
@@ -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);