diff options
author | Aseda Aboagye <aaboagye@google.com> | 2019-03-21 14:44:44 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-07-17 01:32:20 +0000 |
commit | 60d6db8fbf5bae84b94b6dac8ea8c70a08e30555 (patch) | |
tree | 340b53b66f6751eb536463b1c0467feac5974830 /board | |
parent | 9be52b960b3e25ccc8ef0fc4c15db5bc918a9965 (diff) | |
download | chrome-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>
Diffstat (limited to 'board')
-rw-r--r-- | board/fluffy/board.c | 403 | ||||
-rw-r--r-- | board/fluffy/board.h | 72 | ||||
-rw-r--r-- | board/fluffy/build.mk | 18 | ||||
-rw-r--r-- | board/fluffy/ec.tasklist | 12 | ||||
-rw-r--r-- | board/fluffy/gpio.inc | 60 |
5 files changed, 565 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 */ |