diff options
author | CHLin <CHLIN56@nuvoton.com> | 2017-08-08 13:09:00 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-08-17 01:56:54 -0700 |
commit | 7a41d77b15830990c198b22f027bc925f7bc6382 (patch) | |
tree | 5b2c06e983a97fe9a149e254b7b15d80ff677eac /chip | |
parent | 86d7ea33af1d6565afb169aefafff6cd08e30fe6 (diff) | |
download | chrome-ec-7a41d77b15830990c198b22f027bc925f7bc6382.tar.gz |
npcx: shi: add the support for SHI module version 2
In npcx7, we introduce an enhanced version of Serial Host Interface
(SHI) module. This CL adds the support for it.
It includes:
1. Increase the size of IBF/OBF from 64 bytes to 128 bytes.
2. Add IBULVL/IBFLVL2 in SHICFG4/SHICFG5 which can configure at which
level the IBF pointer reaches to trigger an interrupt to core.
The current setting of these two register fields are:
IBFLVL - 64 (half full)
IBFLVL2 - 8 (the size of host command protocol V3 header)
3. Dedicated CS high/low interrupts.
In old SHI module, the way to generate CS high interrupt event is via
EOR bit. However, it has a defect that EOR won't be set to 1 when CS
is de-asserted if there is no SHI CLK generated. It makes the
handling of glitch condition more complicated.
In the new SHI module, we introduce the CS high/low interrupts
(by enabling the CSnFEN/CSnREEN) to make it easier to handle the
glitch.
The new SHI module is enabled during SHI initialization when the chip
family is npcx7.
BRANCH=none
BUG=none
TEST=No build errors for "make buildall". Test host command
communication is ok between npcx7 EVB and a host emulator.
Make sure the glitch condition can be detected and handled.
Also test the driver on gru, make sure it won't break the operation of
old SHI module.
Change-Id: If297fd32a0ec2c9e340c60c8f1942868fa978fbc
Signed-off-by: CHLin <CHLIN56@nuvoton.com>
Reviewed-on: https://chromium-review.googlesource.com/607812
Commit-Ready: CH Lin <chlin56@nuvoton.com>
Tested-by: CH Lin <chlin56@nuvoton.com>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/npcx/config_chip-npcx7.h | 3 | ||||
-rw-r--r-- | chip/npcx/registers.h | 30 | ||||
-rw-r--r-- | chip/npcx/shi.c | 218 | ||||
-rw-r--r-- | chip/npcx/shi_chip.h | 3 |
4 files changed, 210 insertions, 44 deletions
diff --git a/chip/npcx/config_chip-npcx7.h b/chip/npcx/config_chip-npcx7.h index 5e0c538d8e..2506f0f558 100644 --- a/chip/npcx/config_chip-npcx7.h +++ b/chip/npcx/config_chip-npcx7.h @@ -38,6 +38,9 @@ #define I2C_PORT_COUNT 11 #endif +/* Use SHI module version 2 supported by npcx7 family */ +#define NPCX_SHI_V2 + /*****************************************************************************/ /* Memory mapping */ #define NPCX_BTRAM_SIZE 0x800 /* 2KB data ram used by booter. */ diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h index c201576d68..258ad3b787 100644 --- a/chip/npcx/registers.h +++ b/chip/npcx/registers.h @@ -683,6 +683,11 @@ enum { #define NPCX_DEVALTC_UART_SL2 0 #define NPCX_DEVALTC_SHI_SL 1 +#if defined(CHIP_FAMILY_NPCX7) +/* SHI module version 2 enable bit */ +#define NPCX_DEVALTF_SHI_NEW 7 +#endif + /* Others bit definitions */ #define NPCX_LFCGCALCNT_LPREG_CTL_EN 1 @@ -695,7 +700,6 @@ enum { /* DBG register fields */ #define NPCX_DBGFRZEN3_GLBL_FRZ_DIS 7 - /******************************************************************************/ /* SMBus Registers */ #define NPCX_SMBSDA(n) REG8(NPCX_SMB_BASE_ADDR(n) + 0x000) @@ -1348,9 +1352,19 @@ enum ITIM16_MODULE_T { #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) +#if defined(CHIP_FAMILY_NPCX5) #define NPCX_OBUF(n) REG8(NPCX_SHI_BASE_ADDR + 0x020 + (n)) #define NPCX_IBUF(n) REG8(NPCX_SHI_BASE_ADDR + 0x060 + (n)) +#elif defined(CHIP_FAMILY_NPCX7) +/* Serial Host Interface (SHI) Registers - only available on SHI Version 2 */ +#define NPCX_SHICFG3 REG8(NPCX_SHI_BASE_ADDR + 0x00C) +#define NPCX_SHICFG4 REG8(NPCX_SHI_BASE_ADDR + 0x00D) +#define NPCX_SHICFG5 REG8(NPCX_SHI_BASE_ADDR + 0x00E) +#define NPCX_EVSTAT2 REG8(NPCX_SHI_BASE_ADDR + 0x00F) +#define NPCX_EVENABLE2 REG8(NPCX_SHI_BASE_ADDR + 0x010) +#define NPCX_OBUF(n) REG8(NPCX_SHI_BASE_ADDR + 0x020 + (n)) +#define NPCX_IBUF(n) REG8(NPCX_SHI_BASE_ADDR + 0x0A0 + (n)) +#endif /* SHI register fields */ #define NPCX_SHICFG1_EN 0 @@ -1386,6 +1400,18 @@ enum ITIM16_MODULE_T { #define NPCX_EVSTAT_IBOR 7 #define NPCX_STATUS_OBES 6 #define NPCX_STATUS_IBFS 7 +#if defined(CHIP_FAMILY_NPCX7) +#define NPCX_SHICFG3_OBUFLVLDIS 7 +#define NPCX_SHICFG4_IBUFLVLDIS 7 +#define NPCX_SHICFG5_IBUFLVL2 FIELD(0, 6) +#define NPCX_SHICFG5_IBUFLVL2DIS 7 +#define NPCX_EVSTAT2_IBHF2 0 +#define NPCX_EVSTAT2_CSNRE 1 +#define NPCX_EVSTAT2_CSNFE 2 +#define NPCX_EVENABLE2_IBHF2EN 0 +#define NPCX_EVENABLE2_CSNREEN 1 +#define NPCX_EVENABLE2_CSNFEEN 2 +#endif /******************************************************************************/ /* Monotonic Counter (MTC) Registers */ diff --git a/chip/npcx/shi.c b/chip/npcx/shi.c index ec584e82ee..b21482ccb9 100644 --- a/chip/npcx/shi.c +++ b/chip/npcx/shi.c @@ -38,8 +38,15 @@ #endif /* SHI Bus definition */ +#ifdef NPCX_SHI_V2 +#define SHI_OBUF_FULL_SIZE 128 /* Full output buffer size */ +#define SHI_IBUF_FULL_SIZE 128 /* Full input buffer size */ +/* Configure the IBUFLVL2 = the size of V3 protocol header */ +#define SHI_IBUFLVL2_THRESHOLD (sizeof(struct ec_host_request)) +#else #define SHI_OBUF_FULL_SIZE 64 /* Full output buffer size */ #define SHI_IBUF_FULL_SIZE 64 /* Full input buffer size */ +#endif #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 */ @@ -56,7 +63,7 @@ #define SHI_OBUF_VALID_OFFSET ((shi_read_buf_pointer() + \ 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) +#define SHI_IBUF_START_ADDR (&NPCX_IBUF(0)) /* Current address of SHI input buffer */ #define SHI_IBUF_CUR_ADDR (SHI_IBUF_START_ADDR + shi_read_buf_pointer()) @@ -374,6 +381,30 @@ static void shi_fill_out_status(uint8_t status) interrupt_enable(); } +#ifdef NPCX_SHI_V2 + /* + * This routine configures at which level the Input Buffer Half Full 2(IBHF2)) + * event triggers an interrupt to core. + */ +static void shi_sec_ibf_int_enable(int enable) +{ + if (enable) { + /* Setup IBUFLVL2 threshold and enable it */ + SET_BIT(NPCX_SHICFG5, NPCX_SHICFG5_IBUFLVL2DIS); + SET_FIELD(NPCX_SHICFG5, NPCX_SHICFG5_IBUFLVL2, + SHI_IBUFLVL2_THRESHOLD); + CLEAR_BIT(NPCX_SHICFG5, NPCX_SHICFG5_IBUFLVL2DIS); + /* Enable IBHF2 event */ + SET_BIT(NPCX_EVENABLE2, NPCX_EVENABLE2_IBHF2EN); + } else { + /* Disable IBHF2 event first */ + CLEAR_BIT(NPCX_EVENABLE2, NPCX_EVENABLE2_IBHF2EN); + /* Disable IBUFLVL2 and set threshold back to zero */ + SET_BIT(NPCX_SHICFG5, NPCX_SHICFG5_IBUFLVL2DIS); + SET_FIELD(NPCX_SHICFG5, NPCX_SHICFG5_IBUFLVL2, 0); + } +} +#else /* * This routine makes sure it's valid transaction or glitch on CS bus. */ @@ -392,6 +423,7 @@ static int shi_is_cs_glitch(void) /* valid package */ return 0; } +#endif /* * This routine write SHI next half output buffer from msg buffer @@ -557,20 +589,109 @@ static void log_unexpected_state(char *isr_name) last_error_state = state; } +static void shi_handle_cs_assert(void) +{ + /* If not enabled, ignore glitches on SHI_CS_L */ + if (state == SHI_STATE_DISABLED) + return; + + /* SHI V2 module filters cs glitch by hardware automatically */ +#ifndef NPCX_SHI_V2 + /* + * IBUFSTAT resets on the 7th clock cycle after CS assertion, which + * may not have happened yet. We use NPCX_IBUFSTAT for calculating + * buffer fill depth, so make sure it's valid before proceeding. + */ + if (shi_is_cs_glitch()) { + CPRINTS("ERR-GTH"); + shi_reset_prepare(); + DEBUG_CPRINTF("END\n"); + return; + } +#endif + + /* NOT_READY should be sent and there're no spi transaction now. */ + if (state == SHI_STATE_CNL_RESP_NOT_RDY) + return; + + /* Chip select is low = asserted */ + if (state != SHI_STATE_READY_TO_RECV) { + /* State machine should be reset in EVSTAT_EOR ISR */ + CPRINTS("Unexpected state %d in CS ISR", state); + return; + } + + DEBUG_CPRINTF("CSL-"); + + /* + * Clear possible EOR event from previous transaction since it's + * irrelevant now that CS is re-asserted. + */ + NPCX_EVSTAT = 1 << NPCX_EVSTAT_EOR; + + /* Do not deep sleep during SHI transaction */ + disable_sleep(SLEEP_MASK_SPI); + +#ifndef NPCX_SHI_V2 + /* + * Enable SHI interrupt - we will either succeed to parse our host + * command or reset on failure from here. + */ + task_enable_irq(NPCX_IRQ_SHI); + + /* Read first three bytes to parse which protocol is receiving */ + shi_parse_header(); +#endif +} + /* This routine handles all interrupts of this module */ void shi_int_handler(void) { uint8_t stat_reg; +#ifdef NPCX_SHI_V2 + uint8_t stat2_reg; +#endif - /* Read status register and clear interrupt status early*/ + /* Read status register and clear interrupt status early */ stat_reg = NPCX_EVSTAT; NPCX_EVSTAT = stat_reg; +#ifdef NPCX_SHI_V2 + stat2_reg = NPCX_EVSTAT2; + + /* SHI CS pin is asserted in EVSTAT2 */ + if (IS_BIT_SET(stat2_reg, NPCX_EVSTAT2_CSNFE)) { + /* clear CSNFE bit */ + NPCX_EVSTAT2 = (1 << NPCX_EVSTAT2_CSNFE); + DEBUG_CPRINTF("CSNFE-"); + /* + * BUSY bit is set when SHI_CS is asserted. If not, leave it for + * SHI_CS de-asserted event. + */ + if (!IS_BIT_SET(NPCX_SHICFG2, NPCX_SHICFG2_BUSY)) { + DEBUG_CPRINTF("CSNB-"); + return; + } + shi_handle_cs_assert(); + } +#endif /* * End of data for read/write transaction. ie SHI_CS is deasserted. * Host completed or aborted transaction */ +#ifdef NPCX_SHI_V2 + /* + * EOR has the limitation that it will not be set even if the SHI_CS is + * deasserted without SPI clocks. The new SHI module introduce the + * CSNRE bit which will be set when SHI_CS is deasserted regardless of + * SPI clocks. + */ + if (IS_BIT_SET(stat2_reg, NPCX_EVSTAT2_CSNRE)) { + /* Clear pending bit of CSNRE */ + NPCX_EVSTAT2 = (1 << NPCX_EVSTAT2_CSNRE); +#else if (IS_BIT_SET(stat_reg, NPCX_EVSTAT_EOR)) { +#endif /* * We're not in proper state. * Mark not ready to abort next transaction @@ -604,7 +725,11 @@ void shi_int_handler(void) /* Error state for checking*/ if (state != SHI_STATE_SENDING) +#ifdef NPCX_SHI_V2 + log_unexpected_state("CSNRE"); +#else log_unexpected_state("IBEOR"); +#endif /* reset SHI and prepare to next transaction again */ shi_reset_prepare(); @@ -652,6 +777,21 @@ void shi_int_handler(void) log_unexpected_state("IBHF"); } +#ifdef NPCX_SHI_V2 + /* + * The size of input buffer reaches the size of + * protocol V3 header(=8) after CS asserted. + */ + if (IS_BIT_SET(stat2_reg, NPCX_EVSTAT2_IBHF2)) { + /* Clear IBHF2 */ + NPCX_EVSTAT2 = (1 << NPCX_EVSTAT2_IBHF2); + DEBUG_CPRINTF("HDR-"); + /* Disable second IBF interrupt and start to parse header */ + shi_sec_ibf_int_enable(0); + shi_parse_header(); + } +#endif + /* * Indicate input/output buffer pointer reaches the full buffer size. * Transaction is processing. @@ -692,49 +832,19 @@ DECLARE_IRQ(NPCX_IRQ_SHI, shi_int_handler, 1); /* 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; - +#ifdef NPCX_SHI_V2 /* - * IBUFSTAT resets on the 7th clock cycle after CS assertion, which - * may not have happened yet. We use NPCX_IBUFSTAT for calculating - * buffer fill depth, so make sure it's valid before proceeding. + * New SHI module handles the CS low event in the SHI module interrupt + * handler (checking CSNFE bit) instead of in GPIO(MIWU) interrupt + * handler. But there is still a need to configure the MIWU to generate + * event to wake up EC from deep sleep. Immediately return to bypass + * the CS low interrupt event from MIWU module. */ - if (shi_is_cs_glitch()) { - CPRINTS("ERR-GTH"); - shi_reset_prepare(); - DEBUG_CPRINTF("END\n"); - return; - } - - /* NOT_READY should be sent and there're no spi transaction now. */ - if (state == SHI_STATE_CNL_RESP_NOT_RDY) - return; - - /* Chip select is low = asserted */ - if (state != SHI_STATE_READY_TO_RECV) { - /* State machine should be reset in EVSTAT_EOR ISR */ - CPRINTS("Unexpected state %d in CS ISR", state); - return; - } - - DEBUG_CPRINTF("CSL-"); - - /* - * Clear possible EOR event from previous transaction since it's - * irrelevant now that CS is re-asserted. - */ - NPCX_EVSTAT = 1 << NPCX_EVSTAT_EOR; - - /* - * Enable SHI interrupt - we will either succeed to parse our host - * command or reset on failure from here. - */ - task_enable_irq(NPCX_IRQ_SHI); + return; +#else + shi_handle_cs_assert(); +#endif - /* Read first three bytes to parse which protocol is receiving */ - shi_parse_header(); } /*****************************************************************************/ @@ -784,6 +894,15 @@ static void shi_reset_prepare(void) state = SHI_STATE_READY_TO_RECV; last_error_state = -1; + /* Setup second IBF interrupt and enable SHI's interrupt */ +#ifdef NPCX_SHI_V2 + shi_sec_ibf_int_enable(1); + task_enable_irq(NPCX_IRQ_SHI); +#endif + + /* Allow deep sleep at the end of SHI transaction */ + enable_sleep(SLEEP_MASK_SPI); + DEBUG_CPRINTF("RDY-"); } @@ -862,6 +981,11 @@ static void shi_init(void) /* Power on SHI module first */ CLEAR_BIT(NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_5), NPCX_PWDWN_CTL5_SHI_PD); +#ifdef NPCX_SHI_V2 + /* Enable SHI module Version 2 */ + SET_BIT(NPCX_DEVALT(ALT_GROUP_F), NPCX_DEVALTF_SHI_NEW); +#endif + /* * SHICFG1 (SHI Configuration 1) setting * [7] - IWRAP = 1: Wrap input buffer to the first address @@ -901,6 +1025,16 @@ static void shi_init(void) */ NPCX_EVENABLE = 0x1C; +#ifdef NPCX_SHI_V2 + /* + * EVENABLE2 (Event Enable 2) setting + * [2] - CSNFEEN = 1: SHI_CS Falling Edge Interrupt Enable + * [1] - CSNREEN = 1: SHI_CS Rising Edge Interrupt Enable + * [0] - IBHF2EN = 0: Input Buffer Half Full 2 Interrupt Enable + */ + NPCX_EVENABLE2 = 0x06; +#endif + /* Clear SHI events status register */ NPCX_EVSTAT = 0XFF; } diff --git a/chip/npcx/shi_chip.h b/chip/npcx/shi_chip.h index 8aac7661a5..f701067715 100644 --- a/chip/npcx/shi_chip.h +++ b/chip/npcx/shi_chip.h @@ -16,6 +16,9 @@ * @param signal GPIO signal that changed */ void shi_cs_event(enum gpio_signal signal); +#ifdef NPCX_SHI_V2 +void shi_cs_gpio_int(enum gpio_signal signal); +#endif #endif #endif /* SHI_CHIP_H_ */ |