summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2016-08-16 17:52:46 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-09-09 12:33:48 -0700
commit5832b34148ea0574d23f39098a5a43e6374b85c5 (patch)
tree7976e8ea722db0e0b2f345412b881e1836aeea81
parentcd4270d4e318457f27009e6ea2a59a854ec2e880 (diff)
downloadchrome-ec-5832b34148ea0574d23f39098a5a43e6374b85c5.tar.gz
chip: Initial support for rotor.
This commit adds initial support for rotor. Basic drivers including: - hardware timer - GPIO - UART - watchdog BUG=chrome-os-partner:51665 BRANCH=None TEST=make -j buildall tests Change-Id: I4e384fc69297f807268dcd43cf47f99ab059fd05 Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/373202 Commit-Ready: Aseda Aboagye <aaboagye@chromium.org> Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--chip/rotor/build.mk19
-rw-r--r--chip/rotor/clock.c21
-rw-r--r--chip/rotor/config_chip.h73
-rw-r--r--chip/rotor/gpio.c193
-rw-r--r--chip/rotor/hwtimer.c201
-rw-r--r--chip/rotor/jtag.c10
-rw-r--r--chip/rotor/registers.h166
-rw-r--r--chip/rotor/system.c61
-rw-r--r--chip/rotor/uart.c138
-rw-r--r--chip/rotor/watchdog.c88
10 files changed, 970 insertions, 0 deletions
diff --git a/chip/rotor/build.mk b/chip/rotor/build.mk
new file mode 100644
index 0000000000..0dae6571b9
--- /dev/null
+++ b/chip/rotor/build.mk
@@ -0,0 +1,19 @@
+# -*- makefile -*-
+# Copyright 2016 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.
+#
+# Rotor chip specific files build
+#
+
+# Rotor has a Cortex-M4F ARM core
+CORE:=cortex-m
+# Allow the full Cortex-M4 instruction set
+CFLAGS_CPU+=-march=armv7e-m -mcpu=cortex-m4
+
+# Required chip modules
+chip-y=clock.o gpio.o hwtimer.o jtag.o system.o uart.o
+chip-$(CONFIG_WATCHDOG)+=watchdog.o
+
+# Rotor MCU only supports one image, so only build RW.
+all_deps=$(patsubst ro,,$(def_all_deps))
diff --git a/chip/rotor/clock.c b/chip/rotor/clock.c
new file mode 100644
index 0000000000..3327228982
--- /dev/null
+++ b/chip/rotor/clock.c
@@ -0,0 +1,21 @@
+/* Copyright 2016 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.
+ */
+
+/* Clock and power management settings */
+
+#include "common.h"
+
+
+void clock_init(void)
+{
+ /* Clocks should already be initialized for us. */
+}
+
+int clock_get_freq(void)
+{
+ return CPU_CLOCK;
+}
+
+/* TODO(aaboagye): Add support for changing sysclock frequency. */
diff --git a/chip/rotor/config_chip.h b/chip/rotor/config_chip.h
new file mode 100644
index 0000000000..e6bd2705b5
--- /dev/null
+++ b/chip/rotor/config_chip.h
@@ -0,0 +1,73 @@
+/* Copyright 2016 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_CONFIG_CHIP_H
+#define __CROS_EC_CONFIG_CHIP_H
+
+/* CPU core BFD configuration */
+#include "core/cortex-m/config_core.h"
+
+/* Interval between HOOK_TICK notifications */
+#define HOOK_TICK_INTERVAL_MS 250
+#define HOOK_TICK_INTERVAL (HOOK_TICK_INTERVAL_MS * MSEC)
+
+/****************************************************************************/
+/* Memory mapping */
+
+/*
+ * The memory region for RAM is 0x20000000-0x20060000. (384 KB)
+ * - Only 1 image is loaded directly into SRAM.
+ * - The lower 128KB is reserved for the image.
+ * - The next 128KB is reserved for RAM.
+ * - The last 128KB is reserved.
+ */
+
+/****************************************************************************/
+#define ROTOR_MCU_SRAM_BASE 0x20000000
+#define ROTOR_MCU_SRAM_END (ROTOR_MCU_SRAM_BASE + (3 * 0x20000))
+#define CONFIG_RAM_BASE (ROTOR_MCU_SRAM_BASE + CONFIG_RW_SIZE)
+#define CONFIG_RAM_SIZE (1 * 0x20000)
+
+/* Default task stack size. */
+#define TASK_STACK_SIZE 512
+
+/* System stack size */
+#define CONFIG_STACK_SIZE 1024
+
+/* non-standard task stack sizes */
+#define IDLE_TASK_STACK_SIZE 512
+#define LARGER_TASK_STACK_SIZE 768
+
+#define CONFIG_PROGRAM_MEMORY_BASE ROTOR_MCU_SRAM_BASE
+#define CONFIG_MAPPED_STORAGE_BASE CONFIG_PROGRAM_MEMORY_BASE
+
+/* There's only 1 image. */
+#undef CONFIG_FW_INCLUDE_RO
+#define CONFIG_RO_MEM_OFF 0
+#define CONFIG_RO_SIZE 0
+
+#define CONFIG_RW_MEM_OFF 0
+#define CONFIG_RW_SIZE (1 * 0x20000)
+
+/* There's no concept of protected storage for the MCU. */
+#define CONFIG_EC_PROTECTED_STORAGE_OFF 0
+#define CONFIG_EC_PROTECTED_STORAGE_SIZE 0
+#define CONFIG_EC_WRITABLE_STORAGE_OFF 0
+#define CONFIG_EC_WRITABLE_STORAGE_SIZE 0
+#define CONFIG_RO_STORAGE_OFF 0
+#define CONFIG_RW_STORAGE_OFF 0
+
+#define CONFIG_FLASH_SIZE CONFIG_RW_SIZE
+#define CONFIG_FLASH_BANK_SIZE 0
+
+/* Number of IRQ vectors on the NVIC */
+#define CONFIG_IRQ_COUNT 96
+
+#define GPIO_PIN(port, index) GPIO_##port, (1 << index)
+#define GPIO_PIN_MASK(port, mask) GPIO_##port, (mask)
+
+#define I2C_PORT_COUNT 6
+
+#endif /* __CROS_EC_CONFIG_CHIP_H */
diff --git a/chip/rotor/gpio.c b/chip/rotor/gpio.c
new file mode 100644
index 0000000000..14e52e49aa
--- /dev/null
+++ b/chip/rotor/gpio.c
@@ -0,0 +1,193 @@
+/* Copyright 2016 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.
+ */
+
+/* GPIO module for Rotor MCU */
+
+#include "gpio.h"
+#include "registers.h"
+#include "task.h"
+#include "util.h"
+
+test_mockable int gpio_get_level(enum gpio_signal signal)
+{
+ uint32_t mask = gpio_list[signal].mask;
+ uint32_t val;
+
+ if (mask == 0)
+ return 0;
+
+ val = ROTOR_MCU_GPIO_PLR(gpio_list[signal].port);
+ return (val & mask) ? 1 : 0;
+}
+
+void gpio_set_level(enum gpio_signal signal, int value)
+{
+ uint32_t mask = gpio_list[signal].mask;
+
+ if (mask == 0)
+ return;
+
+ /* Enable direct writes to take effect. */
+ ROTOR_MCU_GPIO_DWER(gpio_list[signal].port) |= mask;
+
+ if (value)
+ ROTOR_MCU_GPIO_OLR(gpio_list[signal].port) |= mask;
+ else
+ ROTOR_MCU_GPIO_OLR(gpio_list[signal].port) &= ~mask;
+}
+
+void gpio_pre_init(void)
+{
+ int i;
+ const struct gpio_info *g = gpio_list;
+
+ /* Set all GPIOs to their defaults. */
+ for (i = 0; i < GPIO_COUNT; i++, g++) {
+ int flags = g->flags;
+
+ if (flags & GPIO_DEFAULT)
+ continue;
+
+ gpio_set_flags_by_mask(g->port, g->mask, flags);
+ }
+}
+
+void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
+{
+ while (mask) {
+ int i = GPIO_MASK_TO_NUM(mask);
+ const uint32_t this_mask = (1 << i);
+ mask &= ~this_mask;
+
+ /* Enable direct writes to take effect. */
+ ROTOR_MCU_GPIO_DWER(port) |= this_mask;
+
+ /* Input/Output */
+ if (flags & GPIO_OUTPUT)
+ ROTOR_MCU_GPIO_PDR(port) |= this_mask;
+ else
+ ROTOR_MCU_GPIO_PDR(port) &= ~this_mask;
+
+ /* Pull Up / Pull Down */
+ if (flags & GPIO_PULL_UP) {
+ ROTOR_MCU_GPIO_PCFG(port, i) |= (1 << 14);
+ } else if (flags & GPIO_PULL_DOWN) {
+ ROTOR_MCU_GPIO_PCFG(port, i) |= (1 << 13);
+ } else {
+ /* No pull up/down */
+ ROTOR_MCU_GPIO_PCFG(port, i) &= ~(3 << 14);
+ }
+
+ /* Edge vs. Level Interrupts */
+ if (flags & (GPIO_INT_F_RISING | GPIO_INT_F_FALLING))
+ ROTOR_MCU_GPIO_IMR(port) &= this_mask;
+ else
+ ROTOR_MCU_GPIO_IMR(port) |= this_mask;
+
+ /* Interrupt polarity */
+ if (flags & (GPIO_INT_F_RISING | GPIO_INT_F_HIGH))
+ ROTOR_MCU_GPIO_HRIPR(port) |= this_mask;
+ else
+ ROTOR_MCU_GPIO_HRIPR(port) &= ~this_mask;
+
+ if (flags & (GPIO_INT_F_FALLING | GPIO_INT_F_LOW))
+ ROTOR_MCU_GPIO_LFIPR(port) |= this_mask;
+ else
+ ROTOR_MCU_GPIO_LFIPR(port) &= this_mask;
+
+ /* Set level */
+ if (flags & GPIO_OUTPUT) {
+ if (flags & GPIO_HIGH)
+ ROTOR_MCU_GPIO_OLR(port) |= this_mask;
+ else if (flags & GPIO_LOW)
+ ROTOR_MCU_GPIO_OLR(port) &= ~this_mask;
+ }
+
+ /* No analog support. */
+ };
+}
+
+void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func)
+{
+ int i;
+
+ while (mask) {
+ i = GPIO_MASK_TO_NUM(mask);
+ mask &= ~(1 << i);
+
+ ROTOR_MCU_GPIO_PCFG(port, i) &= ~0x7;
+ if (func > 0)
+ ROTOR_MCU_GPIO_PCFG(port, i) |= (func & 0x7);
+ };
+}
+
+int gpio_enable_interrupt(enum gpio_signal signal)
+{
+ const struct gpio_info *g = gpio_list + signal;
+
+ if ((g->mask == 0) || (signal >= GPIO_IH_COUNT))
+ return EC_ERROR_UNKNOWN;
+
+ ROTOR_MCU_GPIO_ITER(g->port) |= g->mask;
+
+ return EC_SUCCESS;
+}
+
+int gpio_disable_interrupt(enum gpio_signal signal)
+{
+ const struct gpio_info *g = gpio_list + signal;
+
+ if ((g->mask == 0) || (signal >= GPIO_IH_COUNT))
+ return EC_ERROR_UNKNOWN;
+
+ ROTOR_MCU_GPIO_ITER(g->port) &= ~g->mask;
+
+ return EC_SUCCESS;
+}
+
+/**
+ * GPIO IRQ handler.
+ *
+ * @param port GPIO port (GPIO_[ABCDE])
+ * @param int_status interrupt status for the port.
+*/
+static void gpio_interrupt(int port, uint32_t int_status)
+{
+ int i = 0;
+ const struct gpio_info *g = gpio_list;
+
+ /* Search for the right IRQ handler. */
+ for (i = 0; i < GPIO_IH_COUNT && int_status; i++, g++) {
+ if (port == g->port && (int_status & g->mask)) {
+ gpio_irq_handlers[i](i);
+ int_status &= ~g->mask;
+ }
+ }
+}
+
+/**
+ * Handlers for each GPIO port. These read and clear the interrupt bits for
+ * the port, then call the master handler above.
+ */
+#define GPIO_IRQ_FUNC(irqfunc, port) \
+ void irqfunc(void) \
+ { \
+ uint32_t int_status = ROTOR_MCU_GPIO_ISR(port); \
+ ROTOR_MCU_GPIO_ISR(port) = int_status; \
+ gpio_interrupt(port, int_status); \
+ }
+
+GPIO_IRQ_FUNC(__gpio_a_interrupt, GPIO_A);
+GPIO_IRQ_FUNC(__gpio_b_interrupt, GPIO_B);
+GPIO_IRQ_FUNC(__gpio_c_interrupt, GPIO_C);
+GPIO_IRQ_FUNC(__gpio_d_interrupt, GPIO_D);
+GPIO_IRQ_FUNC(__gpio_e_interrupt, GPIO_E);
+
+/* Declare per-bank GPIO IRQs. */
+DECLARE_IRQ(ROTOR_MCU_IRQ_GPIO_0, __gpio_a_interrupt, 1);
+DECLARE_IRQ(ROTOR_MCU_IRQ_GPIO_1, __gpio_b_interrupt, 1);
+DECLARE_IRQ(ROTOR_MCU_IRQ_GPIO_2, __gpio_c_interrupt, 1);
+DECLARE_IRQ(ROTOR_MCU_IRQ_GPIO_3, __gpio_d_interrupt, 1);
+DECLARE_IRQ(ROTOR_MCU_IRQ_GPIO_4, __gpio_e_interrupt, 1);
diff --git a/chip/rotor/hwtimer.c b/chip/rotor/hwtimer.c
new file mode 100644
index 0000000000..27a4199c95
--- /dev/null
+++ b/chip/rotor/hwtimer.c
@@ -0,0 +1,201 @@
+/* Copyright 2016 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.
+ */
+
+/* Hardware timer driver for Rotor MCU */
+
+#include "clock.h"
+#include "common.h"
+#include "hwtimer.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+/*
+ * Timer 0 is the clock timer.
+ * Timer 1 is the event timer.
+ */
+
+#ifdef BOARD_REI
+/* static uint32_t reload_val; */
+#else
+static uint32_t rollover_cnt;
+#endif /* defined(BOARD_REI) */
+
+
+void __hw_clock_event_set(uint32_t deadline)
+{
+ uint32_t ticks;
+ uint32_t delta;
+
+ __hw_clock_event_clear();
+
+ delta = deadline - __hw_clock_source_read();
+
+ /* Convert the delta to ticks. */
+ ticks = delta * (clock_get_freq() / SECOND);
+
+ /* Set the timer load count to the deadline. */
+ ROTOR_MCU_TMR_TNLC(1) = ticks;
+
+ /* Enable the timer. */
+ ROTOR_MCU_TMR_TNCR(1) |= (1 << 0);
+}
+
+uint32_t __hw_clock_event_get(void)
+{
+ uint32_t ticks;
+ /* Get the time of the next programmed deadline. */
+ ticks = ROTOR_MCU_TMR_TNCV(1);
+ return __hw_clock_source_read() + ((ticks * SECOND) / clock_get_freq());
+}
+
+void __hw_clock_event_clear(void)
+{
+ /* Disable the event timer. This also clears any pending interrupt. */
+ ROTOR_MCU_TMR_TNCR(1) &= ~(1 << 0);
+}
+
+/* Triggered when Timer 1 reaches 0. */
+void __hw_clock_event_irq(void)
+{
+ /*
+ * Clear the event which disables the timer and clears the pending
+ * interrupt.
+ */
+ __hw_clock_event_clear();
+
+ /* Process timers now. */
+ process_timers(0);
+}
+DECLARE_IRQ(ROTOR_MCU_IRQ_TIMER_1, __hw_clock_event_irq, 1);
+
+uint32_t __hw_clock_source_read(void)
+{
+#ifdef BOARD_REI
+ /* uint32_t ticks = reload_val - ROTOR_MCU_TMR_TNCV(0); */
+ uint32_t ticks = 0xFFFFFFFF - ROTOR_MCU_TMR_TNCV(0);
+ /* Convert the ticks into microseconds. */
+ /* return ticks * (SECOND / clock_get_freq()); */
+
+ return (ticks * (clock_get_freq() / SECOND));
+#else
+ /* Convert ticks to microseconds and account for the rollovers. */
+ uint32_t ticks = 0xFFFFFFFF - ROTOR_MCU_TMR_TNCV(0);
+ uint32_t us = (0xFFFFFFFF / clock_get_freq()) * rollover_cnt * SECOND;
+ return us + ((ticks * SECOND) / clock_get_freq());
+#endif /* defined(BOARD_REI) */
+}
+
+void __hw_clock_source_set(uint32_t ts)
+{
+ /* Convert microseconds to ticks. */
+ uint32_t ticks;
+
+ /* Disable the timer. */
+ ROTOR_MCU_TMR_TNCR(0) &= ~1;
+#ifdef BOARD_REI
+ /* ticks = (ts / SECOND) * clock_get_freq(); */
+ ticks = (clock_get_freq() / SECOND) * ts;
+ /* Set the load count. */
+ /* ROTOR_MCU_TMR_TNLC(0) = reload_val - ticks; */
+ ROTOR_MCU_TMR_TNLC(0) = 0xFFFFFFFF - ticks;
+
+ /* Re-enable the timer block. */
+ ROTOR_MCU_TMR_TNCR(0) |= 1;
+
+ /*
+ * Restore the behaviour of counting down from the reload value after
+ * the next reload.
+ */
+ /* ROTOR_MCU_TMR_TNLC(0) = reload_val; */
+#else
+ /* Determine the rollover count and set the load count */
+ rollover_cnt = ts / ((0xFFFFFFFF / clock_get_freq()) * SECOND);
+ ticks = (ts % (0xFFFFFFFF / clock_get_freq()) * SECOND);
+ ROTOR_MCU_TMR_TNLC(0) = 0xFFFFFFFF - ticks;
+
+ /* Re-enable the timer block. */
+ ROTOR_MCU_TMR_TNCR(0) |= 1;
+#endif /* defined(BOARD_REI) */
+}
+
+/* Triggered when Timer 0 reaches 0. */
+void __hw_clock_source_irq(void)
+{
+ /* Make sure that the interrupt actually fired. */
+ if (!(ROTOR_MCU_TMR_TNIS(0) & (1 << 0)))
+ return;
+ /*
+ * Clear the interrupt by reading the TNEOI register. Reading from this
+ * register returns all zeroes.
+ */
+ if (ROTOR_MCU_TMR_TNEOI(0))
+ ;
+
+#ifdef BOARD_REI
+ /* Process timers indicating the overflow event. */
+ process_timers(1);
+#else
+ rollover_cnt++;
+ if (rollover_cnt >= (clock_get_freq() / 1000000)) {
+ /* Process timers indicating the overflow event. */
+ process_timers(1);
+ rollover_cnt = 0;
+ } else {
+ process_timers(0);
+ }
+#endif /* defined(BOARD_REI) */
+}
+DECLARE_IRQ(ROTOR_MCU_IRQ_TIMER_0, __hw_clock_source_irq, 1);
+
+void __hw_timer_enable_clock(int n, int enable)
+{
+ /* Should be already be configured. */
+}
+
+int __hw_clock_source_init(uint32_t start_t)
+{
+#ifdef BOARD_REI
+ /* reload_val = (0xFFFFFFFF / SECOND) * clock_get_freq(); */
+ /* reload_val = 0xFFFFFFFF; */
+#endif /* defined(BOARD_REI) */
+ /*
+ * Use Timer 0 as the clock. The clock source for the timer block
+ * cannot be prescaled down to 1MHz, therefore, we'll have to handle the
+ * rollovers.
+ *
+ * There's also no match functionality, so set up an additional timer,
+ * Timer 1, to handle events.
+ */
+
+ /* Disable the timers. */
+ ROTOR_MCU_TMR_TNCR(0) &= ~(1 << 0);
+ ROTOR_MCU_TMR_TNCR(1) &= ~(1 << 0);
+
+ /*
+ * Timer 0
+ *
+ * Unmask interrupt, set user-defined count mode, and disable PWM.
+ */
+ ROTOR_MCU_TMR_TNCR(0) = (1 << 1);
+
+ /* Use the specified start timer value and start the timer. */
+ __hw_clock_source_set(start_t);
+
+ /*
+ * Timer 1
+ *
+ * Unmask interrupt, set user-defined count mode, and disable PWM.
+ */
+ ROTOR_MCU_TMR_TNCR(1) = (1 << 1);
+
+ /* Enable interrupts. */
+ task_enable_irq(ROTOR_MCU_IRQ_TIMER_0);
+ task_enable_irq(ROTOR_MCU_IRQ_TIMER_1);
+
+ /* Return event timer IRQ number. */
+ return ROTOR_MCU_IRQ_TIMER_1;
+}
diff --git a/chip/rotor/jtag.c b/chip/rotor/jtag.c
new file mode 100644
index 0000000000..10dd7b4bcc
--- /dev/null
+++ b/chip/rotor/jtag.c
@@ -0,0 +1,10 @@
+/* Copyright 2016 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.
+ */
+
+/* JTAG module for Rotor MCU */
+
+void jtag_pre_init(void)
+{
+}
diff --git a/chip/rotor/registers.h b/chip/rotor/registers.h
new file mode 100644
index 0000000000..edb6313f84
--- /dev/null
+++ b/chip/rotor/registers.h
@@ -0,0 +1,166 @@
+/* Copyright 2016 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.
+ *
+ * Register map for Rotor MCU
+ */
+
+#ifndef __CROS_EC_REGISTERS_H
+#define __CROS_EC_REGISTERS_H
+
+#include "common.h"
+
+/* Master clocks and resets. */
+#define ROTOR_MCU_CLKRSTGEN_BASE 0xEF000800
+#define ROTOR_MCU_RESETAP REG32(ROTOR_MCU_CLKRSTGEN_BASE + 0x000)
+#define ROTOR_MCU_AP_NRESET (1 << 0)
+#define ROTOR_MCU_M4_BIST_CLKCFG REG32(ROTOR_MCU_CLKRSTGEN_BASE + 0x140)
+
+/* GPIO */
+#define DUMMY_GPIO_BANK 0
+
+#define GPIO_A 0xEF022000
+#define GPIO_B 0xEF022100
+#define GPIO_C 0xEF022200
+#define GPIO_D 0xEF022300
+#define GPIO_E 0xEF022400
+
+#define ROTOR_MCU_GPIO_PLR(b) REG32((b) + 0x0)
+#define ROTOR_MCU_GPIO_PDR(b) REG32((b) + 0x4)
+#define ROTOR_MCU_GPIO_PSR(b) REG32((b) + 0xC)
+#define ROTOR_MCU_GPIO_HRIPR(b) REG32((b) + 0x10)
+#define ROTOR_MCU_GPIO_LFIPR(b) REG32((b) + 0x14)
+#define ROTOR_MCU_GPIO_ISR(b) REG32((b) + 0x18)
+#define ROTOR_MCU_GPIO_SDR(b) REG32((b) + 0x1C)
+#define ROTOR_MCU_GPIO_CDR(b) REG32((b) + 0x20)
+#define ROTOR_MCU_GPIO_SHRIPR(b) REG32((b) + 0x24)
+#define ROTOR_MCU_GPIO_CHRIPR(b) REG32((b) + 0x28)
+#define ROTOR_MCU_GPIO_SLFIPR(b) REG32((b) + 0x2C)
+#define ROTOR_MCU_GPIO_CLFIPR(b) REG32((b) + 0x30)
+#define ROTOR_MCU_GPIO_OLR(b) REG32((b) + 0x34)
+#define ROTOR_MCU_GPIO_DWER(b) REG32((b) + 0x38)
+#define ROTOR_MCU_GPIO_IMR(b) REG32((b) + 0x3C)
+#define ROTOR_MCU_GPIO_SIMR(b) REG32((b) + 0x48)
+#define ROTOR_MCU_GPIO_CIMR(b) REG32((b) + 0x4C)
+/* Interrupt Target Enable regs for MCU are instances 24-31. */
+#define ROTOR_MCU_GPIO_ITER(b) REG32((b) + 0xB0 + \
+ 4*(((b) - GPIO_A) >> 8))
+
+
+/* MCU Pad Wrap */
+#define ROTOR_MCU_PAD_WRAP_BASE 0xEF020000
+#define ROTOR_MCU_IO_PAD_CFG(n) REG32(ROTOR_MCU_PAD_WRAP_BASE + 0x8 + \
+ ((n) * 0x4))
+
+#define GPIO_PAD_CFG_IDX(port, pin) (((((port) % 0x2000) / 0x100) * 32) + \
+ (pin))
+#define GPIO_PAD_CFG_ADDR(port, pin) ((GPIO_PAD_CFG_IDX(port, pin) * 4) + \
+ ROTOR_MCU_PAD_WRAP_BASE + 8)
+#define ROTOR_MCU_GPIO_PCFG(port, pin) REG32(GPIO_PAD_CFG_ADDR(port, pin))
+
+/* I2C */
+#define ROTOR_MCU_I2C_BASE 0xED080000
+#define ROTOR_MCU_I2C_CFG_BASE(n) (ROTOR_MCU_I2C_BASE + (n)*0x1000)
+#define ROTOR_MCU_I2C_CON(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x00)
+#define ROTOR_MCU_I2C_TAR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x04)
+#define ROTOR_MCU_I2C_SAR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x08)
+#define ROTOR_MCU_I2C_HS_MADDR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x0C)
+#define ROTOR_MCU_I2C_DATA_CMD(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x10)
+#define ROTOR_MCU_I2C_SS_SCL_HCNT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x14)
+#define ROTOR_MCU_I2C_SS_SCL_LCNT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x18)
+#define ROTOR_MCU_I2C_FS_SCL_HCNT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x1C)
+#define ROTOR_MCU_I2C_FS_SCL_LCNT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x20)
+#define ROTOR_MCU_I2C_HS_SCL_HCNT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x24)
+#define ROTOR_MCU_I2C_HS_SCL_LCNT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x28)
+#define ROTOR_MCU_I2C_INTR_STAT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x2C)
+#define ROTOR_MCU_I2C_INTR_MASK(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x30)
+#define ROTOR_MCU_I2C_RAW_INTR_STAT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x34)
+#define ROTOR_MCU_I2C_RX_TL(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x38)
+#define ROTOR_MCU_I2C_TX_TL(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x3C)
+#define ROTOR_MCU_I2C_CLR_INTR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x40)
+#define ROTOR_MCU_I2C_CLR_RX_UNDER(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x44)
+#define ROTOR_MCU_I2C_CLR_RX_OVER(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x48)
+#define ROTOR_MCU_I2C_CLR_TX_OVER(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x4C)
+#define ROTOR_MCU_I2C_CLR_RD_REQ(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x50)
+#define ROTOR_MCU_I2C_CLR_TX_ABRT(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x54)
+#define ROTOR_MCU_I2C_CLR_RX_DONE(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x58)
+#define ROTOR_MCU_I2C_CLR_ACTIVITY(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x5C)
+#define ROTOR_MCU_I2C_CLR_STOP_DET(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x60)
+#define ROTOR_MCU_I2C_CLR_START_DET(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x64)
+#define ROTOR_MCU_I2C_CLR_GEN_CALL(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x68)
+#define ROTOR_MCU_I2C_ENABLE(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x6C)
+#define ROTOR_MCU_I2C_STATUS(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x70)
+#define ROTOR_MCU_I2C_TXFLR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x74)
+#define ROTOR_MCU_I2C_RXFLR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x78)
+#define ROTOR_MCU_I2C_SDA_HOLD(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x7C)
+#define ROTOR_MCU_I2C_TX_ABRT_SRC(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x80)
+#define ROTOR_MCU_I2C_DMA_CR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x88)
+#define ROTOR_MCU_I2C_DMA_TDLR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x8C)
+#define ROTOR_MCU_I2C_DMA_RDLR(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x90)
+#define ROTOR_MCU_I2C_SDA_SETUP(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x94)
+#define ROTOR_MCU_I2C_ACK_GEN_CALL(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x98)
+#define ROTOR_MCU_I2C_ENABLE_STATUS(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0x9C)
+#define ROTOR_MCU_I2C_FS_SPKLEN(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0xA0)
+#define ROTOR_MCU_I2C_HS_SPKLEN(n) REG32(ROTOR_MCU_I2C_CFG_BASE(n) + 0xA4)
+#define ROTOR_MCU_I2C_REFCLKGEN(n) REG32((ROTOR_MCU_CLKRSTGEN_BASE + \
+ + 0x3D0 + (0x10 * (n))))
+
+/* UART */
+#define ROTOR_MCU_UART0_CLKGEN REG32(ROTOR_MCU_CLKRSTGEN_BASE + 0x240)
+#define ROTOR_MCU_UART0_REFCLKGEN REG32(ROTOR_MCU_CLKRSTGEN_BASE + 0x3B0)
+#define ROTOR_MCU_UART_CFG_BASE(n) (0xED060000 + (n)*0x1000)
+/* DLAB = 0 */
+#define ROTOR_MCU_UART_RBR(n) /* R */ REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x0)
+#define ROTOR_MCU_UART_THR(n) /* W */ REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x0)
+#define ROTOR_MCU_UART_IER(n) REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x4)
+/* DLAB = 1 */
+#define ROTOR_MCU_UART_DLL(n) REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x0)
+#define ROTOR_MCU_UART_DLH(n) REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x4)
+
+#define ROTOR_MCU_UART_IIR(n) /* R */ REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x8)
+#define ROTOR_MCU_UART_FCR(n) /* W */ REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x8)
+#define ROTOR_MCU_UART_LCR(n) REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0xC)
+#define ROTOR_MCU_UART_MCR(n) REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x10)
+#define ROTOR_MCU_UART_LSR(n) /* R */ REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x14)
+#define ROTOR_MCU_UART_MSR(n) /* R */ REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x18)
+#define ROTOR_MCU_UART_SCR(n) REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x1C)
+#define ROTOR_MCU_UART_USR(n) REG32(ROTOR_MCU_UART_CFG_BASE(n) + 0x7C)
+
+/* Timers */
+#define ROTOR_MCU_TMR_CFG_BASE(n) (0xED020000 + (n)*0x1000)
+#define ROTOR_MCU_TMR_TNLC(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0x0)
+#define ROTOR_MCU_TMR_TNCV(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0x4)
+#define ROTOR_MCU_TMR_TNCR(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0x8)
+#define ROTOR_MCU_TMR_TNEOI(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0xC)
+#define ROTOR_MCU_TMR_TNIS(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0x10)
+#define ROTOR_MCU_TMR_TIS(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0xA0)
+#define ROTOR_MCU_TMR_TEOI(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0xA4)
+#define ROTOR_MCU_TMR_TRIS(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0xA8)
+#define ROTOR_MCU_TMR_TNLC2(n) REG32(ROTOR_MCU_TMR_CFG_BASE(n) + 0xB0)
+
+/* Watchdog */
+#define ROTOR_MCU_WDT_BASE 0xED010000
+#define ROTOR_MCU_WDT_CR REG32(ROTOR_MCU_WDT_BASE + 0x00)
+#define ROTOR_MCU_WDT_TORR REG32(ROTOR_MCU_WDT_BASE + 0x04)
+#define ROTOR_MCU_WDT_CCVR REG32(ROTOR_MCU_WDT_BASE + 0x08)
+#define ROTOR_MCU_WDT_CRR REG32(ROTOR_MCU_WDT_BASE + 0x0C)
+#define ROTOR_MCU_WDT_STAT REG32(ROTOR_MCU_WDT_BASE + 0x10)
+#define ROTOR_MCU_WDT_EOI REG32(ROTOR_MCU_WDT_BASE + 0x14)
+/* To prevent accidental restarts, this magic value must be written to CRR. */
+#define ROTOR_MCU_WDT_KICK 0x76
+
+/* IRQ Numbers */
+#define ROTOR_MCU_IRQ_TIMER_0 6
+#define ROTOR_MCU_IRQ_TIMER_1 7
+#define ROTOR_MCU_IRQ_WDT 14
+#define ROTOR_MCU_IRQ_UART_0 16
+#define ROTOR_MCU_IRQ_GPIO_0 79
+#define ROTOR_MCU_IRQ_GPIO_1 80
+#define ROTOR_MCU_IRQ_GPIO_2 81
+#define ROTOR_MCU_IRQ_GPIO_3 82
+#define ROTOR_MCU_IRQ_GPIO_4 83
+#define ROTOR_MCU_IRQ_GPIO_5 84
+#define ROTOR_MCU_IRQ_GPIO_6 85
+#define ROTOR_MCU_IRQ_GPIO_7 86
+
+#endif /* __CROS_EC_REGISTERS_H */
diff --git a/chip/rotor/system.c b/chip/rotor/system.c
new file mode 100644
index 0000000000..bb804014e2
--- /dev/null
+++ b/chip/rotor/system.c
@@ -0,0 +1,61 @@
+/* Copyright 2016 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.
+ */
+
+/* System module for Rotor MCU */
+
+#include "common.h"
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "watchdog.h"
+
+void system_pre_init(void)
+{
+}
+
+void system_reset(int flags)
+{
+ /* Disable interrupts to avoid task swaps during reboot. */
+ interrupt_disable();
+
+ /* TODO: Implement flags and stuff. */
+
+ /*
+ * Try to trigger a watchdog reset, by setting the smallest timeout
+ * period we can.
+ */
+ ROTOR_MCU_WDT_TORR = 0;
+ watchdog_reload();
+
+ /* Wait for system reset. */
+ while (1)
+ asm("wfi");
+}
+
+const char *system_get_chip_name(void)
+{
+ return "rotor";
+}
+
+const char *system_get_chip_vendor(void)
+{
+ return "";
+}
+
+const char *system_get_chip_revision(void)
+{
+ return "";
+}
+
+int system_get_vbnvcontext(uint8_t *block)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+
+int system_set_vbnvcontext(const uint8_t *block)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+
+}
diff --git a/chip/rotor/uart.c b/chip/rotor/uart.c
new file mode 100644
index 0000000000..a85fdc1dba
--- /dev/null
+++ b/chip/rotor/uart.c
@@ -0,0 +1,138 @@
+/* Copyright 2016 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.
+ */
+
+/* UART module for Rotor MCU */
+
+#include "gpio.h"
+#include "registers.h"
+#include "task.h"
+#include "uart.h"
+
+/* UART reference clock is 200MHz. */
+#define UART_REF_CLK 200000000
+
+static int init_done;
+
+
+void uart_init(void)
+{
+ uint16_t divisor;
+
+ /* Ungate the UART clock and the UART reference clock. */
+ ROTOR_MCU_UART0_CLKGEN |= (1 << 1);
+ ROTOR_MCU_UART0_REFCLKGEN |= (1 << 1);
+
+ /* Set DLAB = 1 */
+ ROTOR_MCU_UART_LCR(0) |= (1 << 7);
+
+ /* Set divisor for baud rate. */
+#ifdef BOARD_REI
+ divisor = 1;
+#else
+ divisor = UART_REF_CLK / (16 * CONFIG_UART_BAUD_RATE);
+#endif /* !defined(BOARD_REI) */
+ ROTOR_MCU_UART_DLH(0) = (divisor & 0xFF00) >> 8;
+ ROTOR_MCU_UART_DLL(0) = divisor & 0xFF;
+
+ /* Clear DLAB bit. */
+ ROTOR_MCU_UART_LCR(0) &= ~(1 << 7);
+
+ /* Set data bits per character to 8. */
+ ROTOR_MCU_UART_LCR(0) |= (1 << 1) | (1 << 0);
+
+ /* Enable FIFOs. */
+ ROTOR_MCU_UART_FCR(0) |= (1 << 0);
+
+ /* Enable the pins for UART functionality. */
+ gpio_config_module(MODULE_UART, 1);
+
+ /* Enable Received Data Available Interrupt. */
+ ROTOR_MCU_UART_IER(0) |= (1 << 0);
+
+ /* Enable the interrupt. */
+ task_enable_irq(ROTOR_MCU_IRQ_UART_0);
+
+ init_done = 1;
+}
+
+int uart_init_done(void)
+{
+ return init_done;
+}
+
+void uart_tx_flush(void)
+{
+ /* Wait for TX FIFO to empty. */
+ while (!(ROTOR_MCU_UART_USR(0) & (1 << 2)))
+ ;
+}
+
+int uart_tx_ready(void)
+{
+ /* Bit set if TX FIFO is not full. */
+ return (ROTOR_MCU_UART_LSR(0) & (1 << 5));
+
+}
+
+int uart_tx_in_progress(void)
+{
+ /* Bit set if TX FIFO is empty. */
+ return !(ROTOR_MCU_UART_USR(0) & (1 << 2));
+}
+
+int uart_rx_available(void)
+{
+ /* Bit set if RX FIFO is not empty. */
+ return (ROTOR_MCU_UART_LSR(0) & (1 << 0));
+}
+
+void uart_write_char(char c)
+{
+ /* Wait for space in TX FIFO. */
+ while (!uart_tx_ready())
+ ;
+
+ ROTOR_MCU_UART_THR(0) = c;
+}
+
+int uart_read_char(void)
+{
+ return ROTOR_MCU_UART_RBR(0);
+}
+
+void uart_disable_interrupt(void)
+{
+ task_disable_irq(ROTOR_MCU_IRQ_UART_0);
+}
+
+void uart_enable_interrupt(void)
+{
+ task_enable_irq(ROTOR_MCU_IRQ_UART_0);
+}
+
+void uart_tx_start(void)
+{
+ /* Nothing to do if the interrupt is already enabled. */
+ if (ROTOR_MCU_UART_IER(0) & (1 << 1))
+ return;
+
+ ROTOR_MCU_UART_IER(0) |= (1 << 1);
+ /* Force trigger a UART interrupt. */
+ task_trigger_irq(ROTOR_MCU_IRQ_UART_0);
+}
+
+void uart_tx_stop(void)
+{
+ /* Disable Transmit Holding Register Empty interrupt. */
+ ROTOR_MCU_UART_IER(0) &= ~(1 << 1);
+}
+
+void uart_ec_interrupt(void)
+{
+ /* Read input FIFO until empty, then fill output FIFO */
+ uart_process_input();
+ uart_process_output();
+}
+DECLARE_IRQ(ROTOR_MCU_IRQ_UART_0, uart_ec_interrupt, 1);
diff --git a/chip/rotor/watchdog.c b/chip/rotor/watchdog.c
new file mode 100644
index 0000000000..8db02318df
--- /dev/null
+++ b/chip/rotor/watchdog.c
@@ -0,0 +1,88 @@
+/* Copyright 2016 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.
+ */
+
+/* Watchdog driver */
+
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "hooks.h"
+#include "registers.h"
+#include "task.h"
+#include "util.h"
+#include "watchdog.h"
+
+void IRQ_HANDLER(ROTOR_MCU_IRQ_WDT)(void) __attribute__((naked));
+void IRQ_HANDLER(ROTOR_MCU_IRQ_WDT)(void)
+{
+ /* Naked call so we can extract raw LR and SP */
+ asm volatile("mov r0, lr\n"
+ "mov r1, sp\n"
+ /*
+ * Must push registers in pairs to keep 64-bit aligned
+ * stack for ARM EABI. This also conveninently saves
+ * R0=LR so we can pass it to task_resched_if_needed.
+ */
+ "push {r0, lr}\n"
+ "bl watchdog_trace\n"
+ /*
+ * Do NOT reset the watchdog interrupt here; it will
+ * be done in watchdog_reload(), or reset will be
+ * triggered if we don't call that by the next watchdog
+ * period. Instead, de-activate the interrupt in the
+ * NVIC, so the watchdog trace will only be printed
+ * once.
+ */
+ "mov r0, %[irq]\n"
+ "bl task_disable_irq\n"
+ "pop {r0, lr}\n"
+ "b task_resched_if_needed\n"
+ : : [irq] "i" (ROTOR_MCU_IRQ_WDT));
+}
+const struct irq_priority IRQ_PRIORITY(ROTOR_MCU_IRQ_WDT)
+ __attribute__((section(".rodata.irqprio")))
+ = {ROTOR_MCU_IRQ_WDT, 0}; /*
+ * put the watchdog at the highest
+ * priority.
+ */
+
+void watchdog_reload(void)
+{
+ /* Kick the watchdog. */
+ ROTOR_MCU_WDT_CRR = ROTOR_MCU_WDT_KICK;
+}
+DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT);
+
+int watchdog_init(void)
+{
+ int i;
+ /*
+ * Set timeout period.
+ *
+ * The watchdog timer only allows you to set a timeout period that's a
+ * power of two. So find the most significant bit. The TOP field only
+ * takes a nibble which is then added to 16. Unfortunately, there will
+ * be some error.
+ */
+ i = __fls(CONFIG_WATCHDOG_PERIOD_MS * (clock_get_freq() / 1000)) - 16;
+ if (i > 0)
+ ROTOR_MCU_WDT_TORR = (i & 0x0f);
+ else
+ ROTOR_MCU_WDT_TORR = 0;
+
+ /*
+ * Reset after 2 timeouts. Reset pulse of 2 pclk cycles, and enable
+ * the WDT.
+ */
+ ROTOR_MCU_WDT_CR = (5 << 2) | 0x3;
+
+ /* Kick */
+ watchdog_reload();
+
+ /* Enable WDT interrupt. */
+ task_enable_irq(ROTOR_MCU_IRQ_WDT);
+
+ return EC_SUCCESS;
+}