summaryrefslogtreecommitdiff
path: root/common/usb_pd_dual_role.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usb_pd_dual_role.c')
-rw-r--r--common/usb_pd_dual_role.c473
1 files changed, 0 insertions, 473 deletions
diff --git a/common/usb_pd_dual_role.c b/common/usb_pd_dual_role.c
deleted file mode 100644
index 52042c5439..0000000000
--- a/common/usb_pd_dual_role.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/* Copyright 2020 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.
- *
- * Dual Role (Source & Sink) USB-PD module.
- */
-
-#include "charge_manager.h"
-#include "charge_state.h"
-#include "dps.h"
-#include "system.h"
-#include "usb_common.h"
-#include "usb_pd.h"
-#include "util.h"
-
-#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
-
-/* The macro is used to prevent a DBZ exception while decoding PDOs. */
-#define PROCESS_ZERO_DIVISOR(x) ((x) == 0 ? 1 : (x))
-
-#if defined(PD_MAX_VOLTAGE_MV) && defined(PD_OPERATING_POWER_MW)
-/*
- * As a sink, this is the max voltage (in millivolts) we can request
- * before getting source caps
- */
-static unsigned int max_request_mv = PD_MAX_VOLTAGE_MV;
-
-/* TODO(b:169532537): deprecate CONFIG_USB_PD_PREFER_MV */
-STATIC_IF_NOT(CONFIG_USB_PD_PREFER_MV)
-struct pd_pref_config_t __maybe_unused pd_pref_config;
-
-void pd_set_max_voltage(unsigned int mv)
-{
- max_request_mv = mv;
-}
-
-unsigned int pd_get_max_voltage(void)
-{
- return max_request_mv;
-}
-
-/*
- * Zinger implements a board specific usb policy that does not define
- * PD_MAX_VOLTAGE_MV and PD_OPERATING_POWER_MW. And in turn, does not
- * use the following functions.
- */
-int pd_find_pdo_index(uint32_t src_cap_cnt, const uint32_t * const src_caps,
- int max_mv, uint32_t *selected_pdo)
-{
- int i, uw, mv;
- int ret = 0;
- int cur_uw = 0;
- int has_preferred_pdo;
- int prefer_cur;
- int desired_uw = 0;
- const int prefer_mv = pd_pref_config.mv;
- const int type = pd_pref_config.type;
-
- int __attribute__((unused)) cur_mv = 0;
-
- if (IS_ENABLED(CONFIG_USB_PD_PREFER_MV))
- desired_uw = charge_get_plt_plus_bat_desired_mw() * 1000;
-
- /* max voltage is always limited by this boards max request */
- max_mv = MIN(max_mv, PD_MAX_VOLTAGE_MV);
-
- /* Get max power that is under our max voltage input */
- for (i = 0; i < src_cap_cnt; i++) {
- if (IS_ENABLED(CONFIG_USB_PD_ONLY_FIXED_PDOS) &&
- (src_caps[i] & PDO_TYPE_MASK) != PDO_TYPE_FIXED)
- continue;
- /* its an unsupported Augmented PDO (PD3.0) */
- if ((src_caps[i] & PDO_TYPE_MASK) == PDO_TYPE_AUGMENTED)
- continue;
-
- mv = ((src_caps[i] >> 10) & 0x3FF) * 50;
- /* Skip invalid voltage */
- if (!mv)
- continue;
- /* Skip any voltage not supported by this board */
- if (!pd_is_valid_input_voltage(mv))
- continue;
-
- if ((src_caps[i] & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) {
- uw = 250000 * (src_caps[i] & 0x3FF);
- } else {
- int ma = (src_caps[i] & 0x3FF) * 10;
-
- ma = MIN(ma, PD_MAX_CURRENT_MA);
- uw = ma * mv;
- }
-
- if (mv > max_mv)
- continue;
- uw = MIN(uw, PD_MAX_POWER_MW * 1000);
- prefer_cur = 0;
-
- /* Apply special rules in favor of voltage */
- if (IS_ENABLED(PD_PREFER_LOW_VOLTAGE)) {
- if (uw == cur_uw && mv < cur_mv)
- prefer_cur = 1;
- } else if (IS_ENABLED(PD_PREFER_HIGH_VOLTAGE)) {
- if (uw == cur_uw && mv > cur_mv)
- prefer_cur = 1;
- } else if (IS_ENABLED(CONFIG_USB_PD_PREFER_MV)) {
- /* Pick if the PDO provides more than desired. */
- if (uw >= desired_uw) {
- /* pick if cur_uw is less than desired watt */
- if (cur_uw < desired_uw)
- prefer_cur = 1;
- else if (type == PD_PREFER_BUCK) {
- /*
- * pick the smallest mV above prefer_mv
- */
- if (mv >= prefer_mv && mv < cur_mv)
- prefer_cur = 1;
- /*
- * pick if cur_mv is less than
- * prefer_mv, and we have higher mV
- */
- else if (cur_mv < prefer_mv &&
- mv > cur_mv)
- prefer_cur = 1;
- } else if (type == PD_PREFER_BOOST) {
- /*
- * pick the largest mV below prefer_mv
- */
- if (mv <= prefer_mv && mv > cur_mv)
- prefer_cur = 1;
- /*
- * pick if cur_mv is larger than
- * prefer_mv, and we have lower mV
- */
- else if (cur_mv > prefer_mv &&
- mv < cur_mv)
- prefer_cur = 1;
- }
- /*
- * pick the largest power if we don't see one staisfy
- * desired power
- */
- } else if (cur_uw == 0 || uw > cur_uw) {
- prefer_cur = 1;
- }
- }
-
- /* Prefer higher power, except for tiebreaker */
- has_preferred_pdo =
- prefer_cur ||
- (!IS_ENABLED(CONFIG_USB_PD_PREFER_MV) && uw > cur_uw);
-
- if (has_preferred_pdo) {
- ret = i;
- cur_uw = uw;
- cur_mv = mv;
- }
- }
-
- if (selected_pdo)
- *selected_pdo = src_caps[ret];
-
- return ret;
-}
-
-void pd_extract_pdo_power(uint32_t pdo, uint32_t *ma, uint32_t *max_mv,
- uint32_t *min_mv)
-{
- int max_ma, mw;
-
- if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_FIXED) {
- *max_mv = PDO_FIXED_VOLTAGE(pdo);
- *min_mv = *max_mv;
- } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_AUGMENTED) {
- *max_mv = PDO_AUG_MAX_VOLTAGE(pdo);
- *min_mv = PDO_AUG_MIN_VOLTAGE(pdo);
- } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_VARIABLE) {
- *max_mv = PDO_VAR_MAX_VOLTAGE(pdo);
- *min_mv = PDO_VAR_MIN_VOLTAGE(pdo);
- } else {
- *max_mv = PDO_BATT_MAX_VOLTAGE(pdo);
- *min_mv = PDO_BATT_MIN_VOLTAGE(pdo);
- }
-
- if (*max_mv == 0) {
- *ma = 0;
- *min_mv = 0;
- return;
- }
-
- if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_FIXED) {
- max_ma = PDO_FIXED_CURRENT(pdo);
- } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_AUGMENTED) {
- max_ma = PDO_AUG_MAX_CURRENT(pdo);
- } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_VARIABLE) {
- max_ma = PDO_VAR_MAX_CURRENT(pdo);
- } else {
- mw = PDO_BATT_MAX_POWER(pdo);
- max_ma = 1000 * mw / PROCESS_ZERO_DIVISOR(*min_mv);
- }
- max_ma = MIN(max_ma,
- PD_MAX_POWER_MW * 1000 / PROCESS_ZERO_DIVISOR(*min_mv));
- *ma = MIN(max_ma, PD_MAX_CURRENT_MA);
-}
-
-void pd_build_request(int32_t vpd_vdo, uint32_t *rdo, uint32_t *ma,
- uint32_t *mv, int port)
-{
- uint32_t pdo;
- int pdo_index, flags = 0;
- int uw;
- int max_or_min_ma;
- int max_or_min_mw;
- int max_vbus;
- int vpd_vbus_dcr;
- int vpd_gnd_dcr;
- uint32_t src_cap_cnt = pd_get_src_cap_cnt(port);
- const uint32_t * const src_caps = pd_get_src_caps(port);
- int charging_allowed;
- int max_request_allowed;
- uint32_t max_request_mv = pd_get_max_voltage();
- uint32_t unused;
-
- /*
- * If this port is the current charge port, or if there isn't an active
- * charge port, set this value to true. If CHARGE_PORT_NONE isn't
- * considered, then there can be a race condition in PD negotiation and
- * the charge manager which forces an incorrect request for
- * vSafe5V. This can then lead to a brownout condition when the input
- * current limit gets incorrectly set to 0.5A.
- */
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) {
- int chg_port = charge_manager_get_selected_charge_port();
-
- charging_allowed =
- (chg_port == port || chg_port == CHARGE_PORT_NONE);
- } else {
- charging_allowed = 1;
- }
-
- if (IS_ENABLED(CONFIG_USB_PD_CHECK_MAX_REQUEST_ALLOWED))
- max_request_allowed = pd_is_max_request_allowed();
- else
- max_request_allowed = 1;
-
- if (IS_ENABLED(CONFIG_USB_PD_DPS) && dps_is_enabled())
- max_request_mv =
- MIN(max_request_mv, dps_get_dynamic_voltage());
-
- /*
- * If currently charging on a different port, or we are not allowed to
- * request the max voltage, then select vSafe5V
- */
- if (charging_allowed && max_request_allowed) {
- /* find pdo index for max voltage we can request */
- pdo_index = pd_find_pdo_index(src_cap_cnt, src_caps,
- max_request_mv, &pdo);
- } else {
- /* src cap 0 should be vSafe5V */
- pdo_index = 0;
- pdo = src_caps[0];
- }
-
- pd_extract_pdo_power(pdo, ma, mv, &unused);
-
- /*
- * Adjust VBUS current if CTVPD device was detected.
- */
- if (vpd_vdo > 0) {
- max_vbus = VPD_VDO_MAX_VBUS(vpd_vdo);
- vpd_vbus_dcr = VPD_VDO_VBUS_IMP(vpd_vdo) << 1;
- vpd_gnd_dcr = VPD_VDO_GND_IMP(vpd_vdo);
-
- /*
- * Valid max_vbus values:
- * 00b - 20000 mV
- * 01b - 30000 mV
- * 10b - 40000 mV
- * 11b - 50000 mV
- */
- max_vbus = 20000 + max_vbus * 10000;
- if (*mv > max_vbus)
- *mv = max_vbus;
-
- /*
- * 5000 mA cable: 150 = 750000 / 50000
- * 3000 mA cable: 250 = 750000 / 30000
- */
- if (*ma > 3000)
- *ma = 750000 / (150 + vpd_vbus_dcr + vpd_gnd_dcr);
- else
- *ma = 750000 / (250 + vpd_vbus_dcr + vpd_gnd_dcr);
- }
-
- uw = *ma * *mv;
- /* Mismatch bit set if less power offered than the operating power */
- if (uw < (1000 * PD_OPERATING_POWER_MW))
- flags |= RDO_CAP_MISMATCH;
-
-#ifdef CONFIG_USB_PD_GIVE_BACK
- /* Tell source we are give back capable. */
- flags |= RDO_GIVE_BACK;
-
- /*
- * BATTERY PDO: Inform the source that the sink will reduce
- * power to this minimum level on receipt of a GotoMin Request.
- */
- max_or_min_mw = PD_MIN_POWER_MW;
-
- /*
- * FIXED or VARIABLE PDO: Inform the source that the sink will
- * reduce current to this minimum level on receipt of a GotoMin
- * Request.
- */
- max_or_min_ma = PD_MIN_CURRENT_MA;
-#else
- /*
- * Can't give back, so set maximum current and power to
- * operating level.
- */
- max_or_min_ma = *ma;
- max_or_min_mw = uw / 1000;
-#endif
-
- if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) {
- int mw = uw / 1000;
- *rdo = RDO_BATT(pdo_index + 1, mw, max_or_min_mw, flags);
- } else {
- *rdo = RDO_FIXED(pdo_index + 1, *ma, max_or_min_ma, flags);
- }
-
- /*
- * Ref: USB Power Delivery Specification
- * (Revision 3.0, Version 2.0 / Revision 2.0, Version 1.3)
- * 6.4.2.4 USB Communications Capable
- * 6.4.2.5 No USB Suspend
- *
- * If the port partner is capable of USB communication set the
- * USB Communications Capable flag.
- * If the port partner is sink device do not suspend USB as the
- * power can be used for charging.
- */
- if (pd_get_partner_usb_comm_capable(port)) {
- *rdo |= RDO_COMM_CAP;
- if (pd_get_power_role(port) == PD_ROLE_SINK)
- *rdo |= RDO_NO_SUSPEND;
- }
-}
-
-void pd_process_source_cap(int port, int cnt, uint32_t *src_caps)
-{
- pd_set_src_caps(port, cnt, src_caps);
-
- if (IS_ENABLED(CONFIG_CHARGE_MANAGER)) {
- uint32_t ma, mv, pdo, unused;
- uint32_t max_mv = pd_get_max_voltage();
-
- if (IS_ENABLED(CONFIG_USB_PD_DPS) && dps_is_enabled())
- max_mv = MIN(max_mv, dps_get_dynamic_voltage());
-
- /* Get max power info that we could request */
- pd_find_pdo_index(pd_get_src_cap_cnt(port),
- pd_get_src_caps(port),
- max_mv, &pdo);
- pd_extract_pdo_power(pdo, &ma, &mv, &unused);
-
- /* Set max. limit, but apply 500mA ceiling */
- charge_manager_set_ceil(port, CEIL_REQUESTOR_PD, PD_MIN_MA);
- pd_set_input_current_limit(port, ma, mv);
- }
-}
-#endif /* defined(PD_MAX_VOLTAGE_MV) && defined(PD_OPERATING_POWER_MW) */
-
-bool pd_is_battery_capable(void)
-{
- bool capable;
-
- /* Battery is present and at some minimum percentage. */
- capable = (usb_get_battery_soc() >=
- CONFIG_USB_PD_TRY_SRC_MIN_BATT_SOC);
-
-#ifdef CONFIG_BATTERY_REVIVE_DISCONNECT
- /*
- * Not capable if the battery is in the disconnect state. The discharge
- * FET may not be enabled and so attempting being a SRC may cut off
- * our only power source at the time.
- */
- capable &= (battery_get_disconnect_state() ==
- BATTERY_NOT_DISCONNECTED);
-#elif defined(CONFIG_BATTERY_PRESENT_CUSTOM) || \
- defined(CONFIG_BATTERY_PRESENT_GPIO)
- /*
- * When battery is cutoff in ship mode it may not be reliable to
- * check if battery is present with its state of charge.
- * Also check if battery is initialized and ready to provide power.
- */
- capable &= (battery_is_present() == BP_YES);
-#endif /* CONFIG_BATTERY_PRESENT_[CUSTOM|GPIO] */
-
- return capable;
-}
-
-#ifdef CONFIG_USB_PD_TRY_SRC
-bool pd_is_try_source_capable(void)
-{
- int i;
- uint8_t try_src = 0;
- bool new_try_src;
-
- for (i = 0; i < board_get_usb_pd_port_count(); i++)
- try_src |= (pd_get_dual_role(i) == PD_DRP_TOGGLE_ON);
-
- /*
- * Enable try source when dual-role toggling AND battery is capable
- * of powering the whole system.
- */
- new_try_src = (try_src && pd_is_battery_capable());
-
-#if CONFIG_DEDICATED_CHARGE_PORT_COUNT > 0
- /*
- * If a dedicated supplier is present, power is not a concern and
- * therefore allow Try.Src if we're toggling.
- */
- new_try_src = try_src && (charge_manager_get_supplier() ==
- CHARGE_SUPPLIER_DEDICATED);
-#endif /* CONFIG_DEDICATED_CHARGE_PORT_COUNT */
-
- return new_try_src;
-}
-#endif /* CONFIG_USB_PD_TRY_SRC */
-
-static int get_bbram_idx(uint8_t port)
-{
- if (port < MAX_SYSTEM_BBRAM_IDX_PD_PORTS)
- return (port + SYSTEM_BBRAM_IDX_PD0);
-
- return -1;
-}
-
-int pd_get_saved_port_flags(int port, uint8_t *flags)
-{
- if (system_get_bbram(get_bbram_idx(port), flags) != EC_SUCCESS) {
-#ifndef CHIP_HOST
- ccprintf("PD NVRAM FAIL");
-#endif
- return EC_ERROR_UNKNOWN;
- }
-
- return EC_SUCCESS;
-}
-
-static void pd_set_saved_port_flags(int port, uint8_t flags)
-{
- if (system_set_bbram(get_bbram_idx(port), flags) != EC_SUCCESS) {
-#ifndef CHIP_HOST
- ccprintf("PD NVRAM FAIL");
-#endif
- }
-}
-
-void pd_update_saved_port_flags(int port, uint8_t flag, uint8_t do_set)
-{
- uint8_t saved_flags;
-
- if (pd_get_saved_port_flags(port, &saved_flags) != EC_SUCCESS)
- return;
-
- if (do_set)
- saved_flags |= flag;
- else
- saved_flags &= ~flag;
-
- pd_set_saved_port_flags(port, saved_flags);
-}