summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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