nuc: Add SHI driver for arm-based platform in chip folder.

Add npcx_evb_arm board-level driver for arm-based platform.
Add header.c: for booting from NPCX5M5G A3 Booter.
Remove lfw folder due to those functionalitie have been replaced with Booter

Modified drivers for
Patch Set 1:
1. flash.c: Implement UMA lock, tri-state and selection register lock functionalities
2. hwtimer.c: Add ITIM32 for hwtimer
3. lpc.c: Add checking for LRESET
4. system.c: Modified CODERAM_ARCH functions for NPCX5M5G A3 Booter.
5. uart.c: Add support for module 2
Patch Set 2:
6. lpc.c: Modified lpc_get_pltrst_asserted() func
Patch Set 3:
7. minimize the changes for CONFIG_CODERAM_ARCH in common layer
8. comments of Patch Set1/2
Patch Set 4:
9. Modified CONFIG_RO_MEM_OFF point to ro image and keep header as a part of ec.RO.flat.
10. Fixed RO_FRID and RW_FRID issues which caused by CONFIG_CODERAM_ARCH.
Patch Set 5:
11. Modified system.c in common folder for supporting *_STORAGE_OFF.
12. Use *_STORAGE_OFF in firmware_image.lds.S to indicate flat file layout in flash.
Patch Set 6:
13. rebase to newest version
14. system.c: Modified for the newest include/system.h
Patch Set 7:
15. Merge from version 0625

BUG=chrome-os-partner:34346
TEST=make buildall -j; test nuvoton IC specific drivers
BRANCH=none

Change-Id: Ifd7c10b81b5781ccd75bb2558dc236486976e8ed
Signed-off-by: Ian Chao <mlchao@nuvoton.com>
Reviewed-on: https://chromium-review.googlesource.com/272034
Reviewed-by: Shawn N <shawnn@chromium.org>
Tested-by: Shawn N <shawnn@chromium.org>
Commit-Queue: Shawn N <shawnn@chromium.org>
This commit is contained in:
Ian Chao
2015-06-25 18:12:09 +08:00
committed by ChromeOS Commit Bot
parent ccb6b15d51
commit 957638c78c
40 changed files with 2108 additions and 695 deletions

View File

@@ -261,16 +261,6 @@ $(npcx-flash-fw-bin):
-Wl,-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
-@ $(CC) $(out)/$(npcx-lfw).o $(LDFLAGS) -o $(out)/$(npcx-lfw).elf \
-Wl,-T,$(npcx-lfw).ld -Wl,-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)

1
board/npcx_evb/Makefile Symbolic link
View File

@@ -0,0 +1 @@
../../Makefile

View File

@@ -97,7 +97,7 @@ const struct mft_t mft_channels[] = {
.module = NPCX_MFT_MODULE_1,
.port = NPCX_MFT_MODULE_PORT_TA,
.default_count = 0xFFFF,
#ifdef CONFIG_MFT_INPUT_LFCLK
#ifdef NPCX_MFT_INPUT_LFCLK
.freq = 32768,
#else
.freq = 2000000,

View File

@@ -16,6 +16,7 @@
#define CONFIG_PECI
#define CONFIG_PWM
#define CONFIG_SPI
#define CONFIG_LPC /* Used in Intel-based platform for host interface */
/* Optional features */
#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands for testing */
@@ -42,8 +43,12 @@
#define CONFIG_FANS 1
/* 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 */
#define NPCX_PWM_INPUT_LFCLK /* PWM use LFCLK for input clock */
#define NPCX_MFT_INPUT_LFCLK /* MFT use LFCLK for input clock */
#define NPCX_I2C0_BUS2 0 /* 0:GPIOB4/B5 1:GPIOB2/B3 as I2C0 */
#define NPCX_UART_MODULE2 0 /* 0:GPIO10/11 1:GPIO64/65 as UART */
#define NPCX_JTAG_MODULE2 0 /* 0:GPIO21/17/16/20 1:GPIOD5/E2/D4/E5 as JTAG*/
#define NPCX_TACH_SEL2 0 /* 0:GPIO40/A4 1:GPIO93/D3 as TACH */
/* Optional for testing */
#undef CONFIG_PSTORE

View File

@@ -5,20 +5,22 @@
* found in the LICENSE file.
*/
/********************** Inputs with interrupt handlers are first for efficiency **********************/
/* TODO: Redefine debug 2 inputs */
GPIO_INT(RECOVERY_L, PIN(0, 0), GPIO_PULL_UP | GPIO_INT_BOTH, switch_interrupt) /* Recovery signal from servo */
GPIO_INT(WP_L, PIN(9, 3), GPIO_PULL_DOWN | GPIO_INT_BOTH, switch_interrupt) /* Write protect input */
GPIO_INT(RECOVERY_L, PIN(0, 0), GPIO_PULL_UP | GPIO_INT_BOTH, switch_interrupt) /* Recovery signal from servo */
GPIO_INT(WP_L, PIN(9, 3), GPIO_PULL_DOWN | GPIO_INT_BOTH, switch_interrupt) /* Write protect input */
/* For testing 8042 commands, we need the following GPIOs */
/* For testing keyboard commands, we need the following 4 GPIOs */
/* TODO: Redefine 4 inputs */
GPIO_INT(POWER_BUTTON_L, PIN(0, 2), GPIO_PULL_UP | GPIO_INT_BOTH, power_button_interrupt) /* Power button */
GPIO_INT(LID_OPEN, PIN(3, 3), GPIO_PULL_DOWN | GPIO_INT_BOTH, lid_interrupt) /* Lid switch */
GPIO_INT(POWER_BUTTON_L, PIN(0, 2), GPIO_PULL_UP | GPIO_INT_BOTH, power_button_interrupt) /* Power button */
GPIO_INT(LID_OPEN, PIN(3, 3), GPIO_PULL_DOWN | GPIO_INT_BOTH, lid_interrupt) /* Lid switch */
/**************************** Need a empty line between GPIO_INT and GPIO ****************************/
GPIO(ENTERING_RW, PIN(3, 6), GPIO_OUT_LOW) /* Indicate when EC is entering RW code */
GPIO(PCH_WAKE_L, PIN(5, 0), GPIO_OUT_HIGH) /* Wake signal output to PCH */
/* Used for module testing */
GPIO(PGOOD_FAN, PIN(C, 7), GPIO_PULL_UP | GPIO_INPUT) /* Power Good for FAN test */
GPIO(PGOOD_FAN, PIN(C, 7), GPIO_PULL_UP | GPIO_INPUT) /* Power Good for FAN test */
GPIO(SPI_CS_L, PIN(A, 5), GPIO_OUT_HIGH) /* SPI_CS Ready, Low Active. */
/*
@@ -35,14 +37,28 @@ GPIO(BOARD_VERSION3, PIN(6, 6), GPIO_INPUT) /* Board version stuffing r
#ifdef CONFIG_KEYBOARD_COL2_INVERTED
GPIO(KBD_KSO2, PIN(1, 7), GPIO_OUT_LOW) /* Negative edge triggered keyboard irq. */
#endif
/**************************** Alternate pins for UART/I2C/ADC/SPI/PWM/MFT ****************************/
/* Alternate pins for UART/I2C/ADC/SPI/PWM/MFT */
#if NPCX_UART_MODULE2
ALTERNATE(PIN_MASK(6, 0x30), 1, MODULE_UART, 0) /* CR_SIN/SOUT GPIO64/65 */
#else
ALTERNATE(PIN_MASK(1, 0x03), 1, MODULE_UART, 0) /* CR_SIN/SOUT GPIO10/11 */
ALTERNATE(PIN_MASK(B, 0x30), 1, MODULE_I2C, 0) /* I2C0SDA/I2C0SCL GPIOB4/B5 */
#endif
#if NPCX_I2C0_BUS2
ALTERNATE(PIN_MASK(B, 0x0C), 1, MODULE_I2C, 0) /* I2C0SDA/I2C0SCL GPIOB2/B3 */
#else
ALTERNATE(PIN_MASK(B, 0x30), 1, MODULE_I2C, 0) /* I2C0SDA/I2C0SCL GPIOB4/B5 */
#endif
ALTERNATE(PIN_MASK(8, 0x80), 1, MODULE_I2C, 0) /* I2C1SDA GPIO87 */
ALTERNATE(PIN_MASK(9, 0x07), 1, MODULE_I2C, 0) /* I2C1SCL/I2C2SDA/I2C2SCL GPIO90/91/92 */
ALTERNATE(PIN_MASK(4, 0x38), 1, MODULE_ADC, 0) /* ADC GPIO45/44/43 */
ALTERNATE(PIN_MASK(A, 0x0A), 1, MODULE_SPI, 0) /* SPIP_MOSI/SPIP_SCLK GPIOA3/A1 */
ALTERNATE(PIN_MASK(A, 0x0A), 1, MODULE_SPI, 0) /* SPIP_MOSI/SPIP_SCLK GPIOA3/A1 */
ALTERNATE(PIN_MASK(9, 0x20), 1, MODULE_SPI, 0) /* SPIP_MISO GPIO95 */
ALTERNATE(PIN_MASK(C, 0x04), 3, MODULE_PWM_KBLIGHT, 0) /* PWM1 for PWM/KBLIGHT Test GPIOC2 */
ALTERNATE(PIN_MASK(C, 0x08), 7, MODULE_PWM_FAN, 0) /* PWM0 for PWM/FAN Test GPIOC3 */
#if NPCX_TACH_SEL2
ALTERNATE(PIN_MASK(9, 0x08), 3, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN GPIO93 */
#else
ALTERNATE(PIN_MASK(4, 0x01), 3, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN Test GPIO40 */
#endif

1
board/npcx_evb_arm/Makefile Symbolic link
View File

@@ -0,0 +1 @@
../../Makefile

131
board/npcx_evb_arm/board.c Normal file
View File

@@ -0,0 +1,131 @@
/* Copyright 2015 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 "shi_chip.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 can reverse the PWM output signal according to
* the board design
*/
.flags = PWM_CONFIG_ACTIVE_LOW,
/*
* freq_operation = freq_input / prescaler_divider
* freq_output = freq_operation / cycle_pulses
* and freq_output <= freq_mft
*/
.freq = 34,
/*
* cycle_pulses = (cycle_pulses * freq_output) *
* RPM_EDGES * RPM_SCALE * 60 / poles / rpm_min
*/
.cycle_pulses = 480,
},
[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 = 1020,
.rpm_start = 1020,
.rpm_max = 8190,
.ch = 0,/* Use PWM/MFT to control fan */
.pgood_gpio = GPIO_PGOOD_FAN,
.enable_gpio = -1,
},
};
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 NPCX_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 */
},
};

View File

@@ -0,0 +1,90 @@
/* Copyright 2015 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 __CROS_EC_BOARD_H
#define __CROS_EC_BOARD_H
/* Support Code RAM architecture (Run code in RAM) */
#define CONFIG_CODERAM_ARCH
/* Optional modules */
#define CONFIG_ADC
#define CONFIG_PWM
#define CONFIG_SHI /* Used in ARM-based platform for host interface */
/* Optional features */
#define CONFIG_SYSTEM_UNLOCKED /* Allow dangerous commands for testing */
#define CONFIG_SPI_FLASH_SIZE 0x00800000 /* 8MB spi flash */
#define CONFIG_SPI_FLASH_W25Q64
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_PROTOCOL_MKBP /* Instead of 8042 protocol of keyboard */
#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
/* Optional feature - used by nuvoton */
#define NPCX_PWM_INPUT_LFCLK /* PWM use LFCLK for input clock */
#define NPCX_MFT_INPUT_LFCLK /* MFT use LFCLK for input clock */
#define NPCX_I2C0_BUS2 0 /* 0:GPIOB4/B5 1:GPIOB2/B3 as I2C0 */
#define NPCX_UART_MODULE2 0 /* 0:GPIO10/11 1:GPIO64/65 as UART */
#define NPCX_JTAG_MODULE2 0 /* 0:GPIO21/17/16/20 1:GPIOD5/E2/D4/E5 as JTAG*/
#define NPCX_TACH_SEL2 0 /* 0:GPIO40/A4 1:GPIO93/D3 as TACH */
/* Optional for testing */
#undef CONFIG_PSTORE
#undef 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 /* __CROS_EC_BOARD_H */

View File

@@ -0,0 +1,12 @@
# -*- makefile -*-
# Copyright 2015 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

View File

@@ -0,0 +1,23 @@
/* Copyright 2015 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_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)

View File

@@ -0,0 +1,64 @@
/* -*- mode:c -*-
*
* Copyright 2015 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.
*/
/********************** Inputs with interrupt handlers are first for efficiency **********************/
/* TODO: Redefine debug 2 inputs */
GPIO_INT(RECOVERY_L, PIN(0, 0), GPIO_PULL_UP | GPIO_INT_BOTH, switch_interrupt) /* Recovery signal from servo */
GPIO_INT(WP_L, PIN(9, 3), GPIO_PULL_DOWN | GPIO_INT_BOTH, switch_interrupt) /* Write protect input */
/* Used for ARM based platform */
GPIO_INT(SHI_CS_L, PIN(5, 3), GPIO_INT_FALLING,shi_cs_event) /* SHI CS Ready, Low Active. */
/* For testing keyboard commands, we need the following 4 GPIOs */
/* TODO: Redefine 4 inputs */
GPIO_INT(POWER_BUTTON_L, PIN(0, 2), GPIO_PULL_UP | GPIO_INT_BOTH, power_button_interrupt) /* Power button */
GPIO_INT(LID_OPEN, PIN(3, 3), GPIO_PULL_DOWN | GPIO_INT_BOTH, lid_interrupt) /* Lid switch */
/**************************** Need a empty line between GPIO_INT and GPIO ****************************/
GPIO(ENTERING_RW, PIN(3, 6), GPIO_OUT_LOW) /* Indicate when EC is entering RW code */
GPIO(PCH_WAKE_L, PIN(5, 0), GPIO_OUT_HIGH) /* Wake signal output to PCH */
/* For testing keyboard mkbp */
GPIO(EC_INT, PIN(7, 4), GPIO_ODR_HIGH) /* Interrupt pin for keyboard mkbp */
/* Used for module testing */
GPIO(PGOOD_FAN, PIN(C, 7), GPIO_PULL_UP | GPIO_INPUT) /* Power Good for FAN test */
/*
* I2C pins should be configured as inputs until I2C module is
* initialized. This will avoid driving the lines unintentionally.
*/
GPIO(MASTER_I2C_SCL, PIN(B, 5), GPIO_INPUT)
GPIO(MASTER_I2C_SDA, PIN(B, 4), GPIO_INPUT)
/* Used for board version command */
GPIO(BOARD_VERSION1, PIN(6, 4), GPIO_INPUT) /* Board version stuffing resistor 1 */
GPIO(BOARD_VERSION2, PIN(6, 5), GPIO_INPUT) /* Board version stuffing resistor 2 */
GPIO(BOARD_VERSION3, PIN(6, 6), GPIO_INPUT) /* Board version stuffing resistor 3 */
#ifdef CONFIG_KEYBOARD_COL2_INVERTED
GPIO(KBD_KSO2, PIN(1, 7), GPIO_OUT_LOW) /* Negative edge triggered keyboard irq. */
#endif
/**************************** Alternate pins for UART/I2C/ADC/SPI/PWM/MFT ****************************/
/* Alternate pins for UART/I2C/ADC/SPI/PWM/MFT */
#if NPCX_UART_MODULE2
ALTERNATE(PIN_MASK(6, 0x30), 1, MODULE_UART, 0) /* CR_SIN/SOUT GPIO64/65 */
#else
ALTERNATE(PIN_MASK(1, 0x03), 1, MODULE_UART, 0) /* CR_SIN/SOUT GPIO10/11 */
#endif
#if NPCX_I2C0_BUS2
ALTERNATE(PIN_MASK(B, 0x0C), 1, MODULE_I2C, 0) /* I2C0SDA/I2C0SCL GPIOB2/B3 */
#else
ALTERNATE(PIN_MASK(B, 0x30), 1, MODULE_I2C, 0) /* I2C0SDA/I2C0SCL GPIOB4/B5 */
#endif
ALTERNATE(PIN_MASK(8, 0x80), 1, MODULE_I2C, 0) /* I2C1SDA GPIO87 */
ALTERNATE(PIN_MASK(9, 0x07), 1, MODULE_I2C, 0) /* I2C1SCL/I2C2SDA/I2C2SCL GPIO90/91/92 */
ALTERNATE(PIN_MASK(4, 0x38), 1, MODULE_ADC, 0) /* ADC GPIO45/44/43 */
ALTERNATE(PIN_MASK(A, 0x0A), 1, MODULE_SPI, 0) /* SPIP_MOSI/SPIP_SCLK GPIOA3/A1 */
ALTERNATE(PIN_MASK(9, 0x20), 1, MODULE_SPI, 0) /* SPIP_MISO GPIO95 */
ALTERNATE(PIN_MASK(C, 0x04), 3, MODULE_PWM_KBLIGHT, 0) /* PWM1 for PWM/KBLIGHT Test GPIOC2 */
ALTERNATE(PIN_MASK(C, 0x08), 7, MODULE_PWM_FAN, 0) /* PWM0 for PWM/FAN Test GPIOC3 */
#if NPCX_TACH_SEL2
ALTERNATE(PIN_MASK(9, 0x08), 3, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN GPIO93 */
#else
ALTERNATE(PIN_MASK(4, 0x01), 3, MODULE_PWM_FAN, 0) /* MFT-1/TA1_TACH1 for FAN Test GPIO40 */
#endif

View File

@@ -12,7 +12,7 @@ CORE:=cortex-m
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
chip-y=header.o clock.o gpio.o hwtimer.o jtag.o system.o uart.o
# Optional chip modules
chip-$(CONFIG_ADC)+=adc.o
@@ -21,17 +21,13 @@ chip-$(CONFIG_FLASH)+=flash.o
chip-$(CONFIG_I2C)+=i2c.o
chip-$(CONFIG_LPC)+=lpc.o
chip-$(CONFIG_PECI)+=peci.o
chip-$(CONFIG_SHI)+=shi.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

View File

@@ -175,7 +175,7 @@ int clock_get_apb2_freq(void)
void clock_wait_cycles(uint32_t cycles)
{
asm("1: subs %0, #1\n"
" bne 1b\n" :: "r"(cycles));
" bne 1b\n" : : "r"(cycles));
}
#ifdef CONFIG_LOW_POWER_IDLE
@@ -190,35 +190,30 @@ void clock_refresh_console_in_use(void)
void clock_uart2gpio(void)
{
/* Is pimux to UART? */
if (IS_BIT_SET(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL)) {
if (npcx_is_uart()) {
/* 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);
/* Set to GPIO */
npcx_uart2gpio();
/* Enable MIWU for GPIO (UARTRX) */
npcx_enable_wakeup(1);
/* 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);
npcx_clear_wakeup_event();
}
}
void clock_gpio2uart(void)
{
/* Is Pending bit of GPIO (UARTRX) */
if (IS_BIT_SET(NPCX_WKPND(1, 1), 0)) {
if (npcx_is_wakeup_from_gpio()) {
/* Clear Pending bit of GPIO (UARTRX) */
SET_BIT(NPCX_WKPCL(1, 1), 0);
uart_clear_wakeup_event();
/* 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);
/* Disable MIWU for GPIO (UARTRX) */
uart_enable_miwu_wakeup(0);
/* Go back CR_SIN*/
SET_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL);
npcx_gpio2uart();
/* Enable uart again */
task_enable_irq(NPCX_IRQ_UART);
}
@@ -227,7 +222,7 @@ void clock_gpio2uart(void)
/* Idle task. Executed when no tasks are ready to be scheduled. */
void __idle(void)
{
#ifdef SUPPORT_JTAG
#if (CHIP_VERSION < 3)
while (1) {
/*
* TODO:(ML) JTAG bug: if debugger is connected,

View File

@@ -35,9 +35,9 @@
/*****************************************************************************/
/* 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_RAM_SIZE (0x00008000 - 0x800) /* 30KB data ram */
#define CONFIG_CDRAM_BASE 0x100A8000 /* memory map address of code ram */
#define CONFIG_CDRAM_SIZE 0x00018000 /* 96KB 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 */
@@ -61,38 +61,44 @@
#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 CONFIG_FLASH_WRITE_IDEAL_SIZE 256 /* one page size for write */
/* 128 KB alignment for SPI status registers protection */
#define CONFIG_FLASH_PHYSICAL_SIZE 0x40000 /* 256 KB Flash used for EC */
/* No PSTATE; uses a real SPI flash */
#undef CONFIG_FLASH_PSTATE
/* Header support which is used by booter to copy FW from flash to code ram */
#define NPCX_RO_HEADER
/****************************************************************************/
/* Define our flash layout. */
/* Define npcx 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_RO_MEM_OFF 0
/* The storage offset of ec.RO.flat which is used for CONFIG_CDRAM_ARCH */
#define CONFIG_RO_STORAGE_OFF 0
#define CONFIG_RO_SIZE CONFIG_FW_IMAGE_SIZE
#ifdef NPCX_RO_HEADER
#define CONFIG_RO_HDR_MEM_OFF 0x0
#define CONFIG_RO_HDR_SIZE 0x40
/* RO firmware offset in flash */
#define CONFIG_RO_MEM_OFF CONFIG_RO_HDR_SIZE
#else
#define CONFIG_RO_MEM_OFF 0x0
#endif
#define CONFIG_RO_SIZE CONFIG_CDRAM_SIZE /* 96KB for RO FW */
#define CONFIG_FLASH_SIZE CONFIG_FLASH_PHYSICAL_SIZE
/* RW firmware is one firmware image offset from the start */
#define CONFIG_RW_MEM_OFF CONFIG_FW_IMAGE_SIZE
#define CONFIG_RW_STORAGE_OFF CONFIG_FW_IMAGE_SIZE
#define CONFIG_RW_SIZE CONFIG_FW_IMAGE_SIZE
/* The storage offset of ec.RW.flat which is used for CONFIG_CDRAM_ARCH */
#define CONFIG_RW_STORAGE_OFF CONFIG_FW_IMAGE_SIZE /* 128 KB alignemnt */
/* RW firmware offset in flash */
#define CONFIG_RW_MEM_OFF CONFIG_RW_STORAGE_OFF
#define CONFIG_RW_SIZE CONFIG_CDRAM_SIZE /* 96KB for RW FW */
#define CONFIG_WP_OFF CONFIG_RO_STORAGE_OFF
#define CONFIG_WP_SIZE CONFIG_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
#define CONFIG_WP_SIZE CONFIG_FW_IMAGE_SIZE
/****************************************************************************/
/* Customize the build */
@@ -101,11 +107,9 @@
#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 */

View File

@@ -114,7 +114,7 @@ static void mft_startmeasure(int ch)
int mft_ch = fan_op_ch(ch, NPCX_FAN_OP_MFT);
/* Start measurement */
#ifdef CONFIG_MFT_INPUT_LFCLK
#ifdef NPCX_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) =
@@ -199,7 +199,7 @@ static void mft_finalmeasure(int ch)
* @return none
* @notes changed when initial or HOOK_FREQ_CHANGE command
*/
#ifndef CONFIG_MFT_INPUT_LFCLK
#ifndef NPCX_MFT_INPUT_LFCLK
void mft_freq_changed(void)
{
uint16_t prescaler_divider = 0;
@@ -243,7 +243,7 @@ static void fan_config(int ch, int enable_mft_read_rpm)
& (~(((1<<3)-1)<<NPCX_TMCTRL_MDSEL)))
| (NPCX_MFT_MDSEL_5<<NPCX_TMCTRL_MDSEL);
#ifndef CONFIG_MFT_INPUT_LFCLK
#ifndef NPCX_MFT_INPUT_LFCLK
/* Set MFT operation frequence */
mft_freq_changed();
/* Set the active power mode. */

View File

@@ -19,6 +19,7 @@
int all_protected; /* Has all-flash protection been requested? */
int addr_prot_start;
int addr_prot_length;
uint8_t flag_prot_inconsistent;
#define FLASH_ABORT_TIMEOUT 10000
@@ -179,15 +180,6 @@ static int reg_to_protect(uint8_t sr1, uint8_t sr2, unsigned int *start,
if (sec && bp == 6)
return EC_ERROR_INVAL;
/*
* If SRP0 is not set, flash is not protected because status register
* can be rewritten.
*/
if (!(sr1 & SPI_FLASH_SR1_SRP0)) {
*start = *len = 0;
return EC_SUCCESS;
}
/* Determine granularity (4kb sector or 64kb block) */
/* Computation using 2 * 1024 is correct */
size = sec ? (2 * 1024) : (64 * 1024);
@@ -212,6 +204,20 @@ static int reg_to_protect(uint8_t sr1, uint8_t sr2, unsigned int *start,
*len = CONFIG_FLASH_SIZE - *len;
}
/*
* If SRP0 is not set, flash is not protected because status register
* can be rewritten.
*/
if (!(sr1 & SPI_FLASH_SR1_SRP0)) {
/* Set protection inconsistent if len != 0*/
if (*len != 0)
flag_prot_inconsistent = 1;
*start = *len = 0;
return EC_SUCCESS;
}
/* Flag for checking protection inconsistent */
flag_prot_inconsistent = 0;
return EC_SUCCESS;
}
@@ -385,6 +391,22 @@ void flash_burst_write(unsigned int dest_addr, unsigned int bytes,
flash_cs_level(1);
}
int flash_uma_lock(int enable)
{
UPDATE_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_UMA_LOCK, enable);
return EC_SUCCESS;
}
int flash_spi_sel_lock(int enable)
{
/*
* F_SPI_QUAD, F_SPI_CS1_1/2, F_SPI_TRIS become read-only
* if this bit is set
*/
UPDATE_BIT(NPCX_DEV_CTL4, NPCX_DEV_CTL4_F_SPI_SLLK, enable);
return IS_BIT_SET(NPCX_DEV_CTL4, NPCX_DEV_CTL4_F_SPI_SLLK);
}
/*****************************************************************************/
/* Physical layer APIs */
@@ -595,6 +617,10 @@ int flash_physical_erase(int offset, int size)
int flash_physical_get_protect(int bank)
{
uint32_t addr = bank * CONFIG_FLASH_BANK_SIZE;
/* All UMA transaction is locked means all banks are protected */
if (IS_BIT_SET(NPCX_UMA_ECTS, NPCX_UMA_ECTS_UMA_LOCK))
return EC_ERROR_ACCESS_DENIED;
return flash_check_prot_reg(addr, CONFIG_FLASH_BANK_SIZE);
}
@@ -611,6 +637,8 @@ uint32_t flash_physical_get_protect_flags(void)
* TODO: If status register protects a range, but SRP0 is not set,
* flags should indicate EC_FLASH_PROTECT_ERROR_INCONSISTENT.
*/
if (flag_prot_inconsistent)
flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
/* Read all-protected state from our shadow copy */
if (all_protected)
@@ -621,9 +649,18 @@ uint32_t flash_physical_get_protect_flags(void)
int flash_physical_protect_now(int all)
{
if (all)
if (all) {
all_protected = 1;
/*
* Set UMA_LOCK bit for locking all UMA transaction.
* But we still can read directly from flash mapping address
*/
flash_uma_lock(1);
} else {
all_protected = 0;
/* Unlocking all UMA transaction */
flash_uma_lock(0);
}
/* TODO: if all, disable SPI interface */
return EC_SUCCESS;
@@ -634,14 +671,26 @@ int flash_physical_protect_at_boot(enum flash_wp_range range)
{
switch (range) {
case FLASH_WP_NONE:
/* Unlock UMA transactions */
if (IS_BIT_SET(NPCX_UMA_ECTS, NPCX_UMA_ECTS_UMA_LOCK))
CLEAR_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_UMA_LOCK);
/* Clear protection bits in status register */
return flash_set_status_for_prot(0, 0);
case FLASH_WP_RO:
/* Unlock UMA transactions */
if (IS_BIT_SET(NPCX_UMA_ECTS, NPCX_UMA_ECTS_UMA_LOCK))
CLEAR_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_UMA_LOCK);
/* Protect read-only */
return flash_write_prot_reg(
WP_BANK_OFFSET*CONFIG_FLASH_BANK_SIZE,
WP_BANK_COUNT*CONFIG_FLASH_BANK_SIZE);
case FLASH_WP_ALL:
/* Protect all */
/*
* Set UMA_LOCK bit for locking all UMA transaction.
* But we still can read directly from flash mapping address
*/
return flash_uma_lock(1);
default:
return EC_ERROR_INVAL;
}
@@ -686,5 +735,43 @@ int flash_pre_init(void)
CLEAR_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS);
#endif
return EC_SUCCESS;
}
/*****************************************************************************/
/* Console commands */
static int command_flash_spi_sel_lock(int argc, char **argv)
{
int ena;
if (argc > 1) {
if (!parse_bool(argv[1], &ena))
return EC_ERROR_PARAM1;
ena = flash_spi_sel_lock(ena);
}
ccprintf("Enabled: %d\n", ena);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(flash_spi_sel_lock, command_flash_spi_sel_lock,
"[0 | 1]",
"Lock spi flash interface selection",
NULL);
static int command_flash_tristate(int argc, char **argv)
{
int ena;
if (argc > 1) {
if (!parse_bool(argv[1], &ena))
return EC_ERROR_PARAM1;
flash_tristate(ena);
}
ccprintf("Enabled: %d\n", ena);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(flash_tristate, command_flash_tristate,
"[0 | 1]",
"Tristate spi flash pins",
NULL);

View File

@@ -218,12 +218,12 @@ struct gpio_alt_map {
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
#if NPCX_I2C0_BUS2
{ NPCX_GPIO(B, 2), NPCX_ALT(2, I2C0_1_SL)}, /* SMB0SDA */
{ NPCX_GPIO(B, 3), NPCX_ALT(2, I2C0_1_SL)}, /* SMB0SCL */
#else
{ NPCX_GPIO(B, 4), NPCX_ALT(2, I2C0_0_SL)}, /* SMB0SDA */
{ NPCX_GPIO(B, 5), NPCX_ALT(2, I2C0_0_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 */
@@ -237,9 +237,14 @@ const struct gpio_alt_map gpio_alt_table[] = {
{ 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*/
/* UART Module 1/2 */
#if NPCX_UART_MODULE2
{ NPCX_GPIO(6, 4), NPCX_ALT(C, UART_SL2)}, /* CR_SIN */
{ NPCX_GPIO(6, 5), NPCX_ALT(C, UART_SL2)}, /* CR_SOUT */
#else
{ NPCX_GPIO(1, 0), NPCX_ALT(9, NO_KSO08_SL)}, /* CR_SIN/KSO09 */
{ NPCX_GPIO(1, 1), NPCX_ALT(9, NO_KSO09_SL)}, /* CR_SOUT/KSO10 */
#endif
/* SPI Module */
{ NPCX_GPIO(9, 5), NPCX_ALT(0, SPIP_SL)}, /* SPIP_MISO */
{ NPCX_GPIO(A, 5), NPCX_ALT(0, SPIP_SL)}, /* SPIP_CS1 */
@@ -255,24 +260,24 @@ const struct gpio_alt_map gpio_alt_table[] = {
{ 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
#if NPCX_TACH_SEL2
{ NPCX_GPIO(9, 3), NPCX_ALT(C, TA1_TACH1_SL2)},/* TA1_TACH1 */
{ NPCX_GPIO(D, 3), NPCX_ALT(C, TB1_TACH2_SL2)},/* TB1_TACH2 */
#else
{ NPCX_GPIO(4, 0), NPCX_ALT(3, TA1_TACH1_SL1)},/* TA1_TACH1 */
{ NPCX_GPIO(A, 4), NPCX_ALT(3, TB1_TACH2_SL1)},/* 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
#if NPCX_JTAG_MODULE2
{ 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 */
#else
{ 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 */
#endif
/* 01 for PWRGD_OUT*/
};
@@ -560,6 +565,13 @@ void gpio_pre_init(void)
SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_GPIO_NO_SPIP);
SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI);
#ifdef CONFIG_SHI
/* Switching to eSPI mode for SHI interface */
NPCX_DEVCNT |= 0x08;
/* Alternate Intel bus interface LPC/eSPI to GPIOs first */
SET_BIT(NPCX_DEVALT(ALT_GROUP_1), NPCX_DEVALT1_NO_LPC_ESPI);
#endif
/* Clear all pending bits of GPIOS*/
for (i = 0; i < 2; i++)
for (j = 0; j < 8; j++)

72
chip/npcx/header.c Normal file
View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2015 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.
*/
/*
* Booter header for Chrome EC.
*
* This header is used by Nuvoton EC Booter.
*/
#include <stdint.h>
#include "registers.h"
#include "config_chip.h"
/* Signature used by fw header */
#define SIG_FW_EC 0x2A3B4D5E
/* Definition used by error detection configuration */
#define CHECK_CRC 0x00
#define CHECK_CHECKSUM 0x01
#define ERROR_DETECTION_EN 0x02
#define ERROR_DETECTION_DIS 0x00
/* Code RAM addresses use by header */
#define FW_START_ADDR CONFIG_CDRAM_BASE /* Put FW at the begin of CODE RAM */
/* TODO: It will be filled automatically by ECST */
/* The entry point of reset handler (filled by ECST tool)*/
#define FW_ENTRY_ADDR 0x100A8169
/* Error detection addresses use by header (A offset relative to flash image) */
#define ERRCHK_START_ADDR 0x0
#define ERRCHK_END_ADDR 0x0
/* Firmware Size -> Booter loads RO region after hard reset (16 bytes aligned)*/
#define FW_SIZE CONFIG_RO_SIZE
/* FW Header used by NPCX5M5G Booter */
struct __packed fw_header_t {
uint32_t anchor; /* A constant used to verify FW header */
uint16_t ext_anchor; /* Enable/disable firmware header CRC check */
uint8_t spi_max_freq; /* Spi maximum allowable clock frequency */
uint8_t spi_read_mode; /* Spi read mode used for firmware loading */
uint8_t cfg_err_detect; /* FW load error detection configuration */
uint32_t fw_load_addr; /* Firmware load start address */
uint32_t fw_entry; /* Firmware entry point */
uint32_t err_detect_start_addr; /* FW error detect start address */
uint32_t err_detect_end_addr; /* FW error detect end address */
uint32_t fw_length; /* Firmware length in bytes */
uint8_t flash_size; /* Indicate SPI flash size */
uint8_t reserved[26]; /* Reserved bytes */
uint32_t sig_header; /* The CRC signature of the firmware header */
uint32_t sig_fw_image; /* The CRC or Checksum of the firmware image */
} __aligned(1);
__attribute__ ((section(".header")))
const struct fw_header_t fw_header = {
/* 00 */ SIG_FW_EC,
/* 04 */ 0x54E1, /* Header CRC check Enable/Disable -> AB1Eh/54E1h */
/* 06 */ 0x04, /* 20/25/33/40/50 MHz -> 00/01/02/03/04h */
/* 07 */ 0x03, /* Normal/Fast/Rev/D_IO/Q_IO Mode -> 00/01/02/03/04h */
/* 08 */ 0x00, /* Disable CRC check functionality */
/* 09 */ FW_START_ADDR,
/* 0D */ FW_ENTRY_ADDR,/* Filling by ECST tool with -usearmrst option */
/* 11 */ ERRCHK_START_ADDR,
/* 15 */ ERRCHK_END_ADDR,
/* 19 */ FW_SIZE,/* Filling by ECST tool */
/* 1D */ 0x0F, /* Flash Size 1/2/4/8/16 Mbytes -> 01/03/07/0F/1Fh */
/* 1E-3F Other fields are filled by ECST tool or reserved */
};

View File

@@ -15,15 +15,15 @@
#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 */
/* Use ITIM32 as main hardware timer */
#define TICK_ITIM32_MAX_CNT 0xFFFFFFFF
/* Depth of event timer */
#define TICK_EVT_DEPTH 16 /* Depth of event timer Unit: bits */
#define TICK_EVT_INTERVAL (1 << TICK_EVT_DEPTH) /* Unit: us */
#define TICK_EVT_INTERVAL_MASK (TICK_EVT_INTERVAL - 1) /* Mask of interval */
#define TICK_EVT_MAX_CNT (TICK_EVT_INTERVAL - 1) /* Maximum event counter */
/* 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 */
@@ -36,20 +36,20 @@ static volatile uint32_t cur_cnt_us_dbg;
/*****************************************************************************/
/* Internal functions */
void init_hw_timer(int itim_no, enum ITIM16_SOURCE_CLOCK_T source)
void init_hw_timer(int itim_no, enum ITIM_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);
UPDATE_BIT(NPCX_ITCTS(itim_no), NPCX_ITCTS_CKSEL,
source != ITIM_SOURCE_CLOCK_APB2);
/* Clear timeout status */
SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITIM16_TO_STS);
SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITCTS_TO_STS);
/* ITIM timeout interrupt enable */
SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITIM16_TO_IE);
SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITCTS_TO_IE);
/* ITIM timeout wake-up enable */
SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITIM16_TO_WUE);
SET_BIT(NPCX_ITCTS(itim_no), NPCX_ITCTS_TO_WUE);
}
/*****************************************************************************/
@@ -70,18 +70,18 @@ void __hw_clock_event_set(uint32_t deadline)
#endif
/* Event module disable */
CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_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;
if (evt_cnt > TICK_EVT_MAX_CNT)
evt_cnt = TICK_EVT_MAX_CNT;
NPCX_ITCNT16(ITIM_EVENT_NO) = evt_cnt;
/* Event module enable */
SET_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
SET_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_ITEN);
/* Enable interrupt of ITIM */
task_enable_irq(ITIM16_INT(ITIM_EVENT_NO));
@@ -102,7 +102,7 @@ uint32_t __hw_clock_get_sleep_time(void)
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))
if (IS_BIT_SET(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_TO_STS))
sleep_time = (uint32_t) (evt_cnt+1)*evt_tick;
/* Event hasn't been triggered */
else
@@ -116,7 +116,7 @@ uint32_t __hw_clock_get_sleep_time(void)
void __hw_clock_event_clear(void)
{
/* ITIM event module disable */
CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_ITEN);
/* Disable interrupt of Event */
task_disable_irq(ITIM16_INT(ITIM_EVENT_NO));
@@ -129,21 +129,15 @@ void __hw_clock_event_clear(void)
/* 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);
SET_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_TO_STS);
/* ITIM event module disable */
CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_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;
@@ -160,49 +154,43 @@ DECLARE_IRQ(ITIM16_INT(ITIM_EVENT_NO) , __hw_clock_event_irq, 1);
/* 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;
uint32_t cnt = NPCX_ITCNT32;
#if DEBUG_TMR
cur_cnt_us_dbg = cur_cnt_us + us;
cur_cnt_us_dbg = TICK_ITIM32_MAX_CNT - cnt;
#endif
return cur_cnt_us + us;
return TICK_ITIM32_MAX_CNT - cnt;
}
/* Override the current value of the hardware counter */
void __hw_clock_source_set(uint32_t ts)
{
#if DEBUG_TMR
cur_cnt_us_dbg = TICK_ITIM32_MAX_CNT - ts;
#endif
/* ITIM32 module disable */
CLEAR_BIT(NPCX_ITCTS(ITIM32), NPCX_ITCTS_ITEN);
/* Set current time */
cur_cnt_us = ts;
NPCX_ITCNT32 = TICK_ITIM32_MAX_CNT - ts;
/* ITIM32 module enable */
SET_BIT(NPCX_ITCTS(ITIM32), NPCX_ITCTS_ITEN);
}
/* 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)) {
if (IS_BIT_SET(NPCX_ITCTS(ITIM32), NPCX_ITCTS_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);
SET_BIT(NPCX_ITCTS(ITIM32), NPCX_ITCTS_TO_STS);
/* 32-bits timer count overflow */
process_timers(1);
} else { /* Handle soft trigger */
process_timers(0);
}
}
DECLARE_IRQ(NPCX_IRQ_ITIM16_1, __hw_clock_source_irq, 1);
DECLARE_IRQ(NPCX_IRQ_ITIM32, __hw_clock_source_irq, 1);
static void update_prescaler(void)
{
@@ -211,7 +199,7 @@ static void update_prescaler(void)
* 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;
NPCX_ITPRE(ITIM32) = (clock_get_apb2_freq() / SECOND) - 1;
/* Set event tick unit = 1/32768 sec */
NPCX_ITPRE(ITIM_EVENT_NO) = 0;
@@ -230,14 +218,14 @@ int __hw_clock_source_init(uint32_t start_t)
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);
init_hw_timer(ITIM32, ITIM_SOURCE_CLOCK_APB2);
init_hw_timer(ITIM_EVENT_NO, ITIM_SOURCE_CLOCK_32K);
/* Set initial prescaler */
update_prescaler();
/* ITIM count down : TICK_INTERVAL expired*/
NPCX_ITCNT16(ITIM_TIME_NO) = TICK_ITIM_MAX_CNT;
/* ITIM count down : TICK_ITIM32_MAX_CNT us expired */
NPCX_ITCNT32 = TICK_ITIM32_MAX_CNT;
/*
* Override the count with the start value now that counting has
@@ -246,10 +234,10 @@ int __hw_clock_source_init(uint32_t start_t)
__hw_clock_source_set(start_t);
/* ITIM module enable */
SET_BIT(NPCX_ITCTS(ITIM_TIME_NO), NPCX_ITIM16_ITEN);
SET_BIT(NPCX_ITCTS(ITIM32), NPCX_ITCTS_ITEN);
/* Enable interrupt of ITIM */
task_enable_irq(ITIM16_INT(ITIM_TIME_NO));
task_enable_irq(NPCX_IRQ_ITIM32);
return ITIM16_INT(ITIM_TIME_NO);
return NPCX_IRQ_ITIM32;
}

View File

@@ -8,19 +8,18 @@
#ifndef __CROS_EC_HWTIMER_CHIP_H
#define __CROS_EC_HWTIMER_CHIP_H
/* Channel definition for ITIM16 */
#define ITIM_TIME_NO ITIM16_1
#define ITIM_EVENT_NO ITIM16_2
/* Channel definition for ITIM */
#define ITIM_EVENT_NO ITIM16_1
#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,
enum ITIM_SOURCE_CLOCK_T {
ITIM_SOURCE_CLOCK_APB2 = 0,
ITIM_SOURCE_CLOCK_32K = 1,
};
/* Initialize ITIM16 timer */
void init_hw_timer(int itim_no, enum ITIM16_SOURCE_CLOCK_T source);
void init_hw_timer(int itim_no, enum ITIM_SOURCE_CLOCK_T source);
/* Returns time delay cause of deep idle */
uint32_t __hw_clock_get_sleep_time(void);

View File

@@ -557,4 +557,4 @@ static void i2c_init(void)
task_enable_irq(i2c_irqs[port]);
}
}
DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT);
DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_INIT_I2C);

View File

@@ -11,6 +11,8 @@
void jtag_pre_init(void)
{
/* Setting for fixing JTAG issue */
NPCX_DBGCTRL = 0x04;
/* Enable automatic freeze mode */
CLEAR_BIT(NPCX_DBGFRZEN3, NPCX_DBGFRZEN3_GLBL_FRZ_DIS);
}

View File

@@ -1,141 +0,0 @@
/* 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"
#include "system_chip.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_RO_MEM_OFF,
CONFIG_CDRAM_BASE, CONFIG_RO_SIZE - LFW_SIZE);
/* copy image from RW base */
else
flash_burst_copy_fw_to_mram(CONFIG_RW_MEM_OFF,
CONFIG_CDRAM_BASE, CONFIG_RW_SIZE - LFW_SIZE);
/* Disable FIU pins to tri-state */
CLEAR_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS);
/* Distinguish reboot or sysjump */
if (org_sp < CONFIG_RAM_BASE) {
/* 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);
/* Copy ram log of booter into bbram */
NPCX_BBRAM(BBRM_DATA_INDEX_RAMLOG) = *((uint8_t *)ADDR_BOOT_RAMLOG);
/* Run code in RAM */
bin2ram();
/* Should never reach this */
for (;;)
;
}

View File

@@ -1,122 +0,0 @@
/* 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
}

View File

@@ -30,6 +30,15 @@
#define LPC_SYSJUMP_TAG 0x4c50 /* "LP" */
/* Timeout to wait PLTRST is deasserted */
#define LPC_PLTRST_TIMEOUT_US 800000
/* Super-IO index and register definitions */
#define SIO_OFFSET 0x4E
#define INDEX_SID 0x20
#define INDEX_CHPREV 0x24
#define INDEX_SRID 0x27
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;
@@ -46,7 +55,6 @@ static uint8_t * const cmd_params = (uint8_t *)shm_mem_host_cmd +
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)
{
@@ -358,12 +366,6 @@ void lpc_clear_acpi_status_mask(uint8_t mask)
/* TODO (crbug.com/p/38224): Implement */
}
int lpc_get_pltrst_asserted(void)
{
/* Read PLTRST status*/
return (NPCX_MSWCTL1 & 0x04) ? 0 : 1;
}
/**
* Handle write to ACPI I/O port
*
@@ -544,6 +546,158 @@ static void lpc_post_sysjump(void)
memcpy(event_mask, prev_mask, sizeof(event_mask));
}
int lpc_get_pltrst_asserted(void)
{
/* Read PLTRST status */
return (NPCX_MSWCTL1 & 0x04) ? 1 : 0;
}
/* Super-IO read/write function */
void lpc_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 lpc_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;
}
/* For LPC host register initial via SIB module */
void lpc_host_register_init(void){
timestamp_t deadline;
deadline.val = 0;
deadline = get_time();
deadline.val += LPC_PLTRST_TIMEOUT_US;
/* Make sure PLTRST is de-asserted. Or any setting for LPC is useless */
while (lpc_get_pltrst_asserted())
if (timestamp_expired(deadline, NULL)) {
CPRINTS("PLTRST is asserted. LPC settings are ignored");
return;
}
/* Setting PMC2 */
/* LDN register = 0x12(PMC2) */
lpc_sib_write_reg(SIO_OFFSET, 0x07, 0x12);
/* CMD port is 0x200 */
lpc_sib_write_reg(SIO_OFFSET, 0x60, 0x02);
lpc_sib_write_reg(SIO_OFFSET, 0x61, 0x00);
/* Data port is 0x204 */
lpc_sib_write_reg(SIO_OFFSET, 0x62, 0x02);
lpc_sib_write_reg(SIO_OFFSET, 0x63, 0x04);
/* enable PMC2 */
lpc_sib_write_reg(SIO_OFFSET, 0x30, 0x01);
/* Setting SHM */
/* LDN register = 0x0F(SHM) */
lpc_sib_write_reg(SIO_OFFSET, 0x07, 0x0F);
/* WIN1&2 mapping to IO */
lpc_sib_write_reg(SIO_OFFSET, 0xF1,
lpc_sib_read_reg(SIO_OFFSET, 0xF1) | 0x30);
/* Host Command on the IO:0x0800 */
lpc_sib_write_reg(SIO_OFFSET, 0xF7, 0x00);
lpc_sib_write_reg(SIO_OFFSET, 0xF6, 0x00);
lpc_sib_write_reg(SIO_OFFSET, 0xF5, 0x08);
lpc_sib_write_reg(SIO_OFFSET, 0xF4, 0x00);
/* WIN1 as Host Command on the IO:0x0800 */
lpc_sib_write_reg(SIO_OFFSET, 0xFB, 0x00);
lpc_sib_write_reg(SIO_OFFSET, 0xFA, 0x00);
/* WIN2 as MEMMAP on the IO:0x900 */
lpc_sib_write_reg(SIO_OFFSET, 0xF9, 0x09);
lpc_sib_write_reg(SIO_OFFSET, 0xF8, 0x00);
/* enable SHM */
lpc_sib_write_reg(SIO_OFFSET, 0x30, 0x01);
}
static void lpc_init(void)
{
/* Enable clock for LPC peripheral */
@@ -643,8 +797,17 @@ static void lpc_init(void)
update_host_event_status();
/*
* TODO: For testing LPC with Chromebox, please make sure LPC_CLK is
* generated before executing this function. EC needs LPC_CLK to access
* LPC register through SIB module. For Chromebook platform, this
* functionality should be done by BIOS or executed in hook function of
* HOOK_CHIPSET_STARTUP
*/
#ifdef BOARD_NPCX_EVB
/* initial IO port address via SIB-write modules */
system_lpc_host_register_init();
lpc_host_register_init();
#endif
}
/* Enable LPC ACPI-EC interrupts */

View File

@@ -43,7 +43,7 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position \
-work-area-size $_WORKAREASIZE
# JTAG speed
adapter_khz 1000
adapter_khz 100
adapter_nsrst_delay 100
if {$using_jtag} {

View File

@@ -10,15 +10,13 @@ source [find mem_helper.tcl]
proc flash_npcx {image_path image_offset image_size spifw_image} {
set UPLOAD_FLAG 0x200C4000;
# Clear whole 128KB Code RAM
mwb 0x10088000 0xFF 0x20000
# Clear whole 96KB Code RAM
mwb 0x100A8000 0xFF 0x18000
# Upload binary image to Code RAM
fast_load_image $image_path 0x10088000
fast_load
load_image $image_path 0x100A8000
# Upload program spi image FW to lower 16KB Data RAM
fast_load_image $spifw_image 0x200C0000
fast_load
load_image $spifw_image 0x200C0000
# Set sp to upper 16KB Data RAM
reg sp 0x200C8000
@@ -48,71 +46,67 @@ proc flash_npcx {image_path image_offset image_size spifw_image} {
halt
}
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} {
proc flash_npcx_ro {image_dir image_offset} {
set MPU_RNR 0xE000ED98;
set MPU_RASR 0xE000EDA0;
# 128 KB for RO& RW regions
set fw_size 0x20000
# 4K little FW
set lfw_size 0x1000
# 8M spi-flash
set flash_size 0x800000
# 96 KB for RO& RW regions
set fw_size 0x18000
# 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)]
set ro_image_path $image_dir/ec.RO.flat
set spifw_image $image_dir/chip/npcx/spiflashfw/ec_npcxflash.bin
# Halt CPU first
halt
adapter_khz 1000
# diable MPU for Data RAM first
# diable MPU for Data RAM
mww $MPU_RNR 0x1
mww $MPU_RASR 0x0
echo "*** Start to program RO region ***"
# Write to lower 128kB from offset
# Write to lower 96kB from offset
flash_npcx $ro_image_path $image_offset $fw_size $spifw_image
echo "*** Finish program RO region ***"
}
proc flash_npcx_all {image_dir image_offset} {
set MPU_RNR 0xE000ED98;
set MPU_RASR 0xE000EDA0;
# 96 KB for RO& RW regions
set fw_size 0x18000
# 8M spi-flash
set flash_size 0x800000
# images path
set ro_image_path $image_dir/ec.RO.flat
set rw_image_path $image_dir/ec.RW.bin
set spifw_image $image_dir/chip/npcx/spiflashfw/ec_npcxflash.bin
# images offset
set rw_image_offset [expr ($image_offset + 0x20000)]
# Halt CPU first
halt
adapter_khz 1000
# diable MPU for Data RAM
mww $MPU_RNR 0x1
mww $MPU_RASR 0x0
echo "*** Start to program RO region ***"
# Write to lower 96kB from offset
flash_npcx $ro_image_path $image_offset $fw_size $spifw_image
echo "*** Finish program RO region ***\r\n"
echo "*** Start to program RW region ***"
# Write to upper 128kB from offset
# Write to upper 96kB from offset
flash_npcx $rw_image_path $rw_image_offset $fw_size $spifw_image
echo "*** Finish program RW region ***\r\n"
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 ***\r\n"
# Reset CPU
reset
}
proc halt_npcx_cpu { } {

View File

@@ -65,7 +65,7 @@ void pwm_freq_changed(void)
* Using PWM Frequency and Resolution we calculate
* prescaler for input clock
*/
#ifdef CONFIG_PWM_INPUT_LFCLK
#ifdef NPCX_PWM_INPUT_LFCLK
prescaler_divider = (uint32_t)(32768 /
(pwm_channels[pwm_init_ch].freq)
/(pwm_channels[pwm_init_ch].cycle_pulses));
@@ -226,7 +226,7 @@ void pwm_config(enum pwm_channel ch)
| (NPCX_PWM_CLOCK_APB2_LFCLK<<NPCX_PWMCTLEX_FCK_SEL);
if (ch == PWM_CH_FAN) {
#ifdef CONFIG_PWM_INPUT_LFCLK
#ifdef NPCX_PWM_INPUT_LFCLK
/* Select default LFCLK clock input to PWM module */
SET_BIT(NPCX_PWMCTL(pwm_channels[ch].channel),
NPCX_PWMCTL_CKSEL);

View File

@@ -27,12 +27,7 @@
*/
/* 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 CHIP_VERSION 3 /* A3 version */
#define I2C_7BITS_ADDR 0
#define I2C_LEVEL_SUPPORT 1
/* Switcher of features */
@@ -49,6 +44,7 @@
#define DEBUG_SPI 0
#define DEBUG_FLH 0
#define DEBUG_PECI 0
#define DEBUG_SHI 1
#define DEBUG_CLK 1
/* Modules Map */
@@ -61,6 +57,7 @@
#define NPCX_GLUE_REGS_BASE 0x400A5000
#define NPCX_BBRAM_BASE_ADDR 0x400AF000
#define NPCX_HFCG_BASE_ADDR 0x400B5000
#define NPCX_SHI_BASE_ADDR 0x4000F000
#define NPCX_MTC_BASE_ADDR 0x400B7000
#define NPCX_MSWC_BASE_ADDR 0x400C1000
#define NPCX_SCFG_BASE_ADDR 0x400C3000
@@ -75,6 +72,7 @@
#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_ITIM32_BASE_ADDR 0x400BC000
#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))
@@ -168,7 +166,7 @@
#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_IRQ_SHI NPCX_IRQ_18
#define NPCX_IRQ19_NOUSED NPCX_IRQ_19
#define NPCX_IRQ20_NOUSED NPCX_IRQ_20
#define NPCX_IRQ_PS2 NPCX_IRQ_21
@@ -196,7 +194,7 @@
#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_ITIM32 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
@@ -393,6 +391,7 @@ enum {
#define GPIO_D GPIO_PORT_D
#define GPIO_E GPIO_PORT_E
#define GPIO_F GPIO_PORT_F
#define DUMMY_GPIO_BANK GPIO_PORT_0
/******************************************************************************/
/* MSWC Registers */
@@ -411,6 +410,7 @@ enum {
#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_LFCGCALCNT REG8(NPCX_SCFG_BASE_ADDR + 0x021)
#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)
@@ -458,6 +458,7 @@ enum {
#define NPCX_RSTCTL_VCC1_RST_SCRATCH 3
#define NPCX_RSTCTL_LRESET_PLTRST_MODE 5
#define NPCX_RSTCTL_HIPRST_MODE 6
#define NPCX_DEV_CTL4_F_SPI_SLLK 2
#define NPCX_DEV_CTL4_SPI_SP_SEL 4
#define NPCX_DEVPU0_I2C0_0_PUE 0
#define NPCX_DEVPU0_I2C0_1_PUE 1
@@ -550,17 +551,21 @@ enum {
#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_DEVALTA_UART_SL1 7
#define NPCX_DEVALTB_RXD_SL 0
#define NPCX_DEVALTB_TXD_SL 1
#define NPCX_DEVALTC_UART_SL2 0
#define NPCX_DEVALTC_SHI_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
#define NPCX_LFCGCALCNT_LPREG_CTL_EN 1
/******************************************************************************/
/* Development and Debug Support (DBG) Registers */
#define NPCX_DBGCTRL REG8(NPCX_SCFG_BASE_ADDR + 0x074)
@@ -645,6 +650,17 @@ enum {
#define NPCX_SMBADDR7_SAEN 7
#define NPCX_SMBADDR8_SAEN 7
/*
* SMB enumeration
* I2C Port.
*/
enum NPCX_I2C_PORT_T {
NPCX_I2C_PORT0 = 0, /* I2C port 0, bus 0/1*/
NPCX_I2C_PORT1 = 1, /* I2C port 1 */
NPCX_I2C_PORT2 = 2, /* I2C port 2 */
NPCX_I2C_PORT3 = 3, /* I2C port 3 */
};
/******************************************************************************/
/* Power Management Controller (PMC) Registers */
#define NPCX_PMCSR REG8(NPCX_PMC_BASE_ADDR + 0x000)
@@ -694,6 +710,7 @@ enum {
#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_SHI_PD 1
#define NPCX_PWDWN_CTL5_MRFSH_DIS 2
#define NPCX_PWDWN_CTL5_C2HACC_PD 3
#define NPCX_PWDWN_CTL5_SHM_REG_PD 4
@@ -724,6 +741,15 @@ enum {
CGC_OFFSET_ESPI = 5,
};
enum NPCX_PMC_PWDWN_CTL_T {
NPCX_PMC_PWDWN_1 = 0,
NPCX_PMC_PWDWN_2 = 1,
NPCX_PMC_PWDWN_3 = 2,
NPCX_PMC_PWDWN_4 = 3,
NPCX_PMC_PWDWN_5 = 4,
NPCX_PMC_PWDWN_6 = 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)
@@ -779,6 +805,7 @@ enum {
#define NPCX_UMA_ECTS_SW_CS0 0
#define NPCX_UMA_ECTS_SW_CS1 1
#define NPCX_UMA_ECTS_SEC_CS 2
#define NPCX_UMA_ECTS_UMA_LOCK 3
/******************************************************************************/
/* Shared Memory (SHM) Registers */
@@ -1072,7 +1099,7 @@ enum PM_CHANNEL_T {
#define NPCX_TWUEN_TCWEN 2
#define NPCX_TWUEN_TDWEN 3
/******************************************************************************/
/*ITIM16 Define*/
/* ITIM16/32 Define */
#define ITIM16_INT(module) CONCAT2(NPCX_IRQ_, module)
/* ITIM16 registers */
@@ -1081,12 +1108,15 @@ enum PM_CHANNEL_T {
#define NPCX_ITCNT16(n) REG16(NPCX_ITIM16_BASE_ADDR(n) + 0x002)
#define NPCX_ITCTS(n) REG8(NPCX_ITIM16_BASE_ADDR(n) + 0x004)
/* ITIM32 registers */
#define NPCX_ITCNT32 REG32(NPCX_ITIM32_BASE_ADDR + 0x008)
/* 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
#define NPCX_ITCTS_TO_STS 0
#define NPCX_ITCTS_TO_IE 2
#define NPCX_ITCTS_TO_WUE 3
#define NPCX_ITCTS_CKSEL 4
#define NPCX_ITCTS_ITEN 7
/* ITIM16 enumeration*/
enum ITIM16_MODULE_T {
@@ -1096,9 +1126,61 @@ enum ITIM16_MODULE_T {
ITIM16_4,
ITIM16_5,
ITIM16_6,
ITIM16_MODULE_COUNT,
ITIM32,
ITIM_MODULE_COUNT,
};
/******************************************************************************/
/* Serial Host Interface (SHI) Registers */
#define NPCX_SHICFG1 REG8(NPCX_SHI_BASE_ADDR + 0x001)
#define NPCX_SHICFG2 REG8(NPCX_SHI_BASE_ADDR + 0x002)
#define NPCX_I2CADDR1 REG8(NPCX_SHI_BASE_ADDR + 0x003)
#define NPCX_I2CADDR2 REG8(NPCX_SHI_BASE_ADDR + 0x004)
#define NPCX_EVENABLE REG8(NPCX_SHI_BASE_ADDR + 0x005)
#define NPCX_EVSTAT REG8(NPCX_SHI_BASE_ADDR + 0x006)
#define NPCX_SHI_CAPABILITY REG8(NPCX_SHI_BASE_ADDR + 0x007)
#define NPCX_STATUS REG8(NPCX_SHI_BASE_ADDR + 0x008)
#define NPCX_IBUFSTAT REG8(NPCX_SHI_BASE_ADDR + 0x00A)
#define NPCX_OBUFSTAT REG8(NPCX_SHI_BASE_ADDR + 0x00B)
#define NPCX_ADVCFG REG8(NPCX_SHI_BASE_ADDR + 0x00E)
#define NPCX_OBUF(n) REG8(NPCX_SHI_BASE_ADDR + 0x020 + (n))
#define NPCX_IBUF(n) REG8(NPCX_SHI_BASE_ADDR + 0x060 + (n))
/* SHI register fields */
#define NPCX_SHICFG1_EN 0
#define NPCX_SHICFG1_MODE 1
#define NPCX_SHICFG1_WEN 2
#define NPCX_SHICFG1_AUTIBF 3
#define NPCX_SHICFG1_AUTOBE 4
#define NPCX_SHICFG1_DAS 5
#define NPCX_SHICFG1_CPOL 6
#define NPCX_SHICFG1_IWRAP 7
#define NPCX_SHICFG2_SIMUL 0
#define NPCX_SHICFG2_BUSY 1
#define NPCX_SHICFG2_ONESHOT 2
#define NPCX_SHICFG2_SLWU 3
#define NPCX_SHICFG2_REEN 4
#define NPCX_SHICFG2_RESTART 5
#define NPCX_SHICFG2_REEVEN 6
#define NPCX_EVENABLE_OBEEN 0
#define NPCX_EVENABLE_OBHEEN 1
#define NPCX_EVENABLE_IBFEN 2
#define NPCX_EVENABLE_IBHFEN 3
#define NPCX_EVENABLE_EOREN 4
#define NPCX_EVENABLE_EOWEN 5
#define NPCX_EVENABLE_STSREN 6
#define NPCX_EVENABLE_IBOREN 7
#define NPCX_EVSTAT_OBE 0
#define NPCX_EVSTAT_OBHE 1
#define NPCX_EVSTAT_IBF 2
#define NPCX_EVSTAT_IBHF 3
#define NPCX_EVSTAT_EOR 4
#define NPCX_EVSTAT_EOW 5
#define NPCX_EVSTAT_STSR 6
#define NPCX_EVSTAT_IBOR 7
#define NPCX_STATUS_OBES 6
#define NPCX_STATUS_IBFS 7
/******************************************************************************/
/* Monotonic Counter (MTC) Registers */
#define NPCX_TTC REG32(NPCX_MTC_BASE_ADDR + 0x000)
@@ -1114,6 +1196,12 @@ enum ITIM16_MODULE_T {
/* Low Power RAM definitions */
#define NPCX_LPRAM_CTRL REG32(0x40001044)
/******************************************************************************/
/* Nuvoton internal used only registers */
#define NPCX_INTERNAL_CTRL1 REG8(0x400DB000)
#define NPCX_INTERNAL_CTRL2 REG8(0x400DD000)
#define NPCX_INTERNAL_CTRL3 REG8(0x400DF000)
/******************************************************************************/
/* Optional M4 Registers */
#define CPU_DHCSR REG32(0xE000EDF0)
@@ -1196,4 +1284,76 @@ enum ITIM16_MODULE_T {
#define MASK_CMD_WR_ADR (MASK(EXEC_DONE) | FLASH_SEL | MASK(RD_WR) \
| MASK(A_SIZE))
/******************************************************************************/
/* Inline functions */
/* This routine checks pending bit of GPIO wake-up functionality */
static inline int uart_is_wakeup_from_gpio(void)
{
#if NPCX_UART_MODULE2
return IS_BIT_SET(NPCX_WKPND(1, 6), 4);
#else
return IS_BIT_SET(NPCX_WKPND(1, 1), 0);
#endif
}
/* This routine clear pending bit of GPIO wake-up functionality */
static inline void uart_clear_wakeup_event(void)
{
#if NPCX_UART_MODULE2
SET_BIT(NPCX_WKPND(1, 6), 4);
#else
SET_BIT(NPCX_WKPND(1, 1), 0);
#endif
}
/* This routine checks wake-up functionality from GPIO is enabled or not */
static inline int uart_is_enable_wakeup(void)
{
#if NPCX_UART_MODULE2
return IS_BIT_SET(NPCX_WKEN(1, 6), 4);
#else
return IS_BIT_SET(NPCX_WKEN(1, 1), 0);
#endif
}
/* This routine enables wake-up functionality from GPIO on UART rx pin */
static inline void uart_enable_wakeup(int enable)
{
#if NPCX_UART_MODULE2
UPDATE_BIT(NPCX_WKEN(1, 6), 4, enable);
#else
UPDATE_BIT(NPCX_WKEN(1, 1), 0, enable);
#endif
}
/* This routine checks functionality is UART rx or not */
static inline int npcx_is_uart(void)
{
#if NPCX_UART_MODULE2
return IS_BIT_SET(NPCX_DEVALT(0x0C), NPCX_DEVALTC_UART_SL2);
#else
return IS_BIT_SET(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL1);
#endif
}
/* This routine switches the functionality from UART rx to GPIO */
static inline void npcx_uart2gpio(void)
{
#if NPCX_UART_MODULE2
CLEAR_BIT(NPCX_DEVALT(0x0C), NPCX_DEVALTC_UART_SL2);
#else
CLEAR_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL1);
#endif
}
/* This routine switches the functionality from GPIO to UART rx */
static inline void npcx_gpio2uart(void)
{
#if NPCX_UART_MODULE2
CLEAR_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL1);
SET_BIT(NPCX_DEVALT(0x0C), NPCX_DEVALTC_UART_SL2);
#else
SET_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL1);
#endif
}
#endif /* __CROS_EC_REGISTERS_H */

66
chip/npcx/rom_chip.h Normal file
View File

@@ -0,0 +1,66 @@
/* Copyright (c) 2015 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_ROM_CHIP_H_
#define __CROS_EC_ROM_CHIP_H_
/******************************************************************************/
/*
* Enumerations of ROM api functions
*/
enum API_SIGN_OPTIONS_T {
SIGN_NO_CHECK = 0,
SIGN_CRC_CHECK = 1,
};
enum API_RETURN_STATUS_T {
/* Successful download */
API_RET_STATUS_OK = 0,
/* Address is outside of flash or not 4 bytes aligned. */
API_RET_STATUS_INVALID_SRC_ADDR = 1,
/* Address is outside of RAM or not 4 bytes aligned. */
API_RET_STATUS_INVALID_DST_ADDR = 2,
/* Size is 0 or not 4 bytes aligned. */
API_RET_STATUS_INVALID_SIZE = 3,
/* Flash Address + Size is out of flash. */
API_RET_STATUS_INVALID_SIZE_OUT_OF_FLASH = 4,
/* RAM Address + Size is out of RAM. */
API_RET_STATUS_INVALID_SIZE_OUT_OF_RAM = 5,
/* Wrong sign option. */
API_RET_STATUS_INVALID_SIGN = 6,
/* Error during Code copy. */
API_RET_STATUS_COPY_FAILED = 7,
/* Execution Address is outside of RAM */
API_RET_STATUS_INVALID_EXE_ADDR = 8,
/* Bad CRC value */
API_RET_STATUS_INVALID_SIGNATURE = 9,
};
/******************************************************************************/
/*
* Macro functions of ROM api functions
*/
#define ADDR_DOWNLOAD_FROM_FLASH (*(volatile uint32_t *) 0x40)
#define download_from_flash(src_offset, dest_addr, size, sign, exe_addr, \
status) \
(((download_from_flash_ptr) ADDR_DOWNLOAD_FROM_FLASH) \
(src_offset, dest_addr, size, sign, exe_addr, status))
/******************************************************************************/
/*
* Declarations of ROM api functions
*/
typedef void (*download_from_flash_ptr) (
uint32_t src_offset, /* The offset of the data to be downloaded */
uint32_t dest_addr, /* The address of the downloaded data in the RAM*/
uint32_t size, /* Number of bytes to download */
enum API_SIGN_OPTIONS_T sign, /* Need CRC check or not */
uint32_t exe_addr, /* jump to this address after download if not zero */
enum API_RETURN_STATUS_T *status /* Status fo download */
);
#endif /* __CROS_EC_ROM_CHIP_H_ */

859
chip/npcx/shi.c Normal file
View File

@@ -0,0 +1,859 @@
/*
* Copyright (c) 2015 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.
*/
/*
* SHI driver for Chrome EC.
*
* This uses Input/Output buffer to handle SPI transmission and reception.
*/
#include "chipset.h"
#include "clock.h"
#include "console.h"
#include "gpio.h"
#include "task.h"
#include "hooks.h"
#include "host_command.h"
#include "registers.h"
#include "spi.h"
#include "system.h"
#include "timer.h"
#include "util.h"
#if !(DEBUG_SHI)
#define CPUTS(...)
#define CPRINTS(...)
#define CPRINTF(...)
#else
#define CPUTS(outstr) cputs(CC_SPI, outstr)
#define CPRINTS(format, args...) cprints(CC_SPI, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_SPI, format, ## args)
#endif
/* SHI Bus definition */
#define SHI_OBUF_FULL_SIZE 64 /* Full output buffer size */
#define SHI_IBUF_FULL_SIZE 64 /* Full input buffer size */
#define SHI_OBUF_HALF_SIZE (SHI_OBUF_FULL_SIZE/2) /* Half output buffer size */
#define SHI_IBUF_HALF_SIZE (SHI_IBUF_FULL_SIZE/2) /* Half input buffer size */
/* Start address of SHI output buffer */
#define SHI_OBUF_START_ADDR (volatile uint8_t *)(NPCX_SHI_BASE_ADDR + 0x020)
/* Middle address of SHI output buffer */
#define SHI_OBUF_HALF_ADDR (SHI_OBUF_START_ADDR + SHI_OBUF_HALF_SIZE)
/* Top address of SHI output buffer */
#define SHI_OBUF_FULL_ADDR (SHI_OBUF_START_ADDR + SHI_IBUF_FULL_SIZE)
/*
* Valid offset of SHI output buffer to write.
* When SIMUL bit is set, IBUFPTR can be used instead of OBUFPTR
*/
#define SHI_OBUF_VALID_OFFSET ((NPCX_IBUFSTAT + SHI_OUT_PREAMBLE_LENGTH) % \
SHI_OBUF_FULL_SIZE)
/* Start address of SHI input buffer */
#define SHI_IBUF_START_ADDR (volatile uint8_t *)(NPCX_SHI_BASE_ADDR + 0x060)
/* Current address of SHI input buffer */
#define SHI_IBUF_CUR_ADDR (SHI_IBUF_START_ADDR + NPCX_IBUFSTAT)
/*
* Timeout to wait for SHI request packet
*
* This affects the slowest SPI clock we can support. A delay of 8192 us
* permits a 512-byte request at 500 KHz, assuming the master starts sending
* bytes as soon as it asserts chip select. That's as slow as we would
* practically want to run the SHI interface, since running it slower
* significantly impacts firmware update times.
*/
#define SHI_CMD_RX_TIMEOUT_US 8192
/* Timeout for glitch case. Make sure it will exceed 8 SPI clocks */
#define SHI_GLITCH_TIMEOUT_US 10
/*
* Max data size for a version 3 request/response packet. This is big enough
* to handle a request/response header, flash write offset/size, and 512 bytes
* of flash data.
*/
#define SHI_MAX_REQUEST_SIZE 0x220
#define SHI_MAX_RESPONSE_SIZE 0x220
/*
* The AP blindly clocks back bytes over the SPI interface looking for a
* framing byte. So this preamble must always precede the actual response
* packet.
*/
#define SHI_OUT_PREAMBLE_LENGTH 2
/*
* Space allocation of the past-end status byte (EC_SPI_PAST_END) in the out_msg
* buffer.
*/
#define EC_SPI_PAST_END_LENGTH 1
/*
* Space allocation of the frame status byte (EC_SPI_FRAME_START) in the out_msg
* buffer.
*/
#define EC_SPI_FRAME_START_LENGTH 1
/*
* Offset of output parameters needs to account for pad and framing bytes and
* one last past-end byte at the end so any additional bytes clocked out by
* the AP will have a known and identifiable value.
*/
#define SHI_PROTO2_OFFSET (EC_PROTO2_RESPONSE_HEADER_BYTES + 1)
#define SHI_PROTO2_OVERHEAD (SHI_PROTO2_OFFSET + \
EC_PROTO2_RESPONSE_TRAILER_BYTES + 1)
#define SHI_PROTO3_OVERHEAD (EC_SPI_PAST_END_LENGTH + EC_SPI_FRAME_START_LENGTH)
/*
* Our input and output msg buffers. These must be large enough for our largest
* message, including protocol overhead, and must be 32-bit aligned.
*/
static uint8_t out_msg[SHI_MAX_RESPONSE_SIZE];
static uint8_t in_msg[SHI_MAX_REQUEST_SIZE];
/* Parameters used by host protocols */
static struct host_cmd_handler_args args;
static struct host_packet shi_packet;
/* Function pointer for handler of host request */
void (*request_handler)(void);
enum shi_state {
/* SHI not enabled (initial state, and when chipset is off) */
SHI_STATE_DISABLED = 0,
/* Ready to receive next request */
SHI_STATE_READY_TO_RECV,
/* Complete transaction but need to initialize */
SHI_STATE_NOT_READY,
/* Receiving request */
SHI_STATE_RECEIVING,
/* Processing request */
SHI_STATE_PROCESSING,
/* Sending response */
SHI_STATE_SENDING,
/* State machine mismatch, timeout, or protocol we can't handle. */
SHI_STATE_ERROR,
} state;
/* SHI bus parameters */
struct shi_bus_parameters {
uint8_t *rx_msg; /* Entry pointer of msg rx buffer */
uint8_t *tx_msg; /* Entry pointer of msg tx buffer */
volatile uint8_t *rx_buf; /* Entry pointer of receive buffer */
volatile uint8_t *tx_buf; /* Entry pointer of transmit buffer */
uint16_t sz_received; /* Size of received data in bytes */
uint16_t sz_sending; /* Size of sending data in bytes */
uint16_t sz_request; /* request bytes need to receive */
uint16_t sz_response; /* response bytes need to receive */
timestamp_t rx_deadline; /* deadline of receiving */
uint8_t pre_ibufstat; /* Previous IBUFSTAT value */
} shi_params;
/* Forward declaraction */
static void shi_reset_prepare(void);
static void shi_error(int need_reset);
static void shi_fill_out_status(uint8_t status);
static void shi_write_half_outbuf(void);
static void shi_write_outbuf_wait(uint16_t szbytes);
static int shi_read_inbuf_wait(uint16_t szbytes);
/*****************************************************************************/
/* V2 protocol layer functions */
/**
* The format of a reply is as per the command interface, with a number of
* preamble bytes before it.
*
* The format of a reply is a sequence of bytes:
*
* <hdr> <status> <len> <msg bytes> <sum> [<postamble byte>...]
*
* The hdr byte is just a tag to indicate that the real message follows. It
* signals the end of any preamble required by the interface.
*
* The length is the entire packet size, including the header, length bytes,
* message payload, checksum, and postamble byte.
*
* We keep an eye on the SHI_CS_L line - if this goes high then the transaction
* is over so there is no point in trying to send the reply.
*/
static void shi_reply_response(enum ec_status status, uint8_t *msg_ptr,
int msg_len)
{
int need_copy = msg_ptr != out_msg + SHI_PROTO2_OFFSET;
int sum, i;
ASSERT(msg_len + SHI_PROTO2_OVERHEAD <= sizeof(out_msg));
/* Add our header bytes - the first one might not actually be sent */
out_msg[0] = EC_SPI_FRAME_START;
out_msg[1] = status;
out_msg[2] = msg_len & 0xff;
/*
* Calculate the checksum; includes the status and message length bytes
* but not the pad and framing bytes since those are stripped by the AP
* driver.
*/
sum = status + msg_len;
for (i = 0; i < msg_len; i++) {
int ch = msg_ptr[i];
sum += ch;
if (need_copy)
out_msg[i + SHI_PROTO2_OFFSET] = ch;
}
/* Add the checksum and get ready to send */
out_msg[SHI_PROTO2_OFFSET + msg_len] = sum & 0xff;
out_msg[SHI_PROTO2_OFFSET + msg_len + 1] = EC_SPI_PAST_END;
/* Computing sending bytes of response */
shi_params.sz_response = msg_len + SHI_PROTO2_OVERHEAD;
/*
* Before the state is set to SENDING, any CS de-assertion would
* give up sending.
*/
if (state == SHI_STATE_PROCESSING) {
/*
* Disable SHI interrupt until we have prepared
* the first package to output
*/
task_disable_irq(NPCX_IRQ_SHI);
/* Transmit the reply */
state = SHI_STATE_SENDING;
CPRINTF("SND-");
/* Start to fill output buffer with msg buffer */
shi_write_outbuf_wait(shi_params.sz_response);
/* Enable SHI interrupt */
task_enable_irq(NPCX_IRQ_SHI);
}
/*
* If we're not processing, then the AP has already terminated the
* transaction, and won't be listening for a response.
*/
else {
/* Reset SHI and prepare to next transaction again */
shi_reset_prepare();
CPRINTF("END\n");
return;
}
}
/**
* Called for V2 protocol to indicate that a command has completed
*
* Some commands can continue for a while. This function is called by
* host_command when it completes.
*
*/
static void shi_send_response(struct host_cmd_handler_args *args)
{
enum ec_status result = args->result;
if (args->response_size > args->response_max)
result = EC_RES_INVALID_RESPONSE;
/* Transmit the reply */
args->response_size += (EC_SPI_PAST_END_LENGTH +
EC_SPI_FRAME_START_LENGTH);
shi_reply_response(result, args->response, args->response_size);
}
void shi_handle_host_command(void)
{
uint16_t sz_inbuf_int = shi_params.sz_request / SHI_IBUF_HALF_SIZE;
uint16_t cnt_inbuf_int = shi_params.sz_received / SHI_IBUF_HALF_SIZE;
if (sz_inbuf_int - cnt_inbuf_int)
/* Need to receive data from buffer */
return;
else {
uint16_t remain_bytes = shi_params.sz_request
- shi_params.sz_received;
/* Move to processing state immediately */
state = SHI_STATE_PROCESSING;
CPRINTF("PRC-");
/* Read remaining bytes from input buffer directly */
if (!shi_read_inbuf_wait(remain_bytes))
return shi_error(1);
}
/* Fill output buffer to indicate we`re processing request */
shi_fill_out_status(EC_SPI_PROCESSING);
/* Set up parameters for host request */
args.params = in_msg + 3;
args.send_response = shi_send_response;
/* Allow room for the header bytes */
args.response = out_msg + SHI_PROTO2_OFFSET;
args.response_max = sizeof(out_msg) - SHI_PROTO2_OVERHEAD;
args.response_size = 0;
args.result = EC_RES_SUCCESS;
/* Go to common-layer to handle request */
host_command_received(&args);
}
/*****************************************************************************/
/* V3 protocol layer functions */
/**
* Called to send a response back to the host.
*
* Some commands can continue for a while. This function is called by
* host_command when it completes.
*
*/
static void shi_send_response_packet(struct host_packet *pkt)
{
/* Append our past-end byte, which we reserved space for. */
((uint8_t *) pkt->response)[pkt->response_size + 0] = EC_SPI_PAST_END;
/* Computing sending bytes of response */
shi_params.sz_response = pkt->response_size + SHI_PROTO3_OVERHEAD;
/*
* Before the state is set to SENDING, any CS de-assertion would
* give up sending.
*/
if (state == SHI_STATE_PROCESSING) {
/*
* Disable SHI interrupt until we have prepared
* the first package to output
*/
task_disable_irq(NPCX_IRQ_SHI);
/* Transmit the reply */
state = SHI_STATE_SENDING;
CPRINTF("SND-");
/* Start to fill output buffer with msg buffer */
shi_write_outbuf_wait(shi_params.sz_response);
/* Enable SHI interrupt */
task_enable_irq(NPCX_IRQ_SHI);
}
/*
* If we're not processing, then the AP has already terminated the
* transaction, and won't be listening for a response.
*/
else {
/* Reset SHI and prepare to next transaction again */
shi_reset_prepare();
CPRINTF("END\n");
return;
}
}
void shi_handle_host_package(void)
{
uint16_t sz_inbuf_int = shi_params.sz_request / SHI_IBUF_HALF_SIZE;
uint16_t cnt_inbuf_int = shi_params.sz_received / SHI_IBUF_HALF_SIZE;
if (sz_inbuf_int - cnt_inbuf_int)
/* Need to receive data from buffer */
return;
else {
uint16_t remain_bytes = shi_params.sz_request
- shi_params.sz_received;
/* Move to processing state immediately */
state = SHI_STATE_PROCESSING;
CPRINTF("PRC-");
/* Read remaining bytes from input buffer directly */
if (!shi_read_inbuf_wait(remain_bytes))
return shi_error(1);
}
/* Fill output buffer to indicate we`re processing request */
shi_fill_out_status(EC_SPI_PROCESSING);
/* Set up parameters for host request */
shi_packet.send_response = shi_send_response_packet;
shi_packet.request = in_msg;
shi_packet.request_temp = NULL;
shi_packet.request_max = sizeof(in_msg);
shi_packet.request_size = shi_params.sz_request;
/* Put FRAME_START in first byte */
out_msg[0] = EC_SPI_FRAME_START;
shi_packet.response = out_msg + 1;
/* Reserve space for frame start and trailing past-end byte */
shi_packet.response_max = sizeof(out_msg) - SHI_PROTO3_OVERHEAD;
shi_packet.response_size = 0;
shi_packet.driver_result = EC_RES_SUCCESS;
/* Go to common-layer to handle request */
host_packet_receive(&shi_packet);
}
/* Parse header for version of spi-protocol */
static void shi_parse_header(void)
{
/* Wait for version, command, length bytes */
if (!shi_read_inbuf_wait(3))
return shi_error(1);
if (in_msg[0] == EC_HOST_REQUEST_VERSION) {
/* Protocol version 3 */
struct ec_host_request *r = (struct ec_host_request *) in_msg;
int pkt_size;
/*
* If request is over 32 bytes,
* we need to modified the algorithm again.
*/
ASSERT(sizeof(*r) < SHI_IBUF_HALF_SIZE);
/* Wait for the rest of the command header */
if (!shi_read_inbuf_wait(sizeof(*r) - 3))
return shi_error(1);
/* Check how big the packet should be */
pkt_size = host_request_expected_size(r);
if (pkt_size == 0 || pkt_size > sizeof(in_msg))
return shi_error(0);
/* Computing total bytes need to receive */
shi_params.sz_request = pkt_size;
/* Set handler for host_package */
request_handler = shi_handle_host_package;
} else if (in_msg[0] >= EC_CMD_VERSION0) {
/*
* Protocol version 2
* TODO(crosbug.com/p/20257): Remove once kernel supports
* version 3.
*/
args.version = in_msg[0] - EC_CMD_VERSION0;
args.command = in_msg[1];
args.params_size = in_msg[2];
/* Computing remaining received bytes */
shi_params.sz_request = args.params_size + 3;
/* Set handler for host_command */
request_handler = shi_handle_host_command;
} else {
/* Invalid version number */
return shi_error(0);
}
/* run receiving handler */
request_handler();
}
/*****************************************************************************/
/* IC specific low-level driver */
/* This routine fills out all SHI output buffer with status byte */
static void shi_fill_out_status(uint8_t status)
{
uint16_t i;
uint16_t offset = SHI_OBUF_VALID_OFFSET;
/* Fill out all output buffer with status byte */
for (i = offset; i < SHI_OBUF_FULL_SIZE; i++)
NPCX_OBUF(i) = status;
for (i = 0; i < offset; i++)
NPCX_OBUF(i) = status;
}
/*
* This routine write SHI next half output buffer from msg buffer
*/
static void shi_write_half_outbuf(void)
{
uint16_t i;
uint16_t size = MIN(SHI_OBUF_HALF_SIZE,
shi_params.sz_response - shi_params.sz_sending);
/* Fill half output buffer */
for (i = 0; i < size; i++, shi_params.sz_sending++)
*(shi_params.tx_buf++) = *(shi_params.tx_msg++);
}
/*
* This routine write SHI output buffer from msg buffer until
* we have sent a certain number of bytes or output buffer is full
*/
static void shi_write_outbuf_wait(uint16_t szbytes)
{
uint16_t i;
static uint16_t offset, size;
offset = SHI_OBUF_VALID_OFFSET;
shi_params.tx_buf = SHI_OBUF_START_ADDR + offset;
/* Fill half output buffer */
size = MIN(SHI_OBUF_HALF_SIZE - (offset % SHI_OBUF_HALF_SIZE),
szbytes - shi_params.sz_sending);
for (i = 0; i < size; i++, shi_params.sz_sending++)
*(shi_params.tx_buf++) = *(shi_params.tx_msg++);
/* Write data from bottom address again */
if (shi_params.tx_buf == SHI_OBUF_FULL_ADDR)
shi_params.tx_buf = SHI_OBUF_START_ADDR;
/* Fill next half output buffer */
size = MIN(SHI_OBUF_HALF_SIZE, szbytes - shi_params.sz_sending);
for (i = 0; i < size; i++, shi_params.sz_sending++)
*(shi_params.tx_buf++) = *(shi_params.tx_msg++);
}
/* This routine copies SHI half input buffer data to msg buffer */
static void shi_read_half_inbuf(void)
{
/*
* Copy to read buffer until reaching middle/top address of
* input buffer or completing receiving data
*/
do {
/* Restore data to msg buffer */
*(shi_params.rx_msg++) = *(shi_params.rx_buf++);
shi_params.sz_received++;
} while (shi_params.sz_received % SHI_IBUF_HALF_SIZE
&& shi_params.sz_received != shi_params.sz_request);
}
/*
* This routine make sure input buffer status register is valid or it will
* return flase after timeout
*/
static int shi_check_inbuf_valid(void)
{
timestamp_t deadline = get_time();
deadline.val += SHI_GLITCH_TIMEOUT_US;
/*
* If input buffer pointer is no changed after timeout, it will
* return false
*/
while (NPCX_IBUFSTAT == shi_params.pre_ibufstat)
if (timestamp_expired(deadline, NULL))
return 0;
/* valid package */
return 1;
}
/*
* This routine read SHI input buffer to msg buffer until
* we have received a certain number of bytes
*/
static int shi_read_inbuf_wait(uint16_t szbytes)
{
uint16_t i;
/* Copy data to msg buffer from input buffer */
for (i = 0; i < szbytes; i++, shi_params.sz_received++) {
/*
* If input buffer pointer equals pointer which wants to read,
* it means data is not ready.
*/
while (shi_params.rx_buf == SHI_IBUF_CUR_ADDR)
if (timestamp_expired(shi_params.rx_deadline, NULL))
return 0;
/* Restore data to msg buffer */
*(shi_params.rx_msg++) = *(shi_params.rx_buf++);
}
return 1;
}
/* This routine handles bus error condition */
static void shi_error(int need_reset)
{
uint16_t i;
/* State machine mismatch, timeout, or protocol we can't handle. */
shi_fill_out_status(EC_SPI_RX_BAD_DATA);
state = SHI_STATE_ERROR;
CPRINTS("ERR-[");
CPRINTF("in_msg=[");
for (i = 0; i < shi_params.sz_received; i++)
CPRINTF("%02x ", in_msg[i]);
CPRINTF("]\n");
/*
* If glitch occurred or losing clocks, EVSTAT_EOR/W
* will not generate. We need to reset SHI bus here.
*/
if (need_reset)
shi_reset_prepare();
}
/* This routine handles all interrupts of this module */
void shi_int_handler(void)
{
uint8_t stat_reg;
/* Read status register and clear interrupt status early*/
stat_reg = NPCX_EVSTAT;
NPCX_EVSTAT = stat_reg;
/*
* End of data for read/write transaction. ie SHI_CS is deasserted.
* Host completed or aborted transaction
*/
if (IS_BIT_SET(stat_reg, NPCX_EVSTAT_EOR)) {
/* Already reset in shi_error or not */
if (state != SHI_STATE_READY_TO_RECV)
/*
* Mark not ready to prevent the other
* transaction immediately
*/
NPCX_OBUF(0) = EC_SPI_NOT_READY;
CPRINTF("CSH-");
/*
* If the buffer is still used by the host command.
* Change tx buffer to NOT_READY
*/
if (state == SHI_STATE_PROCESSING) {
/*
* Mark state to NOT_READY for waiting host executes
* response function
*/
state = SHI_STATE_NOT_READY;
CPRINTF("WAIT-");
return;
}
/* reset SHI and prepare to next transaction again */
shi_reset_prepare();
CPRINTF("END\n");
return;
}
/*
* Indicate input/output buffer pointer reaches the half buffer size.
* Transaction is processing.
*/
if (IS_BIT_SET(stat_reg, NPCX_EVSTAT_IBHF)) {
if (state == SHI_STATE_RECEIVING) {
/* Read data from input to msg buffer */
shi_read_half_inbuf();
return request_handler();
} else if (state == SHI_STATE_SENDING) {
/* Write data from bottom address again */
shi_params.tx_buf = SHI_OBUF_START_ADDR;
/* Write data from msg buffer to output buffer */
return shi_write_half_outbuf();
} else if (state == SHI_STATE_PROCESSING)
/* Wait for host handles request */
return;
else
/* Unexpected status */
return shi_error(1);
}
/*
* Indicate input/output buffer pointer reaches the full buffer size.
* Transaction is processing.
*/
if (IS_BIT_SET(stat_reg, NPCX_EVSTAT_IBF)) {
if (state == SHI_STATE_RECEIVING) {
/* read data from input to msg buffer */
shi_read_half_inbuf();
/* Read to bottom address again */
shi_params.rx_buf = SHI_IBUF_START_ADDR;
return request_handler();
} else if (state == SHI_STATE_SENDING)
/* Write data from msg buffer to output buffer */
return shi_write_half_outbuf();
else if (state == SHI_STATE_PROCESSING)
/* Wait for host handles request */
return;
else
/* Unexpected status */
return shi_error(1);
}
}
/*
* The interrupt priority for SHI interrupt should be higher than
* GPIO. Then we could receive CS-deasserted event even in CS-asserted ISR.
*/
DECLARE_IRQ(NPCX_IRQ_SHI, shi_int_handler, 0);
/* Handle an CS assert event on the SHI_CS_L pin */
void shi_cs_event(enum gpio_signal signal)
{
/* If not enabled, ignore glitches on SHI_CS_L */
if (state == SHI_STATE_DISABLED)
return;
/*
* TODO (ML): Glitches on SHI_CS_L will cause SHI doesn`t generate
* 'End of data for read/write transaction interrupt' and IBUFSTAT will
* keep previous value without clocks. (Workaround) Need to reset it
* manually in CS assert ISR.
*/
if (NPCX_IBUFSTAT == shi_params.pre_ibufstat) {
if (!shi_check_inbuf_valid()) {
CPRINTS("ERR-GTH");
shi_reset_prepare();
CPRINTS("END\n");
return;
}
}
/* Chip select is low = asserted */
if (state != SHI_STATE_READY_TO_RECV) {
/*
* AP started a transaction but we weren't ready for it.
* Tell AP we weren't ready, and ignore the received data.
* The driver should change status later when complete handling
* response from host
*/
NPCX_OBUF(0) = EC_SPI_NOT_READY;
CPRINTS("CSL-NRDY");
/*
* If status still is error, reset SHI Bus and
* abort this transaction.
*/
if (state == SHI_STATE_ERROR) {
CPRINTS("ERR-");
shi_reset_prepare();
CPRINTS("END\n");
return;
}
return;
}
/* We're now inside a transaction */
state = SHI_STATE_RECEIVING;
CPRINTF("CSL-RV-");
/* Setup deadline time for receiving */
shi_params.rx_deadline = get_time();
shi_params.rx_deadline.val += SHI_CMD_RX_TIMEOUT_US;
/* Read first three bytes to parse which protocol is receiving */
shi_parse_header();
}
/*****************************************************************************/
/* Hook functions for chipset and initialization */
/* Reset SHI bus and prepare next transaction */
static void shi_reset_prepare(void)
{
uint16_t i;
state = SHI_STATE_NOT_READY;
/* Initialize parameters of next transaction */
shi_params.rx_msg = in_msg;
shi_params.tx_msg = out_msg;
shi_params.rx_buf = SHI_IBUF_START_ADDR;
shi_params.tx_buf = SHI_OBUF_HALF_ADDR;
shi_params.sz_received = 0;
shi_params.sz_sending = 0;
shi_params.sz_request = 0;
shi_params.sz_response = 0;
/* Record last IBUFSTAT for glitch case */
shi_params.pre_ibufstat = NPCX_IBUFSTAT;
/*
* Fill output buffer to indicate we`re
* ready to receive next transaction
*/
for (i = 1; i < SHI_OBUF_FULL_SIZE; i++)
NPCX_OBUF(i) = EC_SPI_RECEIVING;
NPCX_OBUF(0) = EC_SPI_OLD_READY;
/* Enable SHI & WEN functionality */
NPCX_SHICFG1 = 0x85;
/* Ready to receive */
state = SHI_STATE_READY_TO_RECV;
CPRINTF("RDY-");
}
DECLARE_HOOK(HOOK_CHIPSET_RESUME, shi_reset_prepare, HOOK_PRIO_DEFAULT);
/* Disable SHI bus */
static void shi_disable(void)
{
state = SHI_STATE_DISABLED;
/* Disable pullup and interrupts on SHI_CS_L */
gpio_set_flags(GPIO_SHI_CS_L, GPIO_INPUT);
/* Set SPI pins to inputs so we don't leak power when AP is off */
gpio_config_module(MODULE_SPI, 0);
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, shi_disable, HOOK_PRIO_DEFAULT);
static void shi_init(void)
{
/* Power on SHI module first */
CLEAR_BIT(NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_5), NPCX_PWDWN_CTL5_SHI_PD);
/*
* Mux SHI related pins
* SHI_SDI SHI_SDO SHI_CS# SHI_SCLK are selected to device pins
*/
SET_BIT(NPCX_DEVALT(ALT_GROUP_C), NPCX_DEVALTC_SHI_SL);
/*
* SHICFG1 (SHI Configuration 1) setting
* [7] - IWRAP = 1: Wrap input buffer to the first address
* [6] - CPOL = 0: Sampling on rising edge and output on falling edge
* [5] - DAS = 0: return STATUS reg data after Status command
* [4] - AUTOBE = 0: Automatically update the OBES bit in STATUS reg
* [3] - AUTIBF = 0: Automatically update the IBFS bit in STATUS reg
* [2] - WEN = 0: Enable host write to input buffer
* [1] - Reserved 0
* [0] - ENABLE = 0: Disable SHI at the beginning
*/
NPCX_SHICFG1 = 0x80;
/*
* SHICFG2 (SHI Configuration 2) setting
* [7] - Reserved 0
* [6] - REEVEN = 0: Restart events are not used
* [5] - Reserved 0
* [4] - REEN = 0: Restart transactions are not used
* [3] - SLWU = 0: Seem-less wake-up is enabled by default
* [2] - ONESHOT= 0: WEN is cleared at the end of a write transaction
* [1] - BUSY = 0: SHI bus is busy 0: idle.
* [0] - SIMUL = 1: Turn on simultaneous Read/Write
*/
NPCX_SHICFG2 = 0x01;
/*
* EVENABLE (Event Enable) setting
* [7] - IBOREN = 0: Input buffer overrun interrupt enable
* [6] - STSREN = 0: status read interrupt disable
* [5] - EOWEN = 0: End-of-Data for Write Transaction Interrupt Enable
* [4] - EOREN = 1: End-of-Data for Read Transaction Interrupt Enable
* [3] - IBHFEN = 1: Input Buffer Half Full Interrupt Enable
* [2] - IBFEN = 1: Input Buffer Full Interrupt Enable
* [1] - OBHEEN = 0: Output Buffer Half Empty Interrupt Enable
* [0] - OBEEN = 0: Output Buffer Empty Interrupt Enable
*/
NPCX_EVENABLE = 0x1C;
/* Clear SHI events status register */
NPCX_EVSTAT = 0XFF;
/* Enable SHI_CS_L interrupt */
gpio_enable_interrupt(GPIO_SHI_CS_L);
/* If chipset is already on, prepare for transactions */
#if !(DEBUG_SHI)
if (chipset_in_state(CHIPSET_STATE_ON))
#endif
shi_reset_prepare();
}
DECLARE_HOOK(HOOK_INIT, shi_init, HOOK_PRIO_DEFAULT);
/**
* Get protocol information
*/
static int shi_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 = SHI_MAX_REQUEST_SIZE;
r->max_response_packet_size = SHI_MAX_RESPONSE_SIZE;
r->flags = EC_PROTOCOL_INFO_IN_PROGRESS_SUPPORTED;
args->response_size = sizeof(*r);
return EC_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO, shi_get_protocol_info,
EC_VER_MASK(0));

21
chip/npcx/shi_chip.h Normal file
View File

@@ -0,0 +1,21 @@
/* Copyright (c) 2015 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 SHI module for Chrome EC */
#ifndef SHI_CHIP_H_
#define SHI_CHIP_H_
#ifdef CONFIG_SHI
/**
* Called when the NSS level changes, signalling the start of a SHI
* transaction.
*
* @param signal GPIO signal that changed
*/
void shi_cs_event(enum gpio_signal signal);
#endif
#endif /* SHI_CHIP_H_ */

View File

@@ -18,17 +18,12 @@
#include "util.h"
#include "hwtimer_chip.h"
#include "system_chip.h"
#include "rom_chip.h"
/* Flags for BBRM_DATA_INDEX_WAKE */
#define HIBERNATE_WAKE_MTC (1 << 0) /* MTC alarm */
#define HIBERNATE_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)
@@ -38,109 +33,16 @@
/* ROM address of chip revision */
#define CHIP_REV_ADDR 0x00007FFC
/* Console output macros */
#define CPUTS(outstr) cputs(CC_SYSTEM, outstr)
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
/* 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 */
@@ -277,17 +179,11 @@ void system_check_reset_cause(void)
}
/* Watchdog Reset */
#ifndef CHIP_NPCX5M5G
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);
}
#else
/* Workaround method to check watchdog reset */
if (NPCX_BBRAM(BBRM_DATA_INDEX_RAMLOG) & 0x04)
flags |= RESET_FLAG_WATCHDOG;
#endif
if ((hib_wake_flags & HIBERNATE_WAKE_PIN))
flags |= RESET_FLAG_WAKE_PIN;
@@ -356,12 +252,12 @@ __enter_hibernate_in_lpram(void)
{
/* Disable Code RAM first */
SET_BIT(NPCX_PWDWN_CTL(5), NPCX_PWDWN_CTL5_MRFSH_DIS);
SET_BIT(NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_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;
/* Set deep idle mode*/
NPCX_PMCSR = 0x6;
/* Enter deep idle, wake-up by GPIOxx or RTC */
asm("wfi");
@@ -424,11 +320,11 @@ void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
interrupt_disable();
/* ITIM event module disable */
CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN);
CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_ITEN);
/* ITIM time module disable */
CLEAR_BIT(NPCX_ITCTS(ITIM_TIME_NO), NPCX_ITIM16_ITEN);
CLEAR_BIT(NPCX_ITCTS(ITIM32), NPCX_ITCTS_ITEN);
/* ITIM watchdog warn module disable */
CLEAR_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITIM16_ITEN);
CLEAR_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITCTS_ITEN);
/*
* Set RTC interrupt in time to wake up before
@@ -545,12 +441,21 @@ void system_pre_init(void)
*/
/* Power-down the modules we don't need */
NPCX_PWDWN_CTL(0) = 0xF9; /* Skip SDP_PD FIU_PD */
NPCX_PWDWN_CTL(1) = 0xFF;
NPCX_PWDWN_CTL(2) = 0x8F;
NPCX_PWDWN_CTL(3) = 0xF4; /* Skip ITIM2/1_PD */
NPCX_PWDWN_CTL(4) = 0xF8;
NPCX_PWDWN_CTL(5) = 0x85; /* Skip ITIM5_PD */
NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_1) = 0xF9; /* Skip SDP_PD FIU_PD */
NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_2) = 0xFF;
NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_3) = 0x0F; /* Skip GDMA */
NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_4) = 0xF4; /* Skip ITIM2/1_PD */
NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_5) = 0xF8;
NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_6) = 0x85; /* Skip ITIM5_PD */
/* Power down the modules used internally */
NPCX_INTERNAL_CTRL1 = 0x03;
NPCX_INTERNAL_CTRL2 = 0x03;
NPCX_INTERNAL_CTRL3 = 0x03;
/* Enable low-power regulator */
CLEAR_BIT(NPCX_LFCGCALCNT, NPCX_LFCGCALCNT_LPREG_CTL_EN);
SET_BIT(NPCX_LFCGCALCNT, NPCX_LFCGCALCNT_LPREG_CTL_EN);
/*
* Configure LPRAM in the MPU as a regular memory
@@ -637,12 +542,9 @@ const char *system_get_chip_name(void)
const char *system_get_chip_revision(void)
{
static char rev[4];
#ifndef CHIP_NPCX5M5G
uint8_t rev_num = system_sib_read_reg(SIO_OFFSET, INDEX_CHPREV);
#else
/* Read ROM data for chip revision directly */
uint8_t rev_num = *((uint8_t *)CHIP_REV_ADDR);
#endif
*(rev) = 'A';
*(rev + 1) = '.';
*(rev + 2) = system_to_hex((rev_num & 0xF0) >> 4);
@@ -789,58 +691,53 @@ 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(void)
void system_jump_to_booter(void)
{
/* Little FW located on top of flash - 4K */
uint32_t jump_addr = (CONFIG_FLASH_BASE + CONFIG_SPI_FLASH_SIZE
- CONFIG_LFW_OFFSET + 1);
enum API_RETURN_STATUS_T status;
static uint32_t flash_offset;
static uint32_t flash_used;
static uint32_t addr_entry;
/* RO region FW */
if (IS_BIT_SET(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION)) {
flash_offset = CONFIG_RO_MEM_OFF;
flash_used = CONFIG_RO_SIZE;
} else { /* RW region FW */
flash_offset = CONFIG_RW_MEM_OFF;
flash_used = CONFIG_RW_SIZE;
}
/* Make sure the reset vector is inside the destination image */
addr_entry = *(uintptr_t *)(flash_offset + CONFIG_FLASH_BASE + 4);
download_from_flash(
flash_offset, /* The offset of the data in spi flash */
CONFIG_CDRAM_BASE, /* The address of the downloaded data */
flash_used, /* Number of bytes to download */
SIGN_NO_CHECK, /* Need CRC check or not */
addr_entry, /* jump to this address after download */
&status /* Status fo download */
);
}
uint32_t system_get_lfw_address()
{
/*
* In A3 version, we don't use little FW anymore
* We provide the alternative function in ROM
*/
uint32_t jump_addr = (uint32_t)system_jump_to_booter;
return jump_addr;
}
void system_set_image_copy(enum system_image_copy_t copy)
{
/* Jump to RO region -- set flag */
if (copy == SYSTEM_IMAGE_RO)
SET_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION);
else /* Jump to RW region -- clear flag */
/* Jump to RW region -- clear flag */
if (copy == SYSTEM_IMAGE_RW)
CLEAR_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION);
else /* Jump to RO region -- set flag */
SET_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION);
}
enum system_image_copy_t system_get_shrspi_image_copy(void)

View File

@@ -18,8 +18,6 @@ enum bbram_data_index {
BBRM_DATA_INDEX_RAMLOG = 32, /* RAM log for Booter */
};
/* Init lpc register through SIB */
void system_lpc_host_register_init(void);
/* Issue a watchdog reset*/
void system_watchdog_reset(void);
/* Check reset cause and return reset flags */

View File

@@ -26,13 +26,11 @@ int uart_init_done(void)
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);
if (uart_is_enable_wakeup()) {
/* disable MIWU */
uart_enable_wakeup(0);
/* Set pin-mask for UART */
npcx_gpio2uart();
/* enable uart again from MIWU mode */
task_enable_irq(NPCX_IRQ_UART);
}
@@ -146,9 +144,16 @@ 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);
/* Enable MIWU IRQ of UART*/
#if NPCX_UART_MODULE2
task_enable_irq(NPCX_IRQ_WKINTG_1);
#else
task_enable_irq(NPCX_IRQ_WKINTB_1);
#endif
/* Calculated UART baudrate , clock source from APB2 */
opt_prescalar = opt_dev = 0;
@@ -193,8 +198,7 @@ void uart_init(void)
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);
npcx_gpio2uart();
/* Configure UARTs (identically) */
uart_config();

View File

@@ -26,7 +26,7 @@
void watchdog_init_warning_timer(void)
{
/* init watchdog timer first */
init_hw_timer(ITIM_WDG_NO, ITIM16_SOURCE_CLOCK_32K);
init_hw_timer(ITIM_WDG_NO, ITIM_SOURCE_CLOCK_32K);
/*
* prescaler to TIMER_TICK
@@ -40,7 +40,7 @@ void watchdog_init_warning_timer(void)
/* 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);
SET_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITCTS_ITEN);
/* Enable interrupt of ITIM */
task_enable_irq(ITIM16_INT(ITIM_WDG_NO));
}
@@ -49,7 +49,7 @@ void __keep 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);
SET_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITCTS_TO_STS);
/* Read watchdog counter from TWMWD */
wd_cnt = NPCX_TWMWD;

View File

@@ -14,7 +14,13 @@ MEMORY
SECTIONS
{
. = ALIGN(CONFIG_FLASH_BANK_SIZE);
#if defined(NPCX_RO_HEADER)
/* Replace *_MEM_OFF with *_STORAGE_OFF to indicate flat file contains header
* or some struture which doesn't belong to FW */
.image.RO : AT(CONFIG_FLASH_BASE + CONFIG_RO_STORAGE_OFF) {
#else
.image.RO : AT(CONFIG_FLASH_BASE + CONFIG_RO_MEM_OFF) {
#endif
*(.image.RO)
} > FLASH =0xff
. = ALIGN(CONFIG_FLASH_BANK_SIZE);

View File

@@ -20,7 +20,12 @@
* For address containing CONFIG_FLASH_BASE (symbols in *.RO.lds.S and
* variable), this computes the offset to the start of the image on flash.
*/
#ifdef NPCX_RO_HEADER
#define RELATIVE_RO(addr) ((addr) - CONFIG_CDRAM_BASE)
#else
#define RELATIVE_RO(addr) ((addr) - CONFIG_FLASH_BASE - CONFIG_RO_MEM_OFF)
#endif
struct fmap_header {
char fmap_signature[FMAP_SIGNATURE_SIZE];

View File

@@ -18,6 +18,15 @@ OUTPUT_ARCH(BFD_ARCH)
ENTRY(reset)
MEMORY
{
#if defined(SECTION_IS_RO) && defined(NPCX_RO_HEADER)
/*
* Header structure used by npcx booter in RO region.
* Please notice the location of header must be in front of FW
* which needs copy. But header itself won't be copied to code ram
* by booter.
*/
FLASH_HDR (rx) : ORIGIN = FW_OFF(RO_HDR), LENGTH = FW_SIZE(RO_HDR)
#endif
FLASH (rx) : ORIGIN = FW_OFF(SECTION), LENGTH = FW_SIZE(SECTION)
IRAM (rw) : ORIGIN = CONFIG_RAM_BASE, LENGTH = CONFIG_RAM_SIZE
#ifdef CONFIG_CODERAM_ARCH
@@ -45,6 +54,11 @@ MEMORY
}
SECTIONS
{
#if defined(SECTION_IS_RO) && defined(NPCX_RO_HEADER)
.header : {
KEEP(*(.header))
} > FLASH_HDR
#endif
.text : {
OUTDIR/core/CORE/init.o (.text.vecttable)
. = ALIGN(4);
@@ -66,7 +80,7 @@ SECTIONS
/* Entering deep idle FW for better power consumption */
KEEP(*(.lowpower_ram))
__flash_lpfw_end = .;
} > CDRAM AT > FLASH
} > CDRAM AT > FLASH
#else
#ifdef COMPILE_FOR_RAM
} > IRAM
@@ -182,7 +196,7 @@ SECTIONS
#endif
. = ALIGN(4);
#ifdef CONFIG_CODERAM_ARCH
} > CDRAM AT > FLASH
} > CDRAM AT > FLASH
#else
#ifdef COMPILE_FOR_RAM
} > IRAM
@@ -219,7 +233,6 @@ SECTIONS
.data : {
#else
#ifdef CONFIG_CODERAM_ARCH
__data_start = . ;
.data : AT(LOADADDR(.rodata) + SIZEOF(.rodata)) {
#else
.data : AT(ADDR(.rodata) + SIZEOF(.rodata)) {

View File

@@ -82,6 +82,7 @@ BOARDS_STM32_DFU=(
BOARDS_NPCX=(
npcx_evb
npcx_evb_arm
)
BOARDS_MEC1322=(
@@ -389,6 +390,7 @@ function flash_lm4() {
function flash_npcx() {
OCD_PATH="${EC_DIR}/chip/npcx/openocd"
IMG_PATH="${EC_DIR}/build/${BOARD}"
setup_openocd
dut_control jtag_buf_on_flex_en:on
@@ -396,12 +398,12 @@ function flash_npcx() {
if [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] ; then
# Program RO region only
OCD_CMDS="init; flash_npcx_ro ${FLAGS_offset}; shutdown;"
OCD_CMDS="init; flash_npcx_ro ${IMG_PATH} ${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;"
OCD_CMDS="init; flash_npcx_all ${IMG_PATH} ${FLAGS_offset}; shutdown;"
sudo openocd -s "${OCD_PATH}" -f "${OCD_CFG}" -c "${OCD_CMDS}" || \
die "Failed to program ${IMG}"
fi