Skip to content

Commit

Permalink
mgmt: ec_host_cmd: npcx: workaround for backend SHI
Browse files Browse the repository at this point in the history
There is an issue on the SHI hardware peripheral to detect CS
rising/failing with bits CSnFE/CSnRE in the EVSTAT2 register in
npcx9m7fb chip. This commit workarounds it by using MIWU to detect the
CS rising and failing.

Signed-off-by: Tom Chang <CHChang19@nuvoton.com>
Signed-off-by: Jun Lin <CHLin56@nuvoton.com>
  • Loading branch information
TomChang19 committed Sep 11, 2024
1 parent 8c4a49c commit bc68210
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 3 deletions.
8 changes: 8 additions & 0 deletions dts/arm/nuvoton/npcx9m7fb.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,11 @@
pinctrl-names = "default";
};
};

/*
* Raising the interrupt priority of the MIWU group, which owns SHI CS, to the same as
* SHI's priority.
*/
&group_f1 {
irq-prio = <1>;
};
7 changes: 7 additions & 0 deletions subsys/mgmt/ec_host_cmd/backends/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ config EC_HOST_CMD_BACKEND_SHI_NPCX_ENHANCED_BUF_MODE
single-byte output buffer can be selected/switched to generate a
response to simultaneous Read/Write transactions.

config EC_HOST_CMD_BACKEND_SHI_NPCX_CS_DETECT_WORKAROUND
bool
default y if SOC_NPCX9M7FB
help
Workaround the issue "CSnFE and CSnRE bits of EVSTATS2 Register (SHI)"
in the npcx9m7fb SoC errata.

config EC_HOST_CMD_BACKEND_SHI_MAX_REQUEST
int "Max data size for the version 3 request packet"
default 544 if EC_HOST_CMD_BACKEND_SHI_NPCX
Expand Down
61 changes: 58 additions & 3 deletions subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ struct shi_npcx_data {
uint8_t *const out_msg;
uint8_t in_msg[CONFIG_EC_HOST_CMD_BACKEND_SHI_MAX_REQUEST] __aligned(4);
ATOMIC_DEFINE(pm_policy_state_flag, SHI_NPCX_PM_POLICY_FLAG_COUNT);
#ifdef CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_CS_DETECT_WORKAROUND
struct miwu_callback shi_cs_wui_cb;
/*
* With the workaround, CS assertion/de-assertion INT and SHI module's INT come from
* different sources. CS failing IRQ and IBHF2 IRQ may happen at the same time.
* In this case, IBHF2 ISR is called first because it has lower INT number.
* (with the same priority). This flag is used to guarantee CS assertion ISR is executed
* first.
*/
bool is_entered_cs_asserted_wui_isr;
#endif
};

struct ec_host_cmd_shi_npcx_ctx {
Expand Down Expand Up @@ -605,7 +616,7 @@ static void shi_npcx_handle_cs_deassert(const struct device *dev)

/* Error state for checking*/
if (data->state != SHI_STATE_SENDING) {
shi_npcx_log_unexpected_state(dev, "CSNRE");
shi_npcx_log_unexpected_state(dev, "CS DE-AST");
}

/* reset SHI and prepare to next transaction again */
Expand Down Expand Up @@ -670,11 +681,20 @@ static void shi_npcx_isr(const struct device *dev)
uint8_t stat;
uint8_t stat2;

#ifdef CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_CS_DETECT_WORKAROUND
struct shi_npcx_data *data = dev->data;

if (data->is_entered_cs_asserted_wui_isr != true) {
return;
}
#endif

/* Read status register and clear interrupt status early */
stat = inst->EVSTAT;
inst->EVSTAT = stat;
stat2 = inst->EVSTAT2;

#ifndef CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_CS_DETECT_WORKAROUND
/* SHI CS pin is asserted in EVSTAT2 */
if (IS_BIT_SET(stat2, NPCX_EVSTAT2_CSNFE)) {
/* Clear pending bit of CSNFE */
Expand All @@ -692,7 +712,6 @@ static void shi_npcx_isr(const struct device *dev)

shi_npcx_handle_cs_assert(dev);
}

/*
* End of data for read/write transaction. i.e. SHI_CS is deasserted.
* Host completed or aborted transaction
Expand All @@ -712,6 +731,7 @@ static void shi_npcx_isr(const struct device *dev)
LOG_DBG("CSH-");
return shi_npcx_handle_cs_deassert(dev);
}
#endif

/*
* The number of bytes received reaches the size of
Expand Down Expand Up @@ -821,6 +841,11 @@ static int shi_npcx_enable(const struct device *dev)
}

NVIC_ClearPendingIRQ(DT_INST_IRQN(0));
/*
* Clear the pending bit because switching the pinmux (pinctrl) might casue a faking WUI
* pending bit set.
*/
npcx_miwu_irq_get_and_clear_pending(&config->shi_cs_wui);
npcx_miwu_irq_enable(&config->shi_cs_wui);
irq_enable(DT_INST_IRQN(0));

Expand Down Expand Up @@ -861,6 +886,23 @@ static int shi_npcx_disable(const struct device *dev)
return 0;
}

#ifdef CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_CS_DETECT_WORKAROUND
static void shi_npcx_cs_wui_isr(const struct device *dev, struct npcx_wui *wui)
{

struct shi_reg *const inst = HAL_INSTANCE(dev);
struct shi_npcx_data *data = dev->data;

if (IS_BIT_SET(inst->SHICFG2, NPCX_SHICFG2_BUSY)) {
data->is_entered_cs_asserted_wui_isr = true;
shi_npcx_handle_cs_assert(dev);
} else {
shi_npcx_handle_cs_deassert(dev);
data->is_entered_cs_asserted_wui_isr = false;
}
}
#endif

static int shi_npcx_init_registers(const struct device *dev)
{
int ret;
Expand Down Expand Up @@ -912,15 +954,17 @@ static int shi_npcx_init_registers(const struct device *dev)
* [1] - OBHEEN = 0: Output Buffer Half Empty Interrupt Enable
* [0] - OBEEN = 0: Output Buffer Empty Interrupt Enable
*/
inst->EVENABLE = BIT(NPCX_EVENABLE_EOREN) | IBF_IBHF_EN_MASK;
inst->EVENABLE = IBF_IBHF_EN_MASK;

/*
* 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
*/
#ifndef CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_CS_DETECT_WORKAROUND
inst->EVENABLE2 = BIT(NPCX_EVENABLE2_CSNREEN) | BIT(NPCX_EVENABLE2_CSNFEEN);
#endif

/* Clear SHI events status register */
inst->EVSTAT = 0xff;
Expand All @@ -929,7 +973,18 @@ static int shi_npcx_init_registers(const struct device *dev)
inst->SHICFG6 |= BIT(NPCX_SHICFG6_EBUFMD);
}

#ifdef CONFIG_EC_HOST_CMD_BACKEND_SHI_NPCX_CS_DETECT_WORKAROUND
struct shi_npcx_data *data = dev->data;

npcx_miwu_interrupt_configure(&config->shi_cs_wui, NPCX_MIWU_MODE_EDGE,
NPCX_MIWU_TRIG_BOTH);

npcx_miwu_init_dev_callback(&data->shi_cs_wui_cb, &config->shi_cs_wui, shi_npcx_cs_wui_isr,
dev);
npcx_miwu_manage_callback(&data->shi_cs_wui_cb, true);
#else
npcx_miwu_interrupt_configure(&config->shi_cs_wui, NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_LOW);
#endif

/* SHI interrupt installation */
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), shi_npcx_isr, DEVICE_DT_INST_GET(0),
Expand Down

0 comments on commit bc68210

Please sign in to comment.