summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2019-03-21 14:44:44 -0700
committerCommit Bot <commit-bot@chromium.org>2019-07-17 01:32:20 +0000
commit60d6db8fbf5bae84b94b6dac8ea8c70a08e30555 (patch)
tree340b53b66f6751eb536463b1c0467feac5974830
parent9be52b960b3e25ccc8ef0fc4c15db5bc918a9965 (diff)
downloadchrome-ec-60d6db8fbf5bae84b94b6dac8ea8c70a08e30555.tar.gz
fluffy: Initial board commit.
This contains the initial firmware for Fluffy rev 1.1 boards. Fluffy is a 20:1 USB-C power mux. For more information, see go/usbc-fluffy. BUG=b:136671092,b:134075217,b:134074302,b:134074465,b:134075521, b:134075834 BRANCH=None TEST=flash fluffy, verify it boots and functions. Change-Id: Ica6817e7cfa4481aa98fed1c24ea243bf622eb2a Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1535117 Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org> Commit-Queue: Jett Rink <jettrink@chromium.org> Auto-Submit: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--board/fluffy/board.c403
-rw-r--r--board/fluffy/board.h72
-rw-r--r--board/fluffy/build.mk18
-rw-r--r--board/fluffy/ec.tasklist12
-rw-r--r--board/fluffy/gpio.inc60
-rwxr-xr-xutil/flash_ec1
6 files changed, 566 insertions, 0 deletions
diff --git a/board/fluffy/board.c b/board/fluffy/board.c
new file mode 100644
index 0000000000..a409bc4a89
--- /dev/null
+++ b/board/fluffy/board.c
@@ -0,0 +1,403 @@
+/* Copyright 2019 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.
+ */
+
+/* Fluffy configuration */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "common.h"
+#include "console.h"
+#include "ec_version.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "usb_descriptor.h"
+#include "registers.h"
+#include "timer.h"
+#include "usb_pd.h"
+#include "util.h"
+
+#include "gpio_list.h"
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
+
+/******************************************************************************
+ * Define the strings used in our USB descriptors.
+ */
+
+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("Fluffy"),
+ /* This gets filled in at runtime. */
+ [USB_STR_SERIALNO] = USB_STRING_DESC(""),
+ [USB_STR_VERSION] = USB_STRING_DESC(CROS_EC_VERSION32),
+ [USB_STR_CONSOLE_NAME] = USB_STRING_DESC("Fluffy Shell"),
+};
+
+BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
+
+/* ADC channels */
+const struct adc_t adc_channels[] = {
+ /* Sensing the VBUS voltage at the DUT side. Converted to mV. */
+ [ADC_PPVAR_VBUS_DUT] = {
+ .name = "PPVAR_VBUS_DUT",
+ .factor_mul = 3300,
+ .factor_div = 4096,
+ .shift = 0,
+ .channel = STM32_AIN(0),
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
+/* I2C ports */
+const struct i2c_port_t i2c_ports[] = {
+ {
+ .name = "master",
+ .port = 1,
+ .kbps = 400,
+ .scl = GPIO_I2C_SCL,
+ .sda = GPIO_I2C_SDA,
+ },
+};
+const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
+
+static enum gpio_signal enabled_port = GPIO_EN_C0;
+static uint8_t output_en;
+
+static void print_port_status(void)
+{
+ if (!output_en)
+ CPRINTS("No ports enabled. zZZ");
+ else
+ CPRINTS("Port %d is ON", enabled_port - GPIO_EN_C0);
+
+ CPRINTS("CC Flip: %s", gpio_get_level(GPIO_EN_CC_FLIP) ? "YES" : "NO");
+ CPRINTS("USB MUX: %s", gpio_get_level(GPIO_EN_USB_MUX2) ? "ON" : "OFF");
+}
+
+static int command_cc_flip(int argc, char *argv[])
+{
+ int enable;
+
+ if (argc != 2)
+ return EC_ERROR_PARAM_COUNT;
+
+ if (!parse_bool(argv[1], &enable))
+ return EC_ERROR_INVAL;
+
+ if (output_en) {
+ gpio_set_level(enabled_port, 0);
+ gpio_set_level(GPIO_EN_USB_MUX2, 0);
+ /* Wait long enough for CC to discharge. */
+ usleep(500 * MSEC);
+ }
+
+ gpio_set_level(GPIO_EN_CC_FLIP, enable);
+ /* Allow some time for new CC configuration to settle. */
+ usleep(500 * MSEC);
+
+ if (output_en) {
+ gpio_set_level(enabled_port, 1);
+ gpio_set_level(GPIO_EN_USB_MUX2, 1);
+ }
+
+ print_port_status();
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(ccflip, command_cc_flip,
+ "<enable/disable>",
+ "enable or disable flipping CC orientation");
+/*
+ * Support tca6416 I2C ioexpander.
+ */
+#define GPIOX_I2C_ADDR 0x40
+#define GPIOX_IN_PORT_A 0x0
+#define GPIOX_IN_PORT_B 0x1
+#define GPIOX_OUT_PORT_A 0x2
+#define GPIOX_OUT_PORT_B 0x3
+#define GPIOX_DIR_PORT_A 0x6
+#define GPIOX_DIR_PORT_B 0x7
+#define I2C_PORT_MASTER 1
+
+static void i2c_expander_init(void)
+{
+ gpio_set_level(GPIO_XP_RESET_L, 1);
+
+ /*
+ * Setup P00, P02, P04, P10, and P12 on the I/O expander as an output.
+ */
+ i2c_write8(I2C_PORT_MASTER, GPIOX_I2C_ADDR, GPIOX_DIR_PORT_A, 0xea);
+ i2c_write8(I2C_PORT_MASTER, GPIOX_I2C_ADDR, GPIOX_DIR_PORT_B, 0xfa);
+}
+DECLARE_HOOK(HOOK_INIT, i2c_expander_init, HOOK_PRIO_INIT_I2C+1);
+
+/* Write to a GPIO register on the tca6416 I2C ioexpander. */
+static void write_ioexpander(int bank, int gpio, int reg, int val)
+{
+ int tmp;
+
+ /* Read output port register */
+ i2c_read8(I2C_PORT_MASTER, GPIOX_I2C_ADDR, reg + bank,
+ &tmp);
+ if (val)
+ tmp |= BIT(gpio);
+ else
+ tmp &= ~BIT(gpio);
+ /* Write back modified output port register */
+ i2c_write8(I2C_PORT_MASTER, GPIOX_I2C_ADDR, reg + bank,
+ tmp);
+}
+
+enum led_ch {
+ LED_5V = 0,
+ LED_9V,
+ LED_12V,
+ LED_15V,
+ LED_20V,
+ LED_COUNT,
+};
+
+static void set_led(enum led_ch led, int enable)
+{
+ int bank;
+ int gpio;
+
+ switch (led) {
+ case LED_5V:
+ bank = 0;
+ gpio = 0;
+ break;
+
+ case LED_9V:
+ bank = 0;
+ gpio = 2;
+ break;
+
+ case LED_12V:
+ bank = 0;
+ gpio = 4;
+ break;
+
+ case LED_15V:
+ bank = 1;
+ gpio = 0;
+ break;
+
+ case LED_20V:
+ bank = 1;
+ gpio = 2;
+ break;
+
+ default:
+ return;
+ }
+
+ /*
+ * Setup the LED as an output if enabled, otherwise as an input to keep
+ * the LEDs off.
+ */
+ write_ioexpander(bank, gpio, GPIOX_DIR_PORT_A, !enable);
+
+ /* The LEDs are active low. */
+ if (enable)
+ write_ioexpander(bank, gpio, GPIOX_OUT_PORT_A, 0);
+}
+
+void show_output_voltage_on_leds(void);
+DECLARE_DEFERRED(show_output_voltage_on_leds);
+
+static void board_init(void)
+{
+ /* Do a sweeping LED dance. */
+ for (enum led_ch led = 0; led < LED_COUNT; led++) {
+ set_led(led, 1);
+ msleep(100);
+ }
+
+ msleep(500);
+
+ for (enum led_ch led = 0; led < LED_COUNT; led++)
+ set_led(led, 0);
+
+ show_output_voltage_on_leds();
+}
+DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+
+
+enum usb_mux {
+ USB_MUX0 = 0,
+ USB_MUX1,
+ USB_MUX2,
+ USB_MUX_COUNT,
+};
+
+static void set_mux(enum usb_mux mux, uint8_t val)
+{
+ enum gpio_signal c0;
+ enum gpio_signal c1;
+ enum gpio_signal c2;
+
+ switch (mux) {
+ case USB_MUX0:
+ c0 = GPIO_USB_MUX0_C0;
+ c1 = GPIO_USB_MUX0_C1;
+ c2 = GPIO_USB_MUX0_C2;
+ break;
+
+ case USB_MUX1:
+ c0 = GPIO_USB_MUX1_C0;
+ c1 = GPIO_USB_MUX1_C1;
+ c2 = GPIO_USB_MUX1_C2;
+ break;
+
+ case USB_MUX2:
+ c0 = GPIO_USB_MUX2_C0;
+ c1 = GPIO_USB_MUX2_C1;
+ c2 = GPIO_USB_MUX2_C2;
+ break;
+
+ default:
+ break;
+ }
+
+ val &= 0x7;
+
+ gpio_set_level(c0, val & BIT(0));
+ gpio_set_level(c1, val & BIT(1));
+ gpio_set_level(c2, val & BIT(2));
+}
+
+/* This function assumes only 1 port works at a time. */
+static int command_portctl(int argc, char **argv)
+{
+ int port;
+ int enable;
+
+ if (argc < 2)
+ return EC_ERROR_PARAM_COUNT;
+
+ port = atoi(argv[1]);
+ if ((port < 0) || (port > 19) || !parse_bool(argv[2], &enable))
+ return EC_ERROR_INVAL;
+
+ gpio_set_level(GPIO_EN_USB_MUX2, 0);
+
+ /*
+ * For each port, we must configure the USB 2.0 muxes and make sure that
+ * the power enables are configured as desired.
+ */
+
+ gpio_set_level(enabled_port, 0);
+ if (enabled_port != GPIO_EN_C0 + port)
+ CPRINTS("Port %d: disabled", enabled_port-GPIO_EN_C0);
+
+ /* Allow time for an "unplug" to allow VBUS and CC to fall. */
+ usleep(1 * SECOND);
+
+ /*
+ * The USB 2.0 lines are arranged using 3x 8:1 muxes. Ports 0-7 are
+ * handled by the first mux, ports 8-15 are handled by the 2nd mux, then
+ * the outputs of those muxes are fed into the third mux along with
+ * ports 16-19. The schematic contains the truth table.
+ */
+ if (enable) {
+ enabled_port = GPIO_EN_C0 + port;
+ gpio_set_level(enabled_port, 1);
+
+ if (port < 8) {
+ set_mux(USB_MUX0, 7-port);
+ set_mux(USB_MUX2, 3);
+ } else if (port < 16) {
+ if (port < 14)
+ set_mux(USB_MUX1, 5-(port-8));
+ else
+ set_mux(USB_MUX1, 7-(port-14));
+
+ set_mux(USB_MUX2, 1);
+ } else {
+ set_mux(USB_MUX2, 7-(port-16));
+ }
+
+ gpio_set_level(GPIO_EN_USB_MUX2, 1);
+ output_en = 1;
+ } else {
+ gpio_set_level(enabled_port, 0);
+ output_en = 0;
+ }
+
+ print_port_status();
+ return EC_SUCCESS;
+}
+
+DECLARE_CONSOLE_COMMAND(portctl, command_portctl,
+ "<port# 0-19> <enable/disable>",
+ "enable or disable a port");
+
+static int command_status(int argc, char **argv)
+{
+ int vbus_mv = adc_read_channel(ADC_PPVAR_VBUS_DUT);
+
+ CPRINTS("PPVAR_VBUS_DUT: %dmV (raw: %d)", vbus_mv*7692/1000,
+ vbus_mv);
+ print_port_status();
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(status, command_status, NULL, "show current status");
+
+/*
+ * According to the USB PD Spec, the minimum voltage for a fixed source is 95%
+ * of the new source voltage with an additional 500mV drop.
+ *
+ * vSrcNew | min | vSrcNew(min) + vSrcValid
+ * 5V | 4.75V | 4.25V | 553mV
+ * 9V | 8.55V | 8.05V | 1047mV
+ * 12V | 11.4V | 10.9V | 1417mV
+ * 15V | 14.25V | 13.75V | 1788mV
+ * 20V | 19V | 18.5V | 2405mV
+ *
+ * With the resistor divider that fluffy has, the ADC is only seeing 0.13 of the
+ * actual voltage.
+ */
+void show_output_voltage_on_leds(void)
+{
+ int vbus_mv = adc_read_channel(ADC_PPVAR_VBUS_DUT);
+ static int prev_vbus_mv;
+ int i;
+ int act;
+ enum led_ch max_on_exclusive = LED_5V;
+
+ if (vbus_mv != ADC_READ_ERROR) {
+ if (vbus_mv >= 2405)
+ max_on_exclusive = LED_COUNT;
+ else if (vbus_mv >= 1788)
+ max_on_exclusive = LED_20V;
+ else if (vbus_mv >= 1417)
+ max_on_exclusive = LED_15V;
+ else if (vbus_mv >= 1047)
+ max_on_exclusive = LED_12V;
+ else if (vbus_mv >= 553)
+ max_on_exclusive = LED_9V;
+
+ for (i = 0; i < LED_COUNT; i++)
+ set_led(i, i < max_on_exclusive);
+
+ act = (vbus_mv * 7692) / 1000;
+ if ((vbus_mv > prev_vbus_mv+2) || (vbus_mv < prev_vbus_mv-2)) {
+ CPRINTS("PPVAR_VBUS_DUT: %d mV (raw: %d)", act,
+ vbus_mv);
+ prev_vbus_mv = vbus_mv;
+ }
+ }
+
+ /*
+ * The reason we reschedule this ourselves as opposed to declaring it as
+ * a hook with a HOOK_TICK period is to allow the LED sweep sequence
+ * when the board boots up.
+ */
+ hook_call_deferred(&show_output_voltage_on_leds_data,
+ 500 * MSEC);
+}
diff --git a/board/fluffy/board.h b/board/fluffy/board.h
new file mode 100644
index 0000000000..41c01bd8fa
--- /dev/null
+++ b/board/fluffy/board.h
@@ -0,0 +1,72 @@
+/* Copyright 2019 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.
+ */
+
+/* Fluffy configuration */
+
+#ifndef __CROS_EC_BOARD_H
+#define __CROS_EC_BOARD_H
+
+/*
+ * Allow dangerous commands all the time, since we don't have a write protect
+ * switch.
+ */
+#define CONFIG_SYSTEM_UNLOCKED
+
+/* This is not an EC so disable some features. */
+#undef CONFIG_WATCHDOG_HELP
+#undef CONFIG_LID_SWITCH
+
+/* 48 MHz SYSCLK clock frequency */
+#define CPU_CLOCK 48000000
+
+/* USB Configuration */
+#define CONFIG_USB
+#define CONFIG_USB_CONSOLE
+#define CONFIG_USB_PID 0x503b
+#define CONFIG_USB_SERIALNO
+#define DEFAULT_SERIALNO "Uninitialized"
+
+/* USB interface indexes (use define rather than enum to expand them) */
+#define USB_IFACE_CONSOLE 0
+#define USB_IFACE_COUNT 1
+
+/* USB endpoint indexes (use define rather than enum to expand them) */
+#define USB_EP_CONTROL 0
+#define USB_EP_CONSOLE 1
+#define USB_EP_COUNT 2
+
+/* Optional features */
+#define CONFIG_STM_HWTIMER32
+
+#define CONFIG_ADC
+#define CONFIG_I2C
+#define CONFIG_I2C_MASTER
+
+#ifndef __ASSEMBLER__
+
+/* Timer selection */
+#define TIM_CLOCK32 2
+#define TIM_ADC 3
+
+#include "gpio_signal.h"
+
+/* USB string indexes */
+enum usb_strings {
+ USB_STR_DESC = 0,
+ USB_STR_VENDOR,
+ USB_STR_PRODUCT,
+ USB_STR_SERIALNO,
+ USB_STR_VERSION,
+ USB_STR_CONSOLE_NAME,
+ USB_STR_COUNT
+};
+
+enum adc_channel {
+ ADC_PPVAR_VBUS_DUT,
+ ADC_CH_COUNT,
+};
+
+#endif /* !__ASSEMBLER__ */
+#endif /* __CROS_EC_BOARD_H */
diff --git a/board/fluffy/build.mk b/board/fluffy/build.mk
new file mode 100644
index 0000000000..b6761a4692
--- /dev/null
+++ b/board/fluffy/build.mk
@@ -0,0 +1,18 @@
+# -*- makefile -*-
+# Copyright 2019 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 STM32F072CBU6TR
+CHIP:=stm32
+CHIP_FAMILY:=stm32f0
+CHIP_VARIANT:=stm32f07x
+
+# Use coreboot-sdk
+$(call set-option,CROSS_COMPILE_arm,\
+ $(CROSS_COMPILE_coreboot_sdk_arm),\
+ /opt/coreboot-sdk/bin/arm-eabi-)
+
+board-y=board.o
diff --git a/board/fluffy/ec.tasklist b/board/fluffy/ec.tasklist
new file mode 100644
index 0000000000..c732944a23
--- /dev/null
+++ b/board/fluffy/ec.tasklist
@@ -0,0 +1,12 @@
+/* Copyright 2019 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.
+ */
+
+/*
+ * See CONFIG_TASK_LIST in config.h for details.
+ */
+
+#define CONFIG_TASK_LIST \
+ TASK_ALWAYS(HOOKS, hook_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)
diff --git a/board/fluffy/gpio.inc b/board/fluffy/gpio.inc
new file mode 100644
index 0000000000..4c802554f9
--- /dev/null
+++ b/board/fluffy/gpio.inc
@@ -0,0 +1,60 @@
+/* -*- mode:c -*-
+ *
+ * Copyright 2019 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. */
+
+/* Misc */
+GPIO(XP_RESET_L, PIN(A, 10), GPIO_OUT_LOW)
+GPIO(EN_CC_FLIP, PIN(A, 4), GPIO_OUT_LOW)
+GPIO(ADC_PPVAR_VBUS_DUT, PIN(A, 0), GPIO_ANALOG)
+
+/* Port Enables */
+GPIO(EN_C0, PIN(B, 0), GPIO_OUT_LOW)
+GPIO(EN_C1, PIN(B, 1), GPIO_OUT_LOW)
+GPIO(EN_C2, PIN(B, 2), GPIO_OUT_LOW)
+GPIO(EN_C3, PIN(B, 3), GPIO_OUT_LOW)
+GPIO(EN_C4, PIN(B, 4), GPIO_OUT_LOW)
+GPIO(EN_C5, PIN(B, 5), GPIO_OUT_LOW)
+GPIO(EN_C6, PIN(B, 6), GPIO_OUT_LOW)
+GPIO(EN_C7, PIN(B, 7), GPIO_OUT_LOW)
+GPIO(EN_C8, PIN(B, 8), GPIO_OUT_LOW)
+GPIO(EN_C9, PIN(B, 9), GPIO_OUT_LOW)
+GPIO(EN_C10, PIN(B, 10), GPIO_OUT_LOW)
+GPIO(EN_C11, PIN(B, 11), GPIO_OUT_LOW)
+GPIO(EN_C12, PIN(B, 12), GPIO_OUT_LOW)
+GPIO(EN_C13, PIN(A, 8), GPIO_OUT_LOW)
+GPIO(EN_C14, PIN(A, 9), GPIO_OUT_LOW)
+GPIO(EN_C15, PIN(B, 15), GPIO_OUT_LOW)
+GPIO(EN_C16, PIN(C, 13), GPIO_OUT_LOW)
+GPIO(EN_C17, PIN(C, 14), GPIO_OUT_LOW)
+GPIO(EN_C18, PIN(C, 15), GPIO_OUT_LOW)
+GPIO(EN_C19, PIN(F, 0), GPIO_OUT_LOW)
+
+/* I2C Port for I/O expander */
+GPIO(I2C_SCL, PIN(B, 13), GPIO_INPUT)
+GPIO(I2C_SDA, PIN(B, 14), GPIO_INPUT)
+
+/* USB 2.0 Muxes */
+GPIO(USB_MUX0_C0, PIN(A, 1), GPIO_OUT_LOW)
+GPIO(USB_MUX0_C1, PIN(A, 2), GPIO_OUT_LOW)
+GPIO(USB_MUX0_C2, PIN(A, 3), GPIO_OUT_LOW)
+
+GPIO(USB_MUX1_C0, PIN(A, 5), GPIO_OUT_LOW)
+GPIO(USB_MUX1_C1, PIN(A, 6), GPIO_OUT_LOW)
+GPIO(USB_MUX1_C2, PIN(A, 7), GPIO_OUT_LOW)
+
+GPIO(EN_USB_MUX2, PIN(A, 13), GPIO_OUT_LOW)
+GPIO(USB_MUX2_C0, PIN(A, 14), GPIO_OUT_LOW)
+GPIO(USB_MUX2_C1, PIN(A, 15), GPIO_OUT_LOW)
+GPIO(USB_MUX2_C2, PIN(F, 1), GPIO_OUT_LOW)
+
+/* Unimplemented signals since we are not an EC */
+UNIMPLEMENTED(ENTERING_RW)
+UNIMPLEMENTED(WP_L)
+
+ALTERNATE(PIN_MASK(B, 0x6000), 5, MODULE_I2C, GPIO_ODR_HIGH) /* PB13/14 I2C2 */
diff --git a/util/flash_ec b/util/flash_ec
index 955a0d884b..e4bfcc5f23 100755
--- a/util/flash_ec
+++ b/util/flash_ec
@@ -92,6 +92,7 @@ BOARDS_STM32_DFU=(
polyberry
stm32f446e-eval
tigertail
+ fluffy
)
BOARDS_NPCX_5M5G_JTAG=(