diff options
author | Dino Li <dino.li@ite.com.tw> | 2016-01-25 15:01:18 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-01-26 23:59:47 -0800 |
commit | 72ad2608470a58ad2f82c076229feddfcbc2a6a2 (patch) | |
tree | 52fcbe32d8d8fec4423620818a3b05be4a780756 /chip/it83xx | |
parent | 74e81bf9daba09b989a4e9e3153e7db5e6c4e730 (diff) | |
download | chrome-ec-72ad2608470a58ad2f82c076229feddfcbc2a6a2.tar.gz |
chip: it83xx: update ec2i module
1. The previous EC2I module does not meet section
'7.17.5 EC2I Programming Guide'. We need to correct it to prevent
conflict with H2RAM (LPC I/O cycles 800h ~ 9ffh) which cause LPC keeps
long wait states.
NOTE:
If EC is using EC2I internal bus to access PNPCFG registers while host
accessing EC ram through H2RAM interface at the same time,
the symptom will appear.
2. Remove 'CONFIG_IT83XX_PNPCFG_HOST_ACCESS'.
We don't allow the host access PNPCFG registers.
Signed-off-by: Dino Li <dino.li@ite.com.tw>
BRANCH=none
BUG=none
TEST=1. To use console command 'rwreg' to r/w PNPCFG registers and
there is no error code return.
2. To create a stress test for this change.
- EC use 'ec2i_read()' and 'ec2i_write()' to access PNPCFG
registers per-10ms.
- run ectool 'version' command per-100ms.
Before the change was made, LPC will keep in long wait states
immediately.
After the change, we run the test of ectool 'version' command
over 20000 times.
Change-Id: I84e86fc17ef624d4a60a1a051bc301ebdf56a3da
Reviewed-on: https://chromium-review.googlesource.com/323563
Commit-Ready: Dino Li <dino.li@ite.com.tw>
Tested-by: Dino Li <dino.li@ite.com.tw>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'chip/it83xx')
-rw-r--r-- | chip/it83xx/ec2i.c | 231 |
1 files changed, 112 insertions, 119 deletions
diff --git a/chip/it83xx/ec2i.c b/chip/it83xx/ec2i.c index 05266bec1b..cb8f5d3365 100644 --- a/chip/it83xx/ec2i.c +++ b/chip/it83xx/ec2i.c @@ -5,154 +5,147 @@ /* EC2I control module for IT83xx. */ -#include "hooks.h" +#include "common.h" #include "ec2i_chip.h" +#include "hooks.h" #include "registers.h" +#include "task.h" #include "timer.h" -#define EC2I_ACCESS_TIME_USEC 15 - -static int ec2i_check_status_bit(uint8_t status_bit) +/* EC2I access index/data port */ +enum ec2i_access { + /* index port */ + EC2I_ACCESS_INDEX = 0, + /* data port */ + EC2I_ACCESS_DATA = 1, +}; + +enum ec2i_status_mask { + /* 1: EC read-access is still processing. */ + EC2I_STATUS_CRIB = (1 << 1), + /* 1: EC write-access is still processing with IHD register. */ + EC2I_STATUS_CWIB = (1 << 2), + EC2I_STATUS_ALL = (EC2I_STATUS_CRIB | EC2I_STATUS_CWIB), +}; + +static int ec2i_wait_status_bit_cleared(enum ec2i_status_mask mask) { - int num; - - for (num = 0; num < 10; num++) { - udelay(EC2I_ACCESS_TIME_USEC); - - if (!(IT83XX_EC2I_IBCTL & status_bit)) - return 0; - } + /* delay ~15.25us */ + IT83XX_GCTRL_WNCKR = 0; - /* Timeout */ - return -1; + return (IT83XX_EC2I_IBCTL & mask); } -static void ec2i_ec_access_enable(void) +static enum ec2i_message ec2i_write_pnpcfg(enum ec2i_access sel, uint8_t data) { - /* - * bit0: Host access to the PNPCFG registers is disabled. - * bit1: Host access to the BRAM registers is disabled. - */ - IT83XX_EC2I_LSIOHA |= 0x03; - - /* bit0: EC to I-Bus access enabled. */ - IT83XX_EC2I_IBCTL |= 0x01; - - /* - * Make sure that both CRIB and CWIB bits in IBCTL register - * are cleared. - * bit1: CRIB - * bit2: CWIB - */ - if (ec2i_check_status_bit(0x06)) - IT83XX_EC2I_IBCTL &= ~0x02; - - /* Enable EC access to the PNPCFG registers */ - IT83XX_EC2I_IBMAE |= 0x01; -} + int rv = EC_ERROR_UNKNOWN; -static void ec2i_ec_access_disable(void) -{ - /* Disable EC access to the PNPCFG registers. */ - IT83XX_EC2I_IBMAE &= ~0x01; - - /* Diable EC to I-Bus access. */ - IT83XX_EC2I_IBCTL &= ~0x01; + /* bit1 : VCC power on */ + if (IT83XX_SWUC_SWCTL1 & (1 << 1)) { + /* + * Wait that both CRIB and CWIB bits in IBCTL register + * are cleared. + */ + rv = ec2i_wait_status_bit_cleared(EC2I_STATUS_ALL); + if (!rv) { + /* Set indirect host I/O offset. */ + IT83XX_EC2I_IHIOA = sel; + /* Write the data to IHD register */ + IT83XX_EC2I_IHD = data; + /* Enable EC access to the PNPCFG registers */ + IT83XX_EC2I_IBMAE |= (1 << 0); + /* bit0: EC to I-Bus access enabled. */ + IT83XX_EC2I_IBCTL |= (1 << 0); + /* Wait the CWIB bit in IBCTL cleared. */ + rv = ec2i_wait_status_bit_cleared(EC2I_STATUS_CWIB); + /* Disable EC access to the PNPCFG registers. */ + IT83XX_EC2I_IBMAE &= ~(1 << 0); + /* Disable EC to I-Bus access. */ + IT83XX_EC2I_IBCTL &= ~(1 << 0); + } + } -#ifdef CONFIG_IT83XX_PNPCFG_HOST_ACCESS - /* Enable host access */ - IT83XX_EC2I_LSIOHA &= ~0x03; -#else - /* Host access is disabled */ - IT83XX_EC2I_LSIOHA &= ~0x02; -#endif + return rv ? EC2I_WRITE_ERROR : EC2I_WRITE_SUCCESS; } -/* EC2I write */ -enum ec2i_message ec2i_write(enum host_pnpcfg_index index, uint8_t data) +static enum ec2i_message ec2i_read_pnpcfg(enum ec2i_access sel) { - /* bit1 : VCC power on */ - if (IT83XX_SWUC_SWCTL1 & 0x02) { - /* Enable EC2I EC access */ - ec2i_ec_access_enable(); - - /* Set indirect host I/O offset. (index port) */ - IT83XX_EC2I_IHIOA = 0; - IT83XX_EC2I_IHD = index; - - /* Read the CWIB bit in IBCTL until it returns 0. */ - if (ec2i_check_status_bit(0x04)) { - ec2i_ec_access_disable(); - return EC2I_WRITE_ERROR; - } + int rv = EC_ERROR_UNKNOWN; + uint8_t ihd = 0; - /* Set indirect host I/O offset. (data port) */ - IT83XX_EC2I_IHIOA = 1; - IT83XX_EC2I_IHD = data; - - /* Read the CWIB bit in IBCTL until it returns 0. */ - if (ec2i_check_status_bit(0x04)) { - ec2i_ec_access_disable(); - return EC2I_WRITE_ERROR; + /* bit1 : VCC power on */ + if (IT83XX_SWUC_SWCTL1 & (1 << 1)) { + /* + * Wait that both CRIB and CWIB bits in IBCTL register + * are cleared. + */ + rv = ec2i_wait_status_bit_cleared(EC2I_STATUS_ALL); + if (!rv) { + /* Set indirect host I/O offset. */ + IT83XX_EC2I_IHIOA = sel; + /* Enable EC access to the PNPCFG registers */ + IT83XX_EC2I_IBMAE |= (1 << 0); + /* bit1: a read-action */ + IT83XX_EC2I_IBCTL |= (1 << 1); + /* bit0: EC to I-Bus access enabled. */ + IT83XX_EC2I_IBCTL |= (1 << 0); + /* Wait the CRIB bit in IBCTL cleared. */ + rv = ec2i_wait_status_bit_cleared(EC2I_STATUS_CRIB); + /* Read the data from IHD register */ + ihd = IT83XX_EC2I_IHD; + /* Disable EC access to the PNPCFG registers. */ + IT83XX_EC2I_IBMAE &= ~(1 << 0); + /* Disable EC to I-Bus access. */ + IT83XX_EC2I_IBCTL &= ~(1 << 0); } - - /* Disable EC2I EC access */ - ec2i_ec_access_disable(); - - return EC2I_WRITE_SUCCESS; - } else { - return EC2I_WRITE_ERROR; } + + return rv ? EC2I_READ_ERROR : (EC2I_READ_SUCCESS + ihd); } /* EC2I read */ enum ec2i_message ec2i_read(enum host_pnpcfg_index index) { - uint8_t data; - - /* bit1 : VCC power on */ - if (IT83XX_SWUC_SWCTL1 & 0x02) { - /* Enable EC2I EC access */ - ec2i_ec_access_enable(); - - /* Set indirect host I/O offset. (index port) */ - IT83XX_EC2I_IHIOA = 0; - IT83XX_EC2I_IHD = index; - - /* Read the CWIB bit in IBCTL until it returns 0. */ - if (ec2i_check_status_bit(0x04)) { - ec2i_ec_access_disable(); - return EC2I_READ_ERROR; - } - - /* Set indirect host I/O offset. (data port) */ - IT83XX_EC2I_IHIOA = 1; - - /* This access is a read-action */ - IT83XX_EC2I_IBCTL |= 0x02; - - /* Read the CRIB bit in IBCTL until it returns 0. */ - if (ec2i_check_status_bit(0x02)) { - ec2i_ec_access_disable(); - return EC2I_READ_ERROR; - } - - /* Read the data from IHD register */ - data = IT83XX_EC2I_IHD; - - /* Disable EC2I EC access */ - ec2i_ec_access_disable(); + enum ec2i_message ret = EC2I_READ_ERROR; + uint32_t int_mask = get_int_mask(); + + /* critical section with interrupts off */ + interrupt_disable(); + /* Set index */ + if (ec2i_write_pnpcfg(EC2I_ACCESS_INDEX, index) == EC2I_WRITE_SUCCESS) + /* read data port */ + ret = ec2i_read_pnpcfg(EC2I_ACCESS_DATA); + /* restore interrupts */ + set_int_mask(int_mask); + + return ret; +} - return EC2I_READ_SUCCESS + data; - } else { - return EC2I_READ_ERROR; - } +/* EC2I write */ +enum ec2i_message ec2i_write(enum host_pnpcfg_index index, uint8_t data) +{ + enum ec2i_message ret = EC2I_WRITE_ERROR; + uint32_t int_mask = get_int_mask(); + + /* critical section with interrupts off */ + interrupt_disable(); + /* Set index */ + if (ec2i_write_pnpcfg(EC2I_ACCESS_INDEX, index) == EC2I_WRITE_SUCCESS) + /* Set data */ + ret = ec2i_write_pnpcfg(EC2I_ACCESS_DATA, data); + /* restore interrupts */ + set_int_mask(int_mask); + + return ret; } static void pnpcfg_init(void) { int table; + /* Host access is disabled */ + IT83XX_EC2I_LSIOHA |= 0x3; + for (table = 0x00; table < EC2I_SETTING_COUNT; table++) { if (ec2i_write(pnpcfg_settings[table].index_port, pnpcfg_settings[table].data_port) == EC2I_WRITE_ERROR) |