summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wang <chriswang@ami.corp-partner.google.com>2017-10-05 20:42:56 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-10-23 04:28:27 -0700
commitca013a9780b7d043fc2c126377f297cd557a0e31 (patch)
tree000d6e47591a793287959c1636c72972e0155578
parentf45c06abc665d3114d67e5138531c81be0d43b59 (diff)
downloadchrome-ec-ca013a9780b7d043fc2c126377f297cd557a0e31.tar.gz
ec: add initial nautilus board
For now use the files from poppy. To be changed later on. BUG=b:66458931 TEST=emerge-nautilus chromeos-ec/make buildall -j Change-Id: If829d7307f834f1f30878934623c0e9ee77b907d Signed-off-by: Chris Wang <chriswang@ami.corp-partner.google.com> Reviewed-on: https://chromium-review.googlesource.com/701996 Commit-Ready: Grace Kao <grace.kao@intel.com> Tested-by: Grace Kao <grace.kao@intel.com> Reviewed-by: Philip Chen <philipchen@chromium.org>
-rw-r--r--board/nautilus/battery.c172
-rw-r--r--board/nautilus/board.c1061
-rw-r--r--board/nautilus/board.h258
-rw-r--r--board/nautilus/build.mk15
-rw-r--r--board/nautilus/ec.tasklist36
-rw-r--r--board/nautilus/gpio.inc126
-rw-r--r--board/nautilus/led.c169
-rw-r--r--board/nautilus/usb_pd_policy.c443
-rw-r--r--chip/npcx/system.c4
-rwxr-xr-xutil/flash_ec2
10 files changed, 2285 insertions, 1 deletions
diff --git a/board/nautilus/battery.c b/board/nautilus/battery.c
new file mode 100644
index 0000000000..246250a88c
--- /dev/null
+++ b/board/nautilus/battery.c
@@ -0,0 +1,172 @@
+/* Copyright 2016 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.
+ *
+ * Placeholder values for temporary battery pack.
+ */
+
+#include "battery.h"
+#include "battery_smart.h"
+#include "charge_state.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "extpower.h"
+#include "gpio.h"
+#include "util.h"
+
+static enum battery_present batt_pres_prev = BP_NOT_SURE;
+
+/* Shutdown mode parameter to write to manufacturer access register */
+#define SB_SHIP_MODE_REG SB_MANUFACTURER_ACCESS
+#define SB_SHUTDOWN_DATA 0x0010
+
+static const struct battery_info info = {
+ .voltage_max = 13200,
+ .voltage_normal = 11550,
+ .voltage_min = 9100,
+ /* Pre-charge values. */
+ .precharge_current = 256, /* mA */
+
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 50,
+ .charging_min_c = 0,
+ .charging_max_c = 60,
+ .discharging_min_c = 0,
+ .discharging_max_c = 60,
+};
+
+const struct battery_info *battery_get_info(void)
+{
+ return &info;
+}
+
+int board_cut_off_battery(void)
+{
+ int rv;
+
+ /* Ship mode command must be sent twice to take effect */
+ rv = sb_write(SB_SHIP_MODE_REG, SB_SHUTDOWN_DATA);
+
+ if (rv != EC_SUCCESS)
+ return rv;
+
+ return sb_write(SB_SHIP_MODE_REG, SB_SHUTDOWN_DATA);
+}
+
+int charger_profile_override(struct charge_state_data *curr)
+{
+ const struct battery_info *batt_info;
+ int bat_temp_c;
+
+ batt_info = battery_get_info();
+
+ if ((curr->batt.flags & BATT_FLAG_BAD_ANY) == BATT_FLAG_BAD_ANY) {
+ curr->requested_current = batt_info->precharge_current;
+ curr->requested_voltage = batt_info->voltage_max;
+ return 1000;
+ }
+
+ /* battery temp in 0.1 deg C */
+ bat_temp_c = curr->batt.temperature - 2731;
+
+ /* Don't charge if outside of allowable temperature range */
+ if (bat_temp_c >= batt_info->charging_max_c * 10 ||
+ bat_temp_c < batt_info->charging_min_c * 10) {
+ curr->requested_current = 0;
+ curr->requested_voltage = 0;
+ curr->batt.flags &= ~BATT_FLAG_WANT_CHARGE;
+ curr->state = ST_IDLE;
+ }
+ return 0;
+}
+
+/* Customs options controllable by host command. */
+#define PARAM_FASTCHARGE (CS_PARAM_CUSTOM_PROFILE_MIN + 0)
+
+enum ec_status charger_profile_override_get_param(uint32_t param,
+ uint32_t *value)
+{
+ return EC_RES_INVALID_PARAM;
+}
+
+enum ec_status charger_profile_override_set_param(uint32_t param,
+ uint32_t value)
+{
+ return EC_RES_INVALID_PARAM;
+}
+
+enum battery_present battery_hw_present(void)
+{
+ /* The GPIO is low when the battery is physically present */
+ return gpio_get_level(GPIO_BATTERY_PRESENT_L) ? BP_NO : BP_YES;
+}
+
+static int battery_init(void)
+{
+ int batt_status;
+
+ return battery_status(&batt_status) ? 0 :
+ !!(batt_status & STATUS_INITIALIZED);
+}
+
+/*
+ * Check for case where both XCHG and XDSG bits are set indicating that even
+ * though the FG can be read from the battery, the battery is not able to be
+ * charged or discharged. This situation will happen if a battery disconnect was
+ * intiaited via H1 setting the DISCONN signal to the battery. This will put the
+ * battery pack into a sleep state and when power is reconnected, the FG can be
+ * read, but the battery is still not able to provide power to the system. The
+ * calling function returns batt_pres = BP_NO, which instructs the charging
+ * state machine to prevent powering up the AP on battery alone which could lead
+ * to a brownout event when the battery isn't able yet to provide power to the
+ * system. .
+ */
+static int battery_check_disconnect(void)
+{
+ int rv;
+ uint8_t data[6];
+
+ /* Check if battery charging + discharging is disabled. */
+ rv = sb_read_mfgacc(PARAM_OPERATION_STATUS,
+ SB_ALT_MANUFACTURER_ACCESS, data, sizeof(data));
+ if (rv)
+ return BATTERY_DISCONNECT_ERROR;
+
+ if ((data[3] & (BATTERY_DISCHARGING_DISABLED |
+ BATTERY_CHARGING_DISABLED)) ==
+ (BATTERY_DISCHARGING_DISABLED | BATTERY_CHARGING_DISABLED))
+ return BATTERY_DISCONNECTED;
+
+ return BATTERY_NOT_DISCONNECTED;
+}
+
+enum battery_present battery_is_present(void)
+{
+ enum battery_present batt_pres;
+
+ /* Get the physical hardware status */
+ batt_pres = battery_hw_present();
+
+ /*
+ * Make sure battery status is implemented, I2C transactions are
+ * success & the battery status is Initialized to find out if it
+ * is a working battery and it is not in the cut-off mode.
+ *
+ * If battery I2C fails but VBATT is high, battery is booting from
+ * cut-off mode.
+ *
+ * FETs are turned off after Power Shutdown time.
+ * The device will wake up when a voltage is applied to PACK.
+ * Battery status will be inactive until it is initialized.
+ */
+ if (batt_pres == BP_YES && batt_pres_prev != batt_pres &&
+ (battery_is_cut_off() != BATTERY_CUTOFF_STATE_NORMAL ||
+ battery_check_disconnect() != BATTERY_NOT_DISCONNECTED ||
+ battery_init() == 0)) {
+ batt_pres = BP_NO;
+ }
+
+ batt_pres_prev = batt_pres;
+ return batt_pres;
+}
+
diff --git a/board/nautilus/board.c b/board/nautilus/board.c
new file mode 100644
index 0000000000..ba3395e446
--- /dev/null
+++ b/board/nautilus/board.c
@@ -0,0 +1,1061 @@
+/* Copyright 2016 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.
+ */
+
+/* Poppy board-specific configuration */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "als.h"
+#include "bd99992gw.h"
+#include "board_config.h"
+#include "button.h"
+#include "charge_manager.h"
+#include "charge_state.h"
+#include "charge_ramp.h"
+#include "charger.h"
+#include "chipset.h"
+#include "console.h"
+#include "driver/accelgyro_bmi160.h"
+#include "driver/als_opt3001.h"
+#include "driver/baro_bmp280.h"
+#include "driver/tcpm/anx74xx.h"
+#include "driver/tcpm/ps8xxx.h"
+#include "driver/tcpm/tcpci.h"
+#include "driver/tcpm/tcpm.h"
+#include "driver/temp_sensor/bd99992gw.h"
+#include "extpower.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "i2c.h"
+#include "lid_switch.h"
+#include "math_util.h"
+#include "motion_lid.h"
+#include "motion_sense.h"
+#include "pi3usb9281.h"
+#include "power.h"
+#include "power_button.h"
+#include "spi.h"
+#include "switch.h"
+#include "system.h"
+#include "tablet_mode.h"
+#include "task.h"
+#include "temp_sensor.h"
+#include "timer.h"
+#include "uart.h"
+#include "usb_charge.h"
+#include "usb_mux.h"
+#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
+#include "util.h"
+#include "espi.h"
+
+#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
+
+#define USB_PD_PORT_ANX74XX 0
+
+static void tcpc_alert_event(enum gpio_signal signal)
+{
+ if ((signal == GPIO_USB_C0_PD_INT_ODL) &&
+ !gpio_get_level(GPIO_USB_C0_PD_RST_L))
+ return;
+ else if ((signal == GPIO_USB_C1_PD_INT_ODL) &&
+ !gpio_get_level(GPIO_USB_C1_PD_RST_L))
+ return;
+
+#ifdef HAS_TASK_PDCMD
+ /* Exchange status with TCPCs */
+ host_command_pd_send_status(PD_CHARGE_NO_CHANGE);
+#endif
+}
+
+/* Set PD discharge whenever VBUS detection is high (i.e. below threshold). */
+static void vbus_discharge_handler(void)
+{
+ if (system_get_board_version() >= 2) {
+ pd_set_vbus_discharge(0,
+ gpio_get_level(GPIO_USB_C0_VBUS_WAKE_L));
+ pd_set_vbus_discharge(1,
+ gpio_get_level(GPIO_USB_C1_VBUS_WAKE_L));
+ }
+}
+DECLARE_DEFERRED(vbus_discharge_handler);
+
+void vbus0_evt(enum gpio_signal signal)
+{
+ /* VBUS present GPIO is inverted */
+ usb_charger_vbus_change(0, !gpio_get_level(signal));
+ task_wake(TASK_ID_PD_C0);
+
+ hook_call_deferred(&vbus_discharge_handler_data, 0);
+}
+
+void vbus1_evt(enum gpio_signal signal)
+{
+ /* VBUS present GPIO is inverted */
+ usb_charger_vbus_change(1, !gpio_get_level(signal));
+ task_wake(TASK_ID_PD_C1);
+
+ hook_call_deferred(&vbus_discharge_handler_data, 0);
+}
+
+void usb0_evt(enum gpio_signal signal)
+{
+ task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0);
+}
+
+void usb1_evt(enum gpio_signal signal)
+{
+ task_set_event(TASK_ID_USB_CHG_P1, USB_CHG_EVENT_BC12, 0);
+}
+
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+static void anx74xx_cable_det_handler(void)
+{
+ int cable_det = gpio_get_level(GPIO_USB_C0_CABLE_DET);
+ int reset_n = gpio_get_level(GPIO_USB_C0_PD_RST_L);
+
+ /*
+ * A cable_det low->high transition was detected. If following the
+ * debounce time, cable_det is high, and reset_n is low, then ANX3429 is
+ * currently in standby mode and needs to be woken up. Set the
+ * TCPC_RESET event which will bring the ANX3429 out of standby
+ * mode. Setting this event is gated on reset_n being low because the
+ * ANX3429 will always set cable_det when transitioning to normal mode
+ * and if in normal mode, then there is no need to trigger a tcpc reset.
+ */
+ if (cable_det && !reset_n)
+ task_set_event(TASK_ID_PD_C0, PD_EVENT_TCPC_RESET, 0);
+}
+DECLARE_DEFERRED(anx74xx_cable_det_handler);
+
+void anx74xx_cable_det_interrupt(enum gpio_signal signal)
+{
+ /* debounce for 2 msec */
+ hook_call_deferred(&anx74xx_cable_det_handler_data, (2 * MSEC));
+}
+#endif
+
+/*
+ * Base detection and debouncing
+ *
+ * TODO(b/35585396): Fine-tune these values.
+ */
+#define BASE_DETECT_DEBOUNCE_US (20 * MSEC)
+
+/*
+ * rev0: Lid has 100K pull-up, base has 5.1K pull-down, so the ADC
+ * value should be around 5.1/(100+5.1)*3300 = 160.
+ * >=rev1: Lid has 604K pull-up, base has 30.1K pull-down, so the
+ * ADC value should be around 30.1/(604+30.1)*3300 = 156
+ *
+ * We add a significant marging on the maximum value, due to noise on the line,
+ * especially when PWM is active. See b/64193554 for details.
+ */
+#define BASE_DETECT_MIN_MV 120
+#define BASE_DETECT_MAX_MV 300
+
+/*
+ * When the base is connected in reverse, it presents a 100K pull-down,
+ * so the ADC value should be around 100/(604+100)*3300 = 469
+ *
+ * TODO(b:64370797): Do something with these values.
+ */
+#define BASE_DETECT_REVERSE_MIN_MV 450
+#define BASE_DETECT_REVERSE_MAX_MV 500
+
+/*
+ * Base EC pulses detection pin for 500 us to signal out of band USB wake (that
+ * can be used to wake system from deep S3).
+ */
+#define BASE_DETECT_PULSE_MIN_US 400
+#define BASE_DETECT_PULSE_MAX_US 650
+
+static uint64_t base_detect_debounce_time;
+
+static void base_detect_deferred(void);
+DECLARE_DEFERRED(base_detect_deferred);
+
+enum base_status {
+ BASE_UNKNOWN = 0,
+ BASE_DISCONNECTED = 1,
+ BASE_CONNECTED = 2,
+};
+
+static enum base_status current_base_status;
+
+/*
+ * This function is called whenever there is a change in the base detect
+ * status. Actions taken include:
+ * 1. Change in power to base
+ * 2. Indicate mode change to host.
+ * 3. Indicate tablet mode to host. Current assumption is that if base is
+ * disconnected then the system is in tablet mode, else if the base is
+ * connected, then the system is not in tablet mode.
+ */
+static void base_detect_change(enum base_status status)
+{
+ int connected = (status == BASE_CONNECTED);
+
+ if (current_base_status == status)
+ return;
+
+ CPRINTS("Base %sconnected", connected ? "" : "not ");
+ gpio_set_level(GPIO_PP3300_DX_BASE, connected);
+ host_set_single_event(EC_HOST_EVENT_MODE_CHANGE);
+ tablet_set_mode(!connected);
+ current_base_status = status;
+}
+
+/* Measure detection pin pulse duration (used to wake AP from deep S3). */
+static uint64_t pulse_start;
+static uint32_t pulse_width;
+
+static int command_attach_base(int argc, char **argv)
+{
+ host_set_single_event(EC_HOST_EVENT_MODE_CHANGE);
+ tablet_set_mode(0);
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(attachbase, command_attach_base,
+ NULL, "Simulate attach base");
+
+static int command_detach_base(int argc, char **argv)
+{
+ host_set_single_event(EC_HOST_EVENT_MODE_CHANGE);
+ tablet_set_mode(1);
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(detachbase, command_detach_base,
+ NULL, "Simulate detach base");
+
+
+static void base_detect_deferred(void)
+{
+ uint64_t time_now = get_time().val;
+ int v;
+ uint32_t tmp_pulse_width = pulse_width;
+
+ if (base_detect_debounce_time > time_now) {
+ hook_call_deferred(&base_detect_deferred_data,
+ base_detect_debounce_time - time_now);
+ return;
+ }
+
+ v = adc_read_channel(ADC_BASE_DET);
+ if (v == ADC_READ_ERROR)
+ return;
+ CPRINTS("%s = %d (pulse %d)", adc_channels[ADC_BASE_DET].name,
+ v, tmp_pulse_width);
+
+ if (v >= BASE_DETECT_MIN_MV && v <= BASE_DETECT_MAX_MV) {
+ if (current_base_status != BASE_CONNECTED) {
+ base_detect_change(BASE_CONNECTED);
+ } else if (tmp_pulse_width >= BASE_DETECT_PULSE_MIN_US &&
+ tmp_pulse_width <= BASE_DETECT_PULSE_MAX_US) {
+ CPRINTS("Sending event to AP");
+ host_set_single_event(EC_HOST_EVENT_KEY_PRESSED);
+ }
+ } else {
+ /*
+ * TODO(b/35585396): Figure out what to do with
+ * other ADC values that do not clearly indicate base
+ * presence or absence.
+ */
+ base_detect_change(BASE_DISCONNECTED);
+ }
+}
+
+static inline int detect_pin_connected(enum gpio_signal det_pin)
+{
+ return gpio_get_level(det_pin) == 0;
+}
+
+void base_detect_interrupt(enum gpio_signal signal)
+{
+ uint64_t time_now = get_time().val;
+
+ if (base_detect_debounce_time <= time_now) {
+ /*
+ * Detect and measure detection pin pulse, when base is
+ * connected. Only a single pulse is measured over a debounce
+ * period. If no pulse, or multiple pulses are detected,
+ * pulse_width is set to 0.
+ */
+ if (current_base_status == BASE_CONNECTED &&
+ !detect_pin_connected(signal)) {
+ pulse_start = time_now;
+ } else {
+ pulse_start = 0;
+ }
+ pulse_width = 0;
+
+ hook_call_deferred(&base_detect_deferred_data,
+ BASE_DETECT_DEBOUNCE_US);
+ } else {
+ if (current_base_status == BASE_CONNECTED &&
+ detect_pin_connected(signal) && !pulse_width &&
+ pulse_start) {
+ /* First pulse within period. */
+ pulse_width = time_now - pulse_start;
+ } else {
+ pulse_start = 0;
+ pulse_width = 0;
+ }
+ }
+
+ base_detect_debounce_time = time_now + BASE_DETECT_DEBOUNCE_US;
+}
+
+static void base_enable(void)
+{
+ /* Enable base detection interrupt. */
+ base_detect_debounce_time = get_time().val;
+ hook_call_deferred(&base_detect_deferred_data, 0);
+ gpio_enable_interrupt(GPIO_BASE_DET_A);
+}
+
+static void base_disable(void)
+{
+ /* Disable base detection interrupt and disable power to base. */
+ gpio_disable_interrupt(GPIO_BASE_DET_A);
+ base_detect_change(BASE_DISCONNECTED);
+}
+
+#include "gpio_list.h"
+
+/* power signal list. Must match order of enum power_signal. */
+const struct power_signal_info power_signal_list[] = {
+#ifdef CONFIG_POWER_S0IX
+ {GPIO_PCH_SLP_S0_L,
+ POWER_SIGNAL_ACTIVE_HIGH | POWER_SIGNAL_DISABLE_AT_BOOT,
+ "SLP_S0_DEASSERTED"},
+#endif
+#ifdef CONFIG_ESPI_VW_SIGNALS
+ {VW_SLP_S3_L, POWER_SIGNAL_ACTIVE_HIGH, "SLP_S3_DEASSERTED"},
+ {VW_SLP_S4_L, POWER_SIGNAL_ACTIVE_HIGH, "SLP_S4_DEASSERTED"},
+#else
+ {GPIO_PCH_SLP_S3_L, POWER_SIGNAL_ACTIVE_HIGH, "SLP_S3_DEASSERTED"},
+ {GPIO_PCH_SLP_S4_L, POWER_SIGNAL_ACTIVE_HIGH, "SLP_S4_DEASSERTED"},
+#endif
+ {GPIO_PCH_SLP_SUS_L, POWER_SIGNAL_ACTIVE_HIGH, "SLP_SUS_DEASSERTED"},
+ {GPIO_RSMRST_L_PGOOD, POWER_SIGNAL_ACTIVE_HIGH, "RSMRST_L_PGOOD"},
+ {GPIO_PMIC_DPWROK, POWER_SIGNAL_ACTIVE_HIGH, "PMIC_DPWROK"},
+};
+BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
+
+/* Hibernate wake configuration */
+const enum gpio_signal hibernate_wake_pins[] = {
+ GPIO_AC_PRESENT,
+ GPIO_POWER_BUTTON_L,
+};
+const int hibernate_wake_pins_used = ARRAY_SIZE(hibernate_wake_pins);
+
+/* ADC channels */
+const struct adc_t adc_channels[] = {
+ /* Base detection */
+ [ADC_BASE_DET] = {"BASE_DET", NPCX_ADC_CH0,
+ ADC_MAX_VOLT, ADC_READ_MAX+1, 0},
+ /* Vbus sensing (10x voltage divider). */
+ [ADC_VBUS] = {"VBUS", NPCX_ADC_CH2, ADC_MAX_VOLT*10, ADC_READ_MAX+1, 0},
+ /*
+ * Adapter current output or battery charging/discharging current (uV)
+ * 18x amplification on charger side.
+ */
+ [ADC_AMON_BMON] = {"AMON_BMON", NPCX_ADC_CH1, ADC_MAX_VOLT*1000/18,
+ ADC_READ_MAX+1, 0},
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
+/* I2C port map */
+const struct i2c_port_t i2c_ports[] = {
+ {"tcpc", NPCX_I2C_PORT0_0, 400, GPIO_I2C0_0_SCL, GPIO_I2C0_0_SDA},
+ {"als", NPCX_I2C_PORT0_1, 400, GPIO_I2C0_1_SCL, GPIO_I2C0_1_SDA},
+ {"charger", NPCX_I2C_PORT1, 100, GPIO_I2C1_SCL, GPIO_I2C1_SDA},
+ {"pmic", NPCX_I2C_PORT2, 400, GPIO_I2C2_SCL, GPIO_I2C2_SDA},
+ {"accelgyro", NPCX_I2C_PORT3, 400, GPIO_I2C3_SCL, GPIO_I2C3_SDA},
+};
+const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
+
+/* TCPC mux configuration */
+const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_COUNT] = {
+ {NPCX_I2C_PORT0_0, 0x50, &anx74xx_tcpm_drv, TCPC_ALERT_ACTIVE_LOW},
+ {NPCX_I2C_PORT0_0, 0x16, &ps8xxx_tcpm_drv, TCPC_ALERT_ACTIVE_LOW},
+};
+
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .port_addr = 0, /* don't care / unused */
+ .driver = &anx74xx_tcpm_usb_mux_driver,
+ .hpd_update = &anx74xx_tcpc_update_hpd_status,
+ },
+ {
+ .port_addr = 1,
+ .driver = &tcpci_tcpm_usb_mux_driver,
+ .hpd_update = &ps8xxx_tcpc_update_hpd_status,
+ }
+};
+
+struct pi3usb9281_config pi3usb9281_chips[] = {
+ {
+ .i2c_port = I2C_PORT_USB_CHARGER_0,
+ .mux_lock = NULL,
+ },
+ {
+ .i2c_port = I2C_PORT_USB_CHARGER_1,
+ .mux_lock = NULL,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(pi3usb9281_chips) ==
+ CONFIG_BC12_DETECT_PI3USB9281_CHIP_COUNT);
+
+/**
+ * Power on (or off) a single TCPC.
+ * minimum on/off delays are included.
+ *
+ * @param port Port number of TCPC.
+ * @param mode 0: power off, 1: power on.
+ */
+void board_set_tcpc_power_mode(int port, int mode)
+{
+ if (port != USB_PD_PORT_ANX74XX)
+ return;
+
+ if (mode) {
+ gpio_set_level(GPIO_USB_C0_TCPC_PWR, 1);
+ msleep(ANX74XX_PWR_H_RST_H_DELAY_MS);
+ gpio_set_level(GPIO_USB_C0_PD_RST_L, 1);
+ } else {
+ gpio_set_level(GPIO_USB_C0_PD_RST_L, 0);
+ msleep(ANX74XX_RST_L_PWR_L_DELAY_MS);
+ gpio_set_level(GPIO_USB_C0_TCPC_PWR, 0);
+ msleep(ANX74XX_PWR_L_PWR_H_DELAY_MS);
+ }
+}
+
+void board_reset_pd_mcu(void)
+{
+ /* Assert reset */
+ gpio_set_level(GPIO_USB_C0_PD_RST_L, 0);
+ gpio_set_level(GPIO_USB_C1_PD_RST_L, 0);
+
+ msleep(MAX(1, ANX74XX_RST_L_PWR_L_DELAY_MS));
+ gpio_set_level(GPIO_USB_C1_PD_RST_L, 1);
+ /* Disable TCPC0 (anx3429) power */
+ gpio_set_level(GPIO_USB_C0_TCPC_PWR, 0);
+
+ msleep(ANX74XX_PWR_L_PWR_H_DELAY_MS);
+ board_set_tcpc_power_mode(USB_PD_PORT_ANX74XX, 1);
+}
+
+void board_tcpc_init(void)
+{
+ int port, reg;
+
+ /* Only reset TCPC if not sysjump */
+ if (!system_jumped_to_this_image()) {
+ gpio_set_level(GPIO_PP3300_USB_PD, 1);
+ /* TODO(crosbug.com/p/61098): How long do we need to wait? */
+ msleep(10);
+ board_reset_pd_mcu();
+ }
+
+ /*
+ * TODO: Remove when Poppy is updated with PS8751 A3.
+ *
+ * Force PS8751 A2 to wake from low power mode.
+ * If PS8751 remains in low power mode after sysjump,
+ * TCPM_INIT will fail due to not able to access PS8751.
+ *
+ * NOTE: PS8751 A3 will wake on any I2C access.
+ */
+ i2c_read8(NPCX_I2C_PORT0_1, 0x10, 0xA0, &reg);
+
+ /* Enable TCPC interrupts */
+ gpio_enable_interrupt(GPIO_USB_C0_PD_INT_ODL);
+ gpio_enable_interrupt(GPIO_USB_C1_PD_INT_ODL);
+
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ /* Enable CABLE_DET interrupt for ANX3429 wake from standby */
+ gpio_enable_interrupt(GPIO_USB_C0_CABLE_DET);
+#endif
+
+ /*
+ * Initialize HPD to low; after sysjump SOC needs to see
+ * HPD pulse to enable video path
+ */
+ for (port = 0; port < CONFIG_USB_PD_PORT_COUNT; port++) {
+ const struct usb_mux *mux = &usb_muxes[port];
+
+ mux->hpd_update(port, 0, 0);
+ }
+}
+DECLARE_HOOK(HOOK_INIT, board_tcpc_init, HOOK_PRIO_INIT_I2C+1);
+
+uint16_t tcpc_get_alert_status(void)
+{
+ uint16_t status = 0;
+
+ if (!gpio_get_level(GPIO_USB_C0_PD_INT_ODL)) {
+ if (gpio_get_level(GPIO_USB_C0_PD_RST_L))
+ status |= PD_STATUS_TCPC_ALERT_0;
+ }
+
+ if (!gpio_get_level(GPIO_USB_C1_PD_INT_ODL)) {
+ if (gpio_get_level(GPIO_USB_C1_PD_RST_L))
+ status |= PD_STATUS_TCPC_ALERT_1;
+ }
+
+ return status;
+}
+
+const struct temp_sensor_t temp_sensors[] = {
+ {"Battery", TEMP_SENSOR_TYPE_BATTERY, charge_get_battery_temp, 0, 4},
+
+ /* These BD99992GW temp sensors are only readable in S0 */
+ {"Ambient", TEMP_SENSOR_TYPE_BOARD, bd99992gw_get_val,
+ BD99992GW_ADC_CHANNEL_SYSTHERM0, 4},
+ {"Charger", TEMP_SENSOR_TYPE_BOARD, bd99992gw_get_val,
+ BD99992GW_ADC_CHANNEL_SYSTHERM1, 4},
+ {"DRAM", TEMP_SENSOR_TYPE_BOARD, bd99992gw_get_val,
+ BD99992GW_ADC_CHANNEL_SYSTHERM2, 4},
+ {"eMMC", TEMP_SENSOR_TYPE_BOARD, bd99992gw_get_val,
+ BD99992GW_ADC_CHANNEL_SYSTHERM3, 4},
+};
+BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
+
+/* ALS instances. Must be in same order as enum als_id. */
+struct als_t als[] = {
+ /* TODO(crosbug.com/p/61098): verify attenuation_factor */
+ {"TI", opt3001_init, opt3001_read_lux, 5},
+};
+BUILD_ASSERT(ARRAY_SIZE(als) == ALS_COUNT);
+
+const struct button_config buttons[CONFIG_BUTTON_COUNT] = {
+ [BUTTON_VOLUME_DOWN] = {"Volume Down", KEYBOARD_BUTTON_VOLUME_DOWN,
+ GPIO_VOLUME_DOWN_L, 30 * MSEC, 0},
+ [BUTTON_VOLUME_UP] = {"Volume Up", KEYBOARD_BUTTON_VOLUME_UP,
+ GPIO_VOLUME_UP_L, 30 * MSEC, 0},
+};
+
+const struct button_config *recovery_buttons[] = {
+ &buttons[BUTTON_VOLUME_DOWN],
+ &buttons[BUTTON_VOLUME_UP],
+};
+const int recovery_buttons_count = ARRAY_SIZE(recovery_buttons);
+
+static void board_pmic_disable_slp_s0_vr_decay(void)
+{
+ /*
+ * VCCIOCNT:
+ * Bit 6 (0) - Disable decay of VCCIO on SLP_S0# assertion
+ * Bits 5:4 (00) - Nominal output voltage: 0.975V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x30, 0xa);
+
+ /*
+ * V18ACNT:
+ * Bits 7:6 (00) - Disable low power mode on SLP_S0# assertion
+ * Bits 5:4 (10) - Nominal voltage set to 1.8V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x34, 0x2a);
+
+ /*
+ * V100ACNT:
+ * Bits 7:6 (00) - Disable low power mode on SLP_S0# assertion
+ * Bits 5:4 (01) - Nominal voltage 1.0V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x37, 0x1a);
+
+ /*
+ * V085ACNT:
+ * Bits 7:6 (00) - Disable low power mode on SLP_S0# assertion
+ * Bits 5:4 (11) - Nominal voltage 1.0V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x38, 0x3a);
+}
+
+static void board_pmic_enable_slp_s0_vr_decay(void)
+{
+ /*
+ * VCCIOCNT:
+ * Bit 6 (1) - Enable decay of VCCIO on SLP_S0# assertion
+ * Bits 5:4 (00) - Nominal output voltage: 0.975V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x30, 0x4a);
+
+ /*
+ * V18ACNT:
+ * Bits 7:6 (01) - Enable low power mode on SLP_S0# assertion
+ * Bits 5:4 (10) - Nominal voltage set to 1.8V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x34, 0x6a);
+
+ /*
+ * V100ACNT:
+ * Bits 7:6 (01) - Enable low power mode on SLP_S0# assertion
+ * Bits 5:4 (01) - Nominal voltage 1.0V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x37, 0x5a);
+
+ /*
+ * V085ACNT:
+ * Bits 7:6 (01) - Enable low power mode on SLP_S0# assertion
+ * Bits 5:4 (11) - Nominal voltage 1.0V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x38, 0x7a);
+}
+
+void power_board_handle_host_sleep_event(enum host_sleep_event state)
+{
+ if (state == HOST_SLEEP_EVENT_S0IX_SUSPEND)
+ board_pmic_enable_slp_s0_vr_decay();
+ else if (state == HOST_SLEEP_EVENT_S0IX_RESUME)
+ board_pmic_disable_slp_s0_vr_decay();
+}
+
+static void board_pmic_init(void)
+{
+ if (system_jumped_to_this_image())
+ return;
+
+ /* DISCHGCNT3 - enable 100 ohm discharge on V1.00A */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x3e, 0x04);
+
+ board_pmic_disable_slp_s0_vr_decay();
+
+ /* VRMODECTRL - disable low-power mode for all rails */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x3b, 0x1f);
+}
+DECLARE_HOOK(HOOK_INIT, board_pmic_init, HOOK_PRIO_DEFAULT);
+
+/* Initialize board. */
+static void board_init(void)
+{
+ /*
+ * This enables pull-down on F_DIO1 (SPI MISO), and F_DIO0 (SPI MOSI),
+ * whenever the EC is not doing SPI flash transactions. This avoids
+ * floating SPI buffer input (MISO), which causes power leakage (see
+ * b/64797021).
+ */
+ NPCX_PUPD_EN1 |= (1 << NPCX_DEVPU1_F_SPI_PUD_EN);
+
+ /* Provide AC status to the PCH */
+ gpio_set_level(GPIO_PCH_ACOK, extpower_is_present());
+
+ /* Enable sensors power supply */
+ gpio_set_level(GPIO_PP1800_DX_SENSOR, 1);
+ gpio_set_level(GPIO_PP3300_DX_SENSOR, 1);
+
+ /* Enable VBUS interrupt */
+ if (system_get_board_version() == 0) {
+ /*
+ * crosbug.com/p/61929: rev0 does not have VBUS detection,
+ * force detection on both ports.
+ */
+ gpio_set_flags(GPIO_USB_C0_VBUS_WAKE_L,
+ GPIO_INPUT | GPIO_PULL_DOWN);
+ gpio_set_flags(GPIO_USB_C1_VBUS_WAKE_L,
+ GPIO_INPUT | GPIO_PULL_DOWN);
+
+ vbus0_evt(GPIO_USB_C0_VBUS_WAKE_L);
+ vbus1_evt(GPIO_USB_C1_VBUS_WAKE_L);
+ } else {
+ gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE_L);
+ gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE_L);
+ }
+
+ /* Enable pericom BC1.2 interrupts */
+ gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_L);
+ gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_L);
+
+ /*
+ * If we jumped to this image and chipset is already in S0, enable
+ * base.
+ */
+ if (system_jumped_to_this_image() && chipset_in_state(CHIPSET_STATE_ON))
+ base_enable();
+}
+DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+
+/**
+ * Buffer the AC present GPIO to the PCH.
+ */
+static void board_extpower(void)
+{
+ gpio_set_level(GPIO_PCH_ACOK, extpower_is_present());
+}
+DECLARE_HOOK(HOOK_AC_CHANGE, board_extpower, HOOK_PRIO_DEFAULT);
+
+/**
+ * Set active charge port -- only one port can be active at a time.
+ *
+ * @param charge_port Charge port to enable.
+ *
+ * Returns EC_SUCCESS if charge port is accepted and made active,
+ * EC_ERROR_* otherwise.
+ */
+int board_set_active_charge_port(int charge_port)
+{
+ static uint8_t initialized;
+ /* charge port is a physical port */
+ int is_real_port = (charge_port >= 0 &&
+ charge_port < CONFIG_USB_PD_PORT_COUNT);
+ /* check if we are source VBUS on the port */
+ int source = gpio_get_level(charge_port == 0 ? GPIO_USB_C0_5V_EN :
+ GPIO_USB_C1_5V_EN);
+
+ if (is_real_port && source) {
+ CPRINTF("Skip enable p%d", charge_port);
+ return EC_ERROR_INVAL;
+ }
+
+ if (!initialized &&
+ charge_port == CHARGE_PORT_NONE &&
+ charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) {
+ CPRINTS("Bat critical, don't stop charging");
+ return -1;
+ }
+
+ CPRINTF("New chg p%d", charge_port);
+
+ if (charge_port == CHARGE_PORT_NONE) {
+ /* Disable both ports */
+ gpio_set_level(GPIO_USB_C0_CHARGE_L, 1);
+ gpio_set_level(GPIO_USB_C1_CHARGE_L, 1);
+ } else {
+ /* Make sure non-charging port is disabled */
+ gpio_set_level(charge_port ? GPIO_USB_C0_CHARGE_L :
+ GPIO_USB_C1_CHARGE_L, 1);
+ /* Enable charging port */
+ gpio_set_level(charge_port ? GPIO_USB_C1_CHARGE_L :
+ GPIO_USB_C0_CHARGE_L, 0);
+ }
+
+ initialized = 1;
+ return EC_SUCCESS;
+}
+
+/**
+ * Set the charge limit based upon desired maximum.
+ *
+ * @param port Port number.
+ * @param supplier Charge supplier type.
+ * @param charge_ma Desired charge limit (mA).
+ * @param charge_mv Negotiated charge voltage (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);
+}
+
+/**
+ * Return whether ramping is allowed for given supplier
+ */
+int board_is_ramp_allowed(int supplier)
+{
+ /* Don't allow ramping in RO when write protected */
+ if (!system_is_in_rw() && system_is_locked())
+ return 0;
+ else
+ return (supplier == CHARGE_SUPPLIER_BC12_DCP ||
+ supplier == CHARGE_SUPPLIER_BC12_SDP ||
+ supplier == CHARGE_SUPPLIER_BC12_CDP ||
+ supplier == CHARGE_SUPPLIER_OTHER);
+}
+
+/**
+ * Return the maximum allowed input current
+ */
+int board_get_ramp_current_limit(int supplier, int sup_curr)
+{
+ switch (supplier) {
+ case CHARGE_SUPPLIER_BC12_DCP:
+ return 2000;
+ case CHARGE_SUPPLIER_BC12_SDP:
+ return 1000;
+ case CHARGE_SUPPLIER_BC12_CDP:
+ case CHARGE_SUPPLIER_PROPRIETARY:
+ return sup_curr;
+ default:
+ return 500;
+ }
+}
+
+/**
+ * Return if board is consuming full amount of input current
+ */
+int board_is_consuming_full_charge(void)
+{
+ int chg_perc = charge_get_percent();
+
+ return chg_perc > 2 && chg_perc < 95;
+}
+
+
+void board_hibernate(void)
+{
+ CPRINTS("Triggering PMIC shutdown.");
+ uart_flush_output();
+
+ /* Trigger PMIC shutdown. */
+ if (i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x49, 0x01)) {
+ /*
+ * If we can't tell the PMIC to shutdown, instead reset
+ * and don't start the AP. Hopefully we'll be able to
+ * communicate with the PMIC next time.
+ */
+ CPRINTS("PMIC i2c failed.");
+ system_reset(SYSTEM_RESET_LEAVE_AP_OFF);
+ }
+
+ /* Await shutdown. */
+ while (1)
+ ;
+}
+
+int board_get_version(void)
+{
+ static int ver = -1;
+ uint8_t id4;
+
+ if (ver != -1)
+ return ver;
+
+ ver = 0;
+
+ /* First 3 strappings are binary. */
+ if (gpio_get_level(GPIO_BOARD_VERSION1))
+ ver |= 0x01;
+ if (gpio_get_level(GPIO_BOARD_VERSION2))
+ ver |= 0x02;
+ if (gpio_get_level(GPIO_BOARD_VERSION3))
+ ver |= 0x04;
+
+ /*
+ * 4th bit is using tristate strapping, ternary encoding:
+ * Hi-Z (id4=2) => 0, (id4=0) => 1, (id4=1) => 2
+ */
+ id4 = gpio_get_ternary(GPIO_BOARD_VERSION4);
+ ver |= ((id4 + 1) % 3) * 0x08;
+
+ CPRINTS("Board ID = %d", ver);
+
+ return ver;
+}
+
+/* Lid Sensor mutex */
+static struct mutex g_lid_mutex;
+
+static struct bmi160_drv_data_t g_bmi160_data;
+
+/* Matrix to rotate accelrator into standard reference frame */
+const matrix_3x3_t mag_standard_ref = {
+ { FLOAT_TO_FP(-1), 0, 0},
+ { 0, FLOAT_TO_FP(1), 0},
+ { 0, 0, FLOAT_TO_FP(-1)}
+};
+
+const matrix_3x3_t lid_standard_ref = {
+ {FLOAT_TO_FP(-1), 0, 0},
+ { 0, FLOAT_TO_FP(-1), 0},
+ { 0, 0, FLOAT_TO_FP(1)}
+};
+
+struct motion_sensor_t motion_sensors[] = {
+ [LID_ACCEL] = {
+ .name = "Lid Accel",
+ .active_mask = SENSOR_ACTIVE_S0,
+ .chip = MOTIONSENSE_CHIP_BMI160,
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .location = MOTIONSENSE_LOC_LID,
+ .drv = &bmi160_drv,
+ .mutex = &g_lid_mutex,
+ .drv_data = &g_bmi160_data,
+ .port = I2C_PORT_GYRO,
+ .addr = BMI160_ADDR0,
+ .rot_standard_ref = &lid_standard_ref,
+ .default_range = 2, /* g, enough for laptop. */
+ .min_frequency = BMI160_ACCEL_MIN_FREQ,
+ .max_frequency = BMI160_ACCEL_MAX_FREQ,
+ .config = {
+ /* AP: by default use EC settings */
+ [SENSOR_CONFIG_AP] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* EC use accel for angle detection */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 100 * MSEC,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 0,
+ .ec_rate = 0
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S5] = {
+ .odr = 0,
+ .ec_rate = 0
+ },
+ },
+ },
+
+ [LID_GYRO] = {
+ .name = "Lid Gyro",
+ .active_mask = SENSOR_ACTIVE_S0,
+ .chip = MOTIONSENSE_CHIP_BMI160,
+ .type = MOTIONSENSE_TYPE_GYRO,
+ .location = MOTIONSENSE_LOC_LID,
+ .drv = &bmi160_drv,
+ .mutex = &g_lid_mutex,
+ .drv_data = &g_bmi160_data,
+ .port = I2C_PORT_GYRO,
+ .addr = BMI160_ADDR0,
+ .default_range = 1000, /* dps */
+ .rot_standard_ref = &lid_standard_ref,
+ .min_frequency = BMI160_GYRO_MIN_FREQ,
+ .max_frequency = BMI160_GYRO_MAX_FREQ,
+ .config = {
+ /* AP: by default shutdown all sensors */
+ [SENSOR_CONFIG_AP] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* EC does not need in S0 */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S5] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ },
+ },
+
+ [LID_MAG] = {
+ .name = "Lid Mag",
+ .active_mask = SENSOR_ACTIVE_S0,
+ .chip = MOTIONSENSE_CHIP_BMI160,
+ .type = MOTIONSENSE_TYPE_MAG,
+ .location = MOTIONSENSE_LOC_LID,
+ .drv = &bmi160_drv,
+ .mutex = &g_lid_mutex,
+ .drv_data = &g_bmi160_data,
+ .port = I2C_PORT_GYRO,
+ .addr = BMI160_ADDR0,
+ .default_range = 1 << 11, /* 16LSB / uT, fixed */
+ .rot_standard_ref = &mag_standard_ref,
+ .min_frequency = BMM150_MAG_MIN_FREQ,
+ .max_frequency = BMM150_MAG_MAX_FREQ,
+ .config = {
+ /* AP: by default shutdown all sensors */
+ [SENSOR_CONFIG_AP] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* EC does not need in S0 */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S5] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ },
+ },
+};
+const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
+
+/* Called on AP S3 -> S0 transition */
+static void board_chipset_resume(void)
+{
+ gpio_set_level(GPIO_ENABLE_BACKLIGHT, 1);
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, board_chipset_resume, HOOK_PRIO_DEFAULT);
+
+/* Called on AP S0 -> S3 transition */
+static void board_chipset_suspend(void)
+{
+ gpio_set_level(GPIO_ENABLE_BACKLIGHT, 0);
+}
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, board_chipset_suspend, HOOK_PRIO_DEFAULT);
+
+static void board_chipset_startup(void)
+{
+ /*
+ * Enable V5A in deep sleep state:
+ * VREN (bit 0) : EC_DS4 enable
+ * - Enables V5A voltage regulator in deep Sx states
+ * V5ADS3CNT (bits 1:0) : AUTO
+ * - Control to the VR (0 = off, 1 = PFM, 2 = AUTO, 3 = Forced PWM)
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x41, 0x01);
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x2a, 0x02);
+
+ base_enable();
+}
+DECLARE_HOOK(HOOK_CHIPSET_STARTUP, board_chipset_startup, HOOK_PRIO_DEFAULT);
+
+static void board_chipset_shutdown(void)
+{
+ /*
+ * V5A VREN needs to be reset when chipset is shutdown. This is required
+ * because VREN keeps the V5A powered in all deep Sx states including
+ * deep S5. There is no need to power this rail in deep S5 as wake from
+ * base is not required.
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x41, 0x0);
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x2a, 0x0);
+
+ base_disable();
+}
+DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, board_chipset_shutdown, HOOK_PRIO_DEFAULT);
+
+int board_has_working_reset_flags(void)
+{
+ int version = system_get_board_version();
+
+ /* Boards Rev1 and Rev2 will lose reset flags on power cycle. */
+ if ((version == 1) || (version == 2))
+ return 0;
+
+ /* All other board versions should have working reset flags */
+ return 1;
+}
diff --git a/board/nautilus/board.h b/board/nautilus/board.h
new file mode 100644
index 0000000000..75188e056a
--- /dev/null
+++ b/board/nautilus/board.h
@@ -0,0 +1,258 @@
+/* Copyright 2016 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.
+ */
+
+/* Eve board configuration */
+
+#ifndef __CROS_EC_BOARD_H
+#define __CROS_EC_BOARD_H
+
+/*
+ * Allow dangerous commands.
+ * TODO: Remove this config before production.
+ */
+#define CONFIG_SYSTEM_UNLOCKED
+
+/* EC */
+#define CONFIG_ADC
+#define CONFIG_BACKLIGHT_LID
+#define CONFIG_BOARD_VERSION
+#define CONFIG_BOARD_SPECIFIC_VERSION
+#define CONFIG_BUTTON_COUNT 2
+#define CONFIG_BUTTON_RECOVERY
+#define CONFIG_CASE_CLOSED_DEBUG_EXTERNAL
+#define CONFIG_DPTF
+#define CONFIG_EMULATED_SYSRQ
+#define CONFIG_FLASH_SIZE 0x80000
+#define CONFIG_FPU
+#define CONFIG_I2C
+#define CONFIG_I2C_MASTER
+#define CONFIG_LED_COMMON
+#define CONFIG_LID_SWITCH
+#define CONFIG_LOW_POWER_IDLE
+#define CONFIG_LTO
+#define CONFIG_CHIP_PANIC_BACKUP
+#define CONFIG_SPI_FLASH_REGS
+#define CONFIG_SPI_FLASH_W25X40
+#define CONFIG_UART_HOST 0
+#define CONFIG_VBOOT_HASH
+#define CONFIG_SHA256_UNROLLED
+#define CONFIG_VSTORE
+#define CONFIG_VSTORE_SLOT_COUNT 1
+#define CONFIG_WATCHDOG_HELP
+#define CONFIG_WIRELESS
+#define CONFIG_WIRELESS_SUSPEND \
+ (EC_WIRELESS_SWITCH_WLAN | EC_WIRELESS_SWITCH_WLAN_POWER)
+#define WIRELESS_GPIO_WLAN GPIO_WLAN_OFF_L
+#define WIRELESS_GPIO_WLAN_POWER GPIO_PP3300_DX_WLAN
+#define WIRELESS_GPIO_WWAN GPIO_PP3300_DX_LTE
+
+/* EC console commands */
+#define CONFIG_CMD_ACCELS
+#define CONFIG_CMD_ACCEL_INFO
+#define CONFIG_CMD_BUTTON
+
+/* SOC */
+#define CONFIG_CHIPSET_SKYLAKE
+#define CONFIG_CHIPSET_HAS_PLATFORM_PMIC_RESET
+#define CONFIG_CHIPSET_RESET_HOOK
+#define CONFIG_ESPI
+#define CONFIG_ESPI_VW_SIGNALS
+#define CONFIG_LPC
+#undef CONFIG_PECI
+
+/* Battery */
+#define CONFIG_BATTERY_CUT_OFF
+#define CONFIG_BATTERY_DEVICE_CHEMISTRY "LION"
+#define CONFIG_BATTERY_SMART
+
+/* Charger */
+#define CONFIG_CHARGE_MANAGER
+#define CONFIG_CHARGE_RAMP_HW /* This, or just RAMP? */
+
+#define CONFIG_CHARGER
+#define CONFIG_CHARGER_V2
+#define CONFIG_CHARGER_ISL9238
+#define CONFIG_CHARGER_DISCHARGE_ON_AC
+#define CONFIG_CHARGER_INPUT_CURRENT 512
+#define CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON 2
+#define CONFIG_CHARGER_NARROW_VDC
+#define CONFIG_CHARGER_PROFILE_OVERRIDE
+#define CONFIG_CHARGER_PSYS
+#define CONFIG_CHARGER_SENSE_RESISTOR 10
+#define CONFIG_CHARGER_SENSE_RESISTOR_AC 20
+#define CONFIG_CMD_CHARGER_ADC_AMON_BMON
+#define CONFIG_CMD_PD_CONTROL
+#define CONFIG_EXTPOWER_GPIO
+#undef CONFIG_EXTPOWER_DEBOUNCE_MS
+#define CONFIG_EXTPOWER_DEBOUNCE_MS 1000
+#define CONFIG_POWER_BUTTON
+#define CONFIG_POWER_BUTTON_X86
+#define CONFIG_POWER_COMMON
+#define CONFIG_POWER_SIGNAL_INTERRUPT_STORM_DETECT_THRESHOLD 30
+#define CONFIG_POWER_S0IX
+#define CONFIG_POWER_TRACK_HOST_SLEEP_STATE
+
+/* Sensor */
+#define CONFIG_ALS
+#define CONFIG_ALS_OPT3001
+#define OPT3001_I2C_ADDR OPT3001_I2C_ADDR1
+#define CONFIG_TEMP_SENSOR
+#define CONFIG_TEMP_SENSOR_BD99992GW
+/* TODO(crosbug.com/p/61098): Is this the correct thermistor? */
+#define CONFIG_THERMISTOR_NCP15WB
+
+#define CONFIG_KEYBOARD_PROTOCOL_MKBP
+#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_HOST_EVENT
+#define CONFIG_ACCELGYRO_BMI160
+#define CONFIG_MAG_BMI160_BMM150
+#define CONFIG_ACCEL_INTERRUPTS
+#define CONFIG_ACCELGYRO_BMI160_INT_EVENT TASK_EVENT_CUSTOM(4)
+#define BMM150_I2C_ADDRESS BMM150_ADDR0 /* 8-bit address */
+#define CONFIG_MAG_CALIBRATE
+
+/* FIFO size is in power of 2. */
+#define CONFIG_ACCEL_FIFO 1024
+
+/* Depends on how fast the AP boots and typical ODRs */
+#define CONFIG_ACCEL_FIFO_THRES (CONFIG_ACCEL_FIFO / 3)
+
+#define CONFIG_TABLET_MODE
+#define CONFIG_TABLET_MODE_SWITCH
+
+/* USB */
+#define CONFIG_USB_CHARGER
+#define CONFIG_USB_PD_ALT_MODE
+#define CONFIG_USB_PD_ALT_MODE_DFP
+#define CONFIG_USB_PD_CUSTOM_VDM
+#define CONFIG_USB_PD_DISCHARGE
+#define CONFIG_USB_PD_DISCHARGE_TCPC
+#define CONFIG_USB_PD_DUAL_ROLE
+#define CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
+#define CONFIG_USB_PD_LOGGING
+#define CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT TYPEC_RP_3A0
+#define CONFIG_USB_PD_PORT_COUNT 2
+#define CONFIG_USB_PD_VBUS_DETECT_GPIO
+#define CONFIG_USB_PD_TCPC_LOW_POWER
+#define CONFIG_USB_PD_TCPM_MUX
+#define CONFIG_USB_PD_TCPM_ANX74XX
+#define CONFIG_USB_PD_TCPM_TCPCI
+#define CONFIG_USB_PD_TCPM_PS8751
+#define CONFIG_USB_PD_TRY_SRC
+#define CONFIG_USB_POWER_DELIVERY
+#define CONFIG_USBC_SS_MUX
+#define CONFIG_USBC_SS_MUX_DFP_ONLY
+#define CONFIG_USBC_VCONN
+#define CONFIG_USBC_VCONN_SWAP
+
+/* BC 1.2 charger */
+#define CONFIG_BC12_DETECT_PI3USB9281
+#define CONFIG_BC12_DETECT_PI3USB9281_CHIP_COUNT 2
+
+/* Optional feature to configure npcx chip */
+#define NPCX_UART_MODULE2 1 /* 1:GPIO64/65 as UART */
+#define NPCX_JTAG_MODULE2 0 /* 0:GPIO21/17/16/20 as JTAG */
+#define NPCX_TACH_SEL2 0 /* 0:GPIO40/73 as TACH */
+
+/* I2C ports */
+#define I2C_PORT_TCPC0 NPCX_I2C_PORT0_0
+#define I2C_PORT_TCPC1 NPCX_I2C_PORT0_0
+#define I2C_PORT_ALS NPCX_I2C_PORT0_1
+#define I2C_PORT_USB_CHARGER_1 NPCX_I2C_PORT0_1
+#define I2C_PORT_USB_CHARGER_0 NPCX_I2C_PORT1
+#define I2C_PORT_CHARGER NPCX_I2C_PORT1
+#define I2C_PORT_BATTERY NPCX_I2C_PORT1
+#define I2C_PORT_PMIC NPCX_I2C_PORT2
+#define I2C_PORT_MP2949 NPCX_I2C_PORT2
+#define I2C_PORT_GYRO NPCX_I2C_PORT3
+#define I2C_PORT_BARO NPCX_I2C_PORT3
+#define I2C_PORT_ACCEL I2C_PORT_GYRO
+#define I2C_PORT_THERMAL I2C_PORT_PMIC
+
+/* I2C addresses */
+#define I2C_ADDR_BD99992 0x60
+#define I2C_ADDR_MP2949 0x40
+
+#ifndef __ASSEMBLER__
+
+#include "gpio_signal.h"
+#include "registers.h"
+
+enum power_signal {
+#ifdef CONFIG_POWER_S0IX
+ X86_SLP_S0_DEASSERTED,
+#endif
+ X86_SLP_S3_DEASSERTED,
+ X86_SLP_S4_DEASSERTED,
+ X86_SLP_SUS_DEASSERTED,
+ X86_RSMRST_L_PGOOD,
+ X86_PMIC_DPWROK,
+ POWER_SIGNAL_COUNT
+};
+
+enum temp_sensor_id {
+ TEMP_SENSOR_BATTERY, /* BD99956GW TSENSE */
+ TEMP_SENSOR_AMBIENT, /* BD99992GW SYSTHERM0 */
+ TEMP_SENSOR_CHARGER, /* BD99992GW SYSTHERM1 */
+ TEMP_SENSOR_DRAM, /* BD99992GW SYSTHERM2 */
+ TEMP_SENSOR_EMMC, /* BD99992GW SYSTHERM3 */
+ TEMP_SENSOR_COUNT
+};
+
+enum als_id {
+ ALS_OPT3001,
+ ALS_COUNT
+};
+
+/*
+ * Motion sensors:
+ * When reading through IO memory is set up for sensors (LPC is used),
+ * the first 2 entries must be accelerometers, then gyroscope.
+ * For BMI160, accel, gyro and compass sensors must be next to each other.
+ */
+enum sensor_id {
+ LID_ACCEL = 0,
+ LID_GYRO,
+ LID_MAG,
+};
+
+enum adc_channel {
+ ADC_BASE_DET,
+ ADC_VBUS,
+ ADC_AMON_BMON,
+ ADC_CH_COUNT
+};
+
+enum button {
+ BUTTON_VOLUME_DOWN = 0,
+ BUTTON_VOLUME_UP = 1,
+ BUTTON_COUNT
+};
+
+/* TODO(crosbug.com/p/61098): Verify the numbers below. */
+/*
+ * delay to turn on the power supply max is ~16ms.
+ * delay to turn off the power supply max is about ~180ms.
+ */
+#define PD_POWER_SUPPLY_TURN_ON_DELAY 30000 /* us */
+#define PD_POWER_SUPPLY_TURN_OFF_DELAY 250000 /* us */
+
+/* delay to turn on/off vconn */
+#define PD_VCONN_SWAP_DELAY 5000 /* us */
+
+/* Define typical operating power and max power */
+#define PD_OPERATING_POWER_MW 15000
+#define PD_MAX_POWER_MW 45000
+#define PD_MAX_CURRENT_MA 3000
+#define PD_MAX_VOLTAGE_MV 20000
+
+/* Board specific handlers */
+int board_get_version(void);
+void board_reset_pd_mcu(void);
+void board_set_tcpc_power_mode(int port, int mode);
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* __CROS_EC_BOARD_H */
diff --git a/board/nautilus/build.mk b/board/nautilus/build.mk
new file mode 100644
index 0000000000..d8ae2af836
--- /dev/null
+++ b/board/nautilus/build.mk
@@ -0,0 +1,15 @@
+# -*- makefile -*-
+# Copyright 2016 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.
+#
+# Board specific files build
+#
+
+CHIP:=npcx
+CHIP_VARIANT:=npcx5m6g
+
+board-y=board.o
+board-$(CONFIG_BATTERY_SMART)+=battery.o
+board-$(CONFIG_LED_COMMON)+=led.o
+board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o
diff --git a/board/nautilus/ec.tasklist b/board/nautilus/ec.tasklist
new file mode 100644
index 0000000000..376ac1965e
--- /dev/null
+++ b/board/nautilus/ec.tasklist
@@ -0,0 +1,36 @@
+/* Copyright 2016 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.
+ */
+
+/*
+ * List of enabled tasks in the priority order
+ *
+ * The first one has the lowest priority.
+ *
+ * For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
+ * TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
+ * where :
+ * 'n' in the name of the task
+ * 'r' in the main routine of the task
+ * 'd' in an opaque parameter passed to the routine at startup
+ * 's' is the stack size in bytes; must be a multiple of 8
+ *
+ * For USB PD tasks, IDs must be in consecutive order and correspond to
+ * the port which they are for. See TASK_ID_TO_PD_PORT() macro.
+ */
+
+#define CONFIG_TASK_LIST \
+ TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(ALS, als_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P0, usb_charger_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P1, usb_charger_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(CHARGER, charger_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(MOTIONSENSE, motion_sense_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(PDCMD, pd_command_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(POWERBTN, power_button_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C1, pd_task, NULL, LARGER_TASK_STACK_SIZE)
diff --git a/board/nautilus/gpio.inc b/board/nautilus/gpio.inc
new file mode 100644
index 0000000000..af7576029e
--- /dev/null
+++ b/board/nautilus/gpio.inc
@@ -0,0 +1,126 @@
+/* -*- mode:c -*-
+ *
+ * Copyright 2016 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.
+ */
+
+/* Declare symbolic names for all the GPIOs that we care about.
+ * Note: Those with interrupt handlers must be declared first. */
+
+GPIO_INT(USB_C0_PD_INT_ODL, PIN(3, 7), GPIO_INT_FALLING, tcpc_alert_event)
+GPIO_INT(USB_C1_PD_INT_ODL, PIN(C, 5), GPIO_INT_FALLING, tcpc_alert_event)
+#ifdef CONFIG_POWER_S0IX
+GPIO_INT(PCH_SLP_S0_L, PIN(7, 5), GPIO_INT_BOTH, power_signal_interrupt)
+#endif
+/* Use VW signals instead of GPIOs */
+#ifndef CONFIG_ESPI_VW_SIGNALS
+GPIO_INT(PCH_SLP_S3_L, PIN(7, 3), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(PCH_SLP_S4_L, PIN(8, 6), GPIO_INT_BOTH, power_signal_interrupt)
+#endif
+GPIO_INT(PCH_SLP_SUS_L, PIN(6, 2), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(RSMRST_L_PGOOD, PIN(B, 0), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(PMIC_DPWROK, PIN(C, 7), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(POWER_BUTTON_L, PIN(0, 4), GPIO_INT_BOTH | GPIO_PULL_UP, power_button_interrupt)
+GPIO_INT(LID_OPEN, PIN(6, 7), GPIO_INT_BOTH, lid_interrupt)
+/* TODO(b/35585396): Make use of reverse dock signal. */
+GPIO_INT(REVERSE_DOCK, PIN(B, 7), GPIO_INT_BOTH, lid_interrupt)
+GPIO_INT(VOLUME_DOWN_L, PIN(8, 3), GPIO_INT_BOTH | GPIO_PULL_UP, button_interrupt)
+GPIO_INT(VOLUME_UP_L, PIN(8, 2), GPIO_INT_BOTH | GPIO_PULL_UP, button_interrupt)
+GPIO_INT(WP_L, PIN(4, 0), GPIO_INT_BOTH, switch_interrupt)
+GPIO_INT(AC_PRESENT, PIN(C, 1), GPIO_INT_BOTH, extpower_interrupt)
+GPIO_INT(USB_C0_VBUS_WAKE_L, PIN(9, 3), GPIO_INT_BOTH | GPIO_PULL_UP, vbus0_evt)
+GPIO_INT(USB_C1_VBUS_WAKE_L, PIN(9, 7), GPIO_INT_BOTH | GPIO_PULL_UP, vbus1_evt)
+GPIO_INT(USB_C0_BC12_INT_L, PIN(D, 3), GPIO_INT_FALLING, usb0_evt)
+GPIO_INT(USB_C1_BC12_INT_L, PIN(3, 3), GPIO_INT_FALLING, usb1_evt)
+GPIO_INT(ACCELGYRO3_INT_L, PIN(3, 6), GPIO_INT_FALLING, bmi160_interrupt)
+GPIO_INT(BASE_DET_A, PIN(4, 5), GPIO_INT_BOTH, base_detect_interrupt)
+GPIO_INT(USB_C0_CABLE_DET, PIN(D, 2), GPIO_INT_RISING, anx74xx_cable_det_interrupt)
+
+GPIO(PCH_RTCRST, PIN(2, 7), GPIO_OUT_LOW) /* RTCRST# to SOC (>= rev4) */
+GPIO(ENABLE_BACKLIGHT, PIN(2, 6), GPIO_OUT_LOW) /* Enable Backlight */
+GPIO(WLAN_OFF_L, PIN(7, 2), GPIO_OUT_LOW) /* Disable WLAN */
+GPIO(PP3300_DX_WLAN, PIN(A, 7), GPIO_OUT_LOW) /* Enable WLAN 3.3V Power */
+GPIO(CPU_PROCHOT, PIN(8, 1), GPIO_OUT_HIGH) /* PROCHOT# to SOC */
+GPIO(PCH_ACOK, PIN(5, 0), GPIO_ODR_LOW) /* ACOK to SOC */
+GPIO(PCH_WAKE_L, PIN(A, 3), GPIO_ODR_HIGH) /* Wake SOC */
+GPIO(PCH_RSMRST_L, PIN(7, 0), GPIO_OUT_LOW) /* RSMRST# to SOC */
+GPIO(PCH_PWRBTN_L, PIN(4, 1), GPIO_ODR_HIGH) /* Power Button to SOC */
+GPIO(EC_PLATFORM_RST, PIN(A, 6), GPIO_OUT_LOW) /* EC Reset to LDO_EN */
+GPIO(SYS_RESET_L, PIN(6, 1), GPIO_ODR_HIGH) /* Cold Reset to SOC */
+GPIO(PMIC_SLP_SUS_L, PIN(8, 5), GPIO_OUT_LOW) /* SLP_SUS# to PMIC */
+GPIO(BATTERY_PRESENT_L, PIN(3, 4), GPIO_INPUT) /* Battery Present */
+GPIO(CCD_MODE_ODL, PIN(6, 3), GPIO_INPUT) /* Case Closed Debug Mode */
+GPIO(EC_HAVEN_RESET_ODL, PIN(0, 2), GPIO_ODR_HIGH) /* H1 Reset */
+GPIO(ENTERING_RW, PIN(7, 6), GPIO_OUTPUT) /* EC Entering RW */
+GPIO(PMIC_INT_L, PIN(6, 0), GPIO_INPUT) /* PMIC interrupt */
+#ifndef CONFIG_POWER_S0IX
+GPIO(PCH_SLP_S0_L, PIN(7, 5), GPIO_INPUT)
+#endif
+
+/* Sensor interrupts, not implemented yet */
+GPIO(ALS_INT_L, PIN(2, 5), GPIO_INPUT)
+
+/* TODO(b/35585396): Make use of these GPIOs */
+GPIO(PP1800_DX_SENSOR, PIN(1, 4), GPIO_OUTPUT)
+GPIO(PP3300_DX_SENSOR, PIN(2, 1), GPIO_OUTPUT)
+GPIO(PP3300_USB_PD, PIN(2, 0), GPIO_OUTPUT)
+
+GPIO(WLAN_PE_RST, PIN(1, 2), GPIO_OUTPUT)
+GPIO(PP3300_DX_LTE, PIN(0, 5), GPIO_OUT_LOW)
+GPIO(LTE_GPS_OFF_L, PIN(0, 0), GPIO_ODR_HIGH)
+GPIO(LTE_BODY_SAR_L, PIN(0, 1), GPIO_ODR_HIGH)
+GPIO(LTE_WAKE_L, PIN(7, 1), GPIO_INPUT)
+GPIO(LTE_OFF_ODL, PIN(8, 0), GPIO_ODR_LOW)
+/* end of TODO */
+
+GPIO(PP3300_DX_BASE, PIN(1, 1), GPIO_OUT_LOW)
+
+/* I2C pins - these will be reconfigured for alternate function below */
+GPIO(I2C0_0_SCL, PIN(B, 5), GPIO_INPUT) /* EC_I2C0_0_USBC_3V3_SCL */
+GPIO(I2C0_0_SDA, PIN(B, 4), GPIO_INPUT) /* EC_I2C0_0_USBC_3V3_SDA */
+GPIO(I2C0_1_SCL, PIN(B, 3), GPIO_INPUT) /* EC_I2C0_1_3V3_SCL */
+GPIO(I2C0_1_SDA, PIN(B, 2), GPIO_INPUT) /* EC_I2C0_1_3V3_SDA */
+GPIO(I2C1_SCL, PIN(9, 0), GPIO_INPUT) /* EC_I2C1_3V3_SCL */
+GPIO(I2C1_SDA, PIN(8, 7), GPIO_INPUT) /* EC_I2C1_3V3_SDA */
+GPIO(I2C2_SCL, PIN(9, 2), GPIO_INPUT) /* EC_I2C2_PMIC_3V3_SCL */
+GPIO(I2C2_SDA, PIN(9, 1), GPIO_INPUT) /* EC_I2C2_PMIC_3V3_SDA */
+GPIO(I2C3_SCL, PIN(D, 1), GPIO_INPUT) /* EC_I2C3_SENSOR_1V8_SCL */
+GPIO(I2C3_SDA, PIN(D, 0), GPIO_INPUT) /* EC_I2C3_SENSOR_1V8_SDA */
+
+/* rev0: 5V enables: INPUT=1.5A, OUT_LOW=OFF, OUT_HIGH=3A */
+GPIO(USB_C0_5V_EN, PIN(4, 2), GPIO_OUT_LOW) /* C0 5V Enable */
+GPIO(USB_C0_3A_EN, PIN(6, 6), GPIO_OUT_LOW) /* C0 Enable 3A */
+GPIO(USB_C0_CHARGE_L, PIN(C, 0), GPIO_OUT_LOW) /* C0 Charge enable */
+GPIO(USB_C1_5V_EN, PIN(B, 1), GPIO_OUT_LOW) /* C1 5V Enable */
+GPIO(USB_C1_3A_EN, PIN(3, 5), GPIO_OUT_LOW) /* C1 3A Enable */
+GPIO(USB_C1_CHARGE_L, PIN(C, 3), GPIO_OUT_LOW) /* C1 Charge enable */
+GPIO(USB_C0_PD_RST_L, PIN(0, 3), GPIO_OUT_LOW) /* C0 PD Reset */
+GPIO(USB_C1_PD_RST_L, PIN(7, 4), GPIO_OUT_LOW) /* C1 PD Reset */
+GPIO(USB_C0_DP_HPD, PIN(9, 4), GPIO_INPUT) /* C0 DP Hotplug Detect */
+GPIO(USB_C1_DP_HPD, PIN(A, 5), GPIO_INPUT) /* C1 DP Hotplug Detect */
+GPIO(USB_C0_TCPC_PWR, PIN(8, 4), GPIO_OUT_LOW) /* Enable C0 TCPC Power */
+GPIO(USB2_OTG_ID, PIN(A, 1), GPIO_ODR_LOW) /* OTG ID */
+GPIO(USB2_OTG_VBUSSENSE, PIN(9, 5), GPIO_OUT_LOW) /* OTG VBUS Sense */
+
+/* LEDs (2 colors on each port) */
+GPIO(LED_YELLOW_C0, PIN(2, 4), GPIO_OUT_LOW) /* This is from rev5 */
+GPIO(LED_YELLOW_C0_OLD, PIN(3, 2), GPIO_OUT_LOW) /* This is for rev1 to rev4 */
+GPIO(LED_WHITE_C0, PIN(C, 6), GPIO_OUT_LOW)
+GPIO(LED_YELLOW_C1, PIN(3, 1), GPIO_OUT_LOW)
+GPIO(LED_WHITE_C1, PIN(3, 0), GPIO_OUT_LOW)
+
+/* Board ID */
+GPIO(BOARD_VERSION1, PIN(C, 4), GPIO_INPUT) /* Board ID bit0 */
+GPIO(BOARD_VERSION2, PIN(C, 2), GPIO_INPUT) /* Board ID bit1 */
+GPIO(BOARD_VERSION3, PIN(1, 3), GPIO_INPUT) /* Board ID bit2 */
+GPIO(BOARD_VERSION4, PIN(1, 7), GPIO_INPUT) /* Board ID strap 3 (ternary) */
+
+/* Alternate functions GPIO definitions */
+ALTERNATE(PIN_MASK(6, 0x30), 1, MODULE_UART, 0) /* GPIO64-65 */ /* UART from EC to Servo */
+ALTERNATE(PIN_MASK(8, 0x80), 1, MODULE_I2C, 0) /* GPIO87 */ /* EC_I2C1_3V3_SDA */
+ALTERNATE(PIN_MASK(9, 0x01), 1, MODULE_I2C, 0) /* GPIO90 */ /* EC_I2C1_3V3_SCL */
+ALTERNATE(PIN_MASK(9, 0x06), 1, MODULE_I2C, 0) /* GPIO91-92 */ /* EC_I2C2_PMIC_3V3_SDA/SCL */
+ALTERNATE(PIN_MASK(B, 0x30), 1, MODULE_I2C, 0) /* GPIOB4-B5 */ /* EC_I2C0_0_USBC_3V3_SDA/SCL */
+ALTERNATE(PIN_MASK(B, 0x0C), 1, MODULE_I2C, 0) /* GPOPB2-B3 */ /* EC_I2C0_1_3V3_SDA/SCL */
+ALTERNATE(PIN_MASK(D, 0x03), 1, MODULE_I2C, 0) /* GPIOD0-D1 */ /* EC_I2C3_SENSOR_1V8_SDA/SCL */
diff --git a/board/nautilus/led.c b/board/nautilus/led.c
new file mode 100644
index 0000000000..0d43497c23
--- /dev/null
+++ b/board/nautilus/led.c
@@ -0,0 +1,169 @@
+/* Copyright 2017 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.
+ *
+ * Power and battery LED control.
+ */
+
+#include "battery.h"
+#include "charge_manager.h"
+#include "charge_state.h"
+#include "chipset.h"
+#include "ec_commands.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "led_common.h"
+#include "system.h"
+#include "util.h"
+
+#define BAT_LED_ON 1
+#define BAT_LED_OFF 0
+
+const enum ec_led_id supported_led_ids[] = {
+ EC_LED_ID_LEFT_LED,
+ EC_LED_ID_RIGHT_LED,
+};
+
+const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids);
+
+enum led_color {
+ LED_OFF = 0,
+ LED_AMBER,
+ LED_WHITE,
+ LED_COLOR_COUNT /* Number of colors, not a color itself */
+};
+
+static void side_led_set_color(int port, enum led_color color)
+{
+ int yellow_c0 = (system_get_board_version() >= 5) ?
+ GPIO_LED_YELLOW_C0 : GPIO_LED_YELLOW_C0_OLD;
+ gpio_set_level(port ? GPIO_LED_YELLOW_C1 : yellow_c0,
+ (color == LED_AMBER) ? BAT_LED_ON : BAT_LED_OFF);
+ gpio_set_level(port ? GPIO_LED_WHITE_C1 : GPIO_LED_WHITE_C0,
+ (color == LED_WHITE) ? BAT_LED_ON : BAT_LED_OFF);
+}
+
+void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
+{
+ brightness_range[EC_LED_COLOR_AMBER] = 1;
+ brightness_range[EC_LED_COLOR_WHITE] = 1;
+}
+
+int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness)
+{
+ int port;
+
+ switch (led_id) {
+ case EC_LED_ID_LEFT_LED:
+ port = 0;
+ break;
+ case EC_LED_ID_RIGHT_LED:
+ port = 1;
+ break;
+ default:
+ return EC_ERROR_PARAM1;
+ }
+
+ if (brightness[EC_LED_COLOR_WHITE] != 0)
+ side_led_set_color(port, LED_WHITE);
+ else if (brightness[EC_LED_COLOR_AMBER] != 0)
+ side_led_set_color(port, LED_AMBER);
+ else
+ side_led_set_color(port, LED_OFF);
+
+ return EC_SUCCESS;
+}
+
+/*
+ * Set active charge port color to the parameter, turn off all others.
+ * If no port is active (-1), turn off all LEDs.
+ */
+static void set_active_port_color(enum led_color color)
+{
+ int port = charge_manager_get_active_charge_port();
+
+ if (led_auto_control_is_enabled(EC_LED_ID_LEFT_LED))
+ side_led_set_color(0, (port == 0) ? color : LED_OFF);
+ if (led_auto_control_is_enabled(EC_LED_ID_RIGHT_LED))
+ side_led_set_color(1, (port == 1) ? color : LED_OFF);
+}
+
+static void board_led_set_battery(void)
+{
+ static int battery_ticks;
+ uint32_t chflags = charge_get_flags();
+
+ battery_ticks++;
+
+ switch (charge_get_state()) {
+ case PWR_STATE_CHARGE:
+ /* Always indicate when charging, even in suspend. */
+ set_active_port_color(LED_AMBER);
+ break;
+ case PWR_STATE_DISCHARGE:
+ /*
+ * TODO(b/37970194): Do we really want to blink on low battery?
+ * If yes, what's the threshold? In S0 only?
+ */
+ if (led_auto_control_is_enabled(EC_LED_ID_LEFT_LED)) {
+ if (charge_get_percent() < 12)
+ side_led_set_color(0,
+ (battery_ticks & 0x4) ? LED_WHITE : LED_OFF);
+ else
+ side_led_set_color(0, LED_OFF);
+ }
+
+ if (led_auto_control_is_enabled(EC_LED_ID_RIGHT_LED))
+ side_led_set_color(1, LED_OFF);
+ break;
+ case PWR_STATE_ERROR:
+ set_active_port_color((battery_ticks & 0x2) ?
+ LED_WHITE : LED_OFF);
+ break;
+ case PWR_STATE_CHARGE_NEAR_FULL:
+ set_active_port_color(LED_WHITE);
+ break;
+ case PWR_STATE_IDLE: /* External power connected in IDLE */
+ if (chflags & CHARGE_FLAG_FORCE_IDLE)
+ set_active_port_color((battery_ticks & 0x4) ?
+ LED_AMBER : LED_OFF);
+ else
+ set_active_port_color(LED_WHITE);
+ break;
+ default:
+ /* Other states don't alter LED behavior */
+ break;
+ }
+}
+
+/* Called by hook task every TICK */
+static void led_tick(void)
+{
+ board_led_set_battery();
+}
+DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT);
+
+void led_control(enum ec_led_id led_id, enum ec_led_state state)
+{
+ enum led_color color;
+
+ if ((led_id != EC_LED_ID_RECOVERY_HW_REINIT_LED) &&
+ (led_id != EC_LED_ID_SYSRQ_DEBUG_LED))
+ return;
+
+ if (state == LED_STATE_RESET) {
+ led_auto_control(EC_LED_ID_LEFT_LED, 1);
+ led_auto_control(EC_LED_ID_RIGHT_LED, 1);
+ board_led_set_battery();
+ return;
+ }
+
+ color = state ? LED_WHITE : LED_OFF;
+
+ led_auto_control(EC_LED_ID_LEFT_LED, 0);
+ led_auto_control(EC_LED_ID_RIGHT_LED, 0);
+
+ side_led_set_color(0, color);
+ side_led_set_color(1, color);
+}
diff --git a/board/nautilus/usb_pd_policy.c b/board/nautilus/usb_pd_policy.c
new file mode 100644
index 0000000000..bb1920c6db
--- /dev/null
+++ b/board/nautilus/usb_pd_policy.c
@@ -0,0 +1,443 @@
+/* Copyright 2016 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.
+ */
+
+#include "atomic.h"
+#include "extpower.h"
+#include "charge_manager.h"
+#include "common.h"
+#include "console.h"
+#include "driver/tcpm/anx74xx.h"
+#include "driver/tcpm/ps8xxx.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+#include "usb_mux.h"
+#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
+
+#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
+
+#define PDO_FIXED_FLAGS (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP |\
+ PDO_FIXED_COMM_CAP)
+
+/* TODO(crosbug.com/p/61098): fill in correct source and sink capabilities */
+const uint32_t pd_src_pdo[] = {
+ PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS),
+};
+const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo);
+const uint32_t pd_src_pdo_max[] = {
+ PDO_FIXED(5000, 3000, PDO_FIXED_FLAGS),
+};
+const int pd_src_pdo_max_cnt = ARRAY_SIZE(pd_src_pdo_max);
+
+const uint32_t pd_snk_pdo[] = {
+ PDO_FIXED(5000, 500, PDO_FIXED_FLAGS),
+ PDO_BATT(4750, 21000, 15000),
+ PDO_VAR(4750, 21000, 3000),
+};
+const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo);
+
+int pd_is_valid_input_voltage(int mv)
+{
+ return 1;
+}
+
+void pd_transition_voltage(int idx)
+{
+ /* No-operation: we are always 5V */
+}
+
+static uint8_t vbus_en[CONFIG_USB_PD_PORT_COUNT];
+static uint8_t vbus_rp[CONFIG_USB_PD_PORT_COUNT] = {TYPEC_RP_1A5, TYPEC_RP_1A5};
+
+int board_vbus_source_enabled(int port)
+{
+ return vbus_en[port];
+}
+
+static void board_vbus_update_source_current(int port)
+{
+ enum gpio_signal gpio_5v_en = port ? GPIO_USB_C1_5V_EN :
+ GPIO_USB_C0_5V_EN;
+ enum gpio_signal gpio_3a_en = port ? GPIO_USB_C1_3A_EN :
+ GPIO_USB_C0_3A_EN;
+
+ if (system_get_board_version() >= 1) {
+ /*
+ * For rev1 and beyond, 1.5 vs 3.0 A limit is controlled by a
+ * dedicated gpio where high = 3.0A and low = 1.5A. VBUS on/off
+ * is controlled by GPIO_USB_C0/1_5V_EN. Both of these signals
+ * can remain outputs.
+ */
+ gpio_set_level(gpio_3a_en, vbus_rp[port] == TYPEC_RP_3A0 ?
+ 1 : 0);
+ gpio_set_level(gpio_5v_en, vbus_en[port]);
+ } else {
+ /*
+ * Driving USB_Cx_5V_EN high, actually put a 16.5k resistance
+ * (2x 33k in parallel) on the NX5P3290 load switch ILIM pin,
+ * setting a minimum OCP current of 3186 mA.
+ * Putting an internal pull-up on USB_Cx_5V_EN, effectively put
+ * a 33k resistor on ILIM, setting a minimum OCP current of
+ * 1505 mA.
+ */
+ int flags = (vbus_rp[port] == TYPEC_RP_1A5 && vbus_en[port]) ?
+ (GPIO_INPUT | GPIO_PULL_UP) :
+ (GPIO_OUTPUT | GPIO_PULL_UP);
+ gpio_set_level(gpio_5v_en, vbus_en[port]);
+ gpio_set_flags(gpio_5v_en, flags);
+ }
+}
+
+void typec_set_source_current_limit(int port, int rp)
+{
+ vbus_rp[port] = rp;
+
+ /* change the GPIO driving the load switch if needed */
+ board_vbus_update_source_current(port);
+}
+
+int pd_set_power_supply_ready(int port)
+{
+ /* Disable charging */
+ gpio_set_level(port ? GPIO_USB_C1_CHARGE_L :
+ GPIO_USB_C0_CHARGE_L, 1);
+
+ /* Ensure we advertise the proper available current quota */
+ charge_manager_source_port(port, 1);
+
+ /* Provide VBUS */
+ vbus_en[port] = 1;
+ board_vbus_update_source_current(port);
+
+ if (system_get_board_version() >= 2)
+ pd_set_vbus_discharge(port, 0);
+
+ /* notify host of power info change */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+
+ return EC_SUCCESS; /* we are ready */
+}
+
+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 (system_get_board_version() >= 2 && prev_en)
+ pd_set_vbus_discharge(port, 1);
+
+ /* Give back the current quota we are no longer using */
+ charge_manager_source_port(port, 0);
+
+ /* notify host of power info change */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+}
+
+int pd_snk_is_vbus_provided(int port)
+{
+ return !gpio_get_level(port ? GPIO_USB_C1_VBUS_WAKE_L :
+ GPIO_USB_C0_VBUS_WAKE_L);
+}
+
+int pd_board_checks(void)
+{
+ return EC_SUCCESS;
+}
+
+int pd_check_power_swap(int port)
+{
+ /*
+ * Allow power swap as long as we are acting as a dual role device,
+ * otherwise assume our role is fixed (not in S0 or console command
+ * to fix our role).
+ */
+ return pd_get_dual_role() == PD_DRP_TOGGLE_ON ? 1 : 0;
+}
+
+int pd_check_data_swap(int port, int data_role)
+{
+ /*
+ * Allow data swap if we are a UFP, otherwise don't allow.
+ *
+ * When we are still in the Read-Only firmware, avoid swapping roles
+ * so we don't jump in RW as a SNK/DFP and potentially confuse the
+ * power supply by sending a soft-reset with wrong data role.
+ */
+ return (data_role == PD_ROLE_UFP) &&
+ (system_get_image_copy() != SYSTEM_IMAGE_RO) ? 1 : 0;
+}
+
+int pd_check_vconn_swap(int port)
+{
+ /* in G3, do not allow vconn swap since pp5000_A rail is off */
+ return gpio_get_level(GPIO_PMIC_SLP_SUS_L);
+}
+
+void pd_execute_data_swap(int port, int data_role)
+{
+ /* Do nothing */
+}
+
+void pd_check_pr_role(int port, int pr_role, int flags)
+{
+ /*
+ * If partner is dual-role power and dualrole toggling is on, consider
+ * if a power swap is necessary.
+ */
+ if ((flags & PD_FLAGS_PARTNER_DR_POWER) &&
+ pd_get_dual_role() == PD_DRP_TOGGLE_ON) {
+ /*
+ * If we are a sink and partner is not externally powered, then
+ * swap to become a source. If we are source and partner is
+ * externally powered, swap to become a sink.
+ */
+ int partner_extpower = flags & PD_FLAGS_PARTNER_EXTPOWER;
+
+ if ((!partner_extpower && pr_role == PD_ROLE_SINK) ||
+ (partner_extpower && pr_role == PD_ROLE_SOURCE))
+ pd_request_power_swap(port);
+ }
+}
+
+void pd_check_dr_role(int port, int dr_role, int flags)
+{
+ /* If UFP, try to switch to DFP */
+ if ((flags & PD_FLAGS_PARTNER_DR_DATA) &&
+ dr_role == PD_ROLE_UFP &&
+ system_get_image_copy() != SYSTEM_IMAGE_RO)
+ pd_request_data_swap(port);
+}
+/* ----------------- Vendor Defined Messages ------------------ */
+const struct svdm_response svdm_rsp = {
+ .identity = NULL,
+ .svids = NULL,
+ .modes = NULL,
+};
+
+int pd_custom_vdm(int port, int cnt, uint32_t *payload,
+ uint32_t **rpayload)
+{
+ int cmd = PD_VDO_CMD(payload[0]);
+ uint16_t dev_id = 0;
+ int is_rw, is_latest;
+
+ /* make sure we have some payload */
+ if (cnt == 0)
+ return 0;
+
+ switch (cmd) {
+ case VDO_CMD_VERSION:
+ /* guarantee last byte of payload is null character */
+ *(payload + cnt - 1) = 0;
+ CPRINTF("version: %s\n", (char *)(payload+1));
+ break;
+ case VDO_CMD_READ_INFO:
+ case VDO_CMD_SEND_INFO:
+ /* copy hash */
+ if (cnt == 7) {
+ dev_id = VDO_INFO_HW_DEV_ID(payload[6]);
+ is_rw = VDO_INFO_IS_RW(payload[6]);
+
+ is_latest = pd_dev_store_rw_hash(port,
+ dev_id,
+ payload + 1,
+ is_rw ?
+ SYSTEM_IMAGE_RW :
+ SYSTEM_IMAGE_RO);
+ /*
+ * Send update host event unless our RW hash is
+ * already known to be the latest update RW.
+ */
+ if (!is_rw || !is_latest)
+ pd_send_host_event(PD_EVENT_UPDATE_DEVICE);
+
+ CPRINTF("DevId:%d.%d SW:%d RW:%d\n",
+ HW_DEV_ID_MAJ(dev_id),
+ HW_DEV_ID_MIN(dev_id),
+ VDO_INFO_SW_DBG_VER(payload[6]),
+ is_rw);
+ } else if (cnt == 6) {
+ /* really old devices don't have last byte */
+ pd_dev_store_rw_hash(port, dev_id, payload + 1,
+ SYSTEM_IMAGE_UNKNOWN);
+ }
+ break;
+ case VDO_CMD_CURRENT:
+ CPRINTF("Current: %dmA\n", payload[1]);
+ break;
+ case VDO_CMD_FLIP:
+ usb_mux_flip(port);
+ break;
+#ifdef CONFIG_USB_PD_LOGGING
+ case VDO_CMD_GET_LOG:
+ pd_log_recv_vdm(port, cnt, payload);
+ break;
+#endif /* CONFIG_USB_PD_LOGGING */
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+static int dp_flags[CONFIG_USB_PD_PORT_COUNT];
+static uint32_t dp_status[CONFIG_USB_PD_PORT_COUNT];
+
+static void svdm_safe_dp_mode(int port)
+{
+ /* make DP interface safe until configure */
+ dp_flags[port] = 0;
+ dp_status[port] = 0;
+ usb_mux_set(port, TYPEC_MUX_NONE,
+ USB_SWITCH_CONNECT, pd_get_polarity(port));
+}
+
+static int svdm_enter_dp_mode(int port, uint32_t mode_caps)
+{
+ /* Only enter mode if device is DFP_D capable */
+ if (mode_caps & MODE_DP_SNK) {
+ svdm_safe_dp_mode(port);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int svdm_dp_status(int port, uint32_t *payload)
+{
+ int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
+
+ payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
+ CMD_DP_STATUS | VDO_OPOS(opos));
+ payload[1] = VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */
+ 0, /* HPD level ... not applicable */
+ 0, /* exit DP? ... no */
+ 0, /* usb mode? ... no */
+ 0, /* multi-function ... no */
+ (!!(dp_flags[port] & DP_FLAGS_DP_ON)),
+ 0, /* power low? ... no */
+ (!!(dp_flags[port] & DP_FLAGS_DP_ON)));
+ return 2;
+};
+
+static int svdm_dp_config(int port, uint32_t *payload)
+{
+ int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
+ int mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]);
+ int pin_mode = pd_dfp_dp_get_pin_mode(port, dp_status[port]);
+
+ if (!pin_mode)
+ return 0;
+
+ usb_mux_set(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP,
+ USB_SWITCH_CONNECT, pd_get_polarity(port));
+
+ 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;
+};
+
+static void svdm_dp_post_config(int port)
+{
+ const struct usb_mux *mux = &usb_muxes[port];
+
+ dp_flags[port] |= DP_FLAGS_DP_ON;
+ if (!(dp_flags[port] & DP_FLAGS_HPD_HI_PENDING))
+ return;
+ mux->hpd_update(port, 1, 0);
+}
+
+static 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]);
+ const struct usb_mux *mux = &usb_muxes[port];
+
+ dp_status[port] = payload[1];
+ if (!(dp_flags[port] & DP_FLAGS_DP_ON)) {
+ if (lvl)
+ dp_flags[port] |= DP_FLAGS_HPD_HI_PENDING;
+ return 1;
+ }
+ mux->hpd_update(port, lvl, irq);
+
+ /* ack */
+ return 1;
+}
+
+static void svdm_exit_dp_mode(int port)
+{
+ const struct usb_mux *mux = &usb_muxes[port];
+
+ svdm_safe_dp_mode(port);
+ mux->hpd_update(port, 0, 0);
+}
+
+static int svdm_enter_gfu_mode(int port, uint32_t mode_caps)
+{
+ /* Always enter GFU mode */
+ return 0;
+}
+
+static void svdm_exit_gfu_mode(int port)
+{
+}
+
+static int svdm_gfu_status(int port, uint32_t *payload)
+{
+ /*
+ * This is called after enter mode is successful, send unstructured
+ * VDM to read info.
+ */
+ pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_READ_INFO, NULL, 0);
+ return 0;
+}
+
+static int svdm_gfu_config(int port, uint32_t *payload)
+{
+ return 0;
+}
+
+static int svdm_gfu_attention(int port, uint32_t *payload)
+{
+ return 0;
+}
+
+const struct svdm_amode_fx supported_modes[] = {
+ {
+ .svid = USB_SID_DISPLAYPORT,
+ .enter = &svdm_enter_dp_mode,
+ .status = &svdm_dp_status,
+ .config = &svdm_dp_config,
+ .post_config = &svdm_dp_post_config,
+ .attention = &svdm_dp_attention,
+ .exit = &svdm_exit_dp_mode,
+ },
+ {
+ .svid = USB_VID_GOOGLE,
+ .enter = &svdm_enter_gfu_mode,
+ .status = &svdm_gfu_status,
+ .config = &svdm_gfu_config,
+ .attention = &svdm_gfu_attention,
+ .exit = &svdm_exit_gfu_mode,
+ }
+};
+const int supported_modes_cnt = ARRAY_SIZE(supported_modes);
+#endif /* CONFIG_USB_PD_ALT_MODE_DFP */
diff --git a/chip/npcx/system.c b/chip/npcx/system.c
index 5135fd0979..51c7c6e74a 100644
--- a/chip/npcx/system.c
+++ b/chip/npcx/system.c
@@ -358,7 +358,9 @@ void system_check_reset_cause(void)
/* Use scratch bit to check power on reset or VCC1_RST reset */
if (!IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_SCRATCH)) {
-#if defined(BOARD_WHEATLEY) || defined(BOARD_EVE) || defined(BOARD_POPPY) || defined(BOARD_SORAKA)
+#if defined(BOARD_WHEATLEY) || defined(BOARD_EVE) || defined(BOARD_POPPY) || defined(BOARD_SORAKA)\
+ || defined(BOARD_NAUTILUS)
+
/* TODO(crosbug.com/p/61028): Remove workaround for Eve */
flags |= RESET_FLAG_RESET_PIN;
#else
diff --git a/util/flash_ec b/util/flash_ec
index f2b83e37d3..2645569cd3 100755
--- a/util/flash_ec
+++ b/util/flash_ec
@@ -113,6 +113,7 @@ BOARDS_NPCX_SPI=(
glkrvp
gru
kevin
+ nautilus
nefario
poppy
reef
@@ -150,6 +151,7 @@ BOARDS_RAIDEN=(
fizz
gru
kevin
+ nautilus
nefario
poppy
reef