Exemple #1
0
/* Process the command in the i2c host buffer */
static void i2c_process_command(void)
{
	char *buff = host_buffer;

	/*
	 * TODO(crosbug.com/p/29241): Combine this functionality with the
	 * i2c_process_command function in chip/stm32/i2c-stm32f.c to make one
	 * host command i2c process function which handles all protocol
	 * versions.
	 */
	i2c_packet.send_response = i2c_send_response_packet;

	i2c_packet.request = (const void *)(&buff[1]);
	i2c_packet.request_temp = params_copy;
	i2c_packet.request_max = sizeof(params_copy);
	/* Don't know the request size so pass in the entire buffer */
	i2c_packet.request_size = I2C_MAX_HOST_PACKET_SIZE;

	/*
	 * Stuff response at buff[2] to leave the first two bytes of
	 * buffer available for the result and size to send over i2c.
	 */
	i2c_packet.response = (void *)(&buff[2]);
	i2c_packet.response_max = I2C_MAX_HOST_PACKET_SIZE;
	i2c_packet.response_size = 0;

	if (*buff >= EC_COMMAND_PROTOCOL_3) {
		i2c_packet.driver_result = EC_RES_SUCCESS;
	} else {
		/* Only host command protocol 3 is supported. */
		i2c_packet.driver_result = EC_RES_INVALID_HEADER;
	}
	host_packet_receive(&i2c_packet);
}
Exemple #2
0
/* Task that listens for incomming IPC messages from Host and initiate host
 * command processing.
 */
void ipc_comm_task(void)
{
	int ret = 0;
	uint32_t out_drbl, pkt_len;

	for (;;) {

		ret = task_wait_event_mask(EVENT_FLAG_BIT_READ_IPC
					   | EVENT_FLAG_BIT_WRITE_IPC, -1);

		if ((ret & EVENT_FLAG_BIT_WRITE_IPC))
			continue;
		else if (!(ret & EVENT_FLAG_BIT_READ_IPC))
			continue;

		/* Read the command byte.  This clears the FRMH bit in
		 * the status byte.
		 */
		out_drbl = REG32(IPC_HOST2ISH_DOORBELL);
		pkt_len = out_drbl & IPC_HEADER_LENGTH_MASK;

		ret = ipc_read(IPC_PEER_HOST_ID, ipc_host_args, pkt_len);
		host_cmd_args.command = EC_COMMAND_PROTOCOL_3;

		host_cmd_args.result = EC_RES_SUCCESS;
		host_cmd_flags = ipc_host_args->flags;

		/* We only support new style command (v3) now */
		if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
			ipc_packet.send_response = ipc_send_response_packet;

			ipc_packet.request =
			    (const void *)ipc_get_hostcmd_data_range();
			ipc_packet.request_temp = params_copy;
			ipc_packet.request_max = sizeof(params_copy);
			/* Don't know the request size so pass in
			 * the entire buffer
			 */
			ipc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;

			ipc_packet.response =
			    (void *)ipc_get_hostcmd_data_range();
			ipc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
			ipc_packet.response_size = 0;

			ipc_packet.driver_result = EC_RES_SUCCESS;
			host_packet_receive(&ipc_packet);
			usleep(10);	/* To force yield */

			continue;
		} else {
			/* Old style command unsupported */
			host_cmd_args.result = EC_RES_INVALID_COMMAND;
		}

		/* Hand off to host command handler */
		host_command_received(&host_cmd_args);
	}
}
Exemple #3
0
void acpi_1_interrupt(void)
{
	uint8_t st = MEC1322_ACPI_EC_STATUS(1);
	if (!(st & EC_LPC_STATUS_FROM_HOST) ||
	    !(st & EC_LPC_STATUS_LAST_CMD))
		return;

	/* Set the busy bit */
	MEC1322_ACPI_EC_STATUS(1) |= EC_LPC_STATUS_PROCESSING;

	/*
	 * Read the command byte.  This clears the FRMH bit in
	 * the status byte.
	 */
	host_cmd_args.command = MEC1322_ACPI_EC_OS2EC(1, 0);

	host_cmd_args.result = EC_RES_SUCCESS;
	host_cmd_flags = lpc_host_args->flags;

	/* We only support new style command (v3) now */
	if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
		lpc_packet.send_response = lpc_send_response_packet;

		lpc_packet.request = (const void *)lpc_get_hostcmd_data_range();
		lpc_packet.request_temp = params_copy;
		lpc_packet.request_max = sizeof(params_copy);
		/* Don't know the request size so pass in the entire buffer */
		lpc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;

		lpc_packet.response = (void *)lpc_get_hostcmd_data_range();
		lpc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
		lpc_packet.response_size = 0;

		lpc_packet.driver_result = EC_RES_SUCCESS;
		host_packet_receive(&lpc_packet);
		return;
	} else {
		/* Old style command unsupported */
		host_cmd_args.result = EC_RES_INVALID_COMMAND;
	}

	/* Hand off to host command handler */
	host_command_received(&host_cmd_args);
}
Exemple #4
0
/**
 * Handle write to host command I/O ports.
 *
 * @param is_cmd	Is write command (1) or data (0)?
 */
static void handle_host_write(int is_cmd)
{
	/* Set processing flag before reading command byte */
	SET_BIT(NPCX_HIPMST(PMC_HOST_CMD), 2);
	/*
	 * Read the command byte.  This clears the FRMH bit in
	 * the status byte.
	 */
	host_cmd_args.command = NPCX_HIPMDI(PMC_HOST_CMD);

	host_cmd_args.result = EC_RES_SUCCESS;
	host_cmd_args.send_response = lpc_send_response;
	host_cmd_flags = lpc_host_args->flags;

	/* See if we have an old or new style command */
	if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
		lpc_packet.send_response = lpc_send_response_packet;

		lpc_packet.request = (const void *)shm_mem_host_cmd;
		lpc_packet.request_temp = params_copy;
		lpc_packet.request_max = sizeof(params_copy);
		/* Don't know the request size so pass in the entire buffer */
		lpc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;

		lpc_packet.response = (void *)shm_mem_host_cmd;
		lpc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
		lpc_packet.response_size = 0;

		lpc_packet.driver_result = EC_RES_SUCCESS;

		host_packet_receive(&lpc_packet);
		return;

	} else if (host_cmd_flags & EC_HOST_ARGS_FLAG_FROM_HOST) {
		/* Version 2 (link) style command */
		int size = lpc_host_args->data_size;
		int csum, i;

		/* Clear processing flag */
		CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), 2);

		host_cmd_args.version = lpc_host_args->command_version;
		host_cmd_args.params = params_copy;
		host_cmd_args.params_size = size;
		host_cmd_args.response = cmd_params;
		host_cmd_args.response_max = EC_PROTO2_MAX_PARAM_SIZE;
		host_cmd_args.response_size = 0;

		/* Verify params size */
		if (size > EC_PROTO2_MAX_PARAM_SIZE) {
			host_cmd_args.result = EC_RES_INVALID_PARAM;
		} else {
			const uint8_t *src = cmd_params;
			uint8_t *copy = params_copy;

			/*
			 * Verify checksum and copy params out of LPC space.
			 * This ensures the data acted on by the host command
			 * handler can't be changed by host writes after the
			 * checksum is verified.
			 */
			csum = host_cmd_args.command +
					host_cmd_flags +
					host_cmd_args.version +
					host_cmd_args.params_size;

			for (i = 0; i < size; i++) {
				csum += *src;
				*(copy++) = *(src++);
			}

			if ((uint8_t)csum != lpc_host_args->checksum)
				host_cmd_args.result = EC_RES_INVALID_CHECKSUM;
		}
	} else {
		/* Old style command, now unsupported */
		host_cmd_args.result = EC_RES_INVALID_COMMAND;
		/* Clear processing flag */
		CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), 2);
	}

	/* Hand off to host command handler */
	host_command_received(&host_cmd_args);
}
Exemple #5
0
void pm2_ibf_interrupt(void)
{
	uint8_t value __attribute__((unused)) = 0;
	uint8_t status;

	status = pm_get_status(LPC_HOST_CMD);
	/* IBE */
	if (!(status & EC_LPC_STATUS_FROM_HOST)) {
		task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
		return;
	}

	/* IBF and data port */
	if (!(status & EC_LPC_STATUS_LAST_CMD)) {
		/* R/C IBF*/
		value = pm_get_data_in(LPC_HOST_CMD);
		task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
		return;
	}

	/* Set the busy bit */
	pm_set_status(LPC_HOST_CMD, EC_LPC_STATUS_PROCESSING, 1);

	/*
	 * Read the command byte.  This clears the FRMH bit in
	 * the status byte.
	 */
	host_cmd_args.command = pm_get_data_in(LPC_HOST_CMD);

	host_cmd_args.result = EC_RES_SUCCESS;
	if (host_cmd_args.command != EC_COMMAND_PROTOCOL_3)
		host_cmd_args.send_response = lpc_send_response;
	host_cmd_flags = lpc_host_args->flags;

	/* We only support new style command (v3) now */
	if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
		lpc_packet.send_response = lpc_send_response_packet;

		lpc_packet.request = (const void *)host_cmd_memmap;
		lpc_packet.request_temp = params_copy;
		lpc_packet.request_max = sizeof(params_copy);
		/* Don't know the request size so pass in the entire buffer */
		lpc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;

		lpc_packet.response = (void *)host_cmd_memmap;
		lpc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
		lpc_packet.response_size = 0;

		lpc_packet.driver_result = EC_RES_SUCCESS;
		host_packet_receive(&lpc_packet);

		task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
		return;
	} else {
		/* Old style command, now unsupported */
		host_cmd_args.result = EC_RES_INVALID_COMMAND;
	}

	/* Hand off to host command handler */
	host_command_received(&host_cmd_args);

	task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
}
Exemple #6
0
/**
 * Handle an event on the NSS pin
 *
 * A falling edge of NSS indicates that the master is starting a new
 * transaction. A rising edge indicates that we have finsihed
 *
 * @param signal	GPIO signal for the NSS pin
 */
void spi_event(enum gpio_signal signal)
{
	stm32_dma_chan_t *rxdma;
	uint16_t *nss_reg;
	uint32_t nss_mask;
	uint16_t i;

	/* If not enabled, ignore glitches on NSS */
	if (!enabled)
		return;

	/* Check chip select.  If it's high, the AP ended a transaction. */
	nss_reg = gpio_get_level_reg(GPIO_SPI1_NSS, &nss_mask);
	if (REG16(nss_reg) & nss_mask) {
		enable_sleep(SLEEP_MASK_SPI);

		/*
		 * If the buffer is still used by the host command, postpone
		 * the DMA rx setup.
		 */
		if (state == SPI_STATE_PROCESSING) {
			setup_transaction_later = 1;
			return;
		}

		/* Set up for the next transaction */
		spi_init(); /* Fix for bug chrome-os-partner:31390 */
		return;
	}
	disable_sleep(SLEEP_MASK_SPI);

	/* Chip select is low = asserted */
	if (state != SPI_STATE_READY_TO_RX) {
		/*
		 * AP started a transaction but we weren't ready for it.
		 * Tell AP we weren't ready, and ignore the received data.
		 */
		CPRINTS("SPI not ready");
		tx_status(EC_SPI_NOT_READY);
		state = SPI_STATE_RX_BAD;
		return;
	}

	/* We're now inside a transaction */
	state = SPI_STATE_RECEIVING;
	tx_status(EC_SPI_RECEIVING);
	rxdma = dma_get_channel(STM32_DMAC_SPI1_RX);

	/* Wait for version, command, length bytes */
	if (wait_for_bytes(rxdma, 3, nss_reg, nss_mask))
		goto spi_event_error;

	if (in_msg[0] == EC_HOST_REQUEST_VERSION) {
		/* Protocol version 3 */
		struct ec_host_request *r = (struct ec_host_request *)in_msg;
		int pkt_size;

		/* Wait for the rest of the command header */
		if (wait_for_bytes(rxdma, sizeof(*r), nss_reg, nss_mask))
			goto spi_event_error;

		/*
		 * Check how big the packet should be.  We can't just wait to
		 * see how much data the host sends, because it will keep
		 * sending dummy data until we respond.
		 */
		pkt_size = host_request_expected_size(r);
		if (pkt_size == 0 || pkt_size > sizeof(in_msg))
			goto spi_event_error;

		/* Wait for the packet data */
		if (wait_for_bytes(rxdma, pkt_size, nss_reg, nss_mask))
			goto spi_event_error;

		spi_packet.send_response = spi_send_response_packet;

		spi_packet.request = in_msg;
		spi_packet.request_temp = NULL;
		spi_packet.request_max = sizeof(in_msg);
		spi_packet.request_size = pkt_size;

		/* Response must start with the preamble */
		memcpy(out_msg, out_preamble, sizeof(out_preamble));
		spi_packet.response = out_msg + sizeof(out_preamble);
		/* Reserve space for the preamble and trailing past-end byte */
		spi_packet.response_max = sizeof(out_msg)
			- sizeof(out_preamble) - EC_SPI_PAST_END_LENGTH;
		spi_packet.response_size = 0;

		spi_packet.driver_result = EC_RES_SUCCESS;

		/* Move to processing state */
		state = SPI_STATE_PROCESSING;
		tx_status(EC_SPI_PROCESSING);

		host_packet_receive(&spi_packet);
		return;

	} else if (in_msg[0] >= EC_CMD_VERSION0) {
		/*
		 * Protocol version 2
		 *
		 * TODO(crosbug.com/p/20257): Remove once kernel supports
		 * version 3.
		 */

#ifdef CHIP_FAMILY_STM32F0
		CPRINTS("WARNING: Protocol version 2 is not supported on the F0"
			" line due to crbug.com/31390");
#endif

		args.version = in_msg[0] - EC_CMD_VERSION0;
		args.command = in_msg[1];
		args.params_size = in_msg[2];

		/* Wait for parameters */
		if (wait_for_bytes(rxdma, 3 + args.params_size,
				   nss_reg, nss_mask))
			goto spi_event_error;

		/*
		 * Params are not 32-bit aligned in protocol version 2.  As a
		 * workaround, move them to the beginning of the input buffer
		 * so they are aligned.
		 */
		if (args.params_size)
			memmove(in_msg, in_msg + 3, args.params_size);

		args.params = in_msg;
		args.send_response = spi_send_response;

		/* Allow room for the header bytes */
		args.response = out_msg + SPI_PROTO2_OFFSET;
		args.response_max = sizeof(out_msg) - SPI_PROTO2_OVERHEAD;
		args.response_size = 0;
		args.result = EC_RES_SUCCESS;

		/* Move to processing state */
		state = SPI_STATE_PROCESSING;
		tx_status(EC_SPI_PROCESSING);

		host_command_received(&args);
		return;
	}

 spi_event_error:
	/* Error, timeout, or protocol we can't handle.  Ignore data. */
	tx_status(EC_SPI_RX_BAD_DATA);
	state = SPI_STATE_RX_BAD;
	CPRINTS("SPI rx bad data");

	CPRINTF("in_msg=[");
	for (i = 0; i < dma_bytes_done(rxdma, sizeof(in_msg)); i++)
		CPRINTF("%02x ", in_msg[i]);
	CPRINTF("]\n");
}