コード例 #1
0
ファイル: sps_tpm.c プロジェクト: coreboot/chrome-ec
/* 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);
}
コード例 #2
0
ファイル: sps.c プロジェクト: fourier49/BZ_DEV_EC
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;
}
コード例 #3
0
ファイル: sps_tpm.c プロジェクト: coreboot/chrome-ec
/* 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, &regaddr, &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;
	}
}