diff options
author | Ege Mihmanli <egemih@google.com> | 2017-11-06 11:08:22 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-11-09 11:53:15 -0800 |
commit | ad231bf1d1eb84dbaeeab06006c2b33a52a53874 (patch) | |
tree | 5c7b96236d51d4b79bf3391c332322528e604346 /board | |
parent | a7c8b19aca80412c1c40f75eb208e383a53cafe3 (diff) | |
download | chrome-ec-ad231bf1d1eb84dbaeeab06006c2b33a52a53874.tar.gz |
rainier: initial mainboard
Copied board-related files from scarlet folder and made edits to
fit rainier. Left in most battery related code and config since there
is enough logic to detect absent battery
BUG=chromium:776441
TEST=Run "make -j BOARD=rainier"
BRANCH=none
Signed-off-by: egemih@google.com
Change-Id: Ifd1201a9a44cebd9b433545f0ac7ee04741429c9
Reviewed-on: https://chromium-review.googlesource.com/755949
Commit-Ready: Shawn N <shawnn@chromium.org>
Tested-by: Ege Mihmanli <egemih@google.com>
Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'board')
-rw-r--r-- | board/rainier/board.c | 525 | ||||
-rw-r--r-- | board/rainier/board.h | 177 | ||||
-rw-r--r-- | board/rainier/build.mk | 14 | ||||
-rw-r--r-- | board/rainier/ec.tasklist | 27 | ||||
-rw-r--r-- | board/rainier/gpio.inc | 93 | ||||
-rw-r--r-- | board/rainier/usb_pd_policy.c | 360 |
6 files changed, 1196 insertions, 0 deletions
diff --git a/board/rainier/board.c b/board/rainier/board.c new file mode 100644 index 0000000000..237cfcca12 --- /dev/null +++ b/board/rainier/board.c @@ -0,0 +1,525 @@ +/* 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 "adc_chip.h" +#include "backlight.h" +#include "button.h" +#include "chipset.h" +#include "charge_manager.h" +#include "charge_state.h" +#include "common.h" +#include "console.h" +#include "ec_commands.h" +#include "driver/accelgyro_bmi160.h" +#include "driver/baro_bmp280.h" +#include "driver/tcpm/fusb302.h" +#include "driver/temp_sensor/tmp432.h" +#include "extpower.h" +#include "gpio.h" +#include "hooks.h" +#include "host_command.h" +#include "i2c.h" +#include "power.h" +#include "power_button.h" +#include "pwm.h" +#include "pwm_chip.h" +#include "registers.h" +#include "spi.h" +#include "switch.h" +#include "system.h" +#include "task.h" +#include "tcpm.h" +#include "temp_sensor.h" +#include "temp_sensor_chip.h" +#include "timer.h" +#include "thermal.h" +#include "usb_charge.h" +#include "usb_mux.h" +#include "usb_pd_tcpm.h" +#include "util.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) +{ +#ifdef HAS_TASK_PDCMD + /* Exchange status with TCPCs */ + host_command_pd_send_status(PD_CHARGE_NO_CHANGE); +#endif +} + +static void overtemp_interrupt(enum gpio_signal signal) +{ + CPRINTS("AP wants shutdown"); + chipset_force_shutdown(); +} + +static void warm_reset_request_interrupt(enum gpio_signal signal) +{ + CPRINTS("AP wants warm reset"); + chipset_reset(0); +} + +#include "gpio_list.h" + +/******************************************************************************/ +/* ADC channels. Must be in the exactly same order as in enum adc_channel. */ +const struct adc_t adc_channels[] = { + [ADC_BOARD_ID] = {"BOARD_ID", 16, 4096, 0, STM32_AIN(10)}, +}; +BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); + +/******************************************************************************/ +/* I2C ports */ +const struct i2c_port_t i2c_ports[] = { + {"tcpc0", I2C_PORT_TCPC0, 1000, GPIO_I2C1_SCL, GPIO_I2C1_SDA}, +}; +const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); + +/* power signal list. Must match order of enum power_signal. */ +const struct power_signal_info power_signal_list[] = { + {GPIO_PP1250_S3_PG, POWER_SIGNAL_ACTIVE_HIGH, "PP1250_S3_PWR_GOOD"}, + {GPIO_PP900_S0_PG, POWER_SIGNAL_ACTIVE_HIGH, "PP900_S0_PWR_GOOD"}, + {GPIO_AP_CORE_PG, POWER_SIGNAL_ACTIVE_HIGH, "AP_PWR_GOOD"}, + {GPIO_AP_EC_S3_S0_L, POWER_SIGNAL_ACTIVE_LOW, "SUSPEND_DEASSERTED"}, +}; +BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT); + +#ifdef CONFIG_TEMP_SENSOR_TMP432 +/* Temperature sensors data; must be in same order as enum temp_sensor_id. */ +const struct temp_sensor_t temp_sensors[] = { + {"TMP432_Internal", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val, + TMP432_IDX_LOCAL, 4}, + {"TMP432_Sensor_1", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val, + TMP432_IDX_REMOTE1, 4}, + {"TMP432_Sensor_2", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val, + TMP432_IDX_REMOTE2, 4}, +}; +BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT); + +/* + * Thermal limits for each temp sensor. All temps are in degrees K. Must be in + * same order as enum temp_sensor_id. To always ignore any temp, use 0. + */ +struct ec_thermal_config thermal_params[] = { + {{0, 0, 0}, 0, 0}, /* TMP432_Internal */ + {{0, 0, 0}, 0, 0}, /* TMP432_Sensor_1 */ + {{0, 0, 0}, 0, 0}, /* TMP432_Sensor_2 */ +}; +BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT); +#endif + +/******************************************************************************/ +/* SPI devices */ +const struct spi_device_t spi_devices[] = { + { CONFIG_SPI_ACCEL_PORT, 1, GPIO_SPI_ACCEL_CS_L }, + { CONFIG_SPI_ACCEL_PORT, 1, GPIO_SPI_BARO_CS_L }, +}; +const unsigned int spi_devices_used = ARRAY_SIZE(spi_devices); + +/******************************************************************************/ +/* Wake-up pins for hibernate */ +const enum gpio_signal hibernate_wake_pins[] = { + GPIO_POWER_BUTTON_L, GPIO_CHARGER_INT_L +}; +const int hibernate_wake_pins_used = ARRAY_SIZE(hibernate_wake_pins); + +/******************************************************************************/ +const struct button_config buttons[CONFIG_BUTTON_COUNT] = { + [BUTTON_VOLUME_DOWN] = {"Volume Down", KEYBOARD_BUTTON_VOLUME_DOWN, + GPIO_VOLUME_DOWN_L, 30 * MSEC, 0}, + [BUTTON_VOLUME_UP] = {"Volume Up", KEYBOARD_BUTTON_VOLUME_UP, + GPIO_VOLUME_UP_L, 30 * MSEC, 0}, +}; + +const struct button_config *recovery_buttons[] = { + &buttons[BUTTON_VOLUME_DOWN], + &buttons[BUTTON_VOLUME_UP], + }; +const int recovery_buttons_count = ARRAY_SIZE(recovery_buttons); + +const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_COUNT] = { + {I2C_PORT_TCPC0, FUSB302_I2C_SLAVE_ADDR, &fusb302_tcpm_drv}, +}; + +struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = { + { + .port_addr = 0, + .driver = &virtual_usb_mux_driver, + .hpd_update = &virtual_hpd_update, + }, +}; + +void board_reset_pd_mcu(void) +{ +} + +uint16_t tcpc_get_alert_status(void) +{ + uint16_t status = 0; + + if (!gpio_get_level(GPIO_USB_C0_PD_INT_L)) + status |= PD_STATUS_TCPC_ALERT_0; + + return status; +} + +int board_set_active_charge_port(int charge_port) +{ + /* + * NOP because there is no internal power therefore no charging. + * Placeholder so common/charge_manager.c is built. + */ + return EC_SUCCESS; +} + +void board_set_charge_limit(int port, int supplier, int charge_ma, + int max_ma, int charge_mv) +{ + /* + * NOP because there is no internal power therefore no charging. + * Placeholder so common/charge_manager.c is built. + */ +} + +int extpower_is_present(void) +{ + /* There is no internal power on this board. */ + return 1; +} + +int pd_snk_is_vbus_provided(int port) +{ + /* Must be, if we're at a stage where this function is called. */ + return 1; +} + +static void board_spi_enable(void) +{ + gpio_config_module(MODULE_SPI_MASTER, 1); + + /* Enable clocks to SPI2 module */ + STM32_RCC_APB1ENR |= STM32_RCC_PB1_SPI2; + + /* Reset SPI2 */ + STM32_RCC_APB1RSTR |= STM32_RCC_PB1_SPI2; + STM32_RCC_APB1RSTR &= ~STM32_RCC_PB1_SPI2; + + spi_enable(CONFIG_SPI_ACCEL_PORT, 1); +} +DECLARE_HOOK(HOOK_CHIPSET_STARTUP, + board_spi_enable, + MOTION_SENSE_HOOK_PRIO - 1); + +static void board_spi_disable(void) +{ + spi_enable(CONFIG_SPI_ACCEL_PORT, 0); + + /* Disable clocks to SPI2 module */ + STM32_RCC_APB1ENR &= ~STM32_RCC_PB1_SPI2; + + gpio_config_module(MODULE_SPI_MASTER, 0); +} +DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, + board_spi_disable, + MOTION_SENSE_HOOK_PRIO + 1); + +static void board_init(void) +{ + /* Enable TCPC alert interrupts */ + gpio_enable_interrupt(GPIO_USB_C0_PD_INT_L); + + /* Enable reboot / shutdown control inputs from AP */ + gpio_enable_interrupt(GPIO_WARM_RESET_REQ); + gpio_enable_interrupt(GPIO_AP_OVERTEMP); + + /* Enable interrupts from BMI160 sensor. */ + gpio_enable_interrupt(GPIO_ACCEL_INT_L); + + /* Set SPI2 pins to high speed */ + /* pins D0/D1/D3/D4 */ + STM32_GPIO_OSPEEDR(GPIO_D) |= 0x000003cf; + + /* Sensor Init */ + if (system_jumped_to_this_image() && chipset_in_state(CHIPSET_STATE_ON)) + board_spi_enable(); +} +DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); + +void board_config_pre_init(void) +{ + STM32_RCC_AHBENR |= STM32_RCC_HB_DMA1; + /* + * Remap USART1 and SPI2 DMA: + * + * Ch4: USART1_TX / Ch5: USART1_RX + * Ch6: SPI2_RX / Ch7: SPI2_TX + */ + STM32_DMA_CSELR(STM32_DMAC_CH4) = (1 << 15) | (1 << 19) | + (1 << 20) | (1 << 21) | + (1 << 24) | (1 << 25); +} + +void board_hibernate(void) +{ + int rv; + + /* + * Disable the power enables for the TCPCs since we're going into + * hibernate. The charger VBUS interrupt will wake us up and reset the + * EC. Upon init, we'll reinitialize the TCPCs to be at full power. + */ + CPRINTS("Set TCPCs to low power"); + rv = tcpc_write(0, TCPC_REG_POWER, TCPC_REG_POWER_PWR_LOW); + if (rv) + CPRINTS("Error setting TCPC %d", 0); + + cflush(); +} + +enum rainier_board_version { + BOARD_VERSION_UNKNOWN = -1, + BOARD_VERSION_REV0 = 0, + BOARD_VERSION_REV1 = 1, + BOARD_VERSION_REV2 = 2, + BOARD_VERSION_REV3 = 3, + BOARD_VERSION_REV4 = 4, + BOARD_VERSION_REV5 = 5, + BOARD_VERSION_REV6 = 6, + BOARD_VERSION_REV7 = 7, + BOARD_VERSION_REV8 = 8, + BOARD_VERSION_REV9 = 9, + BOARD_VERSION_REV10 = 10, + BOARD_VERSION_REV11 = 11, + BOARD_VERSION_REV12 = 12, + BOARD_VERSION_REV13 = 13, + BOARD_VERSION_REV14 = 14, + BOARD_VERSION_REV15 = 15, + BOARD_VERSION_COUNT, +}; + +struct { + enum rainier_board_version version; + int expect_mv; +} const rainier_boards[] = { + { BOARD_VERSION_REV0, 109 }, /* 51.1K , 2.2K(gru 3.3K) ohm */ + { BOARD_VERSION_REV1, 211 }, /* 51.1k , 6.8K ohm */ + { BOARD_VERSION_REV2, 319 }, /* 51.1K , 11K ohm */ + { BOARD_VERSION_REV3, 427 }, /* 56K , 17.4K ohm */ + { BOARD_VERSION_REV4, 542 }, /* 51.1K , 22K ohm */ + { BOARD_VERSION_REV5, 666 }, /* 51.1K , 30K ohm */ + { BOARD_VERSION_REV6, 781 }, /* 51.1K , 39.2K ohm */ + { BOARD_VERSION_REV7, 900 }, /* 56K , 56K ohm */ + { BOARD_VERSION_REV8, 1023 }, /* 47K , 61.9K ohm */ + { BOARD_VERSION_REV9, 1137 }, /* 47K , 80.6K ohm */ + { BOARD_VERSION_REV10, 1240 }, /* 56K , 124K ohm */ + { BOARD_VERSION_REV11, 1343 }, /* 51.1K , 150K ohm */ + { BOARD_VERSION_REV12, 1457 }, /* 47K , 200K ohm */ + { BOARD_VERSION_REV13, 1576 }, /* 47K , 330K ohm */ + { BOARD_VERSION_REV14, 1684 }, /* 47K , 680K ohm */ + { BOARD_VERSION_REV15, 1800 }, /* 56K , NC */ +}; +BUILD_ASSERT(ARRAY_SIZE(rainier_boards) == BOARD_VERSION_COUNT); + +#define THRESHOLD_MV 56 /* Simply assume 1800/16/2 */ + +int board_get_version(void) +{ + static int version = BOARD_VERSION_UNKNOWN; + int mv; + int i; + + if (version != BOARD_VERSION_UNKNOWN) + return version; + + gpio_set_level(GPIO_EC_BOARD_ID_EN_L, 0); + /* Wait to allow cap charge */ + msleep(10); + mv = adc_read_channel(ADC_BOARD_ID); + + if (mv == ADC_READ_ERROR) + mv = adc_read_channel(ADC_BOARD_ID); + + gpio_set_level(GPIO_EC_BOARD_ID_EN_L, 1); + + for (i = 0; i < BOARD_VERSION_COUNT; ++i) { + if (mv < rainier_boards[i].expect_mv + THRESHOLD_MV) { + version = rainier_boards[i].version; + break; + } + } + + return version; +} + +/* Motion sensors */ +#ifdef HAS_TASK_MOTIONSENSE +/* Mutexes */ +static struct mutex g_base_mutex; + +static struct bmi160_drv_data_t g_bmi160_data; + +/* Matrix to rotate accelerometer 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)} +}; + +static struct bmp280_drv_data_t bmp280_drv_data; + +struct motion_sensor_t motion_sensors[] = { + /* + * Note: bmi160: supports accelerometer and gyro sensor + * Requirement: accelerometer sensor must init before gyro sensor + * DO NOT change the order of the following table. + */ + [LID_ACCEL] = { + .name = "Accel", + .active_mask = SENSOR_ACTIVE_S0_S3, + .chip = MOTIONSENSE_CHIP_BMI160, + .type = MOTIONSENSE_TYPE_ACCEL, + .location = MOTIONSENSE_LOC_LID, + .drv = &bmi160_drv, + .mutex = &g_base_mutex, + .drv_data = &g_bmi160_data, + .port = CONFIG_SPI_ACCEL_PORT, + .addr = BMI160_SET_SPI_ADDRESS(CONFIG_SPI_ACCEL_PORT), + .rot_standard_ref = &base_standard_ref, + .default_range = 2, /* g, enough for laptop. */ + .min_frequency = BMI160_ACCEL_MIN_FREQ, + .max_frequency = BMI160_ACCEL_MAX_FREQ, + .config = { + /* AP: by default use EC settings */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* Enable accel in S0 */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 10000 | ROUND_UP_FLAG, + .ec_rate = 100 * MSEC, + }, + /* Sensor off in S3/S5 */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 0, + .ec_rate = 0, + }, + /* Sensor off in S3/S5 */ + [SENSOR_CONFIG_EC_S5] = { + .odr = 0, + .ec_rate = 0 + }, + }, + }, + [LID_GYRO] = { + .name = "Gyro", + .active_mask = SENSOR_ACTIVE_S0_S3, + .chip = MOTIONSENSE_CHIP_BMI160, + .type = MOTIONSENSE_TYPE_GYRO, + .location = MOTIONSENSE_LOC_LID, + .drv = &bmi160_drv, + .mutex = &g_base_mutex, + .drv_data = &g_bmi160_data, + .port = CONFIG_SPI_ACCEL_PORT, + .addr = BMI160_SET_SPI_ADDRESS(CONFIG_SPI_ACCEL_PORT), + .default_range = 1000, /* dps */ + .rot_standard_ref = NULL, /* Identity matrix. */ + .min_frequency = BMI160_GYRO_MIN_FREQ, + .max_frequency = BMI160_GYRO_MAX_FREQ, + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* Enable gyro in S0 */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 10000 | ROUND_UP_FLAG, + .ec_rate = 100 * MSEC, + }, + /* Sensor off in S3/S5 */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 0, + .ec_rate = 0, + }, + /* Sensor off in S3/S5 */ + [SENSOR_CONFIG_EC_S5] = { + .odr = 0, + .ec_rate = 0, + }, + }, + }, + [LID_BARO] = { + .name = "Baro", + .active_mask = SENSOR_ACTIVE_S0_S3, + .chip = MOTIONSENSE_CHIP_BMP280, + .type = MOTIONSENSE_TYPE_BARO, + .location = MOTIONSENSE_LOC_LID, + .drv = &bmp280_drv, + .drv_data = &bmp280_drv_data, + .port = CONFIG_SPI_ACCEL_PORT, + .addr = BMI160_SET_SPI_ADDRESS(CONFIG_SPI_ACCEL_PORT), + .default_range = 1 << 18, /* 1bit = 4 Pa, 16bit ~= 2600 hPa */ + .min_frequency = BMP280_BARO_MIN_FREQ, + .max_frequency = BMP280_BARO_MAX_FREQ, + .config = { + /* AP: by default shutdown all sensors */ + [SENSOR_CONFIG_AP] = { + .odr = 0, + .ec_rate = 0, + }, + /* Sensor off in S0 */ + [SENSOR_CONFIG_EC_S0] = { + .odr = 0, + .ec_rate = 0, + }, + /* Sensor off in S3/S5 */ + [SENSOR_CONFIG_EC_S3] = { + .odr = 0, + .ec_rate = 0, + }, + /* Sensor off in S3/S5 */ + [SENSOR_CONFIG_EC_S5] = { + .odr = 0, + .ec_rate = 0, + }, + }, + }, +}; +const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors); +#endif /* defined(HAS_TASK_MOTIONSENSE) */ + +int board_allow_i2c_passthru(int port) +{ + /* + * Battery port is the only port passthru is allowed on and this board + * does not have a battery, therefore always return false. + */ + return 0; +} + +int tablet_get_mode(void) +{ + /* Always in tablet mode */ + return 1; +} + +int charge_want_shutdown(void) +{ + /* + * power/rk3399.c assumes there is internal power. Therefore this stub + * returns false to prevent arbitrary shutdown. + */ + return 0; +} + +int charge_prevent_power_on(int power_button_pressed) +{ + /* Assume there is always sufficient power from charger to power on. */ + return 0; +} diff --git a/board/rainier/board.h b/board/rainier/board.h new file mode 100644 index 0000000000..8c67257695 --- /dev/null +++ b/board/rainier/board.h @@ -0,0 +1,177 @@ +/* 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. + */ + +/* Configuration for Rainier */ + +#ifndef __CROS_EC_BOARD_H +#define __CROS_EC_BOARD_H + +/* Optional modules */ +#define CONFIG_ADC +#undef CONFIG_ADC_WATCHDOG +#define CONFIG_CHIPSET_RK3399 +#define CONFIG_CMD_ACCELS +#define CONFIG_CMD_RTC +#define CONFIG_HOSTCMD_RTC +#define CONFIG_I2C +#define CONFIG_I2C_MASTER +#define CONFIG_I2C_PASSTHRU_RESTRICTED +#define CONFIG_LOW_POWER_IDLE +#define CONFIG_POWER_COMMON +#define CONFIG_SPI +#define CONFIG_SPI_MASTER +#define CONFIG_STM_HWTIMER32 +#define CONFIG_STM32_CLOCK_LSE +#define CONFIG_SWITCH +#define CONFIG_WATCHDOG_HELP + +#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands for testing */ + +#undef CONFIG_UART_CONSOLE +#define CONFIG_UART_CONSOLE 1 + +/* Region sizes are no longer a power of 2 so we can't enable MPU */ +#undef CONFIG_MPU + +/* Enable a different power-on sequence than the one on gru */ +#undef CONFIG_CHIPSET_POWER_SEQ_VERSION +#define CONFIG_CHIPSET_POWER_SEQ_VERSION 2 + +/* Optional features */ +#define CONFIG_BOARD_PRE_INIT +#define CONFIG_BOARD_SPECIFIC_VERSION +#define CONFIG_BOARD_VERSION +#define CONFIG_BUTTON_COUNT 2 +#define CONFIG_BUTTON_RECOVERY +#define CONFIG_CHARGER_ILIM_PIN_DISABLED +#define CONFIG_FORCE_CONSOLE_RESUME +#define CONFIG_HOST_COMMAND_STATUS + +/* By default, set hcdebug to off */ +#undef CONFIG_HOSTCMD_DEBUG_MODE +#define CONFIG_HOSTCMD_DEBUG_MODE HCDEBUG_OFF +#undef CONFIG_LID_SWITCH +#undef CONFIG_LTO +#define CONFIG_POWER_BUTTON +#define CONFIG_POWER_BUTTON_IGNORE_LID +#define CONFIG_POWER_TRACK_HOST_SLEEP_STATE +#define CONFIG_SOFTWARE_PANIC +#define CONFIG_VBOOT_HASH + +#define CONFIG_USB_MUX_VIRTUAL + +/* Increase tx buffer size, as we'd like to stream EC log to AP. */ +#undef CONFIG_UART_TX_BUF_SIZE +#define CONFIG_UART_TX_BUF_SIZE 4096 + +/* Motion Sensors */ +#define CONFIG_ACCELGYRO_BMI160 +#define CONFIG_ACCEL_INTERRUPTS +#define CONFIG_ACCELGYRO_BMI160_INT_EVENT TASK_EVENT_CUSTOM(4) +#define CONFIG_BARO_BMP280 + +/* To be able to indicate the device is in tablet mode. */ +#define CONFIG_TABLET_MODE_SWITCH + +/* FIFO size is in power of 2. */ +#define CONFIG_ACCEL_FIFO 256 +#define CONFIG_ACCEL_FIFO_THRES (CONFIG_ACCEL_FIFO / 3) + +/* Sensors without hardware FIFO are in forced mode. */ +#define CONFIG_ACCEL_FORCE_MODE_MASK (1 << LID_BARO) + +/* USB PD config */ +#define CONFIG_CHARGE_MANAGER +#define CONFIG_USB_POWER_DELIVERY +#define CONFIG_USB_PD_ALT_MODE +#define CONFIG_USB_PD_ALT_MODE_DFP +#define CONFIG_USB_PD_CUSTOM_VDM +#define CONFIG_USB_PD_DISCHARGE +#define CONFIG_USB_PD_DISCHARGE_GPIO +#define CONFIG_USB_PD_DUAL_ROLE +#define CONFIG_USB_PD_PORT_COUNT 1 +#define CONFIG_USB_PD_TCPM_FUSB302 +#define CONFIG_USB_PD_VBUS_DETECT_TCPC +#define ADC_VBUS -1 +#define CONFIG_USBC_SS_MUX +#define CONFIG_USBC_VCONN +#define CONFIG_USBC_VCONN_SWAP +#define CONFIG_USB_PD_COMM_LOCKED + +#define PD_OPERATING_POWER_MW 15000 +#define PD_MAX_POWER_MW ((PD_MAX_VOLTAGE_MV * PD_MAX_CURRENT_MA) / 1000) +#define PD_MAX_CURRENT_MA 3000 +#define PD_MAX_VOLTAGE_MV 12850 + +#define PD_POWER_SUPPLY_TURN_ON_DELAY 30000 /* us */ +#define PD_POWER_SUPPLY_TURN_OFF_DELAY 50000 /* us */ +#define PD_VCONN_SWAP_DELAY 5000 /* us */ + +/* Timer selection */ +#define TIM_CLOCK32 2 +#define TIM_WATCHDOG 7 + +/* 48 MHz SYSCLK clock frequency */ +#define CPU_CLOCK 48000000 + +/* Optional for testing */ +#undef CONFIG_PECI +#undef CONFIG_PSTORE + +#define CONFIG_TASK_PROFILING + +#define I2C_PORT_TCPC0 1 + +/* Enable Accel over SPI */ +#define CONFIG_SPI_ACCEL_PORT 0 /* The first SPI master port (SPI2) */ + +#define CONFIG_KEYBOARD_PROTOCOL_MKBP +#define CONFIG_MKBP_EVENT +/* Define the MKBP events which are allowed to wakeup AP in S3. */ +#define CONFIG_MKBP_WAKEUP_MASK \ + (EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON) |\ + EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC)) + +#ifndef __ASSEMBLER__ + +enum adc_channel { + /* Real ADC channels begin here */ + ADC_BOARD_ID = 0, + ADC_CH_COUNT +}; + +enum button { + BUTTON_VOLUME_DOWN = 0, + BUTTON_VOLUME_UP = 1, + BUTTON_COUNT +}; + +/* power signal definitions */ +enum power_signal { + PP1250_S3_PWR_GOOD = 0, + PP900_S0_PWR_GOOD, + AP_PWR_GOOD, + SUSPEND_DEASSERTED, + + /* Number of signals */ + POWER_SIGNAL_COUNT, +}; + +/* Motion sensors */ +enum sensor_id { + LID_ACCEL = 0, + LID_GYRO, + LID_BARO, +}; + +#include "gpio_signal.h" +#include "registers.h" + +void board_reset_pd_mcu(void); +int board_get_version(void); + +#endif /* !__ASSEMBLER__ */ + +#endif /* __CROS_EC_BOARD_H */ diff --git a/board/rainier/build.mk b/board/rainier/build.mk new file mode 100644 index 0000000000..b77a900d56 --- /dev/null +++ b/board/rainier/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 +# +# +# STmicro STM32F098VC +CHIP:=stm32 +CHIP_FAMILY:=stm32f0 +CHIP_VARIANT:=stm32f09x + +board-y=board.o usb_pd_policy.o diff --git a/board/rainier/ec.tasklist b/board/rainier/ec.tasklist new file mode 100644 index 0000000000..2e197b4ecc --- /dev/null +++ b/board/rainier/ec.tasklist @@ -0,0 +1,27 @@ +/* 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' is the name of the task + * 'r' is the main routine of the task + * 'd' is 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, LARGER_TASK_STACK_SIZE) \ + TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(MOTIONSENSE, motion_sense_task, NULL, VENTI_TASK_STACK_SIZE) \ + TASK_NOTEST(PDCMD, pd_command_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(HOSTCMD, host_command_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \ + TASK_ALWAYS(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE) + diff --git a/board/rainier/gpio.inc b/board/rainier/gpio.inc new file mode 100644 index 0000000000..65bbfe1d6f --- /dev/null +++ b/board/rainier/gpio.inc @@ -0,0 +1,93 @@ +/* -*- 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(SPI1_NSS, PIN(A, 15), GPIO_INT_BOTH, + spi_event) +GPIO_INT(USB_C0_PD_INT_L, PIN(C, 13), GPIO_INT_FALLING | GPIO_PULL_UP, + tcpc_alert_event) +GPIO_INT(VOLUME_UP_L, PIN(D, 10), GPIO_INT_BOTH | GPIO_PULL_UP, + button_interrupt) +GPIO_INT(VOLUME_DOWN_L, PIN(E, 11), GPIO_INT_BOTH | GPIO_PULL_UP, + button_interrupt) +GPIO_INT(POWER_BUTTON_L, PIN(A, 0), GPIO_INT_BOTH | GPIO_PULL_UP, + power_button_interrupt) +GPIO_INT(PP1250_S3_PG, PIN(D, 8), GPIO_INT_BOTH | GPIO_PULL_UP, + power_signal_interrupt) +GPIO_INT(PP900_S0_PG, PIN(D, 9), GPIO_INT_BOTH | GPIO_PULL_UP, + power_signal_interrupt) +GPIO_INT(AP_EC_S3_S0_L, PIN(C, 7), GPIO_INT_BOTH | GPIO_PULL_DOWN, + power_signal_interrupt) +GPIO_INT(WARM_RESET_REQ, PIN(E, 1), GPIO_INT_RISING | GPIO_PULL_DOWN, + warm_reset_request_interrupt) +GPIO_INT(AP_OVERTEMP, PIN(E, 4), GPIO_INT_RISING | GPIO_PULL_DOWN, + overtemp_interrupt) +GPIO_INT(ACCEL_INT_L, PIN(D, 14), GPIO_INT_FALLING | GPIO_SEL_1P8V, + bmi160_interrupt) + +/* Voltage rails control pins */ +GPIO(PP1800_S0_EN, PIN(D, 11), GPIO_OUT_LOW) +GPIO(AP_CORE_EN, PIN(C, 1), GPIO_OUT_LOW) +GPIO(PP3300_S0_EN, PIN(E, 12), GPIO_OUT_LOW) +GPIO(PP1800_USB_EN, PIN(C, 4), GPIO_OUT_LOW) +GPIO(PP900_S0_EN, PIN(E, 8), GPIO_OUT_LOW) +GPIO(PP1250_S3_EN, PIN(D, 13), GPIO_OUT_LOW) +GPIO(PP1800_S3_EN, PIN(C, 3), GPIO_OUT_LOW) +GPIO(PP3300_S3_EN, PIN(E, 2), GPIO_OUT_LOW) +GPIO(PP900_S3_EN, PIN(E, 10), GPIO_OUT_LOW) + +GPIO(PP3300_REDUCE_EFF_L, PIN(D, 12), GPIO_ODR_HIGH) + +/* + * I2C pins should be configured as inputs until I2C module is + * initialized. This will avoid driving the lines unintentionally. + */ +GPIO(I2C0_SCL, PIN(B, 8), GPIO_INPUT) +GPIO(I2C0_SDA, PIN(B, 9), GPIO_INPUT) +GPIO(I2C1_SCL, PIN(B, 10), GPIO_INPUT) +GPIO(I2C1_SDA, PIN(B, 11), GPIO_INPUT) + +/* Analog pins */ +GPIO(BOARD_ID, PIN(C, 0), GPIO_ANALOG) + +/* SPI sensors */ +GPIO(SPI_BARO_CS_L, PIN(B, 12), GPIO_OUT_HIGH) +GPIO(SPI_ACCEL_CS_L, PIN(D, 0), GPIO_OUT_HIGH) + +/* Other input pins */ +GPIO(WP_L, PIN(E, 5), GPIO_INPUT) +GPIO(CCD_MODE_ODL, PIN(C, 5), GPIO_INPUT | GPIO_PULL_UP) +GPIO(CHARGER_INT_L, PIN(E, 6), GPIO_INPUT | GPIO_PULL_UP) +/* Non-INT power signal pin */ +GPIO(AP_CORE_PG, PIN(D, 7), GPIO_INPUT | GPIO_PULL_UP) + + + +/* Other output pins */ +GPIO(ENTERING_RW, PIN(C, 6), GPIO_ODR_HIGH) +GPIO(SYS_RST_L, PIN(C, 8), GPIO_ODR_HIGH) +GPIO(EC_INT_L, PIN(E, 3), GPIO_ODR_HIGH) +GPIO(EC_BOARD_ID_EN_L, PIN(F, 1), GPIO_ODR_HIGH) +GPIO(USB_C0_DISCHARGE, PIN(A, 11), GPIO_OUT_LOW) +GPIO(PCA9468_EN, PIN(E, 15), GPIO_OUT_LOW) + +/* USART1: PA9/PA10 */ +ALTERNATE(PIN_MASK(A, 0x0600), 1, MODULE_UART, 0) +/* I2C MASTER: PB8/9 */ +ALTERNATE(PIN_MASK(B, 0x0300), 1, MODULE_I2C, 0) +/* I2C MASTER: PB10/11 */ +ALTERNATE(PIN_MASK(B, 0x0c00), 1, MODULE_I2C, 0) +/* SPI SLAVE: PB3/4/5 */ +ALTERNATE(PIN_MASK(B, 0x0038), 0, MODULE_SPI, 0) +/* SPI SLAVE CS: PA15 */ +ALTERNATE(PIN_MASK(A, 0x8000), 0, MODULE_SPI, 0) +/* SPI MASTER: PD1/3/4 */ +ALTERNATE(PIN_MASK(D, 0x001a), 1, MODULE_SPI_MASTER, 0) diff --git a/board/rainier/usb_pd_policy.c b/board/rainier/usb_pd_policy.c new file mode 100644 index 0000000000..b74a0503ba --- /dev/null +++ b/board/rainier/usb_pd_policy.c @@ -0,0 +1,360 @@ +/* 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 "common.h" +#include "console.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) + +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, + (int)(PD_MAX_VOLTAGE_MV * 1.05), + PD_OPERATING_POWER_MW), + PDO_VAR(4750, + (int)(PD_MAX_VOLTAGE_MV * 1.05), + PD_MAX_CURRENT_MA), +}; +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; + +int board_vbus_source_enabled(int port) +{ + return vbus_en; +} + +int pd_set_power_supply_ready(int port) +{ + pd_set_vbus_discharge(port, 0); + /* Provide VBUS */ + vbus_en = 1; + + /* 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; + /* Disable VBUS */ + vbus_en = 0; + + /* Enable discharge if we were previously sourcing 5V */ + if (prev_en) + pd_set_vbus_discharge(port, 1); + + /* notify host of power info change */ + pd_send_host_event(PD_EVENT_POWER_CHANGE); +} + +void typec_set_source_current_limit(int port, int rp) +{ + /* No-operation */ +} + +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 */ + return (data_role == PD_ROLE_UFP) ? 1 : 0; +} + +int pd_check_vconn_swap(int port) +{ + /* + * VCONN is provided directly by the battery (PPVAR_SYS) + * but use the same rules as power swap. + */ + return pd_get_dual_role() == PD_DRP_TOGGLE_ON ? 1 : 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) +{ + /* + * 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) + 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; + + /* 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]); + + 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]; +/* DP Status VDM as returned by UFP */ +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 pin_mode = pd_dfp_dp_get_pin_mode(port, dp_status[port]); + + if (!pin_mode) + return 0; + + 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) +{ + dp_flags[port] |= DP_FLAGS_DP_ON; +} + +static int svdm_dp_attention(int port, uint32_t *payload) +{ + const struct usb_mux *mux = &usb_muxes[port]; + int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]); + int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]); + int mf_pref = PD_VDO_DPSTS_MF_PREF(payload[1]); + + dp_status[port] = payload[1]; + + mux->hpd_update(port, lvl, irq); + + if (lvl) + usb_mux_set(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP, + USB_SWITCH_CONNECT, pd_get_polarity(port)); + else + usb_mux_set(port, mf_pref ? TYPEC_MUX_USB : TYPEC_MUX_NONE, + USB_SWITCH_CONNECT, pd_get_polarity(port)); + + 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 */ + |