Exemplo n.º 1
0
int spi_slave_send_response_async(struct spi_comm_packet *resp)
{
	int size = resp->size + SPI_PACKET_HEADER_SIZE;
	stm32_spi_regs_t *spi = STM32_SPI1_REGS;

	if (size > SPI_PACKET_MAX_SIZE)
		return EC_ERROR_OVERFLOW;

	if (out_msg != (uint8_t *)resp)
		memcpy(out_msg, resp, size);

	master_slave_sync(100);

	if (spi->sr & STM32_SPI_SR_RXNE)
		in_msg[0] = spi->dr;
	spi->dr = out_msg[0];

	/* Set N_CHG (master SPI_NSS) to high */
	STM32_GPIO_BSRR(GPIO_A) = 1 << 1;

	while (!(spi->sr & STM32_SPI_SR_RXNE))
		;
	in_msg[0] = spi->dr;

	dma_clear_isr(STM32_DMAC_SPI1_TX);
	dma_clear_isr(STM32_DMAC_SPI1_RX);
	dma_start_rx(&dma_rx_option, size - 1, in_msg);
	dma_prepare_tx(&dma_tx_option, size - 1, out_msg + 1);
	dma_go(dma_get_channel(STM32_DMAC_SPI1_TX));

	master_slave_sync(5);

	return EC_SUCCESS;
}
Exemplo n.º 2
0
static int spi_master_read_write_byte(uint8_t *in_buf, uint8_t *out_buf, int sz)
{
	int ret;

	dma_start_rx(&dma_rx_option, sz, in_buf);
	dma_prepare_tx(&dma_tx_option, sz, out_buf);
	dma_go(dma_get_channel(STM32_DMAC_SPI1_TX));
	ret = dma_wait(STM32_DMAC_SPI1_TX);
	ret |= dma_wait(STM32_DMAC_SPI1_RX);

	dma_disable(STM32_DMAC_SPI1_TX);
	dma_disable(STM32_DMAC_SPI1_RX);
	dma_clear_isr(STM32_DMAC_SPI1_TX);
	dma_clear_isr(STM32_DMAC_SPI1_RX);

	return ret;
}
Exemplo n.º 3
0
static void spi_nss_interrupt(void)
{
	const struct spi_comm_packet *cmd =
		(const struct spi_comm_packet *)in_msg;
	stm32_spi_regs_t *spi = STM32_SPI1_REGS;

	if (spi->sr & STM32_SPI_SR_RXNE)
		in_msg[0] = spi->dr;

	master_slave_sync(5);

	/* Read in the packet size */
	while (!(spi->sr & STM32_SPI_SR_RXNE))
		;
	in_msg[0] = spi->dr;

	/* Read in the rest of the packet */
	dma_clear_isr(STM32_DMAC_SPI1_RX);
	dma_start_rx(&dma_rx_option, in_msg[0] + SPI_PACKET_HEADER_SIZE - 1,
		     in_msg + 1);
	dma_prepare_tx(&dma_tx_option, in_msg[0] + SPI_PACKET_HEADER_SIZE - 1,
		       out_msg);
	dma_go(dma_get_channel(STM32_DMAC_SPI1_TX));

	master_slave_sync(5);

	if (dma_wait(STM32_DMAC_SPI1_RX) != EC_SUCCESS) {
		debug_printf("SPI: Incomplete packet\n");
		spi_slave_nack();
		return;
	}
	if (spi->sr & STM32_SPI_SR_CRCERR) {
		debug_printf("SPI: CRC mismatch\n");
		spi_slave_nack();
		return;
	}

	if (cmd->cmd_sts == TS_CMD_HELLO)
		spi_slave_hello_back(cmd);
	else if (cmd->cmd_sts == TS_CMD_FULL_SCAN)
		touch_scan_slave_start();
	else
		spi_slave_nack();
}
Exemplo n.º 4
0
static int i2c_write_raw_slave(int port, void *buf, int len)
{
	stm32_dma_chan_t *chan;
	int rv;

	/* we don't want to race with TxE interrupt event */
	disable_i2c_interrupt(port);

	/* Configuring DMA1 channel DMAC_SLAVE_TX */
	enable_ack(port);
	chan = dma_get_channel(DMAC_SLAVE_TX);
	dma_prepare_tx(dma_tx_option + port, len, buf);

	/* Start the DMA */
	dma_go(chan);

	/* Configuring i2c to use DMA */
	STM32_I2C_CR2(port) |= (1 << 11);

	if (in_interrupt_context()) {
		/* Poll for the transmission complete flag */
		dma_wait(DMAC_SLAVE_TX);
		dma_clear_isr(DMAC_SLAVE_TX);
	} else {
		/* Wait for the transmission complete Interrupt */
		dma_enable_tc_interrupt(DMAC_SLAVE_TX);
		rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US);
		dma_disable_tc_interrupt(DMAC_SLAVE_TX);

		if (!(rv & TASK_EVENT_WAKE)) {
			CPRINTS("Slave timeout, resetting i2c");
			i2c_init_port(port);
		}
	}

	dma_disable(DMAC_SLAVE_TX);
	STM32_I2C_CR2(port) &= ~(1 << 11);

	enable_i2c_interrupt(port);

	return len;
}
Exemplo n.º 5
0
Arquivo: spi.c Projeto: longsleep/ec
/**
 * Called to send a response back to the host.
 *
 * Some commands can continue for a while. This function is called by
 * host_command when it completes.
 *
 */
static void spi_send_response_packet(struct host_packet *pkt)
{
	stm32_dma_chan_t *txdma;

	/*
	 * If we're not processing, then the AP has already terminated the
	 * transaction, and won't be listening for a response.
	 */
	if (state != SPI_STATE_PROCESSING)
		return;

	/* state == SPI_STATE_PROCESSING */

	/* Append our past-end byte, which we reserved space for. */
	((uint8_t *)pkt->response)[pkt->response_size + 0] = EC_SPI_PAST_END;
#ifdef CHIP_FAMILY_STM32F0
	/* Make sure we are going to be outputting it properly when the DMA
	 * ends due to the TX FIFO bug on the F0. See crbug.com/31390
	 */
	((uint8_t *)pkt->response)[pkt->response_size + 1] = EC_SPI_PAST_END;
	((uint8_t *)pkt->response)[pkt->response_size + 2] = EC_SPI_PAST_END;
	((uint8_t *)pkt->response)[pkt->response_size + 3] = EC_SPI_PAST_END;
#endif

	/* Transmit the reply */
	txdma = dma_get_channel(STM32_DMAC_SPI1_TX);
	dma_prepare_tx(&dma_tx_option, sizeof(out_preamble) + pkt->response_size
		+ EC_SPI_PAST_END_LENGTH, out_msg);
	dma_go(txdma);

	/*
	 * Before the state is set to SENDING, any CS de-assertion would
	 * set setup_transaction_later to 1.
	 */
	state = SPI_STATE_SENDING;
	check_setup_transaction_later();
}
Exemplo n.º 6
0
int spi_master_wait_response_async(void)
{
	stm32_spi_regs_t *spi = STM32_SPI1_REGS;
	int size;

	master_slave_sync(40);
	if (wait_for_signal(GPIO_A, 1 << 0, 1, 40 * MSEC))
		goto err_wait_resp_async;

	/* Discard potential garbage in SPI DR */
	if (spi->sr & STM32_SPI_SR_RXNE)
		in_msg[0] = spi->dr;

	/* Get the packet size */
	spi->dr = DUMMY_DATA;
	while (!(spi->sr & STM32_SPI_SR_RXNE))
		;
	in_msg[0] = spi->dr;
	size = in_msg[0] + SPI_PACKET_HEADER_SIZE;

	master_slave_sync(5);

	dma_clear_isr(STM32_DMAC_SPI1_TX);
	dma_clear_isr(STM32_DMAC_SPI1_RX);

	/* Get the rest of the packet*/
	dma_start_rx(&dma_rx_option, size - 1, in_msg + 1);
	dma_prepare_tx(&dma_tx_option, size - 1, out_msg);
	dma_go(dma_get_channel(STM32_DMAC_SPI1_TX));

	return EC_SUCCESS;
err_wait_resp_async:
	/* Set CS1 (slave SPI_NSS) to high */
	STM32_GPIO_BSRR(GPIO_A) = 1 << 6;
	return EC_ERROR_TIMEOUT;
}
Exemplo n.º 7
0
Arquivo: spi.c Projeto: longsleep/ec
/**
 * Send a reply on a given port.
 *
 * The format of a reply is as per the command interface, with a number of
 * preamble bytes before it.
 *
 * The format of a reply is a sequence of bytes:
 *
 * <hdr> <status> <len> <msg bytes> <sum> [<preamble byte>...]
 *
 * The hdr byte is just a tag to indicate that the real message follows. It
 * signals the end of any preamble required by the interface.
 *
 * The length is the entire packet size, including the header, length bytes,
 * message payload, checksum, and postamble byte.
 *
 * The preamble is at least 2 bytes, but can be longer if the STM takes ages
 * to react to the incoming message. Since we send our first byte as the AP
 * sends us the command, we clearly can't send anything sensible for that
 * byte. The second byte must be written to the output register just when the
 * command byte is ready (I think), so we can't do anything there either.
 * Any processing we do may increase this delay. That's the reason for the
 * preamble.
 *
 * It is interesting to note that it seems to be possible to run the SPI
 * interface faster than the CPU clock with this approach.
 *
 * We keep an eye on the NSS line - if this goes high then the transaction is
 * over so there is no point in trying to send the reply.
 *
 * @param txdma		TX DMA channel to send on
 * @param status	Status result to send
 * @param msg_ptr	Message payload to send, which normally starts
 *			SPI_PROTO2_OFFSET bytes into out_msg
 * @param msg_len	Number of message bytes to send
 */
static void reply(stm32_dma_chan_t *txdma,
		  enum ec_status status, char *msg_ptr, int msg_len)
{
	char *msg = out_msg;
	int need_copy = msg_ptr != msg + SPI_PROTO2_OFFSET;
	int sum, i;

	ASSERT(msg_len + SPI_PROTO2_OVERHEAD <= sizeof(out_msg));

	/* Add our header bytes - the first one might not actually be sent */
	msg[0] = EC_SPI_PROCESSING;
	msg[1] = EC_SPI_FRAME_START;
	msg[2] = status;
	msg[3] = msg_len & 0xff;

	/*
	 * Calculate the checksum; includes the status and message length bytes
	 * but not the pad and framing bytes since those are stripped by the AP
	 * driver.
	 */
	sum = status + msg_len;
	for (i = 0; i < msg_len; i++) {
		int ch = msg_ptr[i];
		sum += ch;
		if (need_copy)
			msg[i + SPI_PROTO2_OFFSET] = ch;
	}

	/* Add the checksum and get ready to send */
	msg[SPI_PROTO2_OFFSET + msg_len] = sum & 0xff;
	msg[SPI_PROTO2_OFFSET + msg_len + 1] = EC_SPI_PAST_END;
	dma_prepare_tx(&dma_tx_option, msg_len + SPI_PROTO2_OVERHEAD, msg);

	/* Kick off the DMA to send the data */
	dma_go(txdma);
}