diff options
author | YH Lin <yueherngl@google.com> | 2022-11-30 21:44:08 +0000 |
---|---|---|
committer | YH Lin <yueherngl@google.com> | 2022-11-30 21:44:08 +0000 |
commit | af25602b15b22b9ef5821dcba9934311f2157c48 (patch) | |
tree | d0c89ae8814c2ba35c238c6c0644ec6b1602c63a /zephyr/program/trogdor/lazor/src/usb_pd_policy.c | |
parent | 54462f034b635260dd09173b3d082e47fc960ef3 (diff) | |
parent | aa40b859b3a73e5a205bc561c1a29eff38485461 (diff) | |
download | chrome-ec-af25602b15b22b9ef5821dcba9934311f2157c48.tar.gz |
Merge remote-tracking branch cros/main into factory-brya-14517.B-main
Generated by: util/update_release_branch.py --baseboard brya --relevant_paths_file
baseboard/brya/relevant-paths.txt factory-brya-14517.B-main
Relevant changes:
git log --oneline 54462f034b..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:259002141 b:255184961 b:247100970 b:259354679 b:260630630
BUG=b:163093572 b:254328661
TEST=`emerge-brya chromeos-ec`
Force-Relevant-Builds: all
Change-Id: Ia85a701fbf6b8e67ec214b9e25e0e55e980a6f47
Signed-off-by: YH Lin <yueherngl@google.com>
Diffstat (limited to 'zephyr/program/trogdor/lazor/src/usb_pd_policy.c')
-rw-r--r-- | zephyr/program/trogdor/lazor/src/usb_pd_policy.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/zephyr/program/trogdor/lazor/src/usb_pd_policy.c b/zephyr/program/trogdor/lazor/src/usb_pd_policy.c new file mode 100644 index 0000000000..32e3376ca0 --- /dev/null +++ b/zephyr/program/trogdor/lazor/src/usb_pd_policy.c @@ -0,0 +1,261 @@ +/* Copyright 2022 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "charge_manager.h" +#include "chipset.h" +#include "console.h" +#include "system.h" +#include "usb_mux.h" +#include "usbc_ppc.h" +#include "util.h" + +#include <zephyr/drivers/gpio.h> + +#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ##args) +#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ##args) + +int pd_check_vconn_swap(int port) +{ + /* In G3, do not allow vconn swap since PP5000 rail is off */ + return gpio_pin_get_dt(GPIO_DT_FROM_NODELABEL(gpio_en_pp5000_a)); +} + +static uint8_t vbus_en[CONFIG_USB_PD_PORT_MAX_COUNT]; +#if CONFIG_USB_PD_PORT_MAX_COUNT == 1 +static uint8_t vbus_rp[CONFIG_USB_PD_PORT_MAX_COUNT] = { TYPEC_RP_1A5 }; +#else +static uint8_t vbus_rp[CONFIG_USB_PD_PORT_MAX_COUNT] = { TYPEC_RP_1A5, + TYPEC_RP_1A5 }; +#endif + +static void board_vbus_update_source_current(int port) +{ + /* Both port are controlled by PPC SN5S330. */ + ppc_set_vbus_source_current_limit(port, vbus_rp[port]); + ppc_vbus_source_enable(port, vbus_en[port]); +} + +void pd_power_supply_reset(int port) +{ + int prev_en; + + prev_en = vbus_en[port]; + + /* Disable VBUS */ + vbus_en[port] = 0; + board_vbus_update_source_current(port); + + /* Enable discharge if we were previously sourcing 5V */ + if (prev_en) + pd_set_vbus_discharge(port, 1); + + /* notify host of power info change */ + pd_send_host_event(PD_EVENT_POWER_CHANGE); +} + +int pd_set_power_supply_ready(int port) +{ + /* Disable charging */ + board_vbus_sink_enable(port, 0); + + pd_set_vbus_discharge(port, 0); + + /* Provide VBUS */ + vbus_en[port] = 1; + board_vbus_update_source_current(port); + + /* notify host of power info change */ + pd_send_host_event(PD_EVENT_POWER_CHANGE); + + return EC_SUCCESS; /* we are ready */ +} + +int board_vbus_source_enabled(int port) +{ + return vbus_en[port]; +} + +__override void typec_set_source_current_limit(int port, enum tcpc_rp_value rp) +{ + vbus_rp[port] = rp; + board_vbus_update_source_current(port); +} + +int pd_snk_is_vbus_provided(int port) +{ + return tcpm_check_vbus_level(port, VBUS_PRESENT); +} + +/* ----------------- Vendor Defined Messages ------------------ */ +#ifdef CONFIG_USB_PD_ALT_MODE_DFP +__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); + + if (!pin_mode) + return 0; + + /* + * 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) +{ + dp_flags[port] |= DP_FLAGS_DP_ON; +} + +/** + * Is the port fine to be muxed its DisplayPort lines? + * + * Only one port can be muxed to DisplayPort at a time. + * + * @param port Port number of TCPC. + * @return 1 is fine; 0 is bad as other port is already muxed; + */ +static int is_dp_muxable(int port) +{ + int i; + + for (i = 0; i < CONFIG_USB_PD_PORT_MAX_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) +{ + const struct gpio_dt_spec *hpd = + GPIO_DT_FROM_NODELABEL(gpio_dp_hot_plug_det); + int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]); + int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]); + int cur_lvl = gpio_pin_get_dt(hpd); + mux_state_t mux_state; + + dp_status[port] = payload[1]; + + if (!is_dp_muxable(port)) { + /* TODO(waihong): Info user? */ + CPRINTS("p%d: The other port is already muxed.", port); + return 0; + } + + /* + * Initial implementation to handle HPD. Only the first-plugged port + * works, i.e. sending HPD signal to AP. The second-plugged port + * will be ignored. + * + * TODO(waihong): Continue the above case, if the first-plugged port + * is then unplugged, switch to the second-plugged port and signal AP? + */ + if (lvl) { + /* + * Enable and switch the DP port selection mux to the + * correct port. + * + * TODO(waihong): Better to move switching DP mux to + * the usb_mux abstraction. + */ + gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(gpio_dp_mux_sel), + port == 1); + gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(gpio_dp_mux_oe_l), 0); + + /* Connect the SBU lines in PPC chip. */ + if (IS_ENABLED(CONFIG_USBC_PPC_SBU)) + ppc_set_sbu(port, 1); + + /* + * Connect the USB SS/DP lines in TCPC chip. + * + * When mf_pref not true, still use the dock muxing + * because of the board USB-C topology (limited to 2 + * lanes DP). + */ + usb_mux_set(port, USB_PD_MUX_DOCK, USB_SWITCH_CONNECT, + polarity_rm_dts(pd_get_polarity(port))); + } else { + /* Disconnect the DP port selection mux. */ + gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(gpio_dp_mux_oe_l), 1); + gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(gpio_dp_mux_sel), 0); + + /* Disconnect the SBU lines in PPC chip. */ + if (IS_ENABLED(CONFIG_USBC_PPC_SBU)) + ppc_set_sbu(port, 0); + + /* Disconnect the DP but keep the USB SS lines in TCPC chip. */ + 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. + */ + pd_notify_dp_alt_mode_entry(port); + + /* Configure TCPC for the HPD event, for proper muxing */ + 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); + + /* Signal AP for the HPD event, through GPIO to AP */ + 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 */ + gpio_pin_set_dt(hpd, 0); + usleep(HPD_DSTREAM_DEBOUNCE_IRQ); + gpio_pin_set_dt(hpd, 1); + + /* Set the minimum time delay (2ms) for the next HPD IRQ */ + svdm_hpd_deadline[port] = + get_time().val + HPD_USTREAM_DEBOUNCE_LVL; + } else if (irq & !lvl) { + CPRINTF("ERR:HPD:IRQ&LOW\n"); + return 0; + } + gpio_pin_set_dt(hpd, lvl); + /* Set the minimum time delay (2ms) for the next HPD IRQ */ + svdm_hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; + + return 1; +} + +__override void svdm_exit_dp_mode(int port) +{ + if (is_dp_muxable(port)) { + /* Disconnect the DP port selection mux. */ + gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(gpio_dp_mux_oe_l), 1); + gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(gpio_dp_mux_sel), 0); + + /* Signal AP for the HPD low event */ + usb_mux_hpd_update(port, USB_PD_MUX_HPD_LVL_DEASSERTED | + USB_PD_MUX_HPD_IRQ_DEASSERTED); + gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(gpio_dp_hot_plug_det), + 0); + } +} +#endif /* CONFIG_USB_PD_ALT_MODE_DFP */ |