summaryrefslogtreecommitdiff
path: root/board/c2d2/board.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/c2d2/board.c')
-rw-r--r--board/c2d2/board.c1095
1 files changed, 0 insertions, 1095 deletions
diff --git a/board/c2d2/board.c b/board/c2d2/board.c
deleted file mode 100644
index 3327ea43b6..0000000000
--- a/board/c2d2/board.c
+++ /dev/null
@@ -1,1095 +0,0 @@
-/* Copyright 2020 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.
- */
-/* C2D2 debug device board configuration */
-
-#include "adc.h"
-#include "common.h"
-#include "console.h"
-#include "ec_version.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "i2c.h"
-#include "i2c_ite_flash_support.h"
-#include "queue_policies.h"
-#include "registers.h"
-#include "spi.h"
-#include "system.h"
-#include "task.h"
-#include "timer.h"
-#include "update_fw.h"
-#include "usart_rx_dma.h"
-#include "usart_tx_dma.h"
-#include "usart-stm32f0.h"
-#include "usb_hw.h"
-#include "usb_i2c.h"
-#include "usb_spi.h"
-#include "usb-stream.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)
-
-/* Forward declarations */
-static void update_vrefs_and_shifters(void);
-DECLARE_DEFERRED(update_vrefs_and_shifters);
-static bool is_ec_i2c_enabled(void);
-
-/* Global state tracking current pin configuration and operations */
-static struct mutex vref_bus_state_mutex;
-static int vref_monitor_disable;
-#define VREF_MON_DIS_H1_RST_HELD BIT(0)
-#define VREF_MON_DIS_EC_PWR_HELD BIT(1)
-#define VREF_MON_DIS_SPI_MODE BIT(2)
-
-/*
- * Tracks if bus pins are locked by a function like UART holding, I2C,
- * or SPI.
- */
-enum bus_lock {
- BUS_UNLOCKED, /* Normal UART; pins available for other functions */
- BUS_UART_HELD, /* UART locked to pins while holding RX low */
- BUS_SPI, /* SPI locked to pins */
- BUS_I2C, /* I2C bus locked to pins */
-};
-/* A0/A1 (H1 UART or SPI) */
-enum bus_lock h1_pins;
-/* B6/B7 (EC UART, EC I2C, or SPI) */
-enum bus_lock ec_pins;
-/* B10/B11 (AP UART, AUX I2C) */
-enum bus_lock ap_pins;
-
-static const char *lock_to_string(const enum bus_lock val)
-{
- static const char *const names[] = {
- [BUS_UNLOCKED] = "UART",
- [BUS_UART_HELD] = "UART HELD",
- [BUS_SPI] = "SPI",
- [BUS_I2C] = "I2C",
- };
-
- if (val < 0 || val >= ARRAY_SIZE(names))
- return "UNKNOWN";
-
- return names[val];
-}
-
-static int command_bus_status(int argc, char **argv)
-{
- if (argc > 1)
- return EC_ERROR_PARAM_COUNT;
-
- ccprintf("H1 pins: %s\n", lock_to_string(h1_pins));
- ccprintf("EC pins: %s\n", lock_to_string(ec_pins));
- ccprintf("AP pins: %s\n", lock_to_string(ap_pins));
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(bus_status, command_bus_status,
- "",
- "Gets the bus state for swappable pins");
-
-
-/******************************************************************************
- ** Chip-specific board configuration
- */
-void board_config_pre_init(void)
-{
- /* enable SYSCFG & COMP clock */
- STM32_RCC_APB2ENR |= STM32_RCC_SYSCFGEN;
-
- /* enable DAC for comparator input */
- STM32_RCC_APB1ENR |= STM32_RCC_DACEN;
-
- /*
- * the DMA mapping is :
- * Chan 3 : USART3_RX
- * Chan 5 : USART1_RX
- * Chan 6 : SPI2_RX
- * Chan 7 : SPI2_TX
- *
- * i2c : no dma
- * tim16/17: no dma
- */
- STM32_SYSCFG_CFGR1 |= BIT(24); /* Remap SPI2_RX to channel 6 */
- STM32_SYSCFG_CFGR1 |= BIT(26); /* Remap USART3 RX/TX DMA */
- STM32_SYSCFG_CFGR1 |= BIT(10); /* Remap USART1 RX/TX DMA */
-}
-
-
-/******************************************************************************
- ** ADC channels
- */
-const struct adc_t adc_channels[] = {
- /* Sensing the H1's voltage at the DUT side. Converted to mV. */
- [ADC_H1_SPI_VREF] = {
- .name = "H1_VREF",
- .factor_mul = 3300,
- .factor_div = 4096,
- .shift = 0,
- .channel = STM32_AIN(3),
- },
- /* Sensing the EC's voltage at the DUT side. Converted to mV. */
- [ADC_EC_SPI_VREF] = {
- .name = "EC_VREF",
- .factor_mul = 3300,
- .factor_div = 4096,
- .shift = 0,
- .channel = STM32_AIN(4),
- }
-};
-BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
-
-/******************************************************************************
- * 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("C2D2"),
- [USB_STR_SERIALNO] = 0,
- [USB_STR_VERSION] = USB_STRING_DESC(CROS_EC_VERSION32),
- [USB_STR_USART4_STREAM_NAME] = USB_STRING_DESC("CR50"),
- [USB_STR_UPDATE_NAME] = USB_STRING_DESC("Firmware update"),
- [USB_STR_CONSOLE_NAME] = USB_STRING_DESC("C2D2 Shell"),
- [USB_STR_I2C_NAME] = USB_STRING_DESC("I2C"),
- [USB_STR_USART3_STREAM_NAME] = USB_STRING_DESC("CPU"),
- [USB_STR_USART1_STREAM_NAME] = USB_STRING_DESC("EC"),
-};
-
-BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
-
-/******************************************************************************
- * Support I2C bridging over USB.
- */
-
-/* I2C ports */
-const struct i2c_port_t i2c_ports[] = {
- {
- .name = "ec",
- .port = I2C_PORT_EC,
- .kbps = 100,
- .scl = GPIO_UART_DBG_TX_EC_RX_SCL,
- .sda = GPIO_UART_EC_TX_DBG_RX_SDA,
- .flags = I2C_PORT_FLAG_DYNAMIC_SPEED,
- },
- {
- .name = "aux",
- .port = I2C_PORT_AUX,
- .kbps = 100,
- .scl = GPIO_UART_DBG_TX_AP_RX_INA_SCL,
- .sda = GPIO_UART_AP_TX_DBG_RX_INA_SDA,
- .flags = I2C_PORT_FLAG_DYNAMIC_SPEED,
- },
-};
-const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
-
-/* Configure ITE flash support module */
-const struct ite_dfu_config_t ite_dfu_config = {
- .i2c_port = I2C_PORT_EC,
- /* PB6/7 are connected to complement outputs of TIM16/17 */
- .use_complement_timer_channel = true,
- .access_allow = &is_ec_i2c_enabled,
- .scl = GPIO_UART_DBG_TX_EC_RX_SCL,
- .sda = GPIO_UART_EC_TX_DBG_RX_SDA,
-};
-
-/*
- * I2C is always enabled, but the i2c pins may not be muxed to DUT. We will
- * let the i2c transactions fail instead of using the USB endpoint disable
- * status.
- */
-int usb_i2c_board_is_enabled(void) { return 1; }
-
-/******************************************************************************
- * Forward UARTs as a USB serial interface.
- */
-
-#define USB_STREAM_RX_SIZE 32
-#define USB_STREAM_TX_SIZE 64
-
-/******************************************************************************
- * Forward USART1 (EC) as a simple USB serial interface.
- */
-
-static struct usart_config const usart1;
-struct usb_stream_config const usart1_usb;
-
-static struct queue const usart1_to_usb = QUEUE_DIRECT(128, uint8_t,
- usart1.producer, usart1_usb.consumer);
-static struct queue const usb_to_usart1 = QUEUE_DIRECT(64, uint8_t,
- usart1_usb.producer, usart1.consumer);
-
-static struct usart_rx_dma const usart1_rx_dma =
- USART_RX_DMA(STM32_DMAC_CH5, 32);
-
-static struct usart_config const usart1 =
- USART_CONFIG(usart1_hw,
- usart1_rx_dma.usart_rx,
- usart_tx_interrupt,
- 115200,
- 0,
- usart1_to_usb,
- usb_to_usart1);
-
-USB_STREAM_CONFIG_USART_IFACE(usart1_usb,
- USB_IFACE_USART1_STREAM,
- USB_STR_USART1_STREAM_NAME,
- USB_EP_USART1_STREAM,
- USB_STREAM_RX_SIZE,
- USB_STREAM_TX_SIZE,
- usb_to_usart1,
- usart1_to_usb,
- usart1)
-
-
-/******************************************************************************
- * Forward USART3 (CPU) as a simple USB serial interface.
- */
-
-static struct usart_config const usart3;
-struct usb_stream_config const usart3_usb;
-
-static struct queue const usart3_to_usb = QUEUE_DIRECT(1024, uint8_t,
- usart3.producer, usart3_usb.consumer);
-static struct queue const usb_to_usart3 = QUEUE_DIRECT(64, uint8_t,
- usart3_usb.producer, usart3.consumer);
-
-static struct usart_rx_dma const usart3_rx_dma =
- USART_RX_DMA(STM32_DMAC_CH3, 32);
-
-static struct usart_config const usart3 =
- USART_CONFIG(usart3_hw,
- usart3_rx_dma.usart_rx,
- usart_tx_interrupt,
- 115200,
- 0,
- usart3_to_usb,
- usb_to_usart3);
-
-USB_STREAM_CONFIG_USART_IFACE(usart3_usb,
- USB_IFACE_USART3_STREAM,
- USB_STR_USART3_STREAM_NAME,
- USB_EP_USART3_STREAM,
- USB_STREAM_RX_SIZE,
- USB_STREAM_TX_SIZE,
- usb_to_usart3,
- usart3_to_usb,
- usart3)
-
-
-/******************************************************************************
- * Forward USART4 (cr50) as a simple USB serial interface.
- *
- * We do not try to share DMA channel 6 with SPI2, so just use interrupts
- */
-
-static struct usart_config const usart4;
-struct usb_stream_config const usart4_usb;
-
-static struct queue const usart4_to_usb = QUEUE_DIRECT(1024, uint8_t,
- usart4.producer, usart4_usb.consumer);
-static struct queue const usb_to_usart4 = QUEUE_DIRECT(64, uint8_t,
- usart4_usb.producer, usart4.consumer);
-
-static struct usart_config const usart4 =
- USART_CONFIG(usart4_hw,
- usart_rx_interrupt,
- usart_tx_interrupt,
- 115200,
- 0,
- usart4_to_usb,
- usb_to_usart4);
-
-USB_STREAM_CONFIG_USART_IFACE(usart4_usb,
- USB_IFACE_USART4_STREAM,
- USB_STR_USART4_STREAM_NAME,
- USB_EP_USART4_STREAM,
- USB_STREAM_RX_SIZE,
- USB_STREAM_TX_SIZE,
- usb_to_usart4,
- usart4_to_usb,
- usart4)
-
-/******************************************************************************
- * Set up SPI over USB
- * Notes DMA Channel 6 is shared and mutually exclusive with USART4 RX
- */
-
-/* SPI devices */
-const struct spi_device_t spi_devices[] = {
- { CONFIG_SPI_FLASH_PORT, 1, GPIO_SPI_CSN},
-};
-const unsigned int spi_devices_used = ARRAY_SIZE(spi_devices);
-
-void usb_spi_board_enable(struct usb_spi_config const *config)
-{
- /* Configure SPI GPIOs */
- gpio_config_module(MODULE_SPI_FLASH, 1);
-
- /* Set all four SPI pins to high speed */
- STM32_GPIO_OSPEEDR(GPIO_B) |= 0xff000000;
-
- /* 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(&spi_devices[0], 1);
-}
-
-void usb_spi_board_disable(struct usb_spi_config const *config)
-{
- spi_enable(&spi_devices[0], 0);
-
- /* Disable clocks to SPI2 module */
- STM32_RCC_APB1ENR &= ~STM32_RCC_PB1_SPI2;
-
- /* Release SPI GPIOs */
- gpio_config_module(MODULE_SPI_FLASH, 0);
-
- /* Reset all four SPI pins to low speed */
- STM32_GPIO_OSPEEDR(GPIO_B) &= ~0xff000000;
-}
-
-USB_SPI_CONFIG(usb_spi, USB_IFACE_SPI, USB_EP_SPI,
- USB_SPI_CONFIG_FLAGS_IGNORE_HOST_SIDE_ENABLE);
-
-/******************************************************************************
- * Check parity setting on usarts.
- */
-static int command_uart_parity(int argc, char **argv)
-{
- int parity = 0, newparity;
- struct usart_config const *usart;
- char *e;
-
- if ((argc < 2) || (argc > 3))
- return EC_ERROR_PARAM_COUNT;
-
- if (!strcasecmp(argv[1], "usart1"))
- usart = &usart1;
- else if (!strcasecmp(argv[1], "usart3"))
- usart = &usart3;
- else if (!strcasecmp(argv[1], "usart4"))
- usart = &usart4;
- else
- return EC_ERROR_PARAM1;
-
- if (argc == 3) {
- parity = strtoi(argv[2], &e, 0);
- if (*e || (parity < 0) || (parity > 2))
- return EC_ERROR_PARAM2;
-
- usart_set_parity(usart, parity);
- }
-
- newparity = usart_get_parity(usart);
- ccprintf("Parity on %s is %d.\n", argv[1], newparity);
-
- if ((argc == 3) && (newparity != parity))
- return EC_ERROR_UNKNOWN;
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(parity, command_uart_parity,
- "usart[2|3|4] [0|1|2]",
- "Set parity on uart");
-
-/******************************************************************************
- * Set baud rate setting on usarts.
- */
-static int command_uart_baud(int argc, char **argv)
-{
- int baud = 0;
- struct usart_config const *usart;
- char *e;
-
- if ((argc < 2) || (argc > 3))
- return EC_ERROR_PARAM_COUNT;
-
- if (!strcasecmp(argv[1], "usart1"))
- usart = &usart1;
- else if (!strcasecmp(argv[1], "usart3"))
- usart = &usart3;
- else if (!strcasecmp(argv[1], "usart4"))
- usart = &usart4;
- else
- return EC_ERROR_PARAM1;
-
- baud = strtoi(argv[2], &e, 0);
- if (*e || baud < 0)
- return EC_ERROR_PARAM2;
-
- usart_set_baud(usart, baud);
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(baud, command_uart_baud,
- "usart[2|3|4] rate",
- "Set baud rate on uart");
-
-/******************************************************************************
- * Hold the usart pins low while disabling it, or return it to normal.
- */
-static int command_hold_usart_low(int argc, char **argv)
-{
- enum bus_lock *bus;
- enum gpio_signal rx;
-
- if (argc > 3 || argc < 2)
- return EC_ERROR_PARAM_COUNT;
-
- if (!strcasecmp(argv[1], "usart1")) {
- bus = &ec_pins;
- rx = GPIO_UART_EC_TX_DBG_RX_SDA;
- } else if (!strcasecmp(argv[1], "usart3")) {
- bus = &ap_pins;
- rx = GPIO_UART_AP_TX_DBG_RX_INA_SDA;
- } else if (!strcasecmp(argv[1], "usart4")) {
- bus = &h1_pins;
- rx = GPIO_UART_H1_TX_DBG_RX;
- } else {
- return EC_ERROR_PARAM1;
- }
-
- /* Updating the status of this port */
- if (argc == 3) {
- char *e;
- const int hold_low = strtoi(argv[2], &e, 0);
-
- if (*e || (hold_low < 0) || (hold_low > 1))
- return EC_ERROR_PARAM2;
-
- mutex_lock(&vref_bus_state_mutex);
-
- if (hold_low && *bus != BUS_UART_HELD) {
- /* Ensure no other use of these pins */
- if (*bus != BUS_UNLOCKED) {
- ccprintf("Cannot hold low! Pins busy: %s.\n",
- lock_to_string(*bus));
- goto busy_error_unlock;
- }
-
- /*
- * No need to shutdown UART, just de-mux the RX pin from
- * UART and change it to a GPIO temporarily
- */
- gpio_config_pin(MODULE_USART, rx, 0);
- gpio_set_flags(rx, GPIO_OUT_LOW);
-
- /* Update global uart state */
- *bus = BUS_UART_HELD;
- } else if (!hold_low && *bus == BUS_UART_HELD) {
- /*
- * Mux the RX pin back to GPIO mode
- */
- gpio_config_pin(MODULE_USART, rx, 1);
-
- /* Update global uart state */
- *bus = BUS_UNLOCKED;
- }
-
- mutex_unlock(&vref_bus_state_mutex);
- }
-
- /* Print status for get and set case. */
- ccprintf("USART status: %s\n",
- *bus == BUS_UART_HELD ? "held low" : "normal");
-
- return EC_SUCCESS;
-
-busy_error_unlock:
- mutex_unlock(&vref_bus_state_mutex);
- return EC_ERROR_BUSY;
-}
-DECLARE_CONSOLE_COMMAND(hold_usart_low, command_hold_usart_low,
- "usart[1|3|4] [0|1]?",
- "Get/set the hold-low state for usart port");
-
-
-/******************************************************************************
- * Console commands SPI programming
- */
-enum vref {
- OFF = 0,
- PP1800 = 1800,
- PP3300 = 3300,
-};
-
-static int command_enable_spi(int argc, char **argv)
-{
- static enum vref current_spi_vref_state;
-
- if (argc > 2)
- return EC_ERROR_PARAM_COUNT;
-
- /* Updating the state */
- if (argc == 2) {
- int i;
- char *e;
- const enum vref spi_vref = strtoi(argv[1], &e, 0);
- const enum gpio_signal uart_pins[] = {
- GPIO_UART_DBG_TX_H1_RX,
- GPIO_UART_H1_TX_DBG_RX,
- GPIO_UART_DBG_TX_EC_RX_SCL,
- GPIO_UART_EC_TX_DBG_RX_SDA,
- };
-
- if (*e)
- return EC_ERROR_PARAM1;
- if (spi_vref != OFF && spi_vref != PP1800 && spi_vref != PP3300)
- return EC_ERROR_PARAM1;
-
- mutex_lock(&vref_bus_state_mutex);
-
- if (vref_monitor_disable & ~VREF_MON_DIS_SPI_MODE) {
- ccprintf("Cannot update SPI with reset held.\n");
- goto busy_error_unlock;
- }
-
- if (current_spi_vref_state == spi_vref) {
- /* No change, do nothing */
- } else if (spi_vref == OFF) {
- /* We are transitioning from SPI to UART mode: */
- /* Disable level shifter pass through */
- gpio_set_level(GPIO_EN_MISO_MOSI_H1_UART, 0);
- gpio_set_level(GPIO_EN_CLK_CSN_EC_UART, 0);
-
- /* Disable SPI. Sets SPI pins to inputs. */
- usb_spi_enable(&usb_spi, 0);
-
- /* Set default state for chip select */
- gpio_set_flags(GPIO_SPI_CSN, GPIO_INPUT);
-
- /* Re-enable all UARTs pins we used. */
- for (i = 0; i < ARRAY_SIZE(uart_pins); ++i)
- gpio_config_pin(MODULE_USART, uart_pins[i], 1);
-
- /* Ensure DUT's muxes are switched to UART mode */
- gpio_set_level(GPIO_C2D2_MUX_UART_ODL, 0);
-
- /* Update state and defer Vrefs update */
- h1_pins = BUS_UNLOCKED;
- ec_pins = BUS_UNLOCKED;
- vref_monitor_disable &= ~VREF_MON_DIS_SPI_MODE;
- hook_call_deferred(&update_vrefs_and_shifters_data, 0);
- } else if (vref_monitor_disable & VREF_MON_DIS_SPI_MODE) {
- /* We are just changing voltages */
- gpio_set_level(GPIO_SEL_SPIVREF_H1VREF_3V3,
- spi_vref == PP3300);
- gpio_set_level(GPIO_SEL_SPIVREF_ECVREF_3V3,
- spi_vref == PP3300);
- } else {
- /* Ensure no other use of these pins */
- if (h1_pins != BUS_UNLOCKED ||
- ec_pins != BUS_UNLOCKED) {
- ccprintf(
- "Cannot enter SPI! H1 pins: %s; EC pins: %s.\n",
- lock_to_string(h1_pins),
- lock_to_string(ec_pins));
- goto busy_error_unlock;
- }
-
- /* We are transitioning from UART to SPI mode: */
- /* Turn off comparator interrupt for Vref detection */
- STM32_EXTI_IMR &= ~EXTI_COMP2_EVENT;
-
- /* Disable level shifters to avoid glitching output */
- gpio_set_level(GPIO_EN_MISO_MOSI_H1_UART, 0);
- gpio_set_level(GPIO_EN_CLK_CSN_EC_UART, 0);
-
- /*
- * De-select UART on all UARTs pins we are using to
- * avoid drive fights with SPI pins.
- */
- for (i = 0; i < ARRAY_SIZE(uart_pins); ++i)
- gpio_config_pin(MODULE_USART, uart_pins[i], 0);
-
- /* Set default state for chip select */
- gpio_set_flags(GPIO_SPI_CSN, GPIO_OUT_HIGH);
-
- /* Enable SPI. Sets SPI pins to SPI alternate mode. */
- usb_spi_enable(&usb_spi, 1);
-
- /* Set requested Vref voltage */
- gpio_set_level(GPIO_SEL_SPIVREF_H1VREF_3V3,
- spi_vref == PP3300);
- gpio_set_level(GPIO_SEL_SPIVREF_ECVREF_3V3,
- spi_vref == PP3300);
-
- /* Ensure DUT's muxes are switched to SPI mode */
- gpio_set_level(GPIO_C2D2_MUX_UART_ODL, 1);
-
- /* Enable level shifters passthrough */
- gpio_set_level(GPIO_EN_MISO_MOSI_H1_UART, 1);
- gpio_set_level(GPIO_EN_CLK_CSN_EC_UART, 1);
-
- h1_pins = BUS_SPI;
- ec_pins = BUS_SPI;
- vref_monitor_disable |= VREF_MON_DIS_SPI_MODE;
- }
-
- current_spi_vref_state = spi_vref;
-
- mutex_unlock(&vref_bus_state_mutex);
- }
-
- /* Print status for get and set case. */
- ccprintf("SPI Vref: %d\n", current_spi_vref_state);
-
- return EC_SUCCESS;
-
-busy_error_unlock:
- mutex_unlock(&vref_bus_state_mutex);
- return EC_ERROR_BUSY;
-}
-DECLARE_CONSOLE_COMMAND(enable_spi, command_enable_spi,
- "[0|1800|3300]?",
- "Get/set the SPI Vref");
-
-/******************************************************************************
- * Console commands I2c programming mode
- */
-static bool is_ec_i2c_enabled(void)
-{
- return ec_pins == BUS_I2C;
-}
-
-static inline enum i2c_freq to_i2c_freq(int kbps)
-{
- switch (kbps) {
- case 400:
- return I2C_FREQ_400KHZ;
- case 1000:
- return I2C_FREQ_1000KHZ;
- default:
- return I2C_FREQ_100KHZ;
- }
-}
-
-static inline int to_kbps(enum i2c_freq freq)
-{
- switch (freq) {
- case I2C_FREQ_400KHZ:
- return 400;
- case I2C_FREQ_1000KHZ:
- return 1000;
- default:
- return 100;
- }
-}
-
-static int command_enable_i2c(int argc, char **argv)
-{
- int i2c_index;
- enum bus_lock *bus;
- enum gpio_signal sda, scl;
-
- if (argc > 3 || argc < 2)
- return EC_ERROR_PARAM_COUNT;
-
- if (!strcasecmp(argv[1], "ec")) {
- bus = &ec_pins;
- i2c_index = I2C_PORT_EC;
- sda = GPIO_UART_EC_TX_DBG_RX_SDA;
- scl = GPIO_UART_DBG_TX_EC_RX_SCL;
-
- } else if (!strcasecmp(argv[1], "ap")) {
- bus = &ap_pins;
- i2c_index = I2C_PORT_AUX;
- sda = GPIO_UART_AP_TX_DBG_RX_INA_SDA;
- scl = GPIO_UART_DBG_TX_AP_RX_INA_SCL;
- } else {
- return EC_ERROR_PARAM1;
- }
-
- /* Updating the state */
- if (argc == 3) {
- char *e;
- const int speed = strtoi(argv[2], &e, 0);
-
- if (*e)
- return EC_ERROR_PARAM2;
- if (speed != 0 && speed != 100 && speed != 400 && speed != 1000)
- return EC_ERROR_PARAM2;
-
- mutex_lock(&vref_bus_state_mutex);
-
- if (speed != 0 && *bus != BUS_I2C) {
- /* Ensure no other use of these pins */
- if (*bus != BUS_UNLOCKED) {
- ccprintf("Cannot enable i2c! Pin busy: %s.\n",
- lock_to_string(*bus));
- goto busy_error_unlock;
- }
-
- /* Change alternate mode to I2C */
- gpio_config_pin(MODULE_I2C, sda, 1);
- gpio_config_pin(MODULE_I2C, scl, 1);
-
- /* Update state */
- *bus = BUS_I2C;
- } else if (speed == 0 && *bus == BUS_I2C) {
- /* Update back to default UART mode */
- gpio_config_pin(MODULE_USART, sda, 1);
- gpio_config_pin(MODULE_USART, scl, 1);
-
- /* Update state */
- *bus = BUS_UNLOCKED;
- }
-
- mutex_unlock(&vref_bus_state_mutex);
-
- /* If we have a non-zero speed, then set frequency */
- if (speed)
- i2c_set_freq(i2c_index, to_i2c_freq(speed));
- }
-
- /* Print status for get and set case. */
- ccprintf("I2C speed kbps: %d\n",
- *bus == BUS_I2C ? to_kbps(i2c_get_freq(i2c_index)) : 0);
-
- return EC_SUCCESS;
-
-busy_error_unlock:
- mutex_unlock(&vref_bus_state_mutex);
- return EC_ERROR_BUSY;
-}
-DECLARE_CONSOLE_COMMAND(enable_i2c, command_enable_i2c,
- "[ec|ap] [0|100|400|1000]?",
- "Get/set the I2C speed in kbps for EC and AP pins");
-
-/******************************************************************************
- * Console commands for asserting H1 reset and EC Power button
- */
-
-static int command_vref_alternate(int argc, char **argv,
- const enum gpio_signal vref_signal,
- const enum gpio_signal en_signal,
- const int state_flag,
- const char *const print_name)
-{
- if (argc > 2)
- return EC_ERROR_PARAM_COUNT;
-
- /* Updating the state */
- if (argc == 2) {
- char *e;
- const int hold_low = strtoi(argv[1], &e, 0);
-
- if (*e || (hold_low < 0) || (hold_low > 1))
- return EC_ERROR_PARAM1;
-
- mutex_lock(&vref_bus_state_mutex);
-
- if (vref_monitor_disable & VREF_MON_DIS_SPI_MODE) {
- ccprintf("Cannot hold pin while in SPI mode.\n");
- goto busy_error_unlock;
- }
-
- if (!!(vref_monitor_disable & state_flag) == hold_low) {
- /* No change, do nothing */
- } else if (hold_low) {
- /* Turn off comparator interrupt for vref detection */
- STM32_EXTI_IMR &= ~EXTI_COMP2_EVENT;
- /* Start holding the ODL signal line low */
- gpio_set_flags(vref_signal, GPIO_OUT_LOW);
- /* Ensure the switch is connecting STM to DUT */
- gpio_set_level(en_signal, 1);
- vref_monitor_disable |= state_flag;
- } else {
- /* Return GPIO back to input for vref detection */
- gpio_set_flags(vref_signal, GPIO_INPUT);
- /* Transitioning out of hold, correct vrefs */
- hook_call_deferred(&update_vrefs_and_shifters_data, 0);
- vref_monitor_disable &= ~state_flag;
- }
-
- mutex_unlock(&vref_bus_state_mutex);
- }
-
- /* Print status for both get and set case */
- ccprintf("%s held: %s\n", print_name,
- vref_monitor_disable & state_flag ? "yes" : "no");
-
-
- return EC_SUCCESS;
-
-busy_error_unlock:
- mutex_unlock(&vref_bus_state_mutex);
- return EC_ERROR_BUSY;
-}
-
-static int command_pwr_button(int argc, char **argv)
-{
- return command_vref_alternate(argc, argv,
- GPIO_SPIVREF_HOLDN_ECVREF_H1_PWRBTN_ODL,
- GPIO_EN_SPIVREF_HOLDN_ECVREF_H1_PWRBTN,
- VREF_MON_DIS_EC_PWR_HELD, "Power button");
-}
-DECLARE_CONSOLE_COMMAND(pwr_button, command_pwr_button,
- "[0|1]?",
- "Get/set the power button state");
-
-static int command_h1_reset(int argc, char **argv)
-{
- return command_vref_alternate(argc, argv,
- GPIO_SPIVREF_RSVD_H1VREF_H1_RST_ODL,
- GPIO_EN_SPIVREF_RSVD_H1VREF_H1_RST,
- VREF_MON_DIS_H1_RST_HELD, "H1 reset");
-}
-DECLARE_CONSOLE_COMMAND(h1_reset, command_h1_reset,
- "[0|1]?",
- "Get/set the h1 reset state");
-
-
-/******************************************************************************
- * Vref detection logic
- */
-
-/* Set by update and read by console command that polls for Vref presence */
-static enum vref h1_vref;
-static enum vref ec_vref;
-
-static int command_h1_vref_present(int argc, char **argv)
-{
- ccprintf("H1 Vref: %s\n", h1_vref ? "on" : "off");
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(h1_vref, command_h1_vref_present,
- "",
- "Get if the h1 vref is present");
-
-/* Voltage thresholds for rail detection */
-#define VREF_3300_MIN_MV 2300
-#define VREF_1800_MIN_MV 1500
-
-static enum vref get_vref(enum adc_channel chan)
-{
- const int adc = adc_read_channel(chan);
-
- if (adc == ADC_READ_ERROR)
- return OFF;
- else if (adc > VREF_3300_MIN_MV)
- return PP3300;
- else if (adc > VREF_1800_MIN_MV)
- return PP1800;
- else
- return OFF;
-}
-
-static inline void drain_vref_lines(void)
-{
- mutex_lock(&vref_bus_state_mutex);
- if (vref_monitor_disable) {
- mutex_unlock(&vref_bus_state_mutex);
- return;
- }
-
- /*
- * Disconnect level shifters to prevent any leakage on DUT side while we
- * are draining Vref lines for a proper read.
- */
- gpio_set_level(GPIO_EN_MISO_MOSI_H1_UART, 0);
- gpio_set_level(GPIO_EN_CLK_CSN_EC_UART, 0);
-
- /* Disconnect Vref switches */
- gpio_set_level(GPIO_EN_SPIVREF_RSVD_H1VREF_H1_RST, 0);
- gpio_set_level(GPIO_EN_SPIVREF_HOLDN_ECVREF_H1_PWRBTN, 0);
-
- /* Actively pull down floating voltage */
- gpio_set_flags(GPIO_SPIVREF_RSVD_H1VREF_H1_RST_ODL, GPIO_OUT_LOW);
- gpio_set_flags(GPIO_SPIVREF_HOLDN_ECVREF_H1_PWRBTN_ODL, GPIO_OUT_LOW);
-
- /* Ensure we have enough time to drain line. Not in mutex */
- mutex_unlock(&vref_bus_state_mutex);
- msleep(5);
- mutex_lock(&vref_bus_state_mutex);
- if (vref_monitor_disable) {
- mutex_unlock(&vref_bus_state_mutex);
- /*
- * One or both of the Vref signals will still be low. This is
- * okay since anyone that just took over these signal will
- * also take over the enabled switch signals appropriately.
- *
- * If no one takes over the Vref signal, then the switch will
- * remain off and we won't pull down the DUT side.
- */
- return;
- }
-
- /* Reset Vref GPIOs back to input for Vref detection */
- gpio_set_flags(GPIO_SPIVREF_RSVD_H1VREF_H1_RST_ODL, GPIO_INPUT);
- gpio_set_flags(GPIO_SPIVREF_HOLDN_ECVREF_H1_PWRBTN_ODL, GPIO_INPUT);
-
- /* Reconnect Vref switches */
- gpio_set_level(GPIO_EN_SPIVREF_RSVD_H1VREF_H1_RST, 1);
- gpio_set_level(GPIO_EN_SPIVREF_HOLDN_ECVREF_H1_PWRBTN, 1);
-
- mutex_unlock(&vref_bus_state_mutex);
- /* Ensure we have enough time to charge line up to real voltage */
- msleep(10);
-}
-
-/* This if forward declared as a deferred function above */
-static void update_vrefs_and_shifters(void)
-{
- static enum vref prev_h1_vref, prev_ec_vref;
-
- int adc_mv;
-
- /* Disable Vref comparator interrupt before draining and measuring */
- STM32_EXTI_IMR &= ~EXTI_COMP2_EVENT;
-
- drain_vref_lines();
-
- /* Ensure we aren't actively using Vref lines for other purposes */
- mutex_lock(&vref_bus_state_mutex);
- if (vref_monitor_disable) {
- mutex_unlock(&vref_bus_state_mutex);
- return;
- }
-
- /* Only get the EC Vref if H1 Vref is on */
- h1_vref = get_vref(ADC_H1_SPI_VREF);
- ec_vref = (h1_vref == OFF) ? OFF : get_vref(ADC_EC_SPI_VREF);
-
- /*
- * It is possible that the user is physically holding the power button
- * while inserting the c2d2 connector on the DUT. In that case the
- * EC Vref (shared with power button ODL) will be OFF while H1 Vref is
- * on. We won't get a valid read on the EC Vref, so we just keep trying
- * to read in the background until we get out of that state.
- */
- if (h1_vref != OFF && ec_vref == OFF) {
- CPRINTS("Looks like DUT power button is held. Will try again.");
- hook_call_deferred(&update_vrefs_and_shifters_data, 100 * MSEC);
- }
-
- /* Update C2D2 Vref and level shifters based on ADC Vref values */
- gpio_set_level(GPIO_SEL_SPIVREF_H1VREF_3V3, h1_vref == PP3300);
- gpio_set_level(GPIO_EN_MISO_MOSI_H1_UART, h1_vref != OFF);
- gpio_set_level(GPIO_SEL_SPIVREF_ECVREF_3V3, ec_vref == PP3300);
- gpio_set_level(GPIO_EN_CLK_CSN_EC_UART, ec_vref != OFF);
-
- /* Set up DAC2 for comparison on H1 Vref */
- adc_mv = (h1_vref == PP3300) ? VREF_3300_MIN_MV : VREF_1800_MIN_MV;
- /* 8-bit DAC based off of 3.3V rail */
- STM32_DAC_DHR8R2 = 256 * adc_mv / 3300;
-
- /* Clear any pending interrupts and enabled H1 Vref comparator */
- STM32_EXTI_PR = EXTI_COMP2_EVENT;
- STM32_EXTI_IMR |= EXTI_COMP2_EVENT;
-
- mutex_unlock(&vref_bus_state_mutex);
-
- if (prev_h1_vref != h1_vref || prev_ec_vref != ec_vref)
- CPRINTS("Vref updated. H1: %d -> %d; EC: %d -> %d",
- prev_h1_vref, h1_vref, prev_ec_vref, ec_vref);
-
- /*
- * Transitioning from 3.3V to 1.8V should not happen and most likely
- * indicates a leakage path on the DUT being backpowered from C2D2 or
- * something else.
- */
- if (prev_h1_vref == PP3300 && h1_vref == PP1800)
- CPRINTS("Check for H1 Leakage!!!");
- if (prev_ec_vref == PP3300 && ec_vref == PP1800)
- CPRINTS("Check for EC Leakage!!!");
- prev_h1_vref = h1_vref;
- prev_ec_vref = ec_vref;
-}
-
-void set_up_comparator(void)
-{
- /* Overwrite any previous values. This is the only comparator usage */
- STM32_COMP_CSR = STM32_COMP_CMP2HYST_HI |
- STM32_COMP_CMP2OUTSEL_NONE |
- STM32_COMP_CMP2INSEL_INM5 | /* Watch DAC_OUT2 (PA5) */
- STM32_COMP_CMP2MODE_LSPEED |
- STM32_COMP_CMP2EN;
-
- /* Set Falling and Rising interrupts for COMP2 */
- STM32_EXTI_FTSR |= EXTI_COMP2_EVENT;
- STM32_EXTI_RTSR |= EXTI_COMP2_EVENT;
-
- /* Interrupt for COMP2 enabled when setting Vrefs */
-
- /* Ensure IRQ will get called when comp module enables interrupt */
- task_enable_irq(STM32_IRQ_COMP);
-}
-
-static void h1_vref_change(void)
-{
- /* Ack the interrupt */
- STM32_EXTI_PR = EXTI_COMP2_EVENT;
-
- /* Disable interrupt, setting Vref will enable again */
- STM32_EXTI_IMR &= ~EXTI_COMP2_EVENT;
-
- hook_call_deferred(&update_vrefs_and_shifters_data, 0);
-}
-DECLARE_IRQ(STM32_IRQ_COMP, h1_vref_change, 1);
-
-/******************************************************************************
- * Initialize board.
- */
-static void board_init(void)
-{
- /* USB to serial queues */
- queue_init(&usart1_to_usb);
- queue_init(&usb_to_usart1);
- queue_init(&usart3_to_usb);
- queue_init(&usb_to_usart3);
- queue_init(&usart4_to_usb);
- queue_init(&usb_to_usart4);
-
- /* UART init */
- usart_init(&usart1);
- usart_init(&usart3);
- usart_init(&usart4);
-
- /* Enabled DAC, when setting Vref, this voltage is adjusted */
- STM32_DAC_CR = STM32_DAC_CR_EN2;
-
- /* Set Vrefs and enabled level shifters */
- set_up_comparator();
-
- /*
- * Ensure we set up vrefs at least once. Don't call here because
- * there are delays in the reads
- */
- hook_call_deferred(&update_vrefs_and_shifters_data, 0);
-}
-DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
-
-/******************************************************************************
- * Turn down USART before jumping to RW.
- */
-static void board_jump(void)
-{
- /* Put the board into safer state while jumping */
- gpio_set_level(GPIO_EN_SPIVREF_RSVD_H1VREF_H1_RST, 0);
- gpio_set_level(GPIO_EN_SPIVREF_HOLDN_ECVREF_H1_PWRBTN, 0);
- gpio_set_level(GPIO_EN_CLK_CSN_EC_UART, 0);
- gpio_set_level(GPIO_EN_MISO_MOSI_H1_UART, 0);
-
- /*
- * Shutdown all UARTS before jumping to RW. They will be reinitialized
- * after the jump is successful.
- */
- usart_shutdown(&usart1);
- usart_shutdown(&usart3);
- usart_shutdown(&usart4);
-
- /* Ensure SPI2 is disabled as well */
- usb_spi_enable(&usb_spi, 0);
-}
-DECLARE_HOOK(HOOK_SYSJUMP, board_jump, HOOK_PRIO_DEFAULT);