summaryrefslogtreecommitdiff
path: root/chip/npcx/lpc.c
diff options
context:
space:
mode:
authorCHLin <CHLIN56@nuvoton.com>2016-12-15 15:04:50 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-01-03 15:13:56 -0800
commit05835a86912bd3beaf1e296739cad83ca89711d3 (patch)
tree308423d5feeb8e15527155e88e0561b9ac744add /chip/npcx/lpc.c
parenta80a815ea2f915cf14b6526f352521765c47add2 (diff)
downloadchrome-ec-05835a86912bd3beaf1e296739cad83ca89711d3.tar.gz
npcx: lpc: Do not use FW_OBF bit to clear OBF bit
Setting HICTRL.FW_OBF clears the HIKMST.OBF and STATUS.OBF flags but it does not deassert IRQ1 when already asserted. To make sure IRQ1 will also be deasserted need to emulate a host read. Modified drivers: 1. lpc.c: emulate a host read to clear OBF and deasserted IRQ1. BRANCH=none BUG=chrome-os-partner:34346 TEST=make buildall; Run FAFT items related to Power on/off, reboot, and keyboard on Wheatley. Change-Id: Ibf0ff3b8a4eeece853916e4e19d67fcc7ae2e989 Signed-off-by: CHLin <CHLIN56@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/419909 Commit-Ready: Aaron Durbin <adurbin@chromium.org> Tested-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'chip/npcx/lpc.c')
-rw-r--r--chip/npcx/lpc.c130
1 files changed, 106 insertions, 24 deletions
diff --git a/chip/npcx/lpc.c b/chip/npcx/lpc.c
index 547e662818..15aa2298d0 100644
--- a/chip/npcx/lpc.c
+++ b/chip/npcx/lpc.c
@@ -47,6 +47,18 @@
#define INDEX_CHPREV 0x24
#define INDEX_SRID 0x27
+/*
+ * Timeout to wait for host transaction to be completed.
+ *
+ * For eSPI - it is 200 us.
+ * For LPC - it is 5 us.
+ */
+#ifdef CONFIG_ESPI
+#define LPC_HOST_TRANSACTION_TIMEOUT_US 200
+#else
+#define LPC_HOST_TRANSACTION_TIMEOUT_US 5
+#endif
+
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;
@@ -316,14 +328,91 @@ void lpc_keyboard_put_char(uint8_t chr, int send_irq)
}
}
+/*
+ * Check host read is not in-progress and no timeout
+ */
+static void lpc_sib_wait_host_read_done(void)
+{
+ timestamp_t deadline;
+
+ deadline.val = get_time().val + LPC_HOST_TRANSACTION_TIMEOUT_US;
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD)) {
+ if (timestamp_expired(deadline, NULL)) {
+ ccprintf("Unexpected time of host read transaction\n");
+ break;
+ }
+ }
+}
+
+/*
+ * Check host write is not in-progress and no timeout
+ */
+static void lpc_sib_wait_host_write_done(void)
+{
+ timestamp_t deadline;
+
+ deadline.val = get_time().val + LPC_HOST_TRANSACTION_TIMEOUT_US;
+ while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) {
+ if (timestamp_expired(deadline, NULL)) {
+ ccprintf("Unexpected time of host write transaction\n");
+ break;
+ }
+ }
+}
+
+/* Emulate host to read Keyboard I/O */
+uint8_t lpc_sib_read_kbc_reg(uint8_t io_offset)
+{
+ uint8_t data_value;
+
+ /* Disable interrupts */
+ interrupt_disable();
+
+ /* Lock host keyboard module */
+ SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKHIKBD);
+ /* Enable Core-to-Host Modules Access */
+ SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE);
+ /* Verify Core read/write to host modules is not in progress */
+ lpc_sib_wait_host_read_done();
+ lpc_sib_wait_host_write_done();
+ /* Enable Core access to keyboard module */
+ SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_HIKBDAE);
+
+ /* Specify the io_offset A0 = 0. the index register is accessed */
+ NPCX_IHIOA = io_offset;
+
+ /* Start a Core read from host module */
+ SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD);
+ /* Wait while Core read operation is in progress */
+ lpc_sib_wait_host_read_done();
+ /* Read the data */
+ data_value = NPCX_IHD;
+
+ /* Disable Core access to keyboard module */
+ CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_HIKBDAE);
+ /* Disable Core-to-Host Modules Access */
+ CLEAR_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE);
+ /* unlock host keyboard module */
+ CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKHIKBD);
+
+ /* Enable interrupts */
+ interrupt_enable();
+
+ return data_value;
+}
+
void lpc_keyboard_clear_buffer(void)
{
- /* Make sure the previous TOH and IRQ has been sent out. */
- udelay(4);
- /* Clear OBE flag in host STATUS and HIKMST regs*/
- SET_BIT(NPCX_HICTRL, NPCX_HICTRL_FW_OBF);
- /* Ensure there is no TOH set in this period. */
- udelay(4);
+ /* Clear OBF flag in host STATUS and HIKMST regs */
+ if (IS_BIT_SET(NPCX_HIKMST, NPCX_HIKMST_OBF)) {
+ /*
+ * Setting HICTRL.FW_OBF clears the HIKMST.OBF and STATUS.OBF
+ * but it does not deassert IRQ1 when it was already asserted.
+ * Emulate a host read to clear these two flags and also
+ * deassert IRQ1
+ */
+ lpc_sib_read_kbc_reg(0x0);
+ }
}
void lpc_keyboard_resume_irq(void)
@@ -642,26 +731,22 @@ void lpc_sib_write_reg(uint8_t io_offset, uint8_t index_value,
/* 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))
- ;
+ lpc_sib_wait_host_read_done();
+ lpc_sib_wait_host_write_done();
/* 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))
- ;
+ lpc_sib_wait_host_write_done();
/* 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))
- ;
+ lpc_sib_wait_host_write_done();
/* Disable Core access to CFG module */
CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE);
@@ -688,27 +773,22 @@ uint8_t lpc_sib_read_reg(uint8_t io_offset, uint8_t index_value)
/* 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))
- ;
-
+ lpc_sib_wait_host_read_done();
+ lpc_sib_wait_host_write_done();
/* 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))
- ;
+ lpc_sib_wait_host_write_done();
/* 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))
- ;
+ lpc_sib_wait_host_read_done();
/* Read the data */
data_value = NPCX_IHD;
@@ -953,7 +1033,9 @@ static void lpc_init(void)
* IBF(K&M) INT enable, OBE(K&M) empty INT enable ,
* OBF Mouse Full INT enable and OBF KB Full INT enable
*/
- NPCX_HICTRL = 0x8F;
+ lpc_keyboard_clear_buffer();
+ NPCX_HICTRL = 0x0F;
+
/*
* Turn on enhance mode on PM channel-1,
* enable OBE/IBF core interrupt