summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2017-02-03 11:54:22 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-05-12 03:25:39 -0700
commit8df3b161e946b2b9aaa5e475766864d3fdb2a9ca (patch)
tree9bdd6dba80502c56582008c22a2bb78117fd4d0d
parent44b9f9df83b3c54b46eb09f593cce32fe822f30a (diff)
downloadchrome-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.h9
-rw-r--r--board/mn50/board.c265
-rw-r--r--board/mn50/board.h188
-rw-r--r--board/mn50/build.mk54
-rw-r--r--board/mn50/ec.tasklist21
-rw-r--r--board/mn50/gpio.inc116
-rw-r--r--board/mn50/usb_spi.c84
-rw-r--r--chip/g/gpio.c25
-rw-r--r--chip/g/spi_master.c32
-rw-r--r--chip/g/system.c7
-rw-r--r--chip/g/usart.c34
-rw-r--r--chip/g/usb_spi.c22
-rw-r--r--chip/g/usb_spi.h10
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