summaryrefslogtreecommitdiff
path: root/driver/usb_mux/usb_mux.c
diff options
context:
space:
mode:
authorDenis Brockus <dbrockus@chromium.org>2020-02-21 14:21:05 -0700
committerCommit Bot <commit-bot@chromium.org>2020-02-28 22:47:11 +0000
commit9c194fd057558a1dfadee419e92aca31953a86fc (patch)
tree001ae7c162a4152312a180574ae58e19a3763eb8 /driver/usb_mux/usb_mux.c
parentab35b456ad8c52f336ea793b17155cfc796c4e44 (diff)
downloadchrome-ec-9c194fd057558a1dfadee419e92aca31953a86fc.tar.gz
usb_mux: retimer: mux as chained mux and retimer
This makes retimers appear as generic muxes. By allowing a chain of muxes they can be stacked up to the new configurations that zork requires and will continue to work as they did before on configurations that only have a single mux. The code used to have two different arrays, 1) muxes and 2) retimers. On one of the zork configurations the processor MUX stopped being the primary mux and the retimer took its place. In a different configuration of that same platform it left the primary and secondary alone but the mux_set FLIP operation had to be ignored. Since the same interfaces needed to be available for both it stopped making sense to have two different structures and two different methods of handling them. This consolodates the two into one. The platforms that do not have retimers, this change will not make any difference. For platforms like zork, it will remove the retimers and make them chained muxes. So testing on trembyle makes sense to verify, BUG=b:147593660 BRANCH=none TEST=verify USB still works on trembyle Change-Id: I286cf1e302f9bd3dd7e81098ec08514a2a009fe3 Signed-off-by: Denis Brockus <dbrockus@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2066794 Commit-Queue: Jett Rink <jettrink@chromium.org> Reviewed-by: Edward Hill <ecgh@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'driver/usb_mux/usb_mux.c')
-rw-r--r--driver/usb_mux/usb_mux.c156
1 files changed, 81 insertions, 75 deletions
diff --git a/driver/usb_mux/usb_mux.c b/driver/usb_mux/usb_mux.c
index 5bf057ed91..3d629a6ab0 100644
--- a/driver/usb_mux/usb_mux.c
+++ b/driver/usb_mux/usb_mux.c
@@ -32,100 +32,107 @@ enum mux_config_type {
USB_MUX_GET_MODE,
};
-/* Configure the retimer */
-static int configure_retimer(int port, enum mux_config_type config,
- mux_state_t mux_state)
+/* Configure the MUX */
+static int configure_mux(int port,
+ enum mux_config_type config,
+ mux_state_t *mux_state)
{
- int res = 0;
+ int rv = EC_SUCCESS;
+ const struct usb_mux *mux_ptr;
+
+ if (config == USB_MUX_SET_MODE ||
+ config == USB_MUX_GET_MODE) {
+ if (mux_state == NULL)
+ return EC_ERROR_INVAL;
- if (IS_ENABLED(CONFIG_USBC_MUX_RETIMER)) {
- const struct usb_retimer *retimer = &usb_retimers[port];
+ if (config == USB_MUX_GET_MODE)
+ *mux_state = USB_PD_MUX_NONE;
+ }
- if (!retimer->driver)
- return 0;
+ /*
+ * a MUX for a particular port can be a linked list chain of
+ * MUXes. So when we change one, we traverse the whole list
+ * to make sure they are all updated appropriately.
+ */
+ for (mux_ptr = &usb_muxes[port];
+ rv == EC_SUCCESS && mux_ptr != NULL;
+ mux_ptr = mux_ptr->next_mux) {
+ mux_state_t lcl_state;
+ const struct usb_mux_driver *drv = mux_ptr->driver;
switch (config) {
case USB_MUX_INIT:
- if (retimer->driver->init)
- res = retimer->driver->init(port);
+ if (drv && drv->init) {
+ rv = drv->init(mux_ptr);
+ if (rv)
+ break;
+ }
+
+ /* Apply board specific initialization */
+ if (mux_ptr->board_init)
+ rv = mux_ptr->board_init(mux_ptr);
+
break;
+
case USB_MUX_LOW_POWER:
- if (retimer->driver->enter_low_power_mode)
- res = retimer->driver->enter_low_power_mode(
- port);
+ if (drv && drv->enter_low_power_mode)
+ rv = drv->enter_low_power_mode(mux_ptr);
+
break;
+
case USB_MUX_SET_MODE:
- if (retimer->driver->set)
- res = retimer->driver->set(port, mux_state);
- break;
- default:
- break;
- }
- }
+ lcl_state = *mux_state;
- return res;
-}
+ if (mux_ptr->flags & USB_MUX_FLAG_SET_WITHOUT_FLIP)
+ lcl_state &= ~USB_PD_MUX_POLARITY_INVERTED;
-/* Configure the MUX */
-static int configure_mux(int port, enum mux_config_type config,
- mux_state_t *mux_state)
-{
- const struct usb_mux *mux = &usb_muxes[port];
- int res;
+ if (drv && drv->set) {
+ rv = drv->set(mux_ptr, lcl_state);
+ if (rv)
+ break;
+ }
- switch (config) {
- case USB_MUX_INIT:
- res = mux->driver->init(port);
- if (res)
- break;
+ /* Apply board specific setting */
+ if (mux_ptr->board_set)
+ rv = mux_ptr->board_set(mux_ptr, lcl_state);
- res = configure_retimer(port, config, USB_PD_MUX_NONE);
- if (res)
break;
- /* Apply board specific initialization */
- if (mux->board_init)
- res = mux->board_init(port);
-
- break;
- case USB_MUX_LOW_POWER:
- if (mux->driver->enter_low_power_mode) {
- res = mux->driver->enter_low_power_mode(port);
- if (res)
- break;
- }
- res = configure_retimer(port, config, USB_PD_MUX_NONE);
- break;
- case USB_MUX_SET_MODE:
- res = mux->driver->set(port, *mux_state);
- if (res)
+ case USB_MUX_GET_MODE:
+ /*
+ * This is doing a GET_CC on all of the MUXes in the
+ * chain and ORing them together. This will make sure
+ * if one of the MUX values has FLIP turned off that
+ * we will end up with the correct value in the end.
+ */
+ if (drv && drv->get) {
+ rv = drv->get(mux_ptr, &lcl_state);
+ if (rv)
+ break;
+ *mux_state |= lcl_state;
+ }
break;
- res = configure_retimer(port, config, *mux_state);
- break;
- case USB_MUX_GET_MODE:
- res = mux->driver->get(port, mux_state);
- break;
+ }
}
- if (res)
- CPRINTS("mux config:%d, port:%d, res:%d", config, port, res);
+ if (rv)
+ CPRINTS("mux config:%d, port:%d, rv:%d",
+ config, port, rv);
- return res;
+ return rv;
}
static void enter_low_power_mode(int port)
{
- mux_state_t mux_state = USB_PD_MUX_NONE;
-
/*
- * Set LPM flag regardless of method presence or method failure. We want
- * know know that we tried to put the device in low power mode so we can
- * re-initialize the device on the next access.
+ * Set LPM flag regardless of method presence or method failure. We
+ * want know know that we tried to put the device in low power mode
+ * so we can re-initialize the device on the next access.
*/
flags[port] |= USB_MUX_FLAG_IN_LPM;
/* Apply any low power customization if present */
- configure_mux(port, USB_MUX_LOW_POWER, &mux_state);
+ configure_mux(port, USB_MUX_LOW_POWER, NULL);
}
static inline void exit_low_power_mode(int port)
@@ -137,11 +144,9 @@ static inline void exit_low_power_mode(int port)
void usb_mux_init(int port)
{
- mux_state_t mux_state = USB_PD_MUX_NONE;
-
ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT);
- configure_mux(port, USB_MUX_INIT, &mux_state);
+ configure_mux(port, USB_MUX_INIT, NULL);
/* Device is always out of LPM after initialization. */
flags[port] &= ~USB_MUX_FLAG_IN_LPM;
@@ -225,16 +230,17 @@ void usb_mux_flip(int port)
void usb_mux_hpd_update(int port, int hpd_lvl, int hpd_irq)
{
- const struct usb_mux *mux = &usb_muxes[port];
mux_state_t mux_state;
+ const struct usb_mux *mux_ptr = &usb_muxes[port];
- if (mux->hpd_update)
- mux->hpd_update(port, hpd_lvl, hpd_irq);
+ for (; mux_ptr; mux_ptr = mux_ptr->next_mux)
+ if (mux_ptr->hpd_update)
+ mux_ptr->hpd_update(mux_ptr, hpd_lvl, hpd_irq);
if (!configure_mux(port, USB_MUX_GET_MODE, &mux_state)) {
mux_state |= (hpd_lvl ? USB_PD_MUX_HPD_LVL : 0) |
- (hpd_irq ? USB_PD_MUX_HPD_IRQ : 0);
- configure_retimer(port, USB_MUX_SET_MODE, mux_state);
+ (hpd_irq ? USB_PD_MUX_HPD_IRQ : 0);
+ configure_mux(port, USB_MUX_SET_MODE, &mux_state);
}
}
@@ -297,7 +303,7 @@ static enum ec_status hc_usb_pd_mux_info(struct host_cmd_handler_args *args)
const struct ec_params_usb_pd_mux_info *p = args->params;
struct ec_response_usb_pd_mux_info *r = args->response;
int port = p->port;
- const struct usb_mux *mux = &usb_muxes[port];
+ const struct usb_mux *me = &usb_muxes[port];
mux_state_t mux_state;
if (port >= board_get_usb_pd_port_count())
@@ -311,7 +317,7 @@ static enum ec_status hc_usb_pd_mux_info(struct host_cmd_handler_args *args)
/* Clear HPD IRQ event since we're about to inform host of it. */
if (IS_ENABLED(CONFIG_USB_MUX_VIRTUAL) &&
(r->flags & USB_PD_MUX_HPD_IRQ) &&
- (mux->hpd_update == &virtual_hpd_update)) {
+ (me->hpd_update == &virtual_hpd_update)) {
usb_mux_hpd_update(port, r->flags & USB_PD_MUX_HPD_LVL, 0);
}