Skip to content

Commit 410457b

Browse files
Prashant MalaniEnric Balletbo i Serra
authored andcommitted
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: Prashant Malani <[email protected]> Reviewed-by: Heikki Krogerus <[email protected]> Signed-off-by: Enric Balletbo i Serra <[email protected]>
1 parent 7e7def1 commit 410457b

File tree

1 file changed

+80
-10
lines changed

1 file changed

+80
-10
lines changed

drivers/platform/chrome/cros_ec_typec.c

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@
1515
#include <linux/platform_device.h>
1616
#include <linux/usb/typec.h>
1717
#include <linux/usb/typec_altmode.h>
18+
#include <linux/usb/typec_dp.h>
1819
#include <linux/usb/typec_mux.h>
1920
#include <linux/usb/role.h>
2021

2122
#define DRV_NAME "cros-ec-typec"
2223

24+
/* Supported alt modes. */
25+
enum {
26+
CROS_EC_ALTMODE_DP = 0,
27+
CROS_EC_ALTMODE_MAX,
28+
};
29+
2330
/* Per port data. */
2431
struct cros_typec_port {
2532
struct typec_port *port;
@@ -35,6 +42,9 @@ struct cros_typec_port {
3542
/* Variables keeping track of switch state. */
3643
struct typec_mux_state state;
3744
uint8_t mux_flags;
45+
46+
/* Port alt modes. */
47+
struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX];
3848
};
3949

4050
/* 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)
142152
}
143153
}
144154

155+
/*
156+
* Fake the alt mode structs until we actually start registering Type C port
157+
* and partner alt modes.
158+
*/
159+
static void cros_typec_register_port_altmodes(struct cros_typec_data *typec,
160+
int port_num)
161+
{
162+
struct cros_typec_port *port = typec->ports[port_num];
163+
164+
/* All PD capable CrOS devices are assumed to support DP altmode. */
165+
port->p_altmode[CROS_EC_ALTMODE_DP].svid = USB_TYPEC_DP_SID;
166+
port->p_altmode[CROS_EC_ALTMODE_DP].mode = USB_TYPEC_DP_MODE;
167+
168+
port->state.alt = NULL;
169+
port->state.mode = TYPEC_STATE_USB;
170+
port->state.data = NULL;
171+
}
172+
145173
static int cros_typec_init_ports(struct cros_typec_data *typec)
146174
{
147175
struct device *dev = typec->dev;
@@ -205,6 +233,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
205233
if (ret)
206234
dev_dbg(dev, "No switch control for port %d\n",
207235
port_num);
236+
237+
cros_typec_register_port_altmodes(typec, port_num);
208238
}
209239

210240
return 0;
@@ -361,8 +391,46 @@ static int cros_typec_usb_safe_state(struct cros_typec_port *port)
361391
return typec_mux_set(port->mux, &port->state);
362392
}
363393

394+
/* Spoof the VDOs that were likely communicated by the partner. */
395+
static int cros_typec_enable_dp(struct cros_typec_data *typec,
396+
int port_num,
397+
struct ec_response_usb_pd_control_v2 *pd_ctrl)
398+
{
399+
struct cros_typec_port *port = typec->ports[port_num];
400+
struct typec_displayport_data dp_data;
401+
int ret;
402+
403+
if (typec->pd_ctrl_ver < 2) {
404+
dev_err(typec->dev,
405+
"PD_CTRL version too old: %d\n", typec->pd_ctrl_ver);
406+
return -ENOTSUPP;
407+
}
408+
409+
/* Status VDO. */
410+
dp_data.status = DP_STATUS_ENABLED;
411+
if (port->mux_flags & USB_PD_MUX_HPD_IRQ)
412+
dp_data.status |= DP_STATUS_IRQ_HPD;
413+
if (port->mux_flags & USB_PD_MUX_HPD_LVL)
414+
dp_data.status |= DP_STATUS_HPD_STATE;
415+
416+
/* Configuration VDO. */
417+
dp_data.conf = DP_CONF_SET_PIN_ASSIGN(pd_ctrl->dp_mode);
418+
if (!port->state.alt) {
419+
port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_DP];
420+
ret = cros_typec_usb_safe_state(port);
421+
if (ret)
422+
return ret;
423+
}
424+
425+
port->state.data = &dp_data;
426+
port->state.mode = TYPEC_MODAL_STATE(ffs(pd_ctrl->dp_mode));
427+
428+
return typec_mux_set(port->mux, &port->state);
429+
}
430+
364431
int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
365-
uint8_t mux_flags)
432+
uint8_t mux_flags,
433+
struct ec_response_usb_pd_control_v2 *pd_ctrl)
366434
{
367435
struct cros_typec_port *port = typec->ports[port_num];
368436
enum typec_orientation orientation;
@@ -380,14 +448,15 @@ int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
380448
if (ret)
381449
return ret;
382450

383-
port->state.alt = NULL;
384-
port->state.mode = TYPEC_STATE_USB;
385-
386-
if (mux_flags & USB_PD_MUX_SAFE_MODE)
451+
if (mux_flags & USB_PD_MUX_DP_ENABLED) {
452+
ret = cros_typec_enable_dp(typec, port_num, pd_ctrl);
453+
} else if (mux_flags & USB_PD_MUX_SAFE_MODE) {
387454
ret = cros_typec_usb_safe_state(port);
388-
else if (mux_flags & USB_PD_MUX_USB_ENABLED)
455+
} else if (mux_flags & USB_PD_MUX_USB_ENABLED) {
456+
port->state.alt = NULL;
457+
port->state.mode = TYPEC_STATE_USB;
389458
ret = typec_mux_set(port->mux, &port->state);
390-
else {
459+
} else {
391460
dev_info(typec->dev,
392461
"Unsupported mode requested, mux flags: %x\n",
393462
mux_flags);
@@ -400,7 +469,7 @@ int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
400469
static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
401470
{
402471
struct ec_params_usb_pd_control req;
403-
struct ec_response_usb_pd_control_v1 resp;
472+
struct ec_response_usb_pd_control_v2 resp;
404473
struct ec_response_usb_pd_mux_info mux_resp;
405474
int ret;
406475

@@ -427,7 +496,8 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
427496
dev_dbg(typec->dev, "State %d: %s\n", port_num, resp.state);
428497

429498
if (typec->pd_ctrl_ver != 0)
430-
cros_typec_set_port_params_v1(typec, port_num, &resp);
499+
cros_typec_set_port_params_v1(typec, port_num,
500+
(struct ec_response_usb_pd_control_v1 *)&resp);
431501
else
432502
cros_typec_set_port_params_v0(typec, port_num,
433503
(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)
446516
return 0;
447517

448518
typec->ports[port_num]->mux_flags = mux_resp.flags;
449-
ret = cros_typec_configure_mux(typec, port_num, mux_resp.flags);
519+
ret = cros_typec_configure_mux(typec, port_num, mux_resp.flags, &resp);
450520
if (ret)
451521
dev_warn(typec->dev, "Configure muxes failed, err = %d\n", ret);
452522

0 commit comments

Comments
 (0)