summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Chao <mlchao@nuvoton.com>2014-12-06 14:23:02 +0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-14 03:16:10 +0000
commit4ee50837a0263a5bfcb61e32a862797ede387c78 (patch)
treeaf86c4bd09ff9e4d364ff66444a26f9091b15d14
parent3951165fe9182cb6c9981d0a69c36765c7fe8916 (diff)
downloadchrome-ec-4ee50837a0263a5bfcb61e32a862797ede387c78.tar.gz
nuc: Add all IC specific drivers of NPCX5M5G
Add npcx_evb in board folder for testing Add shared-spi arch support in common layer. Modified drivers for 1. Fan.c: console command “pwmduty”. 2. Pwm.c: for the issue when set duty to 0. 3. System.c: for hw reset only during system reset. 4. Flash.c: Fixed access denied bug of the flash driver for host command. 5. Comments from Patch Set 1 6. Comments from Patch Set 3 (except sha256.c) 7. Add openocd and flash_ec support for npcx_evb 8. Add little FW and spi-flash upload FW in chip folder 9. Add optional make rules for PROJECT_EXTRA 10.Replace CONFIG_SHRSPI_ARCH with CONFIG_CODERAM_ARCH and remove changes in common layer sources for shared-spi arch. (except sysjump) 11.Find the root cause of JTAG issue and use workaround method with SUPPORT_JTAG in clock.c 12 Execute hibernate in low power RAM for better power consumption 13 Add workaround method for version console command 14 Modified coding style issues by checkpatch.pl tool BUG=chrome-os-partner:34346 TEST=make buildall -j; test nuvoton IC specific drivers BRANCH=none Change-Id: I5e383420642de1643e2bead837a55c8c58481786 Signed-off-by: Ian Chao <mlchao@nuvoton.com> Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/233742
-rw-r--r--Makefile.rules21
-rw-r--r--board/npcx_evb/board.c122
-rw-r--r--board/npcx_evb/board.h87
-rw-r--r--board/npcx_evb/build.mk12
-rw-r--r--board/npcx_evb/ec.tasklist24
-rw-r--r--board/npcx_evb/gpio.inc45
-rw-r--r--chip/npcx/adc.c241
-rw-r--r--chip/npcx/adc_chip.h39
-rw-r--r--chip/npcx/build.mk38
-rw-r--r--chip/npcx/chip_temp_sensor.c32
-rw-r--r--chip/npcx/clock.c379
-rw-r--r--chip/npcx/clock_chip.h21
-rw-r--r--chip/npcx/config_chip.h140
-rw-r--r--chip/npcx/fan.c611
-rw-r--r--chip/npcx/fan_chip.h62
-rw-r--r--chip/npcx/flash.c708
-rw-r--r--chip/npcx/gpio.c648
-rw-r--r--chip/npcx/hwtimer.c255
-rw-r--r--chip/npcx/hwtimer_chip.h28
-rw-r--r--chip/npcx/i2c.c592
-rw-r--r--chip/npcx/jtag.c16
-rw-r--r--chip/npcx/keyboard_raw.c128
-rw-r--r--chip/npcx/lfw/ec_lfw.c158
-rw-r--r--chip/npcx/lfw/ec_lfw.h18
-rw-r--r--chip/npcx/lfw/ec_lfw.ld122
-rw-r--r--chip/npcx/lpc.c672
-rw-r--r--chip/npcx/openocd/jlink.cfg4
-rw-r--r--chip/npcx/openocd/npcx.cfg63
-rw-r--r--chip/npcx/openocd/npcx_cmds.tcl104
-rw-r--r--chip/npcx/openocd/servo_v2.cfg13
-rw-r--r--chip/npcx/peci.c295
-rw-r--r--chip/npcx/pwm.c269
-rw-r--r--chip/npcx/pwm_chip.h26
-rw-r--r--chip/npcx/registers.h1189
-rw-r--r--chip/npcx/spi.c242
-rw-r--r--chip/npcx/spiflashfw/ec_npcxflash.c295
-rw-r--r--chip/npcx/spiflashfw/ec_npcxflash.ld104
-rw-r--r--chip/npcx/system.c780
-rw-r--r--chip/npcx/system_chip.h20
-rw-r--r--chip/npcx/uart.c210
-rw-r--r--chip/npcx/watchdog.c142
-rw-r--r--common/keyboard_8042.c2
-rw-r--r--common/system.c17
-rw-r--r--core/cortex-m/ec.lds.S21
-rw-r--r--include/system.h18
-rwxr-xr-xutil/flash_ec40
46 files changed, 9069 insertions, 4 deletions
diff --git a/Makefile.rules b/Makefile.rules
index b532173e28..4dd8b8a723 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -239,6 +239,27 @@ $(out)/TAGS: $(out)/cscope.files
$(out)/tags: $(out)/cscope.files
$(call quiet,ctags,CTAGS )
+# TODO: optional make rules for PROJECT_EXTRA
+$(npcx-flash-fw-bin):
+ $(if $(V),,@echo ' EXTBIN ' $(subst $(out)/,,$@) ; )
+ -@ mkdir -p $(@D)
+ -@ $(CC) $(CFLAGS) -MMD -MF $(out)/$(npcx-lfw).d -c $(npcx-flash-fw).c \
+ -o $(out)/$(npcx-flash-fw).o
+ -@ $(LD) $(out)/$(npcx-flash-fw).o $(LDFLAGS) \
+ -o $(out)/$(npcx-flash-fw).elf -T $(npcx-flash-fw).ld \
+ -Map $(out)/$(npcx-flash-fw).map
+ -@ $(OBJCOPY) -O binary $(out)/$(npcx-flash-fw).elf $@
+
+# TODO: optional make rules for PROJECT_EXTRA
+$(npcx-lfw-bin):
+ $(if $(V),,@echo ' EXTBIN ' $(subst $(out)/,,$@) ; )
+ -@ mkdir -p $(@D)
+ -@ $(CC) $(CFLAGS) -MMD -MF $(out)/$(npcx-lfw).d -c $(npcx-lfw).c \
+ -o $(out)/$(npcx-lfw).o
+ -@ $(LD) $(out)/$(npcx-lfw).o $(LDFLAGS) -o $(out)/$(npcx-lfw).elf \
+ -T $(npcx-lfw).ld -Map $(out)/$(npcx-lfw).map
+ -@ $(OBJCOPY) -O binary $(out)/$(npcx-lfw).elf $@
+
.PHONY: xrefs
xrefs: $(call targ_if_prog,etags,$(out)/TAGS) \
$(call targ_if_prog,ctags,$(out)/tags)
diff --git a/board/npcx_evb/board.c b/board/npcx_evb/board.c
new file mode 100644
index 0000000000..890c3b2f1f
--- /dev/null
+++ b/board/npcx_evb/board.c
@@ -0,0 +1,122 @@
+/* Copyright (c) 2014 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.
+ */
+/* EC for Nuvoton M4 EB configuration */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "backlight.h"
+#include "chipset.h"
+#include "common.h"
+#include "driver/temp_sensor/tmp006.h"
+#include "extpower.h"
+#include "fan.h"
+#include "fan_chip.h"
+#include "gpio.h"
+#include "i2c.h"
+#include "keyboard_scan.h"
+#include "lid_switch.h"
+#include "peci.h"
+#include "power.h"
+#include "power_button.h"
+#include "pwm.h"
+#include "pwm_chip.h"
+#include "registers.h"
+#include "switch.h"
+#include "temp_sensor.h"
+#include "temp_sensor_chip.h"
+#include "timer.h"
+#include "thermal.h"
+#include "util.h"
+
+#include "gpio_list.h"
+
+/******************************************************************************/
+/* ADC channels. Must be in the exactly same order as in enum adc_channel. */
+const struct adc_t adc_channels[] = {
+ [ADC_CH_0] = {"ADC0", NPCX_ADC_INPUT_CH0, ADC_MAX_VOLT,
+ ADC_READ_MAX+1, 0},
+ [ADC_CH_1] = {"ADC1", NPCX_ADC_INPUT_CH1, ADC_MAX_VOLT,
+ ADC_READ_MAX+1, 0},
+ [ADC_CH_2] = {"ADC2", NPCX_ADC_INPUT_CH2, ADC_MAX_VOLT,
+ ADC_READ_MAX+1, 0},
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
+/******************************************************************************/
+/* PWM channels. Must be in the exactly same order as in enum pwm_channel. */
+const struct pwm_t pwm_channels[] = {
+ [PWM_CH_FAN] = {
+ .channel = 0,
+ .flags = 0,
+#ifdef CONFIG_PWM_INPUT_LFCLK
+ .freq = 20000, /* Need <= mft freq */
+#else
+ .freq = 3000000,
+#endif
+ /* 0xEA60=3000000*60/2/1500,0x190=20000*60/2/1500 */
+ .cycle_pulses = 0x190,
+ },
+ [PWM_CH_KBLIGHT] = {
+ .channel = 1,
+ .flags = 0,
+ .freq = 10000,
+ .cycle_pulses = 100,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
+
+/******************************************************************************/
+/* Physical fans. These are logically separate from pwm_channels. */
+const struct fan_t fans[] = {
+ [FAN_CH_0] = {
+ .flags = FAN_USE_RPM_MODE,
+ .rpm_min = 1500,
+ .rpm_start = 1500,
+ .rpm_max = 8190,
+ .ch = 0,/* Use PWM/MFT to control fan */
+ .pgood_gpio = GPIO_PGOOD_FAN,
+ .enable_gpio = -1,
+ },
+};/*TODO: (Benson_TBD_1) rpm_min/rpm_max not confirm */
+BUILD_ASSERT(ARRAY_SIZE(fans) == FAN_CH_COUNT);
+
+/******************************************************************************/
+/* MFT channels. These are logically separate from mft_channels. */
+const struct mft_t mft_channels[] = {
+ [MFT_CH_0] = {
+ .module = NPCX_MFT_MODULE_1,
+ .port = NPCX_MFT_MODULE_PORT_TA,
+ .default_count = 0xFFFF,
+#ifdef CONFIG_MFT_INPUT_LFCLK
+ .freq = 32768,
+#else
+ .freq = 2000000,
+#endif
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(mft_channels) == MFT_CH_COUNT);
+
+/******************************************************************************/
+/* I2C ports */
+const struct i2c_port_t i2c_ports[] = {
+ {"master", I2C_PORT_MASTER, 100,
+ GPIO_MASTER_I2C_SCL, GPIO_MASTER_I2C_SDA},
+};
+const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
+
+/******************************************************************************/
+/* Keyboard scan setting */
+struct keyboard_scan_config keyscan_config = {
+ .output_settle_us = 40,
+ .debounce_down_us = 6 * MSEC,
+ .debounce_up_us = 30 * MSEC,
+ .scan_period_us = 1500,
+ .min_post_scan_delay_us = 1000,
+ .poll_timeout_us = SECOND,
+ .actual_key_mask = {
+ 0x14, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff,
+ 0xa4, 0xff, 0xf6, 0x55, 0xfa, 0xc8 /* full set */
+ },
+};
diff --git a/board/npcx_evb/board.h b/board/npcx_evb/board.h
new file mode 100644
index 0000000000..c8dd5f6139
--- /dev/null
+++ b/board/npcx_evb/board.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* Configuration for Nuvoton M4 EB */
+
+#ifndef __BOARD_H
+#define __BOARD_H
+
+/* Support Code RAM architecture (Run code in RAM) */
+#define CONFIG_CODERAM_ARCH
+
+/* Optional modules */
+#define CONFIG_ADC
+#define CONFIG_PECI
+#define CONFIG_PWM
+#define CONFIG_SPI
+
+/* Optional features */
+#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands for testing */
+#define CONFIG_SPI_FLASH
+#define CONFIG_KEYBOARD_BOARD_CONFIG
+#define CONFIG_KEYBOARD_PROTOCOL_8042
+#define CONFIG_POWER_BUTTON
+#define CONFIG_VBOOT_HASH
+#define CONFIG_PWM_KBLIGHT
+#define CONFIG_BOARD_VERSION
+
+/* Optional features for test commands */
+#define CONFIG_CMD_TASKREADY
+#define CONFIG_CMD_STACKOVERFLOW
+#define CONFIG_CMD_JUMPTAGS
+#define CONFIG_CMD_FLASH
+#define CONFIG_CMD_SPI_FLASH
+#define CONFIG_CMD_SCRATCHPAD
+#define CONFIG_CMD_I2CWEDGE
+
+#define CONFIG_UART_HOST 0
+#define CONFIG_FANS 1
+#define CONFIG_SPI_FLASH_SIZE 0x00800000 /* 8MB spi flash */
+
+/* Optional feature - used by nuvoton */
+#define CONFIG_PWM_INPUT_LFCLK /* PWM use LFCLK for input clock */
+#define CONFIG_MFT_INPUT_LFCLK /* MFT use LFCLK for input clock */
+
+/* Optional for testing */
+#undef CONFIG_PSTORE
+#define CONFIG_LOW_POWER_IDLE /* Deep Sleep Support */
+
+/* Single I2C port, where the EC is the master. */
+#define I2C_PORT_MASTER 0
+#define I2C_PORT_HOST 0
+
+#ifndef __ASSEMBLER__
+
+enum adc_channel {
+ ADC_CH_0 = 0,
+ ADC_CH_1,
+ ADC_CH_2,
+ ADC_CH_COUNT
+};
+
+enum pwm_channel {
+ PWM_CH_FAN,
+ PWM_CH_KBLIGHT,
+ /* Number of PWM channels */
+ PWM_CH_COUNT
+};
+
+enum fan_channel {
+ FAN_CH_0,
+ /* Number of FAN channels */
+ FAN_CH_COUNT
+};
+
+enum mft_channel {
+ MFT_CH_0,
+ /* Number of MFT channels */
+ MFT_CH_COUNT
+};
+
+#include "gpio_signal.h"
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* __BOARD_H */
diff --git a/board/npcx_evb/build.mk b/board/npcx_evb/build.mk
new file mode 100644
index 0000000000..8689f927bc
--- /dev/null
+++ b/board/npcx_evb/build.mk
@@ -0,0 +1,12 @@
+# -*- makefile -*-
+# Copyright (c) 2014 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.
+#
+# Board specific files build
+#
+
+# the IC is Nuvoton M-Series EC
+CHIP:=npcx
+
+board-y=board.o
diff --git a/board/npcx_evb/ec.tasklist b/board/npcx_evb/ec.tasklist
new file mode 100644
index 0000000000..f0a9acff85
--- /dev/null
+++ b/board/npcx_evb/ec.tasklist
@@ -0,0 +1,24 @@
+/* Copyright (c) 2014 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.
+ */
+
+/**
+ * List of enabled tasks in the priority order
+ *
+ * The first one has the lowest priority.
+ *
+ * For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
+ * TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
+ * where :
+ * 'n' is the name of the task
+ * 'r' is the main routine of the task
+ * 'd' is an opaque parameter passed to the routine at startup
+ * 's' is the stack size in bytes; must be a multiple of 8
+ */
+#define CONFIG_TASK_LIST \
+ TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, TASK_STACK_SIZE)
diff --git a/board/npcx_evb/gpio.inc b/board/npcx_evb/gpio.inc
new file mode 100644
index 0000000000..08837dfea1
--- /dev/null
+++ b/board/npcx_evb/gpio.inc
@@ -0,0 +1,45 @@
+/* -*- mode:c -*-
+ *
+ * Copyright (c) 2014 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.
+ */
+
+/* TODO: Redefine debug 2 inputs */
+GPIO(RECOVERY_L, 0, 0, GPIO_PULL_UP | GPIO_INT_BOTH, switch_interrupt) /* Recovery signal from servo */
+GPIO(WP_L, 0, 1, GPIO_PULL_DOWN | GPIO_INT_BOTH, switch_interrupt) /* Write protect input */
+
+/* For testing 8042 commands, we need the following GPIOs */
+/* TODO: Redefine 4 inputs */
+GPIO(POWER_BUTTON_L, 0, 2, GPIO_PULL_UP | GPIO_INT_BOTH, power_button_interrupt) /* Power button */
+GPIO(LID_OPEN, 3, 3, GPIO_PULL_DOWN | GPIO_INT_BOTH, lid_interrupt) /* Lid switch */
+GPIO(ENTERING_RW, 3, 6, GPIO_OUT_LOW, NULL) /* Indicate when EC is entering RW code */
+GPIO(PCH_WAKE_L, 5, 0, GPIO_OUT_HIGH, NULL) /* Wake signal output to PCH */
+
+/* Used for module testing */
+GPIO(PGOOD_FAN, C, 7, GPIO_PULL_UP | GPIO_INPUT, NULL) /* Power Good for FAN test */
+GPIO(SPI_CS_L, A, 5, GPIO_OUT_HIGH, NULL) /* SPI_CS Ready, Low Active. */
+
+/*
+ * I2C pins should be configured as inputs until I2C module is
+ * initialized. This will avoid driving the lines unintentionally.
+ */
+GPIO(MASTER_I2C_SCL, B, 5, GPIO_INPUT, NULL)
+GPIO(MASTER_I2C_SDA, B, 4, GPIO_INPUT, NULL)
+
+/* Used for board version command */
+GPIO(BOARD_VERSION1, 6, 4, GPIO_INPUT, NULL) /* Board version stuffing resistor 1 */
+GPIO(BOARD_VERSION2, 6, 5, GPIO_INPUT, NULL) /* Board version stuffing resistor 2 */
+GPIO(BOARD_VERSION3, 6, 6, GPIO_INPUT, NULL) /* Board version stuffing resistor 3 */
+
+/* Alternate pins for UART/I2C/ADC/SPI/PWM/MFT */
+ALTERNATE(1, 0x03, 1, MODULE_UART, 0) /* CR_SIN/SOUT GPIO10/11 */
+ALTERNATE(B, 0x30, 1, MODULE_I2C, 0) /* I2C0SDA/I2C0SCL GPIOB4/B5 */
+ALTERNATE(8, 0x80, 1, MODULE_I2C, 0) /* I2C1SDA GPIO87 */
+ALTERNATE(9, 0x07, 1, MODULE_I2C, 0) /* I2C1SCL/I2C2SDA/I2C2SCL GPIO90/91/92 */
+ALTERNATE(4, 0x38, 1, MODULE_ADC, 0) /* ADC GPIO45/44/43 */
+ALTERNATE(A, 0x0A, 1, MODULE_SPI, 0) /* SPIP_MOSI/SPIP_SCLK GPIOA3/A1 */
+ALTERNATE(9, 0x20, 1, MODULE_SPI, 0) /* SPIP_MISO GPIO95 */
+ALTERNATE(C, 0x04, 1, MODULE_PWM_KBLIGHT, 0) /* PWM1 for PWM/KBLIGHT Test GPIOC2 */
+ALTERNATE(C, 0x08, 1, MODULE_PWM_FAN, 0) /* PWM0 for PWM/FAN Test GPIOC3 */
+ALTERNATE(4, 0x01, 1, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN Test GPIOD3 */
diff --git a/chip/npcx/adc.c b/chip/npcx/adc.c
new file mode 100644
index 0000000000..a715b08bfb
--- /dev/null
+++ b/chip/npcx/adc.c
@@ -0,0 +1,241 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* NPCX-specific ADC module for Chrome EC */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "atomic.h"
+#include "clock.h"
+#include "clock_chip.h"
+#include "console.h"
+#include "common.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+/* Maximum time we allow for an ADC conversion */
+#define ADC_TIMEOUT_US SECOND
+#define ADC_CLK 2000000
+#define ADC_REGULAR_DLY 0x11
+#define ADC_REGULAR_ADCCNF2 0x8B07
+#define ADC_REGULAR_GENDLY 0x0100
+#define ADC_REGULAR_MEAST 0x0001
+
+/* ADC conversion mode */
+enum npcx_adc_conversion_mode {
+ ADC_CHN_CONVERSION_MODE = 0,
+ ADC_SCAN_CONVERSION_MODE = 1
+};
+
+/* ADC repetitive mode */
+enum npcx_adc_repetitive_mode {
+ ADC_ONE_SHOT_CONVERSION_TYPE = 0,
+ ADC_REPETITIVE_CONVERSION_TYPE = 1
+};
+
+
+/* Global variables */
+static task_id_t task_waiting;
+
+/**
+ * Preset ADC operation clock.
+ *
+ * @param none
+ * @return none
+ * @notes changed when initial or HOOK_FREQ_CHANGE command
+ */
+void adc_freq_changed(void)
+{
+ uint8_t prescaler_divider = 0;
+
+ /* Set clock prescaler divider to ADC module*/
+ prescaler_divider = (uint8_t)(clock_get_apb1_freq() / ADC_CLK);
+ if (prescaler_divider >= 1)
+ prescaler_divider = prescaler_divider - 1;
+ if (prescaler_divider > 0x3F)
+ prescaler_divider = 0x3F;
+
+ /* Set Core Clock Division Factor in order to obtain the ADC clock */
+ NPCX_ATCTL = (NPCX_ATCTL & (~(((1<<6)-1)<<NPCX_ATCTL_SCLKDIV)))
+ |(prescaler_divider<<NPCX_ATCTL_SCLKDIV);
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, adc_freq_changed, HOOK_PRIO_DEFAULT);
+
+/**
+ * Get current voltage data of the specified channel.
+ *
+ * @param input_ch npcx input channel to read
+ * @return ADC channel voltage data.(Range: 0~1023)
+ */
+static int get_channel_data(enum npcx_adc_input_channel input_ch)
+{
+ return (NPCX_CHNDAT(input_ch)>>NPCX_CHNDAT_CHDAT) & ((1<<10)-1);
+}
+
+/**
+ * Flush an ADC sequencer and initiate a read.
+ *
+ * @param input_ch operation channel
+ * @param timeout preset timeout
+ * @return TRUE/FALSE success/fail
+ * @notes set SW-triggered interrupt conversion and one-shot mode in npcx chip
+ */
+static int start_single_and_wait(enum npcx_adc_input_channel input_ch
+ , int timeout)
+{
+ int event;
+
+ task_waiting = task_get_current();
+
+ /* Set ADC conversion code to SW conversion mode */
+ NPCX_ADCCNF = (NPCX_ADCCNF & (~(((1<<2)-1)<<NPCX_ADCCNF_ADCMD)))
+ |(ADC_CHN_CONVERSION_MODE<<NPCX_ADCCNF_ADCMD);
+
+ /* Set conversion type to one-shot type */
+ NPCX_ADCCNF = (NPCX_ADCCNF & (~(((1<<1)-1)<<NPCX_ADCCNF_ADCRPTC)))
+ |(ADC_ONE_SHOT_CONVERSION_TYPE<<NPCX_ADCCNF_ADCRPTC);
+
+ /* Update number of channel to be converted */
+ NPCX_ASCADD = (NPCX_ASCADD & (~(((1<<5)-1)<<NPCX_ASCADD_SADDR)))
+ |(input_ch<<NPCX_ASCADD_SADDR);
+
+ /* Clear End-of-Conversion Event status */
+ SET_BIT(NPCX_ADCSTS, NPCX_ADCSTS_EOCEV);
+
+ /* Enable ADC End-of-Conversion Interrupt if applicable */
+ SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_INTECEN);
+
+ /* Start conversion */
+ SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_START);
+
+ /* Wait for interrupt */
+ event = task_wait_event(timeout);
+
+ task_waiting = TASK_ID_INVALID;
+
+ return event != TASK_EVENT_TIMER;
+
+}
+
+/**
+ * ADC read specific channel.
+ *
+ * @param ch operation channel
+ * @return ADC converted voltage or error message
+ */
+int adc_read_channel(enum adc_channel ch)
+{
+ const struct adc_t *adc = adc_channels + ch;
+ static struct mutex adc_lock;
+ int value;
+
+ mutex_lock(&adc_lock);
+
+ /* Enable ADC clock (bit4 mask = 0x10) */
+ clock_enable_peripheral(CGC_OFFSET_ADC, CGC_ADC_MASK,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+
+ if (start_single_and_wait(adc->input_ch, ADC_TIMEOUT_US)) {
+ if ((adc->input_ch ==
+ ((NPCX_ASCADD>>NPCX_ASCADD_SADDR)&((1<<5)-1)))
+ && (IS_BIT_SET(NPCX_CHNDAT(adc->input_ch),
+ NPCX_CHNDAT_NEW))) {
+ value = get_channel_data(adc->input_ch) *
+ adc->factor_mul / adc->factor_div + adc->shift;
+ } else {
+ value = ADC_READ_ERROR;
+ }
+ } else {
+ value = ADC_READ_ERROR;
+ }
+ /* Disable ADC clock (bit4 mask = 0x10) */
+ clock_disable_peripheral(CGC_OFFSET_ADC, CGC_ADC_MASK,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+
+ mutex_unlock(&adc_lock);
+
+ return value;
+}
+
+
+/**
+ * ADC read all channels.
+ *
+ * @param data all ADC converted voltage
+ * @return ADC converted error message
+ */
+int adc_read_all_channels(int *data)
+{
+ int i;
+
+ for (i = 0; i < ADC_CH_COUNT; ++i) {
+ data[i] = adc_read_channel(i);
+ if (ADC_READ_ERROR == data[i])
+ return EC_ERROR_UNKNOWN;
+ }
+ return EC_SUCCESS;
+}
+
+/**
+ * ADC interrupt handler
+ *
+ * @param none
+ * @return none
+ * @notes Only handle SW-triggered conversion in npcx chip
+ */
+void adc_interrupt(void)
+{
+ if (IS_BIT_SET(NPCX_ADCSTS, NPCX_ADCSTS_EOCEV)) {
+ /* Disable End-of-Conversion Interrupt */
+ CLEAR_BIT(NPCX_ADCCNF, NPCX_ADCCNF_INTECEN);
+
+ /* Stop conversion */
+ SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_STOP);
+
+ /* Clear End-of-Conversion Event status */
+ SET_BIT(NPCX_ADCSTS, NPCX_ADCSTS_EOCEV);
+
+ /* Wake up the task which was waiting for the interrupt */
+ if (task_waiting != TASK_ID_INVALID)
+ task_wake(task_waiting);
+ }
+}
+DECLARE_IRQ(NPCX_IRQ_ADC, adc_interrupt, 2);
+
+/**
+ * ADC initial.
+ *
+ * @param none
+ * @return none
+ */
+static void adc_init(void)
+{
+ /* Configure pins from GPIOs to ADCs */
+ gpio_config_module(MODULE_ADC, 1);
+
+ /* Enable ADC */
+ SET_BIT(NPCX_ADCCNF, NPCX_ADCCNF_ADCEN);
+
+ /* Set Core Clock Division Factor in order to obtain the ADC clock */
+ adc_freq_changed();
+
+ /* Set regular speed */
+ NPCX_ATCTL = (NPCX_ATCTL & (~(((1<<3)-1)<<NPCX_ATCTL_DLY)))
+ |((ADC_REGULAR_DLY - 1)<<NPCX_ATCTL_DLY);
+ NPCX_ADCCNF2 = ADC_REGULAR_ADCCNF2;
+ NPCX_GENDLY = ADC_REGULAR_GENDLY;
+ NPCX_MEAST = ADC_REGULAR_MEAST;
+
+ task_waiting = TASK_ID_INVALID;
+
+ /* Enable IRQs */
+ task_enable_irq(NPCX_IRQ_ADC);
+
+}
+DECLARE_HOOK(HOOK_INIT, adc_init, HOOK_PRIO_DEFAULT);
diff --git a/chip/npcx/adc_chip.h b/chip/npcx/adc_chip.h
new file mode 100644
index 0000000000..fda98a7d74
--- /dev/null
+++ b/chip/npcx/adc_chip.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* NPCX-specific ADC module for Chrome EC */
+
+#ifndef __CROS_EC_ADC_CHIP_H
+#define __CROS_EC_ADC_CHIP_H
+
+/* Minimum and maximum values returned by raw ADC read. */
+#define ADC_READ_MIN 0
+#define ADC_READ_MAX 1023
+#define ADC_MAX_VOLT 3260
+
+/* ADC input channel select */
+enum npcx_adc_input_channel {
+ NPCX_ADC_INPUT_CH0 = 0,
+ NPCX_ADC_INPUT_CH1,
+ NPCX_ADC_INPUT_CH2,
+ NPCX_ADC_INPUT_CH_COUNT
+};
+
+/* Data structure to define ADC channels. */
+struct adc_t {
+ const char *name;
+ enum npcx_adc_input_channel input_ch;
+ int factor_mul;
+ int factor_div;
+ int shift;
+};
+
+/*
+ * Boards must provide this list of ADC channel definitions. This must match
+ * the enum adc_channel list provided by the board.
+ */
+extern const struct adc_t adc_channels[];
+
+#endif /* __CROS_EC_ADC_CHIP_H */
diff --git a/chip/npcx/build.mk b/chip/npcx/build.mk
new file mode 100644
index 0000000000..c3f9a1c3de
--- /dev/null
+++ b/chip/npcx/build.mk
@@ -0,0 +1,38 @@
+# -*- makefile -*-
+# Copyright (c) 2014 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.
+#
+# NPCX chip specific files build
+#
+
+# NPCX SoC has a Cortex-M4F ARM core
+CORE:=cortex-m
+# Allow the full Cortex-M4 instruction set
+CFLAGS_CPU+=-march=armv7e-m -mcpu=cortex-m4
+
+# Required chip modules
+chip-y=clock.o gpio.o hwtimer.o jtag.o system.o uart.o
+
+# Optional chip modules
+chip-$(CONFIG_ADC)+=adc.o chip_temp_sensor.o
+chip-$(CONFIG_FANS)+=fan.o
+chip-$(CONFIG_FLASH)+=flash.o
+chip-$(CONFIG_I2C)+=i2c.o
+chip-$(CONFIG_LPC)+=lpc.o
+chip-$(CONFIG_PECI)+=peci.o
+# pwm functions are implemented with the fan functions
+chip-$(CONFIG_PWM)+=pwm.o fan.o
+chip-$(CONFIG_SPI)+=spi.o
+chip-$(CONFIG_WATCHDOG)+=watchdog.o
+chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
+
+# little FW for booting
+npcx-lfw=chip/npcx/lfw/ec_lfw
+npcx-lfw-bin=${out}/$(npcx-lfw).bin
+PROJECT_EXTRA+=${npcx-lfw-bin}
+
+# spi flash program fw for openocd
+npcx-flash-fw=chip/npcx/spiflashfw/ec_npcxflash
+npcx-flash-fw-bin=${out}/$(npcx-flash-fw).bin
+PROJECT_EXTRA+=${npcx-flash-fw-bin}
diff --git a/chip/npcx/chip_temp_sensor.c b/chip/npcx/chip_temp_sensor.c
new file mode 100644
index 0000000000..7d2df97dbc
--- /dev/null
+++ b/chip/npcx/chip_temp_sensor.c
@@ -0,0 +1,32 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* Temperature sensor module for Chrome EC */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "common.h"
+#include "hooks.h"
+
+/* Initialize temperature reading to a sane value (27 C) */
+static int last_val = C_TO_K(27);
+
+static void chip_temp_sensor_poll(void)
+{
+#ifdef CONFIG_CMD_ECTEMP
+ last_val = adc_read_channel(ADC_CH_EC_TEMP);
+#endif
+}
+DECLARE_HOOK(HOOK_SECOND, chip_temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR);
+
+int chip_temp_sensor_get_val(int idx, int *temp_ptr)
+{
+ if (last_val == ADC_READ_ERROR)
+ return EC_ERROR_UNKNOWN;
+
+ *temp_ptr = last_val;
+
+ return EC_SUCCESS;
+}
diff --git a/chip/npcx/clock.c b/chip/npcx/clock.c
new file mode 100644
index 0000000000..c96261c543
--- /dev/null
+++ b/chip/npcx/clock.c
@@ -0,0 +1,379 @@
+/* Copyright (c) 2014 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 "clock_chip.h"
+#include "common.h"
+#include "console.h"
+#include "cpu.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "hwtimer.h"
+#include "hwtimer_chip.h"
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "timer.h"
+#include "uart.h"
+#include "util.h"
+#include "watchdog.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_CLOCK, outstr)
+#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
+
+#define OSC_CLK 48000000 /* Default is 40MHz (target is 48MHz) */
+#define WAKE_INTERVAL 61 /* Unit: 61 usec */
+#define IDLE_PARAMS 0x7 /* Support deep idle, instant wake-up */
+
+/*
+ * Frequency multiplier values definition according to the requested
+ * PLL_CLOCK Clock Frequency
+ */
+#define HFCGN 0x02
+#if (OSC_CLK == 50000000)
+#define HFCGMH 0x0B
+#define HFCGML 0xEC
+#elif (OSC_CLK == 48000000)
+#define HFCGMH 0x0B
+#define HFCGML 0x72
+#elif (OSC_CLK == 40000000)
+#define HFCGMH 0x09
+#define HFCGML 0x89
+#elif (OSC_CLK == 33000000)
+#define HFCGMH 0x07
+#define HFCGML 0xDE
+#else
+#error "Unsupported FMCLK Clock Frequency"
+#endif
+
+/* Low power idle statistics */
+#ifdef CONFIG_LOW_POWER_IDLE
+static int idle_sleep_cnt;
+static int idle_dsleep_cnt;
+static uint64_t idle_dsleep_time_us;
+/*
+ * Fixed amount of time to keep the console in use flag true after boot in
+ * order to give a permanent window in which the low speed clock is not used.
+ */
+#define CONSOLE_IN_USE_ON_BOOT_TIME (15*SECOND)
+static int console_in_use_timeout_sec = 15;
+static timestamp_t console_expire_time;
+#endif
+
+
+static int freq;
+
+/* Low power idle statistics */
+
+/**
+ * Enable clock to peripheral by setting the CGC register pertaining
+ * to run, sleep, and/or deep sleep modes.
+ *
+ * @param offset Offset of the peripheral. See enum clock_gate_offsets.
+ * @param mask Bit mask of the bits within CGC reg to set.
+ * @param mode no used
+ */
+void clock_enable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode)
+{
+ /* Don't support for different mode */
+ uint8_t reg_mask = mask & 0xff;
+
+ /* Set PD bit to 0 */
+ NPCX_PWDWN_CTL(offset) &= ~reg_mask;
+ /* Wait for clock change to take affect. */
+ clock_wait_cycles(3);
+}
+
+/**
+ * Disable clock to peripheral by setting the CGC register pertaining
+ * to run, sleep, and/or deep sleep modes.
+ *
+ * @param offset Offset of the peripheral. See enum clock_gate_offsets.
+ * @param mask Bit mask of the bits within CGC reg to clear.
+ * @param mode no used
+ */
+void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode)
+{
+ /* Don't support for different mode */
+ uint8_t reg_mask = mask & 0xff;
+
+ /* Set PD bit to 1 */
+ NPCX_PWDWN_CTL(offset) |= reg_mask;
+
+}
+
+/*****************************************************************************/
+/* IC specific low-level driver */
+
+/**
+ * Set the CPU clocks and PLLs.
+ */
+void clock_init(void)
+{
+ /*
+ * Configure Frequency multiplier values according to the requested
+ * FMCLK Clock Frequency
+ */
+ NPCX_HFCGN = HFCGN;
+ NPCX_HFCGML = HFCGML;
+ NPCX_HFCGMH = HFCGMH;
+
+ /* Load M and N values into the frequency multiplier */
+ SET_BIT(NPCX_HFCGCTRL, NPCX_HFCGCTRL_LOAD);
+
+ /* Wait for stable */
+ while (IS_BIT_SET(NPCX_HFCGCTRL, NPCX_HFCGCTRL_CLK_CHNG))
+ ;
+
+ /* Keep Core CLK & FMCLK are the same */
+ NPCX_HFCGP = 0x00;
+
+ freq = OSC_CLK;
+
+ /* Notify modules of frequency change */
+ hook_notify(HOOK_FREQ_CHANGE);
+}
+
+/**
+ * Return the current clock frequency in Hz.
+ */
+int clock_get_freq(void)
+{
+ return freq;
+}
+
+/**
+ * Return the current APB1 clock frequency in Hz.
+ */
+int clock_get_apb1_freq(void)
+{
+ int apb1_div = (NPCX_HFCBCD & 0x03) + 1;
+ return freq/apb1_div;
+}
+
+/**
+ * Return the current APB2 clock frequency in Hz.
+ */
+int clock_get_apb2_freq(void)
+{
+ int apb2_div = ((NPCX_HFCBCD>>2) & 0x03) + 1;
+ return freq/apb2_div;
+}
+
+/**
+ * Wait for a number of clock cycles.
+ *
+ * Simple busy waiting for use before clocks/timers are initialized.
+ *
+ * @param cycles Number of cycles to wait.
+ */
+void clock_wait_cycles(uint32_t cycles)
+{
+ asm("1: subs %0, #1\n"
+ " bne 1b\n" :: "r"(cycles));
+}
+
+#ifdef CONFIG_LOW_POWER_IDLE
+void clock_refresh_console_in_use(void)
+{
+ /* Set console in use expire time. */
+ console_expire_time = get_time();
+ console_expire_time.val += console_in_use_timeout_sec * SECOND;
+ return;
+}
+
+void clock_uart2gpio(void)
+{
+ /* Is pimux to UART? */
+ if (IS_BIT_SET(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL)) {
+ /* Change pinmux to GPIO and disable UART IRQ */
+ task_disable_irq(NPCX_IRQ_UART);
+ CLEAR_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL);
+
+ /*Enable MIWU for GPIO (UARTRX) */
+ SET_BIT(NPCX_WKEN(1, 1), 0);
+ /* Clear Pending bit of GPIO (UARTRX) */
+ if (IS_BIT_SET(NPCX_WKPND(1, 1), 0))
+ SET_BIT(NPCX_WKPCL(1, 1), 0);
+ /* Disable MIWU IRQ */
+ task_disable_irq(NPCX_IRQ_WKINTB_1);
+ }
+}
+
+void clock_gpio2uart(void)
+{
+ /* Is Pending bit of GPIO (UARTRX) */
+ if (IS_BIT_SET(NPCX_WKPND(1, 1), 0)) {
+ /* Clear Pending bit of GPIO (UARTRX) */
+ SET_BIT(NPCX_WKPCL(1, 1), 0);
+ /* Refresh console in-use timer */
+ clock_refresh_console_in_use();
+ /* Disable MIWU & IRQ for GPIO (UARTRX) */
+ CLEAR_BIT(NPCX_WKEN(1, 1), 0);
+ /* Enable MIWU IRQ */
+ task_enable_irq(NPCX_IRQ_WKINTB_1);
+ /* Go back CR_SIN*/
+ SET_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL);
+ /* Enable uart again */
+ task_enable_irq(NPCX_IRQ_UART);
+ }
+}
+
+/* Idle task. Executed when no tasks are ready to be scheduled. */
+void __idle(void)
+{
+#ifdef SUPPORT_JTAG
+ while (1) {
+ /*
+ * TODO:(ML) JTAG bug: if debugger is connected,
+ * CPU can't enter wfi. Rev.B will fix it.
+ */
+ ;
+ };
+#else
+
+ timestamp_t t0, t1;
+ uint32_t next_evt_us;
+
+ /*
+ * Initialize console in use to true and specify the console expire
+ * time in order to give a fixed window on boot in which the low speed
+ * clock will not be used in idle.
+ */
+ console_expire_time.val = get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME;
+
+ while (1) {
+ /*
+ * Disable interrupts before going to deep sleep in order to
+ * calculate the appropriate time to wake up. Note: the wfi
+ * instruction waits until an interrupt is pending, so it
+ * will still wake up even with interrupts disabled.
+ */
+ interrupt_disable();
+
+ /* Compute event delay */
+ t0 = get_time();
+ next_evt_us = __hw_clock_event_get() - t0.le.lo;
+
+ /* Do we have enough time before next event to deep sleep. */
+ if (DEEP_SLEEP_ALLOWED && (next_evt_us > WAKE_INTERVAL)
+ /* Make sure it's over console expired time */
+ && (t0.val > console_expire_time.val)) {
+#if DEBUG_CLK
+ /* Use GPIO to indicate SLEEP mode */
+ CLEAR_BIT(NPCX_PDOUT(0), 0);
+#endif
+ idle_dsleep_cnt++;
+ /* Set instant wake up mode */
+ SET_BIT(NPCX_ENIDL_CTL, NPCX_ENIDL_CTL_LP_WK_CTL);
+
+ /* Set deep idle - instant wake-up mode */
+ NPCX_PMCSR = IDLE_PARAMS;
+ /* UART-rx(console) become to GPIO (NONE INT mode) */
+ clock_uart2gpio();
+ /* Enter deep idle */
+ asm("wfi");
+ /* GPIO back to UART-rx (console) */
+ clock_gpio2uart();
+
+ /* Get time delay cause of deep idle */
+ next_evt_us = __hw_clock_get_sleep_time();
+ /* Fast forward timer according to wake-up timer. */
+ t1.val = t0.val + next_evt_us;
+ /* Record time spent in deep sleep. */
+ idle_dsleep_time_us += next_evt_us;
+ force_time(t1);
+ } else {
+#if DEBUG_CLK
+ /* Use GPIO to indicate NORMAL mode */
+ SET_BIT(NPCX_PDOUT(0), 0);
+#endif
+ idle_sleep_cnt++;
+ /* normal idle : wait for interrupt */
+ asm("wfi");
+ }
+
+ /*
+ * Restore interrupt
+ * RTOS will leave idle task to handle ISR which wakes up EC
+ */
+ interrupt_enable();
+ }
+#endif
+}
+#endif /* CONFIG_LOW_POWER_IDLE */
+
+
+#ifdef CONFIG_LOW_POWER_IDLE
+/**
+ * Print low power idle statistics
+ */
+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("Time spent in deep-sleep: %.6lds\n",
+ idle_dsleep_time_us);
+ ccprintf("Total time on: %.6lds\n", ts.val);
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats,
+ "",
+ "Print last idle stats",
+ NULL);
+
+/**
+ * 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 low speed clock or
+ * allow it to use the low speed clock.
+ */
+ if (v)
+ disable_sleep(SLEEP_MASK_FORCE_NO_LOW_SPEED);
+ else
+ 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);
+ ccprintf("PMCSR register: 0x%02x\n", NPCX_PMCSR);
+
+ 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 use low speed clock.\nUse 'off' to "
+ "allow deep sleep to auto-select using the low speed "
+ "clock.\n"
+ "Give a timeout value for the console in use timeout.\n"
+ "See also 'sleepmask'.",
+ NULL);
+#endif /* CONFIG_LOW_POWER_IDLE */
diff --git a/chip/npcx/clock_chip.h b/chip/npcx/clock_chip.h
new file mode 100644
index 0000000000..ffc5958869
--- /dev/null
+++ b/chip/npcx/clock_chip.h
@@ -0,0 +1,21 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* NPCX-specific clock module for Chrome EC */
+
+#ifndef CLOCK_CHIP_H_
+#define CLOCK_CHIP_H_
+
+/**
+ * Return the current APB1 clock frequency in Hz.
+ */
+int clock_get_apb1_freq(void);
+
+/**
+ * Return the current APB2 clock frequency in Hz.
+ */
+int clock_get_apb2_freq(void);
+
+#endif /* CLOCK_CHIP_H_ */
diff --git a/chip/npcx/config_chip.h b/chip/npcx/config_chip.h
new file mode 100644
index 0000000000..88afba0266
--- /dev/null
+++ b/chip/npcx/config_chip.h
@@ -0,0 +1,140 @@
+/* Copyright (c) 2014 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"
+#define CONFIG_PSTATE_AT_END
+
+/* 32k hz internal oscillator frequency (FRCLK) */
+#define INT_32K_CLOCK 32768
+
+/* Number of IRQ vectors on the NVIC */
+#define CONFIG_IRQ_COUNT 64
+
+/* Use a bigger console output buffer */
+#undef CONFIG_UART_TX_BUF_SIZE
+#define CONFIG_UART_TX_BUF_SIZE 8192
+
+/* Interval between HOOK_TICK notifications */
+#define HOOK_TICK_INTERVAL_MS 250
+#define HOOK_TICK_INTERVAL (HOOK_TICK_INTERVAL_MS * MSEC)
+
+/* Maximum number of deferrable functions */
+#define DEFERRABLE_MAX_COUNT 8
+
+/* Number of I2C ports */
+#define I2C_PORT_COUNT 4
+
+/* Number of PWM ports */
+#define PWM_COUNT 8
+
+/*****************************************************************************/
+/* Memory mapping */
+#define CONFIG_RAM_BASE 0x200C0000 /* memory map address of data ram */
+#define CONFIG_RAM_SIZE 0x00008000 /* 32KB data ram */
+#define CONFIG_CDRAM_BASE 0x10088000 /* memory map address of code ram */
+#define CONFIG_CDRAM_SIZE 0x00020000 /* 128KB code ram */
+#define CONFIG_FLASH_BASE 0x64000000 /* memory address of spi-flash */
+#define CONFIG_LPRAM_BASE 0x40001600 /* memory address of low power ram */
+#define CONFIG_LPRAM_SIZE 0x00000620 /* 1568B low power ram */
+
+/* System stack size */
+#define CONFIG_STACK_SIZE 4096
+
+/* non-standard task stack sizes */
+#define IDLE_TASK_STACK_SIZE 512
+#define LARGER_TASK_STACK_SIZE 768
+#define SMALLER_TASK_STACK_SIZE 384
+
+/* Default task stack size */
+#define TASK_STACK_SIZE 512
+
+/* SPI Flash Spec of W25Q20CV */
+
+#define CONFIG_FLASH_BANK_SIZE 0x00001000 /* protect bank size 4K bytes */
+#define CONFIG_FLASH_ERASE_SIZE 0x00001000 /* sector erase size 4K bytes */
+#define CONFIG_FLASH_WRITE_SIZE 0x00000001 /* minimum write size */
+
+#define CONFIG_FLASH_WRITE_IDEAL_SIZE 256 /* one page size for write */
+#define CONFIG_FLASH_PHYSICAL_SIZE 0x00040000 /* 256KB Flash used for EC */
+
+/****************************************************************************/
+/* Define our flash layout. */
+/* Size of one firmware image in flash */
+#ifndef CONFIG_FW_IMAGE_SIZE
+#define CONFIG_FW_IMAGE_SIZE (CONFIG_FLASH_PHYSICAL_SIZE / 2)
+#endif
+
+/* RO firmware offset of flash */
+#define CONFIG_FW_RO_OFF 0
+
+/*
+ * The EC uses the one bank of flash to emulate a SPI-like write protect
+ * register with persistent state.
+ */
+#define CONFIG_FW_PSTATE_SIZE CONFIG_FLASH_BANK_SIZE
+
+#ifdef CONFIG_PSTATE_AT_END
+/* PSTATE is at end of flash */
+#define CONFIG_FW_RO_SIZE CONFIG_FW_IMAGE_SIZE
+#define CONFIG_FW_PSTATE_OFF (CONFIG_FLASH_PHYSICAL_SIZE \
+ - CONFIG_FW_PSTATE_SIZE)
+/* Don't claim PSTATE is part of flash */
+#define CONFIG_FLASH_SIZE CONFIG_FW_PSTATE_OFF
+
+#else
+/* PSTATE immediately follows RO, in the first half of flash */
+#define CONFIG_FW_RO_SIZE (CONFIG_FW_IMAGE_SIZE \
+ - CONFIG_FW_PSTATE_SIZE)
+#define CONFIG_FW_PSTATE_OFF CONFIG_FW_RO_SIZE
+#define CONFIG_FLASH_SIZE CONFIG_FLASH_PHYSICAL_SIZE
+#endif
+
+/* Either way, RW firmware is one firmware image offset from the start */
+#define CONFIG_FW_RW_OFF CONFIG_FW_IMAGE_SIZE
+#define CONFIG_FW_RW_SIZE CONFIG_FW_IMAGE_SIZE
+
+/* TODO(crosbug.com/p/23796): why 2 sets of configs with the same numbers? */
+#define CONFIG_FW_WP_RO_OFF CONFIG_FW_RO_OFF
+#define CONFIG_FW_WP_RO_SIZE CONFIG_FW_RO_SIZE
+
+/*
+ * The offset from top of flash wich used by booter
+ * the main funcationality to copy iamge from spi-flash to code ram
+ */
+#define CONFIG_LFW_OFFSET 0x1000
+
+/****************************************************************************/
+/* Lock the boot configuration to prevent brickage. */
+
+/*
+ * No GPIO trigger for ROM bootloader.
+ * Keep JTAG debugging enabled.
+ * Use 0xA442 flash write key.
+ * Lock it this way.
+ */
+#define CONFIG_BOOTCFG_VALUE 0x7ffffffe
+
+/****************************************************************************/
+/* Customize the build */
+
+/* Optional features present on this chip */
+#define CONFIG_ADC
+#define CONFIG_FPU
+#define CONFIG_I2C
+#define CONFIG_LPC
+#define CONFIG_PECI
+#define CONFIG_SWITCH
+#define CONFIG_MPU
+#define CONFIG_SPI
+
+
+/* Compile for running from RAM instead of flash */
+/* #define COMPILE_FOR_RAM */
+
+#endif /* __CROS_EC_CONFIG_CHIP_H */
diff --git a/chip/npcx/fan.c b/chip/npcx/fan.c
new file mode 100644
index 0000000000..924f7716f4
--- /dev/null
+++ b/chip/npcx/fan.c
@@ -0,0 +1,611 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* NPCX fan control module. */
+
+#include "clock.h"
+#include "clock_chip.h"
+#include "fan.h"
+#include "fan_chip.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "registers.h"
+#include "util.h"
+#include "pwm.h"
+#include "pwm_chip.h"
+#include "console.h"
+#include "timer.h"
+#include "task.h"
+
+#if !(DEBUG_FAN)
+#define CPRINTS(...)
+#else
+#define CPRINTS(format, args...) cprints(CC_PWM, format, ## args)
+#endif
+
+/* Fan operation module */
+enum npcx_fan_op_module {
+ NPCX_FAN_OP_PWM,
+ NPCX_FAN_OP_MFT,
+ /* Number of FAN module operations */
+ NPCX_FAN_OP_COUNT
+};
+
+/* MFT model select */
+enum npcx_mft_mdsel {
+ NPCX_MFT_MDSEL_1,
+ NPCX_MFT_MDSEL_2,
+ NPCX_MFT_MDSEL_3,
+ NPCX_MFT_MDSEL_4,
+ NPCX_MFT_MDSEL_5,
+ /* Number of MFT modes */
+ NPCX_MFT_MDSEL_COUNT
+};
+
+/* MFT clock source */
+enum npcx_mft_clk_src {
+ TCKC_NOCLK = 0,
+ TCKC_PRESCALE_APB1_CLK,
+ TCKC_EXTERNAL,
+ TCKC_PULSE_ACC,
+ TCKC_LFCLK
+};
+
+#define RPM_SCALE 1 /* Fan RPM is multiplier of actual RPM */
+#define RPM_EDGES 1 /* Fan number of edges - 1 */
+/*
+ * RPM = (n - 1) * m * f * 60 / poles / TACH
+ * n = Fan number of edges = (RPM_EDGES + 1)
+ * m = Fan multiplier defined by RANGE
+ * f = PWM and MFT freq
+ * poles = 2
+ */
+#define RPM_TO_TACH(pwm_channel, rpm) \
+ MIN(((uint32_t)(pwm_channels[pwm_channel].freq)*30*RPM_EDGES*RPM_SCALE \
+ /MAX((rpm), 1)), (pwm_channels[pwm_channel].cycle_pulses))
+
+#define TACH_TO_RPM(mft_channel, tach) \
+ ((mft_channels[mft_channel].freq)*30*RPM_EDGES*RPM_SCALE \
+ /MAX((tach), 1))
+
+/* Global variables */
+static volatile struct tacho_status_t tacho_status;
+static int rpm_target;
+static int rpm_actual = -1;
+static int fan_init_ch;
+/**
+ * Select fan operation channel by module.
+ *
+ * @param none
+ * @param op_module npcx operation module
+ * @return npcx operation channel by module
+ * @notes Fan is controlled by PWM/MFT module in npcx chip
+ */
+static int fan_op_ch(int ch, enum npcx_fan_op_module op_module)
+{
+ uint8_t op_ch;
+
+ switch (ch) {
+ case 0:
+ if (op_module == NPCX_FAN_OP_PWM)
+ op_ch = PWM_CH_FAN;
+ else
+ op_ch = MFT_CH_0;
+ break;
+ default:
+ op_ch = 0;
+ break;
+ }
+ return op_ch;
+}
+
+/**
+ * MFT start measure.
+ *
+ * @param ch operation channel
+ * @return none
+ */
+static void mft_startmeasure(int ch)
+{
+ int mft_ch = fan_op_ch(ch, NPCX_FAN_OP_MFT);
+
+ /* Start measurement */
+#ifdef CONFIG_MFT_INPUT_LFCLK
+ /* Set the LFCLK clock. */
+ if (NPCX_MFT_MODULE_PORT_TB == mft_channels[mft_ch].port)
+ NPCX_TCKC(mft_channels[mft_ch].module) =
+ (NPCX_TCKC(mft_channels[mft_ch].module)
+ &(~(((1<<3)-1)<<NPCX_TCKC_C2CSEL)))
+ |(TCKC_LFCLK<<NPCX_TCKC_C2CSEL);
+ else
+ NPCX_TCKC(mft_channels[mft_ch].module) =
+ (NPCX_TCKC(mft_channels[mft_ch].module)
+ &(~(((1<<3)-1)<<NPCX_TCKC_C1CSEL)))
+ |(TCKC_LFCLK<<NPCX_TCKC_C1CSEL);
+#else
+ /* Set the core clock. */
+ if (NPCX_MFT_MODULE_PORT_TB == mft_channels[mft_ch].port)
+ NPCX_TCKC(mft_channels[mft_ch].module) =
+ (NPCX_TCKC(mft_channels[mft_ch].module)
+ &(~(((1<<3)-1)<<NPCX_TCKC_C2CSEL)))
+ |(TCKC_PRESCALE_APB1_CLK<<NPCX_TCKC_C2CSEL);
+ else
+ NPCX_TCKC(mft_channels[mft_ch].module) =
+ (NPCX_TCKC(mft_channels[mft_ch].module)
+ &(~(((1<<3)-1)<<NPCX_TCKC_C1CSEL)))
+ |(TCKC_PRESCALE_APB1_CLK<<NPCX_TCKC_C1CSEL);
+#endif
+}
+
+/**
+ * MFT stop measure.
+ *
+ * @param ch operation channel
+ * @return none
+ */
+static void mft_stopmeasure(int ch)
+{
+ int mft_ch = fan_op_ch(ch, NPCX_FAN_OP_MFT);
+
+ /* Clear all pending flag */
+ NPCX_TECLR(mft_channels[mft_ch].module) =
+ NPCX_TECTRL(mft_channels[mft_ch].module);
+
+ /* Stop the timer */
+ if (NPCX_MFT_MODULE_PORT_TB == mft_channels[mft_ch].port)
+ NPCX_TCKC(mft_channels[mft_ch].module) =
+ (NPCX_TCKC(mft_channels[mft_ch].module)
+ &(~(((1<<3)-1)<<NPCX_TCKC_C2CSEL)))
+ |(TCKC_NOCLK<<NPCX_TCKC_C2CSEL);
+ else
+ NPCX_TCKC(mft_channels[mft_ch].module) =
+ (NPCX_TCKC(mft_channels[mft_ch].module)
+ &(~(((1<<3)-1)<<NPCX_TCKC_C1CSEL)))
+ |(TCKC_NOCLK<<NPCX_TCKC_C1CSEL);
+}
+
+/**
+ * MFT final measure.
+ *
+ * @param ch operation channel
+ * @return none
+ */
+static void mft_finalmeasure(int ch)
+{
+ int mft_ch = fan_op_ch(ch, NPCX_FAN_OP_MFT);
+
+ /*
+ * Start of the last tacho cycle is detected -
+ * calculated tacho cycle duration
+ */
+ if (NPCX_MFT_MODULE_PORT_TB == mft_channels[mft_ch].port)
+ tacho_status.edge_interval =
+ (uint32_t)(mft_channels[mft_ch].default_count
+ - NPCX_TCRB(mft_channels[mft_ch].module));
+ else
+ tacho_status.edge_interval =
+ (uint32_t)(mft_channels[mft_ch].default_count
+ - NPCX_TCRA(mft_channels[mft_ch].module));
+}
+
+/**
+ * Preset fan operation clock.
+ *
+ * @param none
+ * @return none
+ * @notes changed when initial or HOOK_FREQ_CHANGE command
+ */
+#ifndef CONFIG_MFT_INPUT_LFCLK
+void mft_freq_changed(void)
+{
+ uint16_t prescaler_divider = 0;
+ int mft_ch = fan_op_ch(fan_init_ch, NPCX_FAN_OP_MFT);
+
+ /* Set clock prescaler divider to MFT module*/
+ prescaler_divider = (uint16_t)(clock_get_apb1_freq()
+ /mft_channels[mft_ch].freq);
+ if (prescaler_divider >= 1)
+ prescaler_divider = prescaler_divider - 1;
+ if (prescaler_divider > 0xFF)
+ prescaler_divider = 0xFF;
+
+ NPCX_TPRSC(mft_channels[mft_ch].module) = (uint8_t)prescaler_divider;
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, mft_freq_changed, HOOK_PRIO_DEFAULT);
+#endif
+
+/**
+ * Fan configuration.
+ *
+ * @param ch operation channel
+ * @param enable_mft_read_rpm FAN_USE_RPM_MODE enable flag
+ * @return none
+ */
+static void fan_config(int ch, int enable_mft_read_rpm)
+{
+ int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM);
+ int mft_ch = fan_op_ch(ch, NPCX_FAN_OP_MFT);
+
+ fan_init_ch = ch;
+ pwm_config(pwm_ch);
+
+ /* Mux mft */
+ CLEAR_BIT(NPCX_DEVALT(3), NPCX_DEVALT3_TB1_TACH2_SL1);
+ /* Configure pins from GPIOs to FAN */
+ gpio_config_module(MODULE_PWM_FAN, 1);
+
+ if (enable_mft_read_rpm) {
+ /* Set mode 5 to MFT module*/
+ NPCX_TMCTRL(mft_channels[mft_ch].module) =
+ (NPCX_TMCTRL(mft_channels[mft_ch].module)
+ & (~(((1<<3)-1)<<NPCX_TMCTRL_MDSEL)))
+ | (NPCX_MFT_MDSEL_5<<NPCX_TMCTRL_MDSEL);
+
+#ifndef CONFIG_MFT_INPUT_LFCLK
+ /* Set MFT operation frequence */
+ mft_freq_changed();
+ /* Set the active power mode. */
+ CLEAR_BIT(NPCX_TCKC(mft_channels[mft_ch].module),
+ NPCX_TCKC_LOW_PWR);
+#else
+ /* Set the low power mode. */
+ SET_BIT(NPCX_TCKC(mft_channels[mft_ch].module),
+ NPCX_TCKC_LOW_PWR);
+#endif
+ if (NPCX_MFT_MODULE_PORT_TB == mft_channels[mft_ch].port) {
+ /* Set the default count-down timer. */
+ NPCX_TCNT2(mft_channels[mft_ch].module) =
+ mft_channels[mft_ch].default_count;
+ NPCX_TCRB(mft_channels[mft_ch].module) =
+ mft_channels[mft_ch].default_count;
+ /* Set the edge polarity to rising. */
+ SET_BIT(NPCX_TMCTRL(mft_channels[mft_ch].module),
+ NPCX_TMCTRL_TBEDG);
+ /* Enable capture TCNT2 into TCRB and preset TCNT2. */
+ SET_BIT(NPCX_TMCTRL(mft_channels[mft_ch].module),
+ NPCX_TMCTRL_TBEN);
+ /* Enable input debounce logic into TB. */
+ SET_BIT(NPCX_TCFG(mft_channels[mft_ch].module),
+ NPCX_TCFG_TBDBEN);
+ /* Set the no clock to TCNT2. */
+ NPCX_TCKC(mft_channels[mft_ch].module) =
+ (NPCX_TCKC(mft_channels[mft_ch].module)
+ & (~(((1<<3)-1)<<NPCX_TCKC_C2CSEL)))
+ | (TCKC_NOCLK<<NPCX_TCKC_C2CSEL);
+ /* Set timer wake-up enable */
+ SET_BIT(NPCX_TWUEN(mft_channels[mft_ch].module),
+ NPCX_TWUEN_TBWEN);
+ SET_BIT(NPCX_TWUEN(mft_channels[mft_ch].module),
+ NPCX_TWUEN_TDWEN);
+ } else {
+ /* Set the default count-down timer. */
+ NPCX_TCNT1(mft_channels[mft_ch].module) =
+ mft_channels[mft_ch].default_count;
+ NPCX_TCRA(mft_channels[mft_ch].module) =
+ mft_channels[mft_ch].default_count;
+ /* Set the edge polarity to rising. */
+ SET_BIT(NPCX_TMCTRL(mft_channels[mft_ch].module),
+ NPCX_TMCTRL_TAEDG);
+ /* Enable capture TCNT1 into TCRA and preset TCNT1. */
+ SET_BIT(NPCX_TMCTRL(mft_channels[mft_ch].module),
+ NPCX_TMCTRL_TAEN);
+ /* Enable input debounce logic into TA. */
+ SET_BIT(NPCX_TCFG(mft_channels[mft_ch].module),
+ NPCX_TCFG_TADBEN);
+ /* Set the no clock to TCNT1. */
+ NPCX_TCKC(mft_channels[mft_ch].module) =
+ (NPCX_TCKC(mft_channels[mft_ch].module)
+ & (~(((1<<3)-1)<<NPCX_TCKC_C1CSEL)))
+ | (TCKC_NOCLK<<NPCX_TCKC_C1CSEL);
+ /* Set timer wake-up enable */
+ SET_BIT(NPCX_TWUEN(mft_channels[mft_ch].module),
+ NPCX_TWUEN_TAWEN);
+ SET_BIT(NPCX_TWUEN(mft_channels[mft_ch].module),
+ NPCX_TWUEN_TCWEN);
+ }
+ }
+
+ /* Back to Idle mode*/
+ tacho_status.cur_state = TACHO_IN_IDLE;
+}
+
+/**
+ * Set fan enabled.
+ *
+ * @param ch operation channel
+ * @param enabled enabled flag
+ * @return none
+ */
+void fan_set_enabled(int ch, int enabled)
+{
+ int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM);
+
+ pwm_enable(pwm_ch, enabled);
+}
+
+/**
+ * Check fan enabled.
+ *
+ * @param ch operation channel
+ * @return enabled or not
+ */
+int fan_get_enabled(int ch)
+{
+ int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM);
+
+ return pwm_get_enabled(pwm_ch);
+}
+
+/**
+ * Set fan duty cycle.
+ *
+ * @param ch operation channel
+ * @param percent duty cycle percent
+ * @return none
+ */
+void fan_set_duty(int ch, int percent)
+{
+ int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM);
+
+ CPRINTS("set duty percent=%d", percent);
+
+ /* Set the duty cycle */
+ pwm_set_duty(pwm_ch, percent);
+}
+
+/**
+ * Get fan duty cycle.
+ *
+ * @param ch operation channel
+ * @return duty cycle
+ */
+int fan_get_duty(int ch)
+{
+ int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM);
+
+ /* Return percent */
+ return pwm_get_duty(pwm_ch);
+}
+
+/**
+ * Check fan is rpm operation mode.
+ *
+ * @param ch operation channel
+ * @return rpm operation mode or not
+ * @notes not support in npcx chip
+ */
+int fan_get_rpm_mode(int ch)
+{
+ /* TODO: (Benson_TBD_4) not support rpm mode, return 0 always */
+ return 0;
+}
+
+/**
+ * Set fan to rpm operation mode.
+ *
+ * @param ch operation channel
+ * @param rpm_mode rpm operation mode flag
+ * @return none
+ * @notes not support in npcx chip
+ */
+void fan_set_rpm_mode(int ch, int rpm_mode)
+{
+ /* TODO: (Benson_TBD_4) not support rpm mode */
+}
+
+/**
+ * Get fan actual operation rpm.
+ *
+ * @param ch operation channel
+ * @return actual operation rpm value
+ */
+int fan_get_rpm_actual(int ch)
+{
+ int mft_ch = fan_op_ch(ch, NPCX_FAN_OP_MFT);
+ uint8_t capture_pnd = NPCX_TECTRL_TBPND,
+ underflow_pnd = NPCX_TECTRL_TDPND;
+ uint8_t capture_clr = NPCX_TECLR_TBCLR,
+ underflow_clr = NPCX_TECLR_TDCLR;
+
+ /* Init pending/clear flag bit */
+ if (NPCX_MFT_MODULE_PORT_TA == mft_channels[mft_ch].port) {
+ capture_pnd = NPCX_TECTRL_TAPND;
+ underflow_pnd = NPCX_TECTRL_TCPND;
+ capture_clr = NPCX_TECLR_TACLR;
+ underflow_clr = NPCX_TECLR_TCCLR;
+ }
+ /* Start measure and return previous value when fan is working*/
+ if ((fan_get_enabled(ch)) && (fan_get_duty(ch))) {
+ if (tacho_status.cur_state == TACHO_IN_IDLE) {
+ CPRINTS("mft_startmeasure");
+ if ((0 == rpm_actual) || (-1 == rpm_actual))
+ rpm_actual = fans[ch].rpm_min;
+ /* Clear all pending flags */
+ NPCX_TECLR(mft_channels[mft_ch].module) =
+ NPCX_TECTRL(mft_channels[mft_ch].module);
+ /* Start from first edge state */
+ tacho_status.cur_state = TACHO_WAIT_FOR_1_EDGE;
+ /* Start measure */
+ mft_startmeasure(ch);
+ }
+ /* Check whether MFT underflow flag is occurred */
+ else if (IS_BIT_SET(NPCX_TECTRL(mft_channels[mft_ch].module),
+ underflow_pnd)) {
+ /* Measurement is active - stop the measurement */
+ mft_stopmeasure(fan_init_ch);
+ /* Need to avoid underflow state happen */
+ rpm_actual = fans[ch].rpm_max;
+ /*
+ * Flag TDPND means mft underflow happen then complete
+ * measurement immediately
+ */
+ tacho_status.cur_state = TACHO_UNDERFLOW;
+ CPRINTS("TACHO_UNDERFLOW");
+
+ /* Clear pending flags */
+ SET_BIT(NPCX_TECLR(mft_channels[mft_ch].module),
+ underflow_clr);
+ }
+ /* Check whether MFT signal detection flag is occurred */
+ else if (IS_BIT_SET(NPCX_TECTRL(mft_channels[mft_ch].module),
+ capture_pnd)) {
+ /* Start of tacho cycle is detected */
+ switch (tacho_status.cur_state) {
+ case TACHO_WAIT_FOR_1_EDGE:
+ CPRINTS("TACHO_WAIT_FOR_1_EDGE");
+ /*
+ * Start of the first tacho cycle is detected
+ * and wait for the second tacho cycle
+ * (second edge)
+ */
+ tacho_status.cur_state = TACHO_WAIT_FOR_2_EDGE;
+ /* Send previous rpm before complete measure */
+ break;
+ case TACHO_WAIT_FOR_2_EDGE:
+ /* Complete measure tach and get actual tach */
+ mft_finalmeasure(fan_init_ch);
+ /* Stop the measurement */
+ mft_stopmeasure(ch);
+ /* Transfer actual tach to actual rpm */
+ rpm_actual = (tacho_status.edge_interval > 0) ?
+ (TACH_TO_RPM(mft_ch,
+ tacho_status.edge_interval)) : 0;
+ /* Back to Idle mode*/
+ tacho_status.cur_state = TACHO_IN_IDLE;
+ CPRINTS("TACHO_WAIT_FOR_2_EDGE");
+ CPRINTS("edge_interval=%x",
+ tacho_status.edge_interval);
+ CPRINTS("rpm_actual=%d", rpm_actual);
+ break;
+ default:
+ break;
+ }
+ /* Clear pending flags */
+ SET_BIT(NPCX_TECLR(mft_channels[mft_ch].module),
+ capture_clr);
+ }
+ } else {
+ CPRINTS("preset rpm");
+ /* Send preset rpm before fan is working */
+ if (fan_get_enabled(ch))
+ rpm_actual = fans[ch].rpm_min;
+ else
+ rpm_actual = 0;
+
+ tacho_status.cur_state = TACHO_IN_IDLE;
+ }
+ return rpm_actual;
+}
+
+/**
+ * Get fan setting rpm.
+ *
+ * @param ch operation channel
+ * @return setting rpm value
+ */
+int fan_get_rpm_target(int ch)
+{
+ return rpm_target;
+}
+
+/**
+ * Set fan setting rpm.
+ *
+ * @param ch operation channel
+ * @param rpm setting rpm value
+ * @return none
+ */
+void fan_set_rpm_target(int ch, int rpm)
+{
+ uint32_t percent = 0;
+ int pwm_ch = fan_op_ch(ch, NPCX_FAN_OP_PWM);
+
+ rpm_target = rpm;
+ /* Transfer rpm to tach then calculate percentage */
+ percent = (RPM_TO_TACH(pwm_ch, rpm_target)*100)
+ /(pwm_channels[pwm_ch].cycle_pulses);
+
+ if (percent < 0)
+ percent = 0;
+ else if (percent > 100)
+ percent = 100;
+
+ /* RPM is inverse ratio to tach and percentage */
+ percent = 100 - percent;
+
+ pwm_set_duty(pwm_ch, percent);
+}
+
+/**
+ * Check fan operation status.
+ *
+ * @param ch operation channel
+ * @return fan_status fan operation status
+ */
+enum fan_status fan_get_status(int ch)
+{
+ int rpm_actual;
+
+ rpm_actual = fan_get_rpm_actual(ch);
+
+ if (((fan_get_duty(ch)) && (0 == rpm_actual))
+ || ((!fan_get_duty(ch)) && (rpm_actual)))
+ return FAN_STATUS_FRUSTRATED;
+ else if ((rpm_actual == 0) && (!fan_get_duty(ch)))
+ return FAN_STATUS_STOPPED;
+ else
+ return FAN_STATUS_LOCKED;
+}
+
+/**
+ * Check fan is stall condition.
+ *
+ * @param ch operation channel
+ * @return non-zero if fan is enabled but stalled
+ */
+int fan_is_stalled(int ch)
+{
+ int rpm_actual;
+
+ rpm_actual = fan_get_rpm_actual(ch);
+
+ /* Check for normal condition, others are stall condition */
+ if ((!fan_get_enabled(ch)) || ((fan_get_duty(ch)) && (rpm_actual))
+ || ((!fan_get_duty(ch)) && (!rpm_actual)))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * Fan channel setup.
+ *
+ * @param ch operation channel
+ * @param flags input flags
+ * @return none
+ */
+void fan_channel_setup(int ch, unsigned int flags)
+{
+ fan_config(ch, (flags & FAN_USE_RPM_MODE));
+}
+
+/**
+ * Fan initial.
+ *
+ * @param none
+ * @return none
+ */
+static void fan_init(void)
+{
+#ifdef CONFIG_PWM_DSLEEP
+ /* Enable the fan module and delay a few clocks */
+ clock_enable_peripheral(CGC_OFFSET_FAN, CGC_FAN_MASK, CGC_MODE_ALL);
+#else
+ /* Enable the fan module and delay a few clocks */
+ clock_enable_peripheral(CGC_OFFSET_FAN, CGC_FAN_MASK,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+#endif
+}
+DECLARE_HOOK(HOOK_INIT, fan_init, HOOK_PRIO_INIT_PWM);
diff --git a/chip/npcx/fan_chip.h b/chip/npcx/fan_chip.h
new file mode 100644
index 0000000000..b6af2a7c2e
--- /dev/null
+++ b/chip/npcx/fan_chip.h
@@ -0,0 +1,62 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* NPCX-specific MFT module for Chrome EC */
+
+#ifndef __CROS_EC_NPCX_FAN_H
+#define __CROS_EC_NPCX_FAN_H
+
+/* MFT module select */
+enum npcx_mft_module {
+ NPCX_MFT_MODULE_1 = 0,
+ NPCX_MFT_MODULE_2 = 0,
+ NPCX_MFT_MODULE_3 = 0,
+ /* Number of MFT modules */
+ NPCX_MFT_MODULE_COUNT
+};
+
+/* MFT module port */
+enum npcx_mft_module_port {
+ NPCX_MFT_MODULE_PORT_TA,
+ NPCX_MFT_MODULE_PORT_TB,
+ /* Number of MFT module ports */
+ NPCX_MFT_MODULE_PORT_COUNT
+};
+
+/* Data structure to define MFT channels. */
+struct mft_t {
+ /* MFT module ID */
+ enum npcx_mft_module module;
+ /* MFT port */
+ enum npcx_mft_module_port port;
+ /* MFT TCNT default count */
+ uint32_t default_count;
+ /* MFT freq */
+ uint32_t freq;
+};
+
+/* Tacho measurement state */
+enum tacho_measure_state {
+ /* Tacho init state */
+ TACHO_IN_IDLE = 0,
+ /* Tacho first edge state */
+ TACHO_WAIT_FOR_1_EDGE,
+ /* Tacho second edge state */
+ TACHO_WAIT_FOR_2_EDGE,
+ /* Tacho underflow state */
+ TACHO_UNDERFLOW
+};
+
+/* Tacho status data structure */
+struct tacho_status_t {
+ /* Current state of the measurement */
+ enum tacho_measure_state cur_state;
+ /* Pulse counter value between edge1 and edge2 */
+ uint32_t edge_interval;
+};
+
+extern const struct mft_t mft_channels[];
+
+#endif /* __CROS_EC_NPCX_FAN_H */
diff --git a/chip/npcx/flash.c b/chip/npcx/flash.c
new file mode 100644
index 0000000000..3114848c3f
--- /dev/null
+++ b/chip/npcx/flash.c
@@ -0,0 +1,708 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* Flash memory module for Chrome EC */
+
+#include "flash.h"
+#include "registers.h"
+#include "switch.h"
+#include "system.h"
+#include "timer.h"
+#include "util.h"
+#include "task.h"
+#include "watchdog.h"
+#include "console.h"
+#include "hwtimer_chip.h"
+
+int all_protected; /* Has all-flash protection been requested? */
+int addr_prot_start;
+int addr_prot_length;
+
+#define FLASH_ABORT_TIMEOUT 10000
+
+#ifdef CONFIG_CODERAM_ARCH
+#define TRISTATE_FLASH(x)
+#else
+#define TRISTATE_FLASH(x) flash_tristate(x)
+#endif
+/*****************************************************************************/
+/* flash internal functions */
+void flash_pinmux(int enable)
+{
+ /* Select pin-mux for FIU*/
+ UPDATE_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI, !enable);
+
+ /* CS0/1 pinmux */
+ if (enable) {
+#if (FIU_CHIP_SELECT == 1)
+ SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_F_SPI_CS1_1);
+#elif (FIU_CHIP_SELECT == 2)
+ SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_F_SPI_CS1_2);
+#endif
+ } else {
+ CLEAR_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_F_SPI_CS1_1);
+ CLEAR_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_F_SPI_CS1_2);
+ }
+}
+
+void flash_tristate(int enable)
+{
+ /* Enable/Disable FIU pins to tri-state */
+ UPDATE_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS, enable);
+}
+
+void flash_execute_cmd(uint8_t code, uint8_t cts)
+{
+ /* set UMA_CODE */
+ NPCX_UMA_CODE = code;
+ /* execute UMA flash transaction */
+ NPCX_UMA_CTS = cts;
+ while (IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
+ ;
+}
+
+void flash_cs_level(int level)
+{
+ /* Set chip select to high/low level */
+ UPDATE_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1, level);
+}
+
+void flash_wait_ready(void)
+{
+ uint8_t mask = SPI_FLASH_SR1_BUSY;
+ uint16_t timeout = FLASH_ABORT_TIMEOUT;
+
+ /* Chip Select down. */
+ flash_cs_level(0);
+ /* Command for Read status register */
+ flash_execute_cmd(CMD_READ_STATUS_REG, MASK_CMD_ONLY);
+ while (--timeout) {
+ /* Read status register */
+ NPCX_UMA_CTS = MASK_RD_1BYTE;
+ while (IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
+ ;
+ /* Busy bit is clear */
+ if ((NPCX_UMA_DB0 & mask) == 0)
+ break;
+
+ /* check task scheduling has started to prevent infinite loop */
+ if (task_start_called())
+ msleep(1);
+ }; /* Wait for Busy clear */
+ /* Chip Select high. */
+ flash_cs_level(1);
+}
+
+int flash_write_enable(void)
+{
+ uint8_t mask = SPI_FLASH_SR1_WEL;
+ /* Write enable command */
+ flash_execute_cmd(CMD_WRITE_EN, MASK_CMD_ONLY);
+ /* Wait for flash is not busy */
+ flash_wait_ready();
+
+ if (NPCX_UMA_DB0 & mask)
+ return 1;
+ else
+ return 0;
+}
+
+void flash_set_address(uint32_t dest_addr)
+{
+ uint8_t *addr = (uint8_t *)&dest_addr;
+ /* Write address */
+ NPCX_UMA_AB2 = addr[2];
+ NPCX_UMA_AB1 = addr[1];
+ NPCX_UMA_AB0 = addr[0];
+}
+
+uint8_t flash_get_status1(void)
+{
+ /* Disable tri-state */
+ TRISTATE_FLASH(0);
+ /* Read status register1 */
+ flash_execute_cmd(CMD_READ_STATUS_REG, MASK_CMD_RD_1BYTE);
+ /* Enable tri-state */
+ TRISTATE_FLASH(1);
+ return NPCX_UMA_DB0;
+}
+
+uint8_t flash_get_status2(void)
+{
+ /* Disable tri-state */
+ TRISTATE_FLASH(0);
+ /* Read status register2 */
+ flash_execute_cmd(CMD_READ_STATUS_REG2, MASK_CMD_RD_1BYTE);
+ /* Enable tri-state */
+ TRISTATE_FLASH(1);
+ return NPCX_UMA_DB0;
+}
+
+/*****************************************************************************/
+/* flash protection functions */
+/* Use a copy function of spi_flash.c in flash driver */
+/**
+ * Computes block write protection range from registers
+ * Returns start == len == 0 for no protection
+ *
+ * @param sr1 Status register 1
+ * @param sr2 Status register 2
+ * @param start Output pointer for protection start offset
+ * @param len Output pointer for protection length
+ *
+ * @return EC_SUCCESS, or non-zero if any error.
+ */
+static int reg_to_protect(uint8_t sr1, uint8_t sr2, unsigned int *start,
+ unsigned int *len)
+{
+ int blocks;
+ int size;
+ uint8_t cmp;
+ uint8_t sec;
+ uint8_t tb;
+ uint8_t bp;
+
+ /* Determine flags */
+ cmp = (sr2 & SPI_FLASH_SR2_CMP) ? 1 : 0;
+ sec = (sr1 & SPI_FLASH_SR1_SEC) ? 1 : 0;
+ tb = (sr1 & SPI_FLASH_SR1_TB) ? 1 : 0;
+ bp = (sr1 & (SPI_FLASH_SR1_BP2 | SPI_FLASH_SR1_BP1 | SPI_FLASH_SR1_BP0))
+ >> 2;
+
+ /* Bad pointers or invalid data */
+ if (!start || !len || sr1 == -1 || sr2 == -1)
+ return EC_ERROR_INVAL;
+
+ /* Not defined by datasheet */
+ if (sec && bp == 6)
+ return EC_ERROR_INVAL;
+
+ /* Determine granularity (4kb sector or 64kb block) */
+ /* Computation using 2 * 1024 is correct */
+ size = sec ? (2 * 1024) : (64 * 1024);
+
+ /* Determine number of blocks */
+ /* Equivalent to pow(2, bp) with pow(2, 0) = 0 */
+ blocks = bp ? (1 << bp) : 0;
+ /* Datasheet specifies don't care for BP == 4, BP == 5 */
+ if (sec && bp == 5)
+ blocks = (1 << 4);
+
+ /* Determine number of bytes */
+ *len = size * blocks;
+
+ /* Determine bottom/top of memory to protect */
+ *start = tb ? 0 :
+ (CONFIG_FLASH_SIZE - *len) % CONFIG_FLASH_SIZE;
+
+ /* Reverse computations if complement set */
+ if (cmp) {
+ *start = (*start + *len) % CONFIG_FLASH_SIZE;
+ *len = CONFIG_FLASH_SIZE - *len;
+ }
+
+ return EC_SUCCESS;
+}
+
+/**
+ * Computes block write protection registers from range
+ *
+ * @param start Desired protection start offset
+ * @param len Desired protection length
+ * @param sr1 Output pointer for status register 1
+ * @param sr2 Output pointer for status register 2
+ *
+ * @return EC_SUCCESS, or non-zero if any error.
+ */
+static int protect_to_reg(unsigned int start, unsigned int len,
+ uint8_t *sr1, uint8_t *sr2)
+{
+ char cmp = 0;
+ char sec = 0;
+ char tb = 0;
+ char bp = 0;
+ int blocks;
+ int size;
+
+ /* Bad pointers */
+ if (!sr1 || !sr2 || *sr1 == -1 || *sr2 == -1)
+ return EC_ERROR_INVAL;
+
+ /* Invalid data */
+ if ((start && !len) || start + len > CONFIG_FLASH_SIZE)
+ return EC_ERROR_INVAL;
+
+ /* Set complement bit based on whether length is power of 2 */
+ if ((len & (len - 1)) != 0) {
+ cmp = 1;
+ start = (start + len) % CONFIG_FLASH_SIZE;
+ len = CONFIG_FLASH_SIZE - len;
+ }
+
+ /* Set bottom/top bit based on start address */
+ /* Do not set if len == 0 or len == CONFIG_FLASH_SIZE */
+ if (!start && (len % CONFIG_FLASH_SIZE))
+ tb = 1;
+
+ /* Set sector bit and determine block length based on protect length */
+ if (len == 0 || len >= 128 * 1024) {
+ sec = 0;
+ size = 64 * 1024;
+ } else if (len >= 4 * 1024 && len <= 32 * 1024) {
+ sec = 1;
+ size = 2 * 1024;
+ } else
+ return EC_ERROR_INVAL;
+
+ /* Determine number of blocks */
+ if (len % size != 0)
+ return EC_ERROR_INVAL;
+ blocks = len / size;
+
+ /* Determine bp = log2(blocks) with log2(0) = 0 */
+ bp = blocks ? (31 - __builtin_clz(blocks)) : 0;
+
+ /* Clear bits */
+ *sr1 &= ~(SPI_FLASH_SR1_SEC | SPI_FLASH_SR1_TB
+ | SPI_FLASH_SR1_BP2 | SPI_FLASH_SR1_BP1 | SPI_FLASH_SR1_BP0);
+ *sr2 &= ~SPI_FLASH_SR2_CMP;
+
+ /* Set bits */
+ *sr1 |= (sec ? SPI_FLASH_SR1_SEC : 0) | (tb ? SPI_FLASH_SR1_TB : 0)
+ | (bp << 2);
+ *sr2 |= (cmp ? SPI_FLASH_SR2_CMP : 0);
+
+ return EC_SUCCESS;
+}
+
+int flash_set_status_for_prot(int reg1, int reg2)
+{
+ /* Disable tri-state */
+ TRISTATE_FLASH(0);
+ /* Enable write */
+ flash_write_enable();
+
+ NPCX_UMA_DB0 = reg1;
+ NPCX_UMA_DB1 = reg2;
+
+ /* Write status register 1/2 */
+ flash_execute_cmd(CMD_WRITE_STATUS_REG, MASK_CMD_WR_2BYTE);
+ /* Enable tri-state */
+ TRISTATE_FLASH(1);
+
+ reg_to_protect(reg1, reg2, &addr_prot_start, &addr_prot_length);
+
+ return EC_SUCCESS;
+}
+
+int flash_check_prot_range(unsigned int offset, unsigned int bytes)
+{
+ /* Invalid value */
+ if (offset + bytes > CONFIG_FLASH_PHYSICAL_SIZE)
+ return EC_ERROR_INVAL;
+ /* Check if ranges overlap */
+ if (MAX(addr_prot_start, offset) < MIN(addr_prot_start +
+ addr_prot_length, offset + bytes))
+ return EC_ERROR_ACCESS_DENIED;
+
+ return EC_SUCCESS;
+}
+
+int flash_check_prot_reg(unsigned int offset, unsigned int bytes)
+{
+ unsigned int start;
+ unsigned int len;
+ uint8_t sr1 = 0, sr2 = 0;
+ int rv = EC_SUCCESS;
+
+ sr1 = flash_get_status1();
+ sr2 = flash_get_status2();
+
+ /* Invalid value */
+ if (offset + bytes > CONFIG_FLASH_PHYSICAL_SIZE)
+ return EC_ERROR_INVAL;
+
+ /* Compute current protect range */
+ rv = reg_to_protect(sr1, sr2, &start, &len);
+ if (rv)
+ return rv;
+
+ /* Check if ranges overlap */
+ if (MAX(start, offset) < MIN(start + len, offset + bytes))
+ return EC_ERROR_ACCESS_DENIED;
+
+ return EC_SUCCESS;
+
+}
+
+int flash_write_prot_reg(unsigned int offset, unsigned int bytes)
+{
+ int rv;
+ uint8_t sr1 = flash_get_status1();
+ uint8_t sr2 = flash_get_status2();
+
+ /* Invalid values */
+ if (offset + bytes > CONFIG_FLASH_SIZE)
+ return EC_ERROR_INVAL;
+
+ /* Compute desired protect range */
+ rv = protect_to_reg(offset, bytes, &sr1, &sr2);
+ if (rv)
+ return rv;
+
+ return flash_set_status_for_prot(sr1, sr2);
+}
+
+void flash_burst_write(unsigned int dest_addr, unsigned int bytes,
+ const char *data)
+{
+ unsigned int i;
+ /* Chip Select down. */
+ flash_cs_level(0);
+ /* Set erase address */
+ flash_set_address(dest_addr);
+ /* Start write */
+ flash_execute_cmd(CMD_FLASH_PROGRAM, MASK_CMD_WR_ADR);
+ for (i = 0; i < bytes; i++) {
+ flash_execute_cmd(*data, MASK_CMD_WR_ONLY);
+ data++;
+ }
+ /* Chip Select up */
+ flash_cs_level(1);
+}
+/*****************************************************************************/
+/* Physical layer APIs */
+int flash_physical_read(int offset, int size, char *data)
+{
+ int dest_addr = offset;
+ uint32_t idx;
+
+ /* Disable tri-state */
+ TRISTATE_FLASH(0);
+ /* Chip Select down. */
+ flash_cs_level(0);
+
+ /* Set read address */
+ flash_set_address(dest_addr);
+ /* Start fast read - 1110 1001 - EXEC, WR, CMD, ADDR */
+ flash_execute_cmd(CMD_FAST_READ, MASK_CMD_ADR_WR);
+
+ /* Burst read transaction */
+ for (idx = 0; idx < size; idx++) {
+ /* 1101 0101 - EXEC, RD, NO CMD, NO ADDR, 4 bytes */
+ NPCX_UMA_CTS = MASK_RD_1BYTE;
+ /* wait for UMA to complete */
+ while (IS_BIT_SET(NPCX_UMA_CTS, EXEC_DONE))
+ ;
+ /* Get read transaction results*/
+ data[idx] = NPCX_UMA_DB0;
+ }
+
+ /* Chip Select up */
+ flash_cs_level(1);
+ /* Enable tri-state */
+ TRISTATE_FLASH(1);
+ return EC_SUCCESS;
+}
+
+int flash_physical_read_image_size(int offset, int size)
+{
+ int dest_addr = offset;
+ uint8_t temp;
+ uint32_t idx;
+ uint32_t image_size = 0;
+
+ /* Disable tri-state */
+ TRISTATE_FLASH(0);
+ /* Chip Select down. */
+ flash_cs_level(0);
+
+ /* Set read address */
+ flash_set_address(dest_addr);
+ /* Start fast read - 1110 1001 - EXEC, WR, CMD, ADDR */
+ flash_execute_cmd(CMD_FAST_READ, MASK_CMD_ADR_WR);
+
+ /* Burst read transaction */
+ for (idx = 0; idx < size; idx++) {
+ /* 1101 0101 - EXEC, RD, NO CMD, NO ADDR, 4 bytes */
+ NPCX_UMA_CTS = MASK_RD_1BYTE;
+ /* wait for UMA to complete */
+ while (IS_BIT_SET(NPCX_UMA_CTS, EXEC_DONE))
+ ;
+ /* Find eof of image */
+ temp = NPCX_UMA_DB0;
+ if (temp == 0xea)
+ image_size = idx;
+ }
+
+ /* Chip Select up */
+ flash_cs_level(1);
+ /* Enable tri-state */
+ TRISTATE_FLASH(1);
+ return image_size;
+}
+
+int flash_physical_is_erased(uint32_t offset, int size)
+{
+ int dest_addr = offset;
+ uint32_t idx;
+ uint8_t temp;
+
+ /* Chip Select down. */
+ flash_cs_level(0);
+
+ /* Set read address */
+ flash_set_address(dest_addr);
+ /* Start fast read -1110 1001 - EXEC, WR, CMD, ADDR */
+ flash_execute_cmd(CMD_FAST_READ, MASK_CMD_ADR_WR);
+
+ /* Burst read transaction */
+ for (idx = 0; idx < size; idx++) {
+ /* 1101 0101 - EXEC, RD, NO CMD, NO ADDR, 4 bytes */
+ NPCX_UMA_CTS = MASK_RD_1BYTE;
+ /* Wait for UMA to complete */
+ while (IS_BIT_SET(NPCX_UMA_CTS, EXEC_DONE))
+ ;
+ /* Get read transaction results */
+ temp = NPCX_UMA_DB0;
+ if (temp != 0xFF)
+ break;
+ }
+
+ /* Chip Select up */
+ flash_cs_level(1);
+
+ if (idx == size)
+ return 1;
+ else
+ return 0;
+}
+
+int flash_physical_write(int offset, int size, const char *data)
+{
+ int dest_addr = offset;
+ const int sz_page = CONFIG_FLASH_WRITE_IDEAL_SIZE;
+
+ /* Fail if offset, size, and data aren't at least word-aligned */
+ if ((offset | size
+ | (uint32_t)(uintptr_t)data) & (CONFIG_FLASH_WRITE_SIZE - 1))
+ return EC_ERROR_INVAL;
+
+ /* check protection */
+ if (all_protected)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Disable tri-state */
+ TRISTATE_FLASH(0);
+
+ /* Write the data per CONFIG_FLASH_WRITE_IDEAL_SIZE bytes */
+ for (; size >= sz_page; size -= sz_page) {
+
+ /* check protection */
+ if (flash_check_prot_range(dest_addr, sz_page))
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Enable write */
+ flash_write_enable();
+ /* Burst UMA transaction */
+ flash_burst_write(dest_addr, sz_page, data);
+ /* Wait write completed */
+ flash_wait_ready();
+
+ data += sz_page;
+ dest_addr += sz_page;
+ }
+
+ /* Handle final partial page, if any */
+ if (size != 0) {
+ /* check protection */
+ if (flash_check_prot_range(dest_addr, size))
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Enable write */
+ flash_write_enable();
+ /* Burst UMA transaction */
+ flash_burst_write(dest_addr, size, data);
+ /* Wait write completed */
+ flash_wait_ready();
+ }
+
+ /* Enable tri-state */
+ TRISTATE_FLASH(1);
+ return EC_SUCCESS;
+}
+
+int flash_physical_erase(int offset, int size)
+{
+ /* check protection */
+ if (all_protected)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* Disable tri-state */
+ TRISTATE_FLASH(0);
+
+ /* Alignment has been checked in upper layer */
+ for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE,
+ offset += CONFIG_FLASH_ERASE_SIZE) {
+
+ /* Do nothing if already erased */
+ if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE))
+ continue;
+
+ /* check protection */
+ if (flash_check_prot_range(offset, CONFIG_FLASH_ERASE_SIZE))
+ return EC_ERROR_ACCESS_DENIED;
+
+
+ /*
+ * Reload the watchdog timer, so that erasing many flash pages
+ * doesn't cause a watchdog reset. May not need this now that
+ * we're using msleep() below.
+ */
+ watchdog_reload();
+
+ /* Enable write */
+ flash_write_enable();
+ /* Set erase address */
+ flash_set_address(offset);
+ /* Start erase */
+ flash_execute_cmd(CMD_SECTOR_ERASE, MASK_CMD_ADR);
+
+ /* Wait erase completed */
+ flash_wait_ready();
+ }
+
+ /* Enable tri-state */
+ TRISTATE_FLASH(1);
+ return EC_SUCCESS;
+}
+
+int flash_physical_get_protect(int bank)
+{
+ uint32_t addr = bank * CONFIG_FLASH_BANK_SIZE;
+ return flash_check_prot_reg(addr, CONFIG_FLASH_BANK_SIZE);
+}
+
+uint32_t flash_physical_get_protect_flags(void)
+{
+ uint32_t flags = 0;
+
+ /* Read all-protected state from our shadow copy */
+ if (all_protected)
+ flags |= EC_FLASH_PROTECT_ALL_NOW;
+
+ return flags;
+}
+
+int flash_physical_protect_now(int all)
+{
+ if (all) {
+ /* Protect the entire flash */
+ all_protected = 1;
+ flash_write_prot_reg(0, CONFIG_FLASH_PHYSICAL_SIZE);
+ } else {
+ /* Protect the read-only section and persistent state */
+#ifdef CONFIG_PSTATE_AT_END
+ flash_write_prot_reg(RO_BANK_OFFSET*CONFIG_FLASH_BANK_SIZE,
+ RO_BANK_COUNT*CONFIG_FLASH_BANK_SIZE);
+ flash_write_prot_reg(PSTATE_BANK * CONFIG_FLASH_BANK_SIZE,
+ CONFIG_FLASH_BANK_SIZE);
+#else
+ /* PSTATE immediately follows RO, in the first half of flash */
+ flash_write_prot_reg(RO_BANK_OFFSET*CONFIG_FLASH_BANK_SIZE,
+ (RO_BANK_COUNT+1) * CONFIG_FLASH_BANK_SIZE);
+#endif
+ }
+
+ return EC_SUCCESS;
+}
+
+uint32_t flash_physical_get_valid_flags(void)
+{
+ return EC_FLASH_PROTECT_RO_AT_BOOT |
+ EC_FLASH_PROTECT_RO_NOW |
+ EC_FLASH_PROTECT_ALL_NOW;
+}
+
+uint32_t flash_physical_get_writable_flags(uint32_t cur_flags)
+{
+ uint32_t ret = 0;
+
+ /* If RO protection isn't enabled, its at-boot state can be changed. */
+ if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW))
+ ret |= EC_FLASH_PROTECT_RO_AT_BOOT;
+
+ /*
+ * If entire flash isn't protected at this boot, it can be enabled if
+ * the WP GPIO is asserted.
+ */
+ if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) &&
+ (cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED))
+ ret |= EC_FLASH_PROTECT_ALL_NOW;
+
+ return ret;
+}
+
+/*****************************************************************************/
+/* High-level APIs */
+
+int flash_pre_init(void)
+{
+ uint32_t reset_flags, prot_flags, unwanted_prot_flags;
+
+ /* Enable FIU interface */
+ flash_pinmux(1);
+
+#ifdef CONFIG_CODERAM_ARCH
+ /* Disable tristate all the time */
+ CLEAR_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS);
+#endif
+
+ reset_flags = system_get_reset_flags();
+ prot_flags = flash_get_protect();
+ unwanted_prot_flags = EC_FLASH_PROTECT_ALL_NOW |
+ EC_FLASH_PROTECT_ERROR_INCONSISTENT;
+
+ /*
+ * If we have already jumped between images, an earlier image could
+ * have applied write protection. Nothing additional needs to be done.
+ */
+ if (reset_flags & RESET_FLAG_SYSJUMP)
+ return EC_SUCCESS;
+
+ /* Handle flash write-protection */
+ if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) {
+ /*
+ * Write protect is asserted. If we want RO flash protected,
+ * protect it now.
+ */
+ if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) &&
+ !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) {
+ int rv = flash_set_protect(EC_FLASH_PROTECT_RO_NOW,
+ EC_FLASH_PROTECT_RO_NOW);
+ if (rv)
+ return rv;
+
+ /* Re-read flags */
+ prot_flags = flash_get_protect();
+ }
+
+ /* Update all-now flag if all flash is protected */
+ if (prot_flags & EC_FLASH_PROTECT_ALL_NOW)
+ all_protected = 1;
+ } else {
+ /* Don't want RO flash protected */
+ unwanted_prot_flags |= EC_FLASH_PROTECT_RO_NOW;
+ }
+
+ /* If there are no unwanted flags, done */
+ if (!(prot_flags & unwanted_prot_flags))
+ return EC_SUCCESS;
+
+ /* Otherwise, clear the flash protection bits of status registers */
+ flash_set_status_for_prot(0, 0);
+
+ return EC_SUCCESS;
+}
diff --git a/chip/npcx/gpio.c b/chip/npcx/gpio.c
new file mode 100644
index 0000000000..bd046c0683
--- /dev/null
+++ b/chip/npcx/gpio.c
@@ -0,0 +1,648 @@
+/* Copyright (c) 2014 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 Chrome EC */
+
+#include "clock.h"
+#include "common.h"
+#include "gpio.h"
+#include "keyboard_config.h"
+#include "hooks.h"
+#include "registers.h"
+#include "switch.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+/* Marco functions for GPIO WUI/ALT table */
+#define NPCX_GPIO(grp, pin) \
+ GPIO_PORT_##grp, MASK_PIN##pin
+#define NPCX_GPIO_NONE \
+ GPIO_PORT_COUNT, 0xFF
+#define NPCX_WUI(tbl, grp, pin) \
+ MIWU_TABLE_##tbl, MIWU_GROUP_##grp, MASK_PIN##pin
+
+#define ALT_MASK(pin) \
+ CONCAT2(MASK_PIN, pin)
+#define ALT_PIN(grp, pin) \
+ ALT_MASK(NPCX_DEVALT##grp##_##pin)
+#define NPCX_ALT(grp, pin) \
+ ALT_GROUP_##grp, ALT_PIN(grp, pin)
+
+struct gpio_wui_map {
+ uint8_t gpio_port;
+ uint8_t gpio_mask;
+ uint8_t wui_table;
+ uint8_t wui_group;
+ uint8_t wui_mask;
+};
+
+struct gpio_wui_item {
+ struct gpio_wui_map wui_map[8];
+ uint8_t irq;
+};
+
+const struct gpio_wui_item gpio_wui_table[] = {
+ /* MIWU0 Group A */
+ { { { NPCX_GPIO(8, 0), NPCX_WUI(0, 1, 0) },
+ { NPCX_GPIO(8, 1), NPCX_WUI(0, 1, 1) },
+ { NPCX_GPIO(8, 2), NPCX_WUI(0, 1, 2) },
+ { NPCX_GPIO(8, 3), NPCX_WUI(0, 1, 3) },
+ { NPCX_GPIO(8, 4), NPCX_WUI(0, 1, 4) },
+ { NPCX_GPIO(8, 5), NPCX_WUI(0, 1, 5) },
+ { NPCX_GPIO(8, 6), NPCX_WUI(0, 1, 6) },
+ { NPCX_GPIO(8, 7), NPCX_WUI(0, 1, 7) },
+ }, NPCX_IRQ_MTC_WKINTAD_0 },
+ /* MIWU0 Group B */
+ { { { NPCX_GPIO(9, 0), NPCX_WUI(0, 2, 0) },
+ { NPCX_GPIO(9, 1), NPCX_WUI(0, 2, 1) },
+ { NPCX_GPIO(9, 2), NPCX_WUI(0, 2, 2) },
+ { NPCX_GPIO(9, 3), NPCX_WUI(0, 2, 3) },
+ { NPCX_GPIO(9, 4), NPCX_WUI(0, 2, 4) },
+ { NPCX_GPIO(9, 5), NPCX_WUI(0, 2, 5) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 2, 6) }, /* MSWC Wake-Up */
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 2, 7) }, /* T0OUT Wake-Up */
+ }, NPCX_IRQ_TWD_WKINTB_0 },
+ /* MIWU0 Group C */
+ { { { NPCX_GPIO(9, 6), NPCX_WUI(0, 3, 0) },
+ { NPCX_GPIO(9, 7), NPCX_WUI(0, 3, 1) },
+ { NPCX_GPIO(A, 0), NPCX_WUI(0, 3, 2) },
+ { NPCX_GPIO(A, 1), NPCX_WUI(0, 3, 3) },
+ { NPCX_GPIO(A, 2), NPCX_WUI(0, 3, 4) },
+ { NPCX_GPIO(A, 3), NPCX_WUI(0, 3, 5) },
+ { NPCX_GPIO(A, 4), NPCX_WUI(0, 3, 6) },
+ { NPCX_GPIO(A, 5), NPCX_WUI(0, 3, 7) },
+ }, NPCX_IRQ_WKINTC_0 },
+ /* MIWU0 Group D */
+ { { { NPCX_GPIO(A, 6), NPCX_WUI(0, 4, 0) },
+ { NPCX_GPIO(A, 7), NPCX_WUI(0, 4, 1) },
+ { NPCX_GPIO(B, 0), NPCX_WUI(0, 4, 2) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 4, 3) }, /* SMB0 Wake-Up */
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 4, 4) }, /* SMB1 Wake-Up */
+ { NPCX_GPIO(B, 1), NPCX_WUI(0, 4, 5) },
+ { NPCX_GPIO(B, 2), NPCX_WUI(0, 4, 6) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 4, 7) }, /* MTC Wake-Up */
+ }, NPCX_IRQ_MTC_WKINTAD_0 },
+
+ /* MIWU0 Group E */
+ { { { NPCX_GPIO(B, 3), NPCX_WUI(0, 5 , 0) },
+ { NPCX_GPIO(B, 4), NPCX_WUI(0, 5 , 1) },
+ { NPCX_GPIO(B, 5), NPCX_WUI(0, 5 , 2) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 5 , 3) },
+ { NPCX_GPIO(B, 7), NPCX_WUI(0, 5 , 4) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 5 , 5) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 5 , 6) }, /* Host Wake-Up */
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 5 , 7) }, /* LRESET Wake-Up */
+ }, NPCX_IRQ_WKINTEFGH_0 },
+
+ /* MIWU0 Group F */
+ { { { NPCX_GPIO(C, 0), NPCX_WUI(0, 6, 0) },
+ { NPCX_GPIO(C, 1), NPCX_WUI(0, 6, 1) },
+ { NPCX_GPIO(C, 2), NPCX_WUI(0, 6, 2) },
+ { NPCX_GPIO(C, 3), NPCX_WUI(0, 6, 3) },
+ { NPCX_GPIO(C, 4), NPCX_WUI(0, 6, 4) },
+ { NPCX_GPIO(C, 5), NPCX_WUI(0, 6, 5) },
+ { NPCX_GPIO(C, 6), NPCX_WUI(0, 6, 6) },
+ { NPCX_GPIO(C, 7), NPCX_WUI(0, 6, 7) },
+ }, NPCX_IRQ_WKINTEFGH_0 },
+ /* MIWU0 Group G */
+ { { { NPCX_GPIO(D, 0), NPCX_WUI(0, 7, 0) },
+ { NPCX_GPIO(D, 1), NPCX_WUI(0, 7, 1) },
+ { NPCX_GPIO(D, 2), NPCX_WUI(0, 7, 2) },
+ { NPCX_GPIO(D, 3), NPCX_WUI(0, 7, 3) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 7, 4) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 7, 5) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 7, 6) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 7, 7) },
+ }, NPCX_IRQ_WKINTEFGH_0 },
+ /* MIWU0 Group H */
+ { { { NPCX_GPIO_NONE, NPCX_WUI(0, 8, 0) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 8, 1) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 8, 2) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 8, 3) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 8, 4) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 8, 5) },
+ { NPCX_GPIO_NONE, NPCX_WUI(0, 8, 6) },
+ { NPCX_GPIO(E, 7), NPCX_WUI(0, 8, 7) },
+ }, NPCX_IRQ_WKINTEFGH_0 },
+
+ /* MIWU1 Group A */
+ { { { NPCX_GPIO(0, 0), NPCX_WUI(1, 1, 0) },
+ { NPCX_GPIO(0, 1), NPCX_WUI(1, 1, 1) },
+ { NPCX_GPIO(0, 2), NPCX_WUI(1, 1, 2) },
+ { NPCX_GPIO(0, 3), NPCX_WUI(1, 1, 3) },
+ { NPCX_GPIO(0, 4), NPCX_WUI(1, 1, 4) },
+ { NPCX_GPIO(0, 5), NPCX_WUI(1, 1, 5) },
+ { NPCX_GPIO(0, 6), NPCX_WUI(1, 1, 6) },
+ { NPCX_GPIO(0, 7), NPCX_WUI(1, 1, 7) },
+ }, NPCX_IRQ_WKINTA_1 },
+ /* MIWU1 Group B */
+ { { { NPCX_GPIO(1, 0), NPCX_WUI(1, 2, 0) },
+ { NPCX_GPIO(1, 1), NPCX_WUI(1, 2, 1) },
+ { NPCX_GPIO_NONE, NPCX_WUI(1, 2, 2) },
+ { NPCX_GPIO(1, 3), NPCX_WUI(1, 2, 3) },
+ { NPCX_GPIO(1, 4), NPCX_WUI(1, 2, 4) },
+ { NPCX_GPIO(1, 5), NPCX_WUI(1, 2, 5) },
+ { NPCX_GPIO(1, 6), NPCX_WUI(1, 2, 6) },
+ { NPCX_GPIO(1, 7), NPCX_WUI(1, 2, 7) },
+ }, NPCX_IRQ_WKINTB_1 },
+ /* MIWU1 Group C -- Skipping */
+ /* MIWU1 Group D */
+ { { { NPCX_GPIO(2, 0), NPCX_WUI(1, 4, 0) },
+ { NPCX_GPIO(2, 1), NPCX_WUI(1, 4, 1) },
+ { NPCX_GPIO_NONE, NPCX_WUI(1, 4, 2) },
+ { NPCX_GPIO(3, 3), NPCX_WUI(1, 4, 3) },
+ { NPCX_GPIO(3, 4), NPCX_WUI(1, 4, 4) },
+ { NPCX_GPIO_NONE, NPCX_WUI(1, 4, 5) },
+ { NPCX_GPIO(3, 6), NPCX_WUI(1, 4, 6) },
+ { NPCX_GPIO(3, 7), NPCX_WUI(1, 4, 7) },
+ }, NPCX_IRQ_WKINTD_1 },
+
+ /* MIWU1 Group E */
+ { { { NPCX_GPIO(4, 0), NPCX_WUI(1, 5, 0) },
+ { NPCX_GPIO(4, 1), NPCX_WUI(1, 5, 1) },
+ { NPCX_GPIO(4, 2), NPCX_WUI(1, 5, 2) },
+ { NPCX_GPIO(4, 3), NPCX_WUI(1, 5, 3) },
+ { NPCX_GPIO(4, 4), NPCX_WUI(1, 5, 4) },
+ { NPCX_GPIO(4, 5), NPCX_WUI(1, 5, 5) },
+ { NPCX_GPIO(4, 6), NPCX_WUI(1, 5, 6) },
+ { NPCX_GPIO(4, 7), NPCX_WUI(1, 5, 7) },
+ }, NPCX_IRQ_WKINTE_1 },
+
+ /* MIWU1 Group F */
+ { { { NPCX_GPIO(5, 0), NPCX_WUI(1, 6, 0) },
+ { NPCX_GPIO(5, 1), NPCX_WUI(1, 6, 1) },
+ { NPCX_GPIO(5, 2), NPCX_WUI(1, 6, 2) },
+ { NPCX_GPIO(5, 3), NPCX_WUI(1, 6, 3) },
+ { NPCX_GPIO(5, 4), NPCX_WUI(1, 6, 4) },
+ { NPCX_GPIO(5, 5), NPCX_WUI(1, 6, 5) },
+ { NPCX_GPIO(5, 6), NPCX_WUI(1, 6, 6) },
+ { NPCX_GPIO(5, 7), NPCX_WUI(1, 6, 7) },
+ }, NPCX_IRQ_WKINTF_1 },
+ /* MIWU1 Group G */
+ { { { NPCX_GPIO(6, 0), NPCX_WUI(1, 7, 0) },
+ { NPCX_GPIO(6, 1), NPCX_WUI(1, 7, 1) },
+ { NPCX_GPIO(6, 2), NPCX_WUI(1, 7, 2) },
+ { NPCX_GPIO(6, 3), NPCX_WUI(1, 7, 3) },
+ { NPCX_GPIO(6, 4), NPCX_WUI(1, 7, 4) },
+ { NPCX_GPIO(6, 5), NPCX_WUI(1, 7, 5) },
+ { NPCX_GPIO(6, 6), NPCX_WUI(1, 7, 6) },
+ { NPCX_GPIO(7, 1), NPCX_WUI(1, 7, 7) },
+ }, NPCX_IRQ_WKINTG_1 },
+ /* MIWU1 Group H */
+ { { { NPCX_GPIO(7, 0), NPCX_WUI(1, 8, 0) },
+ { NPCX_GPIO(6, 7), NPCX_WUI(1, 8, 1) },
+ { NPCX_GPIO(7, 2), NPCX_WUI(1, 8, 2) },
+ { NPCX_GPIO(7, 3), NPCX_WUI(1, 8, 3) },
+ { NPCX_GPIO(7, 4), NPCX_WUI(1, 8, 4) },
+ { NPCX_GPIO(7, 5), NPCX_WUI(1, 8, 5) },
+ { NPCX_GPIO(7, 6), NPCX_WUI(1, 8, 6) },
+ { NPCX_GPIO_NONE, NPCX_WUI(1, 8, 7) },
+ }, NPCX_IRQ_WKINTH_1 },
+};
+
+struct gpio_alt_map {
+ uint8_t gpio_port;
+ uint8_t gpio_mask;
+ uint8_t alt_group;
+ uint8_t alt_mask;
+};
+
+const struct gpio_alt_map gpio_alt_table[] = {
+ /* I2C Module */
+#if I2C0_BUS0
+ { NPCX_GPIO(B, 4), NPCX_ALT(2, I2C0_0_SL)}, /* SMB0SDA */
+ { NPCX_GPIO(B, 5), NPCX_ALT(2, I2C0_0_SL)}, /* SMB0SCL */
+#else
+ { NPCX_GPIO(B, 2), NPCX_ALT(2, I2C0_1_SL)}, /* SMB0SDA */
+ { NPCX_GPIO(B, 3), NPCX_ALT(2, I2C0_1_SL)}, /* SMB0SCL */
+#endif
+ { NPCX_GPIO(8, 7), NPCX_ALT(2, I2C1_0_SL)}, /* SMB1SDA */
+ { NPCX_GPIO(9, 0), NPCX_ALT(2, I2C1_0_SL)}, /* SMB1SCL */
+ { NPCX_GPIO(9, 1), NPCX_ALT(2, I2C2_0_SL)}, /* SMB2SDA */
+ { NPCX_GPIO(9, 2), NPCX_ALT(2, I2C2_0_SL)}, /* SMB2SCL */
+ { NPCX_GPIO(D, 0), NPCX_ALT(2, I2C3_0_SL)}, /* SMB3SDA */
+ { NPCX_GPIO(D, 1), NPCX_ALT(2, I2C3_0_SL)}, /* SMB3SCL */
+ /* ADC Module */
+ { NPCX_GPIO(4, 5), NPCX_ALT(6, ADC0_SL)}, /* ADC0 */
+ { NPCX_GPIO(4, 4), NPCX_ALT(6, ADC1_SL)}, /* ADC1 */
+ { NPCX_GPIO(4, 3), NPCX_ALT(6, ADC2_SL)}, /* ADC2 */
+ { NPCX_GPIO(4, 2), NPCX_ALT(6, ADC3_SL)}, /* ADC3 */
+ { NPCX_GPIO(4, 1), NPCX_ALT(6, ADC4_SL)}, /* ADC4 */
+ /* UART Module */
+ { NPCX_GPIO(1, 0), NPCX_ALT(9, NO_KSO08_SL)}, /* CR_SIN/KSO09/GPIO10*/
+ { NPCX_GPIO(1, 1), NPCX_ALT(9, NO_KSO09_SL)}, /* CR_SOUT/KSO10/GPIO11*/
+ /* SPI Module */
+ { NPCX_GPIO(9, 5), NPCX_ALT(0, SPIP_SL)}, /* SPIP_MISO */
+ { NPCX_GPIO(A, 5), NPCX_ALT(0, SPIP_SL)}, /* SPIP_CS1 */
+ { NPCX_GPIO(A, 3), NPCX_ALT(0, SPIP_SL)}, /* SPIP_MOSI */
+ { NPCX_GPIO(A, 1), NPCX_ALT(0, SPIP_SL)}, /* SPIP_SCLK */
+ /* PWM Module */
+ { NPCX_GPIO(C, 3), NPCX_ALT(4, PWM0_SL)}, /* PWM0 */
+ { NPCX_GPIO(C, 2), NPCX_ALT(4, PWM1_SL)}, /* PWM1 */
+ { NPCX_GPIO(C, 4), NPCX_ALT(4, PWM2_SL)}, /* PWM2 */
+ { NPCX_GPIO(8, 0), NPCX_ALT(4, PWM3_SL)}, /* PWM3 */
+ { NPCX_GPIO(B, 6), NPCX_ALT(4, PWM4_SL)}, /* PWM4 */
+ { NPCX_GPIO(B, 7), NPCX_ALT(4, PWM5_SL)}, /* PWM5 */
+ { NPCX_GPIO(C, 0), NPCX_ALT(4, PWM6_SL)}, /* PWM6 */
+ { NPCX_GPIO(6, 0), NPCX_ALT(4, PWM7_SL)}, /* PWM7 */
+ /* MFT Module */
+#if TACH_SEL1
+ { NPCX_GPIO(4, 0), NPCX_ALT(3, TA1_TACH1_SL1)},/* TA1_TACH1 */
+ { NPCX_GPIO(A, 4), NPCX_ALT(3, TB1_TACH2_SL1)},/* TB1_TACH2 */
+#else
+ { NPCX_GPIO(9, 3), NPCX_ALT(C, TA1_TACH1_SL2)},/* TA1_TACH1 */
+ { NPCX_GPIO(D, 3), NPCX_ALT(C, TB1_TACH2_SL2)},/* TB1_TACH2 */
+#endif
+ /* JTAG Module */
+#if !(JTAG1)
+ { NPCX_GPIO(2, 1), NPCX_ALT(5, NJEN0_EN) }, /* TCLK */
+ { NPCX_GPIO(1, 7), NPCX_ALT(5, NJEN0_EN) }, /* TDI */
+ { NPCX_GPIO(1, 6), NPCX_ALT(5, NJEN0_EN) }, /* TDO */
+ { NPCX_GPIO(2, 0), NPCX_ALT(5, NJEN0_EN) }, /* TMS */
+#else
+ { NPCX_GPIO(D, 5), NPCX_ALT(5, NJEN1_EN) }, /* TCLK */
+ { NPCX_GPIO(E, 2), NPCX_ALT(5, NJEN1_EN) }, /* TDI */
+ { NPCX_GPIO(D, 4), NPCX_ALT(5, NJEN1_EN) }, /* TDO */
+ { NPCX_GPIO(E, 5), NPCX_ALT(5, NJEN1_EN) }, /* TMS */
+#endif
+ /* 01 for PWRGD_OUT*/
+};
+
+/*****************************************************************************/
+/* Internal functions */
+const struct gpio_wui_map *gpio_find_wui_from_io(uint8_t port, uint8_t mask)
+{
+ int i, j;
+ for (i = 0; i < ARRAY_SIZE(gpio_wui_table); i++) {
+ const struct gpio_wui_map *map = gpio_wui_table[i].wui_map;
+ for (j = 0; j < 8; j++, map++) {
+ if (map->gpio_port == port && map->gpio_mask == mask)
+ return map;
+ }
+ }
+ return NULL;
+}
+
+int gpio_find_irq_from_io(uint8_t port, uint8_t mask)
+{
+ int i, j;
+ for (i = 0; i < ARRAY_SIZE(gpio_wui_table); i++) {
+ const struct gpio_wui_map *map = gpio_wui_table[i].wui_map;
+ for (j = 0; j < 8; j++, map++) {
+ if (map->gpio_port == port && map->gpio_mask == mask)
+ return gpio_wui_table[i].irq;
+ }
+ }
+ return -1;
+}
+
+int gpio_alt_sel(uint8_t port, uint8_t mask, uint8_t func)
+{
+ int i;
+ const struct gpio_alt_map *map = gpio_alt_table;
+ for (i = 0; i < ARRAY_SIZE(gpio_alt_table); i++, map++) {
+ if (map->gpio_port == port &&
+ (map->gpio_mask == mask)) {
+ /* Enable alternative function if func >=0 */
+ if (func <= 0) /* GPIO functionality */
+ NPCX_DEVALT(map->alt_group) &= ~(map->alt_mask);
+ else
+ NPCX_DEVALT(map->alt_group) |= (map->alt_mask);
+ return 1;
+ }
+ }
+ return -1;
+}
+
+void gpio_execute_isr(uint8_t port, uint8_t mask)
+{
+ int i;
+ const struct gpio_info *g = gpio_list;
+ /* Find GPIOs and execute interrupt service routine */
+ for (i = 0; i < GPIO_COUNT; i++, g++) {
+ if (port == g->port && mask == g->mask && g->irq_handler) {
+ g->irq_handler(i);
+ return;
+ }
+ }
+}
+
+/* Set interrupt type for GPIO input */
+void gpio_interrupt_type_sel(uint8_t port, uint8_t mask, uint32_t flags)
+{
+ const struct gpio_wui_map *map = gpio_find_wui_from_io(port, mask);
+ uint8_t table, group, pmask;
+
+ if (map == NULL)
+ return;
+
+ table = map->wui_table;
+ group = map->wui_group;
+ pmask = map->wui_mask;
+
+ /* Handle interrupt for level trigger */
+ if ((flags & GPIO_INT_F_HIGH) ||
+ (flags & GPIO_INT_F_LOW)) {
+ /* Set detection mode to level */
+ NPCX_WKMOD(table, group) |= pmask;
+ /* Handle interrupting on level high */
+ if (flags & GPIO_INT_F_HIGH)
+ NPCX_WKEDG(table, group) &= ~pmask;
+ /* Handle interrupting on level low */
+ else if (flags & GPIO_INT_F_LOW)
+ NPCX_WKEDG(table, group) |= pmask;
+
+ /* Enable wake-up input sources */
+ NPCX_WKEN(table, group) |= pmask;
+ }
+ /* Handle interrupt for edge trigger */
+ else if ((flags & GPIO_INT_F_RISING) ||
+ (flags & GPIO_INT_F_FALLING)) {
+ /* Set detection mode to edge */
+ NPCX_WKMOD(table, group) &= ~pmask;
+ /* Handle interrupting on both edges */
+ if ((flags & GPIO_INT_F_RISING) &&
+ (flags & GPIO_INT_F_FALLING)) {
+ /* Enable any edge */
+ NPCX_WKAEDG(table, group) |= pmask;
+ }
+ /* Handle interrupting on rising edge */
+ else if (flags & GPIO_INT_F_RISING) {
+ /* Disable any edge */
+ NPCX_WKAEDG(table, group) &= ~pmask;
+ NPCX_WKEDG(table, group) &= ~pmask;
+ }
+ /* Handle interrupting on falling edge */
+ else if (flags & GPIO_INT_F_FALLING) {
+ /* Disable any edge */
+ NPCX_WKAEDG(table, group) &= ~pmask;
+ NPCX_WKEDG(table, group) |= pmask;
+ }
+ /* Enable wake-up input sources */
+ NPCX_WKEN(table, group) |= pmask;
+ } else{
+ /* Disable wake-up input sources */
+ NPCX_WKEN(table, group) &= ~pmask;
+ }
+
+ /* No support analog mode */
+}
+
+/*****************************************************************************/
+/* IC specific low-level driver */
+
+void gpio_set_alternate_function(uint32_t port, uint32_t mask, int func)
+{
+ /* Enable alternative pins by func*/
+ int pin;
+ uint8_t pmask;
+ /* check each bit from mask */
+ for (pin = 0; pin < 8; pin++) {
+ pmask = (mask & (1 << pin));
+ if (pmask)
+ gpio_alt_sel(port, pmask, func);
+ }
+}
+
+test_mockable int gpio_get_level(enum gpio_signal signal)
+{
+ return (NPCX_PDIN(gpio_list[signal].port) &
+ gpio_list[signal].mask) ? 1 : 0;
+}
+
+void gpio_set_level(enum gpio_signal signal, int value)
+{
+ if (value)
+ NPCX_PDOUT(gpio_list[signal].port) |=
+ gpio_list[signal].mask;
+ else
+ NPCX_PDOUT(gpio_list[signal].port) &=
+ ~gpio_list[signal].mask;
+}
+
+void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
+{
+ /*
+ * Select open drain first, so that we don't glitch the signal
+ * when changing the line to an output. 0:push-pull 1:open-drain
+ */
+ if (flags & GPIO_OPEN_DRAIN)
+ NPCX_PTYPE(port) |= mask;
+ else
+ NPCX_PTYPE(port) &= ~mask;
+
+ /* Select direction of GPIO 0:input 1:output */
+ if (flags & GPIO_OUTPUT)
+ NPCX_PDIR(port) |= mask;
+ else
+ NPCX_PDIR(port) &= ~mask;
+
+ /* Select pull-up/down of GPIO 0:pull-up 1:pull-down */
+ if (flags & GPIO_PULL_UP) {
+ NPCX_PPUD(port) &= ~mask;
+ NPCX_PPULL(port) |= mask; /* enable pull down/up */
+ } else if (flags & GPIO_PULL_DOWN) {
+ NPCX_PPUD(port) |= mask;
+ NPCX_PPULL(port) |= mask; /* enable pull down/up */
+ } else {
+ /* No pull up/down */
+ NPCX_PPULL(port) &= ~mask; /* disable pull down/up */
+ }
+
+ /* Set up interrupt type */
+ if (flags & GPIO_INPUT)
+ gpio_interrupt_type_sel(port, mask, flags);
+
+ /* Set level 0:low 1:high*/
+ if (flags & GPIO_HIGH)
+ NPCX_PDOUT(port) |= mask;
+ else if (flags & GPIO_LOW)
+ NPCX_PDOUT(port) &= ~mask;
+
+}
+
+int gpio_enable_interrupt(enum gpio_signal signal)
+{
+ const struct gpio_info *g = gpio_list + signal;
+ int irq = gpio_find_irq_from_io(g->port, g->mask);
+
+ /* Fail if no interrupt handler */
+ if (irq < 0)
+ return EC_ERROR_UNKNOWN;
+
+ task_enable_irq(irq);
+ return EC_SUCCESS;
+}
+
+int gpio_disable_interrupt(enum gpio_signal signal)
+{
+ const struct gpio_info *g = gpio_list + signal;
+ int irq = gpio_find_irq_from_io(g->port, g->mask);
+
+ /* Fail if no interrupt handler */
+ if (irq < 0)
+ return EC_ERROR_UNKNOWN;
+
+ task_disable_irq(irq);
+ return EC_SUCCESS;
+}
+
+int gpio_is_reboot_warm(void)
+{
+ /* Check for debugger or watch-dog Warm reset */
+ if (IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_DBGRST_STS)
+ /* TODO: 5M5G has cleared WDRST_STS bit in booter */
+#if !defined(CHIP_NPCX5M5G)
+ /* watch-dog warm reset */
+ || (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS)
+ && (IS_BIT_SET(NPCX_TWCFG, NPCX_TWCFG_WDRST_MODE))))
+#else
+ )
+#endif
+ return 1;
+ else
+ return 0;
+}
+
+void gpio_pre_init(void)
+{
+ const struct gpio_info *g = gpio_list;
+ int flags;
+ int i, j;
+ int is_warm = gpio_is_reboot_warm();
+
+ uint32_t ksi_mask = (~((1<<KEYBOARD_ROWS)-1)) & KB_ROW_MASK;
+ uint32_t ks0_mask = (~((1<<KEYBOARD_COLS)-1)) & KB_COL_MASK;
+
+ /* Set necessary pin mux first */
+ /* Pin_Mux for KSO0-17 & KSI0-7 */
+ NPCX_DEVALT(ALT_GROUP_7) = (uint8_t)(ksi_mask);
+ NPCX_DEVALT(ALT_GROUP_8) = (uint8_t)(ks0_mask);
+ NPCX_DEVALT(ALT_GROUP_9) = (uint8_t)(ks0_mask >> 8);
+ NPCX_DEVALT(ALT_GROUP_A) |= (uint8_t)(ks0_mask >> 16);
+
+ /* Pin_Mux for FIU/SPI (set to GPIO) */
+ SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_GPIO_NO_SPIP);
+ SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI);
+
+ /* Clear all pending bits of GPIOS*/
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 8; j++)
+ NPCX_WKPCL(i, j) = 0xFF;
+
+
+ /* No support enable clock for the GPIO port in run and sleep. */
+ /* Set flag for each GPIO pin in 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);
+
+ /* Set up GPIO based on flags */
+ gpio_set_flags_by_mask(g->port, g->mask, flags);
+ }
+}
+
+/* List of GPIO IRQs to enable. Don't automatically enable interrupts for
+ * the keyboard input GPIO bank - that's handled separately. Of course the
+ * bank is different for different systems. */
+static void gpio_init(void)
+{
+ int i;
+ /* Enable IRQs now that pins are set up */
+ for (i = 0; i < ARRAY_SIZE(gpio_wui_table); i++)
+ task_enable_irq(gpio_wui_table[i].irq);
+
+}
+DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT);
+
+/*****************************************************************************/
+/* Interrupt handlers */
+
+/**
+ * Handle a GPIO interrupt.
+ *
+ * @param int_no Interrupt number for GPIO
+ */
+
+static void gpio_interrupt(int int_no)
+{
+#if DEBUG_GPIO
+ static uint8_t i, pin, wui_mask;
+#else
+ uint8_t i, pin, wui_mask;
+#endif
+ for (i = 0; i < ARRAY_SIZE(gpio_wui_table); i++) {
+ /* If interrupt number is the same */
+ if (gpio_wui_table[i].irq == int_no) {
+ /* Mapping relationship between WUI and GPIO */
+ const struct gpio_wui_map *map =
+ gpio_wui_table[i].wui_map;
+ /* Get pending mask */
+ wui_mask = NPCX_WKPND(map->wui_table , map->wui_group);
+
+ /* If pending bits is not zero */
+ if (wui_mask) {
+ /* Clear pending bits of WUI */
+ NPCX_WKPCL(map->wui_table , map->wui_group)
+ = wui_mask;
+
+ for (pin = 0; pin < 8; pin++, map++) {
+ /* If pending bit is high, execute ISR*/
+ if (wui_mask & (1<<pin))
+ gpio_execute_isr(map->gpio_port,
+ map->gpio_mask);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Handlers for each GPIO port. These read and clear the interrupt bits for
+ * the port, then call the master handler above.
+ */
+
+#define GPIO_IRQ_FUNC(_irq_func, int_no) \
+void _irq_func(void) \
+{ \
+ gpio_interrupt(int_no); \
+}
+
+GPIO_IRQ_FUNC(__gpio_wk0ad_interrupt , NPCX_IRQ_MTC_WKINTAD_0);
+GPIO_IRQ_FUNC(__gpio_wk0b_interrupt , NPCX_IRQ_TWD_WKINTB_0);
+GPIO_IRQ_FUNC(__gpio_wk0c_interrupt , NPCX_IRQ_WKINTC_0);
+GPIO_IRQ_FUNC(__gpio_wk0efgh_interrupt, NPCX_IRQ_WKINTEFGH_0);
+GPIO_IRQ_FUNC(__gpio_wk1a_interrupt , NPCX_IRQ_WKINTA_1);
+GPIO_IRQ_FUNC(__gpio_wk1b_interrupt , NPCX_IRQ_WKINTB_1);
+GPIO_IRQ_FUNC(__gpio_wk1d_interrupt , NPCX_IRQ_WKINTD_1);
+GPIO_IRQ_FUNC(__gpio_wk1e_interrupt , NPCX_IRQ_WKINTE_1);
+GPIO_IRQ_FUNC(__gpio_wk1f_interrupt , NPCX_IRQ_WKINTF_1);
+GPIO_IRQ_FUNC(__gpio_wk1g_interrupt , NPCX_IRQ_WKINTG_1);
+GPIO_IRQ_FUNC(__gpio_wk1h_interrupt , NPCX_IRQ_WKINTH_1);
+
+DECLARE_IRQ(NPCX_IRQ_MTC_WKINTAD_0, __gpio_wk0ad_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_TWD_WKINTB_0, __gpio_wk0b_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTC_0, __gpio_wk0c_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTEFGH_0, __gpio_wk0efgh_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTA_1, __gpio_wk1a_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTB_1, __gpio_wk1b_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTD_1, __gpio_wk1d_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTE_1, __gpio_wk1e_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTF_1, __gpio_wk1f_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTG_1, __gpio_wk1g_interrupt, 1);
+DECLARE_IRQ(NPCX_IRQ_WKINTH_1, __gpio_wk1h_interrupt, 1);
+
+
+#undef GPIO_IRQ_FUNC
diff --git a/chip/npcx/hwtimer.c b/chip/npcx/hwtimer.c
new file mode 100644
index 0000000000..80bb903e67
--- /dev/null
+++ b/chip/npcx/hwtimer.c
@@ -0,0 +1,255 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Hardware timers driver */
+
+#include "clock.h"
+#include "clock_chip.h"
+#include "common.h"
+#include "hooks.h"
+#include "hwtimer.h"
+#include "hwtimer_chip.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+
+/* (2^TICK_ITIM_DEPTH us) between 2 ticks of timer */
+#define TICK_ITIM_DEPTH 16 /* Depth of ITIM Unit: bits */
+#define TICK_INTERVAL (1 << TICK_ITIM_DEPTH) /* Unit: us */
+#define TICK_INTERVAL_MASK (TICK_INTERVAL - 1) /* Mask of interval */
+#define TICK_ITIM_MAX_CNT (TICK_INTERVAL - 1) /* Maximum counter value */
+
+/* 32-bits counter value */
+static volatile uint32_t cur_cnt_us;
+static volatile uint32_t pre_cnt_us;
+/* Time when event will be expired unit:us */
+static volatile uint32_t evt_expired_us;
+/* 32-bits event counter */
+static volatile uint32_t evt_cnt;
+/* Debugger information */
+#if DEBUG_TMR
+static volatile uint32_t evt_cnt_us_dbg;
+static volatile uint32_t cur_cnt_us_dbg;
+#endif
+
+/*****************************************************************************/
+/* Internal functions */
+void init_hw_timer(int itim_no, enum ITIM16_SOURCE_CLOCK_T source)
+{
+ /* Use internal 32K clock/APB2 for ITIM16 */
+ UPDATE_BIT(NPCX_ITCTS(itim_no), NPCX_ITIM16_CKSEL,
+ source != ITIM16_SOURCE_CLOCK_APB2);
+
+ /* Clear timeout status */
+ SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITIM16_TO_STS);
+
+ /* ITIM timeout interrupt enable */
+ SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITIM16_TO_IE);
+
+ /* ITIM timeout wake-up enable */
+ SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITIM16_TO_WUE);
+}
+
+/*****************************************************************************/
+/* HWTimer event handlers */
+void __hw_clock_event_set(uint32_t deadline)
+{
+ float inv_evt_tick = INT_32K_CLOCK/(float)SECOND;
+ uint32_t evt_cnt_us;
+ /* Is deadline min value? */
+ if (evt_expired_us != 0 && evt_expired_us < deadline)
+ return;
+
+ /* mark min event value */
+ evt_expired_us = deadline;
+ evt_cnt_us = deadline - __hw_clock_source_read();
+#if DEBUG_TMR
+ evt_cnt_us_dbg = deadline - __hw_clock_source_read();
+#endif
+
+ /* Event module disable */
+ CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
+ /*
+ * ITIM count down : event expired : Unit: 1/32768 sec
+ * It must exceed evt_expired_us for process_timers function
+ */
+ evt_cnt = ((uint32_t)(evt_cnt_us*inv_evt_tick)+1)-1;
+ if (evt_cnt > TICK_ITIM_MAX_CNT)
+ evt_cnt = TICK_ITIM_MAX_CNT;
+ NPCX_ITCNT16(ITIM_EVENT_NO) = evt_cnt;
+
+ /* Event module enable */
+ SET_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
+
+ /* Enable interrupt of ITIM */
+ task_enable_irq(ITIM16_INT(ITIM_EVENT_NO));
+}
+
+/* Returns the time-stamp of the next programmed event */
+uint32_t __hw_clock_event_get(void)
+{
+ return evt_expired_us;
+}
+
+/* Returns time delay cause of deep idle */
+uint32_t __hw_clock_get_sleep_time(void)
+{
+ float evt_tick = SECOND/(float)INT_32K_CLOCK;
+ uint32_t sleep_time;
+ uint32_t cnt = NPCX_ITCNT16(ITIM_EVENT_NO);
+
+ interrupt_disable();
+ /* Event has been triggered but timer ISR dosen't handle it */
+ if (IS_BIT_SET(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_TO_STS))
+ sleep_time = (uint32_t) (evt_cnt+1)*evt_tick;
+ /* Event hasn't been triggered */
+ else
+ sleep_time = (uint32_t) (evt_cnt+1 - cnt)*evt_tick;
+ interrupt_enable();
+
+ return sleep_time;
+}
+
+/* Cancel the next event programmed by __hw_clock_event_set */
+void __hw_clock_event_clear(void)
+{
+ /* ITIM event module disable */
+ CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
+
+ /* Disable interrupt of Event */
+ task_disable_irq(ITIM16_INT(ITIM_EVENT_NO));
+
+ /* Clear event parameters */
+ evt_expired_us = 0;
+ evt_cnt = 0;
+}
+
+/* Irq for hwtimer event */
+void __hw_clock_event_irq(void)
+{
+ int delay;
+ /* Clear timeout status for event */
+ SET_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_TO_STS);
+
+ /* ITIM event module disable */
+ CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
+
+ /* Disable interrupt of event */
+ task_disable_irq(ITIM16_INT(ITIM_EVENT_NO));
+
+ /* Workaround for tick interrupt latency */
+ delay = evt_expired_us - __hw_clock_source_read();
+ if (delay > 0)
+ cur_cnt_us += delay;
+
+ /* Clear event parameters */
+ evt_expired_us = 0;
+ evt_cnt = 0;
+
+ /* handle upper driver */
+ process_timers(0);
+}
+DECLARE_IRQ(ITIM16_INT(ITIM_EVENT_NO) , __hw_clock_event_irq, 1);
+
+
+/*****************************************************************************/
+/* HWTimer tick handlers */
+
+/* Returns the value of the free-running counter used as clock. */
+uint32_t __hw_clock_source_read(void)
+{
+ uint32_t us;
+ uint32_t cnt = NPCX_ITCNT16(ITIM_TIME_NO);
+ /* Is timeout expired? - but timer ISR dosen't handle it */
+ if (IS_BIT_SET(NPCX_ITCTS(ITIM_TIME_NO), NPCX_ITIM16_TO_STS))
+ us = TICK_INTERVAL;
+ else
+ us = TICK_INTERVAL - cnt;
+
+#if DEBUG_TMR
+ cur_cnt_us_dbg = cur_cnt_us + us;
+#endif
+ return cur_cnt_us + us;
+}
+
+/* Override the current value of the hardware counter */
+void __hw_clock_source_set(uint32_t ts)
+{
+ /* Set current time */
+ cur_cnt_us = ts;
+}
+
+/* Irq for hwtimer tick */
+void __hw_clock_source_irq(void)
+{
+ /* Is timeout trigger trigger? */
+ if (IS_BIT_SET(NPCX_ITCTS(ITIM_TIME_NO), NPCX_ITIM16_TO_STS)) {
+ /* Clear timeout status*/
+ SET_BIT(NPCX_ITCTS(ITIM_TIME_NO), NPCX_ITIM16_TO_STS);
+
+ /* Store previous time counter value */
+ pre_cnt_us = cur_cnt_us;
+ /* Increase TICK_INTERVAL unit:us */
+ cur_cnt_us += TICK_INTERVAL;
+
+ /* Is 32-bits timer count overflow? */
+ if (pre_cnt_us > cur_cnt_us)
+ process_timers(1);
+
+ } else { /* Handle soft trigger */
+ process_timers(0);
+ }
+}
+DECLARE_IRQ(NPCX_IRQ_ITIM16_1, __hw_clock_source_irq, 1);
+
+static void update_prescaler(void)
+{
+ /*
+ * prescaler to time tick
+ * Ttick_unit = (PRE_8+1) * Tapb2_clk
+ * PRE_8 = (Ttick_unit/Tapb2_clk) -1
+ */
+ NPCX_ITPRE(ITIM_TIME_NO) = (clock_get_apb2_freq() / SECOND) - 1;
+ /* Set event tick unit = 1/32768 sec */
+ NPCX_ITPRE(ITIM_EVENT_NO) = 0;
+
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, update_prescaler, HOOK_PRIO_DEFAULT);
+
+int __hw_clock_source_init(uint32_t start_t)
+{
+ /*
+ * 1. Use ITIM16-1 as internal time reading
+ * 2. Use ITIM16-2 for event handling
+ */
+
+ /* Enable clock for ITIM peripheral */
+ clock_enable_peripheral(CGC_OFFSET_TIMER, CGC_TIMER_MASK,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+
+ /* init tick & event timer first */
+ init_hw_timer(ITIM_TIME_NO, ITIM16_SOURCE_CLOCK_APB2);
+ init_hw_timer(ITIM_EVENT_NO, ITIM16_SOURCE_CLOCK_32K);
+
+ /* Set initial prescaler */
+ update_prescaler();
+
+ /* ITIM count down : TICK_INTERVAL expired*/
+ NPCX_ITCNT16(ITIM_TIME_NO) = TICK_ITIM_MAX_CNT;
+
+ /*
+ * Override the count with the start value now that counting has
+ * started.
+ */
+ __hw_clock_source_set(start_t);
+
+ /* ITIM module enable */
+ SET_BIT(NPCX_ITCTS(ITIM_TIME_NO), NPCX_ITIM16_ITEN);
+
+ /* Enable interrupt of ITIM */
+ task_enable_irq(ITIM16_INT(ITIM_TIME_NO));
+
+ return ITIM16_INT(ITIM_TIME_NO);
+}
diff --git a/chip/npcx/hwtimer_chip.h b/chip/npcx/hwtimer_chip.h
new file mode 100644
index 0000000000..490d67b80d
--- /dev/null
+++ b/chip/npcx/hwtimer_chip.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* NPCX-specific hwtimer module for Chrome EC */
+
+#ifndef HWTIMER_CHIP_H_
+#define HWTIMER_CHIP_H_
+
+/* Channel definition for ITIM16 */
+#define ITIM_TIME_NO ITIM16_1
+#define ITIM_EVENT_NO ITIM16_2
+#define ITIM_WDG_NO ITIM16_5
+
+/* Clock source for ITIM16 */
+enum ITIM16_SOURCE_CLOCK_T {
+ ITIM16_SOURCE_CLOCK_APB2 = 0,
+ ITIM16_SOURCE_CLOCK_32K = 1,
+};
+
+/* Initialize ITIM16 timer */
+void init_hw_timer(int itim_no, enum ITIM16_SOURCE_CLOCK_T source);
+
+/* Returns time delay cause of deep idle */
+uint32_t __hw_clock_get_sleep_time(void);
+
+#endif /* HWTIMER_CHIP_H_ */
diff --git a/chip/npcx/i2c.c b/chip/npcx/i2c.c
new file mode 100644
index 0000000000..1e71ed6c7b
--- /dev/null
+++ b/chip/npcx/i2c.c
@@ -0,0 +1,592 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* I2C port module for Chrome EC */
+
+#include "clock.h"
+#include "clock_chip.h"
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+#if !(DEBUG_I2C)
+#define CPUTS(...)
+#define CPRINTS(...)
+#else
+#define CPUTS(outstr) cputs(CC_I2C, outstr)
+#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
+#endif
+
+/* Data abort timeout unit:ms*/
+#define I2C_ABORT_TIMEOUT 10000
+/* Maximum time we allow for an I2C transfer */
+#define I2C_TIMEOUT_US (100*MSEC)
+/* Marco functions of I2C */
+#define I2C_START(port) SET_BIT(NPCX_SMBCTL1(port), NPCX_SMBCTL1_START)
+#define I2C_STOP(port) SET_BIT(NPCX_SMBCTL1(port), NPCX_SMBCTL1_STOP)
+#define I2C_NACK(port) SET_BIT(NPCX_SMBCTL1(port), NPCX_SMBCTL1_ACK)
+#define I2C_WRITE_BYTE(port, data) (NPCX_SMBSDA(port) = data)
+#define I2C_READ_BYTE(port, data) (data = NPCX_SMBSDA(port))
+
+/* Error values that functions can return */
+enum smb_error {
+ SMB_OK = 0, /* No error */
+ SMB_CH_OCCUPIED, /* Channel is already occupied */
+ SMB_MEM_POOL_INIT_ERROR, /* Memory pool initialization error */
+ SMB_BUS_FREQ_ERROR, /* SMbus freq was not valid */
+ SMB_INVLAID_REGVALUE, /* Invalid SMbus register value */
+ SMB_UNEXIST_CH_ERROR, /* Channel does not exist */
+ SMB_NO_SUPPORT_PTL, /* Not support SMBus Protocol */
+ SMB_BUS_ERROR, /* Encounter bus error */
+ SMB_MASTER_NO_ADDRESS_MATCH,/* No slave address match (Master Mode)*/
+ SMB_READ_DATA_ERROR, /* Read data for SDA error */
+ SMB_READ_OVERFLOW_ERROR, /* Read data over than we predict */
+ SMB_TIMEOUT_ERROR, /* Timeout expired */
+ SMB_MODULE_ISBUSY, /* Module is occupied by other device */
+ SMB_BUS_BUSY, /* SMBus is occupied by other device */
+};
+
+/*
+ * Internal SMBus Interface driver states values, which reflect events
+ * which occured on the bus
+ */
+enum smb_oper_state_t {
+ SMB_IDLE,
+ SMB_MASTER_START,
+ SMB_WRITE_OPER,
+ SMB_READ_OPER,
+ SMB_REPEAT_START,
+ SMB_WAIT_REPEAT_START,
+};
+
+
+/* IRQ for each port */
+static const uint32_t i2c_irqs[I2C_PORT_COUNT] = {
+ NPCX_IRQ_SMB1, NPCX_IRQ_SMB2, NPCX_IRQ_SMB3, NPCX_IRQ_SMB4};
+BUILD_ASSERT(ARRAY_SIZE(i2c_irqs) == I2C_PORT_COUNT);
+
+/* I2C port state data */
+struct i2c_status {
+ int flags; /* Flags (I2C_XFER_*) */
+ const uint8_t *tx_buf; /* Entry pointer of transmit buffer */
+ uint8_t *rx_buf; /* Entry pointer of receive buffer */
+ uint16_t sz_txbuf; /* Size of Tx buffer in bytes */
+ uint16_t sz_rxbuf; /* Size of rx buffer in bytes */
+ uint16_t idx_buf; /* Current index of Tx/Rx buffer */
+ uint8_t slave_addr;/* target slave address */
+ enum smb_oper_state_t oper_state;/* smbus operation state */
+ enum smb_error err_code; /* Error code */
+ int task_waiting; /* Task waiting on port */
+};
+/* I2C port state data array */
+static struct i2c_status i2c_stsobjs[I2C_PORT_COUNT];
+
+int i2c_bus_busy(int port)
+{
+ return IS_BIT_SET(NPCX_SMBCST(port), NPCX_SMBCST_BB) ? 1 : 0;
+}
+
+void i2c_abort_data(int port)
+{
+ uint16_t timeout = I2C_ABORT_TIMEOUT;
+
+ /* Generate a STOP condition */
+ I2C_STOP(port);
+
+ /* Clear NEGACK, STASTR and BER bits */
+ SET_BIT(NPCX_SMBST(port), NPCX_SMBST_BER);
+ SET_BIT(NPCX_SMBST(port), NPCX_SMBST_STASTR);
+ /*
+ * In Master mode, NEGACK should be cleared only
+ * after generating STOP
+ */
+ SET_BIT(NPCX_SMBST(port), NPCX_SMBST_NEGACK);
+
+ /* Wait till STOP condition is generated */
+ while (--timeout) {
+ msleep(1);
+ if (!IS_BIT_SET(NPCX_SMBCTL1(port), NPCX_SMBCTL1_STOP))
+ break;
+ }
+
+ /* Clear BB (BUS BUSY) bit */
+ SET_BIT(NPCX_SMBCST(port), NPCX_SMBCST_BB);
+}
+
+void i2c_reset(int port)
+{
+ uint16_t timeout = I2C_ABORT_TIMEOUT;
+ /* Disable the SMB module */
+ CLEAR_BIT(NPCX_SMBCTL2(port), NPCX_SMBCTL2_ENABLE);
+
+ while (--timeout) {
+ msleep(1);
+ /* WAIT FOR SCL & SDA IS HIGH */
+ if (IS_BIT_SET(NPCX_SMBCTL3(port), NPCX_SMBCTL3_SCL_LVL) &&
+ IS_BIT_SET(NPCX_SMBCTL3(port), NPCX_SMBCTL3_SDA_LVL))
+ break;
+ }
+
+ /* Enable the SMB module */
+ SET_BIT(NPCX_SMBCTL2(port), NPCX_SMBCTL2_ENABLE);
+}
+
+void i2c_recovery(int port)
+{
+ /* Abort data, generating STOP condition */
+ i2c_abort_data(port);
+
+ /* Reset i2c port by re-enable i2c port*/
+ i2c_reset(port);
+}
+
+enum smb_error i2c_master_transaction(int port)
+{
+ /* Set i2c mode to object */
+ int events = 0;
+ volatile struct i2c_status *p_status = i2c_stsobjs + port;
+
+ if (p_status->oper_state == SMB_IDLE) {
+ p_status->oper_state = SMB_MASTER_START;
+ } else if (p_status->oper_state == SMB_WAIT_REPEAT_START) {
+ p_status->oper_state = SMB_REPEAT_START;
+ CPUTS("R");
+ }
+
+ /* Generate a START condition */
+ I2C_START(port);
+ CPUTS("ST");
+
+ /* Wait for transfer complete or timeout */
+ events = task_wait_event_mask(TASK_EVENT_I2C_IDLE, I2C_TIMEOUT_US);
+ /* Handle timeout */
+ if ((events & TASK_EVENT_I2C_IDLE) == 0) {
+ /* Recovery I2C port */
+ i2c_recovery(port);
+ p_status->err_code = SMB_TIMEOUT_ERROR;
+ }
+
+ /*
+ * In slave write operation, NACK is OK, otherwise it is a problem
+ */
+ else if (p_status->err_code == SMB_BUS_ERROR ||
+ p_status->err_code == SMB_MASTER_NO_ADDRESS_MATCH){
+ i2c_recovery(port);
+ }
+
+ return p_status->err_code;
+}
+
+inline void i2c_handle_sda_irq(int port)
+{
+ volatile struct i2c_status *p_status = i2c_stsobjs + port;
+ /* 1 Issue Start is successful ie. write address byte */
+ if (p_status->oper_state == SMB_MASTER_START
+ || p_status->oper_state == SMB_REPEAT_START) {
+ uint8_t addr = p_status->slave_addr;
+ /* Prepare address byte */
+ if (p_status->sz_txbuf == 0) {/* Receive mode */
+ p_status->oper_state = SMB_READ_OPER;
+ /*
+ * Receiving one byte only - set nack just
+ * before writing address byte
+ */
+ if (p_status->sz_rxbuf == 1)
+ I2C_NACK(port);
+
+ /* Write the address to the bus R bit*/
+ I2C_WRITE_BYTE(port, (addr | 0x1));
+ CPUTS("-ARR");
+ } else {/* Transmit mode */
+ p_status->oper_state = SMB_WRITE_OPER;
+ /* Write the address to the bus W bit*/
+ I2C_WRITE_BYTE(port, addr);
+ CPUTS("-ARW");
+ }
+ /* Completed handling START condition */
+ return;
+ }
+ /* 2 Handle master write operation */
+ else if (p_status->oper_state == SMB_WRITE_OPER) {
+ /* all bytes have been written, in a pure write operation */
+ if (p_status->idx_buf == p_status->sz_txbuf) {
+ /* no more message */
+ if (p_status->sz_rxbuf == 0) {
+ /* need to STOP or not */
+ if (p_status->flags & I2C_XFER_STOP) {
+ /* Issue a STOP condition on the bus */
+ I2C_STOP(port);
+ CPUTS("-SP");
+ }
+ /* Clear SDA Status bit by writing dummy byte */
+ I2C_WRITE_BYTE(port, 0xFF);
+ /* Set error code */
+ p_status->err_code = SMB_OK;
+ /* Notify upper layer */
+ p_status->oper_state
+ = (p_status->flags & I2C_XFER_STOP)
+ ? SMB_IDLE : SMB_WAIT_REPEAT_START;
+ task_set_event(p_status->task_waiting,
+ TASK_EVENT_I2C_IDLE, 0);
+ CPUTS("-END");
+ }
+ /* need to restart & send slave address immediately */
+ else {
+ uint8_t addr_byte = p_status->slave_addr;
+ /*
+ * Prepare address byte
+ * and start to receive bytes
+ */
+ p_status->oper_state = SMB_READ_OPER;
+ /* Reset index of buffer */
+ p_status->idx_buf = 0;
+
+ /*
+ * Generate (Repeated) Start
+ * upon next write to SDA
+ */
+ I2C_START(port);
+ CPUTS("-RST");
+ /*
+ * Receiving one byte only - set nack just
+ * before writing address byte
+ */
+ if (p_status->sz_rxbuf == 1) {
+ I2C_NACK(port);
+ CPUTS("-GNA");
+ }
+ /* Write the address to the bus R bit*/
+ I2C_WRITE_BYTE(port, (addr_byte | 0x1));
+ CPUTS("-ARR");
+ }
+ }
+ /* write next byte (not last byte and not slave address */
+ else {
+ I2C_WRITE_BYTE(port,
+ p_status->tx_buf[p_status->idx_buf++]);
+ CPRINTS("-W(%02x)",
+ p_status->tx_buf[p_status->idx_buf-1]);
+ }
+ }
+ /* 3 Handle master read operation (read or after a write operation) */
+ else if (p_status->oper_state == SMB_READ_OPER) {
+ uint8_t data;
+ /* last byte is about to be read - end of transaction */
+ if (p_status->idx_buf == (p_status->sz_rxbuf - 1)) {
+ /* need to STOP or not */
+ if (p_status->flags & I2C_XFER_STOP) {
+ /* Stop should set before reading last byte */
+ I2C_STOP(port);
+ CPUTS("-SP");
+ }
+ }
+ /* Check if byte-before-last is about to be read */
+ else if (p_status->idx_buf == (p_status->sz_rxbuf - 2)) {
+ /*
+ * Set nack before reading byte-before-last,
+ * so that nack will be generated after receive
+ * of last byte
+ */
+ I2C_NACK(port);
+ CPUTS("-GNA");
+ }
+
+ /* Read data for SMBSDA */
+ I2C_READ_BYTE(port, data);
+ CPRINTS("-R(%02x)", data);
+ /* Read to buffer */
+ p_status->rx_buf[p_status->idx_buf++] = data;
+
+ /* last byte is read - end of transaction */
+ if (p_status->idx_buf == p_status->sz_rxbuf) {
+ /* Set error code */
+ p_status->err_code = SMB_OK;
+ /* Notify upper layer of missing data */
+ p_status->oper_state = (p_status->flags & I2C_XFER_STOP)
+ ? SMB_IDLE : SMB_WAIT_REPEAT_START;
+ task_set_event(p_status->task_waiting,
+ TASK_EVENT_I2C_IDLE, 0);
+ CPUTS("-END");
+ }
+ }
+}
+
+void i2c_master_int_handler (int port)
+{
+ volatile struct i2c_status *p_status = i2c_stsobjs + port;
+ /* Condition 1 : A Bus Error has been identified */
+ if (IS_BIT_SET(NPCX_SMBST(port), NPCX_SMBST_BER)) {
+ /* Clear BER Bit */
+ SET_BIT(NPCX_SMBST(port), NPCX_SMBST_BER);
+ /* Set error code */
+ p_status->err_code = SMB_BUS_ERROR;
+ /* Notify upper layer */
+ p_status->oper_state = SMB_IDLE;
+ task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0);
+ CPUTS("-BER");
+ }
+
+ /* Condition 2: A negative acknowledge has occurred */
+ if (IS_BIT_SET(NPCX_SMBST(port), NPCX_SMBST_NEGACK)) {
+ /* Clear NEGACK Bit */
+ SET_BIT(NPCX_SMBST(port), NPCX_SMBST_NEGACK);
+ /* Set error code */
+ p_status->err_code = SMB_MASTER_NO_ADDRESS_MATCH;
+ /* Notify upper layer */
+ p_status->oper_state = SMB_IDLE;
+ task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0);
+ CPUTS("-NA");
+ }
+
+ /* Condition 3: SDA status is set - transmit or receive */
+ if (IS_BIT_SET(NPCX_SMBST(port), NPCX_SMBST_SDAST))
+ i2c_handle_sda_irq(port);
+}
+
+/**
+ * Handle an interrupt on the specified port.
+ *
+ * @param port I2C port generating interrupt
+ */
+void handle_interrupt(int port)
+{
+ i2c_master_int_handler(port);
+}
+
+void i2c0_interrupt(void) { handle_interrupt(0); }
+void i2c1_interrupt(void) { handle_interrupt(1); }
+void i2c2_interrupt(void) { handle_interrupt(2); }
+void i2c3_interrupt(void) { handle_interrupt(3); }
+
+DECLARE_IRQ(NPCX_IRQ_SMB1, i2c0_interrupt, 2);
+DECLARE_IRQ(NPCX_IRQ_SMB2, i2c1_interrupt, 2);
+DECLARE_IRQ(NPCX_IRQ_SMB3, i2c2_interrupt, 2);
+DECLARE_IRQ(NPCX_IRQ_SMB4, i2c3_interrupt, 2);
+
+/*****************************************************************************/
+/* IC specific low-level driver */
+
+int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
+ uint8_t *in, int in_size, int flags)
+{
+ volatile struct i2c_status *p_status = i2c_stsobjs + port;
+
+ if (port < 0 || port >= i2c_ports_used)
+ return EC_ERROR_INVAL;
+
+ if (out_size == 0 && in_size == 0)
+ return EC_SUCCESS;
+
+ /* Copy data to port struct */
+ p_status->flags = flags;
+ p_status->tx_buf = out;
+ p_status->sz_txbuf = out_size;
+ p_status->rx_buf = in;
+ p_status->sz_rxbuf = in_size;
+#if I2C_7BITS_ADDR
+ /* Set slave address from 7-bits to 8-bits */
+ p_status->slave_addr = (slave_addr<<1);
+#else
+ /* Set slave address (8-bits) */
+ p_status->slave_addr = slave_addr;
+#endif
+ /* Reset index & error */
+ p_status->idx_buf = 0;
+ p_status->err_code = SMB_OK;
+
+
+ /* Make sure we're in a good state to start */
+ if ((flags & I2C_XFER_START) && (i2c_bus_busy(port)
+ || (i2c_get_line_levels(port) != I2C_LINE_IDLE))) {
+
+ /* Attempt to unwedge the port. */
+ i2c_unwedge(port);
+ /* recovery i2c port */
+ i2c_recovery(port);
+ }
+
+ /* Enable SMB interrupt and New Address Match interrupt source */
+ SET_BIT(NPCX_SMBCTL1(port), NPCX_SMBCTL1_NMINTE);
+ SET_BIT(NPCX_SMBCTL1(port), NPCX_SMBCTL1_INTEN);
+
+ CPUTS("\n");
+
+ /* Assign current task ID */
+ p_status->task_waiting = task_get_current();
+
+ /* Start master transaction */
+ i2c_master_transaction(port);
+
+ /* Reset task ID */
+ p_status->task_waiting = TASK_ID_INVALID;
+
+ /* Disable SMB interrupt and New Address Match interrupt source */
+ CLEAR_BIT(NPCX_SMBCTL1(port), NPCX_SMBCTL1_NMINTE);
+ CLEAR_BIT(NPCX_SMBCTL1(port), NPCX_SMBCTL1_INTEN);
+
+ CPRINTS("-Err:0x%02x\n", p_status->err_code);
+
+ return (p_status->err_code == SMB_OK) ? EC_SUCCESS : EC_ERROR_UNKNOWN;
+}
+
+/**
+ * Return raw I/O line levels (I2C_LINE_*) for a port when port is in alternate
+ * function mode.
+ *
+ * @param port Port to check
+ * @return State of SCL/SDA bit 0/1
+ */
+int i2c_get_line_levels(int port)
+{
+ return (i2c_raw_get_sda(port) ? I2C_LINE_SDA_HIGH : 0) |
+ (i2c_raw_get_scl(port) ? I2C_LINE_SCL_HIGH : 0);
+}
+
+int i2c_raw_get_scl(int port)
+{
+ enum gpio_signal g;
+
+ /* Check do we support this port of i2c and return gpio number of scl */
+ if (get_scl_from_i2c_port(port, &g) == EC_SUCCESS)
+#if !(I2C_LEVEL_SUPPORT)
+ return gpio_get_level(g);
+#else
+ return IS_BIT_SET(NPCX_SMBCTL3(port), NPCX_SMBCTL3_SCL_LVL);
+#endif
+
+ /* If no SCL pin defined for this port, then return 1 to appear idle */
+ return 1;
+}
+
+int i2c_raw_get_sda(int port)
+{
+ enum gpio_signal g;
+ /* Check do we support this port of i2c and return gpio number of scl */
+ if (get_sda_from_i2c_port(port, &g) == EC_SUCCESS)
+#if !(I2C_LEVEL_SUPPORT)
+ return gpio_get_level(g);
+#else
+ return IS_BIT_SET(NPCX_SMBCTL3(port), NPCX_SMBCTL3_SDA_LVL);
+#endif
+
+ /* If no SDA pin defined for this port, then return 1 to appear idle */
+ return 1;
+}
+
+int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data,
+ int len)
+{
+ int rv;
+ uint8_t reg, block_length;
+
+ /* Check block protocol size */
+ if ((len <= 0) || (len > 32))
+ return EC_ERROR_INVAL;
+
+ i2c_lock(port, 1);
+ reg = offset;
+
+ /*
+ * Send device reg space offset, and read back block length. Keep this
+ * session open without a stop.
+ */
+ rv = i2c_xfer(port, slave_addr, &reg, 1, &block_length, 1,
+ I2C_XFER_START);
+ if (rv)
+ goto exit;
+
+ if (len && block_length > (len - 1))
+ block_length = len - 1;
+
+ rv = i2c_xfer(port, slave_addr, 0, 0, data, block_length,
+ I2C_XFER_STOP);
+ data[block_length] = 0;
+
+exit:
+ i2c_lock(port, 0);
+
+ return rv;
+}
+
+/*****************************************************************************/
+/* Hooks */
+static void i2c_freq_changed(void)
+{
+ /* I2C is under APB2 */
+ int freq;
+ int port;
+
+ for (port = 0; port < i2c_ports_used; port++) {
+ int bus_freq = i2c_ports[port].kbps;
+ int scl_time;
+
+ /* SMB0/1 use core clock & SMB2/3 use apb2 clock */
+ if (port < 2)
+ freq = clock_get_freq();
+ else
+ freq = clock_get_apb2_freq();
+
+ /* use Fast Mode */
+ SET_BIT(NPCX_SMBCTL3(port) , NPCX_SMBCTL3_400K);
+
+ /*
+ * Set SCLLT/SCLHT:
+ * tSCLL = 2 * SCLLT7-0 * tCLK
+ * tSCLH = 2 * SCLHT7-0 * tCLK
+ * (tSCLL+tSCLH) = 4 * SCLH(L)T * tCLK if tSCLL == tSCLH
+ * SCLH(L)T = T(SCL)/4/T(CLK) = FREQ(CLK)/4/FREQ(SCL)
+ */
+ scl_time = (freq/1000) / (bus_freq * 4); /* bus_freq is KHz */
+
+ /* set SCL High/Low time */
+ NPCX_SMBSCLLT(port) = scl_time;
+ NPCX_SMBSCLHT(port) = scl_time;
+ }
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT);
+
+static void i2c_init(void)
+{
+ int port = 0;
+ /* Configure pins from GPIOs to I2Cs */
+ gpio_config_module(MODULE_I2C, 1);
+
+ /* Enable clock for I2C peripheral */
+ clock_enable_peripheral(CGC_OFFSET_I2C, CGC_I2C_MASK,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+ /*
+ * initialize smb status and register
+ */
+ for (port = 0; port < i2c_ports_used; port++) {
+ volatile struct i2c_status *p_status = i2c_stsobjs + port;
+ /* Configure pull-up for SMB interface pins */
+#ifndef SMB_SUPPORT18V
+ /* Enable 3.3V pull-up */
+ SET_BIT(NPCX_DEVPU0, port);
+#else
+ /* Set GPIO Pin voltage judgment to 1.8V */
+ SET_BIT(NPCX_LV_GPIO_CTL1, port+1);
+#endif
+
+ /* Enable module - before configuring CTL1 */
+ SET_BIT(NPCX_SMBCTL2(port), NPCX_SMBCTL2_ENABLE);
+
+ /* status init */
+ p_status->oper_state = SMB_IDLE;
+
+ /* Reset task ID */
+ p_status->task_waiting = TASK_ID_INVALID;
+
+ /* Enable event and error interrupts */
+ task_enable_irq(i2c_irqs[port]);
+ }
+}
+DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT);
diff --git a/chip/npcx/jtag.c b/chip/npcx/jtag.c
new file mode 100644
index 0000000000..05dda6fa78
--- /dev/null
+++ b/chip/npcx/jtag.c
@@ -0,0 +1,16 @@
+/* Copyright (c) 2014 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.
+ */
+
+#include "clock.h"
+#include "gpio.h"
+#include "jtag.h"
+#include "registers.h"
+#include "system.h"
+
+void jtag_pre_init(void)
+{
+ /* Enable automatic freeze mode */
+ CLEAR_BIT(NPCX_DBGFRZEN3, NPCX_DBGFRZEN3_GLBL_FRZ_DIS);
+}
diff --git a/chip/npcx/keyboard_raw.c b/chip/npcx/keyboard_raw.c
new file mode 100644
index 0000000000..e6599a35e2
--- /dev/null
+++ b/chip/npcx/keyboard_raw.c
@@ -0,0 +1,128 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* Functions needed by keyboard scanner module for Chrome EC */
+
+#include "common.h"
+#include "keyboard_raw.h"
+#include "keyboard_scan.h"
+#include "clock.h"
+#include "registers.h"
+#include "task.h"
+
+/**
+ * Initialize the raw keyboard interface.
+ */
+void keyboard_raw_init(void)
+{
+ /* Enable clock for KBS peripheral */
+ clock_enable_peripheral(CGC_OFFSET_KBS, CGC_KBS_MASK,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+
+ /* Ensure top-level interrupt is disabled */
+ keyboard_raw_enable_interrupt(0);
+
+ /* pull-up KBSIN 0-7 internally */
+ NPCX_KBSINPU = 0xFF;
+
+ /* Disable automatic scan mode */
+ CLEAR_BIT(NPCX_KBSCTL, NPCX_KBSMODE);
+
+ /* Disable automatic interrupt enable */
+ CLEAR_BIT(NPCX_KBSCTL, NPCX_KBSIEN);
+
+ /* Disable increment enable */
+ CLEAR_BIT(NPCX_KBSCTL, NPCX_KBSINC);
+
+ /* Set KBSOUT to zero to detect key-press */
+ NPCX_KBSOUT0 = 0x00;
+ NPCX_KBSOUT1 = 0x00;
+
+ /*
+ * Enable interrupts for the inputs. The top-level interrupt is still
+ * masked off, so this won't trigger interrupts yet.
+ */
+
+ /* Clear pending input sources used by scanner */
+ NPCX_WKPCL(MIWU_TABLE_WKKEY, MIWU_GROUP_WKKEY) = 0xFF;
+
+ /* Enable Wake-up Button */
+ NPCX_WKEN(MIWU_TABLE_WKKEY, MIWU_GROUP_WKKEY) = 0xFF;
+
+ /* Select high to low transition (falling edge) */
+ NPCX_WKEDG(MIWU_TABLE_WKKEY, MIWU_GROUP_WKKEY) = 0xFF;
+
+ /* Enable interrupt of WK KBS */
+ keyboard_raw_enable_interrupt(1);
+}
+
+/**
+ * Finish initialization after task scheduling has started.
+ */
+void keyboard_raw_task_start(void)
+{
+ /* Enable MIWU to trigger KBS interrupt */
+ task_enable_irq(NPCX_IRQ_KSI_WKINTC_1);
+}
+
+/**
+ * Drive the specified column low.
+ */
+test_mockable void keyboard_raw_drive_column(int col)
+{
+ /*
+ * Nuvoton Keyboard Scan IP supports 18x8 Matrix
+ * It also support automatic scan functionality
+ */
+ uint32_t mask;
+
+ /* Drive all lines to high */
+ if (col == KEYBOARD_COLUMN_NONE)
+ mask = KB_COL_MASK;
+ /* Set KBSOUT to zero to detect key-press */
+ else if (col == KEYBOARD_COLUMN_ALL)
+ mask = 0;
+ /* Drive one line for detection */
+ else
+ mask = ((~(1 << col)) & KB_COL_MASK);
+
+ /* Set KBSOUT */
+ NPCX_KBSOUT0 = (mask & 0xFFFF);
+ NPCX_KBSOUT1 = ((mask >> 16) & 0x03);
+}
+
+/**
+ * Read raw row state.
+ * Bits are 1 if signal is present, 0 if not present.
+ */
+test_mockable int keyboard_raw_read_rows(void)
+{
+ /* Bits are active-low, so invert returned levels */
+ return (~NPCX_KBSIN) & KB_ROW_MASK;
+}
+
+/**
+ * Enable or disable keyboard interrupts.
+ */
+void keyboard_raw_enable_interrupt(int enable)
+{
+ if (enable)
+ task_enable_irq(NPCX_IRQ_KSI_WKINTC_1);
+ else
+ task_disable_irq(NPCX_IRQ_KSI_WKINTC_1);
+}
+
+/*
+ * Interrupt handler for the entire GPIO bank of keyboard rows.
+ */
+void keyboard_raw_interrupt(void)
+{
+ /* Clear pending input sources used by scanner */
+ NPCX_WKPCL(MIWU_TABLE_WKKEY, MIWU_GROUP_WKKEY) = 0xFF;
+
+ /* Wake the scan task */
+ task_wake(TASK_ID_KEYSCAN);
+}
+DECLARE_IRQ(NPCX_IRQ_KSI_WKINTC_1, keyboard_raw_interrupt, 3);
diff --git a/chip/npcx/lfw/ec_lfw.c b/chip/npcx/lfw/ec_lfw.c
new file mode 100644
index 0000000000..9875681559
--- /dev/null
+++ b/chip/npcx/lfw/ec_lfw.c
@@ -0,0 +1,158 @@
+/* Copyright (c) 2014 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.
+ *
+ * NPCX5M5G SoC little FW used by booter
+ */
+
+#include <stdint.h>
+#include "registers.h"
+#include "config_chip.h"
+#include "ec_lfw.h"
+
+/* size of little FW */
+#define LFW_SIZE 0x1000
+/* signature used by booter */
+#define SIG_GOOGLE_EC 0x55AA650E
+/* little FW located on TOP of Flash - 4K */
+#define FW_ADDR (CONFIG_SPI_FLASH_SIZE - 0x1000)
+
+/* Header used by NPCX5M5G Booter */
+struct booter_header_t {
+ uint32_t signature; /* A constant used to verify FW pointer is valid */
+ uint32_t pointer_fw;/* Holds the BootLoader location in the flash */
+};
+
+__attribute__ ((section(".booter_pointer")))
+const struct booter_header_t booter_header = {
+ /* 00 */ SIG_GOOGLE_EC,
+ /* 04 */ FW_ADDR
+};
+
+
+/* Original sp during sysjump */
+uint32_t org_sp;
+
+/*****************************************************************************/
+/* flash internal functions */
+
+void __attribute__ ((section(".instrucion_ram")))
+flash_burst_copy_fw_to_mram(uint32_t addr_flash, uint32_t addr_mram,
+ uint32_t size)
+{
+ uint32_t bit32_idx;
+ uint32_t bit32_size;
+ uint32_t *bit32_ptr_mram;
+
+ bit32_ptr_mram = (uint32_t *)addr_mram;
+
+ /* Round it up and get it in 4 bytes */
+ bit32_size = (size+3) / 4;
+
+ /* Set chip select to low */
+ CLEAR_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1);
+
+ /* Write flash address */
+ NPCX_UMA_AB2 = (uint8_t)((addr_flash & 0xFF0000)>>16);
+ NPCX_UMA_AB1 = (uint8_t)((addr_flash & 0xFF00)>>8);
+ NPCX_UMA_AB0 = (uint8_t)((addr_flash & 0xFF));
+
+ NPCX_UMA_CODE = CMD_FAST_READ;
+ NPCX_UMA_CTS = MASK_CMD_ADR_WR;
+ /* wait for UMA to complete */
+ while (IS_BIT_SET(NPCX_UMA_CTS, EXEC_DONE))
+ ;
+
+ /* Start to burst read and copy data to Code RAM */
+ for (bit32_idx = 0; bit32_idx < bit32_size; bit32_idx++) {
+ /* 1101 0100 - EXEC, RD, NO CMD, NO ADDR, 4 bytes */
+ NPCX_UMA_CTS = MASK_RD_4BYTE;
+ while (IS_BIT_SET(NPCX_UMA_CTS, EXEC_DONE))
+ ;
+ /* copy data to Code RAM */
+ bit32_ptr_mram[bit32_idx] = NPCX_UMA_DB0_3;
+ }
+
+ /* Set chip select to high */
+ SET_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1);
+}
+
+void __attribute__ ((section(".instrucion_ram")))
+bin2ram(void)
+{
+ /* copy image from RO base */
+ if (IS_BIT_SET(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION))
+ flash_burst_copy_fw_to_mram(CONFIG_FW_RO_OFF, CONFIG_CDRAM_BASE,
+ CONFIG_FW_RO_SIZE - LFW_SIZE);
+ /* copy image from RW base */
+ else
+ flash_burst_copy_fw_to_mram(CONFIG_FW_RW_OFF, CONFIG_CDRAM_BASE,
+ CONFIG_FW_RW_SIZE - LFW_SIZE);
+
+ /* Disable FIU pins to tri-state */
+ CLEAR_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS);
+
+ /* TODO: (ML) Booter has cleared watchdog flag */
+#ifndef CHIP_NPCX5M5G
+ static uint32_t reset_flag;
+ /* Check for VCC1 reset */
+ if (IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_STS)) {
+ /* Clear flag bit */
+ SET_BIT(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_STS);
+ reset_flag = 1;
+ }
+ /* Software debugger reset */
+ else if (IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_DBGRST_STS))
+ reset_flag = 1;
+ /* Watchdog Reset */
+ else if (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS)) {
+ reset_flag = 1;
+ } else {
+ reset_flag = 0;
+ }
+
+ if (reset_flag) {
+#else
+ /* Workaround method to distinguish reboot or sysjump */
+ if (org_sp < 0x200C0000) {
+#endif
+ /* restore sp from begin of RO image */
+ asm volatile("ldr r0, =0x10088000\n"
+ "ldr r1, [r0]\n"
+ "mov sp, r1\n");
+ } else {
+ /* restore sp from sysjump */
+ asm volatile("mov sp, %0" : : "r"(org_sp));
+ }
+
+ /* Jump to reset ISR */
+ asm volatile(
+ "ldr r0, =0x10088004\n"
+ "ldr r1, [r0]\n"
+ "mov pc, r1\n");
+}
+
+/* Entry function of little FW */
+void __attribute__ ((section(".startup_text"), noreturn))
+entry_lfw(void)
+{
+ uint32_t i;
+
+ /* Backup sp value */
+ asm volatile("mov %0, sp" : "=r"(org_sp));
+ /* initialize sp with Data RAM */
+ asm volatile(
+ "ldr r0, =0x100A8000\n"
+ "mov sp, r0\n");
+
+ /* Copy the bin2ram code to RAM */
+ for (i = 0; i < &__iram_fw_end - &__iram_fw_start; i++)
+ *(&__iram_fw_start + i) = *(&__flash_fw_start + i);
+
+ /* Run code in RAM */
+ bin2ram();
+
+ /* Should never reach this */
+ for (;;)
+ ;
+}
diff --git a/chip/npcx/lfw/ec_lfw.h b/chip/npcx/lfw/ec_lfw.h
new file mode 100644
index 0000000000..857135d6d0
--- /dev/null
+++ b/chip/npcx/lfw/ec_lfw.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2014 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.
+ *
+ * NPCX5M5G SoC little FW used by booter
+ */
+
+#ifndef __CROS_EC_LFW_H_
+#define __CROS_EC_LFW_H_
+
+/* Begin address for the .iram section; defined in linker script */
+extern unsigned int __iram_fw_start;
+/* End address for the .iram section; defined in linker script */
+extern unsigned int __iram_fw_end;
+/* Begin address for the iram codes; defined in linker script */
+extern unsigned int __flash_fw_start;
+
+#endif /* __CROS_EC_LFW_H_ */
diff --git a/chip/npcx/lfw/ec_lfw.ld b/chip/npcx/lfw/ec_lfw.ld
new file mode 100644
index 0000000000..dd93bba89e
--- /dev/null
+++ b/chip/npcx/lfw/ec_lfw.ld
@@ -0,0 +1,122 @@
+/* Copyright (c) 2014 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.
+ *
+ * NPCX5M5G SoC little FW for booting
+ */
+
+/* Memory Spaces Definitions */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x647FF000, LENGTH = 4K - 256
+ POINTER(r) : ORIGIN = 0x647FFF00, LENGTH = 256
+ CODERAM(rx): ORIGIN = 0x100A7C00, LENGTH = 1K - 256
+ RAM (xrw) : ORIGIN = 0x100A7F00, LENGTH = 256
+}
+
+/*
+ * The entry point is informative, for debuggers and simulators,
+ * since the Cortex-M vector points to it anyway.
+ */
+ENTRY(entry_lfw)
+
+/* Sections Definitions */
+
+SECTIONS
+{
+
+ /*
+ * The beginning of the startup code
+ */
+ .startup_text :
+ {
+ . = ALIGN(4);
+ *(.startup_text ) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+
+ /*
+ * The program code is stored in the .text section,
+ * which goes to FLASH.
+ */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text .text.*) /* all remaining code */
+ *(.rodata .rodata.*) /* read-only data (constants) */
+ } >FLASH
+
+ . = ALIGN(4);
+
+ __flash_fw_start = .;
+ .instrucion_ram : AT(__flash_fw_start)
+ {
+ . = ALIGN(4);
+ __iram_fw_start = .;
+ *(.instrucion_ram .instrucion_ram.*) /* CODERAM in 0x200C0000 */
+ __iram_fw_end = .;
+ } > CODERAM
+
+ /*
+ * The POINTER section used for booter
+ */
+ .booter_pointer :
+ {
+ . = ALIGN(4);
+ KEEP(*(.booter_pointer)) /* Booter pointer in 0xFFFF00 */
+ } > POINTER
+
+ . = ALIGN(4);
+ _etext = .;
+
+ /*
+ * This address is used by the startup code to
+ * initialise the .data section.
+ */
+ _sidata = _etext;
+
+ /*
+ * The initialised data section.
+ * The program executes knowing that the data is in the RAM
+ * but the loader puts the initial values in the FLASH (inidata).
+ * It is one task of the startup to copy the initial values from
+ * FLASH to RAM.
+ */
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+
+ /* This is used by the startup code to initialise the .data section */
+ __data_start__ = . ;
+ *(.data_begin .data_begin.*)
+
+ *(.data .data.*)
+
+ *(.data_end .data_end.*)
+ . = ALIGN(4);
+
+ /* This is used by the startup code to initialise the .data section */
+ __data_end__ = . ;
+
+ } > RAM
+
+
+ /*
+ * The uninitialised data section. NOLOAD is used to avoid
+ * the "section `.bss' type changed to PROGBITS" warning
+ */
+ .bss (NOLOAD) :
+ {
+ . = ALIGN(4);
+ __bss_start__ = .; /* standard newlib definition */
+ *(.bss_begin .bss_begin.*)
+
+ *(.bss .bss.*)
+ *(COMMON)
+
+ *(.bss_end .bss_end.*)
+ . = ALIGN(4);
+ __bss_end__ = .; /* standard newlib definition */
+ } >RAM
+} \ No newline at end of file
diff --git a/chip/npcx/lpc.c b/chip/npcx/lpc.c
new file mode 100644
index 0000000000..55d76f46d0
--- /dev/null
+++ b/chip/npcx/lpc.c
@@ -0,0 +1,672 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* LPC module for Chrome EC */
+
+#include "acpi.h"
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "keyboard_protocol.h"
+#include "lpc.h"
+#include "port80.h"
+#include "pwm.h"
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "timer.h"
+#include "uart.h"
+#include "util.h"
+#include "system_chip.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_LPC, outstr)
+#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
+
+#define LPC_SYSJUMP_TAG 0x4c50 /* "LP" */
+
+static uint32_t host_events; /* Currently pending SCI/SMI events */
+static uint32_t event_mask[3]; /* Event masks for each type */
+static struct host_packet lpc_packet;
+static struct host_cmd_handler_args host_cmd_args;
+static uint8_t host_cmd_flags; /* Flags from host command */
+static uint8_t shm_mem_host_cmd[256] __aligned(8);
+static uint8_t shm_memmap[256] __aligned(8);
+/* Params must be 32-bit aligned */
+static uint8_t params_copy[EC_LPC_HOST_PACKET_SIZE] __aligned(4);
+static int init_done;
+
+static uint8_t * const cmd_params = (uint8_t *)shm_mem_host_cmd +
+ EC_LPC_ADDR_HOST_PARAM - EC_LPC_ADDR_HOST_ARGS;
+static struct ec_lpc_host_args * const lpc_host_args =
+ (struct ec_lpc_host_args *)shm_mem_host_cmd;
+
+
+#ifdef CONFIG_KEYBOARD_IRQ_GPIO
+static void keyboard_irq_assert(void)
+{
+ /*
+ * Enforce signal-high for long enough for the signal to be pulled high
+ * by the external pullup resistor. This ensures the host will see the
+ * following falling edge, regardless of the line state before this
+ * function call.
+ */
+ gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1);
+ udelay(4);
+ /* Generate a falling edge */
+ gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 0);
+ udelay(4);
+ /* Set signal high, now that we've generated the edge */
+ gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1);
+}
+#else
+static inline void keyboard_irq_assert(void)
+{
+ /* Use serirq method. */
+ /* Using manual IRQ for KBC */
+ SET_BIT(NPCX_HIIRQC, 0); /* set IRQ1B to high */
+ CLEAR_BIT(NPCX_HICTRL, 0); /* set IRQ1 control by IRQB1 */
+}
+#endif
+
+static void lpc_task_enable_irq(void){
+
+ task_enable_irq(NPCX_IRQ_SHM);
+ task_enable_irq(NPCX_IRQ_KBC_IBF);
+ task_enable_irq(NPCX_IRQ_PM_CHAN_IBF);
+ task_enable_irq(NPCX_IRQ_PORT80);
+}
+static void lpc_task_disable_irq(void){
+
+ task_disable_irq(NPCX_IRQ_SHM);
+ task_disable_irq(NPCX_IRQ_KBC_IBF);
+ task_disable_irq(NPCX_IRQ_PM_CHAN_IBF);
+ task_disable_irq(NPCX_IRQ_PORT80);
+}
+/**
+ * Generate SMI pulse to the host chipset via GPIO.
+ *
+ * If the x86 is in S0, SMI# is sampled at 33MHz, so minimum pulse length is
+ * 60ns. If the x86 is in S3, SMI# is sampled at 32.768KHz, so we need pulse
+ * length >61us. Both are short enough and events are infrequent, so just
+ * delay for 65us.
+ */
+static void lpc_generate_smi(void)
+{
+#ifdef CONFIG_SCI_GPIO
+ /* Enforce signal-high for long enough to debounce high */
+ gpio_set_level(GPIO_PCH_SMI_L, 1);
+ udelay(65);
+ /* Generate a falling edge */
+ gpio_set_level(GPIO_PCH_SMI_L, 0);
+ udelay(65);
+ /* Set signal high, now that we've generated the edge */
+ gpio_set_level(GPIO_PCH_SMI_L, 1);
+#else
+ NPCX_HIPMIE(PM_CHAN_1) |= NPCX_HIPMIE_SMIE;
+#endif
+ if (host_events & event_mask[LPC_HOST_EVENT_SMI])
+ CPRINTS("smi 0x%08x",
+ host_events & event_mask[LPC_HOST_EVENT_SMI]);
+}
+
+/**
+ * Generate SCI pulse to the host chipset via LPC0SCI.
+ */
+static void lpc_generate_sci(void)
+{
+#ifdef CONFIG_SCI_GPIO
+ /* Enforce signal-high for long enough to debounce high */
+ gpio_set_level(CONFIG_SCI_GPIO, 1);
+ udelay(65);
+ /* Generate a falling edge */
+ gpio_set_level(CONFIG_SCI_GPIO, 0);
+ udelay(65);
+ /* Set signal high, now that we've generated the edge */
+ gpio_set_level(CONFIG_SCI_GPIO, 1);
+#else
+ SET_BIT(NPCX_HIPMIE(PM_CHAN_1), NPCX_HIPMIE_SCIE);
+#endif
+
+ if (host_events & event_mask[LPC_HOST_EVENT_SCI])
+ CPRINTS("sci 0x%08x",
+ host_events & event_mask[LPC_HOST_EVENT_SCI]);
+}
+
+/**
+ * Update the level-sensitive wake signal to the AP.
+ *
+ * @param wake_events Currently asserted wake events
+ */
+static void lpc_update_wake(uint32_t wake_events)
+{
+ /*
+ * Mask off power button event, since the AP gets that through a
+ * separate dedicated GPIO.
+ */
+ wake_events &= ~EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON);
+
+ /* Signal is asserted low when wake events is non-zero */
+ gpio_set_level(GPIO_PCH_WAKE_L, !wake_events);
+}
+
+uint8_t *lpc_get_memmap_range(void)
+{
+ return (uint8_t *)shm_memmap;
+}
+
+static void lpc_send_response(struct host_cmd_handler_args *args)
+{
+ uint8_t *out;
+ int size = args->response_size;
+ int csum;
+ int i;
+
+ /* Ignore in-progress on LPC since interface is synchronous anyway */
+ if (args->result == EC_RES_IN_PROGRESS)
+ return;
+
+ /* Handle negative size */
+ if (size < 0) {
+ args->result = EC_RES_INVALID_RESPONSE;
+ size = 0;
+ }
+
+ /* New-style response */
+ lpc_host_args->flags =
+ (host_cmd_flags & ~EC_HOST_ARGS_FLAG_FROM_HOST) |
+ EC_HOST_ARGS_FLAG_TO_HOST;
+
+ lpc_host_args->data_size = size;
+
+ csum = args->command + lpc_host_args->flags +
+ lpc_host_args->command_version +
+ lpc_host_args->data_size;
+
+ for (i = 0, out = (uint8_t *)args->response; i < size; i++, out++)
+ csum += *out;
+
+ lpc_host_args->checksum = (uint8_t)csum;
+
+ /* Fail if response doesn't fit in the param buffer */
+ if (size > EC_PROTO2_MAX_PARAM_SIZE)
+ args->result = EC_RES_INVALID_RESPONSE;
+
+ /* Write result to the data byte. This sets the TOH status bit. */
+ NPCX_HIPMDO(PM_CHAN_2) = args->result;
+ /* Clear processing flag */
+ CLEAR_BIT(NPCX_HIPMST(PM_CHAN_2), 2);
+}
+
+static void lpc_send_response_packet(struct host_packet *pkt)
+{
+ /* Ignore in-progress on LPC since interface is synchronous anyway */
+ if (pkt->driver_result == EC_RES_IN_PROGRESS)
+ return;
+
+ /* Write result to the data byte. This sets the TOH status bit. */
+ NPCX_HIPMDO(PM_CHAN_2) = pkt->driver_result;
+ /* Clear processing flag */
+ CLEAR_BIT(NPCX_HIPMST(PM_CHAN_2), 2);
+}
+
+int lpc_keyboard_has_char(void)
+{
+ /* if OBF '1', that mean still have a data in the FIFO */
+ return (NPCX_HIKMST&0x01) ? 1 : 0;
+}
+
+/* Return true if the FRMH is set */
+int lpc_keyboard_input_pending(void)
+{
+ return (NPCX_HIKMST&0x02) ? 1 : 0;
+}
+
+/* Put a char to host buffer and send IRQ if specified. */
+void lpc_keyboard_put_char(uint8_t chr, int send_irq)
+{
+ UPDATE_BIT(NPCX_HICTRL, NPCX_HICTRL_OBFKIE, send_irq);
+ NPCX_HIKDO = chr;
+ task_enable_irq(NPCX_IRQ_KBC_OBF);
+}
+
+void lpc_keyboard_clear_buffer(void)
+{
+ /* Make sure the previous TOH and IRQ has been sent out. */
+ udelay(4);
+ /*FW_OBF write 1*/
+ NPCX_HICTRL |= 0x80;
+ /* Ensure there is no TOH set in this period. */
+ udelay(4);
+}
+
+void lpc_keyboard_resume_irq(void)
+{
+ if (lpc_keyboard_has_char())
+ keyboard_irq_assert();
+}
+
+/**
+ * Update the host event status.
+ *
+ * Sends a pulse if masked event status becomes non-zero:
+ * - SMI pulse via EC_SMI_L GPIO
+ * - SCI pulse via LPC0SCI
+ */
+static void update_host_event_status(void)
+{
+ int need_sci = 0;
+ int need_smi = 0;
+
+ if (!init_done)
+ return;
+
+ /* Disable LPC interrupt while updating status register */
+ lpc_task_disable_irq();
+ if (host_events & event_mask[LPC_HOST_EVENT_SMI]) {
+ /* Only generate SMI for first event */
+ if (!(NPCX_HIPMIE(PM_CHAN_1) & NPCX_HIPMIE_SMIE))
+ need_smi = 1;
+ SET_BIT(NPCX_HIPMIE(PM_CHAN_1), NPCX_HIPMIE_SMIE);
+ } else
+ CLEAR_BIT(NPCX_HIPMIE(PM_CHAN_1), NPCX_HIPMIE_SMIE);
+
+ if (host_events & event_mask[LPC_HOST_EVENT_SCI]) {
+ /* Generate SCI for every event */
+ need_sci = 1;
+ SET_BIT(NPCX_HIPMIE(PM_CHAN_1), NPCX_HIPMIE_SCIE);
+ } else
+ CLEAR_BIT(NPCX_HIPMIE(PM_CHAN_1), NPCX_HIPMIE_SCIE);
+
+ /* Copy host events to mapped memory */
+ *(uint32_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS) = host_events;
+
+ lpc_task_enable_irq();
+
+ /* Process the wake events. */
+ lpc_update_wake(host_events & event_mask[LPC_HOST_EVENT_WAKE]);
+
+ /* Send pulse on SMI signal if needed */
+ if (need_smi)
+ lpc_generate_smi();
+
+ /* ACPI 5.0-12.6.1: Generate SCI for SCI_EVT=1. */
+ if (need_sci)
+ lpc_generate_sci();
+}
+
+void lpc_set_host_event_state(uint32_t mask)
+{
+ if (mask != host_events) {
+ host_events = mask;
+ update_host_event_status();
+ }
+}
+
+int lpc_query_host_event_state(void)
+{
+ const uint32_t any_mask = event_mask[0] | event_mask[1] | event_mask[2];
+ int evt_index = 0;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ const uint32_t e = (1 << i);
+
+ if (host_events & e) {
+ host_clear_events(e);
+
+ /*
+ * If host hasn't unmasked this event, drop it. We do
+ * this at query time rather than event generation time
+ * so that the host has a chance to unmask events
+ * before they're dropped by a query.
+ */
+ if (!(e & any_mask))
+ continue;
+
+ evt_index = i + 1; /* Events are 1-based */
+ break;
+ }
+ }
+
+ return evt_index;
+}
+
+void lpc_set_host_event_mask(enum lpc_host_event_type type, uint32_t mask)
+{
+ event_mask[type] = mask;
+ update_host_event_status();
+}
+
+uint32_t lpc_get_host_event_mask(enum lpc_host_event_type type)
+{
+ return event_mask[type];
+}
+
+int lpc_get_pltrst_asserted(void)
+{
+ /* TODO: (Simon) need to define GPIO_PLTRST */
+ return 0;
+}
+
+/**
+ * Handle write to ACPI I/O port
+ *
+ * @param is_cmd Is write command (is_cmd=1) or data (is_cmd=0)
+ */
+static void handle_acpi_write(int is_cmd)
+{
+ uint8_t value, result;
+
+ /* Read command/data; this clears the FRMH status bit. */
+ value = NPCX_HIPMDI(PM_CHAN_1);
+
+ /* Handle whatever this was. */
+ if (acpi_ap_to_ec(is_cmd, value, &result))
+ NPCX_HIPMDO(PM_CHAN_1) = result;
+
+ /*
+ * ACPI 5.0-12.6.1: Generate SCI for Input Buffer Empty / Output Buffer
+ * Full condition on the kernel channel.
+ */
+ lpc_generate_sci();
+}
+
+/**
+ * Handle write to host command I/O ports.
+ *
+ * @param is_cmd Is write command (1) or data (0)?
+ */
+static void handle_host_write(int is_cmd)
+{
+ /*
+ * Read the command byte. This clears the FRMH bit in
+ * the status byte.
+ */
+ host_cmd_args.command = NPCX_HIPMDI(PM_CHAN_2);
+
+ host_cmd_args.result = EC_RES_SUCCESS;
+ host_cmd_args.send_response = lpc_send_response;
+ host_cmd_flags = lpc_host_args->flags;
+
+ /* See if we have an old or new style command */
+ if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
+ lpc_packet.send_response = lpc_send_response_packet;
+
+ lpc_packet.request = (const void *)shm_mem_host_cmd;
+ lpc_packet.request_temp = params_copy;
+ lpc_packet.request_max = sizeof(params_copy);
+ /* Don't know the request size so pass in the entire buffer */
+ lpc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;
+
+ lpc_packet.response = (void *)shm_mem_host_cmd;
+ lpc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
+ lpc_packet.response_size = 0;
+
+ lpc_packet.driver_result = EC_RES_SUCCESS;
+ /* Set processing flag */
+ SET_BIT(NPCX_HIPMST(PM_CHAN_2), 2);
+ host_packet_receive(&lpc_packet);
+ return;
+
+ } else if (host_cmd_flags & EC_HOST_ARGS_FLAG_FROM_HOST) {
+ /* Version 2 (link) style command */
+ int size = lpc_host_args->data_size;
+ int csum, i;
+
+ host_cmd_args.version = lpc_host_args->command_version;
+ host_cmd_args.params = params_copy;
+ host_cmd_args.params_size = size;
+ host_cmd_args.response = cmd_params;
+ host_cmd_args.response_max = EC_PROTO2_MAX_PARAM_SIZE;
+ host_cmd_args.response_size = 0;
+
+ /* Verify params size */
+ if (size > EC_PROTO2_MAX_PARAM_SIZE) {
+ host_cmd_args.result = EC_RES_INVALID_PARAM;
+ } else {
+ const uint8_t *src = cmd_params;
+ uint8_t *copy = params_copy;
+
+ /*
+ * Verify checksum and copy params out of LPC space.
+ * This ensures the data acted on by the host command
+ * handler can't be changed by host writes after the
+ * checksum is verified.
+ */
+ csum = host_cmd_args.command +
+ host_cmd_flags +
+ host_cmd_args.version +
+ host_cmd_args.params_size;
+
+ for (i = 0; i < size; i++) {
+ csum += *src;
+ *(copy++) = *(src++);
+ }
+
+ if ((uint8_t)csum != lpc_host_args->checksum)
+ host_cmd_args.result = EC_RES_INVALID_CHECKSUM;
+ }
+ } else {
+ /* Old style command, now unsupported */
+ host_cmd_args.result = EC_RES_INVALID_COMMAND;
+ }
+
+ /* Hand off to host command handler */
+ host_command_received(&host_cmd_args);
+}
+
+
+void lpc_shm_interrupt(void){
+}
+DECLARE_IRQ(NPCX_IRQ_SHM, lpc_shm_interrupt, 2);
+
+void lpc_kbc_ibf_interrupt(void)
+{
+#ifdef CONFIG_KEYBOARD_PROTOCOL_8042
+ /* If "command" input 0, else 1*/
+ keyboard_host_write(NPCX_HIKMDI, (NPCX_HIKMST & 0x08) ? 1 : 0);
+#endif
+}
+DECLARE_IRQ(NPCX_IRQ_KBC_IBF, lpc_kbc_ibf_interrupt, 2);
+
+void lpc_kbc_obf_interrupt(void){
+ /* reserve for future handle */
+ if (!IS_BIT_SET(NPCX_HICTRL, 0)) {
+ SET_BIT(NPCX_HICTRL, 0); /* back to H/W control of IRQ1 */
+ CLEAR_BIT(NPCX_HIIRQC, 0); /* back to default of IRQB1 */
+ }
+ task_disable_irq(NPCX_IRQ_KBC_OBF);
+}
+DECLARE_IRQ(NPCX_IRQ_KBC_OBF, lpc_kbc_obf_interrupt, 2);
+
+void lpc_pmc_ibf_interrupt(void){
+ /* Channel-1 for ACPI usage*/
+ /* Channel-2 for Host Command usage , so the argument data had been
+ * put on the share memory firstly*/
+ if (NPCX_HIPMST(PM_CHAN_1) & 0x02)
+ handle_acpi_write((NPCX_HIPMST(PM_CHAN_1)&0x08) ? 1 : 0);
+ else if (NPCX_HIPMST(PM_CHAN_2)&0x02)
+ handle_host_write((NPCX_HIPMST(PM_CHAN_2)&0x08) ? 1 : 0);
+}
+DECLARE_IRQ(NPCX_IRQ_PM_CHAN_IBF, lpc_pmc_ibf_interrupt, 2);
+
+void lpc_pmc_obf_interrupt(void){
+}
+DECLARE_IRQ(NPCX_IRQ_PM_CHAN_OBF, lpc_pmc_obf_interrupt, 2);
+
+void lpc_port80_interrupt(void){
+ port_80_write((NPCX_GLUE_SDPD0<<0) | (NPCX_GLUE_SDPD1<<8));
+ /* No matter what , just clear error status bit */
+ SET_BIT(NPCX_DP80STS, 7);
+ SET_BIT(NPCX_DP80STS, 5);
+}
+DECLARE_IRQ(NPCX_IRQ_PORT80, lpc_port80_interrupt, 2);
+
+/**
+ * Preserve event masks across a sysjump.
+ */
+static void lpc_sysjump(void)
+{
+ system_add_jump_tag(LPC_SYSJUMP_TAG, 1,
+ sizeof(event_mask), event_mask);
+}
+DECLARE_HOOK(HOOK_SYSJUMP, lpc_sysjump, HOOK_PRIO_DEFAULT);
+
+/**
+ * Restore event masks after a sysjump.
+ */
+static void lpc_post_sysjump(void)
+{
+ const uint32_t *prev_mask;
+ int size, version;
+
+ prev_mask = (const uint32_t *)system_get_jump_tag(LPC_SYSJUMP_TAG,
+ &version, &size);
+ if (!prev_mask || version != 1 || size != sizeof(event_mask))
+ return;
+
+ memcpy(event_mask, prev_mask, sizeof(event_mask));
+}
+
+static void lpc_init(void)
+{
+ /* Enable clock for LPC peripheral */
+ clock_enable_peripheral(CGC_OFFSET_LPC, CGC_LPC_MASK,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+ /* Switching to LPC interface */
+ NPCX_DEVCNT |= 0x04;
+ /* Enable 4E/4F */
+ if (!IS_BIT_SET(NPCX_MSWCTL1, 3)) {
+ NPCX_HCBAL = 0x4E;
+ NPCX_HCBAH = 0x0;
+ }
+ /* Clear Host Access Hold state */
+ NPCX_SMC_CTL = 0xC0;
+
+ /* Initialize Hardware for UART Host */
+#if CONFIG_UART_HOST
+ /* Init COMx LPC UART */
+ /* FMCLK have to using 50MHz */
+ NPCX_DEVALT(0xB) = 0xFF;
+ /* Make sure Host Access unlock */
+ CLEAR_BIT(NPCX_LKSIOHA, 2);
+ /* Clear Host Access Lock Violation */
+ SET_BIT(NPCX_SIOLV, 2);
+#endif
+
+ /* Don't stall SHM transactions */
+ NPCX_SHM_CTL = NPCX_SHM_CTL & ~0x40;
+ /* Semaphore and Indirect access disable */
+ NPCX_SHCFG = 0xE0;
+ /* Disable Protect Win1&2*/
+ NPCX_WIN_WR_PROT(0) = 0;
+ NPCX_WIN_WR_PROT(1) = 0;
+ NPCX_WIN_RD_PROT(0) = 0;
+ NPCX_WIN_RD_PROT(1) = 0;
+ /* Open Win1 256 byte for Host CMD, Win2 256 for MEMMAP*/
+ NPCX_WIN_SIZE = 0x88;
+ NPCX_WIN_BASE(0) = (uint32_t)shm_mem_host_cmd;
+ NPCX_WIN_BASE(1) = (uint32_t)shm_memmap;
+
+ /* Turn on PMC2 for Host Command usage */
+ SET_BIT(NPCX_HIPMCTL(PM_CHAN_2), 0);
+ SET_BIT(NPCX_HIPMCTL(PM_CHAN_2), 1);
+ /* enable PMC2 IRQ */
+ SET_BIT(NPCX_HIPMIE(PM_CHAN_2), 0);
+ /* IRQ control from HW */
+ SET_BIT(NPCX_HIPMIE(PM_CHAN_2), 3);
+ /*
+ * Set required control value (avoid setting HOSTWAIT bit at this stage)
+ */
+ NPCX_SMC_CTL = NPCX_SMC_CTL&~0x7F;
+ /* Clear status */
+ NPCX_SMC_STS = NPCX_SMC_STS;
+ /* Create mailbox */
+
+ /*
+ * Init KBC
+ * Clear OBF status, PM1 IBF/OBF INT enable, IRQ11 enable,
+ * IBF(K&M) INT enable, OBF(K&M) empty INT enable ,
+ * OBF Mouse Full INT enable and OBF KB Full INT enable
+ */
+ NPCX_HICTRL = 0xFF;
+ /* Normally Polarity IRQ1,12,11 type (level + high) setting */
+ NPCX_HIIRQC = 0x00; /* Make sure to default */
+
+ /*
+ * Init PORT80
+ * Enable Port80, Enable Port80 function & Interrupt & Read auto
+ */
+ NPCX_DP80CTL = 0x29;
+ SET_BIT(NPCX_GLUE_SDP_CTS, 3);
+ SET_BIT(NPCX_GLUE_SDP_CTS, 0);
+ /* Just turn on IRQE */
+ NPCX_HIPMIE(PM_CHAN_1) = 0x01;
+ lpc_task_enable_irq();
+
+ /* Initialize host args and memory map to all zero */
+ memset(lpc_host_args, 0, sizeof(*lpc_host_args));
+ memset(lpc_get_memmap_range(), 0, EC_MEMMAP_SIZE);
+
+ /* We support LPC args and version 3 protocol */
+ *(lpc_get_memmap_range() + EC_MEMMAP_HOST_CMD_FLAGS) =
+ EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED |
+ EC_HOST_CMD_FLAG_VERSION_3;
+
+
+
+ /* Restore event masks if needed */
+ lpc_post_sysjump();
+
+ /* Sufficiently initialized */
+ init_done = 1;
+
+ /* Update host events now that we can copy them to memmap */
+
+ update_host_event_status();
+
+ /* initial IO port address via SIB-write modules */
+ system_lpc_host_register_init();
+}
+/*
+ * Set prio to higher than default; this way LPC memory mapped data is ready
+ * before other inits try to initialize their memmap data.
+ */
+DECLARE_HOOK(HOOK_INIT, lpc_init, HOOK_PRIO_INIT_LPC);
+
+static void lpc_resume(void)
+{
+ /* Mask all host events until the host unmasks them itself. */
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, 0);
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SCI, 0);
+ lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, 0);
+
+ /* Store port 80 event so we know where resume happened */
+ port_80_write(PORT_80_EVENT_RESUME);
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, lpc_resume, HOOK_PRIO_DEFAULT);
+
+/* Get protocol information */
+static int lpc_get_protocol_info(struct host_cmd_handler_args *args)
+{
+ struct ec_response_get_protocol_info *r = args->response;
+
+ memset(r, 0, sizeof(*r));
+ r->protocol_versions = (1 << 2) | (1 << 3);
+ r->max_request_packet_size = EC_LPC_HOST_PACKET_SIZE;
+ r->max_response_packet_size = EC_LPC_HOST_PACKET_SIZE;
+ r->flags = 0;
+
+ args->response_size = sizeof(*r);
+
+ return EC_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO,
+ lpc_get_protocol_info,
+ EC_VER_MASK(0));
diff --git a/chip/npcx/openocd/jlink.cfg b/chip/npcx/openocd/jlink.cfg
new file mode 100644
index 0000000000..5294b733fd
--- /dev/null
+++ b/chip/npcx/openocd/jlink.cfg
@@ -0,0 +1,4 @@
+interface jlink
+
+source [find npcx.cfg]
+source [find npcx_cmds.tcl]
diff --git a/chip/npcx/openocd/npcx.cfg b/chip/npcx/openocd/npcx.cfg
new file mode 100644
index 0000000000..ccc53437bb
--- /dev/null
+++ b/chip/npcx/openocd/npcx.cfg
@@ -0,0 +1,63 @@
+# Copyright (c) 2014 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.
+#
+# nuvoton-m4 devices support both JTAG and SWD transports.
+#
+
+source [find target/swj-dp.tcl]
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME npcx5m5g
+}
+
+if { [info exists ENDIAN] } {
+ set _ENDIAN $ENDIAN
+} else {
+ set _ENDIAN little
+}
+
+# Work-area is a space in RAM used for flash programming
+# By default use 16kB
+if { [info exists WORKAREASIZE] } {
+ set _WORKAREASIZE $WORKAREASIZE
+} else {
+ set _WORKAREASIZE 0x8000
+}
+
+#jtag scan chain
+if { [info exists CPUTAPID ] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ set _CPUTAPID 0x4BA00477
+}
+
+#jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID
+swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position \
+ $_CHIPNAME.cpu -work-area-phys 0x200C0000 \
+ -work-area-size $_WORKAREASIZE
+
+# JTAG speed
+adapter_khz 1000
+
+adapter_nsrst_delay 100
+if {$using_jtag} {
+ jtag_ntrst_delay 100
+}
+
+# use srst to perform a system reset
+cortex_m reset_config srst
+
+#reset configuration
+reset_config trst_and_srst
+
+$_TARGETNAME configure -event reset-start {
+ echo "NPCX5M5G Reset..."
+ adapter_khz 1000
+ halt
+}
diff --git a/chip/npcx/openocd/npcx_cmds.tcl b/chip/npcx/openocd/npcx_cmds.tcl
new file mode 100644
index 0000000000..2d5a6c930e
--- /dev/null
+++ b/chip/npcx/openocd/npcx_cmds.tcl
@@ -0,0 +1,104 @@
+# Copyright (c) 2014 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.
+#
+# Command automation for NPCX5M5G chip
+
+# Program spi flash
+source [find mem_helper.tcl]
+
+proc flash_npcx {image_path image_offset image_size spifw_image} {
+ set UPLOAD_FLAG 0x200C4000;
+
+ # Upload program spi image FW to lower 16KB Data RAM
+ fast_load_image $spifw_image 0x200C0000
+ fast_load
+ # Clear whole 128KB Code RAM
+ mwb 0x10088000 0xFF 0x20000
+ # Upload binary image to Code RAM
+ fast_load_image $image_path 0x10088000
+ fast_load
+ # Set sp to upper 16KB Data RAM
+ reg sp 0x200C8000
+ # Set spi offset address of uploaded image
+ reg r0 $image_offset
+ # Set spi program size of uploaded image
+ reg r1 $image_size
+ # Clear upload flag
+ mww $UPLOAD_FLAG 0x0
+ # Start to program spi flash
+ resume 0x200C0001
+ echo "*** Program ... ***"
+ sleep 1
+ # Wait for any pending flash operations to complete
+ while {[expr [mrw $UPLOAD_FLAG] & 0x01] == 0} { sleep 1 }
+
+ # Halt CPU
+ halt
+
+ if {[expr [mrw $UPLOAD_FLAG] & 0x02] == 0} {
+ echo "*** Program Fail ***"
+ } else {
+ echo "*** Program Done ***"
+ }
+
+}
+
+proc flash_npcx_ro {image_offset} {
+ # 128 KB for RO& RW regions
+ set fw_size 0x20000
+ # images path
+ set outdir ../../../build/npcx_evb
+ set ro_image_path $outdir/ec.RO.flat
+ set spifw_image $outdir/chip/npcx/spiflashfw/ec_npcxflash.bin
+
+ # Halt CPU first
+ halt
+ echo "*** Start to program RO region ***"
+ # Write to lower 128kB from offset
+ flash_npcx $ro_image_path $image_offset $fw_size $spifw_image
+ echo "*** Finish program RO region ***"
+
+ # Reset CPU
+ reset
+}
+
+proc flash_npcx_evb {image_offset} {
+ # 128 KB for RO& RW regions
+ set fw_size 0x20000
+ # 4K little FW
+ set lfw_size 0x1000
+ # 8M spi-flash
+ set flash_size 0x800000
+
+ # images path
+ set outdir ../../../build/npcx_evb
+ set ro_image_path $outdir/ec.RO.flat
+ set rw_image_path $outdir/ec.RW.bin
+ set lfw_image_path $outdir/chip/npcx/lfw/ec_lfw.bin
+ set spifw_image $outdir/chip/npcx/spiflashfw/ec_npcxflash.bin
+
+ # images offset
+ set rw_image_offset [expr ($image_offset + $fw_size)]
+ set lfw_image_offset [expr ($flash_size - $lfw_size)]
+
+ # Halt CPU first
+ halt
+ echo "*** Start to program RO region ***"
+ # Write to lower 128kB from offset
+ flash_npcx $ro_image_path $image_offset $fw_size $spifw_image
+ echo "*** Finish program RO region ***"
+
+ echo "*** Start to program RW region ***"
+ # Write to upper 128kB from offset
+ flash_npcx $rw_image_path $rw_image_offset $fw_size $spifw_image
+ echo "*** Finish program RW region ***"
+
+ echo "*** Start to program LFW region ***"
+ # Write to top of flash minus 4KB
+ flash_npcx $lfw_image_path $lfw_image_offset $lfw_size $spifw_image
+ echo "*** Finish program LFW region ***"
+
+ # Reset CPU
+ reset
+}
diff --git a/chip/npcx/openocd/servo_v2.cfg b/chip/npcx/openocd/servo_v2.cfg
new file mode 100644
index 0000000000..578e3f9c43
--- /dev/null
+++ b/chip/npcx/openocd/servo_v2.cfg
@@ -0,0 +1,13 @@
+telnet_port 4444
+gdb_port 3333
+gdb_memory_map enable
+gdb_flash_program enable
+
+interface ftdi
+ftdi_vid_pid 0x18d1 0x5002
+ftdi_layout_init 0x0c08 0x0f1b
+ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400
+ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800
+
+source [find npcx.cfg]
+source [find npcx_cmds.tcl]
diff --git a/chip/npcx/peci.c b/chip/npcx/peci.c
new file mode 100644
index 0000000000..d5de9c1e40
--- /dev/null
+++ b/chip/npcx/peci.c
@@ -0,0 +1,295 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* PECI interface for Chrome EC */
+
+#include "chipset.h"
+#include "clock.h"
+#include "clock_chip.h"
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "peci.h"
+#include "registers.h"
+#include "task.h"
+#include "timer.h"
+#include "temp_sensor.h"
+#include "util.h"
+
+
+/* Initial PECI baud rate */
+#define PECI_BAUD_RATE 750000
+
+#define TEMP_AVG_LENGTH 4 /* Should be power of 2 */
+
+
+/* PECI Time-out */
+#define PECI_DONE_TIMEOUT_US (100*MSEC)
+/* Task Event for PECI */
+#define TASK_EVENT_PECI_DONE TASK_EVENT_CUSTOM(1<<26)
+
+#define NULL_PENDING_TASK_ID 0xFFFFFFFF
+#define PECI_MAX_FIFO_SIZE 16
+#define PROC_SOCKET 0x30
+/* PECI Command Code */
+enum peci_command_t {
+ PECI_COMMAND_PING = 0x00,
+ PECI_COMMAND_GET_DIB = 0xF7,
+ PECI_COMMAND_GET_TEMP = 0x01,
+ PECI_COMMAND_RD_PKG_CFG = 0xA1,
+ PECI_COMMAND_WR_PKG_CFG = 0xA5,
+ PECI_COMMAND_RD_IAMSR = 0xB1,
+ PECI_COMMAND_RD_PCI_CFG = 0x61,
+ PECI_COMMAND_RD_PCI_CFG_LOCAL = 0xE1,
+ PECI_COMMAND_WR_PCI_CFG_LOCAL = 0xE5,
+ PECI_COMMAND_NONE = 0xFF
+};
+
+#define PECI_COMMAND_GET_TEMP_WR_LENS 0x00
+#define PECI_COMMAND_GET_TEMP_RD_LENS 0x02
+
+/* PECI Domain Number */
+static int temp_vals[TEMP_AVG_LENGTH];
+static int temp_idx;
+static uint8_t peci_sts;
+/* For PECI Done interrupt usage */
+static int peci_pending_task_id;
+
+/*****************************************************************************/
+/* Internal functions */
+
+/**
+ * This routine initiates the parameters of a PECI transaction
+ *
+ * @param wr_length How many byte of *wr_data went to be send
+ * @param rd_length How many byte went to received (not include FCS)
+ * @param cmd_code Command code
+ * @param *wr_data Buffer pointer of write data
+ * @return TASK_EVENT_PECI_DONE that mean slave had a response
+ */
+static uint32_t peci_trans(
+ uint8_t wr_length,
+ uint8_t rd_length,
+ enum peci_command_t cmd_code,
+ uint8_t *wr_data
+)
+{
+ uint32_t events;
+ /* Ensure no PECI transaction is in progress */
+ if (IS_BIT_SET(NPCX_PECI_CTL_STS, NPCX_PECI_CTL_STS_START_BUSY)) {
+ /*
+ * PECI transaction is in progress -
+ * can not initiate a new one
+ */
+ return 0;
+ }
+ /* Set basic transaction parameters */
+ NPCX_PECI_ADDR = PROC_SOCKET;
+ NPCX_PECI_CMD = cmd_code;
+ /* Aviod over space */
+ if (rd_length > PECI_MAX_FIFO_SIZE)
+ rd_length = PECI_MAX_FIFO_SIZE;
+ /* Read-Length */
+ NPCX_PECI_RD_LENGTH = rd_length;
+ if (wr_length > PECI_MAX_FIFO_SIZE)
+ wr_length = PECI_MAX_FIFO_SIZE;
+ /* copy of data */
+ for (events = 0; events < wr_length; events++)
+ NPCX_PECI_DATA_OUT(events) = wr_data[events];
+ /* Write-Length */
+ if (cmd_code != PECI_COMMAND_PING) {
+ if ((cmd_code == PECI_COMMAND_WR_PKG_CFG) ||
+ (cmd_code == PECI_COMMAND_WR_PCI_CFG_LOCAL)) {
+ /*CMD+AWFCS*/
+ NPCX_PECI_WR_LENGTH = wr_length + 2;
+ /* Enable AWFCS */
+ SET_BIT(NPCX_PECI_CTL_STS, NPCX_PECI_CTL_STS_AWFCS_EN);
+ } else {
+ /*CMD*/
+ NPCX_PECI_WR_LENGTH = wr_length + 1;
+ /* Enable AWFCS */
+ CLEAR_BIT(NPCX_PECI_CTL_STS,
+ NPCX_PECI_CTL_STS_AWFCS_EN);
+ }
+ }
+
+ /* Start the PECI transaction */
+ SET_BIT(NPCX_PECI_CTL_STS, NPCX_PECI_CTL_STS_START_BUSY);
+
+ /* It should be using a interrupt , don't waste cpu computing power */
+ peci_pending_task_id = task_get_current();
+ return task_wait_event_mask(TASK_EVENT_PECI_DONE,
+ PECI_DONE_TIMEOUT_US);
+
+}
+
+/**
+ * PECI transaction error status.
+ *
+ * @return Bit3 - CRC error Bit4 - ABRT error
+ */
+static uint8_t peci_check_error_state(void)
+{
+ return peci_sts;
+}
+
+/*****************************************************************************/
+/* PECI drivers */
+int peci_get_cpu_temp(void)
+{
+ uint32_t events;
+ int16_t cpu_temp = -1;
+
+ /* Start PECI trans */
+ events = peci_trans(PECI_COMMAND_GET_TEMP_WR_LENS,
+ PECI_COMMAND_GET_TEMP_RD_LENS,
+ PECI_COMMAND_GET_TEMP, NULL);
+ /* if return DONE , that mean slave had a PECI response */
+ if ((events & TASK_EVENT_PECI_DONE) == TASK_EVENT_PECI_DONE) {
+ /* check CRC & ABRT */
+ events = peci_check_error_state();
+ if (events) {
+ ;
+ } else {
+ uint16_t *ptr;
+ ptr = (uint16_t *)&cpu_temp;
+ ptr[0] = (NPCX_PECI_DATA_IN(1) << 8) |
+ (NPCX_PECI_DATA_IN(0) << 0);
+ }
+ }
+ return (int)cpu_temp;
+}
+
+int peci_temp_sensor_get_val(int idx, int *temp_ptr)
+{
+ int sum = 0;
+ int success_cnt = 0;
+ int i;
+
+ if (!chipset_in_state(CHIPSET_STATE_ON))
+ return EC_ERROR_NOT_POWERED;
+
+ for (i = 0; i < TEMP_AVG_LENGTH; ++i) {
+ if (temp_vals[i] >= 0) {
+ success_cnt++;
+ sum += temp_vals[i];
+ }
+ }
+
+ /*
+ * Require at least two valid samples. When the AP transitions into S0,
+ * it is possible, depending on the timing of the PECI sample, to read
+ * an invalid temperature. This is very rare, but when it does happen
+ * the temperature returned is CONFIG_PECI_TJMAX. Requiring two valid
+ * samples here assures us that one bad maximum temperature reading
+ * when entering S0 won't cause us to trigger an over temperature.
+ */
+ if (success_cnt < 2)
+ return EC_ERROR_UNKNOWN;
+
+ *temp_ptr = sum / success_cnt;
+ return EC_SUCCESS;
+}
+
+static void peci_temp_sensor_poll(void)
+{
+ int val;
+
+ val = peci_get_cpu_temp();
+ if (val != -1) {
+ temp_vals[temp_idx] = val;
+ temp_idx = (temp_idx + 1) & (TEMP_AVG_LENGTH - 1);
+ }
+}
+DECLARE_HOOK(HOOK_TICK, peci_temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR);
+
+static void peci_freq_changed(void)
+{
+ /* PECI is under APB2 */
+ int freq = clock_get_freq();
+ int baud = 0xF;
+
+ /* Disable polling while reconfiguring */
+ NPCX_PECI_CTL_STS = 0;
+
+ /*
+ * Set the maximum bit rate used by the PECI module during both
+ * Address Timing Negotiation and Data Timing Negotiation.
+ * The resulting maximum bit rate MAX_BIT_RATE in decimal is
+ * according to the following formula:
+ *
+ * MAX_BIT_RATE [d] = (freq / (4 * baudrate)) - 1
+ * Maximum bit rate should not extend the field's boundaries.
+ */
+ if (freq != 0) {
+ baud = (uint8_t)(freq / (4 * PECI_BAUD_RATE)) - 1;
+ /* Set maximum PECI baud rate (bit0 - bit4) */
+ if (baud > 0x1F)
+ baud = 0x1F;
+ }
+ /* Enhanced High-Speed */
+ if (baud >= 7) {
+ CLEAR_BIT(NPCX_PECI_RATE, 6);
+ CLEAR_BIT(NPCX_PECI_CFG, 3);
+ } else {
+ SET_BIT(NPCX_PECI_RATE, 6);
+ SET_BIT(NPCX_PECI_CFG, 3);
+ }
+ /* Setting Rate */
+ NPCX_PECI_RATE = baud;
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, peci_freq_changed, HOOK_PRIO_DEFAULT);
+
+static void peci_init(void)
+{
+ int i;
+
+ /* make sure PECI_DATA function pin enable */
+ CLEAR_BIT(NPCX_DEVALT(0x0A), 6);
+ /* Set initial clock frequency */
+ peci_freq_changed();
+ /* Initialize temperature reading buffer to a sane value. */
+ for (i = 0; i < TEMP_AVG_LENGTH; ++i)
+ temp_vals[i] = 300; /* 27 C */
+
+ /* init Pending task id */
+ peci_pending_task_id = NULL_PENDING_TASK_ID;
+ /* Enable PECI Done interrupt */
+ SET_BIT(NPCX_PECI_CTL_STS, NPCX_PECI_CTL_STS_DONE_EN);
+
+ task_enable_irq(NPCX_IRQ_PECI);
+}
+DECLARE_HOOK(HOOK_INIT, peci_init, HOOK_PRIO_DEFAULT);
+
+/* If received a PECI DONE interrupt, post the event to PECI task */
+void peci_done_interrupt(void){
+ if (peci_pending_task_id != NULL_PENDING_TASK_ID)
+ task_set_event(peci_pending_task_id, TASK_EVENT_PECI_DONE, 0);
+ peci_sts = NPCX_PECI_CTL_STS & 0x18;
+ /* no matter what, clear status bit again */
+ SET_BIT(NPCX_PECI_CTL_STS, NPCX_PECI_CTL_STS_DONE);
+ SET_BIT(NPCX_PECI_CTL_STS, NPCX_PECI_CTL_STS_CRC_ERR);
+ SET_BIT(NPCX_PECI_CTL_STS, NPCX_PECI_CTL_STS_ABRT_ERR);
+}
+DECLARE_IRQ(NPCX_IRQ_PECI, peci_done_interrupt, 2);
+
+/*****************************************************************************/
+/* Console commands */
+
+static int command_peci_temp(int argc, char **argv)
+{
+ int t = peci_get_cpu_temp();
+ if (t == -1) {
+ ccprintf("PECI response timeout\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ ccprintf("CPU temp = %d K = %d\n", t, K_TO_C(t));
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(pecitemp, command_peci_temp,
+ NULL,
+ "Print CPU temperature",
+ NULL);
diff --git a/chip/npcx/pwm.c b/chip/npcx/pwm.c
new file mode 100644
index 0000000000..bfbf2090d2
--- /dev/null
+++ b/chip/npcx/pwm.c
@@ -0,0 +1,269 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* PWM control module for NPCX.
+ *
+ * On this chip, the PWM logic is implemented by the hardware FAN modules.
+ */
+
+#include "clock.h"
+#include "clock_chip.h"
+#include "fan.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "pwm.h"
+#include "pwm_chip.h"
+#include "registers.h"
+#include "util.h"
+#include "console.h"
+
+#if !(DEBUG_PWM)
+#define CPRINTS(...)
+#else
+#define CPRINTS(format, args...) cprints(CC_PWM, format, ## args)
+#endif
+
+/* PWM clock source */
+enum npcx_pwm_source_clock {
+ NPCX_PWM_CLOCK_APB2_LFCLK = 0,
+ NPCX_PWM_CLOCK_FX = 1,
+ NPCX_PWM_CLOCK_FR = 2,
+ NPCX_PWM_CLOCK_RESERVED = 0x3,
+ NPCX_PWM_CLOCK_UNDEF = 0xFF
+};
+
+/* PWM heartbeat mode */
+enum npcx_pwm_heartbeat_mode {
+ NPCX_PWM_HBM_NORMAL = 0,
+ NPCX_PWM_HBM_25 = 1,
+ NPCX_PWM_HBM_50 = 2,
+ NPCX_PWM_HBM_100 = 3,
+ NPCX_PWM_HBM_UNDEF = 0xFF
+};
+
+/* Global variables */
+static int pwm_init_ch;
+
+/**
+ * Preset PWM operation clock.
+ *
+ * @param none
+ * @return none
+ * @notes changed when initial or HOOK_FREQ_CHANGE command
+ */
+void pwm_freq_changed(void)
+{
+ uint32_t prescaler_divider = 0;
+
+ if (pwm_init_ch == PWM_CH_FAN) {
+ /*
+ * Using PWM Frequency and Resolution we calculate
+ * prescaler for input clock
+ */
+ /* (Benson_TBD_9) pwm_clock/freq/resolution not confirm */
+#ifdef CONFIG_PWM_INPUT_LFCLK
+ prescaler_divider = (uint32_t)(32768 /
+ pwm_channels[pwm_init_ch].freq);
+#else
+ prescaler_divider = (uint32_t)(clock_get_apb2_freq()
+ / pwm_channels[pwm_init_ch].freq);
+#endif
+ } else {
+ prescaler_divider = (uint32_t)(clock_get_apb2_freq()
+ / pwm_channels[pwm_init_ch].freq);
+ }
+ /* Set clock prescalre divider to ADC module*/
+ if (prescaler_divider >= 1)
+ prescaler_divider = prescaler_divider - 1;
+ if (prescaler_divider > 0xFFFF)
+ prescaler_divider = 0xFFFF;
+
+ /* Configure computed prescaler and resolution */
+ NPCX_PRSC(pwm_channels[pwm_init_ch].channel) =
+ (uint16_t)prescaler_divider;
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, pwm_freq_changed, HOOK_PRIO_DEFAULT);
+
+/**
+ * Set PWM enabled.
+ *
+ * @param ch operation channel
+ * @param enabled enabled flag
+ * @return none
+ */
+void pwm_enable(enum pwm_channel ch, int enabled)
+{
+ /* Start or close PWM module */
+ if (enabled)
+ SET_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), NPCX_PWMCTL_PWR);
+ else
+ CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel),
+ NPCX_PWMCTL_PWR);
+}
+
+/**
+ * Check PWM enabled.
+ *
+ * @param ch operation channel
+ * @return enabled or not
+ */
+int pwm_get_enabled(enum pwm_channel ch)
+{
+ return IS_BIT_SET(NPCX_PWMCTL(pwm_channels[ch].channel),
+ NPCX_PWMCTL_PWR);
+}
+
+/**
+ * Set PWM duty cycle.
+ *
+ * @param ch operation channel
+ * @param percent duty cycle percent
+ * @return none
+ */
+void pwm_set_duty(enum pwm_channel ch, int percent)
+{
+ uint32_t resolution = 0;
+ uint16_t duty_cycle = 0;
+
+ CPRINTS("pwm0=%d", percent);
+ /* Assume the fan control is active high and invert it ourselves */
+ if (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW)
+ SET_BIT(NPCX_PWMCTL(pwm_channels[ch].channel),
+ NPCX_PWMCTL_INVP);
+ else
+ CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel),
+ NPCX_PWMCTL_INVP);
+
+ if (percent < 0)
+ percent = 0;
+ /* (Benson_TBD_14) if 100% make mft cannot get TCRB,
+ * it will need to change to 99% */
+ else if (percent > 100)
+ percent = 100;
+ CPRINTS("pwm1duty=%d", percent);
+
+ resolution = NPCX_CTR(pwm_channels[ch].channel) + 1;
+ duty_cycle = percent*resolution/100;
+ CPRINTS("freq=0x%x", pwm_channels[ch].freq);
+ CPRINTS("resolution=%d", resolution);
+ CPRINTS("duty_cycle=%d", duty_cycle);
+
+ /* Set the duty cycle */
+ /* (Benson_TBD_14) Always enable the fan channel or not */
+ if (percent) {
+ NPCX_DCR(pwm_channels[ch].channel) = (duty_cycle - 1);
+ pwm_enable(ch, 1);
+ } else {
+ NPCX_DCR(pwm_channels[ch].channel) = 0;
+ pwm_enable(ch, 0);
+ }
+}
+
+/**
+ * Get PWM duty cycle.
+ *
+ * @param ch operation channel
+ * @return duty cycle percent
+ */
+int pwm_get_duty(enum pwm_channel ch)
+{
+ /* Return percent */
+ if (0 == pwm_get_enabled(ch))
+ return 0;
+ else
+ return (((NPCX_DCR(pwm_channels[ch].channel) + 1) * 100)
+ / (NPCX_CTR(pwm_channels[ch].channel) + 1));
+}
+
+/**
+ * PWM configuration.
+ *
+ * @param ch operation channel
+ * @return none
+ */
+void pwm_config(enum pwm_channel ch)
+{
+ pwm_init_ch = ch;
+
+ /* Configure pins from GPIOs to PWM */
+ if (ch == PWM_CH_FAN)
+ gpio_config_module(MODULE_PWM_FAN, 1);
+ else
+ gpio_config_module(MODULE_PWM_KBLIGHT, 1);
+
+ /* Disable PWM for module configuration */
+ pwm_enable(ch, 0);
+
+ /* Set PWM heartbeat mode is no heartbeat*/
+ NPCX_PWMCTL(pwm_channels[ch].channel) =
+ (NPCX_PWMCTL(pwm_channels[ch].channel)
+ &(~(((1<<2)-1)<<NPCX_PWMCTL_HB_DC_CTL)))
+ |(NPCX_PWM_HBM_NORMAL<<NPCX_PWMCTL_HB_DC_CTL);
+
+ /* Set PWM operation frequence */
+ pwm_freq_changed();
+
+ /* Set PWM cycle time */
+ NPCX_CTR(pwm_channels[ch].channel) =
+ (pwm_channels[ch].cycle_pulses - 1);
+
+ /* Set the duty cycle */
+ NPCX_DCR(pwm_channels[ch].channel) = 0;
+
+ /* Set PWM polarity is normal*/
+ CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), NPCX_PWMCTL_INVP);
+
+ /* Set PWM open drain output is push-pull type*/
+ CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel), NPCX_PWMCTLEX_OD_OUT);
+
+ /* Select default CLK or LFCLK clock input to PWM module */
+ NPCX_PWMCTLEX(pwm_channels[ch].channel) =
+ (NPCX_PWMCTLEX(pwm_channels[ch].channel)
+ & (~(((1<<2)-1)<<NPCX_PWMCTLEX_FCK_SEL)))
+ | (NPCX_PWM_CLOCK_APB2_LFCLK<<NPCX_PWMCTLEX_FCK_SEL);
+
+ if (ch == PWM_CH_FAN) {
+#ifdef CONFIG_PWM_INPUT_LFCLK
+ /* Select default LFCLK clock input to PWM module */
+ SET_BIT(NPCX_PWMCTL(pwm_channels[ch].channel),
+ NPCX_PWMCTL_CKSEL);
+#else
+ /* Select default core clock input to PWM module */
+ CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel),
+ NPCX_PWMCTL_CKSEL);
+#endif
+ } else {
+ /* Select default core clock input to PWM module */
+ CLEAR_BIT(NPCX_PWMCTL(pwm_channels[ch].channel),
+ NPCX_PWMCTL_CKSEL);
+ }
+}
+
+/**
+ * PWM initial.
+ *
+ * @param none
+ * @return none
+ */
+static void pwm_init(void)
+{
+ int i;
+
+#ifdef CONFIG_PWM_DSLEEP
+
+ /* Enable the PWM module and delay a few clocks */
+ clock_enable_peripheral(CGC_OFFSET_PWM, CGC_PWM_MASK, CGC_MODE_ALL);
+#else
+ /* Enable the PWM module and delay a few clocks */
+ clock_enable_peripheral(CGC_OFFSET_PWM, CGC_PWM_MASK,
+ CGC_MODE_RUN | CGC_MODE_SLEEP);
+#endif
+
+ for (i = 0; i < PWM_CH_COUNT; i++)
+ pwm_config(i);
+}
+
+/* The chip-specific fan module initializes before this. */
+DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_DEFAULT);
diff --git a/chip/npcx/pwm_chip.h b/chip/npcx/pwm_chip.h
new file mode 100644
index 0000000000..77d6991c7b
--- /dev/null
+++ b/chip/npcx/pwm_chip.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* NPCX-specific PWM module for Chrome EC */
+
+#ifndef __CROS_EC_NPCX_PWM_H
+#define __CROS_EC_NPCX_PWM_H
+
+/* Data structure to define PWM channels. */
+struct pwm_t {
+ /* PWM channel ID */
+ int channel;
+ /* PWM channel flags. See include/pwm.h */
+ uint32_t flags;
+ /* PWM freq. */
+ uint32_t freq;
+ /* PWM pulses each cycle. */
+ uint32_t cycle_pulses;
+};
+
+extern const struct pwm_t pwm_channels[];
+void pwm_config(enum pwm_channel ch);
+
+#endif /* __CROS_EC_NPCX_PWM_H */
diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h
new file mode 100644
index 0000000000..1d11770ad1
--- /dev/null
+++ b/chip/npcx/registers.h
@@ -0,0 +1,1189 @@
+/* Copyright (c) 2014 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 NPCX processor
+ */
+
+#ifndef __CROS_EC_REGISTERS_H
+#define __CROS_EC_REGISTERS_H
+
+#include "common.h"
+/******************************************************************************/
+/*
+ * Macro Functions
+ */
+#define SET_BIT(reg, bit) ((reg) |= (0x1 << (bit)))
+#define CLEAR_BIT(reg, bit) ((reg) &= (~(0x1 << (bit))))
+#define IS_BIT_SET(reg, bit) ((reg >> bit) & (0x1))
+#define UPDATE_BIT(reg, bit, cond) { if (cond) \
+ SET_BIT(reg, bit); \
+ else \
+ CLEAR_BIT(reg, bit); }
+
+/******************************************************************************/
+/*
+ * NPCX (Nuvoton M4 EC) Register Definitions
+ */
+
+/* Global Definition */
+#define CHIP_NPCX5M5G
+#define SUPPORT_JTAG
+#define I2C0_BUS0 1 /* Use I2C0_SDA0/1 I2C0_SCL0/1 */
+#define TACH_SEL1 1 /* Use TACH_SEL1 or TACH_SEL2 */
+#define JTAG1 0 /* Use JTAG0/1 JTAG1 only support
+ 132-Pins package*/
+#define I2C_7BITS_ADDR 0
+#define I2C_LEVEL_SUPPORT 1
+/* Switcher of features */
+#define SUPPORT_LCT 1
+#define SUPPORT_WDG 0
+#define SUPPORT_HIB 1
+/* Switcher of debugging */
+#define DEBUG_I2C 0
+#define DEBUG_TMR 1
+#define DEBUG_WDG 0
+#define DEBUG_GPIO 1
+#define DEBUG_FAN 0
+#define DEBUG_PWM 0
+#define DEBUG_SPI 0
+#define DEBUG_FLH 0
+#define DEBUG_PECI 0
+#define DEBUG_CLK 1
+
+/* Modules Map */
+#define NPCX_MDC_BASE_ADDR 0x4000C000
+#define NPCX_SIB_BASE_ADDR 0x4000E000
+#define NPCX_PMC_BASE_ADDR 0x4000D000
+#define NPCX_SHM_BASE_ADDR 0x40010000
+#define NPCX_FIU_BASE_ADDR 0x40020000
+#define NPCX_KBSCAN_REGS_BASE 0x400A3000
+#define NPCX_GLUE_REGS_BASE 0x400A5000
+#define NPCX_BBRAM_BASE_ADDR 0x400AF000
+#define NPCX_HFCG_BASE_ADDR 0x400B5000
+#define NPCX_MTC_BASE_ADDR 0x400B7000
+#define NPCX_MSWC_BASE_ADDR 0x400C1000
+#define NPCX_SCFG_BASE_ADDR 0x400C3000
+#define NPCX_CR_UART_BASE_ADDR 0x400C4000
+#define NPCX_KBC_BASE_ADDR 0x400C7000
+#define NPCX_ADC_BASE_ADDR 0x400D1000
+#define NPCX_SPI_BASE_ADDR 0x400D2000
+#define NPCX_PECI_BASE_ADDR 0x400D4000
+#define NPCX_TWD_BASE_ADDR 0x400D8000
+
+/* Multi-Modules Map */
+#define NPCX_PWM_BASE_ADDR(mdl) (0x40080000 + ((mdl) * 0x2000L))
+#define NPCX_GPIO_BASE_ADDR(mdl) (0x40081000 + ((mdl) * 0x2000L))
+#define NPCX_ITIM16_BASE_ADDR(mdl) (0x400B0000 + ((mdl) * 0x2000L))
+#define NPCX_MIWU_BASE_ADDR(mdl) (0x400BB000 + ((mdl) * 0x2000L))
+#define NPCX_MFT_BASE_ADDR(mdl) (0x400E1000 + ((mdl) * 0x2000L))
+#define NPCX_PM_CH_BASE_ADDR(mdl) (0x400C9000 + ((mdl) * 0x2000L))
+#define NPCX_SMB_BASE_ADDR(mdl) ((mdl < 2) ? (0x40009000 + \
+ ((mdl) * 0x2000L)) : \
+ (0x400C0000 + ((mdl) * 0x2000L)))
+
+/*
+ * NPCX-IRQ numbers
+ */
+#define NPCX_IRQ_0 0
+#define NPCX_IRQ_1 1
+#define NPCX_IRQ_2 2
+#define NPCX_IRQ_3 3
+#define NPCX_IRQ_4 4
+#define NPCX_IRQ_5 5
+#define NPCX_IRQ_6 6
+#define NPCX_IRQ_7 7
+#define NPCX_IRQ_8 8
+#define NPCX_IRQ_9 9
+#define NPCX_IRQ_10 10
+#define NPCX_IRQ_11 11
+#define NPCX_IRQ_12 12
+#define NPCX_IRQ_13 13
+#define NPCX_IRQ_14 14
+#define NPCX_IRQ_15 15
+#define NPCX_IRQ_16 16
+#define NPCX_IRQ_17 17
+#define NPCX_IRQ_18 18
+#define NPCX_IRQ_19 19
+#define NPCX_IRQ_20 20
+#define NPCX_IRQ_21 21
+#define NPCX_IRQ_22 22
+#define NPCX_IRQ_23 23
+#define NPCX_IRQ_24 24
+#define NPCX_IRQ_25 25
+#define NPCX_IRQ_26 26
+#define NPCX_IRQ_27 27
+#define NPCX_IRQ_28 28
+#define NPCX_IRQ_29 29
+#define NPCX_IRQ_30 30
+#define NPCX_IRQ_31 31
+#define NPCX_IRQ_32 32
+#define NPCX_IRQ_33 33
+#define NPCX_IRQ_34 34
+#define NPCX_IRQ_35 35
+#define NPCX_IRQ_36 36
+#define NPCX_IRQ_37 37
+#define NPCX_IRQ_38 38
+#define NPCX_IRQ_39 39
+#define NPCX_IRQ_40 40
+#define NPCX_IRQ_41 41
+#define NPCX_IRQ_42 42
+#define NPCX_IRQ_43 43
+#define NPCX_IRQ_44 44
+#define NPCX_IRQ_45 45
+#define NPCX_IRQ_46 46
+#define NPCX_IRQ_47 47
+#define NPCX_IRQ_48 48
+#define NPCX_IRQ_49 49
+#define NPCX_IRQ_50 50
+#define NPCX_IRQ_51 51
+#define NPCX_IRQ_52 52
+#define NPCX_IRQ_53 53
+#define NPCX_IRQ_54 54
+#define NPCX_IRQ_55 55
+#define NPCX_IRQ_56 56
+#define NPCX_IRQ_57 57
+#define NPCX_IRQ_58 58
+#define NPCX_IRQ_59 59
+#define NPCX_IRQ_60 60
+#define NPCX_IRQ_61 61
+#define NPCX_IRQ_62 62
+#define NPCX_IRQ_63 63
+
+#define NPCX_IRQ0_NOUSED NPCX_IRQ_0
+#define NPCX_IRQ1_NOUSED NPCX_IRQ_1
+#define NPCX_IRQ_KBSCAN NPCX_IRQ_2
+#define NPCX_IRQ_PM_CHAN_OBF NPCX_IRQ_3
+#define NPCX_IRQ_PECI NPCX_IRQ_4
+#define NPCX_IRQ5_NOUSED NPCX_IRQ_5
+#define NPCX_IRQ_PORT80 NPCX_IRQ_6
+#define NPCX_IRQ_MTC_WKINTAD_0 NPCX_IRQ_7
+#define NPCX_IRQ8_NOUSED NPCX_IRQ_8
+#define NPCX_IRQ_MFT_1 NPCX_IRQ_9
+#define NPCX_IRQ_ADC NPCX_IRQ_10
+#define NPCX_IRQ_WKINTEFGH_0 NPCX_IRQ_11
+#define NPCX_IRQ_CDMA NPCX_IRQ_12
+#define NPCX_IRQ_SMB1 NPCX_IRQ_13
+#define NPCX_IRQ_SMB2 NPCX_IRQ_14
+#define NPCX_IRQ_WKINTC_0 NPCX_IRQ_15
+#define NPCX_IRQ16_NOUSED NPCX_IRQ_16
+#define NPCX_IRQ_ITIM16_3 NPCX_IRQ_17
+#define NPCX_IRQ_ESPI NPCX_IRQ_18
+#define NPCX_IRQ19_NOUSED NPCX_IRQ_19
+#define NPCX_IRQ20_NOUSED NPCX_IRQ_20
+#define NPCX_IRQ_PS2 NPCX_IRQ_21
+#define NPCX_IRQ22_NOUSED NPCX_IRQ_22
+#define NPCX_IRQ_MFT_2 NPCX_IRQ_23
+#define NPCX_IRQ_SHM NPCX_IRQ_24
+#define NPCX_IRQ_KBC_IBF NPCX_IRQ_25
+#define NPCX_IRQ_PM_CHAN_IBF NPCX_IRQ_26
+#define NPCX_IRQ_ITIM16_2 NPCX_IRQ_27
+#define NPCX_IRQ_ITIM16_1 NPCX_IRQ_28
+#define NPCX_IRQ29_NOUSED NPCX_IRQ_29
+#define NPCX_IRQ30_NOUSED NPCX_IRQ_30
+#define NPCX_IRQ_TWD_WKINTB_0 NPCX_IRQ_31
+#define NPCX_IRQ32_NOUSED NPCX_IRQ_32
+#define NPCX_IRQ_UART NPCX_IRQ_33
+#define NPCX_IRQ34_NOUSED NPCX_IRQ_34
+#define NPCX_IRQ35_NOUSED NPCX_IRQ_35
+#define NPCX_IRQ_SMB3 NPCX_IRQ_36
+#define NPCX_IRQ_SMB4 NPCX_IRQ_37
+#define NPCX_IRQ38_NOUSED NPCX_IRQ_38
+#define NPCX_IRQ39_NOUSED NPCX_IRQ_39
+#define NPCX_IRQ40_NOUSED NPCX_IRQ_40
+#define NPCX_IRQ_MFT_3 NPCX_IRQ_41
+#define NPCX_IRQ42_NOUSED NPCX_IRQ_42
+#define NPCX_IRQ_ITIM16_4 NPCX_IRQ_43
+#define NPCX_IRQ_ITIM16_5 NPCX_IRQ_44
+#define NPCX_IRQ_ITIM16_6 NPCX_IRQ_45
+#define NPCX_IRQ46_NOUSED NPCX_IRQ_46
+#define NPCX_IRQ_WKINTA_1 NPCX_IRQ_47
+#define NPCX_IRQ_WKINTB_1 NPCX_IRQ_48
+#define NPCX_IRQ_KSI_WKINTC_1 NPCX_IRQ_49
+#define NPCX_IRQ_WKINTD_1 NPCX_IRQ_50
+#define NPCX_IRQ_WKINTE_1 NPCX_IRQ_51
+#define NPCX_IRQ_WKINTF_1 NPCX_IRQ_52
+#define NPCX_IRQ_WKINTG_1 NPCX_IRQ_53
+#define NPCX_IRQ_WKINTH_1 NPCX_IRQ_54
+#define NPCX_IRQ55_NOUSED NPCX_IRQ_55
+#define NPCX_IRQ_KBC_OBF NPCX_IRQ_56
+#define NPCX_IRQ_SPI NPCX_IRQ_57
+#define NPCX_IRQ58_NOUSED NPCX_IRQ_58
+#define NPCX_IRQ59_NOUSED NPCX_IRQ_59
+#define NPCX_IRQ_WKINTA_2 NPCX_IRQ_60
+#define NPCX_IRQ_WKINTB_2 NPCX_IRQ_61
+#define NPCX_IRQ_WKINTC_2 NPCX_IRQ_62
+#define NPCX_IRQ_WKINTD_2 PCX_IRQ_63
+
+#define NPCX_IRQ_COUNT 64
+
+/******************************************************************************/
+/* Miscellaneous Device Control (MDC) registers */
+#define NPCX_FWCTRL REG8(NPCX_MDC_BASE_ADDR + 0x007)
+
+/* MDC register fields */
+#define NPCX_FWCTRL_RO_REGION 0
+
+/******************************************************************************/
+/* High Frequency Clock Generator (HFCG) registers */
+#define NPCX_HFCGCTRL REG8(NPCX_HFCG_BASE_ADDR + 0x000)
+#define NPCX_HFCGML REG8(NPCX_HFCG_BASE_ADDR + 0x002)
+#define NPCX_HFCGMH REG8(NPCX_HFCG_BASE_ADDR + 0x004)
+#define NPCX_HFCGN REG8(NPCX_HFCG_BASE_ADDR + 0x006)
+#define NPCX_HFCGP REG8(NPCX_HFCG_BASE_ADDR + 0x008)
+#define NPCX_HFCBCD REG8(NPCX_HFCG_BASE_ADDR + 0x010)
+
+/* HFCG register fields */
+#define NPCX_HFCGCTRL_LOAD 0
+#define NPCX_HFCGCTRL_LOCK 2
+#define NPCX_HFCGCTRL_CLK_CHNG 7
+
+/******************************************************************************/
+/*CR UART Register */
+#define NPCX_UTBUF REG8(NPCX_CR_UART_BASE_ADDR + 0x000)
+#define NPCX_URBUF REG8(NPCX_CR_UART_BASE_ADDR + 0x002)
+#define NPCX_UICTRL REG8(NPCX_CR_UART_BASE_ADDR + 0x004)
+#define NPCX_USTAT REG8(NPCX_CR_UART_BASE_ADDR + 0x006)
+#define NPCX_UFRS REG8(NPCX_CR_UART_BASE_ADDR + 0x008)
+#define NPCX_UMDSL REG8(NPCX_CR_UART_BASE_ADDR + 0x00A)
+#define NPCX_UBAUD REG8(NPCX_CR_UART_BASE_ADDR + 0x00C)
+#define NPCX_UPSR REG8(NPCX_CR_UART_BASE_ADDR + 0x00E)
+
+/******************************************************************************/
+/* KBSCAN registers */
+#define NPCX_KBSIN REG8(NPCX_KBSCAN_REGS_BASE + 0x04)
+#define NPCX_KBSINPU REG8(NPCX_KBSCAN_REGS_BASE + 0x05)
+#define NPCX_KBSOUT0 REG16(NPCX_KBSCAN_REGS_BASE + 0x06)
+#define NPCX_KBSOUT1 REG16(NPCX_KBSCAN_REGS_BASE + 0x08)
+#define NPCX_KBS_BUF_INDX REG8(NPCX_KBSCAN_REGS_BASE + 0x0A)
+#define NPCX_KBS_BUF_DATA REG8(NPCX_KBSCAN_REGS_BASE + 0x0B)
+#define NPCX_KBSEVT REG8(NPCX_KBSCAN_REGS_BASE + 0x0C)
+#define NPCX_KBSCTL REG8(NPCX_KBSCAN_REGS_BASE + 0x0D)
+#define NPCX_KBS_CFG_INDX REG8(NPCX_KBSCAN_REGS_BASE + 0x0E)
+#define NPCX_KBS_CFG_DATA REG8(NPCX_KBSCAN_REGS_BASE + 0x0F)
+
+/* KBSCAN register fields */
+#define NPCX_KBSBUFINDX 0
+#define NPCX_KBSDONE 0
+#define NPCX_KBSERR 1
+#define NPCX_KBSSTART 0
+#define NPCX_KBSMODE 1
+#define NPCX_KBSIEN 2
+#define NPCX_KBSINC 3
+#define NPCX_KBSCFGINDX 0
+
+/* KBSCAN definitions */
+#define KB_ROW_NUM 8 /* Rows numbers of keyboard matrix */
+#define KB_COL_NUM 18 /* Columns numbers of keyboard matrix */
+#define KB_ROW_MASK ((1<<KB_ROW_NUM) - 1) /* Mask of rows of keyboard matrix */
+#define KB_COL_MASK ((1<<KB_COL_NUM) - 1) /* Mask of cols of keyboard matrix */
+
+/******************************************************************************/
+/* GLUE registers */
+#define NPCX_GLUE_SDPD0 REG8(NPCX_GLUE_REGS_BASE + 0x010)
+#define NPCX_GLUE_SDPD1 REG8(NPCX_GLUE_REGS_BASE + 0x012)
+#define NPCX_GLUE_SDP_CTS REG8(NPCX_GLUE_REGS_BASE + 0x014)
+
+/******************************************************************************/
+/* MIWU registers */
+#define NPCX_WKEDG_ADDR(port, n) (NPCX_MIWU_BASE_ADDR(port) + 0x00 + \
+ ((n) * 2L) + ((n) < 5 ? 0 : 0x1E))
+#define NPCX_WKAEDG_ADDR(port, n) (NPCX_MIWU_BASE_ADDR(port) + 0x01 + \
+ ((n) * 2L) + ((n) < 5 ? 0 : 0x1E))
+#define NPCX_WKPND_ADDR(port, n) (NPCX_MIWU_BASE_ADDR(port) + 0x0A + \
+ ((n) * 4L) + ((n) < 5 ? 0 : 0x10))
+#define NPCX_WKPCL_ADDR(port, n) (NPCX_MIWU_BASE_ADDR(port) + 0x0C + \
+ ((n) * 4L) + ((n) < 5 ? 0 : 0x10))
+#define NPCX_WKEN_ADDR(port, n) (NPCX_MIWU_BASE_ADDR(port) + 0x1E + \
+ ((n) * 2L) + ((n) < 5 ? 0 : 0x12))
+#define NPCX_WKMOD_ADDR(port, n) (NPCX_MIWU_BASE_ADDR(port) + 0x70 + n)
+
+#define NPCX_WKEDG(port, n) REG8(NPCX_WKEDG_ADDR(port, n))
+#define NPCX_WKAEDG(port, n) REG8(NPCX_WKAEDG_ADDR(port, n))
+#define NPCX_WKPND(port, n) REG8(NPCX_WKPND_ADDR(port, n))
+#define NPCX_WKPCL(port, n) REG8(NPCX_WKPCL_ADDR(port, n))
+#define NPCX_WKEN(port, n) REG8(NPCX_WKEN_ADDR(port, n))
+#define NPCX_WKMOD(port, n) REG8(NPCX_WKMOD_ADDR(port, n))
+
+/* MIWU enumeration */
+enum {
+ MIWU_TABLE_0,
+ MIWU_TABLE_1,
+ MIWU_TABLE_2,
+ MIWU_TABLE_COUNT
+};
+
+enum {
+ MIWU_GROUP_1,
+ MIWU_GROUP_2,
+ MIWU_GROUP_3,
+ MIWU_GROUP_4,
+ MIWU_GROUP_5,
+ MIWU_GROUP_6,
+ MIWU_GROUP_7,
+ MIWU_GROUP_8,
+ MIWU_GROUP_COUNT
+};
+
+enum {
+ MIWU_EDGE_RISING,
+ MIWU_EDGE_FALLING,
+};
+
+/* MIWU utilities */
+#define MIWU_TABLE_WKKEY MIWU_TABLE_1
+#define MIWU_GROUP_WKKEY MIWU_GROUP_3
+
+/******************************************************************************/
+/* GPIO registers */
+#define NPCX_PDOUT(n) REG8(NPCX_GPIO_BASE_ADDR(n) + 0x000)
+#define NPCX_PDIN(n) REG8(NPCX_GPIO_BASE_ADDR(n) + 0x001)
+#define NPCX_PDIR(n) REG8(NPCX_GPIO_BASE_ADDR(n) + 0x002)
+#define NPCX_PPULL(n) REG8(NPCX_GPIO_BASE_ADDR(n) + 0x003)
+#define NPCX_PPUD(n) REG8(NPCX_GPIO_BASE_ADDR(n) + 0x004)
+#define NPCX_PENVDD(n) REG8(NPCX_GPIO_BASE_ADDR(n) + 0x005)
+#define NPCX_PTYPE(n) REG8(NPCX_GPIO_BASE_ADDR(n) + 0x006)
+
+/* GPIO enumeration */
+enum {
+ GPIO_PORT_0,
+ GPIO_PORT_1,
+ GPIO_PORT_2,
+ GPIO_PORT_3,
+ GPIO_PORT_4,
+ GPIO_PORT_5,
+ GPIO_PORT_6,
+ GPIO_PORT_7,
+ GPIO_PORT_8,
+ GPIO_PORT_9,
+ GPIO_PORT_A,
+ GPIO_PORT_B,
+ GPIO_PORT_C,
+ GPIO_PORT_D,
+ GPIO_PORT_E,
+ GPIO_PORT_F,
+ GPIO_PORT_COUNT
+};
+
+enum {
+ MASK_PIN0 = (1<<0),
+ MASK_PIN1 = (1<<1),
+ MASK_PIN2 = (1<<2),
+ MASK_PIN3 = (1<<3),
+ MASK_PIN4 = (1<<4),
+ MASK_PIN5 = (1<<5),
+ MASK_PIN6 = (1<<6),
+ MASK_PIN7 = (1<<7),
+};
+
+/* Chip-independent aliases for port base group */
+#define GPIO_0 GPIO_PORT_0
+#define GPIO_1 GPIO_PORT_1
+#define GPIO_2 GPIO_PORT_2
+#define GPIO_3 GPIO_PORT_3
+#define GPIO_4 GPIO_PORT_4
+#define GPIO_5 GPIO_PORT_5
+#define GPIO_6 GPIO_PORT_6
+#define GPIO_7 GPIO_PORT_7
+#define GPIO_8 GPIO_PORT_8
+#define GPIO_9 GPIO_PORT_9
+#define GPIO_A GPIO_PORT_A
+#define GPIO_B GPIO_PORT_B
+#define GPIO_C GPIO_PORT_C
+#define GPIO_D GPIO_PORT_D
+#define GPIO_E GPIO_PORT_E
+#define GPIO_F GPIO_PORT_F
+
+/******************************************************************************/
+/* MSWC Registers */
+#define NPCX_MSWCTL1 REG8(NPCX_MSWC_BASE_ADDR + 0x000)
+#define NPCX_HCBAL REG8(NPCX_MSWC_BASE_ADDR + 0x008)
+#define NPCX_HCBAH REG8(NPCX_MSWC_BASE_ADDR + 0x00A)
+
+/******************************************************************************/
+/* System Configuration (SCFG) Registers */
+#define NPCX_DEVCNT REG8(NPCX_SCFG_BASE_ADDR + 0x000)
+#define NPCX_STRPST REG8(NPCX_SCFG_BASE_ADDR + 0x001)
+#define NPCX_RSTCTL REG8(NPCX_SCFG_BASE_ADDR + 0x002)
+#define NPCX_DEV_CTL4 REG8(NPCX_SCFG_BASE_ADDR + 0x006)
+#define NPCX_DEVALT(n) REG8(NPCX_SCFG_BASE_ADDR + 0x010 + n)
+#define NPCX_DEVPU0 REG8(NPCX_SCFG_BASE_ADDR + 0x028)
+#define NPCX_DEVPU1 REG8(NPCX_SCFG_BASE_ADDR + 0x029)
+#define NPCX_LV_GPIO_CTL0 REG8(NPCX_SCFG_BASE_ADDR + 0x02A)
+#define NPCX_LV_GPIO_CTL1 REG8(NPCX_SCFG_BASE_ADDR + 0x02B)
+#define NPCX_LV_GPIO_CTL2 REG8(NPCX_SCFG_BASE_ADDR + 0x02C)
+#define NPCX_LV_GPIO_CTL3 REG8(NPCX_SCFG_BASE_ADDR + 0x02D)
+#define NPCX_SCFG_VER REG8(NPCX_SCFG_BASE_ADDR + 0x02F)
+
+#define TEST_BKSL REG8(NPCX_SCFG_BASE_ADDR + 0x037)
+#define TEST0 REG8(NPCX_SCFG_BASE_ADDR + 0x038)
+#define BLKSEL 0
+
+/* SCFG enumeration */
+enum {
+ ALT_GROUP_0,
+ ALT_GROUP_1,
+ ALT_GROUP_2,
+ ALT_GROUP_3,
+ ALT_GROUP_4,
+ ALT_GROUP_5,
+ ALT_GROUP_6,
+ ALT_GROUP_7,
+ ALT_GROUP_8,
+ ALT_GROUP_9,
+ ALT_GROUP_A,
+ ALT_GROUP_B,
+ ALT_GROUP_C,
+ ALT_GROUP_D,
+ ALT_GROUP_E,
+ ALT_GROUP_F,
+ ALT_GROUP_COUNT
+};
+
+/* SCFG register fields */
+#define NPCX_DEVCNT_F_SPI_TRIS 6
+#define NPCX_DEVCNT_JEN1_HEN 5
+#define NPCX_DEVCNT_JEN0_HEN 4
+#define NPCX_STRPST_TRIST 1
+#define NPCX_STRPST_TEST 2
+#define NPCX_STRPST_JEN1 4
+#define NPCX_STRPST_JEN0 5
+#define NPCX_STRPST_SPI_COMP 7
+#define NPCX_RSTCTL_VCC1_RST_STS 0
+#define NPCX_RSTCTL_DBGRST_STS 1
+#define NPCX_RSTCTL_LRESET_PLTRST_MODE 5
+#define NPCX_RSTCTL_HIPRST_MODE 6
+#define NPCX_DEV_CTL4_SPI_SP_SEL 4
+#define NPCX_DEVPU0_I2C0_0_PUE 0
+#define NPCX_DEVPU0_I2C0_1_PUE 1
+#define NPCX_DEVPU0_I2C1_0_PUE 2
+#define NPCX_DEVPU0_I2C2_0_PUE 4
+#define NPCX_DEVPU0_I2C3_0_PUE 6
+#define NPCX_DEVPU1_F_SPI_PUD_EN 7
+
+/* DEVALT */
+#define NPCX_DEVALT0_SPIP_SL 0
+#define NPCX_DEVALT0_GPIO_NO_SPIP 3
+#define NPCX_DEVALT0_F_SPI_CS1_2 4
+#define NPCX_DEVALT0_F_SPI_CS1_1 5
+#define NPCX_DEVALT0_F_SPI_QUAD 6
+#define NPCX_DEVALT0_NO_F_SPI 7
+
+#define NPCX_DEVALT1_KBRST_SL 0
+#define NPCX_DEVALT1_A20M_SL 1
+#define NPCX_DEVALT1_SMI_SL 2
+#define NPCX_DEVALT1_EC_SCI_SL 3
+#define NPCX_DEVALT1_NO_PWRGD 4
+#define NPCX_DEVALT1_RST_OUT_SL 5
+#define NPCX_DEVALT1_CLKRN_SL 6
+#define NPCX_DEVALT1_NO_LPC_ESPI 7
+
+#define NPCX_DEVALT2_I2C0_0_SL 0
+#define NPCX_DEVALT2_I2C0_1_SL 1
+#define NPCX_DEVALT2_I2C1_0_SL 2
+#define NPCX_DEVALT2_I2C2_0_SL 4
+#define NPCX_DEVALT2_I2C3_0_SL 6
+
+#define NPCX_DEVALT3_PS2_0_SL 0
+#define NPCX_DEVALT3_PS2_1_SL 1
+#define NPCX_DEVALT3_PS2_2_SL 2
+#define NPCX_DEVALT3_PS2_3_SL 3
+#define NPCX_DEVALT3_TA1_TACH1_SL1 4
+#define NPCX_DEVALT3_TB1_TACH2_SL1 5
+#define NPCX_DEVALT3_TA2_SL1 6
+#define NPCX_DEVALT3_TB2_SL1 7
+
+#define NPCX_DEVALT4_PWM0_SL 0
+#define NPCX_DEVALT4_PWM1_SL 1
+#define NPCX_DEVALT4_PWM2_SL 2
+#define NPCX_DEVALT4_PWM3_SL 3
+#define NPCX_DEVALT4_PWM4_SL 4
+#define NPCX_DEVALT4_PWM5_SL 5
+#define NPCX_DEVALT4_PWM6_SL 6
+#define NPCX_DEVALT4_PWM7_SL 7
+
+#define NPCX_DEVALT5_TRACE_EN 0
+#define NPCX_DEVALT5_NJEN1_EN 1
+#define NPCX_DEVALT5_NJEN0_EN 2
+
+#define NPCX_DEVALT6_ADC0_SL 0
+#define NPCX_DEVALT6_ADC1_SL 1
+#define NPCX_DEVALT6_ADC2_SL 2
+#define NPCX_DEVALT6_ADC3_SL 3
+#define NPCX_DEVALT6_ADC4_SL 4
+
+#define NPCX_DEVALT7_NO_KSI0_SL 0
+#define NPCX_DEVALT7_NO_KSI1_SL 1
+#define NPCX_DEVALT7_NO_KSI2_SL 2
+#define NPCX_DEVALT7_NO_KSI3_SL 3
+#define NPCX_DEVALT7_NO_KSI4_SL 4
+#define NPCX_DEVALT7_NO_KSI5_SL 5
+#define NPCX_DEVALT7_NO_KSI6_SL 6
+#define NPCX_DEVALT7_NO_KSI7_SL 7
+
+#define NPCX_DEVALT8_NO_KSO00_SL 0
+#define NPCX_DEVALT8_NO_KSO01_SL 1
+#define NPCX_DEVALT8_NO_KSO02_SL 2
+#define NPCX_DEVALT8_NO_KSO03_SL 3
+#define NPCX_DEVALT8_NO_KSO04_SL 4
+#define NPCX_DEVALT8_NO_KSO05_SL 5
+#define NPCX_DEVALT8_NO_KSO06_SL 6
+#define NPCX_DEVALT8_NO_KSO07_SL 7
+
+#define NPCX_DEVALT9_NO_KSO08_SL 0
+#define NPCX_DEVALT9_NO_KSO09_SL 1
+#define NPCX_DEVALT9_NO_KSO10_SL 2
+#define NPCX_DEVALT9_NO_KSO11_SL 3
+#define NPCX_DEVALT9_NO_KSO12_SL 4
+#define NPCX_DEVALT9_NO_KSO13_SL 5
+#define NPCX_DEVALT9_NO_KSO14_SL 6
+#define NPCX_DEVALT9_NO_KSO15_SL 7
+
+#define NPCX_DEVALTA_NO_KSO16_SL 0
+#define NPCX_DEVALTA_NO_KSO17_SL 1
+#define NPCX_DEVALTA_32K_OUT_SL 2
+#define NPCX_DEVALTA_32KCLKIN_SL 3
+#define NPCX_DEVALTA_NO_VCC1_RST 4
+#define NPCX_DEVALTA_NO_PECI_EN 6
+#define NPCX_DEVALTA_UART_SL 7
+
+#define NPCX_DEVALTB_RXD_SL 0
+#define NPCX_DEVALTB_TXD_SL 1
+
+#define NPCX_DEVALTC_PS2_3_SL2 3
+#define NPCX_DEVALTC_TA1_TACH1_SL2 4
+#define NPCX_DEVALTC_TB1_TACH2_SL2 5
+#define NPCX_DEVALTC_TA2_SL2 6
+#define NPCX_DEVALTC_TB2_SL2 7
+
+/******************************************************************************/
+/* Development and Debug Support (DBG) Registers */
+#define NPCX_DBGCTRL REG8(NPCX_SCFG_BASE_ADDR + 0x074)
+#define NPCX_DBGFRZEN1 REG8(NPCX_SCFG_BASE_ADDR + 0x076)
+#define NPCX_DBGFRZEN2 REG8(NPCX_SCFG_BASE_ADDR + 0x077)
+#define NPCX_DBGFRZEN3 REG8(NPCX_SCFG_BASE_ADDR + 0x078)
+/* DBG register fields */
+#define NPCX_DBGFRZEN3_GLBL_FRZ_DIS 7
+
+
+/******************************************************************************/
+/* SMBus Registers */
+#define NPCX_SMBSDA(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x000)
+#define NPCX_SMBST(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x002)
+#define NPCX_SMBCST(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x004)
+#define NPCX_SMBCTL1(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x006)
+#define NPCX_SMBADDR1(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x008)
+#define NPCX_SMBTMR_ST(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x009)
+#define NPCX_SMBCTL2(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x00A)
+#define NPCX_SMBTMR_EN(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x00B)
+#define NPCX_SMBADDR2(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x00C)
+#define NPCX_SMBCTL3(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x00E)
+#define NPCX_SMBADDR3(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x010)
+#define NPCX_SMBADDR7(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x011)
+#define NPCX_SMBADDR4(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x012)
+#define NPCX_SMBADDR8(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x013)
+#define NPCX_SMBADDR5(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x014)
+#define NPCX_SMBADDR6(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x016)
+#define NPCX_SMBCST2(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x018)
+#define NPCX_SMBCST3(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x019)
+#define NPCX_SMBCTL4(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01A)
+#define NPCX_SMBSCLLT(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01C)
+#define NPCX_SMBSCLHT(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x01E)
+
+/* SMBus register fields */
+#define NPCX_SMBST_XMIT 0
+#define NPCX_SMBST_MASTER 1
+#define NPCX_SMBST_NMATCH 2
+#define NPCX_SMBST_STASTR 3
+#define NPCX_SMBST_NEGACK 4
+#define NPCX_SMBST_BER 5
+#define NPCX_SMBST_SDAST 6
+#define NPCX_SMBST_SLVSTP 7
+#define NPCX_SMBCST_BUSY 0
+#define NPCX_SMBCST_BB 1
+#define NPCX_SMBCST_MATCH 2
+#define NPCX_SMBCST_GCMATCH 3
+#define NPCX_SMBCST_TSDA 4
+#define NPCX_SMBCST_TGSCL 5
+#define NPCX_SMBCST_MATCHAF 6
+#define NPCX_SMBCST_ARPMATCH 7
+#define NPCX_SMBCST2_MATCHA1F 0
+#define NPCX_SMBCST2_MATCHA2F 1
+#define NPCX_SMBCST2_MATCHA3F 2
+#define NPCX_SMBCST2_MATCHA4F 3
+#define NPCX_SMBCST2_MATCHA5F 4
+#define NPCX_SMBCST2_MATCHA6F 5
+#define NPCX_SMBCST2_MATCHA7F 6
+#define NPCX_SMBCST2_INTSTS 7
+#define NPCX_SMBCST3_MATCHA8F 0
+#define NPCX_SMBCST3_MATCHA9F 1
+#define NPCX_SMBCST3_MATCHA10F 2
+#define NPCX_SMBCTL1_START 0
+#define NPCX_SMBCTL1_STOP 1
+#define NPCX_SMBCTL1_INTEN 2
+#define NPCX_SMBCTL1_ACK 4
+#define NPCX_SMBCTL1_GCMEN 5
+#define NPCX_SMBCTL1_NMINTE 6
+#define NPCX_SMBCTL1_STASTRE 7
+#define NPCX_SMBCTL2_ENABLE 0
+#define NPCX_SMBCTL3_ARPMEN 2
+#define NPCX_SMBCTL3_IDL_START 3
+#define NPCX_SMBCTL3_400K 4
+#define NPCX_SMBCTL3_SDA_LVL 6
+#define NPCX_SMBCTL3_SCL_LVL 7
+#define NPCX_SMBADDR1_SAEN 7
+#define NPCX_SMBADDR2_SAEN 7
+#define NPCX_SMBADDR3_SAEN 7
+#define NPCX_SMBADDR4_SAEN 7
+#define NPCX_SMBADDR5_SAEN 7
+#define NPCX_SMBADDR6_SAEN 7
+#define NPCX_SMBADDR7_SAEN 7
+#define NPCX_SMBADDR8_SAEN 7
+
+/******************************************************************************/
+/* Power Management Controller (PMC) Registers */
+#define NPCX_PMCSR REG8(NPCX_PMC_BASE_ADDR + 0x000)
+#define NPCX_ENIDL_CTL REG8(NPCX_PMC_BASE_ADDR + 0x003)
+#define NPCX_DISIDL_CTL REG8(NPCX_PMC_BASE_ADDR + 0x004)
+#define NPCX_DISIDL_CTL1 REG8(NPCX_PMC_BASE_ADDR + 0x005)
+#define NPCX_PWDWN_CTL(offset) REG8(NPCX_PMC_BASE_ADDR + 0x008 + offset)
+#define NPCX_PWDWN_CTL_COUNT 6
+
+/* PMC register fields */
+#define NPCX_PMCSR_DI_INSTW 0
+#define NPCX_PMCSR_DHF 1
+#define NPCX_PMCSR_IDLE 2
+#define NPCX_PMCSR_NWBI 3
+#define NPCX_PMCSR_OHFC 6
+#define NPCX_PMCSR_OLFC 7
+#define NPCX_DISIDL_CTL_RAM_DID 5
+#define NPCX_ENIDL_CTL_ADC_LFSL 7
+#define NPCX_ENIDL_CTL_LP_WK_CTL 6
+#define NPCX_ENIDL_CTL_PECI_ENI 2
+#define NPCX_ENIDL_CTL_ADC_ACC_DIS 1
+#define NPCX_PWDWN_CTL1_KBS_PD 0
+#define NPCX_PWDWN_CTL1_SDP_PD 1
+#define NPCX_PWDWN_CTL1_FIU_PD 2
+#define NPCX_PWDWN_CTL1_PS2_PD 3
+#define NPCX_PWDWN_CTL1_UART_PD 4
+#define NPCX_PWDWN_CTL1_MFT1_PD 5
+#define NPCX_PWDWN_CTL1_MFT2_PD 6
+#define NPCX_PWDWN_CTL1_MFT3_PD 7
+#define NPCX_PWDWN_CTL2_PWM0_PD 0
+#define NPCX_PWDWN_CTL2_PWM1_PD 1
+#define NPCX_PWDWN_CTL2_PWM2_PD 2
+#define NPCX_PWDWN_CTL2_PWM3_PD 3
+#define NPCX_PWDWN_CTL2_PWM4_PD 4
+#define NPCX_PWDWN_CTL2_PWM5_PD 5
+#define NPCX_PWDWN_CTL2_PWM6_PD 6
+#define NPCX_PWDWN_CTL2_PWM7_PD 7
+#define NPCX_PWDWN_CTL3_SMB0_PD 0
+#define NPCX_PWDWN_CTL3_SMB1_PD 1
+#define NPCX_PWDWN_CTL3_SMB2_PD 2
+#define NPCX_PWDWN_CTL3_SMB3_PD 3
+#define NPCX_PWDWN_CTL3_GMDA_PD 7
+#define NPCX_PWDWN_CTL4_ITIM1_PD 0
+#define NPCX_PWDWN_CTL4_ITIM2_PD 1
+#define NPCX_PWDWN_CTL4_ITIM3_PD 2
+#define NPCX_PWDWN_CTL4_ADC_PD 4
+#define NPCX_PWDWN_CTL4_PECI_PD 5
+#define NPCX_PWDWN_CTL4_PWM6_PD 6
+#define NPCX_PWDWN_CTL4_SPIP_PD 7
+#define NPCX_PWDWN_CTL5_MRFSH_DIS 2
+#define NPCX_PWDWN_CTL5_C2HACC_PD 3
+#define NPCX_PWDWN_CTL5_SHM_REG_PD 4
+#define NPCX_PWDWN_CTL5_SHM_PD 5
+#define NPCX_PWDWN_CTL5_DP80_PD 6
+#define NPCX_PWDWN_CTL5_MSWC_PD 7
+#define NPCX_PWDWN_CTL6_ITIM4_PD 0
+#define NPCX_PWDWN_CTL6_ITIM5_PD 1
+#define NPCX_PWDWN_CTL6_ITIM6_PD 2
+#define NPCX_PWDWN_CTL6_ESPI_PD 7
+
+/*
+ * PMC enumeration
+ * Offsets from CGC_BASE registers for each peripheral.
+ */
+enum {
+ CGC_OFFSET_KBS = 0,
+ CGC_OFFSET_UART = 0,
+ CGC_OFFSET_FAN = 0,
+ CGC_OFFSET_FIU = 0,
+ CGC_OFFSET_PWM = 1,
+ CGC_OFFSET_I2C = 2,
+ CGC_OFFSET_ADC = 3,
+ CGC_OFFSET_TIMER = 3,
+ CGC_OFFSET_LPC = 4,
+ CGC_OFFSET_ESPI = 5,
+};
+
+#define CGC_KBS_MASK (1 << NPCX_PWDWN_CTL1_KBS_PD)
+#define CGC_UART_MASK (1 << NPCX_PWDWN_CTL1_UART_PD)
+#define CGC_FAN_MASK (1 << NPCX_PWDWN_CTL1_MFT1_PD)
+#define CGC_FIU_MASK (1 << NPCX_PWDWN_CTL1_FIU_PD)
+#define CGC_PWM_MASK (1 << NPCX_PWDWN_CTL2_PWM2_PD)
+#define CGC_I2C_MASK ((1 << NPCX_PWDWN_CTL3_SMB0_PD) | \
+ (1 << NPCX_PWDWN_CTL3_SMB1_PD) | \
+ (1 << NPCX_PWDWN_CTL3_SMB2_PD))
+#define CGC_ADC_MASK (1 << NPCX_PWDWN_CTL4_ADC_PD)
+#define CGC_TIMER_MASK ((1 << NPCX_PWDWN_CTL4_ITIM1_PD) | \
+ (1 << NPCX_PWDWN_CTL4_ITIM2_PD) | \
+ (1 << NPCX_PWDWN_CTL4_ITIM3_PD))
+#define CGC_LPC_MASK ((1 << NPCX_PWDWN_CTL5_C2HACC_PD) | \
+ (1 << NPCX_PWDWN_CTL5_SHM_REG_PD) | \
+ (1 << NPCX_PWDWN_CTL5_SHM_PD) | \
+ (1 << NPCX_PWDWN_CTL5_DP80_PD) | \
+ (1 << NPCX_PWDWN_CTL5_MSWC_PD))
+#define CGC_ESPI_MASK (1 << NPCX_PWDWN_CTL6_ESPI_PD)
+
+/******************************************************************************/
+/* Flash Interface Unit (FIU) Registers */
+#define NPCX_FIU_CFG REG8(NPCX_FIU_BASE_ADDR + 0x000)
+#define NPCX_BURST_CFG REG8(NPCX_FIU_BASE_ADDR + 0x001)
+#define NPCX_RESP_CFG REG8(NPCX_FIU_BASE_ADDR + 0x002)
+#define NPCX_SPI_FL_CFG REG8(NPCX_FIU_BASE_ADDR + 0x014)
+#define NPCX_UMA_CODE REG8(NPCX_FIU_BASE_ADDR + 0x016)
+#define NPCX_UMA_AB0 REG8(NPCX_FIU_BASE_ADDR + 0x017)
+#define NPCX_UMA_AB1 REG8(NPCX_FIU_BASE_ADDR + 0x018)
+#define NPCX_UMA_AB2 REG8(NPCX_FIU_BASE_ADDR + 0x019)
+#define NPCX_UMA_DB0 REG8(NPCX_FIU_BASE_ADDR + 0x01A)
+#define NPCX_UMA_DB1 REG8(NPCX_FIU_BASE_ADDR + 0x01B)
+#define NPCX_UMA_DB2 REG8(NPCX_FIU_BASE_ADDR + 0x01C)
+#define NPCX_UMA_DB3 REG8(NPCX_FIU_BASE_ADDR + 0x01D)
+#define NPCX_UMA_CTS REG8(NPCX_FIU_BASE_ADDR + 0x01E)
+#define NPCX_UMA_ECTS REG8(NPCX_FIU_BASE_ADDR + 0x01F)
+#define NPCX_UMA_DB0_3 REG32(NPCX_FIU_BASE_ADDR + 0x020)
+#define NPCX_FIU_RD_CMD REG8(NPCX_FIU_BASE_ADDR + 0x030)
+#define NPCX_FIU_DMM_CYC REG8(NPCX_FIU_BASE_ADDR + 0x032)
+#define NPCX_FIU_EXT_CFG REG8(NPCX_FIU_BASE_ADDR + 0x033)
+#define NPCX_FIU_UMA_AB0_3 REG32(NPCX_FIU_BASE_ADDR + 0x034)
+
+/* FIU register fields */
+#define NPCX_RESP_CFG_IAD_EN 0
+#define NPCX_RESP_CFG_DEV_SIZE_EX 2
+#define NPCX_UMA_CTS_A_SIZE 3
+#define NPCX_UMA_CTS_C_SIZE 4
+#define NPCX_UMA_CTS_RD_WR 5
+#define NPCX_UMA_CTS_DEV_NUM 6
+#define NPCX_UMA_CTS_EXEC_DONE 7
+#define NPCX_UMA_ECTS_SW_CS0 0
+#define NPCX_UMA_ECTS_SW_CS1 1
+#define NPCX_UMA_ECTS_SEC_CS 2
+
+/******************************************************************************/
+/* Shared Memory (SHM) Registers */
+#define NPCX_SMC_STS REG8(NPCX_SHM_BASE_ADDR + 0x000)
+#define NPCX_SMC_CTL REG8(NPCX_SHM_BASE_ADDR + 0x001)
+#define NPCX_SHM_CTL REG8(NPCX_SHM_BASE_ADDR + 0x002)
+#define NPCX_IMA_WIN_SIZE REG8(NPCX_SHM_BASE_ADDR + 0x005)
+#define NPCX_WIN_SIZE REG8(NPCX_SHM_BASE_ADDR + 0x007)
+#define NPCX_SHAW_SEM(win) REG8(NPCX_SHM_BASE_ADDR + 0x008 + (win))
+#define NPCX_IMA_SEM REG8(NPCX_SHM_BASE_ADDR + 0x00B)
+#define NPCX_SHCFG REG8(NPCX_SHM_BASE_ADDR + 0x00E)
+#define NPCX_WIN_WR_PROT(win) REG8(NPCX_SHM_BASE_ADDR + 0x010 + (win*2L))
+#define NPCX_WIN_RD_PROT(win) REG8(NPCX_SHM_BASE_ADDR + 0x011 + (win*2L))
+#define NPCX_IMA_WR_PROT REG8(NPCX_SHM_BASE_ADDR + 0x016)
+#define NPCX_IMA_RD_PROT REG8(NPCX_SHM_BASE_ADDR + 0x017)
+#define NPCX_WIN_BASE(win) REG32(NPCX_SHM_BASE_ADDR + 0x020 + (win*4L))
+
+#define NPCX_PWIN_BASEI(win) REG16(NPCX_SHM_BASE_ADDR + 0x020 + (win*4L))
+#define NPCX_PWIN_SIZEI(win) REG16(NPCX_SHM_BASE_ADDR + 0x022 + (win*4L))
+
+#define NPCX_IMA_BASE REG32(NPCX_SHM_BASE_ADDR + 0x02C)
+#define NPCX_RST_CFG REG8(NPCX_SHM_BASE_ADDR + 0x03A)
+#define NPCX_DP80BUF REG16(NPCX_SHM_BASE_ADDR + 0x040)
+#define NPCX_DP80STS REG8(NPCX_SHM_BASE_ADDR + 0x042)
+#define NPCX_DP80CTL REG8(NPCX_SHM_BASE_ADDR + 0x044)
+#define NPCX_HOFS_STS REG8(NPCX_SHM_BASE_ADDR + 0x048)
+#define NPCX_HOFS_CTL REG8(NPCX_SHM_BASE_ADDR + 0x049)
+#define NPCX_COFS2 REG16(NPCX_SHM_BASE_ADDR + 0x04A)
+#define NPCX_COFS1 REG16(NPCX_SHM_BASE_ADDR + 0x04C)
+#define NPCX_IHOFS2 REG16(NPCX_SHM_BASE_ADDR + 0x050)
+#define NPCX_IHOFS1 REG16(NPCX_SHM_BASE_ADDR + 0x052)
+#define NPCX_SHM_VER REG8(NPCX_SHM_BASE_ADDR + 0x07F)
+
+
+/* SHM register fields */
+#define NPCX_SMC_STS_HRERR 0
+#define NPCX_SMC_STS_HWERR 1
+#define NPCX_SMC_STS_HSEM1W 4
+#define NPCX_SMC_STS_HSEM2W 5
+#define NPCX_SMC_STS_SHM_ACC 6
+#define NPCX_SMC_CTL_HERR_IE 2
+#define NPCX_SMC_CTL_HSEM1_IE 3
+#define NPCX_SMC_CTL_HSEM2_IE 4
+#define NPCX_SMC_CTL_ACC_IE 5
+#define NPCX_SMC_CTL_PREF_EN 6
+#define NPCX_SMC_CTL_HOSTWAIT 7
+#define NPCX_FLASH_SIZE_STALL_HOST 6
+#define NPCX_FLASH_SIZE_RD_BURST 7
+#define NPCX_WIN_PROT_RW1L_RP 0
+#define NPCX_WIN_PROT_RW1L_WP 1
+#define NPCX_WIN_PROT_RW1H_RP 2
+#define NPCX_WIN_PROT_RW1H_WP 3
+#define NPCX_WIN_PROT_RW2L_RP 4
+#define NPCX_WIN_PROT_RW2L_WP 5
+#define NPCX_WIN_PROT_RW2H_RP 6
+#define NPCX_WIN_PROT_RW2H_WP 7
+#define NPCX_PWIN_SIZEI_RPROT 13
+#define NPCX_PWIN_SIZEI_WPROT 14
+#define NPCX_CSEM2 6
+#define NPCX_CSEM3 7
+#define NPCX_DP80STS_FWR 5
+#define NPCX_DP80STS_FNE 6
+#define NPCX_DP80STS_FOR 7
+#define NPCX_DP80CTL_DP80EN 0
+#define NPCX_DP80CTL_SYNCEN 1
+#define NPCX_DP80CTL_RFIFO 4
+#define NPCX_DP80CTL_CIEN 5
+
+/******************************************************************************/
+/* KBC Registers */
+#define NPCX_HICTRL REG8(NPCX_KBC_BASE_ADDR + 0x000)
+#define NPCX_HIIRQC REG8(NPCX_KBC_BASE_ADDR + 0x002)
+#define NPCX_HIKMST REG8(NPCX_KBC_BASE_ADDR + 0x004)
+#define NPCX_HIKDO REG8(NPCX_KBC_BASE_ADDR + 0x006)
+#define NPCX_HIMDO REG8(NPCX_KBC_BASE_ADDR + 0x008)
+#define NPCX_KBCVER REG8(NPCX_KBC_BASE_ADDR + 0x009)
+#define NPCX_HIKMDI REG8(NPCX_KBC_BASE_ADDR + 0x00A)
+#define NPCX_SHIKMDI REG8(NPCX_KBC_BASE_ADDR + 0x00B)
+
+/* KBC register field */
+#define NPCX_HICTRL_OBFKIE 0
+#define NPCX_HICTRL_OBFMIE 1
+
+/******************************************************************************/
+/* PM Channel Registers */
+#define NPCX_HIPMST(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x000)
+#define NPCX_HIPMDO(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x002)
+#define NPCX_HIPMDI(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x004)
+#define NPCX_SHIPMDI(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x005)
+#define NPCX_HIPMDOC(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x006)
+#define NPCX_HIPMDOM(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x008)
+#define NPCX_HIPMDIC(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x00A)
+#define NPCX_HIPMCTL(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x00C)
+#define NPCX_HIPMCTL2(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x00D)
+#define NPCX_HIPMIC(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x00E)
+#define NPCX_HIPMIE(n) REG8(NPCX_PM_CH_BASE_ADDR(n) + 0x010)
+
+/* PM Channel register field */
+#define NPCX_HIPMIE_SCIE 1
+#define NPCX_HIPMIE_SMIE 2
+
+/*
+ * PM Channel enumeration
+ */
+enum PM_CHANNEL_T {
+ PM_CHAN_1,
+ PM_CHAN_2,
+ PM_CHAN_3,
+ PM_CHAN_4
+};
+
+/******************************************************************************/
+/* SuperI/O Internal Bus (SIB) Registers */
+#define NPCX_IHIOA REG16(NPCX_SIB_BASE_ADDR + 0x000)
+#define NPCX_IHD REG8(NPCX_SIB_BASE_ADDR + 0x002)
+#define NPCX_LKSIOHA REG16(NPCX_SIB_BASE_ADDR + 0x004)
+#define NPCX_SIOLV REG16(NPCX_SIB_BASE_ADDR + 0x006)
+#define NPCX_CRSMAE REG16(NPCX_SIB_BASE_ADDR + 0x008)
+#define NPCX_SIBCTRL REG8(NPCX_SIB_BASE_ADDR + 0x00A)
+#define NPCX_C2H_VER REG8(NPCX_SIB_BASE_ADDR + 0x00E)
+/* SIB register fields */
+#define NPCX_SIBCTRL_CSAE 0
+#define NPCX_SIBCTRL_CSRD 1
+#define NPCX_SIBCTRL_CSWR 2
+#define NPCX_LKSIOHA_LKCFG 0
+#define NPCX_CRSMAE_CFGAE 0
+
+/******************************************************************************/
+/* Battery-Backed RAM (BBRAM) Registers */
+#define NPCX_BKUP_STS REG8(NPCX_BBRAM_BASE_ADDR + 0x000)
+#define NPCX_BBRAM(offset) REG8(NPCX_BBRAM_BASE_ADDR + 0x001 + offset)
+
+/* BBRAM register fields */
+#define NPCX_BKUP_STS_IBBR 7
+#define NPCX_BBRAM_SIZE 63 /* Size of BBRAM */
+
+/******************************************************************************/
+/* Timer Watch Dog (TWD) Registers */
+#define NPCX_TWCFG REG8(NPCX_TWD_BASE_ADDR + 0x000)
+#define NPCX_TWCP REG8(NPCX_TWD_BASE_ADDR + 0x002)
+#define NPCX_TWDT0 REG16(NPCX_TWD_BASE_ADDR + 0x004)
+#define NPCX_T0CSR REG8(NPCX_TWD_BASE_ADDR + 0x006)
+#define NPCX_WDCNT REG8(NPCX_TWD_BASE_ADDR + 0x008)
+#define NPCX_WDSDM REG8(NPCX_TWD_BASE_ADDR + 0x00A)
+#define NPCX_TWMT0 REG16(NPCX_TWD_BASE_ADDR + 0x00C)
+#define NPCX_TWMWD REG8(NPCX_TWD_BASE_ADDR + 0x00E)
+#define NPCX_WDCP REG8(NPCX_TWD_BASE_ADDR + 0x010)
+
+/* TWD register fields */
+#define NPCX_TWCFG_LTWCFG 0
+#define NPCX_TWCFG_LTWCP 1
+#define NPCX_TWCFG_LTWDT0 2
+#define NPCX_TWCFG_LWDCNT 3
+#define NPCX_TWCFG_WDCT0I 4
+#define NPCX_TWCFG_WDSDME 5
+#define NPCX_TWCFG_WDRST_MODE 6
+#define NPCX_TWCFG_WDC2POR 7
+#define NPCX_T0CSR_RST 0
+#define NPCX_T0CSR_TC 1
+#define NPCX_T0CSR_WDLTD 3
+#define NPCX_T0CSR_WDRST_STS 4
+#define NPCX_T0CSR_WD_RUN 5
+#define NPCX_T0CSR_TESDIS 7
+
+/******************************************************************************/
+/* ADC Registers */
+#define NPCX_ADCSTS REG16(NPCX_ADC_BASE_ADDR + 0x000)
+#define NPCX_ADCCNF REG16(NPCX_ADC_BASE_ADDR + 0x002)
+#define NPCX_ATCTL REG16(NPCX_ADC_BASE_ADDR + 0x004)
+#define NPCX_ASCADD REG16(NPCX_ADC_BASE_ADDR + 0x006)
+#define NPCX_ADCCS REG16(NPCX_ADC_BASE_ADDR + 0x008)
+#define NPCX_CHNDAT(n) REG16(NPCX_ADC_BASE_ADDR + 0x040 + (2L*(n)))
+#define NPCX_ADCCNF2 REG16(NPCX_ADC_BASE_ADDR + 0x020)
+#define NPCX_GENDLY REG16(NPCX_ADC_BASE_ADDR + 0x022)
+#define NPCX_MEAST REG16(NPCX_ADC_BASE_ADDR + 0x026)
+
+/* ADC register fields */
+#define NPCX_ATCTL_SCLKDIV 0
+#define NPCX_ATCTL_DLY 8
+#define NPCX_ASCADD_SADDR 0
+#define NPCX_ADCSTS_EOCEV 0
+#define NPCX_ADCCNF_ADCMD 1
+#define NPCX_ADCCNF_ADCRPTC 3
+#define NPCX_ADCCNF_INTECEN 6
+#define NPCX_ADCCNF_START 4
+#define NPCX_ADCCNF_ADCEN 0
+#define NPCX_ADCCNF_STOP 11
+#define NPCX_CHNDAT_CHDAT 0
+#define NPCX_CHNDAT_NEW 15
+/******************************************************************************/
+/* SPI Register */
+#define NPCX_SPI_DATA REG16(NPCX_SPI_BASE_ADDR + 0x00)
+#define NPCX_SPI_CTL1 REG16(NPCX_SPI_BASE_ADDR + 0x02)
+#define NPCX_SPI_STAT REG8(NPCX_SPI_BASE_ADDR + 0x04)
+
+/* SPI register fields */
+#define NPCX_SPI_CTL1_SPIEN 0
+#define NPCX_SPI_CTL1_SNM 1
+#define NPCX_SPI_CTL1_MOD 2
+#define NPCX_SPI_CTL1_EIR 5
+#define NPCX_SPI_CTL1_EIW 6
+#define NPCX_SPI_CTL1_SCM 7
+#define NPCX_SPI_CTL1_SCIDL 8
+#define NPCX_SPI_CTL1_SCDV 9
+#define NPCX_SPI_STAT_BSY 0
+#define NPCX_SPI_STAT_RBF 1
+
+/******************************************************************************/
+/* PECI Registers */
+
+#define NPCX_PECI_CTL_STS REG8(NPCX_PECI_BASE_ADDR + 0x000)
+#define NPCX_PECI_RD_LENGTH REG8(NPCX_PECI_BASE_ADDR + 0x001)
+#define NPCX_PECI_ADDR REG8(NPCX_PECI_BASE_ADDR + 0x002)
+#define NPCX_PECI_CMD REG8(NPCX_PECI_BASE_ADDR + 0x003)
+#define NPCX_PECI_CTL2 REG8(NPCX_PECI_BASE_ADDR + 0x004)
+#define NPCX_PECI_INDEX REG8(NPCX_PECI_BASE_ADDR + 0x005)
+#define NPCX_PECI_IDATA REG8(NPCX_PECI_BASE_ADDR + 0x006)
+#define NPCX_PECI_WR_LENGTH REG8(NPCX_PECI_BASE_ADDR + 0x007)
+#define NPCX_PECI_CFG REG8(NPCX_PECI_BASE_ADDR + 0x009)
+#define NPCX_PECI_RATE REG8(NPCX_PECI_BASE_ADDR + 0x00F)
+#define NPCX_PECI_DATA_IN(i) REG8(NPCX_PECI_BASE_ADDR + 0x010 + (i))
+#define NPCX_PECI_DATA_OUT(i) REG8(NPCX_PECI_BASE_ADDR + 0x010 + (i))
+
+/* PECI register fields */
+#define NPCX_PECI_CTL_STS_START_BUSY 0
+#define NPCX_PECI_CTL_STS_DONE 1
+#define NPCX_PECI_CTL_STS_AVL_ERR 2
+#define NPCX_PECI_CTL_STS_CRC_ERR 3
+#define NPCX_PECI_CTL_STS_ABRT_ERR 4
+#define NPCX_PECI_CTL_STS_AWFCS_EN 5
+#define NPCX_PECI_CTL_STS_DONE_EN 6
+#define NPCX_ESTRPST_PECIST 0
+#define SFT_STRP_CFG_CK50 5
+
+/******************************************************************************/
+/* PWM Registers */
+#define NPCX_PRSC(n) REG16(NPCX_PWM_BASE_ADDR(n) + 0x000)
+#define NPCX_CTR(n) REG16(NPCX_PWM_BASE_ADDR(n) + 0x002)
+#define NPCX_PWMCTL(n) REG8(NPCX_PWM_BASE_ADDR(n) + 0x004)
+#define NPCX_DCR(n) REG16(NPCX_PWM_BASE_ADDR(n) + 0x006)
+#define NPCX_PWMCTLEX(n) REG8(NPCX_PWM_BASE_ADDR(n) + 0x00C)
+
+/* PWM register fields */
+#define NPCX_PWMCTL_INVP 0
+#define NPCX_PWMCTL_CKSEL 1
+#define NPCX_PWMCTL_HB_DC_CTL 2
+#define NPCX_PWMCTL_PWR 7
+#define NPCX_PWMCTLEX_FCK_SEL 4
+#define NPCX_PWMCTLEX_OD_OUT 7
+/******************************************************************************/
+/* MFT Registers */
+#define NPCX_TCNT1(n) REG16(NPCX_MFT_BASE_ADDR(n) + 0x000)
+#define NPCX_TCRA(n) REG16(NPCX_MFT_BASE_ADDR(n) + 0x002)
+#define NPCX_TCRB(n) REG16(NPCX_MFT_BASE_ADDR(n) + 0x004)
+#define NPCX_TCNT2(n) REG16(NPCX_MFT_BASE_ADDR(n) + 0x006)
+#define NPCX_TPRSC(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x008)
+#define NPCX_TCKC(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x00A)
+#define NPCX_TMCTRL(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x00C)
+#define NPCX_TECTRL(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x00E)
+#define NPCX_TECLR(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x010)
+#define NPCX_TIEN(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x012)
+#define NPCX_TWUEN(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x01A)
+#define NPCX_TCFG(n) REG8(NPCX_MFT_BASE_ADDR(n) + 0x01C)
+
+/* MFT register fields */
+#define NPCX_TMCTRL_MDSEL 0
+#define NPCX_TCKC_LOW_PWR 7
+#define NPCX_TCKC_PLS_ACC_CLK 6
+#define NPCX_TCKC_C1CSEL 0
+#define NPCX_TCKC_C2CSEL 3
+#define NPCX_TMCTRL_TAEN 5
+#define NPCX_TMCTRL_TBEN 6
+#define NPCX_TMCTRL_TAEDG 3
+#define NPCX_TMCTRL_TBEDG 4
+#define NPCX_TCFG_TADBEN 6
+#define NPCX_TCFG_TBDBEN 7
+#define NPCX_TECTRL_TAPND 0
+#define NPCX_TECTRL_TBPND 1
+#define NPCX_TECTRL_TCPND 2
+#define NPCX_TECTRL_TDPND 3
+#define NPCX_TECLR_TACLR 0
+#define NPCX_TECLR_TBCLR 1
+#define NPCX_TECLR_TCCLR 2
+#define NPCX_TECLR_TDCLR 3
+#define NPCX_TIEN_TAIEN 0
+#define NPCX_TIEN_TBIEN 1
+#define NPCX_TIEN_TCIEN 2
+#define NPCX_TIEN_TDIEN 3
+#define NPCX_TWUEN_TAWEN 0
+#define NPCX_TWUEN_TBWEN 1
+#define NPCX_TWUEN_TCWEN 2
+#define NPCX_TWUEN_TDWEN 3
+/******************************************************************************/
+/*ITIM16 Define*/
+#define ITIM16_INT(module) CONCAT2(NPCX_IRQ_, module)
+
+/* ITIM16 registers */
+#define NPCX_ITCNT(n) REG8(NPCX_ITIM16_BASE_ADDR(n) + 0x000)
+#define NPCX_ITPRE(n) REG8(NPCX_ITIM16_BASE_ADDR(n) + 0x001)
+#define NPCX_ITCNT16(n) REG16(NPCX_ITIM16_BASE_ADDR(n) + 0x002)
+#define NPCX_ITCTS(n) REG8(NPCX_ITIM16_BASE_ADDR(n) + 0x004)
+
+/* ITIM16 register fields */
+#define NPCX_ITIM16_TO_STS 0
+#define NPCX_ITIM16_TO_IE 2
+#define NPCX_ITIM16_TO_WUE 3
+#define NPCX_ITIM16_CKSEL 4
+#define NPCX_ITIM16_ITEN 7
+
+/* ITIM16 enumeration*/
+enum ITIM16_MODULE_T {
+ ITIM16_1,
+ ITIM16_2,
+ ITIM16_3,
+ ITIM16_4,
+ ITIM16_5,
+ ITIM16_6,
+ ITIM16_MODULE_COUNT,
+};
+
+/******************************************************************************/
+/* Monotonic Counter (MTC) Registers */
+#define NPCX_TTC REG32(NPCX_MTC_BASE_ADDR + 0x000)
+#define NPCX_WTC REG32(NPCX_MTC_BASE_ADDR + 0x004)
+#define NPCX_MTCTST REG8(NPCX_MTC_BASE_ADDR + 0x008)
+#define NPCX_MTCVER REG8(NPCX_MTC_BASE_ADDR + 0x00C)
+
+/* MTC register fields */
+#define NPCX_WTC_PTO 30
+#define NPCX_WTC_WIE 31
+
+/******************************************************************************/
+/* Low Power RAM definitions */
+#define NPCX_LPRAM_CTRL REG32(0x40001044)
+
+/******************************************************************************/
+/* Optional M4 Registers */
+#define CPU_DHCSR REG32(0xE000EDF0)
+#define CPU_MPU_CTRL REG32(0xE000ED94)
+#define CPU_MPU_RNR REG32(0xE000ED98)
+#define CPU_MPU_RBAR REG32(0xE000ED9C)
+#define CPU_MPU_RASR REG32(0xE000EDA0)
+
+
+/******************************************************************************/
+/* Flash Utiltiy definition */
+/*
+ * Flash commands for the W25Q16CV SPI flash
+ */
+#define CMD_READ_ID 0x9F
+#define CMD_WRITE_EN 0x06
+#define CMD_WRITE_STATUS 0x50
+#define CMD_READ_STATUS_REG 0x05
+#define CMD_READ_STATUS_REG2 0x35
+#define CMD_WRITE_STATUS_REG 0x01
+#define CMD_FLASH_PROGRAM 0x02
+#define CMD_SECTOR_ERASE 0x20
+#define CMD_PROGRAM_UINT_SIZE 0x08
+#define CMD_PAGE_SIZE 0x00
+#define CMD_READ_ID_TYPE 0x47
+#define CMD_FAST_READ 0x0B
+
+/*
+ * Status registers for the W25Q16CV SPI flash
+ */
+#define SPI_FLASH_SR2_SUS (1 << 7)
+#define SPI_FLASH_SR2_CMP (1 << 6)
+#define SPI_FLASH_SR2_LB3 (1 << 5)
+#define SPI_FLASH_SR2_LB2 (1 << 4)
+#define SPI_FLASH_SR2_LB1 (1 << 3)
+#define SPI_FLASH_SR2_QE (1 << 1)
+#define SPI_FLASH_SR2_SRP1 (1 << 0)
+#define SPI_FLASH_SR1_SRP0 (1 << 7)
+#define SPI_FLASH_SR1_SEC (1 << 6)
+#define SPI_FLASH_SR1_TB (1 << 5)
+#define SPI_FLASH_SR1_BP2 (1 << 4)
+#define SPI_FLASH_SR1_BP1 (1 << 3)
+#define SPI_FLASH_SR1_BP0 (1 << 2)
+#define SPI_FLASH_SR1_WEL (1 << 1)
+#define SPI_FLASH_SR1_BUSY (1 << 0)
+
+
+/* 0: F_CS0 1: F_CS1_1(GPIO86) 2:F_CS1_2(GPIOA6) */
+#define FIU_CHIP_SELECT 0
+/* Create UMA control mask */
+#define MASK(bit) (0x1 << (bit))
+#define A_SIZE 0x03 /* 0: No ADR field 1: 3-bytes ADR field */
+#define C_SIZE 0x04 /* 0: 1-Byte CMD field 1:No CMD field */
+#define RD_WR 0x05 /* 0: Read 1: Write */
+#define DEV_NUM 0x06 /* 0: PVT is used 1: SHD is used */
+#define EXEC_DONE 0x07
+#define D_SIZE_1 0x01
+#define D_SIZE_2 0x02
+#define D_SIZE_3 0x03
+#define D_SIZE_4 0x04
+#define FLASH_SEL MASK(DEV_NUM)
+
+#define MASK_CMD_ONLY (MASK(EXEC_DONE) | FLASH_SEL)
+#define MASK_CMD_ADR (MASK(EXEC_DONE) | FLASH_SEL | MASK(A_SIZE))
+#define MASK_CMD_ADR_WR (MASK(EXEC_DONE) | FLASH_SEL | MASK(RD_WR) \
+ |MASK(A_SIZE) | D_SIZE_1)
+#define MASK_RD_1BYTE (MASK(EXEC_DONE) | FLASH_SEL | MASK(C_SIZE) | D_SIZE_1)
+#define MASK_RD_2BYTE (MASK(EXEC_DONE) | FLASH_SEL | MASK(C_SIZE) | D_SIZE_2)
+#define MASK_RD_3BYTE (MASK(EXEC_DONE) | FLASH_SEL | MASK(C_SIZE) | D_SIZE_3)
+#define MASK_RD_4BYTE (MASK(EXEC_DONE) | FLASH_SEL | MASK(C_SIZE) | D_SIZE_4)
+#define MASK_CMD_RD_1BYTE (MASK(EXEC_DONE) | FLASH_SEL | D_SIZE_1)
+#define MASK_CMD_RD_2BYTE (MASK(EXEC_DONE) | FLASH_SEL | D_SIZE_2)
+#define MASK_CMD_RD_3BYTE (MASK(EXEC_DONE) | FLASH_SEL | D_SIZE_3)
+#define MASK_CMD_RD_4BYTE (MASK(EXEC_DONE) | FLASH_SEL | D_SIZE_4)
+#define MASK_CMD_WR_ONLY (MASK(EXEC_DONE) | FLASH_SEL | MASK(RD_WR))
+#define MASK_CMD_WR_1BYTE (MASK(EXEC_DONE) | FLASH_SEL | MASK(RD_WR) \
+ | MASK(C_SIZE) | D_SIZE_1)
+#define MASK_CMD_WR_2BYTE (MASK(EXEC_DONE) | FLASH_SEL | MASK(RD_WR) \
+ | MASK(C_SIZE) | D_SIZE_2)
+#define MASK_CMD_WR_ADR (MASK(EXEC_DONE) | FLASH_SEL | MASK(RD_WR) \
+ | MASK(A_SIZE))
+
+#endif /* __CROS_EC_REGISTERS_H */
diff --git a/chip/npcx/spi.c b/chip/npcx/spi.c
new file mode 100644
index 0000000000..c2802fea4f
--- /dev/null
+++ b/chip/npcx/spi.c
@@ -0,0 +1,242 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* SPI module for Chrome EC */
+
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "clock.h"
+#include "clock_chip.h"
+#include "registers.h"
+#include "spi.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+/* Console output macros */
+#if !DEBUG_SPI
+#define CPUTS(...)
+#define CPRINTS(...)
+#else
+#define CPUTS(outstr) cputs(CC_SPI, outstr)
+#define CPRINTS(format, args...) cprints(CC_SPI, format, ## args)
+#endif
+
+/* SPI IP as SPI master */
+#define SPI_CLK 8000000
+/**
+ * Clear SPI data buffer.
+ *
+ * @param none
+ * @return none.
+ */
+static void clear_databuf(void)
+{
+ volatile uint8_t dummy __attribute__((unused));
+ while (IS_BIT_SET(NPCX_SPI_STAT, NPCX_SPI_STAT_RBF))
+ dummy = NPCX_SPI_DATA;
+}
+
+/**
+ * Preset SPI operation clock.
+ *
+ * @param none
+ * @return none
+ * @notes changed when initial or HOOK_FREQ_CHANGE command
+ */
+void spi_freq_changed(void)
+{
+ uint8_t prescaler_divider = 0;
+
+ /* Set clock prescaler divider to SPI module*/
+ prescaler_divider = (uint8_t)((uint32_t)clock_get_apb2_freq()
+ / 2 / SPI_CLK);
+ if (prescaler_divider >= 1)
+ prescaler_divider = prescaler_divider - 1;
+ if (prescaler_divider > 0x7F)
+ prescaler_divider = 0x7F;
+
+ /* Set core clock division factor in order to obtain the SPI clock */
+ NPCX_SPI_CTL1 = (NPCX_SPI_CTL1&(~(((1<<7)-1)<<NPCX_SPI_CTL1_SCDV)))
+ |(prescaler_divider<<NPCX_SPI_CTL1_SCDV);
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, spi_freq_changed, HOOK_PRIO_DEFAULT);
+
+/**
+ * Set SPI enabled.
+ *
+ * @param enable enabled flag
+ * @return success
+ */
+int spi_enable(int enable)
+{
+ if (enable) {
+ /* Enabling spi module for gpio configuration */
+ gpio_config_module(MODULE_SPI, 1);
+ /* GPIO No SPI Select */
+ CLEAR_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_GPIO_NO_SPIP);
+
+ /* Make sure CS# is a GPIO output mode. */
+ gpio_set_flags(GPIO_SPI_CS_L, GPIO_OUTPUT);
+ /* Make sure CS# is deselected */
+ gpio_set_level(GPIO_SPI_CS_L, 1);
+ /* Enabling spi module */
+ SET_BIT(NPCX_SPI_CTL1, NPCX_SPI_CTL1_SPIEN);
+ } else {
+ /* Disabling spi module */
+ CLEAR_BIT(NPCX_SPI_CTL1, NPCX_SPI_CTL1_SPIEN);
+ /* Make sure CS# is deselected */
+ gpio_set_level(GPIO_SPI_CS_L, 1);
+ gpio_set_flags(GPIO_SPI_CS_L, GPIO_ODR_HIGH);
+ /* Disabling spi module for gpio configuration */
+ gpio_config_module(MODULE_SPI, 0);
+ /* GPIO No SPI Select */
+ SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_GPIO_NO_SPIP);
+ }
+ return EC_SUCCESS;
+}
+
+
+/**
+ * Flush an SPI transaction and receive data from slave.
+ *
+ * @param txdata transfer data
+ * @param txlen transfer length
+ * @param rxdata receive data
+ * @param rxlen receive length
+ * @return success
+ * @notes set master transaction mode in npcx chip
+ */
+int spi_transaction(const uint8_t *txdata, int txlen,
+ uint8_t *rxdata, int rxlen)
+{
+ int i = 0;
+
+ /* Make sure CS# is a GPIO output mode. */
+ gpio_set_flags(GPIO_SPI_CS_L, GPIO_OUTPUT);
+ /* Make sure CS# is deselected */
+ gpio_set_level(GPIO_SPI_CS_L, 1);
+ /* Cleaning junk data in the buffer */
+ clear_databuf();
+ /* Assert CS# to start transaction */
+ gpio_set_level(GPIO_SPI_CS_L, 0);
+ CPRINTS("NPCX_SPI_DATA=%x", NPCX_SPI_DATA);
+ CPRINTS("NPCX_SPI_CTL1=%x", NPCX_SPI_CTL1);
+ CPRINTS("NPCX_SPI_STAT=%x", NPCX_SPI_STAT);
+ /* Writing the data */
+ for (i = 0; i < txlen; ++i) {
+ /* Making sure we can write */
+ while (IS_BIT_SET(NPCX_SPI_STAT, NPCX_SPI_STAT_BSY))
+ ;
+ /* Write the data */
+ NPCX_SPI_DATA = txdata[i];
+ CPRINTS("txdata[i]=%x", txdata[i]);
+ /* Waiting till reading is finished */
+ while (!IS_BIT_SET(NPCX_SPI_STAT, NPCX_SPI_STAT_RBF))
+ ;
+ /* Reading the (dummy) data */
+ clear_databuf();
+ }
+ CPRINTS("write end");
+ /* Reading the data */
+ for (i = 0; i < rxlen; ++i) {
+ /* Making sure we can write */
+ while (IS_BIT_SET(NPCX_SPI_STAT, NPCX_SPI_STAT_BSY))
+ ;
+ /* Write the (dummy) data */
+ NPCX_SPI_DATA = 0;
+ /* Wait till reading is finished */
+ while (!IS_BIT_SET(NPCX_SPI_STAT, NPCX_SPI_STAT_RBF))
+ ;
+ /* Reading the data */
+ rxdata[i] = (uint8_t)NPCX_SPI_DATA;
+ CPRINTS("rxdata[i]=%x", rxdata[i]);
+ }
+ /* Deassert CS# (high) to end transaction */
+ gpio_set_level(GPIO_SPI_CS_L, 1);
+
+ return EC_SUCCESS;
+}
+
+/**
+ * SPI initial.
+ *
+ * @param none
+ * @return none
+ */
+static void spi_init(void)
+{
+ /* Disabling spi module */
+ spi_enable(0);
+
+ /* Disabling spi irq */
+ CLEAR_BIT(NPCX_SPI_CTL1, NPCX_SPI_CTL1_EIR);
+ CLEAR_BIT(NPCX_SPI_CTL1, NPCX_SPI_CTL1_EIW);
+
+ /* Setting clocking mode to normal mode */
+ CLEAR_BIT(NPCX_SPI_CTL1, NPCX_SPI_CTL1_SCM);
+ /* Setting 8bit mode transfer */
+ CLEAR_BIT(NPCX_SPI_CTL1, NPCX_SPI_CTL1_MOD);
+ /* Set core clock division factor in order to obtain the spi clock */
+ spi_freq_changed();
+
+ /* We emit zeros in idle (default behaivor) */
+ CLEAR_BIT(NPCX_SPI_CTL1, NPCX_SPI_CTL1_SCIDL);
+
+ CPRINTS("nSPI_COMP=%x", IS_BIT_SET(NPCX_STRPST, NPCX_STRPST_SPI_COMP));
+ CPRINTS("SPI_SP_SEL=%x", IS_BIT_SET(NPCX_DEV_CTL4,
+ NPCX_DEV_CTL4_SPI_SP_SEL));
+ /* Cleaning junk data in the buffer */
+ clear_databuf();
+}
+DECLARE_HOOK(HOOK_INIT, spi_init, HOOK_PRIO_DEFAULT);
+
+/*****************************************************************************/
+/* Console commands */
+
+static int printrx(const char *desc, const uint8_t *txdata, int txlen,
+ int rxlen)
+{
+ uint8_t rxdata[32];
+ int rv;
+ int i;
+
+ rv = spi_transaction(txdata, txlen, rxdata, rxlen);
+ if (rv)
+ return rv;
+
+ CPRINTS("%-12s:", desc);
+ for (i = 0; i < rxlen; i++)
+ CPRINTS(" 0x%02x", rxdata[i]);
+ CPUTS("\n");
+ return EC_SUCCESS;
+}
+
+
+static int command_spirom(int argc, char **argv)
+{
+ uint8_t txmandev[] = {0x90, 0x00, 0x00, 0x00};
+ uint8_t txjedec[] = {0x9f};
+ uint8_t txunique[] = {0x4b, 0x00, 0x00, 0x00, 0x00};
+ uint8_t txsr1[] = {0x05};
+ uint8_t txsr2[] = {0x35};
+
+ spi_enable(1);
+
+ printrx("Man/Dev ID", txmandev, sizeof(txmandev), 2);
+ printrx("JEDEC ID", txjedec, sizeof(txjedec), 3);
+ printrx("Unique ID", txunique, sizeof(txunique), 8);
+ printrx("Status reg 1", txsr1, sizeof(txsr1), 1);
+ printrx("Status reg 2", txsr2, sizeof(txsr2), 1);
+
+ spi_enable(0);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(spirom, command_spirom,
+ NULL,
+ "Test reading SPI EEPROM",
+ NULL);
diff --git a/chip/npcx/spiflashfw/ec_npcxflash.c b/chip/npcx/spiflashfw/ec_npcxflash.c
new file mode 100644
index 0000000000..0a7dc2b2e2
--- /dev/null
+++ b/chip/npcx/spiflashfw/ec_npcxflash.c
@@ -0,0 +1,295 @@
+/* Copyright (c) 2014 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.
+ *
+ * NPCX5M5G SoC spi flash update tool
+ */
+
+#include <stdint.h>
+#include "registers.h"
+#include "config_chip.h"
+
+/*****************************************************************************/
+/* spi flash internal functions */
+void sspi_flash_pinmux(int enable)
+{
+ if (enable)
+ CLEAR_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI);
+ else
+ SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI);
+
+ /* CS0/1 pinmux */
+ if (enable) {
+#if (FIU_CHIP_SELECT == 1)
+ SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_F_SPI_CS1_1);
+#elif (FIU_CHIP_SELECT == 2)
+ SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_F_SPI_CS1_2);
+#endif
+ } else {
+ CLEAR_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_F_SPI_CS1_1);
+ CLEAR_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_F_SPI_CS1_2);
+ }
+}
+
+void sspi_flash_tristate(int enable)
+{
+ if (enable) {
+ /* Enable FIU pins to tri-state */
+ SET_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS);
+ } else {
+ /* Disable FIU pins to tri-state */
+ CLEAR_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS);
+ }
+}
+
+void sspi_flash_execute_cmd(uint8_t code, uint8_t cts)
+{
+ /* set UMA_CODE */
+ NPCX_UMA_CODE = code;
+ /* execute UMA flash transaction */
+ NPCX_UMA_CTS = cts;
+ while (IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
+ ;
+}
+
+void sspi_flash_cs_level(int level)
+{
+ /* level is high */
+ if (level) {
+ /* Set chip select to high */
+ SET_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1);
+ } else { /* level is low */
+ /* Set chip select to low */
+ CLEAR_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1);
+ }
+}
+
+void sspi_flash_wait_ready(void)
+{
+ uint8_t mask = SPI_FLASH_SR1_BUSY;
+
+ /* Chip Select down. */
+ sspi_flash_cs_level(0);
+ /* Command for Read status register */
+ sspi_flash_execute_cmd(CMD_READ_STATUS_REG, MASK_CMD_ONLY);
+ do {
+ /* Read status register */
+ NPCX_UMA_CTS = MASK_RD_1BYTE;
+ while (IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
+ ;
+ } while (NPCX_UMA_DB0 & mask); /* Wait for Busy clear */
+ /* Chip Select high. */
+ sspi_flash_cs_level(1);
+}
+
+int sspi_flash_write_enable(void)
+{
+ uint8_t mask = SPI_FLASH_SR1_WEL;
+ /* Write enable command */
+ sspi_flash_execute_cmd(CMD_WRITE_EN, MASK_CMD_ONLY);
+ /* Wait for flash is not busy */
+ sspi_flash_wait_ready();
+
+ if (NPCX_UMA_DB0 & mask)
+ return 1;
+ else
+ return 0;
+}
+
+void sspi_flash_set_address(uint32_t dest_addr)
+{
+ uint8_t *addr = (uint8_t *)&dest_addr;
+ /* Write address */
+ NPCX_UMA_AB2 = addr[2];
+ NPCX_UMA_AB1 = addr[1];
+ NPCX_UMA_AB0 = addr[0];
+}
+
+void sspi_flash_burst_write(unsigned int dest_addr, unsigned int bytes,
+ const char *data)
+{
+ unsigned int i;
+ /* Chip Select down. */
+ sspi_flash_cs_level(0);
+ /* Set erase address */
+ sspi_flash_set_address(dest_addr);
+ /* Start write */
+ sspi_flash_execute_cmd(CMD_FLASH_PROGRAM, MASK_CMD_WR_ADR);
+ for (i = 0; i < bytes; i++) {
+ sspi_flash_execute_cmd(*data, MASK_CMD_WR_ONLY);
+ data++;
+ }
+ /* Chip Select up */
+ sspi_flash_cs_level(1);
+}
+
+void sspi_flash_physical_clear_stsreg(void)
+{
+ /* Disable tri-state */
+ sspi_flash_tristate(0);
+ /* Enable write */
+ sspi_flash_write_enable();
+
+ NPCX_UMA_DB0 = 0x0;
+ NPCX_UMA_DB1 = 0x0;
+
+ /* Write status register 1/2 */
+ sspi_flash_execute_cmd(CMD_WRITE_STATUS_REG, MASK_CMD_WR_2BYTE);
+
+ /* Wait writing completed */
+ sspi_flash_wait_ready();
+
+ /* Read status register 1/2 */
+ sspi_flash_execute_cmd(CMD_READ_STATUS_REG, MASK_CMD_RD_1BYTE);
+ sspi_flash_execute_cmd(CMD_READ_STATUS_REG2, MASK_CMD_RD_1BYTE);
+ /* Enable tri-state */
+ sspi_flash_tristate(1);
+}
+
+void sspi_flash_physical_write(int offset, int size, const char *data)
+{
+ int dest_addr = offset;
+ const int sz_page = CONFIG_FLASH_WRITE_IDEAL_SIZE;
+
+ /* Disable tri-state */
+ sspi_flash_tristate(0);
+
+ /* Write the data per CONFIG_FLASH_WRITE_IDEAL_SIZE bytes */
+ for (; size >= sz_page; size -= sz_page) {
+ /* Enable write */
+ sspi_flash_write_enable();
+ /* Burst UMA transaction */
+ sspi_flash_burst_write(dest_addr, sz_page, data);
+ /* Wait write completed */
+ sspi_flash_wait_ready();
+
+ data += sz_page;
+ dest_addr += sz_page;
+ }
+
+ /* Handle final partial page, if any */
+ if (size != 0) {
+ /* Enable write */
+ sspi_flash_write_enable();
+ /* Burst UMA transaction */
+ sspi_flash_burst_write(dest_addr, size, data);
+
+ /* Wait write completed */
+ sspi_flash_wait_ready();
+ }
+
+ /* Enable tri-state */
+ sspi_flash_tristate(1);
+}
+
+void sspi_flash_physical_erase(int offset, int size)
+{
+ /* Disable tri-state */
+ sspi_flash_tristate(0);
+
+ /* Alignment has been checked in upper layer */
+ for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE,
+ offset += CONFIG_FLASH_ERASE_SIZE) {
+ /* Enable write */
+ sspi_flash_write_enable();
+ /* Set erase address */
+ sspi_flash_set_address(offset);
+ /* Start erase */
+ sspi_flash_execute_cmd(CMD_SECTOR_ERASE, MASK_CMD_ADR);
+
+ /* Wait erase completed */
+ sspi_flash_wait_ready();
+ }
+
+ /* Enable tri-state */
+ sspi_flash_tristate(1);
+}
+
+/* Start to write */
+int sspi_flash_verify(int offset, int size, const char *data)
+{
+ int i, result;
+ uint8_t *ptr_flash;
+ uint8_t *ptr_mram;
+
+ ptr_flash = (uint8_t *)(0x64000000+offset);
+ ptr_mram = (uint8_t *)data;
+ result = 1;
+
+ /* Disable tri-state */
+ sspi_flash_tristate(0);
+
+ /* Start to verify */
+ for (i = 0; i < size; i++) {
+ if (ptr_flash[i] != ptr_mram[i]) {
+ result = 0;
+ break;
+ }
+ }
+
+ /* Enable tri-state */
+ sspi_flash_tristate(1);
+ return result;
+}
+
+int sspi_flash_get_image_used(const char *fw_base)
+{
+ const uint8_t *image;
+ int size = 0x20000; /* maximum size is 128KB */
+
+ image = (const uint8_t *)fw_base;
+ /*
+ * Scan backwards looking for 0xea byte, which is by definition the
+ * last byte of the image. See ec.lds.S for how this is inserted at
+ * the end of the image.
+ */
+ for (size--; size > 0 && image[size] != 0xea; size--)
+ ;
+
+ return size ? size + 1 : 0; /* 0xea byte IS part of the image */
+
+}
+
+volatile __attribute__((section(".up_flag"))) unsigned int flag_upload;
+
+/* Entry function of spi upload function */
+void __attribute__ ((section(".startup_text"), noreturn))
+sspi_flash_upload(int spi_offset, int spi_size)
+{
+ /*
+ * Flash image has been uploaded to Code RAM
+ */
+ const char *image_base = (char *)0x10088000;
+ uint32_t sz_image = spi_size;
+
+ /* Set pinmux first */
+ sspi_flash_pinmux(1);
+
+ /* Get size of image automatically */
+ if (sz_image == 0)
+ sz_image = sspi_flash_get_image_used(image_base);
+
+ /* Clear status reg of spi flash for protection */
+ sspi_flash_physical_clear_stsreg();
+
+ /* Start to erase */
+ sspi_flash_physical_erase(spi_offset, sz_image);
+
+ /* Start to write */
+ sspi_flash_physical_write(spi_offset, sz_image, image_base);
+
+ /* Verify data */
+ if (sspi_flash_verify(spi_offset, sz_image, image_base))
+ flag_upload |= 0x02;
+
+ /* Disable pinmux */
+ sspi_flash_pinmux(0);
+
+ /* Mark we have finished upload work */
+ flag_upload |= 0x01;
+
+ /* Should never reach this*/
+ for (;;)
+ ;
+}
+
diff --git a/chip/npcx/spiflashfw/ec_npcxflash.ld b/chip/npcx/spiflashfw/ec_npcxflash.ld
new file mode 100644
index 0000000000..3ab642b074
--- /dev/null
+++ b/chip/npcx/spiflashfw/ec_npcxflash.ld
@@ -0,0 +1,104 @@
+/* Copyright (c) 2014 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.
+ *
+ * NPCX5M5G SoC spi flash update tool
+ */
+
+/* Memory Spaces Definitions */
+MEMORY
+{
+ CODERAM (rx) : ORIGIN = 0x200C0000, LENGTH = 16K
+ RAM (xrw) : ORIGIN = 0x200C4000, LENGTH = 16K
+}
+
+/*
+ * The entry point is informative, for debuggers and simulators,
+ * since the Cortex-M vector points to it anyway.
+ */
+ENTRY(sspi_flash_upload)
+
+
+/* Sections Definitions */
+
+SECTIONS
+{
+ .startup_text :
+ {
+ . = ALIGN(4);
+ *(.startup_text ) /* Startup code */
+ . = ALIGN(4);
+ } >CODERAM
+
+ /*
+ * The program code is stored in the .text section,
+ * which goes to CODERAM.
+ */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text .text.*) /* all remaining code */
+ *(.rodata .rodata.*) /* read-only data (constants) */
+ } >CODERAM
+
+ . = ALIGN(4);
+ _etext = .;
+
+ /*
+ * This address is used by the startup code to
+ * initialise the .data section.
+ */
+ _sidata = _etext;
+
+ /*
+ * Used for validation only, do not allocate anything here!
+ *
+ * This is just to check that there is enough RAM left for the Main
+ * stack. It should generate an error if it's full.
+ */
+ .up_flag :
+ {
+ . = ALIGN(4);
+ *(.up_flag ) /* Startup code */
+ . = ALIGN(4);
+ } >RAM
+
+ /*
+ * The initialised data section.
+ */
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+
+ /* This is used by the startup code to initialise the .data section */
+ __data_start__ = . ;
+ *(.data_begin .data_begin.*)
+
+ *(.data .data.*)
+
+ *(.data_end .data_end.*)
+ . = ALIGN(4);
+
+ /* This is used by the startup code to initialise the .data section */
+ __data_end__ = . ;
+
+ } >RAM
+
+ /*
+ * The uninitialised data section. NOLOAD is used to avoid
+ * the "section `.bss' type changed to PROGBITS" warning
+ */
+ .bss (NOLOAD) :
+ {
+ . = ALIGN(4);
+ __bss_start__ = .; /* standard newlib definition */
+ *(.bss_begin .bss_begin.*)
+
+ *(.bss .bss.*)
+ *(COMMON)
+
+ *(.bss_end .bss_end.*)
+ . = ALIGN(4);
+ __bss_end__ = .; /* standard newlib definition */
+ } >RAM
+}
diff --git a/chip/npcx/system.c b/chip/npcx/system.c
new file mode 100644
index 0000000000..ac6a4ba4d9
--- /dev/null
+++ b/chip/npcx/system.c
@@ -0,0 +1,780 @@
+/* Copyright (c) 2014 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 : NPCX hardware specific implementation */
+
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "cpu.h"
+#include "host_command.h"
+#include "registers.h"
+#include "system.h"
+#include "hooks.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+#include "hwtimer_chip.h"
+#include "system_chip.h"
+
+#ifdef CONFIG_CODERAM_ARCH
+/* base address for jumping */
+uint32_t base_addr;
+#endif
+
+/* Indices for battery-backed ram (BBRAM) data position */
+enum bbram_data_index {
+ BBRM_DATA_INDEX_SCRATCHPAD = 0, /* General-purpose scratchpad */
+ BBRM_DATA_INDEX_SAVED_RESET_FLAGS = 4, /* Saved reset flags */
+ BBRM_DATA_INDEX_WAKE = 8, /* Wake reasons for hibernate */
+};
+
+/* Flags for BBRM_DATA_INDEX_WAKE */
+#define PSLDATA_WAKE_MTC (1 << 0) /* LCT alarm */
+#define PSLDATA_WAKE_PIN (1 << 1) /* Wake pin */
+
+/* Super-IO index and register definitions */
+#define SIO_OFFSET 0x4E
+#define INDEX_SID 0x20
+#define INDEX_CHPREV 0x24
+#define INDEX_SRID 0x27
+
+/* equivalent to 250us according to 48MHz core clock */
+#define MTC_TTC_LOAD_DELAY 1500
+#define MTC_ALARM_MASK ((1 << 25) - 1)
+#define MTC_WUI_GROUP MIWU_GROUP_4
+#define MTC_WUI_MASK MASK_PIN7
+
+uint32_t flag_hibernate;
+
+/* Begin address for the .lpram section; defined in linker script */
+uintptr_t __lpram_fw_start = CONFIG_LPRAM_BASE;
+
+/*****************************************************************************/
+/* Internal functions */
+
+/* Super-IO read/write function */
+void system_sib_write_reg(uint8_t io_offset, uint8_t index_value,
+ uint8_t io_data)
+{
+ /* Disable interrupts */
+ interrupt_disable();
+
+ /* Lock host CFG module */
+ SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG);
+ /* Enable Core-to-Host Modules Access */
+ SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE);
+ /* Enable Core access to CFG module */
+ SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE);
+ /* Verify Core read/write to host modules is not in progress */
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD))
+ ;
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR))
+ ;
+
+ /* Specify the io_offset A0 = 0. the index register is accessed */
+ NPCX_IHIOA = io_offset;
+ /* Write the data. This starts the write access to the host module */
+ NPCX_IHD = index_value;
+ /* Wait while Core write operation is in progress */
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR))
+ ;
+
+ /* Specify the io_offset A0 = 1. the data register is accessed */
+ NPCX_IHIOA = io_offset+1;
+ /* Write the data. This starts the write access to the host module */
+ NPCX_IHD = io_data;
+ /* Wait while Core write operation is in progress */
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR))
+ ;
+
+ /* Disable Core access to CFG module */
+ CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE);
+ /* Disable Core-to-Host Modules Access */
+ CLEAR_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE);
+ /* unlock host CFG module */
+ CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG);
+
+ /* Enable interrupts */
+ interrupt_enable();
+}
+
+uint8_t system_sib_read_reg(uint8_t io_offset, uint8_t index_value)
+{
+ uint8_t data_value;
+
+ /* Disable interrupts */
+ interrupt_disable();
+
+ /* Lock host CFG module */
+ SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG);
+ /* Enable Core-to-Host Modules Access */
+ SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE);
+ /* Enable Core access to CFG module */
+ SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE);
+ /* Verify Core read/write to host modules is not in progress */
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD))
+ ;
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR))
+ ;
+
+
+ /* Specify the io_offset A0 = 0. the index register is accessed */
+ NPCX_IHIOA = io_offset;
+ /* Write the data. This starts the write access to the host module */
+ NPCX_IHD = index_value;
+ /* Wait while Core write operation is in progress */
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR))
+ ;
+
+ /* Specify the io_offset A0 = 1. the data register is accessed */
+ NPCX_IHIOA = io_offset+1;
+ /* Start a Core read from host module */
+ SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD);
+ /* Wait while Core read operation is in progress */
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD))
+ ;
+ /* Read the data */
+ data_value = NPCX_IHD;
+
+ /* Disable Core access to CFG module */
+ CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE);
+ /* Disable Core-to-Host Modules Access */
+ CLEAR_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE);
+ /* unlock host CFG module */
+ CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG);
+
+ /* Enable interrupts */
+ interrupt_enable();
+
+ return data_value;
+}
+
+void system_watchdog_reset(void)
+{
+ /* Unlock & stop watchdog registers */
+ NPCX_WDSDM = 0x87;
+ NPCX_WDSDM = 0x61;
+ NPCX_WDSDM = 0x63;
+
+ /* Reset TWCFG */
+ NPCX_TWCFG = 0;
+ /* Select T0IN clock as watchdog prescaler clock */
+ SET_BIT(NPCX_TWCFG, NPCX_TWCFG_WDCT0I);
+
+ /* Clear watchdog reset status initially*/
+ SET_BIT(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS);
+
+ /* Keep prescaler ratio timer0 clock to 1:1 */
+ NPCX_TWCP = 0x00;
+
+ /* Set internal counter and prescaler */
+ NPCX_TWDT0 = 0x00;
+ NPCX_WDCNT = 0x01;
+
+ /* Disable interrupt */
+ interrupt_disable();
+ /* 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))
+ ;
+ /* Enable interrupt */
+ interrupt_enable();
+}
+
+/**
+ * Read battery-backed ram (BBRAM) at specified index.
+ *
+ * @return The value of the register or 0 if invalid index.
+ */
+static uint32_t bbram_data_read(enum bbram_data_index index)
+{
+ uint32_t value = 0;
+ /* Check index */
+ if (index < 0 || index >= NPCX_BBRAM_SIZE)
+ return 0;
+
+ /* BBRAM is valid */
+ if (IS_BIT_SET(NPCX_BKUP_STS, NPCX_BKUP_STS_IBBR))
+ return 0;
+
+ /* Read BBRAM */
+ value += NPCX_BBRAM(index + 3);
+ value = value << 8;
+ value += NPCX_BBRAM(index + 2);
+ value = value << 8;
+ value += NPCX_BBRAM(index + 1);
+ value = value << 8;
+ value += NPCX_BBRAM(index);
+
+ return value;
+}
+
+/**
+ * Write battery-backed ram (BBRAM) at specified index.
+ *
+ * @return nonzero if error.
+ */
+static int bbram_data_write(enum bbram_data_index index, uint32_t value)
+{
+ /* Check index */
+ if (index < 0 || index >= NPCX_BBRAM_SIZE)
+ return EC_ERROR_INVAL;
+
+ /* BBRAM is valid */
+ if (IS_BIT_SET(NPCX_BKUP_STS, NPCX_BKUP_STS_IBBR))
+ return EC_ERROR_INVAL;
+
+ /* Write BBRAM */
+ NPCX_BBRAM(index) = value & 0xFF;
+ NPCX_BBRAM(index + 1) = (value >> 8) & 0xFF;
+ NPCX_BBRAM(index + 2) = (value >> 16) & 0xFF;
+ NPCX_BBRAM(index + 3) = (value >> 24) & 0xFF;
+
+ /* Wait for write-complete */
+ return EC_SUCCESS;
+}
+
+/* MTC functions */
+uint32_t system_get_rtc_sec(void)
+{
+ /* Get MTC counter unit:seconds */
+ uint32_t sec = NPCX_TTC;
+ return sec;
+}
+
+void system_set_rtc(uint32_t seconds)
+{
+ volatile uint16_t __i;
+
+ /* Set MTC counter unit:seconds */
+ NPCX_TTC = seconds;
+
+ /* Wait till clock is readable */
+ for (__i = 0; __i < MTC_TTC_LOAD_DELAY; ++__i)
+ ;
+}
+
+/* Check reset cause */
+static void check_reset_cause(void)
+{
+ uint32_t hib_wake_flags = bbram_data_read(BBRM_DATA_INDEX_WAKE);
+ uint32_t flags = 0;
+
+ /* Check for VCC1 reset */
+ if (IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_STS))
+ flags |= RESET_FLAG_POWER_ON;
+
+ /* Software debugger reset */
+ if (IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_DBGRST_STS))
+ flags |= RESET_FLAG_SOFT;
+
+ /* Watchdog Reset */
+ if (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS)) {
+ flags |= RESET_FLAG_WATCHDOG;
+ /* Clear watchdog reset status initially*/
+ SET_BIT(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS);
+ }
+
+ if ((hib_wake_flags & PSLDATA_WAKE_PIN))
+ flags |= RESET_FLAG_WAKE_PIN;
+
+ /* Restore then clear saved reset flags */
+ flags |= bbram_data_read(BBRM_DATA_INDEX_SAVED_RESET_FLAGS);
+ bbram_data_write(BBRM_DATA_INDEX_SAVED_RESET_FLAGS, 0);
+
+ system_set_reset_flags(flags);
+}
+
+/**
+ * Configure address 0x40001600 in the the MPU
+ * (Memory Protection Unit) as a "regular" memory
+ */
+void system_mpu_config(void)
+{
+ /* Enable MPU */
+ CPU_MPU_CTRL = 0x7;
+
+ /* Create a new MPU Region for low-power ram */
+ CPU_MPU_RNR = 0; /* Select region number 0 */
+ CPU_MPU_RASR = CPU_MPU_RASR & 0xFFFFFFFE; /* Disable region */
+ CPU_MPU_RBAR = CONFIG_LPRAM_BASE; /* Set region base address */
+ /*
+ * Set region size & attribute and enable region
+ * [31:29] - Reserved.
+ * [28] - XN (Execute Never) = 0
+ * [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 = 01001 (1K)
+ * [0] - ENABLE = 1 (enabled)
+ */
+ CPU_MPU_RASR = 0x03080013;
+}
+
+void __attribute__ ((section(".lowpower_ram")))
+__enter_hibernate_in_lpram(void)
+{
+
+ /* Disable Code RAM first */
+ SET_BIT(NPCX_PWDWN_CTL(5), NPCX_PWDWN_CTL5_MRFSH_DIS);
+ SET_BIT(NPCX_DISIDL_CTL, NPCX_DISIDL_CTL_RAM_DID);
+
+ while (1) {
+ /* Set deep idle - instant wake-up mode*/
+ NPCX_PMCSR = 0x7;
+ /* Enter deep idle, wake-up by GPIOxx or RTC */
+ asm("wfi");
+
+ /*TODO: Using POWER_BUTTON_L GPIO02 to wake-up? */
+ if (IS_BIT_SET(NPCX_WKPND(MIWU_TABLE_1 , MIWU_GROUP_1), 2))
+ break;
+ /* RTC wake-up */
+ else if (IS_BIT_SET(NPCX_WTC, NPCX_WTC_PTO)) {
+ /* Clear WUI pending bit of MTC */
+ NPCX_WKPCL(MIWU_TABLE_0, MTC_WUI_GROUP) = MTC_WUI_MASK;
+ /* Clear interrupt & Disable alarm interrupt */
+ CLEAR_BIT(NPCX_WTC, NPCX_WTC_WIE);
+ SET_BIT(NPCX_WTC, NPCX_WTC_PTO);
+ break;
+ }
+ }
+
+ /* 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)
+ ;
+}
+/**
+ * Internal hibernate function.
+ *
+ * @param seconds Number of seconds to sleep before LCT alarm
+ * @param microseconds Number of microseconds to sleep before LCT alarm
+ */
+void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
+{
+ int i;
+ void (*__hibernate_in_lpram)(void) =
+ (void(*)(void))(__lpram_fw_start | 0x01);
+
+ /* Set instant wake up mode */
+ SET_BIT(NPCX_ENIDL_CTL, NPCX_ENIDL_CTL_LP_WK_CTL);
+ interrupt_disable();
+
+ /* ITIM event module disable */
+ CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
+ /* ITIM time module disable */
+ CLEAR_BIT(NPCX_ITCTS(ITIM_TIME_NO), NPCX_ITIM16_ITEN);
+ /* ITIM watchdog warn module disable */
+ CLEAR_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITIM16_ITEN);
+
+ /*
+ * Set RTC interrupt in time to wake up before
+ * next event.
+ */
+ if (seconds || microseconds)
+ system_set_rtc_alarm(seconds, microseconds);
+
+ /* Unlock & stop watchdog registers */
+ NPCX_WDSDM = 0x87;
+ NPCX_WDSDM = 0x61;
+ NPCX_WDSDM = 0x63;
+
+ /* Configure address LPRAM in the MPU as a regular memory */
+ system_mpu_config();
+
+ /* Enable Low Power RAM */
+ NPCX_LPRAM_CTRL = 1;
+
+ /* Initialize watchdog */
+ NPCX_TWCFG = 0; /* Select T0IN clock as watchdog prescaler clock */
+ SET_BIT(NPCX_TWCFG, NPCX_TWCFG_WDCT0I);
+ NPCX_TWCP = 0x00; /* Keep prescaler ratio timer0 clock to 1:1 */
+ NPCX_TWDT0 = 0x00; /* Set internal counter and prescaler */
+
+ /* Copy the __enter_hibernate_in_lpram instructions to LPRAM */
+ for (i = 0; i < &__flash_lpfw_end - &__flash_lpfw_start; i++)
+ *((uint32_t *)__lpram_fw_start + i) =
+ *(&__flash_lpfw_start + i);
+
+ /* Disable interrupt */
+ interrupt_disable();
+
+ /* execute hibernate func in LPRAM */
+ __hibernate_in_lpram();
+
+}
+
+/*****************************************************************************/
+/* IC specific low-level driver */
+
+/* Microsecond will be ignore for hardware limitation */
+void system_set_rtc_alarm(uint32_t seconds, uint32_t microseconds)
+{
+ uint32_t cur_secs, alarm_secs;
+
+ if (seconds == 0)
+ return;
+
+ /* Get current clock */
+ cur_secs = NPCX_TTC;
+
+ /* If alarm clock is not sequential or not in range */
+ alarm_secs = cur_secs + seconds;
+ alarm_secs = alarm_secs & MTC_ALARM_MASK;
+
+ /* Reset alarm first */
+ system_reset_rtc_alarm();
+
+ /* Set alarm, use first 25 bits of clock value */
+ NPCX_WTC = alarm_secs;
+
+ /* Enable interrupt mode alarm */
+ SET_BIT(NPCX_WTC, NPCX_WTC_WIE);
+
+ /* Enable MTC interrupt */
+ task_enable_irq(NPCX_IRQ_MTC_WKINTAD_0);
+
+ /* Enable wake-up input sources */
+ NPCX_WKEN(MIWU_TABLE_0, MTC_WUI_GROUP) |= MTC_WUI_MASK;
+}
+
+void system_reset_rtc_alarm(void)
+{
+ /*
+ * Clear interrupt & Disable alarm interrupt
+ * Update alarm value to zero
+ */
+ CLEAR_BIT(NPCX_WTC, NPCX_WTC_WIE);
+ SET_BIT(NPCX_WTC, NPCX_WTC_PTO);
+
+ /* Disable MTC interrupt */
+ task_disable_irq(NPCX_IRQ_MTC_WKINTAD_0);
+}
+
+/**
+ * Enable hibernate interrupt
+ */
+void system_enable_hib_interrupt(void)
+{
+ task_enable_irq(NPCX_IRQ_MTC_WKINTAD_0);
+}
+
+void system_hibernate(uint32_t seconds, uint32_t microseconds)
+{
+ /* Flush console before hibernating */
+ cflush();
+
+#if SUPPORT_HIB
+ /* Add additional hibernate operations here */
+ __enter_hibernate(seconds, microseconds);
+#endif
+}
+
+void system_pre_init(void)
+{
+ /*
+ * Add additional initialization here
+ * EC should be initialized in Booter
+ */
+
+#ifndef CHIP_NPCX5M5G
+ /* Power-down the modules we don't need */
+ NPCX_PWDWN_CTL(0) = 0xFD; /* Skip SDP_PD */
+ NPCX_PWDWN_CTL(1) = 0xFF;
+ NPCX_PWDWN_CTL(2) = 0xFF;
+ NPCX_PWDWN_CTL(3) = 0xF0; /*Skip ITIM3/2/1_PD */
+ NPCX_PWDWN_CTL(4) = 0xF8;
+ NPCX_PWDWN_CTL(5) = 0x87;
+#endif
+ /* Check reset cause */
+ check_reset_cause();
+}
+
+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;
+
+ /* Add in AP off flag into saved flags. */
+ if (flags & SYSTEM_RESET_LEAVE_AP_OFF)
+ save_flags |= RESET_FLAG_AP_OFF;
+
+ /* Save reset flag */
+ if (flags & SYSTEM_RESET_HARD)
+ save_flags |= RESET_FLAG_HARD;
+ else {
+ save_flags |= RESET_FLAG_SOFT;
+ /* Use SYSRESETREQ to trigger a soft reboot */
+ CPU_NVIC_APINT = 0x05fa0004;
+ }
+ /* Store flags to battery backed RAM. */
+ bbram_data_write(BBRM_DATA_INDEX_SAVED_RESET_FLAGS, save_flags);
+
+ /* Ask the watchdog to trigger a hard reboot */
+ system_watchdog_reset();
+
+ /* Spin and wait for reboot; should never return */
+ while (1)
+ ;
+}
+
+/**
+ * Return the chip vendor/name/revision string.
+ */
+const char *system_get_chip_vendor(void)
+{
+ uint8_t fam_id = system_sib_read_reg(SIO_OFFSET, INDEX_SID);
+ switch (fam_id) {
+ case 0xFC:
+ return "NUC";
+ default:
+ return "Unknown";
+ }
+}
+
+const char *system_get_chip_name(void)
+{
+ uint8_t chip_id = system_sib_read_reg(SIO_OFFSET, INDEX_SRID);
+ switch (chip_id) {
+ case 0x05:
+ return "NPCX5m5G";
+ default:
+ return "Unknown";
+ }
+}
+
+const char *system_get_chip_revision(void)
+{
+ static char rev[1];
+ uint8_t rev_num = system_sib_read_reg(SIO_OFFSET, INDEX_CHPREV);
+
+ /* set revision from character '0' */
+ rev[0] = '0' + rev_num;
+
+ return rev;
+}
+
+int system_set_console_force_enabled(int val)
+{
+ /* TODO(crosbug.com/p/23575): IMPLEMENT ME ! */
+ return 0;
+}
+
+int system_get_console_force_enabled(void)
+{
+ /* TODO(crosbug.com/p/23575): IMPLEMENT ME ! */
+ return 0;
+}
+
+/**
+ * Get/Set VbNvContext in non-volatile storage. The block should be 16 bytes
+ * long, which is the current size of VbNvContext block.
+ *
+ * @param block Pointer to a buffer holding VbNvContext.
+ * @return 0 on success, !0 on error.
+ */
+int system_get_vbnvcontext(uint8_t *block)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+
+int system_set_vbnvcontext(const uint8_t *block)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+
+/**
+ * Set a scratchpad register to the specified value.
+ *
+ * The scratchpad register must maintain its contents across a
+ * software-requested warm reset.
+ *
+ * @param value Value to store.
+ * @return EC_SUCCESS, or non-zero if error.
+ */
+int system_set_scratchpad(uint32_t value)
+{
+ return bbram_data_write(BBRM_DATA_INDEX_SCRATCHPAD, value);
+}
+
+uint32_t system_get_scratchpad(void)
+{
+ return bbram_data_read(BBRM_DATA_INDEX_SCRATCHPAD);
+}
+
+/*****************************************************************************/
+/* Console commands */
+
+static int command_system_rtc(int argc, char **argv)
+{
+ uint32_t sec;
+ if (argc == 3 && !strcasecmp(argv[1], "set")) {
+ char *e;
+ uint32_t t = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ system_set_rtc(t);
+ } else if (argc > 1) {
+ return EC_ERROR_INVAL;
+ }
+
+ sec = system_get_rtc_sec();
+ ccprintf("RTC: 0x%08x (%d.00 s)\n", sec, sec);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(rtc, command_system_rtc,
+ "[set <seconds>]",
+ "Get/set real-time clock",
+ NULL);
+
+#ifdef CONFIG_CMD_RTC_ALARM
+/**
+ * Test the RTC alarm by setting an interrupt on RTC match.
+ */
+static int command_rtc_alarm_test(int argc, char **argv)
+{
+ int s = 1, us = 0;
+ char *e;
+
+ ccprintf("Setting RTC alarm\n");
+ system_enable_hib_interrupt();
+
+ if (argc > 1) {
+ s = strtoi(argv[1], &e, 10);
+ if (*e)
+ return EC_ERROR_PARAM1;
+
+ }
+ if (argc > 2) {
+ us = strtoi(argv[2], &e, 10);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ }
+
+ system_set_rtc_alarm(s, us);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(rtc_alarm, command_rtc_alarm_test,
+ "[seconds [microseconds]]",
+ "Test alarm",
+ NULL);
+#endif /* CONFIG_CMD_RTC_ALARM */
+
+/*****************************************************************************/
+/* Host commands */
+
+static int system_rtc_get_value(struct host_cmd_handler_args *args)
+{
+ struct ec_response_rtc *r = args->response;
+
+ r->time = system_get_rtc_sec();
+ args->response_size = sizeof(*r);
+
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_RTC_GET_VALUE,
+ system_rtc_get_value,
+ EC_VER_MASK(0));
+
+static int system_rtc_set_value(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_rtc *p = args->params;
+
+ system_set_rtc(p->time);
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_RTC_SET_VALUE,
+ system_rtc_set_value,
+ EC_VER_MASK(0));
+
+/* For LPC host register initial via SIB module */
+void system_lpc_host_register_init(void){
+ /* Setting PMC2 */
+ /* LDN register = 0x12(PMC2) */
+ system_sib_write_reg(SIO_OFFSET, 0x07, 0x12);
+ /* CMD port is 0x200 */
+ system_sib_write_reg(SIO_OFFSET, 0x60, 0x02);
+ system_sib_write_reg(SIO_OFFSET, 0x61, 0x00);
+ /* Data port is 0x204 */
+ system_sib_write_reg(SIO_OFFSET, 0x62, 0x02);
+ system_sib_write_reg(SIO_OFFSET, 0x63, 0x04);
+ /* enable PMC2 */
+ system_sib_write_reg(SIO_OFFSET, 0x30, 0x01);
+
+ /* Setting SHM */
+ /* LDN register = 0x0F(SHM) */
+ system_sib_write_reg(SIO_OFFSET, 0x07, 0x0F);
+ /* WIN1&2 mapping to IO */
+ system_sib_write_reg(SIO_OFFSET, 0xF1,
+ system_sib_read_reg(SIO_OFFSET, 0xF1) | 0x30);
+ /* Host Command on the IO:0x0800 */
+ system_sib_write_reg(SIO_OFFSET, 0xF7, 0x00);
+ system_sib_write_reg(SIO_OFFSET, 0xF6, 0x00);
+ system_sib_write_reg(SIO_OFFSET, 0xF5, 0x08);
+ system_sib_write_reg(SIO_OFFSET, 0xF4, 0x00);
+ /* WIN1 as Host Command on the IO:0x0800 */
+ system_sib_write_reg(SIO_OFFSET, 0xFB, 0x00);
+ system_sib_write_reg(SIO_OFFSET, 0xFA, 0x00);
+ /* WIN2 as MEMMAP on the IO:0x900 */
+ system_sib_write_reg(SIO_OFFSET, 0xF9, 0x09);
+ system_sib_write_reg(SIO_OFFSET, 0xF8, 0x00);
+ /* enable SHM */
+ system_sib_write_reg(SIO_OFFSET, 0x30, 0x01);
+}
+#ifdef CONFIG_CODERAM_ARCH
+uint32_t system_get_lfw_address(uint32_t flash_addr)
+{
+ /* Little FW located on top of flash - 4K */
+ uint32_t jump_addr = (CONFIG_FLASH_BASE + CONFIG_SPI_FLASH_SIZE
+ - CONFIG_LFW_OFFSET + 1);
+ /* restore base address for jumping*/
+ base_addr = flash_addr;
+ return jump_addr;
+}
+
+enum system_image_copy_t system_get_shrspi_image_copy(void)
+{
+ /* RO region FW */
+ if (IS_BIT_SET(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION))
+ return SYSTEM_IMAGE_RO;
+ else/* RW region FW */
+ return SYSTEM_IMAGE_RW;
+}
+
+/**
+ * Set flag for jumping across a sysjump.
+ */
+static void system_sysjump(void)
+{
+ /* Jump to RO region -- set flag */
+ if (base_addr == CONFIG_FLASH_BASE + CONFIG_FW_RO_OFF)
+ SET_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION);
+ else /* Jump to RW region -- clear flag */
+ CLEAR_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION);
+}
+DECLARE_HOOK(HOOK_SYSJUMP, system_sysjump, HOOK_PRIO_DEFAULT);
+#endif
diff --git a/chip/npcx/system_chip.h b/chip/npcx/system_chip.h
new file mode 100644
index 0000000000..280246c414
--- /dev/null
+++ b/chip/npcx/system_chip.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* NPCX-specific SIB module for Chrome EC */
+
+#ifndef __CROS_EC_NPCX_LPC_H
+#define __CROS_EC_NPCX_LPC_H
+
+void system_lpc_host_register_init(void);
+
+/* End address for the .lpram section; defined in linker script */
+extern unsigned int __lpram_fw_end;
+/* Begin flash address for the lpram codes; defined in linker script */
+extern unsigned int __flash_lpfw_start;
+/* End flash address for the lpram codes; defined in linker script */
+extern unsigned int __flash_lpfw_end;
+
+#endif /* __CROS_EC_NPCX_LPC_H */
diff --git a/chip/npcx/uart.c b/chip/npcx/uart.c
new file mode 100644
index 0000000000..893b02aa84
--- /dev/null
+++ b/chip/npcx/uart.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* UART module for Chrome EC */
+
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "lpc.h"
+#include "registers.h"
+#include "clock_chip.h"
+#include "system.h"
+#include "task.h"
+#include "uart.h"
+#include "util.h"
+
+static int init_done;
+
+int uart_init_done(void)
+{
+ return init_done;
+}
+
+void uart_tx_start(void)
+{
+ if (IS_BIT_SET(NPCX_WKEN(1, 1), 0)) {
+ /* disable MIWU*/
+ CLEAR_BIT(NPCX_WKEN(1, 1), 0);
+ /* go back to original setting */
+ task_enable_irq(NPCX_IRQ_WKINTB_1);
+ /* Go back CR_SIN*/
+ SET_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL);
+ /* enable uart again from MIWU mode */
+ task_enable_irq(NPCX_IRQ_UART);
+ }
+
+ /* If interrupt is already enabled, nothing to do */
+ if (NPCX_UICTRL & 0x20)
+ return;
+
+ /* Do not allow deep sleep while transmit in progress */
+ disable_sleep(SLEEP_MASK_UART);
+
+ /*
+ * Re-enable the transmit interrupt, then forcibly trigger the
+ * interrupt. This works around a hardware problem with the
+ * UART where the FIFO only triggers the interrupt when its
+ * threshold is _crossed_, not just met.
+ */
+ NPCX_UICTRL |= 0x20;
+
+ task_trigger_irq(NPCX_IRQ_UART);
+}
+
+void uart_tx_stop(void) /* Disable TX interrupt */
+{
+ NPCX_UICTRL &= ~0x20;
+
+ /* Re-allow deep sleep */
+ enable_sleep(SLEEP_MASK_UART);
+}
+
+void uart_tx_flush(void)
+{
+ /* Wait for transmit FIFO empty */
+ while (!(NPCX_UICTRL & 0x01))
+ ;
+}
+
+int uart_tx_ready(void)
+{
+ return NPCX_UICTRL & 0x01; /*if TX FIFO is empty return 1*/
+}
+
+int uart_tx_in_progress(void)
+{
+ /* Transmit is in progress if the TX busy bit is set. */
+ return NPCX_USTAT & 0x40; /*BUSY bit , if busy return 1*/
+}
+
+int uart_rx_available(void)
+{
+ uint8_t ctrl = NPCX_UICTRL;
+#ifdef CONFIG_LOW_POWER_IDLE
+ /*
+ * Activity seen on UART RX pin while UART was disabled for deep sleep.
+ * The console won't see that character because the UART is disabled,
+ * so we need to inform the clock module of UART activity ourselves.
+ */
+ if (ctrl & 0x02)
+ clock_refresh_console_in_use();
+#endif
+ return ctrl & 0x02; /* If RX FIFO is empty return '0'*/
+}
+
+void uart_write_char(char c)
+{
+ /* Wait for space in transmit FIFO. */
+ while (!uart_tx_ready())
+ ;
+
+ NPCX_UTBUF = c;
+}
+
+int uart_read_char(void)
+{
+ return NPCX_URBUF;
+}
+
+static void uart_clear_rx_fifo(int channel)
+{
+ int scratch __attribute__ ((unused));
+ if (channel == 0) { /* suppose '0' is EC UART*/
+ /*if '1' that mean have a RX data on the FIFO register*/
+ while ((NPCX_UICTRL & 0x02))
+ scratch = NPCX_URBUF;
+ }
+}
+
+void uart_disable_interrupt(void)
+{
+ task_disable_irq(NPCX_IRQ_UART);
+}
+
+void uart_enable_interrupt(void)
+{
+ task_enable_irq(NPCX_IRQ_UART);
+}
+
+/**
+ * Interrupt handler for UART0
+ */
+void uart_ec_interrupt(void)
+{
+ /* Read input FIFO until empty, then fill output FIFO */
+ uart_process_input();
+ uart_process_output();
+}
+DECLARE_IRQ(NPCX_IRQ_UART, uart_ec_interrupt, 1);
+
+
+static void uart_config(void)
+{
+ uint32_t div, opt_dev, min_deviation, clk, calc_baudrate, deviation;
+ uint8_t prescalar, opt_prescalar, i;
+ /* Enable the port */
+ /* Configure pins from GPIOs to CR_UART */
+ gpio_config_module(MODULE_UART, 1);
+
+ /* Calculated UART baudrate , clock source from APB2 */
+ opt_prescalar = opt_dev = 0;
+ prescalar = 10;
+ min_deviation = 0xFFFFFFFF;
+ clk = clock_get_apb2_freq();
+ for (i = 1; i < 31; i++) {
+ div = (clk * 10) / (16 * CONFIG_UART_BAUD_RATE * prescalar);
+ if (div != 0) {
+ calc_baudrate = (clk * 10) / (16 * div * prescalar);
+ deviation = (calc_baudrate > CONFIG_UART_BAUD_RATE) ?
+ (calc_baudrate - CONFIG_UART_BAUD_RATE) :
+ (CONFIG_UART_BAUD_RATE - calc_baudrate);
+ if (deviation < min_deviation) {
+ min_deviation = deviation;
+ opt_prescalar = i;
+ opt_dev = div;
+ }
+ }
+ prescalar += 5;
+ }
+ opt_dev--;
+ NPCX_UPSR = ((opt_prescalar<<3) & 0xF8) | ((opt_dev >> 8) & 0x7);
+ NPCX_UBAUD = (uint8_t)opt_dev;
+ /*
+ * 8-N-1, FIFO enabled. Must be done after setting
+ * the divisor for the new divisor to take effect.
+ */
+ NPCX_UFRS = 0x00;
+ NPCX_UICTRL = 0x40; /* receive int enable only */
+}
+
+void uart_init(void)
+{
+ uint32_t mask = 0;
+
+ /*
+ * Enable UART0 in run, sleep, and deep sleep modes. Enable the Host
+ * UART in run and sleep modes.
+ */
+ mask = 0x10; /* bit 4 */
+ clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_ALL);
+
+ /* Set pin-mask for UART */
+ SET_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL);
+ gpio_config_module(MODULE_UART, 1);
+
+ /* Configure UARTs (identically) */
+ uart_config();
+
+ /*
+ * Enable interrupts for UART0 only. Host UART will have to wait
+ * until the LPC bus is initialized.
+ */
+ uart_clear_rx_fifo(0);
+ task_enable_irq(NPCX_IRQ_UART);
+
+ init_done = 1;
+}
diff --git a/chip/npcx/watchdog.c b/chip/npcx/watchdog.c
new file mode 100644
index 0000000000..411488877a
--- /dev/null
+++ b/chip/npcx/watchdog.c
@@ -0,0 +1,142 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Watchdog driver */
+
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "registers.h"
+#include "hwtimer_chip.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "timer.h"
+#include "task.h"
+#include "util.h"
+#include "watchdog.h"
+
+/* WDCNT value for watchdog period */
+#define WDCNT_VALUE ((CONFIG_WATCHDOG_PERIOD_MS*INT_32K_CLOCK) / (1024*1000))
+/* Delay counter time for print watchdog info through UART */
+#define WDCNT_DELAY 0x10
+
+
+void watchdog_init_warning_timer(void)
+{
+ /* init watchdog timer first */
+ init_hw_timer(ITIM_WDG_NO, ITIM16_SOURCE_CLOCK_32K);
+
+ /*
+ * prescaler to TIMER_TICK
+ * Ttick_unit = (PRE_8+1) * T32k
+ * PRE_8 = (Ttick_unit/T32K) - 1
+ * Unit: 1 msec
+ */
+ NPCX_ITPRE(ITIM_WDG_NO) = DIV_ROUND_NEAREST(1000*INT_32K_CLOCK,
+ SECOND) - 1;
+
+ /* ITIM count down : event expired*/
+ NPCX_ITCNT16(ITIM_WDG_NO) = CONFIG_WATCHDOG_PERIOD_MS-1;
+ /* Event module enable */
+ SET_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITIM16_ITEN);
+ /* Enable interrupt of ITIM */
+ task_enable_irq(ITIM16_INT(ITIM_WDG_NO));
+}
+
+
+void watchdog_check(uint32_t excep_lr, uint32_t excep_sp)
+{
+ int wd_cnt;
+ /* Clear timeout status for event */
+ SET_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITIM16_TO_STS);
+
+ /* Read watchdog counter from TWMWD */
+ wd_cnt = NPCX_TWMWD;
+#if DEBUG_WDG
+ ccprintf("WD (%d)\r\n", wd_cnt);
+#endif
+ if (wd_cnt <= WDCNT_DELAY)
+ watchdog_trace(excep_lr, excep_sp);
+}
+
+/* ISR for watchdog warning naked will keep SP & LR */
+void IRQ_HANDLER(ITIM16_INT(ITIM_WDG_NO))(void) __attribute__((naked));
+void IRQ_HANDLER(ITIM16_INT(ITIM_WDG_NO))(void)
+ {
+ /* Naked call so we can extract raw LR and SP */
+ asm volatile("mov r0, lr\n"
+ "mov r1, sp\n"
+ /* Must push registers in pairs to keep 64-bit aligned
+ * stack for ARM EABI. This also conveninently saves
+ * R0=LR so we can pass it to task_resched_if_needed. */
+ "push {r0, lr}\n"
+ "bl watchdog_check\n"
+ "pop {r0, lr}\n"
+ "b task_resched_if_needed\n");
+ }
+const struct irq_priority IRQ_PRIORITY(ITIM16_INT(ITIM_WDG_NO))
+__attribute__((section(".rodata.irqprio")))
+= {ITIM16_INT(ITIM_WDG_NO), 0};
+/* put the watchdog at the highest priority */
+
+void watchdog_reload(void)
+{
+ /* Disable watchdog interrupt */
+ task_disable_irq(ITIM16_INT(ITIM_WDG_NO));
+
+#if 1 /* mark this for testing watchdog */
+ /* Touch watchdog & reset software counter */
+ NPCX_WDSDM = 0x5C;
+#endif
+
+ /* Enable watchdog interrupt */
+ task_enable_irq(ITIM16_INT(ITIM_WDG_NO));
+}
+DECLARE_HOOK(HOOK_TICK, watchdog_reload, HOOK_PRIO_DEFAULT);
+
+int watchdog_init(void)
+{
+#if SUPPORT_WDG
+ /* Keep prescaler ratio timer0 clock to 1:1024 */
+ NPCX_TWCP = 0x0A;
+ /* Keep prescaler ratio watchdog clock to 1:1 */
+ NPCX_WDCP = 0;
+
+ /* Clear watchdog reset status initially*/
+ SET_BIT(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS);
+
+ /* Reset TWCFG */
+ NPCX_TWCFG = 0;
+ /* Watchdog touch by writing 5Ch to WDSDM */
+ SET_BIT(NPCX_TWCFG, NPCX_TWCFG_WDSDME);
+ /* Select T0IN clock as watchdog prescaler clock */
+ SET_BIT(NPCX_TWCFG, NPCX_TWCFG_WDCT0I);
+ /* Disable early touch functionality */
+ SET_BIT(NPCX_T0CSR, NPCX_T0CSR_TESDIS);
+
+ /*
+ * Set WDCNT initial reload value and T0OUT timeout period
+ * 1. Watchdog clock source is 32768/1024 Hz and disable T0OUT.
+ * 2. ITIM16 will be issued to check WDCNT is under WDCNT_DELAY or not
+ * 3. Set RST to upload TWDT0 & WDCNT
+ */
+ /* Set WDCNT --> WDCNT=0 will generate watchdog reset */
+ NPCX_WDCNT = WDCNT_VALUE + WDCNT_DELAY;
+
+ /* Disable interrupt */
+ interrupt_disable();
+ /* Reload TWDT0/WDCNT */
+ SET_BIT(NPCX_T0CSR, NPCX_T0CSR_RST);
+ /* Wait for timer is loaded and restart */
+ while (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_RST))
+ ;
+ /* Enable interrupt */
+ interrupt_enable();
+
+ /* Init watchdog warning timer */
+ watchdog_init_warning_timer();
+#endif
+ return EC_SUCCESS;
+}
diff --git a/common/keyboard_8042.c b/common/keyboard_8042.c
index cf2b5bec94..d21b4ceae5 100644
--- a/common/keyboard_8042.c
+++ b/common/keyboard_8042.c
@@ -453,7 +453,7 @@ static void clear_typematic_key(void)
void keyboard_state_changed(int row, int col, int is_pressed)
{
uint8_t scan_code[MAX_SCAN_CODE_LEN];
- int32_t len;
+ int32_t len = 0;
enum ec_error_list ret;
CPRINTS5("KB (%d,%d)=%d", row, col, is_pressed);
diff --git a/common/system.c b/common/system.c
index de3000ccd1..cdb940c77b 100644
--- a/common/system.c
+++ b/common/system.c
@@ -310,6 +310,10 @@ void system_disable_jump(void)
test_mockable enum system_image_copy_t system_get_image_copy(void)
{
+ /* TODO: (ML) return which region is used in Code RAM */
+#ifdef CONFIG_CODERAM_ARCH
+ return system_get_shrspi_image_copy();
+#else
uintptr_t my_addr = (uintptr_t)system_get_image_copy -
CONFIG_FLASH_BASE;
@@ -322,6 +326,7 @@ test_mockable enum system_image_copy_t system_get_image_copy(void)
return SYSTEM_IMAGE_RW;
return SYSTEM_IMAGE_UNKNOWN;
+#endif
}
int system_get_image_used(enum system_image_copy_t copy)
@@ -329,7 +334,7 @@ int system_get_image_used(enum system_image_copy_t copy)
const uint8_t *image;
int size = 0;
- image = (const uint8_t *)(get_base(copy));
+ image = (const uint8_t *)get_base(copy);
size = get_size(copy);
if (size <= 0)
@@ -342,7 +347,6 @@ int system_get_image_used(enum system_image_copy_t copy)
*/
for (size--; size > 0 && image[size] != 0xea; size--)
;
-
return size ? size + 1 : 0; /* 0xea byte IS part of the image */
}
@@ -473,12 +477,17 @@ int system_run_image_copy(enum system_image_copy_t copy)
if (base == 0xffffffff)
return EC_ERROR_INVAL;
+ /* TODO: (ML) jump to little FW for code ram architecture */
+#ifdef CONFIG_CODERAM_ARCH
+ init_addr = system_get_lfw_address(base);
+#else
/* Make sure the reset vector is inside the destination image */
init_addr = *(uintptr_t *)(base + 4);
#ifndef EMU_BUILD
if (init_addr < base || init_addr >= base + get_size(copy))
return EC_ERROR_UNKNOWN;
#endif
+#endif
CPRINTS("Jumping to image %s", system_image_copy_t_to_string(copy));
@@ -503,7 +512,11 @@ const char *system_get_version(enum system_image_copy_t copy)
/* The version string is always located after the reset vectors, so
* it's the same as in the current image. */
+#ifdef CONFIG_CODERAM_ARCH /* TODO: (ML) we run FW in Code RAM */
+ addr += ((uintptr_t)&version_data - CONFIG_CDRAM_BASE);
+#else
addr += ((uintptr_t)&version_data - get_base(system_get_image_copy()));
+#endif
/* Make sure the version struct cookies match before returning the
* version string. */
diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S
index bd813a8b22..5d70f366e8 100644
--- a/core/cortex-m/ec.lds.S
+++ b/core/cortex-m/ec.lds.S
@@ -19,6 +19,9 @@ MEMORY
{
FLASH (rx) : ORIGIN = FW_OFF(SECTION), LENGTH = FW_SIZE(SECTION)
IRAM (rw) : ORIGIN = CONFIG_RAM_BASE, LENGTH = CONFIG_RAM_SIZE
+#ifdef CONFIG_CODERAM_ARCH
+ CDRAM (rx) : ORIGIN = CONFIG_CDRAM_BASE, LENGTH = CONFIG_CDRAM_SIZE
+#endif
#ifdef RSA_PUBLIC_KEY_SIZE
PSTATE(r) : ORIGIN = FW_OFF(SECTION) + FW_SIZE(SECTION), \
LENGTH = CONFIG_FW_PSTATE_SIZE
@@ -43,12 +46,21 @@ SECTIONS
#endif
OUTDIR/core/CORE/init.o (.text)
*(.text*)
+#ifdef CONFIG_CODERAM_ARCH
+ __flash_lpfw_start = .;
+ /* Entering deep idle FW for better power consumption */
+ KEEP(*(.lowpower_ram))
+ __flash_lpfw_end = .;
+ } > CDRAM AT > FLASH
+#else
#ifdef COMPILE_FOR_RAM
} > IRAM
#else
} > FLASH
#endif
+#endif
. = ALIGN(4);
+
.rodata : {
/* Symbols defined here are declared in link_defs.h */
__irqprio = .;
@@ -151,11 +163,15 @@ SECTIONS
KEEP(*(.google))
#endif
. = ALIGN(4);
+#ifdef CONFIG_CODERAM_ARCH
+ } > CDRAM AT > FLASH
+#else
#ifdef COMPILE_FOR_RAM
} > IRAM
#else
} > FLASH
#endif
+#endif
__ro_end = . ;
__deferred_funcs_count =
@@ -184,8 +200,13 @@ SECTIONS
#ifdef COMPILE_FOR_RAM
.data : {
#else
+#ifdef CONFIG_CODERAM_ARCH
+ __data_start = . ;
+ .data : AT(LOADADDR(.rodata) + SIZEOF(.rodata)) {
+#else
.data : AT(ADDR(.rodata) + SIZEOF(.rodata)) {
#endif
+#endif
. = ALIGN(4);
__data_start = .;
*(.data.tasks)
diff --git a/include/system.h b/include/system.h
index 71cad098f9..259e34fc92 100644
--- a/include/system.h
+++ b/include/system.h
@@ -369,4 +369,22 @@ void system_set_rtc_alarm(uint32_t seconds, uint32_t microseconds);
*/
void system_reset_rtc_alarm(void);
+#ifdef CONFIG_CODERAM_ARCH
+/**
+ * Determine which address should be jumped and return address of littel FW
+ *
+ * Note: This feature is used for code ram arch
+ *
+ * @param flash_addr jump address of spi flash for RO or RW region
+ */
+uint32_t system_get_lfw_address(uint32_t flash_addr);
+
+/**
+ * Return whcih region is used in Code RAM
+ *
+ * Note: This feature is used for code ram arch
+ *
+ */
+enum system_image_copy_t system_get_shrspi_image_copy(void);
+#endif
#endif /* __CROS_EC_SYSTEM_H */
diff --git a/util/flash_ec b/util/flash_ec
index 0d840a9ae4..9cfc19baa1 100755
--- a/util/flash_ec
+++ b/util/flash_ec
@@ -64,7 +64,7 @@ BOARDS_STM32=(
discovery
firefly
fruitpie
- jerry
+ jerry
kitty
mighty
minimuffin
@@ -92,6 +92,10 @@ BOARDS_STM32_DFU=(
twinkie
)
+BOARDS_NPCX=(
+ npcx_evb
+)
+
# Flags
DEFINE_string board "${DEFAULT_BOARD}" \
"The board to run debugger on."
@@ -405,6 +409,38 @@ function flash_lm4() {
die "Failed to program ${IMG}"
}
+function flash_npcx() {
+ [[ -n "${EC_DIR}" ]] || die "Cannot locate openocd script"
+
+ if [ "${FLAGS_usb}" = ${FLAGS_TRUE} ] ; then
+ OCD_CFG="${BOARD}.cfg"
+ else
+ OCD_CFG="servo_v2.cfg"
+ fi
+
+ OCD_PATH="${EC_DIR}/chip/npcx/openocd"
+ if [ "${FLAGS_unprotect}" = ${FLAGS_TRUE} ] ; then
+ # Unprotect exists, but isn't needed because erasing pstate is
+ # implicit in writing the entire image
+ die "--unprotect not supported for this board."
+ fi
+
+ dut_control jtag_buf_on_flex_en:on
+ dut_control jtag_buf_en:on
+
+ if [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] ; then
+ # Program RO region only
+ OCD_CMDS="init; flash_npcx_ro ${FLAGS_offset}; shutdown;"
+ sudo openocd -s "${OCD_PATH}" -f "${OCD_CFG}" -c "${OCD_CMDS}" || \
+ die "Failed to program ${IMG}"
+ else
+ # Program all EC regions
+ OCD_CMDS="init; flash_npcx_evb ${FLAGS_offset}; shutdown;"
+ sudo openocd -s "${OCD_PATH}" -f "${OCD_CFG}" -c "${OCD_CMDS}" || \
+ die "Failed to program ${IMG}"
+ fi
+}
+
if dut_control boot_mode 2>/dev/null ; then
if [[ "${MCU}" != "ec" ]] ; then
die "Toad cable can't support non-ec UARTs"
@@ -434,6 +470,8 @@ elif $(in_array "${BOARDS_STM32_DFU[@]}" "${BOARD}"); then
flash_stm32_dfu
elif [ "${BOARD}" == "link" ]; then
flash_link
+elif $(in_array "${BOARDS_NPCX[@]}" "${BOARD}"); then
+ flash_npcx
else
die "board ${BOARD} not supported"
fi