From b437f03578e7e19a0ff369fe7ac574ab4414d588 Mon Sep 17 00:00:00 2001 From: Rong Chang Date: Wed, 5 Sep 2018 16:36:12 -0400 Subject: scp: Add mt_scp chip SCP is a Cortex-M4 based sensor hub in Mediatek SoC. This change adds the chip folder and system level drivers. BRANCH=none BUG=b:114326670 TEST=manual make BOARD=kukui_scp -j copy ec.bin to /lib/firmware/scp.img echo 'stop' > /sys/class/remoteproc/remoteproc0/state echo 'start' > /sys/class/remoteproc/remoteproc0/state check EC uart console Change-Id: I6629149f352184108fa520e80b59fd2ce94c76f7 Signed-off-by: Rong Chang Signed-off-by: Yilun Lin Reviewed-on: https://chromium-review.googlesource.com/1208770 Commit-Ready: ChromeOS CL Exonerator Bot Tested-by: Yilun Lin Reviewed-by: Yilun Lin Reviewed-by: Nicolas Boichat --- chip/mt_scp/build.mk | 19 ++ chip/mt_scp/clock.c | 78 +++++++++ chip/mt_scp/config_chip.h | 78 +++++++++ chip/mt_scp/gpio.c | 177 +++++++++++++++++++ chip/mt_scp/hrtimer.c | 235 +++++++++++++++++++++++++ chip/mt_scp/registers.h | 430 ++++++++++++++++++++++++++++++++++++++++++++++ chip/mt_scp/serial_reg.h | 90 ++++++++++ chip/mt_scp/system.c | 307 +++++++++++++++++++++++++++++++++ chip/mt_scp/uart.c | 171 ++++++++++++++++++ chip/mt_scp/watchdog.c | 33 ++++ 10 files changed, 1618 insertions(+) create mode 100644 chip/mt_scp/build.mk create mode 100644 chip/mt_scp/clock.c create mode 100644 chip/mt_scp/config_chip.h create mode 100644 chip/mt_scp/gpio.c create mode 100644 chip/mt_scp/hrtimer.c create mode 100644 chip/mt_scp/registers.h create mode 100644 chip/mt_scp/serial_reg.h create mode 100644 chip/mt_scp/system.c create mode 100644 chip/mt_scp/uart.c create mode 100644 chip/mt_scp/watchdog.c diff --git a/chip/mt_scp/build.mk b/chip/mt_scp/build.mk new file mode 100644 index 0000000000..eb261fbd90 --- /dev/null +++ b/chip/mt_scp/build.mk @@ -0,0 +1,19 @@ +# -*- makefile -*- +# Copyright 2018 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. +# +# SCP specific files build +# + +CORE:=cortex-m +CFLAGS_CPU+=-march=armv7e-m -mcpu=cortex-m4 + +# Required chip modules +chip-y=clock.o gpio.o system.o uart.o + +# Optional chip modules +chip-$(CONFIG_COMMON_TIMER)+=hrtimer.o +chip-$(CONFIG_I2C)+=i2c.o +chip-$(CONFIG_SPI)+=spi.o +chip-$(CONFIG_WATCHDOG)+=watchdog.o diff --git a/chip/mt_scp/clock.c b/chip/mt_scp/clock.c new file mode 100644 index 0000000000..524db8024a --- /dev/null +++ b/chip/mt_scp/clock.c @@ -0,0 +1,78 @@ +/* Copyright 2018 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. + */ + +/* Clocks, PLL and power settings */ + +#include "clock.h" +#include "common.h" +#include "registers.h" +#include "task.h" +#include "util.h" + +void clock_init(void) +{ + /* Set VREQ to HW mode */ + SCP_CPU_VREQ = CPU_VREQ_HW_MODE; + SCP_SECURE_CTRL &= ~ENABLE_SPM_MASK_VREQ; + + /* Set DDREN auto mode */ + SCP_SYS_CTRL |= AUTO_DDREN; + + /* Initialize 26MHz system clock counter reset value to 1. */ + SCP_CLK_SYS_VAL = + (SCP_CLK_SYS_VAL & ~CLK_SYS_VAL_MASK) | CLK_SYS_VAL(1); + /* Initialize high frequency ULPOSC counter reset value to 1. */ + SCP_CLK_HIGH_VAL = + (SCP_CLK_HIGH_VAL & ~CLK_HIGH_VAL_MASK) | CLK_HIGH_VAL(1); + /* Initialize sleep mode control VREQ counter. */ + SCP_CLK_SLEEP_CTRL = + (SCP_CLK_SLEEP_CTRL & ~VREQ_COUNTER_MASK) | VREQ_COUNTER_VAL(1); + + /* Set normal wake clock */ + SCP_WAKE_CKSW &= ~WAKE_CKSW_SEL_NORMAL_MASK; + + /* Enable fast wakeup support */ + SCP_CLK_SLEEP = 0; + SCP_CLK_ON_CTRL = (SCP_CLK_ON_CTRL & ~HIGH_FINAL_VAL_MASK) | + HIGH_FINAL_VAL_DEFAULT; + SCP_FAST_WAKE_CNT_END = + (SCP_FAST_WAKE_CNT_END & ~FAST_WAKE_CNT_END_MASK) | + FAST_WAKE_CNT_END_DEFAULT; + + /* Set slow wake clock */ + SCP_WAKE_CKSW = (SCP_WAKE_CKSW & ~WAKE_CKSW_SEL_SLOW_MASK) | + WAKE_CKSW_SEL_SLOW_DEFAULT; + + /* Select CLK_HIGH as wakeup clock */ + SCP_CLK_SLOW_SEL = (SCP_CLK_SLOW_SEL & + ~(CKSW_SEL_SLOW_MASK | CKSW_SEL_SLOW_DIV_MASK)) | + CKSW_SEL_SLOW_ULPOSC2_CLK; + + /* + * Set legacy wakeup + * - disable SPM sleep control + * - disable SCP sleep mode + */ + SCP_CLK_SLEEP_CTRL &= ~(EN_SLEEP_CTRL | SPM_SLEEP_MODE); + + task_enable_irq(SCP_IRQ_CLOCK); + task_enable_irq(SCP_IRQ_CLOCK2); +} + +void clock_control_irq(void) +{ + /* Read ack CLK_IRQ */ + (SCP_CLK_IRQ_ACK); + task_clear_pending_irq(SCP_IRQ_CLOCK); +} +DECLARE_IRQ(SCP_IRQ_CLOCK, clock_control_irq, 3); + +void clock_fast_wakeup_irq(void) +{ + /* Ack fast wakeup */ + SCP_SLEEP_IRQ2 = 1; + task_clear_pending_irq(SCP_IRQ_CLOCK2); +} +DECLARE_IRQ(SCP_IRQ_CLOCK2, clock_fast_wakeup_irq, 3); diff --git a/chip/mt_scp/config_chip.h b/chip/mt_scp/config_chip.h new file mode 100644 index 0000000000..fb303fe815 --- /dev/null +++ b/chip/mt_scp/config_chip.h @@ -0,0 +1,78 @@ +/* Copyright 2018 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 + +#include "core/cortex-m/config_core.h" + +/* Interval between HOOK_TICK notifications */ +#define HOOK_TICK_INTERVAL_MS 500 +#define HOOK_TICK_INTERVAL (HOOK_TICK_INTERVAL_MS * MSEC) + +/* Default to UART 2 (AP UART) for EC console */ +#define CONFIG_UART_CONSOLE 2 + +/* Number of IRQ vectors */ +#define CONFIG_IRQ_COUNT 56 + +/* + * Number of EINT can be 0 ~ 160. Change this to conditional macro + * on adding other variants. + */ +#define MAX_NUM_EINT 8 +#define MAX_EINT_PORT (MAX_NUM_EINT / 32) + +/* RW only, no flash + * +-------------------- 0x0 + * | free shared space with AP + * +-------------------- 0x005B0 + * | IPI shared buffer with AP (288 + 8) * 2 + * +-------------------- 0x00800 + * | scp.img, exception vectors starting location. + * +-------------------- 0x7B800 + * | free shared space with AP 2KB + * +-------------------- 0x7C000 + * | 8KB I-CACHE + * +-------------------- 0x7E000 + * | 8KB D-CACHE + * +-------------------- 0x80000 + */ +#undef CONFIG_FW_INCLUDE_RO +#define CONFIG_RAM_BASE 0x00800 +#define CONFIG_RAM_SIZE 0x7B000 +#define CONFIG_RO_MEM_OFF 0 +#define CONFIG_RO_SIZE 0 +#define CONFIG_RW_MEM_OFF 0 +#define CONFIG_RW_SIZE 0x40000 /* 256KB */ +#define CONFIG_EC_WRITABLE_STORAGE_OFF 0 +#define CONFIG_EC_PROTECTED_STORAGE_OFF 0 +#define CONFIG_RO_STORAGE_OFF 0 +#define CONFIG_RW_STORAGE_OFF 0 +#define CONFIG_PROGRAM_MEMORY_BASE 0 +#define CONFIG_MAPPED_STORAGE_BASE 0 + +/* Unsupported features/commands */ +#undef CONFIG_CMD_FLASHINFO +#undef CONFIG_CMD_POWER_AP +#undef CONFIG_FLASH +#undef CONFIG_FLASH_PHYSICAL +#undef CONFIG_FMAP +#undef CONFIG_HIBERNATE + +/* Task stack size */ +#define CONFIG_STACK_SIZE 1024 +#define IDLE_TASK_STACK_SIZE 256 +#define SMALLER_TASK_STACK_SIZE 384 +#define TASK_STACK_SIZE 488 +#define LARGER_TASK_STACK_SIZE 640 +#define VENTI_TASK_STACK_SIZE 768 + +#define CONFIG_CHIP_PRE_INIT + +#define GPIO_PIN(num) ((num) / 32), ((num) % 32) +#define GPIO_PIN_MASK(p, m) .port = (p), .mask = (m) + +#endif /* __CROS_EC_CONFIG_CHIP_H */ diff --git a/chip/mt_scp/gpio.c b/chip/mt_scp/gpio.c new file mode 100644 index 0000000000..7d680e6863 --- /dev/null +++ b/chip/mt_scp/gpio.c @@ -0,0 +1,177 @@ +/* Copyright 2018 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 */ + +#include "gpio.h" +#include "hooks.h" +#include "registers.h" +#include "system.h" +#include "task.h" +#include "util.h" + +void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func) +{ + int bit, mode_reg_index, shift; + uint32_t mode_bits, mode_mask; + + /* Up to 8 alt functions per port */ + if (func > 7) + return; + + while (mask) { + /* 32 gpio per port */ + bit = get_next_bit(&mask); + /* 8 gpio per mode reg */ + mode_reg_index = (port << 2) | (bit >> 3); + /* + * b[3] - write enable(?) + * b[2:0] - mode + */ + shift = (bit & 7) << 2; + mode_bits = func << shift; + mode_mask = ~(0xf << shift); + AP_GPIO_MODE(mode_reg_index) = (AP_GPIO_MODE(mode_reg_index) & + mode_mask) | mode_bits; + } +} + +test_mockable int gpio_get_level(enum gpio_signal signal) +{ + return !!(AP_GPIO_DIN(gpio_list[signal].port) & + gpio_list[signal].mask); +} + + +void gpio_set_level(enum gpio_signal signal, int value) +{ + if (value) + AP_GPIO_DOUT(gpio_list[signal].port) |= gpio_list[signal].mask; + else + AP_GPIO_DOUT(gpio_list[signal].port) &= ~gpio_list[signal].mask; +} + +void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags) +{ + /* Set input/output mode */ + if (flags & GPIO_OUTPUT) { + /* Set level before changing to output mode */ + if (flags & GPIO_HIGH) + AP_GPIO_DOUT(port) |= mask; + if (flags & GPIO_LOW) + AP_GPIO_DOUT(port) &= ~mask; + AP_GPIO_DIR(port) |= mask; + } else { + AP_GPIO_DIR(port) &= ~mask; + } + + if (flags & (GPIO_INT_F_RISING | GPIO_INT_F_HIGH)) + SCP_EINT_POLARITY_SET[port] = mask; + + if (flags & (GPIO_INT_F_FALLING | GPIO_INT_F_LOW)) + SCP_EINT_POLARITY_CLR[port] = mask; + else + SCP_EINT_POLARITY_SET[port] = mask; + + /* Set sensitivity register on edge trigger */ + if (flags & (GPIO_INT_F_RISING | GPIO_INT_F_FALLING)) + SCP_EINT_SENS_SET[port] = mask; + else + SCP_EINT_SENS_CLR[port] = mask; +} + +int gpio_get_flags_by_mask(uint32_t port, uint32_t mask) +{ + /* TODO(b/120167145): implement get flags */ + return 0; +} + +int gpio_enable_interrupt(enum gpio_signal signal) +{ + const struct gpio_info *g = gpio_list + signal; + + if (signal >= GPIO_IH_COUNT || !g->mask) + return EC_ERROR_INVAL; + + SCP_EINT_MASK_CLR[g->port] = g->mask; + + return EC_SUCCESS; +} + +int gpio_disable_interrupt(enum gpio_signal signal) +{ + const struct gpio_info *g = gpio_list + signal; + + if (signal >= GPIO_IH_COUNT || !g->mask) + return EC_ERROR_INVAL; + + SCP_EINT_MASK_SET[g->port] = g->mask; + + return EC_SUCCESS; +} + +int gpio_clear_pending_interrupt(enum gpio_signal signal) +{ + const struct gpio_info *g = gpio_list + signal; + + if (signal >= GPIO_IH_COUNT || !g->mask) + return EC_ERROR_INVAL; + + SCP_EINT_ACK[g->port] = g->mask; + + return EC_SUCCESS; +} + +void gpio_pre_init(void) +{ + const struct gpio_info *g = gpio_list; + int i; + int is_warm = system_is_reboot_warm(); + + for (i = 0; i < GPIO_COUNT; i++, g++) { + int flags = g->flags; + + if (flags & GPIO_DEFAULT) + continue; + + if (is_warm) + flags &= ~(GPIO_LOW | GPIO_HIGH); + + gpio_set_flags_by_mask(g->port, g->mask, flags); + } +} + +void gpio_init(void) +{ + /* Enable EINT IRQ */ + task_enable_irq(SCP_IRQ_EINT); +} +DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT); + +/* Interrupt handler */ +void __keep gpio_interrupt(void) +{ + int bit, port; + uint32_t pending; + enum gpio_signal signal; + + for (port = 0; port <= MAX_EINT_PORT; port++) { + pending = SCP_EINT_STATUS[port]; + + while (pending) { + bit = get_next_bit(&pending); + SCP_EINT_ACK[port] = (1 << bit); + /* Skip masked gpio */ + if (SCP_EINT_MASK_GET[port] & (1 << bit)) + continue; + /* Call handler */ + signal = port * 32 + bit; + if (signal < GPIO_IH_COUNT) + gpio_irq_handlers[signal](signal); + } + } +} +DECLARE_IRQ(SCP_IRQ_EINT, gpio_interrupt, 1); + diff --git a/chip/mt_scp/hrtimer.c b/chip/mt_scp/hrtimer.c new file mode 100644 index 0000000000..b0e72fd948 --- /dev/null +++ b/chip/mt_scp/hrtimer.c @@ -0,0 +1,235 @@ +/* Copyright 2018 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. + */ + +/* + * High-res hardware timer + * + * SCP hardware 32bit count down timer can be configured to source clock from + * 32KHz, 26MHz, BCLK or PCLK. This implementation selects 26MHz frequency + * countdown and converts to micro second value matching common timer. + */ + +#include "clock.h" +#include "common.h" +#include "console.h" +#include "hooks.h" +#include "hwtimer.h" +#include "panic.h" +#include "registers.h" +#include "task.h" +#include "timer.h" +#include "watchdog.h" + +#define IRQ_TIMER(n) CONCAT2(SCP_IRQ_TIMER, n) + +#define TIMER_SYSTEM 5 +#define TIMER_EVENT 3 + +/* Common timer overflows at 0x100000000 micro seconds */ +#define OVERFLOW_TICKS (26 * 0x100000000 - 1) + +static uint8_t sys_high; +static uint8_t event_high; + +/* Convert hardware countdown timer to 64bit countup ticks */ +static inline uint64_t timer_read_raw_system(void) +{ + /* TODO(b/120173036): fix racing condition in read_raw */ + return OVERFLOW_TICKS - (((uint64_t)sys_high << 32) | + SCP_TIMER_VAL(TIMER_SYSTEM)); +} + +static inline uint64_t timer_read_raw_event(void) +{ + return OVERFLOW_TICKS - (((uint64_t)event_high << 32) | + SCP_TIMER_VAL(TIMER_EVENT)); +} + +static inline void timer_set_clock(int n, uint32_t clock_source) +{ + SCP_TIMER_EN(n) = (SCP_TIMER_EN(n) & ~TIMER_CLK_MASK) | + clock_source; +} + +static inline void timer_ack_irq(int n) +{ + SCP_TIMER_IRQ_CTRL(n) |= TIMER_IRQ_CLEAR; +} + +/* Set hardware countdown value */ +static inline void timer_set_reset_value(int n, uint32_t reset_value) +{ + SCP_TIMER_RESET_VAL(n) = reset_value; +} + +static void timer_reset(int n) +{ + __hw_timer_enable_clock(n, 0); + timer_ack_irq(n); + timer_set_reset_value(n, 0xffffffff); + timer_set_clock(n, TIMER_CLK_32K); +} + +/* Reload a new 32bit countdown value */ +static void timer_reload(int n, uint32_t value) +{ + __hw_timer_enable_clock(n, 0); + timer_set_reset_value(n, value); + __hw_timer_enable_clock(n, 1); +} + +static int timer_reload_event_high(void) +{ + if (event_high) { + if (SCP_TIMER_RESET_VAL(TIMER_EVENT) == 0xffffffff) + __hw_timer_enable_clock(TIMER_EVENT, 1); + else + timer_reload(TIMER_EVENT, 0xffffffff); + event_high--; + return 1; + } + + /* Disable event timer clock when done. */ + __hw_timer_enable_clock(TIMER_EVENT, 0); + return 0; +} + +void __hw_clock_event_clear(void) +{ + __hw_timer_enable_clock(TIMER_EVENT, 0); + timer_set_reset_value(TIMER_EVENT, 0x0000c1ea4); + event_high = 0; +} + +void __hw_clock_event_set(uint32_t deadline) +{ + uint64_t deadline_raw = (uint64_t)deadline * 26; + uint64_t now_raw = timer_read_raw_system(); + uint32_t event_deadline; + + if (deadline_raw > now_raw) { + deadline_raw -= now_raw; + event_deadline = (uint32_t)deadline_raw; + event_high = deadline_raw >> 32; + } else { + event_deadline = 1; + event_high = 0; + } + + if (event_deadline) + timer_reload(TIMER_EVENT, event_deadline); + else + timer_reload_event_high(); +} + +void __hw_timer_enable_clock(int n, int enable) +{ + if (enable) { + SCP_TIMER_IRQ_CTRL(n) |= 1; + SCP_TIMER_EN(n) |= 1; + } else { + SCP_TIMER_EN(n) &= ~1; + SCP_TIMER_IRQ_CTRL(n) &= ~1; + } +} + +int __hw_clock_source_init(uint32_t start_t) +{ + int t; + + /* + * TODO(b/120169529): check clock tree to see if we need to turn on + * MCLK and BCLK gate. + */ + SCP_CLK_GATE |= (CG_TIMER_M | CG_TIMER_B); + + /* Reset all timer, select 32768Hz clock source */ + for (t = 0; t < NUM_TIMERS; t++) + timer_reset(t); + + /* Enable timer IRQ wake source */ + SCP_INTC_IRQ_WAKEUP |= (1 << IRQ_TIMER(0)) | (1 << IRQ_TIMER(1)) | + (1 << IRQ_TIMER(2)) | (1 << IRQ_TIMER(3)) | + (1 << IRQ_TIMER(4)) | (1 << IRQ_TIMER(5)); + /* + * Timer configuration: + * OS TIMER - count up @ 13MHz, 64bit value with latch. + * SYS TICK - count down @ 26MHz + * EVENT TICK - count down @ 26MHz + */ + + /* Turn on OS TIMER, tick at 13MHz */ + SCP_OSTIMER_CON |= 1; + + /* System timestamp timer */ + timer_set_clock(TIMER_SYSTEM, TIMER_CLK_26M); + sys_high = 25; + timer_set_reset_value(TIMER_SYSTEM, 0xffffffff); + __hw_timer_enable_clock(TIMER_SYSTEM, 1); + task_enable_irq(IRQ_TIMER(TIMER_SYSTEM)); + /* Event tick timer */ + timer_set_clock(TIMER_EVENT, TIMER_CLK_26M); + task_enable_irq(IRQ_TIMER(TIMER_EVENT)); + + return IRQ_TIMER(TIMER_SYSTEM); +} + +uint32_t __hw_clock_source_read(void) +{ + return timer_read_raw_system() / 26; +} + +uint32_t __hw_clock_event_get(void) +{ + return (timer_read_raw_event() + timer_read_raw_system()) / 26; +} + +static void __hw_clock_source_irq(int n) +{ + uint32_t timer_ctrl = SCP_TIMER_IRQ_CTRL(n); + + /* Ack if we're hardware interrupt */ + if (timer_ctrl & TIMER_IRQ_STATUS) + timer_ack_irq(n); + + switch (n) { + case TIMER_EVENT: + if (timer_ctrl & TIMER_IRQ_STATUS) { + if (timer_reload_event_high()) + return; + } + process_timers(0); + break; + case TIMER_SYSTEM: + /* If this is a hardware irq, check overflow */ + if (timer_ctrl & TIMER_IRQ_STATUS) { + if (sys_high) { + sys_high--; + process_timers(0); + } else { + /* Overflow, reload system timer */ + sys_high = 25; + process_timers(1); + } + } else { + process_timers(0); + } + break; + default: + return; + } + +} + +#define DECLARE_TIMER_IRQ(n) \ + void __hw_clock_source_irq_##n(void) { __hw_clock_source_irq(n); } \ + DECLARE_IRQ(IRQ_TIMER(n), __hw_clock_source_irq_##n, 2) + +DECLARE_TIMER_IRQ(0); +DECLARE_TIMER_IRQ(1); +DECLARE_TIMER_IRQ(2); +DECLARE_TIMER_IRQ(3); +DECLARE_TIMER_IRQ(4); +DECLARE_TIMER_IRQ(5); diff --git a/chip/mt_scp/registers.h b/chip/mt_scp/registers.h new file mode 100644 index 0000000000..3f88099e53 --- /dev/null +++ b/chip/mt_scp/registers.h @@ -0,0 +1,430 @@ +/* Copyright 2018 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 SCP + */ + +#ifndef __CROS_EC_REGISTERS_H +#define __CROS_EC_REGISTERS_H + +#include "common.h" + +/* IRQ numbers */ +#define SCP_IRQ_IPC0 0 +#define SCP_IRQ_IPC1 1 +#define SCP_IRQ_IPC2 2 +#define SCP_IRQ_IPC3 3 +#define SCP_IRQ_SPM 4 +#define SCP_IRQ_CIRQ 5 +#define SCP_IRQ_EINT 6 +#define SCP_IRQ_PMIC 7 +#define SCP_IRQ_UART0 8 +#define SCP_IRQ_UART1 9 +#define SCP_IRQ_I2C0 10 +#define SCP_IRQ_I2C1 11 +#define SCP_IRQ_I2C2 12 +#define SCP_IRQ_CLOCK 13 +#define SCP_IRQ_MAD_FIFO 14 +#define SCP_IRQ_TIMER0 15 +#define SCP_IRQ_TIMER1 16 +#define SCP_IRQ_TIMER2 17 +#define SCP_IRQ_TIMER3 18 +#define SCP_IRQ_TIMER4 19 +#define SCP_IRQ_TIMER5 20 +#define SCP_IRQ_TIMER_STATUS 21 +#define SCP_IRQ_UART0_RX 22 +#define SCP_IRQ_UART1_RX 23 +#define SCP_IRQ_DMA 24 +#define SCP_IRQ_AUDIO 25 +#define SCP_IRQ_MD1_F216 26 +#define SCP_IRQ_MD1 27 +#define SCP_IRQ_C2K 28 +#define SCP_IRQ_SPI0 29 +#define SCP_IRQ_SPI1 30 +#define SCP_IRQ_SPI2 31 +#define SCP_IRQ_AP_EINT 32 +#define SCP_IRQ_DEBUG 33 +#define SCP_CCIF0 34 +#define SCP_CCIF1 35 +#define SCP_CCIF2 36 +#define SCP_IRQ_WDT 37 +#define SCP_IRQ_USB0 38 +#define SCP_IRQ_USB1 39 +#define SCP_IRQ_TWAM 40 +#define SCP_IRQ_INFRA 41 +#define SCP_IRQ_HWDVFS_HIGH 42 +#define SCP_IRQ_HWDVFS_LOW 43 +#define SCP_IRQ_CLOCK2 44 +/* RESERVED 45-52 */ +#define SCP_IRQ_AP_EINT2 53 +#define SCP_IRQ_AP_EINT_EVT 54 +#define SCP_IRQ_MAD_DATA 55 + +#define SCP_CFG_BASE 0x405C0000 + +#define SCP_AP_RESOURCE REG32(SCP_CFG_BASE + 0x04) +#define SCP_BUS_RESOURCE REG32(SCP_CFG_BASE + 0x08) + +/* SCP to host interrupt */ +#define SCP_HOST_INT REG32(SCP_CFG_BASE + 0x1C) +#define IPC_SCP2HOST_SSHUB 0xff0000 +#define WDT_INT 0x100 +#define IPC_SCP2HOST 0xff + +/* SCP to SPM interrupt */ +#define SCP_SPM_INT REG32(SCP_CFG_BASE + 0x20) +#define SCP_SPM_INT2 REG32(SCP_CFG_BASE + 0x24) + +#define SCP_GIPC_IN REG32(SCP_CFG_BASE + 0x28) +#define SCP_CONN_INT REG32(SCP_CFG_BASE + 0x2C) + +/* 8 general purpose registers, 0 ~ 7 */ +#define SCP_GPR REG32_ADDR(SCP_CFG_BASE + 0x50) +/* + * SCP_GPR[0] + * b15-b0 : scratchpad + * b31-b16 : saved flags + * SCP_GPR[1] + * b15-b0 : power on state + */ +#define SCP_PWRON_STATE SCP_GPR[1] +#define PWRON_DEFAULT 0xdee80000 +#define PWRON_WATCHDOG (1 << 0) +#define PWRON_RESET (1 << 1) +/* AP defined features */ +#define SCP_EXPECTED_FREQ SCP_GPR[3] +#define SCP_CURRENT_FREQ SCP_GPR[4] +#define SCP_REBOOT SCP_GPR[5] +#define READY_TO_REBOOT 0x34 +#define REBOOT_OK 1 + +/* Miscellaneous */ +#define SCP_SEMAPHORE REG32(SCP_CFG_BASE + 0x90) +#define CORE_CONTROL REG32(SCP_CFG_BASE + 0xA0) +#define CORE_FPU_FLAGS REG32(SCP_CFG_BASE + 0xA4) +#define CORE_REG_SP REG32(SCP_CFG_BASE + 0xA8) +#define CORE_REG_LR REG32(SCP_CFG_BASE + 0xAC) +#define CORE_REG_PSP REG32(SCP_CFG_BASE + 0xB0) +#define CORE_REG_PC REG32(SCP_CFG_BASE + 0xB4) +#define SCP_SLP_PROTECT_CFG REG32(SCP_CFG_BASE + 0xC8) +#define SCP_ONE_TIME_LOCK REG32(SCP_CFG_BASE + 0xDC) +#define SCP_SECURE_CTRL REG32(SCP_CFG_BASE + 0xE0) +#define ENABLE_SPM_MASK_VREQ (1 << 28) +#define DISABLE_REMAP (1 << 22) +#define DISABLE_JTAG (1 << 21) +#define DISABLE_AP_TCM (1 << 20) +#define SCP_SYS_CTRL REG32(SCP_CFG_BASE + 0xE4) +#define DDREN_FIX_VALUE (1 << 28) +#define AUTO_DDREN (1 << 18) + +/* Memory remap control */ +#define SCP_REMAP_CFG1 REG32(SCP_CFG_BASE + 0x120) +#define SCP_REMAP_CFG2 REG32(SCP_CFG_BASE + 0x124) +#define SCP_REMAP_CFG3 REG32(SCP_CFG_BASE + 0x128) +#define SCP_L1_REMAP_CFG0 REG32(SCP_CFG_BASE + 0x130) +#define SCP_L1_REMAP_CFG1 REG32(SCP_CFG_BASE + 0x130) +#define SCP_L1_REMAP_CFG2 REG32(SCP_CFG_BASE + 0x134) +#define SCP_L1_REMAP_CFG3 REG32(SCP_CFG_BASE + 0x138) +#define SCP_L1_REMAP_OTHER REG32(SCP_CFG_BASE + 0x13C) + +/* INTC control */ +#define SCP_INTC_BASE (SCP_CFG_BASE + 0x2000) +#define SCP_INTC_IRQ_STATUS REG32(SCP_INTC_BASE) +#define SCP_INTC_IRQ_ENABLE REG32(SCP_INTC_BASE + 0x04) +#define SCP_INTC_IRQ_OUTPUT REG32(SCP_INTC_BASE + 0x08) +#define SCP_INTC_IRQ_WAKEUP REG32(SCP_INTC_BASE + 0x0C) +#define SCP_INTC_NMI REG32(SCP_INTC_BASE + 0x10) +#define SCP_INTC_SPM_WAKEUP REG32(SCP_INTC_BASE + 0x14) +#define SCP_INTC_SPM_WAKEUP_MSB REG32(SCP_INTC_BASE + 0x18) +#define SCP_INTC_UART_RX_IRQ REG32(SCP_INTC_BASE + 0x1C) +#define SCP_INTC_IRQ_STATUS_MSB REG32(SCP_INTC_BASE + 0x80) +#define SCP_INTC_IRQ_ENABLE_MSB REG32(SCP_INTC_BASE + 0x84) +#define SCP_INTC_IRQ_OUTPUT_MSB REG32(SCP_INTC_BASE + 0x88) +#define SCP_INTC_IRQ_WAKEUP_MSB REG32(SCP_INTC_BASE + 0x8C) + +/* Timer */ +#define NUM_TIMERS 6 +#define SCP_TIMER_BASE(n) (SCP_CFG_BASE + 0x3000 + (0x10 * (n))) +#define SCP_TIMER_EN(n) REG32(SCP_TIMER_BASE(n)) +#define SCP_TIMER_RESET_VAL(n) REG32(SCP_TIMER_BASE(n) + 0x04) +#define SCP_TIMER_VAL(n) REG32(SCP_TIMER_BASE(n) + 0x08) +#define SCP_TIMER_IRQ_CTRL(n) REG32(SCP_TIMER_BASE(n) + 0x0C) +#define TIMER_IRQ_ENABLE (1 << 0) +#define TIMER_IRQ_STATUS (1 << 4) +#define TIMER_IRQ_CLEAR (1 << 5) +#define SCP_TIMER_CLK_SEL(n) REG32(SCP_TIMER_BASE(n) + 0x40) +#define TIMER_CLK_32K (0 << 4) +#define TIMER_CLK_26M (1 << 4) +#define TIMER_CLK_BCLK (2 << 4) +#define TIMER_CLK_PCLK (3 << 4) +#define TIMER_CLK_MASK (3 << 4) +/* OS timer */ +#define SCP_OSTIMER_BASE (SCP_CFG_BASE + 0x3080) +#define SCP_OSTIMER_CON REG32(SCP_OSTIMER_BASE) +#define SCP_OSTIMER_INIT_L REG32(SCP_OSTIMER_BASE + 0x04) +#define SCP_OSTIMER_INIT_H REG32(SCP_OSTIMER_BASE + 0x08) +#define SCP_OSTIMER_VAL_L REG32(SCP_OSTIMER_BASE + 0x0C) +#define SCP_OSTIMER_VAL_H REG32(SCP_OSTIMER_BASE + 0x10) +#define SCP_OSTIMER_TVAL REG32(SCP_OSTIMER_BASE + 0x14) +#define SCP_OSTIMER_IRQ_ACK REG32(SCP_OSTIMER_BASE + 0x18) +#define OSTIMER_LATCH0_EN (1 << 5) +#define OSTIMER_LATCH1_EN (1 << 13) +#define OSTIMER_LATCH2_EN (1 << 21) +#define SCP_OSTIMER_LATCH_CTRL REG32(SCP_OSTIMER_BASE + 0x20) +#define SCP_OSTIMER_LATCH0_L REG32(SCP_OSTIMER_BASE + 0x24) +#define SCP_OSTIMER_LATCH0_H REG32(SCP_OSTIMER_BASE + 0x28) +#define SCP_OSTIMER_LATCH1_L REG32(SCP_OSTIMER_BASE + 0x2C) +#define SCP_OSTIMER_LATCH1_H REG32(SCP_OSTIMER_BASE + 0x30) +#define SCP_OSTIMER_LATCH2_L REG32(SCP_OSTIMER_BASE + 0x34) +#define SCP_OSTIMER_LATCH2_H REG32(SCP_OSTIMER_BASE + 0x38) + +/* Clock, PMIC wrapper, etc. */ +#define SCP_CLK_BASE (SCP_CFG_BASE + 0x4000) +#define SCP_CLK_SEL REG32(SCP_CLK_BASE) +#define SCP_CLK_EN REG32(SCP_CLK_BASE + 0x04) +#define EN_CLK_SYS (1 << 0) /* System clock */ +#define EN_CLK_HIGH (1 << 1) /* ULPOSC */ +#define CG_CLK_HIGH (1 << 2) +#define EN_SYS_IRQ (1 << 16) +#define EN_HIGH_IRQ (1 << 17) +#define SCP_CLK_SAFE_ACK REG32(SCP_CLK_BASE + 0x08) +#define SCP_CLK_ACK REG32(SCP_CLK_BASE + 0x0C) +#define SCP_CLK_IRQ_ACK REG32(SCP_CLK_BASE + 0x10) +/* + * System clock counter value. + * CLK_SYS_VAL[9:0] System clock counter initial/reset value. + */ +#define SCP_CLK_SYS_VAL REG32(SCP_CLK_BASE + 0x14) +#define CLK_SYS_VAL_MASK 0x3ff /* 10 bits */ +#define CLK_SYS_VAL(n) ((n) & CLK_SYS_VAL_MASK) +/* + * ULPOSC clock counter value. + * CLK_HIGH_VAL[9:0] ULPOSC clock counter initial/reset value. + */ +#define SCP_CLK_HIGH_VAL REG32(SCP_CLK_BASE + 0x18) +#define CLK_HIGH_VAL_MASK 0x3ff /* 10 bits */ +#define CLK_HIGH_VAL(n) ((n) & CLK_HIGH_VAL_MASK) +#define SCP_CLK_SLOW_SEL REG32(SCP_CLK_BASE + 0x1C) +#define CKSW_SEL_SLOW_MASK 0x3 +#define CKSW_SEL_SLOW_DIV_MASK 0x30 +#define CKSW_SEL_SLOW_SYS_CLK 0 +#define CKSW_SEL_SLOW_32K_CLK 1 +#define CKSW_SEL_SLOW_ULPOSC1_CLK 2 +#define CKSW_SEL_SLOW_ULPOSC2_CLK 3 +/* + * Sleep mode control. + * VREQ_COUNT[7:1] Number of cycles to wait when requesting PMIC to raise the + * voltage after returning from sleep mode. + */ +#define SCP_CLK_SLEEP_CTRL REG32(SCP_CLK_BASE + 0x20) +#define EN_SLEEP_CTRL (1 << 0) +#define VREQ_COUNTER_MASK 0xfe +#define VREQ_COUNTER_VAL(v) (((v) << 1) & VREQ_COUNTER_MASK) +#define SPM_SLEEP_MODE (1 << 8) +#define SPM_SLEEP_MODE_CLK_AO (1 << 9) +#define SCP_CLK_DIV_SEL REG32(SCP_CLK_BASE + 0x24) +#define SCP_CLK_DEBUG REG32(SCP_CLK_BASE + 0x28) +#define SCP_CLK_SRAM_POWERDOWN REG32(SCP_CLK_BASE + 0x2C) +#define SCP_CLK_GATE REG32(SCP_CLK_BASE + 0x30) +#define CG_TIMER_M (1 << 0) +#define CG_TIMER_B (1 << 1) +#define CG_MAD_M (1 << 2) +#define CG_I2C_M (1 << 3) +#define CG_I2C_B (1 << 4) +#define CG_GPIO_M (1 << 5) +#define CG_AP2P_M (1 << 6) +#define CG_UART_M (1 << 7) +#define CG_UART_B (1 << 8) +#define CG_UART_RSTN (1 << 9) +#define CG_UART1_M (1 << 10) +#define CG_UART1_B (1 << 11) +#define CG_UART1_RSTN (1 << 12) +#define CG_SPI0 (1 << 13) +#define CG_SPI1 (1 << 14) +#define CG_SPI2 (1 << 15) +#define CG_DMA_CH0 (1 << 16) +#define CG_DMA_CH1 (1 << 17) +#define CG_DMA_CH2 (1 << 18) +#define CG_DMA_CH3 (1 << 19) +#define CG_TWAM (1 << 20) +#define CG_CACHE_I_CTRL (1 << 21) +#define CG_CACHE_D_CTRL (1 << 22) +#define SCP_PMICW_CTRL REG32(SCP_CLK_BASE + 0x34) +#define PMICW_SLEEP_REQ (1 << 0) +#define PMICW_SLEEP_ACK (1 << 4) +#define PMICW_CLK_MUX (1 << 8) +#define PMICW_DCM (1 << 9) +#define SCP_SLEEP_WAKE_DEBUG REG32(SCP_CLK_BASE + 0x38) +#define SCP_DCM_EN REG32(SCP_CLK_BASE + 0x3C) +#define SCP_WAKE_CKSW REG32(SCP_CLK_BASE + 0x40) +#define WAKE_CKSW_SEL_NORMAL_MASK 0x3 +#define WAKE_CKSW_SEL_SLOW_MASK 0x30 +#define WAKE_CKSW_SEL_SLOW_DEFAULT 0x10 +#define SCP_CLK_UART REG32(SCP_CLK_BASE + 0x44) +#define SCP_CLK_BCK REG32(SCP_CLK_BASE + 0x48) +#define SCP_CLK_SPI_BCK REG32(SCP_CLK_BASE + 0x4C) +#define SCP_CLK_DIV_CNT REG32(SCP_CLK_BASE + 0x50) +#define SCP_CPU_VREQ REG32(SCP_CLK_BASE + 0x54) +#define CPU_VREQ_HW_MODE 0x10001 +#define SCP_CLK_CLEAR REG32(SCP_CLK_BASE + 0x58) +#define SCP_CLK_HIGH_CORE REG32(SCP_CLK_BASE + 0x5C) +#define SCP_SLEEP_IRQ2 REG32(SCP_CLK_BASE + 0x64) +#define SCP_CLK_ON_CTRL REG32(SCP_CLK_BASE + 0x6C) +#define HIGH_AO (1 << 0) +#define HIGH_CG_AO (1 << 2) +#define HIGH_CORE_AO (1 << 4) +#define HIGH_CORE_DIS_SUB (1 << 5) +#define HIGH_CORE_CG_AO (1 << 6) +#define HIGH_FINAL_VAL_MASK 0x1f00 +#define HIGH_FINAL_VAL_DEFAULT 0x300 +#define SCP_CLK_L1_SRAM_PD REG32(SCP_CLK_BASE + 0x80) +#define SCP_CLK_TCM_TAIL_SRAM_PD REG32(SCP_CLK_BASE + 0x94) +#define SCP_CLK_SLEEP REG32(SCP_CLK_BASE + 0xA0) +#define SLOW_WAKE_DISABLE 1 +#define SCP_FAST_WAKE_CNT_END REG32(SCP_CLK_BASE + 0xA4) +#define FAST_WAKE_CNT_END_MASK 0xfff +#define FAST_WAKE_CNT_END_DEFAULT 0x18 +#define MEM_CK_CS_ISO_CNT_END_MASK 0x7f0000 + +/* Peripherals */ +#define SCP_I2C0_BASE (SCP_CFG_BASE + 0x5000) +#define SCP_I2C1_BASE (SCP_CFG_BASE + 0x6000) +#define SCP_I2C2_BASE (SCP_CFG_BASE + 0x7000) + +#define SCP_GPIO_BASE (SCP_CFG_BASE + 0x8000) +#define SCP_UART0_BASE (SCP_CFG_BASE + 0x9000) +#define SCP_UART1_BASE (SCP_CFG_BASE + 0xE000) +#define SCP_UART_COUNT 2 + +/* External GPIO interrupt */ +#define SCP_EINT_BASE (SCP_CFG_BASE + 0xA000) +#define SCP_EINT_STATUS REG32_ADDR(SCP_EINT_BASE) +#define SCP_EINT_ACK REG32_ADDR(SCP_EINT_BASE + 0x040) +#define SCP_EINT_MASK_GET REG32_ADDR(SCP_EINT_BASE + 0x080) +#define SCP_EINT_MASK_SET REG32_ADDR(SCP_EINT_BASE + 0x0C0) +#define SCP_EINT_MASK_CLR REG32_ADDR(SCP_EINT_BASE + 0x100) +#define SCP_EINT_SENS_GET REG32_ADDR(SCP_EINT_BASE + 0x140) +#define SCP_EINT_SENS_SET REG32_ADDR(SCP_EINT_BASE + 0x180) +#define SCP_EINT_SENS_CLR REG32_ADDR(SCP_EINT_BASE + 0x1C0) +#define SCP_EINT_SOFT_GET REG32_ADDR(SCP_EINT_BASE + 0x200) +#define SCP_EINT_SOFT_SET REG32_ADDR(SCP_EINT_BASE + 0x240) +#define SCP_EINT_SOFT_CLR REG32_ADDR(SCP_EINT_BASE + 0x280) +#define SCP_EINT_POLARITY_GET REG32_ADDR(SCP_EINT_BASE + 0x300) +#define SCP_EINT_POLARITY_SET REG32_ADDR(SCP_EINT_BASE + 0x340) +#define SCP_EINT_POLARITY_CLR REG32_ADDR(SCP_EINT_BASE + 0x380) +#define SCP_EINT_D0_EN REG32_ADDR(SCP_EINT_BASE + 0x400) +#define SCP_EINT_D1_EN REG32_ADDR(SCP_EINT_BASE + 0x420) +#define SCP_EINT_DBNC_GET REG32_ADDR(SCP_EINT_BASE + 0x500) +#define SCP_EINT_DBNC_SET REG32_ADDR(SCP_EINT_BASE + 0x600) +#define SCP_EINT_DBNC_CLR REG32_ADDR(SCP_EINT_BASE + 0x700) + +#define SCP_PMICWP2P_BASE (SCP_CFG_BASE + 0xB000) +#define PMICW_WACS_CMD REG32(SCP_PMICWP2P + 0x200) +#define PMICW_WACS_RDATA REG32(SCP_PMICWP2P + 0x204) +#define PMICW_WACS_VLDCLR REG32(SCP_PMICWP2P + 0x208) +#define SCP_SPMP2P_BASE (SCP_CFG_BASE + 0xC000) +#define SCP_DMA_BASE (SCP_CFG_BASE + 0xD000) +#define DMA_ACKINT_CHX REG32(SCP_DMA_BASE + 0x20) +#define SCP_SPI0_BASE (SCP_CFG_BASE + 0xF000) +#define SCP_SPI1_BASE (SCP_CFG_BASE + 0x10000) +#define SCP_SPI2_BASE (SCP_CFG_BASE + 0x11000) + +/* ARMV7 regs */ +#define ARM_SCB_SCR REG32(0xE000ED10) +#define SCR_DEEPSLEEP (1 << 2) + +/* AP regs */ +#define AP_BASE 0xA0000000 +#define TOPCK_BASE AP_BASE /* Top clock */ +#define SCP_UART2_BASE (AP_BASE + 0x01002000) /* AP UART0 */ + +/* GPIO */ +#define AP_GPIO_BASE (AP_BASE + 0x00005000) +/* + * AP_GPIO_DIR + * GPIO input/out direction, 1 bit per pin. + * 0:input 1:output + */ +#define AP_GPIO_DIR(n) REG32(AP_GPIO_BASE + ((n) << 4)) +/* + * AP_GPIO_DOUT, n in [0..5] + * GPIO output level, 1 bit per pin + * 0:low 1:high + */ +#define AP_GPIO_DOUT(n) REG32(AP_GPIO_BASE + 0x100 + ((n) << 4)) +/* + * AP_GPIO_DIN, n in [0..5] + * GPIO input level, 1 bit per pin + * 0:low 1:high + */ +#define AP_GPIO_DIN(n) REG32(AP_GPIO_BASE + 0x200 + ((n) << 4)) +/* + * AP_GPIO_MODE, n in [0..22] + * Pin mode selection, 4 bit per pin + * bit3 - write enable, set to 1 for hw to fetch bit2,1,0. + * bit2-0 - mode 0 ~ 7 + */ +#define AP_GPIO_MODE(n) REG32(AP_GPIO_BASE + 0x300 + ((n) << 4)) +#define AP_GPIO_TRAP REG32(AP_GPIO_BASE + 0x6B0) +#define AP_GPIO_DUMMY REG32(AP_GPIO_BASE + 0x6C0) +#define AP_GPIO_DBG REG32(AP_GPIO_BASE + 0x6D0) +#define AP_GPIO_BANK REG32(AP_GPIO_BASE + 0x6E0) +/* AP_GPIO_SEC, n in [0..5] */ +#define AP_GPIO_SEC(n) REG32(AP_GPIO_BASE + 0xF00 + ((n) << 4)) + +/* + * PLL ULPOSC + * ULPOSC1: AP_ULPOSC_CON[0] AP_ULPOSC_CON[1] + * ULPOSC2: AP_ULPOSC_CON[2] AP_ULPOSC_CON[3] + * osc: 1 for ULPOSC1, 2 for ULPSOC2. + */ +#define AP_ULPOSC_BASE0 (AP_BASE + 0xC700 - 0x8) +#define AP_ULPOSC_BASE1 (AP_BASE + 0xC704 - 0x8) +#define AP_ULPOSC_CON02(osc) REG32(AP_ULPOSC_BASE0 + (osc) * 0x8) +#define AP_ULPOSC_CON13(osc) REG32(AP_ULPOSC_BASE1 + (osc) * 0x8) +/* + * AP_ULPOSC_CON[0,2] + * bit0-5: calibration + * bit6-12: I-band + * bit13-16: F-band + * bit17-22: div + * bit23: CP_EN + * bit24-31: reserved + */ +#define OSC_CALI_MSK (0x3f << 0) +#define OSC_IBAND_MASK (0x7f << 6) +#define OSC_FBAND_MASK (0x0f << 13) +#define OSC_DIV_MASK (0x1f << 17) +#define OSC_CP_EN (1 << 23) +#define OSC_RESERVED_MASK (0xff << 24) +/* AP_ILPOSC_CON[1,3] */ +#define OSC_MOD_MASK (0x03 << 0) +#define OSC_DIV2_EN (1 << 2) + +#define DUMMY_GPIO_BANK 0 + +#ifndef __ASSEMBLER__ + +/* Cortex-M4 mod */ +#define CM4_MODIFICATION REG32(0xE00FE000) +#define CM4_DCM_FEATURE REG32(0xE00FE004) +/* UART, 16550 compatible */ +#define SCP_UART_BASE(n) CONCAT3(SCP_UART, n, _BASE) +#define UART_REG(n, offset) REG32_ADDR(SCP_UART_BASE(n))[offset] +#define UART_IRQ(n) CONCAT2(SCP_IRQ_UART, n) +#define UART_RX_IRQ(n) CONCAT3(SCP_IRQ_UART, n, _RX) + +/* Watchdog */ +#define SCP_WDT_BASE (SCP_CFG_BASE + 0x84) +#define SCP_WDT_REG(offset) REG32(SCP_WDT_BASE + offset) +#define SCP_WDT_CFG SCP_WDT_REG(0) +#define SCP_WDT_FREQ 33825 +#define SCP_WDT_MAX_PERIOD 0xFFFFF /* 31 seconds */ +#define SCP_WDT_PERIOD(ms) (SCP_WDT_FREQ * (ms) / 1000) +#define SCP_WDT_ENABLE (1 << 31) +#define SCP_WDT_RELOAD SCP_WDT_REG(4) +#define SCP_WDT_RELOAD_VALUE 1 + +#endif /* !__ASSEMBLER__ */ +#endif /* __CROS_EC_REGISTERS_H */ diff --git a/chip/mt_scp/serial_reg.h b/chip/mt_scp/serial_reg.h new file mode 100644 index 0000000000..a23b19ded3 --- /dev/null +++ b/chip/mt_scp/serial_reg.h @@ -0,0 +1,90 @@ +/* Copyright 2018 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 register map + */ + +#ifndef __CROS_EC_SERIAL_REG_H +#define __CROS_EC_SERIAL_REG_H + +#include "registers.h" + +/* Number of hardware ports */ +#define HW_UART_PORTS 2 + +/* DLAB (Divisor Latch Access Bit) == 0 */ + +/* Data register + * (Read) Rcvr buffer register + * (Write) Xmit holding register + */ +#define UART_DATA(n) UART_REG(n, 0) +/* (Write) Interrupt enable register */ +#define UART_IER(n) UART_REG(n, 1) +#define UART_IER_RDI (1 << 0) /* Recv data int */ +#define UART_IER_THRI (1 << 1) /* Xmit holding register int */ +#define UART_IER_RLSI (1 << 2) /* Rcvr line status int */ +#define UART_IER_MSI (1 << 3) /* Modem status int */ +/* (Read) Interrupt ID register */ +#define UART_IIR(n) UART_REG(n, 2) +#define UART_IIR_NO_INT (1 << 0) /* No int pending */ +#define UART_IIR_ID_MASK 0x0e /* Interrupt ID mask */ +#define UART_IIR_MSI 0x00 +#define UART_IIR_THRI 0x02 +#define UART_IIR_RDI 0x04 +#define UART_IIR_RLSI 0x06 +#define UART_IIR_BUSY 0x07 /* DW APB busy */ +/* (Write) FIFO control register */ +#define UART_FCR(n) UART_REG(n, 2) +#define UART_FCR_ENABLE_FIFO (1 << 0) /* Enable FIFO */ +#define UART_FCR_CLEAR_RCVR (1 << 1) /* Clear rcvr FIFO */ +#define UART_FCR_CLEAR_XMIT (1 << 2) /* Clear xmit FIFO */ +#define UART_FCR_DMA_SELECT (1 << 3) +/* FIFO trigger levels */ +#define UART_FCR_T_TRIG_00 0x00 +#define UART_FCR_T_TRIG_01 0x10 +#define UART_FCR_T_TRIG_10 0x20 +#define UART_FCR_T_TRIG_11 0x30 +#define UART_FCR_R_TRIG_00 0x00 +#define UART_FCR_R_TRIG_01 0x40 +#define UART_FCR_R_TRIG_10 0x80 +#define UART_FCR_R_TRIG_11 0x80 +/* (Write) Line control register */ +#define UART_LCR(n) UART_REG(n, 3) +#define UART_LCR_WLEN5 0 /* Word length 5 bits */ +#define UART_LCR_WLEN6 1 +#define UART_LCR_WLEN7 2 +#define UART_LCR_WLEN8 3 +#define UART_LCR_STOP (1 << 2) /* Stop bits: 1bit, 2bits */ +#define UART_LCR_PARITY (1 << 3) /* Parity enable */ +#define UART_LCR_EPAR (1 << 4) /* Even parity */ +#define UART_LCR_SPAR (1 << 5) /* Stick parity */ +#define UART_LCR_SBC (1 << 6) /* Set break control */ +#define UART_LCR_DLAB (1 << 7) /* Divisor latch access */ +/* (Write) Modem control register */ +#define UART_MCR(n) UART_REG(n, 4) +/* (Read) Line status register */ +#define UART_LSR(n) UART_REG(n, 5) +#define UART_LSR_DR (1 << 0) /* Data ready */ +#define UART_LSR_OE (1 << 1) /* Overrun error */ +#define UART_LSR_PE (1 << 2) /* Parity error */ +#define UART_LSR_FE (1 << 3) /* Frame error */ +#define UART_LSR_BI (1 << 4) /* Break interrupt */ +#define UART_LSR_THRE (1 << 5) /* Xmit-hold-register empty */ +#define UART_LSR_TEMT (1 << 6) /* Xmit empty */ +#define UART_LSR_FIFOE (1 << 7) /* FIFO error */ + +/* DLAB == 1 */ + +/* (Write) Divisor latch */ +#define UART_DLL(n) UART_REG(n, 0) /* Low */ +#define UART_DLH(n) UART_REG(n, 1) /* High */ + +/* MTK extension */ +#define UART_HIGHSPEED(n) UART_REG(n, 9) +#define UART_SAMPLE_COUNT(n) UART_REG(n, 10) +#define UART_SAMPLE_POINT(n) UART_REG(n, 11) +#define UART_RATE_FIX(n) UART_REG(n, 13) + +#endif /* __CROS_EC_SERIAL_REG_H */ diff --git a/chip/mt_scp/system.c b/chip/mt_scp/system.c new file mode 100644 index 0000000000..77275a8e85 --- /dev/null +++ b/chip/mt_scp/system.c @@ -0,0 +1,307 @@ +/* Copyright 2018 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 : hardware specific implementation */ + +#include "console.h" +#include "cpu.h" +#include "flash.h" +#include "hooks.h" +#include "host_command.h" +#include "registers.h" +#include "system.h" +#include "task.h" +#include "util.h" +#include "version.h" +#include "watchdog.h" + +/* + * SCP_GPR[0] b15-b0 - scratchpad + * SCP_GPR[0] b31-b16 - saved_flags + */ + +int system_set_scratchpad(uint32_t value) +{ + /* Check if value fits in 16 bits */ + if (value & 0xffff0000) + return EC_ERROR_INVAL; + + SCP_GPR[0] = (SCP_GPR[0] & 0xffff0000) | value; + + return EC_SUCCESS; +} + +uint32_t system_get_scratchpad(void) +{ + return SCP_GPR[0] & 0xffff; +} + +const char *system_get_chip_vendor(void) +{ + return "mtk"; +} + +const char *system_get_chip_name(void) +{ + /* Support only SCP_A for now */ + return "scp_a"; +} + +const char *system_get_chip_revision(void) +{ + return ""; +} + +void chip_pre_init(void) +{ +} + +static void scp_enable_tcm(void) +{ + /* Enable tightly coupled memory (TCM) */ + SCP_CLK_L1_SRAM_PD = 0; + SCP_CLK_TCM_TAIL_SRAM_PD = 0; + /* SCP CM4 mod */ + CM4_MODIFICATION = 3; + CM4_DCM_FEATURE = 3; +} + +static void scp_enable_pirq(void) +{ + /* Enable peripheral to SCP IRQ */ + SCP_INTC_IRQ_ENABLE = 0xFFFFFFFF; + SCP_INTC_IRQ_ENABLE_MSB = 0xFFFFFFFF; +} + +/* TODO(b/120176040): move to clock.c */ +static void scp_ulposc_config(int osc) +{ + /* TODO(b/120176040): add ULPOSC calibration */ + const struct { + uint8_t div; + uint8_t cali; + } ulposc_config[] = { + { .div = 12, .cali = 32}, + { .div = 16, .cali = 32}, + }; + const int osc_index = osc - 1; + uint32_t val; + + if (osc != 1 || osc != 2) + return; + + /* Clear all bits */ + val = 0; + /* Enable CP */ + val |= OSC_CP_EN; + /* Set div */ + val |= ulposc_config[osc_index].div << 17; + /* F-band = 0, I-band = 4 */ + val |= 4 << 6; + /* Set calibration */ + val |= ulposc_config[osc_index].cali; + /* Set control register 1 */ + AP_ULPOSC_CON02(osc) = val; + /* Set control register 2, enable div2 */ + AP_ULPOSC_CON13(osc) |= OSC_DIV2_EN; +} + +/* + * TODO(b/120176040): move to clock.c and separate into + * scp_set_clock_high_enable and _disable functions. + */ +void scp_set_clock_high(int osc, int on) +{ + if (on) { + switch (osc) { + case 1: + /* Enable ULPOSC */ + SCP_CLK_EN |= EN_CLK_HIGH; + /* TODO: Turn on clock gate after 25ms */ + SCP_CLK_EN |= CG_CLK_HIGH; + break; + case 2: + /* Enable ULPOSC1 & ULPOSC2 */ + SCP_CLK_EN |= EN_CLK_HIGH; + SCP_CLK_ON_CTRL &= ~HIGH_CORE_DIS_SUB; + /* TODO: Turn on clock gate after 25ms */ + SCP_CLK_HIGH_CORE |= 1; + break; + default: + break; + } + } else { + switch (osc) { + case 1: + /* Disable clock gate */ + SCP_CLK_EN &= CG_CLK_HIGH; + /* TODO: Turn off ULPOSC1 after 50us */ + SCP_CLK_EN &= EN_CLK_HIGH; + break; + case 2: + SCP_CLK_HIGH_CORE &= ~1; + /* TODO: Turn off ULPOSC1 after 50us */ + SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; + break; + default: + break; + } + } + /* TODO: Wait 25us */ +} + +/* TODO(b/120176040): move to clock.c */ +static void scp_enable_clock(void) +{ + /* VREQ */ + SCP_CPU_VREQ = 0x10001; + SCP_SECURE_CTRL &= ~ENABLE_SPM_MASK_VREQ; + + /* DDREN auto mode */ + SCP_SYS_CTRL |= AUTO_DDREN; + + /* Set settle time */ + SCP_CLK_SYS_VAL = 1; /* System clock */ + SCP_CLK_HIGH_VAL = 1; /* ULPOSC */ + SCP_CLK_SLEEP_CTRL = (SCP_CLK_SLEEP_CTRL & ~VREQ_COUNTER_MASK) | 2; + + /* Disable slow wake */ + SCP_CLK_SLEEP = SLOW_WAKE_DISABLE; + /* Disable SPM sleep control, disable sleep mode */ + SCP_CLK_SLEEP_CTRL &= ~(SPM_SLEEP_MODE | EN_SLEEP_CTRL); + + /* Turn off ULPOSC2 */ + SCP_CLK_ON_CTRL |= HIGH_CORE_DIS_SUB; + scp_ulposc_config(1); + scp_set_clock_high(1, 1); /* Turn on ULPOSC1 */ + scp_ulposc_config(2); + scp_set_clock_high(2, 1); /* Turn on ULPOSC2 */ + + /* Enable default clock gate */ + SCP_CLK_GATE |= CG_DMA_CH3 | CG_DMA_CH2 | CG_DMA_CH1 | CG_DMA_CH0 | + CG_I2C_M | CG_MAD_M; +} + +static void scp_memmap_init(void) +{ + /* + * SCP addr : AP addr + * 0xA0000000 0x10000000 + * 0xB0000000 0x20000000 + * 0xC0000000 0x30000000 + * 0x20000000 0x40000000 + * 0x30000000 0x50000000 + * 0x60000000 0x60000000 + * 0x70000000 0x70000000 + * 0x80000000 0x80000000 + * 0xF0000000 0x90000000 + * + * Default config, LARGE DRAM not active: + * REG32(0xA0001F00) & 0x2000 != 0 + */ + SCP_REMAP_CFG1 = 0x07060504; + SCP_REMAP_CFG2 = 0x02010008; + SCP_REMAP_CFG3 = 0x10000A03; +} + +void system_pre_init(void) +{ + /* SRAM */ + scp_enable_tcm(); + /* Clock */ + scp_enable_clock(); + /* Peripheral IRQ */ + scp_enable_pirq(); + /* Init dram mapping */ + scp_memmap_init(); + /* Init inter processor communication */ + /* scp_ipi_init(); */ +} + +void system_reset(int flags) +{ + uint32_t save_flags = 0; + + /* Disable interrupts to avoid task swaps during reboot */ + interrupt_disable(); + + /* Save current reset reasons if necessary */ + if (flags & SYSTEM_RESET_PRESERVE_FLAGS) + save_flags = system_get_reset_flags() | RESET_FLAG_PRESERVED; + + if (flags & SYSTEM_RESET_LEAVE_AP_OFF) + save_flags |= RESET_FLAG_AP_OFF; + + /* Remember that the software asked us to hard reboot */ + if (flags & SYSTEM_RESET_HARD) + save_flags |= RESET_FLAG_HARD; + + /* Reset flags are 32-bits, but save only 16 bits. */ + ASSERT(!(save_flags >> 16)); + SCP_GPR[0] = (save_flags << 16) | (SCP_GPR[0] & 0xffff); + + /* SCP can not hard reset itself */ + ASSERT(!(flags & SYSTEM_RESET_HARD)); + + if (flags & SYSTEM_RESET_WAIT_EXT) { + int i; + + /* Wait 10 seconds for external reset */ + for (i = 0; i < 1000; i++) { + watchdog_reload(); + udelay(10000); + } + } + + /* SCB AIRCR reset */ + CPU_NVIC_APINT = 0x05fa0004; + /* Spin wait for chip to reboot */ + while (1) + ; +} + +static void check_reset_cause(void) +{ + uint32_t flags = 0; + uint32_t raw_reset_cause = SCP_GPR[1]; + + /* Set state to power-on */ + SCP_PWRON_STATE = PWRON_DEFAULT; + + if ((raw_reset_cause & 0xffff0000) == PWRON_DEFAULT) { + /* Reboot */ + if (raw_reset_cause & PWRON_WATCHDOG) + flags |= RESET_FLAG_WATCHDOG; + else if (raw_reset_cause & PWRON_RESET) + flags |= RESET_FLAG_POWER_ON; + else + flags |= RESET_FLAG_OTHER; + } else { + /* Power lost restart */ + flags |= RESET_FLAG_POWER_ON; + } + system_set_reset_flags(SCP_GPR[0] >> 16); + SCP_GPR[0] &= 0xffff; +} + +int system_is_reboot_warm(void) +{ + const uint32_t cold_flags = + RESET_FLAG_RESET_PIN | + RESET_FLAG_POWER_ON | + RESET_FLAG_WATCHDOG | + RESET_FLAG_HARD | + RESET_FLAG_SOFT | + RESET_FLAG_HIBERNATE; + + check_reset_cause(); + + return !(system_get_reset_flags() & cold_flags); +} + +int system_get_bbram(enum system_bbram_idx idx, uint8_t *value) +{ + return EC_ERROR_INVAL; +} diff --git a/chip/mt_scp/uart.c b/chip/mt_scp/uart.c new file mode 100644 index 0000000000..554a53cc1d --- /dev/null +++ b/chip/mt_scp/uart.c @@ -0,0 +1,171 @@ +/* Copyright 2018 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. + */ + +/* SCP UART module */ + +#include "console.h" +#include "registers.h" +#include "serial_reg.h" +#include "system.h" +#include "task.h" +#include "uart.h" +#include "util.h" + +/* Console UART index */ +#define UARTN CONFIG_UART_CONSOLE +#define UART_WAIT_US 50 +#define UART_IDLE_WAIT_US 500 + +static uint8_t uart_done, tx_started; + +int uart_init_done(void) +{ + /* + * TODO: AP UART support + * When access AP UART port, wait for AP peripheral clock + */ + return uart_done; +} + +void uart_tx_start(void) +{ + tx_started = 1; + + /* AP UART mode doesn't support interrupt */ + if (UARTN >= SCP_UART_COUNT) + return; + + if (UART_IER(UARTN) & UART_IER_THRI) + return; + disable_sleep(SLEEP_MASK_UART); + UART_IER(UARTN) |= UART_IER_THRI; +} + +void uart_tx_stop(void) +{ + tx_started = 0; + + /* AP UART mode doesn't support interrupt */ + if (UARTN >= SCP_UART_COUNT) + return; + + UART_IER(UARTN) &= ~UART_IER_THRI; + enable_sleep(SLEEP_MASK_UART); +} + +void uart_tx_flush(void) +{ + while (!(UART_LSR(UARTN) & UART_LSR_TEMT)) + usleep(uart_wait_us); +} + +int uart_tx_ready(void) +{ + /* Check xmit FIFO empty */ + return UART_LSR(UARTN) & UART_LSR_THRE; +} + +int uart_rx_available(void) +{ + /* Check rcvr data ready */ + return UART_LSR(UARTN) & UART_LSR_DR; +} + +void uart_write_char(char c) +{ + while (!uart_tx_ready()) + usleep(uart_wait_us); + + UART_DATA(UARTN) = c; +} + +int uart_read_char(void) +{ + return UART_DATA(UARTN); +} + +void uart_process(void) +{ + uart_process_input(); + uart_process_output(); +} + +#if (UARTN < SCP_UART_COUNT) +void uart_interrupt(void) +{ + uint8_t ier; + + task_clear_pending_irq(UART_IRQ(UARTN)); + uart_process(); + ier = UART_IER(UARTN); + UART_IER(UARTN) = 0; + UART_IER(UARTN) = ier; +} +DECLARE_IRQ(UART_IRQ(UARTN), uart_interrupt, 2); + +void uart_rx_interrupt(void) +{ + uint8_t ier; + + task_clear_pending_irq(UART_RX_IRQ(UARTN)); + SCP_INTC_UART_RX_IRQ &= ~(1 << UARTN); + uart_process(); + ier = UART_IER(UARTN); + UART_IER(UARTN) = 0; + UART_IER(UARTN) = ier; + SCP_INTC_UART_RX_IRQ |= 1 << UARTN; +} +DECLARE_IRQ(UART_RX_IRQ(UARTN), uart_rx_interrupt, 2); +#endif + +void uart_task(void) +{ +#if (UARTN >= SCP_UART_COUNT) + while (1) { + if (uart_rx_available() || tx_started) + uart_process(); + else + task_wait_event(UART_IDLE_WAIT_US); + } +#endif +} + +void uart_init(void) +{ + const uint32_t baud_rate = CONFIG_UART_BAUD_RATE; + const uint32_t uart_clock = 26000000; + const uint32_t div = DIV_ROUND_NEAREST(uart_clock, baud_rate * 16); + + /* Init clock */ +#if UARTN == 0 + SCP_CLK_GATE |= CG_UART_M | CG_UART_B | CG_UART_RSTN; +#elif UARTN == 1 + SCP_CLK_GATE |= CG_UART1_M | CG_UART1_B | CG_UART1_RSTN; +#endif + + /* Init and clear FIFO */ + UART_FCR(UARTN) = UART_FCR_ENABLE_FIFO + | UART_FCR_CLEAR_RCVR + | UART_FCR_CLEAR_XMIT; + /* Line control: parity none, 8 bit, 1 stop bit */ + UART_LCR(UARTN) = UART_LCR_WLEN8; + /* For baud rate <= 115200 */ + UART_HIGHSPEED(UARTN) = 0; + /* DLAB = 1 and update DLL DLH */ + UART_LCR(UARTN) |= UART_LCR_DLAB; + UART_DLL(UARTN) = div & 0xff; + UART_DLH(UARTN) = (div >> 8) & 0xff; + UART_LCR(UARTN) &= ~UART_LCR_DLAB; + UART_IER(UARTN) |= UART_IER_RDI; + +#if (UARTN < SCP_UART_COUNT) + task_enable_irq(UART_IRQ(UARTN)); + task_enable_irq(UART_RX_IRQ(UARTN)); + /* UART RX IRQ needs an extra enable */ + SCP_INTC_UART_RX_IRQ |= 1 << UARTN; +#endif + gpio_config_module(MODULE_UART, 1); + uart_done = 1; +} diff --git a/chip/mt_scp/watchdog.c b/chip/mt_scp/watchdog.c new file mode 100644 index 0000000000..74e2cad8e5 --- /dev/null +++ b/chip/mt_scp/watchdog.c @@ -0,0 +1,33 @@ +/* Copyright 2018 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 "common.h" +#include "hooks.h" +#include "panic.h" +#include "registers.h" +#include "watchdog.h" + +void watchdog_reload(void) +{ + SCP_WDT_RELOAD = SCP_WDT_RELOAD_VALUE; +} +DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT); + +int watchdog_init(void) +{ + const uint32_t watchdog_timeout = + SCP_WDT_PERIOD(CONFIG_WATCHDOG_PERIOD_MS); + + /* Disable watchdog */ + SCP_WDT_CFG = 0; + /* Enable watchdog */ + SCP_WDT_CFG = SCP_WDT_ENABLE | watchdog_timeout; + /* Reload watchdog */ + watchdog_reload(); + + return EC_SUCCESS; +} -- cgit v1.2.1