void cts_task(void) { enum cts_rc rc; int i; gpio_enable_interrupt(GPIO_CTS_IRQ1); gpio_enable_interrupt(GPIO_CTS_IRQ2); interrupt_enable(); for (i = 0; i < CTS_TEST_ID_COUNT; i++) { clear_state(); sync(); rc = tests[i].run(); interrupt_enable(); CPRINTF("\n%s %d\n", tests[i].name, rc); cflush(); } CPRINTS("Interrupt test suite finished"); cflush(); while (1) { watchdog_reload(); sleep(1); } }
static int command_mem_dump(int argc, char **argv) { volatile uint32_t *address; uint32_t value, num = 1, i; char *e; if (argc < 2) return EC_ERROR_PARAM_COUNT; address = (uint32_t *)(uintptr_t)strtoi(argv[1], &e, 0); if (*e) return EC_ERROR_PARAM1; if (argc >= 3) num = strtoi(argv[2], &e, 0); for (i = 0; i < num; i++) { value = address[i]; if (0 == (i%4)) ccprintf("\n%08X: %08x", address+i, value); else ccprintf(" %08x", value); cflush(); /* Lots of output could take a while. * Let other things happen, too */ if (!(i % 0x100)) { watchdog_reload(); usleep(10 * MSEC); } } ccprintf("\n"); cflush(); return EC_SUCCESS; }
int flash_physical_write(int offset, int size, const char *data) { uint16_t *address = (uint16_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset); int res = EC_SUCCESS; int i; if (unlock(PRG_LOCK) != EC_SUCCESS) { res = EC_ERROR_UNKNOWN; goto exit_wr; } /* Clear previous error status */ STM32_FLASH_SR = 0x34; /* set PG bit */ STM32_FLASH_CR |= PG; for (; size > 0; size -= sizeof(uint16_t)) { /* * Reload the watchdog timer to avoid watchdog reset when doing * long writing with interrupt disabled. */ watchdog_reload(); /* wait to be ready */ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) ; /* write the half word */ *address++ = data[0] + (data[1] << 8); data += 2; /* Wait for writes to complete */ for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); i++) ; if (STM32_FLASH_SR & 1) { res = EC_ERROR_TIMEOUT; goto exit_wr; } /* Check for error conditions - erase failed, voltage error, * protection error */ if (STM32_FLASH_SR & 0x14) { res = EC_ERROR_UNKNOWN; goto exit_wr; } } exit_wr: /* Disable PG bit */ STM32_FLASH_CR &= ~PG; lock(); return res; }
int flash_physical_erase(int offset, int size) { int rv = EC_SUCCESS; /* check protection */ if (all_protected) return EC_ERROR_ACCESS_DENIED; /* Lock physical flash operations */ flash_lock_mapped_storage(1); /* Disable tri-state */ TRISTATE_FLASH(0); /* Alignment has been checked in upper layer */ for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, offset += CONFIG_FLASH_ERASE_SIZE) { /* check protection */ if (flash_check_prot_range(offset, CONFIG_FLASH_ERASE_SIZE)) { rv = EC_ERROR_ACCESS_DENIED; break; } /* * Reload the watchdog timer, so that erasing many flash pages * doesn't cause a watchdog reset. May not need this now that * we're using msleep() below. */ watchdog_reload(); /* Enable write */ rv = flash_write_enable(); if (rv) break; /* Set erase address */ flash_set_address(offset); /* Start erase */ flash_execute_cmd(CMD_SECTOR_ERASE, MASK_CMD_ADR); /* Wait erase completed */ rv = flash_wait_ready(FLASH_ABORT_TIMEOUT); if (rv) break; } /* Enable tri-state */ TRISTATE_FLASH(1); /* Unlock physical flash operations */ flash_lock_mapped_storage(0); return rv; }
static int command_mem_dump(int argc, char **argv) { uint32_t address, i, num = 1; char *e; enum format fmt = FMT_WORD; if (argc > 1) { if ((argv[1][0] == '.') && (strlen(argv[1]) == 2)) { switch (argv[1][1]) { case 'b': fmt = FMT_BYTE; break; case 'h': fmt = FMT_HALF; break; case 's': fmt = FMT_STRING; break; default: return EC_ERROR_PARAM1; } argc--; argv++; } } if (argc < 2) return EC_ERROR_PARAM_COUNT; address = strtoi(argv[1], &e, 0); if (*e) return EC_ERROR_PARAM1; if (argc >= 3) num = strtoi(argv[2], &e, 0); for (i = 0; i < num; i++) { show_val(address, i, fmt); /* Lots of output could take a while. * Let other things happen, too */ if (!(i % 0x100)) { watchdog_reload(); usleep(10 * MSEC); } } ccprintf("\n"); cflush(); return EC_SUCCESS; }
/* * Raw busy loop. Returns 1 if loop finishes before interrupt is triggered. * Loop length is controlled by busy_loop_timeout. It has to be set to the * value which makes the loop last longer than CTS_INTERRUPT_TRIGGER_DELAY_US. */ static int busy_loop(void) { /* TODO: Derive a proper value from clock speed */ const uint32_t busy_loop_timeout = 0xfffff; uint32_t counter = 0; while (counter++ < busy_loop_timeout) { if (got_interrupt) break; watchdog_reload(); } if (counter > busy_loop_timeout) return 1; return 0; }
void system_reset(int flags) { /* Disable interrupts to avoid task swaps during reboot. */ interrupt_disable(); /* TODO: Implement flags and stuff. */ /* * Try to trigger a watchdog reset, by setting the smallest timeout * period we can. */ ROTOR_MCU_WDT_TORR = 0; watchdog_reload(); /* Wait for system reset. */ while (1) asm("wfi"); }
int flash_physical_erase(int offset, int size) { /* check protection */ if (all_protected) return EC_ERROR_ACCESS_DENIED; /* Disable tri-state */ TRISTATE_FLASH(0); /* Alignment has been checked in upper layer */ for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, offset += CONFIG_FLASH_ERASE_SIZE) { /* Do nothing if already erased */ if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE)) continue; /* check protection */ if (flash_check_prot_range(offset, CONFIG_FLASH_ERASE_SIZE)) return EC_ERROR_ACCESS_DENIED; /* * Reload the watchdog timer, so that erasing many flash pages * doesn't cause a watchdog reset. May not need this now that * we're using msleep() below. */ watchdog_reload(); /* Enable write */ flash_write_enable(); /* Set erase address */ flash_set_address(offset); /* Start erase */ flash_execute_cmd(CMD_SECTOR_ERASE, MASK_CMD_ADR); /* Wait erase completed */ flash_wait_ready(); } /* Enable tri-state */ TRISTATE_FLASH(1); return EC_SUCCESS; }
void cts_task(void) { enum cts_rc rc; int i; for (i = 0; i < CTS_TEST_ID_COUNT; i++) { sync(); rc = tests[i].run(); CPRINTF("\n%s %d\n", tests[i].name, rc); cflush(); } CPRINTS("Timer test suite finished"); cflush(); while (1) { watchdog_reload(); sleep(1); } }
void cts_task(void) { enum cts_rc result; int i; uart_flush_output(); for (i = 0; i < CTS_TEST_ID_COUNT; i++) { sync(); result = tests[i].run(); CPRINTF("\n%s %d\n", tests[i].name, result); uart_flush_output(); } CPRINTS("GPIO test suite finished"); uart_flush_output(); while (1) { watchdog_reload(); sleep(1); } }
void cts_task(void) { enum cts_rc rc; int i; gpio_set_flags(GPIO_OUTPUT_TEST, GPIO_ODR_HIGH); for (i = 0; i < CTS_TEST_ID_COUNT; i++) { gpio_set_level(GPIO_OUTPUT_TEST, 1); gpio_set_level(GPIO_CTS_IRQ2, 1); sync(); rc = tests[i].run(); CPRINTF("\n%s %d\n", tests[i].name, rc); cflush(); } CPRINTS("Interrupt test suite finished"); cflush(); while (1) { watchdog_reload(); sleep(1); } }
int flash_physical_erase(int offset, int size) { int res = EC_SUCCESS; if (unlock(PRG_LOCK) != EC_SUCCESS) return EC_ERROR_UNKNOWN; /* Clear previous error status */ STM32_FLASH_SR = 0x34; /* set PER bit */ STM32_FLASH_CR |= PER; for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, offset += CONFIG_FLASH_ERASE_SIZE) { timestamp_t deadline; /* Do nothing if already erased */ if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE)) continue; /* select page to erase */ STM32_FLASH_AR = CONFIG_PROGRAM_MEMORY_BASE + offset; /* set STRT bit : start erase */ STM32_FLASH_CR |= STRT; /* * Reload the watchdog timer to avoid watchdog reset during a * long erase operation. */ watchdog_reload(); deadline.val = get_time().val + FLASH_TIMEOUT_US; /* Wait for erase to complete */ while ((STM32_FLASH_SR & 1) && (get_time().val < deadline.val)) { usleep(300); } if (STM32_FLASH_SR & 1) { res = EC_ERROR_TIMEOUT; goto exit_er; } /* * Check for error conditions - erase failed, voltage error, * protection error */ if (STM32_FLASH_SR & 0x14) { res = EC_ERROR_UNKNOWN; goto exit_er; } } exit_er: /* reset PER bit */ STM32_FLASH_CR &= ~PER; lock(); return res; }
int flash_physical_erase(int offset, int size) { uint32_t *address; int res = EC_SUCCESS; res = unlock(STM32_FLASH_PECR_PRG_LOCK); if (res) return res; /* Clear previous error status */ STM32_FLASH_SR = 0xf00; /* Set PROG and ERASE bits */ STM32_FLASH_PECR |= STM32_FLASH_PECR_PROG | STM32_FLASH_PECR_ERASE; for (address = (uint32_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset); size > 0; size -= CONFIG_FLASH_ERASE_SIZE, address += CONFIG_FLASH_ERASE_SIZE / sizeof(uint32_t)) { timestamp_t deadline; /* Do nothing if already erased */ if (flash_is_erased((uint32_t)address - CONFIG_PROGRAM_MEMORY_BASE, CONFIG_FLASH_ERASE_SIZE)) continue; /* Start erase */ *address = 0x00000000; /* * Reload the watchdog timer to avoid watchdog reset during * multi-page erase operations. */ watchdog_reload(); deadline.val = get_time().val + FLASH_TIMEOUT_MS * MSEC; /* Wait for erase to complete */ while ((STM32_FLASH_SR & 1) && (get_time().val < deadline.val)) { usleep(300); } if (STM32_FLASH_SR & 1) { res = EC_ERROR_TIMEOUT; goto exit_er; } /* * Check for error conditions: erase failed, voltage error, * protection error */ if (STM32_FLASH_SR & 0xF00) { res = EC_ERROR_UNKNOWN; goto exit_er; } } exit_er: /* Disable program and erase, and relock PECR */ STM32_FLASH_PECR &= ~(STM32_FLASH_PECR_PROG | STM32_FLASH_PECR_ERASE); lock(); return res; }
int flash_physical_write(int offset, int size, const char *data) { uint32_t *data32 = (uint32_t *)data; uint32_t *address = (uint32_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset); int res = EC_SUCCESS; int word_mode = 0; int i; /* Fail if offset, size, and data aren't at least word-aligned */ if ((offset | size | (uint32_t)(uintptr_t)data) & 3) return EC_ERROR_INVAL; /* Unlock program area */ res = unlock(STM32_FLASH_PECR_PRG_LOCK); if (res) goto exit_wr; /* Clear previous error status */ STM32_FLASH_SR = 0xf00; /* * If offset and size aren't on word boundaries, do word writes. This * is slower, but since we claim to the outside world that writes must * be half-page size, the only code which hits this path is writing * pstate (which is just writing one word). */ if ((offset | size) & (CONFIG_FLASH_WRITE_SIZE - 1)) word_mode = 1; /* Update flash timeout based on current clock speed */ flash_timeout_loop = FLASH_TIMEOUT_MS * (clock_get_freq() / MSEC) / CYCLE_PER_FLASH_LOOP; while (size > 0) { /* * Reload the watchdog timer to avoid watchdog reset when doing * long writing with interrupt disabled. */ watchdog_reload(); if (word_mode) { /* Word write */ *address++ = *data32++; /* Wait for writes to complete */ for (i = 0; ((STM32_FLASH_SR & 9) != 8) && (i < flash_timeout_loop); i++) ; size -= sizeof(uint32_t); } else { /* Half page write */ interrupt_disable(); iram_flash_write(address, data32); interrupt_enable(); address += CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t); data32 += CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t); size -= CONFIG_FLASH_WRITE_SIZE; } if (STM32_FLASH_SR & 1) { res = EC_ERROR_TIMEOUT; goto exit_wr; } /* * Check for error conditions: erase failed, voltage error, * protection error */ if (STM32_FLASH_SR & 0xf00) { res = EC_ERROR_UNKNOWN; goto exit_wr; } } exit_wr: /* Relock program lock */ lock(); return res; }
static int do_flash_op(enum flash_op op, int is_info_bank, int byte_offset, int words) { volatile uint32_t *fsh_pe_control; uint32_t opcode, tmp, errors; int retry_count, max_attempts, extra_prog_pulse, i; int timedelay_us = 100; uint32_t prev_error = 0; /* Make sure the smart program/erase algorithms are enabled. */ if (!GREAD(FLASH, FSH_TIMING_PROG_SMART_ALGO_ON) || !GREAD(FLASH, FSH_TIMING_ERASE_SMART_ALGO_ON)) { CPRINTF("%s:%d\n", __func__, __LINE__); return EC_ERROR_UNIMPLEMENTED; } /* Error status is self-clearing. Read it until it does (we hope). */ for (i = 0; i < 50; i++) { tmp = GREAD(FLASH, FSH_ERROR); if (!tmp) break; usleep(timedelay_us); } /* If we can't clear the error status register then something is wrong. */ if (tmp) { CPRINTF("%s:%d\n", __func__, __LINE__); return EC_ERROR_UNKNOWN; } /* We have two flash banks. Adjust offset and registers accordingly. */ if (is_info_bank) { /* Only INFO bank operations are supported. */ fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL1); } else if (byte_offset >= CFG_FLASH_HALF) { byte_offset -= CFG_FLASH_HALF; fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL1); } else { fsh_pe_control = GREG32_ADDR(FLASH, FSH_PE_CONTROL0); } /* What are we doing? */ switch (op) { case OP_ERASE_BLOCK: if (is_info_bank) /* Erasing the INFO bank from the RW section is * unsupported. */ return EC_ERROR_INVAL; opcode = 0x31415927; words = 0; /* don't care, really */ /* This number is based on the TSMC spec Nme=Terase/Tsme */ max_attempts = 45; break; case OP_WRITE_BLOCK: opcode = 0x27182818; words--; /* count register is zero-based */ /* This number is based on the TSMC spec Nmp=Tprog/Tsmp */ max_attempts = 9; break; case OP_READ_BLOCK: if (!is_info_bank) /* This code path only supports reading from * the INFO bank. */ return EC_ERROR_INVAL; opcode = 0x16021765; words = 1; max_attempts = 9; break; default: return EC_ERROR_INVAL; } /* * Set the parameters. For writes, we assume the write buffer is * already filled before we call this function. */ GWRITE_FIELD(FLASH, FSH_TRANS, OFFSET, byte_offset / 4); /* word offset */ GWRITE_FIELD(FLASH, FSH_TRANS, MAINB, is_info_bank ? 1 : 0); GWRITE_FIELD(FLASH, FSH_TRANS, SIZE, words); /* TODO: Make sure this function isn't getting called "too often" in * between erases. */ extra_prog_pulse = 0; for (retry_count = 0; retry_count < max_attempts; retry_count++) { /* Kick it off */ GWRITE(FLASH, FSH_PE_EN, 0xb11924e1); *fsh_pe_control = opcode; /* Wait for completion. 150ms should be enough * (crosbug.com/p/45366). */ for (i = 0; i < 1500; i++) { tmp = *fsh_pe_control; if (!tmp) break; usleep(timedelay_us); } /* Timed out waiting for control register to clear */ if (tmp) { CPRINTF("%s:%d\n", __func__, __LINE__); return EC_ERROR_UNKNOWN; } /* Check error status */ errors = GREAD(FLASH, FSH_ERROR); if (errors && (errors != prev_error)) { prev_error = errors; CPRINTF("%s:%d errors %x fsh_pe_control %p\n", __func__, __LINE__, errors, fsh_pe_control); } /* Error status is self-clearing. Read it until it does * (we hope). */ for (i = 0; i < 50; i++) { tmp = GREAD(FLASH, FSH_ERROR); if (!tmp) break; usleep(timedelay_us); } /* If we can't clear the error status register then something * is wrong. */ if (tmp) { CPRINTF("%s:%d\n", __func__, __LINE__); return EC_ERROR_UNKNOWN; } /* The operation was successful. */ if (!errors) { /* From the spec: * "In addition, one more program pulse is needed after * program verification is passed." */ if (op == OP_WRITE_BLOCK && !extra_prog_pulse) { extra_prog_pulse = 1; max_attempts++; continue; } return EC_SUCCESS; } /* If there were errors after completion retry. */ watchdog_reload(); } CPRINTF("%s:%d, retry count %d\n", __func__, __LINE__, retry_count); return EC_ERROR_UNKNOWN; }
static int command_sps(int argc, char **argv) { int count = 0; int target = 10; /* Expect 10 frames by default.*/ char *e; sps_tx_status(GC_SPS_DUMMY_WORD_DEFAULT); rx_state = spstrx_not_started; sps_register_rx_handler(SPS_GENERIC_MODE, sps_receive_callback); if (argc > 1) { target = strtoi(argv[1], &e, 10); if (*e) return EC_ERROR_PARAM1; } while (count++ < target) { size_t transmitted; size_t to_go; size_t index; /* Wait for a frame to be received.*/ while (rx_state != spstrx_finished) { watchdog_reload(); usleep(10); } /* Transmit the frame back to the host.*/ index = frame_base; to_go = frame_index - frame_base; do { if ((index == frame_base) && (to_go > 8)) { /* * This is the first transmit attempt for this * frame. Send a little just to prime the * transmit FIFO. */ transmitted = sps_transmit (test_frame + index, 8); } else { transmitted = sps_transmit (test_frame + index, to_go); } index += transmitted; to_go -= transmitted; } while (to_go); /* * Wait for receive state machine to transition out of 'frame * finised' state. */ while (rx_state == spstrx_finished) { watchdog_reload(); usleep(10); } } sps_unregister_rx_handler(); ccprintf("Processed %d frames\n", count - 1); ccprintf("rx count %d, tx count %d, tx_empty %d, max rx batch %d\n", sps_rx_count, sps_tx_count, tx_empty_count, max_rx_batch); sps_rx_count = sps_tx_count = tx_empty_count = max_rx_batch = 0; return EC_SUCCESS; }