diff options
author | Vic Yang <victoryang@chromium.org> | 2014-06-10 21:13:43 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-06-12 01:37:49 +0000 |
commit | 4670e537169b2ed4befa375cbd9c13a2bd8c39c7 (patch) | |
tree | 113d27315333c85b6e351be5ec9d35966a228076 | |
parent | b170291c3668807ed923748de2ebc7e707856f92 (diff) | |
download | chrome-ec-4670e537169b2ed4befa375cbd9c13a2bd8c39c7.tar.gz |
Keyborg: improve error recovery
Previously an error in master-slave communication often leaves the chips
in bad states and thus prevents further operation. Improve this by:
- Making master_slave_sync() state-less.
- Restoring SPI_NSS and disabling DMA on error.
BUG=None
TEST=Inject errors on master side and slave side. Check the subsequent
operations succeed.
BRANCH=None
Change-Id: Ief8b5b0df3d4be6319957bb1f9daf93e0e9b5d92
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/203337
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | board/keyborg/master_slave.c | 16 | ||||
-rw-r--r-- | board/keyborg/spi_comm.c | 15 | ||||
-rw-r--r-- | board/keyborg/touch_scan.c | 53 |
3 files changed, 56 insertions, 28 deletions
diff --git a/board/keyborg/master_slave.c b/board/keyborg/master_slave.c index a74ddf554b..5bb03c4e70 100644 --- a/board/keyborg/master_slave.c +++ b/board/keyborg/master_slave.c @@ -15,7 +15,6 @@ #define SYNC2 (1 << 2) /* PI2 */ static int is_master = -1; -static int last_sync; /* = 0 -> Low */ int master_slave_is_master(void) { @@ -36,15 +35,20 @@ static int wait_sync_signal(int mask, int v, int timeout_ms) int master_slave_sync(int timeout_ms) { int err = EC_SUCCESS; - last_sync ^= 1; if (is_master) { - STM32_GPIO_BSRR(GPIO_I) = SYNC1 << (last_sync ? 0 : 16); - if (wait_sync_signal(SYNC2, last_sync, timeout_ms)) + STM32_GPIO_BSRR(GPIO_I) = SYNC1 << 0; + if (wait_sync_signal(SYNC2, 1, timeout_ms)) + err = EC_ERROR_TIMEOUT; + STM32_GPIO_BSRR(GPIO_I) = SYNC1 << 16; + if (wait_sync_signal(SYNC2, 0, 5)) err = EC_ERROR_TIMEOUT; } else { - if (wait_sync_signal(SYNC1, last_sync, timeout_ms)) + if (wait_sync_signal(SYNC1, 1, timeout_ms)) + err = EC_ERROR_TIMEOUT; + STM32_GPIO_BSRR(GPIO_I) = SYNC2 << 0; + if (wait_sync_signal(SYNC1, 0, 5)) err = EC_ERROR_TIMEOUT; - STM32_GPIO_BSRR(GPIO_I) = SYNC2 << (last_sync ? 0 : 16); + STM32_GPIO_BSRR(GPIO_I) = SYNC2 << 16; } return err; } diff --git a/board/keyborg/spi_comm.c b/board/keyborg/spi_comm.c index 444661a23c..380ab6906b 100644 --- a/board/keyborg/spi_comm.c +++ b/board/keyborg/spi_comm.c @@ -309,9 +309,12 @@ void spi_slave_init(void) int spi_slave_send_response(struct spi_comm_packet *resp) { - if (spi_slave_send_response_async(resp) != EC_SUCCESS) - return EC_ERROR_UNKNOWN; - return spi_slave_send_response_flush(); + int r; + + r = spi_slave_send_response_async(resp); + r |= spi_slave_send_response_flush(); + + return r; } int spi_slave_send_response_async(struct spi_comm_packet *resp) @@ -325,7 +328,8 @@ int spi_slave_send_response_async(struct spi_comm_packet *resp) if (out_msg != (uint8_t *)resp) memcpy(out_msg, resp, size); - master_slave_sync(100); + if (master_slave_sync(100) != EC_SUCCESS) + return EC_ERROR_UNKNOWN; if (spi->sr & STM32_SPI_SR_RXNE) in_msg[0] = spi->dr; @@ -344,7 +348,8 @@ int spi_slave_send_response_async(struct spi_comm_packet *resp) dma_prepare_tx(&dma_tx_option, size - 1, out_msg + 1); dma_go(dma_get_channel(STM32_DMAC_SPI1_TX)); - master_slave_sync(5); + if (master_slave_sync(5) != EC_SUCCESS) + return EC_ERROR_UNKNOWN; return EC_SUCCESS; } diff --git a/board/keyborg/touch_scan.c b/board/keyborg/touch_scan.c index 53eec0ae16..da71b605a5 100644 --- a/board/keyborg/touch_scan.c +++ b/board/keyborg/touch_scan.c @@ -152,7 +152,7 @@ static inline void set_scan_needed(int col) int fast_scan(uint32_t *data) { int col; - int chip_col; + int chip_col = 0; memset(data, 0, SCAN_BUF_SIZE * 4); @@ -168,7 +168,7 @@ int fast_scan(uint32_t *data) } if (master_slave_sync(5) != EC_SUCCESS) - return EC_ERROR_UNKNOWN; + goto fast_scan_err; start_adc_sample(0, ADC_SMPL_CPU_CYCLE); while (!(STM32_ADC_SR(0) & (1 << 1))) @@ -177,7 +177,7 @@ int fast_scan(uint32_t *data) set_scan_needed(col); if (master_slave_sync(5) != EC_SUCCESS) - return EC_ERROR_UNKNOWN; + goto fast_scan_err; if (chip_col >= 0) { enable_col(chip_col, 0); STM32_PMSE_MCCR = 0; @@ -186,6 +186,11 @@ int fast_scan(uint32_t *data) STM32_PMSE_MRCR = 0; return EC_SUCCESS; +fast_scan_err: + enable_col(chip_col, 0); + STM32_PMSE_MCCR = 0; + STM32_PMSE_MRCR = 0; + return EC_ERROR_UNKNOWN; } #else int fast_scan(uint32_t *data) @@ -224,11 +229,11 @@ void scan_column(uint8_t *data) void touch_scan_slave_start(void) { - int col, i, v; + int col = 0, i, v; struct spi_comm_packet *resp = (struct spi_comm_packet *)buf; if (fast_scan(scan_needed) != EC_SUCCESS) - return; + goto slave_err; /* Discharge the panel */ discharge(); @@ -240,7 +245,7 @@ void touch_scan_slave_start(void) } if (master_slave_sync(20) != EC_SUCCESS) - return; + goto slave_err; if (GET_SCAN_NEEDED(col)) { scan_column(resp->data); @@ -260,13 +265,15 @@ void touch_scan_slave_start(void) /* Flush the last response */ if (col != 0) - spi_slave_send_response_flush(); + if (spi_slave_send_response_flush() != EC_SUCCESS) + goto slave_err; if (master_slave_sync(40) != EC_SUCCESS) - return; + goto slave_err; /* Start sending the response for the current column */ - spi_slave_send_response_async(resp); + if (spi_slave_send_response_async(resp) != EC_SUCCESS) + goto slave_err; /* Disable the current column and discharge */ if (col < COL_COUNT) { @@ -277,13 +284,19 @@ void touch_scan_slave_start(void) } spi_slave_send_response_flush(); master_slave_sync(20); + return; +slave_err: + if (col < COL_COUNT) + enable_col(col, 0); + STM32_PMSE_MCCR = 0; + spi_slave_send_response_flush(); } int touch_scan_full_matrix(void) { struct spi_comm_packet cmd; const struct spi_comm_packet *resp; - int col; + int col = 0; timestamp_t st = get_time(); uint8_t *dptr = NULL, *last_dptr = NULL; @@ -291,12 +304,12 @@ int touch_scan_full_matrix(void) cmd.size = 0; if (spi_master_send_command(&cmd)) - return EC_ERROR_UNKNOWN; + goto master_err; encode_reset(); if (fast_scan(scan_needed) != EC_SUCCESS) - return EC_ERROR_UNKNOWN; + goto master_err; /* Discharge the panel */ discharge(); @@ -308,7 +321,7 @@ int touch_scan_full_matrix(void) } if (master_slave_sync(20) != EC_SUCCESS) - return EC_ERROR_UNKNOWN; + goto master_err; last_dptr = dptr; dptr = buf[col & 1]; @@ -322,7 +335,7 @@ int touch_scan_full_matrix(void) /* Flush the data from the slave for the last column */ resp = spi_master_wait_response_done(); if (resp == NULL) - return EC_ERROR_UNKNOWN; + goto master_err; if (resp->size) memcpy(last_dptr, resp->data, ROW_COUNT); else @@ -331,11 +344,11 @@ int touch_scan_full_matrix(void) } if (master_slave_sync(40) != EC_SUCCESS) - return EC_ERROR_UNKNOWN; + goto master_err; /* Start receiving data for the current column */ if (spi_master_wait_response_async() != EC_SUCCESS) - return EC_ERROR_UNKNOWN; + goto master_err; /* Disable the current column and discharge */ if (col >= COL_COUNT) { @@ -347,7 +360,7 @@ int touch_scan_full_matrix(void) resp = spi_master_wait_response_done(); if (resp == NULL) - return EC_ERROR_UNKNOWN; + goto master_err; if (resp->size) memcpy(last_dptr, resp->data, ROW_COUNT); else @@ -360,4 +373,10 @@ int touch_scan_full_matrix(void) encode_dump_matrix(); return EC_SUCCESS; +master_err: + spi_master_wait_response_done(); + if (col >= COL_COUNT) + enable_col(col - COL_COUNT, 0); + STM32_PMSE_MCCR = 0; + return EC_ERROR_UNKNOWN; } |