2020-10-22 07:01:51

by Prashant Malani

[permalink] [raw]
Subject: [PATCH 0/7] platform/chrome: cros_ec_typec: Register partner PD information

This series adds support to retrieve Type C PD(Power Delivery) Discovery
information from the Chrome OS EC, and register this information with
the Type C connector class framework.

There are also a couple of patches which fix minor bugs with the
existing cros-ec-typec driver.

Prashant Malani (7):
platform/chrome: cros_ec_typec: Relocate set_port_params_v*()
functions
platform/chrome: cros_ec_typec: Fix remove partner logic
platform/chrome: cros_ec_typec: Clear partner identity on device
removal
platform/chrome: cros_ec: Import Type C host commands
platform/chrome: cros_ec_typec: Introduce TYPEC_STATUS
platform/chrome: cros_ec_typec: Parse partner PD ID VDOs
platform/chrome: cros_ec_typec: Register partner altmodes

drivers/platform/chrome/cros_ec_typec.c | 331 ++++++++++++++----
.../linux/platform_data/cros_ec_commands.h | 155 ++++++++
2 files changed, 417 insertions(+), 69 deletions(-)

--
2.29.0.rc1.297.gfa9743e501-goog


2020-10-22 07:05:55

by Prashant Malani

[permalink] [raw]
Subject: [PATCH 7/7] platform/chrome: cros_ec_typec: Register partner altmodes

Use the discovery data from the Chrome EC to register parter altmodes
with the Type C Connector Class framework. Also introduce a node
struct to keep track of the list of registered alt modes.

Cc: Heikki Krogerus <[email protected]>
Signed-off-by: Prashant Malani <[email protected]>
---
drivers/platform/chrome/cros_ec_typec.c | 79 +++++++++++++++++++++++++
1 file changed, 79 insertions(+)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 53d0b4b4fcd7..57d38570e292 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -7,6 +7,7 @@
*/

#include <linux/acpi.h>
+#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/cros_ec_commands.h>
@@ -31,6 +32,12 @@ enum {
CROS_EC_ALTMODE_MAX,
};

+/* Container for altmode pointer nodes. */
+struct cros_typec_altmode_node {
+ struct typec_altmode *amode;
+ struct list_head list;
+};
+
/* Per port data. */
struct cros_typec_port {
struct typec_port *port;
@@ -53,6 +60,7 @@ struct cros_typec_port {
/* Flag indicating that PD discovery data parsing is completed. */
bool disc_done;
struct ec_response_typec_discovery *sop_disc;
+ struct list_head partner_mode_list;
};

/* Platform-specific data for the Chrome OS EC Type C controller. */
@@ -172,11 +180,27 @@ static int cros_typec_add_partner(struct cros_typec_data *typec, int port_num,
return ret;
}

+static void cros_typec_unregister_altmodes(struct cros_typec_data *typec, int port_num)
+{
+ struct cros_typec_port *port = typec->ports[port_num];
+ struct cros_typec_altmode_node *node;
+
+ while (!list_empty(&port->partner_mode_list)) {
+ node = list_first_entry(&port->partner_mode_list, struct cros_typec_altmode_node,
+ list);
+ list_del(&node->list);
+ typec_unregister_altmode(node->amode);
+ devm_kfree(typec->dev, node);
+ }
+}
+
static void cros_typec_remove_partner(struct cros_typec_data *typec,
int port_num)
{
struct cros_typec_port *port = typec->ports[port_num];

+ cros_typec_unregister_altmodes(typec, port_num);
+
port->state.alt = NULL;
port->state.mode = TYPEC_STATE_USB;
port->state.data = NULL;
@@ -306,6 +330,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
ret = -ENOMEM;
goto unregister_ports;
}
+
+ INIT_LIST_HEAD(&cros_port->partner_mode_list);
}

return 0;
@@ -590,6 +616,49 @@ static int cros_typec_get_mux_info(struct cros_typec_data *typec, int port_num,
sizeof(req), resp, sizeof(*resp));
}

+static int cros_typec_register_altmodes(struct cros_typec_data *typec, int port_num)
+{
+ struct cros_typec_port *port = typec->ports[port_num];
+ struct ec_response_typec_discovery *sop_disc = port->sop_disc;
+ struct cros_typec_altmode_node *node;
+ struct typec_altmode_desc desc;
+ struct typec_altmode *amode;
+ int ret = 0;
+ int i, j;
+
+ for (i = 0; i < sop_disc->svid_count; i++) {
+ for (j = 0; j < sop_disc->svids[i].mode_count; j++) {
+ memset(&desc, 0, sizeof(desc));
+ desc.svid = sop_disc->svids[i].svid;
+ desc.mode = j;
+ desc.vdo = sop_disc->svids[i].mode_vdo[j];
+
+ amode = typec_partner_register_altmode(port->partner, &desc);
+ if (IS_ERR(amode)) {
+ ret = PTR_ERR(amode);
+ goto err_cleanup;
+ }
+
+ /* If no memory is available we should unregister and exit. */
+ node = devm_kzalloc(typec->dev, sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ ret = -ENOMEM;
+ typec_unregister_altmode(amode);
+ goto err_cleanup;
+ }
+
+ node->amode = amode;
+ list_add_tail(&node->list, &port->partner_mode_list);
+ }
+ }
+
+ return 0;
+
+err_cleanup:
+ cros_typec_unregister_altmodes(typec, port_num);
+ return ret;
+}
+
static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_num)
{
struct cros_typec_port *port = typec->ports[port_num];
@@ -630,6 +699,16 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu
port->p_identity.vdo[i - 3] = sop_disc->discovery_vdo[i];

ret = typec_partner_set_identity(port->partner);
+ if (ret < 0) {
+ dev_err(typec->dev, "Failed to update partner PD identity, port: %d\n", port_num);
+ goto disc_exit;
+ }
+
+ ret = cros_typec_register_altmodes(typec, port_num);
+ if (ret < 0) {
+ dev_err(typec->dev, "Failed to register partner altmodes, port: %d\n", port_num);
+ goto disc_exit;
+ }

disc_exit:
return ret;
--
2.29.0.rc1.297.gfa9743e501-goog

2020-10-22 12:40:28

by Prashant Malani

[permalink] [raw]
Subject: [PATCH 3/7] platform/chrome: cros_ec_typec: Clear partner identity on device removal

The partner identity struct isn't reset when a partner is removed,
meaning a subsequent partner can inherit an old partner's identity VDOs
before discovery is complete. So, clear that struct when a partner
removal is detected.

Signed-off-by: Prashant Malani <[email protected]>
---
drivers/platform/chrome/cros_ec_typec.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 2665d8125910..faef56bcb9c5 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -181,6 +181,7 @@ static void cros_typec_remove_partner(struct cros_typec_data *typec,

typec_unregister_partner(port->partner);
port->partner = NULL;
+ memset(&port->p_identity, 0, sizeof(port->p_identity));
}

static void cros_unregister_ports(struct cros_typec_data *typec)
--
2.29.0.rc1.297.gfa9743e501-goog

2020-10-22 12:40:38

by Prashant Malani

[permalink] [raw]
Subject: [PATCH 5/7] platform/chrome: cros_ec_typec: Introduce TYPEC_STATUS

Make a call to the newly introduced EC_CMD_TYPEC_STATUS command.
Currently we just check to see if the SOP (port-partner) discovery was
done and emit a debug level print for it.

Subsequent patches will retrieve and parse the discovery data and fill
out the Type C connector class data structures.

Also check the EC_FEATURE_TYPEC_CMD feature flag at probe, and only call
the new TYPEC_STATUS command if the feature flag is supported.

Signed-off-by: Prashant Malani <[email protected]>
---
drivers/platform/chrome/cros_ec_typec.c | 52 +++++++++++++++++++++++++
1 file changed, 52 insertions(+)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index faef56bcb9c5..98d22720b365 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -48,6 +48,9 @@ struct cros_typec_port {

/* Port alt modes. */
struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX];
+
+ /* Flag indicating that PD discovery data parsing is completed. */
+ bool disc_done;
};

/* Platform-specific data for the Chrome OS EC Type C controller. */
@@ -60,6 +63,7 @@ struct cros_typec_data {
struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS];
struct notifier_block nb;
struct work_struct port_work;
+ bool typec_cmd_supported;
};

static int cros_typec_parse_port_props(struct typec_capability *cap,
@@ -182,6 +186,7 @@ static void cros_typec_remove_partner(struct cros_typec_data *typec,
typec_unregister_partner(port->partner);
port->partner = NULL;
memset(&port->p_identity, 0, sizeof(port->p_identity));
+ port->disc_done = false;
}

static void cros_unregister_ports(struct cros_typec_data *typec)
@@ -577,6 +582,31 @@ static int cros_typec_get_mux_info(struct cros_typec_data *typec, int port_num,
sizeof(req), resp, sizeof(*resp));
}

+static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num)
+{
+ struct ec_response_typec_status resp;
+ struct ec_params_typec_status req = {
+ .port = port_num,
+ };
+ int ret;
+
+ ret = cros_typec_ec_command(typec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req),
+ &resp, sizeof(resp));
+ if (ret < 0) {
+ dev_warn(typec->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num);
+ return;
+ }
+
+ if (typec->ports[port_num]->disc_done)
+ return;
+
+ /* Handle any events appropriately. */
+ if (resp.events & PD_STATUS_EVENT_SOP_DISC_DONE) {
+ dev_dbg(typec->dev, "SOP Discovery done for port: %d\n", port_num);
+ typec->ports[port_num]->disc_done = true;
+ }
+}
+
static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
{
struct ec_params_usb_pd_control req;
@@ -613,6 +643,9 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
cros_typec_set_port_params_v0(typec, port_num,
(struct ec_response_usb_pd_control *) &resp);

+ if (typec->typec_cmd_supported)
+ cros_typec_handle_status(typec, port_num);
+
/* Update the switches if they exist, according to requested state */
ret = cros_typec_get_mux_info(typec, port_num, &mux_resp);
if (ret < 0) {
@@ -661,6 +694,23 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
return 0;
}

+/* Check the EC feature flags to see if TYPEC_* commands are supported. */
+int cros_typec_cmds_supported(struct cros_typec_data *typec)
+{
+ struct ec_response_get_features resp = {};
+ int ret;
+
+ ret = cros_typec_ec_command(typec, 0, EC_CMD_GET_FEATURES, NULL, 0,
+ &resp, sizeof(resp));
+ if (ret < 0) {
+ dev_warn(typec->dev,
+ "Failed to get features, assuming typec commands unsupported.\n");
+ return 0;
+ }
+
+ return resp.flags[EC_FEATURE_TYPEC_CMD / 32] & EC_FEATURE_MASK_1(EC_FEATURE_TYPEC_CMD);
+}
+
static void cros_typec_port_work(struct work_struct *work)
{
struct cros_typec_data *typec = container_of(work, struct cros_typec_data, port_work);
@@ -720,6 +770,8 @@ static int cros_typec_probe(struct platform_device *pdev)
return ret;
}

+ typec->typec_cmd_supported = !!cros_typec_cmds_supported(typec);
+
ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
&resp, sizeof(resp));
if (ret < 0)
--
2.29.0.rc1.297.gfa9743e501-goog

2020-10-22 12:40:39

by Prashant Malani

[permalink] [raw]
Subject: [PATCH 4/7] platform/chrome: cros_ec: Import Type C host commands

Import the EC_CMD_TYPEC_STATUS and EC_CMD_TYPEC_DISCOVERY Chrome OS EC
host commands from the EC code base [1].

These commands can be used by the application processor to query Power
Delivery (PD) discovery information concerning connected Type C
peripherals.

Also add the EC_FEATURE_TYPEC_CMD feature flag, which is used to
determine whether these commands are supported by the EC.

[1]:
https://chromium.googlesource.com/chromiumos/platform/ec/+/refs/heads/master/include/ec_commands.h

Signed-off-by: Prashant Malani <[email protected]>
---
.../linux/platform_data/cros_ec_commands.h | 155 ++++++++++++++++++
1 file changed, 155 insertions(+)

diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h
index 1fcfe9e63cb9..7f54fdcdd8cb 100644
--- a/include/linux/platform_data/cros_ec_commands.h
+++ b/include/linux/platform_data/cros_ec_commands.h
@@ -1284,6 +1284,8 @@ enum ec_feature_code {
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,
};

#define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32)
@@ -5528,6 +5530,159 @@ struct ec_response_regulator_get_voltage {
uint32_t voltage_mv;
} __ec_align4;

+/*
+ * Gather all discovery information for the given port and partner type.
+ *
+ * Note that if discovery has not yet completed, only the currently completed
+ * responses will be filled in. If the discovery data structures are changed
+ * in the process of the command running, BUSY will be returned.
+ *
+ * VDO field sizes are set to the maximum possible number of VDOs a VDM may
+ * contain, while the number of SVIDs here is selected to fit within the PROTO2
+ * maximum parameter size.
+ */
+#define EC_CMD_TYPEC_DISCOVERY 0x0131
+
+enum typec_partner_type {
+ TYPEC_PARTNER_SOP = 0,
+ TYPEC_PARTNER_SOP_PRIME = 1,
+};
+
+struct ec_params_typec_discovery {
+ uint8_t port;
+ uint8_t partner_type; /* enum typec_partner_type */
+} __ec_align1;
+
+struct svid_mode_info {
+ uint16_t svid;
+ uint16_t mode_count; /* Number of modes partner sent */
+ uint32_t mode_vdo[6]; /* Max VDOs allowed after VDM header is 6 */
+};
+
+struct ec_response_typec_discovery {
+ uint8_t identity_count; /* Number of identity VDOs partner sent */
+ uint8_t svid_count; /* Number of SVIDs partner sent */
+ uint16_t reserved;
+ uint32_t discovery_vdo[6]; /* Max VDOs allowed after VDM header is 6 */
+ struct svid_mode_info svids[0];
+} __ec_align1;
+
+/*
+ * Gather all status information for a port.
+ *
+ * Note: this covers many of the return fields from the deprecated
+ * EC_CMD_USB_PD_CONTROL command, except those that are redundant with the
+ * discovery data. The "enum pd_cc_states" is defined with the deprecated
+ * EC_CMD_USB_PD_CONTROL command.
+ *
+ * This also combines in the EC_CMD_USB_PD_MUX_INFO flags.
+ */
+#define EC_CMD_TYPEC_STATUS 0x0133
+
+/*
+ * Power role.
+ *
+ * Note this is also used for PD header creation, and values align to those in
+ * the Power Delivery Specification Revision 3.0 (See
+ * 6.2.1.1.4 Port Power Role).
+ */
+enum pd_power_role {
+ PD_ROLE_SINK = 0,
+ PD_ROLE_SOURCE = 1
+};
+
+/*
+ * Data role.
+ *
+ * Note this is also used for PD header creation, and the first two values
+ * align to those in the Power Delivery Specification Revision 3.0 (See
+ * 6.2.1.1.6 Port Data Role).
+ */
+enum pd_data_role {
+ PD_ROLE_UFP = 0,
+ PD_ROLE_DFP = 1,
+ PD_ROLE_DISCONNECTED = 2,
+};
+
+enum pd_vconn_role {
+ PD_ROLE_VCONN_OFF = 0,
+ PD_ROLE_VCONN_SRC = 1,
+};
+
+/*
+ * Note: BIT(0) may be used to determine whether the polarity is CC1 or CC2,
+ * regardless of whether a debug accessory is connected.
+ */
+enum tcpc_cc_polarity {
+ /*
+ * _CCx: is used to indicate the polarity while not connected to
+ * a Debug Accessory. Only one CC line will assert a resistor and
+ * the other will be open.
+ */
+ POLARITY_CC1 = 0,
+ POLARITY_CC2 = 1,
+
+ /*
+ * _CCx_DTS is used to indicate the polarity while connected to a
+ * SRC Debug Accessory. Assert resistors on both lines.
+ */
+ POLARITY_CC1_DTS = 2,
+ POLARITY_CC2_DTS = 3,
+
+ /*
+ * The current TCPC code relies on these specific POLARITY values.
+ * Adding in a check to verify if the list grows for any reason
+ * that this will give a hint that other places need to be
+ * adjusted.
+ */
+ POLARITY_COUNT
+};
+
+#define PD_STATUS_EVENT_SOP_DISC_DONE BIT(0)
+#define PD_STATUS_EVENT_SOP_PRIME_DISC_DONE BIT(1)
+
+struct ec_params_typec_status {
+ uint8_t port;
+} __ec_align1;
+
+struct ec_response_typec_status {
+ uint8_t pd_enabled; /* PD communication enabled - bool */
+ uint8_t dev_connected; /* Device connected - bool */
+ uint8_t sop_connected; /* Device is SOP PD capable - bool */
+ uint8_t source_cap_count; /* Number of Source Cap PDOs */
+
+ uint8_t power_role; /* enum pd_power_role */
+ uint8_t data_role; /* enum pd_data_role */
+ uint8_t vconn_role; /* enum pd_vconn_role */
+ uint8_t sink_cap_count; /* Number of Sink Cap PDOs */
+
+ uint8_t polarity; /* enum tcpc_cc_polarity */
+ uint8_t cc_state; /* enum pd_cc_states */
+ uint8_t dp_pin; /* DP pin mode (MODE_DP_IN_[A-E]) */
+ uint8_t mux_state; /* USB_PD_MUX* - encoded mux state */
+
+ char tc_state[32]; /* TC state name */
+
+ uint32_t events; /* PD_STATUS_EVENT bitmask */
+
+ /*
+ * BCD PD revisions for partners
+ *
+ * The format has the PD major reversion in the upper nibble, and PD
+ * minor version in the next nibble. Following two nibbles are
+ * currently 0.
+ * ex. PD 3.2 would map to 0x3200
+ *
+ * PD major/minor will be 0 if no PD device is connected.
+ */
+ uint16_t sop_revision;
+ uint16_t sop_prime_revision;
+
+ uint32_t source_cap_pdos[7]; /* Max 7 PDOs can be present */
+
+ uint32_t sink_cap_pdos[7]; /* Max 7 PDOs can be present */
+} __ec_align1;
+
/*****************************************************************************/
/* The command range 0x200-0x2FF is reserved for Rotor. */

--
2.29.0.rc1.297.gfa9743e501-goog

2020-10-22 12:40:42

by Prashant Malani

[permalink] [raw]
Subject: [PATCH 6/7] platform/chrome: cros_ec_typec: Parse partner PD ID VDOs

Use EC_CMD_TYPE_DISCOVERY to retrieve and store the discovery data for
the port partner. With that data, update the PD Identity VDO values for
the partner, which were earlier not initialized.

Cc: Heikki Krogerus <[email protected]>
Signed-off-by: Prashant Malani <[email protected]>
---
drivers/platform/chrome/cros_ec_typec.c | 60 ++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 98d22720b365..53d0b4b4fcd7 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -14,6 +14,7 @@
#include <linux/platform_data/cros_usbpd_notify.h>
#include <linux/platform_device.h>
#include <linux/usb/pd.h>
+#include <linux/usb/pd_vdo.h>
#include <linux/usb/typec.h>
#include <linux/usb/typec_altmode.h>
#include <linux/usb/typec_dp.h>
@@ -51,6 +52,7 @@ struct cros_typec_port {

/* Flag indicating that PD discovery data parsing is completed. */
bool disc_done;
+ struct ec_response_typec_discovery *sop_disc;
};

/* Platform-specific data for the Chrome OS EC Type C controller. */
@@ -298,6 +300,12 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
port_num);

cros_typec_register_port_altmodes(typec, port_num);
+
+ cros_port->sop_disc = devm_kzalloc(dev, EC_PROTO2_MAX_RESPONSE_SIZE, GFP_KERNEL);
+ if (!cros_port->sop_disc) {
+ ret = -ENOMEM;
+ goto unregister_ports;
+ }
}

return 0;
@@ -582,6 +590,51 @@ static int cros_typec_get_mux_info(struct cros_typec_data *typec, int port_num,
sizeof(req), resp, sizeof(*resp));
}

+static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_num)
+{
+ struct cros_typec_port *port = typec->ports[port_num];
+ struct ec_response_typec_discovery *sop_disc = port->sop_disc;
+ struct ec_params_typec_discovery req = {
+ .port = port_num,
+ .partner_type = TYPEC_PARTNER_SOP,
+ };
+ int ret = 0;
+ int i;
+
+ if (!port->partner) {
+ dev_err(typec->dev,
+ "SOP Discovery received without partner registered, port: %d\n",
+ port_num);
+ ret = -EINVAL;
+ goto disc_exit;
+ }
+
+ memset(sop_disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE);
+ ret = cros_typec_ec_command(typec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
+ sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE);
+ if (ret < 0) {
+ dev_err(typec->dev, "Failed to get SOP discovery data for port: %d\n", port_num);
+ goto disc_exit;
+ }
+
+ /* First, update the PD identity VDOs for the partner. */
+ if (sop_disc->identity_count > 0)
+ port->p_identity.id_header = sop_disc->discovery_vdo[0];
+ if (sop_disc->identity_count > 1)
+ port->p_identity.cert_stat = sop_disc->discovery_vdo[1];
+ if (sop_disc->identity_count > 2)
+ port->p_identity.product = sop_disc->discovery_vdo[2];
+
+ /* Copy the remaining identity VDOs till a maximum of 6. */
+ for (i = 3; i < sop_disc->identity_count && i < VDO_MAX_OBJECTS; i++)
+ port->p_identity.vdo[i - 3] = sop_disc->discovery_vdo[i];
+
+ ret = typec_partner_set_identity(port->partner);
+
+disc_exit:
+ return ret;
+}
+
static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num)
{
struct ec_response_typec_status resp;
@@ -602,7 +655,12 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num

/* Handle any events appropriately. */
if (resp.events & PD_STATUS_EVENT_SOP_DISC_DONE) {
- dev_dbg(typec->dev, "SOP Discovery done for port: %d\n", port_num);
+ ret = cros_typec_handle_sop_disc(typec, port_num);
+ if (ret < 0) {
+ dev_err(typec->dev, "Couldn't parse SOP Disc data, port: %d\n", port_num);
+ return;
+ }
+
typec->ports[port_num]->disc_done = true;
}
}
--
2.29.0.rc1.297.gfa9743e501-goog

2020-10-22 12:58:01

by Prashant Malani

[permalink] [raw]
Subject: [PATCH 2/7] platform/chrome: cros_ec_typec: Fix remove partner logic

The cros_unregister_ports() function can be called in situations where
the partner has not been registered yet, and so its related data
structures would not have been initialized. Calling
cros_typec_remove_partner() in such a situation can lead to null pointer
dereferences. So, only call cros_typec_remove_partner() if there is a
valid registered partner pointer.

Signed-off-by: Prashant Malani <[email protected]>
---
drivers/platform/chrome/cros_ec_typec.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 49083e21317d..2665d8125910 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -190,7 +190,10 @@ static void cros_unregister_ports(struct cros_typec_data *typec)
for (i = 0; i < typec->num_ports; i++) {
if (!typec->ports[i])
continue;
- cros_typec_remove_partner(typec, i);
+
+ if (typec->ports[i]->partner)
+ cros_typec_remove_partner(typec, i);
+
usb_role_switch_put(typec->ports[i]->role_sw);
typec_switch_put(typec->ports[i]->ori_sw);
typec_mux_put(typec->ports[i]->mux);
--
2.29.0.rc1.297.gfa9743e501-goog

2020-10-22 12:58:26

by Prashant Malani

[permalink] [raw]
Subject: [PATCH 1/7] platform/chrome: cros_ec_typec: Relocate set_port_params_v*() functions

Move the cros_typec_set_port_params_v0/v1() functions closer to the
place where they are called, cros_typec_port_update().

While we are performing the relocation, also move cros_typec_get_mux_info()
closer to its call-site.

No functional changes are introduced by this commit.

Signed-off-by: Prashant Malani <[email protected]>
---
drivers/platform/chrome/cros_ec_typec.c | 136 ++++++++++++------------
1 file changed, 68 insertions(+), 68 deletions(-)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 31be31161350..49083e21317d 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -329,74 +329,6 @@ static int cros_typec_ec_command(struct cros_typec_data *typec,
return ret;
}

-static void cros_typec_set_port_params_v0(struct cros_typec_data *typec,
- int port_num, struct ec_response_usb_pd_control *resp)
-{
- struct typec_port *port = typec->ports[port_num]->port;
- enum typec_orientation polarity;
-
- if (!resp->enabled)
- polarity = TYPEC_ORIENTATION_NONE;
- else if (!resp->polarity)
- polarity = TYPEC_ORIENTATION_NORMAL;
- else
- polarity = TYPEC_ORIENTATION_REVERSE;
-
- typec_set_pwr_role(port, resp->role ? TYPEC_SOURCE : TYPEC_SINK);
- typec_set_orientation(port, polarity);
-}
-
-static void cros_typec_set_port_params_v1(struct cros_typec_data *typec,
- int port_num, struct ec_response_usb_pd_control_v1 *resp)
-{
- struct typec_port *port = typec->ports[port_num]->port;
- enum typec_orientation polarity;
- bool pd_en;
- int ret;
-
- if (!(resp->enabled & PD_CTRL_RESP_ENABLED_CONNECTED))
- polarity = TYPEC_ORIENTATION_NONE;
- else if (!resp->polarity)
- polarity = TYPEC_ORIENTATION_NORMAL;
- else
- polarity = TYPEC_ORIENTATION_REVERSE;
- typec_set_orientation(port, polarity);
- typec_set_data_role(port, resp->role & PD_CTRL_RESP_ROLE_DATA ?
- TYPEC_HOST : TYPEC_DEVICE);
- typec_set_pwr_role(port, resp->role & PD_CTRL_RESP_ROLE_POWER ?
- TYPEC_SOURCE : TYPEC_SINK);
- typec_set_vconn_role(port, resp->role & PD_CTRL_RESP_ROLE_VCONN ?
- TYPEC_SOURCE : TYPEC_SINK);
-
- /* Register/remove partners when a connect/disconnect occurs. */
- if (resp->enabled & PD_CTRL_RESP_ENABLED_CONNECTED) {
- if (typec->ports[port_num]->partner)
- return;
-
- pd_en = resp->enabled & PD_CTRL_RESP_ENABLED_PD_CAPABLE;
- ret = cros_typec_add_partner(typec, port_num, pd_en);
- if (ret)
- dev_warn(typec->dev,
- "Failed to register partner on port: %d\n",
- port_num);
- } else {
- if (!typec->ports[port_num]->partner)
- return;
- cros_typec_remove_partner(typec, port_num);
- }
-}
-
-static int cros_typec_get_mux_info(struct cros_typec_data *typec, int port_num,
- struct ec_response_usb_pd_mux_info *resp)
-{
- struct ec_params_usb_pd_mux_info req = {
- .port = port_num,
- };
-
- return cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_MUX_INFO, &req,
- sizeof(req), resp, sizeof(*resp));
-}
-
static int cros_typec_usb_safe_state(struct cros_typec_port *port)
{
port->state.mode = TYPEC_STATE_SAFE;
@@ -573,6 +505,74 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
return ret;
}

+static void cros_typec_set_port_params_v0(struct cros_typec_data *typec,
+ int port_num, struct ec_response_usb_pd_control *resp)
+{
+ struct typec_port *port = typec->ports[port_num]->port;
+ enum typec_orientation polarity;
+
+ if (!resp->enabled)
+ polarity = TYPEC_ORIENTATION_NONE;
+ else if (!resp->polarity)
+ polarity = TYPEC_ORIENTATION_NORMAL;
+ else
+ polarity = TYPEC_ORIENTATION_REVERSE;
+
+ typec_set_pwr_role(port, resp->role ? TYPEC_SOURCE : TYPEC_SINK);
+ typec_set_orientation(port, polarity);
+}
+
+static void cros_typec_set_port_params_v1(struct cros_typec_data *typec,
+ int port_num, struct ec_response_usb_pd_control_v1 *resp)
+{
+ struct typec_port *port = typec->ports[port_num]->port;
+ enum typec_orientation polarity;
+ bool pd_en;
+ int ret;
+
+ if (!(resp->enabled & PD_CTRL_RESP_ENABLED_CONNECTED))
+ polarity = TYPEC_ORIENTATION_NONE;
+ else if (!resp->polarity)
+ polarity = TYPEC_ORIENTATION_NORMAL;
+ else
+ polarity = TYPEC_ORIENTATION_REVERSE;
+ typec_set_orientation(port, polarity);
+ typec_set_data_role(port, resp->role & PD_CTRL_RESP_ROLE_DATA ?
+ TYPEC_HOST : TYPEC_DEVICE);
+ typec_set_pwr_role(port, resp->role & PD_CTRL_RESP_ROLE_POWER ?
+ TYPEC_SOURCE : TYPEC_SINK);
+ typec_set_vconn_role(port, resp->role & PD_CTRL_RESP_ROLE_VCONN ?
+ TYPEC_SOURCE : TYPEC_SINK);
+
+ /* Register/remove partners when a connect/disconnect occurs. */
+ if (resp->enabled & PD_CTRL_RESP_ENABLED_CONNECTED) {
+ if (typec->ports[port_num]->partner)
+ return;
+
+ pd_en = resp->enabled & PD_CTRL_RESP_ENABLED_PD_CAPABLE;
+ ret = cros_typec_add_partner(typec, port_num, pd_en);
+ if (ret)
+ dev_warn(typec->dev,
+ "Failed to register partner on port: %d\n",
+ port_num);
+ } else {
+ if (!typec->ports[port_num]->partner)
+ return;
+ cros_typec_remove_partner(typec, port_num);
+ }
+}
+
+static int cros_typec_get_mux_info(struct cros_typec_data *typec, int port_num,
+ struct ec_response_usb_pd_mux_info *resp)
+{
+ struct ec_params_usb_pd_mux_info req = {
+ .port = port_num,
+ };
+
+ return cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_MUX_INFO, &req,
+ sizeof(req), resp, sizeof(*resp));
+}
+
static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
{
struct ec_params_usb_pd_control req;
--
2.29.0.rc1.297.gfa9743e501-goog

2020-10-22 13:03:09

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 5/7] platform/chrome: cros_ec_typec: Introduce TYPEC_STATUS

Hi Prashant,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on chrome-platform-linux/for-next]
[also build test WARNING on linus/master v5.9 next-20201021]
[cannot apply to linux/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Prashant-Malani/platform-chrome-cros_ec_typec-Register-partner-PD-information/20201022-045552
base: https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git for-next
config: microblaze-allyesconfig (attached as .config)
compiler: microblaze-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/d95c360f8dc525bd78c299a987c1287867f766a2
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Prashant-Malani/platform-chrome-cros_ec_typec-Register-partner-PD-information/20201022-045552
git checkout d95c360f8dc525bd78c299a987c1287867f766a2
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=microblaze

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> drivers/platform/chrome/cros_ec_typec.c:698:5: warning: no previous prototype for 'cros_typec_cmds_supported' [-Wmissing-prototypes]
698 | int cros_typec_cmds_supported(struct cros_typec_data *typec)
| ^~~~~~~~~~~~~~~~~~~~~~~~~

vim +/cros_typec_cmds_supported +698 drivers/platform/chrome/cros_ec_typec.c

696
697 /* Check the EC feature flags to see if TYPEC_* commands are supported. */
> 698 int cros_typec_cmds_supported(struct cros_typec_data *typec)
699 {
700 struct ec_response_get_features resp = {};
701 int ret;
702
703 ret = cros_typec_ec_command(typec, 0, EC_CMD_GET_FEATURES, NULL, 0,
704 &resp, sizeof(resp));
705 if (ret < 0) {
706 dev_warn(typec->dev,
707 "Failed to get features, assuming typec commands unsupported.\n");
708 return 0;
709 }
710
711 return resp.flags[EC_FEATURE_TYPEC_CMD / 32] & EC_FEATURE_MASK_1(EC_FEATURE_TYPEC_CMD);
712 }
713

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (2.64 kB)
.config.gz (63.38 kB)
Download all attachments

2020-10-27 18:18:42

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 5/7] platform/chrome: cros_ec_typec: Introduce TYPEC_STATUS

Hi Prashant,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on chrome-platform-linux/for-next]
[also build test WARNING on linus/master v5.10-rc1 next-20201027]
[cannot apply to linux/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Prashant-Malani/platform-chrome-cros_ec_typec-Register-partner-PD-information/20201022-045552
base: https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git for-next
config: x86_64-randconfig-a011-20201027 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project f2c25c70791de95d2466e09b5b58fc37f6ccd7a4)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# https://github.com/0day-ci/linux/commit/d95c360f8dc525bd78c299a987c1287867f766a2
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Prashant-Malani/platform-chrome-cros_ec_typec-Register-partner-PD-information/20201022-045552
git checkout d95c360f8dc525bd78c299a987c1287867f766a2
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

drivers/platform/chrome/cros_ec_typec.c:692:3: warning: format specifies type 'unsigned char' but the argument has type 'unsigned int' [-Wformat]
typec->pd_ctrl_ver);
^~~~~~~~~~~~~~~~~~
include/linux/dev_printk.h:123:47: note: expanded from macro 'dev_dbg'
dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \
~~~ ^~~~~~~~~~~
>> drivers/platform/chrome/cros_ec_typec.c:698:5: warning: no previous prototype for function 'cros_typec_cmds_supported' [-Wmissing-prototypes]
int cros_typec_cmds_supported(struct cros_typec_data *typec)
^
drivers/platform/chrome/cros_ec_typec.c:698:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int cros_typec_cmds_supported(struct cros_typec_data *typec)
^
static
2 warnings generated.

vim +/cros_typec_cmds_supported +698 drivers/platform/chrome/cros_ec_typec.c

669
670 static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
671 {
672 struct ec_params_get_cmd_versions_v1 req_v1;
673 struct ec_response_get_cmd_versions resp;
674 int ret;
675
676 /* We're interested in the PD control command version. */
677 req_v1.cmd = EC_CMD_USB_PD_CONTROL;
678 ret = cros_typec_ec_command(typec, 1, EC_CMD_GET_CMD_VERSIONS,
679 &req_v1, sizeof(req_v1), &resp,
680 sizeof(resp));
681 if (ret < 0)
682 return ret;
683
684 if (resp.version_mask & EC_VER_MASK(2))
685 typec->pd_ctrl_ver = 2;
686 else if (resp.version_mask & EC_VER_MASK(1))
687 typec->pd_ctrl_ver = 1;
688 else
689 typec->pd_ctrl_ver = 0;
690
691 dev_dbg(typec->dev, "PD Control has version mask 0x%hhx\n",
> 692 typec->pd_ctrl_ver);
693
694 return 0;
695 }
696
697 /* Check the EC feature flags to see if TYPEC_* commands are supported. */
> 698 int cros_typec_cmds_supported(struct cros_typec_data *typec)
699 {
700 struct ec_response_get_features resp = {};
701 int ret;
702
703 ret = cros_typec_ec_command(typec, 0, EC_CMD_GET_FEATURES, NULL, 0,
704 &resp, sizeof(resp));
705 if (ret < 0) {
706 dev_warn(typec->dev,
707 "Failed to get features, assuming typec commands unsupported.\n");
708 return 0;
709 }
710
711 return resp.flags[EC_FEATURE_TYPEC_CMD / 32] & EC_FEATURE_MASK_1(EC_FEATURE_TYPEC_CMD);
712 }
713

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (4.39 kB)
.config.gz (30.98 kB)
Download all attachments

2020-10-28 09:53:42

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 5/7] platform/chrome: cros_ec_typec: Introduce TYPEC_STATUS

Hi Prashant,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on chrome-platform-linux/for-next]
[also build test WARNING on linus/master v5.10-rc1 next-20201027]
[cannot apply to linux/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Prashant-Malani/platform-chrome-cros_ec_typec-Register-partner-PD-information/20201022-045552
base: https://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git for-next
config: x86_64-randconfig-s022-20201027 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce:
# apt-get install sparse
# sparse version: v0.6.3-56-gc09e8239-dirty
# https://github.com/0day-ci/linux/commit/d95c360f8dc525bd78c299a987c1287867f766a2
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Prashant-Malani/platform-chrome-cros_ec_typec-Register-partner-PD-information/20201022-045552
git checkout d95c360f8dc525bd78c299a987c1287867f766a2
# save the attached .config to linux build tree
make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>


"sparse warnings: (new ones prefixed by >>)"
>> drivers/platform/chrome/cros_ec_typec.c:698:5: sparse: sparse: symbol 'cros_typec_cmds_supported' was not declared. Should it be static?

Please review and possibly fold the followup patch.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (1.79 kB)
.config.gz (35.62 kB)
Download all attachments

2020-10-28 09:54:47

by kernel test robot

[permalink] [raw]
Subject: [RFC PATCH] platform/chrome: cros_ec_typec: cros_typec_cmds_supported() can be static


Signed-off-by: kernel test robot <[email protected]>
---
cros_ec_typec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 98d22720b365fe..f578d0bfbe5a75 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -695,7 +695,7 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
}

/* Check the EC feature flags to see if TYPEC_* commands are supported. */
-int cros_typec_cmds_supported(struct cros_typec_data *typec)
+static int cros_typec_cmds_supported(struct cros_typec_data *typec)
{
struct ec_response_get_features resp = {};
int ret;

2020-10-29 08:46:34

by Prashant Malani

[permalink] [raw]
Subject: Re: [PATCH 6/7] platform/chrome: cros_ec_typec: Parse partner PD ID VDOs

Hi Heikki,

Thanks a lot for reviewing the patch!

On Wed, Oct 28, 2020 at 03:16:33PM +0200, Heikki Krogerus wrote:
> > +
> > + /* Copy the remaining identity VDOs till a maximum of 6. */
> > + for (i = 3; i < sop_disc->identity_count && i < VDO_MAX_OBJECTS; i++)
> > + port->p_identity.vdo[i - 3] = sop_disc->discovery_vdo[i];
>
> Why do you need to put the product type VDOs in reverse order?

The Chrome EC returns all the Identity VDOs as an array of 6 VDOs (the
discovery_vdo[] array). The first three entries are assigned to the
pd_identity.{id_header,cert_stat,product} members.

This for loop assigns the next three discovery_vdo entries (i.e indices
3-5) to pd_identity.vdo[0-2] respectively.

The "i-3" is because discovery_vdo[3] corresponds to pd_identity.vdo[0]
and so on.

Does that help to clarify the for loop?

Best regards,

Prashant

2020-10-29 22:16:50

by Prashant Malani

[permalink] [raw]
Subject: Re: [PATCH 7/7] platform/chrome: cros_ec_typec: Register partner altmodes

Hi Heikki,

Thank you for reviewing the patch!

On Wed, Oct 28, 2020 at 03:17:32PM +0200, Heikki Krogerus wrote:
> Hi,
>
> On Wed, Oct 21, 2020 at 01:53:16PM -0700, Prashant Malani wrote:
> > +static void cros_typec_unregister_altmodes(struct cros_typec_data *typec, int port_num)
> > +{
> > + struct cros_typec_port *port = typec->ports[port_num];
> > + struct cros_typec_altmode_node *node;
> > +
> > + while (!list_empty(&port->partner_mode_list)) {
> > + node = list_first_entry(&port->partner_mode_list, struct cros_typec_altmode_node,
> > + list);
>
> ...
> struct cros_typec_altmode_node *node, *tmp;
>
> list_for_each_entry_safe(node, tmp, &port->partner_mode_list, list) {
>

Nice; I will make this update in v2. Thanks!

Best regards,

-Prashant

2020-10-30 13:27:08

by Heikki Krogerus

[permalink] [raw]
Subject: Re: [PATCH 6/7] platform/chrome: cros_ec_typec: Parse partner PD ID VDOs

On Wed, Oct 28, 2020 at 01:11:35PM -0700, Prashant Malani wrote:
> Hi Heikki,
>
> Thanks a lot for reviewing the patch!
>
> On Wed, Oct 28, 2020 at 03:16:33PM +0200, Heikki Krogerus wrote:
> > > +
> > > + /* Copy the remaining identity VDOs till a maximum of 6. */
> > > + for (i = 3; i < sop_disc->identity_count && i < VDO_MAX_OBJECTS; i++)
> > > + port->p_identity.vdo[i - 3] = sop_disc->discovery_vdo[i];
> >
> > Why do you need to put the product type VDOs in reverse order?
>
> The Chrome EC returns all the Identity VDOs as an array of 6 VDOs (the
> discovery_vdo[] array). The first three entries are assigned to the
> pd_identity.{id_header,cert_stat,product} members.
>
> This for loop assigns the next three discovery_vdo entries (i.e indices
> 3-5) to pd_identity.vdo[0-2] respectively.
>
> The "i-3" is because discovery_vdo[3] corresponds to pd_identity.vdo[0]
> and so on.
>
> Does that help to clarify the for loop?

Yes. Thanks.

Br,

--
heikki