diff options
author | Nick Sanders <nsanders@chromium.org> | 2017-02-03 11:54:22 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-05-12 03:25:39 -0700 |
commit | 8df3b161e946b2b9aaa5e475766864d3fdb2a9ca (patch) | |
tree | 9bdd6dba80502c56582008c22a2bb78117fd4d0d | |
parent | 44b9f9df83b3c54b46eb09f593cce32fe822f30a (diff) | |
download | chrome-ec-8df3b161e946b2b9aaa5e475766864d3fdb2a9ca.tar.gz |
mn50: initial checkin
This firmware supports a board used to initialize firmware on new cr50
parts.
BUG=b:36910757
BRANCH=None
TEST=boots on scribe board, spi/usb/uart/i2c functionality works.
TEST=cr50 boots on reef, CCD EC+AP SPI/UARTS work
Change-Id: I48818225393a6fc0db0c30bc79ad9787de608361
Reviewed-on: https://chromium-review.googlesource.com/437627
Commit-Ready: Nick Sanders <nsanders@chromium.org>
Tested-by: Nick Sanders <nsanders@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r-- | board/cr50/board.h | 9 | ||||
-rw-r--r-- | board/mn50/board.c | 265 | ||||
-rw-r--r-- | board/mn50/board.h | 188 | ||||
-rw-r--r-- | board/mn50/build.mk | 54 | ||||
-rw-r--r-- | board/mn50/ec.tasklist | 21 | ||||
-rw-r--r-- | board/mn50/gpio.inc | 116 | ||||
-rw-r--r-- | board/mn50/usb_spi.c | 84 | ||||
-rw-r--r-- | chip/g/gpio.c | 25 | ||||
-rw-r--r-- | chip/g/spi_master.c | 32 | ||||
-rw-r--r-- | chip/g/system.c | 7 | ||||
-rw-r--r-- | chip/g/usart.c | 34 | ||||
-rw-r--r-- | chip/g/usb_spi.c | 22 | ||||
-rw-r--r-- | chip/g/usb_spi.h | 10 |
13 files changed, 832 insertions, 35 deletions
diff --git a/board/cr50/board.h b/board/cr50/board.h index 85fa1b2f11..601f9a7423 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -87,6 +87,8 @@ #define CONFIG_STREAM_USART #define CONFIG_STREAM_USB +#define CONFIG_STREAM_USART1 +#define CONFIG_STREAM_USART2 /* Enable Case Closed Debugging */ #define CONFIG_CASE_CLOSED_DEBUG @@ -155,13 +157,6 @@ enum device_type { DEVICE_COUNT }; -/* USB SPI device indexes */ -enum usb_spi { - USB_SPI_DISABLE = 0, - USB_SPI_AP, - USB_SPI_EC, -}; - /* NVMem variables. */ enum nvmem_vars { NVMEM_VAR_CONSOLE_LOCKED = 0, diff --git a/board/mn50/board.c b/board/mn50/board.c new file mode 100644 index 0000000000..9833b48e62 --- /dev/null +++ b/board/mn50/board.c @@ -0,0 +1,265 @@ +/* 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 <endian.h> + +#include "case_closed_debug.h" +#include "clock.h" +#include "common.h" +#include "console.h" +#include "dcrypto/dcrypto.h" +#include "device_state.h" +#include "ec_version.h" +#include "extension.h" +#include "flash.h" +#include "flash_config.h" +#include "gpio.h" +#include "hooks.h" +#include "i2c.h" +#include "ina2xx.h" +#include "init_chip.h" +#include "nvmem.h" +#include "nvmem_vars.h" +#include "registers.h" +#include "signed_header.h" +#include "spi.h" +#include "system.h" +#include "task.h" +#include "trng.h" +#include "uartn.h" +#include "usb_api.h" +#include "usb_descriptor.h" +#include "usb_hid.h" +#include "usb_spi.h" +#include "usb_i2c.h" +#include "util.h" + +/* Define interrupt and gpio structs */ +#include "gpio_list.h" + +#include "cryptoc/sha.h" + +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) + +/* NvMem user buffer lengths table */ +uint32_t nvmem_user_sizes[NVMEM_NUM_USERS] = { + NVMEM_CR50_SIZE +}; + +/* I2C Port definition. No GPIO access. */ +const struct i2c_port_t i2c_ports[] = { + {"master", I2C_PORT_MASTER, 100, 0, 0}, +}; +const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); + + +/*****************************************************************************/ +/* */ +#include "gpio.wrap" + +static void init_interrupts(void) +{ + int i; + uint32_t exiten = GREG32(PINMUX, EXITEN0); + + /* Clear wake pin interrupts */ + GREG32(PINMUX, EXITEN0) = 0; + GREG32(PINMUX, EXITEN0) = exiten; + + /* Enable all GPIO interrupts */ + for (i = 0; i < gpio_ih_count; i++) + if (gpio_list[i].flags & GPIO_INT_ANY) + gpio_enable_interrupt(i); +} + +void decrement_retry_counter(void) +{ + uint32_t counter = GREG32(PMU, LONG_LIFE_SCRATCH0); + + if (counter) { + GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG0, 1); + GREG32(PMU, LONG_LIFE_SCRATCH0) = counter - 1; + GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG0, 0); + } +} + +void ccd_phy_init(int none) +{ + usb_select_phy(USB_SEL_PHY1); + + usb_init(); +} + +void usb_i2c_board_disable(void) +{ +} + +int usb_i2c_board_enable(void) +{ + return EC_SUCCESS; +} + +/* Initialize board. */ +static void board_init(void) +{ + /* + * Deep sleep resets should be considered valid and should not impact + * the rolling reboot count. + */ + if (system_get_reset_flags() & RESET_FLAG_HIBERNATE) + decrement_retry_counter(); + init_interrupts(); + init_trng(); + init_jittery_clock(1); + init_runlevel(PERMISSION_MEDIUM); + /* Initialize NvMem partitions */ + nvmem_init(); + /* Initialize the persistent storage. */ + initvars(); + + /* Indication that firmware is running, for debug purposes. */ + GREG32(PMU, PWRDN_SCRATCH16) = 0xCAFECAFE; + + /* Enable USB / CCD */ + ccd_set_mode(CCD_MODE_ENABLED); + uartn_enable(UART_AP); + + /* Calibrate INA0 (VBUS) with 1mA/LSB scale */ + i2cm_init(); + ina2xx_init(0, 0x8000, INA2XX_CALIB_1MA(150 /*mOhm*/)); + ina2xx_init(1, 0x8000, INA2XX_CALIB_1MA(150 /*mOhm*/)); + ina2xx_init(4, 0x8000, INA2XX_CALIB_1MA(150 /*mOhm*/)); +} +DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); + +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("Mn50"), + [USB_STR_VERSION] = USB_STRING_DESC(CROS_EC_VERSION32), + [USB_STR_CONSOLE_NAME] = USB_STRING_DESC("Shell"), + [USB_STR_BLOB_NAME] = USB_STRING_DESC("Blob"), + [USB_STR_AP_NAME] = USB_STRING_DESC("DUT UART"), + [USB_STR_UPGRADE_NAME] = USB_STRING_DESC("Firmware upgrade"), + [USB_STR_SPI_NAME] = USB_STRING_DESC("SPI"), + [USB_STR_SERIALNO] = USB_STRING_DESC(DEFAULT_SERIALNO), + [USB_STR_I2C_NAME] = USB_STRING_DESC("I2C"), +}; +BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT); + +/* SPI devices */ +/* port 0, 40MHz / (16 + 1) = 2.3MHz SPI, no soft CS */ +const struct spi_device_t spi_devices[] = { + [CONFIG_SPI_FLASH_PORT] = {0, 16, GPIO_COUNT} +}; +const unsigned int spi_devices_used = ARRAY_SIZE(spi_devices); + +int flash_regions_to_enable(struct g_flash_region *regions, + int max_regions) +{ + /* + * This needs to account for two regions: the "other" RW partition and + * the NVRAM in TOP_B. + * + * When running from RW_A the two regions are adjacent, but it is + * simpler to keep function logic the same and always configure two + * separate regions. + */ + + if (max_regions < 3) + return 0; + + /* Enable access to the other RW image... */ + if (system_get_image_copy() == SYSTEM_IMAGE_RW) + /* Running RW_A, enable RW_B */ + regions[0].reg_base = CONFIG_MAPPED_STORAGE_BASE + + CONFIG_RW_B_MEM_OFF; + else + /* Running RW_B, enable RW_A */ + regions[0].reg_base = CONFIG_MAPPED_STORAGE_BASE + + CONFIG_RW_MEM_OFF; + /* Size is the same */ + regions[0].reg_size = CONFIG_RW_SIZE; + regions[0].reg_perms = FLASH_REGION_EN_ALL; + + /* Enable access to the NVRAM partition A region */ + regions[1].reg_base = CONFIG_MAPPED_STORAGE_BASE + + CONFIG_FLASH_NVMEM_OFFSET_A; + regions[1].reg_size = NVMEM_PARTITION_SIZE; + regions[1].reg_perms = FLASH_REGION_EN_ALL; + + /* Enable access to the NVRAM partition B region */ + regions[2].reg_base = CONFIG_MAPPED_STORAGE_BASE + + CONFIG_FLASH_NVMEM_OFFSET_B; + regions[2].reg_size = NVMEM_PARTITION_SIZE; + regions[2].reg_perms = FLASH_REGION_EN_ALL; + + return 3; +} + + +/* Determine key type based on the key ID. */ +static const char *key_type(uint32_t key_id) +{ + + /* + * It is a mere convention, but all prod keys are required to have key + * IDs such, that bit D2 is set, and all dev keys are required to have + * key IDs such, that bit D2 is not set. + * + * This convention is enforced at the key generation time. + */ + if (key_id & (1 << 2)) + return "prod"; + else + return "dev"; +} + +static int command_sysinfo(int argc, char **argv) +{ + enum system_image_copy_t active; + uintptr_t vaddr; + const struct SignedHeader *h; + + ccprintf("Reset flags: 0x%08x (", system_get_reset_flags()); + system_print_reset_flags(); + ccprintf(")\n"); + + ccprintf("Chip: %s %s %s\n", system_get_chip_vendor(), + system_get_chip_name(), system_get_chip_revision()); + + active = system_get_ro_image_copy(); + vaddr = get_program_memory_addr(active); + h = (const struct SignedHeader *)vaddr; + ccprintf("RO keyid: 0x%08x(%s)\n", h->keyid, key_type(h->keyid)); + + active = system_get_image_copy(); + vaddr = get_program_memory_addr(active); + h = (const struct SignedHeader *)vaddr; + ccprintf("RW keyid: 0x%08x(%s)\n", h->keyid, key_type(h->keyid)); + + ccprintf("DEV_ID: 0x%08x 0x%08x\n", + GREG32(FUSE, DEV_ID0), GREG32(FUSE, DEV_ID1)); + + return EC_SUCCESS; +} +DECLARE_SAFE_CONSOLE_COMMAND(sysinfo, command_sysinfo, + NULL, + "Print system info"); + +/* + * SysInfo command: + * There are no input args. + * Output is this struct, all fields in network order. + */ +struct sysinfo_s { + uint32_t ro_keyid; + uint32_t rw_keyid; + uint32_t dev_id0; + uint32_t dev_id1; +} __packed; + + + diff --git a/board/mn50/board.h b/board/mn50/board.h new file mode 100644 index 0000000000..92b92c877b --- /dev/null +++ b/board/mn50/board.h @@ -0,0 +1,188 @@ +/* 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. + */ + +#ifndef __CROS_EC_BOARD_H +#define __CROS_EC_BOARD_H + +/* + * Make sure we don't trigger the watchdog accidentally if the timing + * is just a little off. + */ +#undef CONFIG_WATCHDOG_PERIOD_MS +#define CONFIG_WATCHDOG_PERIOD_MS 5000 + +#define CR50_DEV + +/* Features that we don't want */ +#undef CONFIG_CMD_LID_ANGLE +#undef CONFIG_CMD_POWERINDEBUG +#undef CONFIG_DMA_DEFAULT_HANDLERS +#undef CONFIG_FMAP +#undef CONFIG_HIBERNATE +#undef CONFIG_LID_SWITCH +#undef CONFIG_CMD_SYSINFO +#undef CONFIG_CMD_SYSJUMP +#undef CONFIG_CMD_SYSLOCK + +#ifndef CR50_DEV +/* Disable stuff that should only be in debug builds */ +#undef CONFIG_CMD_MD +#undef CONFIG_CMD_RW +#undef CONFIG_CMD_SLEEPMASK +#undef CONFIG_CMD_WAITMS +#undef CONFIG_FLASH +#endif + +/* Flash configuration */ +#undef CONFIG_FLASH_PSTATE +/* TODO(crosbug.com/p/44745): Bringup only! Do the right thing for real! */ +#define CONFIG_WP_ALWAYS +/* TODO(crosbug.com/p/44745): For debugging only */ +#define CONFIG_CMD_FLASH + +/* We're using TOP_A for partition 0, TOP_B for partition 1 */ +#define CONFIG_FLASH_NVMEM +/* Offset to start of NvMem area from base of flash */ +#define CONFIG_FLASH_NVMEM_OFFSET_A (CFG_TOP_A_OFF) +#define CONFIG_FLASH_NVMEM_OFFSET_B (CFG_TOP_B_OFF) +/* Address of start of Nvmem area */ +#define CONFIG_FLASH_NVMEM_BASE_A (CONFIG_PROGRAM_MEMORY_BASE + \ + CONFIG_FLASH_NVMEM_OFFSET_A) +#define CONFIG_FLASH_NVMEM_BASE_B (CONFIG_PROGRAM_MEMORY_BASE + \ + CONFIG_FLASH_NVMEM_OFFSET_B) +/* Size partition in NvMem */ +#define NVMEM_PARTITION_SIZE CFG_TOP_SIZE +/* Size in bytes of NvMem area */ +#define CONFIG_FLASH_NVMEM_SIZE (CFG_TOP_SIZE * NVMEM_NUM_PARTITIONS) +/* Enable <key, value> variable support. */ +#define CONFIG_FLASH_NVMEM_VARS +#define NVMEM_CR50_SIZE 272 +#define CONFIG_FLASH_NVMEM_VARS_USER_SIZE NVMEM_CR50_SIZE + +/* Allow multiple concurrent memory allocations. */ +#define CONFIG_MALLOC + +/* USB configuration */ +#define CONFIG_USB +#define CONFIG_USB_CONSOLE +#define CONFIG_USB_I2C +#define CONFIG_USB_INHIBIT_INIT +#define CONFIG_USB_SELECT_PHY +#define CONFIG_USB_SPI +#define CONFIG_USB_SERIALNO +#define DEFAULT_SERIALNO "0" +#define CONFIG_CMD_GPIO_EXTENDED + +#define CONFIG_STREAM_USART +#define CONFIG_STREAM_USB +#define CONFIG_STREAM_USART1 + +/* Enable Case Closed Debugging */ +#define CONFIG_CASE_CLOSED_DEBUG + +#define CONFIG_USB_PID 0x502a +#define CONFIG_USB_SELF_POWERED + +#undef CONFIG_USB_MAXPOWER_MA +#define CONFIG_USB_MAXPOWER_MA 0 + +/* Enable SPI Master (SPI) module */ +#define CONFIG_SPI_MASTER +#define CONFIG_SPI_MASTER_NO_CS_GPIOS +#define CONFIG_SPI_MASTER_CONFIGURE_GPIOS +#define CONFIG_SPI_FLASH_PORT 0 + +/* We don't need to send events to the AP */ +#undef CONFIG_HOSTCMD_EVENTS + +#define CONFIG_CONSOLE_COMMAND_FLAGS + +/* Include crypto stuff, both software and hardware. */ +#define CONFIG_DCRYPTO +#define CONFIG_UPTO_SHA512 + +#ifndef __ASSEMBLER__ + +#include "gpio_signal.h" + +/* USB string indexes */ +enum usb_strings { + USB_STR_DESC = 0, + USB_STR_VENDOR, + USB_STR_PRODUCT, + USB_STR_VERSION, + USB_STR_CONSOLE_NAME, + USB_STR_BLOB_NAME, + USB_STR_HID_KEYBOARD_NAME, + USB_STR_AP_NAME, + USB_STR_UPGRADE_NAME, + USB_STR_SPI_NAME, + USB_STR_SERIALNO, + USB_STR_I2C_NAME, + + USB_STR_COUNT +}; + +void post_reboot_request(void); +void ccd_force_enable(void); + +#endif /* !__ASSEMBLER__ */ + +/* USB interface indexes (use define rather than enum to expand them) */ +#define USB_IFACE_CONSOLE 0 +#define USB_IFACE_AP 1 +#define USB_IFACE_UPGRADE 2 +#define USB_IFACE_SPI 3 +#define USB_IFACE_I2C 4 +#define USB_IFACE_COUNT 5 + +/* USB endpoint indexes (use define rather than enum to expand them) */ +#define USB_EP_CONTROL 0 +#define USB_EP_CONSOLE 1 +#define USB_EP_AP 2 +#define USB_EP_UPGRADE 3 +#define USB_EP_SPI 4 +#define USB_EP_I2C 5 +#define USB_EP_COUNT 6 + +/* UART indexes (use define rather than enum to expand them) */ +#define UART_CR50 0 +#define UART_AP 1 + +#define UARTN UART_CR50 + +/* TODO(crosbug.com/p/56540): Remove this when UART0_RX works everywhere */ +#define GC_UART0_RX_DISABLE + +#define CC_DEFAULT (CC_ALL & ~CC_MASK(CC_TPM)) + +/* Nv Memory users */ +#ifndef __ASSEMBLER__ +enum nvmem_users { + NVMEM_CR50 = 0, + NVMEM_NUM_USERS +}; +#endif + +#define CONFIG_FLASH_NVMEM_VARS_USER_NUM NVMEM_CR50 + +/* + * Let's be on the lookout for stack overflow, while debugging. + * + * TODO(vbendeb): remove this before finalizing the code. + */ +#define CONFIG_DEBUG_STACK_OVERFLOW +#define CONFIG_RW_B + +/* Firmware upgrade options. */ +#define CONFIG_NON_HC_FW_UPDATE +#define CONFIG_USB_FW_UPDATE + +#define CONFIG_I2C +#define CONFIG_I2C_MASTER +#define I2C_PORT_MASTER 0 +#define CONFIG_INA231 + +#endif /* __CROS_EC_BOARD_H */ diff --git a/board/mn50/build.mk b/board/mn50/build.mk new file mode 100644 index 0000000000..2f52cfa576 --- /dev/null +++ b/board/mn50/build.mk @@ -0,0 +1,54 @@ +# -*- 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 build requirements + +# Define the SoC used by this board +CHIP:=g +CHIP_FAMILY:=cr50 + +# This file is included twice by the Makefile, once to determine the CHIP info +# and then again after defining all the CONFIG_ and HAS_TASK variables. We use +# a guard so that recipe definitions and variable extensions only happen the +# second time. +ifeq ($(BOARD_MK_INCLUDED_ONCE),) +BOARD_MK_INCLUDED_ONCE=1 +SIG_EXTRA = --cros +else + +# Need to generate a .hex file +all: hex + +# The simulator components have their own subdirectory +CFLAGS += -I$(realpath chip/$(CHIP)/dcrypto) +dirs-y += chip/$(CHIP)/dcrypto + +# Objects that we need to build +board-y = board.o +board-${CONFIG_USB_SPI} += usb_spi.o + +INCLUDE_ROOT := $(abspath ./include) +CFLAGS += -I$(INCLUDE_ROOT) +CPPFLAGS += -I$(abspath ./builtin) +CPPFLAGS += -I$(abspath ./chip/$(CHIP)) +# For core includes +CPPFLAGS += -I$(abspath .) +CPPFLAGS += -I$(abspath $(BDIR)) +CPPFLAGS += -I$(abspath ./test) +ifeq ($(CONFIG_UPTO_SHA512),y) +CPPFLAGS += -DSHA512_SUPPORT +endif + +# Make sure the context of the software sha512 implementation fits. If it ever +# increases, a compile time assert will fire in tpm2/hash.c. +ifeq ($(CONFIG_UPTO_SHA512),y) +CFLAGS += -DUSER_MIN_HASH_STATE_SIZE=208 +else +CFLAGS += -DUSER_MIN_HASH_STATE_SIZE=112 +endif +# Configure cryptoc headers to handle unaligned accesses. +CFLAGS += -DSUPPORT_UNALIGNED=1 + +endif # BOARD_MK_INCLUDED_ONCE is nonempty diff --git a/board/mn50/ec.tasklist b/board/mn50/ec.tasklist new file mode 100644 index 0000000000..ac18090c67 --- /dev/null +++ b/board/mn50/ec.tasklist @@ -0,0 +1,21 @@ +/* Copyright 2017 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/** + * List of enabled tasks in the priority order + * + * The first one has the lowest priority. + * + * For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and + * TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries, + * where : + * 'n' in the name of the task + * 'r' in the main routine of the task + * 'd' in an opaque parameter passed to the routine at startup + * 's' is the stack size in bytes; must be a multiple of 8 + */ +#define CONFIG_TASK_LIST \ + TASK_ALWAYS(HOOKS, hook_task, NULL, CONFIG_STACK_SIZE) \ + TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE) diff --git a/board/mn50/gpio.inc b/board/mn50/gpio.inc new file mode 100644 index 0000000000..fd40d34026 --- /dev/null +++ b/board/mn50/gpio.inc @@ -0,0 +1,116 @@ +/* -*- 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. + */ + +/* + * This file describes GPIO mapping for the cr50 code running on the H1 chip. + * + * For the purposes of this file H1 core has the following logical and + * physical items and properties: + * + * - 32 internal GPIOs, which are split into two ports of 16 bits each. + * Ports' architecture and programmig is described in "ARM Cortex-M System + * Design Kit TRM" DDIO47B. + * + * - a set of peripherals - slave and master SPI and I2C controllers, UARTs, + * interrupt controller, etc. + * + * - 28 pins on the package named DIOA0..14, DIOB0..7 and DIOM0..4 + * + * - a PINMUX - a unit which allows to interconnect objects from the three + * groups listed above. Note that some peripherals are attached to some + * pins directly, so in case those peripherals are used the pins should + * not be connected by PINMUX to any other outputs. + * + * The below macros are somewhat misleading (apparently for historical + * reasons), as PIN(p, b) component in fact refers not to the external pin, + * but to the GPIO (bit b on port p), where bit is in 0..15 range, and port is + * in 0..1 range. + * + * To describe routing of an external signal two macro instantiations are + * required: + * + * The GPIO_INT() or GPIO() macro assigns the signal a name and assigns it to + * the internal GPIO port, (again, defining the port using the PIN(port, bit) + * component of the macro invocation). GPIO_INT definitions assign their + * respective signals to interrupts and ISRs. + * + * The PINMUX macro assigns the previously defined GPIO to another object, + * most commonly to an external pin, but possibly to some internal component. + */ + +/* Declare symbolic names for all the GPIOs that we care about. + * Note: Those with interrupt handlers must be declared first. */ + + +/* Use these to reset/flash the DUT haven */ +GPIO(DUT_BOOT_CFG, PIN(0, 0), GPIO_OUT_LOW) /* DIOB2 */ +GPIO(DUT_RST_L, PIN(0, 1), GPIO_ODR_LOW) /* DIOB3 */ +GPIO(DUT_PWR_EN, PIN(0, 2), GPIO_OUT_LOW) /* DIOB5 */ +GPIO(DUT_PWRGOOD, PIN(0, 3), GPIO_INPUT) /* DIOB7 */ + +GPIO(LED_B_L, PIN(0, 4), GPIO_ODR_HIGH) /* DIOA9 */ +GPIO(LED_R_L, PIN(0, 5), GPIO_ODR_HIGH) /* DIOA13 */ +GPIO(LED_G_L, PIN(0, 6), GPIO_ODR_HIGH) /* DIOA14 */ +GPIO(LED_L, PIN(0, 11), GPIO_ODR_HIGH) /* DIOB6 */ + +/* GPIOs used to tristate the SPI bus */ +GPIO(SPI_MOSI, PIN(0, 7), GPIO_INPUT) /* DIOA4 */ +GPIO(SPI_CLK, PIN(0, 8), GPIO_INPUT) /* DIOA8 */ +GPIO(SPI_CS_L, PIN(0, 9), GPIO_INPUT) /* DIOA14 */ +GPIO(SPI_CS_ALT_L, PIN(0, 10), GPIO_OUT_HIGH) /* DIOA5 */ + +/* Unimplemented signals which we need to emulate for now */ +/* TODO(wfrichar): Half the boards don't use this signal. Take it out. */ +UNIMPLEMENTED(ENTERING_RW) + +/* + * If we are included by generic GPIO code that doesn't know about the PINMUX + * macro we need to provide an empty definition so that the invocations don't + * interfere with other GPIO processing. + */ +#ifndef PINMUX +#define PINMUX(...) +#endif + +/* GPIOs - mark outputs as inputs too, to read back from the driven pad */ +PINMUX(GPIO(DUT_BOOT_CFG), B2, DIO_INPUT) +PINMUX(GPIO(DUT_RST_L), B3, DIO_INPUT) +PINMUX(GPIO(DUT_PWR_EN), B5, DIO_INPUT) +PINMUX(GPIO(DUT_PWRGOOD), B7, DIO_INPUT) + +PINMUX(GPIO(LED_B_L), A9, DIO_INPUT) +PINMUX(GPIO(LED_R_L), A13, DIO_INPUT) +PINMUX(GPIO(LED_G_L), A14, DIO_INPUT) +PINMUX(GPIO(LED_L), B6, DIO_INPUT) + +/* UARTs */ +PINMUX(FUNC(UART0_TX), A0, DIO_OUTPUT) /* Cr50 console */ +PINMUX(FUNC(UART0_RX), A1, DIO_INPUT | DIO_WAKE_LOW) + +PINMUX(FUNC(UART1_TX), A7, DIO_OUTPUT) /* DUT console */ +PINMUX(FUNC(UART1_RX), A3, DIO_INPUT) + +/* I2C setup */ +PINMUX(FUNC(I2C0_SCL), B0, DIO_INPUT | DIO_OUTPUT) +PINMUX(FUNC(I2C0_SDA), B1, DIO_INPUT | DIO_OUTPUT) + +/* + * Both SPI master and slave buses are wired directly to specific pads + * + * If CONFIG_SPI_MASTER is defined, these pads are used: + * DIOA4 = SPI_MOSI (output) + * DIOA8 = SPI_CLK (output) + * DIOA11 = SPI_MISO (input) + * DIOA14 = SPI_CS_L (output) - mn50 doesn't use HS CS implementation. + * The pads are only connected to the peripheral outputs when SPI is enabled to + * avoid interfering with other things on the board. + * Note: Double-check to be sure these are configured in spi_master.c + */ +PINMUX(GPIO(SPI_MOSI), A4, DIO_OUTPUT) +PINMUX(GPIO(SPI_CLK), A8, DIO_OUTPUT) +PINMUX(GPIO(SPI_CS_ALT_L), A5, DIO_INPUT) + +#undef PINMUX diff --git a/board/mn50/usb_spi.c b/board/mn50/usb_spi.c new file mode 100644 index 0000000000..48f4728a34 --- /dev/null +++ b/board/mn50/usb_spi.c @@ -0,0 +1,84 @@ +/* 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 "console.h" +#include "gpio.h" +#include "hooks.h" +#include "registers.h" +#include "spi.h" +#include "system.h" +#include "timer.h" +#include "usb_spi.h" + +#define CPRINTS(format, args...) cprints(CC_USB, format, ## args) + +int usb_spi_board_enable(struct usb_spi_config const *config) +{ + /* Connect DIO A4, A8, and A14 to the SPI peripheral */ + GWRITE(PINMUX, DIOA4_SEL, 0); /* SPI_MOSI */ + GWRITE(PINMUX, DIOA8_SEL, 0); /* SPI_CLK */ + + spi_enable(CONFIG_SPI_FLASH_PORT, 1); + + /* Enable SPI framing for H1 bootloader */ + gpio_set_level(GPIO_SPI_CS_ALT_L, 0); + + return EC_SUCCESS; +} + +void usb_spi_board_disable(struct usb_spi_config const *config) +{ + /* End SPI framing for H1 bootloader */ + gpio_set_level(GPIO_SPI_CS_ALT_L, 1); + + spi_enable(CONFIG_SPI_FLASH_PORT, 0); + + /* Disconnect SPI peripheral to tri-state pads */ + ASSERT(GREAD(PINMUX, GPIO0_GPIO7_SEL) == GC_PINMUX_DIOA4_SEL); + ASSERT(GREAD(PINMUX, GPIO0_GPIO8_SEL) == GC_PINMUX_DIOA8_SEL); + + /* Set SPI MOSI, CLK as inputs */ + GWRITE(PINMUX, DIOA4_SEL, GC_PINMUX_GPIO0_GPIO7_SEL); + GWRITE(PINMUX, DIOA8_SEL, GC_PINMUX_GPIO0_GPIO8_SEL); +} + +int usb_spi_interface(struct usb_spi_config const *config, + struct usb_setup_packet *req) +{ + if (req->bmRequestType != (USB_DIR_OUT | + USB_TYPE_VENDOR | + USB_RECIP_INTERFACE)) + return 1; + + if (req->wValue != 0 || + req->wIndex != config->interface || + req->wLength != 0) + return 1; + + if (!config->state->enabled_device) + return 1; + + switch (req->bRequest) { + case USB_SPI_REQ_ENABLE_H1: + config->state->enabled_host = USB_SPI_H1; + break; + case USB_SPI_REQ_ENABLE_AP: + case USB_SPI_REQ_ENABLE: + CPRINTS("ERROR: Must specify target"); + case USB_SPI_REQ_DISABLE: + config->state->enabled_host = USB_SPI_DISABLE; + break; + + default: + return 1; + } + + /* + * Our state has changed, call the deferred function to handle the + * state change. + */ + hook_call_deferred(config->deferred, 0); + return 0; +} diff --git a/chip/g/gpio.c b/chip/g/gpio.c index 122f7f1f24..6f306b78ef 100644 --- a/chip/g/gpio.c +++ b/chip/g/gpio.c @@ -41,6 +41,31 @@ void gpio_set_level(enum gpio_signal signal, int value) set_one_gpio_bit(g->port, g->mask, value); } +int gpio_get_flags_by_mask(uint32_t port, uint32_t mask) +{ + uint32_t flags = 0; + uint32_t val = 0; + + /* Only one bit must be set. */ + if ((mask != (mask & -mask)) || (mask == 0)) + return 0; + + /* Check mode. */ + /* ARM DDI 0479B: 3.5.2 */ + val = GR_GPIO_SETDOUTEN(port) & mask; + if (val) { + flags |= GPIO_OUTPUT; + val = GR_GPIO_DOUT(port) & mask; + if (val) + flags |= GPIO_HIGH; + else + flags |= GPIO_LOW; + } else + flags |= GPIO_INPUT; + + return flags; +} + void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags) { /* Only matters for outputs */ diff --git a/chip/g/spi_master.c b/chip/g/spi_master.c index a602c518e5..13d8e15b75 100644 --- a/chip/g/spi_master.c +++ b/chip/g/spi_master.c @@ -34,6 +34,8 @@ int spi_transaction(const struct spi_device_t *spi_device, int port = spi_device->port; int rv = EC_SUCCESS; timestamp_t timeout; + int transaction_size = 0; + int rxoffset = 0; /* If SPI0's passthrough is enabled, SPI0 is not available unless the * SPS's BUSY bit is set. */ @@ -43,11 +45,26 @@ int spi_transaction(const struct spi_device_t *spi_device, return EC_ERROR_BUSY; } - /* Ensure it'll fit inside of the RX and TX buffers. Note that although - * the buffers are separate, the total transmission size must fit in - * the rx buffer. */ - if (txlen + rxlen > SPI_BUF_SIZE) - return EC_ERROR_INVAL; + if (rxlen == SPI_READBACK_ALL) { + /* Bidirectional SPI sends and receives a bit for each clock. + * We'll need to make sure the buffers for RX and TX are equal + * and return a bit received for every bit sent. + */ + if (txlen > SPI_BUF_SIZE) + return EC_ERROR_INVAL; + rxlen = txlen; + transaction_size = txlen; + rxoffset = 0; + } else { + /* Ensure it'll fit inside of the RX and TX buffers. Note that + * although the buffers are separate, the total transmission + * size must fit in the rx buffer. + */ + if (txlen + rxlen > SPI_BUF_SIZE) + return EC_ERROR_INVAL; + transaction_size = rxlen + txlen; + rxoffset = txlen; + } /* Grab the port's mutex. */ mutex_lock(&spi_mutex[port]); @@ -62,7 +79,7 @@ int spi_transaction(const struct spi_device_t *spi_device, #endif /* CONFIG_SPI_MASTER_NO_CS_GPIOS */ /* Initiate the transaction. */ - GWRITE_FIELD_I(SPI, port, XACT, SIZE, rxlen + txlen - 1); + GWRITE_FIELD_I(SPI, port, XACT, SIZE, transaction_size - 1); GWRITE_FIELD_I(SPI, port, XACT, START, 1); /* Wait for the SPI master to finish the transaction. */ @@ -77,7 +94,8 @@ int spi_transaction(const struct spi_device_t *spi_device, GWRITE_FIELD_I(SPI, port, ISTATE_CLR, TXDONE, 1); /* Copy the result. */ - memmove(rxdata, &((uint8_t *)GREG32_ADDR_I(SPI, port, RX_DATA))[txlen], + memmove(rxdata, + &((uint8_t *)GREG32_ADDR_I(SPI, port, RX_DATA))[rxoffset], rxlen); err_cs_high: diff --git a/chip/g/system.c b/chip/g/system.c index 1dbf3882a4..dea76c082f 100644 --- a/chip/g/system.c +++ b/chip/g/system.c @@ -94,7 +94,7 @@ void system_reset(int flags) /* Disable interrupts to avoid task swaps during reboot */ interrupt_disable(); -#ifdef BOARD_CR50 +#if defined(CHIP_FAMILY_CR50) /* * Decrement the retry counter on manually triggered reboots. We were * able to process the console command, therefore we're probably okay. @@ -139,7 +139,7 @@ void system_reset(int flags) GC_PMU_LOW_POWER_DIS_START_LSB, 1); } -#endif /* ^^^^^^^ BOARD_CR50 Not defined */ +#endif /* ^^^^^^^ CHIP_FAMILY_CR50 Not defined */ /* Wait for reboot; should never return */ asm("wfi"); @@ -366,8 +366,7 @@ const char *system_get_version(enum system_image_copy_t copy) return "Error"; } -#ifdef BOARD_CR50 - +#if defined(CHIP_FAMILY_CR50) void system_clear_retry_counter(void) { GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG0, 1); diff --git a/chip/g/usart.c b/chip/g/usart.c index 9955997652..3e5493c579 100644 --- a/chip/g/usart.c +++ b/chip/g/usart.c @@ -13,26 +13,15 @@ defined(SECTION_IS_RO))) #define QUEUE_SIZE 64 +#ifdef CONFIG_STREAM_USART1 struct usb_stream_config const ap_usb; struct usart_config const ap_uart; -struct usb_stream_config const ec_usb; -struct usart_config const ec_uart; - static struct queue const ap_uart_to_usb = QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ap_uart.producer, ap_usb.consumer); static struct queue const ap_usb_to_uart = QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ap_usb.producer, ap_uart.consumer); -static struct queue const ec_uart_to_usb = - QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ec_uart.producer, ec_usb.consumer); -static struct queue const ec_usb_to_uart = - QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ec_usb.producer, ec_uart.consumer); - -USART_CONFIG(ec_uart, - UART_EC, - ec_uart_to_usb, - ec_usb_to_uart); USART_CONFIG(ap_uart, UART_AP, ap_uart_to_usb, @@ -46,6 +35,22 @@ USB_STREAM_CONFIG(ap_usb, USB_MAX_PACKET_SIZE, ap_usb_to_uart, ap_uart_to_usb) +#endif + +#ifdef CONFIG_STREAM_USART2 +struct usb_stream_config const ec_usb; +struct usart_config const ec_uart; + +static struct queue const ec_uart_to_usb = + QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ec_uart.producer, ec_usb.consumer); +static struct queue const ec_usb_to_uart = + QUEUE_DIRECT(QUEUE_SIZE, uint8_t, ec_usb.producer, ec_uart.consumer); + +USART_CONFIG(ec_uart, + UART_EC, + ec_uart_to_usb, + ec_usb_to_uart); + USB_STREAM_CONFIG(ec_usb, USB_IFACE_EC, USB_STR_EC_NAME, @@ -54,6 +59,7 @@ USB_STREAM_CONFIG(ec_usb, USB_MAX_PACKET_SIZE, ec_usb_to_uart, ec_uart_to_usb) +#endif void get_data_from_usb(struct usart_config const *config) { @@ -112,13 +118,16 @@ struct consumer_ops const uart_consumer_ops = { }; #if USE_UART_INTERRUPTS +#ifdef CONFIG_STREAM_USART1 /* * Interrupt handlers for UART1 */ CONFIGURE_INTERRUPTS(ap_uart, GC_IRQNUM_UART1_RXINT, GC_IRQNUM_UART1_TXINT) +#endif +#ifdef CONFIG_STREAM_USART2 /* * Interrupt handlers for UART2 */ @@ -126,3 +135,4 @@ CONFIGURE_INTERRUPTS(ec_uart, GC_IRQNUM_UART2_RXINT, GC_IRQNUM_UART2_TXINT) #endif +#endif diff --git a/chip/g/usb_spi.c b/chip/g/usb_spi.c index caba2e1ec3..55259b2fc8 100644 --- a/chip/g/usb_spi.c +++ b/chip/g/usb_spi.c @@ -45,8 +45,9 @@ static void usb_spi_write_packet(struct usb_spi_config const *config, void usb_spi_deferred(struct usb_spi_config const *config) { uint16_t count; - uint8_t write_count; - uint8_t read_count; + int write_count; + int read_count; + int read_length; uint16_t res; int rv = EC_SUCCESS; @@ -76,7 +77,18 @@ void usb_spi_deferred(struct usb_spi_config const *config) write_count = config->buffer[0]; read_count = config->buffer[1]; - if (!count || (!read_count && !write_count)) + /* Handle SPI_READBACK_ALL case */ + if (read_count == 255) { + /* Handle simultaneously clocked RX and TX */ + read_count = SPI_READBACK_ALL; + read_length = write_count; + } else { + /* Normal case */ + read_length = read_count; + } + + if (!count || (!read_count && !write_count) || + (!write_count && read_count == (uint8_t)SPI_READBACK_ALL)) return; if (!config->state->enabled) { @@ -84,7 +96,7 @@ void usb_spi_deferred(struct usb_spi_config const *config) } else if (write_count > USB_SPI_MAX_WRITE_COUNT || write_count != (count - HEADER_SIZE)) { res = USB_SPI_WRITE_COUNT_INVALID; - } else if (read_count > USB_SPI_MAX_READ_COUNT) { + } else if (read_length > USB_SPI_MAX_READ_COUNT) { res = USB_SPI_READ_COUNT_INVALID; } else { res = usb_spi_map_error( @@ -96,7 +108,7 @@ void usb_spi_deferred(struct usb_spi_config const *config) } memcpy(config->buffer, &res, HEADER_SIZE); - usb_spi_write_packet(config, read_count + HEADER_SIZE); + usb_spi_write_packet(config, read_length + HEADER_SIZE); } static void usb_spi_written(struct consumer const *consumer, size_t count) diff --git a/chip/g/usb_spi.h b/chip/g/usb_spi.h index ed51780ebc..9d198a7dc2 100644 --- a/chip/g/usb_spi.h +++ b/chip/g/usb_spi.h @@ -66,8 +66,18 @@ enum usb_spi_request { USB_SPI_REQ_DISABLE = 0x0001, USB_SPI_REQ_ENABLE_AP = 0x0002, USB_SPI_REQ_ENABLE_EC = 0x0003, + USB_SPI_REQ_ENABLE_H1 = 0x0004, }; +/* USB SPI device indexes */ +enum usb_spi { + USB_SPI_DISABLE = 0, + USB_SPI_AP, + USB_SPI_EC, + USB_SPI_H1, +}; + + #define USB_SPI_MAX_WRITE_COUNT 62 #define USB_SPI_MAX_READ_COUNT 62 |