diff options
author | Ian Chao <mlchao@nuvoton.com> | 2015-06-25 18:12:09 +0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-06-26 18:57:32 +0000 |
commit | 957638c78cc5aa0ba37ef281e2c6a09215c5d60e (patch) | |
tree | bc783f701e5b968449bfe3652e8cc20680620c8d | |
parent | ccb6b15d514b695b9ea472aa98d5f1730d58e244 (diff) | |
download | chrome-ec-957638c78cc5aa0ba37ef281e2c6a09215c5d60e.tar.gz |
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>
40 files changed, 2094 insertions, 681 deletions
diff --git a/Makefile.rules b/Makefile.rules index a1199bbd7d..5f52fc38c8 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -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) diff --git a/board/npcx_evb/Makefile b/board/npcx_evb/Makefile new file mode 120000 index 0000000000..94aaae2c4d --- /dev/null +++ b/board/npcx_evb/Makefile @@ -0,0 +1 @@ +../../Makefile
\ No newline at end of file diff --git a/board/npcx_evb/board.c b/board/npcx_evb/board.c index 1dacb2ec5c..9523c3b937 100644 --- a/board/npcx_evb/board.c +++ b/board/npcx_evb/board.c @@ -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, diff --git a/board/npcx_evb/board.h b/board/npcx_evb/board.h index 6395947133..f4059151fc 100644 --- a/board/npcx_evb/board.h +++ b/board/npcx_evb/board.h @@ -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 diff --git a/board/npcx_evb/gpio.inc b/board/npcx_evb/gpio.inc index 4c6114c784..c51ecc9c05 100644 --- a/board/npcx_evb/gpio.inc +++ b/board/npcx_evb/gpio.inc @@ -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 diff --git a/board/npcx_evb_arm/Makefile b/board/npcx_evb_arm/Makefile new file mode 120000 index 0000000000..94aaae2c4d --- /dev/null +++ b/board/npcx_evb_arm/Makefile @@ -0,0 +1 @@ +../../Makefile
\ No newline at end of file diff --git a/board/npcx_evb_arm/board.c b/board/npcx_evb_arm/board.c new file mode 100644 index 0000000000..56eb9b5635 --- /dev/null +++ b/board/npcx_evb_arm/board.c @@ -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 */ + }, +}; diff --git a/board/npcx_evb_arm/board.h b/board/npcx_evb_arm/board.h new file mode 100644 index 0000000000..62856cda56 --- /dev/null +++ b/board/npcx_evb_arm/board.h @@ -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 */ diff --git a/board/npcx_evb_arm/build.mk b/board/npcx_evb_arm/build.mk new file mode 100644 index 0000000000..ebebf140d8 --- /dev/null +++ b/board/npcx_evb_arm/build.mk @@ -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 diff --git a/board/npcx_evb_arm/ec.tasklist b/board/npcx_evb_arm/ec.tasklist new file mode 100644 index 0000000000..a44d142596 --- /dev/null +++ b/board/npcx_evb_arm/ec.tasklist @@ -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) diff --git a/board/npcx_evb_arm/gpio.inc b/board/npcx_evb_arm/gpio.inc new file mode 100644 index 0000000000..410ac90894 --- /dev/null +++ b/board/npcx_evb_arm/gpio.inc @@ -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 diff --git a/chip/npcx/build.mk b/chip/npcx/build.mk index 7ad02aaf30..011396eccc 100644 --- a/chip/npcx/build.mk +++ b/chip/npcx/build.mk @@ -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 diff --git a/chip/npcx/clock.c b/chip/npcx/clock.c index 6f21e8e016..c59516043b 100644 --- a/chip/npcx/clock.c +++ b/chip/npcx/clock.c @@ -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, diff --git a/chip/npcx/config_chip.h b/chip/npcx/config_chip.h index cd951e1f22..f7e1541250 100644 --- a/chip/npcx/config_chip.h +++ b/chip/npcx/config_chip.h @@ -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 */ diff --git a/chip/npcx/fan.c b/chip/npcx/fan.c index 5ba20cf315..20208dccdc 100644 --- a/chip/npcx/fan.c +++ b/chip/npcx/fan.c @@ -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. */ diff --git a/chip/npcx/flash.c b/chip/npcx/flash.c index 30091a39f0..161f65b6d1 100644 --- a/chip/npcx/flash.c +++ b/chip/npcx/flash.c @@ -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); + diff --git a/chip/npcx/gpio.c b/chip/npcx/gpio.c index 0b9b4b664f..34634943b3 100644 --- a/chip/npcx/gpio.c +++ b/chip/npcx/gpio.c @@ -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++) diff --git a/chip/npcx/header.c b/chip/npcx/header.c new file mode 100644 index 0000000000..ff0c50eb3b --- /dev/null +++ b/chip/npcx/header.c @@ -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 */ +}; diff --git a/chip/npcx/hwtimer.c b/chip/npcx/hwtimer.c index 80bb903e67..5607222b4d 100644 --- a/chip/npcx/hwtimer.c +++ b/chip/npcx/hwtimer.c @@ -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 */ - -/* 32-bits counter value */ -static volatile uint32_t cur_cnt_us; -static volatile uint32_t pre_cnt_us; +/* 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 */ + /* 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; } diff --git a/chip/npcx/hwtimer_chip.h b/chip/npcx/hwtimer_chip.h index 732ef8fac4..b529bce463 100644 --- a/chip/npcx/hwtimer_chip.h +++ b/chip/npcx/hwtimer_chip.h @@ -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); diff --git a/chip/npcx/i2c.c b/chip/npcx/i2c.c index 03b48c2864..fd21aebbf9 100644 --- a/chip/npcx/i2c.c +++ b/chip/npcx/i2c.c @@ -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); diff --git a/chip/npcx/jtag.c b/chip/npcx/jtag.c index 05dda6fa78..aeef35e9c8 100644 --- a/chip/npcx/jtag.c +++ b/chip/npcx/jtag.c @@ -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); } diff --git a/chip/npcx/lfw/ec_lfw.c b/chip/npcx/lfw/ec_lfw.c deleted file mode 100644 index c3a505ce69..0000000000 --- a/chip/npcx/lfw/ec_lfw.c +++ /dev/null @@ -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 (;;) - ; -} diff --git a/chip/npcx/lfw/ec_lfw.ld b/chip/npcx/lfw/ec_lfw.ld deleted file mode 100644 index dd93bba89e..0000000000 --- a/chip/npcx/lfw/ec_lfw.ld +++ /dev/null @@ -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 -}
\ No newline at end of file diff --git a/chip/npcx/lpc.c b/chip/npcx/lpc.c index 595edf28e9..6a2a85742f 100644 --- a/chip/npcx/lpc.c +++ b/chip/npcx/lpc.c @@ -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 */ diff --git a/chip/npcx/openocd/npcx.cfg b/chip/npcx/openocd/npcx.cfg index ccc53437bb..cd00715d72 100644 --- a/chip/npcx/openocd/npcx.cfg +++ b/chip/npcx/openocd/npcx.cfg @@ -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} { diff --git a/chip/npcx/openocd/npcx_cmds.tcl b/chip/npcx/openocd/npcx_cmds.tcl index 63ed2932bc..a32afccf03 100644 --- a/chip/npcx/openocd/npcx_cmds.tcl +++ b/chip/npcx/openocd/npcx_cmds.tcl @@ -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 +proc flash_npcx_ro {image_dir image_offset} { + set MPU_RNR 0xE000ED98; + set MPU_RASR 0xE000EDA0; + + # 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 spifw_image $outdir/chip/npcx/spiflashfw/ec_npcxflash.bin + 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 + 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 ***" - # Reset CPU - reset } -proc flash_npcx_evb {image_offset} { +proc flash_npcx_all {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 + # 96 KB for RO& RW regions + set fw_size 0x18000 # 8M spi-flash set flash_size 0x800000 # images path - set outdir ../../../build/npcx_evb - set ro_image_path $outdir/ec.RO.flat - set rw_image_path $outdir/ec.RW.bin - set lfw_image_path $outdir/chip/npcx/lfw/ec_lfw.bin - set spifw_image $outdir/chip/npcx/spiflashfw/ec_npcxflash.bin + 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 + $fw_size)] - set lfw_image_offset [expr ($flash_size - $lfw_size)] + set rw_image_offset [expr ($image_offset + 0x20000)] # Halt CPU first halt - # diable MPU for Data RAM first + 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 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 ***\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 { } { diff --git a/chip/npcx/pwm.c b/chip/npcx/pwm.c index 752ffe47fe..4a8ba4dace 100644 --- a/chip/npcx/pwm.c +++ b/chip/npcx/pwm.c @@ -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); diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h index 21a0609d64..aa741ba805 100644 --- a/chip/npcx/registers.h +++ b/chip/npcx/registers.h @@ -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,10 +1126,62 @@ 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) #define NPCX_WTC REG32(NPCX_MTC_BASE_ADDR + 0x004) @@ -1115,6 +1197,12 @@ enum ITIM16_MODULE_T { #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) #define CPU_MPU_CTRL REG32(0xE000ED94) @@ -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 */ diff --git a/chip/npcx/rom_chip.h b/chip/npcx/rom_chip.h new file mode 100644 index 0000000000..6d635f6c4d --- /dev/null +++ b/chip/npcx/rom_chip.h @@ -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_ */ diff --git a/chip/npcx/shi.c b/chip/npcx/shi.c new file mode 100644 index 0000000000..755f043abe --- /dev/null +++ b/chip/npcx/shi.c @@ -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)); diff --git a/chip/npcx/shi_chip.h b/chip/npcx/shi_chip.h new file mode 100644 index 0000000000..2edd513bfc --- /dev/null +++ b/chip/npcx/shi_chip.h @@ -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_ */ diff --git a/chip/npcx/system.c b/chip/npcx/system.c index e1ae1c134a..2a872d0b66 100644 --- a/chip/npcx/system.c +++ b/chip/npcx/system.c @@ -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) diff --git a/chip/npcx/system_chip.h b/chip/npcx/system_chip.h index 2cafb9649f..fab0ca37fc 100644 --- a/chip/npcx/system_chip.h +++ b/chip/npcx/system_chip.h @@ -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 */ diff --git a/chip/npcx/uart.c b/chip/npcx/uart.c index 893b02aa84..570ded4285 100644 --- a/chip/npcx/uart.c +++ b/chip/npcx/uart.c @@ -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(); diff --git a/chip/npcx/watchdog.c b/chip/npcx/watchdog.c index 036a768bb6..6d61ad9581 100644 --- a/chip/npcx/watchdog.c +++ b/chip/npcx/watchdog.c @@ -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; diff --git a/common/firmware_image.lds.S b/common/firmware_image.lds.S index af6aa927b5..089e032d57 100644 --- a/common/firmware_image.lds.S +++ b/common/firmware_image.lds.S @@ -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); diff --git a/common/fmap.c b/common/fmap.c index 16b45c9db6..e61df8d968 100644 --- a/common/fmap.c +++ b/common/fmap.c @@ -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]; diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S index df3898e255..d637860329 100644 --- a/core/cortex-m/ec.lds.S +++ b/core/cortex-m/ec.lds.S @@ -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)) { diff --git a/util/flash_ec b/util/flash_ec index c25c347004..0b9cc52b42 100755 --- a/util/flash_ec +++ b/util/flash_ec @@ -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 |