diff options
author | CHLin <CHLIN56@nuvoton.com> | 2016-12-15 15:04:50 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-01-03 15:13:56 -0800 |
commit | 05835a86912bd3beaf1e296739cad83ca89711d3 (patch) | |
tree | 308423d5feeb8e15527155e88e0561b9ac744add /chip/npcx/lpc.c | |
parent | a80a815ea2f915cf14b6526f352521765c47add2 (diff) | |
download | chrome-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.c | 130 |
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 |