summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRong Chang <rongchang@chromium.org>2017-09-04 14:01:59 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-11-29 04:04:12 -0800
commitcf0153224ebe3acd6264fb15c514184b282e78bb (patch)
treee221d37d46429cd9721cf84deadbe8eae3198b82
parent216bb5f9d7fdeac65e3ed572b463ca13982b7e83 (diff)
downloadchrome-ec-cf0153224ebe3acd6264fb15c514184b282e78bb.tar.gz
coffeecake: initial commit
Clone HoHo board to CoffeeCake. BRANCH=none BUG=none TEST=make BOARD=coffeecake -j Signed-off-by: Rong Chang <rongchang@chromium.org> Change-Id: I62b4bf92a2eaffbc145197c7f36cfb7a29722bf5 Reviewed-on: https://chromium-review.googlesource.com/673963 Reviewed-by: Benson Leung <bleung@chromium.org>
-rw-r--r--board/coffeecake/board.c249
-rw-r--r--board/coffeecake/board.h115
-rw-r--r--board/coffeecake/build.mk14
-rw-r--r--board/coffeecake/dev_key.pem27
-rw-r--r--board/coffeecake/ec.tasklist22
-rw-r--r--board/coffeecake/gpio.inc37
-rw-r--r--board/coffeecake/usb_pd_config.h128
-rw-r--r--board/coffeecake/usb_pd_policy.c281
-rwxr-xr-xutil/flash_ec1
9 files changed, 874 insertions, 0 deletions
diff --git a/board/coffeecake/board.c b/board/coffeecake/board.c
new file mode 100644
index 0000000000..27a5070651
--- /dev/null
+++ b/board/coffeecake/board.c
@@ -0,0 +1,249 @@
+/* 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.
+ */
+/* Coffeecake dock configuration */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "common.h"
+#include "ec_commands.h"
+#include "ec_version.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "mcdp28x0.h"
+#include "registers.h"
+#include "task.h"
+#include "usb_bb.h"
+#include "usb_descriptor.h"
+#include "usb_pd.h"
+#include "timer.h"
+#include "util.h"
+
+static volatile uint64_t hpd_prev_ts;
+static volatile int hpd_prev_level;
+
+void hpd_event(enum gpio_signal signal);
+#include "gpio_list.h"
+
+/**
+ * Hotplug detect deferred task
+ *
+ * Called after level change on hpd GPIO to evaluate (and debounce) what event
+ * has occurred. There are 3 events that occur on HPD:
+ * 1. low : downstream display sink is deattached
+ * 2. high : downstream display sink is attached
+ * 3. irq : downstream display sink signalling an interrupt.
+ *
+ * The debounce times for these various events are:
+ * HPD_USTREAM_DEBOUNCE_LVL : min pulse width of level value.
+ * HPD_USTREAM_DEBOUNCE_IRQ : min pulse width of IRQ low pulse.
+ *
+ * lvl(n-2) lvl(n-1) lvl prev_delta now_delta event
+ * ----------------------------------------------------
+ * 1 0 1 <IRQ n/a low glitch (ignore)
+ * 1 0 1 >IRQ <LVL irq
+ * x 0 1 n/a >LVL high
+ * 0 1 0 <LVL n/a high glitch (ignore)
+ * x 1 0 n/a >LVL low
+ */
+
+void hpd_irq_deferred(void)
+{
+ pd_send_hpd(0, hpd_irq);
+}
+DECLARE_DEFERRED(hpd_irq_deferred);
+
+void hpd_lvl_deferred(void)
+{
+ int level = gpio_get_level(GPIO_DP_HPD);
+
+ if (level != hpd_prev_level)
+ /* It's a glitch while in deferred or canceled action */
+ return;
+
+ pd_send_hpd(0, (level) ? hpd_high : hpd_low);
+}
+DECLARE_DEFERRED(hpd_lvl_deferred);
+
+void hpd_event(enum gpio_signal signal)
+{
+ timestamp_t now = get_time();
+ int level = gpio_get_level(signal);
+ uint64_t cur_delta = now.val - hpd_prev_ts;
+
+ /* store current time */
+ hpd_prev_ts = now.val;
+
+ /* All previous hpd level events need to be re-triggered */
+ hook_call_deferred(&hpd_lvl_deferred_data, -1);
+
+ /* It's a glitch. Previous time moves but level is the same. */
+ if (cur_delta < HPD_USTREAM_DEBOUNCE_IRQ)
+ return;
+
+ if ((!hpd_prev_level && level) &&
+ (cur_delta < HPD_USTREAM_DEBOUNCE_LVL))
+ /* It's an irq */
+ hook_call_deferred(&hpd_irq_deferred_data, 0);
+ else if (cur_delta >= HPD_USTREAM_DEBOUNCE_LVL)
+ hook_call_deferred(&hpd_lvl_deferred_data,
+ HPD_USTREAM_DEBOUNCE_LVL);
+
+ hpd_prev_level = level;
+}
+
+/* Initialize board. */
+void board_config_pre_init(void)
+{
+ /* enable SYSCFG clock */
+ STM32_RCC_APB2ENR |= 1 << 0;
+ /* Remap USART DMA to match the USART driver */
+ STM32_SYSCFG_CFGR1 |= (1 << 9) | (1 << 10);/* Remap USART1 RX/TX DMA */
+}
+
+#ifdef CONFIG_SPI_FLASH
+
+static void board_init_spi2(void)
+{
+ /* Remap SPI2 to DMA channels 6 and 7 */
+ STM32_SYSCFG_CFGR1 |= (1 << 24);
+
+ /* Set pin NSS to general purpose output mode (01b). */
+ /* Set pins SCK, MISO, and MOSI to alternate function (10b). */
+ STM32_GPIO_MODER(GPIO_B) &= ~0xff000000;
+ STM32_GPIO_MODER(GPIO_B) |= 0xa9000000;
+
+ /* Set all four pins to alternate function 0 */
+ STM32_GPIO_AFRH(GPIO_B) &= ~(0xffff0000);
+
+ /* Set all four pins to output push-pull */
+ STM32_GPIO_OTYPER(GPIO_B) &= ~(0xf000);
+
+ /* Set pullup on NSS */
+ STM32_GPIO_PUPDR(GPIO_B) |= 0x1000000;
+
+ /* Set all four pins to high speed */
+ STM32_GPIO_OSPEEDR(GPIO_B) |= 0xff000000;
+
+ /* Reset SPI2 */
+ STM32_RCC_APB1RSTR |= (1 << 14);
+ STM32_RCC_APB1RSTR &= ~(1 << 14);
+
+ /* Enable clocks to SPI2 module */
+ STM32_RCC_APB1ENR |= STM32_RCC_PB1_SPI2;
+}
+#endif /* CONFIG_SPI_FLASH */
+
+static void factory_validation_deferred(void)
+{
+ struct mcdp_info info;
+
+ mcdp_enable();
+
+ /* test mcdp via serial to validate function */
+ if (!mcdp_get_info(&info) && (MCDP_FAMILY(info.family) == 0x0010) &&
+ (MCDP_CHIPID(info.chipid) == 0x2850)) {
+ gpio_set_level(GPIO_MCDP_READY, 1);
+ pd_log_event(PD_EVENT_VIDEO_CODEC,
+ PD_LOG_PORT_SIZE(0, sizeof(info)),
+ 0, &info);
+ }
+
+ mcdp_disable();
+}
+DECLARE_DEFERRED(factory_validation_deferred);
+
+/* Initialize board. */
+static void board_init(void)
+{
+ timestamp_t now;
+#ifdef CONFIG_SPI_FLASH
+ board_init_spi2();
+#endif
+ now = get_time();
+ hpd_prev_level = gpio_get_level(GPIO_DP_HPD);
+ hpd_prev_ts = now.val;
+ gpio_enable_interrupt(GPIO_DP_HPD);
+
+ gpio_set_level(GPIO_STM_READY, 1); /* factory test only */
+ /* Delay needed to allow HDMI MCU to boot. */
+ hook_call_deferred(&factory_validation_deferred_data, 200*MSEC);
+}
+
+DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+
+/* ADC channels */
+const struct adc_t adc_channels[] = {
+ /* USB PD CC lines sensing. Converted to mV (3300mV/4096). */
+ [ADC_CH_CC1_PD] = {"USB_C_CC1_PD", 3300, 4096, 0, STM32_AIN(1)},
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
+const void * const usb_strings[] = {
+ [USB_STR_DESC] = usb_string_desc,
+ [USB_STR_VENDOR] = USB_STRING_DESC("Google Inc."),
+ [USB_STR_PRODUCT] = USB_STRING_DESC("Hoho"),
+ [USB_STR_VERSION] = USB_STRING_DESC(CROS_EC_VERSION32),
+ [USB_STR_BB_URL] = USB_STRING_DESC(USB_GOOGLE_TYPEC_URL),
+};
+BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
+
+/**
+ * USB configuration
+ * Any type-C device with alternate mode capabilities must have the following
+ * set of descriptors.
+ *
+ * 1. Standard Device
+ * 2. BOS
+ * 2a. Container ID
+ * 2b. Billboard Caps
+ */
+struct my_bos {
+ struct usb_bos_hdr_descriptor bos;
+ struct usb_contid_caps_descriptor contid_caps;
+ struct usb_bb_caps_base_descriptor bb_caps;
+ struct usb_bb_caps_svid_descriptor bb_caps_svids[1];
+};
+
+static struct my_bos bos_desc = {
+ .bos = {
+ .bLength = USB_DT_BOS_SIZE,
+ .bDescriptorType = USB_DT_BOS,
+ .wTotalLength = (USB_DT_BOS_SIZE + USB_DT_CONTID_SIZE +
+ USB_BB_CAPS_BASE_SIZE +
+ USB_BB_CAPS_SVID_SIZE * 1),
+ .bNumDeviceCaps = 2, /* contid + bb_caps */
+ },
+ .contid_caps = {
+ .bLength = USB_DT_CONTID_SIZE,
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_DC_DTYPE_CONTID,
+ .bReserved = 0,
+ .ContainerID = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ },
+ .bb_caps = {
+ .bLength = (USB_BB_CAPS_BASE_SIZE + USB_BB_CAPS_SVID_SIZE * 1),
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_DC_DTYPE_BILLBOARD,
+ .iAdditionalInfoURL = USB_STR_BB_URL,
+ .bNumberOfAlternateModes = 1,
+ .bPreferredAlternateMode = 1,
+ .VconnPower = 0,
+ .bmConfigured = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ .bReserved = 0,
+ },
+ .bb_caps_svids = {
+ {
+ .wSVID = 0xff01, /* TODO(tbroch) def'd in other CL remove hardcode */
+ .bAlternateMode = 1,
+ .iAlternateModeString = USB_STR_BB_URL, /* TODO(crosbug.com/p/32687) */
+ },
+ },
+};
+
+const struct bos_context bos_ctx = {
+ .descp = (void *)&bos_desc,
+ .size = sizeof(struct my_bos),
+};
diff --git a/board/coffeecake/board.h b/board/coffeecake/board.h
new file mode 100644
index 0000000000..f7bc554a21
--- /dev/null
+++ b/board/coffeecake/board.h
@@ -0,0 +1,115 @@
+/* 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.
+ */
+
+/* Coffee cake configuration */
+
+#ifndef __CROS_EC_BOARD_H
+#define __CROS_EC_BOARD_H
+
+/* 48 MHz SYSCLK clock frequency */
+#define CPU_CLOCK 48000000
+
+/* the UART console is on USART1 (PA9/PA10) */
+#define CONFIG_UART_CONSOLE 1
+
+/* Optional features */
+#define CONFIG_STM_HWTIMER32
+#define CONFIG_ADC
+#define CONFIG_BOARD_PRE_INIT
+#define CONFIG_CMD_SPI_FLASH
+#define CONFIG_HW_CRC
+#define CONFIG_RSA
+#define CONFIG_RWSIG
+#define CONFIG_RWSIG_TYPE_USBPD1
+#define CONFIG_SHA256
+/* TODO(tbroch) Re-enable once STM spi master can be inhibited at boot so it
+ doesn't interfere with HDMI loading its f/w */
+#undef CONFIG_SPI_FLASH
+#define CONFIG_SPI_MASTER_PORT 2
+#define CONFIG_SPI_CS_GPIO GPIO_PD_MCDP_SPI_CS_L
+#define CONFIG_USB
+#define CONFIG_USB_BOS
+#define CONFIG_USB_INHIBIT_CONNECT
+#define CONFIG_USB_POWER_DELIVERY
+#define CONFIG_USB_PD_ALT_MODE
+#define CONFIG_USB_PD_HW_DEV_ID_BOARD_MAJOR USB_PD_HW_DEV_ID_HOHO
+#define CONFIG_USB_PD_HW_DEV_ID_BOARD_MINOR 2
+#define CONFIG_USB_PD_DUAL_ROLE
+#define CONFIG_USB_PD_CUSTOM_VDM
+#define CONFIG_USB_PD_FLASH
+#define CONFIG_USB_PD_INTERNAL_COMP
+#define CONFIG_USB_PD_IDENTITY_HW_VERS 1
+#define CONFIG_USB_PD_IDENTITY_SW_VERS 1
+#define CONFIG_USB_PD_LOGGING
+#undef CONFIG_EVENT_LOG_SIZE
+#define CONFIG_EVENT_LOG_SIZE 256
+#define CONFIG_USB_PD_PORT_COUNT 1
+#define CONFIG_USB_PD_TCPC
+#define CONFIG_USB_PD_TCPM_STUB
+#define CONFIG_USB_PD_VBUS_DETECT_NONE
+/* mcdp2850 serial interface */
+#define CONFIG_MCDP28X0 usart3_hw
+#define CONFIG_STREAM_USART
+#define CONFIG_STREAM_USART3
+#undef CONFIG_WATCHDOG_HELP
+#undef CONFIG_LID_SWITCH
+#undef CONFIG_TASK_PROFILING
+
+/* USB configuration */
+#define CONFIG_USB_PID 0x5010
+#define CONFIG_USB_BCD_DEV 0x0001 /* v 0.01 */
+
+/* No Write-protect GPIO, force the write-protection */
+#define CONFIG_WP_ALWAYS
+
+#ifndef __ASSEMBLER__
+
+/* Timer selection */
+#define TIM_CLOCK32 2
+#define TIM_ADC 3
+
+#include "gpio_signal.h"
+
+/* ADC signal */
+enum adc_channel {
+ ADC_CH_CC1_PD = 0,
+ /* Number of ADC channels */
+ ADC_CH_COUNT
+};
+
+/* USB string indexes */
+enum usb_strings {
+ USB_STR_DESC = 0,
+ USB_STR_VENDOR,
+ USB_STR_PRODUCT,
+ USB_STR_VERSION,
+ USB_STR_BB_URL,
+
+ USB_STR_COUNT
+};
+
+/* we are never a source : don't care about power supply */
+#define PD_POWER_SUPPLY_TURN_ON_DELAY 0 /* us */
+#define PD_POWER_SUPPLY_TURN_OFF_DELAY 0 /* us */
+
+/* Define typical operating power and max power */
+#define PD_OPERATING_POWER_MW 1000
+#define PD_MAX_POWER_MW 1500
+#define PD_MAX_CURRENT_MA 300
+#define PD_MAX_VOLTAGE_MV 5000
+
+#endif /* !__ASSEMBLER__ */
+
+/* USB Device class */
+#define USB_DEV_CLASS USB_CLASS_BILLBOARD
+
+/* USB interface indexes (use define rather than enum to expand them) */
+#define USB_IFACE_COUNT 0
+
+/* USB endpoint indexes (use define rather than enum to expand them) */
+#define USB_EP_CONTROL 0
+#define USB_EP_COUNT 1
+
+#endif /* __CROS_EC_BOARD_H */
diff --git a/board/coffeecake/build.mk b/board/coffeecake/build.mk
new file mode 100644
index 0000000000..277c5c60f6
--- /dev/null
+++ b/board/coffeecake/build.mk
@@ -0,0 +1,14 @@
+# -*- 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
+
+# the IC is STmicro STM32F072B
+CHIP:=stm32
+CHIP_FAMILY:=stm32f0
+CHIP_VARIANT:=stm32f07x
+
+board-y=board.o
+board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o
diff --git a/board/coffeecake/dev_key.pem b/board/coffeecake/dev_key.pem
new file mode 100644
index 0000000000..08d5bd414c
--- /dev/null
+++ b/board/coffeecake/dev_key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEApfbLqgOYIM6AfRI6SJcj1Crengsp+yjHXtwZFOH6WDVP5Q9c
+KSbwqoKHEKTbWJ90ymjqjfi382hl64L/V6J8SfIqGhrFztwXLhJOwFXRK5Jgzkk+
+YUByDzAKTKOlzvvRqk10Tq5a3wphg1SxGVLLOOsTGoKhGI93Wkf2j8AibMlVVZzz
+Q8DmVszkYZL+Kchv6h1FgSvBW0oZa5tVod+0XToWSrPEYnBWs0zZEywCusIXMy7D
+LaqMPFB4LTkDZ9Ne8jnB5xRad+ME4CgxZqUwGC7tdFdHdiiXpIwzIoxVk6xFIZUF
+uusG4RR3O2ubaPJ/Fpf3UuuCWmddk37WaC7o7QIDAQABAoIBAAG4L94AEYhte0lQ
+cggkgLuHAi1zAilW/9HMx/m+aaCWVNCTuym1/JJXrdyPSLJ/XG9obN2xsP41m7C3
+97tJtK3zc1o34srE3vycNfKqMPOZnaUlfx700vmzTrgCjgo5868nBEh4Z/qdmesJ
+aphPkklxrg39QnwFqH/n9PcCT5j+7LyCeWeGbWxKfpzP2CT6v8XxT3XY1mtFSa4j
+dfYaqb+aunYAhjEb4gqa48hyNTQAZskDOUr1TK433wbGqRughXXrQQix+FBW483u
+IGo8aGgiQsjYxHX+ynNTMKW1Oap9WZRWVxF09Ph1f3MT+k3gKqM/0AejlDfBuTDu
+aLxiKIUCgYEA1FZmfGn4RNlghv/ZCAlfWqbf5NA1/wA/Knk8u0R+kMQ71e8NFjOc
+Ym3Uix+89KcKDBIgHn1360pNvSCeTyVU28wQ2bst5s6pvu4FYDvjym2nTgXcFJX6
+DDnZfVZ+WLSFR8E76LQLJGd00DSq0/uBw3ULyRSirkuQnFI3w3u4BH8CgYEAyBdD
+UMV83kwQaDMuGgKqZtD4Ou3s/MDzMwcNgUSjLIueFdsXVnlzYQwwJXuLFkrp5COx
+Zyoha/d1QQawnYehKmHWWy7qN/l0CO+F2DGb1E6pNXJrn+zn33Mgz9ms8421eqqn
+ATQbq6ZQInk1IrkLfyZ3t09l6cyBMJuJjkoBrJMCgYA2Hfsq1FtJONnILmbjDHh4
+AzXm/EX2wtpWeeXHmLJlNQ5G/REpymeeEn3sI1+mPvhpkSkMfE/W8O4VOL4AT/Rr
+vHvC8ljFjYBnwAQwvbLVwdK1KPspZ/v9p7TNpAC5nPCnFBGvwktgsNltwy6SrnQp
+G6iwTAkWQP4PSUkbEmoZAwKBgF0OLJlQ70y3FV5Qhx1DphohD4DgjDnURoaxvf8j
+e7vIxuGlPgpSe21j7LRR65KXjoUycFvpRRfgQyDVyqfInxSF4doQTI9xrRxGwPmV
+wMIRPzKDHziGRiQud9ESjBPNENyWpwqxQDkpJNWThzm503Xz3vNasqv0FxUTEPsi
+wfqPAoGABXPl7baUkpYzppAJqRlGNxsMjpbWscDPjmPosrGs6d81DP287s/IjfDR
+ysQptvhJRK/lubM8As+d0/VLd6P8wk8dyZR1nRELwnVaPC55cS5+YIjgXK9TBmLA
+hC0BIgujJS2qbXQRQF7yX925Gg77WLN2sJqtVg1Brine056pHTA=
+-----END RSA PRIVATE KEY-----
diff --git a/board/coffeecake/ec.tasklist b/board/coffeecake/ec.tasklist
new file mode 100644
index 0000000000..5254b70e2b
--- /dev/null
+++ b/board/coffeecake/ec.tasklist
@@ -0,0 +1,22 @@
+/* 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
+ */
+#define CONFIG_TASK_LIST \
+ TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE)
diff --git a/board/coffeecake/gpio.inc b/board/coffeecake/gpio.inc
new file mode 100644
index 0000000000..cfb689d825
--- /dev/null
+++ b/board/coffeecake/gpio.inc
@@ -0,0 +1,37 @@
+/* -*- 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(DP_HPD, PIN(A, 0), GPIO_INT_BOTH, hpd_event)
+
+GPIO(USB_C_CC1_PD, PIN(A, 1), GPIO_ANALOG)
+GPIO(STM_READY, PIN(A, 2), GPIO_OUT_LOW) /* factory test only */
+GPIO(MCDP_RESET_L, PIN(A, 3), GPIO_OUT_HIGH)
+GPIO(PD_DAC_REF, PIN(A, 4), GPIO_ANALOG)
+
+GPIO(MCDP_READY, PIN(A, 7), GPIO_OUT_LOW) /* factory test only */
+GPIO(PD_SBU_ENABLE, PIN(A, 8), GPIO_OUT_LOW)
+GPIO(USB_DM, PIN(A, 11), GPIO_ANALOG)
+GPIO(USB_DP, PIN(A, 12), GPIO_ANALOG)
+GPIO(PD_CC1_TX_EN, PIN(A, 15), GPIO_OUT_LOW)
+
+GPIO(MCDP_GPIO1, PIN(B, 0), GPIO_INPUT)
+GPIO(MCDP_CONFIG1, PIN(B, 1), GPIO_INPUT)
+GPIO(PD_MCDP_SPI_WP_L, PIN(B, 2), GPIO_OUT_LOW)
+GPIO(PD_CC1_TX_DATA, PIN(B, 4), GPIO_OUT_LOW)
+GPIO(PD_MCDP_SPI_CS_L, PIN(B, 12), GPIO_INPUT)
+
+/* Unimplemented signals which we need to emulate for now */
+UNIMPLEMENTED(ENTERING_RW)
+UNIMPLEMENTED(WP_L)
+
+ALTERNATE(PIN_MASK(B, 0x0008), 0, MODULE_USB_PD, 0) /* SPI1: SCK(PB3) */
+ALTERNATE(PIN_MASK(B, 0x0200), 2, MODULE_USB_PD, 0) /* TIM17_CH1: PB9 */
+ALTERNATE(PIN_MASK(A, 0x0600), 1, MODULE_UART, GPIO_PULL_UP) /* USART1: PA9/PA10 */
+ALTERNATE(PIN_MASK(B, 0x0C00), 4, MODULE_UART, GPIO_PULL_UP) /* USART3: PB10/PB11 */
diff --git a/board/coffeecake/usb_pd_config.h b/board/coffeecake/usb_pd_config.h
new file mode 100644
index 0000000000..181ccd20c2
--- /dev/null
+++ b/board/coffeecake/usb_pd_config.h
@@ -0,0 +1,128 @@
+/* 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.
+ */
+
+/* USB Power delivery board configuration */
+
+#ifndef __CROS_EC_USB_PD_CONFIG_H
+#define __CROS_EC_USB_PD_CONFIG_H
+
+/* Timer selection for baseband PD communication */
+#define TIM_CLOCK_PD_TX_C0 17
+#define TIM_CLOCK_PD_RX_C0 1
+
+#define TIM_CLOCK_PD_TX(p) TIM_CLOCK_PD_TX_C0
+#define TIM_CLOCK_PD_RX(p) TIM_CLOCK_PD_RX_C0
+
+/* Timer channel */
+#define TIM_RX_CCR_C0 1
+#define TIM_TX_CCR_C0 1
+
+/* RX timer capture/compare register */
+#define TIM_CCR_C0 (&STM32_TIM_CCRx(TIM_CLOCK_PD_RX_C0, TIM_RX_CCR_C0))
+#define TIM_RX_CCR_REG(p) TIM_CCR_C0
+
+/* TX and RX timer register */
+#define TIM_REG_TX_C0 (STM32_TIM_BASE(TIM_CLOCK_PD_TX_C0))
+#define TIM_REG_RX_C0 (STM32_TIM_BASE(TIM_CLOCK_PD_RX_C0))
+#define TIM_REG_TX(p) TIM_REG_TX_C0
+#define TIM_REG_RX(p) TIM_REG_RX_C0
+
+/* use the hardware accelerator for CRC */
+#define CONFIG_HW_CRC
+
+/* TX is using SPI1 on PB3-4 */
+#define SPI_REGS(p) STM32_SPI1_REGS
+
+static inline void spi_enable_clock(int port)
+{
+ STM32_RCC_APB2ENR |= STM32_RCC_PB2_SPI1;
+}
+
+/* SPI1_TX no remap needed */
+#define DMAC_SPI_TX(p) STM32_DMAC_CH3
+
+/* RX is using COMP1 triggering TIM1 CH1 */
+#define CMP1OUTSEL STM32_COMP_CMP1OUTSEL_TIM1_IC1
+#define CMP2OUTSEL 0
+
+#define TIM_TX_CCR_IDX(p) TIM_TX_CCR_C0
+#define TIM_RX_CCR_IDX(p) TIM_RX_CCR_C0
+#define TIM_CCR_CS 1
+#define EXTI_COMP_MASK(p) (1 << 21)
+#define IRQ_COMP STM32_IRQ_COMP
+/* triggers packet detection on comparator falling edge */
+#define EXTI_XTSR STM32_EXTI_FTSR
+
+/* TIM1_CH1 no remap needed */
+#define DMAC_TIM_RX(p) STM32_DMAC_CH2
+
+/* the pins used for communication need to be hi-speed */
+static inline void pd_set_pins_speed(int port)
+{
+ /* 40 Mhz pin speed on TX_EN (PA15) */
+ STM32_GPIO_OSPEEDR(GPIO_A) |= 0xC0000000;
+ /* 40 MHz pin speed on SPI CLK/MOSI (PB3/4) TIM17_CH1 (PB9) */
+ STM32_GPIO_OSPEEDR(GPIO_B) |= 0x000C03C0;
+}
+
+/* Reset SPI peripheral used for TX */
+static inline void pd_tx_spi_reset(int port)
+{
+ /* Reset SPI1 */
+ STM32_RCC_APB2RSTR |= (1 << 12);
+ STM32_RCC_APB2RSTR &= ~(1 << 12);
+}
+
+/* Drive the CC line from the TX block */
+static inline void pd_tx_enable(int port, int polarity)
+{
+ /* PB4 is SPI1_MISO */
+ gpio_set_alternate_function(GPIO_B, 0x0010, 0);
+
+ gpio_set_level(GPIO_PD_CC1_TX_EN, 1);
+}
+
+/* Put the TX driver in Hi-Z state */
+static inline void pd_tx_disable(int port, int polarity)
+{
+ /* output low on SPI TX (PB4) to disable the FET */
+ STM32_GPIO_MODER(GPIO_B) = (STM32_GPIO_MODER(GPIO_B)
+ & ~(3 << (2*4)))
+ | (1 << (2*4));
+ /* put the low level reference in Hi-Z */
+ gpio_set_level(GPIO_PD_CC1_TX_EN, 0);
+}
+
+static inline void pd_select_polarity(int port, int polarity)
+{
+ /*
+ * use the right comparator : CC1 -> PA1 (COMP1 INP)
+ * use VrefInt / 2 as INM (about 600mV)
+ */
+ STM32_COMP_CSR = (STM32_COMP_CSR & ~STM32_COMP_CMP1INSEL_MASK)
+ | STM32_COMP_CMP1EN | STM32_COMP_CMP1INSEL_VREF12;
+}
+
+/* Initialize pins used for TX and put them in Hi-Z */
+static inline void pd_tx_init(void)
+{
+ gpio_config_module(MODULE_USB_PD, 1);
+}
+
+static inline void pd_set_host_mode(int port, int enable) {}
+
+static inline void pd_config_init(int port, uint8_t power_role)
+{
+ /* Initialize TX pins and put them in Hi-Z */
+ pd_tx_init();
+}
+
+static inline int pd_adc_read(int port, int cc)
+{
+ /* only one CC line, assume other one is always low */
+ return (cc == 0) ? adc_read_channel(ADC_CH_CC1_PD) : 0;
+}
+
+#endif /* __CROS_EC_USB_PD_CONFIG_H */
diff --git a/board/coffeecake/usb_pd_policy.c b/board/coffeecake/usb_pd_policy.c
new file mode 100644
index 0000000000..2b9e9d60d3
--- /dev/null
+++ b/board/coffeecake/usb_pd_policy.c
@@ -0,0 +1,281 @@
+/* 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 "adc.h"
+#include "board.h"
+#include "common.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "usb_api.h"
+#include "usb_bb.h"
+#include "usb_pd.h"
+#include "util.h"
+#include "version.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_COMM_CAP
+
+/* Source PDOs */
+const uint32_t pd_src_pdo[] = {};
+const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo);
+
+/* Fake PDOs : we just want our pre-defined voltages */
+const uint32_t pd_snk_pdo[] = {
+ PDO_FIXED(5000, 500, PDO_FIXED_FLAGS),
+};
+const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo);
+
+/* Holds valid object position (opos) for entered mode */
+static int alt_mode[PD_AMODE_COUNT];
+
+void pd_set_input_current_limit(int port, uint32_t max_ma,
+ uint32_t supply_voltage)
+{
+ /* No battery, nothing to do */
+ return;
+}
+
+int pd_is_valid_input_voltage(int mv)
+{
+ /* Any voltage less than the max is allowed */
+ return 1;
+}
+
+void pd_transition_voltage(int idx)
+{
+ /* No operation: sink only */
+}
+
+int pd_set_power_supply_ready(int port)
+{
+ return EC_SUCCESS;
+}
+
+void pd_power_supply_reset(int port)
+{
+}
+
+int pd_snk_is_vbus_provided(int port)
+{
+ return 1;
+}
+
+int pd_board_checks(void)
+{
+ return EC_SUCCESS;
+}
+
+int pd_check_power_swap(int port)
+{
+ /* Always refuse power swap */
+ return 0;
+}
+
+int pd_check_data_swap(int port, int data_role)
+{
+ /* Always refuse data swap */
+ return 0;
+}
+
+void pd_execute_data_swap(int port, int data_role)
+{
+ /* Do nothing */
+}
+
+void pd_check_pr_role(int port, int pr_role, int flags)
+{
+}
+
+void pd_check_dr_role(int port, int dr_role, int flags)
+{
+}
+/* ----------------- Vendor Defined Messages ------------------ */
+const uint32_t vdo_idh = VDO_IDH(0, /* data caps as USB host */
+ 1, /* data caps as USB device */
+ IDH_PTYPE_AMA, /* Alternate mode */
+ 1, /* supports alt modes */
+ USB_VID_GOOGLE);
+
+const uint32_t vdo_product = VDO_PRODUCT(CONFIG_USB_PID, CONFIG_USB_BCD_DEV);
+
+const uint32_t vdo_ama = VDO_AMA(CONFIG_USB_PD_IDENTITY_HW_VERS,
+ CONFIG_USB_PD_IDENTITY_SW_VERS,
+ 0, 0, 0, 0, /* SS[TR][12] */
+ 0, /* Vconn power */
+ 0, /* Vconn power required */
+ 1, /* Vbus power required */
+ AMA_USBSS_BBONLY /* USB SS support */);
+
+static int svdm_response_identity(int port, uint32_t *payload)
+{
+ payload[VDO_I(IDH)] = vdo_idh;
+ /* TODO(tbroch): Do we plan to obtain TID (test ID) for hoho */
+ payload[VDO_I(CSTAT)] = VDO_CSTAT(0);
+ payload[VDO_I(PRODUCT)] = vdo_product;
+ payload[VDO_I(AMA)] = vdo_ama;
+ return VDO_I(AMA) + 1;
+}
+
+static int svdm_response_svids(int port, uint32_t *payload)
+{
+ payload[1] = VDO_SVID(USB_SID_DISPLAYPORT, USB_VID_GOOGLE);
+ payload[2] = 0;
+ return 3;
+}
+
+#define OPOS_DP 1
+#define OPOS_GFU 1
+
+const uint32_t vdo_dp_modes[1] = {
+ VDO_MODE_DP(0, /* UFP pin cfg supported : none */
+ MODE_DP_PIN_C, /* DFP pin cfg supported */
+ 1, /* no usb2.0 signalling in AMode */
+ CABLE_PLUG, /* its a plug */
+ MODE_DP_V13, /* DPv1.3 Support, no Gen2 */
+ MODE_DP_SNK) /* Its a sink only */
+};
+
+const uint32_t vdo_goog_modes[1] = {
+ VDO_MODE_GOOGLE(MODE_GOOGLE_FU)
+};
+
+static int svdm_response_modes(int port, uint32_t *payload)
+{
+ if (PD_VDO_VID(payload[0]) == USB_SID_DISPLAYPORT) {
+ memcpy(payload + 1, vdo_dp_modes, sizeof(vdo_dp_modes));
+ return ARRAY_SIZE(vdo_dp_modes) + 1;
+ } else if (PD_VDO_VID(payload[0]) == USB_VID_GOOGLE) {
+ memcpy(payload + 1, vdo_goog_modes, sizeof(vdo_goog_modes));
+ return ARRAY_SIZE(vdo_goog_modes) + 1;
+ } else {
+ return 0; /* nak */
+ }
+}
+
+static int dp_status(int port, uint32_t *payload)
+{
+ int opos = PD_VDO_OPOS(payload[0]);
+ int hpd = gpio_get_level(GPIO_DP_HPD);
+ if (opos != OPOS_DP)
+ return 0; /* nak */
+
+ payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */
+ (hpd == 1), /* HPD_HI|LOW */
+ 0, /* request exit DP */
+ 0, /* request exit USB */
+ 0, /* MF pref */
+ gpio_get_level(GPIO_PD_SBU_ENABLE),
+ 0, /* power low */
+ 0x2);
+ return 2;
+}
+
+static int dp_config(int port, uint32_t *payload)
+{
+ if (PD_DP_CFG_DPON(payload[1]))
+ gpio_set_level(GPIO_PD_SBU_ENABLE, 1);
+ return 1;
+}
+
+static int svdm_enter_mode(int port, uint32_t *payload)
+{
+ int rv = 0; /* will generate a NAK */
+
+ /* SID & mode request is valid */
+ if ((PD_VDO_VID(payload[0]) == USB_SID_DISPLAYPORT) &&
+ (PD_VDO_OPOS(payload[0]) == OPOS_DP)) {
+ alt_mode[PD_AMODE_DISPLAYPORT] = OPOS_DP;
+ rv = 1;
+ pd_log_event(PD_EVENT_VIDEO_DP_MODE, 0, 1, NULL);
+ } else if ((PD_VDO_VID(payload[0]) == USB_VID_GOOGLE) &&
+ (PD_VDO_OPOS(payload[0]) == OPOS_GFU)) {
+ alt_mode[PD_AMODE_GOOGLE] = OPOS_GFU;
+ rv = 1;
+ }
+
+ if (rv)
+ /*
+ * If we failed initial mode entry we'll have enumerated the USB
+ * Billboard class. If so we should disconnect.
+ */
+ usb_disconnect();
+
+ return rv;
+}
+
+int pd_alt_mode(int port, uint16_t svid)
+{
+ if (svid == USB_SID_DISPLAYPORT)
+ return alt_mode[PD_AMODE_DISPLAYPORT];
+ else if (svid == USB_VID_GOOGLE)
+ return alt_mode[PD_AMODE_GOOGLE];
+ return 0;
+}
+
+static int svdm_exit_mode(int port, uint32_t *payload)
+{
+ if (PD_VDO_VID(payload[0]) == USB_SID_DISPLAYPORT) {
+ gpio_set_level(GPIO_PD_SBU_ENABLE, 0);
+ alt_mode[PD_AMODE_DISPLAYPORT] = 0;
+ pd_log_event(PD_EVENT_VIDEO_DP_MODE, 0, 0, NULL);
+ } else if (PD_VDO_VID(payload[0]) == USB_VID_GOOGLE) {
+ alt_mode[PD_AMODE_GOOGLE] = 0;
+ } else {
+ CPRINTF("Unknown exit mode req:0x%08x\n", payload[0]);
+ }
+
+ return 1; /* Must return ACK */
+}
+
+static struct amode_fx dp_fx = {
+ .status = &dp_status,
+ .config = &dp_config,
+};
+
+const struct svdm_response svdm_rsp = {
+ .identity = &svdm_response_identity,
+ .svids = &svdm_response_svids,
+ .modes = &svdm_response_modes,
+ .enter_mode = &svdm_enter_mode,
+ .amode = &dp_fx,
+ .exit_mode = &svdm_exit_mode,
+};
+
+int pd_custom_vdm(int port, int cnt, uint32_t *payload,
+ uint32_t **rpayload)
+{
+ int rsize;
+
+ if (PD_VDO_VID(payload[0]) != USB_VID_GOOGLE ||
+ !alt_mode[PD_AMODE_GOOGLE])
+ return 0;
+
+ *rpayload = payload;
+
+ rsize = pd_custom_flash_vdm(port, cnt, payload);
+ if (!rsize) {
+ int cmd = PD_VDO_CMD(payload[0]);
+ switch (cmd) {
+ case VDO_CMD_GET_LOG:
+ rsize = pd_vdm_get_log_entry(payload);
+ break;
+ default:
+ /* Unknown : do not answer */
+ return 0;
+ }
+ }
+
+ /* respond (positively) to the request */
+ payload[0] |= VDO_SRC_RESPONDER;
+
+ return rsize;
+}
diff --git a/util/flash_ec b/util/flash_ec
index 8337b41bc0..889ded3eb6 100755
--- a/util/flash_ec
+++ b/util/flash_ec
@@ -58,6 +58,7 @@ BOARDS_STM32=(
big
blaze
chell_pd
+ coffeecake
elm
eve_fp
glados_pd