diff options
author | Daisuke Nojiri <dnojiri@chromium.org> | 2022-03-09 18:16:08 +0000 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-06-15 23:29:29 +0000 |
commit | ce5856c7694b1984784f9e1cc0c7ce3d08cb0439 (patch) | |
tree | 471609774b55ebb389c6e26e29cbe25b17689e3c | |
parent | dbd7e8249d3cf0a834629127ee378fdf4b700681 (diff) | |
download | chrome-ec-ce5856c7694b1984784f9e1cc0c7ce3d08cb0439.tar.gz |
Agah: Enable bypass mode
This patch enables bypass mode for ISL9241 on Agah.
Tested cases:
1. Boot on BJ.
2. Unplug BJ.
3. Boot on Type-C.
4. Unplug Type-C.
5. Switch from Type-C to BJ.
6. Not switching from BJ to Type-C.
BUG=b:214057333, b:216206104
BRANCH=None
TEST=On Agah. See above.
Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
Change-Id: I8d015d401291391b8b8e7f25e9db8697d211cd4d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3583044
Reviewed-by: Kenny Pan <kennypan@google.com>
-rw-r--r-- | baseboard/brya/usb_pd_policy.c | 3 | ||||
-rw-r--r-- | board/agah/board.c | 1 | ||||
-rw-r--r-- | board/agah/board.h | 16 | ||||
-rw-r--r-- | board/agah/charger_isl9241.c | 242 | ||||
-rw-r--r-- | board/agah/ec.tasklist | 1 | ||||
-rw-r--r-- | board/agah/gpio.inc | 4 |
6 files changed, 226 insertions, 41 deletions
diff --git a/baseboard/brya/usb_pd_policy.c b/baseboard/brya/usb_pd_policy.c index 4d5ece38ca..e3e85539bf 100644 --- a/baseboard/brya/usb_pd_policy.c +++ b/baseboard/brya/usb_pd_policy.c @@ -75,6 +75,9 @@ int pd_set_power_supply_ready(int port) int board_vbus_source_enabled(int port) { + /* BJ port is always sink. */ + if (port >= CONFIG_USB_PD_PORT_MAX_COUNT) + return 0; return ppc_is_sourcing_vbus(port); } diff --git a/board/agah/board.c b/board/agah/board.c index e3a9e1b93e..d1cc519402 100644 --- a/board/agah/board.c +++ b/board/agah/board.c @@ -52,6 +52,7 @@ DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, board_chipset_suspend, HOOK_PRIO_DEFAULT); static void board_init(void) { gpio_enable_interrupt(GPIO_PG_PP3300_S5_OD); + gpio_enable_interrupt(GPIO_BJ_ADP_PRESENT_ODL); } DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); diff --git a/board/agah/board.h b/board/agah/board.h index 9b9998d6a8..ed8b43ffd9 100644 --- a/board/agah/board.h +++ b/board/agah/board.h @@ -138,10 +138,15 @@ /* Charger defines */ #define CONFIG_CHARGER_ISL9241 -#define CONFIG_CHARGE_RAMP_SW #define CONFIG_CHARGER_SENSE_RESISTOR 10 #define CONFIG_CHARGER_SENSE_RESISTOR_AC 10 +/* Barrel jack adapter settings */ +#undef CONFIG_DEDICATED_CHARGE_PORT_COUNT +#define CONFIG_DEDICATED_CHARGE_PORT_COUNT 1 +/* This is the next available port # after USB-C ports. */ +#define DEDICATED_CHARGE_PORT 2 + /* * Older boards have a different ADC assignment. */ @@ -197,6 +202,12 @@ enum mft_channel { MFT_CH_COUNT }; +enum charge_port { + CHARGE_PORT_TYPEC0, + CHARGE_PORT_TYPEC1, + CHARGE_PORT_BARRELJACK, +}; + /** * Interrupt handler for PG_PP3300_S5_OD changes. * @@ -204,6 +215,9 @@ enum mft_channel { */ void board_power_interrupt(enum gpio_signal signal); +/* IRQ for BJ plug/unplug. */ +void bj_present_interrupt(enum gpio_signal signal); + #endif /* !__ASSEMBLER__ */ #endif /* __CROS_EC_BOARD_H */ diff --git a/board/agah/charger_isl9241.c b/board/agah/charger_isl9241.c index 85e0de90fe..2276a72e29 100644 --- a/board/agah/charger_isl9241.c +++ b/board/agah/charger_isl9241.c @@ -6,18 +6,21 @@ #include "common.h" #include "charge_manager.h" +#include "charge_state.h" #include "charge_state_v2.h" #include "charger.h" #include "compile_time_macros.h" #include "console.h" #include "driver/charger/isl9241.h" +#include "gpio.h" +#include "hooks.h" +#include "stdbool.h" #include "usbc_ppc.h" #include "usb_pd.h" #include "util.h" - -#define CPRINTSUSB(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTFUSB(format, args...) cprintf(CC_USBCHARGE, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) +#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) /* Charger Chip Configuration */ const struct charger_config_t chg_chips[] = { @@ -29,62 +32,227 @@ const struct charger_config_t chg_chips[] = { }; BUILD_ASSERT(ARRAY_SIZE(chg_chips) == CHARGER_NUM); +static int board_disable_bj_port(void) +{ + gpio_set_level(GPIO_EN_PPVAR_BJ_ADP, 0); + /* If the current port is BJ, disable bypass mode. */ + if (charge_manager_get_supplier() == CHARGE_SUPPLIER_DEDICATED) + return charger_enable_bypass_mode(0, 0); + + CPRINTS("BJ power is disabled"); + + return EC_SUCCESS; +} + +static int board_enable_bj_port(void) +{ + if (gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL)) + return EC_ERROR_INVAL; + gpio_set_level(GPIO_EN_PPVAR_BJ_ADP, 1); + + CPRINTS("BJ power is enabled"); + + return charger_enable_bypass_mode(0, 1); +} + +/* + * TODO: + * + * When AC is being plugged in (including switching source port), + * 1. Deassert NVIDIA_GPU_ACOFF_ODL. + * 2. Call evaluate_d_notify. + * + * When AC is being lost, + * 1. Assert NVIDIA_GPU_ACOFF_ODL. + * 2. Set D-Notify to D5. + * 3. Differ-call + * a. Deassert NVIDIA_GPU_ACOFF_ODL. + * b. evaluate_d_notify + */ +static int board_throttle_ap_gpu(bool enable) +{ + int rv = EC_SUCCESS; + + if (!chipset_in_state(CHIPSET_STATE_ON)) + return EC_SUCCESS; + + CPRINTS("TODO: %s to %s AP & GPU (%d)", rv ? "Failed" : "Succeeded", + enable ? "throttle" : "unthrottle", rv); + + return rv; +} + +/* Disable all VBUS sink ports except <port>. <port> = -1 disables all ports. */ +static int board_disable_vbus_sink(int port) +{ + int i, r, rv = EC_SUCCESS; + + for (i = 0; i < ppc_cnt; i++) { + if (i == port) + continue; + /* + * Do not return early if one fails otherwise we can get into a + * boot loop assertion failure. + */ + r = ppc_vbus_sink_enable(i, 0); + CPRINTS("%s to disable sink path C%d (%d).", + r ? "Failed" : "Succeeded", i, r); + rv |= r; + } + + return rv; +} + +/* Minimum battery SoC required for switching source port. */ +#define MIN_BATT_FOR_SWITCHING_SOURCE_PORT 1 + +/* + * It should also work on POR with/without a battery: + * + * 1. EC gathers power info of all ports. + * 2. Identify the highest power port. + * 3. If + * 1. battery soc = 0% --> Exit + * 2. BJ_ADP_PRESENT_ODL = 1 --> Exit + * 3. highest power port == active port --> Exit + * 4. If + * 1. in S0, throttle AP & GPU to the DC rating. + * 5. Turn off the current active port. + * 6. Turn on the highest power port. + * 7. If + * 1. in S0, throttle AP & GPU back. + * + * TODO: Are the following cases covered? + * 1. Two AC adapters are plugged. Then, the active adapter is removed. + * + * TODO: Recover from incomplete execution: + * 1. Failed to turn on/off PPC. + */ int board_set_active_charge_port(int port) { - int is_valid_port = board_is_usb_pd_port_present(port); - int i; + enum charge_supplier supplier = charge_manager_get_supplier(); + int active_port = charge_manager_get_active_charge_port(); + + CPRINTS("Changing charge port to %d (current port=%d supplier=%d)", + port, active_port, supplier); if (port == CHARGE_PORT_NONE) { - CPRINTSUSB("Disabling all charger ports"); - - /* Disable all ports. */ - for (i = 0; i < ppc_cnt; i++) { - /* - * Do not return early if one fails otherwise we can - * get into a boot loop assertion failure. - */ - if (ppc_vbus_sink_enable(i, 0)) - CPRINTSUSB("Disabling C%d as sink failed.", i); - } + CPRINTS("Disabling all charger ports"); + + board_throttle_ap_gpu(1); + + board_disable_bj_port(); + board_disable_vbus_sink(-1); return EC_SUCCESS; - } else if (!is_valid_port) { - return EC_ERROR_INVAL; } - /* Check if the port is sourcing VBUS. */ - if (ppc_is_sourcing_vbus(port)) { - CPRINTFUSB("Skip enable C%d", port); + if (port < 0 || CHARGE_PORT_COUNT <= port) { + return EC_ERROR_INVAL; + } else if (port == active_port) { + return EC_SUCCESS; + } else if (board_vbus_source_enabled(port)) { + /* Don't charge from a USBC source port */ + CPRINTS("Don't enable C%d. It's sourcing.", port); return EC_ERROR_INVAL; } - CPRINTSUSB("New charge port: C%d", port); - /* - * Turn off the other ports' sink path FETs, before enabling the - * requested charge port. + * We need to check the battery if we're switching a source port. If + * we're just starting up or no AC was previously plugged, we shouldn't + * check the battery. Both cases can be caught by supplier == NONE. */ - for (i = 0; i < ppc_cnt; i++) { - if (i == port) - continue; - - if (ppc_vbus_sink_enable(i, 0)) - CPRINTSUSB("C%d: sink path disable failed.", i); + if (supplier != CHARGE_SUPPLIER_NONE) { + if (charge_get_percent() < MIN_BATT_FOR_SWITCHING_SOURCE_PORT) + return EC_ERROR_NOT_POWERED; } - /* Enable requested charge port. */ - if (ppc_vbus_sink_enable(port, 1)) { - CPRINTSUSB("C%d: sink path enable failed.", port); - return EC_ERROR_UNKNOWN; + /* Turn off other ports' sink paths before enabling requested port. */ + if (port == CHARGE_PORT_TYPEC0 || port == CHARGE_PORT_TYPEC1) { + /* + * BJ port is on POR. So, we need to turn it off even if we're + * not previously on BJ. + */ + board_disable_bj_port(); + if (board_disable_vbus_sink(port)) + return EC_ERROR_UNCHANGED; + + /* Enable requested USBC charge port. */ + if (ppc_vbus_sink_enable(port, 1)) { + CPRINTS("Failed to enable sink path for C%d", port); + return EC_ERROR_UNKNOWN; + } + } else if (port == CHARGE_PORT_BARRELJACK) { + /* + * We can't proceed unless both ports are successfully + * disconnected as sources. + */ + if (board_disable_vbus_sink(-1)) + return EC_ERROR_UNKNOWN; + board_enable_bj_port(); } + /* Switching port is complete. Turn off throttling. */ + if (supplier != CHARGE_SUPPLIER_NONE) + board_throttle_ap_gpu(0); + + CPRINTS("New charger p%d", port); + return EC_SUCCESS; } -__overridable void board_set_charge_limit(int port, int supplier, int charge_ma, - int max_ma, int charge_mv) +void board_set_charge_limit(int port, int supplier, int charge_ma, + int max_ma, int charge_mv) { charge_set_input_current_limit(MAX(charge_ma, CONFIG_CHARGER_INPUT_CURRENT), charge_mv); } + +static const struct charge_port_info bj_power = { + /* 150W (also default) */ + .voltage = 19500, + .current = 7700, +}; + +/* Debounce time for BJ plug/unplug */ +#define BJ_DEBOUNCE_MS 1000 + +static void bj_connect_deferred(void) +{ + static int8_t bj_connected = -1; + const struct charge_port_info *pi = NULL; + int connected = !gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL); + + if (connected == bj_connected) + return; + + if (connected) + pi = &bj_power; + + charge_manager_update_charge(CHARGE_SUPPLIER_DEDICATED, + DEDICATED_CHARGE_PORT, pi); + bj_connected = connected; + CPRINTS("BJ %s", connected ? "connected" : "disconnected"); +} +DECLARE_DEFERRED(bj_connect_deferred); + +void bj_present_interrupt(enum gpio_signal signal) +{ + hook_call_deferred(&bj_connect_deferred_data, BJ_DEBOUNCE_MS * MSEC); +} + +static void bj_state_init(void) +{ + /* + * Initialize all charge suppliers to 0. The charge manager waits until + * all ports have reported in before doing anything. + */ + for (int i = 0; i < CHARGE_PORT_COUNT; i++) { + for (int j = 0; j < CHARGE_SUPPLIER_COUNT; j++) + charge_manager_update_charge(j, i, NULL); + } + + bj_connect_deferred(); +} +DECLARE_HOOK(HOOK_INIT, bj_state_init, HOOK_PRIO_INIT_CHARGE_MANAGER + 1); diff --git a/board/agah/ec.tasklist b/board/agah/ec.tasklist index ea1f6e7e09..7286caf6c6 100644 --- a/board/agah/ec.tasklist +++ b/board/agah/ec.tasklist @@ -12,7 +12,6 @@ #define CONFIG_TASK_LIST \ TASK_ALWAYS(HOOKS, hook_task, NULL, HOOKS_TASK_STACK_SIZE) \ - TASK_ALWAYS(CHG_RAMP, chg_ramp_task, NULL, BASEBOARD_CHG_RAMP_TASK_STACK_SIZE) \ TASK_ALWAYS(USB_CHG_P0, usb_charger_task, 0, TASK_STACK_SIZE) \ TASK_ALWAYS(USB_CHG_P1, usb_charger_task, 0, TASK_STACK_SIZE) \ TASK_ALWAYS(CHARGER, charger_task, NULL, BASEBOARD_CHARGER_TASK_STACK_SIZE) \ diff --git a/board/agah/gpio.inc b/board/agah/gpio.inc index a1573f6290..3c4f2a2bef 100644 --- a/board/agah/gpio.inc +++ b/board/agah/gpio.inc @@ -26,6 +26,7 @@ GPIO_INT(PG_PP3300_S5_OD, PIN(B, 4), GPIO_INT_BOTH | GPIO_PULL_UP GPIO_INT(USB_C2_BC12_INT_ODL, PIN(8, 3), GPIO_INT_FALLING, bc12_interrupt) GPIO_INT(USB_C2_TCPC_INT_ODL, PIN(A, 7), GPIO_INT_FALLING, tcpc_alert_event) GPIO_INT(USB_C2_PPC_INT_ODL, PIN(7, 0), GPIO_INT_FALLING, ppc_interrupt) +GPIO_INT(BJ_ADP_PRESENT_ODL, PIN(5, 6), GPIO_INT_BOTH | GPIO_PULL_UP, bj_present_interrupt) /* USED GPIOs: */ GPIO(CCD_MODE_ODL, PIN(E, 5), GPIO_INPUT) @@ -69,7 +70,6 @@ GPIO(USB_C2_FRS_EN, PIN(D, 4), GPIO_OUT_LOW) /* Barreljack */ GPIO(EN_PPVAR_BJ_ADP, PIN(A, 2), GPIO_OUT_LOW) -GPIO(BJ_ADP_PRESENT_L, PIN(5, 6), GPIO_INPUT) /* * The NPCX keyboard driver does not use named GPIOs to access @@ -128,4 +128,4 @@ UNUSED(PIN(7, 3)) /* GPIO73 */ UNUSED(PIN(4, 1)) /* GPIO41 */ UNUSED(PIN(5, 0)) /* GPIO50 */ UNUSED(PIN(6, 0)) /* GPIO60 */ -UNUSED(PIN(C, 2)) /* GPIOC2 */
\ No newline at end of file +UNUSED(PIN(C, 2)) /* GPIOC2 */ |