/* Set initial conditions to get ready to receive a command. */ static void init_new_cycle(void) { rxbuf_count = 0; rxbuf_needed = 4; sps_tpm_state = SPS_TPM_STATE_RECEIVING_HEADER; rx_fifo_base = sps_rx_fifo_wrptr(); sps_tx_status(TPM_STALL_ASSERT); /* We're just waiting for a new command, so we could sleep. */ delay_sleep_by(1 * SECOND); enable_sleep(SLEEP_MASK_SPI); }
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; }
/* actual RX FIFO handler (runs in interrupt context) */ static void process_rx_data(uint8_t *data, size_t data_size) { /* We're receiving some bytes, so don't sleep */ disable_sleep(SLEEP_MASK_SPI); if ((rxbuf_count + data_size) > RXBUF_MAX) { CPRINTS("TPM SPI input overflow: %d + %d > %d in state %d", rxbuf_count, data_size, RXBUF_MAX, sps_tpm_state); sps_tx_status(TPM_STALL_DEASSERT); sps_tpm_state = SPS_TPM_STATE_RX_BAD; /* In this state, this function won't be called again until * after the CS deasserts and we've prepared for a new * transaction. */ return; } memcpy(rxbuf + rxbuf_count, data, data_size); rxbuf_count += data_size; /* Wait until we have enough. */ if (rxbuf_count < rxbuf_needed) return; /* Okay, we have enough. Now what? */ if (sps_tpm_state == SPS_TPM_STATE_RECEIVING_HEADER) { uint32_t old_wrptr, wrptr; /* Got the header. What's it say to do? */ if (header_says_to_read(rxbuf, ®addr, &bytecount)) { /* Send the stall deassert manually */ txbuf[0] = TPM_STALL_DEASSERT; /* Copy the register contents into the TXFIFO */ /* TODO: This is blindly assuming TXFIFO has enough * room. What can we do if it doesn't? */ tpm_register_get(regaddr - TPM_LOCALITY_0_SPI_BASE, txbuf + 1, bytecount); sps_transmit(txbuf, bytecount + 1); sps_tpm_state = SPS_TPM_STATE_PONDERING; return; } /* * Master is writing, we will need more data. * * This is a tricky part, as we do not know how many dummy * bytes the master has already written. And the actual data * of course will start arriving only after we change the idle * byte to set the LSB to 1. * * What we do know is that the idle byte repeatedly sent on * the MISO line is sampled at the same time as the RX FIFO * write pointer is written by the chip, after clocking in the * next byte. That is, we can synchronize with the line by * waiting for the RX FIFO write pointer to change. Then we * can change the idle byte to indicate that the slave is * ready to receive the rest of the data, and take note of the * RX FIFO write pointer, as the first byte of the message * will show up in the receive FIFO 2 bytes later. */ /* * Let's wait til the start of the next byte cycle. This must * be done in a tight loop (with interrupts disabled?). */ old_wrptr = sps_rx_fifo_wrptr(); do { wrptr = sps_rx_fifo_wrptr(); } while (old_wrptr == wrptr); /* * Write the new idle byte value, it will start transmitting * *next* after the current byte. */ sps_tx_status(TPM_STALL_DEASSERT); /* * Verify that we managed to change the idle byte value within * the required time (RX FIFO write pointer has not changed) */ if (sps_rx_fifo_wrptr() != wrptr) { CPRINTS("%s:" " ERROR: failed to change idle byte in time", __func__); sps_tpm_state = SPS_TPM_STATE_PONDERING; } else { /* * Ok, we're good. Remember where in the receive * stream the actual data will start showing up. It is * two bytes after the current one (the current idle * byte still has the LSB set to zero, the next one * will have the LSB set to one, only after receiving * it the master will start sending the actual data. */ stall_threshold = ((wrptr - rx_fifo_base) & SPS_FIFO_MASK) + 2; rxbuf_needed = stall_threshold + bytecount; sps_tpm_state = SPS_TPM_STATE_RECEIVING_WRITE_DATA; } return; } if (sps_tpm_state == SPS_TPM_STATE_RECEIVING_WRITE_DATA) { /* Ok, we have all the write data. */ tpm_register_put(regaddr - TPM_LOCALITY_0_SPI_BASE, rxbuf + stall_threshold, bytecount); sps_tpm_state = SPS_TPM_STATE_PONDERING; } }