diff options
Diffstat (limited to 'driver/usb_mux/amd_fp6.c')
-rw-r--r-- | driver/usb_mux/amd_fp6.c | 233 |
1 files changed, 0 insertions, 233 deletions
diff --git a/driver/usb_mux/amd_fp6.c b/driver/usb_mux/amd_fp6.c deleted file mode 100644 index b2d5ae1fb4..0000000000 --- a/driver/usb_mux/amd_fp6.c +++ /dev/null @@ -1,233 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * AMD FP6 USB/DP Mux. - */ - -#include "amd_fp6.h" -#include "chipset.h" -#include "common.h" -#include "hooks.h" -#include "i2c.h" -#include "queue.h" -#include "timer.h" -#include "usb_mux.h" - -#define CPRINTSUSB(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTFUSB(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -/* - * The recommendation from "3.3.2 Command Timeout" is 250ms, - * however empirical testing found that a 100ms timeout is sufficient. - */ -#define WRITE_CMD_TIMEOUT_MS 100 - -/* Command retry interval */ -#define CMD_RETRY_INTERVAL_MS 1000 - -/* - * Local data structure for saving mux state so it can be restored after - * an AP reset. - */ -static struct { - const struct usb_mux *mux; - uint8_t val; - bool write_pending; -} saved_mux_state[USBC_PORT_COUNT]; - -static int amd_fp6_mux_port0_read(const struct usb_mux *me, uint8_t *val) -{ - uint8_t payload[3] = { 0 }; - bool mux_ready; - - RETURN_ERROR(i2c_xfer(me->i2c_port, me->i2c_addr_flags, NULL, 0, - payload, 3)); - - /* - * payload[0]: Status/ID - * payload[1]: Port 0 Control/Status - * payload[2]: Port 1 Control/Status (unused on FP6) - */ - mux_ready = !!((payload[0] >> AMD_FP6_MUX_PD_STATUS_OFFSET) - & AMD_FP6_MUX_PD_STATUS_READY); - - if (!mux_ready) - return EC_ERROR_BUSY; - *val = payload[1]; - - return EC_SUCCESS; -} - -static int amd_fp6_mux_port0_write(const struct usb_mux *me, uint8_t write_val) -{ - uint8_t read_val; - uint8_t port_status; - timestamp_t start; - - /* Check if mux is ready */ - RETURN_ERROR(amd_fp6_mux_port0_read(me, &read_val)); - - /* Write control register */ - RETURN_ERROR( - i2c_write8(me->i2c_port, me->i2c_addr_flags, 0, write_val)); - - /* - * Read status until write command finishes or times out. - * The mux has an internal opaque timeout, which we wrap with our own - * timeout to be safe. - */ - start = get_time(); - while (time_since32(start) < WRITE_CMD_TIMEOUT_MS * MSEC) { - - RETURN_ERROR(amd_fp6_mux_port0_read(me, &read_val)); - port_status = read_val >> AMD_FP6_MUX_PORT_STATUS_OFFSET; - - if (port_status == AMD_FP6_MUX_PORT_CMD_COMPLETE) - return EC_SUCCESS; - else if (port_status == AMD_FP6_MUX_PORT_CMD_TIMEOUT) - return EC_ERROR_TIMEOUT; - else if (port_status == AMD_FP6_MUX_PORT_CMD_BUSY) - msleep(5); - else - return EC_ERROR_UNKNOWN; - } - - return EC_ERROR_TIMEOUT; -} - -/* - * Keep trying to write the saved mux state until successful or SOC leaves - * S0 power state. - */ -static void amd_fp6_set_mux_retry(void); -DECLARE_DEFERRED(amd_fp6_set_mux_retry); -static void amd_fp6_set_mux_retry(void) -{ - int rv; - bool try_again = false; - - /* - * Mux can only be written in S0, stop trying. - * Will try again on chipset_resume. - */ - if (!chipset_in_state(CHIPSET_STATE_ON)) - return; - - for (int i = 0; i < ARRAY_SIZE(saved_mux_state); i++) { - /* Make sure mux_state is initialized */ - if (saved_mux_state[i].mux == NULL || - !saved_mux_state[i].write_pending) - continue; - - rv = amd_fp6_mux_port0_write(saved_mux_state[i].mux, - saved_mux_state[i].val); - - if (rv) - try_again = true; - else - saved_mux_state[i].write_pending = false; - } - if (try_again) - hook_call_deferred(&amd_fp6_set_mux_retry_data, - CMD_RETRY_INTERVAL_MS * MSEC); -} - - -static int amd_fp6_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - uint8_t val; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (mux_state == USB_PD_MUX_NONE) - /* - * LOW_POWER must be set when connection mode is - * set to 00b (safe state) - */ - val = AMD_FP6_MUX_MODE_SAFE | AMD_FP6_MUX_LOW_POWER; - else if ((mux_state & USB_PD_MUX_USB_ENABLED) && - (mux_state & USB_PD_MUX_DP_ENABLED)) - val = AMD_FP6_MUX_MODE_DOCK; - else if (mux_state & USB_PD_MUX_USB_ENABLED) - val = AMD_FP6_MUX_MODE_USB; - else if (mux_state & USB_PD_MUX_DP_ENABLED) - val = AMD_FP6_MUX_MODE_DP; - else { - CPRINTSUSB("C%d: unhandled mux_state %x\n", me->usb_port, - mux_state); - return EC_ERROR_INVAL; - } - - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - val |= AMD_FP6_MUX_ORIENTATION; - - saved_mux_state[me->usb_port].mux = me; - saved_mux_state[me->usb_port].val = val; - - /* Mux is not powered in Z1 */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return (mux_state == USB_PD_MUX_NONE) ? EC_SUCCESS - : EC_ERROR_NOT_POWERED; - - saved_mux_state[me->usb_port].write_pending = true; - amd_fp6_set_mux_retry(); - - return EC_SUCCESS; -} - -static int amd_fp6_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - uint8_t val; - bool inverted; - uint8_t mode; - - /* Mux is not powered in Z1 */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return USB_PD_MUX_NONE; - - RETURN_ERROR(amd_fp6_mux_port0_read(me, &val)); - - mode = (val & AMD_FP6_MUX_MODE_MASK); - inverted = !!(val & AMD_FP6_MUX_ORIENTATION); - - if (mode == AMD_FP6_MUX_MODE_USB) - *mux_state = USB_PD_MUX_USB_ENABLED; - else if (mode == AMD_FP6_MUX_MODE_DP) - *mux_state = USB_PD_MUX_DP_ENABLED; - else if (mode == AMD_FP6_MUX_MODE_DOCK) - *mux_state = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED; - else /* AMD_FP6_MUX_MODE_SAFE */ - *mux_state = USB_PD_MUX_NONE; - - if (inverted) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -/* - * The FP6 USB Mux will not be ready for writing until *sometime* after S0. - */ -static void amd_fp6_chipset_resume(void) -{ - for (int i = 0; i < ARRAY_SIZE(saved_mux_state); i++) - saved_mux_state[i].write_pending = true; - hook_call_deferred(&amd_fp6_set_mux_retry_data, - CMD_RETRY_INTERVAL_MS * MSEC); -} -DECLARE_HOOK(HOOK_CHIPSET_RESUME, amd_fp6_chipset_resume, HOOK_PRIO_DEFAULT); - -static int amd_fp6_chipset_reset(const struct usb_mux *me) -{ - amd_fp6_chipset_resume(); - return EC_SUCCESS; -} - -const struct usb_mux_driver amd_fp6_usb_mux_driver = { - .set = &amd_fp6_set_mux, - .get = &amd_fp6_get_mux, - .chipset_reset = &amd_fp6_chipset_reset -}; |