mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-10 17:41:54 +00:00
ec_chip_mchp: Add MCHP chip folder
BRANCH=none BUG= TEST=Review only. Committing small pieces until all code passes review. Change-Id: I9d16f95314a7c97b11c4fe61602c6db2621e6024 Signed-off-by: Scott Worley <scott.worley@microchip.corp-partner.google.com>
This commit is contained in:
@@ -40,6 +40,7 @@ COMMON_WARN = -Wall -Werror -Wundef -Wno-trigraphs -fno-strict-aliasing \
|
||||
CFLAGS_WARN = $(COMMON_WARN) $(C_WARN)
|
||||
CXXFLAGS_WARN = $(COMMON_WARN)
|
||||
CFLAGS_DEBUG= -g
|
||||
CFLAGS_DEBUG+=$(CFLAGS_DEBUG_CHIP)
|
||||
CFLAGS_INCLUDE=$(foreach i,$(includes),-I$(i) ) -I.
|
||||
CFLAGS_TEST=$(if $(TEST_BUILD),-DTEST_BUILD \
|
||||
-DTEST_TASKFILE=$(PROJECT).tasklist,) \
|
||||
|
||||
92
chip/mchp/build.mk
Normal file
92
chip/mchp/build.mk
Normal file
@@ -0,0 +1,92 @@
|
||||
# -*- makefile -*-
|
||||
# Copyright (c) 2013 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.
|
||||
#
|
||||
# Microchip(MCHP) MEC chip specific files build
|
||||
#
|
||||
|
||||
# MCHP MEC SoC's have a Cortex-M4 ARM core
|
||||
CORE:=cortex-m
|
||||
# Allow the full Cortex-M4 instruction set
|
||||
CFLAGS_CPU+=-march=armv7e-m -mcpu=cortex-m4
|
||||
|
||||
# JTAG debug with Keil ARM MDK debugger
|
||||
# do not allow GCC dwarf debug extensions
|
||||
#CFLAGS_DEBUG_EXTRA=-gdwarf-3 -gstrict-dwarf
|
||||
|
||||
LDFLAGS_EXTRA=
|
||||
|
||||
ifeq ($(CONFIG_LTO),y)
|
||||
# Re-include the core's build.mk file so we can remove the lto flag.
|
||||
include core/$(CORE)/build.mk
|
||||
endif
|
||||
|
||||
# Required chip modules
|
||||
chip-y=clock.o gpio.o hwtimer.o system.o uart.o port80.o tfdp.o
|
||||
chip-$(CONFIG_ADC)+=adc.o
|
||||
chip-$(CONFIG_DMA)+=dma.o
|
||||
chip-$(CONFIG_ESPI)+=espi.o
|
||||
chip-$(CONFIG_FANS)+=fan.o
|
||||
chip-$(CONFIG_FLASH_PHYSICAL)+=flash.o
|
||||
chip-$(CONFIG_I2C)+=i2c.o
|
||||
chip-$(CONFIG_MEC_GPIO_EC_CMDS)+=gpio_cmds.o
|
||||
chip-$(CONFIG_LPC)+=lpc.o
|
||||
chip-$(CONFIG_MCHP_GPSPI)+=gpspi.o
|
||||
chip-$(CONFIG_PWM)+=pwm.o
|
||||
chip-$(CONFIG_SPI)+=spi.o qmspi.o
|
||||
chip-$(CONFIG_TFDP)+=tfdp.o
|
||||
chip-$(CONFIG_WATCHDOG)+=watchdog.o
|
||||
chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
|
||||
|
||||
# location of the scripts and keys used to pack the SPI flash image
|
||||
SCRIPTDIR:=./chip/${CHIP}/util
|
||||
|
||||
# Allow SPI size to be overridden by board specific size, default to 512KB
|
||||
CHIP_SPI_SIZE_KB?=512
|
||||
|
||||
TEST_SPI=
|
||||
ifeq ($(CONFIG_MCHP_LFW_DEBUG),y)
|
||||
TEST_SPI=--test_spi
|
||||
endif
|
||||
|
||||
# pack_ec.py creates SPI flash image for MEC
|
||||
# _rw_size is CONFIG_RW_SIZE
|
||||
# Commands to convert $^ to $@.tmp
|
||||
cmd_obj_to_bin = $(OBJCOPY) --gap-fill=0xff -O binary $< $@.tmp1 ; \
|
||||
${SCRIPTDIR}/pack_ec.py -o $@.tmp -i $@.tmp1 \
|
||||
--loader_file $(chip-lfw-flat) ${TEST_SPI} \
|
||||
--spi_size ${CHIP_SPI_SIZE_KB} \
|
||||
--image_size $(_rw_size) ; rm -f $@.tmp1
|
||||
|
||||
chip-lfw = chip/${CHIP}/lfw/ec_lfw
|
||||
chip-lfw-flat = $(out)/RW/$(chip-lfw)-lfw.flat
|
||||
|
||||
# build these specifically for lfw with -lfw suffix
|
||||
objs_lfw = $(patsubst %, $(out)/RW/%-lfw.o, \
|
||||
$(addprefix common/, util gpio) \
|
||||
$(addprefix chip/$(CHIP)/, spi qmspi dma gpio clock hwtimer tfdp) \
|
||||
core/$(CORE)/cpu $(chip-lfw))
|
||||
|
||||
# reuse version.o (and its dependencies) from main board
|
||||
objs_lfw += $(out)/RW/common/version.o
|
||||
|
||||
dirs-y+=chip/$(CHIP)/lfw
|
||||
|
||||
# objs with -lfw suffix are to include lfw's gpio
|
||||
$(out)/RW/%-lfw.o: private CC+=-I$(BDIR)/lfw -DLFW
|
||||
# Remove the lto flag for the loader. It actually causes it to bloat in size.
|
||||
ifeq ($(CONFIG_LTO),y)
|
||||
$(out)/RW/%-lfw.o: private CFLAGS_CPU := $(filter-out -flto, $(CFLAGS_CPU))
|
||||
endif
|
||||
$(out)/RW/%-lfw.o: %.c
|
||||
$(call quiet,c_to_o,CC )
|
||||
|
||||
# let lfw's elf link only with selected objects
|
||||
$(out)/RW/%-lfw.elf: private objs = $(objs_lfw)
|
||||
$(out)/RW/%-lfw.elf: override shlib :=
|
||||
$(out)/RW/%-lfw.elf: %.ld $(objs_lfw)
|
||||
$(call quiet,elf,LD )
|
||||
|
||||
# final image needs lfw loader
|
||||
$(out)/$(PROJECT).bin: $(chip-lfw-flat)
|
||||
763
chip/mchp/clock.c
Normal file
763
chip/mchp/clock.c
Normal file
@@ -0,0 +1,763 @@
|
||||
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* Clocks and power management settings */
|
||||
|
||||
#include "clock.h"
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "cpu.h"
|
||||
#include "hooks.h"
|
||||
#include "hwtimer.h"
|
||||
#include "pwm.h"
|
||||
#include "pwm_chip.h"
|
||||
#include "registers.h"
|
||||
#include "shared_mem.h"
|
||||
#include "system.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "uart.h"
|
||||
#include "util.h"
|
||||
#include "tfdp_chip.h"
|
||||
#include "vboot_hash.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPUTS(outstr) cputs(CC_CLOCK, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
|
||||
|
||||
#ifdef CONFIG_LOW_POWER_IDLE
|
||||
|
||||
#define HTIMER_DIV_1_US_MAX (1998848)
|
||||
#define HTIMER_DIV_1_1SEC (0x8012)
|
||||
|
||||
/* Recovery time for HvySlp2 is 0 usec */
|
||||
#define HEAVY_SLEEP_RECOVER_TIME_USEC 75
|
||||
|
||||
#define SET_HTIMER_DELAY_USEC 200
|
||||
|
||||
static int idle_sleep_cnt;
|
||||
static int idle_dsleep_cnt;
|
||||
static uint64_t total_idle_dsleep_time_us;
|
||||
|
||||
#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG
|
||||
static uint32_t pcr_slp_en[MCHP_PCR_SLP_RST_REG_MAX];
|
||||
static uint32_t pcr_clk_req[MCHP_PCR_SLP_RST_REG_MAX];
|
||||
static uint32_t ecia_result[MCHP_INT_GIRQ_NUM];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fixed amount of time to keep the console in use flag true after
|
||||
* boot in order to give a permanent window in which the heavy sleep
|
||||
* mode is not used.
|
||||
*/
|
||||
#define CONSOLE_IN_USE_ON_BOOT_TIME (15*SECOND)
|
||||
static int console_in_use_timeout_sec = 60;
|
||||
static timestamp_t console_expire_time;
|
||||
#endif /*CONFIG_LOW_POWER_IDLE */
|
||||
|
||||
static int freq = 48000000;
|
||||
|
||||
void clock_wait_cycles(uint32_t cycles)
|
||||
{
|
||||
asm volatile("1: subs %0, #1\n"
|
||||
" bne 1b\n" : "+r"(cycles));
|
||||
}
|
||||
|
||||
int clock_get_freq(void)
|
||||
{
|
||||
return freq;
|
||||
}
|
||||
|
||||
/** clock_init
|
||||
* @note
|
||||
* MCHP MEC implements 4 control bits in the VBAT Clock Enable register.
|
||||
* It also implements an internal silicon 32KHz +/- 2% oscillator powered
|
||||
* by VBAT.
|
||||
* b[3] = XOSEL 0=parallel, 1=single-ended
|
||||
* b[2] = 32KHZ_SOURCE specifies source of always-on clock domain
|
||||
* 0=internal silicon oscillator
|
||||
* 1=crystal XOSEL pin(s)
|
||||
* b[1] = EXT_32K use always-on clock domain or external 32KHZ_IN pin
|
||||
* 0=32K source is always-on clock domain
|
||||
* 1=32K source is 32KHZ_IN pin (GPIO 0165)
|
||||
* b[0] = 32K_SUPPRESS
|
||||
* 0=32K clock domain stays enabled if VTR is off. Powered by VBAT
|
||||
* 1=32K clock domain is disabled if VTR is off.
|
||||
* Set b[3] based on CONFIG_CLOCK_CRYSTAL
|
||||
* Set b[2:0] = 100b
|
||||
* b[0]=0 32K clock domain always on (requires VBAT if VTR is off)
|
||||
* b[1]=0 32K source is the 32K clock domain NOT the 32KHZ_IN pin
|
||||
* b[2]=1 If activity detected on crystal pins switch 32K input from
|
||||
* internal silicon oscillator to XOSEL pin(s) based on b[3].
|
||||
*/
|
||||
void clock_init(void)
|
||||
{
|
||||
int __attribute__((unused)) dummy;
|
||||
|
||||
trace0(0, MEC, 0, "Clock Init");
|
||||
|
||||
#ifdef CONFIG_CLOCK_CRYSTAL
|
||||
/* XOSEL: 0 = Parallel resonant crystal */
|
||||
MCHP_VBAT_CE &= ~(1ul << 3);
|
||||
|
||||
#else
|
||||
/* XOSEL: 1 = Single ended clock source */
|
||||
MCHP_VBAT_CE |= (1ul << 3);
|
||||
#endif
|
||||
|
||||
/* 32K clock enable */
|
||||
MCHP_VBAT_CE = (MCHP_VBAT_CE & ~(0x03)) | (1ul << 2);
|
||||
|
||||
#ifdef CONFIG_CLOCK_CRYSTAL
|
||||
/* Wait for crystal to stabilize (OSC_LOCK == 1) */
|
||||
while (!(MCHP_PCR_CHIP_OSC_ID & 0x100))
|
||||
;
|
||||
#endif
|
||||
trace0(0, MEC, 0, "PLL OSC is Locked");
|
||||
#ifndef LFW
|
||||
dummy = shared_mem_size();
|
||||
trace11(0, MEC, 0, "Shared Memory size = 0x%08x", (uint32_t)dummy);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Speed through boot + vboot hash calculation, dropping our processor
|
||||
* clock only after vboot hashing is completed.
|
||||
*/
|
||||
static void clock_turbo_disable(void);
|
||||
DECLARE_DEFERRED(clock_turbo_disable);
|
||||
|
||||
static void clock_turbo_disable(void)
|
||||
{
|
||||
#ifdef CONFIG_VBOOT_HASH
|
||||
if (vboot_hash_in_progress())
|
||||
hook_call_deferred(&clock_turbo_disable_data, 100 * MSEC);
|
||||
else
|
||||
#endif
|
||||
/* Use 12 MHz processor clock for power savings */
|
||||
MCHP_PCR_PROC_CLK_CTL = 4;
|
||||
}
|
||||
DECLARE_HOOK(HOOK_INIT,
|
||||
clock_turbo_disable,
|
||||
HOOK_PRIO_INIT_VBOOT_HASH + 1);
|
||||
|
||||
#ifdef CONFIG_LOW_POWER_IDLE
|
||||
/**
|
||||
* initialization of Hibernation timer0
|
||||
* Clear PCR sleep enable.
|
||||
* GIRQ=21, aggregator bit = 1, Direct NVIC = 112
|
||||
* NVIC direct connect interrupts are used for all peripherals
|
||||
* (exception GPIO's) then the MCHP_INT_BLK_EN GIRQ bit should not be
|
||||
* set.
|
||||
*/
|
||||
static void htimer_init(void)
|
||||
{
|
||||
MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_HTMR0);
|
||||
MCHP_INT_ENABLE(MCHP_HTIMER_GIRQ) =
|
||||
MCHP_HTIMER_GIRQ_BIT(0);
|
||||
MCHP_HTIMER_PRELOAD(0) = 0; /* disable at beginning */
|
||||
|
||||
task_enable_irq(MCHP_IRQ_HTIMER0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use hibernate module to set up an htimer interrupt at a given
|
||||
* time from now
|
||||
*
|
||||
* @param seconds Number of seconds before htimer interrupt
|
||||
* @param microseconds Number of microseconds before htimer interrupt
|
||||
* @note hibernation timer input clock is 32.768KHz and has two
|
||||
* divider values.
|
||||
* Control register bit[0] selects the divider.
|
||||
* 0 is divide by 1 for 30.5us per LSB for a maximum of ~2 seconds.
|
||||
* 1 is divide by 4096 for 0.125s per LSB for a maximum of ~2 hours.
|
||||
*/
|
||||
static void system_set_htimer_alarm(uint32_t seconds,
|
||||
uint32_t microseconds)
|
||||
{
|
||||
uint32_t hcnt;
|
||||
|
||||
if (microseconds >= 1000000) {
|
||||
seconds += microseconds / 1000000;
|
||||
microseconds -= (microseconds / 1000000) * 1000000;
|
||||
}
|
||||
|
||||
if (seconds || microseconds) {
|
||||
|
||||
/* if (seconds > 2) { */
|
||||
if (seconds > 1) {
|
||||
/* count from 2 sec to 2 hrs, mec1322 sec 18.10.2 */
|
||||
ASSERT(seconds <= 0xffff / 8);
|
||||
/* 0.125(=1/8) per clock */
|
||||
MCHP_HTIMER_CONTROL(0) = 1;
|
||||
/* (number of counts to be loaded)
|
||||
* = seconds * ( 8 clocks per second )
|
||||
* + microseconds / 125000
|
||||
* ---> (0 if (microseconds < 125000)
|
||||
*/
|
||||
hcnt = (seconds * 8 + microseconds / 125000);
|
||||
|
||||
} else { /* count up to 2 sec. */
|
||||
/* 30.5(= 2/61) usec */
|
||||
MCHP_HTIMER_CONTROL(0) = 0;
|
||||
|
||||
/* (number of counts to be loaded)
|
||||
* = (total microseconds) / 30.5;
|
||||
*/
|
||||
hcnt = (seconds * 1000000 + microseconds) *
|
||||
2 / 61;
|
||||
}
|
||||
|
||||
MCHP_HTIMER_PRELOAD(0) = hcnt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return time slept in micro-seconds
|
||||
*/
|
||||
static timestamp_t system_get_htimer(void)
|
||||
{
|
||||
uint16_t count;
|
||||
timestamp_t time;
|
||||
|
||||
count = MCHP_HTIMER_COUNT(0);
|
||||
|
||||
|
||||
if (MCHP_HTIMER_CONTROL(0) == 1) /* if > 2 sec */
|
||||
/* 0.125 sec per count */
|
||||
time.le.lo = (uint32_t)(count * 125000);
|
||||
else /* if < 2 sec */
|
||||
/* 30.5(=61/2)usec per count */
|
||||
time.le.lo = (uint32_t)(count * 61 / 2);
|
||||
|
||||
time.le.hi = 0;
|
||||
|
||||
return time; /* in uSec */
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable and clear hibernation timer interrupt
|
||||
*/
|
||||
static void system_reset_htimer_alarm(void)
|
||||
{
|
||||
MCHP_HTIMER_PRELOAD(0) = 0;
|
||||
MCHP_INT_SOURCE(MCHP_HTIMER_GIRQ) =
|
||||
MCHP_HTIMER_GIRQ_BIT(0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG
|
||||
static void print_pcr_regs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
trace0(0, MEC, 0, "Current PCR registers");
|
||||
for (i = 0; i < 5; i++) {
|
||||
trace12(0, MEC, 0, "REG SLP_EN[%d] = 0x%08X",
|
||||
i, MCHP_PCR_SLP_EN(i));
|
||||
trace12(0, MEC, 0, "REG CLK_REQ[%d] = 0x%08X",
|
||||
i, MCHP_PCR_CLK_REQ(i));
|
||||
}
|
||||
}
|
||||
|
||||
static void print_ecia_regs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
trace0(0, MEC, 0, "Current GIRQn.Result registers");
|
||||
for (i = MCHP_INT_GIRQ_FIRST;
|
||||
i <= MCHP_INT_GIRQ_LAST; i++)
|
||||
trace12(0, MEC, 0, "GIRQ[%d].Result = 0x%08X",
|
||||
i, MCHP_INT_RESULT(i));
|
||||
}
|
||||
|
||||
static void save_regs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MCHP_PCR_SLP_RST_REG_MAX; i++) {
|
||||
pcr_slp_en[i] = MCHP_PCR_SLP_EN(i);
|
||||
pcr_clk_req[i] = MCHP_PCR_CLK_REQ(i);
|
||||
}
|
||||
|
||||
for (i = 0; i < MCHP_INT_GIRQ_NUM; i++)
|
||||
ecia_result[i] =
|
||||
MCHP_INT_RESULT(MCHP_INT_GIRQ_FIRST + i);
|
||||
}
|
||||
|
||||
static void print_saved_regs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
trace0(0, BRD, 0, "Before sleep saved registers");
|
||||
for (i = 0; i < MCHP_PCR_SLP_RST_REG_MAX; i++) {
|
||||
trace12(0, BRD, 0, "PCR_SLP_EN[%d] = 0x%08X",
|
||||
i, pcr_slp_en[i]);
|
||||
trace12(0, BRD, 0, "PCR_CLK_REQ[%d] = 0x%08X",
|
||||
i, pcr_clk_req[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < MCHP_INT_GIRQ_NUM; i++)
|
||||
trace12(0, BRD, 0, "GIRQ[%d].Result = 0x%08X",
|
||||
(i+MCHP_INT_GIRQ_FIRST), ecia_result[i]);
|
||||
}
|
||||
#endif /* #ifdef CONFIG_MCHP_DEEP_SLP_DEBUG */
|
||||
|
||||
/**
|
||||
* This is MCHP specific and equivalent to ARM Cortex's
|
||||
* 'DeepSleep' via system control block register, CPU_SCB_SYSCTRL
|
||||
* MCHP has new SLP_ALL feature.
|
||||
* When SLP_ALL is enabled and HW sees sleep entry trigger from CPU.
|
||||
* 1. HW saves PCR.SLP_EN registers
|
||||
* 2. HW sets all PCR.SLP_EN bits to 1.
|
||||
* 3. System sleeps
|
||||
* 4. wake event wakes system
|
||||
* 5. HW restores original values of all PCR.SLP_EN registers
|
||||
* NOTE1: Current RTOS core (Cortex-Mx) does not use SysTick timer.
|
||||
* We can leave code to disable it but do not re-enable on wake.
|
||||
* NOTE2: Some peripherals will not sleep until outstanding transactions
|
||||
* are complete: I2C, DMA, GPSPI, QMSPI, etc.
|
||||
* NOTE3: Security blocks do not fully implement HW sleep therefore their
|
||||
* sleep enables must be manually set/restored.
|
||||
*
|
||||
*/
|
||||
static void prepare_for_deep_sleep(void)
|
||||
{
|
||||
trace0(0, MEC, 0, "Prepare for Deep Sleep");
|
||||
|
||||
/* sysTick timer */
|
||||
CPU_NVIC_ST_CTRL &= ~ST_ENABLE;
|
||||
CPU_NVIC_ST_CTRL &= ~ST_COUNTFLAG;
|
||||
|
||||
CPU_NVIC_ST_CTRL &= ~ST_TICKINT; /* SYS_TICK_INT_DISABLE */
|
||||
|
||||
/* Enable assertion of DeepSleep signals
|
||||
* from the core when core enters sleep.
|
||||
*/
|
||||
CPU_SCB_SYSCTRL |= (1 << 2);
|
||||
|
||||
/* Stop timers */
|
||||
MCHP_TMR32_CTL(0) &= ~1;
|
||||
MCHP_TMR32_CTL(1) &= ~1;
|
||||
MCHP_TMR16_CTL(0) &= ~1;
|
||||
MCHP_INT_DISABLE(MCHP_TMR32_GIRQ) =
|
||||
MCHP_TMR32_GIRQ_BIT(0) +
|
||||
MCHP_TMR32_GIRQ_BIT(1);
|
||||
MCHP_INT_SOURCE(MCHP_TMR32_GIRQ) =
|
||||
MCHP_TMR32_GIRQ_BIT(0) +
|
||||
MCHP_TMR32_GIRQ_BIT(1);
|
||||
MCHP_INT_DISABLE(MCHP_TMR16_GIRQ) =
|
||||
MCHP_TMR16_GIRQ_BIT(0);
|
||||
MCHP_INT_SOURCE(MCHP_TMR16_GIRQ) =
|
||||
MCHP_TMR16_GIRQ_BIT(0);
|
||||
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
/* Stop watchdog */
|
||||
MCHP_WDG_CTL &= ~1;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_ESPI
|
||||
#ifdef CONFIG_POWER_S0IX
|
||||
MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_ESPI;
|
||||
MCHP_INT_ENABLE(22) = MCHP_INT22_WAKE_ONLY_ESPI;
|
||||
#else
|
||||
MCHP_ESPI_ACTIVATE &= ~1;
|
||||
#endif
|
||||
#else
|
||||
#ifdef CONFIG_POWER_S0IX
|
||||
MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_LPC;
|
||||
MCHP_INT_ENABLE(22) = MCHP_INT22_WAKE_ONLY_LPC;
|
||||
#else
|
||||
MCHP_LPC_ACT |= 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ADC
|
||||
/*
|
||||
* Clear ADC activate bit. If a conversion is in progress the
|
||||
* ADC block will not enter low power until the converstion is
|
||||
* complete.
|
||||
*/
|
||||
MCHP_ADC_CTRL &= ~1;
|
||||
#endif
|
||||
|
||||
/* stop Port80 capture timer */
|
||||
MCHP_P80_ACTIVATE(0) = 0;
|
||||
|
||||
/*
|
||||
* Clear SLP_EN bit(s) for wake sources.
|
||||
* Currently only Hibernation timer 0.
|
||||
* GPIO pins can always wake.
|
||||
*/
|
||||
MCHP_PCR_SLP_EN3 &= ~(MCHP_PCR_SLP_EN3_HTMR0);
|
||||
|
||||
#ifdef CONFIG_PWM
|
||||
pwm_keep_awake(); /* clear sleep enables of active PWM's */
|
||||
#else
|
||||
/* Disable 100 Khz clock */
|
||||
MCHP_PCR_SLOW_CLK_CTL &= 0xFFFFFC00;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CHIPSET_DEBUG
|
||||
/* Disable JTAG and preserve mode */
|
||||
/* MCHP_EC_JTAG_EN &= ~(MCHP_JTAG_ENABLE); */
|
||||
#endif
|
||||
|
||||
/* call board level */
|
||||
#ifdef CONFIG_BOARD_DEEP_SLEEP
|
||||
board_prepare_for_deep_sleep();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG
|
||||
save_regs();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void resume_from_deep_sleep(void)
|
||||
{
|
||||
trace0(0, MEC, 0, "resume_from_deep_sleep");
|
||||
|
||||
MCHP_PCR_SYS_SLP_CTL = 0x00; /* default */
|
||||
|
||||
/* Disable assertion of DeepSleep signal when core executes WFI */
|
||||
CPU_SCB_SYSCTRL &= ~(1 << 2);
|
||||
|
||||
#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG
|
||||
print_saved_regs();
|
||||
print_pcr_regs();
|
||||
print_ecia_regs();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CHIPSET_DEBUG
|
||||
MCHP_EC_JTAG_EN |= (MCHP_JTAG_ENABLE);
|
||||
#endif
|
||||
|
||||
MCHP_PCR_SLOW_CLK_CTL |= 0x1e0;
|
||||
|
||||
/* call board level */
|
||||
#ifdef CONFIG_BOARD_DEEP_SLEEP
|
||||
board_resume_from_deep_sleep();
|
||||
#endif
|
||||
/*
|
||||
* re-enable hibernation timer 0 PCR.SLP_EN to
|
||||
* reduce power.
|
||||
*/
|
||||
MCHP_PCR_SLP_EN3 |= (MCHP_PCR_SLP_EN3_HTMR0);
|
||||
|
||||
#ifdef CONFIG_ESPI
|
||||
#ifdef CONFIG_POWER_S0IX
|
||||
MCHP_INT_DISABLE(22) = MCHP_INT22_WAKE_ONLY_ESPI;
|
||||
MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_ESPI;
|
||||
#else
|
||||
MCHP_ESPI_ACTIVATE |= 1;
|
||||
#endif
|
||||
#else
|
||||
#ifdef CONFIG_POWER_S0IX
|
||||
MCHP_INT_DISABLE(22) = MCHP_INT22_WAKE_ONLY_LPC;
|
||||
MCHP_INT_SOURCE(22) = MCHP_INT22_WAKE_ONLY_LPC;
|
||||
#else
|
||||
MCHP_LPC_ACT |= 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* re-enable Port80 capture */
|
||||
MCHP_P80_ACTIVATE(0) = 1;
|
||||
|
||||
#ifdef CONFIG_ADC
|
||||
MCHP_ADC_CTRL |= 1;
|
||||
#endif
|
||||
|
||||
/* Enable timer */
|
||||
MCHP_TMR32_CTL(0) |= 1;
|
||||
MCHP_TMR32_CTL(1) |= 1;
|
||||
MCHP_TMR16_CTL(0) |= 1;
|
||||
MCHP_INT_ENABLE(MCHP_TMR32_GIRQ) =
|
||||
MCHP_TMR32_GIRQ_BIT(0) +
|
||||
MCHP_TMR32_GIRQ_BIT(1);
|
||||
MCHP_INT_ENABLE(MCHP_TMR16_GIRQ) =
|
||||
MCHP_TMR16_GIRQ_BIT(0);
|
||||
|
||||
/* Enable watchdog */
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
#ifdef CONFIG_CHIPSET_DEBUG
|
||||
/* enable WDG stall on active JTAG and do not start */
|
||||
MCHP_WDG_CTL = (1 << 4);
|
||||
#else
|
||||
MCHP_WDG_CTL |= 1;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void clock_refresh_console_in_use(void)
|
||||
{
|
||||
disable_sleep(SLEEP_MASK_CONSOLE);
|
||||
|
||||
/* Set console in use expire time. */
|
||||
console_expire_time = get_time();
|
||||
console_expire_time.val += console_in_use_timeout_sec * SECOND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Low power idle task. Executed when no tasks are ready to be scheduled.
|
||||
*/
|
||||
void __idle(void)
|
||||
{
|
||||
timestamp_t t0;
|
||||
timestamp_t t1;
|
||||
timestamp_t ht_t1;
|
||||
uint32_t next_delay;
|
||||
uint32_t max_sleep_time;
|
||||
int time_for_dsleep;
|
||||
int uart_ready_for_deepsleep;
|
||||
|
||||
htimer_init(); /* hibernation timer initialize */
|
||||
|
||||
disable_sleep(SLEEP_MASK_CONSOLE);
|
||||
console_expire_time.val = get_time().val +
|
||||
CONSOLE_IN_USE_ON_BOOT_TIME;
|
||||
|
||||
|
||||
/*
|
||||
* Print when the idle task starts. This is the lowest priority
|
||||
* task, so this only starts once all other tasks have gotten a
|
||||
* chance to do their task inits and have gone to sleep.
|
||||
*/
|
||||
CPRINTS("MEC1701 low power idle task started");
|
||||
|
||||
while (1) {
|
||||
/* Disable interrupts */
|
||||
interrupt_disable();
|
||||
|
||||
t0 = get_time(); /* uSec */
|
||||
|
||||
/* __hw_clock_event_get() is next programmed timer event */
|
||||
next_delay = __hw_clock_event_get() - t0.le.lo;
|
||||
|
||||
time_for_dsleep = next_delay >
|
||||
(HEAVY_SLEEP_RECOVER_TIME_USEC +
|
||||
SET_HTIMER_DELAY_USEC);
|
||||
|
||||
max_sleep_time = next_delay -
|
||||
HEAVY_SLEEP_RECOVER_TIME_USEC;
|
||||
|
||||
/* check if there enough time for deep sleep */
|
||||
if (DEEP_SLEEP_ALLOWED && time_for_dsleep) {
|
||||
trace0(0, MEC, 0, "Enough time for Deep Sleep");
|
||||
/*
|
||||
* Check if the console use has expired and
|
||||
* console sleep is masked by GPIO(UART-RX)
|
||||
* interrupt.
|
||||
*/
|
||||
if ((sleep_mask & SLEEP_MASK_CONSOLE) &&
|
||||
t0.val > console_expire_time.val) {
|
||||
/* allow console to sleep. */
|
||||
enable_sleep(SLEEP_MASK_CONSOLE);
|
||||
|
||||
/*
|
||||
* Wait one clock before checking if
|
||||
* heavy sleep is allowed to give time
|
||||
* for sleep mask to be updated.
|
||||
*/
|
||||
clock_wait_cycles(1);
|
||||
|
||||
if (LOW_SPEED_DEEP_SLEEP_ALLOWED)
|
||||
CPRINTS("MEC1701 Disable console "
|
||||
"in deepsleep");
|
||||
}
|
||||
|
||||
|
||||
/* UART is not being used */
|
||||
uart_ready_for_deepsleep =
|
||||
LOW_SPEED_DEEP_SLEEP_ALLOWED &&
|
||||
!uart_tx_in_progress() &&
|
||||
uart_buffer_empty();
|
||||
|
||||
/*
|
||||
* Since MCHP's heavy sleep mode requires all
|
||||
* blocks to be sleepable, UART/console's
|
||||
* readiness is final decision factor of
|
||||
* heavy sleep of EC.
|
||||
*/
|
||||
if (uart_ready_for_deepsleep) {
|
||||
|
||||
idle_dsleep_cnt++;
|
||||
|
||||
/*
|
||||
* config UART Rx as GPIO wakeup
|
||||
* interrupt source
|
||||
*/
|
||||
uart_enter_dsleep();
|
||||
|
||||
/* MCHP specific deep-sleep mode */
|
||||
prepare_for_deep_sleep();
|
||||
|
||||
/*
|
||||
* 'max_sleep_time' value should be big
|
||||
* enough so that hibernation timer's
|
||||
* interrupt triggers only after 'wfi'
|
||||
* completes its excution.
|
||||
*/
|
||||
max_sleep_time -=
|
||||
(get_time().le.lo - t0.le.lo);
|
||||
|
||||
/* setup/enable htimer wakeup interrupt */
|
||||
system_set_htimer_alarm(0,
|
||||
max_sleep_time);
|
||||
|
||||
/* set sleep all just before WFI */
|
||||
MCHP_PCR_SYS_SLP_CTL |=
|
||||
MCHP_PCR_SYS_SLP_HEAVY;
|
||||
MCHP_PCR_SYS_SLP_CTL |=
|
||||
MCHP_PCR_SYS_SLP_ALL;
|
||||
|
||||
} else {
|
||||
idle_sleep_cnt++;
|
||||
}
|
||||
|
||||
/* Wait for interrupt: goes into deep sleep. */
|
||||
asm("dsb");
|
||||
asm("wfi");
|
||||
asm("isb");
|
||||
asm("nop");
|
||||
|
||||
if (uart_ready_for_deepsleep) {
|
||||
|
||||
resume_from_deep_sleep();
|
||||
|
||||
/*
|
||||
* Fast forward timer according to htimer
|
||||
* counter:
|
||||
* Since all blocks including timers
|
||||
* will be in sleep mode, timers stops
|
||||
* except hibernate timer.
|
||||
* And system schedule timer should be
|
||||
* corrected after wakeup by either
|
||||
* hibernate timer or GPIO_UART_RX
|
||||
* interrupt.
|
||||
*/
|
||||
ht_t1 = system_get_htimer();
|
||||
|
||||
/* disable/clear htimer wakeup interrupt */
|
||||
system_reset_htimer_alarm();
|
||||
|
||||
t1.val = t0.val +
|
||||
(uint64_t)(max_sleep_time -
|
||||
ht_t1.le.lo);
|
||||
|
||||
force_time(t1);
|
||||
|
||||
/* re-eanble UART */
|
||||
uart_exit_dsleep();
|
||||
|
||||
/* Record time spent in deep sleep. */
|
||||
total_idle_dsleep_time_us +=
|
||||
(uint64_t)(max_sleep_time -
|
||||
ht_t1.le.lo);
|
||||
}
|
||||
|
||||
} else { /* CPU 'Sleep' mode */
|
||||
|
||||
idle_sleep_cnt++;
|
||||
|
||||
asm("wfi");
|
||||
|
||||
}
|
||||
|
||||
interrupt_enable();
|
||||
} /* while(1) */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CMD_IDLE_STATS
|
||||
/**
|
||||
* Print low power idle statistics
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG
|
||||
static void print_pcr_regs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
ccprintf("PCR regs before WFI\n");
|
||||
for (i = 0; i < 5; i++) {
|
||||
ccprintf("PCR SLP_EN[%d] = 0x%08X\n", pcr_slp_en[i]);
|
||||
ccprintf("PCR CLK_REQ[%d] = 0x%08X\n", pcr_clk_req[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int command_idle_stats(int argc, char **argv)
|
||||
{
|
||||
timestamp_t ts = get_time();
|
||||
|
||||
ccprintf("Num idle calls that sleep: %d\n",
|
||||
idle_sleep_cnt);
|
||||
ccprintf("Num idle calls that deep-sleep: %d\n",
|
||||
idle_dsleep_cnt);
|
||||
|
||||
ccprintf("Total Time spent in deep-sleep(sec): %.6ld(s)\n",
|
||||
total_idle_dsleep_time_us);
|
||||
ccprintf("Total time on: %.6lds\n\n",
|
||||
ts.val);
|
||||
|
||||
#ifdef CONFIG_MCHP_DEEP_SLP_DEBUG
|
||||
print_pcr_regs(); /* debug */
|
||||
#endif
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats,
|
||||
"",
|
||||
"Print last idle stats");
|
||||
#endif /* defined(CONFIG_CMD_IDLE_STATS) */
|
||||
|
||||
/**
|
||||
* Configure deep sleep clock settings.
|
||||
*/
|
||||
static int command_dsleep(int argc, char **argv)
|
||||
{
|
||||
int v;
|
||||
|
||||
if (argc > 1) {
|
||||
if (parse_bool(argv[1], &v)) {
|
||||
/*
|
||||
* Force deep sleep not to use heavy sleep mode or
|
||||
* allow it to use the heavy sleep mode.
|
||||
*/
|
||||
if (v) /* 'on' */
|
||||
disable_sleep(
|
||||
SLEEP_MASK_FORCE_NO_LOW_SPEED);
|
||||
else /* 'off' */
|
||||
enable_sleep(
|
||||
SLEEP_MASK_FORCE_NO_LOW_SPEED);
|
||||
} else {
|
||||
/* Set console in use timeout. */
|
||||
char *e;
|
||||
|
||||
v = strtoi(argv[1], &e, 10);
|
||||
if (*e)
|
||||
return EC_ERROR_PARAM1;
|
||||
|
||||
console_in_use_timeout_sec = v;
|
||||
|
||||
/* Refresh console in use to use new timeout. */
|
||||
clock_refresh_console_in_use();
|
||||
}
|
||||
}
|
||||
|
||||
ccprintf("Sleep mask: %08x\n", sleep_mask);
|
||||
ccprintf("Console in use timeout: %d sec\n",
|
||||
console_in_use_timeout_sec);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(dsleep, command_dsleep,
|
||||
"[ on | off | <timeout> sec]",
|
||||
"Deep sleep clock settings:\nUse 'on' to force deep "
|
||||
"sleep NOT to enter heavysleep mode.\nUse 'off' to "
|
||||
"allow deepsleep to use heavysleep whenever conditions "
|
||||
"allow.\n"
|
||||
"Give a timeout value for the console in use timeout.\n"
|
||||
"See also 'sleepmask'.");
|
||||
#endif /* CONFIG_LOW_POWER_IDLE */
|
||||
191
chip/mchp/config_chip.h
Normal file
191
chip/mchp/config_chip.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef __CROS_EC_CONFIG_CHIP_H
|
||||
#define __CROS_EC_CONFIG_CHIP_H
|
||||
|
||||
/* CPU core BFD configuration */
|
||||
#include "core/cortex-m/config_core.h"
|
||||
|
||||
/* Number of IRQ vectors on the NVIC */
|
||||
#define CONFIG_IRQ_COUNT 157
|
||||
|
||||
/* Use a bigger console output buffer */
|
||||
#undef CONFIG_UART_TX_BUF_SIZE
|
||||
#define CONFIG_UART_TX_BUF_SIZE 2048
|
||||
|
||||
/* Interval between HOOK_TICK notifications */
|
||||
#define HOOK_TICK_INTERVAL_MS 250
|
||||
#define HOOK_TICK_INTERVAL (HOOK_TICK_INTERVAL_MS * MSEC)
|
||||
|
||||
/*
|
||||
* Enable chip_pre_init called from main
|
||||
* Used for configuring peripheral block
|
||||
* sleep enables.
|
||||
*/
|
||||
#define CONFIG_CHIP_PRE_INIT
|
||||
|
||||
|
||||
/*
|
||||
* MCHP EC's have I2C master/slave
|
||||
* controllers and multiple I2C ports. Any
|
||||
* port may be mapped to any controller.
|
||||
* Enable multi-port controller feature.
|
||||
* Board level configuration determines
|
||||
* how many controllers/ports are used and
|
||||
* the mapping of port(s) to controller(s).
|
||||
* NOTE: Some MCHP reduced pin packages
|
||||
* may not implement all 11 I2C ports.
|
||||
*/
|
||||
#define CONFIG_I2C_MULTI_PORT_CONTROLLER
|
||||
|
||||
/*
|
||||
* MCHP I2C controller is master-slave capable and requires
|
||||
* a slave address be programmed even if used as master only.
|
||||
* Each I2C controller can respond to two slave address.
|
||||
* Define dummy slave addresses that aren't used on the I2C port(s)
|
||||
* connected to each controller.
|
||||
*/
|
||||
#define CONFIG_MCHP_I2C0_SLAVE_ADDRS 0xE3E1
|
||||
#define CONFIG_MCHP_I2C1_SLAVE_ADDRS 0xE3E1
|
||||
#define CONFIG_MCHP_I2C2_SLAVE_ADDRS 0xE3E1
|
||||
#define CONFIG_MCHP_I2C3_SLAVE_ADDRS 0xE3E1
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Memory mapping */
|
||||
|
||||
/*
|
||||
* MEC1701H has a total of 256KB SRAM.
|
||||
* CODE at 0xE0000 - 0x117FFF, DATA at 0x118000 - 0x11FFFF
|
||||
* MCHP MEC can fetch code from data or data from code.
|
||||
*/
|
||||
|
||||
/************************************************************************/
|
||||
/* Define our RAM layout. */
|
||||
|
||||
#define CONFIG_MEC_SRAM_BASE_START 0x000E0000
|
||||
#define CONFIG_MEC_SRAM_BASE_END 0x00120000
|
||||
#define CONFIG_MEC_SRAM_SIZE (CONFIG_MEC_SRAM_BASE_END - \
|
||||
CONFIG_MEC_SRAM_BASE_START)
|
||||
|
||||
/* 32k RAM for RO / RW / loader */
|
||||
#define CONFIG_RAM_SIZE 0x00008000
|
||||
#define CONFIG_RAM_BASE (CONFIG_MEC_SRAM_BASE_END - \
|
||||
CONFIG_RAM_SIZE)
|
||||
|
||||
/* System stack size */
|
||||
#define CONFIG_STACK_SIZE 1024
|
||||
|
||||
/* non-standard task stack sizes */
|
||||
#define IDLE_TASK_STACK_SIZE 512
|
||||
#define LARGER_TASK_STACK_SIZE 640
|
||||
#define VENTI_TASK_STACK_SIZE 768
|
||||
|
||||
#define CHARGER_TASK_STACK_SIZE 640
|
||||
#define HOOKS_TASK_STACK_SIZE 640
|
||||
#define CONSOLE_TASK_STACK_SIZE 640
|
||||
#define HOST_CMD_TASK_STACK_SIZE 640
|
||||
|
||||
/*
|
||||
* TODO: Large stack consumption
|
||||
* https://code.google.com/p/chrome-os-partner/issues/detail?id=49245
|
||||
*/
|
||||
#define PD_TASK_STACK_SIZE 800
|
||||
|
||||
/* Default task stack size */
|
||||
#define TASK_STACK_SIZE 512
|
||||
|
||||
/************************************************************************/
|
||||
/* Define our flash layout. */
|
||||
|
||||
/* Protect bank size 4K bytes */
|
||||
#define CONFIG_FLASH_BANK_SIZE 0x00001000
|
||||
/* Sector erase size 4K bytes */
|
||||
#define CONFIG_FLASH_ERASE_SIZE 0x00001000
|
||||
/* Minimum write size */
|
||||
#define CONFIG_FLASH_WRITE_SIZE 0x00000004
|
||||
|
||||
/* One page size for write */
|
||||
#define CONFIG_FLASH_WRITE_IDEAL_SIZE 256
|
||||
|
||||
/* Program memory base address */
|
||||
#define CONFIG_PROGRAM_MEMORY_BASE 0x000E0000
|
||||
|
||||
#include "config_flash_layout.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Customize the build */
|
||||
/* Optional features present on this chip */
|
||||
#define CONFIG_ADC
|
||||
#define CONFIG_DMA
|
||||
#define CONFIG_LPC
|
||||
#define CONFIG_SPI
|
||||
#define CONFIG_SWITCH
|
||||
|
||||
/*
|
||||
* Enable configuration after ESPI_RESET# de-asserts
|
||||
*/
|
||||
#undef CONFIG_MCHP_ESPI_RESET_DEASSERT_INIT
|
||||
|
||||
/*
|
||||
* Enable CPRINT in chip eSPI module
|
||||
* Define at board level.
|
||||
*/
|
||||
#undef CONFIG_MCHP_ESPI_DEBUG
|
||||
|
||||
/*
|
||||
* Enable EC UART commands in eSPI module useful for debugging.
|
||||
*/
|
||||
#undef CONFIG_MCHP_ESPI_EC_CMD
|
||||
|
||||
/*
|
||||
* Define this to use MEC1701 ROM SPI read API
|
||||
* in little firmware module instead of SPI code
|
||||
* from this module
|
||||
*/
|
||||
#undef CONFIG_CHIP_LFW_USE_ROM_SPI
|
||||
|
||||
/*
|
||||
* Use DMA when transmitting commands & data
|
||||
* with GPSPI controllers.
|
||||
*/
|
||||
#define CONFIG_MCHP_GPSPI_TX_DMA
|
||||
|
||||
/*
|
||||
* Use DMA when transmitting command & data of length
|
||||
* greater than QMSPI TX FIFO size.
|
||||
*/
|
||||
#define CONFIG_MCHP_QMSPI_TX_DMA
|
||||
|
||||
/*
|
||||
* Board level gpio.inc is using MCHP data sheet GPIO pin
|
||||
* numbers which are octal.
|
||||
* MCHP has 6 banks/ports each containing 32 GPIO's.
|
||||
* Each bank/port is connected to a GIRQ.
|
||||
* Port numbering:
|
||||
* GPIO_015 = 13 decimal. Port = 13/32 = 0, bit = 13 % 32 = 13
|
||||
* GPIO_0123 = 83 decimal. Port 83/32 = 2, bit = 83 % 32 = 19
|
||||
* OR port = 0123 >> 5, bit = 0123 & 037(0x1F) = 023 = 19 decimal.
|
||||
* You must use octal GPIO numbers in PIN(gpio_num) macro in
|
||||
* gpio.inc files.
|
||||
* Example: GPIO 211 in documentation 0211 = 137 = 0x89
|
||||
* GPIO(PCH_SLP_S0_L, PIN(0211), GPIO_INPUT | GPIO_PULL_DOWN)
|
||||
* OR
|
||||
* GPIO(PCH_SLP_S0_L, PIN(0x89), GPIO_INPUT | GPIO_PULL_DOWN)
|
||||
*/
|
||||
#define GPIO_BANK(index) ((index) >> 5)
|
||||
#define GPIO_BANK_MASK(index) (1ul << ((index) & 0x1F))
|
||||
|
||||
#define GPIO_PIN(index) GPIO_BANK(index), GPIO_BANK_MASK(index)
|
||||
|
||||
#define GPIO_PIN_MASK(bank, mask) (bank), (mask)
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
|
||||
#endif /* #ifndef __ASSEMBLER__ */
|
||||
|
||||
#endif /* __CROS_EC_CONFIG_CHIP_H */
|
||||
419
chip/mchp/gpio.c
Normal file
419
chip/mchp/gpio.c
Normal file
@@ -0,0 +1,419 @@
|
||||
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* GPIO module for MCHP MEC */
|
||||
|
||||
#include "common.h"
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "registers.h"
|
||||
#include "system.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
#include "lpc_chip.h"
|
||||
#include "tfdp_chip.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPUTS(outstr) cputs(CC_LPC, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
|
||||
|
||||
|
||||
struct gpio_int_mapping {
|
||||
int8_t girq_id;
|
||||
int8_t port_offset;
|
||||
};
|
||||
|
||||
/* TODO will this mapping change for other MEC chips?
|
||||
* Mapping from GPIO port to GIRQ info
|
||||
* MEC1701 each bank contains 32 GPIO's. Pin Id is the bit position [0:31]
|
||||
* Bank GPIO's GIRQ
|
||||
* 0 0000 - 0036 11
|
||||
* 1 0040 - 0076 10
|
||||
* 2 0100 - 0135 9
|
||||
* 3 0140 - 0175 8
|
||||
* 4 0200 - 0235 12
|
||||
* 5 0240 - 0276 26
|
||||
*/
|
||||
static const struct gpio_int_mapping int_map[6] = {
|
||||
{ 11, 0 }, { 10, 1 }, { 9, 2 },
|
||||
{ 8, 3 }, { 12, 4 }, { 26, 5 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* NOTE: GCC __builtin_ffs(val) returns (index + 1) of least significant
|
||||
* 1-bit of val or if val == 0 returns 0
|
||||
*/
|
||||
void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
while (mask) {
|
||||
i = __builtin_ffs(mask) - 1;
|
||||
val = MCHP_GPIO_CTL(port, i);
|
||||
val &= ~((1 << 12) | (1 << 13));
|
||||
/* mux_control = 0 indicates GPIO */
|
||||
if (func > 0)
|
||||
val |= (func & 0x3) << 12;
|
||||
MCHP_GPIO_CTL(port, i) = val;
|
||||
mask &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
test_mockable int gpio_get_level(enum gpio_signal signal)
|
||||
{
|
||||
uint32_t mask = gpio_list[signal].mask;
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
if (mask == 0)
|
||||
return 0;
|
||||
i = GPIO_MASK_TO_NUM(mask);
|
||||
val = MCHP_GPIO_CTL(gpio_list[signal].port, i);
|
||||
|
||||
return (val & (1 << 24)) ? 1 : 0;
|
||||
}
|
||||
|
||||
void gpio_set_level(enum gpio_signal signal, int value)
|
||||
{
|
||||
uint32_t mask = gpio_list[signal].mask;
|
||||
int i;
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
i = GPIO_MASK_TO_NUM(mask);
|
||||
|
||||
if (value)
|
||||
MCHP_GPIO_CTL(gpio_list[signal].port, i) |= (1 << 16);
|
||||
else
|
||||
MCHP_GPIO_CTL(gpio_list[signal].port, i) &= ~(1 << 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add support for new #ifdef CONFIG_CMD_GPIO_POWER_DOWN.
|
||||
* If GPIO_POWER_DONW flag is set force GPIO Control to
|
||||
* GPIO input, interrupt detect disabled, power control field
|
||||
* in bits[3:2]=10b.
|
||||
* NOTE: if interrupt detect is enabled when pin is powered down
|
||||
* then a false edge may be detected.
|
||||
*
|
||||
*/
|
||||
void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
|
||||
{
|
||||
int i;
|
||||
uint32_t val;
|
||||
|
||||
while (mask) {
|
||||
i = GPIO_MASK_TO_NUM(mask);
|
||||
mask &= ~(1 << i);
|
||||
val = MCHP_GPIO_CTL(port, i);
|
||||
|
||||
#ifdef CONFIG_GPIO_POWER_DOWN
|
||||
if (flags & GPIO_POWER_DOWN) {
|
||||
val = (MCHP_GPIO_CTRL_PWR_OFF +
|
||||
MCHP_GPIO_INTDET_DISABLED);
|
||||
MCHP_GPIO_CTL(port, i) = val;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
val &= ~(MCHP_GPIO_CTRL_PWR_MASK);
|
||||
val |= MCHP_GPIO_CTRL_PWR_VTR;
|
||||
|
||||
/*
|
||||
* Select open drain first, so that we don't
|
||||
* glitch the signal when changing the line to
|
||||
* an output.
|
||||
*/
|
||||
if (flags & GPIO_OPEN_DRAIN)
|
||||
val |= (MCHP_GPIO_OPEN_DRAIN);
|
||||
else
|
||||
val &= ~(MCHP_GPIO_OPEN_DRAIN);
|
||||
|
||||
if (flags & GPIO_OUTPUT) {
|
||||
val |= (MCHP_GPIO_OUTPUT);
|
||||
val &= ~(MCHP_GPIO_OUTSEL_PAR);
|
||||
} else {
|
||||
val &= ~(MCHP_GPIO_OUTPUT);
|
||||
val |= (MCHP_GPIO_OUTSEL_PAR);
|
||||
}
|
||||
|
||||
/* Handle pull-up / pull-down */
|
||||
val &= ~(MCHP_GPIO_CTRL_PUD_MASK);
|
||||
if (flags & GPIO_PULL_UP)
|
||||
val |= MCHP_GPIO_CTRL_PUD_PU;
|
||||
else if (flags & GPIO_PULL_DOWN)
|
||||
val |= MCHP_GPIO_CTRL_PUD_PD;
|
||||
else
|
||||
val |= MCHP_GPIO_CTRL_PUD_NONE;
|
||||
|
||||
/* Set up interrupt */
|
||||
val &= ~(MCHP_GPIO_INTDET_MASK);
|
||||
switch (flags & GPIO_INT_ANY) {
|
||||
case GPIO_INT_F_RISING:
|
||||
val |= MCHP_GPIO_INTDET_EDGE_RIS;
|
||||
break;
|
||||
case GPIO_INT_F_FALLING:
|
||||
val |= MCHP_GPIO_INTDET_EDGE_FALL;
|
||||
break;
|
||||
case GPIO_INT_BOTH: /* both edges */
|
||||
val |= MCHP_GPIO_INTDET_EDGE_BOTH;
|
||||
break;
|
||||
case GPIO_INT_F_LOW:
|
||||
val |= MCHP_GPIO_INTDET_LVL_LO;
|
||||
break;
|
||||
case GPIO_INT_F_HIGH:
|
||||
val |= MCHP_GPIO_INTDET_LVL_HI;
|
||||
break;
|
||||
default:
|
||||
val |= MCHP_GPIO_INTDET_DISABLED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set up level */
|
||||
if (flags & GPIO_HIGH)
|
||||
val |= (MCHP_GPIO_CTRL_OUT_LVL);
|
||||
else if (flags & GPIO_LOW)
|
||||
val &= ~(MCHP_GPIO_CTRL_OUT_LVL);
|
||||
|
||||
MCHP_GPIO_CTL(port, i) = val;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_power_off_by_mask(uint32_t port, uint32_t mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
while (mask) {
|
||||
i = GPIO_MASK_TO_NUM(mask);
|
||||
mask &= ~(1 << i);
|
||||
|
||||
MCHP_GPIO_CTL(port, i) = (MCHP_GPIO_CTRL_PWR_OFF +
|
||||
MCHP_GPIO_INTDET_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
int gpio_power_off(enum gpio_signal signal)
|
||||
{
|
||||
int i, port;
|
||||
|
||||
if (gpio_list[signal].mask == 0)
|
||||
return EC_ERROR_INVAL;
|
||||
|
||||
i = GPIO_MASK_TO_NUM(gpio_list[signal].mask);
|
||||
port = gpio_list[signal].port;
|
||||
|
||||
MCHP_GPIO_CTL(port, i) = (MCHP_GPIO_CTRL_PWR_OFF +
|
||||
MCHP_GPIO_INTDET_DISABLED);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* gpio_list[signal].port = [0, 6] each port contains up to 32 pins
|
||||
* gpio_list[signal].mask = bit mask in 32-bit port
|
||||
* NOTE: MCHP GPIO are always aggregated not direct connected to NVIC.
|
||||
* GPIO's are aggregated into banks of 32 pins.
|
||||
* Each bank/port are connected to a GIRQ.
|
||||
* int_map[port].girq_id is the GIRQ ID
|
||||
* The bit number in the GIRQ registers is the same as the bit number
|
||||
* in the GPIO bank.
|
||||
*/
|
||||
int gpio_enable_interrupt(enum gpio_signal signal)
|
||||
{
|
||||
int i, port, girq_id;
|
||||
|
||||
if (gpio_list[signal].mask == 0)
|
||||
return EC_SUCCESS;
|
||||
|
||||
i = GPIO_MASK_TO_NUM(gpio_list[signal].mask);
|
||||
port = gpio_list[signal].port;
|
||||
girq_id = int_map[port].girq_id;
|
||||
|
||||
MCHP_INT_ENABLE(girq_id) = (1 << i);
|
||||
MCHP_INT_BLK_EN |= (1 << girq_id);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
int gpio_disable_interrupt(enum gpio_signal signal)
|
||||
{
|
||||
int i, port, girq_id;
|
||||
|
||||
if (gpio_list[signal].mask == 0)
|
||||
return EC_SUCCESS;
|
||||
|
||||
i = GPIO_MASK_TO_NUM(gpio_list[signal].mask);
|
||||
port = gpio_list[signal].port;
|
||||
girq_id = int_map[port].girq_id;
|
||||
|
||||
|
||||
MCHP_INT_DISABLE(girq_id) = (1 << i);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* MCHP Interrupt Source is R/W1C no need for read-modify-write.
|
||||
* GPIO's are aggregated meaning the NVIC Pending bit may be
|
||||
* set for another GPIO in the GIRQ. You can clear NVIC pending
|
||||
* and the hardware should re-assert it within one Cortex-M4 clock.
|
||||
* If the Cortex-M4 is clocked slower than AHB then the Cortex-M4
|
||||
* will take longer to register the interrupt. Not clearing NVIC
|
||||
* pending leave a pending status if only the GPIO this routine
|
||||
* clears is pending.
|
||||
* NVIC (system control) register space is strongly-ordered
|
||||
* Interrupt Aggregator is in Device space (system bus connected
|
||||
* to AHB) with the Cortex-M4 write buffer.
|
||||
* We need to insure the write to aggregator register in device
|
||||
* AHB space completes before NVIC pending is cleared.
|
||||
* The Cortex-M4 memory ordering rules imply Device access
|
||||
* comes before strongly ordered access. Cortex-M4 will not re-order
|
||||
* the writes. Due to the presence of the write buffer a DSB will
|
||||
* not guarantee the clearing of the device status completes. Add
|
||||
* a read back before clearing NVIC pending.
|
||||
* GIRQ 8, 9, 10, 11, 12, 26 map to NVIC inputs 0, 1, 2, 3, 4, and 18.
|
||||
*/
|
||||
int gpio_clear_pending_interrupt(enum gpio_signal signal)
|
||||
{
|
||||
int i, port, girq_id;
|
||||
|
||||
if (gpio_list[signal].mask == 0)
|
||||
return EC_SUCCESS;
|
||||
|
||||
i = GPIO_MASK_TO_NUM(gpio_list[signal].mask);
|
||||
port = gpio_list[signal].port;
|
||||
girq_id = int_map[port].girq_id;
|
||||
|
||||
/* Clear interrupt source sticky status bit even if not enabled */
|
||||
MCHP_INT_SOURCE(girq_id) = (1 << i);
|
||||
i = MCHP_INT_SOURCE(girq_id);
|
||||
task_clear_pending_irq(girq_id - 8);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* MCHP NOTE - called from main before scheduler started
|
||||
*/
|
||||
void gpio_pre_init(void)
|
||||
{
|
||||
int i;
|
||||
int flags;
|
||||
int is_warm = system_is_reboot_warm();
|
||||
const struct gpio_info *g = gpio_list;
|
||||
|
||||
|
||||
for (i = 0; i < GPIO_COUNT; i++, g++) {
|
||||
flags = g->flags;
|
||||
|
||||
if (flags & GPIO_DEFAULT)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If this is a warm reboot, don't set the output levels or
|
||||
* we'll shut off the AP.
|
||||
*/
|
||||
if (is_warm)
|
||||
flags &= ~(GPIO_LOW | GPIO_HIGH);
|
||||
|
||||
gpio_set_flags_by_mask(g->port, g->mask, flags);
|
||||
|
||||
/* Use as GPIO, not alternate function */
|
||||
gpio_set_alternate_function(g->port, g->mask, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear any interrupt flags before enabling GPIO interrupt
|
||||
* Original code has flaws.
|
||||
* Writing result register to source only clears bits that have their
|
||||
* enable and sources bits set.
|
||||
* We must clear the NVIC pending R/W bit before setting NVIC enable.
|
||||
* NVIC Pending is only cleared by the NVIC HW on ISR entry.
|
||||
* Modifications are:
|
||||
* 1. Clear all status bits in each GPIO GIRQ. This assumes any edges
|
||||
* will occur after gpio_init. The old code is also making this
|
||||
* assumption for the GPIO's that have been enabled.
|
||||
* 2. Clear NVIC pending to prevent ISR firing on false edge.
|
||||
*/
|
||||
#define ENABLE_GPIO_GIRQ(x) \
|
||||
do { \
|
||||
MCHP_INT_SOURCE(x) = 0xfffffffful; \
|
||||
task_clear_pending_irq(MCHP_IRQ_GIRQ ## x); \
|
||||
task_enable_irq(MCHP_IRQ_GIRQ ## x); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static void gpio_init(void)
|
||||
{
|
||||
ENABLE_GPIO_GIRQ(8);
|
||||
ENABLE_GPIO_GIRQ(9);
|
||||
ENABLE_GPIO_GIRQ(10);
|
||||
ENABLE_GPIO_GIRQ(11);
|
||||
ENABLE_GPIO_GIRQ(12);
|
||||
ENABLE_GPIO_GIRQ(26);
|
||||
}
|
||||
DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT);
|
||||
|
||||
/************************************************************************/
|
||||
/* Interrupt handlers */
|
||||
|
||||
|
||||
/**
|
||||
* Handler for each GIRQ interrupt. This reads and clears the interrupt
|
||||
* bits for the GIRQ interrupt, then finds and calls the corresponding
|
||||
* GPIO interrupt handlers.
|
||||
*
|
||||
* @param girq GIRQ index
|
||||
* @param port_offset GPIO port offset for the given GIRQ
|
||||
*/
|
||||
static void gpio_interrupt(int girq)
|
||||
{
|
||||
int i, bit;
|
||||
const struct gpio_info *g = gpio_list;
|
||||
uint32_t sts = MCHP_INT_RESULT(girq);
|
||||
|
||||
/* CPRINTS("MEC1701 GPIO GIRQ %d result = 0x%08x", girq, sts); */
|
||||
trace12(0, GPIO, 0, "GPIO GIRQ %d result = 0x%08x", girq, sts);
|
||||
|
||||
/* RW1C, no need for read-modify-write */
|
||||
MCHP_INT_SOURCE(girq) = sts;
|
||||
|
||||
for (i = 0; i < GPIO_IH_COUNT && sts; ++i, ++g) {
|
||||
bit = __builtin_ffs(g->mask) - 1;
|
||||
if (sts & (1 << bit))
|
||||
gpio_irq_handlers[i](i);
|
||||
sts &= ~(1 << bit);
|
||||
}
|
||||
}
|
||||
|
||||
#define GPIO_IRQ_FUNC(irqfunc, girq) \
|
||||
void irqfunc(void) \
|
||||
{ \
|
||||
gpio_interrupt(girq); \
|
||||
}
|
||||
|
||||
GPIO_IRQ_FUNC(__girq_8_interrupt, 8);
|
||||
GPIO_IRQ_FUNC(__girq_9_interrupt, 9);
|
||||
GPIO_IRQ_FUNC(__girq_10_interrupt, 10);
|
||||
GPIO_IRQ_FUNC(__girq_11_interrupt, 11);
|
||||
GPIO_IRQ_FUNC(__girq_12_interrupt, 12);
|
||||
GPIO_IRQ_FUNC(__girq_26_interrupt, 26);
|
||||
|
||||
#undef GPIO_IRQ_FUNC
|
||||
|
||||
/*
|
||||
* Declare IRQs. Nesting this macro inside the GPIO_IRQ_FUNC macro works
|
||||
* poorly because DECLARE_IRQ() stringizes its inputs.
|
||||
*/
|
||||
DECLARE_IRQ(MCHP_IRQ_GIRQ8, __girq_8_interrupt, 1);
|
||||
DECLARE_IRQ(MCHP_IRQ_GIRQ9, __girq_9_interrupt, 1);
|
||||
DECLARE_IRQ(MCHP_IRQ_GIRQ10, __girq_10_interrupt, 1);
|
||||
DECLARE_IRQ(MCHP_IRQ_GIRQ11, __girq_11_interrupt, 1);
|
||||
DECLARE_IRQ(MCHP_IRQ_GIRQ12, __girq_12_interrupt, 1);
|
||||
DECLARE_IRQ(MCHP_IRQ_GIRQ26, __girq_26_interrupt, 1);
|
||||
|
||||
38
chip/mchp/gpio_chip.h
Normal file
38
chip/mchp/gpio_chip.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Copyright 2017 The Chromium OS Authors. All rights reserved
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Register map for MCHP MEC processor
|
||||
*/
|
||||
/** @file gpio_chip.h
|
||||
*MEC GPIO module
|
||||
*/
|
||||
/** @defgroup MEC gpio
|
||||
*/
|
||||
|
||||
#ifndef _GPIO_CHIP_H
|
||||
#define _GPIO_CHIP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Place any C interfaces here */
|
||||
|
||||
int gpio_power_off(enum gpio_signal signal);
|
||||
|
||||
void gpio_power_off_by_mask(uint32_t port, uint32_t mask);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef _GPIO_CHIP_H */
|
||||
/** @}
|
||||
*/
|
||||
|
||||
97
chip/mchp/gpio_cmds.c
Normal file
97
chip/mchp/gpio_cmds.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* MCHP MEC GPIO module EC UART commands */
|
||||
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "registers.h"
|
||||
#include "system.h"
|
||||
#include "util.h"
|
||||
#include "gpio_chip.h"
|
||||
#include "tfdp_chip.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPUTS(outstr) cputs(CC_LPC, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
|
||||
|
||||
|
||||
|
||||
static int cmd_gp_get_config(int argc, char **argv)
|
||||
{
|
||||
char *e;
|
||||
int i;
|
||||
uint32_t gctrl;
|
||||
|
||||
/* If a signal is specified, print only that one */
|
||||
if (argc == 2) {
|
||||
i = strtoi(argv[1], &e, 0);
|
||||
if (*e)
|
||||
return EC_ERROR_PARAM1;
|
||||
|
||||
if (!gpio_is_implemented(i))
|
||||
return EC_ERROR_PARAM1;
|
||||
|
||||
gctrl = MCHP_GPIO_CTRL(i);
|
||||
|
||||
ccprintf(" GPIO[0x%X].Ctrl = 0x%08X\n", i, gctrl);
|
||||
|
||||
} else { /* Otherwise print them all */
|
||||
for (i = 0; i < GPIO_COUNT; i++) {
|
||||
if (!gpio_is_implemented(i))
|
||||
continue; /* Skip unsupported signals */
|
||||
|
||||
gctrl = MCHP_GPIO_CTRL(i);
|
||||
|
||||
ccprintf(" GPIO[0x%X].Ctrl = 0x%08X\n", i, gctrl);
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush console to avoid truncating output */
|
||||
cflush();
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(gpgetcfg, cmd_gp_get_config,
|
||||
"[number]",
|
||||
"Read GPIO config");
|
||||
|
||||
static int cmd_gp_set_config(int argc, char **argv)
|
||||
{
|
||||
char *e;
|
||||
int i;
|
||||
uint32_t gctrl;
|
||||
|
||||
/* If a signal is specified, print only that one */
|
||||
if (argc > 2) {
|
||||
i = strtoi(argv[1], &e, 0);
|
||||
if (*e)
|
||||
return EC_ERROR_PARAM1;
|
||||
|
||||
if (!gpio_is_implemented(i))
|
||||
return EC_ERROR_PARAM1;
|
||||
|
||||
gctrl = (uint32_t)strtoi(argv[2], &e, 0);
|
||||
if (*e)
|
||||
return EC_ERROR_PARAM2;
|
||||
|
||||
MCHP_GPIO_CTRL(i) = gctrl;
|
||||
gctrl = MCHP_GPIO_CTRL(i);
|
||||
ccprintf(" GPIO[0x%X].Ctrl = 0x%08X\n", i, gctrl);
|
||||
|
||||
} else {
|
||||
ccprintf(" Requires two parameters: GPIO num and new config");
|
||||
}
|
||||
/* Flush console to avoid truncating output */
|
||||
cflush();
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(gpsetcfg, cmd_gp_set_config,
|
||||
"gp_num val",
|
||||
"Set GPIO config");
|
||||
|
||||
2226
chip/mchp/registers.h
Normal file
2226
chip/mchp/registers.h
Normal file
File diff suppressed because it is too large
Load Diff
490
chip/mchp/system.c
Normal file
490
chip/mchp/system.c
Normal file
@@ -0,0 +1,490 @@
|
||||
/* Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* System module for Chrome EC : MCHP hardware specific implementation */
|
||||
|
||||
#include "clock.h"
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "cpu.h"
|
||||
#include "gpio.h"
|
||||
#include "host_command.h"
|
||||
#include "registers.h"
|
||||
#include "shared_mem.h"
|
||||
#include "system.h"
|
||||
#include "hooks.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
#include "spi.h"
|
||||
#include "lpc_chip.h"
|
||||
#include "tfdp_chip.h"
|
||||
|
||||
|
||||
#define CPUTS(outstr) cputs(CC_LPC, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
|
||||
|
||||
|
||||
/* Indices for hibernate data registers (RAM backed by VBAT) */
|
||||
enum hibdata_index {
|
||||
HIBDATA_INDEX_SCRATCHPAD = 0, /* General-purpose scratchpad */
|
||||
HIBDATA_INDEX_SAVED_RESET_FLAGS, /* Saved reset flags */
|
||||
HIBDATA_INDEX_PD0, /* USB-PD0 saved port state */
|
||||
HIBDATA_INDEX_PD1, /* USB-PD1 saved port state */
|
||||
};
|
||||
|
||||
static void check_reset_cause(void)
|
||||
{
|
||||
uint32_t status = MCHP_VBAT_STS;
|
||||
uint32_t flags = 0;
|
||||
uint32_t rst_sts = MCHP_PCR_PWR_RST_STS &
|
||||
(MCHP_PWR_RST_STS_VTR |
|
||||
MCHP_PWR_RST_STS_VBAT);
|
||||
|
||||
trace12(0, MEC, 0,
|
||||
"check_reset_cause: VBAT_PFR = 0x%08X PCR PWRST = 0x%08X",
|
||||
status, rst_sts);
|
||||
|
||||
/* Clear the reset causes now that we've read them */
|
||||
MCHP_VBAT_STS |= status;
|
||||
MCHP_PCR_PWR_RST_STS |= rst_sts;
|
||||
|
||||
|
||||
trace0(0, MEC, 0, "check_reset_cause: after clear");
|
||||
trace11(0, MEC, 0, " VBAT_PFR = 0x%08X", MCHP_VBAT_STS);
|
||||
trace11(0, MEC, 0, " PCR PWRST = 0x%08X", MCHP_PCR_PWR_RST_STS);
|
||||
|
||||
/*
|
||||
* BIT[6] determine VTR reset
|
||||
*/
|
||||
if (rst_sts & MCHP_PWR_RST_STS_VTR)
|
||||
flags |= RESET_FLAG_RESET_PIN;
|
||||
|
||||
|
||||
flags |= MCHP_VBAT_RAM(HIBDATA_INDEX_SAVED_RESET_FLAGS);
|
||||
MCHP_VBAT_RAM(HIBDATA_INDEX_SAVED_RESET_FLAGS) = 0;
|
||||
|
||||
if ((status & MCHP_VBAT_STS_WDT) && !(flags & (RESET_FLAG_SOFT |
|
||||
RESET_FLAG_HARD |
|
||||
RESET_FLAG_HIBERNATE)))
|
||||
flags |= RESET_FLAG_WATCHDOG;
|
||||
|
||||
trace11(0, MEC, 0, "check_reset_cause: EC reset flags = 0x%08x", flags);
|
||||
|
||||
system_set_reset_flags(flags);
|
||||
}
|
||||
|
||||
int system_is_reboot_warm(void)
|
||||
{
|
||||
uint32_t reset_flags;
|
||||
/*
|
||||
* Check reset cause here,
|
||||
* gpio_pre_init is executed faster than system_pre_init
|
||||
*/
|
||||
check_reset_cause();
|
||||
reset_flags = system_get_reset_flags();
|
||||
|
||||
if ((reset_flags & RESET_FLAG_RESET_PIN) ||
|
||||
(reset_flags & RESET_FLAG_POWER_ON) ||
|
||||
(reset_flags & RESET_FLAG_WATCHDOG) ||
|
||||
(reset_flags & RESET_FLAG_HARD) ||
|
||||
(reset_flags & RESET_FLAG_SOFT))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sleep unused blocks to reduce power.
|
||||
* Drivers/modules will unsleep their blocks.
|
||||
* Keep sleep enables cleared for required blocks:
|
||||
* ECIA, PMC, CPU, ECS and optionally JTAG.
|
||||
* SLEEP_ALL feature will set these upon sleep entry.
|
||||
* Based on CONFIG_CHIPSET_DEBUG enable or disable JTAG.
|
||||
* JTAG mode (4-pin or 2-pin SWD + 1-pin SWV) was set
|
||||
* by Boot-ROM. We can override Boot-ROM JTAG mode
|
||||
* using
|
||||
* CONFIG_MCHP_JTAG_MODE
|
||||
*/
|
||||
static void chip_periph_sleep_control(void)
|
||||
{
|
||||
uint32_t d;
|
||||
|
||||
d = MCHP_PCR_SLP_EN0_SLEEP;
|
||||
#ifdef CONFIG_CHIPSET_DEBUG
|
||||
d &= ~(MCHP_PCR_SLP_EN0_JTAG);
|
||||
#ifdef CONFIG_MCHP_JTAG_MODE
|
||||
MCHP_EC_JTAG_EN = CONFIG_MCHP_JTAG_MODE;
|
||||
#else
|
||||
MCHP_EC_JTAG_EN |= 0x01;
|
||||
#endif
|
||||
#else
|
||||
MCHP_EC_JTAG_EN &= ~0x01;
|
||||
#endif
|
||||
MCHP_PCR_SLP_EN0 = d;
|
||||
MCHP_PCR_SLP_EN1 = MCHP_PCR_SLP_EN1_UNUSED_BLOCKS;
|
||||
MCHP_PCR_SLP_EN2 = MCHP_PCR_SLP_EN2_SLEEP;
|
||||
MCHP_PCR_SLP_EN3 = MCHP_PCR_SLP_EN3_SLEEP;
|
||||
MCHP_PCR_SLP_EN4 = MCHP_PCR_SLP_EN4_SLEEP;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CHIP_PRE_INIT
|
||||
void chip_pre_init(void)
|
||||
{
|
||||
chip_periph_sleep_control();
|
||||
}
|
||||
#endif
|
||||
|
||||
void system_pre_init(void)
|
||||
{
|
||||
#ifdef CONFIG_MCHP_TFDP
|
||||
uint8_t imgtype;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure AHB Error capture is enabled.
|
||||
* Signals bus fault to Cortex-M4 core if an address presented
|
||||
* to AHB is not claimed by any HW block.
|
||||
*/
|
||||
MCHP_EC_AHB_ERR = 0; /* write any value to clear */
|
||||
MCHP_EC_AHB_ERR_EN = 0; /* enable capture of address on error */
|
||||
|
||||
#ifdef CONFIG_ESPI
|
||||
MCHP_EC_GPIO_BANK_PWR |= MCHP_EC_GPIO_BANK_PWR_VTR3_18;
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_CHIP_PRE_INIT
|
||||
chip_periph_sleep_control();
|
||||
#endif
|
||||
|
||||
/* Enable direct NVIC */
|
||||
MCHP_EC_INT_CTRL |= 1;
|
||||
|
||||
/* Disable ARM TRACE debug port */
|
||||
MCHP_EC_TRACE_EN &= ~1;
|
||||
|
||||
/*
|
||||
* Enable aggregated only interrupt GIRQ's
|
||||
* Make sure direct mode interrupt sources aggregated outputs
|
||||
* are not enabled.
|
||||
* Aggregated only GIRQ's 8,9,10,11,12,22,24,25,26
|
||||
* Direct GIRQ's = 13,14,15,16,17,18,19,21,23
|
||||
* These bits only need to be touched again on RESET_SYS.
|
||||
* NOTE: GIRQ22 wake for AHB peripherals not processor.
|
||||
*/
|
||||
MCHP_INT_BLK_DIS = 0xfffffffful;
|
||||
MCHP_INT_BLK_EN = (0x1Ful << 8) + (0x07ul << 24);
|
||||
|
||||
spi_enable(CONFIG_SPI_FLASH_PORT, 1);
|
||||
|
||||
#ifdef CONFIG_MCHP_TFDP
|
||||
/*
|
||||
* MCHP Enable TFDP for fast debug messages
|
||||
* If not defined then traceN() and TRACEN() macros are empty
|
||||
*/
|
||||
tfdp_power(1);
|
||||
tfdp_enable(1, 1);
|
||||
imgtype = MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX);
|
||||
CPRINTS("system_pre_init. Image type = 0x%02x", imgtype);
|
||||
trace1(0, MEC, 0, "System pre-init. Image type = 0x%02x", imgtype);
|
||||
|
||||
/* Debug: dump some signals */
|
||||
imgtype = gpio_get_level(GPIO_PCH_RSMRST_L);
|
||||
trace1(0, MEC, 0, "PCH_RSMRST_L = %d", imgtype);
|
||||
|
||||
imgtype = gpio_get_level(GPIO_RSMRST_L_PGOOD);
|
||||
trace1(0, MEC, 0, "RSMRST_L_PGOOD = %d", imgtype);
|
||||
imgtype = gpio_get_level(GPIO_POWER_BUTTON_L);
|
||||
trace1(0, MEC, 0, "POWER_BUTTON_L = %d", imgtype);
|
||||
imgtype = gpio_get_level(GPIO_PMIC_DPWROK);
|
||||
trace1(0, MEC, 0, "PMIC_DPWROK = %d", imgtype);
|
||||
imgtype = gpio_get_level(GPIO_ALL_SYS_PWRGD);
|
||||
trace1(0, MEC, 0, "ALL_SYS_PWRGD = %d", imgtype);
|
||||
imgtype = gpio_get_level(GPIO_AC_PRESENT);
|
||||
trace1(0, MEC, 0, "AC_PRESENT = %d", imgtype);
|
||||
imgtype = gpio_get_level(GPIO_PCH_SLP_SUS_L);
|
||||
trace1(0, MEC, 0, "PCH_SLP_SUS_L = %d", imgtype);
|
||||
imgtype = gpio_get_level(GPIO_PMIC_INT_L);
|
||||
trace1(0, MEC, 0, "PCH_PMIC_INT_L = %d", imgtype);
|
||||
#endif
|
||||
}
|
||||
|
||||
void chip_save_reset_flags(int flags)
|
||||
{
|
||||
MCHP_VBAT_RAM(HIBDATA_INDEX_SAVED_RESET_FLAGS) = flags;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) _system_reset(int flags,
|
||||
int wake_from_hibernate)
|
||||
{
|
||||
uint32_t save_flags = 0;
|
||||
|
||||
/* Disable interrupts to avoid task swaps during reboot */
|
||||
interrupt_disable();
|
||||
|
||||
trace12(0, MEC, 0,
|
||||
"_system_reset: flags=0x%08X wake_from_hibernate=%d",
|
||||
flags, wake_from_hibernate);
|
||||
|
||||
/* 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;
|
||||
|
||||
if (wake_from_hibernate)
|
||||
save_flags |= RESET_FLAG_HIBERNATE;
|
||||
else if (flags & SYSTEM_RESET_HARD)
|
||||
save_flags |= RESET_FLAG_HARD;
|
||||
else
|
||||
save_flags |= RESET_FLAG_SOFT;
|
||||
|
||||
chip_save_reset_flags(save_flags);
|
||||
|
||||
trace11(0, MEC, 0, "_system_reset: save_flags=0x%08X", save_flags);
|
||||
|
||||
/*
|
||||
* Trigger chip reset
|
||||
*/
|
||||
#ifndef CONFIG_CHIPSET_DEBUG
|
||||
MCHP_PCR_SYS_RST |= MCHP_PCR_SYS_SOFT_RESET;
|
||||
#endif
|
||||
/* Spin and wait for reboot; should never return */
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void system_reset(int flags)
|
||||
{
|
||||
_system_reset(flags, 0);
|
||||
}
|
||||
|
||||
const char *system_get_chip_vendor(void)
|
||||
{
|
||||
return "mchp";
|
||||
}
|
||||
|
||||
/*
|
||||
* MEC1701H Chip ID = 0x2D
|
||||
* Rev = 0x82
|
||||
*/
|
||||
const char *system_get_chip_name(void)
|
||||
{
|
||||
switch (MCHP_CHIP_DEV_ID) {
|
||||
case 0x2D:
|
||||
return "mec1701";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static char to_hex(int x)
|
||||
{
|
||||
if (x >= 0 && x <= 9)
|
||||
return '0' + x;
|
||||
return 'a' + x - 10;
|
||||
}
|
||||
|
||||
const char *system_get_chip_revision(void)
|
||||
{
|
||||
static char buf[3];
|
||||
uint8_t rev = MCHP_CHIP_DEV_REV;
|
||||
|
||||
buf[0] = to_hex(rev / 16);
|
||||
buf[1] = to_hex(rev & 0xf);
|
||||
buf[2] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int bbram_idx_lookup(enum system_bbram_idx idx)
|
||||
{
|
||||
switch (idx) {
|
||||
#ifdef CONFIG_USB_PD_DUAL_ROLE
|
||||
case SYSTEM_BBRAM_IDX_PD0:
|
||||
return HIBDATA_INDEX_PD0;
|
||||
case SYSTEM_BBRAM_IDX_PD1:
|
||||
return HIBDATA_INDEX_PD1;
|
||||
#endif
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int system_get_bbram(enum system_bbram_idx idx, uint8_t *value)
|
||||
{
|
||||
int hibdata = bbram_idx_lookup(idx);
|
||||
|
||||
if (hibdata < 0)
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
|
||||
*value = MCHP_VBAT_RAM(hibdata);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
int system_set_bbram(enum system_bbram_idx idx, uint8_t value)
|
||||
{
|
||||
int hibdata = bbram_idx_lookup(idx);
|
||||
|
||||
if (hibdata < 0)
|
||||
return EC_ERROR_UNIMPLEMENTED;
|
||||
|
||||
MCHP_VBAT_RAM(hibdata) = value;
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
int system_set_scratchpad(uint32_t value)
|
||||
{
|
||||
MCHP_VBAT_RAM(HIBDATA_INDEX_SCRATCHPAD) = value;
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t system_get_scratchpad(void)
|
||||
{
|
||||
return MCHP_VBAT_RAM(HIBDATA_INDEX_SCRATCHPAD);
|
||||
}
|
||||
|
||||
void system_hibernate(uint32_t seconds, uint32_t microseconds)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_HOSTCMD_PD
|
||||
/* Inform the PD MCU that we are going to hibernate. */
|
||||
host_command_pd_request_hibernate();
|
||||
/* Wait to ensure exchange with PD before hibernating. */
|
||||
msleep(100);
|
||||
#endif
|
||||
|
||||
cflush();
|
||||
|
||||
if (board_hibernate)
|
||||
board_hibernate();
|
||||
|
||||
/* Disable interrupts */
|
||||
interrupt_disable();
|
||||
for (i = 0; i <= 92; ++i) {
|
||||
task_disable_irq(i);
|
||||
task_clear_pending_irq(i);
|
||||
}
|
||||
|
||||
for (i = 8; i <= 26; ++i)
|
||||
MCHP_INT_DISABLE(i) = 0xffffffff;
|
||||
|
||||
MCHP_INT_BLK_DIS |= 0xffff00;
|
||||
|
||||
/* Disable UART */
|
||||
MCHP_UART_ACT(0) &= ~0x1;
|
||||
MCHP_LPC_ACT &= ~0x1;
|
||||
|
||||
/* Disable JTAG */
|
||||
MCHP_EC_JTAG_EN &= ~1;
|
||||
|
||||
/* Disable 32KHz clock */
|
||||
MCHP_VBAT_CE &= ~0x2;
|
||||
|
||||
/* Stop watchdog */
|
||||
MCHP_WDG_CTL &= ~1;
|
||||
|
||||
/* Stop timers */
|
||||
MCHP_TMR32_CTL(0) &= ~1;
|
||||
MCHP_TMR32_CTL(1) &= ~1;
|
||||
MCHP_TMR16_CTL(0) &= ~1;
|
||||
|
||||
/* Power down ADC */
|
||||
/*
|
||||
* If ADC is in middle of acquisition it will continue until finished
|
||||
*/
|
||||
MCHP_ADC_CTRL &= ~1;
|
||||
|
||||
/* Disable blocks */
|
||||
MCHP_PCR_SLOW_CLK_CTL &= ~(MCHP_PCR_SLOW_CLK_CTL_MASK);
|
||||
|
||||
/*
|
||||
* Set sleep state
|
||||
* arm sleep state to trigger on next WFI
|
||||
*/
|
||||
CPU_SCB_SYSCTRL |= 0x4;
|
||||
MCHP_PCR_SYS_SLP_CTL = MCHP_PCR_SYS_SLP_HEAVY;
|
||||
MCHP_PCR_SYS_SLP_CTL = MCHP_PCR_SYS_SLP_ALL;
|
||||
|
||||
/* Setup GPIOs for hibernate */
|
||||
if (board_hibernate_late)
|
||||
board_hibernate_late();
|
||||
|
||||
if (hibernate_wake_pins_used > 0) {
|
||||
for (i = 0; i < hibernate_wake_pins_used; ++i) {
|
||||
const enum gpio_signal pin = hibernate_wake_pins[i];
|
||||
|
||||
gpio_reset(pin);
|
||||
gpio_enable_interrupt(pin);
|
||||
}
|
||||
|
||||
interrupt_enable();
|
||||
task_enable_irq(MCHP_IRQ_GIRQ8);
|
||||
task_enable_irq(MCHP_IRQ_GIRQ9);
|
||||
task_enable_irq(MCHP_IRQ_GIRQ10);
|
||||
task_enable_irq(MCHP_IRQ_GIRQ11);
|
||||
task_enable_irq(MCHP_IRQ_GIRQ12);
|
||||
}
|
||||
|
||||
if (seconds || microseconds) {
|
||||
/*
|
||||
* Not needed when using direct mode interrupts.
|
||||
* MCHP_INT_BLK_EN |= 1 << MCHP_HTIMER_GIRQ;
|
||||
*/
|
||||
MCHP_INT_ENABLE(MCHP_HTIMER_GIRQ) =
|
||||
MCHP_HTIMER_GIRQ_BIT(0);
|
||||
interrupt_enable();
|
||||
task_enable_irq(MCHP_IRQ_HTIMER0);
|
||||
if (seconds > 2) {
|
||||
ASSERT(seconds <= 0xffff / 8);
|
||||
MCHP_HTIMER_CONTROL(0) = 1;
|
||||
MCHP_HTIMER_PRELOAD(0) =
|
||||
(seconds * 8 + microseconds / 125000);
|
||||
} else {
|
||||
MCHP_HTIMER_CONTROL(0) = 0;
|
||||
MCHP_HTIMER_PRELOAD(0) =
|
||||
(seconds * 1000000 + microseconds) * 2 / 71;
|
||||
}
|
||||
}
|
||||
|
||||
asm("wfi");
|
||||
|
||||
/* Use 48MHz clock to speed through wake-up */
|
||||
MCHP_PCR_PROC_CLK_CTL = 1;
|
||||
|
||||
/* Reboot */
|
||||
_system_reset(0, 1);
|
||||
|
||||
/* We should never get here. */
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void htimer_interrupt(void)
|
||||
{
|
||||
/* Time to wake up */
|
||||
}
|
||||
DECLARE_IRQ(MCHP_IRQ_HTIMER0, htimer_interrupt, 1);
|
||||
|
||||
enum system_image_copy_t system_get_shrspi_image_copy(void)
|
||||
{
|
||||
return MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX);
|
||||
}
|
||||
|
||||
uint32_t system_get_lfw_address(void)
|
||||
{
|
||||
uint32_t * const lfw_vector =
|
||||
(uint32_t * const)CONFIG_PROGRAM_MEMORY_BASE;
|
||||
|
||||
return *(lfw_vector + 1);
|
||||
}
|
||||
|
||||
void system_set_image_copy(enum system_image_copy_t copy)
|
||||
{
|
||||
MCHP_VBAT_RAM(MCHP_IMAGETYPE_IDX) = (copy == SYSTEM_IMAGE_RW) ?
|
||||
SYSTEM_IMAGE_RW : SYSTEM_IMAGE_RO;
|
||||
}
|
||||
|
||||
@@ -1067,6 +1067,32 @@
|
||||
/* Use Virtual Wire signals instead of GPIO with eSPI interface */
|
||||
#undef CONFIG_ESPI_VW_SIGNALS
|
||||
|
||||
/* MCHP next two items are EC eSPI slave configuration */
|
||||
/* Maximum clock frequence eSPI EC slave advertises
|
||||
* Values in MHz are 20, 25, 33, 50, and 66
|
||||
*/
|
||||
#undef CONFIG_ESPI_EC_MAX_FREQ
|
||||
|
||||
/* EC eSPI slave advertises IO lanes
|
||||
* 0 = Single
|
||||
* 1 = Single and Dual
|
||||
* 2 = Single and Quad
|
||||
* 3 = Single, Dual, and Quad
|
||||
*/
|
||||
#undef CONFIG_ESPI_EC_MODE
|
||||
|
||||
/* Bit map of eSPI channels EC advertises
|
||||
* bit[0] = 1 Peripheral channel
|
||||
* bit[1] = 1 Virtual Wire channel
|
||||
* bit[2] = 1 OOB channel
|
||||
* bit[3] = 1 Flash channel
|
||||
*/
|
||||
#undef CONFIG_ESPI_EC_CHAN_BITMAP
|
||||
|
||||
/* Use Virtual Wire for Platform Reset instead of a sideband signal */
|
||||
#undef CONFIG_ESPI_PLTRST_IS_VWIRE
|
||||
|
||||
|
||||
/* Include code for handling external power */
|
||||
#define CONFIG_EXTPOWER
|
||||
|
||||
@@ -2277,6 +2303,13 @@
|
||||
* SPI master port's hardwired CS pin. */
|
||||
#undef CONFIG_SPI_MASTER_NO_CS_GPIOS
|
||||
|
||||
/* Support MCHP MEC family GP-SPI master(s)
|
||||
* Define to 0x01 for GPSPI0 only.
|
||||
* Define to 0x02 for GPSPI1 only.
|
||||
* Define to 0x03 for both controllers.
|
||||
*/
|
||||
#undef CONFIG_MCHP_GPSPI
|
||||
|
||||
/* Support testing SPI slave controller driver. */
|
||||
#undef CONFIG_SPS_TEST
|
||||
|
||||
@@ -2319,6 +2352,11 @@
|
||||
*/
|
||||
#undef CONFIG_TABLET_MODE_SWITCH
|
||||
|
||||
/*
|
||||
* Microchip Trace FIFO Debug Port
|
||||
*/
|
||||
#undef CONFIG_MCHP_TFDP
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Task config */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user