Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp1094831imu; Wed, 23 Jan 2019 10:38:31 -0800 (PST) X-Google-Smtp-Source: ALg8bN72v19tL7hHFxGojto6C5ne7HyltOOvHgoP8bUGCGtiCu2Vn8S6cww+KqtFOUSzZh2VDfar X-Received: by 2002:a63:a112:: with SMTP id b18mr3013419pgf.440.1548268711895; Wed, 23 Jan 2019 10:38:31 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1548268711; cv=none; d=google.com; s=arc-20160816; b=TXq7tf3b4dP/+wqJgSCiz3DQ9TzlylKbwjkxYSPQPUYXMg5kl81i/XTSzTNYCLF75C Dn7SYLCRRcn9uWZvcRp2DJyAsqypw/60tRxR1nxymS43Ff7ukT1IL3lm+bYfPGlJ+FnG tafSq2CCX/+3Ii3MCBrPRiVhOlZzUcDzGLZyy0DPP0FC9HkGKPEnCfZS1I27NkPEBijG 6VZViohR7NN/GipZqSfcAt/+9CO2cYjmaX0QUpmaXD1FP/9dert7HBpmodNvhKGAHanv 52slH1jgfkqr7qzgN3BxiWywaTOexl4hikKEBqh950lCoXqXXqjOZdC77tNBB2udlEnX N7vA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=3XsdTDchC0QTRiT7ka+Ky68LUGiriaUcmcnDL9dpWCk=; b=Aq1JmbZZZ6Snz+ESoeEnHJpdMEvd5PlT4aXgok+yBZyYdmGD3icJKkkVquU9+R7KmI MDLLP8tPJVClclImqXcH9nfjYgcr8fcL84COPd0q0oeXapvHYMCzyLzX9OuAkh/WhX00 ImZ66Z7LyCpIp6BX5gARjE+uhq7f2pf+YVuHosNcTIyHSBpDJtbu0E1FJa9JCFEf3VMu QapztlVBnVHElyIXQeOoLYGfpJFPN1UWw8MGTLavRCQwwXqIO1Pwe2UVHQHCGJ91C6NN Elji7zTF3JvUXMl65Cw5BLD4k3mfahOUiVAm1tH/BXG10iVWTuJbc3TQQggihDhXMEO9 SxwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="M/OGvynK"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c5si17772587pgq.434.2019.01.23.10.38.15; Wed, 23 Jan 2019 10:38:31 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b="M/OGvynK"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726895AbfAWSgM (ORCPT + 99 others); Wed, 23 Jan 2019 13:36:12 -0500 Received: from mail-it1-f194.google.com ([209.85.166.194]:54526 "EHLO mail-it1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726766AbfAWSgL (ORCPT ); Wed, 23 Jan 2019 13:36:11 -0500 Received: by mail-it1-f194.google.com with SMTP id i145so683841ita.4 for ; Wed, 23 Jan 2019 10:36:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3XsdTDchC0QTRiT7ka+Ky68LUGiriaUcmcnDL9dpWCk=; b=M/OGvynKZyLMlIZvj8vN93sRYrjF9xZDRyOPkEuH+EnDiwYZG8sCPKhXBRVAPPLcfK mZeg3XpCtLFhC3RngkCtL3i4sNve0HXC5g5oMFKRA5bF9V25a+zTE2cVccFrS1NLQI2Q uws4IuRhg7J/1AMISeyGsaVU4zz6x8NxbESds= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3XsdTDchC0QTRiT7ka+Ky68LUGiriaUcmcnDL9dpWCk=; b=NYw85LLOgiB92C+qygAga1dVBP3X8Z6X4ikOaS9Yeij97GRZ1l5hQ4I592BrHK0p6d gC+8NCOX+YfcDMRL1lEtYEOOA2eXtFhEY16U0FAtH3DXgyAf9j0bCBc4xcZKMifkC8AS M8bSesVjzUBQ0EhmTYsCrJFewoC+zy5f3IP+wvMhTtniuxNb0qLxgmYPASe9kTEi4+G/ BwGto0g0prF6D+sidj0C5Tv1uX9LrcaupykQP6PyC3TSh6orUnlgeio6VIx7yIpgfKPp tP5zZ3aRFiido0pQEy7IsDCTUpqL+/jTnTN/EfHk5tz51LJLy5j+njcEnHMDemo2T7Do PYmQ== X-Gm-Message-State: AJcUukfTHa4Hu5+qSrwWDi7uAuJsQ0upRN2aw7mXkkOBNtGAMlinebia QCzAaZ7c0FijauRI+JU/ZxWTMAUfjeI= X-Received: by 2002:a02:4f88:: with SMTP id r8mr2276072jad.69.1548268569171; Wed, 23 Jan 2019 10:36:09 -0800 (PST) Received: from ncrews2.bld.corp.google.com ([2620:15c:183:200:8140:8e3f:aea5:bcdf]) by smtp.gmail.com with ESMTPSA id 189sm9537577itw.33.2019.01.23.10.36.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 23 Jan 2019 10:36:08 -0800 (PST) From: Nick Crews To: linux-kernel@vger.kernel.org Cc: sjg@chromium.org, dmitry.torokhov@gmail.com, sre@kernel.org, linux-input@vger.kernel.org, groeck@chromium.org, dlaurie@chromium.org, Duncan Laurie , Enric Balletbo i Serra , Nick Crews , Nick Crews , Benson Leung Subject: [PATCH v4 2/9] platform/chrome: Add new driver for Wilco EC Date: Wed, 23 Jan 2019 11:33:18 -0700 Message-Id: <20190123183325.92946-3-ncrews@chromium.org> X-Mailer: git-send-email 2.20.1.321.g9e740568ce-goog In-Reply-To: <20190123183325.92946-1-ncrews@chromium.org> References: <20190123183325.92946-1-ncrews@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Duncan Laurie This EC is an incompatible variant of the typical Chrome OS embedded controller. It uses the same low-level communication and a similar protocol with some significant differences. The EC firmware does not support the same mailbox commands so it is not registered as a cros_ec device type. Signed-off-by: Duncan Laurie Acked-for-chrome-platform-by: Enric Balletbo i Serra Signed-off-by: Nick Crews --- Changes in v4: - add #define DRV_NAME - remove redundant Kconfig nesting - changed my email to @chromium.org - Add better explanation of what core.c does Changes in v3: - remove unused ret in probe() - Add newline spacer in probe() - rm unnecessary res in get_resource() - s/8bit/8-bit - rm first sleep when sending command to EC Changes in v2: - Remove COMPILE_TEST from Kconfig because inb()/outb() won't work on anything but X86 - Add myself as module author - Tweak mailbox() drivers/platform/chrome/Kconfig | 4 +- drivers/platform/chrome/Makefile | 2 + drivers/platform/chrome/wilco_ec/Kconfig | 11 + drivers/platform/chrome/wilco_ec/Makefile | 4 + drivers/platform/chrome/wilco_ec/core.c | 106 +++++++++ drivers/platform/chrome/wilco_ec/mailbox.c | 236 +++++++++++++++++++++ include/linux/platform_data/wilco-ec.h | 138 ++++++++++++ 7 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/chrome/wilco_ec/Kconfig create mode 100644 drivers/platform/chrome/wilco_ec/Makefile create mode 100644 drivers/platform/chrome/wilco_ec/core.c create mode 100644 drivers/platform/chrome/wilco_ec/mailbox.c create mode 100644 include/linux/platform_data/wilco-ec.h diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 16b1615958aa..bf889adfd4ef 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -49,6 +49,8 @@ config CHROMEOS_TBMC To compile this driver as a module, choose M here: the module will be called chromeos_tbmc. +source "drivers/platform/chrome/wilco_ec/Kconfig" + config CROS_EC_CTL tristate @@ -86,7 +88,7 @@ config CROS_EC_LPC config CROS_EC_LPC_MEC bool "ChromeOS Embedded Controller LPC Microchip EC (MEC) variant" - depends on CROS_EC_LPC + depends on CROS_EC_LPC || WILCO_EC default n help If you say Y here, a variant LPC protocol for the Microchip EC diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index cd591bf872bb..7242ee2b13c5 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -13,3 +13,5 @@ cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o + +obj-$(CONFIG_WILCO_EC) += wilco_ec/ diff --git a/drivers/platform/chrome/wilco_ec/Kconfig b/drivers/platform/chrome/wilco_ec/Kconfig new file mode 100644 index 000000000000..20945a301ec6 --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/Kconfig @@ -0,0 +1,11 @@ +config WILCO_EC + tristate "ChromeOS Wilco Embedded Controller" + depends on ACPI && X86 + select CROS_EC_LPC_MEC + help + If you say Y here, you get support for talking to the ChromeOS + Wilco EC over an eSPI bus. This uses a simple byte-level protocol + with a checksum. + + To compile this driver as a module, choose M here: the + module will be called wilco_ec. diff --git a/drivers/platform/chrome/wilco_ec/Makefile b/drivers/platform/chrome/wilco_ec/Makefile new file mode 100644 index 000000000000..03b32301dc61 --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +wilco_ec-objs := core.o mailbox.o +obj-$(CONFIG_WILCO_EC) += wilco_ec.o diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c new file mode 100644 index 000000000000..7dcb3bde132a --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/core.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Core driver for Wilco Embedded Controller + * + * Copyright 2018 Google LLC + * + * This is the entry point for the drivers that control the Wilco EC. + * This driver is responsible for several tasks: + * - Initialize the register interface that is used by wilco_ec_mailbox() + * - Create a platform device which is picked up by the debugfs driver + * - Create a platform device which is picked up by the RTC driver + * - Initialize the sysfs entries + * - Set up event handling + */ + +#include +#include +#include +#include +#include +#include + +#include "../cros_ec_lpc_mec.h" + +#define DRV_NAME "wilco-ec" + +static struct resource *wilco_get_resource(struct platform_device *pdev, + int index) +{ + struct device *dev = &pdev->dev; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_IO, index); + if (!res) { + dev_dbg(dev, "couldn't find IO resource %d\n", index); + return res; + } + + return devm_request_region(dev, res->start, resource_size(res), + dev_name(dev)); +} + +static int wilco_ec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct wilco_ec_device *ec; + + ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); + if (!ec) + return -ENOMEM; + + platform_set_drvdata(pdev, ec); + ec->dev = dev; + mutex_init(&ec->mailbox_lock); + + /* Largest data buffer size requirement is extended data response */ + ec->data_size = sizeof(struct wilco_ec_response) + + EC_MAILBOX_DATA_SIZE_EXTENDED; + ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL); + if (!ec->data_buffer) + return -ENOMEM; + + /* Prepare access to IO regions provided by ACPI */ + ec->io_data = wilco_get_resource(pdev, 0); /* Host Data */ + ec->io_command = wilco_get_resource(pdev, 1); /* Host Command */ + ec->io_packet = wilco_get_resource(pdev, 2); /* MEC EMI */ + if (!ec->io_data || !ec->io_command || !ec->io_packet) + return -ENODEV; + + /* Initialize cros_ec register interface for communication */ + cros_ec_lpc_mec_init(ec->io_packet->start, + ec->io_packet->start + EC_MAILBOX_DATA_SIZE); + + return 0; +} + +static int wilco_ec_remove(struct platform_device *pdev) +{ + /* Teardown cros_ec interface */ + cros_ec_lpc_mec_destroy(); + + return 0; +} + +static const struct acpi_device_id wilco_ec_acpi_device_ids[] = { + { "GOOG000C", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids); + +static struct platform_driver wilco_ec_driver = { + .driver = { + .name = DRV_NAME, + .acpi_match_table = wilco_ec_acpi_device_ids, + }, + .probe = wilco_ec_probe, + .remove = wilco_ec_remove, +}; + +module_platform_driver(wilco_ec_driver); + +MODULE_AUTHOR("Nick Crews "); +MODULE_AUTHOR("Duncan Laurie "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/platform/chrome/wilco_ec/mailbox.c b/drivers/platform/chrome/wilco_ec/mailbox.c new file mode 100644 index 000000000000..4920a86d83f9 --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/mailbox.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Mailbox interface for Wilco Embedded Controller + * + * Copyright 2018 Google LLC + * + * The Wilco EC is similar to a typical ChromeOS embedded controller. + * It uses the same MEC based low-level communication and a similar + * protocol, but with some important differences. The EC firmware does + * not support the same mailbox commands so it is not registered as a + * cros_ec device type. + * + * Most messages follow a standard format, but there are some exceptions + * and an interface is provided to do direct/raw transactions that do not + * make assumptions about byte placement. + */ + +#include +#include +#include +#include +#include + +#include "../cros_ec_lpc_mec.h" + +/* 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 + +/* Number of header bytes to be counted as data bytes */ +#define EC_MAILBOX_DATA_EXTRA 2 + +/* Maximum timeout */ +#define EC_MAILBOX_TIMEOUT HZ + +/* 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 */ + +/** + * wilco_ec_response_timed_out() - Wait for EC response. + * @ec: EC device. + * + * Return: true if EC timed out, false if EC did not time out. + */ +static bool wilco_ec_response_timed_out(struct wilco_ec_device *ec) +{ + unsigned long timeout = jiffies + EC_MAILBOX_TIMEOUT; + + do { + if (!(inb(ec->io_command->start) & + (EC_CMDR_PENDING | EC_CMDR_BUSY))) + return false; + usleep_range(100, 200); + } while (time_before(jiffies, timeout)); + + return true; +} + +/** + * wilco_ec_checksum() - Compute 8-bit checksum over data range. + * @data: Data to checksum. + * @size: Number of bytes to checksum. + * + * Return: 8-bit checksum of provided data. + */ +static u8 wilco_ec_checksum(const void *data, size_t size) +{ + u8 *data_bytes = (u8 *)data; + u8 checksum = 0; + size_t i; + + for (i = 0; i < size; i++) + checksum += data_bytes[i]; + + return checksum; +} + +/** + * wilco_ec_prepare() - Prepare the request structure for the EC. + * @msg: EC message with request information. + * @rq: EC request structure to fill. + */ +static void wilco_ec_prepare(struct wilco_ec_message *msg, + struct wilco_ec_request *rq) +{ + memset(rq, 0, sizeof(*rq)); + + /* Handle messages without trimming bytes from the request */ + if (msg->request_size && msg->flags & WILCO_EC_FLAG_RAW_REQUEST) { + rq->reserved_raw = *(u8 *)msg->request_data; + msg->request_size--; + memmove(msg->request_data, msg->request_data + 1, + msg->request_size); + } + + /* Fill in request packet */ + rq->struct_version = EC_MAILBOX_PROTO_VERSION; + rq->mailbox_id = msg->type; + 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->request_data, msg->request_size); + rq->checksum = -rq->checksum; +} + +/** + * wilco_ec_transfer() - Perform actual data transfer. + * @ec: EC device. + * @msg: EC message data for request and response. + * @rq: Filled in request structure + * + * Context: ec->mailbox_lock should be held while using this function. + * Return: number of bytes received or negative error code on failure. + */ +int wilco_ec_transfer(struct wilco_ec_device *ec, struct wilco_ec_message *msg, + struct wilco_ec_request *rq) +{ + struct wilco_ec_response *rs; + u8 checksum; + u8 flag; + size_t size; + + /* Write request header, then data */ + cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, 0, sizeof(*rq), (u8 *)rq); + cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, sizeof(*rq), msg->request_size, + msg->request_data); + + /* Start the command */ + outb(EC_MAILBOX_START_COMMAND, ec->io_command->start); + + /* Wait for it to complete */ + if (wilco_ec_response_timed_out(ec)) { + dev_dbg(ec->dev, "response timed out\n"); + return -ETIMEDOUT; + } + + /* For some commands (eg shutdown) the EC will not respond, that's OK */ + if (msg->flags & WILCO_EC_FLAG_NO_RESPONSE) { + dev_dbg(ec->dev, "EC does not respond to this command\n"); + return 0; + } + + /* Check result */ + flag = inb(ec->io_data->start); + if (flag) { + dev_dbg(ec->dev, "bad response: 0x%02x\n", flag); + return -EIO; + } + + if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA) + size = EC_MAILBOX_DATA_SIZE_EXTENDED; + else + size = EC_MAILBOX_DATA_SIZE; + + /* Read back response */ + rs = ec->data_buffer; + checksum = cros_ec_lpc_io_bytes_mec(MEC_IO_READ, 0, + sizeof(*rs) + size, (u8 *)rs); + if (checksum) { + dev_dbg(ec->dev, "bad packet checksum 0x%02x\n", rs->checksum); + return -EBADMSG; + } + + /* Check that the EC reported success */ + msg->result = rs->result; + if (msg->result) { + dev_dbg(ec->dev, "bad response: 0x%02x\n", msg->result); + return -EBADMSG; + } + + /* Check the returned data size, skipping the header */ + if (rs->data_size != size) { + dev_dbg(ec->dev, "unexpected packet size (%u != %zu)", + rs->data_size, size); + return -EMSGSIZE; + } + + /* Skip 1 response data byte unless specified */ + size = (msg->flags & WILCO_EC_FLAG_RAW_RESPONSE) ? 0 : 1; + if ((ssize_t) rs->data_size - size < msg->response_size) { + dev_dbg(ec->dev, "response data too short (%zd < %zu)", + (ssize_t) rs->data_size - size, msg->response_size); + return -EMSGSIZE; + } + + /* Ignore response data bytes as requested */ + memcpy(msg->response_data, rs->data + size, msg->response_size); + + /* Return actual amount of data received */ + return msg->response_size; +} + +/** + * wilco_ec_mailbox() - Send EC request and receive EC response. + * @ec: EC device. + * @msg: EC message data for request and response. + * + * On entry msg->type, msg->flags, msg->command, msg->request_size, + * msg->response_size, and msg->request_data should all be filled in. + * + * On exit msg->result and msg->response_data will be filled. + * + * Return: number of bytes received or negative error code on failure. + */ +int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg) +{ + struct wilco_ec_request *rq; + int ret; + + dev_dbg(ec->dev, "cmd=%02x type=%04x flags=%02x rslen=%zu rqlen=%zu\n", + msg->command, msg->type, msg->flags, msg->response_size, + msg->request_size); + + /* Prepare request packet */ + rq = ec->data_buffer; + wilco_ec_prepare(msg, rq); + + mutex_lock(&ec->mailbox_lock); + ret = wilco_ec_transfer(ec, msg, rq); + mutex_unlock(&ec->mailbox_lock); + + return ret; + +} +EXPORT_SYMBOL_GPL(wilco_ec_mailbox); diff --git a/include/linux/platform_data/wilco-ec.h b/include/linux/platform_data/wilco-ec.h new file mode 100644 index 000000000000..5477b8802f81 --- /dev/null +++ b/include/linux/platform_data/wilco-ec.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ChromeOS Wilco Embedded Controller + * + * Copyright 2018 Google LLC + */ + +#ifndef WILCO_EC_H +#define WILCO_EC_H + +#include +#include + +#define WILCO_EC_FLAG_NO_RESPONSE BIT(0) /* EC does not respond */ +#define WILCO_EC_FLAG_EXTENDED_DATA BIT(1) /* EC returns 256 data bytes */ +#define WILCO_EC_FLAG_RAW_REQUEST BIT(2) /* Do not trim request data */ +#define WILCO_EC_FLAG_RAW_RESPONSE BIT(3) /* Do not trim response data */ +#define WILCO_EC_FLAG_RAW (WILCO_EC_FLAG_RAW_REQUEST | \ + WILCO_EC_FLAG_RAW_RESPONSE) + +/* Normal commands have a maximum 32 bytes of data */ +#define EC_MAILBOX_DATA_SIZE 32 + +/* Extended commands have 256 bytes of response data */ +#define EC_MAILBOX_DATA_SIZE_EXTENDED 256 + +/** + * struct wilco_ec_device - Wilco Embedded Controller handle. + * @dev: Device handle. + * @mailbox_lock: Mutex to ensure one mailbox command at a time. + * @io_command: I/O port for mailbox command. Provided by ACPI. + * @io_data: I/O port for mailbox data. Provided by ACPI. + * @io_packet: I/O port for mailbox packet data. Provided by ACPI. + * @data_buffer: Buffer used for EC communication. The same buffer + * is used to hold the request and the response. + * @data_size: Size of the data buffer used for EC communication. + */ +struct wilco_ec_device { + struct device *dev; + struct mutex mailbox_lock; + struct resource *io_command; + struct resource *io_data; + struct resource *io_packet; + void *data_buffer; + size_t data_size; +}; + +/** + * enum wilco_ec_msg_type - Message type to select a set of command codes. + * @WILCO_EC_MSG_LEGACY: Legacy EC messages for standard EC behavior. + * @WILCO_EC_MSG_PROPERTY: Get/Set/Sync EC controlled NVRAM property. + * @WILCO_EC_MSG_TELEMETRY: Telemetry data provided by the EC. + */ +enum wilco_ec_msg_type { + WILCO_EC_MSG_LEGACY = 0x00f0, + WILCO_EC_MSG_PROPERTY = 0x00f2, + WILCO_EC_MSG_TELEMETRY = 0x00f5, +}; + +/** + * struct wilco_ec_message - Request and response message. + * @type: Mailbox message type. + * @flags: Message flags. + * @command: Mailbox command code. + * @result: Result code from the EC. Non-zero indicates an error. + * @request_size: Number of bytes to send to the EC. + * @request_data: Buffer containing the request data. + * @response_size: Number of bytes expected from the EC. + * This is 32 by default and 256 if the flag + * is set for %WILCO_EC_FLAG_EXTENDED_DATA + * @response_data: Buffer containing the response data, should be + * response_size bytes and allocated by caller. + */ +struct wilco_ec_message { + enum wilco_ec_msg_type type; + u8 flags; + u8 command; + u8 result; + size_t request_size; + void *request_data; + size_t response_size; + void *response_data; +}; + +/** + * struct wilco_ec_request - Mailbox request message format. + * @struct_version: Should be %EC_MAILBOX_PROTO_VERSION + * @checksum: Sum of all bytes must be 0. + * @mailbox_id: Mailbox identifier, specifies the command set. + * @mailbox_version: Mailbox interface version %EC_MAILBOX_VERSION + * @reserved: Set to zero. + * @data_size: Length of request, data + last 2 bytes of the header. + * @command: Mailbox command code, unique for each mailbox_id set. + * @reserved_raw: Set to zero for most commands, but is used by + * some command types and for raw commands. + */ +struct wilco_ec_request { + u8 struct_version; + u8 checksum; + u16 mailbox_id; + u8 mailbox_version; + u8 reserved; + u16 data_size; + u8 command; + u8 reserved_raw; +} __packed; + +/** + * struct wilco_ec_response - Mailbox response message format. + * @struct_version: Should be %EC_MAILBOX_PROTO_VERSION + * @checksum: Sum of all bytes must be 0. + * @result: Result code from the EC. Non-zero indicates an error. + * @data_size: Length of the response data buffer. + * @reserved: Set to zero. + * @mbox0: EC returned data at offset 0 is unused (always 0) so this byte + * is treated as part of the header instead of the data. + * @data: Response data buffer. Max size is %EC_MAILBOX_DATA_SIZE_EXTENDED. + */ +struct wilco_ec_response { + u8 struct_version; + u8 checksum; + u16 result; + u16 data_size; + u8 reserved[2]; + u8 mbox0; + u8 data[0]; +} __packed; + +/** + * wilco_ec_mailbox() - Send request to the EC and receive the response. + * @ec: Wilco EC device. + * @msg: Wilco EC message. + * + * Return: Number of bytes received or negative error code on failure. + */ +int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg); + +#endif /* WILCO_EC_H */ -- 2.20.1.321.g9e740568ce-goog