summaryrefslogtreecommitdiff
path: root/zephyr/projects/corsola/src/usb_pd_policy.c
diff options
context:
space:
mode:
authorYH Lin <yueherngl@chromium.org>2022-12-03 00:17:55 +0000
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-12-05 17:43:18 +0000
commitdd732876495ed4942d00b9f9ca8dd3b01bad7120 (patch)
treebdff671e5ad3e71e30ab56f4f084f34a2fd72e28 /zephyr/projects/corsola/src/usb_pd_policy.c
parent184d13e77614be3be5374d3fef9d1edf66ec8687 (diff)
downloadchrome-ec-factory-brya-14909.124.B-main.tar.gz
Revert "Merge remote-tracking branch cros/main into factory-brya-14909.124.B-main"factory-brya-14909.124.B-main
This reverts commit 184d13e77614be3be5374d3fef9d1edf66ec8687. Reason for revert: broken build due to ec-utils. Original change's description: > Merge remote-tracking branch cros/main into factory-brya-14909.124.B-main > > Generated by: util/update_release_branch.py --baseboard brya --relevant_paths_file > baseboard/brya/relevant-paths.txt factory-brya-14909.124.B-main > > Relevant changes: > > git log --oneline 19d4d68ffa..aa40b859b3 -- baseboard/brya board/agah > board/anahera board/banshee board/brya board/crota board/felwinter > board/gimble board/kano board/mithrax board/osiris board/primus > board/redrix board/taeko board/taniks board/vell board/volmar > driver/bc12/pi3usb9201_public.* driver/charger/bq25710.* > driver/ppc/nx20p348x.* driver/ppc/syv682x_public.* > driver/retimer/bb_retimer_public.* driver/tcpm/nct38xx.* > driver/tcpm/ps8xxx_public.* driver/tcpm/tcpci.* include/power/alderlake* > include/intel_x86.h power/alderlake* power/intel_x86.c > util/getversion.sh > > e6da633c38 driver: Sort header files > 234a87ae2d tcpci: Add FRS enable to driver structure > a56be59ccd tcpm_header: add test for tcpm_dump_registers > 57b3256963 Rename CONFIG_CHARGER_INPUT_CURRENT to _CHARGER_DEFAULT_CURRENT_LIMIT > e420c8ff9a marasov: Modify TypeC and TypeA configuration. > 43b53e0045 Add default implementation of board_set_charge_limit > b75dc90677 Add CONFIG_CHARGER_MIN_INPUT_CURRENT_LIMIT > f1b563c350 baseboard: Sort header files > 7d01b1e58d driver/retimer/ps8818.h: Add I2C ADDR FLAGS 0x30, 0x58, 0x70 > ec31407993 Add CONFIG_CHARGER_INPUT_CURRENT_DERATE_PCT > 8f89f69a5b crota: disable lid angle sensor for clamshell > > BRANCH=None > BUG=b:260630630 b:163093572 b:259002141 b:255184961 b:259354679 > BUG=b:247100970 b:254328661 > TEST=`emerge-brya chromeos-ec` > > Force-Relevant-Builds: all > Change-Id: I0ecfa0e6af68631283c7a9e8f1afb9d827176c62 > Signed-off-by: YH Lin <yueherngl@google.com> Bug: b:260630630 b:163093572 b:259002141 b:255184961 b:259354679 Bug: b:247100970 b:254328661 Change-Id: Ia14942d1bd6a502062399d77cb59d1f4b549b2c9 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4077247 Auto-Submit: YH Lin <yueherngl@chromium.org> Tested-by: YH Lin <yueherngl@chromium.org> Reviewed-by: Boris Mittelberg <bmbm@google.com> Commit-Queue: YH Lin <yueherngl@chromium.org>
Diffstat (limited to 'zephyr/projects/corsola/src/usb_pd_policy.c')
-rw-r--r--zephyr/projects/corsola/src/usb_pd_policy.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/zephyr/projects/corsola/src/usb_pd_policy.c b/zephyr/projects/corsola/src/usb_pd_policy.c
new file mode 100644
index 0000000000..a885362c61
--- /dev/null
+++ b/zephyr/projects/corsola/src/usb_pd_policy.c
@@ -0,0 +1,226 @@
+/* Copyright 2021 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "atomic.h"
+#include "console.h"
+#include "chipset.h"
+#include "hooks.h"
+#include "timer.h"
+#include "typec_control.h"
+#include "usb_dp_alt_mode.h"
+#include "usb_mux.h"
+#include "usb_pd.h"
+#include "usbc_ppc.h"
+
+#include "baseboard_usbc_config.h"
+
+#define CPRINTS(format, args...) cprints(CC_USBPD, format, ##args)
+#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ##args)
+
+static int active_aux_port = -1;
+
+int pd_check_vconn_swap(int port)
+{
+ /* Allow Vconn swap if AP is on. */
+ return chipset_in_state(CHIPSET_STATE_SUSPEND | CHIPSET_STATE_ON);
+}
+
+static void set_dp_aux_path_sel(int port)
+{
+ gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(dp_aux_path_sel), port);
+ CPRINTS("Set DP_AUX_PATH_SEL: %d", port);
+}
+
+int svdm_get_hpd_gpio(int port)
+{
+ /* HPD is low active, inverse the result */
+ return !gpio_pin_get_dt(GPIO_DT_FROM_NODELABEL(ec_ap_dp_hpd_odl));
+}
+
+static void reset_aux_deferred(void)
+{
+ if (active_aux_port == -1)
+ /* reset to 1 for lower power consumption. */
+ set_dp_aux_path_sel(1);
+}
+DECLARE_DEFERRED(reset_aux_deferred);
+
+void svdm_set_hpd_gpio(int port, int en)
+{
+ /*
+ * HPD is low active, inverse the en.
+ *
+ * Implement FCFS policy:
+ * 1) Enable hpd if no active port.
+ * 2) Disable hpd if active port is the given port.
+ */
+ if (en && active_aux_port < 0) {
+ gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(ec_ap_dp_hpd_odl), 0);
+ active_aux_port = port;
+ hook_call_deferred(&reset_aux_deferred_data, -1);
+ }
+
+ if (!en && active_aux_port == port) {
+ gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(ec_ap_dp_hpd_odl), 1);
+ active_aux_port = -1;
+ /*
+ * This might be a HPD debounce to send a HPD IRQ (500us), so
+ * do not reset the aux path immediately. Defer this call and
+ * re-check if this is a real disable.
+ */
+ hook_call_deferred(&reset_aux_deferred_data, 1 * MSEC);
+ }
+}
+
+__override int svdm_dp_config(int port, uint32_t *payload)
+{
+ int opos = pd_alt_mode(port, TCPCI_MSG_SOP, USB_SID_DISPLAYPORT);
+ uint8_t pin_mode = get_dp_pin_mode(port);
+ mux_state_t mux_mode = svdm_dp_get_mux_mode(port);
+ int mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]);
+
+ if (!pin_mode) {
+ return 0;
+ }
+
+ CPRINTS("pin_mode: %x, mf: %d, mux: %d", pin_mode, mf_pref, mux_mode);
+ /*
+ * Defer setting the usb_mux until HPD goes high, svdm_dp_attention().
+ * The AP only supports one DP phy. An external DP mux switches between
+ * the two ports. Should switch those muxes when it is really used,
+ * i.e. HPD high; otherwise, the real use case is preempted, like:
+ * (1) plug a dongle without monitor connected to port-0,
+ * (2) plug a dongle without monitor connected to port-1,
+ * (3) plug a monitor to the port-1 dongle.
+ */
+
+ payload[0] =
+ VDO(USB_SID_DISPLAYPORT, 1, CMD_DP_CONFIG | VDO_OPOS(opos));
+ payload[1] = VDO_DP_CFG(pin_mode, /* pin mode */
+ 1, /* DPv1.3 signaling */
+ 2); /* UFP connected */
+ return 2;
+};
+
+__override void svdm_dp_post_config(int port)
+{
+ mux_state_t mux_mode = svdm_dp_get_mux_mode(port);
+
+ typec_set_sbu(port, true);
+
+ /*
+ * Prior to post-config, the mux will be reset to safe mode, and this
+ * will break mux config and aux path config we did in the first DP
+ * status command. Only enable this if the port is the current aux-port.
+ */
+ if (port == active_aux_port) {
+ usb_mux_set(port, mux_mode, USB_SWITCH_CONNECT,
+ polarity_rm_dts(pd_get_polarity(port)));
+ usb_mux_hpd_update(port, USB_PD_MUX_HPD_LVL |
+ USB_PD_MUX_HPD_IRQ_DEASSERTED);
+ }
+
+ dp_flags[port] |= DP_FLAGS_DP_ON;
+}
+
+int corsola_is_dp_muxable(int port)
+{
+ int i;
+
+ for (i = 0; i < board_get_usb_pd_port_count(); i++) {
+ if (i != port) {
+ if (usb_mux_get(i) & USB_PD_MUX_DP_ENABLED) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+__override int svdm_dp_attention(int port, uint32_t *payload)
+{
+ int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]);
+ int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]);
+#ifdef CONFIG_USB_PD_DP_HPD_GPIO
+ int cur_lvl = svdm_get_hpd_gpio(port);
+#endif /* CONFIG_USB_PD_DP_HPD_GPIO */
+ mux_state_t mux_state;
+
+ dp_status[port] = payload[1];
+
+ if (!corsola_is_dp_muxable(port)) {
+ /* TODO(waihong): Info user? */
+ CPRINTS("p%d: The other port is already muxed.", port);
+ return 0; /* nak */
+ }
+
+ if (lvl) {
+ set_dp_aux_path_sel(port);
+
+ usb_mux_set(port, USB_PD_MUX_DOCK, USB_SWITCH_CONNECT,
+ polarity_rm_dts(pd_get_polarity(port)));
+ } else {
+ usb_mux_set(port, USB_PD_MUX_USB_ENABLED, USB_SWITCH_CONNECT,
+ polarity_rm_dts(pd_get_polarity(port)));
+ }
+
+ if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND) && (irq || lvl)) {
+ /*
+ * Wake up the AP. IRQ or level high indicates a DP sink is now
+ * present.
+ */
+ if (IS_ENABLED(CONFIG_MKBP_EVENT)) {
+ pd_notify_dp_alt_mode_entry(port);
+ }
+ }
+
+#ifdef CONFIG_USB_PD_DP_HPD_GPIO
+ if (irq && !lvl) {
+ /*
+ * IRQ can only be generated when the level is high, because
+ * the IRQ is signaled by a short low pulse from the high level.
+ */
+ CPRINTF("ERR:HPD:IRQ&LOW\n");
+ return 0; /* nak */
+ }
+
+ if (irq && cur_lvl) {
+ uint64_t now = get_time().val;
+ /* wait for the minimum spacing between IRQ_HPD if needed */
+ if (now < svdm_hpd_deadline[port]) {
+ usleep(svdm_hpd_deadline[port] - now);
+ }
+
+ /* generate IRQ_HPD pulse */
+ svdm_set_hpd_gpio(port, 0);
+ /*
+ * b/171172053#comment14: since the HPD_DSTREAM_DEBOUNCE_IRQ is
+ * very short (500us), we can use udelay instead of usleep for
+ * more stable pulse period.
+ */
+ udelay(HPD_DSTREAM_DEBOUNCE_IRQ);
+ svdm_set_hpd_gpio(port, 1);
+ } else {
+ svdm_set_hpd_gpio(port, lvl);
+ }
+
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ svdm_hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
+#endif /* CONFIG_USB_PD_DP_HPD_GPIO */
+
+ mux_state = (lvl ? USB_PD_MUX_HPD_LVL : USB_PD_MUX_HPD_LVL_DEASSERTED) |
+ (irq ? USB_PD_MUX_HPD_IRQ : USB_PD_MUX_HPD_IRQ_DEASSERTED);
+ usb_mux_hpd_update(port, mux_state);
+
+#ifdef USB_PD_PORT_TCPC_MST
+ if (port == USB_PD_PORT_TCPC_MST) {
+ baseboard_mst_enable_control(port, lvl);
+ }
+#endif
+
+ /* ack */
+ return 1;
+}