[coreboot-gerrit] Change in coreboot[master]: ec/google/wilco: Add Wilco EC mailbox interface

Duncan Laurie (Code Review) gerrit at coreboot.org
Tue Oct 16 00:54:32 CEST 2018


Duncan Laurie has uploaded this change for review. ( https://review.coreboot.org/29113


Change subject: ec/google/wilco: Add Wilco EC mailbox interface
......................................................................

ec/google/wilco: Add Wilco EC mailbox interface

The Google "Wilco" Embedded Controller is a new embedded controller that
will be used in some future devices.  The mailbox interface is simliar
to the existing Chromium EC protocol version 3, but not close enough
that it was convenient to re-use the full Chrome EC driver.

This commit adds the basic mailbox interface for ramstage which will be
used by future commits to send varous mailbox commands during the boot
process.  The IO base addresses for the mailbox interface are defined in
Kconfig so they can be changed by the mainboard if needed.

Change-Id: I8520dadfa982c9d14357cf2aa644e255cef425c2
Signed-off-by: Duncan Laurie <dlaurie at google.com>
---
A src/ec/google/wilco/Kconfig
A src/ec/google/wilco/Makefile.inc
A src/ec/google/wilco/ec.h
A src/ec/google/wilco/mailbox.c
4 files changed, 352 insertions(+), 0 deletions(-)



  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/13/29113/1

diff --git a/src/ec/google/wilco/Kconfig b/src/ec/google/wilco/Kconfig
new file mode 100644
index 0000000..e905d5e
--- /dev/null
+++ b/src/ec/google/wilco/Kconfig
@@ -0,0 +1,47 @@
+config EC_GOOGLE_WILCO
+	bool
+	default n
+	select EC_GOOGLE_COMMON_MEC
+	help
+	  Google Wilco Embedded Controller interface.
+
+config EC_BASE_ACPI_DATA
+	hex
+	default 0x930
+	help
+	  This option provides the 16-bit IO base address for the ACPI
+	  data interface.  This is the standard ACPI EC interface that
+	  is used by the ACPI EC drivers in the OS.
+
+config EC_BASE_ACPI_COMMAND
+	hex
+	default 0x934
+	help
+	  This option provides the 16-bit IO base address for the ACPI
+	  EC command interface.  This is the standard ACPI EC interface
+	  that is used by the ACPI EC drivers in the OS.
+
+config EC_BASE_HOST_DATA
+	hex
+	default 0x940
+	help
+	  This option provides the 16-bit IO base address for the host
+	  data interface.  This is the interface that is used to drive
+	  the mailbox protocol.
+
+config EC_BASE_HOST_COMMAND
+	hex
+	default 0x944
+	help
+	  This option provides the 16-bit IO base address for the host
+	  command interface.  This is the interface that is used to drive
+	  the mailbox protocol.
+
+config EC_BASE_PACKET
+	hex
+	default 0x950
+	help
+	  This option provides the 16-bit IO base address for the EC
+	  mailbox interface data region.  This data buffer is used along
+	  with the host command and data registers to drive the EC
+	  mailbox interface.  This is also the MEC EMI base address.
diff --git a/src/ec/google/wilco/Makefile.inc b/src/ec/google/wilco/Makefile.inc
new file mode 100644
index 0000000..6130f6f
--- /dev/null
+++ b/src/ec/google/wilco/Makefile.inc
@@ -0,0 +1,5 @@
+ifeq ($(CONFIG_EC_GOOGLE_WILCO),y)
+
+ramstage-y += mailbox.c
+
+endif
diff --git a/src/ec/google/wilco/ec.h b/src/ec/google/wilco/ec.h
new file mode 100644
index 0000000..7b58473
--- /dev/null
+++ b/src/ec/google/wilco/ec.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef EC_GOOGLE_WILCO_EC_H
+#define EC_GOOGLE_WILCO_EC_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* Maximum request or response data size */
+#define WILCO_EC_DATA_MAX		32
+
+/* Different supported message types */
+enum wilco_ec_msg_type {
+	WILCO_EC_MSG_RAW,		/* Raw message, do not skip any data */
+	WILCO_EC_MSG_DEFAULT,		/* Skip 1 byte of response data */
+	WILCO_EC_MSG_NO_RESPONSE,	/* EC does not respond to command */
+};
+
+/**
+ * wilco_ec_mailbox
+ *
+ * Send a command request to the EC mailbox and receive the response.
+ *
+ * @type:          Mailbox message type, see enum above
+ * @command:       Command to execute
+ * @request_data:  Request data buffer
+ * @request_size:  Number of bytes in request data buffer
+ * @response_data: Response data buffer
+ * @response_size: Number of bytes in response data buffer
+ *
+ * @return number of bytes received, negative error code on failure
+ */
+int wilco_ec_mailbox(enum wilco_ec_msg_type type, uint8_t command,
+		     const void *request_data, size_t request_size,
+		     void *response_data, size_t response_size);
+
+#endif /* EC_GOOGLE_WILCO_EC_H */
diff --git a/src/ec/google/wilco/mailbox.c b/src/ec/google/wilco/mailbox.c
new file mode 100644
index 0000000..c3f393a
--- /dev/null
+++ b/src/ec/google/wilco/mailbox.c
@@ -0,0 +1,250 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <delay.h>
+#include <ec/google/common/mec.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <timer.h>
+#include <types.h>
+
+#include "ec.h"
+
+/* Mailbox ID */
+#define EC_MAILBOX_ID			0x00f0
+
+/* Version of mailbox interface */
+#define EC_MAILBOX_VERSION		0
+
+/* Command to start mailbox transaction */
+#define EC_MAILBOX_START_COMMAND	0xda
+
+/* Version of EC protocol */
+#define EC_MAILBOX_PROTO_VERSION	3
+
+/* Max number of bytes in protocol data payload */
+#define EC_MAILBOX_DATA_SIZE		WILCO_EC_DATA_MAX
+
+/* Number of header bytes to be counted as data bytes */
+#define EC_MAILBOX_DATA_EXTRA		2
+
+/* Maximum timeout */
+#define EC_MAILBOX_TIMEOUT_US		USECS_PER_SEC
+
+/* EC response flags */
+#define EC_CMDR_DATA		BIT(0)	/* Data ready for host to read */
+#define EC_CMDR_PENDING		BIT(1)	/* Write pending to EC */
+#define EC_CMDR_BUSY		BIT(2)	/* EC is busy processing a command */
+#define EC_CMDR_CMD		BIT(3)	/* Last host write was a command */
+
+/* Request to EC */
+struct wilco_ec_request {
+	uint8_t struct_version;		/* version (=3) */
+	uint8_t checksum;		/* sum of all bytes must be 0 */
+	uint16_t mailbox_id;		/* mailbox identifier */
+	uint8_t mailbox_version;	/* mailbox version (=0) */
+	uint8_t reserved1;		/* unused (=0) */
+	uint16_t data_size;		/* length (data + 2 bytes of header) */
+	uint8_t command;		/* mailbox command */
+	uint8_t reserved2;		/* unused (=0) */
+} __packed;
+
+/* Response from EC */
+struct wilco_ec_response {
+	uint8_t struct_version;		/* version (=3) */
+	uint8_t checksum;		/* sum of all bytes must be 0 */
+	uint16_t result;		/* result code */
+	uint16_t data_size;		/* length of data after header */
+	uint8_t reserved[3];		/* unused (=0) */
+	uint8_t data[EC_MAILBOX_DATA_SIZE];
+} __packed;
+
+struct wilco_ec_message {
+	uint8_t command;		/* mailbox command code */
+	uint8_t result;			/* request result */
+	size_t request_size;		/* bytes to send to the EC */
+	size_t response_size;		/* bytes expected from the EC */
+	enum wilco_ec_msg_type type;	/* message type */
+	uint8_t data[EC_MAILBOX_DATA_SIZE];
+};
+
+static bool wilco_ec_response_timed_out(void)
+{
+	uint8_t mask = EC_CMDR_PENDING | EC_CMDR_BUSY;
+	uint32_t time_count = 0;
+
+	do {
+		if (!(inb(CONFIG_EC_BASE_HOST_COMMAND) & mask))
+			return false;
+		mdelay(1);
+	} while (time_count++ < EC_MAILBOX_TIMEOUT_US);
+
+	printk(BIOS_ERR, "%s: Command timeout\n", __func__);
+	return true;
+}
+
+static uint8_t wilco_ec_checksum(void *data, size_t size)
+{
+	uint8_t *data_bytes = (uint8_t *)data;
+	uint8_t checksum = 0;
+	size_t i;
+
+	for (i = 0; i < size; i++)
+		checksum += data_bytes[i];
+
+	return checksum;
+}
+
+static void wilco_ec_prepare(struct wilco_ec_message *msg,
+			     struct wilco_ec_request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+
+	/* Fill in request packet */
+	rq->struct_version = EC_MAILBOX_PROTO_VERSION;
+	rq->mailbox_id = EC_MAILBOX_ID;
+	rq->mailbox_version = EC_MAILBOX_VERSION;
+	rq->data_size = msg->request_size + EC_MAILBOX_DATA_EXTRA;
+	rq->command = msg->command;
+
+	/* Checksum header and data */
+	rq->checksum = wilco_ec_checksum(rq, sizeof(*rq));
+	rq->checksum += wilco_ec_checksum(msg->data, msg->request_size);
+	rq->checksum = -rq->checksum;
+}
+
+static int wilco_ec_transfer(struct wilco_ec_message *msg)
+{
+	struct wilco_ec_request rq;
+	struct wilco_ec_response rs;
+	uint8_t checksum;
+	size_t skip_size;
+
+	/* Prepare request packet */
+	wilco_ec_prepare(msg, &rq);
+
+	/* Write request header */
+	mec_io_bytes(MEC_IO_WRITE, CONFIG_EC_BASE_PACKET, 0, &rq, sizeof(rq));
+
+	/* Write request data */
+	mec_io_bytes(MEC_IO_WRITE, CONFIG_EC_BASE_PACKET, sizeof(rq),
+		     msg->data, msg->request_size);
+
+	/* Start the command */
+	outb(EC_MAILBOX_START_COMMAND, CONFIG_EC_BASE_HOST_COMMAND);
+
+	/* Wait for it to complete */
+	if (wilco_ec_response_timed_out()) {
+		printk(BIOS_ERR, "%s: response timed out\n", __func__);
+		return -1;
+	}
+
+	/* Some commands will put the EC into a state where it cannot respond */
+	if (msg->type == WILCO_EC_MSG_NO_RESPONSE) {
+		printk(BIOS_DEBUG, "%s: EC does not respond to this command\n",
+		       __func__);
+		return 0;
+	}
+
+	/* Check result */
+	msg->result = inb(CONFIG_EC_BASE_HOST_DATA);
+	if (msg->result != 0) {
+		printk(BIOS_ERR, "%s: bad response: 0x%02x\n",
+		       __func__, msg->result);
+		return -1;
+	}
+
+	/* Read back response */
+	checksum = mec_io_bytes(MEC_IO_READ, CONFIG_EC_BASE_PACKET, 0,
+				&rs, sizeof(rs));
+	if (checksum) {
+		printk(BIOS_ERR, "%s: bad checksum %02x\n", __func__, checksum);
+		return -1;
+	}
+	msg->result = rs.result;
+
+	/* EC always returns EC_MAILBOX_DATA_SIZE bytes */
+	if (rs.data_size > EC_MAILBOX_DATA_SIZE) {
+		printk(BIOS_ERR, "%s: packet too long (%d bytes, expected %d)",
+		       __func__, rs.data_size, EC_MAILBOX_DATA_SIZE);
+		return -1;
+	}
+
+	if (msg->response_size > rs.data_size) {
+		printk(BIOS_ERR, "%s: data too short (%d bytes, expected %zu)",
+		       __func__, rs.data_size, msg->response_size);
+		return -1;
+	}
+
+	/* Skip response data bytes as requested */
+	skip_size = (msg->type == WILCO_EC_MSG_DEFAULT) ? 1 : 0;
+	memcpy(msg->data, rs.data + skip_size, msg->response_size);
+
+	/* Return actual amount of data received */
+	return msg->response_size;
+}
+
+int wilco_ec_mailbox(enum wilco_ec_msg_type type, uint8_t command,
+		     const void *request_data, size_t request_size,
+		     void *response_data, size_t response_size)
+{
+	struct wilco_ec_message msg;
+	int ret;
+
+	if (request_size > EC_MAILBOX_DATA_SIZE) {
+		printk(BIOS_ERR, "%s: provided request data too large: %zu\n",
+		       __func__, request_size);
+		return -1;
+	}
+	if (response_size > EC_MAILBOX_DATA_SIZE) {
+		printk(BIOS_ERR, "%s: expected response data too large: %zu\n",
+		       __func__, response_size);
+		return -1;
+	}
+	if (request_size && !request_data) {
+		printk(BIOS_ERR, "%s: request data missing\n", __func__);
+		return -1;
+	}
+	if (response_size && !response_data) {
+		printk(BIOS_ERR, "%s: request data missing\n", __func__);
+		return -1;
+	}
+
+	/* Prepare message structure */
+	msg.command = command;
+	msg.request_size = request_size;
+	msg.response_size = response_size;
+	msg.type = type;
+
+	/* Copy request data if present */
+	if (request_size)
+		memcpy(msg.data, request_data, request_size);
+
+	/* Do the EC transfer */
+	ret = wilco_ec_transfer(&msg);
+
+	/* Copy response data if present */
+	if (ret > 0 && response_size)
+		memcpy(response_data, msg.data, response_size);
+
+	/* Return error if message result is non-zero */
+	if (ret >= 0 && msg.result)
+		ret = -1;
+
+	return ret;
+}

-- 
To view, visit https://review.coreboot.org/29113
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8520dadfa982c9d14357cf2aa644e255cef425c2
Gerrit-Change-Number: 29113
Gerrit-PatchSet: 1
Gerrit-Owner: Duncan Laurie <dlaurie at chromium.org>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20181015/de0f6176/attachment-0001.html>


More information about the coreboot-gerrit mailing list