mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-08 00:21:46 +00:00
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>
This commit is contained in:
@@ -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. */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
218
chip/npcx/shi.c
218
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;
|
||||
}
|
||||
return;
|
||||
#else
|
||||
shi_handle_cs_assert();
|
||||
#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;
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
Reference in New Issue
Block a user