diff options
author | Aseda Aboagye <aaboagye@google.com> | 2016-08-16 17:52:46 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-09-09 12:33:48 -0700 |
commit | 5832b34148ea0574d23f39098a5a43e6374b85c5 (patch) | |
tree | 7976e8ea722db0e0b2f345412b881e1836aeea81 | |
parent | cd4270d4e318457f27009e6ea2a59a854ec2e880 (diff) | |
download | chrome-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.mk | 19 | ||||
-rw-r--r-- | chip/rotor/clock.c | 21 | ||||
-rw-r--r-- | chip/rotor/config_chip.h | 73 | ||||
-rw-r--r-- | chip/rotor/gpio.c | 193 | ||||
-rw-r--r-- | chip/rotor/hwtimer.c | 201 | ||||
-rw-r--r-- | chip/rotor/jtag.c | 10 | ||||
-rw-r--r-- | chip/rotor/registers.h | 166 | ||||
-rw-r--r-- | chip/rotor/system.c | 61 | ||||
-rw-r--r-- | chip/rotor/uart.c | 138 | ||||
-rw-r--r-- | chip/rotor/watchdog.c | 88 |
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; +} |