summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2022-06-09 10:01:41 -0600
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-06-29 23:40:06 +0000
commitbd8cdbe80c41895a39591a3cb79d5a7f7f9d19fb (patch)
tree12d6123bbadf62111fb95a46088efbc05667f9db
parent122ce784c72a2c623dd9615eda5d2ff6a0fe2c94 (diff)
downloadchrome-ec-bd8cdbe80c41895a39591a3cb79d5a7f7f9d19fb.tar.gz
Agah: Enable Nvidia GPU D-Notify driver
This patch enables Nvidia GPU D-Notify driver for Agah. BUG=b:216485035, b:236674641 BRANCH=None TEST=On Agah, plug & unplug BJ & USB-C and verify expected modes (nvdc, nvdc_chrg, bypass, bypass_chrg, bat) are selected. TEST=On Agah, plug & unplug BJ & USB-C and verify expected D-levels are selected. Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> Change-Id: I17b60e6054c91c60a7c1931e10a738607951055c Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3704268 Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
-rw-r--r--board/agah/board.c13
-rw-r--r--board/agah/board.h5
-rw-r--r--board/agah/charger_isl9241.c218
-rw-r--r--board/agah/gpio.inc8
4 files changed, 146 insertions, 98 deletions
diff --git a/board/agah/board.c b/board/agah/board.c
index 979c9a38aa..47f2628fbb 100644
--- a/board/agah/board.c
+++ b/board/agah/board.c
@@ -26,6 +26,8 @@
#include "usbc_config.h"
#include "util.h"
+#include "driver/nvidia_gpu.h"
+
#include "gpio_list.h" /* Must come after other header files. */
/* Console output macros */
@@ -34,6 +36,15 @@
static int block_sequence;
+struct d_notify_policy d_notify_policies[] = {
+ AC_ATLEAST_W(100),
+ AC_ATLEAST_W(65),
+ AC_DC,
+ DC_ATLEAST_SOC(20),
+ DC_ATLEAST_SOC(5),
+};
+BUILD_ASSERT(ARRAY_SIZE(d_notify_policies) == D_NOTIFY_COUNT);
+
__override void board_cbi_init(void)
{
}
@@ -63,6 +74,8 @@ static void board_init(void)
}
gpio_enable_interrupt(GPIO_PG_PP3300_S5_OD);
gpio_enable_interrupt(GPIO_BJ_ADP_PRESENT_ODL);
+
+ nvidia_gpu_init_policy(d_notify_policies);
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
diff --git a/board/agah/board.h b/board/agah/board.h
index d4ce9f23d1..d03aba2580 100644
--- a/board/agah/board.h
+++ b/board/agah/board.h
@@ -14,6 +14,11 @@
#include "baseboard.h"
/*
+ * Nvidia GPU
+ */
+#define CONFIG_GPU_NVIDIA
+
+/*
* This will happen automatically on NPCX9 ES2 and later. Do not remove
* until we can confirm all earlier chips are out of service.
*/
diff --git a/board/agah/charger_isl9241.c b/board/agah/charger_isl9241.c
index 138c3841f7..1bc77c0ee4 100644
--- a/board/agah/charger_isl9241.c
+++ b/board/agah/charger_isl9241.c
@@ -3,6 +3,36 @@
* found in the LICENSE file.
*/
+/*
+ *
+ * We need to deal with plug / unplug of AC chargers:
+ *
+ * +---------+ +USB +---------+
+ * | BATTERY |------------>| BATTERY |
+ * | |<------------| +USB |
+ * +---------+ -USB +---------+
+ * | ^ | ^
+ * +BJ | | -BJ +BJ | | -BJ
+ * v | v |
+ * +---------+ +USB +---------+
+ * | BATTERY |------------>| BATTERY |
+ * | +BJ |<------------| +BJ+USB |
+ * +---------+ -USB +---------+
+ *
+ * Depending on available battery charge, power rating of the new charger, and
+ * the system power state, transition/throttling may or may not occur but
+ * switching chargers is handled as follows:
+ *
+ * 1. Detects a new charger or removal of an existing charger.
+ * 2. charge_manager_update_charge is called with new charger's info.
+ * 3. board_set_active_charge_port is called.
+ * 3.1 It triggers hard & soft throttling for AP & GPU.
+ * 3.2 It disable active port then enables the new port.
+ * 4. HOOK_POWER_SUPPLY_CHANGE is called. We disables hard throttling.
+ * 5. charger task wakes up on HOOK_POWER_SUPPLY_CHANGE, enables (or disables)
+ * bypass mode.
+ */
+
#include "common.h"
#include "charge_manager.h"
@@ -15,6 +45,7 @@
#include "gpio.h"
#include "hooks.h"
#include "stdbool.h"
+#include "throttle_ap.h"
#include "usbc_ppc.h"
#include "usb_pd.h"
#include "util.h"
@@ -32,71 +63,42 @@ const struct charger_config_t chg_chips[] = {
};
BUILD_ASSERT(ARRAY_SIZE(chg_chips) == CHARGER_NUM);
-static int board_disable_bj_port(void)
+static int board_enable_bj_port(bool enable)
{
- gpio_set_level(GPIO_EN_PPVAR_BJ_ADP_L, 1);
- /* If the current port is BJ, disable bypass mode. */
- if (charge_manager_get_supplier() == CHARGE_SUPPLIER_DEDICATED)
- return charger_enable_bypass_mode(0, 0);
+ if (enable) {
+ if (gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL))
+ return EC_ERROR_INVAL;
+ gpio_set_level(GPIO_EN_PPVAR_BJ_ADP_L, 0);
+ } else {
+ gpio_set_level(GPIO_EN_PPVAR_BJ_ADP_L, 1);
+ }
- CPRINTS("BJ power is disabled");
+ CPRINTS("BJ power is %sabled", enable ? "en" : "dis");
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_L, 0);
-
- 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)
+static void board_throttle_ap_gpu(void)
{
- 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;
+ throttle_ap(THROTTLE_ON, THROTTLE_HARD, THROTTLE_SRC_AC);
+ throttle_gpu(THROTTLE_ON, THROTTLE_HARD, THROTTLE_SRC_AC);
}
/* Disable all VBUS sink ports except <port>. <port> = -1 disables all ports. */
-static int board_disable_vbus_sink(int port)
+static int board_disable_other_vbus_sink(int except_port)
{
int i, r, rv = EC_SUCCESS;
for (i = 0; i < ppc_cnt; i++) {
- if (i == port)
+ if (i == except_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);
+ if (r)
+ CPRINTS("Failed to disable sink path C%d (%d)", i, r);
rv |= r;
}
@@ -107,74 +109,71 @@ static int board_disable_vbus_sink(int 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)
{
- enum charge_supplier supplier = charge_manager_get_supplier();
+ enum charge_supplier active_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);
+ CPRINTS("Switching charger from P%d (supplier=%d) to P%d",
+ active_port, active_supplier, port);
if (port == CHARGE_PORT_NONE) {
CPRINTS("Disabling all charger ports");
- board_throttle_ap_gpu(1);
-
- board_disable_bj_port();
- board_disable_vbus_sink(-1);
+ board_enable_bj_port(false);
+ board_disable_other_vbus_sink(-1);
return EC_SUCCESS;
}
+ /* Return on invalid or no-op call. */
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);
+ CPRINTS("Don't enable P%d. It's sourcing.", port);
return EC_ERROR_INVAL;
}
/*
+ * If we're in S0, throttle AP and GPU. They'll be unthrottled when
+ * a port/supply switch completes (via HOOK_POWER_SUPPLY_CHANGE).
+ *
+ * If we're running currently on a battery (active_supplier == NONE), we
+ * don't need to throttle because we're not disabling any port.
+ */
+ if (chipset_in_state(CHIPSET_STATE_ON)
+ && active_supplier != CHARGE_SUPPLIER_NONE)
+ board_throttle_ap_gpu();
+
+ /*
+ * We're here for the two cases:
+ * 1. A new charger was connected.
+ * 2. One charger was disconnected and we're switching to another.
+ */
+
+ /*
* 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.
*/
- if (supplier != CHARGE_SUPPLIER_NONE) {
+ if (active_supplier != CHARGE_SUPPLIER_NONE) {
if (charge_get_percent() < MIN_BATT_FOR_SWITCHING_SOURCE_PORT)
return EC_ERROR_NOT_POWERED;
}
/* Turn off other ports' sink paths before enabling requested port. */
- if (port == CHARGE_PORT_TYPEC0 || port == CHARGE_PORT_TYPEC1) {
+ if (is_pd_port(port)) {
/*
- * BJ port is on POR. So, we need to turn it off even if we're
- * not previously on BJ.
+ * BJ port is enabled on start-up. So, we need to turn it off
+ * even if we were not previously on BJ.
*/
- board_disable_bj_port();
- if (board_disable_vbus_sink(port))
+ board_enable_bj_port(false);
+ if (board_disable_other_vbus_sink(port))
return EC_ERROR_UNCHANGED;
/* Enable requested USBC charge port. */
@@ -187,16 +186,12 @@ int board_set_active_charge_port(int port)
* We can't proceed unless both ports are successfully
* disconnected as sources.
*/
- if (board_disable_vbus_sink(-1))
+ if (board_disable_other_vbus_sink(-1))
return EC_ERROR_UNKNOWN;
- board_enable_bj_port();
+ board_enable_bj_port(true);
}
- /* Switching port is complete. Turn off throttling. */
- if (supplier != CHARGE_SUPPLIER_NONE)
- board_throttle_ap_gpu(0);
-
- CPRINTS("New charger p%d", port);
+ CPRINTS("New charger P%d", port);
return EC_SUCCESS;
}
@@ -215,31 +210,62 @@ static const struct charge_port_info bj_power = {
};
/* Debounce time for BJ plug/unplug */
-#define BJ_DEBOUNCE_MS 1000
+#define BJ_DEBOUNCE_MS CONFIG_EXTPOWER_DEBOUNCE_MS
+
+int board_should_charger_bypass(void)
+{
+ return charge_manager_get_active_charge_port() == DEDICATED_CHARGE_PORT;
+}
-static void bj_connect_deferred(void)
+static void bj_connect(void)
{
static int8_t bj_connected = -1;
- const struct charge_port_info *pi = NULL;
int connected = !gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL);
+ /* Debounce */
if (connected == bj_connected)
return;
- if (connected)
- pi = &bj_power;
+ bj_connected = connected;
+ CPRINTS("BJ %sconnected", connected ? "" : "dis");
charge_manager_update_charge(CHARGE_SUPPLIER_DEDICATED,
- DEDICATED_CHARGE_PORT, pi);
- bj_connected = connected;
- CPRINTS("BJ %s", connected ? "connected" : "disconnected");
+ DEDICATED_CHARGE_PORT,
+ connected ? &bj_power : NULL);
}
-DECLARE_DEFERRED(bj_connect_deferred);
+DECLARE_DEFERRED(bj_connect);
+/* This handler shouldn't be needed if ACOK from isl9241 is working. */
void bj_present_interrupt(enum gpio_signal signal)
{
- hook_call_deferred(&bj_connect_deferred_data, BJ_DEBOUNCE_MS * MSEC);
+ hook_call_deferred(&bj_connect_data, BJ_DEBOUNCE_MS * MSEC);
+}
+
+void ac_change(void)
+{
+ /*
+ * Serialize. We don't handle USB-C here because we'll get a
+ * notification from TCPC.
+ */
+ hook_call_deferred(&bj_connect_data, 0);
+}
+DECLARE_HOOK(HOOK_AC_CHANGE, ac_change, HOOK_PRIO_DEFAULT);
+
+
+static void power_supply_changed(void)
+{
+ /*
+ * We've switched to a new charge port (or no port). Hardware throttles
+ * can be removed now. Software throttles may stay enabled and change
+ * as the situation changes.
+ */
+ throttle_ap(THROTTLE_OFF, THROTTLE_HARD, THROTTLE_SRC_AC);
+ /*
+ * Unthrottling GPU is done through a deferred call scheduled when it
+ * was throttled.
+ */
}
+DECLARE_HOOK(HOOK_POWER_SUPPLY_CHANGE, power_supply_changed, HOOK_PRIO_DEFAULT);
static void bj_state_init(void)
{
@@ -252,6 +278,6 @@ static void bj_state_init(void)
charge_manager_update_charge(j, i, NULL);
}
- bj_connect_deferred();
+ bj_connect();
}
DECLARE_HOOK(HOOK_INIT, bj_state_init, HOOK_PRIO_INIT_CHARGE_MANAGER + 1);
diff --git a/board/agah/gpio.inc b/board/agah/gpio.inc
index b708231cc4..7f38c87057 100644
--- a/board/agah/gpio.inc
+++ b/board/agah/gpio.inc
@@ -67,8 +67,13 @@ GPIO(VCCST_PWRGD_OD, PIN(A, 4), GPIO_ODR_LOW)
GPIO(EN_USB_A_LOW_POWER, PIN(9, 3), GPIO_OUT_LOW)
GPIO(PG_PP3300_S5_EC_SEQ_OD, PIN(B, 5), GPIO_OUT_LOW)
GPIO(USB_C2_FRS_EN, PIN(D, 4), GPIO_OUT_LOW)
+GPIO(NVIDIA_GPU_ACOFF_ODL, PIN(9, 5), GPIO_ODR_HIGH)
-/* Barreljack */
+/*
+ * Barrel-jack adapter enable switch. When starting up on a depleted battery,
+ * we'll be powered by either BJ or USB-C but not both. The EC will detect BJ
+ * or USBC and disable the other ports.
+ */
GPIO(EN_PPVAR_BJ_ADP_L, PIN(A, 2), GPIO_OUT_LOW)
/*
@@ -122,7 +127,6 @@ UNUSED(PIN(0, 2)) /* GPIO02 */
UNUSED(PIN(6, 6)) /* GPIO66 */
UNUSED(PIN(5, 7)) /* GPIO57/SER_IRQ/ESPI_ALERT_L */
UNUSED(PIN(8, 1)) /* GPIO81 */
-UNUSED(PIN(9, 5)) /* GPIO95 */
UNUSED(PIN(7, 3)) /* GPIO73 */
UNUSED(PIN(5, 0)) /* GPIO50 */
UNUSED(PIN(6, 0)) /* GPIO60 */