Commit 410457b9 authored by Prashant Malani's avatar Prashant Malani Committed by Enric Balletbo i Serra

platform/chrome: cros_ec_typec: Support DP alt mode

Handle Chrome EC mux events to configure on-board muxes correctly while
entering DP alternate mode. Since we don't surface SVID and VDO
information regarding the DP alternate mode, configure the Type C
muxes directly from the port driver. Later, when mode discovery
information is correctly surfaced to the driver, we can register the DP
alternate mode driver and let it handle the mux configuration.

Also, modify the struct_typec_state state management to account for the
addition of DP alternate mode.
Signed-off-by: default avatarPrashant Malani <pmalani@chromium.org>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: default avatarEnric Balletbo i Serra <enric.balletbo@collabora.com>
parent 7e7def15
...@@ -15,11 +15,18 @@ ...@@ -15,11 +15,18 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/usb/typec.h> #include <linux/usb/typec.h>
#include <linux/usb/typec_altmode.h> #include <linux/usb/typec_altmode.h>
#include <linux/usb/typec_dp.h>
#include <linux/usb/typec_mux.h> #include <linux/usb/typec_mux.h>
#include <linux/usb/role.h> #include <linux/usb/role.h>
#define DRV_NAME "cros-ec-typec" #define DRV_NAME "cros-ec-typec"
/* Supported alt modes. */
enum {
CROS_EC_ALTMODE_DP = 0,
CROS_EC_ALTMODE_MAX,
};
/* Per port data. */ /* Per port data. */
struct cros_typec_port { struct cros_typec_port {
struct typec_port *port; struct typec_port *port;
...@@ -35,6 +42,9 @@ struct cros_typec_port { ...@@ -35,6 +42,9 @@ struct cros_typec_port {
/* Variables keeping track of switch state. */ /* Variables keeping track of switch state. */
struct typec_mux_state state; struct typec_mux_state state;
uint8_t mux_flags; uint8_t mux_flags;
/* Port alt modes. */
struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX];
}; };
/* Platform-specific data for the Chrome OS EC Type C controller. */ /* Platform-specific data for the Chrome OS EC Type C controller. */
...@@ -142,6 +152,24 @@ static void cros_unregister_ports(struct cros_typec_data *typec) ...@@ -142,6 +152,24 @@ static void cros_unregister_ports(struct cros_typec_data *typec)
} }
} }
/*
* Fake the alt mode structs until we actually start registering Type C port
* and partner alt modes.
*/
static void cros_typec_register_port_altmodes(struct cros_typec_data *typec,
int port_num)
{
struct cros_typec_port *port = typec->ports[port_num];
/* All PD capable CrOS devices are assumed to support DP altmode. */
port->p_altmode[CROS_EC_ALTMODE_DP].svid = USB_TYPEC_DP_SID;
port->p_altmode[CROS_EC_ALTMODE_DP].mode = USB_TYPEC_DP_MODE;
port->state.alt = NULL;
port->state.mode = TYPEC_STATE_USB;
port->state.data = NULL;
}
static int cros_typec_init_ports(struct cros_typec_data *typec) static int cros_typec_init_ports(struct cros_typec_data *typec)
{ {
struct device *dev = typec->dev; struct device *dev = typec->dev;
...@@ -205,6 +233,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec) ...@@ -205,6 +233,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
if (ret) if (ret)
dev_dbg(dev, "No switch control for port %d\n", dev_dbg(dev, "No switch control for port %d\n",
port_num); port_num);
cros_typec_register_port_altmodes(typec, port_num);
} }
return 0; return 0;
...@@ -361,8 +391,46 @@ static int cros_typec_usb_safe_state(struct cros_typec_port *port) ...@@ -361,8 +391,46 @@ static int cros_typec_usb_safe_state(struct cros_typec_port *port)
return typec_mux_set(port->mux, &port->state); return typec_mux_set(port->mux, &port->state);
} }
/* Spoof the VDOs that were likely communicated by the partner. */
static int cros_typec_enable_dp(struct cros_typec_data *typec,
int port_num,
struct ec_response_usb_pd_control_v2 *pd_ctrl)
{
struct cros_typec_port *port = typec->ports[port_num];
struct typec_displayport_data dp_data;
int ret;
if (typec->pd_ctrl_ver < 2) {
dev_err(typec->dev,
"PD_CTRL version too old: %d\n", typec->pd_ctrl_ver);
return -ENOTSUPP;
}
/* Status VDO. */
dp_data.status = DP_STATUS_ENABLED;
if (port->mux_flags & USB_PD_MUX_HPD_IRQ)
dp_data.status |= DP_STATUS_IRQ_HPD;
if (port->mux_flags & USB_PD_MUX_HPD_LVL)
dp_data.status |= DP_STATUS_HPD_STATE;
/* Configuration VDO. */
dp_data.conf = DP_CONF_SET_PIN_ASSIGN(pd_ctrl->dp_mode);
if (!port->state.alt) {
port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_DP];
ret = cros_typec_usb_safe_state(port);
if (ret)
return ret;
}
port->state.data = &dp_data;
port->state.mode = TYPEC_MODAL_STATE(ffs(pd_ctrl->dp_mode));
return typec_mux_set(port->mux, &port->state);
}
int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
uint8_t mux_flags) uint8_t mux_flags,
struct ec_response_usb_pd_control_v2 *pd_ctrl)
{ {
struct cros_typec_port *port = typec->ports[port_num]; struct cros_typec_port *port = typec->ports[port_num];
enum typec_orientation orientation; enum typec_orientation orientation;
...@@ -380,14 +448,15 @@ int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, ...@@ -380,14 +448,15 @@ int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
if (ret) if (ret)
return ret; return ret;
if (mux_flags & USB_PD_MUX_DP_ENABLED) {
ret = cros_typec_enable_dp(typec, port_num, pd_ctrl);
} else if (mux_flags & USB_PD_MUX_SAFE_MODE) {
ret = cros_typec_usb_safe_state(port);
} else if (mux_flags & USB_PD_MUX_USB_ENABLED) {
port->state.alt = NULL; port->state.alt = NULL;
port->state.mode = TYPEC_STATE_USB; port->state.mode = TYPEC_STATE_USB;
if (mux_flags & USB_PD_MUX_SAFE_MODE)
ret = cros_typec_usb_safe_state(port);
else if (mux_flags & USB_PD_MUX_USB_ENABLED)
ret = typec_mux_set(port->mux, &port->state); ret = typec_mux_set(port->mux, &port->state);
else { } else {
dev_info(typec->dev, dev_info(typec->dev,
"Unsupported mode requested, mux flags: %x\n", "Unsupported mode requested, mux flags: %x\n",
mux_flags); mux_flags);
...@@ -400,7 +469,7 @@ int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, ...@@ -400,7 +469,7 @@ int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
{ {
struct ec_params_usb_pd_control req; struct ec_params_usb_pd_control req;
struct ec_response_usb_pd_control_v1 resp; struct ec_response_usb_pd_control_v2 resp;
struct ec_response_usb_pd_mux_info mux_resp; struct ec_response_usb_pd_mux_info mux_resp;
int ret; int ret;
...@@ -427,7 +496,8 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) ...@@ -427,7 +496,8 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
dev_dbg(typec->dev, "State %d: %s\n", port_num, resp.state); dev_dbg(typec->dev, "State %d: %s\n", port_num, resp.state);
if (typec->pd_ctrl_ver != 0) if (typec->pd_ctrl_ver != 0)
cros_typec_set_port_params_v1(typec, port_num, &resp); cros_typec_set_port_params_v1(typec, port_num,
(struct ec_response_usb_pd_control_v1 *)&resp);
else else
cros_typec_set_port_params_v0(typec, port_num, cros_typec_set_port_params_v0(typec, port_num,
(struct ec_response_usb_pd_control *) &resp); (struct ec_response_usb_pd_control *) &resp);
...@@ -446,7 +516,7 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) ...@@ -446,7 +516,7 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
return 0; return 0;
typec->ports[port_num]->mux_flags = mux_resp.flags; typec->ports[port_num]->mux_flags = mux_resp.flags;
ret = cros_typec_configure_mux(typec, port_num, mux_resp.flags); ret = cros_typec_configure_mux(typec, port_num, mux_resp.flags, &resp);
if (ret) if (ret)
dev_warn(typec->dev, "Configure muxes failed, err = %d\n", ret); dev_warn(typec->dev, "Configure muxes failed, err = %d\n", ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment