Files
OpenCellular/chip/npcx/system-npcx7.c
Mulin Chao 375b607761 npcx: system: Add support for npcx7 series ec
This CL implements two methods for hibernating on npcx7 ec. One is using
PSL (Power Switch Logic) circuit to cut off ec's VCC power rail. The
other is turning off the power of all ram blocks except the last code
ram block. In order to make sure hibernate utilities are located in the
last code ram block and work properly, we introduce a new section called
'after_init' in ec.lds.S.

We also moved the hibernate utilities, workarounds for sysjump and so on
which are related to chip family into system-npcx5/7.c. It should be
easier to maintain.

It also includes:
1. Add CONFIG_HIBERNATE_PSL to select which method is used on npcx7 for
   hibernating.
2. Add new flag GPIO_HIB_WAKE_HIGH to configure the active priority of
   wake-up inputs during hibernating.
3. Add DEVICE_ID for npcx796f.

BRANCH=none
BUG=none
TEST=No build errors for all boards using npcx5 series.
     Build poppy board and upload FW to platform. No issues found. Make
     sure AC_PRESENT and POWER_BUTTON_L can wake up system from
     hibernate. Passed hibernate tests no matter CONFIG_HIBERNATE_PSL is
     enabled or not on npcx796f evb.

Change-Id: I4e045ebce4120b6fabaa582ed2ec31b5335dfdc3
Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
Reviewed-on: https://chromium-review.googlesource.com/493006
Reviewed-by: Randall Spangler <rspangler@chromium.org>
2017-05-09 23:20:11 -07:00

180 lines
5.0 KiB
C

/* Copyright 2017 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* System module driver depends on chip series for Chrome EC */
#include "common.h"
#include "console.h"
#include "cpu.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "util.h"
#include "gpio.h"
#include "hwtimer_chip.h"
#include "system_chip.h"
#include "rom_chip.h"
/* Macros for last 32K ram block */
#define LAST_RAM_BLK ((NPCX_RAM_SIZE / (32 * 1024)) - 1)
#define RAM_PD_MASK (~(1 << LAST_RAM_BLK))
/*****************************************************************************/
/* IC specific low-level driver depends on chip series */
void system_mpu_config(void)
{
/* Enable MPU */
CPU_MPU_CTRL = 0x7;
/* Create a new MPU Region for data ram */
CPU_MPU_RNR = 0; /* Select region number 0 */
CPU_MPU_RASR = CPU_MPU_RASR & 0xFFFFFFFE; /* Disable region */
CPU_MPU_RBAR = CONFIG_RAM_BASE; /* Set region base address */
/*
* Set region size & attribute and enable region
* [31:29] - Reserved.
* [28] - XN (Execute Never) = 1
* [27] - Reserved.
* [26:24] - AP = 011 (Full access)
* [23:22] - Reserved.
* [21:19,18,17,16] - TEX,S,C,B = 001000 (Normal memory)
* [15:8] - SRD = 0 (Subregions enabled)
* [7:6] - Reserved.
* [5:1] - SIZE = 01111 (64KB in NPCX796F)
* [0] - ENABLE = 1 (enabled)
*/
/* TODO: Add the configurations for the other npcx7 series. */
CPU_MPU_RASR = 0x1308001F;
}
#ifdef CONFIG_HIBERNATE_PSL
#ifndef NPCX_PSL_MODE_SUPPORT
#error "Do not enable CONFIG_HIBERNATE_PSL if npcx ec doesn't support PSL mode!"
#endif
/* Hibernate function implemented by PSL (Power Switch Logic) mode. */
void __keep __attribute__ ((noreturn)) __enter_hibernate_in_psl(void)
{
/* Configure pins from GPIOs to PSL which rely on VSBY power rail. */
gpio_config_module(MODULE_PMU, 1);
/*
* Only PSL_IN events can pull PSL_OUT to high and reboot ec.
* We should treat it as wake-up pin reset.
*/
NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_PIN;
/*
* Pull PSL_OUT (GPIO85) to low to cut off ec's VCC power rail by
* setting bit 5 of PDOUT(8).
*/
SET_BIT(NPCX_PDOUT(GPIO_PORT_8), 5);
/* Spin and wait for PSL cuts power; should never return */
while (1)
;
}
static void system_psl_type_sel(int psl_no, uint32_t flags)
{
/* Set PSL input events' type as level or edge trigger */
if ((flags & GPIO_INT_F_HIGH) || (flags & GPIO_INT_F_LOW))
CLEAR_BIT(NPCX_GLUE_PSL_CTS, psl_no + 4);
else if ((flags & GPIO_INT_F_RISING) || (flags & GPIO_INT_F_FALLING))
SET_BIT(NPCX_GLUE_PSL_CTS, psl_no + 4);
/*
* Set PSL input events' polarity is low (high-to-low) active or
* high (low-to-high) active
*/
if (flags & GPIO_HIB_WAKE_HIGH)
SET_BIT(NPCX_DEVALT(ALT_GROUP_D), 2 * psl_no);
else
CLEAR_BIT(NPCX_DEVALT(ALT_GROUP_D), 2 * psl_no);
}
int system_config_psl_mode(enum gpio_signal signal)
{
int psl_no;
const struct gpio_info *g = gpio_list + signal;
if (g->port == GPIO_PORT_D && g->mask == MASK_PIN2) /* GPIOD2 */
psl_no = 0;
else if (g->port == GPIO_PORT_0 && (g->mask & 0x07)) /* GPIO00/01/02 */
psl_no = GPIO_MASK_TO_NUM(g->mask) + 1;
else
return 0;
system_psl_type_sel(psl_no, g->flags);
return 1;
}
#else
/**
* Hibernate function in last 32K ram block for npcx7 series.
* Do not use global variable since we also turn off data ram.
*/
void __keep __attribute__ ((noreturn, section(".after_init")))
__enter_hibernate_in_last_block(void)
{
/*
* The hibernate utility is located in the last block of RAM. The size
* of each RAM block is 32KB. We turn off all blocks except last one
* for better power consumption.
*/
NPCX_RAM_PD(0) = RAM_PD_MASK & 0xFF;
NPCX_RAM_PD(1) = RAM_PD_MASK >> 8;
/* Set deep idle mode */
NPCX_PMCSR = 0x6;
/* Enter deep idle, wake-up by GPIOs or RTC */
asm volatile ("wfi");
/* RTC wake-up */
if (IS_BIT_SET(NPCX_WTC, NPCX_WTC_PTO))
/*
* Mark wake-up reason for hibernate
* Do not call bbram_data_write directly cause of
* no stack.
*/
NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_MTC;
else
/* Otherwise, we treat it as GPIOs wake-up */
NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_PIN;
/* Start a watchdog reset */
NPCX_WDCNT = 0x01;
/* Reload and restart Timer 0 */
SET_BIT(NPCX_T0CSR, NPCX_T0CSR_RST);
/* Wait for timer is loaded and restart */
while (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_RST))
;
/* Spin and wait for reboot; should never return */
while (1)
;
}
#endif
/**
* Hibernate function for different Nuvoton chip series.
*/
void __hibernate_npcx_series(void)
{
#ifdef CONFIG_HIBERNATE_PSL
__enter_hibernate_in_psl();
#else
/* Make sure this is located in the last 32K code RAM block */
ASSERT((uint32_t)(&__after_init_end) - CONFIG_PROGRAM_MEMORY_BASE
< (32*1024));
/* Execute hibernate func in last 32K block */
__enter_hibernate_in_last_block();
#endif
}