summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhuohao Lee <zhuohao@chromium.org>2018-07-24 22:44:01 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-07-26 04:07:45 -0700
commita59038668c9bde21225563c8cd994dc961d15128 (patch)
treec22414dc56f60ef84b26c421d0f8e819a0ec906a
parent1542c8c5b9c7f934edc9ce7a6e42b09986e6a54f (diff)
downloadchrome-ec-a59038668c9bde21225563c8cd994dc961d15128.tar.gz
rammus: initial setup for ec
The initial files are copied from nautilus and will be revised later. BUG=b:111579280 BRANCH=master TEST=emerge-rammus chromeos-ec Change-Id: Ic1312716ca0b2200ec2d396f9e1e8c1bbe226904 Signed-off-by: Zhuohao Lee <zhuohao@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1149771 Reviewed-by: Furquan Shaikh <furquan@chromium.org>
-rw-r--r--board/rammus/analyzestack.yaml211
-rw-r--r--board/rammus/battery.c224
-rw-r--r--board/rammus/board.c808
-rw-r--r--board/rammus/board.h259
-rw-r--r--board/rammus/build.mk15
-rw-r--r--board/rammus/ec.tasklist37
-rw-r--r--board/rammus/gpio.inc123
-rw-r--r--board/rammus/led.c136
-rw-r--r--board/rammus/usb_pd_policy.c449
9 files changed, 2262 insertions, 0 deletions
diff --git a/board/rammus/analyzestack.yaml b/board/rammus/analyzestack.yaml
new file mode 100644
index 0000000000..c9004e6376
--- /dev/null
+++ b/board/rammus/analyzestack.yaml
@@ -0,0 +1,211 @@
+# Size of extra stack frame needed by exception context switch.
+# See core/cortex-m/switch.S
+exception_frame_size: 224
+# Add some missing calls.
+add:
+ # TCPC stuff:
+ tcpm_init.lto_priv.255[driver/tcpm/tcpm.h:77]:
+ - tcpci_tcpm_init
+ tcpm_release[driver/tcpm/tcpm.h:90]:
+ - ps8xxx_tcpm_release
+ tcpm_get_cc.lto_priv.246[driver/tcpm/tcpm.h:95]:
+ - tcpci_tcpm_get_cc
+ tcpm_select_rp_value[driver/tcpm/tcpm.h:105]:
+ - tcpci_tcpm_select_rp_value
+ tcpm_set_cc.lto_priv.239[driver/tcpm/tcpm.h:110]:
+ - tcpci_tcpm_set_cc
+ tcpm_set_polarity[driver/tcpm/tcpm.h:115]:
+ - tcpci_tcpm_set_polarity
+ tcpm_set_vconn.lto_priv.249[driver/tcpm/tcpm.h:120]:
+ - tcpci_tcpm_set_vconn
+ tcpm_set_msg_header[driver/tcpm/tcpm.h:125]:
+ - tcpci_tcpm_set_msg_header
+ tcpm_set_rx_enable.lto_priv.252[driver/tcpm/tcpm.h:131]:
+ - tcpci_tcpm_set_rx_enable
+ tcpm_get_message[driver/tcpm/tcpm.h:136]:
+ - tcpci_tcpm_get_message
+ tcpm_transmit[driver/tcpm/tcpm.h:142]:
+ - ps8xxx_tcpm_transmit
+ tcpc_alert[driver/tcpm/tcpm.h:147]:
+ - tcpci_tcpc_alert
+ tcpc_discharge_vbus[driver/tcpm/tcpm.h:152]:
+ - tcpci_tcpc_discharge_vbus
+ tcpm_set_drp_toggle[driver/tcpm/tcpm.h:163]:
+ - tcpci_tcpc_drp_toggle
+ tcpm_get_chip_info[driver/tcpm/tcpm.h:185]:
+ - tcpci_get_chip_info
+ board_tcpc_init[board/nautilus/board.c:233]:
+ - ps8xxx_tcpc_update_hpd_status
+ tcpci_tcpc_drp_toggle[driver/tcpm/tcpci.c:148]:
+ - None
+ # USB mux stuff
+ usb_mux_init[driver/usb_mux.c:25]:
+ - tcpci_tcpm_mux_init
+ usb_mux_init[driver/usb_mux.c:31]:
+ - None
+ usb_mux_set[driver/usb_mux.c:52]:
+ - tcpci_tcpm_mux_set
+ usb_mux_get[driver/usb_mux.c:71]:
+ - tcpci_tcpm_mux_get
+ usb_mux_flip[driver/usb_mux.c:92]:
+ - tcpci_tcpm_mux_get
+ usb_mux_flip[driver/usb_mux.c:103]:
+ - tcpci_tcpm_mux_set
+ hc_usb_pd_mux_info[driver/usb_mux.c:169]:
+ - tcpci_tcpm_mux_get
+ svdm_dp_post_config.lto_priv.271[board/nautilus/usb_pd_policy.c:363]:
+ - ps8xxx_tcpc_update_hpd_status
+ svdm_dp_attention.lto_priv.272[board/nautilus/usb_pd_policy.c:378]:
+ - ps8xxx_tcpc_update_hpd_status
+ svdm_exit_dp_mode.lto_priv.273[board/nautilus/usb_pd_policy.c:389]:
+ - ps8xxx_tcpc_update_hpd_status
+ # pd_svdm
+ pd_dfp_enter_mode[common/usb_pd_policy.c:459]:
+ - svdm_enter_dp_mode
+ dfp_consume_attention.lto_priv.259[common/usb_pd_policy.c:497]:
+ - svdm_dp_attention
+ pd_dfp_exit_mode[common/usb_pd_policy.c:563]:
+ - svdm_exit_dp_mode
+ pd_dfp_exit_mode[common/usb_pd_policy.c:580]:
+ - svdm_exit_dp_mode
+ pd_svdm[common/usb_pd_policy.c:767]:
+ - svdm_dp_status
+ pd_svdm[common/usb_pd_policy.c:778]:
+ - svdm_dp_config
+ pd_svdm[common/usb_pd_policy.c:784]:
+ - svdm_dp_post_config
+ # Motion sense
+ queue_advance_head[common/queue.c:105]:
+ - queue_action_null
+ queue_advance_tail[common/queue.c:116]:
+ - queue_action_null
+ motion_sense_set_data_rate[common/motion_sense.c:270]:
+ - set_data_rate[driver/accelgyro_bmi160.c]
+ - set_data_rate[driver/accel_bma2x2.c]
+ motion_sense_set_data_rate[common/motion_sense.c:289]:
+ - get_data_rate[driver/accelgyro_bmi160.c]
+ - get_data_rate[driver/accel_bma2x2.c]
+ motion_sense_set_ec_rate_from_ap[common/motion_sense.c:308]:
+ - get_data_rate[driver/accelgyro_bmi160.c]
+ - get_data_rate[driver/accel_bma2x2.c]
+ motion_sense_set_motion_intervals.lto_priv.303[common/motion_sense.c:414]:
+ - get_data_rate[driver/accelgyro_bmi160.c]
+ - get_data_rate[driver/accel_bma2x2.c]
+ motion_sense_init[common/motion_sense.c:450]:
+ - init[driver/accelgyro_bmi160.c]
+ - init[driver/accel_bma2x2.c]
+ sensor_init_done[common/motion_sense.c:471]:
+ - set_range[driver/accelgyro_bmi160.c]
+ - set_range[driver/accel_bma2x2.c]
+ sensor_init_done[common/motion_sense.c:474]:
+ - get_range[driver/accelgyro_bmi160.c]
+ - get_range[driver/accel_bma2x2.c]
+ motion_sense_process.isra.9[common/motion_sense.c:721]:
+ - irq_handler[driver/accelgyro_bmi160.c]
+ host_cmd_motion_sense[common/motion_sense.c:1251]:
+ - set_range[driver/accelgyro_bmi160.c]
+ - set_range[driver/accel_bma2x2.c]
+ host_cmd_motion_sense[common/motion_sense.c:1259]:
+ - get_range[driver/accelgyro_bmi160.c]
+ - get_range[driver/accel_bma2x2.c]
+ host_cmd_motion_sense[common/motion_sense.c:1274]:
+ - set_offset[driver/accelgyro_bmi160.c]
+ - set_offset[driver/accel_bma2x2.c]
+ host_cmd_motion_sense[common/motion_sense.c:1297]:
+ - perform_calib[driver/accelgyro_bmi160.c]
+ host_cmd_motion_sense[common/motion_sense.c:1300]:
+ - get_offset[driver/accelgyro_bmi160.c]
+ - get_offset[driver/accel_bma2x2.c]
+ command_accelrange[common/motion_sense.c:1515]:
+ - set_range[driver/accelgyro_bmi160.c]
+ - set_range[driver/accel_bma2x2.c]
+ command_accelrange[common/motion_sense.c:1520]:
+ - get_range[driver/accelgyro_bmi160.c]
+ - get_range[driver/accel_bma2x2.c]
+ host_cmd_motion_sense[common/motion_sense.c:1520]:
+ - get_range[driver/accelgyro_bmi160.c]
+ - get_range[driver/accel_bma2x2.c]
+ command_accelresolution[common/motion_sense.c:1564]:
+ - None
+ command_accelresolution[common/motion_sense.c:1568]:
+ - get_resolution[driver/accelgyro_bmi160.c]
+ - get_resolution[driver/accel_bma2x2.c]
+ command_accel_data_rate[common/motion_sense.c:1623]:
+ - get_data_rate[driver/accelgyro_bmi160.c]
+ - get_data_rate[driver/accel_bma2x2.c]
+ command_accel_read_xyz[common/motion_sense.c:1659]:
+ - read[driver/accelgyro_bmi160.c]
+ - read[driver/accel_bma2x2.c]
+ calculate_lid_angle[common/motion_lid.c:255]:
+ - get_range[driver/accelgyro_bmi160.c]
+ - get_range[driver/accel_bma2x2.c]
+ calculate_lid_angle[common/motion_lid.c:256]:
+ - get_range[driver/accelgyro_bmi160.c]
+ - get_range[driver/accel_bma2x2.c]
+ # Temp (see temp_sensors array in board file)
+ temp_sensor_read[common/temp_sensor.c:26]:
+ - charge_get_battery_temp
+ - bd99992gw_get_val
+ # Misc
+ jump_to_image[common/system.c:568]:
+ - None
+ system_download_from_flash[chip/npcx/system-npcx5.c:257]:
+ - None
+ __hibernate_npcx_series[chip/npcx/system-npcx5.c:144]:
+ - None
+ handle_command[common/console.c:248]:
+ - { name: __cmds, stride: 16, offset: 4 }
+ hook_task[common/hooks.c:197]:
+ - { name: __deferred_funcs, stride: 4, offset: 0 }
+ - { name: __hooks_second, stride: 8, offset: 0 }
+ - { name: __hooks_tick, stride: 8, offset: 0 }
+ # Note: This assumes worse case, where all hook functions can be called from
+ # any hook_notify call
+ # Generate using `grep hooks_.*_end build/nautilus/R*/ec.R*.smap |
+ # sed -e 's/.*\(__hooks.*\)_end/ - { name: \1, stride: 8, offset: 0 }/' |
+ # sort -u`
+ hook_notify[common/hooks.c:127]:
+ - { name: __hooks_ac_change, stride: 8, offset: 0 }
+ - { name: __hooks_battery_soc_change, stride: 8, offset: 0 }
+ - { name: __hooks_chipset_pre_init, stride: 8, offset: 0 }
+ - { name: __hooks_chipset_reset, stride: 8, offset: 0 }
+ - { name: __hooks_chipset_resume, stride: 8, offset: 0 }
+ - { name: __hooks_chipset_shutdown, stride: 8, offset: 0 }
+ - { name: __hooks_chipset_startup, stride: 8, offset: 0 }
+ - { name: __hooks_chipset_suspend, stride: 8, offset: 0 }
+ - { name: __hooks_freq_change, stride: 8, offset: 0 }
+ - { name: __hooks_lid_change, stride: 8, offset: 0 }
+ - { name: __hooks_pre_freq_change, stride: 8, offset: 0 }
+ - { name: __hooks_pwrbtn_change, stride: 8, offset: 0 }
+ - { name: __hooks_sysjump, stride: 8, offset: 0 }
+ - { name: __hooks_tablet_mode_change, stride: 8, offset: 0 }
+ mkbp_get_next_event[common/mkbp_event.c:130]:
+ - { name: __mkbp_evt_srcs, stride: 8, offset: 4 }
+ host_send_response[common/host_command.c:153]:
+ - lpc_send_response
+ host_packet_respond[common/host_command.c:240]:
+ - lpc_send_response
+ host_command_process[common/host_command.c:704]:
+ - { name: __hcmds, stride: 12, offset: 0 }
+ # gpio_interrupt.lto_priv.407[chip/npcx/gpio.c:479]
+ vfnprintf:
+ # This covers all the addchar in vfnprintf, but stackanalyzer does not
+ # realize that...
+ - __tx_char
+ i2c_command_passthru[common/i2c_master.c:597]:
+ - None
+remove:
+# Remove all callsites pointing to panic_assert_fail.
+- panic_assert_fail
+# Remove hook paths that don't make sense
+- [ [ common_intel_x86_power_handle_state, power_button_change_deferred, hook_task, lpc_chipset_reset, espi_chipset_reset ], hook_notify, powerbtn_x86_lid_change ]
+- [ system_common_shutdown, hook_notify, system_run_image_copy ]
+- [ jump_to_image, hook_notify, [ powerbtn_x86_lid_change, system_common_shutdown, power_up_inhibited_cb, motion_sense_shutdown, motion_sense_resume ] ]
+- [ [ extpower_deferred, charger_task, motion_sense_switch_sensor_rate, lid_switch_open, lid_switch_close, motion_sense_task ], hook_notify, [ powerbtn_x86_lid_change, power_up_inhibited_cb, system_common_shutdown, motion_sense_shutdown, motion_sense_resume ] ]
+- [ common_intel_x86_power_handle_state, hook_notify, power_up_inhibited_cb ]
+# pd_request_power_swap calls set_state with either PD_STATE_SRC_SWAP_INIT or
+# PD_STATE_SNK_SWAP_INIT as parameters, which cannot call any of the
+# charge_manager functions.
+- [ [ pd_request_power_swap, pd_execute_hard_reset, pd_request_data_swap, pd_request_vconn_swap.lto_priv.237, pd_send_request_msg.lto_priv.250 ], set_state.lto_priv.236, [ typec_set_input_current_limit, charge_manager_update_charge, pd_power_supply_reset, pd_dfp_exit_mode, usb_mux_set ] ]
+# Debug prints that do not actually need a 64 uint division, of the time
+- [ [i2c_reset, i2c_abort_data, i2c_xfer], cprintf, vfnprintf, [uint64divmod.part.3.lto_priv.141, get_time] ]
diff --git a/board/rammus/battery.c b/board/rammus/battery.c
new file mode 100644
index 0000000000..642497cdfe
--- /dev/null
+++ b/board/rammus/battery.c
@@ -0,0 +1,224 @@
+/* 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.
+ *
+ * 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 parameters to write to manufacturer access register */
+#define SB_SHIP_MODE_REG SB_MANUFACTURER_ACCESS
+#define SB_SHUTDOWN_DATA 0x0010
+
+/*
+ * Unlike other smart batteries, Nautilus battery uses different bit fields
+ * in manufacturer access register for the conditions of the CHG/DSG FETs.
+ */
+#define BATFETS_SHIFT (14)
+#define BATFETS_MASK (0x3)
+#define BATFETS_DISABLED (0x2)
+
+#define CHARGING_VOLTAGE_MV_SAFE 8400
+#define CHARGING_CURRENT_MA_SAFE 1500
+
+static const struct battery_info info = {
+ .voltage_max = 8700,
+ .voltage_normal = 7700,
+ .voltage_min = 6000,
+ /* Pre-charge values. */
+ .precharge_current = 200, /* mA */
+
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 45,
+ .charging_min_c = 0,
+ .charging_max_c = 50,
+ .discharging_min_c = -20,
+ .discharging_max_c = 70,
+};
+
+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)
+{
+ int current;
+ int voltage;
+ /* battery temp in 0.1 deg C */
+ int bat_temp_c;
+
+ /*
+ * Keep track of battery temperature range:
+ *
+ * ZONE_0 ZONE_1 ZONE_2 ZONE_3
+ * ---+------+--------+--------+------+--- Temperature (C)
+ * 0 5 12 45 50
+ */
+ enum {
+ TEMP_ZONE_0, /* 0 <= bat_temp_c <= 5 */
+ TEMP_ZONE_1, /* 5 < bat_temp_c <= 12 */
+ TEMP_ZONE_2, /* 12 < bat_temp_c <= 45 */
+ TEMP_ZONE_3, /* 45 < bat_temp_c <= 50 */
+ TEMP_ZONE_COUNT,
+ TEMP_OUT_OF_RANGE = TEMP_ZONE_COUNT
+ } temp_zone;
+
+ current = curr->requested_current;
+ voltage = curr->requested_voltage;
+ bat_temp_c = curr->batt.temperature - 2731;
+
+ /*
+ * If the temperature reading is bad, assume the temperature
+ * is out of allowable range.
+ */
+ if ((curr->batt.flags & BATT_FLAG_BAD_TEMPERATURE) ||
+ (bat_temp_c < 0) || (bat_temp_c > 500))
+ temp_zone = TEMP_OUT_OF_RANGE;
+ else if (bat_temp_c <= 50)
+ temp_zone = TEMP_ZONE_0;
+ else if (bat_temp_c <= 120)
+ temp_zone = TEMP_ZONE_1;
+ else if (bat_temp_c <= 450)
+ temp_zone = TEMP_ZONE_2;
+ else
+ temp_zone = TEMP_ZONE_3;
+
+ switch (temp_zone) {
+ case TEMP_ZONE_0:
+ voltage = CHARGING_VOLTAGE_MV_SAFE;
+ current = CHARGING_CURRENT_MA_SAFE;
+ break;
+ case TEMP_ZONE_1:
+ current = CHARGING_CURRENT_MA_SAFE;
+ break;
+ case TEMP_ZONE_2:
+ break;
+ case TEMP_ZONE_3:
+ voltage = CHARGING_VOLTAGE_MV_SAFE;
+ break;
+ case TEMP_OUT_OF_RANGE:
+ /* Don't charge if outside of allowable temperature range */
+ current = 0;
+ voltage = 0;
+ curr->batt.flags &= ~BATT_FLAG_WANT_CHARGE;
+ curr->state = ST_IDLE;
+ break;
+ }
+
+ curr->requested_voltage = MIN(curr->requested_voltage, voltage);
+ curr->requested_current = MIN(curr->requested_current, current);
+
+ 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 might happen when power is reconnected
+ * to a battery pack in sleep mode. In this transient siuation, 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;
+ int batt_mfgacc;
+
+ /* Check if battery charging + discharging is disabled. */
+ rv = sb_read(SB_MANUFACTURER_ACCESS, &batt_mfgacc);
+ if (rv)
+ return BATTERY_DISCONNECT_ERROR;
+
+ if (((batt_mfgacc >> BATFETS_SHIFT) & BATFETS_MASK) ==
+ BATFETS_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
+ * successful & 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/rammus/board.c b/board/rammus/board.c
new file mode 100644
index 0000000000..57b9de2388
--- /dev/null
+++ b/board/rammus/board.c
@@ -0,0 +1,808 @@
+/* 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.
+ */
+
+/* Poppy board-specific configuration */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "bd99992gw.h"
+#include "board_config.h"
+#include "battery_smart.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/accel_bma2x2.h"
+#include "driver/baro_bmp280.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 "keyboard_scan.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)
+
+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);
+}
+
+#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_HOSTCMD_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[] = {
+ {"tcpc0", NPCX_I2C_PORT0_0, 400, GPIO_I2C0_0_SCL, GPIO_I2C0_0_SDA},
+ {"tcpc1", 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] = {
+ {
+ .i2c_host_port = NPCX_I2C_PORT0_0,
+ .i2c_slave_addr = PS8751_I2C_ADDR1,
+ .drv = &ps8xxx_tcpm_drv,
+ .pol = TCPC_ALERT_ACTIVE_LOW,
+ },
+ {
+ .i2c_host_port = NPCX_I2C_PORT0_1,
+ .i2c_slave_addr = PS8751_I2C_ADDR1,
+ .drv = &ps8xxx_tcpm_drv,
+ .pol = TCPC_ALERT_ACTIVE_LOW,
+ },
+};
+
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .port_addr = 0,
+ .driver = &tcpci_tcpm_usb_mux_driver,
+ .hpd_update = &ps8xxx_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);
+
+const int usb_port_enable[CONFIG_USB_PORT_POWER_SMART_PORT_COUNT] = {
+ GPIO_USB1_ENABLE,
+};
+
+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(1);
+ gpio_set_level(GPIO_USB_C0_PD_RST_L, 1);
+ gpio_set_level(GPIO_USB_C1_PD_RST_L, 1);
+}
+
+void board_tcpc_init(void)
+{
+ int port;
+
+ /* Only reset TCPC if not sysjump */
+ if (!system_jumped_to_this_image()) {
+ board_reset_pd_mcu();
+ }
+
+ /* Enable TCPC interrupts */
+ gpio_enable_interrupt(GPIO_USB_C0_PD_INT_ODL);
+ gpio_enable_interrupt(GPIO_USB_C1_PD_INT_ODL);
+
+ /*
+ * 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 */
+ {"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},
+};
+BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
+
+/*
+ * Check if PMIC fault registers indicate VR fault. If yes, print out fault
+ * register info to console. Additionally, set panic reason so that the OS can
+ * check for fault register info by looking at offset 0x14(PWRSTAT1) and
+ * 0x15(PWRSTAT2) in cros ec panicinfo.
+ */
+static void board_report_pmic_fault(const char *str)
+{
+ int vrfault, pwrstat1 = 0, pwrstat2 = 0;
+ uint32_t info;
+
+ /* RESETIRQ1 -- Bit 4: VRFAULT */
+ if (i2c_read8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x8, &vrfault)
+ != EC_SUCCESS)
+ return;
+
+ if (!(vrfault & (1 << 4)))
+ return;
+
+ /* VRFAULT has occurred, print VRFAULT status bits. */
+
+ /* PWRSTAT1 */
+ i2c_read8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x16, &pwrstat1);
+
+ /* PWRSTAT2 */
+ i2c_read8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x17, &pwrstat2);
+
+ CPRINTS("PMIC VRFAULT: %s", str);
+ CPRINTS("PMIC VRFAULT: PWRSTAT1=0x%02x PWRSTAT2=0x%02x", pwrstat1,
+ pwrstat2);
+
+ /* Clear all faults -- Write 1 to clear. */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x8, (1 << 4));
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x16, pwrstat1);
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x17, pwrstat2);
+
+ /*
+ * Status of the fault registers can be checked in the OS by looking at
+ * offset 0x14(PWRSTAT1) and 0x15(PWRSTAT2) in cros ec panicinfo.
+ */
+ info = ((pwrstat2 & 0xFF) << 8) | (pwrstat1 & 0xFF);
+ panic_set_reason(PANIC_SW_PMIC_FAULT, info, 0);
+}
+
+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 (11) - Nominal output voltage: 0.850V
+ * 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, 0x3a);
+
+ /*
+ * 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 (11) - Nominal output voltage: 0.850V
+ * 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, 0x7a);
+
+ /*
+ * 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)
+{
+ board_report_pmic_fault("SYSJUMP");
+
+ 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_DEFERRED(board_pmic_init);
+
+/* 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 VBUS interrupt */
+ 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);
+
+ /* Level of sensor's I2C and interrupt are 3.3V on proto board */
+ if(system_get_board_version() < 2) {
+ /* ACCELGYRO3_INT_L */
+ gpio_set_flags(GPIO_ACCELGYRO3_INT_L, GPIO_INT_FALLING);
+ /* I2C3_SCL / I2C3_SDA */
+ gpio_set_flags(GPIO_I2C3_SCL, GPIO_INPUT);
+ gpio_set_flags(GPIO_I2C3_SDA, GPIO_INPUT);
+ }
+
+ /* Enable Gyro interrupts */
+ gpio_enable_interrupt(GPIO_ACCELGYRO3_INT_L);
+
+ /* Initialize PMIC */
+ hook_call_deferred(&board_pmic_init_data, 0);
+}
+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)
+{
+ /* 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;
+ }
+
+ 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);
+ }
+
+ 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)
+{
+ /*
+ * Limit the input current to 96% negotiated limit,
+ * to account for the charger chip margin.
+ */
+ charge_ma = charge_ma * 96 / 100;
+ 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;
+ }
+}
+
+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 id3;
+
+ if (ver != -1)
+ return ver;
+
+ ver = 0;
+
+ /* First 2 strappings are binary. */
+ if (gpio_get_level(GPIO_BOARD_VERSION1))
+ ver |= 0x01;
+ if (gpio_get_level(GPIO_BOARD_VERSION2))
+ ver |= 0x02;
+
+ /*
+ * The 3rd strapping pin is tristate.
+ * id3 = 2 if Hi-Z, id3 = 1 if high, and id3 = 0 if low.
+ */
+ id3 = gpio_get_ternary(GPIO_BOARD_VERSION3);
+ ver |= id3 * 0x04;
+
+ CPRINTS("Board ID = %d", ver);
+
+ return ver;
+}
+
+/* Lid Sensor mutex */
+static struct mutex g_lid_mutex;
+static struct mutex g_base_mutex;
+
+static struct bmi160_drv_data_t g_bmi160_data;
+
+/* BMA255 private data */
+static struct accelgyro_saved_data_t g_bma255_data;
+
+/* Matrix to rotate accelrator into standard reference frame */
+const matrix_3x3_t base_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_S3,
+ .chip = MOTIONSENSE_CHIP_BMA255,
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .location = MOTIONSENSE_LOC_LID,
+ .drv = &bma2x2_accel_drv,
+ .mutex = &g_lid_mutex,
+ .drv_data = &g_bma255_data,
+ .port = I2C_PORT_ACCEL,
+ .addr = BMA2x2_I2C_ADDR1,
+ .rot_standard_ref = &lid_standard_ref,
+ .min_frequency = BMA255_ACCEL_MIN_FREQ,
+ .max_frequency = BMA255_ACCEL_MAX_FREQ,
+ .default_range = 2, /* g, to support tablet mode */
+ .config = {
+ /* EC use accel for angle detection */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ },
+ /* Sensor on in S3 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ },
+ },
+ },
+ [BASE_ACCEL] = {
+ .name = "Base Accel",
+ .active_mask = SENSOR_ACTIVE_S0_S3,
+ .chip = MOTIONSENSE_CHIP_BMI160,
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .location = MOTIONSENSE_LOC_BASE,
+ .drv = &bmi160_drv,
+ .mutex = &g_base_mutex,
+ .drv_data = &g_bmi160_data,
+ .port = I2C_PORT_ACCEL,
+ .addr = BMI160_ADDR0,
+ .rot_standard_ref = &base_standard_ref,
+ .min_frequency = BMI160_ACCEL_MIN_FREQ,
+ .max_frequency = BMI160_ACCEL_MAX_FREQ,
+ .default_range = 2, /* g, to support tablet mode */
+ .config = {
+ /* EC use accel for angle detection */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 100 * MSEC,
+ },
+ /* Sensor on in S3 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ },
+ },
+ },
+ [BASE_GYRO] = {
+ .name = "Base Gyro",
+ .active_mask = SENSOR_ACTIVE_S0_S3,
+ .chip = MOTIONSENSE_CHIP_BMI160,
+ .type = MOTIONSENSE_TYPE_GYRO,
+ .location = MOTIONSENSE_LOC_BASE,
+ .drv = &bmi160_drv,
+ .mutex = &g_base_mutex,
+ .drv_data = &g_bmi160_data,
+ .port = I2C_PORT_ACCEL,
+ .addr = BMI160_ADDR0,
+ .default_range = 1000, /* dps */
+ .rot_standard_ref = &base_standard_ref,
+ .min_frequency = BMI160_GYRO_MIN_FREQ,
+ .max_frequency = BMI160_GYRO_MAX_FREQ,
+ },
+};
+const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
+
+/* Enable or disable input devices, based on chipset state and tablet mode */
+#ifndef TEST_BUILD
+void lid_angle_peripheral_enable(int enable)
+{
+ /* If the lid is in 360 position, ignore the lid angle,
+ * which might be faulty. Disable keyboard.
+ */
+ if (tablet_get_mode() || chipset_in_state(CHIPSET_STATE_ANY_OFF))
+ enable = 0;
+ keyboard_scan_enable(enable, KB_SCAN_DISABLE_LID_ANGLE);
+}
+#endif
+
+static void board_chipset_reset(void)
+{
+ board_report_pmic_fault("CHIPSET RESET");
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESET, board_chipset_reset, HOOK_PRIO_DEFAULT);
+
+/* 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 USB-A port. */
+ gpio_set_level(GPIO_USB1_ENABLE, 1);
+
+ gpio_set_level(GPIO_ENABLE_TOUCHPAD, 1);
+
+ gpio_set_level(GPIO_PP1800_DX_SENSOR, 1);
+}
+DECLARE_HOOK(HOOK_CHIPSET_STARTUP, board_chipset_startup, HOOK_PRIO_DEFAULT);
+
+static void board_chipset_shutdown(void)
+{
+ /* Disable USB-A port. */
+ gpio_set_level(GPIO_USB1_ENABLE, 0);
+
+ gpio_set_level(GPIO_ENABLE_TOUCHPAD, 0);
+
+ gpio_set_level(GPIO_PP1800_DX_SENSOR, 0);
+}
+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, Rev2 and Rev3 will lose reset flags on power cycle. */
+ if ((version == 1) || (version == 2) || (version == 3))
+ return 0;
+
+ /* All other board versions should have working reset flags */
+ return 1;
+}
+
+/*
+ * I2C callbacks to ensure bus free time for battery I2C transactions is at
+ * least 5ms.
+ */
+#define BATTERY_FREE_MIN_DELTA_US (5 * MSEC)
+static timestamp_t battery_last_i2c_time;
+
+static int is_battery_i2c(int port, int slave_addr)
+{
+ return (port == I2C_PORT_BATTERY) && (slave_addr == BATTERY_ADDR);
+}
+
+void i2c_start_xfer_notify(int port, int slave_addr)
+{
+ unsigned int time_delta_us;
+
+ if (!is_battery_i2c(port, slave_addr))
+ return;
+
+ time_delta_us = time_since32(battery_last_i2c_time);
+ if (time_delta_us >= BATTERY_FREE_MIN_DELTA_US)
+ return;
+
+ usleep(BATTERY_FREE_MIN_DELTA_US - time_delta_us);
+}
+
+void i2c_end_xfer_notify(int port, int slave_addr)
+{
+ if (!is_battery_i2c(port, slave_addr))
+ return;
+
+ battery_last_i2c_time = get_time();
+}
diff --git a/board/rammus/board.h b/board/rammus/board.h
new file mode 100644
index 0000000000..80e2111774
--- /dev/null
+++ b/board/rammus/board.h
@@ -0,0 +1,259 @@
+/* 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.
+ */
+
+/* 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_CUSTOM
+#define CONFIG_BOARD_FORCE_RESET_PIN
+#define CONFIG_CASE_CLOSED_DEBUG_EXTERNAL
+#define CONFIG_DPTF
+#define CONFIG_DPTF_DEVICE_ORIENTATION
+#define CONFIG_FLASH_SIZE 0x80000
+#define CONFIG_FPU
+#define CONFIG_I2C
+#define CONFIG_I2C_MASTER
+#define CONFIG_I2C_XFER_BOARD_CALLBACK
+#define CONFIG_KEYBOARD_COL2_INVERTED
+#define CONFIG_KEYBOARD_PROTOCOL_8042
+#define CONFIG_LED_COMMON
+#define CONFIG_LID_SWITCH
+#define CONFIG_LOW_POWER_IDLE
+#define CONFIG_LTO
+#define CONFIG_CHIP_PANIC_BACKUP
+#define CONFIG_SOFTWARE_PANIC
+#define CONFIG_SPI_FLASH_REGS
+#define CONFIG_SPI_FLASH_W25X40
+#define CONFIG_VBOOT_HASH
+#define CONFIG_SHA256_UNROLLED
+#define CONFIG_VOLUME_BUTTONS
+#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
+
+/* EC console commands */
+#define CONFIG_CMD_ACCELS
+#define CONFIG_CMD_ACCEL_INFO
+#define CONFIG_CMD_BUTTON
+
+/* Port80 */
+#undef CONFIG_PORT80_HISTORY_LEN
+#define CONFIG_PORT80_HISTORY_LEN 256
+
+/* SOC */
+#define CONFIG_CHIPSET_SKYLAKE
+#define CONFIG_CHIPSET_HAS_PLATFORM_PMIC_RESET
+#define CONFIG_CHIPSET_RESET_HOOK
+#define CONFIG_HOSTCMD_ESPI
+#define CONFIG_HOSTCMD_ESPI_VW_SIGNALS
+
+/* Battery */
+#define CONFIG_BATTERY_CUT_OFF
+#define CONFIG_BATTERY_HW_PRESENT_CUSTOM
+#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_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
+
+/* USB-A config */
+#define CONFIG_USB_PORT_POWER_SMART
+#define CONFIG_USB_PORT_POWER_SMART_CDP_SDP_ONLY
+#undef CONFIG_USB_PORT_POWER_SMART_PORT_COUNT
+#define CONFIG_USB_PORT_POWER_SMART_PORT_COUNT 1
+#define GPIO_USB1_ILIM_SEL GPIO_USB_A_ILIM_SEL
+
+/* Sensor */
+#define CONFIG_TEMP_SENSOR
+#define CONFIG_TEMP_SENSOR_BD99992GW
+#define CONFIG_THERMISTOR_NCP15WB
+
+#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_HOST_EVENT
+#define CONFIG_ACCELGYRO_BMI160
+#define CONFIG_ACCELGYRO_BMI160_INT_EVENT TASK_EVENT_CUSTOM(4)
+#define CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT
+#define CONFIG_ACCEL_BMA255
+#define CONFIG_ACCEL_INTERRUPTS
+#define CONFIG_LID_ANGLE
+#define CONFIG_LID_ANGLE_SENSOR_BASE BASE_ACCEL
+#define CONFIG_LID_ANGLE_SENSOR_LID LID_ACCEL
+#define CONFIG_LID_ANGLE_UPDATE
+#define CONFIG_LID_ANGLE_TABLET_MODE
+#define CONFIG_LID_ANGLE_INVALID_CHECK
+
+/* FIFO size is in power of 2. */
+#define CONFIG_ACCEL_FIFO 512
+
+/* Depends on how fast the AP boots and typical ODRs */
+#define CONFIG_ACCEL_FIFO_THRES (CONFIG_ACCEL_FIFO / 3)
+
+#undef CONFIG_UART_TX_BUF_SIZE
+#define CONFIG_UART_TX_BUF_SIZE 4096
+
+#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_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_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_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
+};
+
+/* Nautilus doesn't have systherm0 and systherm3 */
+enum temp_sensor_id {
+ TEMP_SENSOR_BATTERY, /* BD99956GW TSENSE */
+ TEMP_SENSOR_CHARGER, /* BD99992GW SYSTHERM1 */
+ TEMP_SENSOR_DRAM, /* BD99992GW SYSTHERM2 */
+ TEMP_SENSOR_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,
+ BASE_ACCEL,
+ BASE_GYRO,
+};
+
+enum adc_channel {
+ ADC_BASE_DET,
+ ADC_VBUS,
+ ADC_AMON_BMON,
+ ADC_CH_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);
+
+/* Sensors without hardware FIFO are in forced mode */
+#define CONFIG_ACCEL_FORCE_MODE_MASK (1 << LID_ACCEL)
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* __CROS_EC_BOARD_H */
diff --git a/board/rammus/build.mk b/board/rammus/build.mk
new file mode 100644
index 0000000000..f4bf21113d
--- /dev/null
+++ b/board/rammus/build.mk
@@ -0,0 +1,15 @@
+# -*- makefile -*-
+# 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.
+#
+# 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/rammus/ec.tasklist b/board/rammus/ec.tasklist
new file mode 100644
index 0000000000..8afac3eebb
--- /dev/null
+++ b/board/rammus/ec.tasklist
@@ -0,0 +1,37 @@
+/* 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.
+ */
+
+/*
+ * 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, 800) \
+ TASK_ALWAYS(USB_CHG_P0, usb_charger_task, NULL, 720) \
+ TASK_ALWAYS(USB_CHG_P1, usb_charger_task, NULL, 720) \
+ TASK_ALWAYS(CHARGER, charger_task, NULL, 800) \
+ TASK_ALWAYS(MOTIONSENSE, motion_sense_task, NULL, 768) \
+ TASK_NOTEST(CHIPSET, chipset_task, NULL, 800) \
+ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, 600) \
+ TASK_NOTEST(PDCMD, pd_command_task, NULL, 800) \
+ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, 840) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, 880) \
+ TASK_ALWAYS(POWERBTN, power_button_task, NULL, 800) \
+ TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, 600) \
+ TASK_ALWAYS(PD_C0, pd_task, NULL, 1000) \
+ TASK_ALWAYS(PD_C1, pd_task, NULL, 1000)
diff --git a/board/rammus/gpio.inc b/board/rammus/gpio.inc
new file mode 100644
index 0000000000..0d6f04e977
--- /dev/null
+++ b/board/rammus/gpio.inc
@@ -0,0 +1,123 @@
+/* -*- mode:c -*-
+ *
+ * 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.
+ */
+
+/* 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_HOSTCMD_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)
+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 | GPIO_SEL_1P8V, bmi160_interrupt)
+
+GPIO(ENABLE_TOUCHPAD, PIN(4, 5), GPIO_OUT_LOW)
+GPIO(PCH_RTCRST, PIN(2, 7), GPIO_OUT_LOW) /* RTCRST# to SOC (>= rev4) */
+GPIO(ENABLE_BACKLIGHT, PIN(5, 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(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
+
+/* NC pins */
+GPIO(GPIO02_NC, PIN(0, 2), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(GPIO32_NC, PIN(3, 2), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(GPIO71_NC, PIN(7, 1), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(GPIO80_NC, PIN(8, 0), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(GPIOD2_NC, PIN(D, 2), GPIO_INPUT | GPIO_PULL_UP)
+
+/* Sensor Power */
+GPIO(PP1800_DX_SENSOR, PIN(E, 7), 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_USBC_3V3_SCL */
+GPIO(I2C0_1_SDA, PIN(B, 2), GPIO_INPUT) /* EC_I2C0_1_USBC_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 | GPIO_SEL_1P8V) /* EC_I2C3_SENSOR_1V8_SCL */
+GPIO(I2C3_SDA, PIN(D, 0), GPIO_INPUT | GPIO_SEL_1P8V) /* 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_ODR_HIGH) /* C0 PD Reset */
+GPIO(USB_C1_PD_RST_L, PIN(7, 4), GPIO_ODR_HIGH) /* 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 */
+
+/* USB Type-A control */
+GPIO(USB_A_ILIM_SEL, PIN(0, 0), GPIO_OUT_LOW)
+GPIO(USB1_ENABLE, PIN(0, 1), GPIO_OUT_LOW)
+
+/* LEDs (2 colors on each port) */
+GPIO(LED_ACIN, PIN(B, 6), GPIO_OUT_HIGH) /* ACIN LED */
+GPIO(POWER_LED, PIN(B, 7), GPIO_OUT_HIGH) /* Power LED */
+GPIO(LED_CHARGE, PIN(C, 6), GPIO_OUT_HIGH) /* Charge LED */
+
+/* Board ID */
+GPIO(BOARD_VERSION1, PIN(8, 6), GPIO_INPUT) /* Board ID bit0 */
+GPIO(BOARD_VERSION2, PIN(C, 2), GPIO_INPUT) /* Board ID bit1 */
+GPIO(BOARD_VERSION3, PIN(C, 4), GPIO_INPUT) /* Board ID bit2 */
+
+/* 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 */
+
+/* Keyboard pins */
+ALTERNATE(PIN_MASK(3, 0x03), 0, MODULE_KEYBOARD_SCAN, 0)
+ALTERNATE(PIN_MASK(2, 0xfc), 0, MODULE_KEYBOARD_SCAN, 0)
+ALTERNATE(PIN_MASK(2, 0x03), 0, MODULE_KEYBOARD_SCAN, 0)
+ALTERNATE(PIN_MASK(0, 0xe0), 0, MODULE_KEYBOARD_SCAN, 0)
+ALTERNATE(PIN_MASK(1, 0x7f), 0, MODULE_KEYBOARD_SCAN, 0)
+GPIO(KBD_KSO2, PIN(1, 7), GPIO_OUT_LOW)
diff --git a/board/rammus/led.c b/board/rammus/led.c
new file mode 100644
index 0000000000..86567701f0
--- /dev/null
+++ b/board/rammus/led.c
@@ -0,0 +1,136 @@
+/* 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
+
+#define LED_TOTAL_TICKS 16
+#define LED_ON_TICKS 8
+
+const enum ec_led_id supported_led_ids[] = {
+ EC_LED_ID_POWER_LED,
+ EC_LED_ID_BATTERY_LED};
+
+const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids);
+
+enum led_color {
+ LED_OFF = 0,
+ LED_RED,
+ LED_GREEN,
+ LED_BLUE,
+
+ /* Number of colors, not a color itself */
+ LED_COLOR_COUNT
+};
+
+/**
+ * Set LED color
+ *
+ * @param color Enumerated color value
+ */
+static void set_color(enum led_color color)
+{
+ gpio_set_level(GPIO_POWER_LED, !(color == LED_BLUE));
+ gpio_set_level(GPIO_LED_ACIN, !(color == LED_GREEN));
+ gpio_set_level(GPIO_LED_CHARGE, !(color == LED_RED));
+}
+
+void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
+{
+ brightness_range[EC_LED_COLOR_RED] = 1;
+ brightness_range[EC_LED_COLOR_BLUE] = 1;
+ brightness_range[EC_LED_COLOR_GREEN] = 1;
+}
+
+int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness)
+{
+ gpio_set_level(GPIO_POWER_LED, !brightness[EC_LED_COLOR_BLUE]);
+ gpio_set_level(GPIO_LED_ACIN, !brightness[EC_LED_COLOR_GREEN]);
+ gpio_set_level(GPIO_LED_CHARGE, !brightness[EC_LED_COLOR_RED]);
+
+ return EC_SUCCESS;
+}
+
+
+static void nautilus_led_set_power_battery(void)
+{
+ static unsigned int power_ticks;
+ enum led_color cur_led_color = LED_RED;
+ enum charge_state chg_state = charge_get_state();
+ int charge_percent = charge_get_percent();
+
+ if (chipset_in_state(CHIPSET_STATE_ON)) {
+ set_color(LED_BLUE);
+ return;
+ }
+
+ /* Flash red on critical battery, which usually inhibits AP power-on. */
+ if (battery_is_present() != BP_YES ||
+ charge_percent < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) {
+ set_color(((power_ticks++ % LED_TOTAL_TICKS) < LED_ON_TICKS) ?
+ LED_RED : LED_OFF);
+ return;
+ }
+
+ /* CHIPSET_STATE_OFF */
+ switch (chg_state) {
+ case PWR_STATE_DISCHARGE:
+ if ((charge_get_flags() & CHARGE_FLAG_EXTERNAL_POWER) &&
+ charge_percent >= BATTERY_LEVEL_NEAR_FULL)
+ cur_led_color = LED_GREEN;
+ else
+ cur_led_color = LED_OFF;
+ break;
+ case PWR_STATE_CHARGE:
+ cur_led_color = LED_RED;
+ break;
+ case PWR_STATE_ERROR:
+ cur_led_color = ((power_ticks++ % LED_TOTAL_TICKS)
+ < LED_ON_TICKS) ? LED_RED : LED_GREEN;
+ break;
+ case PWR_STATE_CHARGE_NEAR_FULL:
+ case PWR_STATE_IDLE:
+ if(charge_get_flags() & CHARGE_FLAG_EXTERNAL_POWER)
+ cur_led_color = LED_GREEN;
+ else
+ cur_led_color = LED_OFF;
+ break;
+ default:
+ cur_led_color = LED_RED;
+ break;
+ }
+
+ set_color(cur_led_color);
+
+ if (chg_state != PWR_STATE_ERROR)
+ power_ticks = 0;
+}
+
+/**
+ * Called by hook task every 250 ms
+ */
+static void led_tick(void)
+{
+ if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED) &&
+ led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) {
+ nautilus_led_set_power_battery();
+ }
+}
+
+DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT);
diff --git a/board/rammus/usb_pd_policy.c b/board/rammus/usb_pd_policy.c
new file mode 100644
index 0000000000..f30882f475
--- /dev/null
+++ b/board/rammus/usb_pd_policy.c
@@ -0,0 +1,449 @@
+/* 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.
+ */
+
+#include "atomic.h"
+#include "extpower.h"
+#include "charge_manager.h"
+#include "common.h"
+#include "console.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)
+{
+ /* Only port 0 supports device mode. */
+ if (port != 0)
+ return;
+
+ gpio_set_level(GPIO_USB2_OTG_ID,
+ (data_role == PD_ROLE_UFP) ? 1 : 0);
+ gpio_set_level(GPIO_USB2_OTG_VBUSSENSE,
+ (data_role == PD_ROLE_UFP) ? 1 : 0);
+}
+
+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 */