Skip to content

Commit

Permalink
usb: typec: intel_pmc_mux: Support for device role (UFP)
Browse files Browse the repository at this point in the history
This adds support for device data role, and data role
swapping. The driver no longer relies on the cached role, as
it may not be valid (for example after bootup). Instead, the
role is always checked by readding the port status from IOM.

Note. After this, the orientation is always only cached, so
the driver does not support scenario where the role is set
before orientation. It means the typec drivers must always
set the orientation first before role.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Rajmohan Mani <rajmohan.mani@intel.com>
Reviewed-by: Utkarsh Patel <utkarsh.h.patel@intel.com>
Tested-by: Utkarsh Patel <utkarsh.h.patel@intel.com>
Link: https://lore.kernel.org/r/20200907142428.35838-3-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Heikki Krogerus authored and Greg Kroah-Hartman committed Sep 7, 2020
1 parent 43d596e commit a5a6d27
Showing 1 changed file with 35 additions and 33 deletions.
68 changes: 35 additions & 33 deletions drivers/usb/typec/mux/intel_pmc_mux.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,6 @@ pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state)
return pmc_usb_mux_dp_hpd(port, state->data);
}

if (data->status & DP_STATUS_IRQ_HPD)
return pmc_usb_mux_dp_hpd(port, state->data);

req.usage = PMC_USB_ALT_MODE;
req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
req.mode_type = PMC_USB_MODE_TYPE_DP << PMC_USB_MODE_TYPE_SHIFT;
Expand Down Expand Up @@ -345,39 +342,52 @@ static int pmc_usb_mux_safe_state(struct pmc_usb_port *port)
return pmc_usb_command(port, &msg, sizeof(msg));
}

static int pmc_usb_connect(struct pmc_usb_port *port)
static int pmc_usb_disconnect(struct pmc_usb_port *port)
{
struct typec_displayport_data data = { };
u8 msg[2];

if (port->iom_status & IOM_PORT_STATUS_CONNECTED)
if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED))
return 0;

msg[0] = PMC_USB_CONNECT;
/* Clear DisplayPort HPD if it's still asserted. */
if (IOM_PORT_HPD_ASSERTED(port->iom_status))
pmc_usb_mux_dp_hpd(port, &data);

msg[0] = PMC_USB_DISCONNECT;
msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;

msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT;
msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT;
msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT;

return pmc_usb_command(port, msg, sizeof(msg));
}

static int pmc_usb_disconnect(struct pmc_usb_port *port)
static int pmc_usb_connect(struct pmc_usb_port *port, enum usb_role role)
{
struct typec_displayport_data data = { };
u8 ufp = role == USB_ROLE_DEVICE ? 1 : 0;
u8 msg[2];
int ret;

if (!(port->iom_status & IOM_PORT_STATUS_CONNECTED))
return 0;
if (port->orientation == TYPEC_ORIENTATION_NONE)
return -EINVAL;

/* Clear DisplayPort HPD if it's still asserted. */
if (IOM_PORT_HPD_ASSERTED(port->iom_status))
pmc_usb_mux_dp_hpd(port, &data);
if (port->iom_status & IOM_PORT_STATUS_CONNECTED) {
if (port->role == role || port->role == USB_ROLE_NONE)
return 0;

msg[0] = PMC_USB_DISCONNECT;
/* Role swap */
ret = pmc_usb_disconnect(port);
if (ret)
return ret;
}

msg[0] = PMC_USB_CONNECT;
msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;

msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT;
msg[1] |= ufp << PMC_USB_MSG_UFP_SHIFT;
msg[1] |= hsl_orientation(port) << PMC_USB_MSG_ORI_HSL_SHIFT;
msg[1] |= sbu_orientation(port) << PMC_USB_MSG_ORI_AUX_SHIFT;

return pmc_usb_command(port, msg, sizeof(msg));
}
Expand All @@ -395,7 +405,7 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
if (state->mode == TYPEC_STATE_SAFE)
return pmc_usb_mux_safe_state(port);
if (state->mode == TYPEC_STATE_USB)
return pmc_usb_connect(port);
return pmc_usb_connect(port, port->role);

if (state->alt) {
switch (state->alt->svid) {
Expand All @@ -410,7 +420,7 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
/* REVISIT: Try with usb3_port set to 0? */
break;
case TYPEC_MODE_USB3:
return pmc_usb_connect(port);
return pmc_usb_connect(port, port->role);
case TYPEC_MODE_USB4:
return pmc_usb_mux_usb4(port, state);
}
Expand All @@ -428,32 +438,24 @@ static int pmc_usb_set_orientation(struct typec_switch *sw,

port->orientation = orientation;

if (port->role) {
if (orientation == TYPEC_ORIENTATION_NONE)
return pmc_usb_disconnect(port);
else
return pmc_usb_connect(port);
}

return 0;
}

static int pmc_usb_set_role(struct usb_role_switch *sw, enum usb_role role)
{
struct pmc_usb_port *port = usb_role_switch_get_drvdata(sw);
int ret;

update_port_status(port);

port->role = role;
if (role == USB_ROLE_NONE)
ret = pmc_usb_disconnect(port);
else
ret = pmc_usb_connect(port, role);

if (port->orientation) {
if (role == USB_ROLE_NONE)
return pmc_usb_disconnect(port);
else
return pmc_usb_connect(port);
}
port->role = role;

return 0;
return ret;
}

static int pmc_usb_register_port(struct pmc_usb *pmc, int index,
Expand Down

0 comments on commit a5a6d27

Please sign in to comment.